diff --git a/VERSION b/VERSION
index 2cea6f95..0d7356f4 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-0.2.1-26-g368de33-master
+0.2.1-26-g368de33-master
\ No newline at end of file
diff --git a/dist/main.bundle.js b/dist/main.bundle.js
index a244e352..179246ef 100644
--- a/dist/main.bundle.js
+++ b/dist/main.bundle.js
@@ -141,4 +141,4 @@ $(function () {
/***/ })
/******/ ]);
-//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vd2VicGFjay9ib290c3RyYXAgZDZjNjM4ZTFkY2EwMzA4MWZmNzMiLCJ3ZWJwYWNrOi8vLy4vc3JjL2luZGV4LmpzIiwid2VicGFjazovLy8uL3NyYy9zdHlsZS5jc3MiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtRQUFBO1FBQ0E7O1FBRUE7UUFDQTs7UUFFQTtRQUNBO1FBQ0E7UUFDQTtRQUNBO1FBQ0E7UUFDQTtRQUNBO1FBQ0E7UUFDQTs7UUFFQTtRQUNBOztRQUVBO1FBQ0E7O1FBRUE7UUFDQTtRQUNBOzs7UUFHQTtRQUNBOztRQUVBO1FBQ0E7O1FBRUE7UUFDQTtRQUNBO1FBQ0E7UUFDQTtRQUNBO1FBQ0E7UUFDQSxLQUFLO1FBQ0w7UUFDQTs7UUFFQTtRQUNBO1FBQ0E7UUFDQSwyQkFBMkIsMEJBQTBCLEVBQUU7UUFDdkQsaUNBQWlDLGVBQWU7UUFDaEQ7UUFDQTtRQUNBOztRQUVBO1FBQ0Esc0RBQXNELCtEQUErRDs7UUFFckg7UUFDQTs7UUFFQTtRQUNBOzs7Ozs7OztBQzdEQTtBQUFBO0FBQUE7QUFBb0I7O0FBRXBCOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTtBQUNGO0FBQ0E7QUFDQTtBQUNBLEtBQUs7O0FBRUw7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxZQUFZLGVBQWU7QUFDM0IsZUFBZTtBQUNmO0FBQ0E7QUFDQSxNQUFNO0FBQ047QUFDQTtBQUNBOztBQUVBLEtBQUs7O0FBRUw7QUFDQTtBQUNBOztBQUVBOztBQUVBLGdCQUFnQixtQkFBbUI7O0FBRW5DO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsTUFBTTs7QUFFTixFQUFFOztBQUVGO0FBQ0E7O0FBRUE7O0FBRUEsQ0FBQzs7Ozs7OztBQzNERCx5QyIsImZpbGUiOiJtYWluLmJ1bmRsZS5qcyIsInNvdXJjZXNDb250ZW50IjpbIiBcdC8vIFRoZSBtb2R1bGUgY2FjaGVcbiBcdHZhciBpbnN0YWxsZWRNb2R1bGVzID0ge307XG5cbiBcdC8vIFRoZSByZXF1aXJlIGZ1bmN0aW9uXG4gXHRmdW5jdGlvbiBfX3dlYnBhY2tfcmVxdWlyZV9fKG1vZHVsZUlkKSB7XG5cbiBcdFx0Ly8gQ2hlY2sgaWYgbW9kdWxlIGlzIGluIGNhY2hlXG4gXHRcdGlmKGluc3RhbGxlZE1vZHVsZXNbbW9kdWxlSWRdKSB7XG4gXHRcdFx0cmV0dXJuIGluc3RhbGxlZE1vZHVsZXNbbW9kdWxlSWRdLmV4cG9ydHM7XG4gXHRcdH1cbiBcdFx0Ly8gQ3JlYXRlIGEgbmV3IG1vZHVsZSAoYW5kIHB1dCBpdCBpbnRvIHRoZSBjYWNoZSlcbiBcdFx0dmFyIG1vZHVsZSA9IGluc3RhbGxlZE1vZHVsZXNbbW9kdWxlSWRdID0ge1xuIFx0XHRcdGk6IG1vZHVsZUlkLFxuIFx0XHRcdGw6IGZhbHNlLFxuIFx0XHRcdGV4cG9ydHM6IHt9XG4gXHRcdH07XG5cbiBcdFx0Ly8gRXhlY3V0ZSB0aGUgbW9kdWxlIGZ1bmN0aW9uXG4gXHRcdG1vZHVsZXNbbW9kdWxlSWRdLmNhbGwobW9kdWxlLmV4cG9ydHMsIG1vZHVsZSwgbW9kdWxlLmV4cG9ydHMsIF9fd2VicGFja19yZXF1aXJlX18pO1xuXG4gXHRcdC8vIEZsYWcgdGhlIG1vZHVsZSBhcyBsb2FkZWRcbiBcdFx0bW9kdWxlLmwgPSB0cnVlO1xuXG4gXHRcdC8vIFJldHVybiB0aGUgZXhwb3J0cyBvZiB0aGUgbW9kdWxlXG4gXHRcdHJldHVybiBtb2R1bGUuZXhwb3J0cztcbiBcdH1cblxuXG4gXHQvLyBleHBvc2UgdGhlIG1vZHVsZXMgb2JqZWN0IChfX3dlYnBhY2tfbW9kdWxlc19fKVxuIFx0X193ZWJwYWNrX3JlcXVpcmVfXy5tID0gbW9kdWxlcztcblxuIFx0Ly8gZXhwb3NlIHRoZSBtb2R1bGUgY2FjaGVcbiBcdF9fd2VicGFja19yZXF1aXJlX18uYyA9IGluc3RhbGxlZE1vZHVsZXM7XG5cbiBcdC8vIGRlZmluZSBnZXR0ZXIgZnVuY3Rpb24gZm9yIGhhcm1vbnkgZXhwb3J0c1xuIFx0X193ZWJwYWNrX3JlcXVpcmVfXy5kID0gZnVuY3Rpb24oZXhwb3J0cywgbmFtZSwgZ2V0dGVyKSB7XG4gXHRcdGlmKCFfX3dlYnBhY2tfcmVxdWlyZV9fLm8oZXhwb3J0cywgbmFtZSkpIHtcbiBcdFx0XHRPYmplY3QuZGVmaW5lUHJvcGVydHkoZXhwb3J0cywgbmFtZSwge1xuIFx0XHRcdFx0Y29uZmlndXJhYmxlOiBmYWxzZSxcbiBcdFx0XHRcdGVudW1lcmFibGU6IHRydWUsXG4gXHRcdFx0XHRnZXQ6IGdldHRlclxuIFx0XHRcdH0pO1xuIFx0XHR9XG4gXHR9O1xuXG4gXHQvLyBnZXREZWZhdWx0RXhwb3J0IGZ1bmN0aW9uIGZvciBjb21wYXRpYmlsaXR5IHdpdGggbm9uLWhhcm1vbnkgbW9kdWxlc1xuIFx0X193ZWJwYWNrX3JlcXVpcmVfXy5uID0gZnVuY3Rpb24obW9kdWxlKSB7XG4gXHRcdHZhciBnZXR0ZXIgPSBtb2R1bGUgJiYgbW9kdWxlLl9fZXNNb2R1bGUgP1xuIFx0XHRcdGZ1bmN0aW9uIGdldERlZmF1bHQoKSB7IHJldHVybiBtb2R1bGVbJ2RlZmF1bHQnXTsgfSA6XG4gXHRcdFx0ZnVuY3Rpb24gZ2V0TW9kdWxlRXhwb3J0cygpIHsgcmV0dXJuIG1vZHVsZTsgfTtcbiBcdFx0X193ZWJwYWNrX3JlcXVpcmVfXy5kKGdldHRlciwgJ2EnLCBnZXR0ZXIpO1xuIFx0XHRyZXR1cm4gZ2V0dGVyO1xuIFx0fTtcblxuIFx0Ly8gT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsXG4gXHRfX3dlYnBhY2tfcmVxdWlyZV9fLm8gPSBmdW5jdGlvbihvYmplY3QsIHByb3BlcnR5KSB7IHJldHVybiBPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwob2JqZWN0LCBwcm9wZXJ0eSk7IH07XG5cbiBcdC8vIF9fd2VicGFja19wdWJsaWNfcGF0aF9fXG4gXHRfX3dlYnBhY2tfcmVxdWlyZV9fLnAgPSBcIlwiO1xuXG4gXHQvLyBMb2FkIGVudHJ5IG1vZHVsZSBhbmQgcmV0dXJuIGV4cG9ydHNcbiBcdHJldHVybiBfX3dlYnBhY2tfcmVxdWlyZV9fKF9fd2VicGFja19yZXF1aXJlX18ucyA9IDApO1xuXG5cblxuLy8gV0VCUEFDSyBGT09URVIgLy9cbi8vIHdlYnBhY2svYm9vdHN0cmFwIGQ2YzYzOGUxZGNhMDMwODFmZjczIiwiaW1wb3J0ICcuL3N0eWxlLmNzcydcblxuJChmdW5jdGlvbiAoKSB7XG5cbiAgICBzZXRJbnRlcnZhbChmdW5jdGlvbigpIHtcblx0dmFyIHRpbWVsZWZ0ID0gcGFyc2VJbnQoJChcIiN0aW1lbGVmdFwiKS5odG1sKCkpO1xuXHRpZiAodGltZWxlZnQgPiAwKSB7XG5cdCAgICB0aW1lbGVmdC0tO1xuXHR9IGVsc2Uge1xuXHQgICAgdGltZWxlZnQgPSAwO1xuXHR9XG5cdCQoXCIjdGltZWxlZnRcIikuaHRtbCh0aW1lbGVmdClcbiAgICB9LCAxMDAwKTtcbiAgICBcbiAgICAkKFwiI215SW5wdXRcIikub24oXCJrZXl1cFwiLCBmdW5jdGlvbihldmVudE9iamVjdCkge1xuXHRcblx0dmFyIGlucHV0LCBmaWx0ZXIsIHVsLCBsaSwgYSwgaTtcblxuXHRpbnB1dCA9IGV2ZW50T2JqZWN0LmN1cnJlbnRUYXJnZXQ7XG5cdGZpbHRlciA9IGlucHV0LnZhbHVlLnRvVXBwZXJDYXNlKCk7XG5cdHVsID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoXCJteVVMXCIpO1xuXHRsaSA9IHVsLmdldEVsZW1lbnRzQnlUYWdOYW1lKCdhJyk7XG5cblx0Ly8gTG9vcCB0aHJvdWdoIGFsbCBsaXN0IGl0ZW1zLCBhbmQgaGlkZSB0aG9zZSB3aG8gZG9uJ3QgbWF0Y2ggdGhlIHNlYXJjaCBxdWVyeVxuXHRmb3IgKGkgPSAwOyBpIDwgbGkubGVuZ3RoOyBpKyspIHtcblx0ICAgIGEgPSBsaVtpXTsgLy9saVtpXS5nZXRFbGVtZW50c0J5VGFnTmFtZShcImFcIilbMF07XG5cdCAgICBpZiAoYS5pbm5lckhUTUwudG9VcHBlckNhc2UoKS5pbmRleE9mKGZpbHRlcikgPiAtMSkge1xuXHRcdGxpW2ldLnN0eWxlLmRpc3BsYXkgPSBcIlwiO1xuXHQgICAgfSBlbHNlIHtcblx0XHRsaVtpXS5zdHlsZS5kaXNwbGF5ID0gXCJub25lXCI7XG5cdCAgICB9XG5cdH1cblxuICAgIH0pO1xuXG4gICAgZnVuY3Rpb24gZGVsZXRlSGFuZGxlcihldmVudE9iamVjdCkge1xuXHR2YXIgdXJsID0gdGhpcy5kYXRhc2V0LnVybDtcblx0dmFyIG1vZGFsRWwgPSAkKCcja2FybWVuLW1vZGFsLXJlbW92ZScpO1xuXHRcblx0dmFyIGVsID0gJCh0aGlzKTtcblxuXHRtb2RhbEVsLm1vZGFsKHtiYWNrZHJvcDogJ3N0YXRpYyd9KS5vbmUoJ2NsaWNrJywgJyNrYXJtZW4tbW9kYWwtYnRuLWNvbmZpcm0nLCBmdW5jdGlvbigpIHtcblx0ICAgIFxuXHQgICAgJC5hamF4KHtcblx0XHR1cmw6IHVybCxcblx0XHR0eXBlOiAnREVMRVRFJyxcblx0XHRzdWNjZXNzOiBmdW5jdGlvbihyZXN1bHQpIHtcblx0XHQgICAgbW9kYWxFbC5tb2RhbCgnaGlkZScpO1xuXHRcdCAgICB3aW5kb3cubG9jYXRpb24ucmVwbGFjZShyZXN1bHQucmVkaXJlY3RfdXJsKTtcblx0XHR9XG5cdCAgICB9KTtcblx0ICAgIFxuXHR9KTtcblx0XG5cdHJldHVybiBmYWxzZTtcbiAgICB9O1xuICAgIFxuICAgICQoXCIua2FybWVuLWFqYXgtZGVsZXRlXCIpLm9uKFwiY2xpY2tcIiwgZGVsZXRlSGFuZGxlcik7XG5cbn0pO1xuXG5cblxuLy8vLy8vLy8vLy8vLy8vLy8vXG4vLyBXRUJQQUNLIEZPT1RFUlxuLy8gLi9zcmMvaW5kZXguanNcbi8vIG1vZHVsZSBpZCA9IDBcbi8vIG1vZHVsZSBjaHVua3MgPSAwIiwiLy8gcmVtb3ZlZCBieSBleHRyYWN0LXRleHQtd2VicGFjay1wbHVnaW5cblxuXG4vLy8vLy8vLy8vLy8vLy8vLy9cbi8vIFdFQlBBQ0sgRk9PVEVSXG4vLyAuL3NyYy9zdHlsZS5jc3Ncbi8vIG1vZHVsZSBpZCA9IDFcbi8vIG1vZHVsZSBjaHVua3MgPSAwIl0sInNvdXJjZVJvb3QiOiIifQ==
\ No newline at end of file
+//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vd2VicGFjay9ib290c3RyYXAgYTcxMGM3Y2ZkNTA0OTgyOGNjMmEiLCJ3ZWJwYWNrOi8vLy4vc3JjL2luZGV4LmpzIiwid2VicGFjazovLy8uL3NyYy9zdHlsZS5jc3MiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtRQUFBO1FBQ0E7O1FBRUE7UUFDQTs7UUFFQTtRQUNBO1FBQ0E7UUFDQTtRQUNBO1FBQ0E7UUFDQTtRQUNBO1FBQ0E7UUFDQTs7UUFFQTtRQUNBOztRQUVBO1FBQ0E7O1FBRUE7UUFDQTtRQUNBOzs7UUFHQTtRQUNBOztRQUVBO1FBQ0E7O1FBRUE7UUFDQTtRQUNBO1FBQ0E7UUFDQTtRQUNBO1FBQ0E7UUFDQSxLQUFLO1FBQ0w7UUFDQTs7UUFFQTtRQUNBO1FBQ0E7UUFDQSwyQkFBMkIsMEJBQTBCLEVBQUU7UUFDdkQsaUNBQWlDLGVBQWU7UUFDaEQ7UUFDQTtRQUNBOztRQUVBO1FBQ0Esc0RBQXNELCtEQUErRDs7UUFFckg7UUFDQTs7UUFFQTtRQUNBOzs7Ozs7OztBQzdEQTtBQUFBO0FBQUE7QUFBb0I7O0FBRXBCOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTtBQUNGO0FBQ0E7QUFDQTtBQUNBLEtBQUs7O0FBRUw7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxZQUFZLGVBQWU7QUFDM0IsZUFBZTtBQUNmO0FBQ0E7QUFDQSxNQUFNO0FBQ047QUFDQTtBQUNBOztBQUVBLEtBQUs7O0FBRUw7QUFDQTtBQUNBOztBQUVBOztBQUVBLGdCQUFnQixtQkFBbUI7O0FBRW5DO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsTUFBTTs7QUFFTixFQUFFOztBQUVGO0FBQ0E7O0FBRUE7O0FBRUEsQ0FBQzs7Ozs7OztBQzNERCx5QyIsImZpbGUiOiJtYWluLmJ1bmRsZS5qcyIsInNvdXJjZXNDb250ZW50IjpbIiBcdC8vIFRoZSBtb2R1bGUgY2FjaGVcbiBcdHZhciBpbnN0YWxsZWRNb2R1bGVzID0ge307XG5cbiBcdC8vIFRoZSByZXF1aXJlIGZ1bmN0aW9uXG4gXHRmdW5jdGlvbiBfX3dlYnBhY2tfcmVxdWlyZV9fKG1vZHVsZUlkKSB7XG5cbiBcdFx0Ly8gQ2hlY2sgaWYgbW9kdWxlIGlzIGluIGNhY2hlXG4gXHRcdGlmKGluc3RhbGxlZE1vZHVsZXNbbW9kdWxlSWRdKSB7XG4gXHRcdFx0cmV0dXJuIGluc3RhbGxlZE1vZHVsZXNbbW9kdWxlSWRdLmV4cG9ydHM7XG4gXHRcdH1cbiBcdFx0Ly8gQ3JlYXRlIGEgbmV3IG1vZHVsZSAoYW5kIHB1dCBpdCBpbnRvIHRoZSBjYWNoZSlcbiBcdFx0dmFyIG1vZHVsZSA9IGluc3RhbGxlZE1vZHVsZXNbbW9kdWxlSWRdID0ge1xuIFx0XHRcdGk6IG1vZHVsZUlkLFxuIFx0XHRcdGw6IGZhbHNlLFxuIFx0XHRcdGV4cG9ydHM6IHt9XG4gXHRcdH07XG5cbiBcdFx0Ly8gRXhlY3V0ZSB0aGUgbW9kdWxlIGZ1bmN0aW9uXG4gXHRcdG1vZHVsZXNbbW9kdWxlSWRdLmNhbGwobW9kdWxlLmV4cG9ydHMsIG1vZHVsZSwgbW9kdWxlLmV4cG9ydHMsIF9fd2VicGFja19yZXF1aXJlX18pO1xuXG4gXHRcdC8vIEZsYWcgdGhlIG1vZHVsZSBhcyBsb2FkZWRcbiBcdFx0bW9kdWxlLmwgPSB0cnVlO1xuXG4gXHRcdC8vIFJldHVybiB0aGUgZXhwb3J0cyBvZiB0aGUgbW9kdWxlXG4gXHRcdHJldHVybiBtb2R1bGUuZXhwb3J0cztcbiBcdH1cblxuXG4gXHQvLyBleHBvc2UgdGhlIG1vZHVsZXMgb2JqZWN0IChfX3dlYnBhY2tfbW9kdWxlc19fKVxuIFx0X193ZWJwYWNrX3JlcXVpcmVfXy5tID0gbW9kdWxlcztcblxuIFx0Ly8gZXhwb3NlIHRoZSBtb2R1bGUgY2FjaGVcbiBcdF9fd2VicGFja19yZXF1aXJlX18uYyA9IGluc3RhbGxlZE1vZHVsZXM7XG5cbiBcdC8vIGRlZmluZSBnZXR0ZXIgZnVuY3Rpb24gZm9yIGhhcm1vbnkgZXhwb3J0c1xuIFx0X193ZWJwYWNrX3JlcXVpcmVfXy5kID0gZnVuY3Rpb24oZXhwb3J0cywgbmFtZSwgZ2V0dGVyKSB7XG4gXHRcdGlmKCFfX3dlYnBhY2tfcmVxdWlyZV9fLm8oZXhwb3J0cywgbmFtZSkpIHtcbiBcdFx0XHRPYmplY3QuZGVmaW5lUHJvcGVydHkoZXhwb3J0cywgbmFtZSwge1xuIFx0XHRcdFx0Y29uZmlndXJhYmxlOiBmYWxzZSxcbiBcdFx0XHRcdGVudW1lcmFibGU6IHRydWUsXG4gXHRcdFx0XHRnZXQ6IGdldHRlclxuIFx0XHRcdH0pO1xuIFx0XHR9XG4gXHR9O1xuXG4gXHQvLyBnZXREZWZhdWx0RXhwb3J0IGZ1bmN0aW9uIGZvciBjb21wYXRpYmlsaXR5IHdpdGggbm9uLWhhcm1vbnkgbW9kdWxlc1xuIFx0X193ZWJwYWNrX3JlcXVpcmVfXy5uID0gZnVuY3Rpb24obW9kdWxlKSB7XG4gXHRcdHZhciBnZXR0ZXIgPSBtb2R1bGUgJiYgbW9kdWxlLl9fZXNNb2R1bGUgP1xuIFx0XHRcdGZ1bmN0aW9uIGdldERlZmF1bHQoKSB7IHJldHVybiBtb2R1bGVbJ2RlZmF1bHQnXTsgfSA6XG4gXHRcdFx0ZnVuY3Rpb24gZ2V0TW9kdWxlRXhwb3J0cygpIHsgcmV0dXJuIG1vZHVsZTsgfTtcbiBcdFx0X193ZWJwYWNrX3JlcXVpcmVfXy5kKGdldHRlciwgJ2EnLCBnZXR0ZXIpO1xuIFx0XHRyZXR1cm4gZ2V0dGVyO1xuIFx0fTtcblxuIFx0Ly8gT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsXG4gXHRfX3dlYnBhY2tfcmVxdWlyZV9fLm8gPSBmdW5jdGlvbihvYmplY3QsIHByb3BlcnR5KSB7IHJldHVybiBPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwob2JqZWN0LCBwcm9wZXJ0eSk7IH07XG5cbiBcdC8vIF9fd2VicGFja19wdWJsaWNfcGF0aF9fXG4gXHRfX3dlYnBhY2tfcmVxdWlyZV9fLnAgPSBcIlwiO1xuXG4gXHQvLyBMb2FkIGVudHJ5IG1vZHVsZSBhbmQgcmV0dXJuIGV4cG9ydHNcbiBcdHJldHVybiBfX3dlYnBhY2tfcmVxdWlyZV9fKF9fd2VicGFja19yZXF1aXJlX18ucyA9IDApO1xuXG5cblxuLy8gV0VCUEFDSyBGT09URVIgLy9cbi8vIHdlYnBhY2svYm9vdHN0cmFwIGE3MTBjN2NmZDUwNDk4MjhjYzJhIiwiaW1wb3J0ICcuL3N0eWxlLmNzcydcblxuJChmdW5jdGlvbiAoKSB7XG5cbiAgICBzZXRJbnRlcnZhbChmdW5jdGlvbigpIHtcblx0dmFyIHRpbWVsZWZ0ID0gcGFyc2VJbnQoJChcIiN0aW1lbGVmdFwiKS5odG1sKCkpO1xuXHRpZiAodGltZWxlZnQgPiAwKSB7XG5cdCAgICB0aW1lbGVmdC0tO1xuXHR9IGVsc2Uge1xuXHQgICAgdGltZWxlZnQgPSAwO1xuXHR9XG5cdCQoXCIjdGltZWxlZnRcIikuaHRtbCh0aW1lbGVmdClcbiAgICB9LCAxMDAwKTtcbiAgICBcbiAgICAkKFwiI215SW5wdXRcIikub24oXCJrZXl1cFwiLCBmdW5jdGlvbihldmVudE9iamVjdCkge1xuXHRcblx0dmFyIGlucHV0LCBmaWx0ZXIsIHVsLCBsaSwgYSwgaTtcblxuXHRpbnB1dCA9IGV2ZW50T2JqZWN0LmN1cnJlbnRUYXJnZXQ7XG5cdGZpbHRlciA9IGlucHV0LnZhbHVlLnRvVXBwZXJDYXNlKCk7XG5cdHVsID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoXCJteVVMXCIpO1xuXHRsaSA9IHVsLmdldEVsZW1lbnRzQnlUYWdOYW1lKCdhJyk7XG5cblx0Ly8gTG9vcCB0aHJvdWdoIGFsbCBsaXN0IGl0ZW1zLCBhbmQgaGlkZSB0aG9zZSB3aG8gZG9uJ3QgbWF0Y2ggdGhlIHNlYXJjaCBxdWVyeVxuXHRmb3IgKGkgPSAwOyBpIDwgbGkubGVuZ3RoOyBpKyspIHtcblx0ICAgIGEgPSBsaVtpXTsgLy9saVtpXS5nZXRFbGVtZW50c0J5VGFnTmFtZShcImFcIilbMF07XG5cdCAgICBpZiAoYS5pbm5lckhUTUwudG9VcHBlckNhc2UoKS5pbmRleE9mKGZpbHRlcikgPiAtMSkge1xuXHRcdGxpW2ldLnN0eWxlLmRpc3BsYXkgPSBcIlwiO1xuXHQgICAgfSBlbHNlIHtcblx0XHRsaVtpXS5zdHlsZS5kaXNwbGF5ID0gXCJub25lXCI7XG5cdCAgICB9XG5cdH1cblxuICAgIH0pO1xuXG4gICAgZnVuY3Rpb24gZGVsZXRlSGFuZGxlcihldmVudE9iamVjdCkge1xuXHR2YXIgdXJsID0gdGhpcy5kYXRhc2V0LnVybDtcblx0dmFyIG1vZGFsRWwgPSAkKCcja2FybWVuLW1vZGFsLXJlbW92ZScpO1xuXHRcblx0dmFyIGVsID0gJCh0aGlzKTtcblxuXHRtb2RhbEVsLm1vZGFsKHtiYWNrZHJvcDogJ3N0YXRpYyd9KS5vbmUoJ2NsaWNrJywgJyNrYXJtZW4tbW9kYWwtYnRuLWNvbmZpcm0nLCBmdW5jdGlvbigpIHtcblx0ICAgIFxuXHQgICAgJC5hamF4KHtcblx0XHR1cmw6IHVybCxcblx0XHR0eXBlOiAnREVMRVRFJyxcblx0XHRzdWNjZXNzOiBmdW5jdGlvbihyZXN1bHQpIHtcblx0XHQgICAgbW9kYWxFbC5tb2RhbCgnaGlkZScpO1xuXHRcdCAgICB3aW5kb3cubG9jYXRpb24ucmVwbGFjZShyZXN1bHQucmVkaXJlY3RfdXJsKTtcblx0XHR9XG5cdCAgICB9KTtcblx0ICAgIFxuXHR9KTtcblx0XG5cdHJldHVybiBmYWxzZTtcbiAgICB9O1xuICAgIFxuICAgICQoXCIua2FybWVuLWFqYXgtZGVsZXRlXCIpLm9uKFwiY2xpY2tcIiwgZGVsZXRlSGFuZGxlcik7XG5cbn0pO1xuXG5cblxuLy8vLy8vLy8vLy8vLy8vLy8vXG4vLyBXRUJQQUNLIEZPT1RFUlxuLy8gLi9zcmMvaW5kZXguanNcbi8vIG1vZHVsZSBpZCA9IDBcbi8vIG1vZHVsZSBjaHVua3MgPSAwIiwiLy8gcmVtb3ZlZCBieSBleHRyYWN0LXRleHQtd2VicGFjay1wbHVnaW5cblxuXG4vLy8vLy8vLy8vLy8vLy8vLy9cbi8vIFdFQlBBQ0sgRk9PVEVSXG4vLyAuL3NyYy9zdHlsZS5jc3Ncbi8vIG1vZHVsZSBpZCA9IDFcbi8vIG1vZHVsZSBjaHVua3MgPSAwIl0sInNvdXJjZVJvb3QiOiIifQ==
\ No newline at end of file
diff --git a/dist/styles.css b/dist/styles.css
index 333cbf45..ba4645a6 100644
--- a/dist/styles.css
+++ b/dist/styles.css
@@ -4,7 +4,7 @@ html {
body {
padding-top: 60px;
- position: relative;
+ /*position: relative;*/
}
div.login {
diff --git a/handlers/handlers.go b/handlers/handlers.go
index dd25f5cc..44659f56 100644
--- a/handlers/handlers.go
+++ b/handlers/handlers.go
@@ -473,7 +473,7 @@ func DefaultHomeHandler() http.Handler {
r,
fmt.Sprintf(
"/participants/%s?format=html&tpl_layout=base&tpl_content=participants_show",
- claims["user_id"].(string)),
+ claims["model_id"].(string)),
http.StatusSeeOther,
)
@@ -483,7 +483,7 @@ func DefaultHomeHandler() http.Handler {
r,
fmt.Sprintf(
"/schools/%s?format=html&tpl_layout=base&tpl_content=schools_show",
- claims["user_id"].(string)),
+ claims["model_id"].(string)),
http.StatusSeeOther,
)
diff --git a/handlers/login.go b/handlers/login.go
index bf80e488..cfeec108 100644
--- a/handlers/login.go
+++ b/handlers/login.go
@@ -16,6 +16,7 @@ type UserToken struct {
Username string
Admin bool
Role string
+ ModelID string
UserID string
}
@@ -68,13 +69,13 @@ func checkCredential(db *orm.Database, username string, password string) (*UserT
// Check if user is the administrator
if username == db.Config.Admin.Username && password == db.Config.Admin.Password {
- return &UserToken{username, true, "administrator", "0"}, nil
+ return &UserToken{username, true, "administrator", "0", "0"}, nil
}
// Check if user is a subscriber
if password == db.Config.Subscriber.Password {
- return &UserToken{"subscriber", false, "subscriber", "0"}, nil
+ return &UserToken{"subscriber", false, "subscriber", "0", "0"}, nil
}
var token *UserToken
@@ -89,13 +90,13 @@ func checkCredential(db *orm.Database, username string, password string) (*UserT
if err := db.DB().First(&participant, &orm.Participant{UserID: user.ID}).Error; err != nil {
return nil, errors.New("Authentication failed!")
}
- token = &UserToken{username, false, user.Role, strconv.Itoa(int(participant.ID))}
+ token = &UserToken{username, false, user.Role, strconv.Itoa(int(participant.ID)), strconv.Itoa(int(user.ID))}
case "school":
var school orm.School
if err := db.DB().First(&school, &orm.School{UserID: user.ID}).Error; err != nil {
return nil, errors.New("Authentication failed!")
}
- token = &UserToken{username, false, user.Role, strconv.Itoa(int(school.ID))}
+ token = &UserToken{username, false, user.Role, strconv.Itoa(int(school.ID)), strconv.Itoa(int(user.ID))}
}
return token, nil
@@ -113,6 +114,7 @@ func getToken(db *orm.Database, username string, password string, signingKey []b
claims["admin"] = user.Admin
claims["username"] = user.Username
claims["role"] = user.Role
+ claims["model_id"] = user.ModelID
claims["user_id"] = user.UserID
claims["exp"] = time.Now().Add(time.Hour * 24).Unix()
diff --git a/orm/participant.go b/orm/participant.go
index eda653e0..85b07575 100644
--- a/orm/participant.go
+++ b/orm/participant.go
@@ -467,7 +467,7 @@ func CreateParticipant(db *Database, participant *Participant) (*Participant, er
func SaveParticipant(db *Database, participant interface{}) (interface{}, error) {
participant.(*Participant).FiscalCode = strings.ToUpper(participant.(*Participant).FiscalCode)
- if err := db._db.Omit("Category", "School").Save(participant).Error; err != nil {
+ if err := db._db.Omit("Category", "School", "Creator", "Updater").Save(participant).Error; err != nil {
return nil, err
}
return participant, nil
diff --git a/orm/response.go b/orm/response.go
index dbd5cc36..a5244615 100644
--- a/orm/response.go
+++ b/orm/response.go
@@ -275,7 +275,7 @@ func CreateResponse(db *Database, response *Response) (*Response, error) {
}
func SaveResponse(db *Database, response interface{}) (interface{}, error) {
- if err := db._db. /*.Omit("Something")*/ Save(response).Error; err != nil {
+ if err := db._db.Omit("Creator", "Updater").Save(response).Error; err != nil {
return nil, err
}
return response, nil
diff --git a/orm/role.go b/orm/role.go
index 1b1306ca..ded7ee93 100644
--- a/orm/role.go
+++ b/orm/role.go
@@ -42,6 +42,10 @@ func getUserIDFromToken(r *http.Request) string {
return getClaims(r)["user_id"].(string)
}
+func getModelIDFromToken(r *http.Request) string {
+ return getClaims(r)["model_id"].(string)
+}
+
func getUserIDFromTokenAsUint(r *http.Request) uint {
id, _ := strconv.Atoi(getUserIDFromToken(r))
return uint(id)
diff --git a/orm/school.go b/orm/school.go
index d7d5fb56..b40d0ebc 100644
--- a/orm/school.go
+++ b/orm/school.go
@@ -306,7 +306,7 @@ func CreateSchool(db *Database, school *School) (*School, error) {
}
func SaveSchool(db *Database, school interface{}) (interface{}, error) {
- if err := db._db.Omit("Region").Save(school).Error; err != nil {
+ if err := db._db.Omit("Region", "Creator", "Updater").Save(school).Error; err != nil {
return nil, err
}
return school, nil
@@ -317,7 +317,7 @@ func (model *School) HasCategory(db *Database, participant *Participant) (bool,
if err := db._db.
Where("category_id = ? AND school_id = ? AND id <> ?", participant.CategoryID, model.ID, participant.ID).
- Find(&participants).Error; err != nil {
+ Find(&participants).Error; err != nil {
return false, err
}
return len(participants) > 0, nil
diff --git a/orm/usermodifier.go b/orm/usermodifier.go
index c678af32..2af014c3 100644
--- a/orm/usermodifier.go
+++ b/orm/usermodifier.go
@@ -1,6 +1,8 @@
package orm
-import "net/http"
+import (
+ "net/http"
+)
type Modifier interface {
SetCreatorID(id uint)
diff --git a/renderer/funcmap.go b/renderer/funcmap.go
index 7b87ded7..aaf6296c 100644
--- a/renderer/funcmap.go
+++ b/renderer/funcmap.go
@@ -64,7 +64,7 @@ var (
"isSubscriber": isSubscriber,
"isSchool": isSchool,
"attr": attr,
- "userId": userId,
+ "modelId": modelId,
}
)
@@ -105,8 +105,8 @@ func username(claims jwt.MapClaims) string {
return claims["username"].(string)
}
-func userId(claims jwt.MapClaims) (uint, error) {
- id, err := strconv.Atoi(claims["user_id"].(string))
+func modelId(claims jwt.MapClaims) (uint, error) {
+ id, err := strconv.Atoi(claims["model_id"].(string))
if err != nil {
return 0, err
}
diff --git a/src/style.css b/src/style.css
index d0f10dbf..ed1e3abe 100644
--- a/src/style.css
+++ b/src/style.css
@@ -4,7 +4,7 @@ html {
body {
padding-top: 60px;
- position: relative;
+ /*position: relative;*/
}
div.login {
diff --git a/templates/layout/base.html.tpl b/templates/layout/base.html.tpl
index 31c9d95b..077814fe 100644
--- a/templates/layout/base.html.tpl
+++ b/templates/layout/base.html.tpl
@@ -48,7 +48,7 @@
Prove
{{- end -}}
{{- if $isSchool -}}
- Scuola
+ Scuola
Partecipanti
{{- end -}}
diff --git a/templates/layout/login.html.tpl b/templates/layout/login.html.tpl
index 428a9390..42058533 100644
--- a/templates/layout/login.html.tpl
+++ b/templates/layout/login.html.tpl
@@ -38,16 +38,14 @@
-
-