commit 6286a0d13dab8f9f0ef2339a935e5cbad6149baa Author: freds Date: Thu Nov 28 17:55:25 2019 +0000 messy learning environment for merging grav with bulma diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 00000000..e84f52bf --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,8 @@ +# These are supported funding model platforms + +github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] +patreon: # Replace with a single Patreon username +open_collective: grav +ko_fi: # Replace with a single Ko-fi username +tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel +custom: # Replace with a single custom sponsorship URL diff --git a/.htaccess b/.htaccess new file mode 100644 index 00000000..ef79a4bc --- /dev/null +++ b/.htaccess @@ -0,0 +1,75 @@ + + +RewriteEngine On + +## Begin RewriteBase +# If you are getting 500 or 404 errors on subpages, you may have to uncomment the RewriteBase entry +# You should change the '/' to your appropriate subfolder. For example if you have +# your Grav install at the root of your site '/' should work, else it might be something +# along the lines of: RewriteBase / +## + +# RewriteBase / + +## End - RewriteBase + +## Begin - X-Forwarded-Proto +# In some hosted or load balanced environments, SSL negotiation happens upstream. +# In order for Grav to recognize the connection as secure, you need to uncomment +# the following lines. +# +# RewriteCond %{HTTP:X-Forwarded-Proto} https +# RewriteRule .* - [E=HTTPS:on] +# +## End - X-Forwarded-Proto + +## Begin - Exploits +# If you experience problems on your site block out the operations listed below +# This attempts to block the most common type of exploit `attempts` to Grav +# +# Block out any script trying to base64_encode data within the URL. +RewriteCond %{QUERY_STRING} base64_encode[^(]*\([^)]*\) [OR] +# Block out any script that includes a +"; + } + + public function getTemplateName() + { + return "partials/noscript.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 69 => 30, 63 => 29, 57 => 26, 30 => 1,); + } + + /** @deprecated since 1.27 (to be removed in 2.0). Use getSourceContext() instead */ + public function getSource() + { + @trigger_error('The '.__METHOD__.' method is deprecated since version 1.27 and will be removed in 2.0. Use getSourceContext() instead.', E_USER_DEPRECATED); + + return $this->getSourceContext()->getCode(); + } + + public function getSourceContext() + { + return new Source(" + +
+
+
+

{{ \"PLUGIN_ADMIN.ERROR\"|tu }}

+
+
+
+ {{ \"PLUGIN_ADMIN.ADMIN_NOSCRIPT_MSG\"|tu }} +
+
+
+
+ + +", "partials/noscript.html.twig", "/srv/http/berryfarmprojects.org.uk/stay-grav/user/plugins/admin/themes/grav/templates/partials/noscript.html.twig"); + } +} diff --git a/cache/twig/16/1693146376c444e01f264489dce6644691581ff234599116d94b4fb19ecb4759.php b/cache/twig/16/1693146376c444e01f264489dce6644691581ff234599116d94b4fb19ecb4759.php new file mode 100644 index 00000000..f9c9ac6d --- /dev/null +++ b/cache/twig/16/1693146376c444e01f264489dce6644691581ff234599116d94b4fb19ecb4759.php @@ -0,0 +1,348 @@ +blocks = [ + 'stylesheets' => [$this, 'block_stylesheets'], + 'javascripts' => [$this, 'block_javascripts'], + 'titlebar' => [$this, 'block_titlebar'], + 'messages' => [$this, 'block_messages'], + 'content' => [$this, 'block_content'], + ]; + } + + protected function doGetParent(array $context) + { + // line 1 + return "partials/base.html.twig"; + } + + protected function doDisplay(array $context, array $blocks = []) + { + // line 3 + if ($this->getAttribute(($context["admin"] ?? null), "route", [])) { + // line 4 + $context["installing"] = (is_string($__internal_f607aeef2c31a95a7bf963452dff024ffaeb6aafbe4603f9ca3bec57be8633f4 = $this->getAttribute(($context["admin"] ?? null), "route", [])) && is_string($__internal_62824350bc4502ee19dbc2e99fc6bdd3bd90e7d8dd6e72f42c35efd048542144 = "install") && ('' === $__internal_62824350bc4502ee19dbc2e99fc6bdd3bd90e7d8dd6e72f42c35efd048542144 || 0 === strpos($__internal_f607aeef2c31a95a7bf963452dff024ffaeb6aafbe4603f9ca3bec57be8633f4, $__internal_62824350bc4502ee19dbc2e99fc6bdd3bd90e7d8dd6e72f42c35efd048542144))); + // line 6 + if (($context["installing"] ?? null)) { + // line 7 + $context["title"] = $this->env->getExtension('Grav\Plugin\Admin\Twig\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.THEMES"); + } else { + // line 9 + $context["installed"] = true; + // line 12 + $context["package"] = $this->getAttribute($this->getAttribute(($context["admin"] ?? null), "themes", [0 => true], "method"), $this->getAttribute(($context["admin"] ?? null), "route", []), [], "array"); + // line 13 + if ( !($context["package"] ?? null)) { + // line 14 + $context["package"] = $this->getAttribute($this->getAttribute(($context["admin"] ?? null), "themes", [0 => false], "method"), $this->getAttribute(($context["admin"] ?? null), "route", []), [], "array"); + // line 15 + $context["installed"] = false; + } + // line 18 + $context["theme"] = $this->getAttribute(($context["package"] ?? null), "toArray", [], "method"); + // line 19 + $context["title"] = (($this->env->getExtension('Grav\Plugin\Admin\Twig\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.THEME") . ": ") . twig_escape_filter($this->env, $this->getAttribute(($context["theme"] ?? null), "name", []))); + } + } else { + // line 22 + $context["title"] = $this->env->getExtension('Grav\Plugin\Admin\Twig\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.THEMES"); + } + // line 25 + if (($this->getAttribute(($context["admin"] ?? null), "route", []) || ($context["installing"] ?? null))) { + } + // line 1 + $this->parent = $this->loadTemplate("partials/base.html.twig", "themes.html.twig", 1); + $this->parent->display($context, array_merge($this->blocks, $blocks)); + } + + // line 26 + public function block_stylesheets($context, array $blocks = []) + { + // line 27 + echo " "; + $this->getAttribute(($context["assets"] ?? null), "addCss", [0 => (($context["theme_url"] ?? null) . "/css/codemirror/codemirror.css")], "method"); + // line 28 + echo " "; + $this->displayParentBlock("stylesheets", $context, $blocks); + echo " + "; + } + + // line 31 + public function block_javascripts($context, array $blocks = []) + { + // line 32 + echo " "; + $this->displayParentBlock("javascripts", $context, $blocks); + echo " + "; + } + + // line 36 + public function block_titlebar($context, array $blocks = []) + { + // line 37 + echo " "; + if (( !$this->getAttribute(($context["admin"] ?? null), "route", []) || ($context["installing"] ?? null))) { + // line 38 + echo "
+ "; + // line 39 + if (($context["installing"] ?? null)) { + // line 40 + echo " env, ($context["base_url_relative"] ?? null), "html", null, true); + echo "/themes\"> "; + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\Twig\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.BACK"), "html", null, true); + echo " + "; + } else { + // line 42 + echo " env, ($context["base_url"] ?? null), "html", null, true); + echo "/\"> "; + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\Twig\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.BACK"), "html", null, true); + echo " + env, ($context["base_url_relative"] ?? null), "html", null, true); + echo "/themes/install\"> "; + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\Twig\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.ADD"), "html", null, true); + echo " + "; + // line 44 + if ($this->env->getExtension('Grav\Common\Twig\TwigExtension')->authorize([0 => "admin.maintenance", 1 => "admin.super"])) { + // line 45 + echo " + "; + } + // line 47 + echo " "; + } + // line 48 + echo "
+

"; + // line 49 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\Twig\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.THEMES"), "html", null, true); + echo "

+ "; + } else { + // line 51 + echo " "; + if (($context["installed"] ?? null)) { + // line 52 + echo "
+ env, ($context["base_url_relative"] ?? null), "html", null, true); + echo "/themes\"> "; + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\Twig\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.BACK_TO_THEMES"), "html", null, true); + echo " + +
+ "; + } else { + // line 57 + echo " + "; + } + // line 61 + echo "

"; + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\Twig\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.THEME"), "html", null, true); + echo ": "; + echo twig_escape_filter($this->env, $this->getAttribute(($context["theme"] ?? null), "name", [])); + echo "

+ "; + } + } + + // line 65 + public function block_messages($context, array $blocks = []) + { + // line 66 + echo " "; + $this->displayParentBlock("messages", $context, $blocks); + echo " + "; + // line 67 + if ($this->getAttribute($this->getAttribute($this->getAttribute($this->getAttribute(($context["config"] ?? null), "plugins", []), "admin", []), "notifications", []), "themes", [])) { + // line 68 + echo "
+ "; + } + } + + // line 72 + public function block_content($context, array $blocks = []) + { + // line 73 + echo "
+ "; + // line 74 + if (( !$this->getAttribute(($context["admin"] ?? null), "route", []) || ($context["installing"] ?? null))) { + // line 75 + echo " "; + $this->loadTemplate("partials/themes-list.html.twig", "themes.html.twig", 75)->display($context); + // line 76 + echo " "; + } else { + // line 77 + echo " "; + if ((null === ($context["theme"] ?? null))) { + // line 78 + echo " "; + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Common\Twig\TwigExtension')->redirectFunc((($context["base_url_relative"] ?? null) . "/404")), "html", null, true); + echo " + "; + } + // line 80 + echo " "; + $this->loadTemplate("partials/themes-details.html.twig", "themes.html.twig", 80)->display($context); + // line 81 + echo " "; + } + // line 82 + echo "
+"; + } + + public function getTemplateName() + { + return "themes.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 234 => 82, 231 => 81, 228 => 80, 222 => 78, 219 => 77, 216 => 76, 213 => 75, 211 => 74, 208 => 73, 205 => 72, 199 => 68, 197 => 67, 192 => 66, 189 => 65, 179 => 61, 171 => 58, 168 => 57, 162 => 54, 156 => 53, 153 => 52, 150 => 51, 145 => 49, 142 => 48, 139 => 47, 133 => 45, 131 => 44, 125 => 43, 118 => 42, 110 => 40, 108 => 39, 105 => 38, 102 => 37, 99 => 36, 92 => 32, 89 => 31, 82 => 28, 79 => 27, 76 => 26, 71 => 1, 68 => 25, 65 => 22, 61 => 19, 59 => 18, 56 => 15, 54 => 14, 52 => 13, 50 => 12, 48 => 9, 45 => 7, 43 => 6, 41 => 4, 39 => 3, 33 => 1,); + } + + /** @deprecated since 1.27 (to be removed in 2.0). Use getSourceContext() instead */ + public function getSource() + { + @trigger_error('The '.__METHOD__.' method is deprecated since version 1.27 and will be removed in 2.0. Use getSourceContext() instead.', E_USER_DEPRECATED); + + return $this->getSourceContext()->getCode(); + } + + public function getSourceContext() + { + return new Source("{% extends 'partials/base.html.twig' %} + +{% if admin.route %} + {% set installing = admin.route starts with 'install' %} + + {% if installing %} + {% set title = \"PLUGIN_ADMIN.THEMES\"|tu %} + {% else %} + {% set installed = true %} + + {# Try installed packages first, then remote #} + {% set package = admin.themes(true)[admin.route] %} + {% if (not package) %} + {% set package = admin.themes(false)[admin.route] %} + {% set installed = false %} + {% endif %} + + {% set theme = package.toArray() %} + {% set title = \"PLUGIN_ADMIN.THEME\"|tu ~ \": \" ~ theme.name|e %} + {% endif %} +{% else %} + {% set title = \"PLUGIN_ADMIN.THEMES\"|tu %} +{% endif %} + +{% if admin.route or installing %} + {% block stylesheets %} + {% do assets.addCss(theme_url~'/css/codemirror/codemirror.css') %} + {{ parent() }} + {% endblock %} + + {% block javascripts %} + {{ parent() }} + {% endblock %} +{% endif %} + +{% block titlebar %} + {% if not admin.route or installing %} +
+ {% if (installing) %} + {{ \"PLUGIN_ADMIN.BACK\"|tu }} + {% else %} + {{ \"PLUGIN_ADMIN.BACK\"|tu }} + {{ \"PLUGIN_ADMIN.ADD\"|tu }} + {% if authorize(['admin.maintenance', 'admin.super']) %} + + {% endif %} + {% endif %} +
+

{{ \"PLUGIN_ADMIN.THEMES\"|tu }}

+ {% else %} + {% if (installed) %} +
+ {{ \"PLUGIN_ADMIN.BACK_TO_THEMES\"|tu }} + +
+ {% else %} + + {% endif %} +

{{ \"PLUGIN_ADMIN.THEME\"|tu }}: {{ theme.name|e }}

+ {% endif %} +{% endblock %} + +{% block messages %} + {{ parent() }} + {% if config.plugins.admin.notifications.themes %} +
+ {% endif %} +{% endblock %} + +{% block content %} +
+ {% if not admin.route or installing %} + {% include 'partials/themes-list.html.twig' %} + {% else %} + {% if theme is null %} + {{redirect_me(base_url_relative ~ '/404')}} + {% endif %} + {% include 'partials/themes-details.html.twig' %} + {% endif %} +
+{% endblock %} +", "themes.html.twig", "/srv/http/berryfarmprojects.org.uk/stay-grav/user/plugins/admin/themes/grav/templates/themes.html.twig"); + } +} diff --git a/cache/twig/1d/1dacca3c9b9ffaa409f85306b1b4d635288b9b193944e1fab061a307a34dc523.php b/cache/twig/1d/1dacca3c9b9ffaa409f85306b1b4d635288b9b193944e1fab061a307a34dc523.php new file mode 100644 index 00000000..d9053f68 --- /dev/null +++ b/cache/twig/1d/1dacca3c9b9ffaa409f85306b1b4d635288b9b193944e1fab061a307a34dc523.php @@ -0,0 +1,220 @@ +parent = false; + + $this->blocks = [ + ]; + } + + protected function doDisplay(array $context, array $blocks = []) + { + // line 1 + $context["clear_cache_url"] = (((($context["base_url_relative"] ?? null) . "/cache.json/task") . $this->getAttribute($this->getAttribute(($context["config"] ?? null), "system", []), "param_sep", [])) . twig_escape_filter($this->env, "clearCache", "html_attr")); + // line 2 + echo "
    + "; + // line 3 + if ($this->env->getExtension('Grav\Common\Twig\TwigExtension')->authorize([0 => "admin.maintenance", 1 => "admin.super", 2 => "admin.cache"])) { + // line 4 + echo "
  • env, $this->env->getExtension('Grav\Plugin\Admin\Twig\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.CLEAR_CACHE"), "html", null, true); + echo "\"> + env, $this->getAttribute(($context["uri"] ?? null), "addNonce", [0 => ($context["clear_cache_url"] ?? null), 1 => "admin-form", 2 => "admin-nonce"], "method"), "html", null, true); + echo "\"> + + +
  • + "; + } + // line 10 + echo " "; + if ($this->getAttribute($this->getAttribute(($context["grav"] ?? null), "twig", []), "plugins_quick_tray", [])) { + // line 11 + echo " "; + $context['_parent'] = $context; + $context['_seq'] = twig_ensure_traversable($this->getAttribute($this->getAttribute(($context["grav"] ?? null), "twig", []), "plugins_quick_tray", [])); + foreach ($context['_seq'] as $context["label"] => $context["item"]) { + // line 12 + echo " "; + if ($this->env->getExtension('Grav\Common\Twig\TwigExtension')->authorize(((($this->getAttribute($context["item"], "authorize", [], "any", true, true) && twig_test_iterable($this->getAttribute($context["item"], "authorize", [])))) ? ($this->getAttribute($context["item"], "authorize", [])) : ([0 => (($this->getAttribute($context["item"], "authorize", [])) ? ($this->getAttribute($context["item"], "authorize", [])) : (("admin." . (($this->getAttribute($context["item"], "location", [])) ? ($this->getAttribute($context["item"], "location", [])) : ($this->getAttribute($context["item"], "route", [])))))), 1 => "admin.super"])))) { + // line 13 + echo " "; + $context["data_tags"] = ""; + // line 14 + echo " "; + if ($this->getAttribute($context["item"], "data", [])) { + // line 15 + echo " "; + $context['_parent'] = $context; + $context['_seq'] = twig_ensure_traversable($this->getAttribute($context["item"], "data", [])); + foreach ($context['_seq'] as $context["key"] => $context["value"]) { + // line 16 + echo " "; + $context["data_tags"] = (((((($context["data_tags"] ?? null) . " data-") . $context["key"]) . "=\"") . $context["value"]) . "\""); + // line 17 + echo " "; + } + $_parent = $context['_parent']; + unset($context['_seq'], $context['_iterated'], $context['key'], $context['value'], $context['_parent'], $context['loop']); + $context = array_intersect_key($context, $_parent) + $_parent; + // line 18 + echo " "; + } + // line 19 + echo "
  • env, $this->getAttribute($context["item"], "class", []), "html", null, true); + echo " hint--bottom\" data-hint=\""; + echo twig_escape_filter($this->env, $this->getAttribute($context["item"], "hint", []), "html", null, true); + echo "\" "; + echo ($context["data_tags"] ?? null); + echo "> + "; + // line 20 + if ($this->getAttribute($context["item"], "route", [])) { + // line 21 + echo " env, $this->env->getExtension('Grav\Common\Twig\TwigExtension')->urlFunc($this->getAttribute($context["item"], "route", [])), "html", null, true); + echo "\" "; + if ($this->getAttribute($context["item"], "target", [])) { + echo "target=\""; + echo twig_escape_filter($this->env, $this->getAttribute($context["item"], "target", []), "html", null, true); + echo "\""; + } + echo "> + env, $this->getAttribute($context["item"], "icon", []), "html", null, true); + echo "\"> + + "; + } else { + // line 25 + echo " env, $this->getAttribute($context["item"], "icon", []), "html", null, true); + echo "\"> + "; + } + // line 27 + echo "
  • + "; + } + // line 29 + echo " "; + } + $_parent = $context['_parent']; + unset($context['_seq'], $context['_iterated'], $context['label'], $context['item'], $context['_parent'], $context['loop']); + $context = array_intersect_key($context, $_parent) + $_parent; + // line 30 + echo " "; + } else { + // line 31 + echo " "; + if ($this->env->getExtension('Grav\Common\Twig\TwigExtension')->authorize([0 => "admin.maintenance", 1 => "admin.super"])) { + // line 32 + echo "
  • + env, (($context["base_url_relative"] ?? null) . "/plugins/install"), "html", null, true); + echo "\"> + + +
  • + "; + } + // line 38 + echo " "; + } + // line 39 + echo "
+ +"; + } + + public function getTemplateName() + { + return "partials/nav-quick-tray.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 148 => 39, 145 => 38, 137 => 33, 134 => 32, 131 => 31, 128 => 30, 122 => 29, 118 => 27, 112 => 25, 106 => 22, 95 => 21, 93 => 20, 84 => 19, 81 => 18, 75 => 17, 72 => 16, 67 => 15, 64 => 14, 61 => 13, 58 => 12, 53 => 11, 50 => 10, 42 => 5, 37 => 4, 35 => 3, 32 => 2, 30 => 1,); + } + + /** @deprecated since 1.27 (to be removed in 2.0). Use getSourceContext() instead */ + public function getSource() + { + @trigger_error('The '.__METHOD__.' method is deprecated since version 1.27 and will be removed in 2.0. Use getSourceContext() instead.', E_USER_DEPRECATED); + + return $this->getSourceContext()->getCode(); + } + + public function getSourceContext() + { + return new Source("{% set clear_cache_url = base_url_relative ~ '/cache.json/task' ~ config.system.param_sep ~ 'clearCache'|e('html_attr') %} +
    + {% if authorize(['admin.maintenance', 'admin.super', 'admin.cache']) %} +
  • + + + +
  • + {% endif %} + {% if grav.twig.plugins_quick_tray %} + {% for label, item in grav.twig.plugins_quick_tray %} + {% if authorize((item.authorize is defined and item.authorize is iterable) ? item.authorize : [item.authorize ?: ('admin.' ~ (item.location ?: item.route)), 'admin.super']) %} + {% set data_tags = '' %} + {% if (item.data) %} + {% for key, value in item.data %} + {% set data_tags = data_tags ~ ' data-' ~ key ~ '=\"' ~ value ~ '\"' %} + {% endfor %} + {% endif %} +
  • + {% if item.route %} + + + + {% else %} + + {% endif %} +
  • + {% endif %} + {% endfor %} + {% else %} + {% if authorize(['admin.maintenance', 'admin.super']) %} +
  • + + + +
  • + {% endif %} + {% endif %} +
+ +", "partials/nav-quick-tray.html.twig", "/srv/http/berryfarmprojects.org.uk/stay-grav/user/plugins/admin/themes/grav/templates/partials/nav-quick-tray.html.twig"); + } +} diff --git a/cache/twig/3f/3f1e56088ed74af2ea5dececf453ce6c406d6098835c98632cca9ed7f20edf20.php b/cache/twig/3f/3f1e56088ed74af2ea5dececf453ce6c406d6098835c98632cca9ed7f20edf20.php new file mode 100644 index 00000000..7f13fff5 --- /dev/null +++ b/cache/twig/3f/3f1e56088ed74af2ea5dececf453ce6c406d6098835c98632cca9ed7f20edf20.php @@ -0,0 +1,67 @@ +parent = false; + + $this->blocks = [ + ]; + } + + protected function doDisplay(array $context, array $blocks = []) + { + // line 1 + $context["user_avatar"] = $this->getAttribute($this->getAttribute(($context["admin"] ?? null), "user", []), "getAvatarUrl", [], "method"); + // line 2 + echo "env, ((!twig_in_filter("?", ($context["user_avatar"] ?? null))) ? ((($context["user_avatar"] ?? null) . "?s=80")) : (($context["user_avatar"] ?? null))), "html", null, true); + echo "\" /> +"; + } + + public function getTemplateName() + { + return "partials/nav-user-avatar.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 32 => 2, 30 => 1,); + } + + /** @deprecated since 1.27 (to be removed in 2.0). Use getSourceContext() instead */ + public function getSource() + { + @trigger_error('The '.__METHOD__.' method is deprecated since version 1.27 and will be removed in 2.0. Use getSourceContext() instead.', E_USER_DEPRECATED); + + return $this->getSourceContext()->getCode(); + } + + public function getSourceContext() + { + return new Source("{% set user_avatar = admin.user.getAvatarUrl() %} + +", "partials/nav-user-avatar.html.twig", "/srv/http/berryfarmprojects.org.uk/stay-grav/user/plugins/admin/themes/grav/templates/partials/nav-user-avatar.html.twig"); + } +} diff --git a/cache/twig/43/4323ee11cfc84af0a94f53495eaf4be23b1ab587eadb5cf06c4dd5e956a4f678.php b/cache/twig/43/4323ee11cfc84af0a94f53495eaf4be23b1ab587eadb5cf06c4dd5e956a4f678.php new file mode 100644 index 00000000..ed6dfc80 --- /dev/null +++ b/cache/twig/43/4323ee11cfc84af0a94f53495eaf4be23b1ab587eadb5cf06c4dd5e956a4f678.php @@ -0,0 +1,371 @@ +parent = false; + + $this->blocks = [ + ]; + } + + protected function doDisplay(array $context, array $blocks = []) + { + // line 1 + echo "
+"; + // line 2 + if (($context["installing"] ?? null)) { + // line 3 + echo " "; + $this->loadTemplate("partials/release-toggle.html.twig", "partials/themes-list.html.twig", 3)->display($context); + } + // line 5 + $this->loadTemplate("partials/list-sort.html.twig", "partials/themes-list.html.twig", 5)->display(twig_array_merge($context, ["list_view" => "themes"])); + // line 6 + echo "

+ "; + // line 7 + echo twig_escape_filter($this->env, ((($context["installing"] ?? null)) ? ($this->env->getExtension('Grav\Plugin\Admin\Twig\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.AVAILABLE_THEMES")) : ($this->env->getExtension('Grav\Plugin\Admin\Twig\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.INSTALLED_THEMES"))), "html", null, true); + echo " +

+
+
+ env, $this->env->getExtension('Grav\Plugin\Admin\Twig\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.RESOURCE_FILTER"), "html", null, true); + echo "\" data-gpm-filter> +
+
+ +
+ "; + // line 16 + $context['_parent'] = $context; + $context['_seq'] = twig_ensure_traversable($this->env->getExtension('Grav\Common\Twig\TwigExtension')->ksortFilter($this->getAttribute($this->getAttribute(($context["admin"] ?? null), "themes", [0 => !($context["installing"] ?? null)], "method"), "toArray", []))); + $context['_iterated'] = false; + foreach ($context['_seq'] as $context["slug"] => $context["theme"]) { + // line 17 + echo " "; + $context["state"] = "inactive"; + // line 18 + echo " "; + if (($context["installing"] ?? null)) { + $context["state"] = "installing"; + } + // line 19 + echo " "; + if (($this->getAttribute(($context["config"] ?? null), "get", [0 => "system.pages.theme"], "method") == $context["slug"])) { + $context["state"] = "active"; + } + // line 20 + echo " "; + $context["isTestingRelease"] = $this->getAttribute($this->getAttribute(($context["admin"] ?? null), "gpm", []), "isTestingRelease", [0 => $context["slug"]], "method"); + // line 21 + echo " "; + $context["releaseDate"] = (($this->getAttribute($context["theme"], "date", [])) ? ($this->getAttribute($context["theme"], "date", [])) : ($this->getAttribute($this->getAttribute($this->getAttribute(($context["admin"] ?? null), "gpm", []), "findPackage", [0 => $context["slug"], 1 => true], "method"), "date", []))); + // line 22 + echo " +
env, ($context["state"] ?? null), "html", null, true); + echo "-theme\" data-gpm-theme=\""; + echo twig_escape_filter($this->env, twig_urlencode_filter($context["slug"]), "html", null, true); + echo "\" data-gpm-name=\""; + echo twig_escape_filter($this->env, $this->getAttribute($context["theme"], "name", []), "html", null, true); + echo "\" data-gpm-release-date=\""; + echo twig_escape_filter($this->env, ($context["releaseDate"] ?? null), "html", null, true); + echo "\" data-gpm-author=\""; + echo twig_escape_filter($this->env, $this->getAttribute($this->getAttribute($context["theme"], "author", []), "name", []), "html", null, true); + echo "\" data-gpm-official=\""; + echo (($this->getAttribute(($context["admin"] ?? null), "isTeamGrav", [0 => $context["theme"]], "method")) ? ("1") : ("2")); + echo "\" data-gpm-updatable=\""; + echo (($this->getAttribute($this->getAttribute(($context["admin"] ?? null), "gpm", []), "isUpdatable", [0 => $context["slug"]], "method")) ? ("1") : ("2")); + echo "\" data-gpm-enabled=\""; + echo (($this->getAttribute(($context["data"] ?? null), "get", [0 => "enabled"], "method")) ? ("1") : ("2")); + echo "\" data-gpm-testing=\""; + echo ((($context["isTestingRelease"] ?? null)) ? ("1") : ("2")); + echo "\"> +
+ env, $this->getAttribute($context["theme"], "icon", []), "html", null, true); + echo "\"> + env, ($context["base_url_relative"] ?? null), "html", null, true); + echo "/themes/"; + echo twig_escape_filter($this->env, twig_urlencode_filter($context["slug"]), "html", null, true); + echo "\">"; + echo twig_escape_filter($this->env, $this->getAttribute($context["theme"], "name", []), "html", null, true); + echo " + "; + // line 27 + if ($this->getAttribute(($context["admin"] ?? null), "isTeamGrav", [0 => $context["theme"]], "method")) { + // line 28 + echo " env, $this->env->getExtension('Grav\Plugin\Admin\Twig\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.GRAV_OFFICIAL_THEME"), "html", null, true); + echo "\"> + "; + } + // line 30 + echo " "; + if ($this->getAttribute(($context["admin"] ?? null), "isPremiumProduct", [0 => $context["theme"]], "method")) { + // line 31 + echo " "; + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\Twig\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.PREMIUM_PRODUCT"), "html", null, true); + echo " + "; + } + // line 33 + echo " "; + if ($this->getAttribute($context["theme"], "symlink", [])) { + // line 34 + echo " env, $this->env->getExtension('Grav\Plugin\Admin\Twig\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.THEME_SYMBOLICALLY_LINKED"), "html", null, true); + echo "\"> + + + "; + } + // line 38 + echo " v"; + echo twig_escape_filter($this->env, $this->getAttribute($context["theme"], "version", []), "html", null, true); + echo " + "; + // line 39 + if (($context["isTestingRelease"] ?? null)) { + echo "test release"; + } + // line 40 + echo "
+
+ "; + // line 42 + $context["thumb"] = ((($context["installing"] ?? null)) ? (("//getgrav.org/images/" . $this->getAttribute($context["theme"], "screenshot", []))) : ($this->getAttribute($context["theme"], "thumbnail", []))); + // line 43 + echo " env, ($context["base_url_relative"] ?? null), "html", null, true); + echo "/themes/"; + echo twig_escape_filter($this->env, twig_urlencode_filter($context["slug"]), "html", null, true); + echo "\">env, ($context["thumb"] ?? null), "html", null, true); + echo "\" /> +
+ "; + // line 45 + if ((($context["state"] ?? null) == "installing")) { + // line 46 + echo " + "; + } elseif (( // line 49 +($context["state"] ?? null) == "active")) { + // line 50 + echo "
+ "; + // line 51 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\Twig\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.ACTIVE_THEME"), "html", null, true); + echo " +
+ "; + } else { + // line 54 + echo " env, $this->getAttribute(($context["uri"] ?? null), "addNonce", [0 => (((((($context["base_url_relative"] ?? null) . "/themes/") . $context["slug"]) . "/task") . $this->getAttribute($this->getAttribute(($context["config"] ?? null), "system", []), "param_sep", [])) . "activate"), 1 => "admin-form", 2 => "admin-nonce"], "method"), "html", null, true); + echo "\" class=\"gpm-actions\"> + "; + // line 55 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\Twig\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.ACTIVATE"), "html", null, true); + echo " + + "; + } + // line 58 + echo "
+ "; + $context['_iterated'] = true; + } + if (!$context['_iterated']) { + // line 60 + echo " "; + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\Twig\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.OFFLINE_WARNING"), "html", null, true); + echo " + "; + } + $_parent = $context['_parent']; + unset($context['_seq'], $context['_iterated'], $context['slug'], $context['theme'], $context['_parent'], $context['loop']); + $context = array_intersect_key($context, $_parent) + $_parent; + // line 62 + echo "
+ +
+
+

"; + // line 66 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\Twig\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.SWITCHING_TO"), "html", null, true); + echo " {theme_name}

+

+ "; + // line 68 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\Twig\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.SWITCHING_TO_DESCRIPTION"), "html", null, true); + echo " +

+

+ "; + // line 71 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\Twig\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.SWITCHING_TO_CONFIRMATION"), "html", null, true); + echo " {theme_name}? +

+
+
+ + "; + // line 76 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\Twig\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.CONTINUE"), "html", null, true); + echo " +
+
+
+ +"; + // line 81 + $this->loadTemplate("partials/modal-add-package.html.twig", "partials/themes-list.html.twig", 81)->display(twig_array_merge($context, ["type" => "theme"])); + // line 82 + $this->loadTemplate("partials/modal-update-packages.html.twig", "partials/themes-list.html.twig", 82)->display(twig_array_merge($context, ["type" => "theme"])); + } + + public function getTemplateName() + { + return "partials/themes-list.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 259 => 82, 257 => 81, 249 => 76, 245 => 75, 238 => 71, 232 => 68, 227 => 66, 221 => 62, 212 => 60, 206 => 58, 200 => 55, 195 => 54, 189 => 51, 186 => 50, 184 => 49, 177 => 47, 174 => 46, 172 => 45, 162 => 43, 160 => 42, 156 => 40, 152 => 39, 147 => 38, 139 => 34, 136 => 33, 130 => 31, 127 => 30, 121 => 28, 119 => 27, 111 => 26, 107 => 25, 86 => 23, 83 => 22, 80 => 21, 77 => 20, 72 => 19, 67 => 18, 64 => 17, 59 => 16, 51 => 11, 44 => 7, 41 => 6, 39 => 5, 35 => 3, 33 => 2, 30 => 1,); + } + + /** @deprecated since 1.27 (to be removed in 2.0). Use getSourceContext() instead */ + public function getSource() + { + @trigger_error('The '.__METHOD__.' method is deprecated since version 1.27 and will be removed in 2.0. Use getSourceContext() instead.', E_USER_DEPRECATED); + + return $this->getSourceContext()->getCode(); + } + + public function getSourceContext() + { + return new Source("
+{% if installing %} + {% include 'partials/release-toggle.html.twig' %} +{% endif %} +{% include 'partials/list-sort.html.twig' with { list_view: 'themes' } %} +

+ {{ installing ? \"PLUGIN_ADMIN.AVAILABLE_THEMES\"|tu : \"PLUGIN_ADMIN.INSTALLED_THEMES\"|tu }} +

+
+
+ +
+
+ +
+ {% for slug, theme in admin.themes(not installing).toArray|ksort %} + {% set state = 'inactive' %} + {% if (installing) %}{% set state = 'installing' %}{% endif %} + {% if (config.get('system.pages.theme') == slug) %}{% set state = 'active' %}{% endif %} + {% set isTestingRelease = admin.gpm.isTestingRelease(slug) %} + {% set releaseDate = theme.date ?: admin.gpm.findPackage(slug, true).date %} + +
+
+ + {{ theme.name }} + {% if admin.isTeamGrav(theme) %} + + {% endif %} + {% if admin.isPremiumProduct(theme) %} + {{ \"PLUGIN_ADMIN.PREMIUM_PRODUCT\"|tu }} + {% endif %} + {% if theme.symlink %} + + + + {% endif %} + v{{ theme.version }} + {% if isTestingRelease %}test release{% endif %} +
+
+ {% set thumb = installing ? '//getgrav.org/images/' ~ theme.screenshot : theme.thumbnail %} + +
+ {% if (state == 'installing') %} + + {% elseif state == 'active' %} +
+ {{ \"PLUGIN_ADMIN.ACTIVE_THEME\"|tu }} +
+ {% else %} + + {{ \"PLUGIN_ADMIN.ACTIVATE\"|tu }} + + {% endif %} +
+ {% else %} + {{ \"PLUGIN_ADMIN.OFFLINE_WARNING\"|tu }} + {% endfor %} +
+ +
+
+

{{ \"PLUGIN_ADMIN.SWITCHING_TO\"|tu }} {theme_name}

+

+ {{ \"PLUGIN_ADMIN.SWITCHING_TO_DESCRIPTION\"|tu }} +

+

+ {{ \"PLUGIN_ADMIN.SWITCHING_TO_CONFIRMATION\"|tu }} {theme_name}? +

+
+
+ + {{ \"PLUGIN_ADMIN.CONTINUE\"|tu }} +
+
+
+ +{% include 'partials/modal-add-package.html.twig' with { type: 'theme' } %} +{% include 'partials/modal-update-packages.html.twig' with { type: 'theme' } %} +", "partials/themes-list.html.twig", "/srv/http/berryfarmprojects.org.uk/stay-grav/user/plugins/admin/themes/grav/templates/partials/themes-list.html.twig"); + } +} diff --git a/cache/twig/52/52541702b7793472628f519411d6e36d0c1a8ca7f264b5e1eab6b6f9627be701.php b/cache/twig/52/52541702b7793472628f519411d6e36d0c1a8ca7f264b5e1eab6b6f9627be701.php new file mode 100644 index 00000000..d7c6e191 --- /dev/null +++ b/cache/twig/52/52541702b7793472628f519411d6e36d0c1a8ca7f264b5e1eab6b6f9627be701.php @@ -0,0 +1,282 @@ +parent = false; + + $this->blocks = [ + ]; + } + + protected function doDisplay(array $context, array $blocks = []) + { + // line 24 + echo " + + +"; + } + + // line 1 + public function getloop($__page__ = null, ...$__varargs__) + { + $context = $this->env->mergeGlobals([ + "page" => $__page__, + "varargs" => $__varargs__, + ]); + + $blocks = []; + + ob_start(); + try { + // line 2 + echo " "; + $context['_parent'] = $context; + $context['_seq'] = twig_ensure_traversable($this->getAttribute($this->getAttribute(($context["page"] ?? null), "children", []), "visible", [])); + foreach ($context['_seq'] as $context["_key"] => $context["p"]) { + // line 3 + echo " "; + $context["current_page"] = ((($this->getAttribute($context["p"], "active", []) || $this->getAttribute($context["p"], "activeChild", []))) ? ("selected") : ("")); + // line 4 + echo " "; + if (($this->getAttribute($this->getAttribute($this->getAttribute($context["p"], "children", []), "visible", []), "count", []) > 0)) { + // line 5 + echo "
  • + getAttribute($context["p"], "url", []); + echo "\"> + "; + // line 7 + if ($this->getAttribute($this->getAttribute($context["p"], "header", []), "icon", [])) { + echo "getAttribute($this->getAttribute($context["p"], "header", []), "icon", []); + echo "\">"; + } + // line 8 + echo " "; + echo $this->getAttribute($context["p"], "menu", []); + echo " + +
      + "; + // line 11 + echo $this->getAttribute($this, "loop", [0 => $context["p"]], "method"); + echo " +
    +
  • + "; + } else { + // line 15 + echo "
  • + getAttribute($context["p"], "url", []); + echo "\"> + "; + // line 17 + if ($this->getAttribute($this->getAttribute($context["p"], "header", []), "icon", [])) { + echo "getAttribute($this->getAttribute($context["p"], "header", []), "icon", []); + echo "\">"; + } + // line 18 + echo " "; + echo $this->getAttribute($context["p"], "menu", []); + echo " + +
  • + "; + } + // line 22 + echo " "; + } + $_parent = $context['_parent']; + unset($context['_seq'], $context['_iterated'], $context['_key'], $context['p'], $context['_parent'], $context['loop']); + $context = array_intersect_key($context, $_parent) + $_parent; + } catch (\Exception $e) { + ob_end_clean(); + + throw $e; + } catch (\Throwable $e) { + ob_end_clean(); + + throw $e; + } + + return ('' === $tmp = ob_get_clean()) ? '' : new Markup($tmp, $this->env->getCharset()); + } + + public function getTemplateName() + { + return "partials/navigation.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 189 => 22, 181 => 18, 175 => 17, 171 => 16, 166 => 15, 159 => 11, 152 => 8, 146 => 7, 142 => 6, 137 => 5, 134 => 4, 131 => 3, 126 => 2, 114 => 1, 108 => 47, 97 => 43, 91 => 42, 87 => 41, 84 => 40, 79 => 39, 76 => 38, 65 => 34, 59 => 33, 55 => 32, 50 => 31, 47 => 30, 42 => 29, 36 => 27, 34 => 26, 30 => 24,); + } + + /** @deprecated since 1.27 (to be removed in 2.0). Use getSourceContext() instead */ + public function getSource() + { + @trigger_error('The '.__METHOD__.' method is deprecated since version 1.27 and will be removed in 2.0. Use getSourceContext() instead.', E_USER_DEPRECATED); + + return $this->getSourceContext()->getCode(); + } + + public function getSourceContext() + { + return new Source("{% macro loop(page) %} + {% for p in page.children.visible %} + {% set current_page = (p.active or p.activeChild) ? 'selected' : '' %} + {% if p.children.visible.count > 0 %} +
  • + + {% if p.header.icon %}{% endif %} + {{ p.menu }} + +
      + {{ _self.loop(p) }} +
    +
  • + {% else %} +
  • + + {% if p.header.icon %}{% endif %} + {{ p.menu }} + +
  • + {% endif %} + {% endfor %} +{% endmacro %} + + + +", "partials/navigation.html.twig", "/srv/http/berryfarmprojects.org.uk/stay-grav/user/themes/goku/templates/partials/navigation.html.twig"); + } +} diff --git a/cache/twig/56/5607f8f0c91ee346245f899f025cef6cd5e0453bce48c662c7eb17f5b5266bac.php b/cache/twig/56/5607f8f0c91ee346245f899f025cef6cd5e0453bce48c662c7eb17f5b5266bac.php new file mode 100644 index 00000000..eaa875ee --- /dev/null +++ b/cache/twig/56/5607f8f0c91ee346245f899f025cef6cd5e0453bce48c662c7eb17f5b5266bac.php @@ -0,0 +1,80 @@ +blocks = [ + 'content' => [$this, 'block_content'], + ]; + } + + protected function doGetParent(array $context) + { + // line 1 + return "partials/base.html.twig"; + } + + protected function doDisplay(array $context, array $blocks = []) + { + $this->parent = $this->loadTemplate("partials/base.html.twig", "default.html.twig", 1); + $this->parent->display($context, array_merge($this->blocks, $blocks)); + } + + // line 3 + public function block_content($context, array $blocks = []) + { + // line 4 + echo " "; + echo $this->getAttribute(($context["page"] ?? null), "content", []); + echo " +"; + } + + public function getTemplateName() + { + return "default.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 42 => 4, 39 => 3, 29 => 1,); + } + + /** @deprecated since 1.27 (to be removed in 2.0). Use getSourceContext() instead */ + public function getSource() + { + @trigger_error('The '.__METHOD__.' method is deprecated since version 1.27 and will be removed in 2.0. Use getSourceContext() instead.', E_USER_DEPRECATED); + + return $this->getSourceContext()->getCode(); + } + + public function getSourceContext() + { + return new Source("{% extends 'partials/base.html.twig' %} + +{% block content %} + {{ page.content }} +{% endblock %} +", "default.html.twig", "/srv/http/berryfarmprojects.org.uk/stay-grav/user/themes/goku/templates/default.html.twig"); + } +} diff --git a/cache/twig/76/761878fd8c19f6e73600f1cde86a7a4096e41e6106b2e93a0dbf340c0851211e.php b/cache/twig/76/761878fd8c19f6e73600f1cde86a7a4096e41e6106b2e93a0dbf340c0851211e.php new file mode 100644 index 00000000..2353f4e0 --- /dev/null +++ b/cache/twig/76/761878fd8c19f6e73600f1cde86a7a4096e41e6106b2e93a0dbf340c0851211e.php @@ -0,0 +1,288 @@ +parent = false; + + $this->blocks = [ + ]; + } + + protected function doDisplay(array $context, array $blocks = []) + { + // line 1 + echo "
    +
    +
    +

    "; + // line 7 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\Twig\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.INSTALLING"), "html", null, true); + echo "

    + +
    +

    + "; + // line 11 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\Twig\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.LOADING"), "html", null, true); + echo " + +

    +
    + +
    +

    "; + // line 17 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\Twig\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.DEPENDENCIES_NOT_MET_MESSAGE"), "html", null, true); + echo "

    + +
    +

    "; + // line 20 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\Twig\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.PACKAGES_NOT_INSTALLED"), "html", null, true); + echo ":

    +
      +
      +
      +

      "; + // line 24 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\Twig\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.PACKAGES_NEED_UPDATE"), "html", null, true); + echo ":

      +
        +
        +
        +

        "; + // line 28 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\Twig\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.PACKAGES_SUGGESTED_UPDATE"), "html", null, true); + echo ":

        +
          +
          + + +
          + +
          +

          + "; + // line 40 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\Twig\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.READY_TO_INSTALL_PACKAGES"), "html", null, true); + echo " +

          + +
            + +
            + + env, ($context["type"] ?? null), "html", null, true); + echo "-action=\"install-package\" class=\"button\"> "; + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\Twig\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.CONTINUE"), "html", null, true); + echo " +
            +
            + +
            +

            + "; + // line 53 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\Twig\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.ERROR_INSTALLING_PACKAGES"), "html", null, true); + echo " +

            + +
              + +
              + +
              +
              + +
              +

              + "; + // line 65 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\Twig\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.INSTALLING_DEPENDENCIES"), "html", null, true); + echo " + +

              +
              + +
              +

              + "; + // line 72 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\Twig\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.INSTALLING_PACKAGES"), "html", null, true); + echo " + +

              + +
                +
                + +
                +

                + "; + // line 81 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\Twig\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.PACKAGES_SUCCESSFULLY_INSTALLED"), "html", null, true); + echo " +

                + +
                  +
                  +
                  + +
                  +
                  "; + } + + public function getTemplateName() + { + return "partials/modal-add-package.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 161 => 81, 149 => 72, 139 => 65, 130 => 59, 121 => 53, 110 => 47, 106 => 46, 97 => 40, 86 => 34, 82 => 33, 74 => 28, 67 => 24, 60 => 20, 54 => 17, 45 => 11, 38 => 7, 30 => 1,); + } + + /** @deprecated since 1.27 (to be removed in 2.0). Use getSourceContext() instead */ + public function getSource() + { + @trigger_error('The '.__METHOD__.' method is deprecated since version 1.27 and will be removed in 2.0. Use getSourceContext() instead.', E_USER_DEPRECATED); + + return $this->getSourceContext()->getCode(); + } + + public function getSourceContext() + { + return new Source("
                  +
                  +
                  +

                  {{ \"PLUGIN_ADMIN.INSTALLING\"|tu }}

                  + +
                  +

                  + {{ \"PLUGIN_ADMIN.LOADING\"|tu }} + +

                  +
                  + +
                  +

                  {{ \"PLUGIN_ADMIN.DEPENDENCIES_NOT_MET_MESSAGE\"|tu }}

                  + +
                  +

                  {{ \"PLUGIN_ADMIN.PACKAGES_NOT_INSTALLED\"|tu }}:

                  +
                    +
                    +
                    +

                    {{ \"PLUGIN_ADMIN.PACKAGES_NEED_UPDATE\"|tu }}:

                    +
                      +
                      +
                      +

                      {{ \"PLUGIN_ADMIN.PACKAGES_SUGGESTED_UPDATE\"|tu }}:

                      +
                        +
                        + +
                        + + {{ \"PLUGIN_ADMIN.CONTINUE\"|tu }} +
                        +
                        + +
                        +

                        + {{ \"PLUGIN_ADMIN.READY_TO_INSTALL_PACKAGES\"|tu }} +

                        + +
                          + +
                          + + {{ \"PLUGIN_ADMIN.CONTINUE\"|tu }} +
                          +
                          + +
                          +

                          + {{ \"PLUGIN_ADMIN.ERROR_INSTALLING_PACKAGES\"|tu }} +

                          + +
                            + +
                            + +
                            +
                            + +
                            +

                            + {{ \"PLUGIN_ADMIN.INSTALLING_DEPENDENCIES\"|tu }} + +

                            +
                            + +
                            +

                            + {{ \"PLUGIN_ADMIN.INSTALLING_PACKAGES\"|tu }} + +

                            + +
                              +
                              + +
                              +

                              + {{ \"PLUGIN_ADMIN.PACKAGES_SUCCESSFULLY_INSTALLED\"|tu }} +

                              + +
                                +
                                +
                                + +
                                +
                                ", "partials/modal-add-package.html.twig", "/srv/http/berryfarmprojects.org.uk/stay-grav/user/plugins/admin/themes/grav/templates/partials/modal-add-package.html.twig"); + } +} diff --git a/cache/twig/7b/7b996569ede0f89171021e63f28cab5ef1058ca9f269191946daacebcd05a9ff.php b/cache/twig/7b/7b996569ede0f89171021e63f28cab5ef1058ca9f269191946daacebcd05a9ff.php new file mode 100644 index 00000000..7c3f99dc --- /dev/null +++ b/cache/twig/7b/7b996569ede0f89171021e63f28cab5ef1058ca9f269191946daacebcd05a9ff.php @@ -0,0 +1,65 @@ +blocks = [ + ]; + } + + protected function doGetParent(array $context) + { + // line 1 + return "partials/base-root.html.twig"; + } + + protected function doDisplay(array $context, array $blocks = []) + { + $this->parent = $this->loadTemplate("partials/base-root.html.twig", "partials/base.html.twig", 1); + $this->parent->display($context, array_merge($this->blocks, $blocks)); + } + + public function getTemplateName() + { + return "partials/base.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 28 => 1,); + } + + /** @deprecated since 1.27 (to be removed in 2.0). Use getSourceContext() instead */ + public function getSource() + { + @trigger_error('The '.__METHOD__.' method is deprecated since version 1.27 and will be removed in 2.0. Use getSourceContext() instead.', E_USER_DEPRECATED); + + return $this->getSourceContext()->getCode(); + } + + public function getSourceContext() + { + return new Source("{% extends 'partials/base-root.html.twig' %} +", "partials/base.html.twig", "/srv/http/berryfarmprojects.org.uk/stay-grav/user/plugins/admin/themes/grav/templates/partials/base.html.twig"); + } +} diff --git a/cache/twig/7d/7d378d8f2dc6769b1003534f78e4173a6875fda2ade4398123b8da05c7021c11.php b/cache/twig/7d/7d378d8f2dc6769b1003534f78e4173a6875fda2ade4398123b8da05c7021c11.php new file mode 100644 index 00000000..c811de77 --- /dev/null +++ b/cache/twig/7d/7d378d8f2dc6769b1003534f78e4173a6875fda2ade4398123b8da05c7021c11.php @@ -0,0 +1,61 @@ +parent = false; + + $this->blocks = [ + ]; + } + + protected function doDisplay(array $context, array $blocks = []) + { + // line 1 + echo " +"; + } + + public function getTemplateName() + { + return "partials/nav-toggle.html.twig"; + } + + public function getDebugInfo() + { + return array ( 30 => 1,); + } + + /** @deprecated since 1.27 (to be removed in 2.0). Use getSourceContext() instead */ + public function getSource() + { + @trigger_error('The '.__METHOD__.' method is deprecated since version 1.27 and will be removed in 2.0. Use getSourceContext() instead.', E_USER_DEPRECATED); + + return $this->getSourceContext()->getCode(); + } + + public function getSourceContext() + { + return new Source(" +", "partials/nav-toggle.html.twig", "/srv/http/berryfarmprojects.org.uk/stay-grav/user/plugins/admin/themes/grav/templates/partials/nav-toggle.html.twig"); + } +} diff --git a/cache/twig/88/88b3f0e94cc071f35e3d8ac0fa0559c794b9efcb8cc0346016fd20a2cffa8ca1.php b/cache/twig/88/88b3f0e94cc071f35e3d8ac0fa0559c794b9efcb8cc0346016fd20a2cffa8ca1.php new file mode 100644 index 00000000..40681542 --- /dev/null +++ b/cache/twig/88/88b3f0e94cc071f35e3d8ac0fa0559c794b9efcb8cc0346016fd20a2cffa8ca1.php @@ -0,0 +1,233 @@ +parent = false; + + $this->blocks = [ + ]; + } + + protected function doDisplay(array $context, array $blocks = []) + { + // line 1 + if ($this->env->getExtension('Grav\Common\Twig\TwigExtension')->authorize([0 => "admin.login", 1 => "admin.super"])) { + // line 2 + $context["notifications"] = ((((($this->getAttribute($this->getAttribute($this->getAttribute($this->getAttribute(($context["config"] ?? null), "plugins", []), "admin", []), "widgets", []), "dashboard-notifications", [], "array") || $this->getAttribute($this->getAttribute($this->getAttribute($this->getAttribute(($context["config"] ?? null), "plugins", []), "admin", []), "notifications", []), "dashboard", [])) || $this->getAttribute($this->getAttribute($this->getAttribute($this->getAttribute(($context["config"] ?? null), "plugins", []), "admin", []), "notifications", []), "plugins", [])) || $this->getAttribute($this->getAttribute($this->getAttribute($this->getAttribute(($context["config"] ?? null), "plugins", []), "admin", []), "notifications", []), "themes", []))) ? (1) : (0)); + // line 3 + switch (($context["template_route"] ?? null)) { + case "dashboard": + { + // line 5 + echo " "; + $context["notifications_filters"] = "['feed', 'dashboard', 'top']"; + // line 6 + echo " "; + break; + } + case "plugins": + { + // line 7 + echo " "; + $context["notifications_filters"] = "['plugins', 'top']"; + // line 8 + echo " "; + break; + } + case "themes": + { + // line 9 + echo " "; + $context["notifications_filters"] = "['themes', 'top']"; + // line 10 + echo " "; + break; + } + default: + { + // line 11 + echo " "; + $context["notifications_filters"] = "['top']"; + } + } + // line 13 + echo " +"; + } + } + + public function getTemplateName() + { + return "partials/javascript-config.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 158 => 42, 147 => 40, 143 => 39, 135 => 34, 130 => 32, 125 => 30, 121 => 29, 116 => 27, 112 => 26, 108 => 25, 103 => 24, 97 => 22, 95 => 21, 91 => 20, 87 => 19, 83 => 18, 79 => 17, 75 => 16, 70 => 13, 65 => 11, 59 => 10, 56 => 9, 50 => 8, 47 => 7, 41 => 6, 38 => 5, 34 => 3, 32 => 2, 30 => 1,); + } + + /** @deprecated since 1.27 (to be removed in 2.0). Use getSourceContext() instead */ + public function getSource() + { + @trigger_error('The '.__METHOD__.' method is deprecated since version 1.27 and will be removed in 2.0. Use getSourceContext() instead.', E_USER_DEPRECATED); + + return $this->getSourceContext()->getCode(); + } + + public function getSourceContext() + { + return new Source("{% if authorize(['admin.login', 'admin.super']) %} +{% set notifications = (config.plugins.admin.widgets['dashboard-notifications'] or config.plugins.admin.notifications.dashboard or config.plugins.admin.notifications.plugins or config.plugins.admin.notifications.themes) ? 1 : 0 %} +{% switch template_route %} + {% case 'dashboard' %} + {% set notifications_filters = \"['feed', 'dashboard', 'top']\" %} + {% case 'plugins' %} + {% set notifications_filters = \"['plugins', 'top']\" %} + {% case 'themes' %} + {% set notifications_filters = \"['themes', 'top']\" %} + {% default %} + {% set notifications_filters = \"['top']\" %} +{% endswitch %} + +{% endif %} +", "partials/javascript-config.html.twig", "/srv/http/berryfarmprojects.org.uk/stay-grav/user/plugins/admin/themes/grav/templates/partials/javascript-config.html.twig"); + } +} diff --git a/cache/twig/89/89e0a35ebeec0da6a1a9a0436b0dcbbe6c19510bbab66806a939ca071d19ed31.php b/cache/twig/89/89e0a35ebeec0da6a1a9a0436b0dcbbe6c19510bbab66806a939ca071d19ed31.php new file mode 100644 index 00000000..7da45b38 --- /dev/null +++ b/cache/twig/89/89e0a35ebeec0da6a1a9a0436b0dcbbe6c19510bbab66806a939ca071d19ed31.php @@ -0,0 +1,57 @@ +parent = false; + + $this->blocks = [ + ]; + } + + protected function doDisplay(array $context, array $blocks = []) + { + // line 1 + echo " +"; + } + + public function getTemplateName() + { + return "@admin-images/grav-small.svg"; + } + + public function getDebugInfo() + { + return array ( 30 => 1,); + } + + /** @deprecated since 1.27 (to be removed in 2.0). Use getSourceContext() instead */ + public function getSource() + { + @trigger_error('The '.__METHOD__.' method is deprecated since version 1.27 and will be removed in 2.0. Use getSourceContext() instead.', E_USER_DEPRECATED); + + return $this->getSourceContext()->getCode(); + } + + public function getSourceContext() + { + return new Source(" +", "@admin-images/grav-small.svg", "/srv/http/berryfarmprojects.org.uk/stay-grav/user/plugins/admin/themes/grav/images/grav-small.svg"); + } +} diff --git a/cache/twig/8a/8a6a34230b45ae9d6f47a5f2074a1d13bf343826c49d855c65e9a05f75f678fb.php b/cache/twig/8a/8a6a34230b45ae9d6f47a5f2074a1d13bf343826c49d855c65e9a05f75f678fb.php new file mode 100644 index 00000000..f58f41a3 --- /dev/null +++ b/cache/twig/8a/8a6a34230b45ae9d6f47a5f2074a1d13bf343826c49d855c65e9a05f75f678fb.php @@ -0,0 +1,57 @@ +parent = false; + + $this->blocks = [ + ]; + } + + protected function doDisplay(array $context, array $blocks = []) + { + // line 1 + echo " +"; + } + + public function getTemplateName() + { + return "@admin-images/grav-regular.svg"; + } + + public function getDebugInfo() + { + return array ( 30 => 1,); + } + + /** @deprecated since 1.27 (to be removed in 2.0). Use getSourceContext() instead */ + public function getSource() + { + @trigger_error('The '.__METHOD__.' method is deprecated since version 1.27 and will be removed in 2.0. Use getSourceContext() instead.', E_USER_DEPRECATED); + + return $this->getSourceContext()->getCode(); + } + + public function getSourceContext() + { + return new Source(" +", "@admin-images/grav-regular.svg", "/srv/http/berryfarmprojects.org.uk/stay-grav/user/plugins/admin/themes/grav/images/grav-regular.svg"); + } +} diff --git a/cache/twig/a4/a46c464f706f6be2ed255c75c560e14cbfbbff56774e2bbc40c13d9a3b3b07c2.php b/cache/twig/a4/a46c464f706f6be2ed255c75c560e14cbfbbff56774e2bbc40c13d9a3b3b07c2.php new file mode 100644 index 00000000..62beb4c9 --- /dev/null +++ b/cache/twig/a4/a46c464f706f6be2ed255c75c560e14cbfbbff56774e2bbc40c13d9a3b3b07c2.php @@ -0,0 +1,83 @@ +parent = false; + + $this->blocks = [ + ]; + } + + protected function doDisplay(array $context, array $blocks = []) + { + // line 1 + if (($context["custom_admin_footer"] ?? null)) { + // line 2 + echo " "; + echo ($context["custom_admin_footer"] ?? null); + echo " +"; + } else { + // line 4 + echo " Grav v"; + echo twig_escape_filter($this->env, twig_constant("GRAV_VERSION"), "html", null, true); + echo " - Admin v"; + echo twig_escape_filter($this->env, ($context["admin_version"] ?? null), "html", null, true); + echo " - "; + echo twig_escape_filter($this->env, twig_lower_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\Twig\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.WAS_MADE_WITH")), "html", null, true); + echo " "; + echo twig_escape_filter($this->env, twig_lower_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\Twig\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.BY")), "html", null, true); + echo " Trilby Media. +"; + } + } + + public function getTemplateName() + { + return "partials/footer.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 38 => 4, 32 => 2, 30 => 1,); + } + + /** @deprecated since 1.27 (to be removed in 2.0). Use getSourceContext() instead */ + public function getSource() + { + @trigger_error('The '.__METHOD__.' method is deprecated since version 1.27 and will be removed in 2.0. Use getSourceContext() instead.', E_USER_DEPRECATED); + + return $this->getSourceContext()->getCode(); + } + + public function getSourceContext() + { + return new Source("{% if custom_admin_footer %} + {{ custom_admin_footer|raw }} +{% else %} + Grav v{{ constant('GRAV_VERSION') }} - Admin v{{ admin_version }} - {{ \"PLUGIN_ADMIN.WAS_MADE_WITH\"|tu|lower }} {{ \"PLUGIN_ADMIN.BY\"|tu|lower }} Trilby Media. +{% endif %} +", "partials/footer.html.twig", "/srv/http/berryfarmprojects.org.uk/stay-grav/user/plugins/admin/themes/grav/templates/partials/footer.html.twig"); + } +} diff --git a/cache/twig/a8/a84560553eb72d31b6da0a31475c039c6143ce4b0b71679890463542fe5423c3.php b/cache/twig/a8/a84560553eb72d31b6da0a31475c039c6143ce4b0b71679890463542fe5423c3.php new file mode 100644 index 00000000..4a1f9382 --- /dev/null +++ b/cache/twig/a8/a84560553eb72d31b6da0a31475c039c6143ce4b0b71679890463542fe5423c3.php @@ -0,0 +1,628 @@ +parent = false; + + $this->blocks = [ + 'head' => [$this, 'block_head'], + 'stylesheets' => [$this, 'block_stylesheets'], + 'javascripts' => [$this, 'block_javascripts'], + 'assets' => [$this, 'block_assets'], + 'body' => [$this, 'block_body'], + 'noscript' => [$this, 'block_noscript'], + 'page' => [$this, 'block_page'], + 'navigation' => [$this, 'block_navigation'], + 'titlebar' => [$this, 'block_titlebar'], + 'content_wrapper' => [$this, 'block_content_wrapper'], + 'messages' => [$this, 'block_messages'], + 'widgets' => [$this, 'block_widgets'], + 'content_top' => [$this, 'block_content_top'], + 'content' => [$this, 'block_content'], + 'content_bottom' => [$this, 'block_content_bottom'], + 'footer' => [$this, 'block_footer'], + 'modals' => [$this, 'block_modals'], + 'bottom' => [$this, 'block_bottom'], + ]; + } + + protected function doDisplay(array $context, array $blocks = []) + { + // line 1 + if (($this->getAttribute(($context["uri"] ?? null), "extension", [], "method") == "json")) { + $this->loadTemplate("default.json.twig", "partials/base-root.html.twig", 1)->display($context); + } else { + // line 2 + echo " + + + "; + // line 5 + $this->displayBlock('head', $context, $blocks); + // line 30 + echo " + "; + // line 31 + $this->displayBlock('assets', $context, $blocks); + // line 35 + echo " + "; + // line 36 + $this->displayBlock('body', $context, $blocks); + // line 136 + echo " +"; + } + $this->env->getExtension('Phive\Twig\Extensions\Deferred\DeferredExtension')->resolve($this, $context, $blocks); + } + + // line 5 + public function block_head($context, array $blocks = []) + { + // line 6 + echo " + "; + // line 7 + if (($context["title"] ?? null)) { + echo twig_escape_filter($this->env, ($context["title"] ?? null), "html", null, true); + echo " | "; + } else { + if ($this->getAttribute(($context["header"] ?? null), "title", [])) { + echo twig_escape_filter($this->env, $this->getAttribute(($context["header"] ?? null), "title", []), "html", null, true); + echo " | "; + } + } + echo twig_escape_filter($this->env, $this->getAttribute(($context["site"] ?? null), "title", []), "html", null, true); + echo " + "; + // line 8 + if ($this->getAttribute(($context["header"] ?? null), "description", [])) { + // line 9 + echo " env, $this->getAttribute(($context["header"] ?? null), "description", []), "html", null, true); + echo "\"> + "; + } else { + // line 11 + echo " env, $this->getAttribute(($context["site"] ?? null), "description", []), "html", null, true); + echo "\"> + "; + } + // line 13 + echo " "; + if ($this->getAttribute(($context["header"] ?? null), "robots", [])) { + // line 14 + echo " env, $this->getAttribute(($context["header"] ?? null), "robots", []), "html", null, true); + echo "\"> + "; + } else { + // line 16 + echo " + "; + } + // line 18 + echo " + env, ($context["base_url_simple"] ?? null), "html", null, true); + echo twig_escape_filter($this->env, ($context["theme_url"] ?? null), "html", null, true); + echo "/images/favicon.png\"> + + "; + // line 21 + $this->displayBlock('stylesheets', $context, $blocks); + // line 24 + echo " + "; + // line 25 + $this->loadTemplate("partials/javascript-config.html.twig", "partials/base-root.html.twig", 25)->display($context); + // line 26 + echo " "; + $this->displayBlock('javascripts', $context, $blocks); + // line 29 + echo " "; + } + + // line 21 + public function block_stylesheets($context, array $blocks = []) + { + // line 22 + echo " "; + $this->loadTemplate("partials/stylesheets.html.twig", "partials/base-root.html.twig", 22)->display($context); + // line 23 + echo " "; + } + + // line 26 + public function block_javascripts($context, array $blocks = []) + { + // line 27 + echo " "; + $this->loadTemplate("partials/javascripts.html.twig", "partials/base-root.html.twig", 27)->display($context); + // line 28 + echo " "; + } + + public function block_assets($context, array $blocks = array()) + { + $this->env->getExtension('Phive\Twig\Extensions\Deferred\DeferredExtension')->defer($this, 'assets'); + } + + // line 31 + public function block_assets_deferred($context, array $blocks = array()) + { + // line 32 + echo " "; + echo $this->getAttribute(($context["assets"] ?? null), "css", [], "method"); + echo " + "; + // line 33 + echo $this->getAttribute(($context["assets"] ?? null), "js", [], "method"); + echo " + "; + $this->env->getExtension('Phive\Twig\Extensions\Deferred\DeferredExtension')->resolve($this, $context, $blocks); + } + + // line 36 + public function block_body($context, array $blocks = []) + { + // line 37 + echo " getAttribute($this->getAttribute($this->getAttribute($this->getAttribute(($context["config"] ?? null), "plugins", []), "admin", []), "sidebar", []), "size", []) == "small")) ? ("sidebar-closed") : ("")); + echo " "; + echo twig_escape_filter($this->env, $this->getAttribute($this->getAttribute($this->getAttribute(($context["config"] ?? null), "plugins", []), "admin", []), "body_classes", []), "html", null, true); + echo " "; + echo twig_escape_filter($this->env, ($context["body_classes"] ?? null), "html", null, true); + echo "\"> + + "; + // line 39 + if ( !$this->env->getExtension('Grav\Common\Twig\TwigExtension')->authorize([0 => "admin.login"])) { + // line 40 + echo " "; + $this->loadTemplate("partials/messages.html.twig", "partials/base-root.html.twig", 40)->display($context); + // line 41 + echo " "; + } else { + // line 42 + echo " + "; + // line 43 + $this->displayBlock('noscript', $context, $blocks); + // line 46 + echo " + "; + // line 47 + $this->displayBlock('page', $context, $blocks); + // line 128 + echo " + "; + } + // line 130 + echo " + "; + // line 131 + $this->displayBlock('bottom', $context, $blocks); + // line 134 + echo " + "; + } + + // line 43 + public function block_noscript($context, array $blocks = []) + { + // line 44 + echo " "; + $this->loadTemplate("partials/noscript.html.twig", "partials/base-root.html.twig", 44)->display($context); + // line 45 + echo " "; + } + + // line 47 + public function block_page($context, array $blocks = []) + { + // line 48 + echo "
                                + + "; + // line 50 + $this->displayBlock('navigation', $context, $blocks); + // line 53 + echo " +
                                + "; + // line 55 + $this->loadTemplate("partials/nav-toggle.html.twig", "partials/base-root.html.twig", 55)->display($context); + // line 56 + echo "
                                + "; + // line 57 + $this->displayBlock('titlebar', $context, $blocks); + // line 58 + echo "
                                + + "; + // line 60 + $this->displayBlock('content_wrapper', $context, $blocks); + // line 86 + echo " + "; + // line 87 + $this->displayBlock('modals', $context, $blocks); + // line 123 + echo " +
                                +
                                +
                                + "; + } + + // line 50 + public function block_navigation($context, array $blocks = []) + { + // line 51 + echo " "; + $this->loadTemplate("partials/nav.html.twig", "partials/base-root.html.twig", 51)->display($context); + // line 52 + echo " "; + } + + // line 57 + public function block_titlebar($context, array $blocks = []) + { + } + + // line 60 + public function block_content_wrapper($context, array $blocks = []) + { + // line 61 + echo "
                                +
                                getAttribute($this->getAttribute($this->getAttribute(($context["config"] ?? null), "plugins", []), "admin", []), "content_padding", [])) { + echo "content-padding"; + } + echo "\"> + "; + // line 63 + $this->displayBlock('messages', $context, $blocks); + // line 66 + echo " + "; + // line 67 + $this->displayBlock('widgets', $context, $blocks); + // line 68 + echo "
                                + "; + // line 69 + $this->displayBlock('content_top', $context, $blocks); + // line 70 + echo "
                                "; + // line 71 + $this->displayBlock('content', $context, $blocks); + // line 72 + echo "
                                + "; + // line 73 + if ($this->getAttribute($this->getAttribute($this->getAttribute(($context["config"] ?? null), "plugins", []), "admin", []), "show_github_msg", [])) { + // line 74 + echo " + "; + } + // line 76 + echo " "; + $this->displayBlock('content_bottom', $context, $blocks); + // line 77 + echo "
                                + "; + // line 78 + $this->displayBlock('footer', $context, $blocks); + // line 83 + echo "
                                +
                                + "; + } + + // line 63 + public function block_messages($context, array $blocks = []) + { + // line 64 + echo " "; + $this->loadTemplate("partials/messages.html.twig", "partials/base-root.html.twig", 64)->display($context); + // line 65 + echo " "; + } + + // line 67 + public function block_widgets($context, array $blocks = []) + { + } + + // line 69 + public function block_content_top($context, array $blocks = []) + { + } + + // line 71 + public function block_content($context, array $blocks = []) + { + } + + // line 76 + public function block_content_bottom($context, array $blocks = []) + { + } + + // line 78 + public function block_footer($context, array $blocks = []) + { + // line 79 + echo "
                                + "; + // line 80 + $this->loadTemplate("partials/footer.html.twig", "partials/base-root.html.twig", 80)->display($context); + // line 81 + echo "
                                + "; + } + + // line 87 + public function block_modals($context, array $blocks = []) + { + // line 88 + echo "
                                +
                                +

                                "; + // line 90 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\Twig\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.ERROR"), "html", null, true); + echo "

                                +
                                + +
                                +
                                +
                                +
                                +

                                "; + // line 99 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\Twig\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.METADATA"), "html", null, true); + echo " for

                                + + +
                                +
                                +
                                +
                                +

                                "; + // line 111 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\Twig\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.MODAL_DELETE_FILE_CONFIRMATION_REQUIRED_TITLE"), "html", null, true); + echo "

                                +

                                + "; + // line 113 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\Twig\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.MODAL_DELETE_FILE_CONFIRMATION_REQUIRED_DESC"), "html", null, true); + echo " +

                                +
                                +
                                + + +
                                +
                                +
                                + "; + } + + // line 131 + public function block_bottom($context, array $blocks = []) + { + // line 132 + echo " "; + echo $this->getAttribute(($context["assets"] ?? null), "js", [0 => "bottom"], "method"); + echo " + "; + } + + public function getTemplateName() + { + return "partials/base-root.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 458 => 132, 455 => 131, 446 => 118, 442 => 117, 435 => 113, 430 => 111, 421 => 105, 412 => 99, 403 => 93, 397 => 90, 393 => 88, 390 => 87, 385 => 81, 383 => 80, 380 => 79, 377 => 78, 372 => 76, 367 => 71, 362 => 69, 357 => 67, 353 => 65, 350 => 64, 347 => 63, 341 => 83, 339 => 78, 336 => 77, 333 => 76, 327 => 74, 325 => 73, 322 => 72, 320 => 71, 318 => 70, 316 => 69, 313 => 68, 311 => 67, 308 => 66, 306 => 63, 300 => 62, 297 => 61, 294 => 60, 289 => 57, 285 => 52, 282 => 51, 279 => 50, 271 => 123, 269 => 87, 266 => 86, 264 => 60, 260 => 58, 258 => 57, 255 => 56, 253 => 55, 249 => 53, 247 => 50, 243 => 48, 240 => 47, 236 => 45, 233 => 44, 230 => 43, 225 => 134, 223 => 131, 220 => 130, 216 => 128, 214 => 47, 211 => 46, 209 => 43, 206 => 42, 203 => 41, 200 => 40, 198 => 39, 188 => 37, 185 => 36, 178 => 33, 173 => 32, 170 => 31, 161 => 28, 158 => 27, 155 => 26, 151 => 23, 148 => 22, 145 => 21, 141 => 29, 138 => 26, 136 => 25, 133 => 24, 131 => 21, 125 => 19, 122 => 18, 118 => 16, 112 => 14, 109 => 13, 103 => 11, 97 => 9, 95 => 8, 82 => 7, 79 => 6, 76 => 5, 69 => 136, 67 => 36, 64 => 35, 62 => 31, 59 => 30, 57 => 5, 52 => 2, 48 => 1,); + } + + /** @deprecated since 1.27 (to be removed in 2.0). Use getSourceContext() instead */ + public function getSource() + { + @trigger_error('The '.__METHOD__.' method is deprecated since version 1.27 and will be removed in 2.0. Use getSourceContext() instead.', E_USER_DEPRECATED); + + return $this->getSourceContext()->getCode(); + } + + public function getSourceContext() + { + return new Source("{% if uri.extension() == 'json' %}{% include 'default.json.twig' %}{% else %} + + + + {% block head %} + + {% if title %}{{ title }} | {% else %}{% if header.title %}{{ header.title }} | {% endif %}{% endif %}{{ site.title }} + {% if header.description %} + + {% else %} + + {% endif %} + {% if header.robots %} + + {% else %} + + {% endif %} + + + + {% block stylesheets %} + {% include 'partials/stylesheets.html.twig' %} + {% endblock %} + + {% include 'partials/javascript-config.html.twig' %} + {% block javascripts %} + {% include 'partials/javascripts.html.twig' %} + {% endblock %} + {% endblock %} + + {% block assets deferred %} + {{ assets.css()|raw }} + {{ assets.js()|raw }} + {% endblock %} + + {% block body %} + + + {% if not authorize(['admin.login']) %} + {% include 'partials/messages.html.twig' %} + {% else %} + + {% block noscript %} + {% include 'partials/noscript.html.twig' %} + {% endblock noscript %} + + {% block page %} +
                                + + {% block navigation %} + {% include 'partials/nav.html.twig' %} + {% endblock %} + +
                                + {% include 'partials/nav-toggle.html.twig' %} +
                                + {% block titlebar %}{% endblock %} +
                                + + {% block content_wrapper %} +
                                +
                                + {% block messages %} + {% include 'partials/messages.html.twig' %} + {% endblock %} + + {% block widgets %}{% endblock %} +
                                + {% block content_top %}{% endblock %} +
                                + {%- block content %}{% endblock -%} +
                                + {% if config.plugins.admin.show_github_msg %} + + {% endif %} + {% block content_bottom %}{% endblock %} +
                                + {% block footer %} +
                                + {% include 'partials/footer.html.twig' %} +
                                + {% endblock %} +
                                +
                                + {% endblock %} + + {% block modals %} +
                                +
                                +

                                {{ \"PLUGIN_ADMIN.ERROR\"|tu }}

                                +
                                + +
                                +
                                +
                                +
                                +

                                {{ \"PLUGIN_ADMIN.METADATA\"|tu }} for

                                + + +
                                +
                                +
                                +
                                +

                                {{ \"PLUGIN_ADMIN.MODAL_DELETE_FILE_CONFIRMATION_REQUIRED_TITLE\"|tu }}

                                +

                                + {{ \"PLUGIN_ADMIN.MODAL_DELETE_FILE_CONFIRMATION_REQUIRED_DESC\"|tu }} +

                                +
                                +
                                + + +
                                +
                                +
                                + {% endblock %} + +
                                +
                                +
                                + {% endblock page %} + + {% endif %} + + {% block bottom %} + {{ assets.js('bottom')|raw }} + {% endblock %} + + {% endblock body %} + +{% endif %} +", "partials/base-root.html.twig", "/srv/http/berryfarmprojects.org.uk/stay-grav/user/plugins/admin/themes/grav/templates/partials/base-root.html.twig"); + } +} diff --git a/cache/twig/b2/b2d655065eb1c0494954411ece536a7eb736deafcfe391c36880431443004a16.php b/cache/twig/b2/b2d655065eb1c0494954411ece536a7eb736deafcfe391c36880431443004a16.php new file mode 100644 index 00000000..45b4c06e --- /dev/null +++ b/cache/twig/b2/b2d655065eb1c0494954411ece536a7eb736deafcfe391c36880431443004a16.php @@ -0,0 +1,417 @@ +parent = false; + + $this->blocks = [ + ]; + } + + protected function doDisplay(array $context, array $blocks = []) + { + // line 1 + $context["nav_hover"] = ($this->getAttribute($this->getAttribute($this->getAttribute($this->getAttribute(($context["config"] ?? null), "plugins", []), "admin", []), "sidebar", []), "activate", []) == "hover"); + // line 2 + if ($this->env->getExtension('Grav\Common\Twig\TwigExtension')->authorize([0 => "admin.login", 1 => "admin.super"])) { + // line 3 + echo " +"; + } + } + + public function getTemplateName() + { + return "partials/nav.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 282 => 91, 278 => 89, 268 => 88, 265 => 87, 258 => 83, 253 => 81, 248 => 80, 245 => 79, 237 => 74, 231 => 71, 226 => 69, 221 => 68, 218 => 67, 210 => 62, 204 => 59, 199 => 57, 194 => 56, 191 => 55, 188 => 54, 182 => 53, 177 => 50, 170 => 47, 164 => 46, 157 => 45, 155 => 44, 151 => 43, 147 => 42, 141 => 41, 136 => 40, 133 => 39, 128 => 38, 125 => 37, 117 => 32, 112 => 30, 107 => 28, 102 => 27, 99 => 26, 89 => 23, 84 => 22, 82 => 21, 75 => 19, 71 => 18, 66 => 15, 64 => 14, 61 => 13, 59 => 12, 55 => 10, 52 => 9, 48 => 7, 46 => 6, 42 => 5, 34 => 3, 32 => 2, 30 => 1,); + } + + /** @deprecated since 1.27 (to be removed in 2.0). Use getSourceContext() instead */ + public function getSource() + { + @trigger_error('The '.__METHOD__.' method is deprecated since version 1.27 and will be removed in 2.0. Use getSourceContext() instead.', E_USER_DEPRECATED); + + return $this->getSourceContext()->getCode(); + } + + public function getSourceContext() + { + return new Source("{% set nav_hover = config.plugins.admin.sidebar.activate == 'hover' %} +{% if authorize(['admin.login', 'admin.super']) %} + +{% endif %} +", "partials/nav.html.twig", "/srv/http/berryfarmprojects.org.uk/stay-grav/user/plugins/admin/themes/grav/templates/partials/nav.html.twig"); + } +} diff --git a/cache/twig/c1/c17bf5b65524ef149988eb91f9703be4fedfc1499fb95f5f084bc078e1a2a728.php b/cache/twig/c1/c17bf5b65524ef149988eb91f9703be4fedfc1499fb95f5f084bc078e1a2a728.php new file mode 100644 index 00000000..48447e9e --- /dev/null +++ b/cache/twig/c1/c17bf5b65524ef149988eb91f9703be4fedfc1499fb95f5f084bc078e1a2a728.php @@ -0,0 +1,121 @@ +parent = false; + + $this->blocks = [ + ]; + } + + protected function doDisplay(array $context, array $blocks = []) + { + // line 1 + echo "
                                + You are offline +
                                +"; + // line 4 + $context["user"] = $this->getAttribute(($context["admin"] ?? null), "user", []); + // line 5 + $context["route"] = (($this->getAttribute(($context["grav"] ?? null), "flex_objects", [], "array", true, true)) ? ($this->getAttribute($this->getAttribute(($context["grav"] ?? null), "flex_objects", [], "array"), "adminRoute", [0 => ($context["user"] ?? null)], "method")) : ("")); + // line 6 + if ((($context["route"] ?? null) == "")) { + // line 7 + echo " "; + $context["route"] = ("/user/" . $this->getAttribute(($context["user"] ?? null), "username", [])); + } + // line 9 + echo " + +"; + } + + public function getTemplateName() + { + return "partials/nav-user-details.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 67 => 16, 59 => 15, 55 => 13, 53 => 12, 49 => 11, 45 => 9, 41 => 7, 39 => 6, 37 => 5, 35 => 4, 30 => 1,); + } + + /** @deprecated since 1.27 (to be removed in 2.0). Use getSourceContext() instead */ + public function getSource() + { + @trigger_error('The '.__METHOD__.' method is deprecated since version 1.27 and will be removed in 2.0. Use getSourceContext() instead.', E_USER_DEPRECATED); + + return $this->getSourceContext()->getCode(); + } + + public function getSourceContext() + { + return new Source("
                                + You are offline +
                                +{% set user = admin.user %} +{% set route = grav['flex_objects'] is defined ? grav['flex_objects'].adminRoute(user) : '' %} +{% if route == '' %} + {% set route = '/user/' ~ user.username %} +{% endif %} + + +", "partials/nav-user-details.html.twig", "/srv/http/berryfarmprojects.org.uk/stay-grav/user/plugins/admin/themes/grav/templates/partials/nav-user-details.html.twig"); + } +} diff --git a/cache/twig/c5/c58a8c71f831190c06ede1bf43388c7a677bf3b4634c073c292cdc582c8f30cb.php b/cache/twig/c5/c58a8c71f831190c06ede1bf43388c7a677bf3b4634c073c292cdc582c8f30cb.php new file mode 100644 index 00000000..a75a513f --- /dev/null +++ b/cache/twig/c5/c58a8c71f831190c06ede1bf43388c7a677bf3b4634c073c292cdc582c8f30cb.php @@ -0,0 +1,112 @@ +parent = false; + + $this->blocks = [ + ]; + } + + protected function doDisplay(array $context, array $blocks = []) + { + // line 1 + echo "
                                + +
                                +
                                +"; + } + + public function getTemplateName() + { + return "partials/list-sort.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 67 => 10, 60 => 9, 53 => 8, 47 => 7, 43 => 6, 38 => 4, 34 => 3, 30 => 1,); + } + + /** @deprecated since 1.27 (to be removed in 2.0). Use getSourceContext() instead */ + public function getSource() + { + @trigger_error('The '.__METHOD__.' method is deprecated since version 1.27 and will be removed in 2.0. Use getSourceContext() instead.', E_USER_DEPRECATED); + + return $this->getSourceContext()->getCode(); + } + + public function getSourceContext() + { + return new Source("
                                + +
                                +
                                +", "partials/list-sort.html.twig", "/srv/http/berryfarmprojects.org.uk/stay-grav/user/plugins/admin/themes/grav/templates/partials/list-sort.html.twig"); + } +} diff --git a/cache/twig/ca/ca3b24f3b5adf0a430ea4f272bc68b52afa59e8b5c97896ba7ffb22690f5ba0f.php b/cache/twig/ca/ca3b24f3b5adf0a430ea4f272bc68b52afa59e8b5c97896ba7ffb22690f5ba0f.php new file mode 100644 index 00000000..b090acde --- /dev/null +++ b/cache/twig/ca/ca3b24f3b5adf0a430ea4f272bc68b52afa59e8b5c97896ba7ffb22690f5ba0f.php @@ -0,0 +1,355 @@ +parent = false; + + $this->blocks = [ + 'head' => [$this, 'block_head'], + 'stylesheets' => [$this, 'block_stylesheets'], + 'javascripts' => [$this, 'block_javascripts'], + 'assets' => [$this, 'block_assets'], + 'header' => [$this, 'block_header'], + 'header_navigation' => [$this, 'block_header_navigation'], + 'body' => [$this, 'block_body'], + 'content' => [$this, 'block_content'], + 'footer' => [$this, 'block_footer'], + 'bottom' => [$this, 'block_bottom'], + ]; + } + + protected function doDisplay(array $context, array $blocks = []) + { + // line 1 + $context["theme_config"] = $this->getAttribute($this->getAttribute(($context["config"] ?? null), "themes", []), $this->getAttribute($this->getAttribute($this->getAttribute(($context["config"] ?? null), "system", []), "pages", []), "theme", [])); + // line 2 + echo " +getAttribute($this->getAttribute(($context["grav"] ?? null), "language", []), "getActive", [])) ? ($this->getAttribute($this->getAttribute(($context["grav"] ?? null), "language", []), "getActive", [])) : ($this->getAttribute($this->getAttribute($this->getAttribute(($context["grav"] ?? null), "config", []), "site", []), "default_lang", []))); + echo "\"> + +"; + // line 5 + $this->displayBlock('head', $context, $blocks); + // line 16 + echo " +"; + // line 17 + $this->displayBlock('stylesheets', $context, $blocks); + // line 23 + echo " +"; + // line 24 + $this->displayBlock('javascripts', $context, $blocks); + // line 27 + echo " +"; + // line 28 + $this->displayBlock('assets', $context, $blocks); + // line 32 + echo " +getAttribute($this->getAttribute(($context["page"] ?? null), "header", []), "body_classes", []); + echo "\"> + +"; + // line 35 + $this->displayBlock('header', $context, $blocks); + // line 50 + echo " +"; + // line 51 + $this->displayBlock('body', $context, $blocks); + // line 58 + echo " +"; + // line 59 + $this->displayBlock('footer', $context, $blocks); + // line 66 + echo " +"; + // line 67 + $this->displayBlock('bottom', $context, $blocks); + // line 70 + echo " + + +"; + $this->env->getExtension('Phive\Twig\Extensions\Deferred\DeferredExtension')->resolve($this, $context, $blocks); + } + + // line 5 + public function block_head($context, array $blocks = []) + { + // line 6 + echo " + "; + // line 7 + if ($this->getAttribute(($context["header"] ?? null), "title", [])) { + echo twig_escape_filter($this->env, $this->getAttribute(($context["header"] ?? null), "title", []), "html"); + echo " | "; + } + echo twig_escape_filter($this->env, $this->getAttribute(($context["site"] ?? null), "title", []), "html"); + echo " + + + + "; + // line 11 + $this->loadTemplate("partials/metadata.html.twig", "partials/base.html.twig", 11)->display($context); + // line 12 + echo " + env->getExtension('Grav\Common\Twig\TwigExtension')->urlFunc("theme://images/logo.png"); + echo "\" /> + getAttribute(($context["page"] ?? null), "url", [0 => true, 1 => true], "method"); + echo "\" /> +"; + } + + // line 17 + public function block_stylesheets($context, array $blocks = []) + { + // line 18 + echo " "; + $this->getAttribute(($context["assets"] ?? null), "addCss", [0 => "https://unpkg.com/purecss@1.0.0/build/pure-min.css", 1 => 100], "method"); + // line 19 + echo " "; + $this->getAttribute(($context["assets"] ?? null), "addCss", [0 => "https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css", 1 => 99], "method"); + // line 20 + echo " "; + $this->getAttribute(($context["assets"] ?? null), "addCss", [0 => "theme://css/custom.css", 1 => 98], "method"); + // line 21 + echo " "; + $this->getAttribute(($context["assets"] ?? null), "addCss", [0 => "theme://css-compiled/goku.css", 1 => 97], "method"); + } + + // line 24 + public function block_javascripts($context, array $blocks = []) + { + // line 25 + echo " "; + $this->getAttribute(($context["assets"] ?? null), "addJs", [0 => "jquery", 1 => 100], "method"); + } + + public function block_assets($context, array $blocks = array()) + { + $this->env->getExtension('Phive\Twig\Extensions\Deferred\DeferredExtension')->defer($this, 'assets'); + } + + // line 28 + public function block_assets_deferred($context, array $blocks = array()) + { + // line 29 + echo " "; + echo $this->getAttribute(($context["assets"] ?? null), "css", [], "method"); + echo " + "; + // line 30 + echo $this->getAttribute(($context["assets"] ?? null), "js", [], "method"); + echo " +"; + $this->env->getExtension('Phive\Twig\Extensions\Deferred\DeferredExtension')->resolve($this, $context, $blocks); + } + + // line 35 + public function block_header($context, array $blocks = []) + { + // line 36 + echo "
                                +
                                + + "; + // line 42 + $this->displayBlock('header_navigation', $context, $blocks); + // line 47 + echo "
                                +
                                +"; + } + + // line 42 + public function block_header_navigation($context, array $blocks = []) + { + // line 43 + echo " + "; + } + + // line 51 + public function block_body($context, array $blocks = []) + { + // line 52 + echo "
                                +
                                + "; + // line 54 + $this->displayBlock('content', $context, $blocks); + // line 55 + echo "
                                +
                                +"; + } + + // line 54 + public function block_content($context, array $blocks = []) + { + } + + // line 59 + public function block_footer($context, array $blocks = []) + { + // line 60 + echo "
                                +
                                +

                                Grav was with by RocketTheme.

                                +
                                +
                                +"; + } + + // line 67 + public function block_bottom($context, array $blocks = []) + { + // line 68 + echo " "; + echo $this->getAttribute(($context["assets"] ?? null), "js", [0 => "bottom"], "method"); + echo " +"; + } + + public function getTemplateName() + { + return "partials/base.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 250 => 68, 247 => 67, 238 => 60, 235 => 59, 230 => 54, 224 => 55, 222 => 54, 218 => 52, 215 => 51, 210 => 45, 208 => 44, 205 => 43, 202 => 42, 196 => 47, 194 => 42, 189 => 40, 184 => 38, 180 => 36, 177 => 35, 170 => 30, 165 => 29, 162 => 28, 152 => 25, 149 => 24, 144 => 21, 141 => 20, 138 => 19, 135 => 18, 132 => 17, 126 => 14, 122 => 13, 119 => 12, 117 => 11, 106 => 7, 103 => 6, 100 => 5, 92 => 70, 90 => 67, 87 => 66, 85 => 59, 82 => 58, 80 => 51, 77 => 50, 75 => 35, 70 => 33, 67 => 32, 65 => 28, 62 => 27, 60 => 24, 57 => 23, 55 => 17, 52 => 16, 50 => 5, 45 => 3, 42 => 2, 40 => 1,); + } + + /** @deprecated since 1.27 (to be removed in 2.0). Use getSourceContext() instead */ + public function getSource() + { + @trigger_error('The '.__METHOD__.' method is deprecated since version 1.27 and will be removed in 2.0. Use getSourceContext() instead.', E_USER_DEPRECATED); + + return $this->getSourceContext()->getCode(); + } + + public function getSourceContext() + { + return new Source("{% set theme_config = attribute(config.themes, config.system.pages.theme) %} + + + +{% block head %} + + {% if header.title %}{{ header.title|e('html') }} | {% endif %}{{ site.title|e('html') }} + + + + {% include 'partials/metadata.html.twig' %} + + + +{% endblock head %} + +{% block stylesheets %} + {% do assets.addCss('https://unpkg.com/purecss@1.0.0/build/pure-min.css', 100) %} + {% do assets.addCss('https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css', 99) %} + {% do assets.addCss('theme://css/custom.css', 98) %} + {% do assets.addCss('theme://css-compiled/goku.css', 97) %} +{% endblock %} + +{% block javascripts %} + {% do assets.addJs('jquery', 100) %} +{% endblock %} + +{% block assets deferred %} + {{ assets.css()|raw }} + {{ assets.js()|raw }} +{% endblock %} + + + +{% block header %} +
                                +
                                + + {% block header_navigation %} + + {% endblock %} +
                                +
                                +{% endblock %} + +{% block body %} +
                                +
                                + {% block content %}{% endblock %} +
                                +
                                +{% endblock %} + +{% block footer %} +
                                +
                                +

                                Grav was with by RocketTheme.

                                +
                                +
                                +{% endblock %} + +{% block bottom %} + {{ assets.js('bottom')|raw }} +{% endblock %} + + + +", "partials/base.html.twig", "/srv/http/berryfarmprojects.org.uk/stay-grav/user/themes/goku/templates/partials/base.html.twig"); + } +} diff --git a/cache/twig/d6/d655a85edd67de5bd3155c9c302a12fc22c14c038ebc55b261e8f678f5b7c0a2.php b/cache/twig/d6/d655a85edd67de5bd3155c9c302a12fc22c14c038ebc55b261e8f678f5b7c0a2.php new file mode 100644 index 00000000..2ea47cf7 --- /dev/null +++ b/cache/twig/d6/d655a85edd67de5bd3155c9c302a12fc22c14c038ebc55b261e8f678f5b7c0a2.php @@ -0,0 +1,97 @@ +parent = false; + + $this->blocks = [ + ]; + } + + protected function doDisplay(array $context, array $blocks = []) + { + // line 1 + $context['_parent'] = $context; + $context['_seq'] = twig_ensure_traversable($this->getAttribute(($context["page"] ?? null), "metadata", [])); + foreach ($context['_seq'] as $context["_key"] => $context["meta"]) { + // line 2 + echo " getAttribute($context["meta"], "name", [])) { + echo "name=\""; + echo $this->getAttribute($context["meta"], "name", []); + echo "\" "; + } + if ($this->getAttribute($context["meta"], "http_equiv", [])) { + echo "http-equiv=\""; + echo $this->getAttribute($context["meta"], "http_equiv", []); + echo "\" "; + } + if ($this->getAttribute($context["meta"], "charset", [])) { + echo "charset=\""; + echo $this->getAttribute($context["meta"], "charset", []); + echo "\" "; + } + if ($this->getAttribute($context["meta"], "property", [])) { + echo "property=\""; + echo $this->getAttribute($context["meta"], "property", []); + echo "\" "; + } + if ($this->getAttribute($context["meta"], "content", [])) { + echo "content=\""; + echo $this->getAttribute($context["meta"], "content", []); + echo "\" "; + } + echo "/> +"; + } + $_parent = $context['_parent']; + unset($context['_seq'], $context['_iterated'], $context['_key'], $context['meta'], $context['_parent'], $context['loop']); + $context = array_intersect_key($context, $_parent) + $_parent; + } + + public function getTemplateName() + { + return "partials/metadata.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 34 => 2, 30 => 1,); + } + + /** @deprecated since 1.27 (to be removed in 2.0). Use getSourceContext() instead */ + public function getSource() + { + @trigger_error('The '.__METHOD__.' method is deprecated since version 1.27 and will be removed in 2.0. Use getSourceContext() instead.', E_USER_DEPRECATED); + + return $this->getSourceContext()->getCode(); + } + + public function getSourceContext() + { + return new Source("{% for meta in page.metadata %} + +{% endfor %}", "partials/metadata.html.twig", "/srv/http/berryfarmprojects.org.uk/stay-grav/system/templates/partials/metadata.html.twig"); + } +} diff --git a/cache/twig/d7/d7db7c4a0a28dd4f38cee49b05982b02158144d11f02459e09068d4d69d40349.php b/cache/twig/d7/d7db7c4a0a28dd4f38cee49b05982b02158144d11f02459e09068d4d69d40349.php new file mode 100644 index 00000000..86e81bfa --- /dev/null +++ b/cache/twig/d7/d7db7c4a0a28dd4f38cee49b05982b02158144d11f02459e09068d4d69d40349.php @@ -0,0 +1,110 @@ +parent = false; + + $this->blocks = [ + ]; + } + + protected function doDisplay(array $context, array $blocks = []) + { + // line 1 + $this->getAttribute(($context["assets"] ?? null), "addCss", [0 => (($context["theme_url"] ?? null) . "/css-compiled/nucleus.css")], "method"); + // line 2 + $this->getAttribute(($context["assets"] ?? null), "addCss", [0 => (($context["theme_url"] ?? null) . "/css-compiled/template.css")], "method"); + // line 3 + $this->getAttribute(($context["assets"] ?? null), "addCss", [0 => (($context["preset_url"] ?? null) . "/css-compiled/preset.css")], "method"); + // line 4 + if ($this->getAttribute($this->getAttribute($this->getAttribute(($context["config"] ?? null), "plugins", []), "admin", []), "google_fonts", [])) { + // line 5 + echo " "; + $this->getAttribute(($context["assets"] ?? null), "addCss", [0 => (($context["theme_url"] ?? null) . "/css-compiled/fonts.css")], "method"); + } else { + // line 7 + echo " "; + $this->getAttribute(($context["assets"] ?? null), "addCss", [0 => (($context["theme_url"] ?? null) . "/css-compiled/simple-fonts.css")], "method"); + } + // line 9 + $this->getAttribute(($context["assets"] ?? null), "addCss", [0 => (($context["theme_url"] ?? null) . "/css/fork-awesome.min.css")], "method"); + // line 10 + $this->getAttribute(($context["assets"] ?? null), "addCss", [0 => (($context["theme_url"] ?? null) . "/css/chartist.min.css")], "method"); + // line 11 + $this->getAttribute(($context["assets"] ?? null), "addCss", [0 => (($context["theme_url"] ?? null) . "/css/selectize.min.css")], "method"); + // line 12 + $this->getAttribute(($context["assets"] ?? null), "addCss", [0 => (($context["theme_url"] ?? null) . "/css/hint.base.min.css")], "method"); + // line 13 + $this->getAttribute(($context["assets"] ?? null), "addCss", [0 => (($context["theme_url"] ?? null) . "/css/iconpicker.css")], "method"); + // line 14 + if (((($this->getAttribute(($context["browser"] ?? null), "getBrowser", []) == "msie") && ($this->getAttribute(($context["browser"] ?? null), "getVersion", []) >= 8)) && ($this->getAttribute(($context["browser"] ?? null), "getVersion", []) <= 9))) { + // line 15 + echo " "; + $this->getAttribute(($context["assets"] ?? null), "addCss", [0 => (($context["theme_url"] ?? null) . "/css/nucleus-ie9.css")], "method"); + // line 16 + echo " "; + $this->getAttribute(($context["assets"] ?? null), "addCss", [0 => (($context["theme_url"] ?? null) . "/css/pure-0.5.0/grids-min.css")], "method"); + } + } + + public function getTemplateName() + { + return "partials/stylesheets.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 61 => 16, 58 => 15, 56 => 14, 54 => 13, 52 => 12, 50 => 11, 48 => 10, 46 => 9, 42 => 7, 38 => 5, 36 => 4, 34 => 3, 32 => 2, 30 => 1,); + } + + /** @deprecated since 1.27 (to be removed in 2.0). Use getSourceContext() instead */ + public function getSource() + { + @trigger_error('The '.__METHOD__.' method is deprecated since version 1.27 and will be removed in 2.0. Use getSourceContext() instead.', E_USER_DEPRECATED); + + return $this->getSourceContext()->getCode(); + } + + public function getSourceContext() + { + return new Source("{% do assets.addCss(theme_url~'/css-compiled/nucleus.css') %} +{% do assets.addCss(theme_url~'/css-compiled/template.css') %} +{% do assets.addCss(preset_url~'/css-compiled/preset.css') %} +{% if config.plugins.admin.google_fonts %} + {% do assets.addCss(theme_url~'/css-compiled/fonts.css') %} +{% else %} + {% do assets.addCss(theme_url~'/css-compiled/simple-fonts.css') %} +{% endif %} +{% do assets.addCss(theme_url~'/css/fork-awesome.min.css') %} +{% do assets.addCss(theme_url~'/css/chartist.min.css') %} +{% do assets.addCss(theme_url~'/css/selectize.min.css') %} +{% do assets.addCss(theme_url~'/css/hint.base.min.css') %} +{% do assets.addCss(theme_url~'/css/iconpicker.css') %} +{% if browser.getBrowser == 'msie' and browser.getVersion >= 8 and browser.getVersion <= 9 %} + {% do assets.addCss(theme_url~'/css/nucleus-ie9.css') %} + {% do assets.addCss(theme_url~'/css/pure-0.5.0/grids-min.css') %} +{% endif %} +", "partials/stylesheets.html.twig", "/srv/http/berryfarmprojects.org.uk/stay-grav/user/plugins/admin/themes/grav/templates/partials/stylesheets.html.twig"); + } +} diff --git a/cache/twig/ef/efe2ab974c7cefd22cd3d3548a4288a75c9518c33e0cc6227cea566e98f5bdb9.php b/cache/twig/ef/efe2ab974c7cefd22cd3d3548a4288a75c9518c33e0cc6227cea566e98f5bdb9.php new file mode 100644 index 00000000..dd511982 --- /dev/null +++ b/cache/twig/ef/efe2ab974c7cefd22cd3d3548a4288a75c9518c33e0cc6227cea566e98f5bdb9.php @@ -0,0 +1,119 @@ +parent = false; + + $this->blocks = [ + ]; + } + + protected function doDisplay(array $context, array $blocks = []) + { + // line 1 + $context["admin_messages"] = twig_array_merge($this->getAttribute(($context["admin"] ?? null), "messages", []), $this->getAttribute(($context["admin"] ?? null), "getTempMessages", [], "method")); + // line 2 + $context["form_message"] = $this->getAttribute(($context["form"] ?? null), "message", []); + // line 3 + echo "
                                env, ($context["admin_messages"] ?? null)) || ($context["form_message"] ?? null))) ? (" default-box-shadow") : ("")); + echo "\"> +
                                "; + // line 5 + $context['_parent'] = $context; + $context['_seq'] = twig_ensure_traversable(($context["admin_messages"] ?? null)); + foreach ($context['_seq'] as $context["_key"] => $context["message"]) { + // line 6 + echo "
                                env, $this->getAttribute($context["message"], "scope", [])); + echo " alert\">"; + echo $this->getAttribute($context["message"], "message", []); + echo "
                                "; + } + $_parent = $context['_parent']; + unset($context['_seq'], $context['_iterated'], $context['_key'], $context['message'], $context['_parent'], $context['loop']); + $context = array_intersect_key($context, $_parent) + $_parent; + // line 8 + if (($context["form_message"] ?? null)) { + // line 9 + echo "
                                "; + echo ($context["form_message"] ?? null); + echo "
                                "; + } + // line 11 + $context['_parent'] = $context; + $context['_seq'] = twig_ensure_traversable(($context["plugin_messages"] ?? null)); + foreach ($context['_seq'] as $context["_key"] => $context["message"]) { + // line 12 + echo "
                                env, $this->getAttribute($context["message"], "scope", [])); + echo " alert\">"; + echo $this->getAttribute($context["message"], "message", []); + echo "
                                "; + } + $_parent = $context['_parent']; + unset($context['_seq'], $context['_iterated'], $context['_key'], $context['message'], $context['_parent'], $context['loop']); + $context = array_intersect_key($context, $_parent) + $_parent; + // line 14 + echo "
                                +"; + } + + public function getTemplateName() + { + return "partials/messages.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 74 => 14, 64 => 12, 60 => 11, 55 => 9, 53 => 8, 43 => 6, 39 => 5, 34 => 3, 32 => 2, 30 => 1,); + } + + /** @deprecated since 1.27 (to be removed in 2.0). Use getSourceContext() instead */ + public function getSource() + { + @trigger_error('The '.__METHOD__.' method is deprecated since version 1.27 and will be removed in 2.0. Use getSourceContext() instead.', E_USER_DEPRECATED); + + return $this->getSourceContext()->getCode(); + } + + public function getSourceContext() + { + return new Source("{% set admin_messages = admin.messages|merge(admin.getTempMessages()) %} +{% set form_message = form.message %} +
                                +
                                + {%- for message in admin_messages -%} +
                                {{ message.message|raw }}
                                + {%- endfor -%} + {%- if form_message -%} +
                                {{ form_message|raw }}
                                + {%- endif -%} + {%- for message in plugin_messages -%} +
                                {{ message.message|raw }}
                                + {%- endfor -%} +
                                +", "partials/messages.html.twig", "/srv/http/berryfarmprojects.org.uk/stay-grav/user/plugins/admin/themes/grav/templates/partials/messages.html.twig"); + } +} diff --git a/cache/twig/fe/fe74efa19d5468919ceccb2c3685912cb1fc6e8533a3a8841738380fe876f1c7.php b/cache/twig/fe/fe74efa19d5468919ceccb2c3685912cb1fc6e8533a3a8841738380fe876f1c7.php new file mode 100644 index 00000000..47092942 --- /dev/null +++ b/cache/twig/fe/fe74efa19d5468919ceccb2c3685912cb1fc6e8533a3a8841738380fe876f1c7.php @@ -0,0 +1,288 @@ +parent = false; + + $this->blocks = [ + ]; + } + + protected function doDisplay(array $context, array $blocks = []) + { + // line 1 + echo "
                                +
                                +
                                +

                                "; + // line 7 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\Twig\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.UPDATING"), "html", null, true); + echo "

                                + +
                                +

                                + "; + // line 11 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\Twig\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.LOADING"), "html", null, true); + echo " + +

                                +
                                + +
                                +

                                "; + // line 17 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\Twig\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.DEPENDENCIES_NOT_MET_MESSAGE"), "html", null, true); + echo "

                                + +
                                +

                                "; + // line 20 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\Twig\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.PACKAGES_NOT_INSTALLED"), "html", null, true); + echo ":

                                +
                                  +
                                  +
                                  +

                                  "; + // line 24 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\Twig\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.PACKAGES_NEED_UPDATE"), "html", null, true); + echo ":

                                  +
                                    +
                                    +
                                    +

                                    "; + // line 28 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\Twig\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.PACKAGES_SUGGESTED_UPDATE"), "html", null, true); + echo ":

                                    +
                                      +
                                      + + +
                                      + +
                                      +

                                      + "; + // line 40 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\Twig\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.READY_TO_UPDATE_PACKAGES"), "html", null, true); + echo " +

                                      + +
                                        + +
                                        + + env, ($context["type"] ?? null), "html", null, true); + echo "-action=\"install-package\" class=\"button\"> "; + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\Twig\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.CONTINUE"), "html", null, true); + echo " +
                                        +
                                        + +
                                        +

                                        + "; + // line 53 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\Twig\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.ERROR_UPDATING_PACKAGES"), "html", null, true); + echo " +

                                        + +
                                          + +
                                          + +
                                          +
                                          + +
                                          +

                                          + "; + // line 65 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\Twig\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.INSTALLING_DEPENDENCIES"), "html", null, true); + echo " + +

                                          +
                                          + +
                                          +

                                          + "; + // line 72 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\Twig\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.UPDATING_PACKAGES"), "html", null, true); + echo " + +

                                          + +
                                            +
                                            + +
                                            +

                                            + "; + // line 81 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\Twig\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.PACKAGES_SUCCESSFULLY_UPDATED"), "html", null, true); + echo " +

                                            + +
                                              +
                                              +
                                              + +
                                              +
                                              "; + } + + public function getTemplateName() + { + return "partials/modal-update-packages.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 161 => 81, 149 => 72, 139 => 65, 130 => 59, 121 => 53, 110 => 47, 106 => 46, 97 => 40, 86 => 34, 82 => 33, 74 => 28, 67 => 24, 60 => 20, 54 => 17, 45 => 11, 38 => 7, 30 => 1,); + } + + /** @deprecated since 1.27 (to be removed in 2.0). Use getSourceContext() instead */ + public function getSource() + { + @trigger_error('The '.__METHOD__.' method is deprecated since version 1.27 and will be removed in 2.0. Use getSourceContext() instead.', E_USER_DEPRECATED); + + return $this->getSourceContext()->getCode(); + } + + public function getSourceContext() + { + return new Source("
                                              +
                                              +
                                              +

                                              {{ \"PLUGIN_ADMIN.UPDATING\"|tu }}

                                              + +
                                              +

                                              + {{ \"PLUGIN_ADMIN.LOADING\"|tu }} + +

                                              +
                                              + +
                                              +

                                              {{ \"PLUGIN_ADMIN.DEPENDENCIES_NOT_MET_MESSAGE\"|tu }}

                                              + +
                                              +

                                              {{ \"PLUGIN_ADMIN.PACKAGES_NOT_INSTALLED\"|tu }}:

                                              +
                                                +
                                                +
                                                +

                                                {{ \"PLUGIN_ADMIN.PACKAGES_NEED_UPDATE\"|tu }}:

                                                +
                                                  +
                                                  +
                                                  +

                                                  {{ \"PLUGIN_ADMIN.PACKAGES_SUGGESTED_UPDATE\"|tu }}:

                                                  +
                                                    +
                                                    + +
                                                    + + {{ \"PLUGIN_ADMIN.CONTINUE\"|tu }} +
                                                    +
                                                    + +
                                                    +

                                                    + {{ \"PLUGIN_ADMIN.READY_TO_UPDATE_PACKAGES\"|tu }} +

                                                    + +
                                                      + +
                                                      + + {{ \"PLUGIN_ADMIN.CONTINUE\"|tu }} +
                                                      +
                                                      + +
                                                      +

                                                      + {{ \"PLUGIN_ADMIN.ERROR_UPDATING_PACKAGES\"|tu }} +

                                                      + +
                                                        + +
                                                        + +
                                                        +
                                                        + +
                                                        +

                                                        + {{ \"PLUGIN_ADMIN.INSTALLING_DEPENDENCIES\"|tu }} + +

                                                        +
                                                        + +
                                                        +

                                                        + {{ \"PLUGIN_ADMIN.UPDATING_PACKAGES\"|tu }} + +

                                                        + +
                                                          +
                                                          + +
                                                          +

                                                          + {{ \"PLUGIN_ADMIN.PACKAGES_SUCCESSFULLY_UPDATED\"|tu }} +

                                                          + +
                                                            +
                                                            +
                                                            + +
                                                            +
                                                            ", "partials/modal-update-packages.html.twig", "/srv/http/berryfarmprojects.org.uk/stay-grav/user/plugins/admin/themes/grav/templates/partials/modal-update-packages.html.twig"); + } +} diff --git a/composer.json b/composer.json new file mode 100644 index 00000000..34b4c8d1 --- /dev/null +++ b/composer.json @@ -0,0 +1,112 @@ +{ + "name": "getgrav/grav", + "type": "project", + "description": "Modern, Crazy Fast, Ridiculously Easy and Amazingly Powerful Flat-File CMS", + "keywords": [ + "cms", + "flat-file cms", + "flat cms", + "flatfile cms", + "php" + ], + "homepage": "https://getgrav.org", + "license": "MIT", + "require": { + "php": ">=7.1.3", + "ext-json": "*", + "ext-mbstring": "*", + "ext-openssl": "*", + "ext-curl": "*", + "ext-zip": "*", + "ext-dom": "*", + "symfony/polyfill-iconv": "^1.9", + "symfony/polyfill-php72": "^1.9", + "symfony/polyfill-php73": "^1.9", + "psr/simple-cache": "^1.0", + "psr/http-message": "^1.0", + "psr/http-server-middleware": "^1.0", + "kodus/psr7-server": "*", + "nyholm/psr7": "^1.0", + "twig/twig": "~1.40", + "erusev/parsedown": "1.6.4", + "erusev/parsedown-extra": "~0.7", + "symfony/yaml": "~4.2.0", + "symfony/console": "~4.2.0", + "symfony/event-dispatcher": "~4.2.0", + "symfony/var-dumper": "~4.2.0", + "symfony/process": "~4.2.0", + "doctrine/cache": "^1.8", + "doctrine/collections": "^1.5", + "guzzlehttp/psr7": "^1.4", + "filp/whoops": "~2.2", + "matthiasmullie/minify": "^1.3", + "monolog/monolog": "~1.0", + "gregwar/image": "2.*", + "donatj/phpuseragentparser": "~0.10", + "pimple/pimple": "~3.2", + "rockettheme/toolbox": "~1.4", + "maximebf/debugbar": "~1.15", + "league/climate": "^3.4", + "antoligy/dom-string-iterators": "^1.0", + "miljar/php-exif": "^0.6.4", + "composer/ca-bundle": "^1.0", + "dragonmantank/cron-expression": "^1.2", + "phive/twig-extensions-deferred": "^1.0", + "willdurand/negotiation": "^2.3" + }, + "require-dev": { + "codeception/codeception": "^2.4", + "phpstan/phpstan": "^0.11", + "phpstan/phpstan-deprecation-rules": "^0.11.0", + "phpunit/php-code-coverage": "~6.0", + "fzaninotto/faker": "^1.8", + "victorjonsson/markdowndocs": "dev-master" + }, + "suggest": { + "ext-zend-opcache": "Recommended for better performance", + "ext-intl": "Recommended for multi-language sites", + "ext-memcache": "Needed to support Memcache servers", + "ext-memcached": "Needed to support Memcached servers", + "ext-redis": "Needed to support Redis servers" + }, + "config": { + "apcu-autoloader": true, + "platform": { + "php": "7.1.3" + } + }, + "repositories": [ + { + "type": "vcs", + "url": "https://github.com/trilbymedia/PHP-Markdown-Documentation-Generator" + } + ], + "autoload": { + "psr-4": { + "Grav\\": "system/src/Grav" + }, + "files": [ + "system/defines.php" + ] + }, + "archive": { + "exclude": [ + "VERSION" + ] + }, + "scripts": { + "api-16": "vendor/bin/phpdoc-md generate system/src > user/pages/14.api/default.16.md", + "api-15": "vendor/bin/phpdoc-md generate system/src > user/pages/14.api/default.md", + "post-create-project-cmd": "bin/grav install", + "phpstan": "vendor/bin/phpstan analyse -l 2 -c ./tests/phpstan/phpstan.neon system/src --memory-limit=256M", + "phpstan-framework": "vendor/bin/phpstan analyse -l 5 -c ./tests/phpstan/phpstan.neon system/src/Grav/Framework --memory-limit=256M", + "phpstan-plugins": "vendor/bin/phpstan analyse -l 0 -c ./tests/phpstan/plugins.neon user/plugins --memory-limit=256M", + "test": "vendor/bin/codecept run unit", + "test-windows": "vendor\\bin\\codecept run unit" + }, + "extra": { + "branch-alias": { + "dev-develop": "1.x-dev" + } + } +} diff --git a/composer.lock b/composer.lock new file mode 100644 index 00000000..647b0810 --- /dev/null +++ b/composer.lock @@ -0,0 +1,5677 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "171fc8a6af028b50024e0f5f8c3eca82", + "packages": [ + { + "name": "antoligy/dom-string-iterators", + "version": "v1.0.1", + "source": { + "type": "git", + "url": "https://github.com/antoligy/dom-string-iterators.git", + "reference": "fae88f66e1970d68c5585fc42db44f1217bf74e6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/antoligy/dom-string-iterators/zipball/fae88f66e1970d68c5585fc42db44f1217bf74e6", + "reference": "fae88f66e1970d68c5585fc42db44f1217bf74e6", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "CC0-1.0" + ], + "authors": [ + { + "name": "Alex Wilson", + "email": "a@ax.gy" + }, + { + "name": "Kornel Lesinski", + "email": "pornel@pornel.net" + }, + { + "name": "Patrick Galbraith", + "email": "patrick.j.galbraith@gmail.com" + } + ], + "description": "Composer package for DOMWordsIterator and DOMLettersIterator", + "time": "2018-02-03T16:01:11+00:00" + }, + { + "name": "composer/ca-bundle", + "version": "1.2.3", + "source": { + "type": "git", + "url": "https://github.com/composer/ca-bundle.git", + "reference": "f26a67e397be0e5c00d7c52ec7b5010098e15ce5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/ca-bundle/zipball/f26a67e397be0e5c00d7c52ec7b5010098e15ce5", + "reference": "f26a67e397be0e5c00d7c52ec7b5010098e15ce5", + "shasum": "" + }, + "require": { + "ext-openssl": "*", + "ext-pcre": "*", + "php": "^5.3.2 || ^7.0 || ^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35 || ^5.7 || 6.5 - 8", + "psr/log": "^1.0", + "symfony/process": "^2.5 || ^3.0 || ^4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\CaBundle\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "Lets you find a path to the system CA bundle, and includes a fallback to the Mozilla CA bundle.", + "keywords": [ + "cabundle", + "cacert", + "certificate", + "ssl", + "tls" + ], + "time": "2019-08-02T09:05:43+00:00" + }, + { + "name": "doctrine/cache", + "version": "v1.8.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/cache.git", + "reference": "d768d58baee9a4862ca783840eca1b9add7a7f57" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/cache/zipball/d768d58baee9a4862ca783840eca1b9add7a7f57", + "reference": "d768d58baee9a4862ca783840eca1b9add7a7f57", + "shasum": "" + }, + "require": { + "php": "~7.1" + }, + "conflict": { + "doctrine/common": ">2.2,<2.4" + }, + "require-dev": { + "alcaeus/mongo-php-adapter": "^1.1", + "doctrine/coding-standard": "^4.0", + "mongodb/mongodb": "^1.1", + "phpunit/phpunit": "^7.0", + "predis/predis": "~1.0" + }, + "suggest": { + "alcaeus/mongo-php-adapter": "Required to use legacy MongoDB driver" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.8.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Common\\Cache\\": "lib/Doctrine/Common/Cache" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "Caching library offering an object-oriented API for many cache backends", + "homepage": "https://www.doctrine-project.org", + "keywords": [ + "cache", + "caching" + ], + "time": "2018-08-21T18:01:43+00:00" + }, + { + "name": "doctrine/collections", + "version": "v1.6.2", + "source": { + "type": "git", + "url": "https://github.com/doctrine/collections.git", + "reference": "c5e0bc17b1620e97c968ac409acbff28b8b850be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/collections/zipball/c5e0bc17b1620e97c968ac409acbff28b8b850be", + "reference": "c5e0bc17b1620e97c968ac409acbff28b8b850be", + "shasum": "" + }, + "require": { + "php": "^7.1.3" + }, + "require-dev": { + "doctrine/coding-standard": "^6.0", + "phpstan/phpstan-shim": "^0.9.2", + "phpunit/phpunit": "^7.0", + "vimeo/psalm": "^3.2.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.6.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Common\\Collections\\": "lib/Doctrine/Common/Collections" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "PHP Doctrine Collections library that adds additional functionality on top of PHP arrays.", + "homepage": "https://www.doctrine-project.org/projects/collections.html", + "keywords": [ + "array", + "collections", + "iterators", + "php" + ], + "time": "2019-06-09T13:48:14+00:00" + }, + { + "name": "donatj/phpuseragentparser", + "version": "v0.13.0", + "source": { + "type": "git", + "url": "https://github.com/donatj/PhpUserAgent.git", + "reference": "5f2da266d2a386f9b231d4344ae37baf7a467c2d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/donatj/PhpUserAgent/zipball/5f2da266d2a386f9b231d4344ae37baf7a467c2d", + "reference": "5f2da266d2a386f9b231d4344ae37baf7a467c2d", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "require-dev": { + "camspiers/json-pretty": "0.1.*", + "donatj/drop": "*", + "phpunit/phpunit": "~4.8" + }, + "type": "library", + "autoload": { + "files": [ + "src/UserAgentParser.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jesse G. Donat", + "role": "Developer", + "email": "donatj@gmail.com", + "homepage": "http://donatstudios.com" + } + ], + "description": "Lightning fast, minimalist PHP UserAgent string parser.", + "homepage": "http://donatstudios.com/PHP-Parser-HTTP_USER_AGENT", + "keywords": [ + "browser", + "browser detection", + "parser", + "user agent", + "useragent" + ], + "time": "2019-03-08T20:52:23+00:00" + }, + { + "name": "dragonmantank/cron-expression", + "version": "v1.2.1", + "source": { + "type": "git", + "url": "https://github.com/dragonmantank/cron-expression.git", + "reference": "9504fa9ea681b586028adaaa0877db4aecf32bad" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/dragonmantank/cron-expression/zipball/9504fa9ea681b586028adaaa0877db4aecf32bad", + "reference": "9504fa9ea681b586028adaaa0877db4aecf32bad", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "require-dev": { + "phpunit/phpunit": "~4.0|~5.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Cron\\": "src/Cron/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "CRON for PHP: Calculate the next or previous run date and determine if a CRON expression is due", + "keywords": [ + "cron", + "schedule" + ], + "time": "2017-01-23T04:29:33+00:00" + }, + { + "name": "erusev/parsedown", + "version": "1.6.4", + "source": { + "type": "git", + "url": "https://github.com/erusev/parsedown.git", + "reference": "fbe3fe878f4fe69048bb8a52783a09802004f548" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/erusev/parsedown/zipball/fbe3fe878f4fe69048bb8a52783a09802004f548", + "reference": "fbe3fe878f4fe69048bb8a52783a09802004f548", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35" + }, + "type": "library", + "autoload": { + "psr-0": { + "Parsedown": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Emanuil Rusev", + "email": "hello@erusev.com", + "homepage": "http://erusev.com" + } + ], + "description": "Parser for Markdown.", + "homepage": "http://parsedown.org", + "keywords": [ + "markdown", + "parser" + ], + "time": "2017-11-14T20:44:03+00:00" + }, + { + "name": "erusev/parsedown-extra", + "version": "0.7.1", + "source": { + "type": "git", + "url": "https://github.com/erusev/parsedown-extra.git", + "reference": "0db5cce7354e4b76f155d092ab5eb3981c21258c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/erusev/parsedown-extra/zipball/0db5cce7354e4b76f155d092ab5eb3981c21258c", + "reference": "0db5cce7354e4b76f155d092ab5eb3981c21258c", + "shasum": "" + }, + "require": { + "erusev/parsedown": "~1.4" + }, + "type": "library", + "autoload": { + "psr-0": { + "ParsedownExtra": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Emanuil Rusev", + "email": "hello@erusev.com", + "homepage": "http://erusev.com" + } + ], + "description": "An extension of Parsedown that adds support for Markdown Extra.", + "homepage": "https://github.com/erusev/parsedown-extra", + "keywords": [ + "markdown", + "markdown extra", + "parsedown", + "parser" + ], + "time": "2015-11-01T10:19:22+00:00" + }, + { + "name": "filp/whoops", + "version": "2.5.0", + "source": { + "type": "git", + "url": "https://github.com/filp/whoops.git", + "reference": "cde50e6720a39fdacb240159d3eea6865d51fd96" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/filp/whoops/zipball/cde50e6720a39fdacb240159d3eea6865d51fd96", + "reference": "cde50e6720a39fdacb240159d3eea6865d51fd96", + "shasum": "" + }, + "require": { + "php": "^5.5.9 || ^7.0", + "psr/log": "^1.0.1" + }, + "require-dev": { + "mockery/mockery": "^0.9 || ^1.0", + "phpunit/phpunit": "^4.8.35 || ^5.7", + "symfony/var-dumper": "^2.6 || ^3.0 || ^4.0" + }, + "suggest": { + "symfony/var-dumper": "Pretty print complex values better with var-dumper available", + "whoops/soap": "Formats errors as SOAP responses" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.2-dev" + } + }, + "autoload": { + "psr-4": { + "Whoops\\": "src/Whoops/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Filipe Dobreira", + "role": "Developer", + "homepage": "https://github.com/filp" + } + ], + "description": "php error handling for cool kids", + "homepage": "https://filp.github.io/whoops/", + "keywords": [ + "error", + "exception", + "handling", + "library", + "throwable", + "whoops" + ], + "time": "2019-08-07T09:00:00+00:00" + }, + { + "name": "gregwar/cache", + "version": "v1.0.12", + "target-dir": "Gregwar/Cache", + "source": { + "type": "git", + "url": "https://github.com/Gregwar/Cache.git", + "reference": "305d0f5a12c0beecbbd7e1de236f59f39e0c0ac3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Gregwar/Cache/zipball/305d0f5a12c0beecbbd7e1de236f59f39e0c0ac3", + "reference": "305d0f5a12c0beecbbd7e1de236f59f39e0c0ac3", + "shasum": "" + }, + "require": { + "php": ">=5.3" + }, + "type": "library", + "autoload": { + "psr-0": { + "Gregwar\\Cache": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gregwar", + "email": "g.passault@gmail.com" + } + ], + "description": "A lightweight file-system cache system", + "keywords": [ + "cache", + "caching", + "file-system", + "system" + ], + "time": "2016-09-23T08:16:04+00:00" + }, + { + "name": "gregwar/image", + "version": "v2.0.25", + "target-dir": "Gregwar/Image", + "source": { + "type": "git", + "url": "https://github.com/Gregwar/Image.git", + "reference": "03534d5760cbea5c96e6292041ff81a3bb205c36" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Gregwar/Image/zipball/03534d5760cbea5c96e6292041ff81a3bb205c36", + "reference": "03534d5760cbea5c96e6292041ff81a3bb205c36", + "shasum": "" + }, + "require": { + "ext-gd": "*", + "gregwar/cache": "^1.0.6", + "php": "^5.3 || ^7.0" + }, + "require-dev": { + "sllh/php-cs-fixer-styleci-bridge": "~1.0", + "symfony/phpunit-bridge": "^2.7.4 || ^3.0" + }, + "suggest": { + "behat/transliterator": "Transliterator provides ability to set non-latin1 pretty names" + }, + "type": "library", + "autoload": { + "psr-0": { + "Gregwar\\Image": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Grégoire Passault", + "email": "g.passault@gmail.com", + "homepage": "http://www.gregwar.com/" + } + ], + "description": "Image handling", + "homepage": "https://github.com/Gregwar/Image", + "keywords": [ + "gd", + "image" + ], + "time": "2019-03-01T15:55:29+00:00" + }, + { + "name": "guzzlehttp/psr7", + "version": "1.6.1", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "239400de7a173fe9901b9ac7c06497751f00727a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/239400de7a173fe9901b9ac7c06497751f00727a", + "reference": "239400de7a173fe9901b9ac7c06497751f00727a", + "shasum": "" + }, + "require": { + "php": ">=5.4.0", + "psr/http-message": "~1.0", + "ralouphie/getallheaders": "^2.0.5 || ^3.0.0" + }, + "provide": { + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "ext-zlib": "*", + "phpunit/phpunit": "~4.8.36 || ^5.7.27 || ^6.5.8" + }, + "suggest": { + "zendframework/zend-httphandlerrunner": "Emit PSR-7 responses" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.6-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Psr7\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Tobias Schultze", + "homepage": "https://github.com/Tobion" + } + ], + "description": "PSR-7 message implementation that also provides common utility methods", + "keywords": [ + "http", + "message", + "psr-7", + "request", + "response", + "stream", + "uri", + "url" + ], + "time": "2019-07-01T23:21:34+00:00" + }, + { + "name": "kodus/psr7-server", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/kodus/psr7-server.git", + "reference": "dcfd0116451b0f0e7c6b23b831757ed288347278" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/kodus/psr7-server/zipball/dcfd0116451b0f0e7c6b23b831757ed288347278", + "reference": "dcfd0116451b0f0e7c6b23b831757ed288347278", + "shasum": "" + }, + "require": { + "php": "^7.1", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.0" + }, + "replace": { + "nyholm/psr7-server": "^0.3" + }, + "require-dev": { + "nyholm/nsa": "^1.1", + "nyholm/psr7": "^1.0", + "phpunit/phpunit": "^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Nyholm\\Psr7Server\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com" + }, + { + "name": "Martijn van der Ven", + "email": "martijn@vanderven.se" + } + ], + "description": "Helper classes to handle PSR-7 server requests", + "homepage": "http://tnyholm.se", + "keywords": [ + "psr-17", + "psr-7" + ], + "time": "2019-06-17T10:48:13+00:00" + }, + { + "name": "league/climate", + "version": "3.5.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/climate.git", + "reference": "0d2fdbf8829f60f6ba6433df68d6f3fe1271b8e6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/climate/zipball/0d2fdbf8829f60f6ba6433df68d6f3fe1271b8e6", + "reference": "0d2fdbf8829f60f6ba6433df68d6f3fe1271b8e6", + "shasum": "" + }, + "require": { + "php": "^7.1", + "psr/log": "^1.0", + "seld/cli-prompt": "^1.0" + }, + "require-dev": { + "mikey179/vfsstream": "^1.4", + "mockery/mockery": "^1.0", + "phpunit/phpunit": "^5.7.16" + }, + "suggest": { + "ext-mbstring": "If ext-mbstring is not available you MUST install symfony/polyfill-mbstring" + }, + "type": "library", + "autoload": { + "psr-4": { + "League\\CLImate\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Craig Duncan", + "role": "Developer", + "email": "git@duncanc.co.uk", + "homepage": "https://github.com/duncan3dc" + }, + { + "name": "Joe Tannenbaum", + "role": "Developer", + "email": "hey@joe.codes", + "homepage": "http://joe.codes/" + } + ], + "description": "PHP's best friend for the terminal. CLImate allows you to easily output colored text, special formats, and more.", + "keywords": [ + "cli", + "colors", + "command", + "php", + "terminal" + ], + "time": "2019-02-10T18:25:19+00:00" + }, + { + "name": "matthiasmullie/minify", + "version": "1.3.61", + "source": { + "type": "git", + "url": "https://github.com/matthiasmullie/minify.git", + "reference": "d5acb8ce5b6acb7d11bafe97cecc533f6e4fd751" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/matthiasmullie/minify/zipball/d5acb8ce5b6acb7d11bafe97cecc533f6e4fd751", + "reference": "d5acb8ce5b6acb7d11bafe97cecc533f6e4fd751", + "shasum": "" + }, + "require": { + "ext-pcre": "*", + "matthiasmullie/path-converter": "~1.1", + "php": ">=5.3.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "~2.0", + "matthiasmullie/scrapbook": "~1.0", + "phpunit/phpunit": "~4.8" + }, + "suggest": { + "psr/cache-implementation": "Cache implementation to use with Minify::cache" + }, + "bin": [ + "bin/minifycss", + "bin/minifyjs" + ], + "type": "library", + "autoload": { + "psr-4": { + "MatthiasMullie\\Minify\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Matthias Mullie", + "role": "Developer", + "email": "minify@mullie.eu", + "homepage": "http://www.mullie.eu" + } + ], + "description": "CSS & JavaScript minifier, in PHP. Removes whitespace, strips comments, combines files (incl. @import statements and small assets in CSS files), and optimizes/shortens a few common programming patterns.", + "homepage": "http://www.minifier.org", + "keywords": [ + "JS", + "css", + "javascript", + "minifier", + "minify" + ], + "time": "2018-11-26T23:10:39+00:00" + }, + { + "name": "matthiasmullie/path-converter", + "version": "1.1.2", + "source": { + "type": "git", + "url": "https://github.com/matthiasmullie/path-converter.git", + "reference": "5e4b121c8b9f97c80835c1d878b0812ba1d607c9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/matthiasmullie/path-converter/zipball/5e4b121c8b9f97c80835c1d878b0812ba1d607c9", + "reference": "5e4b121c8b9f97c80835c1d878b0812ba1d607c9", + "shasum": "" + }, + "require": { + "ext-pcre": "*", + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.8" + }, + "type": "library", + "autoload": { + "psr-4": { + "MatthiasMullie\\PathConverter\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Matthias Mullie", + "role": "Developer", + "email": "pathconverter@mullie.eu", + "homepage": "http://www.mullie.eu" + } + ], + "description": "Relative path converter", + "homepage": "http://github.com/matthiasmullie/path-converter", + "keywords": [ + "converter", + "path", + "paths", + "relative" + ], + "time": "2018-10-25T15:19:41+00:00" + }, + { + "name": "maximebf/debugbar", + "version": "v1.15.0", + "source": { + "type": "git", + "url": "https://github.com/maximebf/php-debugbar.git", + "reference": "30e7d60937ee5f1320975ca9bc7bcdd44d500f07" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/maximebf/php-debugbar/zipball/30e7d60937ee5f1320975ca9bc7bcdd44d500f07", + "reference": "30e7d60937ee5f1320975ca9bc7bcdd44d500f07", + "shasum": "" + }, + "require": { + "php": ">=5.3.0", + "psr/log": "^1.0", + "symfony/var-dumper": "^2.6|^3.0|^4.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.0|^5.0" + }, + "suggest": { + "kriswallsmith/assetic": "The best way to manage assets", + "monolog/monolog": "Log using Monolog", + "predis/predis": "Redis storage" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.14-dev" + } + }, + "autoload": { + "psr-4": { + "DebugBar\\": "src/DebugBar/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Maxime Bouroumeau-Fuseau", + "email": "maxime.bouroumeau@gmail.com", + "homepage": "http://maximebf.com" + }, + { + "name": "Barry vd. Heuvel", + "email": "barryvdh@gmail.com" + } + ], + "description": "Debug bar in the browser for php application", + "homepage": "https://github.com/maximebf/php-debugbar", + "keywords": [ + "debug", + "debugbar" + ], + "time": "2017-12-15T11:13:46+00:00" + }, + { + "name": "miljar/php-exif", + "version": "v0.6.5", + "source": { + "type": "git", + "url": "https://github.com/PHPExif/php-exif.git", + "reference": "41f23db39d7b48e4af0e134c2e80e577c1782ac9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHPExif/php-exif/zipball/41f23db39d7b48e4af0e134c2e80e577c1782ac9", + "reference": "41f23db39d7b48e4af0e134c2e80e577c1782ac9", + "shasum": "" + }, + "require": { + "php": ">=5.4" + }, + "require-dev": { + "jakub-onderka/php-parallel-lint": "^1.0", + "phpmd/phpmd": "~2.2", + "phpunit/phpunit": ">=4.0 <6.0", + "satooshi/php-coveralls": "~0.6", + "sebastian/phpcpd": "1.4.*@stable", + "squizlabs/php_codesniffer": "1.4.*@stable" + }, + "suggest": { + "ext-exif": "Use exif PHP extension as adapter", + "lib-exiftool": "Use perl lib exiftool as adapter" + }, + "type": "library", + "autoload": { + "psr-0": { + "PHPExif": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Tom Van Herreweghe", + "role": "Developer", + "homepage": "http://theanalogguy.be" + } + ], + "description": "Object-Oriented EXIF parsing", + "keywords": [ + "IPTC", + "exif", + "exiftool", + "jpeg", + "tiff" + ], + "time": "2019-02-11T13:47:52+00:00" + }, + { + "name": "monolog/monolog", + "version": "1.24.0", + "source": { + "type": "git", + "url": "https://github.com/Seldaek/monolog.git", + "reference": "bfc9ebb28f97e7a24c45bdc3f0ff482e47bb0266" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/bfc9ebb28f97e7a24c45bdc3f0ff482e47bb0266", + "reference": "bfc9ebb28f97e7a24c45bdc3f0ff482e47bb0266", + "shasum": "" + }, + "require": { + "php": ">=5.3.0", + "psr/log": "~1.0" + }, + "provide": { + "psr/log-implementation": "1.0.0" + }, + "require-dev": { + "aws/aws-sdk-php": "^2.4.9 || ^3.0", + "doctrine/couchdb": "~1.0@dev", + "graylog2/gelf-php": "~1.0", + "jakub-onderka/php-parallel-lint": "0.9", + "php-amqplib/php-amqplib": "~2.4", + "php-console/php-console": "^3.1.3", + "phpunit/phpunit": "~4.5", + "phpunit/phpunit-mock-objects": "2.3.0", + "ruflin/elastica": ">=0.90 <3.0", + "sentry/sentry": "^0.13", + "swiftmailer/swiftmailer": "^5.3|^6.0" + }, + "suggest": { + "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB", + "doctrine/couchdb": "Allow sending log messages to a CouchDB server", + "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)", + "ext-mongo": "Allow sending log messages to a MongoDB server", + "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", + "mongodb/mongodb": "Allow sending log messages to a MongoDB server via PHP Driver", + "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib", + "php-console/php-console": "Allow sending log messages to Google Chrome", + "rollbar/rollbar": "Allow sending log messages to Rollbar", + "ruflin/elastica": "Allow sending log messages to an Elastic Search server", + "sentry/sentry": "Allow sending log messages to a Sentry server" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Monolog\\": "src/Monolog" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "Sends your logs to files, sockets, inboxes, databases and various web services", + "homepage": "http://github.com/Seldaek/monolog", + "keywords": [ + "log", + "logging", + "psr-3" + ], + "time": "2018-11-05T09:00:11+00:00" + }, + { + "name": "nyholm/psr7", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/Nyholm/psr7.git", + "reference": "701fe7ea8c12c07b985b156d589134d328160cf7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Nyholm/psr7/zipball/701fe7ea8c12c07b985b156d589134d328160cf7", + "reference": "701fe7ea8c12c07b985b156d589134d328160cf7", + "shasum": "" + }, + "require": { + "php": "^7.1", + "php-http/message-factory": "^1.0", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.0" + }, + "provide": { + "psr/http-factory-implementation": "1.0", + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "http-interop/http-factory-tests": "dev-master", + "php-http/psr7-integration-tests": "dev-master", + "phpunit/phpunit": "^7.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "psr-4": { + "Nyholm\\Psr7\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com" + }, + { + "name": "Martijn van der Ven", + "email": "martijn@vanderven.se" + } + ], + "description": "A fast PHP7 implementation of PSR-7", + "homepage": "http://tnyholm.se", + "keywords": [ + "psr-17", + "psr-7" + ], + "time": "2019-02-16T17:20:43+00:00" + }, + { + "name": "phive/twig-extensions-deferred", + "version": "v1.0.2", + "source": { + "type": "git", + "url": "https://github.com/rybakit/twig-deferred-extension.git", + "reference": "5a2426d622afa74034e754ca5ea1d1ff7887627f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/rybakit/twig-deferred-extension/zipball/5a2426d622afa74034e754ca5ea1d1ff7887627f", + "reference": "5a2426d622afa74034e754ca5ea1d1ff7887627f", + "shasum": "" + }, + "require": { + "twig/twig": "~1.18" + }, + "type": "library", + "autoload": { + "psr-4": { + "Phive\\Twig\\Extensions\\Deferred\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Eugene Leonovich", + "email": "gen.work@gmail.com" + } + ], + "description": "An extension for Twig that allows to defer block rendering", + "homepage": "https://github.com/rybakit/twig-extensions-deferred", + "keywords": [ + "defer", + "extension", + "lazy", + "twig" + ], + "time": "2017-03-17T21:39:21+00:00" + }, + { + "name": "php-http/message-factory", + "version": "v1.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-http/message-factory.git", + "reference": "a478cb11f66a6ac48d8954216cfed9aa06a501a1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-http/message-factory/zipball/a478cb11f66a6ac48d8954216cfed9aa06a501a1", + "reference": "a478cb11f66a6ac48d8954216cfed9aa06a501a1", + "shasum": "" + }, + "require": { + "php": ">=5.4", + "psr/http-message": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "psr-4": { + "Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com" + } + ], + "description": "Factory interfaces for PSR-7 HTTP Message", + "homepage": "http://php-http.org", + "keywords": [ + "factory", + "http", + "message", + "stream", + "uri" + ], + "time": "2015-12-19T14:08:53+00:00" + }, + { + "name": "pimple/pimple", + "version": "v3.2.3", + "source": { + "type": "git", + "url": "https://github.com/silexphp/Pimple.git", + "reference": "9e403941ef9d65d20cba7d54e29fe906db42cf32" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/silexphp/Pimple/zipball/9e403941ef9d65d20cba7d54e29fe906db42cf32", + "reference": "9e403941ef9d65d20cba7d54e29fe906db42cf32", + "shasum": "" + }, + "require": { + "php": ">=5.3.0", + "psr/container": "^1.0" + }, + "require-dev": { + "symfony/phpunit-bridge": "^3.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.2.x-dev" + } + }, + "autoload": { + "psr-0": { + "Pimple": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Pimple, a simple Dependency Injection Container", + "homepage": "http://pimple.sensiolabs.org", + "keywords": [ + "container", + "dependency injection" + ], + "time": "2018-01-21T07:42:36+00:00" + }, + { + "name": "psr/cache", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/cache.git", + "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/cache/zipball/d11b50ad223250cf17b86e38383413f5a6764bf8", + "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Cache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for caching libraries", + "keywords": [ + "cache", + "psr", + "psr-6" + ], + "time": "2016-08-06T20:24:11+00:00" + }, + { + "name": "psr/container", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", + "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/b7ce3b176482dbbc1245ebf52b181af44c2cf55f", + "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], + "time": "2017-02-14T16:28:37+00:00" + }, + { + "name": "psr/http-factory", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-factory.git", + "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-factory/zipball/12ac7fcd07e5b077433f5f2bee95b3a771bf61be", + "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be", + "shasum": "" + }, + "require": { + "php": ">=7.0.0", + "psr/http-message": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interfaces for PSR-7 HTTP message factories", + "keywords": [ + "factory", + "http", + "message", + "psr", + "psr-17", + "psr-7", + "request", + "response" + ], + "time": "2019-04-30T12:38:16+00:00" + }, + { + "name": "psr/http-message", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "time": "2016-08-06T14:39:51+00:00" + }, + { + "name": "psr/http-server-handler", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-server-handler.git", + "reference": "aff2f80e33b7f026ec96bb42f63242dc50ffcae7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-server-handler/zipball/aff2f80e33b7f026ec96bb42f63242dc50ffcae7", + "reference": "aff2f80e33b7f026ec96bb42f63242dc50ffcae7", + "shasum": "" + }, + "require": { + "php": ">=7.0", + "psr/http-message": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Server\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP server-side request handler", + "keywords": [ + "handler", + "http", + "http-interop", + "psr", + "psr-15", + "psr-7", + "request", + "response", + "server" + ], + "time": "2018-10-30T16:46:14+00:00" + }, + { + "name": "psr/http-server-middleware", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-server-middleware.git", + "reference": "2296f45510945530b9dceb8bcedb5cb84d40c5f5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-server-middleware/zipball/2296f45510945530b9dceb8bcedb5cb84d40c5f5", + "reference": "2296f45510945530b9dceb8bcedb5cb84d40c5f5", + "shasum": "" + }, + "require": { + "php": ">=7.0", + "psr/http-message": "^1.0", + "psr/http-server-handler": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Server\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP server-side middleware", + "keywords": [ + "http", + "http-interop", + "middleware", + "psr", + "psr-15", + "psr-7", + "request", + "response" + ], + "time": "2018-10-30T17:12:04+00:00" + }, + { + "name": "psr/log", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd", + "reference": "6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "Psr/Log/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "time": "2018-11-20T15:27:04+00:00" + }, + { + "name": "psr/simple-cache", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/simple-cache.git", + "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/simple-cache/zipball/408d5eafb83c57f6365a3ca330ff23aa4a5fa39b", + "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\SimpleCache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interfaces for simple caching", + "keywords": [ + "cache", + "caching", + "psr", + "psr-16", + "simple-cache" + ], + "time": "2017-10-23T01:57:42+00:00" + }, + { + "name": "ralouphie/getallheaders", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/ralouphie/getallheaders.git", + "reference": "120b605dfeb996808c31b6477290a714d356e822" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", + "reference": "120b605dfeb996808c31b6477290a714d356e822", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^5 || ^6.5" + }, + "type": "library", + "autoload": { + "files": [ + "src/getallheaders.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ralph Khattar", + "email": "ralph.khattar@gmail.com" + } + ], + "description": "A polyfill for getallheaders.", + "time": "2019-03-08T08:55:37+00:00" + }, + { + "name": "rockettheme/toolbox", + "version": "1.4.6", + "source": { + "type": "git", + "url": "https://github.com/rockettheme/toolbox.git", + "reference": "e7010c2a956aff241dfa100ab8aef5b6cf83892a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/rockettheme/toolbox/zipball/e7010c2a956aff241dfa100ab8aef5b6cf83892a", + "reference": "e7010c2a956aff241dfa100ab8aef5b6cf83892a", + "shasum": "" + }, + "require": { + "ext-json": "*", + "php": ">=5.4.0", + "pimple/pimple": "~3.0", + "symfony/event-dispatcher": ">2.5", + "symfony/yaml": ">2.5" + }, + "require-dev": { + "phpunit/phpunit": "~6" + }, + "type": "library", + "autoload": { + "psr-4": { + "RocketTheme\\Toolbox\\ArrayTraits\\": "ArrayTraits/src", + "RocketTheme\\Toolbox\\Blueprints\\": "Blueprints/src", + "RocketTheme\\Toolbox\\Compat\\": "Compat/src", + "RocketTheme\\Toolbox\\DI\\": "DI/src", + "RocketTheme\\Toolbox\\Event\\": "Event/src", + "RocketTheme\\Toolbox\\File\\": "File/src", + "RocketTheme\\Toolbox\\ResourceLocator\\": "ResourceLocator/src", + "RocketTheme\\Toolbox\\Session\\": "Session/src", + "RocketTheme\\Toolbox\\StreamWrapper\\": "StreamWrapper/src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "RocketTheme Toolbox Library", + "homepage": "http://www.rockettheme.com", + "keywords": [ + "php", + "rockettheme" + ], + "time": "2019-03-20T19:59:17+00:00" + }, + { + "name": "seld/cli-prompt", + "version": "1.0.3", + "source": { + "type": "git", + "url": "https://github.com/Seldaek/cli-prompt.git", + "reference": "a19a7376a4689d4d94cab66ab4f3c816019ba8dd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Seldaek/cli-prompt/zipball/a19a7376a4689d4d94cab66ab4f3c816019ba8dd", + "reference": "a19a7376a4689d4d94cab66ab4f3c816019ba8dd", + "shasum": "" + }, + "require": { + "php": ">=5.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Seld\\CliPrompt\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be" + } + ], + "description": "Allows you to prompt for user input on the command line, and optionally hide the characters they type", + "keywords": [ + "cli", + "console", + "hidden", + "input", + "prompt" + ], + "time": "2017-03-18T11:32:45+00:00" + }, + { + "name": "symfony/console", + "version": "v4.2.11", + "source": { + "type": "git", + "url": "https://github.com/symfony/console.git", + "reference": "fc2e274aade6567a750551942094b2145ade9b6c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/console/zipball/fc2e274aade6567a750551942094b2145ade9b6c", + "reference": "fc2e274aade6567a750551942094b2145ade9b6c", + "shasum": "" + }, + "require": { + "php": "^7.1.3", + "symfony/contracts": "^1.0", + "symfony/polyfill-mbstring": "~1.0" + }, + "conflict": { + "symfony/dependency-injection": "<3.4", + "symfony/process": "<3.3" + }, + "provide": { + "psr/log-implementation": "1.0" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/config": "~3.4|~4.0", + "symfony/dependency-injection": "~3.4|~4.0", + "symfony/event-dispatcher": "~3.4|~4.0", + "symfony/lock": "~3.4|~4.0", + "symfony/process": "~3.4|~4.0" + }, + "suggest": { + "psr/log": "For using the console logger", + "symfony/event-dispatcher": "", + "symfony/lock": "", + "symfony/process": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.2-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Console\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Console Component", + "homepage": "https://symfony.com", + "time": "2019-07-24T17:13:20+00:00" + }, + { + "name": "symfony/contracts", + "version": "v1.1.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/contracts.git", + "reference": "3f3f796d5f24a098a9da62828b8daa1b11494c1b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/contracts/zipball/3f3f796d5f24a098a9da62828b8daa1b11494c1b", + "reference": "3f3f796d5f24a098a9da62828b8daa1b11494c1b", + "shasum": "" + }, + "require": { + "php": "^7.1.3", + "psr/cache": "^1.0", + "psr/container": "^1.0" + }, + "replace": { + "symfony/cache-contracts": "self.version", + "symfony/event-dispatcher-contracts": "self.version", + "symfony/http-client-contracts": "self.version", + "symfony/service-contracts": "self.version", + "symfony/translation-contracts": "self.version" + }, + "require-dev": { + "symfony/polyfill-intl-idn": "^1.10" + }, + "suggest": { + "psr/event-dispatcher": "When using the EventDispatcher contracts", + "symfony/cache-implementation": "", + "symfony/event-dispatcher-implementation": "", + "symfony/http-client-implementation": "", + "symfony/service-implementation": "", + "symfony/translation-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\": "" + }, + "exclude-from-classmap": [ + "**/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "A set of abstractions extracted out of the Symfony components", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "time": "2019-06-20T06:46:26+00:00" + }, + { + "name": "symfony/event-dispatcher", + "version": "v4.2.11", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher.git", + "reference": "852548c7c704f14d2f6700c8d872a05bd2028732" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/852548c7c704f14d2f6700c8d872a05bd2028732", + "reference": "852548c7c704f14d2f6700c8d872a05bd2028732", + "shasum": "" + }, + "require": { + "php": "^7.1.3", + "symfony/contracts": "^1.0" + }, + "conflict": { + "symfony/dependency-injection": "<3.4" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/config": "~3.4|~4.0", + "symfony/dependency-injection": "~3.4|~4.0", + "symfony/expression-language": "~3.4|~4.0", + "symfony/stopwatch": "~3.4|~4.0" + }, + "suggest": { + "symfony/dependency-injection": "", + "symfony/http-kernel": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.2-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\EventDispatcher\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony EventDispatcher Component", + "homepage": "https://symfony.com", + "time": "2019-06-26T06:46:55+00:00" + }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.12.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "550ebaac289296ce228a706d0867afc34687e3f4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/550ebaac289296ce228a706d0867afc34687e3f4", + "reference": "550ebaac289296ce228a706d0867afc34687e3f4", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.12-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "time": "2019-08-06T08:03:45+00:00" + }, + { + "name": "symfony/polyfill-iconv", + "version": "v1.12.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-iconv.git", + "reference": "685968b11e61a347c18bf25db32effa478be610f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/685968b11e61a347c18bf25db32effa478be610f", + "reference": "685968b11e61a347c18bf25db32effa478be610f", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "suggest": { + "ext-iconv": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.12-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Iconv\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Iconv extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "iconv", + "polyfill", + "portable", + "shim" + ], + "time": "2019-08-06T08:03:45+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.12.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "b42a2f66e8f1b15ccf25652c3424265923eb4f17" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/b42a2f66e8f1b15ccf25652c3424265923eb4f17", + "reference": "b42a2f66e8f1b15ccf25652c3424265923eb4f17", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.12-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "time": "2019-08-06T08:03:45+00:00" + }, + { + "name": "symfony/polyfill-php72", + "version": "v1.12.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php72.git", + "reference": "04ce3335667451138df4307d6a9b61565560199e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/04ce3335667451138df4307d6a9b61565560199e", + "reference": "04ce3335667451138df4307d6a9b61565560199e", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.12-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Php72\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "time": "2019-08-06T08:03:45+00:00" + }, + { + "name": "symfony/polyfill-php73", + "version": "v1.12.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php73.git", + "reference": "2ceb49eaccb9352bff54d22570276bb75ba4a188" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/2ceb49eaccb9352bff54d22570276bb75ba4a188", + "reference": "2ceb49eaccb9352bff54d22570276bb75ba4a188", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.12-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Php73\\": "" + }, + "files": [ + "bootstrap.php" + ], + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "time": "2019-08-06T08:03:45+00:00" + }, + { + "name": "symfony/process", + "version": "v4.2.11", + "source": { + "type": "git", + "url": "https://github.com/symfony/process.git", + "reference": "808a4be7e0dd7fcb6a2b1ed2ba22dd581402c5e2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/process/zipball/808a4be7e0dd7fcb6a2b1ed2ba22dd581402c5e2", + "reference": "808a4be7e0dd7fcb6a2b1ed2ba22dd581402c5e2", + "shasum": "" + }, + "require": { + "php": "^7.1.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.2-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Process\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Process Component", + "homepage": "https://symfony.com", + "time": "2019-05-30T16:06:08+00:00" + }, + { + "name": "symfony/var-dumper", + "version": "v4.2.11", + "source": { + "type": "git", + "url": "https://github.com/symfony/var-dumper.git", + "reference": "4e18e041a477edbb8c54e053f179672f9413816c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/4e18e041a477edbb8c54e053f179672f9413816c", + "reference": "4e18e041a477edbb8c54e053f179672f9413816c", + "shasum": "" + }, + "require": { + "php": "^7.1.3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php72": "~1.5" + }, + "conflict": { + "phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0", + "symfony/console": "<3.4" + }, + "require-dev": { + "ext-iconv": "*", + "symfony/console": "~3.4|~4.0", + "symfony/process": "~3.4|~4.0", + "twig/twig": "~1.34|~2.4" + }, + "suggest": { + "ext-iconv": "To convert non-UTF-8 strings to UTF-8 (or symfony/polyfill-iconv in case ext-iconv cannot be used).", + "ext-intl": "To show region name in time zone dump", + "symfony/console": "To use the ServerDumpCommand and/or the bin/var-dump-server script" + }, + "bin": [ + "Resources/bin/var-dump-server" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.2-dev" + } + }, + "autoload": { + "files": [ + "Resources/functions/dump.php" + ], + "psr-4": { + "Symfony\\Component\\VarDumper\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony mechanism for exploring and dumping PHP variables", + "homepage": "https://symfony.com", + "keywords": [ + "debug", + "dump" + ], + "time": "2019-07-27T06:42:33+00:00" + }, + { + "name": "symfony/yaml", + "version": "v4.2.11", + "source": { + "type": "git", + "url": "https://github.com/symfony/yaml.git", + "reference": "9468fef6f1c740b96935e9578560a9e9189ca154" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/yaml/zipball/9468fef6f1c740b96935e9578560a9e9189ca154", + "reference": "9468fef6f1c740b96935e9578560a9e9189ca154", + "shasum": "" + }, + "require": { + "php": "^7.1.3", + "symfony/polyfill-ctype": "~1.8" + }, + "conflict": { + "symfony/console": "<3.4" + }, + "require-dev": { + "symfony/console": "~3.4|~4.0" + }, + "suggest": { + "symfony/console": "For validating YAML files using the lint command" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.2-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Yaml\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Yaml Component", + "homepage": "https://symfony.com", + "time": "2019-07-24T14:47:26+00:00" + }, + { + "name": "twig/twig", + "version": "v1.42.2", + "source": { + "type": "git", + "url": "https://github.com/twigphp/Twig.git", + "reference": "21707d6ebd05476854805e4f91b836531941bcd4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/21707d6ebd05476854805e4f91b836531941bcd4", + "reference": "21707d6ebd05476854805e4f91b836531941bcd4", + "shasum": "" + }, + "require": { + "php": ">=5.4.0", + "symfony/polyfill-ctype": "^1.8" + }, + "require-dev": { + "psr/container": "^1.0", + "symfony/debug": "^2.7", + "symfony/phpunit-bridge": "^3.4.19|^4.1.8|^5.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.42-dev" + } + }, + "autoload": { + "psr-0": { + "Twig_": "lib/" + }, + "psr-4": { + "Twig\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Fabien Potencier", + "role": "Lead Developer", + "email": "fabien@symfony.com", + "homepage": "http://fabien.potencier.org" + }, + { + "name": "Armin Ronacher", + "role": "Project Founder", + "email": "armin.ronacher@active-4.com" + }, + { + "name": "Twig Team", + "role": "Contributors", + "homepage": "https://twig.symfony.com/contributors" + } + ], + "description": "Twig, the flexible, fast, and secure template language for PHP", + "homepage": "https://twig.symfony.com", + "keywords": [ + "templating" + ], + "time": "2019-06-18T15:35:16+00:00" + }, + { + "name": "willdurand/negotiation", + "version": "v2.3.1", + "source": { + "type": "git", + "url": "https://github.com/willdurand/Negotiation.git", + "reference": "03436ededa67c6e83b9b12defac15384cb399dc9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/willdurand/Negotiation/zipball/03436ededa67c6e83b9b12defac15384cb399dc9", + "reference": "03436ededa67c6e83b9b12defac15384cb399dc9", + "shasum": "" + }, + "require": { + "php": ">=5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.3-dev" + } + }, + "autoload": { + "psr-4": { + "Negotiation\\": "src/Negotiation" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "William Durand", + "email": "will+git@drnd.me" + } + ], + "description": "Content Negotiation tools for PHP provided as a standalone library.", + "homepage": "http://williamdurand.fr/Negotiation/", + "keywords": [ + "accept", + "content", + "format", + "header", + "negotiation" + ], + "time": "2017-05-14T17:21:12+00:00" + } + ], + "packages-dev": [ + { + "name": "behat/gherkin", + "version": "v4.6.0", + "source": { + "type": "git", + "url": "https://github.com/Behat/Gherkin.git", + "reference": "ab0a02ea14893860bca00f225f5621d351a3ad07" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Behat/Gherkin/zipball/ab0a02ea14893860bca00f225f5621d351a3ad07", + "reference": "ab0a02ea14893860bca00f225f5621d351a3ad07", + "shasum": "" + }, + "require": { + "php": ">=5.3.1" + }, + "require-dev": { + "phpunit/phpunit": "~4.5|~5", + "symfony/phpunit-bridge": "~2.7|~3|~4", + "symfony/yaml": "~2.3|~3|~4" + }, + "suggest": { + "symfony/yaml": "If you want to parse features, represented in YAML files" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.4-dev" + } + }, + "autoload": { + "psr-0": { + "Behat\\Gherkin": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Konstantin Kudryashov", + "email": "ever.zet@gmail.com", + "homepage": "http://everzet.com" + } + ], + "description": "Gherkin DSL parser for PHP 5.3", + "homepage": "http://behat.org/", + "keywords": [ + "BDD", + "Behat", + "Cucumber", + "DSL", + "gherkin", + "parser" + ], + "time": "2019-01-16T14:22:17+00:00" + }, + { + "name": "codeception/codeception", + "version": "2.5.6", + "source": { + "type": "git", + "url": "https://github.com/Codeception/Codeception.git", + "reference": "b83a9338296e706fab2ceb49de8a352fbca3dc98" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Codeception/Codeception/zipball/b83a9338296e706fab2ceb49de8a352fbca3dc98", + "reference": "b83a9338296e706fab2ceb49de8a352fbca3dc98", + "shasum": "" + }, + "require": { + "behat/gherkin": "^4.4.0", + "codeception/phpunit-wrapper": "^6.0.9|^7.0.6", + "codeception/stub": "^2.0", + "ext-curl": "*", + "ext-json": "*", + "ext-mbstring": "*", + "facebook/webdriver": ">=1.1.3 <2.0", + "guzzlehttp/guzzle": ">=4.1.4 <7.0", + "guzzlehttp/psr7": "~1.0", + "php": ">=5.6.0 <8.0", + "symfony/browser-kit": ">=2.7 <5.0", + "symfony/console": ">=2.7 <5.0", + "symfony/css-selector": ">=2.7 <5.0", + "symfony/dom-crawler": ">=2.7 <5.0", + "symfony/event-dispatcher": ">=2.7 <5.0", + "symfony/finder": ">=2.7 <5.0", + "symfony/yaml": ">=2.7 <5.0" + }, + "require-dev": { + "codeception/specify": "~0.3", + "facebook/graph-sdk": "~5.3", + "flow/jsonpath": "~0.2", + "monolog/monolog": "~1.8", + "pda/pheanstalk": "~3.0", + "php-amqplib/php-amqplib": "~2.4", + "predis/predis": "^1.0", + "squizlabs/php_codesniffer": "~2.0", + "symfony/process": ">=2.7 <5.0", + "vlucas/phpdotenv": "^3.0" + }, + "suggest": { + "aws/aws-sdk-php": "For using AWS Auth in REST module and Queue module", + "codeception/phpbuiltinserver": "Start and stop PHP built-in web server for your tests", + "codeception/specify": "BDD-style code blocks", + "codeception/verify": "BDD-style assertions", + "flow/jsonpath": "For using JSONPath in REST module", + "league/factory-muffin": "For DataFactory module", + "league/factory-muffin-faker": "For Faker support in DataFactory module", + "phpseclib/phpseclib": "for SFTP option in FTP Module", + "stecman/symfony-console-completion": "For BASH autocompletion", + "symfony/phpunit-bridge": "For phpunit-bridge support" + }, + "bin": [ + "codecept" + ], + "type": "library", + "extra": { + "branch-alias": [] + }, + "autoload": { + "psr-4": { + "Codeception\\": "src/Codeception", + "Codeception\\Extension\\": "ext" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Bodnarchuk", + "email": "davert@mail.ua", + "homepage": "http://codegyre.com" + } + ], + "description": "BDD-style testing framework", + "homepage": "http://codeception.com/", + "keywords": [ + "BDD", + "TDD", + "acceptance testing", + "functional testing", + "unit testing" + ], + "time": "2019-04-24T11:28:19+00:00" + }, + { + "name": "codeception/phpunit-wrapper", + "version": "7.7.1", + "source": { + "type": "git", + "url": "https://github.com/Codeception/phpunit-wrapper.git", + "reference": "ab04a956264291505ea84998f43cf91639b4575d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Codeception/phpunit-wrapper/zipball/ab04a956264291505ea84998f43cf91639b4575d", + "reference": "ab04a956264291505ea84998f43cf91639b4575d", + "shasum": "" + }, + "require": { + "phpunit/php-code-coverage": "^6.0", + "phpunit/phpunit": "7.5.*", + "sebastian/comparator": "^3.0", + "sebastian/diff": "^3.0" + }, + "require-dev": { + "codeception/specify": "*", + "vlucas/phpdotenv": "^3.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Codeception\\PHPUnit\\": "src\\" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Davert", + "email": "davert.php@resend.cc" + } + ], + "description": "PHPUnit classes used by Codeception", + "time": "2019-02-26T20:35:32+00:00" + }, + { + "name": "codeception/stub", + "version": "2.1.0", + "source": { + "type": "git", + "url": "https://github.com/Codeception/Stub.git", + "reference": "853657f988942f7afb69becf3fd0059f192c705a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Codeception/Stub/zipball/853657f988942f7afb69becf3fd0059f192c705a", + "reference": "853657f988942f7afb69becf3fd0059f192c705a", + "shasum": "" + }, + "require": { + "codeception/phpunit-wrapper": ">6.0.15 <6.1.0 | ^6.6.1 | ^7.7.1 | ^8.0.3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Codeception\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Flexible Stub wrapper for PHPUnit's Mock Builder", + "time": "2019-03-02T15:35:10+00:00" + }, + { + "name": "composer/xdebug-handler", + "version": "1.3.3", + "source": { + "type": "git", + "url": "https://github.com/composer/xdebug-handler.git", + "reference": "46867cbf8ca9fb8d60c506895449eb799db1184f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/46867cbf8ca9fb8d60c506895449eb799db1184f", + "reference": "46867cbf8ca9fb8d60c506895449eb799db1184f", + "shasum": "" + }, + "require": { + "php": "^5.3.2 || ^7.0", + "psr/log": "^1.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "Composer\\XdebugHandler\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "John Stevenson", + "email": "john-stevenson@blueyonder.co.uk" + } + ], + "description": "Restarts a process without xdebug.", + "keywords": [ + "Xdebug", + "performance" + ], + "time": "2019-05-27T17:52:04+00:00" + }, + { + "name": "doctrine/instantiator", + "version": "1.2.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/instantiator.git", + "reference": "a2c590166b2133a4633738648b6b064edae0814a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/a2c590166b2133a4633738648b6b064edae0814a", + "reference": "a2c590166b2133a4633738648b6b064edae0814a", + "shasum": "" + }, + "require": { + "php": "^7.1" + }, + "require-dev": { + "doctrine/coding-standard": "^6.0", + "ext-pdo": "*", + "ext-phar": "*", + "phpbench/phpbench": "^0.13", + "phpstan/phpstan-phpunit": "^0.11", + "phpstan/phpstan-shim": "^0.11", + "phpunit/phpunit": "^7.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com", + "homepage": "http://ocramius.github.com/" + } + ], + "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", + "homepage": "https://www.doctrine-project.org/projects/instantiator.html", + "keywords": [ + "constructor", + "instantiate" + ], + "time": "2019-03-17T17:37:11+00:00" + }, + { + "name": "facebook/webdriver", + "version": "1.7.1", + "source": { + "type": "git", + "url": "https://github.com/facebook/php-webdriver.git", + "reference": "e43de70f3c7166169d0f14a374505392734160e5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/facebook/php-webdriver/zipball/e43de70f3c7166169d0f14a374505392734160e5", + "reference": "e43de70f3c7166169d0f14a374505392734160e5", + "shasum": "" + }, + "require": { + "ext-curl": "*", + "ext-json": "*", + "ext-mbstring": "*", + "ext-zip": "*", + "php": "^5.6 || ~7.0", + "symfony/process": "^2.8 || ^3.1 || ^4.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^2.0", + "jakub-onderka/php-parallel-lint": "^0.9.2", + "php-coveralls/php-coveralls": "^2.0", + "php-mock/php-mock-phpunit": "^1.1", + "phpunit/phpunit": "^5.7", + "sebastian/environment": "^1.3.4 || ^2.0 || ^3.0", + "squizlabs/php_codesniffer": "^2.6", + "symfony/var-dumper": "^3.3 || ^4.0" + }, + "suggest": { + "ext-SimpleXML": "For Firefox profile creation" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-community": "1.5-dev" + } + }, + "autoload": { + "psr-4": { + "Facebook\\WebDriver\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "description": "A PHP client for Selenium WebDriver", + "homepage": "https://github.com/facebook/php-webdriver", + "keywords": [ + "facebook", + "php", + "selenium", + "webdriver" + ], + "time": "2019-06-13T08:02:18+00:00" + }, + { + "name": "fzaninotto/faker", + "version": "v1.8.0", + "source": { + "type": "git", + "url": "https://github.com/fzaninotto/Faker.git", + "reference": "f72816b43e74063c8b10357394b6bba8cb1c10de" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/fzaninotto/Faker/zipball/f72816b43e74063c8b10357394b6bba8cb1c10de", + "reference": "f72816b43e74063c8b10357394b6bba8cb1c10de", + "shasum": "" + }, + "require": { + "php": "^5.3.3 || ^7.0" + }, + "require-dev": { + "ext-intl": "*", + "phpunit/phpunit": "^4.8.35 || ^5.7", + "squizlabs/php_codesniffer": "^1.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.8-dev" + } + }, + "autoload": { + "psr-4": { + "Faker\\": "src/Faker/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "François Zaninotto" + } + ], + "description": "Faker is a PHP library that generates fake data for you.", + "keywords": [ + "data", + "faker", + "fixtures" + ], + "time": "2018-07-12T10:23:15+00:00" + }, + { + "name": "guzzlehttp/guzzle", + "version": "6.3.3", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle.git", + "reference": "407b0cb880ace85c9b63c5f9551db498cb2d50ba" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/407b0cb880ace85c9b63c5f9551db498cb2d50ba", + "reference": "407b0cb880ace85c9b63c5f9551db498cb2d50ba", + "shasum": "" + }, + "require": { + "guzzlehttp/promises": "^1.0", + "guzzlehttp/psr7": "^1.4", + "php": ">=5.5" + }, + "require-dev": { + "ext-curl": "*", + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.4 || ^7.0", + "psr/log": "^1.0" + }, + "suggest": { + "psr/log": "Required for using the Log middleware" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "6.3-dev" + } + }, + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "GuzzleHttp\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Guzzle is a PHP HTTP client library", + "homepage": "http://guzzlephp.org/", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "rest", + "web service" + ], + "time": "2018-04-22T15:46:56+00:00" + }, + { + "name": "guzzlehttp/promises", + "version": "v1.3.1", + "source": { + "type": "git", + "url": "https://github.com/guzzle/promises.git", + "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/promises/zipball/a59da6cf61d80060647ff4d3eb2c03a2bc694646", + "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646", + "shasum": "" + }, + "require": { + "php": ">=5.5.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Promise\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Guzzle promises library", + "keywords": [ + "promise" + ], + "time": "2016-12-20T10:07:11+00:00" + }, + { + "name": "jean85/pretty-package-versions", + "version": "1.2", + "source": { + "type": "git", + "url": "https://github.com/Jean85/pretty-package-versions.git", + "reference": "75c7effcf3f77501d0e0caa75111aff4daa0dd48" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Jean85/pretty-package-versions/zipball/75c7effcf3f77501d0e0caa75111aff4daa0dd48", + "reference": "75c7effcf3f77501d0e0caa75111aff4daa0dd48", + "shasum": "" + }, + "require": { + "ocramius/package-versions": "^1.2.0", + "php": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Jean85\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Alessandro Lai", + "email": "alessandro.lai85@gmail.com" + } + ], + "description": "A wrapper for ocramius/package-versions to get pretty versions strings", + "keywords": [ + "composer", + "package", + "release", + "versions" + ], + "time": "2018-06-13T13:22:40+00:00" + }, + { + "name": "myclabs/deep-copy", + "version": "1.9.3", + "source": { + "type": "git", + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "007c053ae6f31bba39dfa19a7726f56e9763bbea" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/007c053ae6f31bba39dfa19a7726f56e9763bbea", + "reference": "007c053ae6f31bba39dfa19a7726f56e9763bbea", + "shasum": "" + }, + "require": { + "php": "^7.1" + }, + "replace": { + "myclabs/deep-copy": "self.version" + }, + "require-dev": { + "doctrine/collections": "^1.0", + "doctrine/common": "^2.6", + "phpunit/phpunit": "^7.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + }, + "files": [ + "src/DeepCopy/deep_copy.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Create deep copies (clones) of your objects", + "keywords": [ + "clone", + "copy", + "duplicate", + "object", + "object graph" + ], + "time": "2019-08-09T12:45:53+00:00" + }, + { + "name": "nette/bootstrap", + "version": "v3.0.0", + "source": { + "type": "git", + "url": "https://github.com/nette/bootstrap.git", + "reference": "e1075af05c211915e03e0c86542f3ba5433df4a3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/bootstrap/zipball/e1075af05c211915e03e0c86542f3ba5433df4a3", + "reference": "e1075af05c211915e03e0c86542f3ba5433df4a3", + "shasum": "" + }, + "require": { + "nette/di": "^3.0", + "nette/utils": "^3.0", + "php": ">=7.1" + }, + "require-dev": { + "latte/latte": "^2.2", + "nette/application": "^3.0", + "nette/caching": "^3.0", + "nette/database": "^3.0", + "nette/forms": "^3.0", + "nette/http": "^3.0", + "nette/mail": "^3.0", + "nette/robot-loader": "^3.0", + "nette/safe-stream": "^2.2", + "nette/security": "^3.0", + "nette/tester": "^2.0", + "tracy/tracy": "^2.6" + }, + "suggest": { + "nette/robot-loader": "to use Configurator::createRobotLoader()", + "tracy/tracy": "to use Configurator::enableTracy()" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0", + "GPL-3.0" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "🅱 Nette Bootstrap: the simple way to configure and bootstrap your Nette application.", + "homepage": "https://nette.org", + "keywords": [ + "bootstrapping", + "configurator", + "nette" + ], + "time": "2019-03-26T12:59:07+00:00" + }, + { + "name": "nette/di", + "version": "v3.0.1", + "source": { + "type": "git", + "url": "https://github.com/nette/di.git", + "reference": "4aff517a1c6bb5c36fa09733d4cea089f529de6d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/di/zipball/4aff517a1c6bb5c36fa09733d4cea089f529de6d", + "reference": "4aff517a1c6bb5c36fa09733d4cea089f529de6d", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "nette/neon": "^3.0", + "nette/php-generator": "^3.2.2", + "nette/robot-loader": "^3.2", + "nette/schema": "^1.0", + "nette/utils": "^3.0", + "php": ">=7.1" + }, + "conflict": { + "nette/bootstrap": "<3.0" + }, + "require-dev": { + "nette/tester": "^2.2", + "tracy/tracy": "^2.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ], + "files": [ + "src/compatibility.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0", + "GPL-3.0" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "💎 Nette Dependency Injection Container: Flexible, compiled and full-featured DIC with perfectly usable autowiring and support for all new PHP 7.1 features.", + "homepage": "https://nette.org", + "keywords": [ + "compiled", + "di", + "dic", + "factory", + "ioc", + "nette", + "static" + ], + "time": "2019-08-07T12:11:33+00:00" + }, + { + "name": "nette/finder", + "version": "v2.5.0", + "source": { + "type": "git", + "url": "https://github.com/nette/finder.git", + "reference": "6be1b83ea68ac558aff189d640abe242e0306fe2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/finder/zipball/6be1b83ea68ac558aff189d640abe242e0306fe2", + "reference": "6be1b83ea68ac558aff189d640abe242e0306fe2", + "shasum": "" + }, + "require": { + "nette/utils": "^2.4 || ~3.0.0", + "php": ">=7.1" + }, + "conflict": { + "nette/nette": "<2.2" + }, + "require-dev": { + "nette/tester": "^2.0", + "tracy/tracy": "^2.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.5-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0", + "GPL-3.0" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "? Nette Finder: find files and directories with an intuitive API.", + "homepage": "https://nette.org", + "keywords": [ + "filesystem", + "glob", + "iterator", + "nette" + ], + "time": "2019-02-28T18:13:25+00:00" + }, + { + "name": "nette/neon", + "version": "v3.0.0", + "source": { + "type": "git", + "url": "https://github.com/nette/neon.git", + "reference": "cbff32059cbdd8720deccf9e9eace6ee516f02eb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/neon/zipball/cbff32059cbdd8720deccf9e9eace6ee516f02eb", + "reference": "cbff32059cbdd8720deccf9e9eace6ee516f02eb", + "shasum": "" + }, + "require": { + "ext-iconv": "*", + "ext-json": "*", + "php": ">=7.0" + }, + "require-dev": { + "nette/tester": "^2.0", + "tracy/tracy": "^2.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0", + "GPL-3.0" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "? Nette NEON: encodes and decodes NEON file format.", + "homepage": "http://ne-on.org", + "keywords": [ + "export", + "import", + "neon", + "nette", + "yaml" + ], + "time": "2019-02-05T21:30:40+00:00" + }, + { + "name": "nette/php-generator", + "version": "v3.2.3", + "source": { + "type": "git", + "url": "https://github.com/nette/php-generator.git", + "reference": "aea6e81437bb238e5f0e5b5ce06337433908e63b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/php-generator/zipball/aea6e81437bb238e5f0e5b5ce06337433908e63b", + "reference": "aea6e81437bb238e5f0e5b5ce06337433908e63b", + "shasum": "" + }, + "require": { + "nette/utils": "^2.4.2 || ~3.0.0", + "php": ">=7.1" + }, + "require-dev": { + "nette/tester": "^2.0", + "tracy/tracy": "^2.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.2-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0", + "GPL-3.0" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "🐘 Nette PHP Generator: generates neat PHP code for you. Supports new PHP 7.3 features.", + "homepage": "https://nette.org", + "keywords": [ + "code", + "nette", + "php", + "scaffolding" + ], + "time": "2019-07-05T13:01:56+00:00" + }, + { + "name": "nette/robot-loader", + "version": "v3.2.0", + "source": { + "type": "git", + "url": "https://github.com/nette/robot-loader.git", + "reference": "0712a0e39ae7956d6a94c0ab6ad41aa842544b5c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/robot-loader/zipball/0712a0e39ae7956d6a94c0ab6ad41aa842544b5c", + "reference": "0712a0e39ae7956d6a94c0ab6ad41aa842544b5c", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "nette/finder": "^2.5", + "nette/utils": "^3.0", + "php": ">=7.1" + }, + "require-dev": { + "nette/tester": "^2.0", + "tracy/tracy": "^2.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.2-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0", + "GPL-3.0" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "? Nette RobotLoader: high performance and comfortable autoloader that will search and autoload classes within your application.", + "homepage": "https://nette.org", + "keywords": [ + "autoload", + "class", + "interface", + "nette", + "trait" + ], + "time": "2019-03-08T21:57:24+00:00" + }, + { + "name": "nette/schema", + "version": "v1.0.0", + "source": { + "type": "git", + "url": "https://github.com/nette/schema.git", + "reference": "6241d8d4da39e825dd6cb5bfbe4242912f4d7e4d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/schema/zipball/6241d8d4da39e825dd6cb5bfbe4242912f4d7e4d", + "reference": "6241d8d4da39e825dd6cb5bfbe4242912f4d7e4d", + "shasum": "" + }, + "require": { + "nette/utils": "^3.0.1", + "php": ">=7.1" + }, + "require-dev": { + "nette/tester": "^2.2", + "tracy/tracy": "^2.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0", + "GPL-3.0" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "📐 Nette Schema: validating data structures against a given Schema.", + "homepage": "https://nette.org", + "keywords": [ + "config", + "nette" + ], + "time": "2019-04-03T15:53:25+00:00" + }, + { + "name": "nette/utils", + "version": "v3.0.1", + "source": { + "type": "git", + "url": "https://github.com/nette/utils.git", + "reference": "bd961f49b211997202bda1d0fbc410905be370d4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/utils/zipball/bd961f49b211997202bda1d0fbc410905be370d4", + "reference": "bd961f49b211997202bda1d0fbc410905be370d4", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "require-dev": { + "nette/tester": "~2.0", + "tracy/tracy": "^2.3" + }, + "suggest": { + "ext-gd": "to use Image", + "ext-iconv": "to use Strings::webalize() and toAscii()", + "ext-intl": "to use Strings::webalize(), toAscii(), normalize() and compare()", + "ext-json": "to use Nette\\Utils\\Json", + "ext-mbstring": "to use Strings::lower() etc...", + "ext-xml": "to use Strings::length() etc. when mbstring is not available" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0", + "GPL-3.0" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "🛠 Nette Utils: lightweight utilities for string & array manipulation, image handling, safe JSON encoding/decoding, validation, slug or strong password generating etc.", + "homepage": "https://nette.org", + "keywords": [ + "array", + "core", + "datetime", + "images", + "json", + "nette", + "paginator", + "password", + "slugify", + "string", + "unicode", + "utf-8", + "utility", + "validation" + ], + "time": "2019-03-22T01:00:30+00:00" + }, + { + "name": "nikic/php-parser", + "version": "v4.2.3", + "source": { + "type": "git", + "url": "https://github.com/nikic/PHP-Parser.git", + "reference": "e612609022e935f3d0337c1295176505b41188c8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/e612609022e935f3d0337c1295176505b41188c8", + "reference": "e612609022e935f3d0337c1295176505b41188c8", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=7.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0" + }, + "bin": [ + "bin/php-parse" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.2-dev" + } + }, + "autoload": { + "psr-4": { + "PhpParser\\": "lib/PhpParser" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Nikita Popov" + } + ], + "description": "A PHP parser written in PHP", + "keywords": [ + "parser", + "php" + ], + "time": "2019-08-12T20:17:41+00:00" + }, + { + "name": "ocramius/package-versions", + "version": "1.4.0", + "source": { + "type": "git", + "url": "https://github.com/Ocramius/PackageVersions.git", + "reference": "a4d4b60d0e60da2487bd21a2c6ac089f85570dbb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Ocramius/PackageVersions/zipball/a4d4b60d0e60da2487bd21a2c6ac089f85570dbb", + "reference": "a4d4b60d0e60da2487bd21a2c6ac089f85570dbb", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^1.0.0", + "php": "^7.1.0" + }, + "require-dev": { + "composer/composer": "^1.6.3", + "doctrine/coding-standard": "^5.0.1", + "ext-zip": "*", + "infection/infection": "^0.7.1", + "phpunit/phpunit": "^7.0.0" + }, + "type": "composer-plugin", + "extra": { + "class": "PackageVersions\\Installer", + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "PackageVersions\\": "src/PackageVersions" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com" + } + ], + "description": "Composer plugin that provides efficient querying for installed package versions (no runtime IO)", + "time": "2019-02-21T12:16:21+00:00" + }, + { + "name": "phar-io/manifest", + "version": "1.0.3", + "source": { + "type": "git", + "url": "https://github.com/phar-io/manifest.git", + "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/7761fcacf03b4d4f16e7ccb606d4879ca431fcf4", + "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-phar": "*", + "phar-io/version": "^2.0", + "php": "^5.6 || ^7.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "role": "Developer", + "email": "arne@blankerts.de" + }, + { + "name": "Sebastian Heuer", + "role": "Developer", + "email": "sebastian@phpeople.de" + }, + { + "name": "Sebastian Bergmann", + "role": "Developer", + "email": "sebastian@phpunit.de" + } + ], + "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", + "time": "2018-07-08T19:23:20+00:00" + }, + { + "name": "phar-io/version", + "version": "2.0.1", + "source": { + "type": "git", + "url": "https://github.com/phar-io/version.git", + "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/version/zipball/45a2ec53a73c70ce41d55cedef9063630abaf1b6", + "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "role": "Developer", + "email": "arne@blankerts.de" + }, + { + "name": "Sebastian Heuer", + "role": "Developer", + "email": "sebastian@phpeople.de" + }, + { + "name": "Sebastian Bergmann", + "role": "Developer", + "email": "sebastian@phpunit.de" + } + ], + "description": "Library for handling version information and constraints", + "time": "2018-07-08T19:19:57+00:00" + }, + { + "name": "phpdocumentor/reflection-common", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionCommon.git", + "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6", + "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6", + "shasum": "" + }, + "require": { + "php": ">=5.5" + }, + "require-dev": { + "phpunit/phpunit": "^4.6" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": [ + "src" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jaap van Otterdijk", + "email": "opensource@ijaap.nl" + } + ], + "description": "Common reflection classes used by phpdocumentor to reflect the code structure", + "homepage": "http://www.phpdoc.org", + "keywords": [ + "FQSEN", + "phpDocumentor", + "phpdoc", + "reflection", + "static analysis" + ], + "time": "2017-09-11T18:02:19+00:00" + }, + { + "name": "phpdocumentor/reflection-docblock", + "version": "4.3.1", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", + "reference": "bdd9f737ebc2a01c06ea7ff4308ec6697db9b53c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/bdd9f737ebc2a01c06ea7ff4308ec6697db9b53c", + "reference": "bdd9f737ebc2a01c06ea7ff4308ec6697db9b53c", + "shasum": "" + }, + "require": { + "php": "^7.0", + "phpdocumentor/reflection-common": "^1.0.0", + "phpdocumentor/type-resolver": "^0.4.0", + "webmozart/assert": "^1.0" + }, + "require-dev": { + "doctrine/instantiator": "~1.0.5", + "mockery/mockery": "^1.0", + "phpunit/phpunit": "^6.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + } + ], + "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", + "time": "2019-04-30T17:48:53+00:00" + }, + { + "name": "phpdocumentor/type-resolver", + "version": "0.4.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/TypeResolver.git", + "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/9c977708995954784726e25d0cd1dddf4e65b0f7", + "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7", + "shasum": "" + }, + "require": { + "php": "^5.5 || ^7.0", + "phpdocumentor/reflection-common": "^1.0" + }, + "require-dev": { + "mockery/mockery": "^0.9.4", + "phpunit/phpunit": "^5.2||^4.8.24" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + } + ], + "time": "2017-07-14T14:27:02+00:00" + }, + { + "name": "phpspec/prophecy", + "version": "1.8.1", + "source": { + "type": "git", + "url": "https://github.com/phpspec/prophecy.git", + "reference": "1927e75f4ed19131ec9bcc3b002e07fb1173ee76" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/1927e75f4ed19131ec9bcc3b002e07fb1173ee76", + "reference": "1927e75f4ed19131ec9bcc3b002e07fb1173ee76", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.0.2", + "php": "^5.3|^7.0", + "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0", + "sebastian/comparator": "^1.1|^2.0|^3.0", + "sebastian/recursion-context": "^1.0|^2.0|^3.0" + }, + "require-dev": { + "phpspec/phpspec": "^2.5|^3.2", + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5 || ^7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.8.x-dev" + } + }, + "autoload": { + "psr-4": { + "Prophecy\\": "src/Prophecy" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Konstantin Kudryashov", + "email": "ever.zet@gmail.com", + "homepage": "http://everzet.com" + }, + { + "name": "Marcello Duarte", + "email": "marcello.duarte@gmail.com" + } + ], + "description": "Highly opinionated mocking framework for PHP 5.3+", + "homepage": "https://github.com/phpspec/prophecy", + "keywords": [ + "Double", + "Dummy", + "fake", + "mock", + "spy", + "stub" + ], + "time": "2019-06-13T12:50:23+00:00" + }, + { + "name": "phpstan/phpdoc-parser", + "version": "0.3.5", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpdoc-parser.git", + "reference": "8c4ef2aefd9788238897b678a985e1d5c8df6db4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/8c4ef2aefd9788238897b678a985e1d5c8df6db4", + "reference": "8c4ef2aefd9788238897b678a985e1d5c8df6db4", + "shasum": "" + }, + "require": { + "php": "~7.1" + }, + "require-dev": { + "consistence/coding-standard": "^3.5", + "jakub-onderka/php-parallel-lint": "^0.9.2", + "phing/phing": "^2.16.0", + "phpstan/phpstan": "^0.10", + "phpunit/phpunit": "^6.3", + "slevomat/coding-standard": "^4.7.2", + "squizlabs/php_codesniffer": "^3.3.2", + "symfony/process": "^3.4 || ^4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "0.3-dev" + } + }, + "autoload": { + "psr-4": { + "PHPStan\\PhpDocParser\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPDoc parser with support for nullable, intersection and generic types", + "time": "2019-06-07T19:13:52+00:00" + }, + { + "name": "phpstan/phpstan", + "version": "0.11.15", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpstan.git", + "reference": "1be5b3a706db16ac472a4c40ec03cf4c810b118d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/1be5b3a706db16ac472a4c40ec03cf4c810b118d", + "reference": "1be5b3a706db16ac472a4c40ec03cf4c810b118d", + "shasum": "" + }, + "require": { + "composer/xdebug-handler": "^1.3.0", + "jean85/pretty-package-versions": "^1.0.3", + "nette/bootstrap": "^2.4 || ^3.0", + "nette/di": "^2.4.7 || ^3.0", + "nette/robot-loader": "^3.0.1", + "nette/schema": "^1.0", + "nette/utils": "^2.4.5 || ^3.0", + "nikic/php-parser": "^4.2.3", + "php": "~7.1", + "phpstan/phpdoc-parser": "^0.3.5", + "symfony/console": "~3.2 || ~4.0", + "symfony/finder": "~3.2 || ~4.0" + }, + "conflict": { + "symfony/console": "3.4.16 || 4.1.5" + }, + "require-dev": { + "brianium/paratest": "^2.0 || ^3.0", + "consistence/coding-standard": "^3.5", + "dealerdirect/phpcodesniffer-composer-installer": "^0.4.4", + "ext-intl": "*", + "ext-mysqli": "*", + "ext-simplexml": "*", + "ext-soap": "*", + "ext-zip": "*", + "jakub-onderka/php-parallel-lint": "^1.0", + "localheinz/composer-normalize": "^1.1.0", + "phing/phing": "^2.16.0", + "phpstan/phpstan-deprecation-rules": "^0.11", + "phpstan/phpstan-php-parser": "^0.11", + "phpstan/phpstan-phpunit": "^0.11", + "phpstan/phpstan-strict-rules": "^0.11", + "phpunit/phpunit": "^7.5.14 || ^8.0", + "slevomat/coding-standard": "^4.7.2", + "squizlabs/php_codesniffer": "^3.3.2" + }, + "bin": [ + "bin/phpstan" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "0.11-dev" + } + }, + "autoload": { + "psr-4": { + "PHPStan\\": [ + "src/", + "build/PHPStan" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPStan - PHP Static Analysis Tool", + "time": "2019-08-18T20:51:53+00:00" + }, + { + "name": "phpstan/phpstan-deprecation-rules", + "version": "0.11.2", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpstan-deprecation-rules.git", + "reference": "5685fe48873efc5af1f2cc95d9c1b8ae82c728fe" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan-deprecation-rules/zipball/5685fe48873efc5af1f2cc95d9c1b8ae82c728fe", + "reference": "5685fe48873efc5af1f2cc95d9c1b8ae82c728fe", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^4.0", + "php": "~7.1", + "phpstan/phpstan": "^0.11.8" + }, + "require-dev": { + "consistence/coding-standard": "^3.0.1", + "dealerdirect/phpcodesniffer-composer-installer": "^0.4.4", + "jakub-onderka/php-parallel-lint": "^1.0", + "phing/phing": "^2.16.0", + "phpstan/phpstan-phpunit": "^0.11", + "phpunit/phpunit": "^7.0", + "slevomat/coding-standard": "^4.5.2" + }, + "type": "phpstan-extension", + "extra": { + "branch-alias": { + "dev-master": "0.11-dev" + }, + "phpstan": { + "includes": [ + "rules.neon" + ] + } + }, + "autoload": { + "psr-4": { + "PHPStan\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPStan rules for detecting usage of deprecated classes, methods, properties, constants and traits.", + "time": "2019-05-28T19:54:04+00:00" + }, + { + "name": "phpunit/php-code-coverage", + "version": "6.1.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "807e6013b00af69b6c5d9ceb4282d0393dbb9d8d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/807e6013b00af69b6c5d9ceb4282d0393dbb9d8d", + "reference": "807e6013b00af69b6c5d9ceb4282d0393dbb9d8d", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-xmlwriter": "*", + "php": "^7.1", + "phpunit/php-file-iterator": "^2.0", + "phpunit/php-text-template": "^1.2.1", + "phpunit/php-token-stream": "^3.0", + "sebastian/code-unit-reverse-lookup": "^1.0.1", + "sebastian/environment": "^3.1 || ^4.0", + "sebastian/version": "^2.0.1", + "theseer/tokenizer": "^1.1" + }, + "require-dev": { + "phpunit/phpunit": "^7.0" + }, + "suggest": { + "ext-xdebug": "^2.6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "6.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "role": "lead", + "email": "sebastian@phpunit.de" + } + ], + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "coverage", + "testing", + "xunit" + ], + "time": "2018-10-31T16:06:48+00:00" + }, + { + "name": "phpunit/php-file-iterator", + "version": "2.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "050bedf145a257b1ff02746c31894800e5122946" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/050bedf145a257b1ff02746c31894800e5122946", + "reference": "050bedf145a257b1ff02746c31894800e5122946", + "shasum": "" + }, + "require": { + "php": "^7.1" + }, + "require-dev": { + "phpunit/phpunit": "^7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "role": "lead", + "email": "sebastian@phpunit.de" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "filesystem", + "iterator" + ], + "time": "2018-09-13T20:33:42+00:00" + }, + { + "name": "phpunit/php-text-template", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "role": "lead", + "email": "sebastian@phpunit.de" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "time": "2015-06-21T13:50:34+00:00" + }, + { + "name": "phpunit/php-timer", + "version": "2.1.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "1038454804406b0b5f5f520358e78c1c2f71501e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/1038454804406b0b5f5f520358e78c1c2f71501e", + "reference": "1038454804406b0b5f5f520358e78c1c2f71501e", + "shasum": "" + }, + "require": { + "php": "^7.1" + }, + "require-dev": { + "phpunit/phpunit": "^7.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "role": "lead", + "email": "sebastian@phpunit.de" + } + ], + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "time": "2019-06-07T04:22:29+00:00" + }, + { + "name": "phpunit/php-token-stream", + "version": "3.1.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-token-stream.git", + "reference": "e899757bb3df5ff6e95089132f32cd59aac2220a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/e899757bb3df5ff6e95089132f32cd59aac2220a", + "reference": "e899757bb3df5ff6e95089132f32cd59aac2220a", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": "^7.1" + }, + "require-dev": { + "phpunit/phpunit": "^7.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Wrapper around PHP's tokenizer extension.", + "homepage": "https://github.com/sebastianbergmann/php-token-stream/", + "keywords": [ + "tokenizer" + ], + "time": "2019-07-25T05:29:42+00:00" + }, + { + "name": "phpunit/phpunit", + "version": "7.5.14", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "2834789aeb9ac182ad69bfdf9ae91856a59945ff" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/2834789aeb9ac182ad69bfdf9ae91856a59945ff", + "reference": "2834789aeb9ac182ad69bfdf9ae91856a59945ff", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.1", + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-xml": "*", + "myclabs/deep-copy": "^1.7", + "phar-io/manifest": "^1.0.2", + "phar-io/version": "^2.0", + "php": "^7.1", + "phpspec/prophecy": "^1.7", + "phpunit/php-code-coverage": "^6.0.7", + "phpunit/php-file-iterator": "^2.0.1", + "phpunit/php-text-template": "^1.2.1", + "phpunit/php-timer": "^2.1", + "sebastian/comparator": "^3.0", + "sebastian/diff": "^3.0", + "sebastian/environment": "^4.0", + "sebastian/exporter": "^3.1", + "sebastian/global-state": "^2.0", + "sebastian/object-enumerator": "^3.0.3", + "sebastian/resource-operations": "^2.0", + "sebastian/version": "^2.0.1" + }, + "conflict": { + "phpunit/phpunit-mock-objects": "*" + }, + "require-dev": { + "ext-pdo": "*" + }, + "suggest": { + "ext-soap": "*", + "ext-xdebug": "*", + "phpunit/php-invoker": "^2.0" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "7.5-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "role": "lead", + "email": "sebastian@phpunit.de" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "time": "2019-07-15T06:24:08+00:00" + }, + { + "name": "sebastian/code-unit-reverse-lookup", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", + "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/4419fcdb5eabb9caa61a27c7a1db532a6b55dd18", + "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^5.7 || ^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Looks up which function or method a line of code belongs to", + "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", + "time": "2017-03-04T06:30:41+00:00" + }, + { + "name": "sebastian/comparator", + "version": "3.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "5de4fc177adf9bce8df98d8d141a7559d7ccf6da" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/5de4fc177adf9bce8df98d8d141a7559d7ccf6da", + "reference": "5de4fc177adf9bce8df98d8d141a7559d7ccf6da", + "shasum": "" + }, + "require": { + "php": "^7.1", + "sebastian/diff": "^3.0", + "sebastian/exporter": "^3.1" + }, + "require-dev": { + "phpunit/phpunit": "^7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "https://github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], + "time": "2018-07-12T15:12:46+00:00" + }, + { + "name": "sebastian/diff", + "version": "3.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "720fcc7e9b5cf384ea68d9d930d480907a0c1a29" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/720fcc7e9b5cf384ea68d9d930d480907a0c1a29", + "reference": "720fcc7e9b5cf384ea68d9d930d480907a0c1a29", + "shasum": "" + }, + "require": { + "php": "^7.1" + }, + "require-dev": { + "phpunit/phpunit": "^7.5 || ^8.0", + "symfony/process": "^2 || ^3.3 || ^4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Diff implementation", + "homepage": "https://github.com/sebastianbergmann/diff", + "keywords": [ + "diff", + "udiff", + "unidiff", + "unified diff" + ], + "time": "2019-02-04T06:01:07+00:00" + }, + { + "name": "sebastian/environment", + "version": "4.2.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "f2a2c8e1c97c11ace607a7a667d73d47c19fe404" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/f2a2c8e1c97c11ace607a7a667d73d47c19fe404", + "reference": "f2a2c8e1c97c11ace607a7a667d73d47c19fe404", + "shasum": "" + }, + "require": { + "php": "^7.1" + }, + "require-dev": { + "phpunit/phpunit": "^7.5" + }, + "suggest": { + "ext-posix": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.2-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "http://www.github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], + "time": "2019-05-05T09:05:15+00:00" + }, + { + "name": "sebastian/exporter", + "version": "3.1.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "06a9a5947f47b3029d76118eb5c22802e5869687" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/06a9a5947f47b3029d76118eb5c22802e5869687", + "reference": "06a9a5947f47b3029d76118eb5c22802e5869687", + "shasum": "" + }, + "require": { + "php": "^7.0", + "sebastian/recursion-context": "^3.0" + }, + "require-dev": { + "ext-mbstring": "*", + "phpunit/phpunit": "^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "http://www.github.com/sebastianbergmann/exporter", + "keywords": [ + "export", + "exporter" + ], + "time": "2019-08-11T12:43:14+00:00" + }, + { + "name": "sebastian/global-state", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4", + "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4", + "shasum": "" + }, + "require": { + "php": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.0" + }, + "suggest": { + "ext-uopz": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Snapshotting of global state", + "homepage": "http://www.github.com/sebastianbergmann/global-state", + "keywords": [ + "global state" + ], + "time": "2017-04-27T15:39:26+00:00" + }, + { + "name": "sebastian/object-enumerator", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-enumerator.git", + "reference": "7cfd9e65d11ffb5af41198476395774d4c8a84c5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/7cfd9e65d11ffb5af41198476395774d4c8a84c5", + "reference": "7cfd9e65d11ffb5af41198476395774d4c8a84c5", + "shasum": "" + }, + "require": { + "php": "^7.0", + "sebastian/object-reflector": "^1.1.1", + "sebastian/recursion-context": "^3.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Traverses array structures and object graphs to enumerate all referenced objects", + "homepage": "https://github.com/sebastianbergmann/object-enumerator/", + "time": "2017-08-03T12:35:26+00:00" + }, + { + "name": "sebastian/object-reflector", + "version": "1.1.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-reflector.git", + "reference": "773f97c67f28de00d397be301821b06708fca0be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/773f97c67f28de00d397be301821b06708fca0be", + "reference": "773f97c67f28de00d397be301821b06708fca0be", + "shasum": "" + }, + "require": { + "php": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Allows reflection of object attributes, including inherited and non-public ones", + "homepage": "https://github.com/sebastianbergmann/object-reflector/", + "time": "2017-03-29T09:07:27+00:00" + }, + { + "name": "sebastian/recursion-context", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8", + "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8", + "shasum": "" + }, + "require": { + "php": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides functionality to recursively process PHP variables", + "homepage": "http://www.github.com/sebastianbergmann/recursion-context", + "time": "2017-03-03T06:23:57+00:00" + }, + { + "name": "sebastian/resource-operations", + "version": "2.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/resource-operations.git", + "reference": "4d7a795d35b889bf80a0cc04e08d77cedfa917a9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/4d7a795d35b889bf80a0cc04e08d77cedfa917a9", + "reference": "4d7a795d35b889bf80a0cc04e08d77cedfa917a9", + "shasum": "" + }, + "require": { + "php": "^7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides a list of PHP built-in functions that operate on resources", + "homepage": "https://www.github.com/sebastianbergmann/resource-operations", + "time": "2018-10-04T04:07:39+00:00" + }, + { + "name": "sebastian/version", + "version": "2.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/99732be0ddb3361e16ad77b68ba41efc8e979019", + "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "role": "lead", + "email": "sebastian@phpunit.de" + } + ], + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "time": "2016-10-03T07:35:21+00:00" + }, + { + "name": "symfony/browser-kit", + "version": "v4.3.3", + "source": { + "type": "git", + "url": "https://github.com/symfony/browser-kit.git", + "reference": "a29dd02a1f3f81b9a15c7730cc3226718ddb55ca" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/browser-kit/zipball/a29dd02a1f3f81b9a15c7730cc3226718ddb55ca", + "reference": "a29dd02a1f3f81b9a15c7730cc3226718ddb55ca", + "shasum": "" + }, + "require": { + "php": "^7.1.3", + "symfony/dom-crawler": "~3.4|~4.0" + }, + "require-dev": { + "symfony/css-selector": "~3.4|~4.0", + "symfony/http-client": "^4.3", + "symfony/mime": "^4.3", + "symfony/process": "~3.4|~4.0" + }, + "suggest": { + "symfony/process": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.3-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\BrowserKit\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony BrowserKit Component", + "homepage": "https://symfony.com", + "time": "2019-06-11T15:41:59+00:00" + }, + { + "name": "symfony/css-selector", + "version": "v4.3.3", + "source": { + "type": "git", + "url": "https://github.com/symfony/css-selector.git", + "reference": "105c98bb0c5d8635bea056135304bd8edcc42b4d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/105c98bb0c5d8635bea056135304bd8edcc42b4d", + "reference": "105c98bb0c5d8635bea056135304bd8edcc42b4d", + "shasum": "" + }, + "require": { + "php": "^7.1.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.3-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\CssSelector\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Jean-François Simon", + "email": "jeanfrancois.simon@sensiolabs.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony CssSelector Component", + "homepage": "https://symfony.com", + "time": "2019-01-16T21:53:39+00:00" + }, + { + "name": "symfony/dom-crawler", + "version": "v4.3.3", + "source": { + "type": "git", + "url": "https://github.com/symfony/dom-crawler.git", + "reference": "291397232a2eefb3347eaab9170409981eaad0e2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/291397232a2eefb3347eaab9170409981eaad0e2", + "reference": "291397232a2eefb3347eaab9170409981eaad0e2", + "shasum": "" + }, + "require": { + "php": "^7.1.3", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-mbstring": "~1.0" + }, + "conflict": { + "masterminds/html5": "<2.6" + }, + "require-dev": { + "masterminds/html5": "^2.6", + "symfony/css-selector": "~3.4|~4.0" + }, + "suggest": { + "symfony/css-selector": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.3-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\DomCrawler\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony DomCrawler Component", + "homepage": "https://symfony.com", + "time": "2019-06-13T11:03:18+00:00" + }, + { + "name": "symfony/finder", + "version": "v4.3.3", + "source": { + "type": "git", + "url": "https://github.com/symfony/finder.git", + "reference": "9638d41e3729459860bb96f6247ccb61faaa45f2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/finder/zipball/9638d41e3729459860bb96f6247ccb61faaa45f2", + "reference": "9638d41e3729459860bb96f6247ccb61faaa45f2", + "shasum": "" + }, + "require": { + "php": "^7.1.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.3-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Finder\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Finder Component", + "homepage": "https://symfony.com", + "time": "2019-06-28T13:16:30+00:00" + }, + { + "name": "theseer/tokenizer", + "version": "1.1.3", + "source": { + "type": "git", + "url": "https://github.com/theseer/tokenizer.git", + "reference": "11336f6f84e16a720dae9d8e6ed5019efa85a0f9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/11336f6f84e16a720dae9d8e6ed5019efa85a0f9", + "reference": "11336f6f84e16a720dae9d8e6ed5019efa85a0f9", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": "^7.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "role": "Developer", + "email": "arne@blankerts.de" + } + ], + "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", + "time": "2019-06-13T22:48:21+00:00" + }, + { + "name": "victorjonsson/markdowndocs", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/trilbymedia/PHP-Markdown-Documentation-Generator.git", + "reference": "c9fa153b28a79f5da89ec32aa501be92db212aed" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/trilbymedia/PHP-Markdown-Documentation-Generator/zipball/c9fa153b28a79f5da89ec32aa501be92db212aed", + "reference": "c9fa153b28a79f5da89ec32aa501be92db212aed", + "shasum": "" + }, + "require": { + "php": ">=5.5.0", + "symfony/console": ">=2.6" + }, + "require-dev": { + "phpunit/phpunit": "3.7.23" + }, + "bin": [ + "bin/phpdoc-md" + ], + "type": "library", + "autoload": { + "psr-0": { + "PHPDocsMD": "src/" + } + }, + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Victor Jonsson", + "email": "kontakt@victorjonsson.se" + } + ], + "description": "Command line tool for generating markdown-formatted class documentation", + "homepage": "https://github.com/victorjonsson/PHP-Markdown-Documentation-Generator", + "support": { + "source": "https://github.com/trilbymedia/PHP-Markdown-Documentation-Generator/tree/master" + }, + "time": "2017-09-20T13:29:22+00:00" + }, + { + "name": "webmozart/assert", + "version": "1.4.0", + "source": { + "type": "git", + "url": "https://github.com/webmozart/assert.git", + "reference": "83e253c8e0be5b0257b881e1827274667c5c17a9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozart/assert/zipball/83e253c8e0be5b0257b881e1827274667c5c17a9", + "reference": "83e253c8e0be5b0257b881e1827274667c5c17a9", + "shasum": "" + }, + "require": { + "php": "^5.3.3 || ^7.0", + "symfony/polyfill-ctype": "^1.8" + }, + "require-dev": { + "phpunit/phpunit": "^4.6", + "sebastian/version": "^1.0.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3-dev" + } + }, + "autoload": { + "psr-4": { + "Webmozart\\Assert\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Assertions to validate method input/output with nice error messages.", + "keywords": [ + "assert", + "check", + "validate" + ], + "time": "2018-12-25T11:19:39+00:00" + } + ], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": { + "victorjonsson/markdowndocs": 20 + }, + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "php": ">=7.1.3", + "ext-json": "*", + "ext-mbstring": "*", + "ext-openssl": "*", + "ext-curl": "*", + "ext-zip": "*", + "ext-dom": "*" + }, + "platform-dev": [], + "platform-overrides": { + "php": "7.1.3" + } +} diff --git a/images/.gitkeep b/images/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/index.php b/index.php new file mode 100644 index 00000000..64154df8 --- /dev/null +++ b/index.php @@ -0,0 +1,60 @@ +PHP %s to run.', $ver, $req)); +} + +if (PHP_SAPI === 'cli-server' && !isset($_SERVER['PHP_CLI_ROUTER'])) { + die("PHP webserver requires a router to run Grav, please use:
                                                            php -S {$_SERVER['SERVER_NAME']}:{$_SERVER['SERVER_PORT']} system/router.php
                                                            "); +} + +// Ensure vendor libraries exist +$autoload = __DIR__ . '/vendor/autoload.php'; +if (!is_file($autoload)) { + die('Please run: bin/grav install'); +} + +// Register the auto-loader. +$loader = require $autoload; + +use Grav\Common\Grav; +use RocketTheme\Toolbox\Event\Event; + +// Set timezone to default, falls back to system if php.ini not set +date_default_timezone_set(@date_default_timezone_get()); + +// Set internal encoding if mbstring loaded +if (!\extension_loaded('mbstring')) { + die("'mbstring' extension is not loaded. This is required for Grav to run correctly"); +} +mb_internal_encoding('UTF-8'); + +// Get the Grav instance +$grav = Grav::instance( + array( + 'loader' => $loader + ) +); + +// Process the page +try { + $grav->process(); +} catch (\Error $e) { + $grav->fireEvent('onFatalException', new Event(array('exception' => $e))); + throw $e; +} catch (\Exception $e) { + $grav->fireEvent('onFatalException', new Event(array('exception' => $e))); + throw $e; +} diff --git a/logs/.gitkeep b/logs/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/node_modules/.yarn-integrity b/node_modules/.yarn-integrity new file mode 100644 index 00000000..dea44209 --- /dev/null +++ b/node_modules/.yarn-integrity @@ -0,0 +1,10 @@ +{ + "systemParams": "linux-x64-57", + "modulesFolders": [], + "flags": [], + "linkedModules": [], + "topLevelPatterns": [], + "lockfileEntries": {}, + "files": [], + "artifacts": {} +} \ No newline at end of file diff --git a/node_modules/bulma/CHANGELOG.md b/node_modules/bulma/CHANGELOG.md new file mode 100644 index 00000000..00f04f6b --- /dev/null +++ b/node_modules/bulma/CHANGELOG.md @@ -0,0 +1,1371 @@ +# Bulma Changelog + +## 0.8.0 + +### Big update + +#### Larger form controls + +Controls and buttons are now `2.5em` high. You can revert this resizing by setting these previous values: + +```sass +$control-height: 2.25em +$control-padding-vertical: calc(0.375em - #{$control-border-width}) +$control-padding-horizontal: calc(0.625em - #{$control-border-width}) +$button-padding-vertical: calc(0.375em - #{$button-border-width}) +$button-padding-horizontal: 0.75em +``` + +#### Light and dark colors + +Each main color (`"primary"`, `"info"`, `"success"`, `"warning"`, `"danger"`) now has a `*-light` and `*-dark` version. They are calculated using 2 new color functions: + +* `findLightColor()` which finds the light version of a color +* `findDarkolor()` which finds the dark version of a color + +The light colors are used by the `button` element, while the light and dark colors are used by the `message` component. + +#### Panel colors + +The `panel` component is now available in all the different colors. + +#### 4-value color map + +The `$colors` Sass map now accepts, for each of its values, a map of up to **4** values. For example: the key `"info"` now has the `($info, $info-invert, $info-light, $info-dark)` map. + +If you provide a `$custom-colors` map, you can decide to provide a map of 1, 2, 3 or 4 values for each value. If fewer than 4 are provided, Bulma will calculate the remaining ones: + +```scss +$custom-colors: ( + "lime": (lime), + "tomato": (tomato, white), + "orange": ($orange, $orange-invert, $orange-light), + "lavender": ($lavender, $lavender-invert, $lavender-light, $lavender-dark) +); +``` + +This is processed by the updated `mergeColorMaps()` Sass function. + +#### Scheme variables + +There are 6 new `$scheme` derived variables: `$scheme-main` `$scheme-main-bis` `$scheme-main-ter` `$scheme-invert` `$scheme-invert-bis` `$scheme-invert-ter` +They replace the `$white` and `$black` occurences in the codebase. This makes it easy to create a "Dark mode" simply by swapping the values: + +```sass +$scheme-main: $black +$scheme-invert: $white +// etc. +``` + +That is also why most of the codebase now references **derived** variables (`$text`, `$background`, `$border` etc.) instead of **initial** ones (`$grey`, `$grey-lighter`, `$grey-darker` etc.): updating the derived variables will affect all elements and components directly. + +#### Initial variables + +* `$green: hsl(141, 53%, 53%)` +* `$cyan: hsl(204, 71%, 53%)` +* `$red: hsl(348, 86%, 61%)` + +#### Derived variables + +* `$primary-invert: findColorInvert($primary)` +* `$primary-light: findLightColor($primary)` +* `$primary-dark: findDarkColor($primary)` +* `$info-invert: findColorInvert($info)` +* `$info-light: findLightColor($info)` +* `$info-dark: findDarkColor($info)` +* `$success-invert: findColorInvert($success)` +* `$success-light: findLightColor($success)` +* `$success-dark: findDarkColor($success)` +* `$warning-invert: findColorInvert($warning)` +* `$warning-light: findLightColor($warning)` +* `$warning-dark: findDarkColor($warning)` +* `$danger-invert: findColorInvert($danger)` +* `$danger-light: findLightColor($danger)` +* `$danger-dark: findDarkColor($danger)` +* `$light-invert: findColorInvert($light)` +* `$dark-invert: findColorInvert($dark)` + +* `$scheme-main: $white` +* `$scheme-main-bis: $white-bis` +* `$scheme-main-ter: $white-ter` +* `$scheme-invert: $black` +* `$scheme-invert-bis: $black-bis` +* `$scheme-invert-ter: $black-ter` + +### Other variables + +* `$control-height: 2.5em` +* `$control-padding-vertical: calc(0.5em - #{$control-border-width})` +* `$control-padding-horizontal: calc(0.75em - #{$control-border-width})` +* `$media-border-color: rgba($border, 0.5)` +* `$notification-code-background-color: $scheme-main` +* `$panel-radius: $radius-large` +* `$panel-shadow: 0 0.5em 1em -0.125em rgba($scheme-invert, 0.1), 0 0px 0 1px rgba($scheme-invert, 0.02)` +* `$textarea-padding: $control-padding-horizontal` +* `$textarea-max-height: 40em` +* `$textarea-min-height: 8em` + +### Bug fixes + +* Fix #2647 -> Missing meta tags in snippet +* Fix #2031, Fix #2483 -> Invalid output when declaring a custom shade map +* Fix #2060 -> `height: auto` on HTML `audio` element breaks height of element +* Fix #706 -> Derive `-invert` variables using `findColorInvert()` +* #1608 Fix #1552 -> `.container.is-fluid` margins + +### New features + +* #2563 `.image` has a new `.is-fullwidth` modifier + +## 0.7.5 + +### Deprecation warning + +The `form.sass` file is **deprecated**. It has moved into its own `/form` folder. If you were importing `form.sass`, please import `sass/form/_all.sass` now. +If you were simply importing the whole of Bulma with `@import "~/bulma/bulma.sass"` or similar, you won't have to change anything, and everything will work as bbefore. + +### New features + +#### Support for overriding the `font-family` + +You can now specify a different `font-family` for the `.title`, `.subtitle` and `.button` by using the variables `$title-family`, `$subtitle-family` and `$button-family` respectively. + +Simply set a value when importing Bulma: + +```scss +$title-family: "Georgia", serif; +``` + +* #2375 Add `.is-relative` helper +* #2321 Make `.navbar` focus behave like hover for the navigation +* #2290 Fix #1186 -> Reset the offset on columns +* #2231 Add `.has-text-weight-medium` helper +* #2224 Add customizable border radius to progress bar +* #2480 Add `$footer-color` variable + +### Improvements + +* #2396 Update docs with webpack 4 example +* #2381 Make centered buttons have equal margin +* Fix #2297 -> Remove `.container` fixed width values, use `flex-grow` +* #2478 Move form.sass into its own folder + +### Bug fixes + +* #2420 Fix #2414 -> Fix `align` attribute in `td/th` being ignored +* #2463 Remove duplicate `.has-addons` in `tag.sass` +* #2253 Fix `$gap` variable default value +* #2273 Fix #2258 -> Fix Indeterminate Progress Bar animation in Firefox +* #2175 Proper aligning for `.tabs` within `.content` +* #2476 Fix #2441 -> Correct active pagination link text colour on hero + +Fix #1979 -> Correct loading spinner color when a button is: + +* outlined and hovered/focused +* outlined, inverted and hovered/focused + +### New variables + +#### Initial variables + +* `$block-spacing` + +#### Base + +* `$body-font-size` +* `$small-font-size` +* `$pre-font-size` +* `$pre-padding` +* `$pre-code-font-size` + +#### Components + +* `$card-header-padding` +* `$card-content-padding` +* `$card-media-margin` +* `$dropdown-menu-min-width` +* `$dropdown-content-padding-bottom` +* `$dropdown-content-padding-top` +* `$level-item-spacing` +* `$menu-list-line-height` +* `$menu-list-link-padding` +* `$menu-nested-list-margin` +* `$menu-nested-list-padding-left` +* `$menu-label-font-size` +* `$menu-label-letter-spacing` +* `$menu-label-spacing` +* `$pagination-item-font-size` +* `$pagination-item-margin` +* `$pagination-item-padding-left` +* `$pagination-item-padding-right` +* `$panel-margin` +* `$panel-tabs-font-size` + +#### Elements + +* `$container-offset` + +#### Grid + +* `$tile-spacing` + +## 0.7.3 + +### New features + +* #2145 Fix #372 -> New indeterminate progress bars +* #2206 Fix #2046 -> New variables `$table-head-background-color`, `$table-body-background-color` and `$table-foot-background-color` for the `.table` element +* #592 -> Give arbitrary elements access to the image/ratio classes +* #1682 Fix #1681 -> Adds disabled styles for `
                                                            ` +* #2201 Fix #1875 -> `.buttons` and `.tags` group sizing (`.are-small`, `.are-medium`, `.are-large`) + +### Improvements + +* #1978 Fix #1696 -> Force `box-sizing: border-box` on `details` element +* #2167 Fix #1878 -> New `$footer-padding` variable +* #2168 -> New `$input-placeholder-color` and `$input-disabled-placeholder-color` variables + +### Bug fixes + +* #2157 Fix #1656 -> Allow border radius if only one `.control` in `.field` +* #2091 Fix #2091 -> Remove CSS rule which causes `.tag.has-addons` to not work correctly +* #2186 Fix #1130 -> Prevent `.dropdown` links underlining in `.message` component +* Fix #2154 -> Move `.hero.is-fullheight-with-navbar` to `navbar.sass` file + +### Deprecation + +* `.control.has-icon` deprecated in favor of `.control.has-icons` + +## 0.7.2 + +### New features + +* #1884 New `$navbar-burger-color` variable +* #1679 Add breakpoint based column gaps +* #1905 Fix `modal` for IE11 #1902 +* #1919 New `is-arrowless` class for navbar items +* #1949 New `is-fullheight-with-navbar` class for heros +* #1764 New `.is-sr-only` helper +* #2109 Add and use `$navbar-breakpoint` variable +* New variables `$control-height`, `$control-line-height`, `$pagination-min-width`, `$input-height` +* #1720 Add list element feature +* #2123 Add `.content ol` types: `.is-lower-roman`, `.is-upper-roman`, `.is-lower-alpha`, `.is-upper-alpha`, and support for the `type=` HTML attribute + +### Improvements + +* #1964 Allow `.notification` to have a `.dropdown-item` +* #1999 Change `$border` to `$grey-lighter` in mixins +* #2085 `.media-content` will allow scrolling horizontally if the content is too wide +* #1744 Fix #1710 by using `$table-striped-row-even-hover-background-color` only for even rows +* #2074 Allow ` + + + + + + + +{% endblock prepend %} + +{% block input_attributes %} + type="hidden" + {{ parent() }} +{% endblock %} \ No newline at end of file diff --git a/user/plugins/form/templates/forms/fields/spacer/spacer.html.twig b/user/plugins/form/templates/forms/fields/spacer/spacer.html.twig new file mode 100644 index 00000000..cdeafd7b --- /dev/null +++ b/user/plugins/form/templates/forms/fields/spacer/spacer.html.twig @@ -0,0 +1,19 @@ +{% extends "forms/field.html.twig" %} + +{% block field %} +
                                                            + {% if field.title %} +

                                                            {{- field.title|t|raw -}}

                                                            + {% endif %} + + {% if field.markdown %} +

                                                            {{- field.text|t|markdown|raw -}}

                                                            + {% else %} +

                                                            {{- field.text|t|raw -}}

                                                            + {% endif %} + + {% if field.underline %} +
                                                            + {% endif %} +
                                                            +{% endblock %} diff --git a/user/plugins/form/templates/forms/fields/switch/switch.html.twig b/user/plugins/form/templates/forms/fields/switch/switch.html.twig new file mode 100644 index 00000000..f449d8ac --- /dev/null +++ b/user/plugins/form/templates/forms/fields/switch/switch.html.twig @@ -0,0 +1 @@ +{% extends 'forms/fields/checkbox/checkbox.html.twig' %} \ No newline at end of file diff --git a/user/plugins/form/templates/forms/fields/tab/tab.html.twig b/user/plugins/form/templates/forms/fields/tab/tab.html.twig new file mode 100644 index 00000000..25a726ca --- /dev/null +++ b/user/plugins/form/templates/forms/fields/tab/tab.html.twig @@ -0,0 +1,9 @@ +{% extends "forms/field.html.twig" %} + +{% block field %} + {% if field.fields %} +
                                                            + {% include 'forms/default/fields.html.twig' with {name: field.name, fields: field.fields} %} +
                                                            + {% endif %} +{% endblock %} \ No newline at end of file diff --git a/user/plugins/form/templates/forms/fields/tabs/tabs.html.twig b/user/plugins/form/templates/forms/fields/tabs/tabs.html.twig new file mode 100644 index 00000000..4d51f439 --- /dev/null +++ b/user/plugins/form/templates/forms/fields/tabs/tabs.html.twig @@ -0,0 +1,66 @@ +{% extends "forms/field.html.twig" %} + +{% if grav.admin is not defined %} +{% do assets.addJs('plugin://form/assets/form.vendor.js', { 'group': 'bottom', 'loading': 'defer' }) %} +{% do assets.addJs('plugin://form/assets/form.min.js', { 'group': 'bottom', 'loading': 'defer' }) %} +{% endif %} + +{% block field %} +
                                                            + + {% if field.fields %} + {% set tabs = {} %} + {% for tab in field.fields %} + {% if tab.type == 'tab' and not tab.validate.ignore and (tab.security is empty or authorize(array(tab.security))) %} + {% set tabs = tabs|merge([tab]) %} + {% endif %} + {% endfor %} + {% set count = tabs|count %} + + {% if count == 0 %} + {# Nothing to display #} + {% elseif count == 1 %} + {% for field in (tabs|first).fields %} + {% if field.type %} + {% set value = field.name ? (form ? form.value(field.name) : data.value(field.name)) : data.toArray %} + {% include ["forms/fields/#{field.type}/#{field.type}.html.twig", 'forms/fields/text/text.html.twig'] %} + {% endif %} + {% endfor %} + {% else %} + {% set tabsKey = field.fields|keys|join('.') %} + {% set storedValue = grav.admin is defined ? get_cookie('grav-tabs-state')|default('{}')|json_decode : [] %} + {% set storedTab = attribute(storedValue, 'tab-' ~ tabsKey) %} + + {% if storedTab is empty %} + {% if uri.params.tab %} + {% set active = uri.params.tab %} + {% elseif field.active %} + {% set active = field.active %} + {% else %} + {% set active = 1 %} + {% endif %} + {% endif %} + +
                                                            + {% for tab in tabs %} + {% if tab.type == 'tab' %} + + {{ tab.title|t }} + {% endif %} + + {% endfor %} +
                                                            +
                                                            + {% embed 'forms/default/fields.html.twig' with {name: field.name, fields: field.fields} %} + {% block inner_markup_field_open %} +
                                                            + {% endblock %} + {% block inner_markup_field_close %} +
                                                            + {% endblock %} + {% endembed %} +
                                                            + {% endif %} +{% endif %} +
                                                            +{% endblock %} diff --git a/user/plugins/form/templates/forms/fields/tel/tel.html.twig b/user/plugins/form/templates/forms/fields/tel/tel.html.twig new file mode 100644 index 00000000..68983131 --- /dev/null +++ b/user/plugins/form/templates/forms/fields/tel/tel.html.twig @@ -0,0 +1,6 @@ +{% extends "forms/field.html.twig" %} + +{% block input_attributes %} + type="tel" + {{ parent() }} +{% endblock %} \ No newline at end of file diff --git a/user/plugins/form/templates/forms/fields/text/edit_list.html.twig b/user/plugins/form/templates/forms/fields/text/edit_list.html.twig new file mode 100644 index 00000000..a5b95823 --- /dev/null +++ b/user/plugins/form/templates/forms/fields/text/edit_list.html.twig @@ -0,0 +1,5 @@ +{% if link -%} + {{ value|join(', ')|e }} +{%- else -%} + {{ value|join(', ')|e }} +{%- endif %} diff --git a/user/plugins/form/templates/forms/fields/text/text.html.twig b/user/plugins/form/templates/forms/fields/text/text.html.twig new file mode 100644 index 00000000..db139bbb --- /dev/null +++ b/user/plugins/form/templates/forms/fields/text/text.html.twig @@ -0,0 +1,39 @@ +{% if field.prepend or field.append or field.copy_to_clipboard %} + {% set field = field|merge({'wrapper_classes': 'form-input-addon-wrapper'}) %} +{% endif %} + +{% extends "forms/field.html.twig" %} + +{% block prepend %} +{% if field.prepend %} +
                                                            + {{- field.prepend|t|raw -}} +
                                                            +{% endif %} +{% endblock %} + +{% block input_attributes %} + type="text" + {% if field.size %}size="{{ field.size }}"{% endif %} + {% if field.minlength is defined or field.validate.min is defined %}minlength="{{ field.minlength | default(field.validate.min) }}"{% endif %} + {% if field.maxlength is defined or field.validate.max is defined %}maxlength="{{ field.maxlength | default(field.validate.max) }}"{% endif %} + {{ parent() }} +{% endblock %} + +{% block append %} + {% if field.copy_to_clipboard %} +
                                                            + {% if field.copy_to_clipboard in ['0', '1'] %} + + {% else %} + {{- field.copy_to_clipboard|t|raw -}} + {% endif %} +
                                                            + {% elseif field.append %} +
                                                            + {{- field.append|t|raw -}} +
                                                            + {% endif %} +{% endblock %} + + diff --git a/user/plugins/form/templates/forms/fields/textarea/textarea.html.twig b/user/plugins/form/templates/forms/fields/textarea/textarea.html.twig new file mode 100644 index 00000000..a3088ee2 --- /dev/null +++ b/user/plugins/form/templates/forms/fields/textarea/textarea.html.twig @@ -0,0 +1,42 @@ +{% extends "forms/field.html.twig" %} + +{% block input %} +
                                                            + {% block prepend %}{% endblock prepend %} + + {% block append %}{% endblock append %} + {% if inline_errors and errors %} +
                                                            +

                                                            {{ errors|first }}

                                                            +
                                                            + {% endif %} +
                                                            +{% endblock %} diff --git a/user/plugins/form/templates/forms/fields/time/edit_list.html.twig b/user/plugins/form/templates/forms/fields/time/edit_list.html.twig new file mode 100644 index 00000000..9da9fc9c --- /dev/null +++ b/user/plugins/form/templates/forms/fields/time/edit_list.html.twig @@ -0,0 +1 @@ +{{ value ? value|date('g:i A')|e }} diff --git a/user/plugins/form/templates/forms/fields/time/time.html.twig b/user/plugins/form/templates/forms/fields/time/time.html.twig new file mode 100644 index 00000000..b6bb10ec --- /dev/null +++ b/user/plugins/form/templates/forms/fields/time/time.html.twig @@ -0,0 +1,6 @@ +{% extends "forms/field.html.twig" %} + +{% block input_attributes %} + type="time" + {{ parent() }} +{% endblock %} diff --git a/user/plugins/form/templates/forms/fields/toggle/edit_list.html.twig b/user/plugins/form/templates/forms/fields/toggle/edit_list.html.twig new file mode 100644 index 00000000..b2b4838e --- /dev/null +++ b/user/plugins/form/templates/forms/fields/toggle/edit_list.html.twig @@ -0,0 +1,5 @@ +{%- if value -%} + +{%- else -%} + +{%- endif -%} diff --git a/user/plugins/form/templates/forms/fields/toggle/toggle.html.twig b/user/plugins/form/templates/forms/fields/toggle/toggle.html.twig new file mode 100644 index 00000000..cea180f4 --- /dev/null +++ b/user/plugins/form/templates/forms/fields/toggle/toggle.html.twig @@ -0,0 +1,63 @@ +{% extends "forms/field.html.twig" %} + +{% macro spanToggle(input, length) %} + {% set space = repeat('  ', (length - input|length) / 2) %} + {{ (space ~ input ~ space)|raw }} +{% endmacro %} + +{% import _self as macro %} + +{% set value = value ?? field.default %} +{% set value = (value is same as(false) ? 0 : value) %} + +{% set has_hidden = false %} +{% for key, text in field.options %} + {% if key is empty %} + {% set has_hidden = true %} + {% endif %} +{% endfor %} + +{% block global_attributes %} + {{ parent() }} + data-grav-field-name="{{ (scope ~ field.name)|fieldName }}" +{% endblock %} + +{% block input %} + +
                                                            + {% set maxLen = 0 %} + {% for text in field.options %} + {% set translation = text|t|trim %} + {% set maxLen = max(translation|length, maxLen) %} + {% endfor %} + + {% for key, text in field.options %} + {% set id = "toggle_" ~ field.name ~ key %} + {% set translation = text|t|trim %} + + + + {% endfor %} +
                                                            +{% endblock %} diff --git a/user/plugins/form/templates/forms/fields/uniqueid/uniqueid.html.twig b/user/plugins/form/templates/forms/fields/uniqueid/uniqueid.html.twig new file mode 100644 index 00000000..dc23d4fd --- /dev/null +++ b/user/plugins/form/templates/forms/fields/uniqueid/uniqueid.html.twig @@ -0,0 +1,5 @@ +{% extends "forms/field.html.twig" %} + +{% block field %} + +{% endblock %} \ No newline at end of file diff --git a/user/plugins/form/templates/forms/fields/url/edit_list.html.twig b/user/plugins/form/templates/forms/fields/url/edit_list.html.twig new file mode 100644 index 00000000..010e8679 --- /dev/null +++ b/user/plugins/form/templates/forms/fields/url/edit_list.html.twig @@ -0,0 +1 @@ +{{ value|e }} diff --git a/user/plugins/form/templates/forms/fields/url/url.html.twig b/user/plugins/form/templates/forms/fields/url/url.html.twig new file mode 100644 index 00000000..1caae0f8 --- /dev/null +++ b/user/plugins/form/templates/forms/fields/url/url.html.twig @@ -0,0 +1,6 @@ +{% extends "forms/field.html.twig" %} + +{% block input_attributes %} + type="url" + {{ parent() }} +{% endblock %} \ No newline at end of file diff --git a/user/plugins/form/templates/forms/fields/value/value.html.twig b/user/plugins/form/templates/forms/fields/value/value.html.twig new file mode 100644 index 00000000..41d645e8 --- /dev/null +++ b/user/plugins/form/templates/forms/fields/value/value.html.twig @@ -0,0 +1,18 @@ +{% extends "forms/field.html.twig" %} + +{% if field.options %} + {% set value = field.options[value] ?: value %} +{% endif %} + +{% block input %} + + {% switch field.filter %} + {% case 'date' %} + {{ value|date }} + {% case 'raw' %} + {{ value|raw }} + {% default %} + {{ value }} + {% endswitch %} + +{% endblock %} \ No newline at end of file diff --git a/user/plugins/form/templates/forms/fields/week/week.html.twig b/user/plugins/form/templates/forms/fields/week/week.html.twig new file mode 100644 index 00000000..c56f8711 --- /dev/null +++ b/user/plugins/form/templates/forms/fields/week/week.html.twig @@ -0,0 +1,6 @@ +{% extends "forms/field.html.twig" %} + +{% block input_attributes %} + type="week" + {{ parent() }} +{% endblock %} diff --git a/user/plugins/form/templates/forms/form.html.twig b/user/plugins/form/templates/forms/form.html.twig new file mode 100644 index 00000000..8f1d4670 --- /dev/null +++ b/user/plugins/form/templates/forms/form.html.twig @@ -0,0 +1 @@ +{% extends "forms/default/form.html.twig" %} diff --git a/user/plugins/form/templates/forms/layouts/button.html.twig b/user/plugins/form/templates/forms/layouts/button.html.twig new file mode 100644 index 00000000..ef603640 --- /dev/null +++ b/user/plugins/form/templates/forms/layouts/button.html.twig @@ -0,0 +1,12 @@ +{% set button_tag %} + +{% endset %} + +{% if button_url %} + {{ button_tag|trim|raw }} +{% else %} + {{ button_tag|trim|raw }} +{% endif %} diff --git a/user/plugins/form/templates/forms/layouts/field-variables.html.twig b/user/plugins/form/templates/forms/layouts/field-variables.html.twig new file mode 100644 index 00000000..74091326 --- /dev/null +++ b/user/plugins/form/templates/forms/layouts/field-variables.html.twig @@ -0,0 +1 @@ +{% block field_input_classes %}{% endblock %} \ No newline at end of file diff --git a/user/plugins/form/templates/forms/layouts/field.html.twig b/user/plugins/form/templates/forms/layouts/field.html.twig new file mode 100644 index 00000000..dd037da8 --- /dev/null +++ b/user/plugins/form/templates/forms/layouts/field.html.twig @@ -0,0 +1,52 @@ +{% block field %} +
                                                            + {% block contents %} + {% if show_label %} +
                                                            + {{- form_field_toggleable -}} + +
                                                            + {% endif %} +
                                                            + {% block group %} + {% block input %} +
                                                            + {% block prepend %}{% endblock prepend %} + + {% block append %}{% endblock append %} + {% if inline_errors and errors %} +
                                                            +

                                                            {{ errors|first|raw }}

                                                            +
                                                            + {% endif %} +
                                                            + {% endblock %} + {% endblock %} + {% if field.description %} +
                                                            + + {{ form_field_description|raw }} + +
                                                            + {% endif %} +
                                                            + {% endblock %} +
                                                            +{% endblock %} \ No newline at end of file diff --git a/user/plugins/form/templates/forms/layouts/form.html.twig b/user/plugins/form/templates/forms/layouts/form.html.twig new file mode 100644 index 00000000..ef6b1693 --- /dev/null +++ b/user/plugins/form/templates/forms/layouts/form.html.twig @@ -0,0 +1,7 @@ +
                                                            + {% block embed_fields %}{% endblock %} + {% block embed_buttons %}{% endblock %} +
                                                            \ No newline at end of file diff --git a/user/plugins/form/templates/modular/form.html.twig b/user/plugins/form/templates/modular/form.html.twig new file mode 100644 index 00000000..3e06da56 --- /dev/null +++ b/user/plugins/form/templates/modular/form.html.twig @@ -0,0 +1,4 @@ +
                                                            + {{ content|raw }} + {% include "forms/form.html.twig" %} +
                                                            \ No newline at end of file diff --git a/user/plugins/form/templates/partials/form-messages.html.twig b/user/plugins/form/templates/partials/form-messages.html.twig new file mode 100644 index 00000000..bf302649 --- /dev/null +++ b/user/plugins/form/templates/partials/form-messages.html.twig @@ -0,0 +1,6 @@ +{% if form.message %} + {% set inline_errors = form.inline_errors is not null ? form.inline_errors : config.plugins.form.inline_errors(false) %} + {% set status_mapping = {'success':'green', 'error': 'red', 'warning': 'yellow'} %} + {% set message = inline_errors and form.messages ? "GRAV.FORM.VALIDATION_FAIL"|t : form.message %} +

                                                            {{ message|raw }}

                                                            +{% endif %} \ No newline at end of file diff --git a/user/plugins/form/templates/partials/form-messages.json.twig b/user/plugins/form/templates/partials/form-messages.json.twig new file mode 100644 index 00000000..7d380196 --- /dev/null +++ b/user/plugins/form/templates/partials/form-messages.json.twig @@ -0,0 +1,3 @@ +{% set inline_errors = form.inline_errors is not null ? form.inline_errors : config.plugins.form.inline_errors(false) %} +{% set message = inline_errors and form.messages ? "GRAV.FORM.VALIDATION_FAIL"|t : form.message %} +{{ {'status':form.status, 'message':message}|json_encode|raw }} diff --git a/user/plugins/form/vendor/autoload.php b/user/plugins/form/vendor/autoload.php new file mode 100644 index 00000000..3704b65c --- /dev/null +++ b/user/plugins/form/vendor/autoload.php @@ -0,0 +1,7 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer\Autoload; + +/** + * ClassLoader implements a PSR-0, PSR-4 and classmap class loader. + * + * $loader = new \Composer\Autoload\ClassLoader(); + * + * // register classes with namespaces + * $loader->add('Symfony\Component', __DIR__.'/component'); + * $loader->add('Symfony', __DIR__.'/framework'); + * + * // activate the autoloader + * $loader->register(); + * + * // to enable searching the include path (eg. for PEAR packages) + * $loader->setUseIncludePath(true); + * + * In this example, if you try to use a class in the Symfony\Component + * namespace or one of its children (Symfony\Component\Console for instance), + * the autoloader will first look for the class under the component/ + * directory, and it will then fallback to the framework/ directory if not + * found before giving up. + * + * This class is loosely based on the Symfony UniversalClassLoader. + * + * @author Fabien Potencier + * @author Jordi Boggiano + * @see http://www.php-fig.org/psr/psr-0/ + * @see http://www.php-fig.org/psr/psr-4/ + */ +class ClassLoader +{ + // PSR-4 + private $prefixLengthsPsr4 = array(); + private $prefixDirsPsr4 = array(); + private $fallbackDirsPsr4 = array(); + + // PSR-0 + private $prefixesPsr0 = array(); + private $fallbackDirsPsr0 = array(); + + private $useIncludePath = false; + private $classMap = array(); + private $classMapAuthoritative = false; + private $missingClasses = array(); + private $apcuPrefix; + + public function getPrefixes() + { + if (!empty($this->prefixesPsr0)) { + return call_user_func_array('array_merge', $this->prefixesPsr0); + } + + return array(); + } + + public function getPrefixesPsr4() + { + return $this->prefixDirsPsr4; + } + + public function getFallbackDirs() + { + return $this->fallbackDirsPsr0; + } + + public function getFallbackDirsPsr4() + { + return $this->fallbackDirsPsr4; + } + + public function getClassMap() + { + return $this->classMap; + } + + /** + * @param array $classMap Class to filename map + */ + public function addClassMap(array $classMap) + { + if ($this->classMap) { + $this->classMap = array_merge($this->classMap, $classMap); + } else { + $this->classMap = $classMap; + } + } + + /** + * Registers a set of PSR-0 directories for a given prefix, either + * appending or prepending to the ones previously set for this prefix. + * + * @param string $prefix The prefix + * @param array|string $paths The PSR-0 root directories + * @param bool $prepend Whether to prepend the directories + */ + public function add($prefix, $paths, $prepend = false) + { + if (!$prefix) { + if ($prepend) { + $this->fallbackDirsPsr0 = array_merge( + (array) $paths, + $this->fallbackDirsPsr0 + ); + } else { + $this->fallbackDirsPsr0 = array_merge( + $this->fallbackDirsPsr0, + (array) $paths + ); + } + + return; + } + + $first = $prefix[0]; + if (!isset($this->prefixesPsr0[$first][$prefix])) { + $this->prefixesPsr0[$first][$prefix] = (array) $paths; + + return; + } + if ($prepend) { + $this->prefixesPsr0[$first][$prefix] = array_merge( + (array) $paths, + $this->prefixesPsr0[$first][$prefix] + ); + } else { + $this->prefixesPsr0[$first][$prefix] = array_merge( + $this->prefixesPsr0[$first][$prefix], + (array) $paths + ); + } + } + + /** + * Registers a set of PSR-4 directories for a given namespace, either + * appending or prepending to the ones previously set for this namespace. + * + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param array|string $paths The PSR-4 base directories + * @param bool $prepend Whether to prepend the directories + * + * @throws \InvalidArgumentException + */ + public function addPsr4($prefix, $paths, $prepend = false) + { + if (!$prefix) { + // Register directories for the root namespace. + if ($prepend) { + $this->fallbackDirsPsr4 = array_merge( + (array) $paths, + $this->fallbackDirsPsr4 + ); + } else { + $this->fallbackDirsPsr4 = array_merge( + $this->fallbackDirsPsr4, + (array) $paths + ); + } + } elseif (!isset($this->prefixDirsPsr4[$prefix])) { + // Register directories for a new namespace. + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = (array) $paths; + } elseif ($prepend) { + // Prepend directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + (array) $paths, + $this->prefixDirsPsr4[$prefix] + ); + } else { + // Append directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + $this->prefixDirsPsr4[$prefix], + (array) $paths + ); + } + } + + /** + * Registers a set of PSR-0 directories for a given prefix, + * replacing any others previously set for this prefix. + * + * @param string $prefix The prefix + * @param array|string $paths The PSR-0 base directories + */ + public function set($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr0 = (array) $paths; + } else { + $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths; + } + } + + /** + * Registers a set of PSR-4 directories for a given namespace, + * replacing any others previously set for this namespace. + * + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param array|string $paths The PSR-4 base directories + * + * @throws \InvalidArgumentException + */ + public function setPsr4($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr4 = (array) $paths; + } else { + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = (array) $paths; + } + } + + /** + * Turns on searching the include path for class files. + * + * @param bool $useIncludePath + */ + public function setUseIncludePath($useIncludePath) + { + $this->useIncludePath = $useIncludePath; + } + + /** + * Can be used to check if the autoloader uses the include path to check + * for classes. + * + * @return bool + */ + public function getUseIncludePath() + { + return $this->useIncludePath; + } + + /** + * Turns off searching the prefix and fallback directories for classes + * that have not been registered with the class map. + * + * @param bool $classMapAuthoritative + */ + public function setClassMapAuthoritative($classMapAuthoritative) + { + $this->classMapAuthoritative = $classMapAuthoritative; + } + + /** + * Should class lookup fail if not found in the current class map? + * + * @return bool + */ + public function isClassMapAuthoritative() + { + return $this->classMapAuthoritative; + } + + /** + * APCu prefix to use to cache found/not-found classes, if the extension is enabled. + * + * @param string|null $apcuPrefix + */ + public function setApcuPrefix($apcuPrefix) + { + $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null; + } + + /** + * The APCu prefix in use, or null if APCu caching is not enabled. + * + * @return string|null + */ + public function getApcuPrefix() + { + return $this->apcuPrefix; + } + + /** + * Registers this instance as an autoloader. + * + * @param bool $prepend Whether to prepend the autoloader or not + */ + public function register($prepend = false) + { + spl_autoload_register(array($this, 'loadClass'), true, $prepend); + } + + /** + * Unregisters this instance as an autoloader. + */ + public function unregister() + { + spl_autoload_unregister(array($this, 'loadClass')); + } + + /** + * Loads the given class or interface. + * + * @param string $class The name of the class + * @return bool|null True if loaded, null otherwise + */ + public function loadClass($class) + { + if ($file = $this->findFile($class)) { + includeFile($file); + + return true; + } + } + + /** + * Finds the path to the file where the class is defined. + * + * @param string $class The name of the class + * + * @return string|false The path if found, false otherwise + */ + public function findFile($class) + { + // class map lookup + if (isset($this->classMap[$class])) { + return $this->classMap[$class]; + } + if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) { + return false; + } + if (null !== $this->apcuPrefix) { + $file = apcu_fetch($this->apcuPrefix.$class, $hit); + if ($hit) { + return $file; + } + } + + $file = $this->findFileWithExtension($class, '.php'); + + // Search for Hack files if we are running on HHVM + if (false === $file && defined('HHVM_VERSION')) { + $file = $this->findFileWithExtension($class, '.hh'); + } + + if (null !== $this->apcuPrefix) { + apcu_add($this->apcuPrefix.$class, $file); + } + + if (false === $file) { + // Remember that this class does not exist. + $this->missingClasses[$class] = true; + } + + return $file; + } + + private function findFileWithExtension($class, $ext) + { + // PSR-4 lookup + $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext; + + $first = $class[0]; + if (isset($this->prefixLengthsPsr4[$first])) { + $subPath = $class; + while (false !== $lastPos = strrpos($subPath, '\\')) { + $subPath = substr($subPath, 0, $lastPos); + $search = $subPath . '\\'; + if (isset($this->prefixDirsPsr4[$search])) { + $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1); + foreach ($this->prefixDirsPsr4[$search] as $dir) { + if (file_exists($file = $dir . $pathEnd)) { + return $file; + } + } + } + } + } + + // PSR-4 fallback dirs + foreach ($this->fallbackDirsPsr4 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) { + return $file; + } + } + + // PSR-0 lookup + if (false !== $pos = strrpos($class, '\\')) { + // namespaced class name + $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1) + . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR); + } else { + // PEAR-like class name + $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext; + } + + if (isset($this->prefixesPsr0[$first])) { + foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) { + if (0 === strpos($class, $prefix)) { + foreach ($dirs as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + } + } + } + + // PSR-0 fallback dirs + foreach ($this->fallbackDirsPsr0 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + + // PSR-0 include paths. + if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { + return $file; + } + + return false; + } +} + +/** + * Scope isolated include. + * + * Prevents access to $this/self from included files. + */ +function includeFile($file) +{ + include $file; +} diff --git a/user/plugins/form/vendor/composer/LICENSE b/user/plugins/form/vendor/composer/LICENSE new file mode 100644 index 00000000..f27399a0 --- /dev/null +++ b/user/plugins/form/vendor/composer/LICENSE @@ -0,0 +1,21 @@ + +Copyright (c) Nils Adermann, Jordi Boggiano + +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. + diff --git a/user/plugins/form/vendor/composer/autoload_classmap.php b/user/plugins/form/vendor/composer/autoload_classmap.php new file mode 100644 index 00000000..58c38337 --- /dev/null +++ b/user/plugins/form/vendor/composer/autoload_classmap.php @@ -0,0 +1,10 @@ + $baseDir . '/form.php', +); diff --git a/user/plugins/form/vendor/composer/autoload_namespaces.php b/user/plugins/form/vendor/composer/autoload_namespaces.php new file mode 100644 index 00000000..b7fc0125 --- /dev/null +++ b/user/plugins/form/vendor/composer/autoload_namespaces.php @@ -0,0 +1,9 @@ + array($vendorDir . '/google/recaptcha/src/ReCaptcha'), + 'Grav\\Plugin\\Form\\' => array($baseDir . '/classes'), +); diff --git a/user/plugins/form/vendor/composer/autoload_real.php b/user/plugins/form/vendor/composer/autoload_real.php new file mode 100644 index 00000000..e9ea4f26 --- /dev/null +++ b/user/plugins/form/vendor/composer/autoload_real.php @@ -0,0 +1,52 @@ += 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded()); + if ($useStaticLoader) { + require_once __DIR__ . '/autoload_static.php'; + + call_user_func(\Composer\Autoload\ComposerStaticInitd9f2f96e3ad6fd86ce688af0527a1d7b::getInitializer($loader)); + } else { + $map = require __DIR__ . '/autoload_namespaces.php'; + foreach ($map as $namespace => $path) { + $loader->set($namespace, $path); + } + + $map = require __DIR__ . '/autoload_psr4.php'; + foreach ($map as $namespace => $path) { + $loader->setPsr4($namespace, $path); + } + + $classMap = require __DIR__ . '/autoload_classmap.php'; + if ($classMap) { + $loader->addClassMap($classMap); + } + } + + $loader->register(true); + + return $loader; + } +} diff --git a/user/plugins/form/vendor/composer/autoload_static.php b/user/plugins/form/vendor/composer/autoload_static.php new file mode 100644 index 00000000..eda5edc0 --- /dev/null +++ b/user/plugins/form/vendor/composer/autoload_static.php @@ -0,0 +1,44 @@ + + array ( + 'ReCaptcha\\' => 10, + ), + 'G' => + array ( + 'Grav\\Plugin\\Form\\' => 17, + ), + ); + + public static $prefixDirsPsr4 = array ( + 'ReCaptcha\\' => + array ( + 0 => __DIR__ . '/..' . '/google/recaptcha/src/ReCaptcha', + ), + 'Grav\\Plugin\\Form\\' => + array ( + 0 => __DIR__ . '/../..' . '/classes', + ), + ); + + public static $classMap = array ( + 'Grav\\Plugin\\FormPlugin' => __DIR__ . '/../..' . '/form.php', + ); + + public static function getInitializer(ClassLoader $loader) + { + return \Closure::bind(function () use ($loader) { + $loader->prefixLengthsPsr4 = ComposerStaticInitd9f2f96e3ad6fd86ce688af0527a1d7b::$prefixLengthsPsr4; + $loader->prefixDirsPsr4 = ComposerStaticInitd9f2f96e3ad6fd86ce688af0527a1d7b::$prefixDirsPsr4; + $loader->classMap = ComposerStaticInitd9f2f96e3ad6fd86ce688af0527a1d7b::$classMap; + + }, null, ClassLoader::class); + } +} diff --git a/user/plugins/form/vendor/composer/installed.json b/user/plugins/form/vendor/composer/installed.json new file mode 100644 index 00000000..faaf4f2b --- /dev/null +++ b/user/plugins/form/vendor/composer/installed.json @@ -0,0 +1,51 @@ +[ + { + "name": "google/recaptcha", + "version": "1.2.3", + "version_normalized": "1.2.3.0", + "source": { + "type": "git", + "url": "https://github.com/google/recaptcha.git", + "reference": "98c4a6573b27e8b0990ea8789c74ea378795134c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/google/recaptcha/zipball/98c4a6573b27e8b0990ea8789c74ea378795134c", + "reference": "98c4a6573b27e8b0990ea8789c74ea378795134c", + "shasum": "" + }, + "require": { + "php": ">=5.5" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^2.2.20|^2.15", + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^4.8.36|^5.7.27|^6.59|^7.5.11" + }, + "time": "2019-08-16T15:48:25+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "ReCaptcha\\": "src/ReCaptcha" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "Client library for reCAPTCHA, a free service that protects websites from spam and abuse.", + "homepage": "https://www.google.com/recaptcha/", + "keywords": [ + "Abuse", + "captcha", + "recaptcha", + "spam" + ] + } +] diff --git a/user/plugins/form/vendor/google/recaptcha/.github/ISSUE_TEMPLATE/bug_report.md b/user/plugins/form/vendor/google/recaptcha/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 00000000..a14dcfee --- /dev/null +++ b/user/plugins/form/vendor/google/recaptcha/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,28 @@ +--- +name: PHP client issue +about: Report an issue with the PHP client library + +--- + +**Issue description** + + +**Environment** + + + * OS name and version: + * PHP version: + * Web server name and version: + * `google/recaptcha` version: + * Browser name and version: + +**Reproducing the issue** + + + * URL (optional): + * Code (optional): + + ***User steps*** + + + 1. Visit page... diff --git a/user/plugins/form/vendor/google/recaptcha/ARCHITECTURE.md b/user/plugins/form/vendor/google/recaptcha/ARCHITECTURE.md new file mode 100644 index 00000000..13add265 --- /dev/null +++ b/user/plugins/form/vendor/google/recaptcha/ARCHITECTURE.md @@ -0,0 +1,64 @@ +# Architecture + +The general pattern of usage is to instantiate the `ReCaptcha` class with your +secret key, specify any additional validation rules, and then call `verify()` +with the reCAPTCHA response and user's IP address. For example: + +```php +setExpectedHostname('recaptcha-demo.appspot.com') + ->verify($gRecaptchaResponse, $remoteIp); +if ($resp->isSuccess()) { + // Verified! +} else { + $errors = $resp->getErrorCodes(); +} +``` + +By default, this will use the +[`stream_context_create()`](https://secure.php.net/stream_context_create) and +[`file_get_contents()`](https://secure.php.net/file_get_contents) to make a POST +request to the reCAPTCHA service. This is handled by the +[`RequestMethod\Post`](./src/ReCaptcha/RequestMethod/Post.php) class. + +## Alternate request methods + +You may need to use other methods for making requests in your environment. The +[`ReCaptcha`](./src/ReCaptcha/ReCaptcha.php) class allows an optional +[`RequestMethod`](./src/ReCaptcha/RequestMethod.php) instance to configure this. +For example, if you want to use [cURL](https://secure.php.net/curl) instead you +can do this: + +```php +setExpectedHostname('recaptcha-demo.appspot.com') + ->verify($gRecaptchaResponse, $remoteIp); +if ($resp->isSuccess()) { + // Verified! +} else { + $errors = $resp->getErrorCodes(); +} +``` + +The following methods are available: + +- `setExpectedHostname($hostname)`: ensures the hostname matches. You must do + this if you have disabled "Domain/Package Name Validation" for your + credentials. +- `setExpectedApkPackageName($apkPackageName)`: if you're verifying a response + from an Android app. Again, you must do this if you have disabled + "Domain/Package Name Validation" for your credentials. +- `setExpectedAction($action)`: ensures the action matches for the v3 API. +- `setScoreThreshold($threshold)`: set a score theshold for responses from the + v3 API +- `setChallengeTimeout($timeoutSeconds)`: set a timeout between the user passing + the reCAPTCHA and your server processing it. + +Each of the `set`\*`()` methods return the `ReCaptcha` instance so you can chain +them together. For example: + +```php +setExpectedHostname('recaptcha-demo.appspot.com') + ->setExpectedAction('homepage') + ->setScoreThreshold(0.5) + ->verify($gRecaptchaResponse, $remoteIp); + +if ($resp->isSuccess()) { + // Verified! +} else { + $errors = $resp->getErrorCodes(); +} +``` + +You can find the constants for the libraries error codes in the `ReCaptcha` +class constants, e.g. `ReCaptcha::E_HOSTNAME_MISMATCH` + +For more details on usage and structure, see [ARCHITECTURE](ARCHITECTURE.md). + +### Examples + +You can see examples of each reCAPTCHA type in [examples/](examples/). You can +run the examples locally by using the Composer script: + +```sh +composer run-script serve-examples +``` + +This makes use of the in-built PHP dev server to host the examples at +http://localhost:8080/ + +These are also hosted on Google AppEngine Flexible environment at +https://recaptcha-demo.appspot.com/. This is configured by +[`app.yaml`](./app.yaml) which you can also use to [deploy to your own AppEngine +project](https://cloud.google.com/appengine/docs/flexible/php/download). + +## Contributing + +No one ever has enough engineers, so we're very happy to accept contributions +via Pull Requests. For details, see [CONTRIBUTING](CONTRIBUTING.md) diff --git a/user/plugins/form/vendor/google/recaptcha/app.yaml b/user/plugins/form/vendor/google/recaptcha/app.yaml new file mode 100644 index 00000000..b6ccaf18 --- /dev/null +++ b/user/plugins/form/vendor/google/recaptcha/app.yaml @@ -0,0 +1,8 @@ +runtime: php +env: flex + +skip_files: +- tests + +runtime_config: + document_root: examples diff --git a/user/plugins/form/vendor/google/recaptcha/composer.json b/user/plugins/form/vendor/google/recaptcha/composer.json new file mode 100644 index 00000000..ab6b4f1c --- /dev/null +++ b/user/plugins/form/vendor/google/recaptcha/composer.json @@ -0,0 +1,39 @@ +{ + "name": "google/recaptcha", + "description": "Client library for reCAPTCHA, a free service that protects websites from spam and abuse.", + "type": "library", + "keywords": ["recaptcha", "captcha", "spam", "abuse"], + "homepage": "https://www.google.com/recaptcha/", + "license": "BSD-3-Clause", + "support": { + "forum": "https://groups.google.com/forum/#!forum/recaptcha", + "source": "https://github.com/google/recaptcha" + }, + "require": { + "php": ">=5.5" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.36|^5.7.27|^6.59|^7.5.11", + "friendsofphp/php-cs-fixer": "^2.2.20|^2.15", + "php-coveralls/php-coveralls": "^2.1" + }, + "autoload": { + "psr-4": { + "ReCaptcha\\": "src/ReCaptcha" + } + }, + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + }, + "scripts": { + "lint": "vendor/bin/php-cs-fixer -vvv fix --using-cache=no --dry-run .", + "lint-fix": "vendor/bin/php-cs-fixer -vvv fix --using-cache=no .", + "test": "vendor/bin/phpunit --colors=always", + "serve-examples": "@php -S localhost:8080 -t examples" + }, + "config": { + "process-timeout": 0 + } +} diff --git a/user/plugins/form/vendor/google/recaptcha/examples/appengine-https.php b/user/plugins/form/vendor/google/recaptcha/examples/appengine-https.php new file mode 100644 index 00000000..039e2db6 --- /dev/null +++ b/user/plugins/form/vendor/google/recaptcha/examples/appengine-https.php @@ -0,0 +1,42 @@ + [ + 'site' => '', + 'secret' => '', + ], + 'v2-invisible' => [ + 'site' => '', + 'secret' => '', + ], + 'v3' => [ + 'site' => '', + 'secret' => '', + ], +]; diff --git a/user/plugins/form/vendor/google/recaptcha/examples/examples.css b/user/plugins/form/vendor/google/recaptcha/examples/examples.css new file mode 100644 index 00000000..cb3647b3 --- /dev/null +++ b/user/plugins/form/vendor/google/recaptcha/examples/examples.css @@ -0,0 +1,37 @@ +body { + font-family: sans-serif; + margin: 0; + padding: 0; +} + +h1, +h2, +p { + margin: 0; + padding: 0.5rem 0 0 0; + font-weight: normal; +} + +h1, +h2 { + color: #222244; +} + +header { + padding: 0.5rem 2rem 0.5rem 2rem; + background: #f0f0f4; + border-bottom: 1px solid #aaaabb; +} + +main { + padding: 0.5rem 2rem 0.5rem 2rem; +} + +.form-field { + display: block; + margin: 1rem; +} + +.hidden { + display: none; +} diff --git a/user/plugins/form/vendor/google/recaptcha/examples/google0afd8760fd68f119.html b/user/plugins/form/vendor/google/recaptcha/examples/google0afd8760fd68f119.html new file mode 100644 index 00000000..457c4717 --- /dev/null +++ b/user/plugins/form/vendor/google/recaptcha/examples/google0afd8760fd68f119.html @@ -0,0 +1 @@ +google-site-verification: google0afd8760fd68f119.html \ No newline at end of file diff --git a/user/plugins/form/vendor/google/recaptcha/examples/index.php b/user/plugins/form/vendor/google/recaptcha/examples/index.php new file mode 100644 index 00000000..b715acc8 --- /dev/null +++ b/user/plugins/form/vendor/google/recaptcha/examples/index.php @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + +reCAPTCHA demo + +
                                                            +

                                                            reCAPTCHA demo

                                                            +
                                                            +
                                                            +

                                                            Try out the various forms of reCAPTCHA.

                                                            +

                                                            You can find the source code for these examples on GitHub in google/recaptcha.

                                                            + +
                                                            + + + + diff --git a/user/plugins/form/vendor/google/recaptcha/examples/recaptcha-content-security-policy.php b/user/plugins/form/vendor/google/recaptcha/examples/recaptcha-content-security-policy.php new file mode 100644 index 00000000..aaf7eb27 --- /dev/null +++ b/user/plugins/form/vendor/google/recaptcha/examples/recaptcha-content-security-policy.php @@ -0,0 +1,152 @@ + + + + + + + + + + + + + + +reCAPTCHA demo - Content Security Policy +
                                                            +

                                                            reCAPTCHA demo

                                                            Content Security Policy

                                                            +

                                                            ↩️ Home

                                                            +
                                                            +
                                                            + +

                                                            Add your keys

                                                            +

                                                            If you do not have keys already then visit https://www.google.com/recaptcha/admin to generate them. Edit this file and set the respective keys in $siteKey and $secret. Reload the page after this.

                                                            + +

                                                            This example is sending the Content-Security-Policy header. Look at the source and inspect the network tab for this request to see what's happening. The reCAPTCHA v3 API is being called here, however you can use the same approach for the v2 API calls as well.

                                                            +

                                                            NOTE:This is a sample implementation, the score returned here is not a reflection on your Google account or type of traffic. In production, refer to the distribution of scores shown in your admin interface and adjust your own threshold accordingly. Do not raise issues regarding the score you see here.

                                                            +
                                                              +
                                                            1. reCAPTCHA script loading
                                                            2. + + + +
                                                            +

                                                            ⤴️ Try again

                                                            + + + + + + + +
                                                            + + + + diff --git a/user/plugins/form/vendor/google/recaptcha/examples/recaptcha-v2-checkbox-explicit.php b/user/plugins/form/vendor/google/recaptcha/examples/recaptcha-v2-checkbox-explicit.php new file mode 100644 index 00000000..fb429a27 --- /dev/null +++ b/user/plugins/form/vendor/google/recaptcha/examples/recaptcha-v2-checkbox-explicit.php @@ -0,0 +1,148 @@ + + + + + + + + + + + + + + +reCAPTCHA demo - "I'm not a robot" checkbox - Explicit render + +
                                                            +

                                                            reCAPTCHA demo

                                                            "I'm not a robot" checkbox - Explicit render

                                                            +

                                                            ↩️ Home

                                                            +
                                                            +
                                                            + +

                                                            Add your keys

                                                            +

                                                            If you do not have keys already then visit https://www.google.com/recaptcha/admin to generate them. Edit this file and set the respective keys in the config.php file or directly to $siteKey and $secret. Reload the page after this.

                                                            + +

                                                            POST data

                                                            +
                                                            + setExpectedHostname($_SERVER['SERVER_NAME']) + ->verify($_POST['g-recaptcha-response'], $_SERVER['REMOTE_ADDR']); + + if ($resp->isSuccess()): + // If the response is a success, that's it! + ?> +

                                                            Success!

                                                            +
                                                            +

                                                            That's it. Everything is working. Go integrate this into your real project.

                                                            +

                                                            ⤴️ Try again

                                                            + +

                                                            Something went wrong

                                                            +
                                                            +

                                                            Check the error code reference at https://developers.google.com/recaptcha/docs/verify#error-code-reference. +

                                                            Note: Error code missing-input-response may mean the user just didn't complete the reCAPTCHA.

                                                            +

                                                            ⤴️ Try again

                                                            + +

                                                            Complete the reCAPTCHA then submit the form.

                                                            +
                                                            +
                                                            + An example form + + + +
                                                            + + +
                                                            +
                                                            + + + +
                                                            + + + + diff --git a/user/plugins/form/vendor/google/recaptcha/examples/recaptcha-v2-checkbox.php b/user/plugins/form/vendor/google/recaptcha/examples/recaptcha-v2-checkbox.php new file mode 100644 index 00000000..9395d592 --- /dev/null +++ b/user/plugins/form/vendor/google/recaptcha/examples/recaptcha-v2-checkbox.php @@ -0,0 +1,139 @@ + + + + + + + + + + + + + + +reCAPTCHA demo - "I'm not a robot" checkbox + +
                                                            +

                                                            reCAPTCHA demo

                                                            "I'm not a robot" checkbox

                                                            +

                                                            ↩️ Home

                                                            +
                                                            +
                                                            + +

                                                            Add your keys

                                                            +

                                                            If you do not have keys already then visit https://www.google.com/recaptcha/admin to generate them. Edit this file and set the respective keys in the config.php file or directly to $siteKey and $secret. Reload the page after this.

                                                            + +

                                                            POST data

                                                            +
                                                            + setExpectedHostname($_SERVER['SERVER_NAME']) + ->verify($_POST['g-recaptcha-response'], $_SERVER['REMOTE_ADDR']); + if ($resp->isSuccess()): + // If the response is a success, that's it! + ?> +

                                                            Success!

                                                            +
                                                            +

                                                            That's it. Everything is working. Go integrate this into your real project.

                                                            +

                                                            ⤴️ Try again

                                                            + +

                                                            Something went wrong

                                                            +
                                                            +

                                                            Check the error code reference at https://developers.google.com/recaptcha/docs/verify#error-code-reference. +

                                                            Note: Error code missing-input-response may mean the user just didn't complete the reCAPTCHA.

                                                            +

                                                            ⤴️ Try again

                                                            + +

                                                            Complete the reCAPTCHA then submit the form.

                                                            +
                                                            +
                                                            + An example form + + + +
                                                            + + +
                                                            +
                                                            + + +
                                                            + + + + diff --git a/user/plugins/form/vendor/google/recaptcha/examples/recaptcha-v2-invisible.php b/user/plugins/form/vendor/google/recaptcha/examples/recaptcha-v2-invisible.php new file mode 100644 index 00000000..c3b93978 --- /dev/null +++ b/user/plugins/form/vendor/google/recaptcha/examples/recaptcha-v2-invisible.php @@ -0,0 +1,141 @@ + + + + + + + + + + + + + + +reCAPTCHA demo - Invisible + +
                                                            +

                                                            reCAPTCHA demo

                                                            Invisible

                                                            +

                                                            ↩️ Home

                                                            +
                                                            +
                                                            + +

                                                            Add your keys

                                                            +

                                                            If you do not have keys already then visit https://www.google.com/recaptcha/admin to generate them. Edit this file and set the respective keys in $siteKey and $secret. Reload the page after this.

                                                            + +

                                                            POST data

                                                            +
                                                            + setExpectedHostname($_SERVER['SERVER_NAME']) + ->verify($_POST['g-recaptcha-response'], $_SERVER['REMOTE_ADDR']); + if ($resp->isSuccess()): + // If the response is a success, that's it! + ?> +

                                                            Success!

                                                            +
                                                            +

                                                            That's it. Everything is working. Go integrate this into your real project.

                                                            +

                                                            ⤴️ Try again

                                                            + +

                                                            Something went wrong

                                                            +
                                                            +

                                                            Check the error code reference at https://developers.google.com/recaptcha/docs/verify#error-code-reference. +

                                                            Note: Error code missing-input-response may mean the user just didn't complete the reCAPTCHA.

                                                            +

                                                            ⤴️ Try again

                                                            + +

                                                            Submit the form and reCAPTCHA will run automatically.

                                                            +
                                                            +
                                                            + An example form + + + +
                                                            +
                                                            + + + +
                                                            + + + + diff --git a/user/plugins/form/vendor/google/recaptcha/examples/recaptcha-v3-request-scores.php b/user/plugins/form/vendor/google/recaptcha/examples/recaptcha-v3-request-scores.php new file mode 100644 index 00000000..d9430bb0 --- /dev/null +++ b/user/plugins/form/vendor/google/recaptcha/examples/recaptcha-v3-request-scores.php @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + +reCAPTCHA demo - Request scores +
                                                            +

                                                            reCAPTCHA demo

                                                            Request scores

                                                            +

                                                            ↩️ Home

                                                            +
                                                            +
                                                            + +

                                                            Add your keys

                                                            +

                                                            If you do not have keys already then visit https://www.google.com/recaptcha/admin to generate them. Edit this file and set the respective keys in $siteKey and $secret. Reload the page after this.

                                                            + +

                                                            The reCAPTCHA v3 API provides a confidence score for each request.

                                                            +

                                                            NOTE:This is a sample implementation, the score returned here is not a reflection on your Google account or type of traffic. In production, refer to the distribution of scores shown in your admin interface and adjust your own threshold accordingly. Do not raise issues regarding the score you see here.

                                                            +
                                                              +
                                                            1. reCAPTCHA script loading
                                                            2. + + + +
                                                            +

                                                            ⤴️ Try again

                                                            + + + +
                                                            + + + diff --git a/user/plugins/form/vendor/google/recaptcha/examples/recaptcha-v3-verify.php b/user/plugins/form/vendor/google/recaptcha/examples/recaptcha-v3-verify.php new file mode 100644 index 00000000..3b6517a5 --- /dev/null +++ b/user/plugins/form/vendor/google/recaptcha/examples/recaptcha-v3-verify.php @@ -0,0 +1,59 @@ +setExpectedHostname($_SERVER['SERVER_NAME']) + ->setExpectedAction($_GET['action']) + ->setScoreThreshold(0.5) + ->verify($_GET['token'], $_SERVER['REMOTE_ADDR']); +header('Content-type:application/json'); +echo json_encode($resp->toArray()); diff --git a/user/plugins/form/vendor/google/recaptcha/examples/robots.txt b/user/plugins/form/vendor/google/recaptcha/examples/robots.txt new file mode 100644 index 00000000..eb053628 --- /dev/null +++ b/user/plugins/form/vendor/google/recaptcha/examples/robots.txt @@ -0,0 +1,2 @@ +User-agent: * +Disallow: diff --git a/user/plugins/form/vendor/google/recaptcha/phpunit.xml.dist b/user/plugins/form/vendor/google/recaptcha/phpunit.xml.dist new file mode 100644 index 00000000..ae866104 --- /dev/null +++ b/user/plugins/form/vendor/google/recaptcha/phpunit.xml.dist @@ -0,0 +1,20 @@ + + + + + tests/ReCaptcha/ + + + + + src/ReCaptcha/ + + + + + + diff --git a/user/plugins/form/vendor/google/recaptcha/src/ReCaptcha/ReCaptcha.php b/user/plugins/form/vendor/google/recaptcha/src/ReCaptcha/ReCaptcha.php new file mode 100644 index 00000000..177fa44c --- /dev/null +++ b/user/plugins/form/vendor/google/recaptcha/src/ReCaptcha/ReCaptcha.php @@ -0,0 +1,269 @@ +secret = $secret; + $this->requestMethod = (is_null($requestMethod)) ? new RequestMethod\Post() : $requestMethod; + } + + /** + * Calls the reCAPTCHA siteverify API to verify whether the user passes + * CAPTCHA test and additionally runs any specified additional checks + * + * @param string $response The user response token provided by reCAPTCHA, verifying the user on your site. + * @param string $remoteIp The end user's IP address. + * @return Response Response from the service. + */ + public function verify($response, $remoteIp = null) + { + // Discard empty solution submissions + if (empty($response)) { + $recaptchaResponse = new Response(false, array(self::E_MISSING_INPUT_RESPONSE)); + return $recaptchaResponse; + } + + $params = new RequestParameters($this->secret, $response, $remoteIp, self::VERSION); + $rawResponse = $this->requestMethod->submit($params); + $initialResponse = Response::fromJson($rawResponse); + $validationErrors = array(); + + if (isset($this->hostname) && strcasecmp($this->hostname, $initialResponse->getHostname()) !== 0) { + $validationErrors[] = self::E_HOSTNAME_MISMATCH; + } + + if (isset($this->apkPackageName) && strcasecmp($this->apkPackageName, $initialResponse->getApkPackageName()) !== 0) { + $validationErrors[] = self::E_APK_PACKAGE_NAME_MISMATCH; + } + + if (isset($this->action) && strcasecmp($this->action, $initialResponse->getAction()) !== 0) { + $validationErrors[] = self::E_ACTION_MISMATCH; + } + + if (isset($this->threshold) && $this->threshold > $initialResponse->getScore()) { + $validationErrors[] = self::E_SCORE_THRESHOLD_NOT_MET; + } + + if (isset($this->timeoutSeconds)) { + $challengeTs = strtotime($initialResponse->getChallengeTs()); + + if ($challengeTs > 0 && time() - $challengeTs > $this->timeoutSeconds) { + $validationErrors[] = self::E_CHALLENGE_TIMEOUT; + } + } + + if (empty($validationErrors)) { + return $initialResponse; + } + + return new Response( + false, + array_merge($initialResponse->getErrorCodes(), $validationErrors), + $initialResponse->getHostname(), + $initialResponse->getChallengeTs(), + $initialResponse->getApkPackageName(), + $initialResponse->getScore(), + $initialResponse->getAction() + ); + } + + /** + * Provide a hostname to match against in verify() + * This should be without a protocol or trailing slash, e.g. www.google.com + * + * @param string $hostname Expected hostname + * @return ReCaptcha Current instance for fluent interface + */ + public function setExpectedHostname($hostname) + { + $this->hostname = $hostname; + return $this; + } + + /** + * Provide an APK package name to match against in verify() + * + * @param string $apkPackageName Expected APK package name + * @return ReCaptcha Current instance for fluent interface + */ + public function setExpectedApkPackageName($apkPackageName) + { + $this->apkPackageName = $apkPackageName; + return $this; + } + + /** + * Provide an action to match against in verify() + * This should be set per page. + * + * @param string $action Expected action + * @return ReCaptcha Current instance for fluent interface + */ + public function setExpectedAction($action) + { + $this->action = $action; + return $this; + } + + /** + * Provide a threshold to meet or exceed in verify() + * Threshold should be a float between 0 and 1 which will be tested as response >= threshold. + * + * @param float $threshold Expected threshold + * @return ReCaptcha Current instance for fluent interface + */ + public function setScoreThreshold($threshold) + { + $this->threshold = floatval($threshold); + return $this; + } + + /** + * Provide a timeout in seconds to test against the challenge timestamp in verify() + * + * @param int $timeoutSeconds Expected hostname + * @return ReCaptcha Current instance for fluent interface + */ + public function setChallengeTimeout($timeoutSeconds) + { + $this->timeoutSeconds = $timeoutSeconds; + return $this; + } +} diff --git a/user/plugins/form/vendor/google/recaptcha/src/ReCaptcha/RequestMethod.php b/user/plugins/form/vendor/google/recaptcha/src/ReCaptcha/RequestMethod.php new file mode 100644 index 00000000..0a2a6716 --- /dev/null +++ b/user/plugins/form/vendor/google/recaptcha/src/ReCaptcha/RequestMethod.php @@ -0,0 +1,50 @@ +curl = (is_null($curl)) ? new Curl() : $curl; + $this->siteVerifyUrl = (is_null($siteVerifyUrl)) ? ReCaptcha::SITE_VERIFY_URL : $siteVerifyUrl; + } + + /** + * Submit the cURL request with the specified parameters. + * + * @param RequestParameters $params Request parameters + * @return string Body of the reCAPTCHA response + */ + public function submit(RequestParameters $params) + { + $handle = $this->curl->init($this->siteVerifyUrl); + + $options = array( + CURLOPT_POST => true, + CURLOPT_POSTFIELDS => $params->toQueryString(), + CURLOPT_HTTPHEADER => array( + 'Content-Type: application/x-www-form-urlencoded' + ), + CURLINFO_HEADER_OUT => false, + CURLOPT_HEADER => false, + CURLOPT_RETURNTRANSFER => true, + CURLOPT_SSL_VERIFYPEER => true + ); + $this->curl->setoptArray($handle, $options); + + $response = $this->curl->exec($handle); + $this->curl->close($handle); + + if ($response !== false) { + return $response; + } + + return '{"success": false, "error-codes": ["'.ReCaptcha::E_CONNECTION_FAILED.'"]}'; + } +} diff --git a/user/plugins/form/vendor/google/recaptcha/src/ReCaptcha/RequestMethod/Post.php b/user/plugins/form/vendor/google/recaptcha/src/ReCaptcha/RequestMethod/Post.php new file mode 100644 index 00000000..a4ff716f --- /dev/null +++ b/user/plugins/form/vendor/google/recaptcha/src/ReCaptcha/RequestMethod/Post.php @@ -0,0 +1,88 @@ +siteVerifyUrl = (is_null($siteVerifyUrl)) ? ReCaptcha::SITE_VERIFY_URL : $siteVerifyUrl; + } + + /** + * Submit the POST request with the specified parameters. + * + * @param RequestParameters $params Request parameters + * @return string Body of the reCAPTCHA response + */ + public function submit(RequestParameters $params) + { + $options = array( + 'http' => array( + 'header' => "Content-type: application/x-www-form-urlencoded\r\n", + 'method' => 'POST', + 'content' => $params->toQueryString(), + // Force the peer to validate (not needed in 5.6.0+, but still works) + 'verify_peer' => true, + ), + ); + $context = stream_context_create($options); + $response = file_get_contents($this->siteVerifyUrl, false, $context); + + if ($response !== false) { + return $response; + } + + return '{"success": false, "error-codes": ["'.ReCaptcha::E_CONNECTION_FAILED.'"]}'; + } +} diff --git a/user/plugins/form/vendor/google/recaptcha/src/ReCaptcha/RequestMethod/Socket.php b/user/plugins/form/vendor/google/recaptcha/src/ReCaptcha/RequestMethod/Socket.php new file mode 100644 index 00000000..236bd5f5 --- /dev/null +++ b/user/plugins/form/vendor/google/recaptcha/src/ReCaptcha/RequestMethod/Socket.php @@ -0,0 +1,112 @@ +handle = fsockopen($hostname, $port, $errno, $errstr, (is_null($timeout) ? ini_get("default_socket_timeout") : $timeout)); + + if ($this->handle != false && $errno === 0 && $errstr === '') { + return $this->handle; + } + return false; + } + + /** + * fwrite + * + * @see http://php.net/fwrite + * @param string $string + * @param int $length + * @return int | bool + */ + public function fwrite($string, $length = null) + { + return fwrite($this->handle, $string, (is_null($length) ? strlen($string) : $length)); + } + + /** + * fgets + * + * @see http://php.net/fgets + * @param int $length + * @return string + */ + public function fgets($length = null) + { + return fgets($this->handle, $length); + } + + /** + * feof + * + * @see http://php.net/feof + * @return bool + */ + public function feof() + { + return feof($this->handle); + } + + /** + * fclose + * + * @see http://php.net/fclose + * @return bool + */ + public function fclose() + { + return fclose($this->handle); + } +} diff --git a/user/plugins/form/vendor/google/recaptcha/src/ReCaptcha/RequestMethod/SocketPost.php b/user/plugins/form/vendor/google/recaptcha/src/ReCaptcha/RequestMethod/SocketPost.php new file mode 100644 index 00000000..7edffb86 --- /dev/null +++ b/user/plugins/form/vendor/google/recaptcha/src/ReCaptcha/RequestMethod/SocketPost.php @@ -0,0 +1,108 @@ +socket = (is_null($socket)) ? new Socket() : $socket; + $this->siteVerifyUrl = (is_null($siteVerifyUrl)) ? ReCaptcha::SITE_VERIFY_URL : $siteVerifyUrl; + } + + /** + * Submit the POST request with the specified parameters. + * + * @param RequestParameters $params Request parameters + * @return string Body of the reCAPTCHA response + */ + public function submit(RequestParameters $params) + { + $errno = 0; + $errstr = ''; + $urlParsed = parse_url($this->siteVerifyUrl); + + if (false === $this->socket->fsockopen('ssl://' . $urlParsed['host'], 443, $errno, $errstr, 30)) { + return '{"success": false, "error-codes": ["'.ReCaptcha::E_CONNECTION_FAILED.'"]}'; + } + + $content = $params->toQueryString(); + + $request = "POST " . $urlParsed['path'] . " HTTP/1.1\r\n"; + $request .= "Host: " . $urlParsed['host'] . "\r\n"; + $request .= "Content-Type: application/x-www-form-urlencoded\r\n"; + $request .= "Content-length: " . strlen($content) . "\r\n"; + $request .= "Connection: close\r\n\r\n"; + $request .= $content . "\r\n\r\n"; + + $this->socket->fwrite($request); + $response = ''; + + while (!$this->socket->feof()) { + $response .= $this->socket->fgets(4096); + } + + $this->socket->fclose(); + + if (0 !== strpos($response, 'HTTP/1.1 200 OK')) { + return '{"success": false, "error-codes": ["'.ReCaptcha::E_BAD_RESPONSE.'"]}'; + } + + $parts = preg_split("#\n\s*\n#Uis", $response); + + return $parts[1]; + } +} diff --git a/user/plugins/form/vendor/google/recaptcha/src/ReCaptcha/RequestParameters.php b/user/plugins/form/vendor/google/recaptcha/src/ReCaptcha/RequestParameters.php new file mode 100644 index 00000000..e9ba4535 --- /dev/null +++ b/user/plugins/form/vendor/google/recaptcha/src/ReCaptcha/RequestParameters.php @@ -0,0 +1,111 @@ +secret = $secret; + $this->response = $response; + $this->remoteIp = $remoteIp; + $this->version = $version; + } + + /** + * Array representation. + * + * @return array Array formatted parameters. + */ + public function toArray() + { + $params = array('secret' => $this->secret, 'response' => $this->response); + + if (!is_null($this->remoteIp)) { + $params['remoteip'] = $this->remoteIp; + } + + if (!is_null($this->version)) { + $params['version'] = $this->version; + } + + return $params; + } + + /** + * Query string representation for HTTP request. + * + * @return string Query string formatted parameters. + */ + public function toQueryString() + { + return http_build_query($this->toArray(), '', '&'); + } +} diff --git a/user/plugins/form/vendor/google/recaptcha/src/ReCaptcha/Response.php b/user/plugins/form/vendor/google/recaptcha/src/ReCaptcha/Response.php new file mode 100644 index 00000000..55838c07 --- /dev/null +++ b/user/plugins/form/vendor/google/recaptcha/src/ReCaptcha/Response.php @@ -0,0 +1,218 @@ +success = $success; + $this->hostname = $hostname; + $this->challengeTs = $challengeTs; + $this->apkPackageName = $apkPackageName; + $this->score = $score; + $this->action = $action; + $this->errorCodes = $errorCodes; + } + + /** + * Is success? + * + * @return boolean + */ + public function isSuccess() + { + return $this->success; + } + + /** + * Get error codes. + * + * @return array + */ + public function getErrorCodes() + { + return $this->errorCodes; + } + + /** + * Get hostname. + * + * @return string + */ + public function getHostname() + { + return $this->hostname; + } + + /** + * Get challenge timestamp + * + * @return string + */ + public function getChallengeTs() + { + return $this->challengeTs; + } + + /** + * Get APK package name + * + * @return string + */ + public function getApkPackageName() + { + return $this->apkPackageName; + } + /** + * Get score + * + * @return float + */ + public function getScore() + { + return $this->score; + } + + /** + * Get action + * + * @return string + */ + public function getAction() + { + return $this->action; + } + + public function toArray() + { + return array( + 'success' => $this->isSuccess(), + 'hostname' => $this->getHostname(), + 'challenge_ts' => $this->getChallengeTs(), + 'apk_package_name' => $this->getApkPackageName(), + 'score' => $this->getScore(), + 'action' => $this->getAction(), + 'error-codes' => $this->getErrorCodes(), + ); + } +} diff --git a/user/plugins/form/vendor/google/recaptcha/src/autoload.php b/user/plugins/form/vendor/google/recaptcha/src/autoload.php new file mode 100644 index 00000000..7947a105 --- /dev/null +++ b/user/plugins/form/vendor/google/recaptcha/src/autoload.php @@ -0,0 +1,69 @@ +verify(''); + $this->assertFalse($response->isSuccess()); + $this->assertEquals(array(Recaptcha::E_MISSING_INPUT_RESPONSE), $response->getErrorCodes()); + } + + private function getMockRequestMethod($responseJson) + { + $method = $this->getMockBuilder(\ReCaptcha\RequestMethod::class) + ->disableOriginalConstructor() + ->setMethods(array('submit')) + ->getMock(); + $method->expects($this->any()) + ->method('submit') + ->with($this->callback(function ($params) { + return true; + })) + ->will($this->returnValue($responseJson)); + return $method; + } + + public function testVerifyReturnsResponse() + { + $method = $this->getMockRequestMethod('{"success": true}'); + $rc = new ReCaptcha('secret', $method); + $response = $rc->verify('response'); + $this->assertTrue($response->isSuccess()); + } + + public function testVerifyReturnsInitialResponseWithoutAdditionalChecks() + { + $method = $this->getMockRequestMethod('{"success": true}'); + $rc = new ReCaptcha('secret', $method); + $initialResponse = $rc->verify('response'); + $this->assertEquals($initialResponse, $rc->verify('response')); + } + + public function testVerifyHostnameMatch() + { + $method = $this->getMockRequestMethod('{"success": true, "hostname": "host.name"}'); + $rc = new ReCaptcha('secret', $method); + $response = $rc->setExpectedHostname('host.name')->verify('response'); + $this->assertTrue($response->isSuccess()); + } + + public function testVerifyHostnameMisMatch() + { + $method = $this->getMockRequestMethod('{"success": true, "hostname": "host.NOTname"}'); + $rc = new ReCaptcha('secret', $method); + $response = $rc->setExpectedHostname('host.name')->verify('response'); + $this->assertFalse($response->isSuccess()); + $this->assertEquals(array(ReCaptcha::E_HOSTNAME_MISMATCH), $response->getErrorCodes()); + } + + public function testVerifyApkPackageNameMatch() + { + $method = $this->getMockRequestMethod('{"success": true, "apk_package_name": "apk.name"}'); + $rc = new ReCaptcha('secret', $method); + $response = $rc->setExpectedApkPackageName('apk.name')->verify('response'); + $this->assertTrue($response->isSuccess()); + } + + public function testVerifyApkPackageNameMisMatch() + { + $method = $this->getMockRequestMethod('{"success": true, "apk_package_name": "apk.NOTname"}'); + $rc = new ReCaptcha('secret', $method); + $response = $rc->setExpectedApkPackageName('apk.name')->verify('response'); + $this->assertFalse($response->isSuccess()); + $this->assertEquals(array(ReCaptcha::E_APK_PACKAGE_NAME_MISMATCH), $response->getErrorCodes()); + } + + public function testVerifyActionMatch() + { + $method = $this->getMockRequestMethod('{"success": true, "action": "action/name"}'); + $rc = new ReCaptcha('secret', $method); + $response = $rc->setExpectedAction('action/name')->verify('response'); + $this->assertTrue($response->isSuccess()); + } + + public function testVerifyActionMisMatch() + { + $method = $this->getMockRequestMethod('{"success": true, "action": "action/NOTname"}'); + $rc = new ReCaptcha('secret', $method); + $response = $rc->setExpectedAction('action/name')->verify('response'); + $this->assertFalse($response->isSuccess()); + $this->assertEquals(array(ReCaptcha::E_ACTION_MISMATCH), $response->getErrorCodes()); + } + + public function testVerifyAboveThreshold() + { + $method = $this->getMockRequestMethod('{"success": true, "score": "0.9"}'); + $rc = new ReCaptcha('secret', $method); + $response = $rc->setScoreThreshold('0.5')->verify('response'); + $this->assertTrue($response->isSuccess()); + } + + public function testVerifyBelowThreshold() + { + $method = $this->getMockRequestMethod('{"success": true, "score": "0.1"}'); + $rc = new ReCaptcha('secret', $method); + $response = $rc->setScoreThreshold('0.5')->verify('response'); + $this->assertFalse($response->isSuccess()); + $this->assertEquals(array(ReCaptcha::E_SCORE_THRESHOLD_NOT_MET), $response->getErrorCodes()); + } + + public function testVerifyWithinTimeout() + { + // Responses come back like 2018-07-31T13:48:41Z + $challengeTs = date('Y-M-d\TH:i:s\Z', time()); + $method = $this->getMockRequestMethod('{"success": true, "challenge_ts": "'.$challengeTs.'"}'); + $rc = new ReCaptcha('secret', $method); + $response = $rc->setChallengeTimeout('1000')->verify('response'); + $this->assertTrue($response->isSuccess()); + } + + public function testVerifyOverTimeout() + { + // Responses come back like 2018-07-31T13:48:41Z + $challengeTs = date('Y-M-d\TH:i:s\Z', time() - 600); + $method = $this->getMockRequestMethod('{"success": true, "challenge_ts": "'.$challengeTs.'"}'); + $rc = new ReCaptcha('secret', $method); + $response = $rc->setChallengeTimeout('60')->verify('response'); + $this->assertFalse($response->isSuccess()); + $this->assertEquals(array(ReCaptcha::E_CHALLENGE_TIMEOUT), $response->getErrorCodes()); + } + + public function testVerifyMergesErrors() + { + $method = $this->getMockRequestMethod('{"success": false, "error-codes": ["initial-error"], "score": "0.1"}'); + $rc = new ReCaptcha('secret', $method); + $response = $rc->setScoreThreshold('0.5')->verify('response'); + $this->assertFalse($response->isSuccess()); + $this->assertEquals(array('initial-error', ReCaptcha::E_SCORE_THRESHOLD_NOT_MET), $response->getErrorCodes()); + } +} diff --git a/user/plugins/form/vendor/google/recaptcha/tests/ReCaptcha/RequestMethod/CurlPostTest.php b/user/plugins/form/vendor/google/recaptcha/tests/ReCaptcha/RequestMethod/CurlPostTest.php new file mode 100644 index 00000000..8fb17dc0 --- /dev/null +++ b/user/plugins/form/vendor/google/recaptcha/tests/ReCaptcha/RequestMethod/CurlPostTest.php @@ -0,0 +1,123 @@ +markTestSkipped( + 'The cURL extension is not available.' + ); + } + } + + public function testSubmit() + { + $curl = $this->getMockBuilder(\ReCaptcha\RequestMethod\Curl::class) + ->disableOriginalConstructor() + ->setMethods(array('init', 'setoptArray', 'exec', 'close')) + ->getMock(); + $curl->expects($this->once()) + ->method('init') + ->willReturn(new \stdClass); + $curl->expects($this->once()) + ->method('setoptArray') + ->willReturn(true); + $curl->expects($this->once()) + ->method('exec') + ->willReturn('RESPONSEBODY'); + $curl->expects($this->once()) + ->method('close'); + + $pc = new CurlPost($curl); + $response = $pc->submit(new RequestParameters("secret", "response")); + $this->assertEquals('RESPONSEBODY', $response); + } + + public function testOverrideSiteVerifyUrl() + { + $url = 'OVERRIDE'; + + $curl = $this->getMockBuilder(\ReCaptcha\RequestMethod\Curl::class) + ->disableOriginalConstructor() + ->setMethods(array('init', 'setoptArray', 'exec', 'close')) + ->getMock(); + $curl->expects($this->once()) + ->method('init') + ->with($url) + ->willReturn(new \stdClass); + $curl->expects($this->once()) + ->method('setoptArray') + ->willReturn(true); + $curl->expects($this->once()) + ->method('exec') + ->willReturn('RESPONSEBODY'); + $curl->expects($this->once()) + ->method('close'); + + $pc = new CurlPost($curl, $url); + $response = $pc->submit(new RequestParameters("secret", "response")); + $this->assertEquals('RESPONSEBODY', $response); + } + + public function testConnectionFailureReturnsError() + { + $curl = $this->getMockBuilder(\ReCaptcha\RequestMethod\Curl::class) + ->disableOriginalConstructor() + ->setMethods(array('init', 'setoptArray', 'exec', 'close')) + ->getMock(); + $curl->expects($this->once()) + ->method('init') + ->willReturn(new \stdClass); + $curl->expects($this->once()) + ->method('setoptArray') + ->willReturn(true); + $curl->expects($this->once()) + ->method('exec') + ->willReturn(false); + $curl->expects($this->once()) + ->method('close'); + + $pc = new CurlPost($curl); + $response = $pc->submit(new RequestParameters("secret", "response")); + $this->assertEquals('{"success": false, "error-codes": ["'.ReCaptcha::E_CONNECTION_FAILED.'"]}', $response); + } +} diff --git a/user/plugins/form/vendor/google/recaptcha/tests/ReCaptcha/RequestMethod/PostTest.php b/user/plugins/form/vendor/google/recaptcha/tests/ReCaptcha/RequestMethod/PostTest.php new file mode 100644 index 00000000..bdfb78ee --- /dev/null +++ b/user/plugins/form/vendor/google/recaptcha/tests/ReCaptcha/RequestMethod/PostTest.php @@ -0,0 +1,149 @@ +parameters = new RequestParameters('secret', 'response', 'remoteip', 'version'); + } + + public function tearDown() + { + self::$assert = null; + } + + public function testHTTPContextOptions() + { + $req = new Post(); + self::$assert = array($this, 'httpContextOptionsCallback'); + $req->submit($this->parameters); + $this->assertEquals(1, $this->runcount, 'The assertion was ran'); + } + + public function testSSLContextOptions() + { + $req = new Post(); + self::$assert = array($this, 'sslContextOptionsCallback'); + $req->submit($this->parameters); + $this->assertEquals(1, $this->runcount, 'The assertion was ran'); + } + + public function testOverrideVerifyUrl() + { + $req = new Post('https://over.ride/some/path'); + self::$assert = array($this, 'overrideUrlOptions'); + $req->submit($this->parameters); + $this->assertEquals(1, $this->runcount, 'The assertion was ran'); + } + + public function testConnectionFailureReturnsError() + { + $req = new Post('https://bad.connection/'); + self::$assert = array($this, 'connectionFailureResponse'); + $response = $req->submit($this->parameters); + $this->assertEquals('{"success": false, "error-codes": ["'.ReCaptcha::E_CONNECTION_FAILED.'"]}', $response); + } + + public function connectionFailureResponse() + { + return false; + } + public function overrideUrlOptions(array $args) + { + $this->runcount++; + $this->assertEquals('https://over.ride/some/path', $args[0]); + } + + public function httpContextOptionsCallback(array $args) + { + $this->runcount++; + $this->assertCommonOptions($args); + + $options = stream_context_get_options($args[2]); + $this->assertArrayHasKey('http', $options); + + $this->assertArrayHasKey('method', $options['http']); + $this->assertEquals('POST', $options['http']['method']); + + $this->assertArrayHasKey('content', $options['http']); + $this->assertEquals($this->parameters->toQueryString(), $options['http']['content']); + + $this->assertArrayHasKey('header', $options['http']); + $headers = array( + 'Content-type: application/x-www-form-urlencoded', + ); + foreach ($headers as $header) { + $this->assertContains($header, $options['http']['header']); + } + } + + public function sslContextOptionsCallback(array $args) + { + $this->runcount++; + $this->assertCommonOptions($args); + + $options = stream_context_get_options($args[2]); + $this->assertArrayHasKey('http', $options); + $this->assertArrayHasKey('verify_peer', $options['http']); + $this->assertTrue($options['http']['verify_peer']); + } + + protected function assertCommonOptions(array $args) + { + $this->assertCount(3, $args); + $this->assertStringStartsWith('https://www.google.com/', $args[0]); + $this->assertFalse($args[1]); + $this->assertTrue(is_resource($args[2]), 'The context options should be a resource'); + } +} + +function file_get_contents() +{ + if (PostTest::$assert) { + return call_user_func(PostTest::$assert, func_get_args()); + } + // Since we can't represent maxlen in userland... + return call_user_func_array('file_get_contents', func_get_args()); +} diff --git a/user/plugins/form/vendor/google/recaptcha/tests/ReCaptcha/RequestMethod/SocketPostTest.php b/user/plugins/form/vendor/google/recaptcha/tests/ReCaptcha/RequestMethod/SocketPostTest.php new file mode 100644 index 00000000..8656be4c --- /dev/null +++ b/user/plugins/form/vendor/google/recaptcha/tests/ReCaptcha/RequestMethod/SocketPostTest.php @@ -0,0 +1,136 @@ +getMockBuilder(\ReCaptcha\RequestMethod\Socket::class) + ->disableOriginalConstructor() + ->setMethods(array('fsockopen', 'fwrite', 'fgets', 'feof', 'fclose')) + ->getMock(); + $socket->expects($this->once()) + ->method('fsockopen') + ->willReturn(true); + $socket->expects($this->once()) + ->method('fwrite'); + $socket->expects($this->once()) + ->method('fgets') + ->willReturn("HTTP/1.1 200 OK\n\nRESPONSEBODY"); + $socket->expects($this->exactly(2)) + ->method('feof') + ->will($this->onConsecutiveCalls(false, true)); + $socket->expects($this->once()) + ->method('fclose') + ->willReturn(true); + + $ps = new SocketPost($socket); + $response = $ps->submit(new RequestParameters("secret", "response", "remoteip", "version")); + $this->assertEquals('RESPONSEBODY', $response); + } + + public function testOverrideSiteVerifyUrl() + { + $socket = $this->getMockBuilder(\ReCaptcha\RequestMethod\Socket::class) + ->disableOriginalConstructor() + ->setMethods(array('fsockopen', 'fwrite', 'fgets', 'feof', 'fclose')) + ->getMock(); + $socket->expects($this->once()) + ->method('fsockopen') + ->with('ssl://over.ride', 443, 0, '', 30) + ->willReturn(true); + $socket->expects($this->once()) + ->method('fwrite') + ->with($this->matchesRegularExpression('/^POST \/some\/path.*Host: over\.ride/s')); + $socket->expects($this->once()) + ->method('fgets') + ->willReturn("HTTP/1.1 200 OK\n\nRESPONSEBODY"); + $socket->expects($this->exactly(2)) + ->method('feof') + ->will($this->onConsecutiveCalls(false, true)); + $socket->expects($this->once()) + ->method('fclose') + ->willReturn(true); + + $ps = new SocketPost($socket, 'https://over.ride/some/path'); + $response = $ps->submit(new RequestParameters("secret", "response", "remoteip", "version")); + $this->assertEquals('RESPONSEBODY', $response); + } + + public function testSubmitBadResponse() + { + $socket = $this->getMockBuilder(\ReCaptcha\RequestMethod\Socket::class) + ->disableOriginalConstructor() + ->setMethods(array('fsockopen', 'fwrite', 'fgets', 'feof', 'fclose')) + ->getMock(); + $socket->expects($this->once()) + ->method('fsockopen') + ->willReturn(true); + $socket->expects($this->once()) + ->method('fwrite'); + $socket->expects($this->once()) + ->method('fgets') + ->willReturn("HTTP/1.1 500 NOPEn\\nBOBBINS"); + $socket->expects($this->exactly(2)) + ->method('feof') + ->will($this->onConsecutiveCalls(false, true)); + $socket->expects($this->once()) + ->method('fclose') + ->willReturn(true); + + $ps = new SocketPost($socket); + $response = $ps->submit(new RequestParameters("secret", "response", "remoteip", "version")); + $this->assertEquals('{"success": false, "error-codes": ["'.ReCaptcha::E_BAD_RESPONSE.'"]}', $response); + } + + public function testConnectionFailureReturnsError() + { + $socket = $this->getMockBuilder(\ReCaptcha\RequestMethod\Socket::class) + ->disableOriginalConstructor() + ->setMethods(array('fsockopen')) + ->getMock(); + $socket->expects($this->once()) + ->method('fsockopen') + ->willReturn(false); + $ps = new SocketPost($socket); + $response = $ps->submit(new RequestParameters("secret", "response", "remoteip", "version")); + $this->assertEquals('{"success": false, "error-codes": ["'.ReCaptcha::E_CONNECTION_FAILED.'"]}', $response); + } +} diff --git a/user/plugins/form/vendor/google/recaptcha/tests/ReCaptcha/RequestParametersTest.php b/user/plugins/form/vendor/google/recaptcha/tests/ReCaptcha/RequestParametersTest.php new file mode 100644 index 00000000..fafded2e --- /dev/null +++ b/user/plugins/form/vendor/google/recaptcha/tests/ReCaptcha/RequestParametersTest.php @@ -0,0 +1,70 @@ + 'SECRET', 'response' => 'RESPONSE', 'remoteip' => 'REMOTEIP', 'version' => 'VERSION'), + 'secret=SECRET&response=RESPONSE&remoteip=REMOTEIP&version=VERSION'), + array('SECRET', 'RESPONSE', null, null, + array('secret' => 'SECRET', 'response' => 'RESPONSE'), + 'secret=SECRET&response=RESPONSE'), + ); + } + + /** + * @dataProvider provideValidData + */ + public function testToArray($secret, $response, $remoteIp, $version, $expectedArray, $expectedQuery) + { + $params = new RequestParameters($secret, $response, $remoteIp, $version); + $this->assertEquals($params->toArray(), $expectedArray); + } + + /** + * @dataProvider provideValidData + */ + public function testToQueryString($secret, $response, $remoteIp, $version, $expectedArray, $expectedQuery) + { + $params = new RequestParameters($secret, $response, $remoteIp, $version); + $this->assertEquals($params->toQueryString(), $expectedQuery); + } +} diff --git a/user/plugins/form/vendor/google/recaptcha/tests/ReCaptcha/ResponseTest.php b/user/plugins/form/vendor/google/recaptcha/tests/ReCaptcha/ResponseTest.php new file mode 100644 index 00000000..7894c2a9 --- /dev/null +++ b/user/plugins/form/vendor/google/recaptcha/tests/ReCaptcha/ResponseTest.php @@ -0,0 +1,173 @@ +assertEquals($success, $response->isSuccess()); + $this->assertEquals($errorCodes, $response->getErrorCodes()); + $this->assertEquals($hostname, $response->getHostname()); + $this->assertEquals($challengeTs, $response->getChallengeTs()); + $this->assertEquals($apkPackageName, $response->getApkPackageName()); + $this->assertEquals($score, $response->getScore()); + $this->assertEquals($action, $response->getAction()); + } + + public function provideJson() + { + return array( + array( + '{"success": true}', + true, array(), null, null, null, null, null, + ), + array( + '{"success": true, "hostname": "google.com"}', + true, array(), 'google.com', null, null, null, null, + ), + array( + '{"success": false, "error-codes": ["test"]}', + false, array('test'), null, null, null, null, null, + ), + array( + '{"success": false, "error-codes": ["test"], "hostname": "google.com"}', + false, array('test'), 'google.com', null, null, null, null, + ), + array( + '{"success": false, "error-codes": ["test"], "hostname": "google.com", "challenge_ts": "timestamp", "apk_package_name": "apk", "score": "0.5", "action": "action"}', + false, array('test'), 'google.com', 'timestamp', 'apk', 0.5, 'action', + ), + array( + '{"success": true, "error-codes": ["test"]}', + true, array(), null, null, null, null, null, + ), + array( + '{"success": true, "error-codes": ["test"], "hostname": "google.com"}', + true, array(), 'google.com', null, null, null, null, + ), + array( + '{"success": false}', + false, array(ReCaptcha::E_UNKNOWN_ERROR), null, null, null, null, null, + ), + array( + '{"success": false, "hostname": "google.com"}', + false, array(ReCaptcha::E_UNKNOWN_ERROR), 'google.com', null, null, null, null, + ), + array( + 'BAD JSON', + false, array(ReCaptcha::E_INVALID_JSON), null, null, null, null, null, + ), + ); + } + + public function testIsSuccess() + { + $response = new Response(true); + $this->assertTrue($response->isSuccess()); + + $response = new Response(false); + $this->assertFalse($response->isSuccess()); + + $response = new Response(true, array(), 'example.com'); + $this->assertEquals('example.com', $response->getHostName()); + } + + public function testGetErrorCodes() + { + $errorCodes = array('test'); + $response = new Response(true, $errorCodes); + $this->assertEquals($errorCodes, $response->getErrorCodes()); + } + + public function testGetHostname() + { + $hostname = 'google.com'; + $errorCodes = array(); + $response = new Response(true, $errorCodes, $hostname); + $this->assertEquals($hostname, $response->getHostname()); + } + + public function testGetChallengeTs() + { + $timestamp = 'timestamp'; + $errorCodes = array(); + $response = new Response(true, array(), 'hostname', $timestamp); + $this->assertEquals($timestamp, $response->getChallengeTs()); + } + + public function TestGetApkPackageName() + { + $apk = 'apk'; + $response = new Response(true, array(), 'hostname', 'timestamp', 'apk'); + $this->assertEquals($apk, $response->getApkPackageName()); + } + + public function testGetScore() + { + $score = 0.5; + $response = new Response(true, array(), 'hostname', 'timestamp', 'apk', $score); + $this->assertEquals($score, $response->getScore()); + } + + public function testGetAction() + { + $action = 'homepage'; + $response = new Response(true, array(), 'hostname', 'timestamp', 'apk', '0.5', 'homepage'); + $this->assertEquals($action, $response->getAction()); + } + + public function testToArray() + { + $response = new Response(true, array(), 'hostname', 'timestamp', 'apk', '0.5', 'homepage'); + $expected = array( + 'success' => true, + 'error-codes' => array(), + 'hostname' => 'hostname', + 'challenge_ts' => 'timestamp', + 'apk_package_name' => 'apk', + 'score' => 0.5, + 'action' => 'homepage', + ); + $this->assertEquals($expected, $response->toArray()); + } +} diff --git a/user/plugins/form/webpack.conf.js b/user/plugins/form/webpack.conf.js new file mode 100644 index 00000000..bee5278a --- /dev/null +++ b/user/plugins/form/webpack.conf.js @@ -0,0 +1,65 @@ +var webpack = require('webpack'), + path = require('path'), + UglifyJsPlugin = require('uglifyjs-webpack-plugin'), + isProd = process.env.NODE_ENV === 'production' || process.env.NODE_ENV === 'production-wip'; + +module.exports = { + entry: { + site: './app/main.js' + }, + devtool: isProd ? false : 'eval-source-map', + target: 'web', + output: { + path: path.resolve(__dirname, 'assets'), + filename: 'form.min.js', + chunkFilename: 'form.vendor.js' + }, + optimization: { + minimize: isProd, + minimizer: [ + new UglifyJsPlugin({ + uglifyOptions: { + compress: { + drop_console: true + }, + dead_code: true + } + }) + ], + splitChunks: { + cacheGroups: { + vendors: { + test: /[\\/]node_modules[\\/]/, + priority: 1, + name: 'vendor', + enforce: true, + chunks: 'all' + } + } + } + }, + plugins: [ + new webpack.ProvidePlugin({ + 'fetch': 'imports-loader?this=>global!exports-loader?global.fetch!whatwg-fetch' + }) + ], + externals: { + jquery: 'jQuery', + 'grav-form': 'GravForm' + }, + module: { + rules: [ + { enforce: 'pre', test: /\.json$/, loader: 'json-loader' }, + { enforce: 'pre', test: /\.js$/, loader: 'eslint-loader', exclude: /node_modules/ }, + { test: /\.css$/, loader: 'style-loader!css-loader' }, + { + test: /\.js$/, + loader: 'babel-loader', + exclude: /node_modules/, + query: { + presets: ['es2015', 'stage-3'] + } + } + ] + } +}; diff --git a/user/plugins/login/CHANGELOG.md b/user/plugins/login/CHANGELOG.md new file mode 100644 index 00000000..41e54810 --- /dev/null +++ b/user/plugins/login/CHANGELOG.md @@ -0,0 +1,640 @@ +# 3.0.4 +## 10/03/2019 + +1. [](#bugfix) + * Fixed bad redirect after login on multi-language site [#217](https://github.com/getgrav/grav-plugin-login/issues/217) + * Fixed basic login not obeying `redirect_after_login` option + * Provide default `redirect_after_activation` option [#225](https://github.com/getgrav/grav-plugin-login/issues/225) + +# 3.0.3 +## 07/01/2019 + +1. [](#bugfix) + * Fix for not redirecting to secure page after login [#199](https://github.com/getgrav/grav-plugin-login/issues/199) + * Fixed `bin/plugin login new-user` ACL when using Flex Users + +# 3.0.2 +## 05/09/2019 + +1. [](#new) + * Added `ru` and `uk` translations [#208](https://github.com/getgrav/grav-plugin-login/pulls/208) +1. [](#improved) + * Fixed typo in README.md + * Added support for IPv6 addresses for login rate limiting @Vivalldi [#204](https://github.com/getgrav/grav-plugin-login/issues/204) + +# 3.0.1 +## 04/17/2019 + +1. [](#improved) + * Extra checks for page visibility [#166](https://github.com/getgrav/grav-plugin-login/issues/166) + +# 3.0.0 +## 04/11/2019 + +1. [](#new) + * Added **2-Factor Authentication** support for front-end (2FA) + * New CLI command to `lookup` users + * Check requirements to use new `lookup` command + * Added support for the new `Flex User` object +1. [](#improved) + * Use `$grav['accounts']` instead of `$grav['users']` + * Update all Login classes to rely on `PageInterface` instead of `Page` class + * Updated typehints from `User` to `UserInterface` + * Use `$grav['users']` collection instead of deprecated static calls + * Invalidate cache when modifying users from CLI + * Updated code to PHP 7.1 features +1. [](#bugfix) + * Fix login on registration (FlexUsers) + +# v2.8.4 +## 03/20/2019 + +1. [](#improved) + * Enable "brute force" protection by default [#195](https://github.com/getgrav/grav-plugin-login/pulls/195) + * UPdated various language translations +1. [](#bugfix) + * Set security timeouts in blueprints to use `minutes` rather than `seconds` [#194](https://github.com/getgrav/grav-plugin-login/issues/194) + * Send "notification" email to `to` address rather than `from` [#188](https://github.com/getgrav/grav-plugin-login/pulls/188) + +# v2.8.3 +## 01/25/2019 + +1. [](#new) + * Wrap data in `onUserLoginRegisterData` event in object to allow reference +1. [](#improved) + * IP pseudonymization for rate limiter [#196](https://github.com/getgrav/grav-plugin-login/pull/196) + * Made some error lang strings more generic to relfect ability to change username/password requirements +1. [](#bugfix) + * Fix redirectLangSafe in login controller [#192](https://github.com/getgrav/grav-plugin-login/pull/192) + +# v2.8.2 +## 12/14/2018 + +1. [](#new) + * Fire `onUserLoginRegisteredUser()` event to allow manipulation of User object after registration + +# v2.8.1 +## 12/13/2018 + +1. [](#bugfix) + * Fix various redirects to use `lang-safe` variety for better multi-language support [#186]((https://github.com/getgrav/grav-plugin-login/issues/186)) + * Ensure only defined `user_registration.fields` are allowed in registration and profile forms + +# v2.8.0 +## 11/12/2018 + +1. [](#new) + * Store remember me triplets into `user://data/rememberme` instead of storing them into the cache + * Ability to register + authorize but require accounts to be manually enabled [#180](https://github.com/getgrav/grav-plugin-login/issues/180) +1. [](#improved) + * If login on registration or activation has been turned on, use login redirect if override is not set + * Don’t set default templates for `register` and `unauthorized`, use overridable templates [#179](https://github.com/getgrav/grav-plugin-login/issues/179) + * Updated `de.yaml` [#175](https://github.com/getgrav/grav-plugin-login/pull/175) + * Updated `ru.yaml` [#176](https://github.com/getgrav/grav-plugin-login/pull/176) +1. [](#bugfix) + * Fixed broken remember me functionality + * Fixed client side validation in login forms + * Fix uppercase and Unicode username handling [#177](https://github.com/getgrav/grav-plugin-login/pull/177) + +# v2.7.3 +## 06/20/2018 + +1. [](#bugfix) + * Fixed regression with `redirect_after_login` setting [#164](https://github.com/getgrav/grav-plugin-login/issues/164) + +# v2.7.2 +## 06/11/2018 + +1. [](#new) + * Norwegian translation added [#163](https://github.com/getgrav/grav-plugin-login/issues/163) +1. [](#bugfix) + * Fixed issue with `redirect_after_login` being ignored [#164](https://github.com/getgrav/grav-plugin-login/issues/164) + * CLI commands `change-user-state` and `change-password` were ignoring desired username [#161](https://github.com/getgrav/grav-plugin-login/issues/161) + +# v2.7.1 +## 06/03/2018 + +1. [](#bugfix) + * Removed extra unnecessary username check [#159](https://github.com/getgrav/grav-plugin-login/issues/159) + * CLI command `add-user` ignores desired username [#157](https://github.com/getgrav/grav-plugin-login/issues/157) + +# v2.7.0 +## 05/11/2018 + +1. [](#new) + * Moved support for 2FA authentication into Login plugin (only supported in Admin currently) + * Updated plugin dependencies (Grav >= 1.4.5, Form >=2.13.4, Email >=2.7.0) +1. [](#improved) + * Added cleaner way for 3rd party providers to add twig templates to login form + * Use `Login` class validation methods in CLI + * Added logging of login exceptions + * Show denied message only when authenticated but not authorized +1. [](#bugfix) + * Don't allow Profile saving if a Grav user account doesn't exist (OAuth/LDAP users for example) + * Don't allow PW reset if no current password exists (OAuth/LDAP users for example) + +# v2.6.3 +## 04/12/2018 + +1. [](#bugfix) + * Fixed issue with saving profile and stating email has already exists + +# v2.6.2 +## 04/12/2018 + +1. [](#new) + * Added custom logout redirect configuration option + * Added support for `Login::login()` and `Login::logout()` to return `UserLoginEvent` instance instead of `User` + * Added support for custom login messages and redirects set in `UserLoginEvent` +1. [](#bugfix) + * Fixed typo in activation email body [#151](https://github.com/getgrav/grav-plugin-login/issues/151) + +# v2.6.1 +## 03/19/2018 + +1. [](#improved) + * Fixed undefined index if login form didn't contain username/password + +# v2.6.0 +## 02/22/2018 + +1. [](#improved) + * Disabled user registration by default. Enable it manually if you need it. + * Disabled user-login-on-registration by default. Enable it manually if you need it. + * Check for existing email addresses when updating User profile. + +# v2.5.0 +## 12/05/2017 + +1. [](#new) + * Added `$grav['login']->login()` and `$grav['login']->logout()` functions with event hooks + * Added `$grav['login']->getRateLimiter($context)` function + * Added events `onUserLoginAuthenticate`, `onUserLoginAuthorize`, `onUserLoginFailure`, `onUserLogin`, `onUserLogout` + * Logout message is now maintained during session destruction +1. [](#improved) + * Remember entered username if login fails + * Improved rate limiter to work without sessions and against distributed attacks + * Removed `partials/messages.html.twig` and rely on new core version + * Moved languages from unified file into dedicated language file structure + * Welcome / Notice / Activation emails now more flushed out and in HTML like Reset Password +1. [](#bugfix) + * Do not send nonce with activation link, email app can open the link in another browser + +# v2.4.3 +## 10/11/2017 + +1. [](#bugfix) + * Fix an issue when a user only has `groups` and no `access` defined [#134](https://github.com/getgrav/grav-plugin-login/issues/134) + * Escape untrusted URLs in the template files + +# v2.4.2 +## 09/29/2017 + +1. [](#bugfix) + * Fixed issue with protected page media without access [#132](https://github.com/getgrav/grav-plugin-login/issues/132) + * Improved validation of email to support RFC5322 [Grav#1648](https://github.com/getgrav/grav/issues/1648) + +# v2.4.1 +## 09/12/2017 + +1. [](#bugfix) + * Fixed an issue with 3rd party login plugins [#130](https://github.com/getgrav/grav-plugin-login/issues/130) + +# v2.4.0 +## 09/07/2017 + +1. [](#new) + * Added the ability to have a custom route for login page, but not redirect + * Added a new `unauthorized.md` page that can be customized as needed +1. [](#improved) + * Differentiated between `authenticated` and `authorized` + * Moved rate-limiting logic to the Login class + * Much code cleanup and removing of cruft + * Updated vendor libraries + * Added Russian translation +1. [](#bugfix) + * Fixed login JSON response in case of login failure + * Fixed issue with profile form displaying on login page + * Store referrer page when trying to access Profile page + * Fixed error when logging out with an expired session + +# v2.3.2 +## 06/22/2017 + +1. [](#bugfix) + * Grav plugin cli error on password change [#120](https://github.com/getgrav/grav-plugin-login/issues/120) + +# v2.3.1 +## 05/16/2017 + +1. [](#improved) + * Added routes to the Admin blueprints + +# v2.3.0 +## 04/19/2017 + +1. [](#new) + * Added new built-in profile page support + * Added optional flood protection for password resets and login attempts [#91](https://github.com/getgrav/grav-plugin-login/issues/91) +1. [](#improved) + * Use new system configuration entries for username and password format + * Use initialized form object in Twig templates rather than array from page.header + * Improved alert styling in login templates + * Added `appends` for number field + * Added missing `route` options in admin options (blueprints) +1. [](#bugfix) + * Set cookie path to `/` if `base_url_relative` is empty [#102](https://github.com/getgrav/grav-plugin-login/issues/102) + * Fixed some redirect logic + +# v2.2.1 +## 01/24/2017 + +1. [](#bugfix) + * Fix login form/status templates displaying user as logged in even if he's not authenticated + * Use email validation instead of text validation in the forgot password form [https://github.com/gantry/gantry5/issues/1813](https://github.com/gantry/gantry5/issues/1813) + +# v2.2.0 +## 12/13/2016 + +1. [](#new) + * RC released as stable + +# v2.2.0-rc.5 +## 12/07/2016 + +1. [](#improved) + * Added support for hiding `Remember me` checkbox and and `Forgot` button (for Offline functionality) +1. [](#bugfix) + * Fixed redirect issue in admin plugin + +# v2.2.0-rc.4 +## 12/04/2016 + +1. [](#improved) + * Improved logic for redirect after login to not include login-related pages. + +# v2.2.0-rc.3 +## 11/26/2016 + +1. [](#improved) + * Added some validity checks in the reset password form +1. [](#bugfix) + * Correctly redirect to the last page visited after login, unless `redirect_after_login` is defined + +# v2.2.0-rc.2 +## 11/17/2016 + +1. [](#new) + * Allow to set permissions using nested array syntax [#96](https://github.com/getgrav/grav-plugin-login/issues/96) +1. [](#improved) + * Use the same feedback message when resetting the password if the email exists or not. Remove email in the message as we now recover via email, useless +1. [](#bugfix) + * Fix registration form, fields were not visible [#97](https://github.com/getgrav/grav-plugin-login/issues/97) + * Do not initialize the user session if the user exists but has no `site.login` permission + +# v2.2.0-rc.1 +## 11/09/2016 + +1. [](#new) + * Allow login via `username` or `email` + * Only allow password recovery via `email` address + +# v2.1.2 +## 10/01/2016 + +1. [](#bugfix) + * Fixed an old reference to `LoginUtils` and replaced with new `EmailUtils` + +# v2.1.1 +## 09/08/2016 + +1. [](#improved) + * Use better detection for admin allowing multi-site setup with subfolders + +# v2.1.0 +## 09/07/2016 + +1. [](#improved) + * Added support for Grav's autoescape twig setting + * Dropped unused variable reference + * Moved Email Utils to Email plugin + * Updated vendor libraries + * Allow explicitly showing the login page on pages that are not the Login form template [#11](https://github.com/getgrav/grav-plugin-maintenance/issues/11) + +# v2.0.1 +## 08/10/2016 + +1. [](#improved) + * Added Romanian + +# v2.0.0 +## 07/14/2016 + +1. [](#improved) + * Optimized nonce creation + * Point account path to core's account stream [#85](https://github.com/getgrav/grav-plugin-login/issues/85) + +# v2.0.0-rc.2 +## 06/21/2016 + +1. [](#new) + * Add an option to login protect a login-protected page media accessed through the page route [#45](https://github.com/getgrav/grav-plugin-login/issues/45) +1. [](#improved) + * Fixed some language keys +1. [](#bugfix) + * Correctly show an error message when the reset password form does not provide the correct nonce + +# v2.0.0-rc.1 +## 06/01/2016 + +1. [](#improved) + * French updated +1. [](#bugfix) + * Enable twig processing in a page #75 + * Deny access to registration when user registration is disabled #72 + +# v2.0.0-beta.3 +## 05/23/2016 + +1. [](#improved) + * Added a redirect after activation + * Changed hardcoded redirect routes to config-based +1. [](#bugfix) + * Fix a redirect issue #74 + * Don't error if missing a HTTP_USER_AGENT browser string + +# v2.0.0-beta.2 +## 05/03/2016 + +1. [](#improved) + * Improved the login form page once logged in + * Translate welcome and logout strings +1. [](#bugfix) + * Fixed logging out on the homepage + * Fixed an issue in processing user registration + +# v2.0.0-beta.1 +## 04/20/2016 + +1. [](#new) + * Introduce a more flexible Login plugin architecture, which allows separate authentication plugins to hook into the Login events. Separated OAuth to its own plugin. + * OAuth has been separated to its own plugin, needs to be installed separately and configured. The users account filename format has changed too, to fix an issue that involved people with the same name on a service. + * The `redirect` option has been changed to `redirect_after_login`. Make sure you update your configuration file. +1. [](#improved) + * Add a proper 'Access levels' config section for Login. + * Various underlying improvements + * Updated french, added german +1. [](#bugfix) + * Make username field autofocus + * Add validation to the password reset form + * Fixed an issue that allowed a user logged in, without access to the actual permissions set to view a page, to see its content, and the login form again even if already logged in. + +# v1.3.1 +## 02/05/2016 + +1. [](#new) + * Add translations for Username and Password (placeholders are not translated) +1. [](#improved) + * Improve registration, forgot, reset and login forms accessibility by setting the id attribute + * Improved french translation + * Add the correct message type when raising a form processing error +1. [](#bugfix) + * Show the correct error message when the user is not authorized to view a page + * Fix showing the OAuth links in the login form + +# v1.3.0 +## 01/06/2016 + +1. [](#new) + * Added a new CLI command to change a user's password + * Added a new CLI command to edit the user state +1. [](#improved) + * Improved french translation + +# v1.2.1 +## 12/18/2015 + +1. [](#new) + * Croatian translation +1. [](#improved) + * Use type `email` in registration form + * Drop manual validation in registration + +# v1.2.0 +## 12/11/2015 + +1. [](#new) + * Added account activation email upon registration + * Added forgot password functionality + * Support ACL from parent page + * Allow login immediately after account activation +1. [](#improved) + * Handle admin login page if available + * Example registration form now provided by plugin + * Better error handling of registration + * Tab-based plugin configuration + * Updated translations +1. [](#bugfix) + * Prevent failing when no default values are set + +# v1.1.0 +## 12/01/2015 + +1. [](#new) + * Support new **User Registration** +1. [](#improved) + * Use new security salt for newer and fallback otherwise + * Composer update of libraries + * Check for session existence else throw a runtime error +1. [](#bugfix) + * Fix remember-me functionality + * Check page exists so as not to fail hard + * Fix for static Inflector references #17 + + +# v1.0.1 +## 11/23/2015 + +1. [](#improved) + * Hardening cookies with user-agent and system cache key instead of deprecated system hash + * Set a custom route for login only if it's not an admin path + +# v1.0.0 +## 11/21/2015 + +1. [](#new) + * Added OAuth login support for _Facebook_, _Google_, _GitHub_ and _Twitter_ + * Added **Nonce** form security support + * Added option to "redirect after login" + * Added "remember me" functionality + * Added Hungarian translation +2. [](#improved) + * Added blueprints for Grav Admin plugin (multi-language support!) + +# v0.3.3 +## 09/11/2015 + +1. [](#improved) + * Changed authorise to authorize +1. [](#bugfix) + * Fix denied string + +# v0.3.2 +## 09/01/2015 + +1. [](#improved) + * Broke out login form into its own partial + +# v0.3.1 +## 08/31/2015 + +1. [](#improved) + * Added username field autofocus + +# v0.3.0 +## 08/24/2015 + +1. [](#new) + * Added simple CSS styling + * Added simple login status with logout +1. [](#improved) + * Improved README documentation + * More strings translated + * Updated blueprints + +# v0.2.0 +## 08/11/2015 + +1. [](#improved) + * Disable `enable` in admin + +# v0.1.0 +## 08/04/2015 + +1. [](#new) + * ChangeLog started... + +# v1.3.1 +## 02/05/2016 + +1. [](#new) + * Add translations for Username and Password (placeholders are not translated) +1. [](#improved) + * Improve registration, forgot, reset and login forms accessibility by setting the id attribute + * Improved french translation + * Add the correct message type when raising a form processing error +1. [](#bugfix) + * Show the correct error message when the user is not authorized to view a page + * Fix showing the OAuth links in the login form + +# v1.3.0 +## 01/06/2016 + +1. [](#new) + * Added a new CLI command to change a user's password + * Added a new CLI command to edit the user state +1. [](#improved) + * Improved french translation + +# v1.2.1 +## 12/18/2015 + +1. [](#new) + * Croatian translation +1. [](#improved) + * Use type `email` in registration form + * Drop manual validation in registration + +# v1.2.0 +## 12/11/2015 + +1. [](#new) + * Added account activation email upon registration + * Added forgot password functionality + * Support ACL from parent page + * Allow login immediately after account activation +1. [](#improved) + * Handle admin login page if available + * Example registration form now provided by plugin + * Better error handling of registration + * Tab-based plugin configuration + * Updated translations +1. [](#bugfix) + * Prevent failing when no default values are set + +# v1.1.0 +## 12/01/2015 + +1. [](#new) + * Support new **User Registration** +1. [](#improved) + * Use new security salt for newer and fallback otherwise + * Composer update of libraries + * Check for session existence else throw a runtime error +1. [](#bugfix) + * Fix remember-me functionality + * Check page exists so as not to fail hard + * Fix for static Inflector references #17 + + +# v1.0.1 +## 11/23/2015 + +1. [](#improved) + * Hardening cookies with user-agent and system cache key instead of deprecated system hash + * Set a custom route for login only if it's not an admin path + +# v1.0.0 +## 11/21/2015 + +1. [](#new) + * Added OAuth login support for _Facebook_, _Google_, _GitHub_ and _Twitter_ + * Added **Nonce** form security support + * Added option to "redirect after login" + * Added "remember me" functionality + * Added Hungarian translation +2. [](#improved) + * Added blueprints for Grav Admin plugin (multi-language support!) + +# v0.3.3 +## 09/11/2015 + +1. [](#improved) + * Changed authorise to authorize +1. [](#bugfix) + * Fix denied string + +# v0.3.2 +## 09/01/2015 + +1. [](#improved) + * Broke out login form into its own partial + +# v0.3.1 +## 08/31/2015 + +1. [](#improved) + * Added username field autofocus + +# v0.3.0 +## 08/24/2015 + +1. [](#new) + * Added simple CSS styling + * Added simple login status with logout +1. [](#improved) + * Improved README documentation + * More strings translated + * Updated blueprints + +# v0.2.0 +## 08/11/2015 + +1. [](#improved) + * Disable `enable` in admin + +# v0.1.0 +## 08/04/2015 + +1. [](#new) + * ChangeLog started... diff --git a/user/plugins/login/LICENSE b/user/plugins/login/LICENSE new file mode 100644 index 00000000..4bb70928 --- /dev/null +++ b/user/plugins/login/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2016 Grav + +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. diff --git a/user/plugins/login/README.md b/user/plugins/login/README.md new file mode 100644 index 00000000..7e7a592d --- /dev/null +++ b/user/plugins/login/README.md @@ -0,0 +1,535 @@ +# Grav Login Plugin + +The **login plugin** for [Grav](http://github.com/getgrav/grav) adds login, basic ACL, and session wide messages to Grav. It is designed to provide a way to secure front-end and admin content throughout Grav. + +# Installation + +The **login** plugin actually requires the help of the **email** and **form** plugins. The **email** plugin is needed to ensure that you can recover a password via email if required. The **form** plugin is used to generate the forms required. + +These are available via GPM, and because the plugin has dependencies you just need to proceed and install the login plugin, and agree when prompted to install the others: + +``` +$ bin/gpm install login +``` + +# Changes in version 2.6 + +* User registration is now disabled by default. If you were relying on it being activated, you need to manually enable it in your `user/config/plugins/login.yaml`: + + ``` + user_registration: + enabled: true + ``` +* `login_after_registration` has also been changed to a default value of `false` for security purposes. + + +# Changes in version 2.5 + +Added new `$grav['login']->login()` and `$grav['login']->logout()` functions for you to use. + +They use following events which can be hooked by plugins: + +* `onUserLoginAuthenticate` Allows plugins to include their own authentication methods. +* `onUserLoginAuthorize` Allows plugins to block user from being logged in. +* `onUserLoginFailure` Allows plugins to include their own logic when user authentication failed. +* `onUserLogin` Allows plugins to include their own logic when user logs in. +* `onUserLogout` Allows plugins to include their own logic when user logs out. +* `onUserLoginRegisterData` Allows plugins to include their own data to be added to the user object during registration. +* `onUserLoginRegistered` Allows plugins to hook into user registration just before the redirect. + +New Plugin options have been added for: + +* `dynamic_page_visibility` - Integrate access into page visibility so things can be shown or hidden in the menu + +# Changes in version 2.0 + +* OAuth has been separated to its own plugin, needs to be installed separately and configured. The users account filename format has changed too, to fix an issue that involved people with the same name on a service. +* The `redirect` option has been changed to `redirect_after_login`. +* The Remember Me session minimum length is now 1 week. +* Removed the option to login from oauth without creating the corresponding user file under `user/accounts/`. + +# Messages Output + +There is not a guaranteed way to display system messages including those added by the Login plugin, so in order to see messages you will need to make sure your theme has a method to output the messages. This is done by adding a simple Twig include, and the best place to do this to ensure it's visible in all your pages, is to add it to the `partials/base.html.twig` (or whatever your base Twig template is called): + +```twig + {% block messages %} + {% include 'partials/messages.html.twig' ignore missing %} + {% endblock %} +``` + +A good location is probably to add this right above where your content is going to be output. + +# Creating Users + +You can either use the built-in CLI capabilities, or you create a user manually by creating a new YAML file in your `user/accounts` folder. + + +# CLI Usage + +The simplest way to create a new user is to simply run the `bin/plugin login newuser` command. This will take you through a few questions to gather information with which to create your user. You can also use inline arguments to avoid the interactive questions. + +### Commands + +| Command | Arguments | Explination | +|---------------|--------------------------------------|----------------------------| +|`newuser`|Aliases: `add-user`, `new-user`|Creates a new user (creates file in `user/accounts/`) +|| [ -u, --user=USER ] | The username. | +|| [ -p, --password=PASSWORD ] | The password. Ensure the password respects Grav's password policy. **Note that this option is not recommended because the password will be visible by users listing the processes.** | +|| [ -e, --email=EMAIL ] | The user email address. | +|| [ -P, --permissions=PERMISSIONS ] | The user permissions. It can be either `a` for Admin access only, `s` for Site access only and `b` for both Admin and Site access. | +|| [ -N, --fullname=FULLNAME ] | The user full name | +|| [ -t, --title=TITLE ] | The title of the user. Usually used as a subtext. Example: Admin, Collaborator, Developer | +|| [ -s, --state=STATE ] | The state of the account. Either `enabled` (default) or `disabled` | +||| +|`changepass`|Aliases: `newpass`, `passwd`|Changes password of the specified user (User file must exist) +|| [ -u, --user=USER ] | The username. | +|| [ -p, --password=PASSWORD ] | The new password. Ensure the password respects Grav's password policy. **Note that this option is not recommended because the password will be visible by users listing the processes.** | + + +### CLI Example +``` +> bin/plugin login newuser -u joeuser -p 8c9sRCeBExAiwk -e joeuser@grav.org -P b -N "Joe User" -t "Site Administrator" +Creating new user + + +Success! User joeuser created. +``` + +### Interactive Example +``` +> bin/plugin login newuser +Creating new user + +Enter a username: joeuser +Enter a password: 8c9sRCeBExAiwk +Enter an email: joeuser@grav.org +Please choose a set of permissions: + [a] admin access + [s] site access + [b] admin and site access + > b +Enter a fullname: Joe User +Enter a title: Site Administrator +Please choose the state for the account: + [enabled ] Enabled + [disabled] Disabled + > enabled + +Success! User joeuser created. +``` + +### Manual User Creation + +Here is example user defined in `user/accounts/admin.yaml`: + +``` +password: password +email: youremail@mail.com +fullname: Johnny Appleseed +title: Site Administrator +access: + admin: + login: true + super: true +``` + +>> Note: the username is based on the name of the YAML file. + +# Default Configuration + +```yaml +enabled: true # Enable the plugin +built_in_css: true # Use built-in CSS +route: # Specific route for Login page (default is '/login') +redirect_to_login: true # If you try to access a page you don't have access to, should you redirect to login route +redirect_after_login: # Path to redirect to after a successful login (eg '/user_profile') +redirect_after_logout: '/' # Path to redirect to after a successful logout (eg '/') +route_activate: '/activate_user' # Route for the user activation process +route_forgot: '/forgot_password' # Route for the forgot password process +route_reset: '/reset_password' # Route for the reset password process +route_profile: '/user_profile' # Route for the user profile page +route_register: '/user_register' # Route for the user registration page +route_unauthorized: '/user_unauthorized' # Route for a page to display if user is unauthorized + +dynamic_page_visibility: false # Integrate access into page visibility so things can be shown or hidden in the menu +parent_acl: false # Look to parent `access` rules for access requirements +protect_protected_page_media: false # Take `access` rules into account when directly accessing a page's media + +rememberme: + enabled: true # Enable 'remember me' functionality + timeout: 604800 # Timeout in seconds. Defaults to 1 week + name: grav-rememberme # Name prefix of the session cookie + +max_pw_resets_count: 2 # Number of password resets in a specific time frame (0 = unlimited) +max_pw_resets_interval: 60 # Time in minutes to track password resets +max_login_count: 5 # Number of failed login attempts in a specific time frame (0 = unlimited) +max_login_interval: 10 # Time in minutes to track login attempts + +user_registration: + enabled: false # Enable User Registration Process + + fields: # List of fields to validate and store during user registration + - 'username' # This should match up with your registration form definition + - 'password' + - 'email' + - 'fullname' + - 'title' + - 'level' + + default_values: # Any default values for fields you would like to set + level: Newbie # Here the 'level' field will be pre-populated with 'Newbie' text + + access: # Default access to set for users created during registration + site: + login: 'true' + + redirect_after_registration: '' # Route to redirect to after registration + + options: + validate_password1_and_password2: true # Ensure that password1 and password2 match during registration (allows you to have just 1 pw field or 2) + set_user_disabled: false # Set this `true` if you want a user to activate their account via email + login_after_registration: false # Automatically login after registration + send_activation_email: false # Send an email that requires a special link to be clicked in order to activate the account + manually_enable: false # When using activation email, don't enable until an admin does it manually + send_notification_email: false # Send an email to the site administrator to indicate a user has registered + send_welcome_email: false # Send a welcome email to the user (probably should not be used with `send_activation_email` +``` + +# Usage + +You can add ACL to any page by typing something like below into the page header: + +``` +access: + site.login: true + admin.login: true +``` + +Users who have any of the listed ACL roles enabled will have access to the page. +Others will be forwarded to login screen. + +Because the admin user contains an `admin.login: true` reference he will be able to login to the secured page because that is one of the conditions defined in the page header. You are free to create any specific set of ACL rules you like. Your user account must simply contain those same rules if you wish the user to have access. + +## Create Private Areas + +Enabling the setting "Use parent access rules" (`parent_acl` in login.yaml) allows you to create private areas where you set the access level on the parent page, and all the subpages inherit that requirement. + +# Login Page + +>> Note: the **frontend site** and **admin plugin** use different sessions so you need to explicitly provide a login on the frontend. + +The login plugin can **automatically generate** a login page for you when you try to access a page that your user (or guest account) does not have access to. + +Alternatively, you can also provide a specific login route if you wish to forward users to a specific login page. To do this you need to create a copy of the `login.yaml` from the plugin in your `user/config/plugins` folder and provide a specific route (or just edit the plugin setttings in the admin plugin). + +``` +route: /user-login +``` + +You would then need to provide a suitable login form, probably based on the one that is provided with the plugin. + +## Redirection after Login + +By default Grav will redirect to the prior page visited before entering the login process. Any page is fair game unless you manually set: + +``` +login_redirect_here: false +``` + +In the page's header. If you set this value to `false`, this page will not be a valid redirect page, and the page visited prior to this page will be considered. + +You can override this default behavior by forcing a standard location by specifying an explicit option in your Login configuration YAML: + +``` +redirect_after_login: '/profile' +``` + +This will always take you to the `/profile` route after a successful login. + +# Logout + +The login plugin comes with a simple Twig partial to provide a logout link (`login-status.html.twig`). You will need to include it in your theme however. An example of this can be found in the Antimatter theme's `partials/navigation.html.twig` file: + +``` +{% if config.plugins.login.enabled and grav.user.username %} +
                                                          • {% include 'partials/login-status.html.twig' %}
                                                          • +{% endif %} +``` + +You can also copy this `login-status.html.twig` file into your theme and modify it as you see fit. + +# Allow User Registration + +The Login plugin handles user registration. +To enable the built-in registration form, in the Login Plugin configuration enable user registration and just add a value to the "Registration path" field. + +Then just open your browser on that page, and you'll be presented a registration form. + +## Adding the registration page to the menu + +Here are two ways you can do it, but of course Grav is flexible and you can come up with other ways too. + +The first and easiest way is to add a page with the same slug (route) as the registration form. So for example if in the Login Plugin settings you set /register as the registration form path, then create a `04.register` page (the 04 number is just an example, use your own ordering), with no content. +The Login plugin will "override" that page, serving the registration page form when the user clicks on that menu item. + +A second way is to add a custom menu item that points to the registration page, by editing `site.yaml` with this code, that will append a "Register" menu item: + +``` +menu: + - + url: 'register' + text: Register +``` + +This works in most themes, Antimatter included, but it's not guaranteed to work in all themes, as it's something that must be added to the navigation twig code. + +## Customizing the registration form + +The provided registration form is just a quick way to start using it. You might however need different fields on the registration form, or you want to add more content. Here's how to do it. + +First, create a registration form page. + +Create a folder `04.registration/form.md`. The folder name is just an example. Pick the one that suits you. The important part is the file name: since we're building a form, we need a `form.md` file. + +Also, your theme needs to implement forms. Use Antimatter or another form-compatible theme if yours does not work, then once you're setup with the form you can migrate the forms files and make it work on your theme too. + +Add the following content to your registration form page: + +```yaml +--- +form: + + fields: + fullname: + type: text + validate: + required: true + + username: + type: text + validate: + required: true + message: PLUGIN_LOGIN.USERNAME_NOT_VALID + config-pattern@: system.username_regex + + email: + type: email + validate: + required: true + message: PLUGIN_LOGIN.EMAIL_VALIDATION_MESSAGE + + password1: + type: password + label: Enter a password + validate: + required: true + message: PLUGIN_LOGIN.PASSWORD_VALIDATION_MESSAGE + config-pattern@: system.pwd_regex + + password2: + type: password + label: Enter the password again + validate: + required: true + message: PLUGIN_LOGIN.PASSWORD_VALIDATION_MESSAGE + config-pattern@: system.pwd_regex + + buttons: + - + type: submit + value: Submit + - + type: reset + value: Reset + + process: + register_user: true + message: "Thanks for registering..." + reset: true +--- +``` + +# Registration of Users + +Create a new user account by entering all the required fields below: + +This is a normal form. The only thing different from a contact form or another form that you might write on your site is the process field `register_user`, which takes care of processing the user registration. + +Once the user is registered, Grav redirects the user to the `display` page with the `message` message. + +The only field strictly required by Grav is `username`. Then the other fields can be added as needed. + +For example in this case we added + +- password1 +- password2 + +to the form. And, in the Login plugin configuration we have by default enable the double password verification with the "Validate double entered password" option. What this does is picking the password1 and password2 fields, validate them, check they are equal and put the content in the `password` field. + +You can avoid having 2 fields for the password, which by the way is a recommended option, and just put a single `password` field. + +Last important thing before the registration is correctly setup: make sure in the Login plugin settings you have the user registration enabled, otherwise the registration will trigger an error, as by default user registration is DISABLED. + + +# Registration Options + +There are several options that can be configured when registering users via `user/plugins/login.yaml`, they are pretty self-explanatory: + +```yaml +user_registration: + enabled: false # Enable User Registration Process + + fields: # List of fields to validate and store during user registration + - 'username' # This should match up with your registration form definition + - 'password' + - 'email' + - 'fullname' + - 'title' + - 'level' + + default_values: # Any default values for fields you would like to set + level: Newbie # Here the 'level' field will be pre-populated with 'Newbie' text + + access: # Default access to set for users created during registration + site: + login: 'true' + + redirect_after_registration: '' # Route to redirect to after registration + + options: + validate_password1_and_password2: true # Ensure that password1 and password2 match during registration (allows you to have just 1 pw field or 2) + set_user_disabled: false # Set this `true` if you want a user to activate their account via email + login_after_registration: false # Automatically login after registration + send_activation_email: false # Send an email that requires a special link to be clicked in order to activate the account + send_notification_email: false # Send an email to the site administrator to indicate a user has registered + send_welcome_email: false # Send a welcome email to the user (probably should not be used with `send_activation_email` +``` + +## Sending an activation email + +By default the registration process adds a new user, and sets it as enabled. +Grav allows disabled user accounts, so we can take advantage of this functionality and add a new user, but with a disabled state. Then we can send an email to the user, asking to validate the email address. + +That validation email will contain a link to set the user account to enabled. To do this, just enable "Set the user as disabled" and "Send activation email" in the Login Plugin options. + +## Send a welcome email + +Enable "Send welcome email" in the options. + +The content of the welcome email is defined in the language file, strings `PLUGIN_LOGIN.WELCOME_EMAIL_SUBJECT` and `PLUGIN_LOGIN.WELCOME_EMAIL_BODY`. Customize them as needed in your language file override. + +Note: if the activation email is enabled, the welcome email to be sent upon the account activation action (when the user clicks the link to activate the account) + +## Send a notification email to the site owner + +Enable "Send notification email" in the options. + +The content of the notification email is defined in the language file, strings `PLUGIN_LOGIN.NOTIFICATION_EMAIL_SUBJECT` and `PLUGIN_LOGIN.NOTIFICATION_EMAIL_BODY`. Customize them as needed in your language file override. + +Note: if the activation email is enabled, the notification email to be sent upon the account activation action (when the user clicks the link to activate the account) + +## Default Access + +To control what access your users have upon registering you can edit the `user_registration.access:` attribute in the `user/plugins/login.yaml`. The default is simply `site.login: true`: + +``` +user_registration: + access: + site: + login: 'true' +``` + +## Adding your own fields + +If you want to add your own custom fields to the registration form, just add fields to the form like you would with any other form. + +Then, to let the Login plugin add those fields to the user yaml file, you also need to add it to the "Registration fields" option in the Login Plugin configuration. + +By default we have + +``` +user_registration: + fields: + - 'username' + - 'password' + - 'email' + - 'fullname' + - 'title' +``` + +Add your own as you prefer, to build any custom registration form you can think of. + +## Specifying a default value for a field + +If you want to pre-fill a field, without showing it to the user in the form, you could set it as an hidden field. But the user could see it - and modify it via the browser dev tools. + +To add a field and make sure the user cannot modify it, add it to "default_values" list: + +``` +user_registration: + default_values: + title: "Newbie User" +``` + +## Login users directly after the registration + +Just enable "Login the user after registration" + +If the user activation email is enabled, the user will be logged in as soon as the activation link is clicked. + +## Add captcha to the user registration + +Add a captcha like you would with any form: + +Add + +``` + - name: g-recaptcha-response + label: Captcha + type: captcha + recaptcha_site_key: aeio43kdk3idko3k4ikd4 + recaptcha_not_validated: 'Captcha not valid!' + validate: + required: true +``` + +to the form field, and + +``` +process: + - captcha +``` + +to validate it server-side. Put this process action before all the other actions, so it's processed first and the user is not created if the captcha is not valid. + +## Redirect to another page after login + +You can set the "Redirect after registration" option in the Login plugin, or as with any form, use the `process.display` property, and set it to the destination page route: + +``` + process: + - + display: /welcome +``` + +## Dynamic Page Visibility + +You can control whether or not a page is visible to a user by first enabling the option in the `login` configuration: + +``` +dyanamic_page_visilbity: true +``` + +With this activated you can put the following option into the header of each page: + +``` +login: + visibility_requires_access: true +``` + +This will ensure the `access:` options on the page are satisfied in order for this page to be `visible` and therefore displayed in the menu structure. + +# Known issues + +When updating from an older version, pre-october 2015, you might have an error `Class 'Grav\Login\Controller' Not Found`. The problem is during the update, since a file name was changed from lowercase to capitalized. Solution: reinstall the Login plugin, or change the file name `user/plugins/login/classes/controller.php` to `user/plugins/login/classes/Controller.php` (notice the capital `C`). diff --git a/user/plugins/login/blueprints.yaml b/user/plugins/login/blueprints.yaml new file mode 100644 index 00000000..cd617589 --- /dev/null +++ b/user/plugins/login/blueprints.yaml @@ -0,0 +1,421 @@ +name: Login +version: 3.0.4 +testing: false +description: Enables user authentication and login screen. +icon: sign-in +author: + name: Team Grav + email: devs@getgrav.org + url: http://getgrav.org +homepage: https://github.com/getgrav/grav-plugin-login +keywords: login, authentication, admin, security +bugs: https://github.com/getgrav/grav-plugin-login/issues +license: MIT + +dependencies: + - { name: grav, version: '>=1.6.7' } + - { name: form, version: '>=3.0.0' } + - { name: email, version: '>=3.0.0' } + +form: + validation: loose + fields: + + tabs: + type: tabs + active: 1 + class: subtle + + fields: + login: + type: tab + title: PLUGIN_LOGIN.BTN_LOGIN + + fields: + + enabled: + type: hidden + label: PLUGIN_LOGIN.PLUGIN_STATUS + highlight: 1 + default: 1 + options: + 1: PLUGIN_ADMIN.ENABLED + 0: PLUGIN_ADMIN.DISABLED + validate: + type: bool + + built_in_css: + type: toggle + label: PLUGIN_LOGIN.BUILTIN_CSS + highlight: 1 + default: 1 + help: PLUGIN_LOGIN.BUILTIN_CSS_HELP + options: + 1: PLUGIN_ADMIN.ENABLED + 0: PLUGIN_ADMIN.DISABLED + validate: + type: bool + + route: + type: text + size: medium + label: PLUGIN_LOGIN.ROUTE + help: PLUGIN_LOGIN.ROUTE_HELP + placeholder: "/my-custom-login" + + redirect_after_login: + type: text + label: PLUGIN_LOGIN.REDIRECT_AFTER_LOGIN + help: PLUGIN_LOGIN.REDIRECT_AFTER_LOGIN_HELP + placeholder: "/my-page" + + redirect_after_logout: + type: text + label: PLUGIN_LOGIN.REDIRECT_AFTER_LOGOUT + help: PLUGIN_LOGIN.REDIRECT_AFTER_LOGOUT_HELP + placeholder: "/" + + route_forgot: + type: text + size: medium + label: PLUGIN_LOGIN.ROUTE_FORGOT + placeholder: "/forgot_password" + + route_reset: + type: text + size: medium + label: PLUGIN_LOGIN.ROUTE_RESET + placeholder: "/reset_password" + + route_profile: + type: text + size: medium + label: PLUGIN_LOGIN.ROUTE_PROFILE + placeholder: "/user_profile" + + parent_acl: + type: toggle + label: PLUGIN_LOGIN.USE_PARENT_ACL_LABEL + highlight: 1 + default: 0 + help: PLUGIN_LOGIN.USE_PARENT_ACL_HELP + options: + 1: PLUGIN_ADMIN.ENABLED + 0: PLUGIN_ADMIN.DISABLED + validate: + type: bool + + dynamic_page_visibility: + type: toggle + label: PLUGIN_LOGIN.DYNAMIC_VISIBILITY + highlight: 0 + default: 0 + help: PLUGIN_LOGIN.DYNAMIC_VISIBILITY_HELP + options: + 1: PLUGIN_ADMIN.ENABLED + 0: PLUGIN_ADMIN.DISABLED + validate: + type: bool + + twofa_enabled: + type: toggle + label: PLUGIN_LOGIN.2FA_ENABLED + highlight: 0 + default: 0 + help: PLUGIN_LOGIN.2FA_ENABLED_HELP + options: + 1: PLUGIN_ADMIN.ENABLED + 0: PLUGIN_ADMIN.DISABLED + validate: + type: bool + + protect_protected_page_media: + type: toggle + label: PLUGIN_LOGIN.PROTECT_PROTECTED_PAGE_MEDIA_LABEL + highlight: 1 + default: 0 + help: PLUGIN_LOGIN.PROTECT_PROTECTED_PAGE_MEDIA_HELP + options: + 1: PLUGIN_ADMIN.ENABLED + 0: PLUGIN_ADMIN.DISABLED + validate: + type: bool + + routes: + type: section + title: PLUGIN_LOGIN.ROUTES + + fields: + + route_activate: + type: text + size: medium + label: PLUGIN_LOGIN.ROUTE_ACTIVATE + placeholder: '/activate_user' + + route_forgot: + type: text + size: medium + label: PLUGIN_LOGIN.ROUTE_FORGOT + placeholder: '/forgot_password' + + route_reset: + type: text + size: medium + label: PLUGIN_LOGIN.ROUTE_RESET + placeholder: '/reset_password' + + route_profile: + type: text + size: medium + label: PLUGIN_LOGIN.ROUTE_PROFILE + placeholder: '/user_profile' + + route_register: + type: text + size: medium + label: PLUGIN_LOGIN.ROUTE_REGISTER + help: PLUGIN_LOGIN.ROUTE_REGISTER_HELP + placeholder: "/register" + + user_registration.redirect_after_registration: + type: text + label: PLUGIN_LOGIN.REDIRECT_AFTER_REGISTRATION + help: PLUGIN_LOGIN.REDIRECT_AFTER_REGISTRATION_HELP + placeholder: "/page-to-show-after-registration" + + user_registration.redirect_after_activation: + type: text + label: PLUGIN_LOGIN.REDIRECT_AFTER_ACTIVATION + help: PLUGIN_LOGIN.REDIRECT_AFTER_ACTIVATION_HELP + placeholder: "/page-to-show-after-activation" + + rememberme: + type: section + title: PLUGIN_LOGIN.REMEMBER_ME + + fields: + rememberme.enabled: + type: toggle + label: PLUGIN_ADMIN.ENABLED + help: PLUGIN_ADMIN.SESSION_ENABLED_HELP + highlight: 1 + options: + 1: PLUGIN_ADMIN.YES + 0: PLUGIN_ADMIN.NO + validate: + type: bool + + rememberme.timeout: + type: text + size: small + default: 604800 + label: PLUGIN_ADMIN.TIMEOUT + help: PLUGIN_LOGIN.TIMEOUT_HELP + validate: + type: number + min: 1 + + rememberme.name: + type: text + size: small + label: PLUGIN_ADMIN.NAME + help: PLUGIN_ADMIN.SESSION_NAME_HELP + + registration: + type: tab + title: PLUGIN_LOGIN.USER_REGISTRATION + + fields: + user_registration.enabled: + type: toggle + label: PLUGIN_ADMIN.ENABLED + help: PLUGIN_LOGIN.USER_REGISTRATION_ENABLED_HELP + highlight: 0 + options: + 1: PLUGIN_ADMIN.YES + 0: PLUGIN_ADMIN.NO + validate: + type: bool + + registration_fields: + type: section + title: PLUGIN_LOGIN.REGISTRATION_FIELDS + + fields: + user_registration.fields: + type: array + value_only: true + label: PLUGIN_LOGIN.REGISTRATION_FIELDS + help: PLUGIN_LOGIN.REGISTRATION_FIELDS_HELP + placeholder_key: PLUGIN_LOGIN.REGISTRATION_FIELD_KEY + placeholder_value: PLUGIN_LOGIN.ADDITIONAL_PARAM_VALUE + + user_registration.default_values: + type: array + label: PLUGIN_LOGIN.DEFAULT_VALUES + help: PLUGIN_LOGIN.DEFAULT_VALUES_HELP + placeholder_key: PLUGIN_LOGIN.ADDITIONAL_PARAM_KEY + placeholder_value: PLUGIN_LOGIN.ADDITIONAL_PARAM_VALUE + + access_levels: + title: PLUGIN_ADMIN.ACCESS_LEVELS + type: section + security: admin.super + + fields: + user_registration.groups: + type: selectize + size: large + label: PLUGIN_ADMIN.GROUPS + '@data-options': '\Grav\User\Groups::groups' + classes: fancy + help: PLUGIN_LOGIN.GROUPS_HELP + validate: + type: commalist + + user_registration.access.site: + type: array + label: PLUGIN_ADMIN.SITE_ACCESS + help: PLUGIN_LOGIN.SITE_ACCESS_HELP + multiple: false + validate: + type: array + + options: + type: section + title: PLUGIN_LOGIN.OPTIONS + + fields: + + user_registration.options.validate_password1_and_password2: + type: toggle + label: PLUGIN_LOGIN.VALIDATE_PASSWORD1_AND_PASSWORD2 + help: PLUGIN_LOGIN.VALIDATE_PASSWORD1_AND_PASSWORD2_HELP + highlight: 1 + options: + 1: PLUGIN_ADMIN.YES + 0: PLUGIN_ADMIN.NO + validate: + type: bool + + user_registration.options.set_user_disabled: + type: toggle + label: PLUGIN_LOGIN.SET_USER_DISABLED + help: PLUGIN_LOGIN.SET_USER_DISABLED_HELP + highlight: 0 + options: + 1: PLUGIN_ADMIN.YES + 0: PLUGIN_ADMIN.NO + validate: + type: bool + + user_registration.options.login_after_registration: + type: toggle + label: PLUGIN_LOGIN.LOGIN_AFTER_REGISTRATION + help: PLUGIN_LOGIN.LOGIN_AFTER_REGISTRATION_HELP + highlight: 0 + options: + 1: PLUGIN_ADMIN.YES + 0: PLUGIN_ADMIN.NO + validate: + type: bool + + user_registration.options.send_activation_email: + type: toggle + label: PLUGIN_LOGIN.SEND_ACTIVATION_EMAIL + help: PLUGIN_LOGIN.SEND_ACTIVATION_EMAIL_HELP + highlight: 0 + options: + 1: PLUGIN_ADMIN.YES + 0: PLUGIN_ADMIN.NO + validate: + type: bool + + user_registration.options.manually_enable: + type: toggle + label: PLUGIN_LOGIN.MANUALLY_ENABLE + help: PLUGIN_LOGIN.MANUALLY_ENABLE_HELP + highlight: 0 + options: + 1: PLUGIN_ADMIN.YES + 0: PLUGIN_ADMIN.NO + validate: + type: bool + + user_registration.options.send_notification_email: + type: toggle + label: PLUGIN_LOGIN.SEND_NOTIFICATION_EMAIL + help: PLUGIN_LOGIN.SEND_NOTIFICATION_EMAIL_HELP + highlight: 0 + options: + 1: PLUGIN_ADMIN.YES + 0: PLUGIN_ADMIN.NO + validate: + type: bool + + user_registration.options.send_welcome_email: + type: toggle + label: PLUGIN_LOGIN.SEND_WELCOME_EMAIL + help: PLUGIN_LOGIN.SEND_WELCOME_EMAIL_HELP + highlight: 0 + options: + 1: PLUGIN_ADMIN.YES + 0: PLUGIN_ADMIN.NO + validate: + type: bool + + Security: + type: tab + title: PLUGIN_LOGIN.SECURITY_TAB + + fields: + max_pw_resets_count: + type: number + size: x-small + label: PLUGIN_LOGIN.MAX_RESETS_COUNT + help: PLUGIN_LOGIN.MAX_RESETS_COUNT_HELP + append: PLUGIN_LOGIN.RESETS + validate: + type: number + min: 0 + + max_pw_resets_interval: + type: number + size: x-small + label: PLUGIN_LOGIN.MAX_RESETS_INTERVAL + help: PLUGIN_LOGIN.MAX_RESETS_INTERVAL_HELP + append: PLUGIN_LOGIN.MINUTES + validate: + type: number + min: 1 + + max_login_count: + type: number + size: x-small + label: PLUGIN_LOGIN.MAX_LOGINS_COUNT + help: PLUGIN_LOGIN.MAX_LOGINS_COUNT_HELP + append: PLUGIN_LOGIN.ATTEMPTS + validate: + type: number + min: 0 + + max_login_interval: + type: number + size: x-small + label: PLUGIN_LOGIN.MAX_LOGINS_INTERVAL + help: PLUGIN_LOGIN.MAX_LOGINS_INTERVAL_HELP + append: PLUGIN_LOGIN.MINUTES + validate: + type: number + min: 1 + + ipv6_subnet_size: + type: number + size: x-small + label: PLUGIN_LOGIN.IPV6_SUBNET_SIZE + help: PLUGIN_LOGIN.IPV6_SUBNET_SIZE_HELP + append: PLUGIN_LOGIN.MINUTES + validate: + type: number + min: 1 diff --git a/user/plugins/login/classes/Controller.php b/user/plugins/login/classes/Controller.php new file mode 100644 index 00000000..ef98e0b5 --- /dev/null +++ b/user/plugins/login/classes/Controller.php @@ -0,0 +1,605 @@ +rememberMe() instead + */ + protected $rememberMe; + + /** + * @var Login + */ + protected $login; + + /** + * @param Grav $grav + * @param string $action + * @param array $post + */ + public function __construct(Grav $grav, $action, $post = null) + { + $this->grav = $grav; + $this->action = $action; + $this->login = $this->grav['login']; + $this->post = $post ? $this->getPost($post) : []; + + $this->rememberMe(); + } + + /** + * Performs an action. + * @throws \RuntimeException + */ + public function execute() + { + $messages = $this->grav['messages']; + + // Set redirect if available. + $redirect = $this->post['_redirect'] ?? null; + unset($this->post['_redirect']); + + $success = false; + $method = $this->prefix . ucfirst($this->action); + + if (!method_exists($this, $method)) { + throw new \RuntimeException('Page Not Found', 404); + } + + try { + $success = $this->{$method}(); + } catch (\RuntimeException $e) { + $messages->add($e->getMessage(), 'error'); + $this->grav['log']->error('plugin.login: '. $e->getMessage()); + } + + if (!$this->redirect && $redirect) { + $this->setRedirect($redirect, 303); + } + + return $success; + } + + /** + * Handle login. + * + * @return bool True if the action was performed. + */ + public function taskLogin() + { + /** @var Language $t */ + $t = $this->grav['language']; + + /** @var Message $messages */ + $messages = $this->grav['messages']; + + $userKey = (string)($this->post['username'] ?? ''); + $ip = Uri::ip(); + $isIPv4 = filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4); + $ipKey = $isIPv4 ? $ip : Utils::getSubnet($ip, $this->grav['config']->get('plugins.login.ipv6_subnet_size')); + + // Is twofa enabled? + $twofa = $this->grav['config']->get('plugins.login.twofa_enabled', false); + + // Pseudonymization of the IP + $ipKey = sha1($ipKey . $this->grav['config']->get('security.salt')); + + $rateLimiter = $this->login->getRateLimiter('login_attempts'); + + // Check if the current IP has been used in failed login attempts. + $attempts = \count($rateLimiter->getAttempts($ipKey, 'ip')); + + $rateLimiter->registerRateLimitedAction($ipKey, 'ip')->registerRateLimitedAction($userKey); + + // Check rate limit for both IP and user, but allow each IP a single try even if user is already rate limited. + if ($rateLimiter->isRateLimited($ipKey, 'ip') || ($attempts && $rateLimiter->isRateLimited($userKey))) { + $messages->add($t->translate(['PLUGIN_LOGIN.TOO_MANY_LOGIN_ATTEMPTS', $rateLimiter->getInterval()]), 'error'); + $this->setRedirect($this->grav['config']->get('plugins.login.route', '/')); + + return true; + } + + // Remove login nonce from the form. + $form = array_diff_key($this->post, ['login-form-nonce' => true]); + + // Fire Login process. + $event = $this->login->login($form, ['remember_me' => true, 'twofa' => $twofa], ['return_event' => true]); + $user = $event->getUser(); + + if ($user->authenticated) { + $rateLimiter->resetRateLimit($ipKey, 'ip')->resetRateLimit($userKey); + if ($user->authorized) { + $event->defMessage('PLUGIN_LOGIN.LOGIN_SUCCESSFUL', 'info'); + + $event->defRedirect( + $this->grav['session']->redirect_after_login ?: + $this->grav['config']->get('plugins.login.redirect_after_login') ?: + $this->grav['uri']->referrer('/') + ); + } else { + $login_route = $this->grav['config']->get('plugins.login.route'); + $event->defRedirect($login_route ?: $this->grav['uri']->referrer('/')); + } + } else { + if ($user->authorized) { + $event->defMessage('PLUGIN_LOGIN.ACCESS_DENIED', 'error'); + + $event->defRedirect($this->grav['config']->get('plugins.login.route_unauthorized', '/')); + } else { + $event->defMessage('PLUGIN_LOGIN.LOGIN_FAILED', 'error'); + } + } + + $message = $event->getMessage(); + if ($message) { + $messages->add($t->translate($message), $event->getMessageType()); + } + + $redirect = $event->getRedirect(); + if ($redirect) { + $this->setRedirect($redirect, $event->getRedirectCode()); + } + + return true; + } + + public function taskTwoFa() + { + /** @var Language $t */ + $t = $this->grav['language']; + + /** @var Message $messages */ + $messages = $this->grav['messages']; + + /** @var TwoFactorAuth $twoFa */ + $twoFa = $this->grav['login']->twoFactorAuth(); + $user = $this->grav['user']; + + $code = $this->post['2fa_code'] ?? null; + $secret = $user->twofa_secret ?? null; + + if (!$code || !$secret || !$twoFa->verifyCode($secret, $code)) { + $messages->add($t->translate('PLUGIN_LOGIN.2FA_FAILED'), 'error'); + + $user->authenticated = false; + + $login_route = $this->grav['config']->get('plugins.login.route'); + if ($login_route) { + $this->setRedirect($login_route, 303); + } + + return true; + } + + $messages->add($t->translate('PLUGIN_LOGIN.LOGIN_SUCCESSFUL'), 'info'); + + $user->authorized = true; + + $this->setRedirect( + $this->grav['session']->redirect_after_login + ?: $this->grav['config']->get('plugins.login.redirect_after_login') + ?: $this->grav['uri']->referrer('/') + ); + + return true; + } + + /** + * Handle logout. + * + * @return bool True if the action was performed. + */ + public function taskLogout() + { + $event = $this->login->logout(['remember_me' => true], ['return_event' => true]); + + $message = $event->getMessage(); + if ($message) { + /** @var Language $t */ + $t = $this->grav['language']; + + $messages = $this->grav['messages']; + $messages->add($t->translate($message), $event->getMessageType()); + } + + $redirect = $event->getRedirect() ?: $this->grav['config']->get('plugins.login.redirect_after_logout'); + if ($redirect) { + $this->setRedirect($redirect, $event->getRedirectCode()); + } + + $this->grav['session']->setFlashCookieObject(LoginPlugin::TMP_COOKIE_NAME, ['message' => $this->grav['language']->translate('PLUGIN_LOGIN.LOGGED_OUT'), + 'status' => 'info']); + + return true; + } + + /** + * Handle the email password recovery procedure. + * + * @return bool True if the action was performed. + */ + protected function taskForgot() + { + $param_sep = $this->grav['config']->get('system.param_sep', ':'); + $data = $this->post; + + /** @var UserCollectionInterface $users */ + $users = $this->grav['accounts']; + + $email = $data['email'] ?? ''; + $user = !empty($email) ? $users->find($email, ['email']) : null; + + /** @var Language $language */ + $language = $this->grav['language']; + $messages = $this->grav['messages']; + + if (!isset($this->grav['Email'])) { + $messages->add($language->translate('PLUGIN_LOGIN.FORGOT_EMAIL_NOT_CONFIGURED'), 'error'); + $this->setRedirect($this->grav['config']->get('plugins.login.route_forgot', '/')); + + return true; + } + + if (!$user || !$user->exists()) { + $messages->add($language->translate('PLUGIN_LOGIN.FORGOT_INSTRUCTIONS_SENT_VIA_EMAIL'), 'info'); + $this->setRedirect($this->grav['config']->get('plugins.login.route_forgot', '/')); + + return true; + } + + if (empty($user->email)) { + $messages->add($language->translate(['PLUGIN_LOGIN.FORGOT_CANNOT_RESET_EMAIL_NO_EMAIL', $email]), + 'error'); + $this->setRedirect($this->grav['config']->get('plugins.login.route_forgot', '/')); + + return true; + } + + if (empty($user->password) && empty($user->hashed_password)) { + $messages->add($language->translate(['PLUGIN_LOGIN.FORGOT_CANNOT_RESET_EMAIL_NO_PASSWORD', $email]), + 'error'); + $this->setRedirect($this->grav['config']->get('plugins.login.route_forgot', '/')); + + return true; + } + + $from = $this->grav['config']->get('plugins.email.from'); + + if (empty($from)) { + $messages->add($language->translate('PLUGIN_LOGIN.FORGOT_EMAIL_NOT_CONFIGURED'), 'error'); + $this->setRedirect($this->grav['config']->get('plugins.login.route_forgot', '/')); + + return true; + } + + $userKey = $user->username; + $rateLimiter = $this->login->getRateLimiter('pw_resets'); + $rateLimiter->registerRateLimitedAction($userKey); + + if ($rateLimiter->isRateLimited($userKey)) { + $messages->add($language->translate(['PLUGIN_LOGIN.FORGOT_CANNOT_RESET_IT_IS_BLOCKED', $email, $rateLimiter->getInterval()]), 'error'); + $this->setRedirect($this->grav['config']->get('plugins.login.route', '/')); + + return true; + } + + $token = md5(uniqid(mt_rand(), true)); + $expire = time() + 604800; // next week + + $user->reset = $token . '::' . $expire; + $user->save(); + + $author = $this->grav['config']->get('site.author.name', ''); + $fullname = $user->fullname ?: $user->username; + + if ($this->grav['language']->getDefault() != $this->grav['language']->getLanguage()) { + $lang = '/'.$this->grav['language']->getLanguage(); + } else { + $lang = ''; + } + + $reset_link = $this->grav['base_url_absolute'] . $lang . $this->grav['config']->get('plugins.login.route_reset') . '/task:login.reset/token' . $param_sep . $token . '/user' . $param_sep . $user->username . '/nonce' . $param_sep . Utils::getNonce('reset-form'); + + $sitename = $this->grav['config']->get('site.title', 'Website'); + + $to = $user->email; + + $subject = $language->translate(['PLUGIN_LOGIN.FORGOT_EMAIL_SUBJECT', $sitename]); + $content = $language->translate(['PLUGIN_LOGIN.FORGOT_EMAIL_BODY', $fullname, $reset_link, $author, $sitename]); + + $sent = EmailUtils::sendEmail($subject, $content, $to); + + if ($sent < 1) { + $messages->add($language->translate('PLUGIN_LOGIN.FORGOT_FAILED_TO_EMAIL'), 'error'); + } else { + $messages->add($language->translate('PLUGIN_LOGIN.FORGOT_INSTRUCTIONS_SENT_VIA_EMAIL'), 'info'); + } + + $this->setRedirect($this->grav['config']->get('plugins.login.route', '/')); + + return true; + } + + /** + * Handle the reset password action. + * + * @return bool True if the action was performed. + * @throws \Exception + */ + public function taskReset() + { + $data = $this->post; + $language = $this->grav['language']; + $messages = $this->grav['messages']; + + if (isset($data['password'])) { + /** @var UserCollectionInterface $users */ + $users = $this->grav['accounts']; + + $username = $data['username'] ?? null; + $user = !empty($username) ? $users->find($username) : null; + $password = $data['password'] ?? null; + $token = $data['token'] ?? null; + + if ($user && !empty($user->reset) && $user->exists()) { + [$good_token, $expire] = explode('::', $user->reset); + + if ($good_token === $token) { + if (time() > $expire) { + $messages->add($language->translate('PLUGIN_LOGIN.RESET_LINK_EXPIRED'), 'error'); + $this->grav->redirectLangSafe($this->grav['config']->get('plugins.login.route_forgot', '/')); + + return true; + } + + unset($user->hashed_password, $user->reset); + $user->password = $password; + $user->save(); + + $messages->add($language->translate('PLUGIN_LOGIN.RESET_PASSWORD_RESET'), 'info'); + $this->setRedirect($this->grav['config']->get('plugins.login.route', '/')); + + return true; + } + } + + $messages->add($language->translate('PLUGIN_LOGIN.RESET_INVALID_LINK'), 'error'); + $this->grav->redirectLangSafe($this->grav['config']->get('plugins.login.route_forgot')); + + return true; + + } + + $user = $this->grav['uri']->param('user'); + $token = $this->grav['uri']->param('token'); + + if (!$user || !$token) { + $messages->add($language->translate('PLUGIN_LOGIN.RESET_INVALID_LINK'), 'error'); + $this->grav->redirectLangSafe($this->grav['config']->get('plugins.login.route_forgot')); + + return true; + } + + return true; + } + + /** + * @param null $secret + * @return bool + */ + public function taskRegenerate2FASecret() + { + try { + /** @var UserInterface $user */ + $user = $this->grav['user']; + + if ($user->exists()) { + /** @var TwoFactorAuth $twoFa */ + $twoFa = $this->grav['login']->twoFactorAuth(); + $secret = $twoFa->createSecret(); + $image = $twoFa->getQrImageData($user->username, $secret); + + // Change secret in the session. + $user->twofa_secret = $secret; + + // Save secret into the user file. + $user->save(); + + $json_response = ['status' => 'success', 'image' => $image, 'secret' => trim(preg_replace('|(\w{4})|', '\\1 ', $secret))]; + } else { + $json_response = ['status' => 'error', 'message' => 'user does not exist']; + } + } catch (\Exception $e) { + $json_response = ['status' => 'error', 'message' => $e->getMessage()]; + } + + // Return JSON + header('Content-Type: application/json'); + echo json_encode($json_response); + exit; + } + + /** + * Redirects an action + */ + public function redirect() + { + if ($this->redirect) { + $this->grav->redirectLangSafe($this->redirect, $this->redirectCode); + } + } + + /** + * Set redirect. + * + * @param $path + * @param int $code + */ + public function setRedirect($path, $code = 303) + { + $this->redirect = $path; + $this->redirectCode = $code; + } + + /** + * @return array Array containing [redirect, code]. + */ + public function getRedirect() + { + return [$this->redirect, $this->redirectCode]; + } + + /** + * Prepare and return POST data. + * + * @param array $post + * + * @return array + */ + protected function &getPost(array $post) + { + unset($post[$this->prefix]); + + // Decode JSON encoded fields and merge them to data. + if (isset($post['_json'])) { + $post = array_merge_recursive($post, $this->jsonDecode($post['_json'])); + unset($post['_json']); + } + + return $post; + } + + /** + * Recursively JSON decode data. + * + * @param array $data + * + * @return array + */ + protected function jsonDecode(array $data) + { + foreach ($data as &$value) { + if (\is_array($value)) { + $value = $this->jsonDecode($value); + } else { + $value = json_decode($value, true); + } + } + + return $data; + } + + /** + * Gets and sets the RememberMe class + * + * @param mixed $var A rememberMe instance to set + * + * @return RememberMe\RememberMe Returns the current rememberMe instance + * @deprecated 2.5.0 Use $grav['login']->rememberMe() instead + */ + public function rememberMe($var = null) + { + $this->rememberMe = $this->login->rememberMe($var); + + return $this->rememberMe; + } + + /** + * Check if user may use password reset functionality. + * + * @param UserInterface $user + * @param $field + * @param $count + * @param $interval + * @return bool + * @deprecated 2.5.0 Use $grav['login']->getRateLimiter($context) instead. See Grav\Plugin\Login\RateLimiter class. + */ + protected function isUserRateLimited(UserInterface $user, $field, $count, $interval) + { + return $this->login->isUserRateLimited($user, $field, $count, $interval); + } + + /** + * Reset the rate limit counter + * + * @param UserInterface $user + * @param $field + * @deprecated 2.5.0 Use $grav['login']->getRateLimiter($context) instead. See Grav\Plugin\Login\RateLimiter class. + */ + protected function resetRateLimit(UserInterface $user, $field) + { + $this->login->resetRateLimit($user, $field); + } + + + /** + * Authenticate user. + * + * @param array $form Form fields. + * + * @return bool + * @deprecated 2.6.2 Will be removed without replacement. + */ + protected function authenticate($form) + { + // Remove login nonce. + $form = array_diff_key($form, ['login-form-nonce' => true]); + + return $this->login->login($form, ['remember_me' => true])->authenticated; + } +} diff --git a/user/plugins/login/classes/Events/UserLoginEvent.php b/user/plugins/login/classes/Events/UserLoginEvent.php new file mode 100644 index 00000000..8b16112e --- /dev/null +++ b/user/plugins/login/classes/Events/UserLoginEvent.php @@ -0,0 +1,352 @@ + [], + 'options' => [], + 'authorize' => 'site.login', + 'status' => static::AUTHENTICATION_UNDEFINED, + 'session' => null, + 'user' => null, + 'message' => null, + 'redirect' => null, + 'redirect_code' => 303 + ]; + $items['credentials'] += ['username' => '', 'password' => '']; + + parent::__construct($items); + + if (!$this->offsetExists('session') && isset(Grav::instance()['session'])) { + $this->offsetSet('session', Grav::instance()['session']); + } + if (!$this->offsetExists('user')) { + /** @var UserCollectionInterface $users */ + $users = Grav::instance()['accounts']; + $this->offsetSet('user', $users->load($this['credentials']['username'])); + } + } + + public function isSuccess() + { + $status = $this->offsetGet('status'); + $failure = static::AUTHENTICATION_FAILURE | static::AUTHENTICATION_CANCELLED | static::AUTHORIZATION_EXPIRED + | static::AUTHORIZATION_DENIED; + + return ($status & static::AUTHENTICATION_SUCCESS) && !($status & $failure); + } + + public function isDelayed() + { + return $this->isSuccess() && ($this->offsetGet('status') & static::AUTHORIZATION_DELAYED); + } + + /** + * @return int + */ + public function getStatus() + { + return (int)$this->offsetGet('status'); + } + + /** + * @param int $status + * @return $this + */ + public function setStatus($status) + { + $this->offsetSet('status', $this->offsetGet('status') | (int)$status); + + return $this; + } + + /** + * @return array + */ + public function getCredentials() + { + return $this->offsetGet('credentials') + ['username' => '', 'password' => '']; + } + + /** + * @param string $name + * @return mixed + */ + public function getCredential($name) + { + return $this->items['credentials'][$name] ?? null; + } + + /** + * @param string $name + * @param mixed $value + * @return $this + */ + public function setCredential($name, $value) + { + $this->items['credentials'][$name] = $value; + + return $this; + } + + /** + * @return array + */ + public function getOptions() + { + return $this->offsetGet('options'); + } + + /** + * @param string $name + * @return mixed + */ + public function getOption($name) + { + return $this->items['options'][$name] ?? null; + } + + /** + * @param string $name + * @param mixed $value + * @return $this + */ + public function setOption($name, $value) + { + $this->items['options'][$name] = $value; + + return $this; + } + + /** + * @return Session|null + */ + public function getSession() + { + return $this->offsetGet('session'); + } + + /** + * @return UserInterface + */ + public function getUser() + { + return $this->offsetGet('user'); + } + + /** + * @param UserInterface $user + * @return $this + */ + public function setUser(UserInterface $user) + { + $this->offsetSet('user', $user); + + return $this; + } + + /** + * @return array + */ + public function getAuthorize() + { + return (array)$this->offsetGet('authorize'); + } + + /** + * @return string|null + */ + public function getMessage() + { + return !empty($this->items['message'][0]) ? (string)$this->items['message'][0] : null; + } + + /** + * @return string|null + */ + public function getMessageType() + { + return !empty($this->items['message'][1]) ? (string)$this->items['message'][1] : 'info'; + } + + /** + * @param string $message + * @param string|null $type + * @return $this + */ + public function setMessage($message, $type = null) + { + $this->items['message'] = $message ? [$message, $type] : null; + + return $this; + } + + /** + * @param string $message + * @param string|null $type + * @return $this + */ + public function defMessage($message, $type = null) + { + if ($message && !isset($this->items['message'])) { + $this->setMessage($message, $type); + } + + return $this; + } + + /** + * @return string|null + */ + public function getRedirect() + { + return $this->items['redirect'] ?? null; + } + + /** + * @return int + */ + public function getRedirectCode() + { + return $this->items['redirect_code'] ?? 303; + } + + /** + * @param string $path + * @param int $code + * @return $this + */ + public function setRedirect($path, $code = 303) + { + $this->items['redirect'] = $path ?: null; + $this->items['redirect_code'] = (int)$code; + + return $this; + } + + /** + * @param string $path + * @param int $code + * @return $this + */ + public function defRedirect($path, $code = 303) + { + if ($path && !isset($this->items['redirect'])) { + $this->setRedirect($path, $code); + } + + return $this; + } + + /** + * Magic setter method + * + * @param mixed $offset Asset name value + * @param mixed $value Asset value + */ + public function __set($offset, $value) + { + $this->offsetSet($offset, $value); + } + + /** + * Magic getter method + * + * @param mixed $offset Asset name value + * @return mixed Asset value + */ + public function __get($offset) + { + return $this->offsetGet($offset); + } + + /** + * Magic method to determine if the attribute is set + * + * @param mixed $offset Asset name value + * @return boolean True if the value is set + */ + public function __isset($offset) + { + return $this->offsetExists($offset); + } + + /** + * Magic method to unset the attribute + * + * @param mixed $offset The name value to unset + */ + public function __unset($offset) + { + $this->offsetUnset($offset); + } +} diff --git a/user/plugins/login/classes/Login.php b/user/plugins/login/classes/Login.php new file mode 100644 index 00000000..a87b202d --- /dev/null +++ b/user/plugins/login/classes/Login.php @@ -0,0 +1,650 @@ +grav = $grav; + $this->config = $this->grav['config']; + $this->language = $this->grav['language']; + $this->session = $this->grav['session']; + $this->uri = $this->grav['uri']; + } + + /** + * Login user. + * + * @param array $credentials Login credentials, eg: ['username' => '', 'password' => ''] + * @param array $options Login options, eg: ['remember_me' => true] + * @param array $extra Example: ['authorize' => 'site.login', 'user' => null], undefined variables get set. + * @return UserInterface|UserLoginEvent Returns event if $extra['return_event'] is true. + */ + public function login(array $credentials, array $options = [], array $extra = []) + { + $grav = Grav::instance(); + + $eventOptions = [ + 'credentials' => $credentials, + 'options' => $options + ] + $extra; + + // Attempt to authenticate the user. + $event = new UserLoginEvent($eventOptions); + $grav->fireEvent('onUserLoginAuthenticate', $event); + + if ($event->isSuccess()) { + + // Make sure that event didn't mess up with the user authorization. + $user = $event->getUser(); + $user->authenticated = true; + $user->authorized = false; + + // Allow plugins to prevent login after successful authentication. + $event = new UserLoginEvent($event->toArray()); + $grav->fireEvent('onUserLoginAuthorize', $event); + } + + if ($event->isSuccess()) { + // User has been logged in, let plugins know. + $event = new UserLoginEvent($event->toArray()); + $grav->fireEvent('onUserLogin', $event); + + // Make sure that event didn't mess up with the user authorization. + $user = $event->getUser(); + $user->authenticated = true; + $user->authorized = !$event->isDelayed(); + + } else { + // Allow plugins to log errors or do other tasks on failure. + $event = new UserLoginEvent($event->toArray()); + $grav->fireEvent('onUserLoginFailure', $event); + + // Make sure that event didn't mess up with the user authorization. + $user = $event->getUser(); + $user->authenticated = false; + $user->authorized = false; + } + + $user = $event->getUser(); + $user->def('language', 'en'); + + return !empty($event['return_event']) ? $event : $user; + } + + /** + * Logout user. + * + * @param array $options + * @param array|UserInterface $extra Array of: ['user' => $user, ...] or UserInterface object (deprecated). + * @return UserInterface|UserLoginEvent Returns event if $extra['return_event'] is true. + */ + public function logout(array $options = [], $extra = []) + { + $grav = Grav::instance(); + + if ($extra instanceof UserInterface) { + $extra = ['user' => $extra]; + } elseif (isset($extra['user'])) { + $extra['user'] = $grav['user']; + } + + $eventOptions = [ + 'options' => $options + ] + $extra; + + $event = new UserLoginEvent($eventOptions); + + // Logout the user. + $grav->fireEvent('onUserLogout', $event); + + $user = $event->getUser(); + $user->authenticated = false; + $user->authorized = false; + + return !empty($event['return_event']) ? $event : $user; + } + + /** + * Authenticate user. + * + * @param array $credentials Form fields. + * @param array $options + * + * @return bool + * @deprecated Uses the Controller::taskLogin() event + */ + public function authenticate($credentials, $options = ['remember_me' => true]) + { + $event = $this->login($credentials, $options, ['return_event' => true]); + $user = $event['user']; + + $redirect = $event->getRedirect(); + $message = $event->getMessage(); + $messageType = $event->getMessageType(); + + if ($user->authenticated && $user->authorized) { + if (!$message) { + $message = 'PLUGIN_LOGIN.LOGIN_SUCCESSFUL'; + $messageType = 'info'; + } + + if (!$redirect) { + $redirect = $this->uri->route(); + } + } + + if ($message) { + $this->grav['messages']->add($this->language->translate($message, [$user->language]), $messageType); + } + + if ($redirect) { + $this->grav->redirectLangSafe($redirect, $event->getRedirectCode()); + } + + return $user->authenticated && $user->authorized; + } + + /** + * Create a new user file + * + * @param array $data + * @param array $files + * + * @return UserInterface + */ + public function register(array $data, array $files = []) + { + if (!isset($data['groups'])) { + //Add new user ACL settings + $groups = (array) $this->config->get('plugins.login.user_registration.groups', []); + + if (\count($groups) > 0) { + $data['groups'] = $groups; + } + } + + if (!isset($data['access'])) { + $access = (array) $this->config->get('plugins.login.user_registration.access.site', []); + + if (\count($access) > 0) { + $data['access']['site'] = $access; + } + } + + $username = $this->validateField('username', $data['username']); + + /** @var UserCollectionInterface $users */ + $users = $this->grav['accounts']; + + // Create user object and save it + $user = $users->load($username); + if ($user->exists()) { + throw new \RuntimeException('User ' . $username . ' cannot be registered: user already exists!'); + } + + $user->update($data, $files); + if (isset($data['groups'])) { + $user->groups = $data['groups']; + } + if (isset($data['access'])) { + $user->access = $data['access']; + } + $user->save(); + + return $user; + } + + /** + * @param string $type + * @param mixed $value + * @param string $extra + * + * @return string + */ + public function validateField($type, $value, $extra = '') + { + switch ($type) { + case 'user': + case 'username': + /** @var Config $config */ + $config = Grav::instance()['config']; + $username_regex = '/' . $config->get('system.username_regex') . '/'; + + if (!\is_string($value) || !preg_match($username_regex, $value)) { + throw new \RuntimeException('Username does not pass the minimum requirements'); + } + + break; + + case 'password1': + /** @var Config $config */ + $config = Grav::instance()['config']; + $pwd_regex = '/' . $config->get('system.pwd_regex') . '/'; + + if (!\is_string($value) || !preg_match($pwd_regex, $value)) { + throw new \RuntimeException('Password does not pass them minimum requirements'); + } + + break; + + case 'password2': + if (!\is_string($value) || strcmp($value, $extra)) { + throw new \RuntimeException('Passwords did not match.'); + } + + break; + + case 'email': + if (!\is_string($value) || !filter_var($value, FILTER_VALIDATE_EMAIL)) { + throw new \RuntimeException('Not a valid email address'); + } + + break; + + case 'permissions': + if (!\is_string($value) || !\in_array($value, ['a', 's', 'b'], true)) { + throw new \RuntimeException('Permissions ' . $value . ' are invalid.'); + } + + break; + + case 'fullname': + if (!\is_string($value) || trim($value) === '') { + throw new \RuntimeException('Fullname cannot be empty'); + } + + break; + + case 'state': + if ($value !== 'enabled' && $value !== 'disabled') { + throw new \RuntimeException('State is not valid'); + } + + break; + + } + + return $value; + } + + /** + * Handle the email to notify the user account creation to the site admin. + * + * @param UserInterface $user + * + * @return bool True if the action was performed. + * @throws \RuntimeException + */ + public function sendNotificationEmail(UserInterface $user) + { + if (empty($user->email)) { + throw new \RuntimeException($this->language->translate('PLUGIN_LOGIN.USER_NEEDS_EMAIL_FIELD')); + } + + $site_name = $this->config->get('site.title', 'Website'); + + $subject = $this->language->translate(['PLUGIN_LOGIN.NOTIFICATION_EMAIL_SUBJECT', $site_name]); + $content = $this->language->translate([ + 'PLUGIN_LOGIN.NOTIFICATION_EMAIL_BODY', + $site_name, + $user->username, + $user->email, + $this->grav['base_url_absolute'], + ]); + $to = $this->config->get('plugins.email.to'); + + if (empty($to)) { + throw new \RuntimeException($this->language->translate('PLUGIN_LOGIN.EMAIL_NOT_CONFIGURED')); + } + + $sent = EmailUtils::sendEmail($subject, $content, $to); + + if ($sent < 1) { + throw new \RuntimeException($this->language->translate('PLUGIN_LOGIN.EMAIL_SENDING_FAILURE')); + } + + return true; + } + + /** + * Handle the email to welcome the new user + * + * @param UserInterface $user + * + * @return bool True if the action was performed. + * @throws \RuntimeException + */ + public function sendWelcomeEmail(UserInterface $user) + { + if (empty($user->email)) { + throw new \RuntimeException($this->language->translate('PLUGIN_LOGIN.USER_NEEDS_EMAIL_FIELD')); + } + + $site_name = $this->config->get('site.title', 'Website'); + $author = $this->grav['config']->get('site.author.name', ''); + $fullname = $user->fullname ?: $user->username; + + $subject = $this->language->translate(['PLUGIN_LOGIN.WELCOME_EMAIL_SUBJECT', $site_name]); + $content = $this->language->translate(['PLUGIN_LOGIN.WELCOME_EMAIL_BODY', + $fullname, + $this->grav['base_url_absolute'], + $site_name, + $author + ]); + $to = $user->email; + + $sent = EmailUtils::sendEmail($subject, $content, $to); + + if ($sent < 1) { + throw new \RuntimeException($this->language->translate('PLUGIN_LOGIN.EMAIL_SENDING_FAILURE')); + } + + return true; + } + + /** + * Handle the email to activate the user account. + * + * @param UserInterface $user + * + * @return bool True if the action was performed. + * @throws \RuntimeException + */ + public function sendActivationEmail(UserInterface $user) + { + if (empty($user->email)) { + throw new \RuntimeException($this->language->translate('PLUGIN_LOGIN.USER_NEEDS_EMAIL_FIELD')); + } + + $token = md5(uniqid(mt_rand(), true)); + $expire = time() + 604800; // next week + $user->activation_token = $token . '::' . $expire; + $user->save(); + + $param_sep = $this->config->get('system.param_sep', ':'); + $activation_link = $this->grav['base_url_absolute'] . $this->config->get('plugins.login.route_activate') . '/token' . $param_sep . $token . '/username' . $param_sep . $user->username; + + $site_name = $this->config->get('site.title', 'Website'); + $author = $this->grav['config']->get('site.author.name', ''); + $fullname = $user->fullname ?: $user->username; + + $subject = $this->language->translate(['PLUGIN_LOGIN.ACTIVATION_EMAIL_SUBJECT', $site_name]); + $content = $this->language->translate(['PLUGIN_LOGIN.ACTIVATION_EMAIL_BODY', + $fullname, + $activation_link, + $site_name, + $author + ]); + $to = $user->email; + $sent = EmailUtils::sendEmail($subject, $content, $to); + + if ($sent < 1) { + throw new \RuntimeException($this->language->translate('PLUGIN_LOGIN.EMAIL_SENDING_FAILURE')); + } + + return true; + } + + /** + * Gets and sets the RememberMe class + * + * @param mixed $var A rememberMe instance to set + * + * @return RememberMe Returns the current rememberMe instance + * @throws \InvalidArgumentException + */ + public function rememberMe($var = null) + { + if ($var !== null) { + $this->rememberMe = $var; + } + + if (!$this->rememberMe) { + /** @var Config $config */ + $config = $this->grav['config']; + $cookieName = $config->get('plugins.login.rememberme.name'); + $timeout = $config->get('plugins.login.rememberme.timeout'); + + // Setup storage for RememberMe cookies + $storage = new TokenStorage('user-data://rememberme', $timeout); + $this->rememberMe = new RememberMe($storage); + $this->rememberMe->setCookieName($cookieName); + $this->rememberMe->setExpireTime($timeout); + + // Hardening cookies with user-agent and random salt or + // fallback to use system based cache key + $server_agent = $_SERVER['HTTP_USER_AGENT'] ?? 'unknown'; + $data = $server_agent . $config->get('security.salt', $this->grav['cache']->getKey()); + $this->rememberMe->setSalt(hash('sha512', $data)); + + // Set cookie with correct base path of Grav install + $cookie = new Cookie; + $cookie->setPath($this->grav['base_url_relative'] ?: '/'); + $this->rememberMe->setCookie($cookie); + } + + return $this->rememberMe; + } + + /** + * Gets and sets the TwoFactorAuth object + * + * @param TwoFactorAuth $var + * @return TwoFactorAuth + * @throws \RobThree\Auth\TwoFactorAuthException + */ + public function twoFactorAuth($var = null) + { + if ($var !== null) { + $this->twoFa = $var; + } + + if (!$this->twoFa) { + $this->twoFa = new TwoFactorAuth; + } + + return $this->twoFa; + } + + /** + * @param string $context + * @param int $maxCount + * @param int $interval + * @return RateLimiter + */ + public function getRateLimiter($context, $maxCount = null, $interval = null) + { + if (!isset($this->rateLimiters[$context])) { + switch ($context) { + case 'login_attempts': + $maxCount = $this->grav['config']->get('plugins.login.max_login_count', 5); + $interval = $this->grav['config']->get('plugins.login.max_login_interval', 10); + break; + case 'pw_resets': + $maxCount = $this->grav['config']->get('plugins.login.max_pw_resets_count', 2); + $interval = $this->grav['config']->get('plugins.login.max_pw_resets_interval', 60); + break; + } + $this->rateLimiters[$context] = new RateLimiter($context, $maxCount, $interval); + } + + return $this->rateLimiters[$context]; + } + + /** + * @param UserInterface $user + * @param PageInterface $page + * @param Data|null $config + * @return bool + */ + public function isUserAuthorizedForPage(UserInterface $user, PageInterface $page, $config = null) + { + $header = $page->header(); + $rules = isset($header->access) ? (array)$header->access : []; + + if (!$rules && $config !== null && $config->get('parent_acl')) { + // If page has no ACL rules, use its parent's rules + $parent = $page->parent(); + while (!$rules and $parent) { + $header = $parent->header(); + $rules = isset($header->access) ? (array)$header->access : []; + $parent = $parent->parent(); + } + } + + // Continue to the page if it has no ACL rules. + if (!$rules) { + return true; + } + + if (!$user->authorized) { + return false; + } + + // Continue to the page if user is authorized to access the page. + foreach ($rules as $rule => $value) { + if (\is_array($value)) { + foreach ($value as $nested_rule => $nested_value) { + if ($user->authorize($rule . '.' . $nested_rule) === Utils::isPositive($nested_value)) { + return true; + } + } + } elseif ($user->authorize($rule) === Utils::isPositive($value)) { + return true; + } + } + + return false; + } + + /** + * Check if user may use password reset functionality. + * + * @param UserInterface $user + * @param string $field + * @param int $count + * @param int $interval + * @return bool + * @deprecated 2.5.0 Use $grav['login']->getRateLimiter($context) instead. See Grav\Plugin\Login\RateLimiter class. + */ + public function isUserRateLimited(UserInterface $user, $field, $count, $interval) + { + if ($count > 0) { + if (!isset($user->{$field})) { + $user->{$field} = []; + } + //remove older than $interval x minute attempts + $actual_resets = []; + foreach ((array)$user->{$field} as $reset) { + if ($reset > (time() - $interval * 60)) { + $actual_resets[] = $reset; + } + } + + if (\count($actual_resets) >= $count) { + return true; + } + $actual_resets[] = time(); // current reset + $user->{$field} = $actual_resets; + + } + return false; + } + + /** + * Reset the rate limit counter. + * + * @param UserInterface $user + * @param string $field + * @deprecated 2.5.0 Use $grav['login']->getRateLimiter($context) instead. See Grav\Plugin\Login\RateLimiter class. + */ + public function resetRateLimit(UserInterface $user, $field) + { + $user->{$field} = []; + } + + /** + * Get Current logged in user + * + * @return UserInterface + * @deprecated 2.5.0 Use $grav['user'] instead. + */ + public function getUser() + { + /** @var UserInterface $user */ + return $this->grav['user']; + } + + public function addProviderLoginTemplate($template) + { + $this->provider_login_templates[] = $template; + } + + public function getProviderLoginTemplates() + { + return $this->provider_login_templates; + } + +} diff --git a/user/plugins/login/classes/LoginCache.php b/user/plugins/login/classes/LoginCache.php new file mode 100644 index 00000000..5f8f058b --- /dev/null +++ b/user/plugins/login/classes/LoginCache.php @@ -0,0 +1,105 @@ +lifetime = (int)$defaultLifetime; + $this->driver = new FilesystemCache(Grav::instance()['locator']->findResource('cache://login/' . $namespace, true, true)); + } + + /** + * Fetches a value from the cache. + * + * @param string $key The unique key of this item in the cache. + * @param mixed $default Default value to return if the key does not exist. + * + * @return mixed The value of the item from the cache, or $default in case of cache miss. + */ + public function get($key, $default = null) + { + $value = $this->driver->fetch($key); + + // Doctrine cache does not differentiate between no result and cached 'false'. Make sure that we do. + return $value !== false || $this->driver->contains($key) ? $value : $default; + } + + /** + * Persists data in the cache, uniquely referenced by a key with an optional expiration TTL time. + * + * @param string $key The key of the item to store. + * @param mixed $value The value of the item to store, must be serializable. + * @param null|int $ttl Optional. The TTL value of this item. + * + * @return bool True on success and false on failure. + */ + public function set($key, $value, $ttl = null) + { + $ttl = $ttl !== null ? (int)$ttl : $this->lifetime; + + return $this->driver->save($key, $value, $ttl); + } + + /** + * Determines whether an item is present in the cache. + * + * @param string $key The cache item key. + * + * @return bool + */ + public function has($key) + { + return $this->driver->contains($key); + } + + /** + * Delete an item from the cache by its unique key. + * + * @param string $key The unique cache key of the item to delete. + * + * @return bool True if the item was successfully removed. False if there was an error. + */ + public function delete($key) + { + return $this->driver->delete($key); + } + + /** + * Wipes clean the entire cache's keys. + * + * @return bool True on success and false on failure. + */ + public function clear() + { + return $this->driver->flushAll(); + } +} diff --git a/user/plugins/login/classes/RateLimiter.php b/user/plugins/login/classes/RateLimiter.php new file mode 100644 index 00000000..9be5cce8 --- /dev/null +++ b/user/plugins/login/classes/RateLimiter.php @@ -0,0 +1,110 @@ +cache = new LoginCache($context, (int)$interval * 60); + $this->maxCount = (int) $maxCount; + $this->interval = (int) $interval; + } + + /** + * @return int + */ + public function getInterval() + { + return $this->interval; + } + + /** + * Check if user has hit rate limiter. Remember to use registerRateLimitedAction() before doing the check. + * + * @param string $key + * @param string $type + * @return bool + */ + public function isRateLimited($key, $type = 'username') + { + if (!$key || !$this->interval) { + return false; + } + + return $this->maxCount && \count($this->getAttempts($key, $type)) > $this->maxCount; + } + + /** + * + * + * @param string $key + * @param string $type + * @return array + */ + public function getAttempts($key, $type = 'username') + { + return (array) $this->cache->get($type . $key, []); + } + + /** + * Register rate limited action. + * + * @param string $key + * @param string $type + * @return $this + */ + public function registerRateLimitedAction($key, $type = 'username') + { + if ($key && $this->interval) { + $tries = (array)$this->cache->get($type . $key, []); + $tries[] = time(); + + $this->cache->set($type . $key, $tries); + } + + return $this; + } + + /** + * Reset the user rate limit counter. + * + * @param string $key + * @param string $type + * @return $this + */ + public function resetRateLimit($key, $type = 'username') + { + if ($key) { + $this->cache->delete($type . $key); + } + + return $this; + } +} diff --git a/user/plugins/login/classes/RememberMe/RememberMe.php b/user/plugins/login/classes/RememberMe/RememberMe.php new file mode 100644 index 00000000..0857905f --- /dev/null +++ b/user/plugins/login/classes/RememberMe/RememberMe.php @@ -0,0 +1,43 @@ + + */ +class RememberMe extends Authenticator +{ + /** + * Gets storage interface + * + * @return StorageInterface + */ + public function getStorage() + { + return $this->storage; + } + + /** + * Set storage interface + * + * @param StorageInterface $storage Storage interface + */ + public function setStorage($storage) + { + $this->storage = $storage; + } +} diff --git a/user/plugins/login/classes/RememberMe/TokenStorage.php b/user/plugins/login/classes/RememberMe/TokenStorage.php new file mode 100644 index 00000000..92315583 --- /dev/null +++ b/user/plugins/login/classes/RememberMe/TokenStorage.php @@ -0,0 +1,172 @@ +path = Grav::instance()['locator']->findResource($path, true, true); + $this->timeout = $timeout; + } + + /** + * Return Tri-state value constant + * + * @param mixed $credential Unique credential (user id, email address, user name) + * @param string $token One-Time Token + * @param string $persistentToken Persistent Token + * + * @return int + */ + public function findTriplet($credential, $token, $persistentToken) + { + // Hash the tokens, because they can contain a salt and can be accessed in the file system + $persistentToken = sha1($persistentToken); + $token = sha1($token); + + $file = $this->getFile($credential); + $tokens = (array)$file->content(); + + if (!isset($tokens[$persistentToken]) || $tokens[$persistentToken] < time() + $this->timeout) { + return self::TRIPLET_NOT_FOUND; + } + + $stored = key($tokens[$persistentToken]); + if ($stored !== $token) { + return self::TRIPLET_INVALID; + } + + return self::TRIPLET_FOUND; + } + + /** + * Store the new token for the credential and the persistent token. Create a new storage entry, if the combination + * of credential and persistent token does not exist. + * + * @param mixed $credential + * @param string $token + * @param string $persistentToken + * @param int $expire Timestamp when this triplet will expire (0 = no expiry) + */ + public function storeTriplet($credential, $token, $persistentToken, $expire = null) + { + // Hash the tokens, because they can contain a salt and can be accessed in the file system + $persistentToken = sha1($persistentToken); + $token = sha1($token); + + $file = $this->getFile($credential); + $tokens = (array)$file->content(); + + // Update token + $tokens[$persistentToken] = [$token => time()]; + + $file->save($tokens); + } + + /** + * Replace current token after successful authentication + * + * @param mixed $credential + * @param string $token + * @param string $persistentToken + * @param int $expire + */ + public function replaceTriplet($credential, $token, $persistentToken, $expire = null) + { + $this->storeTriplet($credential, $token, $persistentToken, $expire); + } + + /** + * Remove one triplet of the user from the store + * + * @param mixed $credential + * @param string $persistentToken + */ + public function cleanTriplet($credential, $persistentToken) + { + // Hash the tokens, because they can contain a salt and can be accessed in the file system + $persistentToken = sha1($persistentToken); + + $file = $this->getFile($credential); + if (!$file->exists()) { + return; + } + + $tokens = (array)$file->content(); + + if (isset($tokens[$persistentToken])) { + // Delete token from storage + unset($tokens[$persistentToken]); + + if ($tokens) { + $file->save($tokens); + } else { + $file->delete(); + } + } + } + + /** + * Remove all triplets of a user, effectively logging him out on all + * machines + * + * @param mixed $credential + */ + public function cleanAllTriplets($credential) + { + $file = $this->getFile($credential); + if ($file->exists()) { + $file->delete(); + } + } + + /** + * Helper method to clear RememberMe cache + */ + public function clearCache() + { + if (is_dir($this->path)) { + Folder::delete($this->path, false); + } + } + + /** + * @param string $credential + * @return CompiledYamlFile + */ + protected function getFile($credential) + { + return CompiledYamlFile::instance($this->path . '/' . sha1($credential) . '.yaml'); + } +} diff --git a/user/plugins/login/classes/TwoFactorAuth/BaconQrProvider.php b/user/plugins/login/classes/TwoFactorAuth/BaconQrProvider.php new file mode 100644 index 00000000..9d458c63 --- /dev/null +++ b/user/plugins/login/classes/TwoFactorAuth/BaconQrProvider.php @@ -0,0 +1,32 @@ +setHeight($size); + $renderer->setWidth($size); + $writer = new BaconWriter($renderer); + + return $writer->writeString($qrtext); + } +} diff --git a/user/plugins/login/classes/TwoFactorAuth/TwoFactorAuth.php b/user/plugins/login/classes/TwoFactorAuth/TwoFactorAuth.php new file mode 100644 index 00000000..e493db02 --- /dev/null +++ b/user/plugins/login/classes/TwoFactorAuth/TwoFactorAuth.php @@ -0,0 +1,76 @@ +twoFa = new Auth('Grav', 6, 30, 'sha1', new BaconQrProvider); + } + + /** + * @return Auth + */ + public function get2FA() + { + return $this->twoFa; + } + + /** + * @param int $bits + * @return string + * @throws TwoFactorAuthException + */ + public function createSecret($bits = 160) + { + return $this->twoFa->createSecret($bits); + } + + /** + * @param string $secret + * @param string $code + * @return bool + */ + public function verifyCode($secret, $code) + { + $secret = str_replace(' ', '', $secret); + + return $this->twoFa->verifyCode($secret, $code); + } + + /** + * @param string $username + * @param string $secret + * @return string + * @throws TwoFactorAuthException + */ + public function getQrImageData($username, $secret) + { + $label = $username . ':' . Grav::instance()['config']->get('site.title'); + $secret = str_replace(' ', '', $secret); + + return $this->twoFa->getQRCodeImageAsDataUri($label, $secret); + } +} diff --git a/user/plugins/login/cli/ChangePasswordCommand.php b/user/plugins/login/cli/ChangePasswordCommand.php new file mode 100644 index 00000000..1285a884 --- /dev/null +++ b/user/plugins/login/cli/ChangePasswordCommand.php @@ -0,0 +1,177 @@ +setName('change-password') + ->setAliases(['edit-password', 'newpass', 'changepass', 'passwd']) + ->addOption( + 'user', + 'u', + InputOption::VALUE_REQUIRED, + 'The username' + ) + ->addOption( + 'password', + 'p', + InputOption::VALUE_REQUIRED, + "The password. Note that this option is not recommended because the password will be visible by users listing the processes. You should also make sure the password respects Grav's password policy." + ) + ->setDescription('Changes a User Password') + ->setHelp('The change-password changes the password of the specified user. (User must exist)') + ; + } + + /** + * @return int|null|void + */ + protected function serve() + { + include __DIR__ . '/../vendor/autoload.php'; + + $grav = Grav::instance(); + if (!isset($grav['login'])) { + $grav['login'] = new Login($grav); + } + $this->login = $grav['login']; + + $this->options = [ + 'user' => $this->input->getOption('user'), + 'password1' => $this->input->getOption('password') + ]; + + $this->validateOptions(); + + $helper = $this->getHelper('question'); + $data = []; + + $this->output->writeln('Changing User Password'); + $this->output->writeln(''); + + /** @var UserCollectionInterface $users */ + $users = $grav['accounts']; + + if (!$this->options['user']) { + // Get username and validate + $question = new Question('Enter a username: '); + $question->setValidator(function ($value) use ($users) { + $this->validate('user', $value); + + if (!$users->find($value, ['username'])->exists()) { + throw new \RuntimeException('Username "' . $value . '" does not exist, please pick another username'); + }; + + return $value; + }); + + $username = $helper->ask($this->input, $this->output, $question); + } else { + $username = $this->options['user']; + } + + + if (!$this->options['password1']) { + // Get password and validate + $password = $this->askForPassword($helper, 'Enter a new password: ', function ($password1) use ($helper) { + $this->validate('password1', $password1); + + // Since input is hidden when prompting for passwords, the user is asked to repeat the password + return $this->askForPassword($helper, 'Repeat the password: ', function ($password2) use ($password1) { + return $this->validate('password2', $password2, $password1); + }); + }); + + $data['password'] = $password; + } else { + $data['password'] = $this->options['password1']; + } + + $user = $users->load($username); + if (!$user->exists()) { + $this->output->writeln('Failure User ' . $username . ' does not exist!'); + exit(); + } + //Set the password field to new password + $user->set('password', $data['password']); + $user->save(); + + $this->invalidateCache(); + + $this->output->writeln(''); + $this->output->writeln('Success! User ' . $username . '\'s password changed.'); + } + + /** + * + */ + protected function validateOptions() + { + foreach (array_filter($this->options) as $type => $value) { + $this->validate($type, $value); + } + } + + /** + * @param string $type + * @param mixed $value + * @param string $extra + * + * @return string + */ + protected function validate($type, $value, $extra = '') + { + return $this->login->validateField($type, $value, $extra); + } + + /** + * Get password and validate. + * + * @param Helper $helper + * @param string $question + * @param callable $validator + * + * @return string + */ + protected function askForPassword(Helper $helper, $question, callable $validator) + { + $question = new Question($question); + $question->setValidator($validator); + $question->setHidden(true); + $question->setHiddenFallback(true); + + return $helper->ask($this->input, $this->output, $question); + } +} diff --git a/user/plugins/login/cli/ChangeUserStateCommand.php b/user/plugins/login/cli/ChangeUserStateCommand.php new file mode 100644 index 00000000..89e2f054 --- /dev/null +++ b/user/plugins/login/cli/ChangeUserStateCommand.php @@ -0,0 +1,157 @@ +setName('toggle-user') + ->setAliases(['disableuser', 'enableuser', 'toggleuser', 'change-user-state']) + ->addOption( + 'user', + 'u', + InputOption::VALUE_REQUIRED, + 'The username' + ) + ->addOption( + 'state', + 's', + InputOption::VALUE_REQUIRED, + 'The state of the account. Can be either `enabled` or `disabled`. [default: "enabled"]' + ) + ->setDescription('Changes whether user can login or not') + ->setHelp('The toggle-user sets a user\'s login status to enabled or disabled.') + ; + } + + /** + * @return int|null|void + */ + protected function serve() + { + include __DIR__ . '/../vendor/autoload.php'; + + $grav = Grav::instance(); + if (!isset($grav['login'])) { + $grav['login'] = new Login($grav); + } + $this->login = $grav['login']; + + $this->options = [ + 'user' => $this->input->getOption('user'), + 'state' => $this->input->getOption('state') + ]; + + $this->validateOptions(); + + $helper = $this->getHelper('question'); + $data = []; + + $this->output->writeln('Setting User State'); + $this->output->writeln(''); + + /** @var UserCollectionInterface $users */ + $users = $grav['accounts']; + + if (!$this->options['user']) { + // Get username and validate + $question = new Question('Enter a username: '); + $question->setValidator(function ($value) use ($users) { + $this->validate('user', $value); + + if (!$users->find($value, ['username'])->exists()) { + throw new \RuntimeException('Username "' . $value . '" does not exist, please pick another username'); + }; + + return $value; + }); + + $username = $helper->ask($this->input, $this->output, $question); + } else { + $username = $this->options['user']; + } + + + if (!$this->options['state'] && !\count(array_filter($this->options))) { + // Choose State + $question = new ChoiceQuestion( + 'Please choose the state for the account:', + array('enabled' => 'Enabled', 'disabled' => 'Disabled'), + 'enabled' + ); + + $question->setErrorMessage('State %s is invalid.'); + $data['state'] = $helper->ask($this->input, $this->output, $question); + } else { + $data['state'] = $this->options['state'] ?: 'enabled'; + } + + $user = $users->load($username); + if (!$user->exists()) { + $this->output->writeln('Failure! User ' . $username . ' does not exist!'); + exit(); + } + + //Set the state field to new state + $user->set('state', $data['state']); + $user->save(); + + $this->invalidateCache(); + + $this->output->writeln(''); + $this->output->writeln('Success! User ' . $username . ' state set to .' . $data['state']); + } + + /** + * + */ + protected function validateOptions() + { + foreach (array_filter($this->options) as $type => $value) { + $this->validate($type, $value); + } + } + + /** + * @param string $type + * @param mixed $value + * @param string $extra + * + * @return string + */ + protected function validate($type, $value) + { + return $this->login->validateField($type, $value); + } +} diff --git a/user/plugins/login/cli/LookupUserCommand.php b/user/plugins/login/cli/LookupUserCommand.php new file mode 100644 index 00000000..19ef994a --- /dev/null +++ b/user/plugins/login/cli/LookupUserCommand.php @@ -0,0 +1,94 @@ +setName('lookup-user') + ->setAliases(['lookup']) + ->addArgument( + 'key', + InputArgument::REQUIRED, + 'The username, email, id, or key to lookup' + ) + ->setDescription('Finds user info based on some data') + ->setHelp('The lookup-user finds a user based on some data query.') + ; + } + + /** + * @return int|null|void + */ + protected function serve() + { + include __DIR__ . '/../vendor/autoload.php'; + + $io = new SymfonyStyle($this->input, $this->output); + + $grav = Grav::instance(); + $grav->setup(); + + $io->title('Looking up user'); + + // Initialize Plugins + $grav['plugins']->init(); + $grav->fireEvent('onCliInitialize'); + + $key = $this->input->getArgument('key'); + + /** @var UserCollectionInterface $users */ + $users = $grav['accounts']; + + /** @var UserInterface $user */ + $user = $users->find($key, ['username', 'email', 'fullname', 'storage_key', 'flex_key']); + + if ($user->exists()) { + /** @var $io SymfonyStyle */ + $io->text('Username: '. $user->username . ''); + $io->text('Name: ' . $user->fullname . ''); + if ($user instanceof FlexObject) { + $io->text('Flex Key: ' . $user->getFlexKey() . ''); + } + $io->text('Email: ' . $user->email . ''); + + $io->newLine(); + exit; + } + + + $io->error('Sorry, the user with query: "' . $key . '", was not found'); + } +} diff --git a/user/plugins/login/cli/NewUserCommand.php b/user/plugins/login/cli/NewUserCommand.php new file mode 100644 index 00000000..13b7a955 --- /dev/null +++ b/user/plugins/login/cli/NewUserCommand.php @@ -0,0 +1,302 @@ +setName('new-user') + ->setAliases(['add-user', 'newuser']) + ->addOption( + 'user', + 'u', + InputOption::VALUE_REQUIRED, + 'The username' + ) + ->addOption( + 'password', + 'p', + InputOption::VALUE_REQUIRED, + "The password. Note that this option is not recommended because the password will be visible by users listing the processes. You should also make sure the password respects Grav's password policy." + ) + ->addOption( + 'email', + 'e', + InputOption::VALUE_REQUIRED, + 'The user email' + ) + ->addOption( + 'permissions', + 'P', + InputOption::VALUE_REQUIRED, + 'The user permissions. It can be either `a` for Admin access only, `s` for Site access only and `b` for both Admin and Site access.' + ) + ->addOption( + 'fullname', + 'N', + InputOption::VALUE_REQUIRED, + 'The user full name.' + ) + ->addOption( + 'title', + 't', + InputOption::VALUE_REQUIRED, + 'The title of the user. Usually used as a subtext. Example: Admin, Collaborator, Developer' + ) + ->addOption( + 'state', + 's', + InputOption::VALUE_REQUIRED, + 'The state of the account. Can be either `enabled` or `disabled`. [default: "enabled"]' + ) + ->setDescription('Creates a new user') + ->setHelp('The new-user creates a new user file in user/accounts/ folder') + ; + } + + /** + * @return int|null|void + */ + protected function serve() + { + include __DIR__ . '/../vendor/autoload.php'; + + $grav = Grav::instance(); + if (!isset($grav['login'])) { + $grav['login'] = new Login($grav); + } + $this->login = $grav['login']; + + $this->options = [ + 'user' => $this->input->getOption('user'), + 'password1' => $this->input->getOption('password'), + 'email' => $this->input->getOption('email'), + 'permissions' => $this->input->getOption('permissions'), + 'fullname' => $this->input->getOption('fullname'), + 'title' => $this->input->getOption('title'), + 'state' => $this->input->getOption('state') + ]; + + $this->validateOptions(); + + $helper = $this->getHelper('question'); + $data = []; + + $this->output->writeln('Creating new user'); + $this->output->writeln(''); + + /** @var UserCollectionInterface $users */ + $users = $grav['accounts']; + + if (!$this->options['user']) { + // Get username and validate + $question = new Question('Enter a username: ', 'admin'); + $question->setValidator(function ($value) use ($users) { + $this->validate('user', $value); + + if ($users->find($value, ['username'])->exists()) { + throw new \RuntimeException('Username "' . $value . '" already exists, please pick another username'); + }; + + return $value; + }); + + $username = $helper->ask($this->input, $this->output, $question); + } else { + $username = $this->options['user']; + } + + $user = $users->load($username); + if ($user->exists()) { + $this->output->writeln('Failure! User ' . $data['username'] . ' already exists!'); + exit(); + } + + if (!$this->options['password1']) { + // Get password and validate + $password = $this->askForPassword($helper, 'Enter a password: ', function ($password1) use ($helper) { + $this->validate('password1', $password1); + + // Since input is hidden when prompting for passwords, the user is asked to repeat the password + return $this->askForPassword($helper, 'Repeat the password: ', function ($password2) use ($password1) { + return $this->validate('password2', $password2, $password1); + }); + }); + + $user->set('password', $password); + } else { + $user->set('password', $this->options['password1']); + } + + if (!$this->options['email']) { + // Get email and validate + $question = new Question('Enter an email: '); + $question->setValidator(function ($value) { + return $this->validate('email', $value); + }); + + $user->set('email', $helper->ask($this->input, $this->output, $question)); + } else { + $user->set('email', $this->options['email']); + } + + if (!$this->options['permissions']) { + // Choose permissions + $question = new ChoiceQuestion( + 'Please choose a set of permissions:', + array('a' => 'Admin Access', 's' => 'Site Access', 'b' => 'Admin and Site Access'), + 'a' + ); + + $question->setErrorMessage('Permissions %s is invalid.'); + $permissions_choice = $helper->ask($this->input, $this->output, $question); + } else { + $permissions_choice = $this->options['permissions']; + } + + switch ($permissions_choice) { + case 'a': + $access = [ + 'admin' => [ + 'login' => true, + 'super' => true + ] + ]; + break; + case 's': + $access = [ + 'site' => [ + 'login' => true + ] + ]; + break; + case 'b': + $access = [ + 'admin' => [ + 'login' => true, + 'super' => true + ], + 'site' => [ + 'login' => true + ] + ]; + } + + if (isset($access)) { + $user->set('access', $access); + } + + if (!$this->options['fullname']) { + // Get fullname + $question = new Question('Enter a fullname: '); + $question->setValidator(function ($value) { + return $this->validate('fullname', $value); + }); + + $user->set('fullname', $helper->ask($this->input, $this->output, $question)); + } else { + $user->set('fullname', $this->options['fullname']); + } + + + if (!$this->options['title'] && !count(array_filter($this->options))) { + // Get title + $question = new Question('Enter a title: '); + $user->set('title', $helper->ask($this->input, $this->output, $question)); + } else { + $user->set('title', $this->options['title']); + } + + if (!$this->options['state'] && !count(array_filter($this->options))) { + // Choose State + $question = new ChoiceQuestion( + 'Please choose the state for the account:', + array('enabled' => 'Enabled', 'disabled' => 'Disabled'), + 'enabled' + ); + + $question->setErrorMessage('State %s is invalid.'); + $user->set('state', $helper->ask($this->input, $this->output, $question)); + } else { + $user->set('state', $this->options['state'] ?: 'enabled'); + } + + $user->validate(); + $user->save(); + + $this->invalidateCache(); + + $this->output->writeln(''); + $this->output->writeln('Success! User ' . $user->username . ' created.'); + } + + /** + * + */ + protected function validateOptions() + { + foreach (array_filter($this->options) as $type => $value) { + $this->validate($type, $value); + } + } + + /** + * @param string $type + * @param mixed $value + * @param string $extra + * + * @return string + */ + protected function validate($type, $value, $extra = '') + { + return $this->login->validateField($type, $value, $extra); + } + + /** + * Get password and validate. + * + * @param Helper $helper + * @param string $question + * @param callable $validator + * + * @return string + */ + protected function askForPassword(Helper $helper, $question, callable $validator) + { + $question = new Question($question); + $question->setValidator($validator); + $question->setHidden(true); + $question->setHiddenFallback(true); + return $helper->ask($this->input, $this->output, $question); + } +} diff --git a/user/plugins/login/composer.json b/user/plugins/login/composer.json new file mode 100644 index 00000000..c670f50d --- /dev/null +++ b/user/plugins/login/composer.json @@ -0,0 +1,45 @@ +{ + "name": "grav-plugin-login", + "description": "Enables user authentication and login screen.", + "keywords": ["login", "authentication", "admin", "security"], + "homepage": "https://github.com/getgrav/grav-plugin-login", + "license": "MIT", + "authors": [ + { + "name": "Team Grav", + "email": "devs@getgrav.org", + "homepage": "http://getgrav.org", + "role": "Developer" + }, + { + "name": "Sommerregen", + "email": "sommerregen@benjamin-regler.de", + "homepage": "http://benjamin-regler.de", + "role": "Developer" + } + ], + "support": { + "email": "support@example.org", + "issues": "https://github.com/getgrav/grav-plugin-login/issues", + "irc": "https://gitter.im/getgrav/grav", + "forum": "http://getgrav.org/forum", + "docs": "https://github.com/getgrav/grav-plugin-login/blob/master/README.md" + }, + "require": { + "php": ">=7.1.3", + "ext-json": "*", + "birke/rememberme": "1.*", + "robthree/twofactorauth": "^1.6", + "bacon/bacon-qr-code": "^1.0" + }, + "autoload": { + "psr-4": { + "Grav\\Plugin\\Login\\": "classes/" + } + }, + "config": { + "platform": { + "php": "7.1.3" + } + } +} diff --git a/user/plugins/login/composer.lock b/user/plugins/login/composer.lock new file mode 100644 index 00000000..453b273c --- /dev/null +++ b/user/plugins/login/composer.lock @@ -0,0 +1,210 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "bb17626cbf2be970add218a7cab0535f", + "packages": [ + { + "name": "bacon/bacon-qr-code", + "version": "1.0.3", + "source": { + "type": "git", + "url": "https://github.com/Bacon/BaconQrCode.git", + "reference": "5a91b62b9d37cee635bbf8d553f4546057250bee" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Bacon/BaconQrCode/zipball/5a91b62b9d37cee635bbf8d553f4546057250bee", + "reference": "5a91b62b9d37cee635bbf8d553f4546057250bee", + "shasum": "" + }, + "require": { + "ext-iconv": "*", + "php": "^5.4|^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8" + }, + "suggest": { + "ext-gd": "to generate QR code images" + }, + "type": "library", + "autoload": { + "psr-0": { + "BaconQrCode": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-2-Clause" + ], + "authors": [ + { + "name": "Ben Scholzen 'DASPRiD'", + "email": "mail@dasprids.de", + "homepage": "http://www.dasprids.de", + "role": "Developer" + } + ], + "description": "BaconQrCode is a QR code generator for PHP.", + "homepage": "https://github.com/Bacon/BaconQrCode", + "time": "2017-10-17T09:59:25+00:00" + }, + { + "name": "birke/rememberme", + "version": "1.0.5", + "source": { + "type": "git", + "url": "https://github.com/gbirke/rememberme.git", + "reference": "810473852eb4823098e47e23376a19b77ba0c165" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/gbirke/rememberme/zipball/810473852eb4823098e47e23376a19b77ba0c165", + "reference": "810473852eb4823098e47e23376a19b77ba0c165", + "shasum": "" + }, + "require": { + "paragonie/random_compat": "^1.1.4" + }, + "require-dev": { + "phpunit/phpunit": "4.*" + }, + "type": "library", + "autoload": { + "psr-4": { + "Birke\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gabriel Birke", + "email": "gb@birke-software.de" + } + ], + "description": "Secure \"Remember Me\" functionality", + "homepage": "https://github.com/gbirke/rememberme", + "keywords": [ + "cookie", + "remember", + "security" + ], + "time": "2017-02-12T12:43:00+00:00" + }, + { + "name": "paragonie/random_compat", + "version": "v1.4.3", + "source": { + "type": "git", + "url": "https://github.com/paragonie/random_compat.git", + "reference": "9b3899e3c3ddde89016f576edb8c489708ad64cd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/paragonie/random_compat/zipball/9b3899e3c3ddde89016f576edb8c489708ad64cd", + "reference": "9b3899e3c3ddde89016f576edb8c489708ad64cd", + "shasum": "" + }, + "require": { + "php": ">=5.2.0" + }, + "require-dev": { + "phpunit/phpunit": "4.*|5.*" + }, + "suggest": { + "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes." + }, + "type": "library", + "autoload": { + "files": [ + "lib/random.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Paragon Initiative Enterprises", + "email": "security@paragonie.com", + "homepage": "https://paragonie.com" + } + ], + "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7", + "keywords": [ + "csprng", + "pseudorandom", + "random" + ], + "time": "2018-04-04T21:48:54+00:00" + }, + { + "name": "robthree/twofactorauth", + "version": "1.6.1", + "source": { + "type": "git", + "url": "https://github.com/RobThree/TwoFactorAuth.git", + "reference": "a77e7d822343bb88112baef808839cfae7bc5abb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/RobThree/TwoFactorAuth/zipball/a77e7d822343bb88112baef808839cfae7bc5abb", + "reference": "a77e7d822343bb88112baef808839cfae7bc5abb", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": "@stable" + }, + "type": "library", + "autoload": { + "psr-4": { + "RobThree\\Auth\\": "lib" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Rob Janssen", + "homepage": "http://robiii.me", + "role": "Developer" + } + ], + "description": "Two Factor Authentication", + "homepage": "https://github.com/RobThree/TwoFactorAuth", + "keywords": [ + "Authentication", + "MFA", + "Multi Factor Authentication", + "Two Factor Authentication", + "authenticator", + "authy", + "php", + "tfa" + ], + "time": "2017-11-06T17:55:56+00:00" + } + ], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "php": ">=5.5.9" + }, + "platform-dev": [] +} diff --git a/user/plugins/login/css/login.css b/user/plugins/login/css/login.css new file mode 100644 index 00000000..3b470c40 --- /dev/null +++ b/user/plugins/login/css/login.css @@ -0,0 +1,86 @@ +#grav-login { + max-width: 30rem; + margin: 5rem auto; + background: #fcfcfc; + border: 4px solid #eee; + border-radius: 4px; + padding: 1rem 3rem 3rem 3rem; + text-align: center; +} + +#grav-login .form-actions { + text-align: right; +} + +#grav-logout { + position: absolute; + bottom: 5px; + right: 5px; +} + +.alert.info { + color: #27ae60; +} + +.alert.error { + color: #e74c3c; +} + +#grav-login p { + font-size: small; + margin: 1rem 0; + padding: 0; + text-align: center; +} +#grav-login .form-actions p { + margin-bottom: 0; +} + +#grav-login .button { + vertical-align: middle; +} + +#grav-login .delimiter { + display: block; + font-size: 1.6rem; + letter-spacing: 1px; + line-height: 1.6rem; + position: relative; + text-transform: uppercase; + margin: 1rem 0; +} + +#grav-login .delimiter:after, +#grav-login .delimiter:before { + background-color: #777777; + content: ""; + height: 1px; + position: absolute; + top: 0.8rem; + width: 40%; +} +#grav-login .delimiter:before { + background-image: -moz-linear-gradient(right center , #777777, #ffffff); + left: 0; +} +#grav-login .delimiter:after { + background-image: -moz-linear-gradient(left center , #777777, #ffffff); + right: 0; +} + +#grav-login .rememberme { + display: inline-block; + float: left; + padding: 7px 0; + vertical-align: middle; +} + +#grav-login .rememberme label { + font-weight: inherit; + display: inline; +} + +.login-status { + white-space: nowrap; + vertical-align: middle; +} \ No newline at end of file diff --git a/user/plugins/login/js/2fa.js b/user/plugins/login/js/2fa.js new file mode 100644 index 00000000..07843f80 --- /dev/null +++ b/user/plugins/login/js/2fa.js @@ -0,0 +1,34 @@ +(function($) { + if (typeof window.GravForm === 'undefined') { return; } + + var config = window.GravForm.config; + var body = $('body'); + + body.on('click', '[data-2fa-regenerate]', function(event) { + event.preventDefault(); + let element = $(this); + let url = `${config.base_url_relative}/task${config.param_sep}login.regenerate2FASecret`; + + element.attr('disabled', 'disabled').find('> .fa').addClass('fa-spin'); + + jQuery.post(url, function(response) { + $('[data-2fa-image]').attr('src', response.image); + $('[data-2fa-secret]').text(response.secret); + $('[data-2fa-value]').val(response.secret); + + element.removeAttr('disabled').find('> .fa').removeClass('fa-spin'); + }); + }); + + var toggleSecret = function() { + const toggle = $('#toggle_twofa_enabled1'); + const secret = $('.twofa-secret'); + + secret.css('display', toggle.is(':checked') ? 'inherit' : 'none'); + // [toggle.is(':checked') ? 'addClass' : 'removeClass']('login-show'); + }; + + body.on('click', '.twofa-toggle input', toggleSecret); + toggleSecret(); + +})(jQuery); diff --git a/user/plugins/login/languages/de.yaml b/user/plugins/login/languages/de.yaml new file mode 100644 index 00000000..dcf260bf --- /dev/null +++ b/user/plugins/login/languages/de.yaml @@ -0,0 +1,128 @@ +PLUGIN_LOGIN: + USERNAME: "Benutzername" + EMAIL: "E-Mail" + USERNAME_EMAIL: "Benutzername/E-Mail" + PASSWORD: "Passwort" + ACCESS_DENIED: "Zugang verweigert…" + LOGIN_FAILED: "Login fehlgeschlagen…" + LOGIN_SUCCESSFUL: "Sie wurden erfolgreich angemeldet." + BTN_LOGIN: "Anmelden" + BTN_LOGOUT: "Abmelden" + BTN_FORGOT: "Vergessen" + BTN_REGISTER: "Registrieren" + BTN_RESET: "Passwort zurücksetzen" + BTN_SEND_INSTRUCTIONS: "Sende Anweisungen zum Zurücksetzen" + RESET_LINK_EXPIRED: "Der Link zum Zurücksetzen ist abgelaufen. Bitte erneut versuchen." + RESET_PASSWORD_RESET: "Das Passwort wurde zurückgesetzt" + RESET_INVALID_LINK: "Es wurde ein ungültiger Link zum Zurücksetzen verwendet. Bitte erneut versuchen." + FORGOT_INSTRUCTIONS_SENT_VIA_EMAIL: "Die Anweisungen zum Zurücksetzen Ihres Passworts wurden per E-Mail gesendet." + FORGOT_FAILED_TO_EMAIL: "Das Versenden der Anweisung per E-Mail ist fehlgeschlagen. Bitte später erneut versuchen." + FORGOT_CANNOT_RESET_EMAIL_NO_EMAIL: "Das Passwort für %s kann nicht zurückgesetzt werden. Es ist keine E-Mail-Adresse hinterlegt." + FORGOT_CANNOT_RESET_EMAIL_NO_PASSWORD: "Das Passwort für %s kann nicht zurückgesetzt werden. Diese E-Mail ist mit einem Remote-Account verknüpft." + FORGOT_USERNAME_DOES_NOT_EXIST: "Der Benutzer mit dem Benutzername %s existiert nicht." + FORGOT_EMAIL_NOT_CONFIGURED: "Das Passwort kann nicht zurückgesetzt werden, da die Website ist nicht zum Versenden von E-Mails konfiguriert." + FORGOT_EMAIL_SUBJECT: "Passwort zurückzusetzen für %s" + FORGOT_EMAIL_BODY: "

                                                            Passwort Zurücksetzen

                                                            Hallo %1$s,

                                                            Es wurde ein Anfrage auf %4$s gestellt, um Ihr Passwort zu ändern.


                                                            Klicken Sie hier, um Ihr Passwort zurückzusetzen

                                                            Alternativ kopieren Sie die folgende URL in die Adresszeile Ihres Browsers:

                                                            %2$s


                                                            Mit freundlichen Grüßen,

                                                            %3$s

                                                            " + REMEMBER_ME: "Angemeldet bleiben" + REMEMBER_ME_HELP: "Speichert einen Cookie im Browser, welcher eine fortwährende Anmeldung sicherstellt." + REMEMBER_ME_STOLEN_COOKIE: "Jemand anderes hat Ihre Zugangsdaten verwendet, um auf diese Seite zuzugreifen! Alle Sitzungen wurden ausgeloggt. Bitte melden Sie sich mit Ihren Zugangsdaten an und überprüfen Sie Ihre Daten." + BUILTIN_CSS: "Nutze das integrierte Plugin CSS" + BUILTIN_CSS_HELP: "Nutze das CSS, welches vom Admin Plugin bereitgestellt werden" + ROUTE: "Anmeldepfad" + ROUTE_HELP: "Route zu einer benutzerdefinierten Anmeldeseite, die von Ihrem Theme bereitgestellt wird." + ROUTE_REGISTER: "Registrierungspfad" + ROUTE_REGISTER_HELP: "Pfad zur Registrierungsseite. Stellen Sie dies ein, wenn Sie die eingebaute Registrierungsseite verwenden möchten. Lassen Sie das Feld leer, wenn Sie ein eigenes Anmeldeformular haben." + USERNAME_NOT_VALID: "Der Benutzername sollte zwischen 3 und 16 Zeichen enthalten, einschließlich Kleinbuchstaben, Zahlen, Unterstrichen und Bindestrichen. Großbuchstaben, Leerzeichen und Sonderzeichen sind nicht zulässig" + USERNAME_NOT_AVAILABLE: "Der Benutzername %s existiert bereits. Bitte wählen Sie einen anderen Benutzernamen." + EMAIL_NOT_AVAILABLE: "Die E-Mail-Adresse %s ist bereits vorhanden. Bitte wählen Sie eine andere E-Mail-Adresse aus." + PASSWORD_NOT_VALID: "Das Passwort muss mindestens eine Zahl und einen Groß- und Kleinbuchstaben sowie mindestens 8 oder mehr Zeichen enthalten." + PASSWORDS_DO_NOT_MATCH: "Die Passwörter stimmen nicht überein. Überprüfen Sie, ob Sie das gleiche Passwort zweimal eingegeben haben." + USER_NEEDS_EMAIL_FIELD: "Der Benutzer benötigt ein E-Mail Feld." + EMAIL_SENDING_FAILURE: "Beim Senden der E-Mail ist ein Fehler aufgetreten." + ACTIVATION_EMAIL_SUBJECT: "Aktivieren Sie Ihren Account bei %s" + ACTIVATION_EMAIL_BODY: "

                                                            Account Aktivierung

                                                            Hallo %1$s,

                                                            Ihr Konto bei %3$s wurde erfolgreich erstellt, aber Sie können sich erst anmelden, wenn es aktiviert ist.


                                                            Account jetzt aktivieren

                                                            Alternativ kopieren Sie die folgende URL in die Adresszeile Ihres Browsers:

                                                            %2$s


                                                            Mit freundlichen Grüßen,

                                                            %4$s

                                                            " + ACTIVATION_NOTICE_MSG: "Hallo %s, Ihr Konto wurde erstellt. Bitte überprüfen Sie Ihre E-Mail, um es vollständig zu aktivieren" + WELCOME_EMAIL_SUBJECT: "Willkommen bei %s" + WELCOME_EMAIL_BODY: "

                                                            Account erstellt

                                                            Hallo %1$s,

                                                            Ihr Konto bei %3$s wurde erfolgreich erstellt.


                                                            Jetzt anmelden

                                                            Alternativ kopieren Sie die folgende URL in die Adresszeile Ihres Browsers:

                                                            %2$s


                                                            Mit freundlichen Grüßen,

                                                            %4$s

                                                            " + WELCOME_NOTICE_MSG: "Hallo %s, Ihr Account wurde erfolgreich erstellt" + NOTIFICATION_EMAIL_SUBJECT: "Neuer Benutzer bei %s" + NOTIFICATION_EMAIL_BODY: "

                                                            Neuer Benutzer

                                                            Hallo, ein neuer Benutzer hat sich bei %1$s registriert.

                                                            • Benutzername: %2$s
                                                            • E-Mail: %3$s


                                                            %1$s aufrufen

                                                            " + EMAIL_FOOTER: "GetGrav.org" + ACTIVATION_LINK_EXPIRED: "Der Aktivierungslink ist abgelaufen." + USER_ACTIVATED_SUCCESSFULLY: "Benutzer wurde erfolgreich aktiviert." + INVALID_REQUEST: "Ungültige Anfrage." + USER_REGISTRATION: "Benutzerregistrierung." + USER_REGISTRATION_ENABLED_HELP: "Benutzerregistrierung aktivieren." + VALIDATE_PASSWORD1_AND_PASSWORD2: "Doppelt eingegebenes Passwort bestätigen." + VALIDATE_PASSWORD1_AND_PASSWORD2_HELP: "Validieren und vergleichen Sie zwei verschiedene Felder für die Passwörter mit den Namen `password1` und` password2`. Aktivieren Sie diese Option, wenn Sie im Anmeldeformular zwei Passwortfelder haben." + SET_USER_DISABLED: "Benutzer als deaktiviert festlegen" + SET_USER_DISABLED_HELP: "Am besten zusammen mit der E-Mail 'Aktivierungs-E-Mail senden' verwenden. Fügt den Benutzer zu Grav hinzu, setzt ihn jedoch als deaktiviert" + LOGIN_AFTER_REGISTRATION: "Benutzer nach Registrierung anmelden." + LOGIN_AFTER_REGISTRATION_HELP: "Meldet den Benutzer direkt nach der Registrierung an. Wenn eine E-Mail-Aktivierung erforderlich ist, wird der Benutzer sofort nach der Aktivierung des Kontos angemeldet." + SEND_ACTIVATION_EMAIL: "Aktivierungs-E-Mail senden" + SEND_ACTIVATION_EMAIL_HELP: "Sendet eine E-Mail an den Benutzer, um seinen Account zu aktivieren. Aktivieren Sie die Option 'Benutzer als deaktiviert festlegen', wenn Sie diese Funktion verwenden, sodass der Benutzer als deaktiviert festgelegt wird und eine E-Mail gesendet wird, um das Konto zu aktivieren" + SEND_NOTIFICATION_EMAIL: "Benachrichtigungs-E-Mail senden" + SEND_NOTIFICATION_EMAIL_HELP: "Benachrichtigt den Seiten-Administrator, dass sich ein neuer Benutzer registriert hat. Die E-Mail wird in der E-Mail-Plugin-Konfiguration an das Feld 'to' gesendet" + SEND_WELCOME_EMAIL: "Sende Willkommens-E-Mail" + SEND_WELCOME_EMAIL_HELP: "Sendet eine E-Mail an den neu registrierten Benutzer" + DEFAULT_VALUES: "Standardwerte" + DEFAULT_VALUES_HELP: "Liste der Feldnamen und der zugehörigen Werte, die standardmäßig dem Benutzerprofil (Yaml-Datei) hinzugefügt werden, ohne vom Benutzer konfiguriert zu werden. Trennen Sie mehrere Werte durch ein Komma ohne Leerzeichen zwischen den Werten." + ADDITIONAL_PARAM_KEY: "Parameter" + ADDITIONAL_PARAM_VALUE: "Wert" + REGISTRATION_FIELDS: "Registrierungsfelder" + REGISTRATION_FIELDS_HELP: "Fügen Sie die Felder hinzu, die der Yaml-Datei des Benutzers hinzugefügt werden. Felder, die hier nicht aufgeführt sind, werden nicht hinzugefügt, auch wenn sie im Anmeldeformular vorhanden sind." + REGISTRATION_FIELD_KEY: "Feldname" + REDIRECT_AFTER_LOGIN: "Weiterleitung nach Login." + REDIRECT_AFTER_LOGIN_HELP: "Benutzerdefinierte Seite zu der, nach erfolgreichem Login, weitergeleitet wird." + REDIRECT_AFTER_LOGOUT: "Weiterleitung nach Abmelden." + REDIRECT_AFTER_LOGOUT_HELP: "Benutzerdefinierte Seite zu der, nach dem Abmelden des Benutzers, weitergeleitet wird." + REDIRECT_AFTER_REGISTRATION: "Weiterleitung nach Registrierung." + REDIRECT_AFTER_REGISTRATION_HELP: "Benutzerdefinierte Seite zu der, nach Abschluss der Registrierung, weitergeleitet wird." + OPTIONS: "Optionen" + EMAIL_VALIDATION_MESSAGE: "Muss eine gültige E-Mail-Adresse sein." + PASSWORD_VALIDATION_MESSAGE: "Das Passwort muss mindestens eine Zahl und einen Groß- und Kleinbuchstaben sowie mindestens 8 oder mehr Zeichen enthalten." + TIMEOUT_HELP: "Legt das Sitzungszeitlimit in Sekunden fest, wenn 'Angemeldet bleiben' vom Benutzer aktiviert und überprüft wird. Das Minimum ist 604800, was einer Woche entspricht." + GROUPS_HELP: "Liste der Gruppen, denen neu registrierte Benutzer zugewiesen werden, falls vorhanden." + SITE_ACCESS_HELP: "Liste der Seiten, auf die neu registrierte Benutzer Zugriff haben. Beispiel: `login` -> `true`" + WELCOME: "Willkommen" + REDIRECT_AFTER_ACTIVATION: "Weiterleitung nach Benutzeraktivierung" + REDIRECT_AFTER_ACTIVATION_HELP: "Wird verwendet, wenn der Benutzer das Konto per E-Mail aktivieren muss. Einmal aktiviert, wird diese Seite angezeigt" + REGISTRATION_DISABLED: "Registrierung deaktiviert" + USE_PARENT_ACL_LABEL: "Übergeordnete Zugriffsregeln verwenden" + USE_PARENT_ACL_HELP: "Verwende übergeordneten Zugriffsregeln, wenn keine Regeln definiert sind." + PROTECT_PROTECTED_PAGE_MEDIA_LABEL: Schütze auch die Medien, von Login-geschützten Seiten." + PROTECT_PROTECTED_PAGE_MEDIA_HELP: "Wenn diese Option aktiviert ist, ist das Medium einer, durch einen Login geschützten, Seite ebenfalls Login-geschützt und kann nur angezeigt werden, wenn Sie angemeldet sind." + SECURITY_TAB: "Sicherheit" + MAX_RESETS_COUNT: "Max. Anzahl an Versuchen, um das Passwort zurücksetzen." + MAX_RESETS_COUNT_HELP: "'Flood protection' Einstellung, um das Passwort zurücksetzen (0 - nicht begrenzt)" + MAX_RESETS_INTERVAL: "Max. Intervall an Versuchen, um das Passwort zurücksetzen." + MAX_RESETS_INTERVAL_HELP: "Zeitintervall für die max. Anzahl an Versuchen das Passwort zurückzusetzen." + FORGOT_CANNOT_RESET_IT_IS_BLOCKED: "Kann das Passwort für %s nicht zurücksetzen, die Funktion zum Zurücksetzen des Passworts wurde vorübergehend blockiert. Bitte versuchen Sie es später erneut (maximal %s Minuten)" + MAX_LOGINS_COUNT: "Max. Anzahl an Anmeldeversuche" + MAX_LOGINS_COUNT_HELP: "'Flood protection' Einstellung (0 - nicht begrenzt)" + MAX_LOGINS_INTERVAL: "Max. Login Intervall" + MAX_LOGINS_INTERVAL_HELP: "Das max. Zeitintervall für Anmeldeversuche." + TOO_MANY_LOGIN_ATTEMPTS: "Zu viele fehlgeschlagene Anmeldeversuche in der konfigurierten Zeit (%s Minuten)" + SECONDS: "Sekunden" + RESETS: "Resets" + ATTEMPTS: "Versuche" + ROUTES: "Pfade" + ROUTE_FORGOT: "Pfad für 'Passwort vergessen'" + ROUTE_RESET: "Pfad für 'Passwort zurücksetzen'" + ROUTE_PROFILE: "Benutzerprofil Pfad" + ROUTE_ACTIVATE: "Benutzeraktivierung Pfad" + LOGGED_OUT: "Sie wurden erfolgreich abgemeldet…" + PAGE_RESTRICTED: "Der Zugang ist eingeschränkt, bitte melden Sie sich an…" + DYNAMIC_VISIBILITY: "Dynamische Seitensichtbarkeit" + DYNAMIC_VISIBILITY_HELP: "Ermöglicht die dynamische Verarbeitung der Seitensichtbarkeit basierend auf Zugriffsregeln, wenn 'login.visibility_requires_access' auf einer Seite auf 'true' gesetzt ist." + USER_IS_REMOTE_ONLY: "Dieser Benutzer wurde mit einem Remotedienst authentifiziert, sodass sein Profil nicht gespeichert werden kann." + 2FA_TITLE: "2-Faktor-Authentifizierung" + 2FA_INSTRUCTIONS: "##### 2-Faktor-Authentifizierung\n Sie haben **2FA** für dieses Konto aktiviert. Bitte verwenden Sie Ihre **2FA** App, um den aktuellen **6-stelligen Code ** einzugeben, damit der Anmeldevorgang abgeschlossen werden kann." + 2FA_REGEN_HINT: "Wenn Sie das Secret neu generieren, müssen Sie Ihre Authentifikator-App aktualisieren." + 2FA_FAILED: "Ungültiger 2-Faktor-Authentifizierungscode, bitte versuchen Sie es erneut…" + 2FA_ENABLED: "2FA aktiviert" + 2FA_CODE_INPUT: "000000" + 2FA_SECRET: "2FA Secret" + 2FA_SECRET_HELP: "Scannen Sie diesen QR-Code in Ihre [Authenticator App](https://learn.getgrav.org/admin-panel/2fa#apps). Es ist sinnvoll, das Secret an einem sicheren Ort zu sichern, falls Sie Ihre App neu installieren müssen. In der [Grav Doku](https://learn.getgrav.org/admin-panel/2fa) finden Sie weitere Informationen." + 2FA_REGENERATE: "Neu generieren" + BTN_CANCEL: "Abbrechen" diff --git a/user/plugins/login/languages/en.yaml b/user/plugins/login/languages/en.yaml new file mode 100644 index 00000000..95bfa31b --- /dev/null +++ b/user/plugins/login/languages/en.yaml @@ -0,0 +1,136 @@ +PLUGIN_LOGIN: + USERNAME: "Username" + EMAIL: "Email" + USERNAME_EMAIL: "Username/Email" + PASSWORD: "Password" + ACCESS_DENIED: "Access denied..." + LOGIN_FAILED: "Login failed..." + LOGIN_SUCCESSFUL: "You have been successfully logged in." + BTN_LOGIN: "Login" + BTN_LOGOUT: "Logout" + BTN_FORGOT: "Forgot" + BTN_REGISTER: "Register" + BTN_RESET: "Reset Password" + BTN_SEND_INSTRUCTIONS: "Send Reset Instructions" + RESET_LINK_EXPIRED: "Reset link has expired, please try again" + RESET_PASSWORD_RESET: "Password has been reset" + RESET_INVALID_LINK: "Invalid reset link used, please try again" + FORGOT_INSTRUCTIONS_SENT_VIA_EMAIL: "Instructions to reset your password have been sent via email" + FORGOT_FAILED_TO_EMAIL: "Failed to email instructions, please try again later" + FORGOT_CANNOT_RESET_EMAIL_NO_EMAIL: "Cannot reset password for %s, no email address is set" + FORGOT_CANNOT_RESET_EMAIL_NO_PASSWORD: "Cannot reset password for %s, this email is associated with a remote account" + FORGOT_USERNAME_DOES_NOT_EXIST: "User with username %s does not exist" + FORGOT_EMAIL_NOT_CONFIGURED: "Cannot reset password. This site is not configured to send emails" + FORGOT_EMAIL_SUBJECT: "%s Password Reset Request" + FORGOT_EMAIL_BODY: "

                                                            Password Reset

                                                            Dear %1$s,

                                                            A request was made on %4$s to reset your password.


                                                            Click this to reset your password

                                                            Alternatively, copy the following URL into your browser's address bar:

                                                            %2$s


                                                            Kind regards,

                                                            %3$s

                                                            " + SESSION: "“Remember Me”-Session" + REMEMBER_ME: "Remember Me" + REMEMBER_ME_HELP: "Sets a persistent cookie on your browser to allow persistent-login authentication between sessions." + REMEMBER_ME_STOLEN_COOKIE: "Someone else has used your login information to access this page! All sessions were logged out. Please log in with your credentials and check your data." + BUILTIN_CSS: "Use built in CSS" + BUILTIN_CSS_HELP: "Include the CSS provided by the admin plugin" + ROUTE: "Login path" + ROUTE_HELP: "Custom route to a custom login page that your theme provides" + ROUTE_REGISTER: "Registration path" + ROUTE_REGISTER_HELP: "Route to the registration page. Set this if you want to use the built-in registration page. Leave it empty if you have your own registration form" + USERNAME_NOT_VALID: "Username should be between 3 and 16 characters, including lowercase letters, numbers, underscores, and hyphens. Uppercase letters, spaces, and special characters are not allowed" + USERNAME_NOT_AVAILABLE: "Username %s already exists, please pick another username" + EMAIL_NOT_AVAILABLE: "Email address %s already exists, please pick another email address" + PASSWORD_NOT_VALID: "Password must contain at least one number and one uppercase and lowercase letter, and at least 8 or more characters" + PASSWORDS_DO_NOT_MATCH: "Passwords do not match. Double-check you entered the same password twice" + USER_NEEDS_EMAIL_FIELD: "The user needs an email field" + EMAIL_SENDING_FAILURE: "An error occurred while sending the email" + ACTIVATION_EMAIL_SUBJECT: "Activate your account on %s" + ACTIVATION_EMAIL_BODY: "

                                                            Account Activation

                                                            Hi %1$s,

                                                            Your account has been successfully created on %3$s, but you cannot login until it is activated.


                                                            Activate Your Account Now

                                                            Alternatively, copy the following URL into your browser's address bar:

                                                            %2$s


                                                            Kind regards,

                                                            %4$s

                                                            " + ACTIVATION_NOTICE_MSG: "Hi %s, your account is created, please check your email to fully activate it" + WELCOME_EMAIL_SUBJECT: "Welcome to %s" + WELCOME_EMAIL_BODY: "

                                                            Account Created

                                                            Hi %1$s,

                                                            Your account has been successfully created on %3$s.


                                                            Login Now

                                                            Alternatively, copy the following URL into your browser's address bar:

                                                            %2$s


                                                            Kind regards,

                                                            %4$s

                                                            " + WELCOME_NOTICE_MSG: "Hi %s, your account has been successfully created" + NOTIFICATION_EMAIL_SUBJECT: "New user on %s" + NOTIFICATION_EMAIL_BODY: "

                                                            New User

                                                            Hi, a new user registered on %1$s.

                                                            • Username: %2$s
                                                            • Email: %3$s


                                                            Visit %1$s

                                                            " + EMAIL_FOOTER: "GetGrav.org" + ACTIVATION_LINK_EXPIRED: "Activation link expired" + USER_ACTIVATED_SUCCESSFULLY: "User account activated successfully" + USER_ACTIVATED_SUCCESSFULLY_NOT_ENABLED: "User account activated but account is being reviewed" + INVALID_REQUEST: "Invalid request" + USER_REGISTRATION: "User Registration" + USER_REGISTRATION_ENABLED_HELP: "Enable the user registration" + VALIDATE_PASSWORD1_AND_PASSWORD2: "Validate double entered password" + VALIDATE_PASSWORD1_AND_PASSWORD2_HELP: "Validate and compare two different fields for the passwords, named `password1` and `password2`. Enable this if you have two password fields in the registration form" + SET_USER_DISABLED: "Set the user as disabled" + SET_USER_DISABLED_HELP: "Best used along with the `Send activation email` email. Adds the user to Grav, but sets it as disabled" + LOGIN_AFTER_REGISTRATION: "Login the user after registration" + LOGIN_AFTER_REGISTRATION_HELP: "Immediately login the user after the registration. If email activation is required, the user will be logged in immediately after activating the account" + SEND_ACTIVATION_EMAIL: "Send activation email" + SEND_ACTIVATION_EMAIL_HELP: "Sends an email to the user to activate his account. Enable the `Set the user as disabled` option when using this feature, so the user will be set as disabled and an email will be sent to activate the account" + SEND_NOTIFICATION_EMAIL: "Send notification email" + SEND_NOTIFICATION_EMAIL_HELP: "Notifies the site admin that a new user has registered. The email will be sent to the `To` field in the Email Plugin configuration" + SEND_WELCOME_EMAIL: "Send welcome email" + SEND_WELCOME_EMAIL_HELP: "Sends an email to the newly registered user" + DEFAULT_VALUES: "Default values" + DEFAULT_VALUES_HELP: "List of field names and values associated, that will be added to the user profile (yaml file) by default, without being configurable by the user. Separate multiple values with a comma, with no spaces between the values" + ADDITIONAL_PARAM_KEY: "Parameter" + ADDITIONAL_PARAM_VALUE: "Value" + REGISTRATION_FIELDS: "Registration fields" + REGISTRATION_FIELDS_HELP: "Add the fields that will be added to the user Yaml file. Fields not listed here will not be added even if present in the registration form" + REGISTRATION_FIELD_KEY: "Field name" + REDIRECT_AFTER_LOGIN: "Redirect after login" + REDIRECT_AFTER_LOGIN_HELP: "Custom route to redirect after login" + REDIRECT_AFTER_LOGOUT: "Redirect after logout" + REDIRECT_AFTER_LOGOUT_HELP: "Custom route to redirect after logout" + REDIRECT_AFTER_REGISTRATION: "Redirect after registration" + REDIRECT_AFTER_REGISTRATION_HELP: "Custom route to redirect after the registration" + OPTIONS: "Options" + EMAIL_VALIDATION_MESSAGE: "Must be a valid email address" + PASSWORD_VALIDATION_MESSAGE: "Password must contain at least one number and one uppercase and lowercase letter, and at least 8 or more characters" + TIMEOUT_HELP: "Sets the session timeout in seconds when Remember Me is enabled and checked by the user. Minimum is 604800 which means 1 week" + GROUPS_HELP: "List of groups the new registered user will be part of, if any" + SITE_ACCESS_HELP: "List of site access levels the new registered user will have. Example: `login` -> `true` " + WELCOME: "Welcome" + REDIRECT_AFTER_ACTIVATION: "Redirect after the user activation" + REDIRECT_AFTER_ACTIVATION_HELP: "Used if the user is required to activate the account via email. Once activated, this route will be shown" + REGISTRATION_DISABLED: "Registration disabled" + USE_PARENT_ACL_LABEL: "Use parent access rules" + USE_PARENT_ACL_HELP: "Check for parent access rules if no rules are defined" + PROTECT_PROTECTED_PAGE_MEDIA_LABEL: "Protect a login-protected page media" + PROTECT_PROTECTED_PAGE_MEDIA_HELP: "If enabled, media of a login protected page is login protected as well and cannot be seen unless logged in" + SECURITY_TAB: "Security" + MAX_RESETS_COUNT: "Max password resets count" + MAX_RESETS_COUNT_HELP: "Password reset flood protection setting (0 - not limited)" + MAX_RESETS_INTERVAL: "Max password resets interval" + MAX_RESETS_INTERVAL_HELP: "The time interval for the max password resets count value" + FORGOT_CANNOT_RESET_IT_IS_BLOCKED: "Cannot reset password for %s, password reset functionality temporarily blocked, please try later (maximum %s minutes)" + MAX_LOGINS_COUNT: "Max logins count" + MAX_LOGINS_COUNT_HELP: "Flood protection setting (0 - not limited)" + MAX_LOGINS_INTERVAL: "Max logins interval" + MAX_LOGINS_INTERVAL_HELP: "The time interval for the login count value" + TOO_MANY_LOGIN_ATTEMPTS: "Too many failed login attempted in the configured time (%s minutes)" + SECONDS: "seconds" + MINUTES: "minutes" + RESETS: "resets" + ATTEMPTS: "attempts" + ROUTES: "Routes" + ROUTE_FORGOT: "Forgot password route" + ROUTE_RESET: "Reset password route" + ROUTE_PROFILE: "User profile route" + ROUTE_ACTIVATE: "User activation route" + LOGGED_OUT: "You have been successfully logged out..." + PAGE_RESTRICTED: "Access is restricted, please login..." + DYNAMIC_VISIBILITY: "Dynamic Page Visibility" + DYNAMIC_VISIBILITY_HELP: "Allows dynamic processing of page visibility base on access rules if login.visibility_requires_access is set to true on a page" + USER_IS_REMOTE_ONLY: "This user authenticated with a remote service, so profile cannot be saved" + 2FA_TITLE: "2-Factor Authentication" + 2FA_INSTRUCTIONS: "##### 2-Factor Authentication\nYou have **2FA** enabled on this account. Please use your **2FA** app to enter the current **6-digit code** to complete the login process." + 2FA_REGEN_HINT: "Regenerating the secret will require you to update your authenticator app" + 2FA_FAILED: "Invalid 2-Factor Authentication code, please try again..." + 2FA_ENABLED: "2FA Enabled" + 2FA_ENABLED_HELP: "Enables 2-Factor Authentication for all users" + 2FA_CODE_INPUT: "000000" + 2FA_SECRET: "2FA Secret" + 2FA_SECRET_HELP: "Scan this QR code into your [Authenticator App](https://learn.getgrav.org/admin-panel/2fa#apps). Also it's a good idea to backup the secret in a safe location, in case you need to reinstall your app. Check the [Grav docs](https://learn.getgrav.org/admin-panel/2fa) for more information " + 2FA_REGENERATE: "Regenerate" + BTN_CANCEL: "Cancel" + MANUALLY_ENABLE: "Manually Enable" + MANUALLY_ENABLE_HELP: "When using 'activation email' and 'notification email', you can ensure the user can self activate, but requires manually enabling the user to login" + IPV6_SUBNET_SIZE: "IPv6 Subnet Size" + IPV6_SUBNET_SIZE_HELP: "The number of IPv6 addresses typically assigned to a machine" \ No newline at end of file diff --git a/user/plugins/login/languages/es.yaml b/user/plugins/login/languages/es.yaml new file mode 100644 index 00000000..c81a8dfa --- /dev/null +++ b/user/plugins/login/languages/es.yaml @@ -0,0 +1,115 @@ +PLUGIN_LOGIN: + USERNAME: "Nombre de usuario" + EMAIL: "Email" + USERNAME_EMAIL: "Nombre de usuario/Email" + PASSWORD: "Contraseña" + ACCESS_DENIED: "Acceso denegado..." + LOGIN_FAILED: "El acceso ha fallado..." + LOGIN_SUCCESSFUL: "Ha accedido correctamente." + BTN_LOGIN: "Acceder" + BTN_LOGOUT: "Salir" + BTN_FORGOT: "Olvidado" + BTN_REGISTER: "Registro" + BTN_RESET: "Restaurar contraseña" + BTN_SEND_INSTRUCTIONS: "Enviar instrucciones para restauración" + RESET_LINK_EXPIRED: "El enlace para la restauración ha caducado, inténtelo de nuevo." + RESET_PASSWORD_RESET: "La contraseña ha sido restaurada" + RESET_INVALID_LINK: "Ha utilizado un enlace de restauración inválido, inténtelo de nuevo." + FORGOT_INSTRUCTIONS_SENT_VIA_EMAIL: "Instructions to reset your password have been sent via email" + FORGOT_FAILED_TO_EMAIL: "No se ha podido enviar el email con instrucciones, inténtelo de nuevo." + FORGOT_CANNOT_RESET_EMAIL_NO_EMAIL: "No se puede restaurar la contraseña para %s, no hay dirección de email." + FORGOT_USERNAME_DOES_NOT_EXIST: "No existe ningún usuario con el nombre %s." + FORGOT_EMAIL_NOT_CONFIGURED: "No se puede restaurar la contraseña. Este sitio no está configurado para enviar emails." + FORGOT_EMAIL_SUBJECT: "%s solicitud de restauración de contraseña" + FORGOT_EMAIL_BODY: "

                                                            Restauración de contraseña

                                                            Estimado/a %1$s,

                                                            Se ha realizado una petición de restauración de contraseña en %4$s.


                                                            Pulse aquí para restaurar su contraseña

                                                            Como alternativa puede copiar la siguiente URL en la barra de direcciones de su navegador:

                                                            %2$s


                                                            Saludos cordiales,

                                                            %3$s

                                                            " + SESSION: "“Recuérdame”-Sesión" + REMEMBER_ME: "Recuérdame" + REMEMBER_ME_HELP: "Fija una cookie persistente en su navegador para permitir autenticación persistente entre sesiones." + REMEMBER_ME_STOLEN_COOKIE: "Alguien ha usado su información de acceso para acceder a este sitio. Se han cerrado todas las sesiones. Vuelva a acceder con sus credenciales y compruebe sus datos." + BUILTIN_CSS: "Usar CSS incorporado" + BUILTIN_CSS_HELP: "Incluir CSS proporcionado por el plugin de administración" + ROUTE: "Ruta de acceso" + ROUTE_HELP: "Ruta de acceso personalizada que proporciona su tema" + ROUTE_REGISTER: "Ruta de registro" + ROUTE_REGISTER_HELP: "Ruta a la página de registro. Ajuste esto si desea utilizar la página de registro incorporada. Déjelo vacío so tiene su propio formulario de registro." + USERNAME_NOT_VALID: "El nombre de usuario deberá contener entre 3 y 16 caracteresEl nombre de usuario deberá contener entre 3 y 16 caracteres y puede incluir minúsculas, números, guiones bajos y normales. No se permiten letras mayúsculas, espacios ni caracteres especiales." + USERNAME_NOT_AVAILABLE: "El nombre de usuario %s ya existe, elija otro." + EMAIL_NOT_AVAILABLE: "El email %s ya existe, elija otro." + PASSWORD_NOT_VALID: "La contraseña debe contener por lo menois un número y una letra mayúscula y minúscula, y debe ser de al menos 8 caracteres." + PASSWORDS_DO_NOT_MATCH: "Las contraseñas no coinciden. Compruebe que ha introducido la misma contrasenna dos veces." + USER_NEEDS_EMAIL_FIELD: "El usuario necesita un campo de email." + EMAIL_SENDING_FAILURE: "Ha ocurrido un error al enviar el email." + ACTIVATION_EMAIL_SUBJECT: "Active su cuenta en %s" + ACTIVATION_EMAIL_BODY: "

                                                            %Activación de cuenta

                                                            Hola %1$s,

                                                            Su cuenta en %3$s ha sido creada con éxito, pero no podrá acceder hasta que se active..


                                                            Active su cuenta ahora

                                                            Como alternativa puede copiar la siguiente URL en la barra de direcciones de su navegador:

                                                            %2$s


                                                            Saludos cordiales,

                                                            %4$s

                                                            " + ACTIVATION_NOTICE_MSG: "Hola %s, su cuenta ha sido creada, compruebe su correo electrónico para acivarla completamente." + WELCOME_EMAIL_SUBJECT: "Bienvenido/a a %s" + WELCOME_EMAIL_BODY: "

                                                            Cuenta creada

                                                            Hola %1$s,

                                                            Su cuenta en %3$s ha sido creada con éxito.


                                                            Acceda ahora

                                                            Como alternativa puede copiar la siguiente URL en la barra de direcciones de su navegador:

                                                            %2$s


                                                            Saludos cordiales,

                                                            %4$s

                                                            " + WELCOME_NOTICE_MSG: "Hola %s, su cuenta ha sido creada con éxito." + NOTIFICATION_EMAIL_SUBJECT: "Usuario nuevo en %s" + NOTIFICATION_EMAIL_BODY: "

                                                            Usuario nuevo

                                                            Hola, se ha registrado un usuario nuevo en %1$s.

                                                            • Nombre de usuario: %2$s
                                                            • Email: %3$s


                                                            Visite %1$s

                                                            " + EMAIL_FOOTER: "GetGrav.org" + ACTIVATION_LINK_EXPIRED: "Enlace de activación caducado" + USER_ACTIVATED_SUCCESSFULLY: "Usiario activado con éxito" + INVALID_REQUEST: "Solicitud inválida" + USER_REGISTRATION: "Registro de usuarios" + USER_REGISTRATION_ENABLED_HELP: "Activar el registro de usuarios" + VALIDATE_PASSWORD1_AND_PASSWORD2: "Validar contraseñas" + VALIDATE_PASSWORD1_AND_PASSWORD2_HELP: "Validar y comparar dos campos diferentes para las contraseñas, llamados `password1` y `password2`. Active esto si tiene dos cambpos de contraseña en el formulario de registro." + SET_USER_DISABLED: "Crear usuario inactivo" + SET_USER_DISABLED_HELP: "Utilizado en combinación con `Enviar email de activación`. Añade el usuario a Grav, pero lo marca inactivo." + LOGIN_AFTER_REGISTRATION: "Acceder con el usuario después del registro." + LOGIN_AFTER_REGISTRATION_HELP: "Hacer que el usuario acceda inmediatamente después del registro. Si se requiere activación mediante email, al usuario se le permitirá entrada justo después de activar la cuenta." + SEND_ACTIVATION_EMAIL: "Enviar email de activación" + SEND_ACTIVATION_EMAIL_HELP: "Envía un email al usuario para activar su cuenta. Active la opción `Crear usuario inactivo` si usa esta característica de modo que el usuario se creará en modo inactivo y se enviará un email para activar la cuenta." + SEND_NOTIFICATION_EMAIL: "Enviar email de notificación" + SEND_NOTIFICATION_EMAIL_HELP: "Notifica al administrador del sitio de que se ha registrado un usuario nuevo. El email se enviará a la dirección del campo `Para` en la configuración del Plugin Email." + SEND_WELCOME_EMAIL: "Enviar email de bienvenida" + SEND_WELCOME_EMAIL_HELP: "Envía un email al usuario recién creado" + DEFAULT_VALUES: "Valores predeterminados" + DEFAULT_VALUES_HELP: "Lista de nombres de campo y sus valores asociados que se añadirán al perfil de usuario (archivo yaml) de forma predeterminada, sin ser configurables por el usuario. Separe los valores con coma, sin espacios entre los valores." + ADDITIONAL_PARAM_KEY: "Parámetro" + ADDITIONAL_PARAM_VALUE: "Valor" + REGISTRATION_FIELDS: "Campos de registro" + REGISTRATION_FIELDS_HELP: "Añada los campos que se incluirán en el archivo Yaml del usuario. Los campos que no se muestren aquí no estarán presentes en el formulario de registro." + REGISTRATION_FIELD_KEY: "Nombre del campo" + REDIRECT_AFTER_LOGIN: "Redireccionar después del acceso" + REDIRECT_AFTER_LOGIN_HELP: "Ruta personalizada para redireccionar al acceder" + REDIRECT_AFTER_REGISTRATION: "Redireccionar después del registro" + REDIRECT_AFTER_REGISTRATION_HELP: "Ruta personalizada para redireccionar después del registro" + OPTIONS: "Opciones" + EMAIL_VALIDATION_MESSAGE: "Debe ser un email válido" + PASSWORD_VALIDATION_MESSAGE: "La contraseña debe contener al menos un número, una mayúscula y una minúscula, y debe ser de al menos 8 caracteres." + TIMEOUT_HELP: "Fija el tiempo de caducidad de la sesión en segundos cuando `Recuérdame` está activado y marcadopor el usuario. El mínimo es 604800, que es una semana." + GROUPS_HELP: "Lista de grupos del que formará parte el usuario reci´n registrado." + SITE_ACCESS_HELP: "Lista de niveles de acceso al sitio que tendrá el usuario nuevo. Por ejemplo: `login` -> `true` " + WELCOME: "Bienvenido/a" + REDIRECT_AFTER_ACTIVATION: "Redireccionar después de activación de usuario" + REDIRECT_AFTER_ACTIVATION_HELP: "Se usará si el usuario debe activar la cuenta vía email. Una vez activado, se mostrará esta ruta" + REGISTRATION_DISABLED: "Registro desactivado" + USE_PARENT_ACL_LABEL: "Usar reglas de acceso del padre" + USE_PARENT_ACL_HELP: "Comprobar reglas de acceso superiores si no hay reglas de acceso definidas." + PROTECT_PROTECTED_PAGE_MEDIA_LABEL: "Proteger medios de una página protegida por acceso" + PROTECT_PROTECTED_PAGE_MEDIA_HELP: "Si está activo, los medios (imágenes, etc.) de una página protegido por acceso también estarán protegidos y solo serán visibles para usuarios que hayan accedido (login)" + SECURITY_TAB: "Seguridad" + MAX_RESETS_COUNT: "Cantidad máxima de restauraciones de contraseña" + MAX_RESETS_COUNT_HELP: "Protección de avalancha de restauración de contraseña (0 - ilimitado)" + MAX_RESETS_INTERVAL: "Intervalo máximo de restauración de contraseña" + MAX_RESETS_INTERVAL_HELP: "El intervalo máximo de tiempo para el valor máximo de restauración" + FORGOT_CANNOT_RESET_IT_IS_BLOCKED: "No se puede restaurar la contraseña de %s, la funcionalidad de restauración ha sido bloqueada temporalmente. Inténtelo de nuevo más tarde (máximo %s minutos)" + MAX_LOGINS_COUNT: "Número máximo de accesos" + MAX_LOGINS_COUNT_HELP: "Protección de avalancha (0 - ilimitado)" + MAX_LOGINS_INTERVAL: "Intervalo máximo de acceso" + MAX_LOGINS_INTERVAL_HELP: "El intervalo de tiempo para el número máximo de accesos" + TOO_MANY_LOGIN_ATTEMPTS: "Ha habido demasiados intentos fallidos de acceso en el tiempo permitido (%s minutos)" + SECONDS: "segundos" + RESETS: "reinicios" + ATTEMPTS: "intentos" + ROUTES: "Rutas" + ROUTE_FORGOT: "Ruta de contraseña olvidada" + ROUTE_RESET: "Ruta de restauración de contraseña" + ROUTE_PROFILE: "Ruta del perfil de usuario" + ROUTE_ACTIVATE: "Ruta de activación de usuario" + LOGGED_OUT: "Su sesión ha finalizado correctamente..." + PAGE_RESTRICTED: "Acceso restringido, acceda con sus credenciales..." + DYNAMIC_VISIBILITY: "Visibilidad de páginas dinámicas" + DYNAMIC_VISIBILITY_HELP: "Permite el procesamiento de la visibilidad de páginas basada en reglas de acceso si login.visibility_requires_access es true en un página" diff --git a/user/plugins/login/languages/fr.yaml b/user/plugins/login/languages/fr.yaml new file mode 100644 index 00000000..028af859 --- /dev/null +++ b/user/plugins/login/languages/fr.yaml @@ -0,0 +1,89 @@ +PLUGIN_LOGIN: + USERNAME: "Nom d’utilisateur" + EMAIL: "E-mail" + USERNAME_EMAIL: "Nom d’utilisateur/E-mail" + PASSWORD: "Mot de passe" + ACCESS_DENIED: "Accès refusé..." + LOGIN_FAILED: "Échec de la connexion..." + LOGIN_SUCCESSFUL: "Vous vous êtes connecté avec succès." + BTN_LOGIN: "Connexion" + BTN_LOGOUT: "Déconnexion" + BTN_FORGOT: "Mot de passe oublié" + BTN_REGISTER: "S’enregister" + BTN_RESET: "Réinitialiser le mot de passe" + BTN_SEND_INSTRUCTIONS: "Envoyer les instructions de Réinitialisation" + RESET_LINK_EXPIRED: "Le lien de réinitialisation a expiré, veuillez réessayer" + RESET_PASSWORD_RESET: "Le mot de passe a été réinitialisé" + RESET_INVALID_LINK: "Le lien de réinitialisation utilisé n’est pas valide, veuillez réessayer" + FORGOT_INSTRUCTIONS_SENT_VIA_EMAIL: "Les instructions pour la réinitialisation de votre mot de passe ont été envoyées par e-mail" + FORGOT_FAILED_TO_EMAIL: "Impossible d’envoyer les instructions, veuillez réessayer ultérieurement" + FORGOT_CANNOT_RESET_EMAIL_NO_EMAIL: "Impossible de réinitialiser le mot de passe pour %s, aucune adresse e-mail n’a été paramétrée" + FORGOT_USERNAME_DOES_NOT_EXIST: "L’utilisateur avec le nom d’utilisateur %s n’existe pas" + FORGOT_EMAIL_NOT_CONFIGURED: "Impossible de réinitialiser le mot de passe. Ce site n’est pas configuré pour envoyer des e-mails" + FORGOT_EMAIL_SUBJECT: "Demande de réinitialisation de mot de passe %s" + FORGOT_EMAIL_BODY: "

                                                            Réinitialisation de mot de passe

                                                            %1$s,

                                                            Une demande a été faite sur %4$s pour la réinitialisation de votre mot de passe.


                                                            Cliquez ici pour réinitialiser votre mot de passe

                                                            Vous pouvez également copier l’URL suivante dans la barre d’adresse de votre navigateur :

                                                            %2$s


                                                            Cordialement,

                                                            %3$s

                                                            " + SESSION: "Session - “Se souvenir de moi”" + REMEMBER_ME: "Se souvenir de moi" + REMEMBER_ME_HELP: "Définit un cookie persistant sur votre navigateur autorisant l’authentification par connexion persistante entre les sessions." + REMEMBER_ME_STOLEN_COOKIE: "Quelqu’un d’autre a utilisé vos informations de connexion pour accéder à cette page ! Toutes les sessions ont été déconnectées. Veuillez vous connecter avec vos identifiants et vérifier vos données." + BUILTIN_CSS: "Utiliser les CSS intégrés" + BUILTIN_CSS_HELP: "Utiliser les CSS fournis dans le plugin d’administration" + ROUTE: "Chemin de connexion" + ROUTE_HELP: "Chemin personnalisé vers une page de connexion personnalisée proposée par votre thème" + ROUTE_REGISTER: "Chemin vers l’inscription" + ROUTE_REGISTER_HELP: "Chemin vers la page d’inscription. A définir si vous souhaitez utiliser la page d’inscription intégrée. Laisser vide si vous disposez de votre propre formulaire d’inscription." + USERNAME_NOT_VALID: "Le nom d’utilisateur doit comporter entre 3 et 16 caractères et peut être composé de lettres minuscules, de chiffres et de tirets de soulignement (underscores) et des traits d’union. Les lettres majuscules, les espaces et les caractères spéciaux ne sont pas autorisés." + USERNAME_NOT_AVAILABLE: "Le nom d’utilisateur %s existe déjà, veuillez en choisir un autre." + PASSWORD_NOT_VALID: "Le mot de passe doit contenir au moins un chiffre, une majuscule et une minuscule et être composé d’au moins 8 caractères" + PASSWORDS_DO_NOT_MATCH: "Les mots de passe sont différents. Réessayez de saisir le même mot de passe deux fois." + USER_NEEDS_EMAIL_FIELD: "L’utilisateur a besoin d’un champ pour e-mail" + EMAIL_SENDING_FAILURE: "Une erreur est survenue lors de l’envoi de l’e-mail." + ACTIVATION_EMAIL_SUBJECT: "Activer votre compte sur %s" + ACTIVATION_EMAIL_BODY: "Bonjour %s, cliquez pour activer votre compte sur %s" + WELCOME_EMAIL_SUBJECT: "Bienvenue sur %s" + WELCOME_EMAIL_BODY: "Bonjour %s, bienvenue sur %s!" + NOTIFICATION_EMAIL_SUBJECT: "Nouvel utilisateur sur %s" + EMAIL_FOOTER: "GetGrav.org" + NOTIFICATION_EMAIL_BODY: "Bonjour, un nouvel utilisateur s’est inscrit sur %s. Nom d’utilisateur : %s, e-mail : %s" + ACTIVATION_LINK_EXPIRED: "Le lien d’activation a expiré" + USER_ACTIVATED_SUCCESSFULLY: "Utilisateur activé avec succès" + INVALID_REQUEST: "Requête non valide" + USER_REGISTRATION: "Inscription de l’utilisateur" + USER_REGISTRATION_ENABLED_HELP: "Activer l’inscription des utilisateurs" + VALIDATE_PASSWORD1_AND_PASSWORD2: "Valider la double saisie du mot de passe" + VALIDATE_PASSWORD1_AND_PASSWORD2_HELP: "Comparer et valider deux champs pour les mots de passe `Mot de passe 1` et `Mot de passe 2`. Activez cette option si vous avez deux champs de mots de passe dans le formulaire d’inscription." + SET_USER_DISABLED: "Définir l’utilisateur comme désactivé" + SET_USER_DISABLED_HELP: "La meilleure pratique si vous utilisez l’option `Envoyer un e-mail d’activation`. Ajoute l’utilisateur à Grav, mais le défini comme étant désactivé." + LOGIN_AFTER_REGISTRATION: "Connecte l’utilisateur après son inscription" + LOGIN_AFTER_REGISTRATION_HELP: "Identifier immédiatement l’utilisateur après l’inscription. Si l’e-mail d’activation est demandé, l’utilisateur sera connecté immédiatement après l’activation du compte." + SEND_ACTIVATION_EMAIL: "Envoyer un e-mail d’activation" + SEND_ACTIVATION_EMAIL_HELP: "Envoyer un e-mail à l’utilisateur pour l’activation son compte. Lorsque vous utilisez cette fonction, activez l’option `Définir l’utilisateur comme désactivé` afin que l’utilisateur soit désactivé et qu’un e-mail lui soit envoyé pour activer son compte." + SEND_NOTIFICATION_EMAIL: "Envoyer un e-mail de notification" + SEND_NOTIFICATION_EMAIL_HELP: "Informe l’administrateur du site qu’un nouvel utilisateur s’est enregistré. L’e-mail sera envoyé à la personne renseignée dans le champ `À` dans la configuration du plugin e-mail." + SEND_WELCOME_EMAIL: "Envoyer un e-mail de bienvenue" + SEND_WELCOME_EMAIL_HELP: "Envoyer un e-mail à un nouvel utilisateur enregistré." + DEFAULT_VALUES: "Valeurs par défaut" + DEFAULT_VALUES_HELP: "Liste des noms et valeurs associés pour les champs. Ils seront ajoutés au profil utilisateur par défaut (fichier yaml), sans pouvoir être configurables par l’utilisateur. Séparez les différentes valeurs par une virgule, sans espaces entre les valeurs." + ADDITIONAL_PARAM_KEY: "Paramètre" + ADDITIONAL_PARAM_VALUE: "Valeur" + REGISTRATION_FIELDS: "Champs d’inscription" + REGISTRATION_FIELDS_HELP: "Ajouter les champs qui seront ajoutés au fichier yaml de l’utilisateur. Les champs non listés ne seront pas ajoutés même s’ils sont présent sur le formulaire d’inscription" + REGISTRATION_FIELD_KEY: "Nom du champ" + REDIRECT_AFTER_LOGIN: "Redirection après connexion" + REDIRECT_AFTER_LOGIN_HELP: "Chemin personnalisé de redirection après la connexion" + REDIRECT_AFTER_REGISTRATION: "Redirection après inscription" + REDIRECT_AFTER_REGISTRATION_HELP: "Chemin personnalisé de redirection après l’inscription" + OPTIONS: "Options" + EMAIL_VALIDATION_MESSAGE: "Doit-être une adresse e-mail valide" + PASSWORD_VALIDATION_MESSAGE: "Le mot de passe doit-être composé d’au moins un chiffre, une majuscule et une minuscule, et au moins 8 caractères" + TIMEOUT_HELP: "Définit le délai d’expiration de la session en secondes lorsque `Se souvenir de moi` est activé et coché par l’utilisateur. Minimum de 604800 ce qui correspond à 1 semaine." + GROUPS_HELP: "Liste des groupes auxquels le nouvel utilisateur enregistré fera partie, le cas échéant." + SITE_ACCESS_HELP: "Liste des niveaux d’accès au site attribués au nouvel utilisateur enregistré. Exemple : `login` -> `true` " + WELCOME: "Bienvenue" + REDIRECT_AFTER_ACTIVATION: "Redirection après l’activation de l’utilisateur" + REDIRECT_AFTER_ACTIVATION_HELP: "Utilisé s’il est nécessaire pour l’utilisateur d’activer le compte par e-mail. Une fois activé, ce chemin s’affichera" + REGISTRATION_DISABLED: "Inscription désactivée" + USE_PARENT_ACL_LABEL: "Appliquer les règles d’accès parentes" + USE_PARENT_ACL_HELP: "Utiliser les règles d’accès parentes si aucune règle n’a été définie" + PROTECT_PROTECTED_PAGE_MEDIA_LABEL: "Protéger le média d'une page par une protection par connexion" + PROTECT_PROTECTED_PAGE_MEDIA_HELP: "Si activé, les médias d'une page protégée par connexion sera également protégé par un système de connexion et ne pourra pas être visible à moins d'être connecté." \ No newline at end of file diff --git a/user/plugins/login/languages/hr.yaml b/user/plugins/login/languages/hr.yaml new file mode 100644 index 00000000..30908859 --- /dev/null +++ b/user/plugins/login/languages/hr.yaml @@ -0,0 +1,41 @@ +PLUGIN_LOGIN: + ACCESS_DENIED: "Pristup odbijen..." + LOGIN_FAILED: "Prijava nije uspjela..." + BTN_LOGIN: "Prijava" + BTN_LOGOUT: "Odjava" + BTN_FORGOT: "Zaboravih" + BTN_REGISTER: "Registriraj" + REMEMBER_ME: "Zapamti me" + BUILTIN_CSS: "Koristi ugrađeni CSS" + BUILTIN_CSS_HELP: "Uključi CSS koji dolazi sa admin pluginom" + ROUTE: "Putanja prijave" + ROUTE_REGISTER: "Putanja registracije" + USERNAME_NOT_VALID: "Korisničko ime bi trebalo biti između 3 i 16 znakova, uključujući mala slova, brojeve, _, i crtice. VELIKA SLOVA, razmaci, i posebni znakovi nisu dopušteni" + USERNAME_NOT_AVAILABLE: "Korisničko ime %s već postoji, odaberi neko drugo" + PASSWORD_NOT_VALID: "Lozinka mora sadržavati bar jedan broj i jedno veliko i malo slovo, i bar još 8 ili više znakova" + PASSWORDS_DO_NOT_MATCH: "Lozinke se ne slažu. Poonovo provjeri da li si unio istu lozinku dva puta" + USER_NEEDS_EMAIL_FIELD: "Korisnik treba email polje" + EMAIL_SENDING_FAILURE: "Došlo je do greške pri slanju emaila" + ACTIVATION_LINK_EXPIRED: "Aktivacijski link je istekao" + USER_ACTIVATED_SUCCESSFULLY: "Korisnik je uspješno aktiviran" + INVALID_REQUEST: "Nevaljani zahtjev" + USER_REGISTRATION: "Registracija korisnika" + USER_REGISTRATION_ENABLED_HELP: "Omogući registraciju korisnika" + VALIDATE_PASSWORD1_AND_PASSWORD2: "Validiraj duplo unesenu lozinku" + VALIDATE_PASSWORD1_AND_PASSWORD2_HELP: "Validiraj i usporedi dva različčita polja za lozinke, imenovana `lozinka1` i `lozinka2`. Omogući ovo ako imaš dva polja za lozinke u formularu registracije" + LOGIN_AFTER_REGISTRATION: "Ulogiraj korisnika nakon reegistracije" + LOGIN_AFTER_REGISTRATION_HELP: "Ulogiraj korisnika odmah nakon registracije. Ako je potrebna email aktivacija, korisnik će biti ulogiran odmah nakon aktiviranja računa" + SEND_ACTIVATION_EMAIL: "Pošalji aktivacijski email" + SEND_ACTIVATION_EMAIL_HELP: "Šalje email korisniku da aktivira svoja račun." + SEND_NOTIFICATION_EMAIL: "Pošalji email obavijest" + SEND_NOTIFICATION_EMAIL_HELP: "Obavještava administratora da se novi korisnik registrirao. Email će biti poslan na `To` polje u Email Plugin konfiguraciji" + SEND_WELCOME_EMAIL: "Pošalji email dobrodošlice" + SEND_WELCOME_EMAIL_HELP: "Šalje email novoregistriranom korisniku" + DEFAULT_VALUES: "Određene vrijednosti" + DEFAULT_VALUES_HELP: "List of field names and values associated, that will be added to the user profile (yaml file) by default, without being configurable by the user. Separate multiple values with a comma, with no spaces between the values" + ADDITIONAL_PARAM_KEY: "Parametar" + ADDITIONAL_PARAM_VALUE: "Vrijednost" + REGISTRATION_FIELDS: "Registracijska polja" + REGISTRATION_FIELDS_HELP: "Add the fields that will be added to the user yaml file. Fields not listed here will not be added even if present in the registration form" + REGISTRATION_FIELD_KEY: "Ime polja" + OPTIONS: "Opcije" \ No newline at end of file diff --git a/user/plugins/login/languages/hu.yaml b/user/plugins/login/languages/hu.yaml new file mode 100644 index 00000000..e5457815 --- /dev/null +++ b/user/plugins/login/languages/hu.yaml @@ -0,0 +1,22 @@ +PLUGIN_LOGIN: + ACCESS_DENIED: "Hozzáférés megtagadva..." + LOGIN_FAILED: "Sikertelen belépés..." + LOGIN_SUCCESSFUL: "Sikeresen beléptél." + LOGGED_OUT: "Sikeresen kiléptél." + BTN_LOGIN: "Belépés" + BTN_LOGOUT: "Kilépés" + BTN_FORGOT: "Elfelejtettem" + BTN_REGISTER: "Regisztráció" + REMEMBER_ME: "Jegyezz meg" + REMEMBER_ME_HELP: "Elhelyezünk egy hosszú lejáratú sütit a böngésződben, hogy belépve maradhass két munkamenet között." + REMEMBER_ME_STOLEN_COOKIE: "Valaki a belépési adataid felhasználásával látogatta meg ezt az oldalt! Minden munkamenetet kiléptettünk. Kérlek, jelentkezz be ismét és ellenőrizd az adataidat." + BUILTIN_CSS: "Beépített CSS használata" + BUILTIN_CSS_HELP: "Az admin plugin által biztosított CSS beillesztése" + ROUTE: "Belépés útvonala" + ROUTE_HELP: "Egyedi útvonal egy egyedi belépő oldalhoz, melyet az aktuális téma biztosít" + ROUTE_REGISTER: "Regisztráció útvonala" + ROUTE_REGISTER_HELP: "A regisztrációs oldal elérési útja. Akkor állítsd be, ha a beépített regisztrációs oldalt szeretnéd használni" + USERNAME_NOT_VALID: "A felhasználónév 3-16 karakter hosszú legyen, tartalmazhat kisbetűket, számokat, aláhúzást és kötőjelet. Nagybetűk, szóköz és speciális karakterek használata nem megengedett" + USERNAME_NOT_AVAILABLE: "%s nevű felhasználó már létezik, kérlek válassz más felhasználónevet" + PASSWORD_NOT_VALID: "A jelszónak tartalmaznia kell legalább egy számot, egy kisbetűt és egy nagybetűt, valamint legalább 8 karakter hosszú kell, hogy legyen" + PASSWORDS_DO_NOT_MATCH: "A két jelszó nem egyezik meg. Győzödj meg róla, hogy azonos legyen a kettő" diff --git a/user/plugins/login/languages/no.yaml b/user/plugins/login/languages/no.yaml new file mode 100644 index 00000000..a885ef19 --- /dev/null +++ b/user/plugins/login/languages/no.yaml @@ -0,0 +1,62 @@ +PLUGIN_LOGIN: + USERNAME: "Brukernavn" + EMAIL: "E-post" + USERNAME_EMAIL: "Brukernavn/E-post" + PASSWORD: "Passord" + ACCESS_DENIED: "Adgang forbudt..." + LOGIN_FAILED: "Innlogging feilet..." + LOGIN_SUCCESSFUL: "Du har logget inn." + BTN_LOGIN: "Logg inn" + BTN_LOGOUT: "Logg ut" + BTN_FORGOT: "Glemt passord" + BTN_REGISTER: "Registrer" + BTN_RESET: "Tilbakestill Passord" + BTN_SEND_INSTRUCTIONS: "Send instruksjoner for tilbakestilling" + RESET_LINK_EXPIRED: "Tilbakestillingslenke har utløpt, vennligst prøv igjen" + RESET_PASSWORD_RESET: "Passord har blitt nullstilt" + RESET_INVALID_LINK: "Ugyldig ilbakestillingslenke, vennligst prøv igjen" + FORGOT_INSTRUCTIONS_SENT_VIA_EMAIL: "Instruksjoner for å tilbakestille passordet ditt er sendt via e-post" + FORGOT_FAILED_TO_EMAIL: "Kunne ikke sende instruksjoner, prøv igjen senere" + FORGOT_CANNOT_RESET_EMAIL_NO_EMAIL: "Kan ikke tilbakestille passord for %s, ingen e-postadresse er angitt" + FORGOT_USERNAME_DOES_NOT_EXIST: "Bruker med brukernavn %s eksisterer ikke" + FORGOT_EMAIL_NOT_CONFIGURED: "Kan ikke tilbakestille passord. Dette nettstedet er ikke konfigurert til å sende e-post" + FORGOT_EMAIL_SUBJECT: "Forespørsel om tilbakestilling av passord for %s" + FORGOT_EMAIL_BODY: "

                                                            Tilbekestilling av passord

                                                            %1$s,

                                                            En forespørsel om tilbakestilling av passord ble gjort på %4$s.


                                                            Klikk her for å tilbakestille passordet ditt

                                                            Du kan også kopiere følgende nettadresse til nettleserens adressefelt:

                                                            %2$s


                                                            Vennlig hilsen,

                                                            %3$s

                                                            " + SESSION: "“Husk meg”-Sesjon" + REMEMBER_ME: "Husk meg" + REMEMBER_ME_HELP: "Setter en informasjonskapsel i nettleseren din for å tillate persistent innlogging." + REMEMBER_ME_STOLEN_COOKIE: "Din innloggingsinformasjon har blitt benyttet et annet sted. Alle sesjoner har blitt logget ut. Vennligst logg inn med brukernavn og passord, og sjekk din brukerinformasjon." + BUILTIN_CSS: "Bruk innebygget stil" + BUILTIN_CSS_HELP: "Bruk stil fra admin-plugin" + ROUTE: "Adresse til innlogging" + ROUTE_HELP: "Adresse til innlogging" + USERNAME_NOT_VALID: "Brukernavn skal være fra 3 til 16 tegn, og kan bestå av små bokstaver, tall, understrek, and bindestrek. Store bokstaver, mellomrom og spesialtegn er ikke tillatt" + USERNAME_NOT_AVAILABLE: "Brukernavnet %s er allerede i bruk, vennligst velg et annet brukernavn" + EMAIL_NOT_AVAILABLE: "E-postadressen %s er i bruk, vennligst velg en annen e-postadresse" + PASSWORD_NOT_VALID: "Passord må inneholde minst ett tall, en listen og en stor bokstav, og må være minst 8 tegn" + PASSWORDS_DO_NOT_MATCH: "Passwordene er ikke like. Sjekk at du skrev inn samme passord to ganger" + USER_NEEDS_EMAIL_FIELD: "Brukeren trenger felt for e-post" + WELCOME_EMAIL_SUBJECT: "Velkommen til %s" + ADDITIONAL_PARAM_VALUE: "Verdi" + REGISTRATION_FIELD_KEY: "Feltnavn" + REDIRECT_AFTER_LOGIN: "Gå til side etter innlogging" + REDIRECT_AFTER_LOGIN_HELP: "Gå til side etter innlogging" + OPTIONS: "Valg" + EMAIL_VALIDATION_MESSAGE: "Må være en gyldig e-postadresse" + PASSWORD_VALIDATION_MESSAGE: "Passordet må bestå av minst ett tall, både store og små bokstaver, og minst 8 tegn" + WELCOME: "Velkommen" + SECURITY_TAB: "Sikkerhet" + MAX_RESETS_COUNT: "Maksimum antall tilbakestilling av passord" + MAX_RESETS_INTERVAL: "Minimum tid mellom tilbakestilling av passord" + MAX_RESETS_INTERVAL_HELP: "Minimum tid mellom hvert forsøk på tilbakestilling av passord" + MAX_LOGINS_COUNT: "Maksimum antall innlogginger" + MAX_LOGINS_INTERVAL: "Maksimum innloggingsinterval" + MAX_LOGINS_INTERVAL_HELP: "Tidsintervall for telling av innlogginsforsøk" + TOO_MANY_LOGIN_ATTEMPTS: "For mange innloggingsforsøk i løpet av %s minutter" + SECONDS: "sekunder" + RESETS: "nullstillinger" + ATTEMPTS: "forsøk" + ROUTE_FORGOT: "Adresse for ”Glemt passord”" + ROUTE_RESET: "Adresse for tilbakestilling av passord" + ROUTE_PROFILE: "Adresse til brukerprofil" + PAGE_RESTRICTED: "Begrenset tilgang, vennligst logg inn..." diff --git a/user/plugins/login/languages/ro.yaml b/user/plugins/login/languages/ro.yaml new file mode 100644 index 00000000..307e5905 --- /dev/null +++ b/user/plugins/login/languages/ro.yaml @@ -0,0 +1,86 @@ +PLUGIN_LOGIN: + USERNAME: "Nume utilizator" + PASSWORD: "Parolă" + ACCESS_DENIED: "Acces refuzat..." + LOGIN_FAILED: "Logare eșuată..." + LOGIN_SUCCESSFUL: "Ați fost logat cu succes." + BTN_LOGIN: "Logare" + BTN_LOGOUT: "Ieșire din cont " + BTN_FORGOT: "Am uitat" + BTN_REGISTER: "Înregistrare" + BTN_RESET: "Resetează parola" + BTN_SEND_INSTRUCTIONS: "Trimite instrucțiuni pentru resetare" + RESET_LINK_EXPIRED: "Link-ul pentru resetarea parolei a expirat, vă rugăm încercați din nou " + RESET_PASSWORD_RESET: "Parola a fost modificată" + RESET_INVALID_LINK: "Link-ul pentru resetare este invalid, Invalid reset link used, vă rugăm încercați din nou " + FORGOT_INSTRUCTIONS_SENT_VIA_EMAIL: "Instrucțiunile pentru resetarea parolei au fst trimise pe email" + FORGOT_FAILED_TO_EMAIL: "Instrucțiunile nu au putut fi trimise pe email, vă rugăm încercați mai târziu " + FORGOT_CANNOT_RESET_EMAIL_NO_EMAIL: "Parola nu poate fi resetată pentru %s, nu este setată nici o adresă de email" + FORGOT_USERNAME_DOES_NOT_EXIST: "Utilizatorul cu numele %s nu există" + FORGOT_EMAIL_NOT_CONFIGURED: "Parola nu poate fi resetată. Acest site nu este configurat pentru a trimite email-uri." + FORGOT_EMAIL_SUBJECT: "%s Cerere de resetare a parolei" + FORGOT_EMAIL_BODY: "

                                                            Resetare parolă

                                                            Dragă %1$s,

                                                            O cerere de resetare a parolei a fost făcută în data de %4$s.


                                                            Apasă aici pentru a reseta parola

                                                            Alternativ, copiază URL de mai jos în bara de adrese a browser-ului favorit:

                                                            %2$s


                                                            Cu respect,

                                                            %3$s

                                                            " + SESSION: "“Ține-mă minte”-Sesiune" + REMEMBER_ME: "Ține-mă minte" + REMEMBER_ME_HELP: "Setează o cookie în browserul Dvs. ce permite menținerea datelor de logare între sesiuni." + REMEMBER_ME_STOLEN_COOKIE: "Altcineva a folosit darele Dvs de logare pentru a accesa această pagină! Toate sesiunile au fost deconectate. Vă rugăm să vă logați cu datele Dvs. și să verificați toate detaliile. " + BUILTIN_CSS: "Folosește CSS-ul din modul" + BUILTIN_CSS_HELP: "Include CSS-ul furnizat de către modulul Admin" + ROUTE: "Calea pentru logare" + ROUTE_HELP: "O rută personalizată către pagina de logare pe care o furnizează tema activă " + ROUTE_REGISTER: "Calea pentru înregistrare " + ROUTE_REGISTER_HELP: "Ruta către pagina de înregistrare. Setați această rută dacă doriți folosirea paginei implicite pentru înregistrare. Lăsați gol dacă folosiți o pagină personalizată pentru înregistrare." + USERNAME_NOT_VALID: "Numele de utilizator trebuie să fie între 3-16 caractere, incluzând litere mici, numere, linii de subliniere și cratime. Literele de tipar, spațiile și caracterele speciale nu sunt permise. " + USERNAME_NOT_AVAILABLE: "Utilizatorul %s există deja, vă rugăm alegeți un alt nume de utilizator " + PASSWORD_NOT_VALID: " Parola trebuie să conțină cel puțin 1 număr și o literă de tipar și o literă mică; și să aibă minim 8 caractere" + PASSWORDS_DO_NOT_MATCH: " Parolele nu sunt identice. Vă rugăm verificați că ași scris aceeiași parolă de două ori." + USER_NEEDS_EMAIL_FIELD: "Utilizatorul trebuie să aibă adresa de email completată" + EMAIL_SENDING_FAILURE: "A apărut o eroare la trimirea email-ului" + ACTIVATION_EMAIL_SUBJECT: "Activați-vă contrul pentru %s" + ACTIVATION_EMAIL_BODY: "Salut %s, apasă aici pentru a-ți activa contul de pe %s" + WELCOME_EMAIL_SUBJECT: "Bine ați venit pe %s" + WELCOME_EMAIL_BODY: "Salut %s, bine ai venit la %s!" + NOTIFICATION_EMAIL_SUBJECT: "Utilizator nou pe %s" + NOTIFICATION_EMAIL_BODY: "Salut, un nou utilizator s-a înregistrat pe %s. Nume de utilizator: %s, adresă de email: %s" + ACTIVATION_LINK_EXPIRED: "Link-ul pentru activare este expirat" + USER_ACTIVATED_SUCCESSFULLY: "Utilizator activat cu succes" + INVALID_REQUEST: "Cerere invalidă " + USER_REGISTRATION: "Înregistrare utilizator " + USER_REGISTRATION_ENABLED_HELP: "Activați înregistrarea utilizatorilor" + VALIDATE_PASSWORD1_AND_PASSWORD2: "Validați parola introdusă de două ori" + VALIDATE_PASSWORD1_AND_PASSWORD2_HELP: "Validați și comparați cele două câmpuri pentru parolă cu numele `password1` și `password2`. Activați această opțiune dacă există două câmpuri pentru parolă în formularul de înregistrare." + SET_USER_DISABLED: "Setați utilizatorul dezactivat" + SET_USER_DISABLED_HELP: "Cel mai bine să fie folosit împreună cu email-ul pentru activare. Adaugă utilizatorul în Grav dar îl setează ca dezactivat" + LOGIN_AFTER_REGISTRATION: "Loghează utilizatorul după înregistrare" + LOGIN_AFTER_REGISTRATION_HELP: "Imediat după înregistrare loghează utilizatorul în cont. Dacă este necesară activarea prin email, utilizatorul va fi logat imediat după activarea contului." + SEND_ACTIVATION_EMAIL: "Trimite email-ul pentru activare" + SEND_ACTIVATION_EMAIL_HELP: "Trimite un email către utilizatorul nou înregistrat pentru activarea contului. Activați opțiunea `Setați utilizatorul dezactivat` când folosiți această opțiune pentru a seta utilizatorul dezactivat și pentru a trimite un email automat pentru activarea contului. " + SEND_NOTIFICATION_EMAIL: "Trimite email cu notificare" + SEND_NOTIFICATION_EMAIL_HELP: "Notifică adminstratorul site-ului când un utilizator nou s-a înregistrat. Email-ul va di trimis către adresa `Către` din configurarea modului de Email" + SEND_WELCOME_EMAIL: "Trimite email de bun venit" + SEND_WELCOME_EMAIL_HELP: "Trimite un email către utilizatorul nou înregistrat." + DEFAULT_VALUES: " Valori implicite" + DEFAULT_VALUES_HELP: "Listă de câmpuri și valorile asociate acestora ce vor fi adăugate profilului utilizatorului (în fișierul yaml) în mod implicit fără a putea fi configurabile de către utilizator. Separați valorile multiple cu virgulă, fără spații între valori." + ADDITIONAL_PARAM_KEY: "Parametru" + ADDITIONAL_PARAM_VALUE: "Valoare" + REGISTRATION_FIELDS: "Câmpuri pentru înregistrare" + REGISTRATION_FIELDS_HELP: "Adaugă câmpurile ce vor fi adăugate fișierului yaml al utilizatorului. Câmpurile care nu sunt listate aici nu vor fi adăugate chiar dacă sunt prezente în formularul de înregistrare." + REGISTRATION_FIELD_KEY: " Numele câmpului" + REDIRECT_AFTER_LOGIN: "Redirecționează după logare" + REDIRECT_AFTER_LOGIN_HELP: "Ruta personalizată pentru redirecționare după logare" + REDIRECT_AFTER_REGISTRATION: "Redirecționează după înregistrare" + REDIRECT_AFTER_REGISTRATION_HELP: "Ruta personalizată pentru redirecționare după înregistrare" + OPTIONS: "Opțiuni" + EMAIL_VALIDATION_MESSAGE: "Trebuie să fie o adresă de email validă" + PASSWORD_VALIDATION_MESSAGE: "Parola trebuie să conțină cel puțin un număr și o literă de tipar și să aibă cel puțin 8 caractere" + TIMEOUT_HELP: "Setează pauza pentru sesiune când este activat 'Ține-mă minte' de către utilizator. Minimul este de 604800 care înseamnă 1 săptămână." + GROUPS_HELP: "Lista grupurilor din care utilizatorii nou înregistrați vor face parte, dacă este necesar" + SITE_ACCESS_HELP: "Lista cu niveluri de acces la care utilizatorul nou înregistrat are acces. De eg: `login` -> `true` " + WELCOME: "Bine ați venit" + REDIRECT_AFTER_ACTIVATION: "Redirecționează după activarea utilizatorului" + REDIRECT_AFTER_ACTIVATION_HELP: "Folosită dacă utilizatorul trebuie să-și activeze contul prin email. Odată activat contul va fi folosită această rută." + REGISTRATION_DISABLED: " Dezactivează înregistrarea " + USE_PARENT_ACL_LABEL: "Folosește regulile de acces ale părintelui" + USE_PARENT_ACL_HELP: "Verifică regulie de acces ale părintelui dacă nu sunt specificate alte reguli de acces" + PROTECT_PROTECTED_PAGE_MEDIA_LABEL: " Protejează media ce aparține paginii de logare " + PROTECT_PROTECTED_PAGE_MEDIA_HELP: "Dacă este activată, media ce aparține unei pagini de logare este protejată și nu poate fi accesată decât după logare." \ No newline at end of file diff --git a/user/plugins/login/languages/ru.yaml b/user/plugins/login/languages/ru.yaml new file mode 100644 index 00000000..9e35ee2b --- /dev/null +++ b/user/plugins/login/languages/ru.yaml @@ -0,0 +1,134 @@ +PLUGIN_LOGIN: + USERNAME: "Логин" + EMAIL: "Email" + USERNAME_EMAIL: "Логин/Email" + PASSWORD: "Пароль" + ACCESS_DENIED: "Доступ закрыт..." + LOGIN_FAILED: "Ошибка входа..." + LOGIN_SUCCESSFUL: "Вы успешно вошли в систему." + BTN_LOGIN: "Войти" + BTN_LOGOUT: "Выйти" + BTN_FORGOT: "Забыл" + BTN_REGISTER: "Регистрация" + BTN_RESET: "Сброс пароля" + BTN_SEND_INSTRUCTIONS: "Отправить инструкции по сбросу" + RESET_LINK_EXPIRED: "Время ссылки для сброса истекло, повторите попытку" + RESET_PASSWORD_RESET: "Пароль был сброшен" + RESET_INVALID_LINK: "Неверная ссылка сброса, повторите попытку" + FORGOT_INSTRUCTIONS_SENT_VIA_EMAIL: "Инструкции по сбросу пароля были отправлены по электронной почте" + FORGOT_FAILED_TO_EMAIL: "Не удалось отправить инструкции по электронной почте, повторите попытку позже" + FORGOT_CANNOT_RESET_EMAIL_NO_EMAIL: "Не удается сбросить пароль для %s, адресс электронной почты не установлен" + FORGOT_CANNOT_RESET_EMAIL_NO_PASSWORD: "Невозможно сбросить пароль для %s, этот email связан с удаленной учетной записью" + FORGOT_USERNAME_DOES_NOT_EXIST: "Пользователь с именем %s не существует" + FORGOT_EMAIL_NOT_CONFIGURED: "Невозможно сбросить пароль. Этот сайт не настроен для отправки писем" + FORGOT_EMAIL_SUBJECT: "%s Запрос на сброс пароля" + FORGOT_EMAIL_BODY: "

                                                            Восстановление пароля

                                                            Уважаемый %1$s,

                                                            Был сделан запрос для сброса пароля от %4$s.


                                                            Нажмите, чтобы сбросить пароль

                                                            Или скопируйте следующий URL-адрес в адресную строку браузера:

                                                            %2$s


                                                            С уважением,

                                                            %3$s

                                                            " + SESSION: "“Запомнить меня”-Сессия" + REMEMBER_ME: "Запомнить меня" + REMEMBER_ME_HELP: "Устанавливает постоянный файл cookie в вашем браузере, чтобы разрешить постоянную аутентификацию входа между сеансами." + REMEMBER_ME_STOLEN_COOKIE: "Кто-то еще использовал вашу регистрационную информацию для доступа к этой странице! Все сеансы были отключены. Войдите в свою учетную запись и проверьте свои данные." + BUILTIN_CSS: "Использовать встроенный CSS" + BUILTIN_CSS_HELP: "Использовать CSS, предоставленный плагином администратора." + ROUTE: "Путь страницы входа" + ROUTE_HELP: "Путь к пользовательской странице входа, которую предоставляет ваша тема" + ROUTE_REGISTER: "Путь регистрации" + ROUTE_REGISTER_HELP: "Путь к пользовательской странице регистрации. Заполните, если вы хотите использовать встроенную страницу регистрации. Оставьте его пустым, если у вас есть собственная регистрационная форма" + USERNAME_NOT_VALID: "Имя пользователя должно быть от 3 до 16 символов, включая строчные буквы, цифры, символы подчеркивания и дефисы. Прописные буквы, пробелы и специальные символы не допускаются" + USERNAME_NOT_AVAILABLE: "Имя пользователя %s уже существует, выберите другое имя пользователя" + EMAIL_NOT_AVAILABLE: "Адрес электронной почты %s уже существует, выберите другой адрес электронной почты" + PASSWORD_NOT_VALID: "Пароль должен содержать как минимум одно число, одну прописную и строчную букву, и быть не менее 8 символов" + PASSWORDS_DO_NOT_MATCH: "Пароли не совпадают. Дважды проверьте, что вы дважды ввели тот же пароль" + USER_NEEDS_EMAIL_FIELD: "Пользователю требуется поле электронной почты" + EMAIL_SENDING_FAILURE: "Произошла ошибка при отправке письма" + ACTIVATION_EMAIL_SUBJECT: "Активируйте свою учетную запись %s" + ACTIVATION_EMAIL_BODY: "Привет %s, перейдите сюда для активации вашей учетной записи %s" + ACTIVATION_NOTICE_MSG: "Привет %s, ваша учетная запись создана, пожалуйста проверьте электронную почту, чтобы полностью ее активировать" + WELCOME_EMAIL_SUBJECT: "Добро пожаловать в %s" + WELCOME_EMAIL_BODY: "Привет %s, добро пожаловать в %s!" + WELCOME_NOTICE_MSG: "Привет %s, ваша учетная запись была успешно создана" + NOTIFICATION_EMAIL_SUBJECT: "Новый пользователь %s" + NOTIFICATION_EMAIL_BODY: "Привет, новый пользователь, зарегистрированный на %s. Имя пользователя: %s, email: %s" + EMAIL_FOOTER: "GetGrav.org" + ACTIVATION_LINK_EXPIRED: "Время ссылки для активации истекло" + USER_ACTIVATED_SUCCESSFULLY: "Пользователь успешно активирован" + USER_ACTIVATED_SUCCESSFULLY_NOT_ENABLED: "Аккаунт пользователя активирован, но учетная запись просматривается" + INVALID_REQUEST: "Неверный запрос" + USER_REGISTRATION: "Регистрация пользователя" + USER_REGISTRATION_ENABLED_HELP: "Включить регистрацию пользователя" + VALIDATE_PASSWORD1_AND_PASSWORD2: "Двойная проверка введенного пароля" + VALIDATE_PASSWORD1_AND_PASSWORD2_HELP: "Подтвердить и сравнить два разных поля для паролей с именами `password1` и` password2`. Включите это, если у вас есть два поля пароля в регистрационной форме" + SET_USER_DISABLED: "Установить пользователя как отключенный" + SET_USER_DISABLED_HELP: "Лучше всего использовать электронную почту «Отправить электронную почту активации». Добавляет пользователя в Grav, но устанавливает его как отключенный" + LOGIN_AFTER_REGISTRATION: "Вход в систему после регистрации" + LOGIN_AFTER_REGISTRATION_HELP: "Автоматический вход в систему после регистрации. Если требуется активация электронной почты, пользователь будет входить в систему сразу после активации учетной записи" + SEND_ACTIVATION_EMAIL: "Отправить письмо активации" + SEND_ACTIVATION_EMAIL_HELP: "Отправляет электронное письмо пользователю для активации своей учетной записи. Включите параметр «Установить пользователя как отключенный» при использовании этой функции, чтобы пользователь был отключен, и для активации учетной записи будет отправлено электронное письмо" + SEND_NOTIFICATION_EMAIL: "Отправить уведомление по электронной почте" + SEND_NOTIFICATION_EMAIL_HELP: "Сообщает администратору сайта о регистрации нового пользователя. Электронная почта будет отправлена в поле «Кому» в конфигурации плагина электронной почты" + SEND_WELCOME_EMAIL: "Отправить приветственное письмо" + SEND_WELCOME_EMAIL_HELP: "Отправляет электронное письмо вновь зарегистрированному пользователю" + DEFAULT_VALUES: "Значения по умолчанию" + DEFAULT_VALUES_HELP: "Список названий полей и связанных значений, которые будут добавлены в профиль пользователя (файл yaml) по умолчанию, без настройки пользователем. Разделите несколько значений запятой, без пробелов между значениями" + ADDITIONAL_PARAM_KEY: "Параметр" + ADDITIONAL_PARAM_VALUE: "Значение" + REGISTRATION_FIELDS: "Регистрационные поля" + REGISTRATION_FIELDS_HELP: "Добавьте поля, которые будут добавлены в файл yaml пользователя. Поля, не перечисленные здесь, не будут добавлены, даже если они присутствуют в регистрационной форме" + REGISTRATION_FIELD_KEY: "Имя поля" + REDIRECT_AFTER_LOGIN: "Перенаправление после входа в систему" + REDIRECT_AFTER_LOGIN_HELP: "Пользовательский маршрут для перенаправления после входа в систему" + REDIRECT_AFTER_LOGOUT: "Перенаправление после выхода из системы" + REDIRECT_AFTER_LOGOUT_HELP: "Пользовательский маршрут для перенаправления после выхода из системы" + REDIRECT_AFTER_REGISTRATION: "Перенаправление после регистрации" + REDIRECT_AFTER_REGISTRATION_HELP: "Пользовательский маршрут для перенаправления после регистрации" + OPTIONS: "Опции" + EMAIL_VALIDATION_MESSAGE: "Адрес эл. почты должен быть действительным" + PASSWORD_VALIDATION_MESSAGE: "Пароль должен содержать как минимум одно число, одну прописную и строчную букву и быть не менее 8 символов" + TIMEOUT_HELP: "Устанавливает тайм-аут сеанса в секундах, когда функция «Запомнить меня» включена и установлена пользователем. Минимум 604800, что означает 1 неделю" + GROUPS_HELP: "Список групп, в которые войдет новый зарегистрированный пользователь" + SITE_ACCESS_HELP: "Список уровней доступа к сайту, зарегистрированных пользователей. Пример: `login` ->` true`" + WELCOME: "Добро пожаловать" + REDIRECT_AFTER_ACTIVATION: "Перенаправление после активации пользователя" + REDIRECT_AFTER_ACTIVATION_HELP: "Используется, если пользователю требуется активировать учетную запись по электронной почте. После активации этот маршрут будет показан" + REGISTRATION_DISABLED: "Регистрация отключена" + USE_PARENT_ACL_LABEL: "Использовать родительские правила доступа" + USE_PARENT_ACL_HELP: "Проверьте правила доступа к родителям, если правила не определены" + PROTECT_PROTECTED_PAGE_MEDIA_LABEL: "Защита защищенных страниц." + PROTECT_PROTECTED_PAGE_MEDIA_HELP: "Если этот параметр включен, то доступ к защищенной странице для входа в систему также защищен паролем, и его нельзя увидеть, если он не зарегистрирован" + SECURITY_TAB: "Безопасность" + MAX_RESETS_COUNT: "Максимальное количество сброса пароля" + MAX_RESETS_COUNT_HELP: "Настройка защиты пароля от флуда (0 - не ограничено)" + MAX_RESETS_INTERVAL: "Максимальный интервал сброса пароля" + MAX_RESETS_INTERVAL_HELP: "Интервал времени для максимального количества сбросов пароля" + FORGOT_CANNOT_RESET_IT_IS_BLOCKED: "Невозможно сбросить пароль для %s, функция сброса пароля временно отключена, попробуйте позже (максимум %s минут)" + MAX_LOGINS_COUNT: "Максимальное количество входов" + MAX_LOGINS_COUNT_HELP: "Настройка защиты от флуда (0 - не ограничено)" + MAX_LOGINS_INTERVAL: "Максимальный интервал входа" + MAX_LOGINS_INTERVAL_HELP: "Временной интервал для значения счетчика входа" + TOO_MANY_LOGIN_ATTEMPTS: "Слишком много неудачных попыток входа в настроенное время (%s минут)" + SECONDS: "секунд" + MINUTES: "минут" + RESETS: "сбросов" + ATTEMPTS: "попыток" + ROUTES: "Маршруты" + ROUTE_FORGOT: "Забыли пароль" + ROUTE_RESET: "Сброса пароля" + ROUTE_PROFILE: "Профиля пользователя" + ROUTE_ACTIVATE: "Активации пользователя" + LOGGED_OUT: "Вы успешно вышли из системы..." + PAGE_RESTRICTED: "Доступ ограничен, войдите в систему..." + DYNAMIC_VISIBILITY: "Динамическая видимость страницы" + DYNAMIC_VISIBILITY_HELP: "Позволяет динамически обрабатывать видимость страницы на основе правил доступа, если для параметра login.visibility_requires_access установлено значение true на странице" + USER_IS_REMOTE_ONLY: "Этот пользователь аутентифицирован с помощью удаленного сервиса, поэтому профиль не может быть сохранен" + 2FA_TITLE: "2-факторная аутентификация" + 2FA_INSTRUCTIONS: "##### 2-факторная аутентификация\nВ вашем аккаунте включена **2FA**. Пожалуйста, используйте свое **2FA** приложение для ввода текущего **6-значного кода** для завершения процесса входа в систему." + 2FA_REGEN_HINT: "Чтобы восстановить секрет, вам потребуется обновить приложение для аутентификации" + 2FA_FAILED: "Недопустимый код проверки подлинности 2-факторной аутентификации, повторите попытку...." + 2FA_ENABLED: "2FA Включена" + 2FA_ENABLED_HELP: "Включает двухфакторную аутентификацию для всех пользователей" + 2FA_CODE_INPUT: "000000" + 2FA_SECRET: "2FA Секрет" + 2FA_SECRET_HELP: "Сканируйте этот QR-код в свое [Приложение аутентификации](https://learn.getgrav.org/admin-panel/2fa#apps). Также рекомендуется сохранить секрет в безопасном месте, если вам прийдется переустановить приложение. Проверьте [Grav docs](https://learn.getgrav.org/admin-panel/2fa) для дополнительной информации " + 2FA_REGENERATE: "Сгенерировать повторно" + BTN_CANCEL: "Отмена" + MANUALLY_ENABLE: "Вручную включить" + MANUALLY_ENABLE_HELP: "При использовании «активации по электронной почте» и «уведомление по электронной почте» вы можете убедиться, что пользователь может самостоятельно активироваться, но пользователь требует ручного включения для входа в систему" diff --git a/user/plugins/login/languages/uk.yaml b/user/plugins/login/languages/uk.yaml new file mode 100644 index 00000000..67a6bdda --- /dev/null +++ b/user/plugins/login/languages/uk.yaml @@ -0,0 +1,134 @@ +PLUGIN_LOGIN: + USERNAME: "Логін" + EMAIL: "Email" + USERNAME_EMAIL: "Логін/Email" + PASSWORD: "Пароль" + ACCESS_DENIED: "Доступ заборонено..." + LOGIN_FAILED: "Помилка входу..." + LOGIN_SUCCESSFUL: "Ви успішно увійшли в систему." + BTN_LOGIN: "Увійти" + BTN_LOGOUT: "Вийти" + BTN_FORGOT: "Забув" + BTN_REGISTER: "Реєстрація" + BTN_RESET: "Скидання пароля" + BTN_SEND_INSTRUCTIONS: "Надіслати інструкції по скиданню" + RESET_LINK_EXPIRED: "Час посилання для скидання минув, спробуйте ще раз" + RESET_PASSWORD_RESET: "Пароль був скинутий" + RESET_INVALID_LINK: "Невірне посилання скидання, спробуйте ще раз" + FORGOT_INSTRUCTIONS_SENT_VIA_EMAIL: "Інструкції щодо скидання пароля були надіслані по електронній пошті" + FORGOT_FAILED_TO_EMAIL: "Не вдалося надіслати інструкції електронною поштою, повторіть спробу пізніше" + FORGOT_CANNOT_RESET_EMAIL_NO_EMAIL: "Не вдається скинути пароль для %s, адреса електронної пошти не встановлена" + FORGOT_CANNOT_RESET_EMAIL_NO_PASSWORD: "Неможливо скинути пароль для %s, цей email пов'язаний з віддаленим обліковим записом" + FORGOT_USERNAME_DOES_NOT_EXIST: "Користувач з ім'ям %s не існує" + FORGOT_EMAIL_NOT_CONFIGURED: "Неможливо скинути пароль. Цей сайт не налаштований для надіслання листів" + FORGOT_EMAIL_SUBJECT: "%s Запит на скидання пароля" + FORGOT_EMAIL_BODY: "

                                                            Відновлення паролю

                                                            Шановний %1$s,

                                                            Був зроблений запит для скидання пароля від %4$s.


                                                            Нажмите, чтобы сбросить пароль

                                                            Или скопируйте следующий URL-адрес в адресную строку браузера:

                                                            %2$s


                                                            С уважением,

                                                            %3$s

                                                            " + SESSION: "“Запам'ятати мене”-Сесія" + REMEMBER_ME: "Запам'ятати мене" + REMEMBER_ME_HELP: "Встановлює постійний файл cookie у вашому браузері, щоб дозволити постійну аутентифікацію входу між сеансами." + REMEMBER_ME_STOLEN_COOKIE: "Хтось ще використовував вашу реєстраційну інформацію для доступу до цієї сторінки! Всі сеанси були відключені. Увійдіть до свого облікового запису та перевірте свої дані." + BUILTIN_CSS: "Використовувати вбудований CSS" + BUILTIN_CSS_HELP: "Використовувати CSS, наданий плагіном адміністратора." + ROUTE: "Шлях сторінки входу" + ROUTE_HELP: "Шлях до користувальницької сторінці входу, яку надає ваша тема" + ROUTE_REGISTER: "Шлях реєстрації" + ROUTE_REGISTER_HELP: "Шлях до користувальницької сторінці реєстрації. Заповніть, якщо ви хочете використовувати вбудовану сторінку реєстрації. Залиште його порожнім, якщо у вас є власна реєстраційна форма" + USERNAME_NOT_VALID: "Ім'я користувача має бути від 3 до 16 символів, включаючи малі літери, цифри, символи підкреслення та дефіси. Великі літери, пробіли та спеціальні символи не допускаються" + USERNAME_NOT_AVAILABLE: "Ім'я користувача %s вже існує, виберіть інше ім'я користувача" + EMAIL_NOT_AVAILABLE: "Адреса електронної пошти %s вже існує, виберіть іншу адресу електронної пошти" + PASSWORD_NOT_VALID: "Пароль повинен містити як мінімум одне число, одну прописну і малу літеру, і бути не менше 8 символів" + PASSWORDS_DO_NOT_MATCH: "Паролі не співпадають. Двічі перевірте, що ви двічі ввели той же пароль" + USER_NEEDS_EMAIL_FIELD: "Користувачеві потрібно поле електронної пошти" + EMAIL_SENDING_FAILURE: "Помилка під час надіслання листа" + ACTIVATION_EMAIL_SUBJECT: "Активуйте свій обліковий запис %s" + ACTIVATION_EMAIL_BODY: "Привіт %s, перейдіть сюди для активації вашого облікового запису %s" + ACTIVATION_NOTICE_MSG: "Привіт %s, ваш обліковий запис створено, будь ласка перевірте електронну пошту, щоб повністю його активувати" + WELCOME_EMAIL_SUBJECT: "Ласкаво просимо в %s" + WELCOME_EMAIL_BODY: "Привіт %s, ласкаво просимо в %s!" + WELCOME_NOTICE_MSG: "Привіт %s, ваш обліковий запис був успішно створений" + NOTIFICATION_EMAIL_SUBJECT: "Новий користувач %s" + NOTIFICATION_EMAIL_BODY: "Привіт, новий користувач, зареєстрований на %s. Ім'я користувача: %s, email: %s" + EMAIL_FOOTER: "GetGrav.org" + ACTIVATION_LINK_EXPIRED: "Час посилання для активації минув" + USER_ACTIVATED_SUCCESSFULLY: "Користувач успішно активований" + USER_ACTIVATED_SUCCESSFULLY_NOT_ENABLED: "Аккаунт користувача активований, але обліковий запис проглядається" + INVALID_REQUEST: "Невірний запит" + USER_REGISTRATION: "Реєстрація користувача" + USER_REGISTRATION_ENABLED_HELP: "Включити реєстрацію користувача" + VALIDATE_PASSWORD1_AND_PASSWORD2: "Подвійна перевірка введеного пароля" + VALIDATE_PASSWORD1_AND_PASSWORD2_HELP: "Підтвердити і порівняти два різних поля для паролів з іменами `password1` і` password2`. Увімкніть це, якщо у вас є два поля пароля в реєстраційній формі" + SET_USER_DISABLED: "Встановити користувача як відключений" + SET_USER_DISABLED_HELP: "Найкраще використовувати електронну пошту «Надіслати електронну пошту активації». Додає користувача в Grav, але встановлює його як відключений" + LOGIN_AFTER_REGISTRATION: "Вхід в систему після реєстрації" + LOGIN_AFTER_REGISTRATION_HELP: "Автоматичний вхід в систему після реєстрації. Якщо потрібна активація електронної пошти, користувач буде входити в систему відразу після активації облікового запису" + SEND_ACTIVATION_EMAIL: "Надіслати лист активації" + SEND_ACTIVATION_EMAIL_HELP: "Надіслати електронного листа користувачу для активації облікового запису. Увімкніть параметр «Встановити користувача як відключений» при використанні цієї функції, щоб користувач був відключений, і для активації облікового запису буде надіслано повідомлення електронної пошти" + SEND_NOTIFICATION_EMAIL: "Надіслати повідомлення по електронній пошті" + SEND_NOTIFICATION_EMAIL_HELP: "Повідомляє адміністратору сайту про реєстрацію нового користувача. Електронна пошта буде відправлена в поле «Кому» в конфігурації плагіна електронної пошти" + SEND_WELCOME_EMAIL: "Надіслати вітальний лист" + SEND_WELCOME_EMAIL_HELP: "Надсилає електронного листа знову зареєстрованому користувачу" + DEFAULT_VALUES: "Значення за замовчуванням" + DEFAULT_VALUES_HELP: "Список назв полів і пов'язаних значень, які будуть додані в профіль користувача (файл yaml) за замовчуванням, без налаштування користувачем. Розділіть декілька значень комою, без пробілів між значеннями" + ADDITIONAL_PARAM_KEY: "Параметр" + ADDITIONAL_PARAM_VALUE: "Значення" + REGISTRATION_FIELDS: "Реєстраційні поля" + REGISTRATION_FIELDS_HELP: "Додайте поля, які будуть додані в файл yaml користувача. Поля, не перераховані тут, не будуть додані, навіть якщо вони присутні в реєстраційній формі" + REGISTRATION_FIELD_KEY: "Ім'я поля" + REDIRECT_AFTER_LOGIN: "Перенаправлення після входу в систему" + REDIRECT_AFTER_LOGIN_HELP: "Призначений для користувача маршрут для перенаправлення після входу в систему" + REDIRECT_AFTER_LOGOUT: "Перенаправлення після виходу з системи" + REDIRECT_AFTER_LOGOUT_HELP: "Призначений для користувача маршрут для перенаправлення після виходу з системи" + REDIRECT_AFTER_REGISTRATION: "Перенаправлення після реєстрації" + REDIRECT_AFTER_REGISTRATION_HELP: "Призначений для користувача маршрут для перенаправлення після реєстрації" + OPTIONS: "Опції" + EMAIL_VALIDATION_MESSAGE: "Адреса ел. пошти повинна бути дійсною" + PASSWORD_VALIDATION_MESSAGE: "Пароль повинен містити як мінімум одне число, одну прописну і малу літеру і бути не менше 8 символів" + TIMEOUT_HELP: "Встановлює тайм-аут сеансу в секундах, коли функція «Запам'ятати мене» включена і встановлена користувачем. Мінімум 604800, що означає 1 тиждень" + GROUPS_HELP: "Список груп, в які увійде новий зареєстрований користувач" + SITE_ACCESS_HELP: "Список рівнів доступу до сайту, зареєстрованих користувачів. Приклад: `login` ->` true`" + WELCOME: "Ласкаво просимо" + REDIRECT_AFTER_ACTIVATION: "Перенаправлення після активації користувача" + REDIRECT_AFTER_ACTIVATION_HELP: "Використовується, якщо користувачеві потрібно активувати обліковий запис по електронній пошті. Після активації цей маршрут буде показаний" + REGISTRATION_DISABLED: "Реєстрація відключена" + USE_PARENT_ACL_LABEL: "Використовувати батьківські правила доступу" + USE_PARENT_ACL_HELP: "Перевірте правила доступу до батьків, якщо правила не визначені" + PROTECT_PROTECTED_PAGE_MEDIA_LABEL: "Захист захищених сторінок." + PROTECT_PROTECTED_PAGE_MEDIA_HELP: "Якщо цей параметр включений, то доступ до захищеної сторінці для входу в систему також захищений паролем, і його не можна побачити, якщо він не зареєстрований" + SECURITY_TAB: "Безпека" + MAX_RESETS_COUNT: "Максимальна кількість скидання пароля" + MAX_RESETS_COUNT_HELP: "Налаштування захисту пароля від флуду (0 - не обмежена)" + MAX_RESETS_INTERVAL: "Максимальний інтервал скидання пароля" + MAX_RESETS_INTERVAL_HELP: "Інтервал часу для максимальної кількості скидання пароля" + FORGOT_CANNOT_RESET_IT_IS_BLOCKED: "Неможливо скинути пароль для %s, функція скидання пароля тимчасово відключена, спробуйте пізніше (максимум %s хвилин)" + MAX_LOGINS_COUNT: "Максимальна кількість входів" + MAX_LOGINS_COUNT_HELP: "Налаштування захисту від флуду (0 - не обмежена)" + MAX_LOGINS_INTERVAL: "Максимальний інтервал входу" + MAX_LOGINS_INTERVAL_HELP: "Часовий інтервал для значення лічильника входу" + TOO_MANY_LOGIN_ATTEMPTS: "Занадто багато невдалих спроб входу в налаштований час (%s хвилин)" + SECONDS: "секунд" + MINUTES: "хвилин" + RESETS: "скидань" + ATTEMPTS: "спроб" + ROUTES: "Маршрути" + ROUTE_FORGOT: "Забули пароль" + ROUTE_RESET: "Скидання пароля" + ROUTE_PROFILE: "Профілю користувача" + ROUTE_ACTIVATE: "Активації користувача" + LOGGED_OUT: "Ви успішно вийшли з системи..." + PAGE_RESTRICTED: "Доступ обмежений, увійдіть в систему..." + DYNAMIC_VISIBILITY: "Динамічна видимість сторінки" + DYNAMIC_VISIBILITY_HELP: "Дозволяє динамічно обробляти видимість сторінки на основі правил доступу, якщо для параметра login.visibility_requires_access встановлено значення true на сторінці" + USER_IS_REMOTE_ONLY: "Цей користувач аутентифікований за допомогою віддаленого сервісу, тому профіль не може бути збережений" + 2FA_TITLE: "2-факторна аутентифікація" + 2FA_INSTRUCTIONS: "##### 2-факторна аутентифікація\nУ вашому обліковому запису включена **2FA**. Будь ласка, використовуйте свою **2FA** програму для введення цього **6-значного коду** для завершення процесу входу в систему." + 2FA_REGEN_HINT: "Щоб відновити секрет, вам буде потрібно оновити програму для аутентифікації" + 2FA_FAILED: "Неприпустимий код перевірки справжності 2-факторної аутентифікації, спробуйте ще раз...." + 2FA_ENABLED: "2FA Увімкнено" + 2FA_ENABLED_HELP: "Вмикає двухфакторную аутентифікацію для всіх користувачів" + 2FA_CODE_INPUT: "000000" + 2FA_SECRET: "2FA Секрет" + 2FA_SECRET_HELP: "Відскануйте цей QR-код у свою [Програму аутентифікації](https://learn.getgrav.org/admin-panel/2fa#apps). Також рекомендується зберегти секрет в безпечному місці, якщо вам доведеться перевстановити програму. Перевірте [Grav docs](https://learn.getgrav.org/admin-panel/2fa) для додаткової інформації " + 2FA_REGENERATE: "Згенерувати повторно" + BTN_CANCEL: "Скасування" + MANUALLY_ENABLE: "Вручну включити" + MANUALLY_ENABLE_HELP: "При використанні «активації по електронній пошті» і «повідомлення по електронній пошті» ви можете переконатися, що користувач може самостійно активуватися, але користувач вимагає ручного включення для входу в систему" diff --git a/user/plugins/login/login.php b/user/plugins/login/login.php new file mode 100644 index 00000000..69476707 --- /dev/null +++ b/user/plugins/login/login.php @@ -0,0 +1,1109 @@ + [['autoload', 100000], ['initializeSession', 10000], ['initializeLogin', 1000]], + 'onTask.login.login' => ['loginController', 0], + 'onTask.login.twofa' => ['loginController', 0], + 'onTask.login.forgot' => ['loginController', 0], + 'onTask.login.logout' => ['loginController', 0], + 'onTask.login.reset' => ['loginController', 0], + 'onTask.login.regenerate2FASecret' => ['loginController', 0], + 'onPagesInitialized' => [['storeReferrerPage', 0], ['pageVisibility', 0]], + 'onPageInitialized' => ['authorizePage', 0], + 'onPageFallBackUrl' => ['authorizeFallBackUrl', 0], + 'onTwigTemplatePaths' => ['onTwigTemplatePaths', 0], + 'onTwigSiteVariables' => ['onTwigSiteVariables', -100000], + 'onFormProcessed' => ['onFormProcessed', 0], + 'onUserLoginAuthenticate' => [['userLoginAuthenticateByRegistration', 10002], ['userLoginAuthenticateByRememberMe', 10001], ['userLoginAuthenticateByEmail', 10000], ['userLoginAuthenticate', 0]], + 'onUserLoginAuthorize' => ['userLoginAuthorize', 0], + 'onUserLoginFailure' => ['userLoginFailure', 0], + 'onUserLogin' => ['userLogin', 0], + 'onUserLogout' => ['userLogout', 0], + ]; + } + + /** + * [onPluginsInitialized:100000] Composer autoload. + * + * @return ClassLoader + */ + public function autoload() : ClassLoader + { + return require __DIR__ . '/vendor/autoload.php'; + } + + /** + * [onPluginsInitialized] Initialize login plugin if path matches. + * @throws \RuntimeException + */ + public function initializeSession() + { + // Check to ensure sessions are enabled. + if (!$this->config->get('system.session.enabled')) { + throw new \RuntimeException('The Login plugin requires "system.session" to be enabled'); + } + + // Define login service. + $this->grav['login'] = function (Grav $c) { + return new Login($c); + }; + + // Define current user service. + $this->grav['user'] = function (Grav $c) { + $session = $c['session']; + + if (empty($session->user)) { + $session->user = $c['login']->login(['username' => ''], ['remember_me' => true, 'remember_me_login' => true]); + } + + return $session->user; + }; + } + + /** + * [onPluginsInitialized] Initialize login plugin if path matches. + * @throws \RuntimeException + */ + public function initializeLogin() + { + $this->login = $this->grav['login']; + + /** @var Uri $uri */ + $uri = $this->grav['uri']; + + // Admin has its own login; make sure we're not in admin. + if (!isset($this->grav['admin'])) { + $this->route = $this->config->get('plugins.login.route'); + } + + $path = $uri->path(); + $this->redirect_to_login = $this->config->get('plugins.login.redirect_to_login'); + + // Register route to login page if it has been set. + if ($this->route && $this->route === $path) { + $this->enable([ + 'onPagesInitialized' => ['addLoginPage', 0], + ]); + return; + } + + if ($path === $this->config->get('plugins.login.route_forgot')) { + $this->enable([ + 'onPagesInitialized' => ['addForgotPage', 0], + ]); + return; + } + + if ($path === $this->config->get('plugins.login.route_reset')) { + $this->enable([ + 'onPagesInitialized' => ['addResetPage', 0], + ]); + return; + } + + if ($path === $this->config->get('plugins.login.route_register')) { + if ($this->config->get('plugins.login.user_registration.enabled')) { + $this->enable([ + 'onPagesInitialized' => ['addRegisterPage', 0], + ]); + } else { + throw new \RuntimeException($this->grav['language']->translate('PLUGIN_LOGIN.REGISTRATION_DISABLED'), 404); + } + return; + } + + if ($path === $this->config->get('plugins.login.route_activate')) { + $this->enable([ + 'onPagesInitialized' => ['handleUserActivation', 0], + ]); + return; + } + + if ($path === $this->config->get('plugins.login.route_profile')) { + $this->enable([ + 'onPagesInitialized' => ['addProfilePage', 0], + ]); + return; + } + } + + /** + * Optional ability to dynamically set visibility based on page access and page header + * that states `login.visibility_requires_access: true` + * + * Note that this setting may be slow on large sites as it loads all pages into memory for each page load! + * + * @param Event $e + */ + public function pageVisibility(Event $e) + { + if ($this->config->get('plugins.login.dynamic_page_visibility')) { + /** @var Pages $pages */ + $pages = $e['pages']; + $user = $this->grav['user']; + + foreach ($pages->instances() as $page) { + $header = $page->header(); + if (isset($header) && isset($header->access) && isset($header->login['visibility_requires_access']) && $header->login['visibility_requires_access'] === true) { + $config = $this->mergeConfig($page); + $access = $this->login->isUserAuthorizedForPage($user, $page, $config); + if ($access === false) { + $page->visible(false); + } + } + } + } + } + + /** + * [onPagesInitialized] + */ + public function storeReferrerPage() + { + $invalid_redirect_routes = [ + $this->config->get('plugins.login.route') ?: '/login', + $this->config->get('plugins.login.route_register') ?: '/register', + $this->config->get('plugins.login.route_activate') ?: '/activate_user', + $this->config->get('plugins.login.route_forgot') ?: '/forgot_password', + $this->config->get('plugins.login.route_reset') ?: '/reset_password', + ]; + + /** @var Uri $uri */ + $uri = $this->grav['uri']; + $current_route = $uri->route(); + $redirect = $this->grav['config']->get('plugins.login.redirect_after_login'); + + if (!$redirect && !in_array($current_route, $invalid_redirect_routes, true)) { + // No login redirect set in the configuration; can we redirect to the current page? + $allowed = true; + + /** @var PageInterface $page */ + $page = $this->grav['pages']->dispatch($current_route); + + if ($page) { + $header = $page->header(); + if (isset($header->login_redirect_here) && $header->login_redirect_here === false) { + $allowed = false; + } + + if ($allowed && $page->routable()) { + $redirect = $page->route() . ($uri->params() ?: ''); + } + } + } else { + $redirect = $this->grav['session']->redirect_after_login; + } + + $this->grav['session']->redirect_after_login = $redirect; + } + + /** + * Add Login page + * @throws \Exception + */ + public function addLoginPage() + { + /** @var Pages $pages */ + $pages = $this->grav['pages']; + $page = $pages->dispatch($this->route); + + if (!$page) { + // Only add login page if it hasn't already been defined. + $page = new Page(); + $page->init(new \SplFileInfo(__DIR__ . '/pages/login.md')); + $page->slug(basename($this->route)); + + $pages->addPage($page, $this->route); + } + } + + /** + * Add Login page + * @throws \Exception + */ + public function addForgotPage() + { + $route = $this->config->get('plugins.login.route_forgot'); + /** @var Pages $pages */ + $pages = $this->grav['pages']; + $page = $pages->dispatch($route); + + if (!$page) { + // Only add forgot page if it hasn't already been defined. + $page = new Page(); + $page->init(new \SplFileInfo(__DIR__ . '/pages/forgot.md')); + $page->slug(basename($route)); + + $pages->addPage($page, $route); + } + } + + /** + * Add Reset page + * @throws \Exception + */ + public function addResetPage() + { + $route = $this->config->get('plugins.login.route_reset'); + + $uri = $this->grav['uri']; + $token = $uri->param('token'); + $user = $uri->param('user'); + + if (!$user || !$token) { + return; + } + + /** @var Pages $pages */ + $pages = $this->grav['pages']; + $page = $pages->dispatch($route); + + if (!$page) { + // Only add login page if it hasn't already been defined. + $page = new Page(); + $page->init(new \SplFileInfo(__DIR__ . '/pages/reset.md')); + $page->slug(basename($route)); + + $pages->addPage($page, $route); + } + } + + /** + * Add Register page + * @throws \Exception + */ + public function addRegisterPage() + { + $route = $this->config->get('plugins.login.route_register'); + + /** @var Pages $pages */ + $pages = $this->grav['pages']; + $page = $pages->dispatch($route); + + if (!$page) { + $page = new Page(); + $page->init(new \SplFileInfo(__DIR__ . '/pages/register.md')); + $page->slug(basename($route)); + + $pages->addPage($page, $route); + } + } + + /** + * Handle user activation + * @throws \RuntimeException + */ + public function handleUserActivation() + { + /** @var Uri $uri */ + $uri = $this->grav['uri']; + + /** @var Message $messages */ + $messages = $this->grav['messages']; + + /** @var UserCollectionInterface $users */ + $users = $this->grav['accounts']; + + $username = $uri->param('username'); + + $token = $uri->param('token'); + $user = $users->load($username); + + $redirect_route = $this->config->get('plugins.login.user_registration.redirect_after_activation'); + $redirect_code = null; + + if (empty($user->activation_token)) { + $message = $this->grav['language']->translate('PLUGIN_LOGIN.INVALID_REQUEST'); + $messages->add($message, 'error'); + } else { + list($good_token, $expire) = explode('::', $user->activation_token, 2); + + if ($good_token === $token) { + if (time() > $expire) { + $message = $this->grav['language']->translate('PLUGIN_LOGIN.ACTIVATION_LINK_EXPIRED'); + $messages->add($message, 'error'); + } else { + if ($this->config->get('plugins.login.user_registration.options.manually_enable', false)) { + $message = $this->grav['language']->translate('PLUGIN_LOGIN.USER_ACTIVATED_SUCCESSFULLY_NOT_ENABLED'); + } else { + $user['state'] = 'enabled'; + $message = $this->grav['language']->translate('PLUGIN_LOGIN.USER_ACTIVATED_SUCCESSFULLY'); + } + + $messages->add($message, 'info'); + unset($user->activation_token); + $user->save(); + + if ($this->config->get('plugins.login.user_registration.options.send_welcome_email', false)) { + $this->login->sendWelcomeEmail($user); + } + if ($this->config->get('plugins.login.user_registration.options.send_notification_email', false)) { + $this->login->sendNotificationEmail($user); + } + + if ($this->config->get('plugins.login.user_registration.options.login_after_registration', false)) { + $loginEvent = $this->login->login(['username' => $username], ['after_registration' => true], ['user' => $user, 'return_event' => true]); + + // If there's no activation redirect, get one from login. + if (!$redirect_route) { + $message = $loginEvent->getMessage(); + if ($message) { + $messages->add($message, $loginEvent->getMessageType()); + } + + $redirect_route = $loginEvent->getRedirect(); + $redirect_code = $loginEvent->getRedirectCode(); + } + } + } + } else { + $message = $this->grav['language']->translate('PLUGIN_LOGIN.INVALID_REQUEST'); + $messages->add($message, 'error'); + } + } + + $this->grav->redirectLangSafe($redirect_route ?: '/', $redirect_code); + } + + /** + * Add Profile page + */ + public function addProfilePage() + { + $route = $this->config->get('plugins.login.route_profile'); + /** @var Pages $pages */ + $pages = $this->grav['pages']; + $page = $pages->dispatch($route); + + if (!$page) { + // Only add forgot page if it hasn't already been defined. + $page = new Page(); + $page->init(new \SplFileInfo(__DIR__ . '/pages/profile.md')); + $page->slug(basename($route)); + + $pages->addPage($page, $route); + } + + $this->storeReferrerPage(); + } + + /** + * Set Unauthorized page + * @throws \Exception + */ + public function setUnauthorizedPage() + { + $route = $this->config->get('plugins.login.route_unauthorized'); + + /** @var Pages $pages */ + $pages = $this->grav['pages']; + $page = $pages->dispatch($route); + + if (!$page) { + $page = new Page(); + $page->init(new \SplFileInfo(__DIR__ . '/pages/unauthorized.md')); + $page->slug(basename($route)); + + $pages->addPage($page, $route); + } + + unset($this->grav['page']); + $this->grav['page'] = $page; + } + + /** + * Initialize login controller + */ + public function loginController() + { + /** @var Uri $uri */ + $uri = $this->grav['uri']; + $task = !empty($_POST['task']) ? $_POST['task'] : $uri->param('task'); + $task = substr($task, \strlen('login.')); + $post = !empty($_POST) ? $_POST : []; + + switch ($task) { + case 'login': + if (!isset($post['login-form-nonce']) || !Utils::verifyNonce($post['login-form-nonce'], 'login-form')) { + $this->grav['messages']->add($this->grav['language']->translate('PLUGIN_LOGIN.ACCESS_DENIED'), + 'info'); + $twig = $this->grav['twig']; + $twig->twig_vars['notAuthorized'] = true; + + return; + } + break; + + case 'forgot': + if (!isset($post['forgot-form-nonce']) || !Utils::verifyNonce($post['forgot-form-nonce'], 'forgot-form')) { + $this->grav['messages']->add($this->grav['language']->translate('PLUGIN_LOGIN.ACCESS_DENIED'),'info'); + return; + } + break; + } + + $controller = new Controller($this->grav, $task, $post); + $controller->execute(); + $controller->redirect(); + } + + /** + * Authorize the Page fallback url (page media accessed through the page route) + */ + public function authorizeFallBackUrl() + { + if ($this->config->get('plugins.login.protect_protected_page_media', false)) { + $page_url = \dirname($this->grav['uri']->path()); + $page = $this->grav['pages']->find($page_url); + unset($this->grav['page']); + $this->grav['page'] = $page; + $this->authorizePage(); + } + } + + /** + * [onPageInitialized] Authorize Page + */ + public function authorizePage() + { + if (!$this->authenticated) { + return; + } + + /** @var UserInterface $user */ + $user = $this->grav['user']; + + /** @var PageInterface $page */ + $page = $this->grav['page']; + + if (!$page || $this->grav['login']->isUserAuthorizedForPage($user, $page, $this->mergeConfig($page))) { + return; + } + + // If this is not an HTML page request, simply throw a 403 error + $uri_extension = $this->grav['uri']->extension('html'); + $supported_types = $this->config->get('media.types'); + if ($uri_extension !== 'html' && array_key_exists($uri_extension, $supported_types)) { + header('HTTP/1.0 403 Forbidden'); + exit; + } + + $authorized = $user->authenticated && $user->authorized; + + // User is not logged in; redirect to login page. + if ($this->redirect_to_login && $this->route && !$authorized) { + $this->grav->redirectLangSafe($this->route, 302); + } + + /** @var Twig $twig */ + $twig = $this->grav['twig']; + + // Reset page with login page. + if (!$authorized) { + if ($this->route) { + $page = $this->grav['pages']->dispatch($this->route); + } else { + + $page = new Page(); + // $this->grav['session']->redirect_after_login = $this->grav['uri']->path() . ($this->grav['uri']->params() ?: ''); + + // Get the admin Login page is needed, else teh default + if ($this->isAdmin()) { + $login_file = $this->grav['locator']->findResource('plugins://admin/pages/admin/login.md'); + $page->init(new \SplFileInfo($login_file)); + } else { + $page->init(new \SplFileInfo(__DIR__ . '/pages/login.md')); + } + + $page->slug(basename($this->route)); + + /** @var Pages $pages */ + $pages = $this->grav['pages']; + $pages->addPage($page, $this->route); + } + + $this->authenticated = false; + unset($this->grav['page']); + $this->grav['page'] = $page; + + $twig->twig_vars['form'] = new Form($page); + } else { + /** @var Language $l */ + $l = $this->grav['language']; + $this->grav['messages']->add($l->translate('PLUGIN_LOGIN.ACCESS_DENIED'), 'error'); + $twig->twig_vars['notAuthorized'] = true; + + $this->setUnauthorizedPage(); + } + } + + /** + * [onTwigTemplatePaths] Add twig paths to plugin templates. + */ + public function onTwigTemplatePaths() + { + $twig = $this->grav['twig']; + $twig->twig_paths[] = __DIR__ . '/templates'; + } + + /** + * [onTwigSiteVariables] Set all twig variables for generating output. + */ + public function onTwigSiteVariables() + { + /** @var Twig $twig */ + $twig = $this->grav['twig']; + + $this->grav->fireEvent('onLoginPage'); + + $extension = $this->grav['uri']->extension(); + $extension = $extension ?: 'html'; + + if (!$this->authenticated) { + $twig->template = "login.{$extension}.twig"; + } + + // add CSS for frontend if required + if (!$this->isAdmin() && $this->config->get('plugins.login.built_in_css')) { + $this->grav['assets']->add('plugin://login/css/login.css'); + } + + $task = $this->grav['uri']->param('task') ?: ($_POST['task'] ?? ''); + $task = substr($task, \strlen('login.')); + if ($task === 'reset') { + $username = $this->grav['uri']->param('user'); + $token = $this->grav['uri']->param('token'); + + if (!empty($username) && !empty($token)) { + $twig->twig_vars['username'] = $username; + $twig->twig_vars['token'] = $token; + } + } elseif ($task === 'login') { + $twig->twig_vars['username'] = $_POST['username'] ?? ''; + } + + $flashData = $this->grav['session']->getFlashCookieObject(self::TMP_COOKIE_NAME); + + if (isset($flashData->message)) { + $this->grav['messages']->add($flashData->message, $flashData->status); + } + } + + /** + * Process the user registration, triggered by a registration form + * + * @param Form $form + * @throws \RuntimeException + */ + private function processUserRegistration($form, Event $event) + { + $language = $this->grav['language']; + $messages = $this->grav['messages']; + + if (!$this->config->get('plugins.login.enabled')) { + throw new \RuntimeException($language->translate('PLUGIN_LOGIN.PLUGIN_LOGIN_DISABLED')); + } + + if (!$this->config->get('plugins.login.user_registration.enabled')) { + throw new \RuntimeException($language->translate('PLUGIN_LOGIN.USER_REGISTRATION_DISABLED')); + } + + $form->validate(); + $form->filter(); + + /** @var Data $form_data */ + $form_data = $form->getData(); + + /** @var UserCollectionInterface $users */ + $users = $this->grav['accounts']; + + // Check for existing username + $username = $form_data->get('username'); + $existing_username = $users->find($username, ['username']); + if ($existing_username->exists()) { + $this->grav->fireEvent('onFormValidationError', new Event([ + 'form' => $form, + 'message' => $language->translate([ + 'PLUGIN_LOGIN.USERNAME_NOT_AVAILABLE', + $username + ]) + ])); + $event->stopPropagation(); + return; + } + + // Check for existing email + $email = $form_data->get('email'); + $existing_email = $users->find($email, ['email']); + if ($existing_email->exists()) { + $this->grav->fireEvent('onFormValidationError', new Event([ + 'form' => $form, + 'message' => $language->translate([ + 'PLUGIN_LOGIN.EMAIL_NOT_AVAILABLE', + $email + ]) + ])); + $event->stopPropagation(); + return; + } + + $data = []; + $data['username'] = $username; + + + // if multiple password fields, check they match and set password field from it + if ($this->config->get('plugins.login.user_registration.options.validate_password1_and_password2', + false) + ) { + if ($form_data->get('password1') !== $form_data->get('password2')) { + $this->grav->fireEvent('onFormValidationError', new Event([ + 'form' => $form, + 'message' => $language->translate('PLUGIN_LOGIN.PASSWORDS_DO_NOT_MATCH') + ])); + $event->stopPropagation(); + + return; + } + $data['password'] = $form_data->get('password1'); + } + + $fields = (array)$this->config->get('plugins.login.user_registration.fields', []); + + foreach ($fields as $field) { + // Process value of field if set in the page process.register_user + $default_values = (array)$this->config->get('plugins.login.user_registration.default_values'); + if ($default_values) { + foreach ($default_values as $key => $param) { + + if ($key === $field) { + if (\is_array($param)) { + $values = explode(',', $param); + } else { + $values = $param; + } + $data[$field] = $values; + } + } + } + + if (!isset($data[$field]) && $form_data->get($field)) { + $data[$field] = $form_data->get($field); + } + } + + if ($this->config->get('plugins.login.user_registration.options.set_user_disabled', false)) { + $data['state'] = 'disabled'; + } else { + $data['state'] = 'enabled'; + } + $data_object = (object) $data; + $this->grav->fireEvent('onUserLoginRegisterData', new Event(['data' => &$data_object])); + + $flash = $form->getFlash(); + $user = $this->login->register((array)$data_object, $flash->getFilesByFields(true)); + if ($user instanceof FlexObjectInterface) { + $flash->clearFiles(); + $flash->save(); + } + + $this->grav->fireEvent('onUserLoginRegisteredUser', new Event(['user' => &$user])); + + $fullname = $user->fullname ?? $user->username; + + if ($this->config->get('plugins.login.user_registration.options.send_activation_email', false)) { + $this->login->sendActivationEmail($user); + $message = $language->translate(['PLUGIN_LOGIN.ACTIVATION_NOTICE_MSG', $fullname]); + $messages->add($message, 'info'); + } else { + if ($this->config->get('plugins.login.user_registration.options.send_welcome_email', false)) { + $this->login->sendWelcomeEmail($user); + } + if ($this->config->get('plugins.login.user_registration.options.send_notification_email', false)) { + $this->login->sendNotificationEmail($user); + } + $message = $language->translate(['PLUGIN_LOGIN.WELCOME_NOTICE_MSG', $fullname]); + $messages->add($message, 'info'); + } + + $this->grav->fireEvent('onUserLoginRegistered', new Event(['user' => $user])); + + $redirect = $this->config->get('plugins.login.user_registration.redirect_after_registration'); + $redirect_code = null; + + if (isset($user['state']) && $user['state'] === 'enabled' && $this->config->get('plugins.login.user_registration.options.login_after_registration', false)) { + $loginEvent = $this->login->login(['username' => $user->username], ['after_registration' => true], ['user' => $user, 'return_event' => true]); + + // If there's no registration redirect, get one from login. + if (!$redirect) { + $message = $loginEvent->getMessage(); + if ($message) { + $messages->add($message, $loginEvent->getMessageType()); + } + + $redirect = $loginEvent->getRedirect(); + $redirect_code = $loginEvent->getRedirectCode(); + } + } + + if ($redirect) { + $event['redirect'] = $redirect; + $event['redirect_code'] = $redirect_code; + } + } + + /** + * Save user profile information + * + * @param Form $form + * @param Event $event + * @return bool + */ + private function processUserProfile($form, Event $event) + { + /** @var UserInterface $user */ + $user = $this->grav['user']; + $language = $this->grav['language']; + + $form->validate(); + $form->filter(); + + /** @var Data $form_data */ + $form_data = $form->getData(); + + // Don't save if user doesn't exist + if (!$user->exists()) { + $this->grav->fireEvent('onFormValidationError', new Event([ + 'form' => $form, + 'message' => $language->translate('PLUGIN_LOGIN.USER_IS_REMOTE_ONLY') + ])); + $event->stopPropagation(); + return false; + } + + // Stop overloading of username + $username = $form->data('username'); + if (isset($username)) { + $this->grav->fireEvent('onFormValidationError', new Event([ + 'form' => $form, + 'message' => $language->translate([ + 'PLUGIN_LOGIN.USERNAME_NOT_AVAILABLE', + $username + ]) + ])); + $event->stopPropagation(); + return false; + } + + /** @var UserCollectionInterface $users */ + $users = $this->grav['accounts']; + + // Check for existing email + $email = $form->getData('email'); + $existing_email = $users->find($email, ['email']); + if ($user->username !== $existing_email->username && $existing_email->exists()) { + $this->grav->fireEvent('onFormValidationError', new Event([ + 'form' => $form, + 'message' => $language->translate([ + 'PLUGIN_LOGIN.EMAIL_NOT_AVAILABLE', + $email + ]) + ])); + $event->stopPropagation(); + return false; + } + + $fields = (array)$this->config->get('plugins.login.user_registration.fields', []); + + $data = []; + foreach ($fields as $field) { + $data_field = $form_data->get($field); + if (!isset($data[$field]) && isset($data_field)) { + $data[$field] = $form_data->get($field); + } + } + + try { + $flash = $form->getFlash(); + $user->update($data, $flash->getFilesByFields(true)); + $user->save(); + + if ($user instanceof FlexObjectInterface) { + $flash->clearFiles(); + $flash->save(); + } + } catch (\Exception $e) { + $form->setMessage($e->getMessage(), 'error'); + return false; + } + + return true; + } + + /** + * [onFormProcessed] Process a registration form. Handles the following actions: + * + * - register_user: registers a user + * - update_user: updates user profile + * + * @param Event $event + * @throws \RuntimeException + */ + public function onFormProcessed(Event $event) + { + $form = $event['form']; + $action = $event['action']; + + switch ($action) { + case 'register_user': + $this->processUserRegistration($form, $event); + break; + case 'update_user': + $this->processUserProfile($form, $event); + break; + } + } + + /** + * @param UserLoginEvent $event + * @throws \RuntimeException + */ + public function userLoginAuthenticateByRegistration(UserLoginEvent $event) + { + // Check that we're logging in after registration. + if (!$event->getOption('after_registration') || $this->isAdmin()) { + return; + } + + $event->setStatus($event::AUTHENTICATION_SUCCESS); + $event->stopPropagation(); + } + + /** + * @param UserLoginEvent $event + * @throws \RuntimeException + */ + public function userLoginAuthenticateByRememberMe(UserLoginEvent $event) + { + // Check that we're logging in with remember me. + if (!$event->getOption('remember_me_login') || !$event->getOption('remember_me') || $this->isAdmin()) { + return; + } + + // Only use remember me if user isn't set and feature is enabled. + if ($this->grav['config']->get('plugins.login.rememberme.enabled') && !$event->getUser()->exists()) { + /** @var Debugger $debugger */ + $debugger = $this->grav['debugger']; + + /** @var RememberMe $rememberMe */ + $rememberMe = $this->grav['login']->rememberMe(); + $username = $rememberMe->login(); + + if ($rememberMe->loginTokenWasInvalid()) { + // Token was invalid. We will display error page as this was likely an attack. + $debugger->addMessage('Remember Me: Stolen token!'); + + throw new \RuntimeException($this->grav['language']->translate('PLUGIN_LOGIN.REMEMBER_ME_STOLEN_COOKIE'), 403); + } + + if ($username === false) { + // User has not been remembered, there is no point of continuing. + $debugger->addMessage('Remember Me: No token matched.'); + + $event->setStatus($event::AUTHENTICATION_FAILURE); + $event->stopPropagation(); + + return; + } + + /** @var UserCollectionInterface $users */ + $users = $this->grav['accounts']; + + // Allow remember me to work with different login methods. + $user = $users->load($username); + $event->setCredential('username', $username); + $event->setUser($user); + + if (!$user->exists()) { + $debugger->addMessage('Remember Me: User does not exist'); + + $event->setStatus($event::AUTHENTICATION_FAILURE); + $event->stopPropagation(); + + return; + } + + $debugger->addMessage('Remember Me: Authenticated!'); + + $event->setStatus($event::AUTHENTICATION_SUCCESS); + $event->stopPropagation(); + + return; + } + } + + public function userLoginAuthenticateByEmail(UserLoginEvent $event) + { + if (($username = $event->getCredential('username')) && !$event->getUser()->exists()) { + /** @var UserCollectionInterface $users */ + $users = $this->grav['accounts']; + + $event->setUser($users->find($username)); + } + } + + public function userLoginAuthenticate(UserLoginEvent $event) + { + $user = $event->getUser(); + $credentials = $event->getCredentials(); + + if (!$user->exists()) { + // Never let non-existing users to pass the authentication. + // Higher level plugins may override this behavior by stopping propagation. + $event->setStatus($event::AUTHENTICATION_FAILURE); + $event->stopPropagation(); + + return; + } + + // Never let empty password to pass the authentication. + // Higher level plugins may override this behavior by stopping propagation. + if (empty($credentials['password'])) { + $event->setStatus($event::AUTHENTICATION_FAILURE); + $event->stopPropagation(); + + return; + } + + // Try default user authentication. Stop propagation if authentication succeeds. + if ($user->authenticate($credentials['password'])) { + $event->setStatus($event::AUTHENTICATION_SUCCESS); + $event->stopPropagation(); + + return; + } + + // If authentication status is undefined, lower level event handlers may still be able to authenticate user. + } + + public function userLoginAuthorize(UserLoginEvent $event) + { + // Always block access if authorize defaulting to site.login fails. + $user = $event->getUser(); + foreach ($event->getAuthorize() as $authorize) { + if (!$user->authorize($authorize)) { + $event->setStatus($event::AUTHORIZATION_DENIED); + $event->stopPropagation(); + + return; + } + } + + if ($event->getOption('twofa') && $user->twofa_enabled && $user->twofa_secret) { + $event->setStatus($event::AUTHORIZATION_DELAYED); + } + } + + public function userLoginFailure(UserLoginEvent $event) + { + /** @var UserCollectionInterface $users */ + $users = $this->grav['accounts']; + + $this->grav['session']->user = $users->load(''); + } + + public function userLogin(UserLoginEvent $event) + { + $session = $this->grav['session']; + $session->user = $event->getUser(); + + if ($event->getOption('remember_me')) { + /** @var Login $login */ + $login = $this->grav['login']; + + $session->remember_me = (bool)$event->getOption('remember_me_login'); + + // If the user wants to be remembered, create Rememberme cookie. + $username = $event->getUser()->get('username'); + if ($event->getCredential('rememberme')) { + $login->rememberMe()->createCookie($username); + } + } + } + + public function userLogout(UserLoginEvent $event) + { + if ($event->getOption('remember_me')) { + /** @var Login $login */ + $login = $this->grav['login']; + + if (!$login->rememberMe()->login()) { + $login->rememberMe()->getStorage()->cleanAllTriplets($event->getUser()->get('username')); + } + $login->rememberMe()->clearCookie(); + } + + $this->grav['session']->invalidate()->start(); + } +} diff --git a/user/plugins/login/login.yaml b/user/plugins/login/login.yaml new file mode 100644 index 00000000..c3d6d428 --- /dev/null +++ b/user/plugins/login/login.yaml @@ -0,0 +1,59 @@ +enabled: true # Enable the plugin +built_in_css: true # Use built-in CSS +route: # Specific route for Login page (default is '/login') +redirect_to_login: true # If you try to access a page you don't have access to, should you redirect to login route +redirect_after_login: # Path to redirect to after a successful login (eg '/user_profile') +redirect_after_logout: '/' # Path to redirect to after a successful logout (eg '/') +route_activate: '/activate_user' # Route for the user activation process +route_forgot: '/forgot_password' # Route for the forgot password process +route_reset: '/reset_password' # Route for the reset password process +route_profile: '/user_profile' # Route for the user profile page +route_register: '/user_register' # Route for the user registration page +route_unauthorized: '/user_unauthorized' # Route for a page to display if user is unauthorized + +twofa_enabled: false # Two factor authentication enabled +dynamic_page_visibility: false # Integrate access into page visibility so things can be shown or hidden in the menu +parent_acl: false # Look to parent `access` rules for access requirements +protect_protected_page_media: false # Take `access` rules into account when directly accessing a page's media + +rememberme: + enabled: true # Enable 'remember me' functionality + timeout: 604800 # Timeout in seconds. Defaults to 1 week + name: grav-rememberme # Name prefix of the session cookie + +max_pw_resets_count: 2 # Number of password resets in a specific time frame (0 = unlimited) +max_pw_resets_interval: 60 # Time in minutes to track password resets +max_login_count: 5 # Number of failed login attempts in a specific time frame (0 = unlimited) +max_login_interval: 10 # Time in minutes to track login attempts +ipv6_subnet_size: 64 # Size of IPv6 block to track login attempts + +user_registration: + enabled: false # Enable User Registration Process + + fields: # List of fields to validate and store during user registration + - 'username' # This should match up with your registration form definition + - 'password' + - 'email' + - 'fullname' + - 'title' + - 'level' + - 'twofa_enabled' + + default_values: # Any default values for fields you would like to set + level: Newbie # Here the 'level' field will be pre-populated with 'Newbie' text + + access: # Default access to set for users created during registration + site: + login: 'true' + + redirect_after_registration: '' # Route to redirect to after registration + redirect_after_activation: '' # Route to redirect to after activation + + options: + validate_password1_and_password2: true # Ensure that password1 and password2 match during registration (allows you to have just 1 pw field or 2) + set_user_disabled: false # Set this `true` if you want a user to activate their account via email + login_after_registration: false # Automatically login after registration + send_activation_email: false # Send an email that requires a special link to be clicked in order to activate the account + manually_enable: false # When using activation email, don't enable until an admin does it manually + send_notification_email: false # Send an email to the site administrator to indicate a user has registered + send_welcome_email: false # Send a welcome email to the user (probably should not be used with `send_activation_email` diff --git a/user/plugins/login/pages/forgot.md b/user/plugins/login/pages/forgot.md new file mode 100644 index 00000000..6f46df64 --- /dev/null +++ b/user/plugins/login/pages/forgot.md @@ -0,0 +1,21 @@ +--- +title: Forgot password + +login_redirect_here: false + +form: + + fields: + - name: email + type: email + label: PLUGIN_LOGIN.EMAIL + autofocus: true + validate: + required: true + type: email +--- + + +# Recover your password + +Enter your email to recover your password diff --git a/user/plugins/login/pages/login.md b/user/plugins/login/pages/login.md new file mode 100644 index 00000000..a6700479 --- /dev/null +++ b/user/plugins/login/pages/login.md @@ -0,0 +1,42 @@ +--- +title: Login + +login_redirect_here: false + +forms: + login: + action: + method: post + + fields: + username: + type: text + id: username + placeholder: Username + label: PLUGIN_LOGIN.USERNAME_EMAIL + autofocus: true + + password: + type: password + id: password + placeholder: Password + label: PLUGIN_LOGIN.PASSWORD + + login-twofa: + action: + method: post + + fields: + 2fa_instructions: + type: display + markdown: true + content: PLUGIN_LOGIN.2FA_INSTRUCTIONS + 2fa_code: + type: text + id: twofa-code + autofocus: true + placeholder: PLUGIN_LOGIN.2FA_CODE_INPUT +--- + +# User Login + diff --git a/user/plugins/login/pages/profile.md b/user/plugins/login/pages/profile.md new file mode 100644 index 00000000..d0a2594e --- /dev/null +++ b/user/plugins/login/pages/profile.md @@ -0,0 +1,80 @@ +--- +title: Profile +access: + site.login: true + +form: + fields: + avatar_img: + type: avatar + + username: + type: text + readonly: true + disabled: true + + email: + type: email + placeholder: "Enter your email" + validate: + required: true + message: PLUGIN_LOGIN.EMAIL_VALIDATION_MESSAGE + + fullname: + type: text + + title: + type: text + + password: + type: password + label: Enter new password + validate: + message: PLUGIN_LOGIN.PASSWORD_VALIDATION_MESSAGE + config-pattern@: system.pwd_regex + + twofa_check: + type: conditional + condition: config.plugins.login.twofa_enabled + + fields: + + twofa: + title: PLUGIN_LOGIN.2FA_TITLE + type: section + underline: true + + twofa_enabled: + type: toggle + label: PLUGIN_LOGIN.2FA_ENABLED + classes: twofa-toggle + highlight: 1 + default: 0 + options: + 1: GRAV.YES + 0: GRAV.NO + validate: + type: bool + + twofa_secret: + type: 2fa_secret + outerclasses: 'twofa-secret' + markdown: true + label: PLUGIN_LOGIN.2FA_SECRET + sublabel: PLUGIN_LOGIN.2FA_SECRET_HELP + + + buttons: + - + type: submit + value: Submit + - + type: reset + value: Reset + + process: + update_user: true + message: "Your profile has been updated" +--- + +# Profile \ No newline at end of file diff --git a/user/plugins/login/pages/register.md b/user/plugins/login/pages/register.md new file mode 100644 index 00000000..36bdaffe --- /dev/null +++ b/user/plugins/login/pages/register.md @@ -0,0 +1,58 @@ +--- +login_redirect_here: false + +form: + + fields: + fullname: + type: text + validate: + required: true + + + username: + type: text + validate: + required: true + message: PLUGIN_LOGIN.USERNAME_NOT_VALID + config-pattern@: system.username_regex + + email: + type: email + validate: + required: true + message: PLUGIN_LOGIN.EMAIL_VALIDATION_MESSAGE + + password1: + type: password + label: Enter a password + validate: + required: true + message: PLUGIN_LOGIN.PASSWORD_VALIDATION_MESSAGE + config-pattern@: system.pwd_regex + + password2: + type: password + label: Enter the password again + validate: + required: true + message: PLUGIN_LOGIN.PASSWORD_VALIDATION_MESSAGE + config-pattern@: system.pwd_regex + + buttons: + - + type: submit + value: Submit + - + type: reset + value: Reset + + process: + register_user: true + message: "Thanks for registering..." + reset: true +--- + +# Register + +Create a new user account by entering all the required fields below: diff --git a/user/plugins/login/pages/reset.md b/user/plugins/login/pages/reset.md new file mode 100644 index 00000000..1c3048a4 --- /dev/null +++ b/user/plugins/login/pages/reset.md @@ -0,0 +1,35 @@ +--- +title: Reset password + +login_redirect_here: false + +form: + + fields: + - name: username + type: hidden + id: username + placeholder: Username + readonly: true + + - name: password + type: password + id: password + placeholder: Password + autofocus: true + validate: + required: true + message: PLUGIN_LOGIN.PASSWORD_VALIDATION_MESSAGE + config-pattern@: system.pwd_regex + + - name: token + type: hidden + +process: + twig: true +--- + +# Password Reset + +### Username: {{uri.param('user')}} + diff --git a/user/plugins/login/pages/unauthorized.md b/user/plugins/login/pages/unauthorized.md new file mode 100644 index 00000000..6b9aa13d --- /dev/null +++ b/user/plugins/login/pages/unauthorized.md @@ -0,0 +1,5 @@ +--- +title: Unauthorized +--- + +# You don't have access to this page... \ No newline at end of file diff --git a/user/plugins/login/templates/forgot.html.twig b/user/plugins/login/templates/forgot.html.twig new file mode 100644 index 00000000..9ca0001e --- /dev/null +++ b/user/plugins/login/templates/forgot.html.twig @@ -0,0 +1,6 @@ +{% extends 'partials/base.html.twig' %} + +{% block content %} + {% include 'partials/messages.html.twig' %} + {% include 'partials/forgot-form.html.twig' %} +{% endblock %} diff --git a/user/plugins/login/templates/forms/fields/2fa_secret/2fa_secret.html.twig b/user/plugins/login/templates/forms/fields/2fa_secret/2fa_secret.html.twig new file mode 100644 index 00000000..c57bdc33 --- /dev/null +++ b/user/plugins/login/templates/forms/fields/2fa_secret/2fa_secret.html.twig @@ -0,0 +1,31 @@ +{% extends "forms/field.html.twig" %} + +{% block input %} +
                                                            + {% try %} + {% set user = grav.user %} + + {% set secret = user.twofa_secret ?: grav.login.twoFactorAuth.createSecret() %} + {% set image = grav.login.twoFactorAuth.getQrImageData(user.username, secret) %} + + +
                                                            + {{ 'PLUGIN_LOGIN.2FA_SECRET'|t }}: {{ secret|regex_replace('/(\\w{4})/', '\\1 ') }} +
                                                            + +
                                                            + +
                                                            + + + + {% catch %} +
                                                            +

                                                            {{ e.message }}

                                                            +
                                                            + {% endcatch %} +
                                                            + + {% do assets.addJs('jquery', 101) %} + {% do assets.addJs('plugin://login/js/2fa.js', { 'group': 'bottom', 'loading': 'defer' }) %} +{% endblock %} diff --git a/user/plugins/login/templates/login.html.twig b/user/plugins/login/templates/login.html.twig new file mode 100644 index 00000000..7ac282fe --- /dev/null +++ b/user/plugins/login/templates/login.html.twig @@ -0,0 +1,6 @@ +{% extends 'partials/base.html.twig' %} + +{% block content %} + {% include 'partials/messages.html.twig' %} + {% include 'partials/login-form.html.twig' %} +{% endblock %} diff --git a/user/plugins/login/templates/login.json.twig b/user/plugins/login/templates/login.json.twig new file mode 100644 index 00000000..14dbf959 --- /dev/null +++ b/user/plugins/login/templates/login.json.twig @@ -0,0 +1,5 @@ +{%- if not grav.user.authenticated -%} +{"code":401,"status":"unauthenticated","error":{"message":"Authentication required","login":{{ include('partials/login-form.html.twig')|trim|json_encode }}}} +{%- else -%} +{"code":200,"status":"authenticated","message":"You have been authenticated"} +{%- endif -%} \ No newline at end of file diff --git a/user/plugins/login/templates/partials/forgot-form.html.twig b/user/plugins/login/templates/partials/forgot-form.html.twig new file mode 100644 index 00000000..7ed2cc50 --- /dev/null +++ b/user/plugins/login/templates/partials/forgot-form.html.twig @@ -0,0 +1,21 @@ +{% set client_side_validation = form.client_side_validation is not null ? form.client_side_validation : config.plugins.form.client_side_validation|default(true) %} +{% set inline_errors = form.inline_errors is not null ? form.inline_errors : config.plugins.form.inline_errors(false) %} + +
                                                            + {{ content|raw }} + +
                                                            + {% for field in form.fields %} + {% if field.type %} +
                                                            + {% include ["forms/fields/#{field.type}/#{field.type}.html.twig", 'forms/fields/text/text.html.twig'] %} +
                                                            + {% endif %} + {% endfor %} +
                                                            + +
                                                            + + {{ nonce_field('forgot-form', 'forgot-form-nonce')|raw }} +
                                                            +
                                                            diff --git a/user/plugins/login/templates/partials/login-form.html.twig b/user/plugins/login/templates/partials/login-form.html.twig new file mode 100644 index 00000000..34d46382 --- /dev/null +++ b/user/plugins/login/templates/partials/login-form.html.twig @@ -0,0 +1,64 @@ +{% set client_side_validation = form.client_side_validation is not null ? form.client_side_validation : config.plugins.form.client_side_validation|default(true) %} +{% set inline_errors = form.inline_errors is not null ? form.inline_errors : config.plugins.form.inline_errors(false) %} + +
                                                            + + {% if page.template == 'login' or show_login_form %} + {% set user = grav.user %} + {% if user.authenticated and user.authorized %} +

                                                            {{ 'PLUGIN_LOGIN.WELCOME'|t }} {{ user.fullname ?: user.username }}

                                                            +
                                                            + {{ 'PLUGIN_LOGIN.BTN_LOGOUT'|t }} + + {% elseif user.authenticated and user.twofa_enabled %} + {% include 'partials/login-twofa.html.twig' %} + + {% else %} + {{ content|raw }} + + {# NEW WAY OF INCLUDING 3RD PARTY LOGIN OPTIONS #} + {% for template in grav.login.getProviderLoginTemplates %} + {% include template %} + {% endfor %} + + + + {% endif %} + + {% endif %} + +
                                                            diff --git a/user/plugins/login/templates/partials/login-status.html.twig b/user/plugins/login/templates/partials/login-status.html.twig new file mode 100644 index 00000000..7c060168 --- /dev/null +++ b/user/plugins/login/templates/partials/login-status.html.twig @@ -0,0 +1,5 @@ + diff --git a/user/plugins/login/templates/partials/login-twofa.html.twig b/user/plugins/login/templates/partials/login-twofa.html.twig new file mode 100644 index 00000000..2bcca2d9 --- /dev/null +++ b/user/plugins/login/templates/partials/login-twofa.html.twig @@ -0,0 +1,25 @@ +{% set form = forms('login-twofa') %} +{% set client_side_validation = form.client_side_validation is not null ? form.client_side_validation : config.plugins.form.client_side_validation|default(true) %} +{% set inline_errors = form.inline_errors is not null ? form.inline_errors : config.plugins.form.inline_errors(false) %} + +
                                                            + {% for field in form.fields %} + {% if field.type %} +
                                                            + {% include ["forms/fields/#{field.type}/#{field.type}.html.twig", 'forms/fields/text/text.html.twig'] %} +
                                                            + {% endif %} + {% endfor %} + + {{ nonce_field('login-form', 'login-form-nonce')|raw }} + +
                                                            +
                                                            + + + + + +
                                                            +
                                                            +
                                                            diff --git a/user/plugins/login/templates/partials/reset-form.html.twig b/user/plugins/login/templates/partials/reset-form.html.twig new file mode 100644 index 00000000..563e89a6 --- /dev/null +++ b/user/plugins/login/templates/partials/reset-form.html.twig @@ -0,0 +1,27 @@ +{% if uri.param('token') and uri.param('task') %} +{% set client_side_validation = form.client_side_validation is not null ? form.client_side_validation : config.plugins.form.client_side_validation|default(true) %} +{% set inline_errors = form.inline_errors is not null ? form.inline_errors : config.plugins.form.inline_errors(false) %} + +
                                                            + {{ content|raw }} + +
                                                            + {% for field in form.fields %} + {% set value = attribute(grav.twig.twig_vars, field.name) is defined ? attribute(grav.twig.twig_vars, field.name) : null %} + + {% if field.type %} +
                                                            + {% include ["forms/fields/#{field.type}/#{field.type}.html.twig", 'forms/fields/text/text.html.twig'] %} +
                                                            + {% endif %} + {% endfor %} +
                                                            + +
                                                            + + {{ nonce_field('reset-form', 'reset-form-nonce')|raw }} +
                                                            +
                                                            +{% endif %} + + diff --git a/user/plugins/login/templates/profile.html.twig b/user/plugins/login/templates/profile.html.twig new file mode 100644 index 00000000..e35b743d --- /dev/null +++ b/user/plugins/login/templates/profile.html.twig @@ -0,0 +1,9 @@ +{% extends 'partials/base.html.twig' %} + +{% do form.setAllData(grav.user.toArray) %} + +{% block content %} + {% include 'partials/messages.html.twig' %} + {{ page.content }} + {% include 'forms/form.html.twig' %} +{% endblock %} \ No newline at end of file diff --git a/user/plugins/login/templates/profile.json.twig b/user/plugins/login/templates/profile.json.twig new file mode 100644 index 00000000..da0d0233 --- /dev/null +++ b/user/plugins/login/templates/profile.json.twig @@ -0,0 +1 @@ +{% extends 'forms/ajax.json.twig' %} \ No newline at end of file diff --git a/user/plugins/login/templates/register.html.twig b/user/plugins/login/templates/register.html.twig new file mode 100644 index 00000000..f6d81e9f --- /dev/null +++ b/user/plugins/login/templates/register.html.twig @@ -0,0 +1 @@ +{% extends 'form.html.twig' %} \ No newline at end of file diff --git a/user/plugins/login/templates/reset.html.twig b/user/plugins/login/templates/reset.html.twig new file mode 100644 index 00000000..f4597846 --- /dev/null +++ b/user/plugins/login/templates/reset.html.twig @@ -0,0 +1,8 @@ +{% extends 'partials/base.html.twig' %} + +{% block content %} + {% include 'partials/messages.html.twig' %} + {% include 'partials/reset-form.html.twig' %} +{% endblock %} + + diff --git a/user/plugins/login/templates/unauthorized.html.twig b/user/plugins/login/templates/unauthorized.html.twig new file mode 100644 index 00000000..47548136 --- /dev/null +++ b/user/plugins/login/templates/unauthorized.html.twig @@ -0,0 +1 @@ +{% extends 'default.html.twig' %} \ No newline at end of file diff --git a/user/plugins/login/vendor/autoload.php b/user/plugins/login/vendor/autoload.php new file mode 100644 index 00000000..c13a8a31 --- /dev/null +++ b/user/plugins/login/vendor/autoload.php @@ -0,0 +1,7 @@ + array( + __DIR__ . '/autoload_classmap.php', + ), + 'Zend\Loader\StandardAutoloader' => array( + 'namespaces' => array( + __NAMESPACE__ => __DIR__ . '/src/' . __NAMESPACE__, + ), + ), + ); + } +} diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/README.md b/user/plugins/login/vendor/bacon/bacon-qr-code/README.md new file mode 100644 index 00000000..a836bd61 --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/README.md @@ -0,0 +1,24 @@ +QR Code generator +================= + +Master: [![Build Status](https://api.travis-ci.org/Bacon/BaconQrCode.png?branch=master)](http://travis-ci.org/Bacon/BaconQrCode) + +Introduction +------------ +BaconQrCode is a port of QR code portion of the ZXing library. It currently +only features the encoder part, but could later receive the decoder part as +well. + +As the Reed Solomon codec implementation of the ZXing library performs quite +slow in PHP, it was exchanged with the implementation by Phil Karn. + + +Example usage +------------- +```php +$renderer = new \BaconQrCode\Renderer\Image\Png(); +$renderer->setHeight(256); +$renderer->setWidth(256); +$writer = new \BaconQrCode\Writer($renderer); +$writer->writeFile('Hello World!', 'qrcode.png'); +``` diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/autoload_classmap.php b/user/plugins/login/vendor/bacon/bacon-qr-code/autoload_classmap.php new file mode 100644 index 00000000..9fbeb35b --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/autoload_classmap.php @@ -0,0 +1,43 @@ + __DIR__ . '/src/BaconQrCode/Common/AbstractEnum.php', + 'BaconQrCode\Common\BitArray' => __DIR__ . '/src/BaconQrCode/Common/BitArray.php', + 'BaconQrCode\Common\BitMatrix' => __DIR__ . '/src/BaconQrCode/Common/BitMatrix.php', + 'BaconQrCode\Common\BitUtils' => __DIR__ . '/src/BaconQrCode/Common/BitUtils.php', + 'BaconQrCode\Common\CharacterSetEci' => __DIR__ . '/src/BaconQrCode/Common/CharacterSetEci.php', + 'BaconQrCode\Common\EcBlock' => __DIR__ . '/src/BaconQrCode/Common/EcBlock.php', + 'BaconQrCode\Common\EcBlocks' => __DIR__ . '/src/BaconQrCode/Common/EcBlocks.php', + 'BaconQrCode\Common\ErrorCorrectionLevel' => __DIR__ . '/src/BaconQrCode/Common/ErrorCorrectionLevel.php', + 'BaconQrCode\Common\FormatInformation' => __DIR__ . '/src/BaconQrCode/Common/FormatInformation.php', + 'BaconQrCode\Common\Mode' => __DIR__ . '/src/BaconQrCode/Common/Mode.php', + 'BaconQrCode\Common\ReedSolomonCodec' => __DIR__ . '/src/BaconQrCode/Common/ReedSolomonCodec.php', + 'BaconQrCode\Common\Version' => __DIR__ . '/src/BaconQrCode/Common/Version.php', + 'BaconQrCode\Encoder\BlockPair' => __DIR__ . '/src/BaconQrCode/Encoder/BlockPair.php', + 'BaconQrCode\Encoder\ByteMatrix' => __DIR__ . '/src/BaconQrCode/Encoder/ByteMatrix.php', + 'BaconQrCode\Encoder\Encoder' => __DIR__ . '/src/BaconQrCode/Encoder/Encoder.php', + 'BaconQrCode\Encoder\MaskUtil' => __DIR__ . '/src/BaconQrCode/Encoder/MaskUtil.php', + 'BaconQrCode\Encoder\MatrixUtil' => __DIR__ . '/src/BaconQrCode/Encoder/MatrixUtil.php', + 'BaconQrCode\Encoder\QrCode' => __DIR__ . '/src/BaconQrCode/Encoder/QrCode.php', + 'BaconQrCode\Exception\ExceptionInterface' => __DIR__ . '/src/BaconQrCode/Exception/ExceptionInterface.php', + 'BaconQrCode\Exception\InvalidArgumentException' => __DIR__ . '/src/BaconQrCode/Exception/InvalidArgumentException.php', + 'BaconQrCode\Exception\OutOfBoundsException' => __DIR__ . '/src/BaconQrCode/Exception/OutOfBoundsException.php', + 'BaconQrCode\Exception\RuntimeException' => __DIR__ . '/src/BaconQrCode/Exception/RuntimeException.php', + 'BaconQrCode\Exception\UnexpectedValueException' => __DIR__ . '/src/BaconQrCode/Exception/UnexpectedValueException.php', + 'BaconQrCode\Exception\WriterException' => __DIR__ . '/src/BaconQrCode/Exception/WriterException.php', + 'BaconQrCode\Renderer\Color\Cmyk' => __DIR__ . '/src/BaconQrCode/Renderer/Color/Cmyk.php', + 'BaconQrCode\Renderer\Color\ColorInterface' => __DIR__ . '/src/BaconQrCode/Renderer/Color/ColorInterface.php', + 'BaconQrCode\Renderer\Color\Gray' => __DIR__ . '/src/BaconQrCode/Renderer/Color/Gray.php', + 'BaconQrCode\Renderer\Color\Rgb' => __DIR__ . '/src/BaconQrCode/Renderer/Color/Rgb.php', + 'BaconQrCode\Renderer\Image\AbstractRenderer' => __DIR__ . '/src/BaconQrCode/Renderer/Image/AbstractRenderer.php', + 'BaconQrCode\Renderer\Image\Decorator\DecoratorInterface' => __DIR__ . '/src/BaconQrCode/Renderer/Image/Decorator/DecoratorInterface.php', + 'BaconQrCode\Renderer\Image\Decorator\FinderPattern' => __DIR__ . '/src/BaconQrCode/Renderer/Image/Decorator/FinderPattern.php', + 'BaconQrCode\Renderer\Image\Eps' => __DIR__ . '/src/BaconQrCode/Renderer/Image/Eps.php', + 'BaconQrCode\Renderer\Image\Png' => __DIR__ . '/src/BaconQrCode/Renderer/Image/Png.php', + 'BaconQrCode\Renderer\Image\RendererInterface' => __DIR__ . '/src/BaconQrCode/Renderer/Image/RendererInterface.php', + 'BaconQrCode\Renderer\Image\Svg' => __DIR__ . '/src/BaconQrCode/Renderer/Image/Svg.php', + 'BaconQrCode\Renderer\RendererInterface' => __DIR__ . '/src/BaconQrCode/Renderer/RendererInterface.php', + 'BaconQrCode\Renderer\Text\Plain' => __DIR__ . '/src/BaconQrCode/Renderer/Text/Plain.php', + 'BaconQrCode\Renderer\Text\Html' => __DIR__ . '/src/BaconQrCode/Renderer/Text/Html.php', + 'BaconQrCode\Writer' => __DIR__ . '/src/BaconQrCode/Writer.php', +); \ No newline at end of file diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/autoload_function.php b/user/plugins/login/vendor/bacon/bacon-qr-code/autoload_function.php new file mode 100644 index 00000000..9148da38 --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/autoload_function.php @@ -0,0 +1,12 @@ +strict = $strict; + $this->change($initialValue); + } + + /** + * Changes the value of the enum. + * + * @param mixed $value + * @return void + */ + public function change($value) + { + if (!in_array($value, $this->getConstList(), $this->strict)) { + throw new Exception\UnexpectedValueException('Value not a const in enum ' . get_class($this)); + } + + $this->value = $value; + } + + /** + * Gets current value. + * + * @return mixed + */ + public function get() + { + return $this->value; + } + + /** + * Gets all constants (possible values) as an array. + * + * @param boolean $includeDefault + * @return array + */ + public function getConstList($includeDefault = true) + { + if ($this->constants === null) { + $reflection = new ReflectionClass($this); + $this->constants = $reflection->getConstants(); + } + + if ($includeDefault) { + return $this->constants; + } + + $constants = $this->constants; + unset($constants['__default']); + + return $constants; + } + + /** + * Gets the name of the enum. + * + * @return string + */ + public function __toString() + { + return array_search($this->value, $this->getConstList()); + } +} diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/BitArray.php b/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/BitArray.php new file mode 100644 index 00000000..0a99d9a9 --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/BitArray.php @@ -0,0 +1,435 @@ +size = $size; + $this->bits = new SplFixedArray(($this->size + 31) >> 3); + } + + /** + * Gets the size in bits. + * + * @return integer + */ + public function getSize() + { + return $this->size; + } + + /** + * Gets the size in bytes. + * + * @return integer + */ + public function getSizeInBytes() + { + return ($this->size + 7) >> 3; + } + + /** + * Ensures that the array has a minimum capacity. + * + * @param integer $size + * @return void + */ + public function ensureCapacity($size) + { + if ($size > count($this->bits) << 5) { + $this->bits->setSize(($size + 31) >> 5); + } + } + + /** + * Gets a specific bit. + * + * @param integer $i + * @return boolean + */ + public function get($i) + { + return ($this->bits[$i >> 5] & (1 << ($i & 0x1f))) !== 0; + } + + /** + * Sets a specific bit. + * + * @param integer $i + * @return void + */ + public function set($i) + { + $this->bits[$i >> 5] = $this->bits[$i >> 5] | 1 << ($i & 0x1f); + } + + /** + * Flips a specific bit. + * + * @param integer $i + * @return void + */ + public function flip($i) + { + $this->bits[$i >> 5] ^= 1 << ($i & 0x1f); + } + + /** + * Gets the next set bit position from a given position. + * + * @param integer $from + * @return integer + */ + public function getNextSet($from) + { + if ($from >= $this->size) { + return $this->size; + } + + $bitsOffset = $from >> 5; + $currentBits = $this->bits[$bitsOffset]; + $bitsLength = count($this->bits); + + $currentBits &= ~((1 << ($from & 0x1f)) - 1); + + while ($currentBits === 0) { + if (++$bitsOffset === $bitsLength) { + return $this->size; + } + + $currentBits = $this->bits[$bitsOffset]; + } + + $result = ($bitsOffset << 5) + BitUtils::numberOfTrailingZeros($currentBits); + + return $result > $this->size ? $this->size : $result; + } + + /** + * Gets the next unset bit position from a given position. + * + * @param integer $from + * @return integer + */ + public function getNextUnset($from) + { + if ($from >= $this->size) { + return $this->size; + } + + $bitsOffset = $from >> 5; + $currentBits = ~$this->bits[$bitsOffset]; + $bitsLength = count($this->bits); + + $currentBits &= ~((1 << ($from & 0x1f)) - 1); + + while ($currentBits === 0) { + if (++$bitsOffset === $bitsLength) { + return $this->size; + } + + $currentBits = ~$this->bits[$bitsOffset]; + } + + $result = ($bitsOffset << 5) + BitUtils::numberOfTrailingZeros($currentBits); + + return $result > $this->size ? $this->size : $result; + } + + /** + * Sets a bulk of bits. + * + * @param integer $i + * @param integer $newBits + * @return void + */ + public function setBulk($i, $newBits) + { + $this->bits[$i >> 5] = $newBits; + } + + /** + * Sets a range of bits. + * + * @param integer $start + * @param integer $end + * @return void + * @throws Exception\InvalidArgumentException + */ + public function setRange($start, $end) + { + if ($end < $start) { + throw new Exception\InvalidArgumentException('End must be greater or equal to start'); + } + + if ($end === $start) { + return; + } + + $end--; + + $firstInt = $start >> 5; + $lastInt = $end >> 5; + + for ($i = $firstInt; $i <= $lastInt; $i++) { + $firstBit = $i > $firstInt ? 0 : $start & 0x1f; + $lastBit = $i < $lastInt ? 31 : $end & 0x1f; + + if ($firstBit === 0 && $lastBit === 31) { + $mask = 0x7fffffff; + } else { + $mask = 0; + + for ($j = $firstBit; $j < $lastBit; $j++) { + $mask |= 1 << $j; + } + } + + $this->bits[$i] = $this->bits[$i] | $mask; + } + } + + /** + * Clears the bit array, unsetting every bit. + * + * @return void + */ + public function clear() + { + $bitsLength = count($this->bits); + + for ($i = 0; $i < $bitsLength; $i++) { + $this->bits[$i] = 0; + } + } + + /** + * Checks if a range of bits is set or not set. + * + * @param integer $start + * @param integer $end + * @param integer $value + * @return boolean + * @throws Exception\InvalidArgumentException + */ + public function isRange($start, $end, $value) + { + if ($end < $start) { + throw new Exception\InvalidArgumentException('End must be greater or equal to start'); + } + + if ($end === $start) { + return; + } + + $end--; + + $firstInt = $start >> 5; + $lastInt = $end >> 5; + + for ($i = $firstInt; $i <= $lastInt; $i++) { + $firstBit = $i > $firstInt ? 0 : $start & 0x1f; + $lastBit = $i < $lastInt ? 31 : $end & 0x1f; + + if ($firstBit === 0 && $lastBit === 31) { + $mask = 0x7fffffff; + } else { + $mask = 0; + + for ($j = $firstBit; $j <= $lastBit; $j++) { + $mask |= 1 << $j; + } + } + + if (($this->bits[$i] & $mask) !== ($value ? $mask : 0)) { + return false; + } + } + + return true; + } + + /** + * Appends a bit to the array. + * + * @param boolean $bit + * @return void + */ + public function appendBit($bit) + { + $this->ensureCapacity($this->size + 1); + + if ($bit) { + $this->bits[$this->size >> 5] = $this->bits[$this->size >> 5] | (1 << ($this->size & 0x1f)); + } + + $this->size++; + } + + /** + * Appends a number of bits (up to 32) to the array. + * + * @param integer $value + * @param integer $numBits + * @return void + * @throws Exception\InvalidArgumentException + */ + public function appendBits($value, $numBits) + { + if ($numBits < 0 || $numBits > 32) { + throw new Exception\InvalidArgumentException('Num bits must be between 0 and 32'); + } + + $this->ensureCapacity($this->size + $numBits); + + for ($numBitsLeft = $numBits; $numBitsLeft > 0; $numBitsLeft--) { + $this->appendBit((($value >> ($numBitsLeft - 1)) & 0x01) === 1); + } + } + + /** + * Appends another bit array to this array. + * + * @param BitArray $other + * @return void + */ + public function appendBitArray(self $other) + { + $otherSize = $other->getSize(); + $this->ensureCapacity($this->size + $other->getSize()); + + for ($i = 0; $i < $otherSize; $i++) { + $this->appendBit($other->get($i)); + } + } + + /** + * Makes an exclusive-or comparision on the current bit array. + * + * @param BitArray $other + * @return void + * @throws Exception\InvalidArgumentException + */ + public function xorBits(self $other) + { + $bitsLength = count($this->bits); + $otherBits = $other->getBitArray(); + + if ($bitsLength !== count($otherBits)) { + throw new Exception\InvalidArgumentException('Sizes don\'t match'); + } + + for ($i = 0; $i < $bitsLength; $i++) { + $this->bits[$i] = $this->bits[$i] ^ $otherBits[$i]; + } + } + + /** + * Converts the bit array to a byte array. + * + * @param integer $bitOffset + * @param integer $numBytes + * @return SplFixedArray + */ + public function toBytes($bitOffset, $numBytes) + { + $bytes = new SplFixedArray($numBytes); + + for ($i = 0; $i < $numBytes; $i++) { + $byte = 0; + + for ($j = 0; $j < 8; $j++) { + if ($this->get($bitOffset)) { + $byte |= 1 << (7 - $j); + } + + $bitOffset++; + } + + $bytes[$i] = $byte; + } + + return $bytes; + } + + /** + * Gets the internal bit array. + * + * @return SplFixedArray + */ + public function getBitArray() + { + return $this->bits; + } + + /** + * Reverses the array. + * + * @return void + */ + public function reverse() + { + $newBits = new SplFixedArray(count($this->bits)); + + for ($i = 0; $i < $this->size; $i++) { + if ($this->get($this->size - $i - 1)) { + $newBits[$i >> 5] = $newBits[$i >> 5] | (1 << ($i & 0x1f)); + } + } + + $this->bits = newBits; + } + + /** + * Returns a string representation of the bit array. + * + * @return string + */ + public function __toString() + { + $result = ''; + + for ($i = 0; $i < $this->size; $i++) { + if (($i & 0x07) === 0) { + $result .= ' '; + } + + $result .= $this->get($i) ? 'X' : '.'; + } + + return $result; + } +} diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/BitMatrix.php b/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/BitMatrix.php new file mode 100644 index 00000000..b930f88b --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/BitMatrix.php @@ -0,0 +1,350 @@ +width = $width; + $this->height = $height; + $this->rowSize = ($width + 31) >> 5; + $this->bits = new SplFixedArray($this->rowSize * $height); + } + + /** + * Gets the requested bit, where true means black. + * + * @param integer $x + * @param integer $y + * @return boolean + */ + public function get($x, $y) + { + $offset = $y * $this->rowSize + ($x >> 5); + return (BitUtils::unsignedRightShift($this->bits[$offset], ($x & 0x1f)) & 1) !== 0; + } + + /** + * Sets the given bit to true. + * + * @param integer $x + * @param integer $y + * @return void + */ + public function set($x, $y) + { + $offset = $y * $this->rowSize + ($x >> 5); + $this->bits[$offset] = $this->bits[$offset] | (1 << ($x & 0x1f)); + } + + /** + * Flips the given bit. + * + * @param integer $x + * @param integer $y + * @return void + */ + public function flip($x, $y) + { + $offset = $y * $this->rowSize + ($x >> 5); + $this->bits[$offset] = $this->bits[$offset] ^ (1 << ($x & 0x1f)); + } + + /** + * Clears all bits (set to false). + * + * @return void + */ + public function clear() + { + $max = count($this->bits); + + for ($i = 0; $i < $max; $i++) { + $this->bits[$i] = 0; + } + } + + /** + * Sets a square region of the bit matrix to true. + * + * @param integer $left + * @param integer $top + * @param integer $width + * @param integer $height + * @return void + */ + public function setRegion($left, $top, $width, $height) + { + if ($top < 0 || $left < 0) { + throw new Exception\InvalidArgumentException('Left and top must be non-negative'); + } + + if ($height < 1 || $width < 1) { + throw new Exception\InvalidArgumentException('Width and height must be at least 1'); + } + + $right = $left + $width; + $bottom = $top + $height; + + if ($bottom > $this->height || $right > $this->width) { + throw new Exception\InvalidArgumentException('The region must fit inside the matrix'); + } + + for ($y = $top; $y < $bottom; $y++) { + $offset = $y * $this->rowSize; + + for ($x = $left; $x < $right; $x++) { + $index = $offset + ($x >> 5); + $this->bits[$index] = $this->bits[$index] | (1 << ($x & 0x1f)); + } + } + } + + /** + * A fast method to retrieve one row of data from the matrix as a BitArray. + * + * @param integer $y + * @param BitArray $row + * @return BitArray + */ + public function getRow($y, BitArray $row = null) + { + if ($row === null || $row->getSize() < $this->width) { + $row = new BitArray($this->width); + } + + $offset = $y * $this->rowSize; + + for ($x = 0; $x < $this->rowSize; $x++) { + $row->setBulk($x << 5, $this->bits[$offset + $x]); + } + + return $row; + } + + /** + * Sets a row of data from a BitArray. + * + * @param integer $y + * @param BitArray $row + * @return void + */ + public function setRow($y, BitArray $row) + { + $bits = $row->getBitArray(); + + for ($i = 0; $i < $this->rowSize; $i++) { + $this->bits[$y * $this->rowSize + $i] = $bits[$i]; + } + } + + /** + * This is useful in detecting the enclosing rectangle of a 'pure' barcode. + * + * @return SplFixedArray + */ + public function getEnclosingRectangle() + { + $left = $this->width; + $top = $this->height; + $right = -1; + $bottom = -1; + + for ($y = 0; $y < $this->height; $y++) { + for ($x32 = 0; $x32 < $this->rowSize; $x32++) { + $bits = $this->bits[$y * $this->rowSize + $x32]; + + if ($bits !== 0) { + if ($y < $top) { + $top = $y; + } + + if ($y > $bottom) { + $bottom = $y; + } + + if ($x32 * 32 < $left) { + $bit = 0; + + while (($bits << (31 - $bit)) === 0) { + $bit++; + } + + if (($x32 * 32 + $bit) < $left) { + $left = $x32 * 32 + $bit; + } + } + } + + if ($x32 * 32 + 31 > $right) { + $bit = 31; + + while (BitUtils::unsignedRightShift($bits, $bit) === 0) { + $bit--; + } + + if (($x32 * 32 + $bit) > $right) { + $right = $x32 * 32 + $bit; + } + } + } + } + + $width = $right - $left; + $height = $bottom - $top; + + if ($width < 0 || $height < 0) { + return null; + } + + return SplFixedArray::fromArray(array($left, $top, $width, $height), false); + } + + /** + * Gets the most top left set bit. + * + * This is useful in detecting a corner of a 'pure' barcode. + * + * @return SplFixedArray + */ + public function getTopLeftOnBit() + { + $bitsOffset = 0; + + while ($bitsOffset < count($this->bits) && $this->bits[$bitsOffset] === 0) { + $bitsOffset++; + } + + if ($bitsOffset === count($this->bits)) { + return null; + } + + $x = intval($bitsOffset / $this->rowSize); + $y = ($bitsOffset % $this->rowSize) << 5; + + $bits = $this->bits[$bitsOffset]; + $bit = 0; + + while (($bits << (31 - $bit)) === 0) { + $bit++; + } + + $x += $bit; + + return SplFixedArray::fromArray(array($x, $y), false); + } + + /** + * Gets the most bottom right set bit. + * + * This is useful in detecting a corner of a 'pure' barcode. + * + * @return SplFixedArray + */ + public function getBottomRightOnBit() + { + $bitsOffset = count($this->bits) - 1; + + while ($bitsOffset >= 0 && $this->bits[$bitsOffset] === 0) { + $bitsOffset--; + } + + if ($bitsOffset < 0) { + return null; + } + + $x = intval($bitsOffset / $this->rowSize); + $y = ($bitsOffset % $this->rowSize) << 5; + + $bits = $this->bits[$bitsOffset]; + $bit = 0; + + while (BitUtils::unsignedRightShift($bits, $bit) === 0) { + $bit--; + } + + $x += $bit; + + return SplFixedArray::fromArray(array($x, $y), false); + } + + /** + * Gets the width of the matrix, + * + * @return integer + */ + public function getWidth() + { + return $this->width; + } + + /** + * Gets the height of the matrix. + * + * @return integer + */ + public function getHeight() + { + return $this->height; + } +} diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/BitUtils.php b/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/BitUtils.php new file mode 100644 index 00000000..a6412440 --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/BitUtils.php @@ -0,0 +1,51 @@ +>>" in other + * languages. + * + * @param integer $a + * @param integer $b + * @return integer + */ + public static function unsignedRightShift($a, $b) + { + return ( + $a >= 0 + ? $a >> $b + : (($a & 0x7fffffff) >> $b) | (0x40000000 >> ($b - 1)) + ); + } + + /** + * Gets the number of trailing zeros. + * + * @param integer $i + * @return integer + */ + public static function numberOfTrailingZeros($i) + { + $lastPos = strrpos(str_pad(decbin($i), 32, '0', STR_PAD_LEFT), '1'); + + return $lastPos === false ? 32 : 31 - $lastPos; + } +} \ No newline at end of file diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/CharacterSetEci.php b/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/CharacterSetEci.php new file mode 100644 index 00000000..77662360 --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/CharacterSetEci.php @@ -0,0 +1,134 @@ + self::ISO8859_1, + 'ISO-8859-2' => self::ISO8859_2, + 'ISO-8859-3' => self::ISO8859_3, + 'ISO-8859-4' => self::ISO8859_4, + 'ISO-8859-5' => self::ISO8859_5, + 'ISO-8859-6' => self::ISO8859_6, + 'ISO-8859-7' => self::ISO8859_7, + 'ISO-8859-8' => self::ISO8859_8, + 'ISO-8859-9' => self::ISO8859_9, + 'ISO-8859-10' => self::ISO8859_10, + 'ISO-8859-11' => self::ISO8859_11, + 'ISO-8859-12' => self::ISO8859_12, + 'ISO-8859-13' => self::ISO8859_13, + 'ISO-8859-14' => self::ISO8859_14, + 'ISO-8859-15' => self::ISO8859_15, + 'ISO-8859-16' => self::ISO8859_16, + 'SHIFT-JIS' => self::SJIS, + 'WINDOWS-1250' => self::CP1250, + 'WINDOWS-1251' => self::CP1251, + 'WINDOWS-1252' => self::CP1252, + 'WINDOWS-1256' => self::CP1256, + 'UTF-16BE' => self::UNICODE_BIG_UNMARKED, + 'UTF-8' => self::UTF8, + 'ASCII' => self::ASCII, + 'GBK' => self::GB18030, + 'EUC-KR' => self::EUC_KR, + ); + + /** + * Additional possible values for character sets. + * + * @var array + */ + protected $additionalValues = array( + self::CP437 => 2, + self::ASCII => 170, + ); + + /** + * Gets character set ECI by value. + * + * @param string $name + * @return CharacterSetEci|null + */ + public static function getCharacterSetECIByValue($value) + { + if ($value < 0 || $value >= 900) { + throw new Exception\InvalidArgumentException('Value must be between 0 and 900'); + } + + if (false !== ($key = array_search($value, self::$additionalValues))) { + $value = $key; + } + + try { + return new self($value); + } catch (Exception\UnexpectedValueException $e) { + return null; + } + } + + /** + * Gets character set ECI by name. + * + * @param string $name + * @return CharacterSetEci|null + */ + public static function getCharacterSetECIByName($name) + { + $name = strtoupper($name); + + if (isset(self::$nameToEci[$name])) { + return new self(self::$nameToEci[$name]); + } + + return null; + } +} diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/EcBlock.php b/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/EcBlock.php new file mode 100644 index 00000000..cbcc2ba0 --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/EcBlock.php @@ -0,0 +1,65 @@ +count = $count; + $this->dataCodewords = $dataCodewords; + } + + /** + * Returns how many times the block is used. + * + * @return integer + */ + public function getCount() + { + return $this->count; + } + + /** + * Returns the number of data codewords. + * + * @return integer + */ + public function getDataCodewords() + { + return $this->dataCodewords; + } +} diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/EcBlocks.php b/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/EcBlocks.php new file mode 100644 index 00000000..87cef5d0 --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/EcBlocks.php @@ -0,0 +1,101 @@ +ecCodewordsPerBlock = $ecCodewordsPerBlock; + + $this->ecBlocks = new SplFixedArray($ecb2 === null ? 1 : 2); + $this->ecBlocks[0] = $ecb1; + + if ($ecb2 !== null) { + $this->ecBlocks[1] = $ecb2; + } + } + + /** + * Gets the number of EC codewords per block. + * + * @return integer + */ + public function getEcCodewordsPerBlock() + { + return $this->ecCodewordsPerBlock; + } + + /** + * Gets the total number of EC block appearances. + * + * @return integer + */ + public function getNumBlocks() + { + $total = 0; + + foreach ($this->ecBlocks as $ecBlock) { + $total += $ecBlock->getCount(); + } + + return $total; + } + + /** + * Gets the total count of EC codewords. + * + * @return integer + */ + public function getTotalEcCodewords() + { + return $this->ecCodewordsPerBlock * $this->getNumBlocks(); + } + + /** + * Gets the EC blocks included in this collection. + * + * @return SplFixedArray + */ + public function getEcBlocks() + { + return $this->ecBlocks; + } +} diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/ErrorCorrectionLevel.php b/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/ErrorCorrectionLevel.php new file mode 100644 index 00000000..bd0a60a3 --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/ErrorCorrectionLevel.php @@ -0,0 +1,62 @@ +value) { + case self::L: + return 0; + break; + + case self::M: + return 1; + break; + + case self::Q: + return 2; + break; + + case self::H: + return 3; + break; + } + } +} diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/FormatInformation.php b/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/FormatInformation.php new file mode 100644 index 00000000..5ec9ffd4 --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/FormatInformation.php @@ -0,0 +1,236 @@ +ecLevel = new ErrorCorrectionLevel(($formatInfo >> 3) & 0x3); + $this->dataMask = $formatInfo & 0x7; + } + + /** + * Checks how many bits are different between two integers. + * + * @param integer $a + * @param integer $b + * @return integer + */ + public static function numBitsDiffering($a, $b) + { + $a ^= $b; + + return ( + self::$bitsSetInHalfByte[$a & 0xf] + + self::$bitsSetInHalfByte[(BitUtils::unsignedRightShift($a, 4) & 0xf)] + + self::$bitsSetInHalfByte[(BitUtils::unsignedRightShift($a, 8) & 0xf)] + + self::$bitsSetInHalfByte[(BitUtils::unsignedRightShift($a, 12) & 0xf)] + + self::$bitsSetInHalfByte[(BitUtils::unsignedRightShift($a, 16) & 0xf)] + + self::$bitsSetInHalfByte[(BitUtils::unsignedRightShift($a, 20) & 0xf)] + + self::$bitsSetInHalfByte[(BitUtils::unsignedRightShift($a, 24) & 0xf)] + + self::$bitsSetInHalfByte[(BitUtils::unsignedRightShift($a, 28) & 0xf)] + ); + } + + /** + * Decodes format information. + * + * @param integer $maskedFormatInfo1 + * @param integer $maskedFormatInfo2 + * @return FormatInformation|null + */ + public static function decodeFormatInformation($maskedFormatInfo1, $maskedFormatInfo2) + { + $formatInfo = self::doDecodeFormatInformation($maskedFormatInfo1, $maskedFormatInfo2); + + if ($formatInfo !== null) { + return $formatInfo; + } + + // Should return null, but, some QR codes apparently do not mask this + // info. Try again by actually masking the pattern first. + return self::doDecodeFormatInformation( + $maskedFormatInfo1 ^ self::FORMAT_INFO_MASK_QR, + $maskedFormatInfo2 ^ self::FORMAT_INFO_MASK_QR + ); + } + + /** + * Internal method for decoding format information. + * + * @param integer $maskedFormatInfo1 + * @param integer $maskedFormatInfo2 + * @return FormatInformation|null + */ + protected static function doDecodeFormatInformation($maskedFormatInfo1, $maskedFormatInfo2) + { + $bestDifference = PHP_INT_MAX; + $bestFormatInfo = 0; + + foreach (self::$formatInfoDecodeLookup as $decodeInfo) { + $targetInfo = $decodeInfo[0]; + + if ($targetInfo === $maskedFormatInfo1 || $targetInfo === $maskedFormatInfo2) { + // Found an exact match + return new self($decodeInfo[1]); + } + + $bitsDifference = self::numBitsDiffering($maskedFormatInfo1, $targetInfo); + + if ($bitsDifference < $bestDifference) { + $bestFormatInfo = $decodeInfo[1]; + $bestDifference = $bitsDifference; + } + + if ($maskedFormatInfo1 !== $maskedFormatInfo2) { + // Also try the other option + $bitsDifference = self::numBitsDiffering($maskedFormatInfo2, $targetInfo); + + if ($bitsDifference < $bestDifference) { + $bestFormatInfo = $decodeInfo[1]; + $bestDifference = $bitsDifference; + } + } + } + + // Hamming distance of the 32 masked codes is 7, by construction, so + // <= 3 bits differing means we found a match. + if ($bestDifference <= 3) { + return new self($bestFormatInfo); + } + + return null; + } + + /** + * Gets the error correction level. + * + * @return ErrorCorrectionLevel + */ + public function getErrorCorrectionLevel() + { + return $this->ecLevel; + } + + /** + * Gets the data mask. + * + * @return integer + */ + public function getDataMask() + { + return $this->dataMask; + } + + /** + * Hashes the code of the EC level. + * + * @return integer + */ + public function hashCode() + { + return ($this->ecLevel->get() << 3) | $this->dataMask; + } + + /** + * Verifies if this instance equals another one. + * + * @param mixed $other + * @return boolean + */ + public function equals($other) { + if (!$other instanceof self) { + return false; + } + + return ( + $this->ecLevel->get() === $other->getErrorCorrectionLevel()->get() + && $this->dataMask === $other->getDataMask() + ); + } +} diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/Mode.php b/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/Mode.php new file mode 100644 index 00000000..8faf344e --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/Mode.php @@ -0,0 +1,70 @@ + array(0, 0, 0), + self::NUMERIC => array(10, 12, 14), + self::ALPHANUMERIC => array(9, 11, 13), + self::STRUCTURED_APPEND => array(0, 0, 0), + self::BYTE => array(8, 16, 16), + self::ECI => array(0, 0, 0), + self::KANJI => array(8, 10, 12), + self::FNC1_FIRST_POSITION => array(0, 0, 0), + self::FNC1_SECOND_POSITION => array(0, 0, 0), + self::HANZI => array(8, 10, 12), + ); + + /** + * Gets the number of bits used in a specific QR code version. + * + * @param Version $version + * @return integer + */ + public function getCharacterCountBits(Version $version) + { + $number = $version->getVersionNumber(); + + if ($number <= 9) { + $offset = 0; + } elseif ($number <= 26) { + $offset = 1; + } else { + $offset = 2; + } + + return self::$characterCountBitsForVersions[$this->value][$offset]; + } +} diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/ReedSolomonCodec.php b/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/ReedSolomonCodec.php new file mode 100644 index 00000000..e8d45b94 --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/ReedSolomonCodec.php @@ -0,0 +1,476 @@ + 8) { + throw new Exception\InvalidArgumentException('Symbol size must be between 0 and 8'); + } + + if ($firstRoot < 0 || $firstRoot >= (1 << $symbolSize)) { + throw new Exception\InvalidArgumentException('First root must be between 0 and ' . (1 << $symbolSize)); + } + + if ($numRoots < 0 || $numRoots >= (1 << $symbolSize)) { + throw new Exception\InvalidArgumentException('Num roots must be between 0 and ' . (1 << $symbolSize)); + } + + if ($padding < 0 || $padding >= ((1 << $symbolSize) - 1 - $numRoots)) { + throw new Exception\InvalidArgumentException('Padding must be between 0 and ' . ((1 << $symbolSize) - 1 - $numRoots)); + } + + $this->symbolSize = $symbolSize; + $this->blockSize = (1 << $symbolSize) - 1; + $this->padding = $padding; + $this->alphaTo = SplFixedArray::fromArray(array_fill(0, $this->blockSize + 1, 0), false); + $this->indexOf = SplFixedArray::fromArray(array_fill(0, $this->blockSize + 1, 0), false); + + // Generate galous field lookup table + $this->indexOf[0] = $this->blockSize; + $this->alphaTo[$this->blockSize] = 0; + + $sr = 1; + + for ($i = 0; $i < $this->blockSize; $i++) { + $this->indexOf[$sr] = $i; + $this->alphaTo[$i] = $sr; + + $sr <<= 1; + + if ($sr & (1 << $symbolSize)) { + $sr ^= $gfPoly; + } + + $sr &= $this->blockSize; + } + + if ($sr !== 1) { + throw new Exception\RuntimeException('Field generator polynomial is not primitive'); + } + + // Form RS code generator polynomial from its roots + $this->generatorPoly = SplFixedArray::fromArray(array_fill(0, $numRoots + 1, 0), false); + $this->firstRoot = $firstRoot; + $this->primitive = $primitive; + $this->numRoots = $numRoots; + + // Find prim-th root of 1, used in decoding + for ($iPrimitive = 1; ($iPrimitive % $primitive) !== 0; $iPrimitive += $this->blockSize); + $this->iPrimitive = intval($iPrimitive / $primitive); + + $this->generatorPoly[0] = 1; + + for ($i = 0, $root = $firstRoot * $primitive; $i < $numRoots; $i++, $root += $primitive) { + $this->generatorPoly[$i + 1] = 1; + + for ($j = $i; $j > 0; $j--) { + if ($this->generatorPoly[$j] !== 0) { + $this->generatorPoly[$j] = $this->generatorPoly[$j - 1] ^ $this->alphaTo[$this->modNn($this->indexOf[$this->generatorPoly[$j]] + $root)]; + } else { + $this->generatorPoly[$j] = $this->generatorPoly[$j - 1]; + } + } + + $this->generatorPoly[$j] = $this->alphaTo[$this->modNn($this->indexOf[$this->generatorPoly[0]] + $root)]; + } + + // Convert generator poly to index form for quicker encoding + for ($i = 0; $i <= $numRoots; $i++) { + $this->generatorPoly[$i] = $this->indexOf[$this->generatorPoly[$i]]; + } + } + + /** + * Encodes data and writes result back into parity array. + * + * @param SplFixedArray $data + * @param SplFixedArray $parity + * @return void + */ + public function encode(SplFixedArray $data, SplFixedArray $parity) + { + for ($i = 0; $i < $this->numRoots; $i++) { + $parity[$i] = 0; + } + + $iterations = $this->blockSize - $this->numRoots - $this->padding; + + for ($i = 0; $i < $iterations; $i++) { + $feedback = $this->indexOf[$data[$i] ^ $parity[0]]; + + if ($feedback !== $this->blockSize) { + // Feedback term is non-zero + $feedback = $this->modNn($this->blockSize - $this->generatorPoly[$this->numRoots] + $feedback); + + for ($j = 1; $j < $this->numRoots; $j++) { + $parity[$j] = $parity[$j] ^ $this->alphaTo[$this->modNn($feedback + $this->generatorPoly[$this->numRoots - $j])]; + } + } + + for ($j = 0; $j < $this->numRoots - 1; $j++) { + $parity[$j] = $parity[$j + 1]; + } + + if ($feedback !== $this->blockSize) { + $parity[$this->numRoots - 1] = $this->alphaTo[$this->modNn($feedback + $this->generatorPoly[0])]; + } else { + $parity[$this->numRoots - 1] = 0; + } + } + } + + /** + * Decodes received data. + * + * @param SplFixedArray $data + * @param SplFixedArray|null $erasures + * @return null|integer + */ + public function decode(SplFixedArray $data, SplFixedArray $erasures = null) + { + // This speeds up the initialization a bit. + $numRootsPlusOne = SplFixedArray::fromArray(array_fill(0, $this->numRoots + 1, 0), false); + $numRoots = SplFixedArray::fromArray(array_fill(0, $this->numRoots, 0), false); + + $lambda = clone $numRootsPlusOne; + $b = clone $numRootsPlusOne; + $t = clone $numRootsPlusOne; + $omega = clone $numRootsPlusOne; + $root = clone $numRoots; + $loc = clone $numRoots; + + $numErasures = ($erasures !== null ? count($erasures) : 0); + + // Form the Syndromes; i.e., evaluate data(x) at roots of g(x) + $syndromes = SplFixedArray::fromArray(array_fill(0, $this->numRoots, $data[0]), false); + + for ($i = 1; $i < $this->blockSize - $this->padding; $i++) { + for ($j = 0; $j < $this->numRoots; $j++) { + if ($syndromes[$j] === 0) { + $syndromes[$j] = $data[$i]; + } else { + $syndromes[$j] = $data[$i] ^ $this->alphaTo[ + $this->modNn($this->indexOf[$syndromes[$j]] + ($this->firstRoot + $j) * $this->primitive) + ]; + } + } + } + + // Convert syndromes to index form, checking for nonzero conditions + $syndromeError = 0; + + for ($i = 0; $i < $this->numRoots; $i++) { + $syndromeError |= $syndromes[$i]; + $syndromes[$i] = $this->indexOf[$syndromes[$i]]; + } + + if (!$syndromeError) { + // If syndrome is zero, data[] is a codeword and there are no errors + // to correct, so return data[] unmodified. + return 0; + } + + $lambda[0] = 1; + + if ($numErasures > 0) { + // Init lambda to be the erasure locator polynomial + $lambda[1] = $this->alphaTo[$this->modNn($this->primitive * ($this->blockSize - 1 - $erasures[0]))]; + + for ($i = 1; $i < $numErasures; $i++) { + $u = $this->modNn($this->primitive * ($this->blockSize - 1 - $erasures[$i])); + + for ($j = $i + 1; $j > 0; $j--) { + $tmp = $this->indexOf[$lambda[$j - 1]]; + + if ($tmp !== $this->blockSize) { + $lambda[$j] = $lambda[$j] ^ $this->alphaTo[$this->modNn($u + $tmp)]; + } + } + } + } + + for ($i = 0; $i <= $this->numRoots; $i++) { + $b[$i] = $this->indexOf[$lambda[$i]]; + } + + // Begin Berlekamp-Massey algorithm to determine error+erasure locator + // polynomial + $r = $numErasures; + $el = $numErasures; + + while (++$r <= $this->numRoots) { + // Compute discrepancy at the r-th step in poly form + $discrepancyR = 0; + + for ($i = 0; $i < $r; $i++) { + if ($lambda[$i] !== 0 && $syndromes[$r - $i - 1] !== $this->blockSize) { + $discrepancyR ^= $this->alphaTo[$this->modNn($this->indexOf[$lambda[$i]] + $syndromes[$r - $i - 1])]; + } + } + + $discrepancyR = $this->indexOf[$discrepancyR]; + + if ($discrepancyR === $this->blockSize) { + $tmp = $b->toArray(); + array_unshift($tmp, $this->blockSize); + array_pop($tmp); + $b = SplFixedArray::fromArray($tmp, false); + } else { + $t[0] = $lambda[0]; + + for ($i = 0; $i < $this->numRoots; $i++) { + if ($b[$i] !== $this->blockSize) { + $t[$i + 1] = $lambda[$i + 1] ^ $this->alphaTo[$this->modNn($discrepancyR + $b[$i])]; + } else { + $t[$i + 1] = $lambda[$i + 1]; + } + } + + if (2 * $el <= $r + $numErasures - 1) { + $el = $r + $numErasures - $el; + + for ($i = 0; $i <= $this->numRoots; $i++) { + $b[$i] = ( + $lambda[$i] === 0 + ? $this->blockSize + : $this->modNn($this->indexOf[$lambda[$i]] - $discrepancyR + $this->blockSize) + ); + } + } else { + $tmp = $b->toArray(); + array_unshift($tmp, $this->blockSize); + array_pop($tmp); + $b = SplFixedArray::fromArray($tmp, false); + } + + $lambda = clone $t; + } + } + + // Convert lambda to index form and compute deg(lambda(x)) + $degLambda = 0; + + for ($i = 0; $i <= $this->numRoots; $i++) { + $lambda[$i] = $this->indexOf[$lambda[$i]]; + + if ($lambda[$i] !== $this->blockSize) { + $degLambda = $i; + } + } + + // Find roots of the error+erasure locator polynomial by Chien search. + $reg = clone $lambda; + $reg[0] = 0; + $count = 0; + + for ($i = 1, $k = $this->iPrimitive - 1; $i <= $this->blockSize; $i++, $k = $this->modNn($k + $this->iPrimitive)) { + $q = 1; + + for ($j = $degLambda; $j > 0; $j--) { + if ($reg[$j] !== $this->blockSize) { + $reg[$j] = $this->modNn($reg[$j] + $j); + $q ^= $this->alphaTo[$reg[$j]]; + } + } + + if ($q !== 0) { + // Not a root + continue; + } + + // Store root (index-form) and error location number + $root[$count] = $i; + $loc[$count] = $k; + + if (++$count === $degLambda) { + break; + } + } + + if ($degLambda !== $count) { + // deg(lambda) unequal to number of roots: uncorreactable error + // detected + return null; + } + + // Compute err+eras evaluate poly omega(x) = s(x)*lambda(x) (modulo + // x**numRoots). In index form. Also find deg(omega). + $degOmega = $degLambda - 1; + + for ($i = 0; $i <= $degOmega; $i++) { + $tmp = 0; + + for ($j = $i; $j >= 0; $j--) { + if ($syndromes[$i - $j] !== $this->blockSize && $lambda[$j] !== $this->blockSize) { + $tmp ^= $this->alphaTo[$this->modNn($syndromes[$i - $j] + $lambda[$j])]; + } + } + + $omega[$i] = $this->indexOf[$tmp]; + } + + // Compute error values in poly-form. num1 = omega(inv(X(l))), num2 = + // inv(X(l))**(firstRoot-1) and den = lambda_pr(inv(X(l))) all in poly + // form. + for ($j = $count - 1; $j >= 0; $j--) { + $num1 = 0; + + for ($i = $degOmega; $i >= 0; $i--) { + if ($omega[$i] !== $this->blockSize) { + $num1 ^= $this->alphaTo[$this->modNn($omega[$i] + $i * $root[$j])]; + } + } + + $num2 = $this->alphaTo[$this->modNn($root[$j] * ($this->firstRoot - 1) + $this->blockSize)]; + $den = 0; + + // lambda[i+1] for i even is the formal derivativelambda_pr of + // lambda[i] + for ($i = min($degLambda, $this->numRoots - 1) & ~1; $i >= 0; $i -= 2) { + if ($lambda[$i + 1] !== $this->blockSize) { + $den ^= $this->alphaTo[$this->modNn($lambda[$i + 1] + $i * $root[$j])]; + } + } + + // Apply error to data + if ($num1 !== 0 && $loc[$j] >= $this->padding) { + $data[$loc[$j] - $this->padding] = $data[$loc[$j] - $this->padding] ^ ( + $this->alphaTo[ + $this->modNn( + $this->indexOf[$num1] + $this->indexOf[$num2] + $this->blockSize - $this->indexOf[$den] + ) + ] + ); + } + } + + if ($erasures !== null) { + if (count($erasures) < $count) { + $erasures->setSize($count); + } + + for ($i = 0; $i < $count; $i++) { + $erasures[$i] = $loc[$i]; + } + } + + return $count; + } + + /** + * Computes $x % GF_SIZE, where GF_SIZE is 2**GF_BITS - 1, without a slow + * divide. + * + * @param itneger $x + * @return integer + */ + protected function modNn($x) + { + while ($x >= $this->blockSize) { + $x -= $this->blockSize; + $x = ($x >> $this->symbolSize) + ($x & $this->blockSize); + } + + return $x; + } +} diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/Version.php b/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/Version.php new file mode 100644 index 00000000..d6986399 --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/Version.php @@ -0,0 +1,687 @@ +versionNumber = $versionNumber; + $this->alignmentPatternCenters = $alignmentPatternCenters; + $this->errorCorrectionBlocks = $ecBlocks; + + $totalCodewords = 0; + $ecCodewords = $ecBlocks[0]->getEcCodewordsPerBlock(); + + foreach ($ecBlocks[0]->getEcBlocks() as $ecBlock) { + $totalCodewords += $ecBlock->getCount() * ($ecBlock->getDataCodewords() + $ecCodewords); + } + + $this->totalCodewords = $totalCodewords; + } + + /** + * Gets the version number. + * + * @return integer + */ + public function getVersionNumber() + { + return $this->versionNumber; + } + + /** + * Gets the alignment pattern centers. + * + * @return SplFixedArray + */ + public function getAlignmentPatternCenters() + { + return $this->alignmentPatternCenters; + } + + /** + * Gets the total number of codewords. + * + * @return integer + */ + public function getTotalCodewords() + { + return $this->totalCodewords; + } + + /** + * Gets the dimension for the current version. + * + * @return integer + */ + public function getDimensionForVersion() + { + return 17 + 4 * $this->versionNumber; + } + + /** + * Gets the number of EC blocks for a specific EC level. + * + * @param ErrorCorrectionLevel $ecLevel + * @return integer + */ + public function getEcBlocksForLevel(ErrorCorrectionLevel $ecLevel) + { + return $this->errorCorrectionBlocks[$ecLevel->getOrdinal()]; + } + + /** + * Gets a provisional version number for a specific dimension. + * + * @param integer $dimension + * @return Version + * @throws Exception\InvalidArgumentException + */ + public static function getProvisionalVersionForDimension($dimension) + { + if ($dimension % 4 !== 1) { + throw new Exception\InvalidArgumentException('Dimension is not 1 mod 4'); + } + + return self::getVersionForNumber(($dimension - 17) >> 2); + } + + /** + * Gets a version instance for a specific version number. + * + * @param integer $versionNumber + * @return Version + * @throws Exception\InvalidArgumentException + */ + public static function getVersionForNumber($versionNumber) + { + if ($versionNumber < 1 || $versionNumber > 40) { + throw new Exception\InvalidArgumentException('Version number must be between 1 and 40'); + } + + if (!isset(self::$versions[$versionNumber])) { + self::buildVersion($versionNumber); + } + + return self::$versions[$versionNumber - 1]; + } + + /** + * Decodes version information from an integer and returns the version. + * + * @param integer $versionBits + * @return Version|null + */ + public static function decodeVersionInformation($versionBits) + { + $bestDifference = PHP_INT_MAX; + $bestVersion = 0; + + foreach (self::$versionDecodeInfo as $i => $targetVersion) { + if ($targetVersion === $versionBits) { + return self::getVersionForNumber($i + 7); + } + + $bitsDifference = FormatInformation::numBitsDiffering($versionBits, $targetVersion); + + if ($bitsDifference < $bestDifference) { + $bestVersion = $i + 7; + $bestDifference = $bitsDifference; + } + } + + if ($bestDifference <= 3) { + return self::getVersionForNumber($bestVersion); + } + + return null; + } + + /** + * Builds the function pattern for the current version. + * + * @return BitMatrix + */ + public function buildFunctionPattern() + { + $dimension = $this->getDimensionForVersion(); + $bitMatrix = new BitMatrix($dimension); + + // Top left finder pattern + separator + format + $bitMatrix->setRegion(0, 0, 9, 9); + // Top right finder pattern + separator + format + $bitMatrix->setRegion($dimension - 8, 0, 8, 9); + // Bottom left finder pattern + separator + format + $bitMatrix->setRegion(0, $dimension - 8, 9, 8); + + // Alignment patterns + $max = count($this->alignmentPatternCenters); + + for ($x = 0; $x < $max; $x++) { + $i = $this->alignmentPatternCenters[$x] - 2; + + for ($y = 0; $y < $max; $y++) { + if (($x === 0 && ($y === 0 || $y === $max - 1)) || ($x === $max - 1 && $y === 0)) { + // No alignment patterns near the three finder paterns + continue; + } + + $bitMatrix->setRegion($this->alignmentPatternCenters[$y] - 2, $i, 5, 5); + } + } + + // Vertical timing pattern + $bitMatrix->setRegion(6, 9, 1, $dimension - 17); + // Horizontal timing pattern + $bitMatrix->setRegion(9, 6, $dimension - 17, 1); + + if ($this->versionNumber > 6) { + // Version info, top right + $bitMatrix->setRegion($dimension - 11, 0, 3, 6); + // Version info, bottom left + $bitMatrix->setRegion(0, $dimension - 11, 6, 3); + } + + return $bitMatrix; + } + + /** + * Returns a string representation for the version. + * + * @return string + */ + public function __toString() + { + return (string) $this->versionNumber; + } + + /** + * Build and cache a specific version. + * + * See ISO 18004:2006 6.5.1 Table 9. + * + * @param integer $versionNumber + * @return void + */ + protected static function buildVersion($versionNumber) + { + switch ($versionNumber) { + case 1: + $patterns = array(); + $ecBlocks = array( + new EcBlocks(7, new EcBlock(1, 19)), + new EcBlocks(10, new EcBlock(1, 16)), + new EcBlocks(13, new EcBlock(1, 13)), + new EcBlocks(17, new EcBlock(1, 9)), + ); + break; + + case 2: + $patterns = array(6, 18); + $ecBlocks = array( + new EcBlocks(10, new EcBlock(1, 34)), + new EcBlocks(16, new EcBlock(1, 28)), + new EcBlocks(22, new EcBlock(1, 22)), + new EcBlocks(28, new EcBlock(1, 16)), + ); + break; + + case 3: + $patterns = array(6, 22); + $ecBlocks = array( + new EcBlocks(15, new EcBlock(1, 55)), + new EcBlocks(26, new EcBlock(1, 44)), + new EcBlocks(18, new EcBlock(2, 17)), + new EcBlocks(22, new EcBlock(2, 13)), + ); + break; + + case 4: + $patterns = array(6, 26); + $ecBlocks = array( + new EcBlocks(20, new EcBlock(1, 80)), + new EcBlocks(18, new EcBlock(2, 32)), + new EcBlocks(26, new EcBlock(3, 24)), + new EcBlocks(16, new EcBlock(4, 9)), + ); + break; + + case 5: + $patterns = array(6, 30); + $ecBlocks = array( + new EcBlocks(26, new EcBlock(1, 108)), + new EcBlocks(24, new EcBlock(2, 43)), + new EcBlocks(18, new EcBlock(2, 15), new EcBlock(2, 16)), + new EcBlocks(22, new EcBlock(2, 11), new EcBlock(2, 12)), + ); + break; + + case 6: + $patterns = array(6, 34); + $ecBlocks = array( + new EcBlocks(18, new EcBlock(2, 68)), + new EcBlocks(16, new EcBlock(4, 27)), + new EcBlocks(24, new EcBlock(4, 19)), + new EcBlocks(28, new EcBlock(4, 15)), + ); + break; + + case 7: + $patterns = array(6, 22, 38); + $ecBlocks = array( + new EcBlocks(20, new EcBlock(2, 78)), + new EcBlocks(18, new EcBlock(4, 31)), + new EcBlocks(18, new EcBlock(2, 14), new EcBlock(4, 15)), + new EcBlocks(26, new EcBlock(4, 13), new EcBlock(1, 14)), + ); + break; + + case 8: + $patterns = array(6, 24, 42); + $ecBlocks = array( + new EcBlocks(24, new EcBlock(2, 97)), + new EcBlocks(22, new EcBlock(2, 38), new EcBlock(2, 39)), + new EcBlocks(22, new EcBlock(4, 18), new EcBlock(2, 19)), + new EcBlocks(26, new EcBlock(4, 14), new EcBlock(2, 15)), + ); + break; + + case 9: + $patterns = array(6, 26, 46); + $ecBlocks = array( + new EcBlocks(30, new EcBlock(2, 116)), + new EcBlocks(22, new EcBlock(3, 36), new EcBlock(2, 37)), + new EcBlocks(20, new EcBlock(4, 16), new EcBlock(4, 17)), + new EcBlocks(24, new EcBlock(4, 12), new EcBlock(4, 13)), + ); + break; + + case 10: + $patterns = array(6, 28, 50); + $ecBlocks = array( + new EcBlocks(18, new EcBlock(2, 68), new EcBlock(2, 69)), + new EcBlocks(26, new EcBlock(4, 43), new EcBlock(1, 44)), + new EcBlocks(24, new EcBlock(6, 19), new EcBlock(2, 20)), + new EcBlocks(28, new EcBlock(6, 15), new EcBlock(2, 16)), + ); + break; + + case 11: + $patterns = array(6, 30, 54); + $ecBlocks = array( + new EcBlocks(20, new EcBlock(4, 81)), + new EcBlocks(30, new EcBlock(1, 50), new EcBlock(4, 51)), + new EcBlocks(28, new EcBlock(4, 22), new EcBlock(4, 23)), + new EcBlocks(24, new EcBlock(3, 12), new EcBlock(8, 13)), + ); + break; + + case 12: + $patterns = array(6, 32, 58); + $ecBlocks = array( + new EcBlocks(24, new EcBlock(2, 92), new EcBlock(2, 93)), + new EcBlocks(22, new EcBlock(6, 36), new EcBlock(2, 37)), + new EcBlocks(26, new EcBlock(4, 20), new EcBlock(6, 21)), + new EcBlocks(28, new EcBlock(7, 14), new EcBlock(4, 15)), + ); + break; + + case 13: + $patterns = array(6, 34, 62); + $ecBlocks = array( + new EcBlocks(26, new EcBlock(4, 107)), + new EcBlocks(22, new EcBlock(8, 37), new EcBlock(1, 38)), + new EcBlocks(24, new EcBlock(8, 20), new EcBlock(4, 21)), + new EcBlocks(22, new EcBlock(12, 11), new EcBlock(4, 12)), + ); + break; + + case 14: + $patterns = array(6, 26, 46, 66); + $ecBlocks = array( + new EcBlocks(30, new EcBlock(3, 115), new EcBlock(1, 116)), + new EcBlocks(24, new EcBlock(4, 40), new EcBlock(5, 41)), + new EcBlocks(20, new EcBlock(11, 16), new EcBlock(5, 17)), + new EcBlocks(24, new EcBlock(11, 12), new EcBlock(5, 13)), + ); + break; + + case 15: + $patterns = array(6, 26, 48, 70); + $ecBlocks = array( + new EcBlocks(22, new EcBlock(5, 87), new EcBlock(1, 88)), + new EcBlocks(24, new EcBlock(5, 41), new EcBlock(5, 42)), + new EcBlocks(30, new EcBlock(5, 24), new EcBlock(7, 25)), + new EcBlocks(24, new EcBlock(11, 12), new EcBlock(7, 13)), + ); + break; + + case 16: + $patterns = array(6, 26, 50, 74); + $ecBlocks = array( + new EcBlocks(24, new EcBlock(5, 98), new EcBlock(1, 99)), + new EcBlocks(28, new EcBlock(7, 45), new EcBlock(3, 46)), + new EcBlocks(24, new EcBlock(15, 19), new EcBlock(2, 20)), + new EcBlocks(30, new EcBlock(3, 15), new EcBlock(13, 16)), + ); + break; + + case 17: + $patterns = array(6, 30, 54, 78); + $ecBlocks = array( + new EcBlocks(28, new EcBlock(1, 107), new EcBlock(5, 108)), + new EcBlocks(28, new EcBlock(10, 46), new EcBlock(1, 47)), + new EcBlocks(28, new EcBlock(1, 22), new EcBlock(15, 23)), + new EcBlocks(28, new EcBlock(2, 14), new EcBlock(17, 15)), + ); + break; + + case 18: + $patterns = array(6, 30, 56, 82); + $ecBlocks = array( + new EcBlocks(30, new EcBlock(5, 120), new EcBlock(1, 121)), + new EcBlocks(26, new EcBlock(9, 43), new EcBlock(4, 44)), + new EcBlocks(28, new EcBlock(17, 22), new EcBlock(1, 23)), + new EcBlocks(28, new EcBlock(2, 14), new EcBlock(19, 15)), + ); + break; + + case 19: + $patterns = array(6, 30, 58, 86); + $ecBlocks = array( + new EcBlocks(28, new EcBlock(3, 113), new EcBlock(4, 114)), + new EcBlocks(26, new EcBlock(3, 44), new EcBlock(11, 45)), + new EcBlocks(26, new EcBlock(17, 21), new EcBlock(4, 22)), + new EcBlocks(26, new EcBlock(9, 13), new EcBlock(16, 14)), + ); + break; + + case 20: + $patterns = array(6, 34, 62, 90); + $ecBlocks = array( + new EcBlocks(28, new EcBlock(3, 107), new EcBlock(5, 108)), + new EcBlocks(26, new EcBlock(3, 41), new EcBlock(13, 42)), + new EcBlocks(30, new EcBlock(15, 24), new EcBlock(5, 25)), + new EcBlocks(28, new EcBlock(15, 15), new EcBlock(10, 16)), + ); + break; + + case 21: + $patterns = array(6, 28, 50, 72, 94); + $ecBlocks = array( + new EcBlocks(28, new EcBlock(4, 116), new EcBlock(4, 117)), + new EcBlocks(26, new EcBlock(17, 42)), + new EcBlocks(28, new EcBlock(17, 22), new EcBlock(6, 23)), + new EcBlocks(30, new EcBlock(19, 16), new EcBlock(6, 17)), + ); + break; + + case 22: + $patterns = array(6, 26, 50, 74, 98); + $ecBlocks = array( + new EcBlocks(28, new EcBlock(2, 111), new EcBlock(7, 112)), + new EcBlocks(28, new EcBlock(17, 46)), + new EcBlocks(30, new EcBlock(7, 24), new EcBlock(16, 25)), + new EcBlocks(24, new EcBlock(34, 13)), + ); + break; + + case 23: + $patterns = array(6, 30, 54, 78, 102); + $ecBlocks = array( + new EcBlocks(30, new EcBlock(4, 121), new EcBlock(5, 122)), + new EcBlocks(28, new EcBlock(4, 47), new EcBlock(14, 48)), + new EcBlocks(30, new EcBlock(11, 24), new EcBlock(14, 25)), + new EcBlocks(30, new EcBlock(16, 15), new EcBlock(14, 16)), + ); + break; + + case 24: + $patterns = array(6, 28, 54, 80, 106); + $ecBlocks = array( + new EcBlocks(30, new EcBlock(6, 117), new EcBlock(4, 118)), + new EcBlocks(28, new EcBlock(6, 45), new EcBlock(14, 46)), + new EcBlocks(30, new EcBlock(11, 24), new EcBlock(16, 25)), + new EcBlocks(30, new EcBlock(30, 16), new EcBlock(2, 17)), + ); + break; + + case 25: + $patterns = array(6, 32, 58, 84, 110); + $ecBlocks = array( + new EcBlocks(26, new EcBlock(8, 106), new EcBlock(4, 107)), + new EcBlocks(28, new EcBlock(8, 47), new EcBlock(13, 48)), + new EcBlocks(30, new EcBlock(7, 24), new EcBlock(22, 25)), + new EcBlocks(30, new EcBlock(22, 15), new EcBlock(13, 16)), + ); + break; + + case 26: + $patterns = array(6, 30, 58, 86, 114); + $ecBlocks = array( + new EcBlocks(28, new EcBlock(10, 114), new EcBlock(2, 115)), + new EcBlocks(28, new EcBlock(19, 46), new EcBlock(4, 47)), + new EcBlocks(28, new EcBlock(28, 22), new EcBlock(6, 23)), + new EcBlocks(30, new EcBlock(33, 16), new EcBlock(4, 17)), + ); + break; + + case 27: + $patterns = array(6, 34, 62, 90, 118); + $ecBlocks = array( + new EcBlocks(30, new EcBlock(8, 122), new EcBlock(4, 123)), + new EcBlocks(28, new EcBlock(22, 45), new EcBlock(3, 46)), + new EcBlocks(30, new EcBlock(8, 23), new EcBlock(26, 24)), + new EcBlocks(30, new EcBlock(12, 15), new EcBlock(28, 16)), + ); + break; + + case 28: + $patterns = array(6, 26, 50, 74, 98, 122); + $ecBlocks = array( + new EcBlocks(30, new EcBlock(3, 117), new EcBlock(10, 118)), + new EcBlocks(28, new EcBlock(3, 45), new EcBlock(23, 46)), + new EcBlocks(30, new EcBlock(4, 24), new EcBlock(31, 25)), + new EcBlocks(30, new EcBlock(11, 15), new EcBlock(31, 16)), + ); + break; + + case 29: + $patterns = array(6, 30, 54, 78, 102, 126); + $ecBlocks = array( + new EcBlocks(30, new EcBlock(7, 116), new EcBlock(7, 117)), + new EcBlocks(28, new EcBlock(21, 45), new EcBlock(7, 46)), + new EcBlocks(30, new EcBlock(1, 23), new EcBlock(37, 24)), + new EcBlocks(30, new EcBlock(19, 15), new EcBlock(26, 16)), + ); + break; + + case 30: + $patterns = array(6, 26, 52, 78, 104, 130); + $ecBlocks = array( + new EcBlocks(30, new EcBlock(5, 115), new EcBlock(10, 116)), + new EcBlocks(28, new EcBlock(19, 47), new EcBlock(10, 48)), + new EcBlocks(30, new EcBlock(15, 24), new EcBlock(25, 25)), + new EcBlocks(30, new EcBlock(23, 15), new EcBlock(25, 16)), + ); + break; + + case 31: + $patterns = array(6, 30, 56, 82, 108, 134); + $ecBlocks = array( + new EcBlocks(30, new EcBlock(13, 115), new EcBlock(3, 116)), + new EcBlocks(28, new EcBlock(2, 46), new EcBlock(29, 47)), + new EcBlocks(30, new EcBlock(42, 24), new EcBlock(1, 25)), + new EcBlocks(30, new EcBlock(23, 15), new EcBlock(28, 16)), + ); + break; + + case 32: + $patterns = array(6, 34, 60, 86, 112, 138); + $ecBlocks = array( + new EcBlocks(30, new EcBlock(17, 115)), + new EcBlocks(28, new EcBlock(10, 46), new EcBlock(23, 47)), + new EcBlocks(30, new EcBlock(10, 24), new EcBlock(35, 25)), + new EcBlocks(30, new EcBlock(19, 15), new EcBlock(35, 16)), + ); + break; + + case 33: + $patterns = array(6, 30, 58, 86, 114, 142); + $ecBlocks = array( + new EcBlocks(30, new EcBlock(17, 115), new EcBlock(1, 116)), + new EcBlocks(28, new EcBlock(14, 46), new EcBlock(21, 47)), + new EcBlocks(30, new EcBlock(29, 24), new EcBlock(19, 25)), + new EcBlocks(30, new EcBlock(11, 15), new EcBlock(46, 16)), + ); + break; + + case 34: + $patterns = array(6, 34, 62, 90, 118, 146); + $ecBlocks = array( + new EcBlocks(30, new EcBlock(13, 115), new EcBlock(6, 116)), + new EcBlocks(28, new EcBlock(14, 46), new EcBlock(23, 47)), + new EcBlocks(30, new EcBlock(44, 24), new EcBlock(7, 25)), + new EcBlocks(30, new EcBlock(59, 16), new EcBlock(1, 17)), + ); + break; + + case 35: + $patterns = array(6, 30, 54, 78, 102, 126, 150); + $ecBlocks = array( + new EcBlocks(30, new EcBlock(12, 121), new EcBlock(7, 122)), + new EcBlocks(28, new EcBlock(12, 47), new EcBlock(26, 48)), + new EcBlocks(30, new EcBlock(39, 24), new EcBlock(14, 25)), + new EcBlocks(30, new EcBlock(22, 15), new EcBlock(41, 16)), + ); + break; + + case 36: + $patterns = array(6, 24, 50, 76, 102, 128, 154); + $ecBlocks = array( + new EcBlocks(30, new EcBlock(6, 121), new EcBlock(14, 122)), + new EcBlocks(28, new EcBlock(6, 47), new EcBlock(34, 48)), + new EcBlocks(30, new EcBlock(46, 24), new EcBlock(10, 25)), + new EcBlocks(30, new EcBlock(2, 15), new EcBlock(64, 16)), + ); + break; + + case 37: + $patterns = array(6, 28, 54, 80, 106, 132, 158); + $ecBlocks = array( + new EcBlocks(30, new EcBlock(17, 122), new EcBlock(4, 123)), + new EcBlocks(28, new EcBlock(29, 46), new EcBlock(14, 47)), + new EcBlocks(30, new EcBlock(49, 24), new EcBlock(10, 25)), + new EcBlocks(30, new EcBlock(24, 15), new EcBlock(46, 16)), + ); + break; + + case 38: + $patterns = array(6, 32, 58, 84, 110, 136, 162); + $ecBlocks = array( + new EcBlocks(30, new EcBlock(4, 122), new EcBlock(18, 123)), + new EcBlocks(28, new EcBlock(13, 46), new EcBlock(32, 47)), + new EcBlocks(30, new EcBlock(48, 24), new EcBlock(14, 25)), + new EcBlocks(30, new EcBlock(42, 15), new EcBlock(32, 16)), + ); + break; + + case 39: + $patterns = array(6, 26, 54, 82, 110, 138, 166); + $ecBlocks = array( + new EcBlocks(30, new EcBlock(20, 117), new EcBlock(4, 118)), + new EcBlocks(28, new EcBlock(40, 47), new EcBlock(7, 48)), + new EcBlocks(30, new EcBlock(43, 24), new EcBlock(22, 25)), + new EcBlocks(30, new EcBlock(10, 15), new EcBlock(67, 16)), + ); + break; + + case 40: + $patterns = array(6, 30, 58, 86, 114, 142, 170); + $ecBlocks = array( + new EcBlocks(30, new EcBlock(19, 118), new EcBlock(6, 119)), + new EcBlocks(28, new EcBlock(18, 47), new EcBlock(31, 48)), + new EcBlocks(30, new EcBlock(34, 24), new EcBlock(34, 25)), + new EcBlocks(30, new EcBlock(20, 15), new EcBlock(61, 16)), + ); + break; + } + + self::$versions[$versionNumber - 1] = new self( + $versionNumber, + SplFixedArray::fromArray($patterns, false), + SplFixedArray::fromArray($ecBlocks, false) + ); + } +} diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Encoder/BlockPair.php b/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Encoder/BlockPair.php new file mode 100644 index 00000000..090db297 --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Encoder/BlockPair.php @@ -0,0 +1,64 @@ +dataBytes = $data; + $this->errorCorrectionBytes = $errorCorrection; + } + + /** + * Gets the data bytes. + * + * @return SplFixedArray + */ + public function getDataBytes() + { + return $this->dataBytes; + } + + /** + * Gets the error correction bytes. + * + * @return SplFixedArray + */ + public function getErrorCorrectionBytes() + { + return $this->errorCorrectionBytes; + } +} diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Encoder/ByteMatrix.php b/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Encoder/ByteMatrix.php new file mode 100644 index 00000000..a378f083 --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Encoder/ByteMatrix.php @@ -0,0 +1,158 @@ +height = $height; + $this->width = $width; + $this->bytes = new SplFixedArray($height); + + for ($y = 0; $y < $height; $y++) { + $this->bytes[$y] = new SplFixedArray($width); + } + } + + /** + * Gets the width of the matrix. + * + * @return integer + */ + public function getWidth() + { + return $this->width; + } + + /** + * Gets the height of the matrix. + * + * @return integer + */ + public function getHeight() + { + return $this->height; + } + + /** + * Gets the internal representation of the matrix. + * + * @return SplFixedArray + */ + public function getArray() + { + return $this->bytes; + } + + /** + * Gets the byte for a specific position. + * + * @param integer $x + * @param integer $y + * @return integer + */ + public function get($x, $y) + { + return $this->bytes[$y][$x]; + } + + /** + * Sets the byte for a specific position. + * + * @param integer $x + * @param integer $y + * @param integer $value + * @return void + */ + public function set($x, $y, $value) + { + $this->bytes[$y][$x] = (int) $value; + } + + /** + * Clears the matrix with a specific value. + * + * @param integer $value + * @return void + */ + public function clear($value) + { + for ($y = 0; $y < $this->height; $y++) { + for ($x = 0; $x < $this->width; $x++) { + $this->bytes[$y][$x] = $value; + } + } + } + + /** + * Returns a string representation of the matrix. + * + * @return string + */ + public function __toString() + { + $result = ''; + + for ($y = 0; $y < $this->height; $y++) { + for ($x = 0; $x < $this->width; $x++) { + switch ($this->bytes[$y][$x]) { + case 0: + $result .= ' 0'; + break; + + case 1: + $result .= ' 1'; + break; + + default: + $result .= ' '; + break; + } + } + + $result .= "\n"; + } + + return $result; + } +} diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Encoder/Encoder.php b/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Encoder/Encoder.php new file mode 100644 index 00000000..c8efc35d --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Encoder/Encoder.php @@ -0,0 +1,687 @@ +get() === Mode::BYTE && $encoding !== self::DEFAULT_BYTE_MODE_ECODING) { + $eci = CharacterSetEci::getCharacterSetEciByName($encoding); + + if ($eci !== null) { + self::appendEci($eci, $headerBits); + } + } + + // (With ECI in place,) Write the mode marker + self::appendModeInfo($mode, $headerBits); + + // Collect data within the main segment, separately, to count its size + // if needed. Don't add it to main payload yet. + $dataBits = new BitArray(); + self::appendBytes($content, $mode, $dataBits, $encoding); + + // Hard part: need to know version to know how many bits length takes. + // But need to know how many bits it takes to know version. First we + // take a guess at version by assuming version will be the minimum, 1: + $provisionalBitsNeeded = $headerBits->getSize() + + $mode->getCharacterCountBits(Version::getVersionForNumber(1)) + + $dataBits->getSize(); + $provisionalVersion = self::chooseVersion($provisionalBitsNeeded, $ecLevel); + + // Use that guess to calculate the right version. I am still not sure + // this works in 100% of cases. + $bitsNeeded = $headerBits->getSize() + + $mode->getCharacterCountBits($provisionalVersion) + + $dataBits->getSize(); + $version = self::chooseVersion($bitsNeeded, $ecLevel); + + $headerAndDataBits = new BitArray(); + $headerAndDataBits->appendBitArray($headerBits); + + // Find "length" of main segment and write it. + $numLetters = ($mode->get() === Mode::BYTE ? $dataBits->getSizeInBytes() : strlen($content)); + self::appendLengthInfo($numLetters, $version, $mode, $headerAndDataBits); + + // Put data together into the overall payload. + $headerAndDataBits->appendBitArray($dataBits); + $ecBlocks = $version->getEcBlocksForLevel($ecLevel); + $numDataBytes = $version->getTotalCodewords() - $ecBlocks->getTotalEcCodewords(); + + // Terminate the bits properly. + self::terminateBits($numDataBytes, $headerAndDataBits); + + // Interleave data bits with error correction code. + $finalBits = self::interleaveWithEcBytes( + $headerAndDataBits, + $version->getTotalCodewords(), + $numDataBytes, + $ecBlocks->getNumBlocks() + ); + + $qrCode = new QrCode(); + $qrCode->setErrorCorrectionLevel($ecLevel); + $qrCode->setMode($mode); + $qrCode->setVersion($version); + + // Choose the mask pattern and set to "qrCode". + $dimension = $version->getDimensionForVersion(); + $matrix = new ByteMatrix($dimension, $dimension); + $maskPattern = self::chooseMaskPattern($finalBits, $ecLevel, $version, $matrix); + $qrCode->setMaskPattern($maskPattern); + + // Build the matrix and set it to "qrCode". + MatrixUtil::buildMatrix($finalBits, $ecLevel, $version, $maskPattern, $matrix); + $qrCode->setMatrix($matrix); + + return $qrCode; + } + + /** + * Gets the alphanumeric code for a byte. + * + * @param string|integer $code + * @return integer + */ + protected static function getAlphanumericCode($code) + { + $code = (is_string($code) ? ord($code) : $code); + + if (isset(self::$alphanumericTable[$code])) { + return self::$alphanumericTable[$code]; + } + + return -1; + } + + /** + * Chooses the best mode for a given content. + * + * @param string $content + * @param string $encoding + * @return Mode + */ + protected static function chooseMode($content, $encoding = null) + { + if (strcasecmp($encoding, 'SHIFT-JIS') === 0) { + return self::isOnlyDoubleByteKanji($content) ? new Mode(Mode::KANJI) : new Mode(Mode::BYTE); + } + + $hasNumeric = false; + $hasAlphanumeric = false; + $contentLength = strlen($content); + + for ($i = 0; $i < $contentLength; $i++) { + $char = $content[$i]; + + if (ctype_digit($char)) { + $hasNumeric = true; + } elseif (self::getAlphanumericCode($char) !== -1) { + $hasAlphanumeric = true; + } else { + return new Mode(Mode::BYTE); + } + } + + if ($hasAlphanumeric) { + return new Mode(Mode::ALPHANUMERIC); + } elseif ($hasNumeric) { + return new Mode(Mode::NUMERIC); + } + + return new Mode(Mode::BYTE); + } + + /** + * Calculates the mask penalty for a matrix. + * + * @param ByteMatrix $matrix + * @return integer + */ + protected static function calculateMaskPenalty(ByteMatrix $matrix) + { + return ( + MaskUtil::applyMaskPenaltyRule1($matrix) + + MaskUtil::applyMaskPenaltyRule2($matrix) + + MaskUtil::applyMaskPenaltyRule3($matrix) + + MaskUtil::applyMaskPenaltyRule4($matrix) + ); + } + + /** + * Chooses the best mask pattern for a matrix. + * + * @param BitArray $bits + * @param ErrorCorrectionLevel $ecLevel + * @param Version $version + * @param ByteMatrix $matrix + * @return integer + */ + protected static function chooseMaskPattern( + BitArray $bits, + ErrorCorrectionLevel $ecLevel, + Version $version, + ByteMatrix $matrix + ) { + $minPenality = PHP_INT_MAX; + $bestMaskPattern = -1; + + for ($maskPattern = 0; $maskPattern < QrCode::NUM_MASK_PATTERNS; $maskPattern++) { + MatrixUtil::buildMatrix($bits, $ecLevel, $version, $maskPattern, $matrix); + $penalty = self::calculateMaskPenalty($matrix); + + if ($penalty < $minPenality) { + $minPenality = $penalty; + $bestMaskPattern = $maskPattern; + } + } + + return $bestMaskPattern; + } + + /** + * Chooses the best version for the input. + * + * @param integer $numInputBits + * @param ErrorCorrectionLevel $ecLevel + * @return Version + * @throws Exception\WriterException + */ + protected static function chooseVersion($numInputBits, ErrorCorrectionLevel $ecLevel) + { + for ($versionNum = 1; $versionNum <= 40; $versionNum++) { + $version = Version::getVersionForNumber($versionNum); + $numBytes = $version->getTotalCodewords(); + + $ecBlocks = $version->getEcBlocksForLevel($ecLevel); + $numEcBytes = $ecBlocks->getTotalEcCodewords(); + + $numDataBytes = $numBytes - $numEcBytes; + $totalInputBytes = intval(($numInputBits + 8) / 8); + + if ($numDataBytes >= $totalInputBytes) { + return $version; + } + } + + throw new Exception\WriterException('Data too big'); + } + + /** + * Terminates the bits in a bit array. + * + * @param integer $numDataBytes + * @param BitArray $bits + * @throws Exception\WriterException + */ + protected static function terminateBits($numDataBytes, BitArray $bits) + { + $capacity = $numDataBytes << 3; + + if ($bits->getSize() > $capacity) { + throw new Exception\WriterException('Data bits cannot fit in the QR code'); + } + + for ($i = 0; $i < 4 && $bits->getSize() < $capacity; $i++) { + $bits->appendBit(false); + } + + $numBitsInLastByte = $bits->getSize() & 0x7; + + if ($numBitsInLastByte > 0) { + for ($i = $numBitsInLastByte; $i < 8; $i++) { + $bits->appendBit(false); + } + } + + $numPaddingBytes = $numDataBytes - $bits->getSizeInBytes(); + + for ($i = 0; $i < $numPaddingBytes; $i++) { + $bits->appendBits(($i & 0x1) === 0 ? 0xec : 0x11, 8); + } + + if ($bits->getSize() !== $capacity) { + throw new Exception\WriterException('Bits size does not equal capacity'); + } + } + + /** + * Gets number of data- and EC bytes for a block ID. + * + * @param integer $numTotalBytes + * @param integer $numDataBytes + * @param integer $numRsBlocks + * @param integer $blockId + * @return array + * @throws Exception\WriterException + */ + protected static function getNumDataBytesAndNumEcBytesForBlockId( + $numTotalBytes, + $numDataBytes, + $numRsBlocks, + $blockId + ) { + if ($blockId >= $numRsBlocks) { + throw new Exception\WriterException('Block ID too large'); + } + + $numRsBlocksInGroup2 = $numTotalBytes % $numRsBlocks; + $numRsBlocksInGroup1 = $numRsBlocks - $numRsBlocksInGroup2; + $numTotalBytesInGroup1 = intval($numTotalBytes / $numRsBlocks); + $numTotalBytesInGroup2 = $numTotalBytesInGroup1 + 1; + $numDataBytesInGroup1 = intval($numDataBytes / $numRsBlocks); + $numDataBytesInGroup2 = $numDataBytesInGroup1 + 1; + $numEcBytesInGroup1 = $numTotalBytesInGroup1 - $numDataBytesInGroup1; + $numEcBytesInGroup2 = $numTotalBytesInGroup2 - $numDataBytesInGroup2; + + if ($numEcBytesInGroup1 !== $numEcBytesInGroup2) { + throw new Exception\WriterException('EC bytes mismatch'); + } + + if ($numRsBlocks !== $numRsBlocksInGroup1 + $numRsBlocksInGroup2) { + throw new Exception\WriterException('RS blocks mismatch'); + } + + if ($numTotalBytes !== + (($numDataBytesInGroup1 + $numEcBytesInGroup1) * $numRsBlocksInGroup1) + + (($numDataBytesInGroup2 + $numEcBytesInGroup2) * $numRsBlocksInGroup2) + ) { + throw new Exception\WriterException('Total bytes mismatch'); + } + + if ($blockId < $numRsBlocksInGroup1) { + return array($numDataBytesInGroup1, $numEcBytesInGroup1); + } else { + return array($numDataBytesInGroup2, $numEcBytesInGroup2); + } + } + + /** + * Interleaves data with EC bytes. + * + * @param BitArray $bits + * @param integer $numTotalBytes + * @param integer $numDataBytes + * @param integer $numRsBlocks + * @return BitArray + * @throws Exception\WriterException + */ + protected static function interleaveWithEcBytes(BitArray $bits, $numTotalBytes, $numDataBytes, $numRsBlocks) + { + if ($bits->getSizeInBytes() !== $numDataBytes) { + throw new Exception\WriterException('Number of bits and data bytes does not match'); + } + + $dataBytesOffset = 0; + $maxNumDataBytes = 0; + $maxNumEcBytes = 0; + + $blocks = new SplFixedArray($numRsBlocks); + + for ($i = 0; $i < $numRsBlocks; $i++) { + list($numDataBytesInBlock, $numEcBytesInBlock) = self::getNumDataBytesAndNumEcBytesForBlockId( + $numTotalBytes, + $numDataBytes, + $numRsBlocks, + $i + ); + + $size = $numDataBytesInBlock; + $dataBytes = $bits->toBytes(8 * $dataBytesOffset, $size); + $ecBytes = self::generateEcBytes($dataBytes, $numEcBytesInBlock); + $blocks[$i] = new BlockPair($dataBytes, $ecBytes); + + $maxNumDataBytes = max($maxNumDataBytes, $size); + $maxNumEcBytes = max($maxNumEcBytes, count($ecBytes)); + $dataBytesOffset += $numDataBytesInBlock; + } + + if ($numDataBytes !== $dataBytesOffset) { + throw new Exception\WriterException('Data bytes does not match offset'); + } + + $result = new BitArray(); + + for ($i = 0; $i < $maxNumDataBytes; $i++) { + foreach ($blocks as $block) { + $dataBytes = $block->getDataBytes(); + + if ($i < count($dataBytes)) { + $result->appendBits($dataBytes[$i], 8); + } + } + } + + for ($i = 0; $i < $maxNumEcBytes; $i++) { + foreach ($blocks as $block) { + $ecBytes = $block->getErrorCorrectionBytes(); + + if ($i < count($ecBytes)) { + $result->appendBits($ecBytes[$i], 8); + } + } + } + + if ($numTotalBytes !== $result->getSizeInBytes()) { + throw new Exception\WriterException('Interleaving error: ' . $numTotalBytes . ' and ' . $result->getSizeInBytes() . ' differ'); + } + + return $result; + } + + /** + * Generates EC bytes for given data. + * + * @param SplFixedArray $dataBytes + * @param integer $numEcBytesInBlock + * @return SplFixedArray + */ + protected static function generateEcBytes(SplFixedArray $dataBytes, $numEcBytesInBlock) + { + $numDataBytes = count($dataBytes); + $toEncode = new SplFixedArray($numDataBytes + $numEcBytesInBlock); + + for ($i = 0; $i < $numDataBytes; $i++) { + $toEncode[$i] = $dataBytes[$i] & 0xff; + } + + $ecBytes = new SplFixedArray($numEcBytesInBlock); + $codec = self::getCodec($numDataBytes, $numEcBytesInBlock); + $codec->encode($toEncode, $ecBytes); + + return $ecBytes; + } + + /** + * Gets an RS codec and caches it. + * + * @param integer $numDataBytes + * @param integer $numEcBytesInBlock + * @return ReedSolomonCodec + */ + protected static function getCodec($numDataBytes, $numEcBytesInBlock) + { + $cacheId = $numDataBytes . '-' . $numEcBytesInBlock; + + if (!isset(self::$codecs[$cacheId])) { + self::$codecs[$cacheId] = new ReedSolomonCodec( + 8, + 0x11d, + 0, + 1, + $numEcBytesInBlock, + 255 - $numDataBytes - $numEcBytesInBlock + ); + } + + return self::$codecs[$cacheId]; + } + + /** + * Appends mode information to a bit array. + * + * @param Mode $mode + * @param BitArray $bits + * @return void + */ + protected static function appendModeInfo(Mode $mode, BitArray $bits) + { + $bits->appendBits($mode->get(), 4); + } + + /** + * Appends length information to a bit array. + * + * @param integer $numLetters + * @param Version $version + * @param Mode $mode + * @param BitArray $bits + * @return void + * @throws Exception\WriterException + */ + protected static function appendLengthInfo($numLetters, Version $version, Mode $mode, BitArray $bits) + { + $numBits = $mode->getCharacterCountBits($version); + + if ($numLetters >= (1 << $numBits)) { + throw new Exception\WriterException($numLetters . ' is bigger than ' . ((1 << $numBits) - 1)); + } + + $bits->appendBits($numLetters, $numBits); + } + + /** + * Appends bytes to a bit array in a specific mode. + * + * @param stirng $content + * @param Mode $mode + * @param BitArray $bits + * @param string $encoding + * @return void + * @throws Exception\WriterException + */ + protected static function appendBytes($content, Mode $mode, BitArray $bits, $encoding) + { + switch ($mode->get()) { + case Mode::NUMERIC: + self::appendNumericBytes($content, $bits); + break; + + case Mode::ALPHANUMERIC: + self::appendAlphanumericBytes($content, $bits); + break; + + case Mode::BYTE: + self::append8BitBytes($content, $bits, $encoding); + break; + + case Mode::KANJI: + self::appendKanjiBytes($content, $bits); + break; + + default: + throw new Exception\WriterException('Invalid mode: ' . $mode->get()); + } + } + + /** + * Appends numeric bytes to a bit array. + * + * @param string $content + * @param BitArray $bits + * @return void + */ + protected static function appendNumericBytes($content, BitArray $bits) + { + $length = strlen($content); + $i = 0; + + while ($i < $length) { + $num1 = (int) $content[$i]; + + if ($i + 2 < $length) { + // Encode three numeric letters in ten bits. + $num2 = (int) $content[$i + 1]; + $num3 = (int) $content[$i + 2]; + $bits->appendBits($num1 * 100 + $num2 * 10 + $num3, 10); + $i += 3; + } elseif ($i + 1 < $length) { + // Encode two numeric letters in seven bits. + $num2 = (int) $content[$i + 1]; + $bits->appendBits($num1 * 10 + $num2, 7); + $i += 2; + } else { + // Encode one numeric letter in four bits. + $bits->appendBits($num1, 4); + $i++; + } + } + } + + /** + * Appends alpha-numeric bytes to a bit array. + * + * @param string $content + * @param BitArray $bits + * @return void + */ + protected static function appendAlphanumericBytes($content, BitArray $bits) + { + $length = strlen($content); + $i = 0; + + while ($i < $length) { + if (-1 === ($code1 = self::getAlphanumericCode($content[$i]))) { + throw new Exception\WriterException('Invalid alphanumeric code'); + } + + if ($i + 1 < $length) { + if (-1 === ($code2 = self::getAlphanumericCode($content[$i + 1]))) { + throw new Exception\WriterException('Invalid alphanumeric code'); + } + + // Encode two alphanumeric letters in 11 bits. + $bits->appendBits($code1 * 45 + $code2, 11); + $i += 2; + } else { + // Encode one alphanumeric letter in six bits. + $bits->appendBits($code1, 6); + $i++; + } + } + } + + /** + * Appends regular 8-bit bytes to a bit array. + * + * @param string $content + * @param BitArray $bits + * @return void + */ + protected static function append8BitBytes($content, BitArray $bits, $encoding) + { + if (false === ($bytes = @iconv('utf-8', $encoding, $content))) { + throw new Exception\WriterException('Could not encode content to ' . $encoding); + } + + $length = strlen($bytes); + + for ($i = 0; $i < $length; $i++) { + $bits->appendBits(ord($bytes[$i]), 8); + } + } + + /** + * Appends KANJI bytes to a bit array. + * + * @param string $content + * @param BitArray $bits + * @return void + */ + protected static function appendKanjiBytes($content, BitArray $bits) + { + if (strlen($content) % 2 > 0) { + // We just do a simple length check here. The for loop will check + // individual characters. + throw new Exception\WriterException('Content does not seem to be encoded in SHIFT-JIS'); + } + + $length = strlen($content); + + for ($i = 0; $i < $length; $i += 2) { + $byte1 = ord($content[$i]) & 0xff; + $byte2 = ord($content[$i + 1]) & 0xff; + $code = ($byte1 << 8) | $byte2; + + if ($code >= 0x8140 && $code <= 0x9ffc) { + $subtracted = $code - 0x8140; + } elseif ($code >= 0xe040 && $code <= 0xebbf) { + $subtracted = $code - 0xc140; + } else { + throw new Exception\WriterException('Invalid byte sequence'); + } + + $encoded = (($subtracted >> 8) * 0xc0) + ($subtracted & 0xff); + + $bits->appendBits($encoded, 13); + } + } + + /** + * Appends ECI information to a bit array. + * + * @param CharacterSetEci $eci + * @param BitArray $bits + * @return void + */ + protected static function appendEci(CharacterSetEci $eci, BitArray $bits) + { + $mode = new Mode(Mode::ECI); + $bits->appendBits($mode->get(), 4); + $bits->appendBits($eci->get(), 8); + } +} diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Encoder/MaskUtil.php b/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Encoder/MaskUtil.php new file mode 100644 index 00000000..c294d557 --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Encoder/MaskUtil.php @@ -0,0 +1,291 @@ +getArray(); + $width = $matrix->getWidth(); + $height = $matrix->getHeight(); + + for ($y = 0; $y < $height - 1; $y++) { + for ($x = 0; $x < $width - 1; $x++) { + $value = $array[$y][$x]; + + if ($value === $array[$y][$x + 1] && $value === $array[$y + 1][$x] && $value === $array[$y + 1][$x + 1]) { + $penalty++; + } + } + } + + return self::N2 * $penalty; + } + + /** + * Applies mask penalty rule 3 and returns the penalty. + * + * Finds consecutive cells of 00001011101 or 10111010000, and gives penalty + * to them. If we find patterns like 000010111010000, we give penalties + * twice (i.e. 40 * 2). + * + * @param ByteMatrix $matrix + * @return integer + */ + public static function applyMaskPenaltyRule3(ByteMatrix $matrix) + { + $penalty = 0; + $array = $matrix->getArray(); + $width = $matrix->getWidth(); + $height = $matrix->getHeight(); + + for ($y = 0; $y < $height; $y++) { + for ($x = 0; $x < $width; $x++) { + if ( + $x + 6 < $width + && $array[$y][$x] === 1 + && $array[$y][$x + 1] === 0 + && $array[$y][$x + 2] === 1 + && $array[$y][$x + 3] === 1 + && $array[$y][$x + 4] === 1 + && $array[$y][$x + 5] === 0 + && $array[$y][$x + 6] === 1 + && ( + ( + $x + 10 < $width + && $array[$y][$x + 7] === 0 + && $array[$y][$x + 8] === 0 + && $array[$y][$x + 9] === 0 + && $array[$y][$x + 10] === 0 + ) + || ( + $x - 4 >= 0 + && $array[$y][$x - 1] === 0 + && $array[$y][$x - 2] === 0 + && $array[$y][$x - 3] === 0 + && $array[$y][$x - 4] === 0 + ) + ) + ) { + $penalty += self::N3; + } + + if ( + $y + 6 < $height + && $array[$y][$x] === 1 + && $array[$y + 1][$x] === 0 + && $array[$y + 2][$x] === 1 + && $array[$y + 3][$x] === 1 + && $array[$y + 4][$x] === 1 + && $array[$y + 5][$x] === 0 + && $array[$y + 6][$x] === 1 + && ( + ( + $y + 10 < $height + && $array[$y + 7][$x] === 0 + && $array[$y + 8][$x] === 0 + && $array[$y + 9][$x] === 0 + && $array[$y + 10][$x] === 0 + ) + || ( + $y - 4 >= 0 + && $array[$y - 1][$x] === 0 + && $array[$y - 2][$x] === 0 + && $array[$y - 3][$x] === 0 + && $array[$y - 4][$x] === 0 + ) + ) + ) { + $penalty += self::N3; + } + } + } + + return $penalty; + } + + /** + * Applies mask penalty rule 4 and returns the penalty. + * + * Calculates the ratio of dark cells and gives penalty if the ratio is far + * from 50%. It gives 10 penalty for 5% distance. + * + * @param ByteMatrix $matrix + * @return integer + */ + public static function applyMaskPenaltyRule4(ByteMatrix $matrix) + { + $numDarkCells = 0; + + $array = $matrix->getArray(); + $width = $matrix->getWidth(); + $height = $matrix->getHeight(); + + for ($y = 0; $y < $height; $y++) { + $arrayY = $array[$y]; + + for ($x = 0; $x < $width; $x++) { + if ($arrayY[$x] === 1) { + $numDarkCells++; + } + } + } + + $numTotalCells = $height * $width; + $darkRatio = $numDarkCells / $numTotalCells; + $fixedPercentVariances = (int) (abs($darkRatio - 0.5) * 20); + + return $fixedPercentVariances * self::N4; + } + + /** + * Returns the mask bit for "getMaskPattern" at "x" and "y". + * + * See 8.8 of JISX0510:2004 for mask pattern conditions. + * + * @param integer $maskPattern + * @param integer $x + * @param integer $y + * @return integer + * @throws Exception\InvalidArgumentException + */ + public static function getDataMaskBit($maskPattern, $x, $y) + { + switch ($maskPattern) { + case 0: + $intermediate = ($y + $x) & 0x1; + break; + + case 1: + $intermediate = $y & 0x1; + break; + + case 2: + $intermediate = $x % 3; + break; + + case 3: + $intermediate = ($y + $x) % 3; + break; + + case 4: + $intermediate = (BitUtils::unsignedRightShift($y, 1) + ($x / 3)) & 0x1; + break; + + case 5: + $temp = $y * $x; + $intermediate = ($temp & 0x1) + ($temp % 3); + break; + + case 6: + $temp = $y * $x; + $intermediate = (($temp & 0x1) + ($temp % 3)) & 0x1; + break; + + case 7: + $temp = $y * $x; + $intermediate = (($temp % 3) + (($y + $x) & 0x1)) & 0x1; + break; + + default: + throw new Exception\InvalidArgumentException('Invalid mask pattern: ' . $maskPattern); + } + + return $intermediate === 0; + } + + /** + * Helper function for applyMaskPenaltyRule1. + * + * We need this for doing this calculation in both vertical and horizontal + * orders respectively. + * + * @param ByteMatrix $matrix + * @param boolean $isHorizontal + * @return integer + */ + protected static function applyMaskPenaltyRule1Internal(ByteMatrix $matrix, $isHorizontal) + { + $penalty = 0; + $iLimit = $isHorizontal ? $matrix->getHeight() : $matrix->getWidth(); + $jLimit = $isHorizontal ? $matrix->getWidth() : $matrix->getHeight(); + $array = $matrix->getArray(); + + for ($i = 0; $i < $iLimit; $i++) { + $numSameBitCells = 0; + $prevBit = -1; + + for ($j = 0; $j < $jLimit; $j++) { + $bit = $isHorizontal ? $array[$i][$j] : $array[$j][$i]; + + if ($bit === $prevBit) { + $numSameBitCells++; + } else { + if ($numSameBitCells >= 5) { + $penalty += self::N1 + ($numSameBitCells - 5); + } + + $numSameBitCells = 1; + $prevBit = $bit; + } + } + + if ($numSameBitCells >= 5) { + $penalty += self::N1 + ($numSameBitCells - 5); + } + } + + return $penalty; + } +} diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Encoder/MatrixUtil.php b/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Encoder/MatrixUtil.php new file mode 100644 index 00000000..83273818 --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Encoder/MatrixUtil.php @@ -0,0 +1,580 @@ +clear(-1); + } + + /** + * Builds a complete matrix. + * + * @param BitArray $dataBits + * @param ErrorCorrectionLevel $level + * @param Version $version + * @param integer $maskPattern + * @param ByteMatrix $matrix + * @return void + */ + public static function buildMatrix( + BitArray $dataBits, + ErrorCorrectionLevel $level, + Version $version, + $maskPattern, + ByteMatrix $matrix + ) { + self::clearMatrix($matrix); + self::embedBasicPatterns($version, $matrix); + self::embedTypeInfo($level, $maskPattern, $matrix); + self::maybeEmbedVersionInfo($version, $matrix); + self::embedDataBits($dataBits, $maskPattern, $matrix); + } + + /** + * Embeds type information into a matrix. + * + * @param ErrorCorrectionLevel $level + * @param integer $maskPattern + * @param ByteMatrix $matrix + * @return void + */ + protected static function embedTypeInfo(ErrorCorrectionLevel $level, $maskPattern, ByteMatrix $matrix) + { + $typeInfoBits = new BitArray(); + self::makeTypeInfoBits($level, $maskPattern, $typeInfoBits); + + $typeInfoBitsSize = $typeInfoBits->getSize(); + + for ($i = 0; $i < $typeInfoBitsSize; $i++) { + $bit = $typeInfoBits->get($typeInfoBitsSize - 1 - $i); + + $x1 = self::$typeInfoCoordinates[$i][0]; + $y1 = self::$typeInfoCoordinates[$i][1]; + + $matrix->set($x1, $y1, $bit); + + if ($i < 8) { + $x2 = $matrix->getWidth() - $i - 1; + $y2 = 8; + } else { + $x2 = 8; + $y2 = $matrix->getHeight() - 7 + ($i - 8); + } + + $matrix->set($x2, $y2, $bit); + } + } + + /** + * Generates type information bits and appends them to a bit array. + * + * @param ErrorCorrectionLevel $level + * @param integer $maskPattern + * @param BitArray $bits + * @return void + * @throws Exception\RuntimeException + */ + protected static function makeTypeInfoBits(ErrorCorrectionLevel $level, $maskPattern, BitArray $bits) + { + $typeInfo = ($level->get() << 3) | $maskPattern; + $bits->appendBits($typeInfo, 5); + + $bchCode = self::calculateBchCode($typeInfo, self::$typeInfoPoly); + $bits->appendBits($bchCode, 10); + + $maskBits = new BitArray(); + $maskBits->appendBits(self::$typeInfoMaskPattern, 15); + $bits->xorBits($maskBits); + + if ($bits->getSize() !== 15) { + throw new Exception\RuntimeException('Bit array resulted in invalid size: ' . $bits->getSize()); + } + } + + /** + * Embeds version information if required. + * + * @param Version $version + * @param ByteMatrix $matrix + * @return void + */ + protected static function maybeEmbedVersionInfo(Version $version, ByteMatrix $matrix) + { + if ($version->getVersionNumber() < 7) { + return; + } + + $versionInfoBits = new BitArray(); + self::makeVersionInfoBits($version, $versionInfoBits); + + $bitIndex = 6 * 3 - 1; + + for ($i = 0; $i < 6; $i++) { + for ($j = 0; $j < 3; $j++) { + $bit = $versionInfoBits->get($bitIndex); + $bitIndex--; + + $matrix->set($i, $matrix->getHeight() - 11 + $j, $bit); + $matrix->set($matrix->getHeight() - 11 + $j, $i, $bit); + } + } + } + + /** + * Generates version information bits and appends them to a bit array. + * + * @param Version $version + * @param BitArray $bits + * @return void + * @throws Exception\RuntimeException + */ + protected static function makeVersionInfoBits(Version $version, BitArray $bits) + { + $bits->appendBits($version->getVersionNumber(), 6); + + $bchCode = self::calculateBchCode($version->getVersionNumber(), self::$versionInfoPoly); + $bits->appendBits($bchCode, 12); + + if ($bits->getSize() !== 18) { + throw new Exception\RuntimeException('Bit array resulted in invalid size: ' . $bits->getSize()); + } + } + + /** + * Calculates the BHC code for a value and a polynomial. + * + * @param integer $value + * @param integer $poly + * @return integer + */ + protected static function calculateBchCode($value, $poly) + { + $msbSetInPoly = self::findMsbSet($poly); + $value <<= $msbSetInPoly - 1; + + while (self::findMsbSet($value) >= $msbSetInPoly) { + $value ^= $poly << (self::findMsbSet($value) - $msbSetInPoly); + } + + return $value; + } + + /** + * Finds and MSB set. + * + * @param integer $value + * @return integer + */ + protected static function findMsbSet($value) + { + $numDigits = 0; + + while ($value !== 0) { + $value >>= 1; + $numDigits++; + } + + return $numDigits; + } + + /** + * Embeds basic patterns into a matrix. + * + * @param Version $version + * @param ByteMatrix $matrix + * @return void + */ + protected static function embedBasicPatterns(Version $version, ByteMatrix $matrix) + { + self::embedPositionDetectionPatternsAndSeparators($matrix); + self::embedDarkDotAtLeftBottomCorner($matrix); + self::maybeEmbedPositionAdjustmentPatterns($version, $matrix); + self::embedTimingPatterns($matrix); + } + + /** + * Embeds position detection patterns and separators into a byte matrix. + * + * @param ByteMatrix $matrix + * @return void + */ + protected static function embedPositionDetectionPatternsAndSeparators(ByteMatrix $matrix) + { + $pdpWidth = count(self::$positionDetectionPattern[0]); + + self::embedPositionDetectionPattern(0, 0, $matrix); + self::embedPositionDetectionPattern($matrix->getWidth() - $pdpWidth, 0, $matrix); + self::embedPositionDetectionPattern(0, $matrix->getWidth() - $pdpWidth, $matrix); + + $hspWidth = 8; + + self::embedHorizontalSeparationPattern(0, $hspWidth - 1, $matrix); + self::embedHorizontalSeparationPattern($matrix->getWidth() - $hspWidth, $hspWidth - 1, $matrix); + self::embedHorizontalSeparationPattern(0, $matrix->getWidth() - $hspWidth, $matrix); + + $vspSize = 7; + + self::embedVerticalSeparationPattern($vspSize, 0, $matrix); + self::embedVerticalSeparationPattern($matrix->getHeight() - $vspSize - 1, 0, $matrix); + self::embedVerticalSeparationPattern($vspSize, $matrix->getHeight() - $vspSize, $matrix); + } + + /** + * Embeds a single position detection pattern into a byte matrix. + * + * @param integer $xStart + * @param integer $yStart + * @param ByteMatrix $matrix + * @return void + */ + protected static function embedPositionDetectionPattern($xStart, $yStart, ByteMatrix $matrix) + { + for ($y = 0; $y < 7; $y++) { + for ($x = 0; $x < 7; $x++) { + $matrix->set($xStart + $x, $yStart + $y, self::$positionDetectionPattern[$y][$x]); + } + } + } + + /** + * Embeds a single horizontal separation pattern. + * + * @param integer $xStart + * @param integer $yStart + * @param ByteMatrix $matrix + * @return void + * @throws Exception\RuntimeException + */ + protected static function embedHorizontalSeparationPattern($xStart, $yStart, ByteMatrix $matrix) + { + for ($x = 0; $x < 8; $x++) { + if ($matrix->get($xStart + $x, $yStart) !== -1) { + throw new Exception\RuntimeException('Byte already set'); + } + + $matrix->set($xStart + $x, $yStart, 0); + } + } + + /** + * Embeds a single vertical separation pattern. + * + * @param integer $xStart + * @param integer $yStart + * @param ByteMatrix $matrix + * @return void + * @throws Exception\RuntimeException + */ + protected static function embedVerticalSeparationPattern($xStart, $yStart, ByteMatrix $matrix) + { + for ($y = 0; $y < 7; $y++) { + if ($matrix->get($xStart, $yStart + $y) !== -1) { + throw new Exception\RuntimeException('Byte already set'); + } + + $matrix->set($xStart, $yStart + $y, 0); + } + } + + /** + * Embeds a dot at the left bottom corner. + * + * @param ByteMatrix $matrix + * @return void + * @throws Exception\RuntimeException + */ + protected static function embedDarkDotAtLeftBottomCorner(ByteMatrix $matrix) + { + if ($matrix->get(8, $matrix->getHeight() - 8) === 0) { + throw new Exception\RuntimeException('Byte already set to 0'); + } + + $matrix->set(8, $matrix->getHeight() - 8, 1); + } + + /** + * Embeds position adjustment patterns if required. + * + * @param Version $version + * @param ByteMatrix $matrix + * @return void + */ + protected static function maybeEmbedPositionAdjustmentPatterns(Version $version, ByteMatrix $matrix) + { + if ($version->getVersionNumber() < 2) { + return; + } + + $index = $version->getVersionNumber() - 1; + + $coordinates = self::$positionAdjustmentPatternCoordinateTable[$index]; + $numCoordinates = count($coordinates); + + for ($i = 0; $i < $numCoordinates; $i++) { + for ($j = 0; $j < $numCoordinates; $j++) { + $y = $coordinates[$i]; + $x = $coordinates[$j]; + + if ($x === null || $y === null) { + continue; + } + + if ($matrix->get($x, $y) === -1) { + self::embedPositionAdjustmentPattern($x - 2, $y - 2, $matrix); + } + } + } + } + + /** + * Embeds a single position adjustment pattern. + * + * @param integer $xStart + * @param intger $yStart + * @param ByteMatrix $matrix + * @return void + */ + protected static function embedPositionAdjustmentPattern($xStart, $yStart, ByteMatrix $matrix) + { + for ($y = 0; $y < 5; $y++) { + for ($x = 0; $x < 5; $x++) { + $matrix->set($xStart + $x, $yStart + $y, self::$positionAdjustmentPattern[$y][$x]); + } + } + } + + /** + * Embeds timing patterns into a matrix. + * + * @param ByteMatrix $matrix + * @return void + */ + protected static function embedTimingPatterns(ByteMatrix $matrix) + { + $matrixWidth = $matrix->getWidth(); + + for ($i = 8; $i < $matrixWidth - 8; $i++) { + $bit = ($i + 1) % 2; + + if ($matrix->get($i, 6) === -1) { + $matrix->set($i, 6, $bit); + } + + if ($matrix->get(6, $i) === -1) { + $matrix->set(6, $i, $bit); + } + } + } + + /** + * Embeds "dataBits" using "getMaskPattern". + * + * For debugging purposes, it skips masking process if "getMaskPattern" is + * -1. See 8.7 of JISX0510:2004 (p.38) for how to embed data bits. + * + * @param BitArray $dataBits + * @param integer $maskPattern + * @param ByteMatrix $matrix + * @return void + * @throws Exception\WriterException + */ + protected static function embedDataBits(BitArray $dataBits, $maskPattern, ByteMatrix $matrix) + { + $bitIndex = 0; + $direction = -1; + + // Start from the right bottom cell. + $x = $matrix->getWidth() - 1; + $y = $matrix->getHeight() - 1; + + while ($x > 0) { + // Skip vertical timing pattern. + if ($x === 6) { + $x--; + } + + while ($y >= 0 && $y < $matrix->getHeight()) { + for ($i = 0; $i < 2; $i++) { + $xx = $x - $i; + + // Skip the cell if it's not empty. + if ($matrix->get($xx, $y) !== -1) { + continue; + } + + if ($bitIndex < $dataBits->getSize()) { + $bit = $dataBits->get($bitIndex); + $bitIndex++; + } else { + // Padding bit. If there is no bit left, we'll fill the + // left cells with 0, as described in 8.4.9 of + // JISX0510:2004 (p. 24). + $bit = false; + } + + // Skip masking if maskPattern is -1. + if ($maskPattern !== -1 && MaskUtil::getDataMaskBit($maskPattern, $xx, $y)) { + $bit = !$bit; + } + + $matrix->set($xx, $y, $bit); + } + + $y += $direction; + } + + $direction = -$direction; + $y += $direction; + $x -= 2; + } + + // All bits should be consumed + if ($bitIndex !== $dataBits->getSize()) { + throw new Exception\WriterException('Not all bits consumed (' . $bitIndex . ' out of ' . $dataBits->getSize() .')'); + } + } +} diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Encoder/QrCode.php b/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Encoder/QrCode.php new file mode 100644 index 00000000..07e1c385 --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Encoder/QrCode.php @@ -0,0 +1,201 @@ +mode; + } + + /** + * Sets the mode. + * + * @param Mode $mode + * @return void + */ + public function setMode(Mode $mode) + { + $this->mode = $mode; + } + + /** + * Gets the EC level. + * + * @return ErrorCorrectionLevel + */ + public function getErrorCorrectionLevel() + { + return $this->errorCorrectionLevel; + } + + /** + * Sets the EC level. + * + * @param ErrorCorrectionLevel $errorCorrectionLevel + * @return void + */ + public function setErrorCorrectionLevel(ErrorCorrectionLevel $errorCorrectionLevel) + { + $this->errorCorrectionLevel = $errorCorrectionLevel; + } + + /** + * Gets the version. + * + * @return Version + */ + public function getVersion() + { + return $this->version; + } + + /** + * Sets the version. + * + * @param Version $version + * @return void + */ + public function setVersion(Version $version) + { + $this->version = $version; + } + + /** + * Gets the mask pattern. + * + * @return integer + */ + public function getMaskPattern() + { + return $this->maskPattern; + } + + /** + * Sets the mask pattern. + * + * @param integer $maskPattern + * @return void + */ + public function setMaskPattern($maskPattern) + { + $this->maskPattern = $maskPattern; + } + + /** + * Gets the matrix. + * + * @return ByteMatrix + */ + public function getMatrix() + { + return $this->matrix; + } + + /** + * Sets the matrix. + * + * @param ByteMatrix $matrix + * @return void + */ + public function setMatrix(ByteMatrix $matrix) + { + $this->matrix = $matrix; + } + + /** + * Validates whether a mask pattern is valid. + * + * @param integer $maskPattern + * @return boolean + */ + public static function isValidMaskPattern($maskPattern) + { + return $maskPattern > 0 && $maskPattern < self::NUM_MASK_PATTERNS; + } + + /** + * Returns a string representation of the QR code. + * + * @return string + */ + public function __toString() + { + $result = "<<\n" + . " mode: " . $this->mode . "\n" + . " ecLevel: " . $this->errorCorrectionLevel . "\n" + . " version: " . $this->version . "\n" + . " maskPattern: " . $this->maskPattern . "\n"; + + if ($this->matrix === null) { + $result .= " matrix: null\n"; + } else { + $result .= " matrix:\n"; + $result .= $this->matrix; + } + + $result .= ">>\n"; + + return $result; + } +} diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Exception/ExceptionInterface.php b/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Exception/ExceptionInterface.php new file mode 100644 index 00000000..5c58fc51 --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Exception/ExceptionInterface.php @@ -0,0 +1,14 @@ + 100) { + throw new Exception\InvalidArgumentException('Cyan must be between 0 and 100'); + } + + if ($magenta < 0 || $magenta > 100) { + throw new Exception\InvalidArgumentException('Magenta must be between 0 and 100'); + } + + if ($yellow < 0 || $yellow > 100) { + throw new Exception\InvalidArgumentException('Yellow must be between 0 and 100'); + } + + if ($black < 0 || $black > 100) { + throw new Exception\InvalidArgumentException('Black must be between 0 and 100'); + } + + $this->cyan = (int) $cyan; + $this->magenta = (int) $magenta; + $this->yellow = (int) $yellow; + $this->black = (int) $black; + } + + /** + * Returns the cyan value. + * + * @return integer + */ + public function getCyan() + { + return $this->cyan; + } + + /** + * Returns the magenta value. + * + * @return integer + */ + public function getMagenta() + { + return $this->magenta; + } + + /** + * Returns the yellow value. + * + * @return integer + */ + public function getYellow() + { + return $this->yellow; + } + + /** + * Returns the black value. + * + * @return integer + */ + public function getBlack() + { + return $this->black; + } + + /** + * toRgb(): defined by ColorInterface. + * + * @see ColorInterface::toRgb() + * @return Rgb + */ + public function toRgb() + { + $k = $this->black / 100; + $c = (-$k * $this->cyan + $k * 100 + $this->cyan) / 100; + $m = (-$k * $this->magenta + $k * 100 + $this->magenta) / 100; + $y = (-$k * $this->yellow + $k * 100 + $this->yellow) / 100; + + return new Rgb( + -$c * 255 + 255, + -$m * 255 + 255, + -$y * 255 + 255 + ); + } + + /** + * toCmyk(): defined by ColorInterface. + * + * @see ColorInterface::toCmyk() + * @return Cmyk + */ + public function toCmyk() + { + return $this; + } + + /** + * toGray(): defined by ColorInterface. + * + * @see ColorInterface::toGray() + * @return Gray + */ + public function toGray() + { + return $this->toRgb()->toGray(); + } +} \ No newline at end of file diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Color/ColorInterface.php b/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Color/ColorInterface.php new file mode 100644 index 00000000..747accc1 --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Color/ColorInterface.php @@ -0,0 +1,37 @@ + 100) { + throw new Exception\InvalidArgumentException('Gray must be between 0 and 100'); + } + + $this->gray = (int) $gray; + } + + /** + * Returns the gray value. + * + * @return integer + */ + public function getGray() + { + return $this->gray; + } + + /** + * toRgb(): defined by ColorInterface. + * + * @see ColorInterface::toRgb() + * @return Rgb + */ + public function toRgb() + { + return new Rgb($this->gray * 2.55, $this->gray * 2.55, $this->gray * 2.55); + } + + /** + * toCmyk(): defined by ColorInterface. + * + * @see ColorInterface::toCmyk() + * @return Cmyk + */ + public function toCmyk() + { + return new Cmyk(0, 0, 0, 100 - $this->gray); + } + + /** + * toGray(): defined by ColorInterface. + * + * @see ColorInterface::toGray() + * @return Gray + */ + public function toGray() + { + return $this; + } +} \ No newline at end of file diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Color/Rgb.php b/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Color/Rgb.php new file mode 100644 index 00000000..44e4060c --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Color/Rgb.php @@ -0,0 +1,148 @@ + 255) { + throw new Exception\InvalidArgumentException('Red must be between 0 and 255'); + } + + if ($green < 0 || $green > 255) { + throw new Exception\InvalidArgumentException('Green must be between 0 and 255'); + } + + if ($blue < 0 || $blue > 255) { + throw new Exception\InvalidArgumentException('Blue must be between 0 and 255'); + } + + $this->red = (int) $red; + $this->green = (int) $green; + $this->blue = (int) $blue; + } + + /** + * Returns the red value. + * + * @return integer + */ + public function getRed() + { + return $this->red; + } + + /** + * Returns the green value. + * + * @return integer + */ + public function getGreen() + { + return $this->green; + } + + /** + * Returns the blue value. + * + * @return integer + */ + public function getBlue() + { + return $this->blue; + } + + /** + * Returns a hexadecimal string representation of the RGB value. + * + * @return string + */ + public function __toString() + { + return sprintf('%02x%02x%02x', $this->red, $this->green, $this->blue); + } + + /** + * toRgb(): defined by ColorInterface. + * + * @see ColorInterface::toRgb() + * @return Rgb + */ + public function toRgb() + { + return $this; + } + + /** + * toCmyk(): defined by ColorInterface. + * + * @see ColorInterface::toCmyk() + * @return Cmyk + */ + public function toCmyk() + { + $c = 1 - ($this->red / 255); + $m = 1 - ($this->green / 255); + $y = 1 - ($this->blue / 255); + $k = min($c, $m, $y); + + return new Cmyk( + 100 * ($c - $k) / (1 - $k), + 100 * ($m - $k) / (1 - $k), + 100 * ($y - $k) / (1 - $k), + 100 * $k + ); + } + + /** + * toGray(): defined by ColorInterface. + * + * @see ColorInterface::toGray() + * @return Gray + */ + public function toGray() + { + return new Gray(($this->red * 0.21 + $this->green * 0.71 + $this->blue * 0.07) / 2.55); + } +} \ No newline at end of file diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Image/AbstractRenderer.php b/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Image/AbstractRenderer.php new file mode 100644 index 00000000..b0bb02ac --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Image/AbstractRenderer.php @@ -0,0 +1,338 @@ +margin = (int) $margin; + return $this; + } + + /** + * Gets the margin around the QR code. + * + * @return integer + */ + public function getMargin() + { + return $this->margin; + } + + /** + * Sets the height around the renderd image. + * + * If the width is smaller than the matrix width plus padding, the renderer + * will automatically use that as the width instead of the specified one. + * + * @param integer $width + * @return AbstractRenderer + */ + public function setWidth($width) + { + $this->width = (int) $width; + return $this; + } + + /** + * Gets the width of the rendered image. + * + * @return integer + */ + public function getWidth() + { + return $this->width; + } + + /** + * Sets the height around the renderd image. + * + * If the height is smaller than the matrix height plus padding, the + * renderer will automatically use that as the height instead of the + * specified one. + * + * @param integer $height + * @return AbstractRenderer + */ + public function setHeight($height) + { + $this->height = (int) $height; + return $this; + } + + /** + * Gets the height around the rendered image. + * + * @return integer + */ + public function getHeight() + { + return $this->height; + } + + /** + * Sets whether dimensions should be rounded down. + * + * @param boolean $flag + * @return AbstractRenderer + */ + public function setRoundDimensions($flag) + { + $this->floorToClosestDimension = $flag; + return $this; + } + + /** + * Gets whether dimensions should be rounded down. + * + * @return boolean + */ + public function shouldRoundDimensions() + { + return $this->floorToClosestDimension; + } + + /** + * Sets background color. + * + * @param Color\ColorInterface $color + * @return AbstractRenderer + */ + public function setBackgroundColor(Color\ColorInterface $color) + { + $this->backgroundColor = $color; + return $this; + } + + /** + * Gets background color. + * + * @return Color\ColorInterface + */ + public function getBackgroundColor() + { + if ($this->backgroundColor === null) { + $this->backgroundColor = new Color\Gray(100); + } + + return $this->backgroundColor; + } + + /** + * Sets foreground color. + * + * @param Color\ColorInterface $color + * @return AbstractRenderer + */ + public function setForegroundColor(Color\ColorInterface $color) + { + $this->foregroundColor = $color; + return $this; + } + + /** + * Gets foreground color. + * + * @return Color\ColorInterface + */ + public function getForegroundColor() + { + if ($this->foregroundColor === null) { + $this->foregroundColor = new Color\Gray(0); + } + + return $this->foregroundColor; + } + + /** + * Adds a decorator to the renderer. + * + * @param DecoratorInterface $decorator + * @return AbstractRenderer + */ + public function addDecorator(DecoratorInterface $decorator) + { + $this->decorators[] = $decorator; + return $this; + } + + /** + * render(): defined by RendererInterface. + * + * @see RendererInterface::render() + * @param QrCode $qrCode + * @return string + */ + public function render(QrCode $qrCode) + { + $input = $qrCode->getMatrix(); + $inputWidth = $input->getWidth(); + $inputHeight = $input->getHeight(); + $qrWidth = $inputWidth + ($this->getMargin() << 1); + $qrHeight = $inputHeight + ($this->getMargin() << 1); + $outputWidth = max($this->getWidth(), $qrWidth); + $outputHeight = max($this->getHeight(), $qrHeight); + $multiple = (int) min($outputWidth / $qrWidth, $outputHeight / $qrHeight); + + if ($this->shouldRoundDimensions()) { + $outputWidth -= $outputWidth % $multiple; + $outputHeight -= $outputHeight % $multiple; + } + + // Padding includes both the quiet zone and the extra white pixels to + // accommodate the requested dimensions. For example, if input is 25x25 + // the QR will be 33x33 including the quiet zone. If the requested size + // is 200x160, the multiple will be 4, for a QR of 132x132. These will + // handle all the padding from 100x100 (the actual QR) up to 200x160. + $leftPadding = (int) (($outputWidth - ($inputWidth * $multiple)) / 2); + $topPadding = (int) (($outputHeight - ($inputHeight * $multiple)) / 2); + + // Store calculated parameters + $this->finalWidth = $outputWidth; + $this->finalHeight = $outputHeight; + $this->blockSize = $multiple; + + $this->init(); + $this->addColor('background', $this->getBackgroundColor()); + $this->addColor('foreground', $this->getForegroundColor()); + $this->drawBackground('background'); + + foreach ($this->decorators as $decorator) { + $decorator->preProcess( + $qrCode, + $this, + $outputWidth, + $outputHeight, + $leftPadding, + $topPadding, + $multiple + ); + } + + for ($inputY = 0, $outputY = $topPadding; $inputY < $inputHeight; $inputY++, $outputY += $multiple) { + for ($inputX = 0, $outputX = $leftPadding; $inputX < $inputWidth; $inputX++, $outputX += $multiple) { + if ($input->get($inputX, $inputY) === 1) { + $this->drawBlock($outputX, $outputY, 'foreground'); + } + } + } + + foreach ($this->decorators as $decorator) { + $decorator->postProcess( + $qrCode, + $this, + $outputWidth, + $outputHeight, + $leftPadding, + $topPadding, + $multiple + ); + } + + return $this->getByteStream(); + } +} \ No newline at end of file diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Image/Decorator/DecoratorInterface.php b/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Image/Decorator/DecoratorInterface.php new file mode 100644 index 00000000..e67268b5 --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Image/Decorator/DecoratorInterface.php @@ -0,0 +1,63 @@ +outerColor = $color; + return $this; + } + + /** + * Gets outer color. + * + * @return Color\ColorInterface + */ + public function getOuterColor() + { + if ($this->outerColor === null) { + $this->outerColor = new Color\Gray(100); + } + + return $this->outerColor; + } + + /** + * Sets inner color. + * + * @param Color\ColorInterface $color + * @return FinderPattern + */ + public function setInnerColor(Color\ColorInterface $color) + { + $this->innerColor = $color; + return $this; + } + + /** + * Gets inner color. + * + * @return Color\ColorInterface + */ + public function getInnerColor() + { + if ($this->innerColor === null) { + $this->innerColor = new Color\Gray(0); + } + + return $this->innerColor; + } + + /** + * preProcess(): defined by DecoratorInterface. + * + * @see DecoratorInterface::preProcess() + * @param QrCode $qrCode + * @param RendererInterface $renderer + * @param integer $outputWidth + * @param integer $outputHeight + * @param integer $leftPadding + * @param integer $topPadding + * @param integer $multiple + * @return void + */ + public function preProcess( + QrCode $qrCode, + RendererInterface $renderer, + $outputWidth, + $outputHeight, + $leftPadding, + $topPadding, + $multiple + ) { + $matrix = $qrCode->getMatrix(); + $positions = array( + array(0, 0), + array($matrix->getWidth() - 7, 0), + array(0, $matrix->getHeight() - 7), + ); + + foreach (self::$outerPositionDetectionPattern as $y => $row) { + foreach ($row as $x => $isSet) { + foreach ($positions as $position) { + $matrix->set($x + $position[0], $y + $position[1], 0); + } + } + } + } + + /** + * postProcess(): defined by DecoratorInterface. + * + * @see DecoratorInterface::postProcess() + * + * @param QrCode $qrCode + * @param RendererInterface $renderer + * @param integer $outputWidth + * @param integer $outputHeight + * @param integer $leftPadding + * @param integer $topPadding + * @param integer $multiple + * @return void + */ + public function postProcess( + QrCode $qrCode, + RendererInterface $renderer, + $outputWidth, + $outputHeight, + $leftPadding, + $topPadding, + $multiple + ) { + $matrix = $qrCode->getMatrix(); + $positions = array( + array(0, 0), + array($matrix->getWidth() - 7, 0), + array(0, $matrix->getHeight() - 7), + ); + + $renderer->addColor('finder-outer', $this->getOuterColor()); + $renderer->addColor('finder-inner', $this->getInnerColor()); + + foreach (self::$outerPositionDetectionPattern as $y => $row) { + foreach ($row as $x => $isOuterSet) { + $isInnerSet = self::$innerPositionDetectionPattern[$y][$x]; + + if ($isOuterSet) { + foreach ($positions as $position) { + $renderer->drawBlock( + $leftPadding + $x * $multiple + $position[0] * $multiple, + $topPadding + $y * $multiple + $position[1] * $multiple, + 'finder-outer' + ); + } + } + + if ($isInnerSet) { + foreach ($positions as $position) { + $renderer->drawBlock( + $leftPadding + $x * $multiple + $position[0] * $multiple, + $topPadding + $y * $multiple + $position[1] * $multiple, + 'finder-inner' + ); + } + } + } + } + } +} \ No newline at end of file diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Image/Eps.php b/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Image/Eps.php new file mode 100644 index 00000000..97661951 --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Image/Eps.php @@ -0,0 +1,152 @@ +eps = "%!PS-Adobe-3.0 EPSF-3.0\n" + . "%%BoundingBox: 0 0 " . $this->finalWidth . " " . $this->finalHeight . "\n" + . "/F { rectfill } def\n"; + } + + /** + * addColor(): defined by RendererInterface. + * + * @see ImageRendererInterface::addColor() + * @param string $id + * @param ColorInterface $color + * @return void + */ + public function addColor($id, ColorInterface $color) + { + if ( + !$color instanceof Rgb + && !$color instanceof Cmyk + && !$color instanceof Gray + ) { + $color = $color->toCmyk(); + } + + $this->colors[$id] = $color; + } + + /** + * drawBackground(): defined by RendererInterface. + * + * @see ImageRendererInterface::drawBackground() + * @param string $colorId + * @return void + */ + public function drawBackground($colorId) + { + $this->setColor($colorId); + $this->eps .= "0 0 " . $this->finalWidth . " " . $this->finalHeight . " F\n"; + } + + /** + * drawBlock(): defined by RendererInterface. + * + * @see ImageRendererInterface::drawBlock() + * @param integer $x + * @param integer $y + * @param string $colorId + * @return void + */ + public function drawBlock($x, $y, $colorId) + { + $this->setColor($colorId); + $this->eps .= $x . " " . ($this->finalHeight - $y - $this->blockSize) . " " . $this->blockSize . " " . $this->blockSize . " F\n"; + } + + /** + * getByteStream(): defined by RendererInterface. + * + * @see ImageRendererInterface::getByteStream() + * @return string + */ + public function getByteStream() + { + return $this->eps; + } + + /** + * Sets color to use. + * + * @param string $colorId + * @return void + */ + protected function setColor($colorId) + { + if ($colorId !== $this->currentColor) { + $color = $this->colors[$colorId]; + + if ($color instanceof Rgb) { + $this->eps .= sprintf( + "%F %F %F setrgbcolor\n", + $color->getRed() / 100, + $color->getGreen() / 100, + $color->getBlue() / 100 + ); + } elseif ($color instanceof Cmyk) { + $this->eps .= sprintf( + "%F %F %F %F setcmykcolor\n", + $color->getCyan() / 100, + $color->getMagenta() / 100, + $color->getYellow() / 100, + $color->getBlack() / 100 + ); + } elseif ($color instanceof Gray) { + $this->eps .= sprintf( + "%F setgray\n", + $color->getGray() / 100 + ); + } + + $this->currentColor = $colorId; + } + } +} diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Image/Png.php b/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Image/Png.php new file mode 100644 index 00000000..dd593a8b --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Image/Png.php @@ -0,0 +1,115 @@ +image = imagecreatetruecolor($this->finalWidth, $this->finalHeight); + } + + /** + * addColor(): defined by RendererInterface. + * + * @see ImageRendererInterface::addColor() + * @param string $id + * @param ColorInterface $color + * @return void + * @throws Exception\RuntimeException + */ + public function addColor($id, ColorInterface $color) + { + if ($this->image === null) { + throw new Exception\RuntimeException('Colors can only be added after init'); + } + + $color = $color->toRgb(); + + $this->colors[$id] = imagecolorallocate( + $this->image, + $color->getRed(), + $color->getGreen(), + $color->getBlue() + ); + } + + /** + * drawBackground(): defined by RendererInterface. + * + * @see ImageRendererInterface::drawBackground() + * @param string $colorId + * @return void + */ + public function drawBackground($colorId) + { + imagefill($this->image, 0, 0, $this->colors[$colorId]); + } + + /** + * drawBlock(): defined by RendererInterface. + * + * @see ImageRendererInterface::drawBlock() + * @param integer $x + * @param integer $y + * @param string $colorId + * @return void + */ + public function drawBlock($x, $y, $colorId) + { + imagefilledrectangle( + $this->image, + $x, + $y, + $x + $this->blockSize - 1, + $y + $this->blockSize - 1, + $this->colors[$colorId] + ); + } + + /** + * getByteStream(): defined by RendererInterface. + * + * @see ImageRendererInterface::getByteStream() + * @return string + */ + public function getByteStream() + { + ob_start(); + imagepng($this->image); + return ob_get_clean(); + } +} \ No newline at end of file diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Image/RendererInterface.php b/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Image/RendererInterface.php new file mode 100644 index 00000000..52101a65 --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Image/RendererInterface.php @@ -0,0 +1,61 @@ +svg = new SimpleXMLElement( + '' + . '' + ); + $this->svg->addAttribute('version', '1.1'); + $this->svg->addAttribute('width', $this->finalWidth . 'px'); + $this->svg->addAttribute('height', $this->finalHeight . 'px'); + $this->svg->addAttribute('viewBox', '0 0 ' . $this->finalWidth . ' ' . $this->finalHeight); + $this->svg->addChild('defs'); + } + + /** + * addColor(): defined by RendererInterface. + * + * @see ImageRendererInterface::addColor() + * @param string $id + * @param ColorInterface $color + * @return void + * @throws Exception\InvalidArgumentException + */ + public function addColor($id, ColorInterface $color) + { + $this->colors[$id] = (string) $color->toRgb(); + } + + /** + * drawBackground(): defined by RendererInterface. + * + * @see ImageRendererInterface::drawBackground() + * @param string $colorId + * @return void + */ + public function drawBackground($colorId) + { + $rect = $this->svg->addChild('rect'); + $rect->addAttribute('x', 0); + $rect->addAttribute('y', 0); + $rect->addAttribute('width', $this->finalWidth); + $rect->addAttribute('height', $this->finalHeight); + $rect->addAttribute('fill', '#' . $this->colors[$colorId]); + } + + /** + * drawBlock(): defined by RendererInterface. + * + * @see ImageRendererInterface::drawBlock() + * @param integer $x + * @param integer $y + * @param string $colorId + * @return void + */ + public function drawBlock($x, $y, $colorId) + { + $use = $this->svg->addChild('use'); + $use->addAttribute('x', $x); + $use->addAttribute('y', $y); + $use->addAttribute( + 'xlink:href', + $this->getRectPrototypeId($colorId), + 'http://www.w3.org/1999/xlink' + ); + } + + /** + * getByteStream(): defined by RendererInterface. + * + * @see ImageRendererInterface::getByteStream() + * @return string + */ + public function getByteStream() + { + return $this->svg->asXML(); + } + + /** + * Get the prototype ID for a color. + * + * @param integer $colorId + * @return string + */ + protected function getRectPrototypeId($colorId) + { + if (!isset($this->prototypeIds[$colorId])) { + $id = 'r' . dechex(count($this->prototypeIds)); + + $rect = $this->svg->defs->addChild('rect'); + $rect->addAttribute('id', $id); + $rect->addAttribute('width', $this->blockSize); + $rect->addAttribute('height', $this->blockSize); + $rect->addAttribute('fill', '#' . $this->colors[$colorId]); + + $this->prototypeIds[$colorId] = '#' . $id; + } + + return $this->prototypeIds[$colorId]; + } +} diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/RendererInterface.php b/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/RendererInterface.php new file mode 100644 index 00000000..554e1d88 --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/RendererInterface.php @@ -0,0 +1,26 @@ +class = $class; + } + + /** + * Get CSS class name. + * + * @return string + */ + public function getClass() + { + return $this->class; + } + + /** + * Set CSS style value. + * + * @param string $style + */ + public function setStyle($style) + { + $this->style = $style; + } + + /** + * Get CSS style value. + * + * @return string + */ + public function getStyle() + { + return $this->style; + } + + /** + * render(): defined by RendererInterface. + * + * @see RendererInterface::render() + * @param QrCode $qrCode + * @return string + */ + public function render(QrCode $qrCode) + { + $textCode = parent::render($qrCode); + + $result = '' . $textCode . ''; + + return $result; + } +} diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Text/Plain.php b/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Text/Plain.php new file mode 100644 index 00000000..a7e4cfb7 --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Text/Plain.php @@ -0,0 +1,150 @@ +fullBlock = $fullBlock; + } + + /** + * Get char used as full block (occupied space, "black"). + * + * @return string + */ + public function getFullBlock() + { + return $this->fullBlock; + } + + /** + * Set char used as empty block (empty space, "white"). + * + * @param string $emptyBlock + */ + public function setEmptyBlock($emptyBlock) + { + $this->emptyBlock = $emptyBlock; + } + + /** + * Get char used as empty block (empty space, "white"). + * + * @return string + */ + public function getEmptyBlock() + { + return $this->emptyBlock; + } + + /** + * Sets the margin around the QR code. + * + * @param integer $margin + * @return AbstractRenderer + * @throws Exception\InvalidArgumentException + */ + public function setMargin($margin) + { + if ($margin < 0) { + throw new Exception\InvalidArgumentException('Margin must be equal to greater than 0'); + } + + $this->margin = (int) $margin; + + return $this; + } + + /** + * Gets the margin around the QR code. + * + * @return integer + */ + public function getMargin() + { + return $this->margin; + } + + /** + * render(): defined by RendererInterface. + * + * @see RendererInterface::render() + * @param QrCode $qrCode + * @return string + */ + public function render(QrCode $qrCode) + { + $result = ''; + $matrix = $qrCode->getMatrix(); + $width = $matrix->getWidth(); + + // Top margin + for ($x = 0; $x < $this->margin; $x++) { + $result .= str_repeat($this->emptyBlock, $width + 2 * $this->margin)."\n"; + } + + // Body + $array = $matrix->getArray(); + + foreach ($array as $row) { + $result .= str_repeat($this->emptyBlock, $this->margin); // left margin + foreach ($row as $byte) { + $result .= $byte ? $this->fullBlock : $this->emptyBlock; + } + $result .= str_repeat($this->emptyBlock, $this->margin); // right margin + $result .= "\n"; + } + + // Bottom margin + for ($x = 0; $x < $this->margin; $x++) { + $result .= str_repeat($this->emptyBlock, $width + 2 * $this->margin)."\n"; + } + + return $result; + } +} diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Writer.php b/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Writer.php new file mode 100644 index 00000000..0f803138 --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Writer.php @@ -0,0 +1,105 @@ +renderer = $renderer; + } + + /** + * Sets the renderer used to create a byte stream. + * + * @param RendererInterface $renderer + * @return Writer + */ + public function setRenderer(RendererInterface $renderer) + { + $this->renderer = $renderer; + return $this; + } + + /** + * Gets the renderer used to create a byte stream. + * + * @return RendererInterface + */ + public function getRenderer() + { + return $this->renderer; + } + + /** + * Writes QR code and returns it as string. + * + * Content is a string which *should* be encoded in UTF-8, in case there are + * non ASCII-characters present. + * + * @param string $content + * @param string $encoding + * @param integer $ecLevel + * @return string + * @throws Exception\InvalidArgumentException + */ + public function writeString( + $content, + $encoding = Encoder::DEFAULT_BYTE_MODE_ECODING, + $ecLevel = ErrorCorrectionLevel::L + ) { + if (strlen($content) === 0) { + throw new Exception\InvalidArgumentException('Found empty contents'); + } + + $qrCode = Encoder::encode($content, new ErrorCorrectionLevel($ecLevel), $encoding); + + return $this->getRenderer()->render($qrCode); + } + + /** + * Writes QR code to a file. + * + * @see Writer::writeString() + * @param string $content + * @param string $filename + * @param string $encoding + * @param integer $ecLevel + * @return void + */ + public function writeFile( + $content, + $filename, + $encoding = Encoder::DEFAULT_BYTE_MODE_ECODING, + $ecLevel = ErrorCorrectionLevel::L + ) { + file_put_contents($filename, $this->writeString($content, $encoding, $ecLevel)); + } +} diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/src/Common/BitArray.php b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Common/BitArray.php new file mode 100644 index 00000000..158384fe --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Common/BitArray.php @@ -0,0 +1,372 @@ + + */ + private $bits; + + /** + * Size of the bit array in bits. + * + * @var int + */ + private $size; + + /** + * Creates a new bit array with a given size. + */ + public function __construct(int $size = 0) + { + $this->size = $size; + $this->bits = SplFixedArray::fromArray(array_fill(0, ($this->size + 31) >> 3, 0)); + } + + /** + * Gets the size in bits. + */ + public function getSize() : int + { + return $this->size; + } + + /** + * Gets the size in bytes. + */ + public function getSizeInBytes() : int + { + return ($this->size + 7) >> 3; + } + + /** + * Ensures that the array has a minimum capacity. + */ + public function ensureCapacity(int $size) : void + { + if ($size > count($this->bits) << 5) { + $this->bits->setSize(($size + 31) >> 5); + } + } + + /** + * Gets a specific bit. + */ + public function get(int $i) : bool + { + return 0 !== ($this->bits[$i >> 5] & (1 << ($i & 0x1f))); + } + + /** + * Sets a specific bit. + */ + public function set(int $i) : void + { + $this->bits[$i >> 5] = $this->bits[$i >> 5] | 1 << ($i & 0x1f); + } + + /** + * Flips a specific bit. + */ + public function flip(int $i) : void + { + $this->bits[$i >> 5] ^= 1 << ($i & 0x1f); + } + + /** + * Gets the next set bit position from a given position. + */ + public function getNextSet(int $from) : int + { + if ($from >= $this->size) { + return $this->size; + } + + $bitsOffset = $from >> 5; + $currentBits = $this->bits[$bitsOffset]; + $bitsLength = count($this->bits); + $currentBits &= ~((1 << ($from & 0x1f)) - 1); + + while (0 === $currentBits) { + if (++$bitsOffset === $bitsLength) { + return $this->size; + } + + $currentBits = $this->bits[$bitsOffset]; + } + + $result = ($bitsOffset << 5) + BitUtils::numberOfTrailingZeros($currentBits); + return $result > $this->size ? $this->size : $result; + } + + /** + * Gets the next unset bit position from a given position. + */ + public function getNextUnset(int $from) : int + { + if ($from >= $this->size) { + return $this->size; + } + + $bitsOffset = $from >> 5; + $currentBits = ~$this->bits[$bitsOffset]; + $bitsLength = count($this->bits); + $currentBits &= ~((1 << ($from & 0x1f)) - 1); + + while (0 === $currentBits) { + if (++$bitsOffset === $bitsLength) { + return $this->size; + } + + $currentBits = ~$this->bits[$bitsOffset]; + } + + $result = ($bitsOffset << 5) + BitUtils::numberOfTrailingZeros($currentBits); + return $result > $this->size ? $this->size : $result; + } + + /** + * Sets a bulk of bits. + */ + public function setBulk(int $i, int $newBits) : void + { + $this->bits[$i >> 5] = $newBits; + } + + /** + * Sets a range of bits. + * + * @throws InvalidArgumentException if end is smaller than start + */ + public function setRange(int $start, int $end) : void + { + if ($end < $start) { + throw new InvalidArgumentException('End must be greater or equal to start'); + } + + if ($end === $start) { + return; + } + + --$end; + + $firstInt = $start >> 5; + $lastInt = $end >> 5; + + for ($i = $firstInt; $i <= $lastInt; ++$i) { + $firstBit = $i > $firstInt ? 0 : $start & 0x1f; + $lastBit = $i < $lastInt ? 31 : $end & 0x1f; + + if (0 === $firstBit && 31 === $lastBit) { + $mask = 0x7fffffff; + } else { + $mask = 0; + + for ($j = $firstBit; $j < $lastBit; ++$j) { + $mask |= 1 << $j; + } + } + + $this->bits[$i] = $this->bits[$i] | $mask; + } + } + + /** + * Clears the bit array, unsetting every bit. + */ + public function clear() : void + { + $bitsLength = count($this->bits); + + for ($i = 0; $i < $bitsLength; ++$i) { + $this->bits[$i] = 0; + } + } + + /** + * Checks if a range of bits is set or not set. + + * @throws InvalidArgumentException if end is smaller than start + */ + public function isRange(int $start, int $end, bool $value) : bool + { + if ($end < $start) { + throw new InvalidArgumentException('End must be greater or equal to start'); + } + + if ($end === $start) { + return true; + } + + --$end; + + $firstInt = $start >> 5; + $lastInt = $end >> 5; + + for ($i = $firstInt; $i <= $lastInt; ++$i) { + $firstBit = $i > $firstInt ? 0 : $start & 0x1f; + $lastBit = $i < $lastInt ? 31 : $end & 0x1f; + + if (0 === $firstBit && 31 === $lastBit) { + $mask = 0x7fffffff; + } else { + $mask = 0; + + for ($j = $firstBit; $j <= $lastBit; ++$j) { + $mask |= 1 << $j; + } + } + + if (($this->bits[$i] & $mask) !== ($value ? $mask : 0)) { + return false; + } + } + + return true; + } + + /** + * Appends a bit to the array. + */ + public function appendBit(bool $bit) : void + { + $this->ensureCapacity($this->size + 1); + + if ($bit) { + $this->bits[$this->size >> 5] = $this->bits[$this->size >> 5] | (1 << ($this->size & 0x1f)); + } + + ++$this->size; + } + + /** + * Appends a number of bits (up to 32) to the array. + + * @throws InvalidArgumentException if num bits is not between 0 and 32 + */ + public function appendBits(int $value, int $numBits) : void + { + if ($numBits < 0 || $numBits > 32) { + throw new InvalidArgumentException('Num bits must be between 0 and 32'); + } + + $this->ensureCapacity($this->size + $numBits); + + for ($numBitsLeft = $numBits; $numBitsLeft > 0; $numBitsLeft--) { + $this->appendBit((($value >> ($numBitsLeft - 1)) & 0x01) === 1); + } + } + + /** + * Appends another bit array to this array. + */ + public function appendBitArray(self $other) : void + { + $otherSize = $other->getSize(); + $this->ensureCapacity($this->size + $other->getSize()); + + for ($i = 0; $i < $otherSize; ++$i) { + $this->appendBit($other->get($i)); + } + } + + /** + * Makes an exclusive-or comparision on the current bit array. + * + * @throws InvalidArgumentException if sizes don't match + */ + public function xorBits(self $other) : void + { + $bitsLength = count($this->bits); + $otherBits = $other->getBitArray(); + + if ($bitsLength !== count($otherBits)) { + throw new InvalidArgumentException('Sizes don\'t match'); + } + + for ($i = 0; $i < $bitsLength; ++$i) { + $this->bits[$i] = $this->bits[$i] ^ $otherBits[$i]; + } + } + + /** + * Converts the bit array to a byte array. + * + * @return SplFixedArray + */ + public function toBytes(int $bitOffset, int $numBytes) : SplFixedArray + { + $bytes = new SplFixedArray($numBytes); + + for ($i = 0; $i < $numBytes; ++$i) { + $byte = 0; + + for ($j = 0; $j < 8; ++$j) { + if ($this->get($bitOffset)) { + $byte |= 1 << (7 - $j); + } + + ++$bitOffset; + } + + $bytes[$i] = $byte; + } + + return $bytes; + } + + /** + * Gets the internal bit array. + * + * @return SplFixedArray + */ + public function getBitArray() : SplFixedArray + { + return $this->bits; + } + + /** + * Reverses the array. + */ + public function reverse() : void + { + $newBits = new SplFixedArray(count($this->bits)); + + for ($i = 0; $i < $this->size; ++$i) { + if ($this->get($this->size - $i - 1)) { + $newBits[$i >> 5] = $newBits[$i >> 5] | (1 << ($i & 0x1f)); + } + } + + $this->bits = $newBits; + } + + /** + * Returns a string representation of the bit array. + */ + public function __toString() : string + { + $result = ''; + + for ($i = 0; $i < $this->size; ++$i) { + if (0 === ($i & 0x07)) { + $result .= ' '; + } + + $result .= $this->get($i) ? 'X' : '.'; + } + + return $result; + } +} diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/src/Common/BitMatrix.php b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Common/BitMatrix.php new file mode 100644 index 00000000..10bf8fe2 --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Common/BitMatrix.php @@ -0,0 +1,313 @@ + + */ + private $bits; + + /** + * @throws InvalidArgumentException if a dimension is smaller than zero + */ + public function __construct(int $width, int $height = null) + { + if (null === $height) { + $height = $width; + } + + if ($width < 1 || $height < 1) { + throw new InvalidArgumentException('Both dimensions must be greater than zero'); + } + + $this->width = $width; + $this->height = $height; + $this->rowSize = ($width + 31) >> 5; + $this->bits = SplFixedArray::fromArray(array_fill(0, $this->rowSize * $height, 0)); + } + + /** + * Gets the requested bit, where true means black. + */ + public function get(int $x, int $y) : bool + { + $offset = $y * $this->rowSize + ($x >> 5); + return 0 !== (BitUtils::unsignedRightShift($this->bits[$offset], ($x & 0x1f)) & 1); + } + + /** + * Sets the given bit to true. + */ + public function set(int $x, int $y) : void + { + $offset = $y * $this->rowSize + ($x >> 5); + $this->bits[$offset] = $this->bits[$offset] | (1 << ($x & 0x1f)); + } + + /** + * Flips the given bit. + */ + public function flip(int $x, int $y) : void + { + $offset = $y * $this->rowSize + ($x >> 5); + $this->bits[$offset] = $this->bits[$offset] ^ (1 << ($x & 0x1f)); + } + + /** + * Clears all bits (set to false). + */ + public function clear() : void + { + $max = count($this->bits); + + for ($i = 0; $i < $max; ++$i) { + $this->bits[$i] = 0; + } + } + + /** + * Sets a square region of the bit matrix to true. + * + * @throws InvalidArgumentException if left or top are negative + * @throws InvalidArgumentException if width or height are smaller than 1 + * @throws InvalidArgumentException if region does not fit into the matix + */ + public function setRegion(int $left, int $top, int $width, int $height) : void + { + if ($top < 0 || $left < 0) { + throw new InvalidArgumentException('Left and top must be non-negative'); + } + + if ($height < 1 || $width < 1) { + throw new InvalidArgumentException('Width and height must be at least 1'); + } + + $right = $left + $width; + $bottom = $top + $height; + + if ($bottom > $this->height || $right > $this->width) { + throw new InvalidArgumentException('The region must fit inside the matrix'); + } + + for ($y = $top; $y < $bottom; ++$y) { + $offset = $y * $this->rowSize; + + for ($x = $left; $x < $right; ++$x) { + $index = $offset + ($x >> 5); + $this->bits[$index] = $this->bits[$index] | (1 << ($x & 0x1f)); + } + } + } + + /** + * A fast method to retrieve one row of data from the matrix as a BitArray. + */ + public function getRow(int $y, BitArray $row = null) : BitArray + { + if (null === $row || $row->getSize() < $this->width) { + $row = new BitArray($this->width); + } + + $offset = $y * $this->rowSize; + + for ($x = 0; $x < $this->rowSize; ++$x) { + $row->setBulk($x << 5, $this->bits[$offset + $x]); + } + + return $row; + } + + /** + * Sets a row of data from a BitArray. + */ + public function setRow(int $y, BitArray $row) : void + { + $bits = $row->getBitArray(); + + for ($i = 0; $i < $this->rowSize; ++$i) { + $this->bits[$y * $this->rowSize + $i] = $bits[$i]; + } + } + + /** + * This is useful in detecting the enclosing rectangle of a 'pure' barcode. + * + * @return int[]|null + */ + public function getEnclosingRectangle() : ?array + { + $left = $this->width; + $top = $this->height; + $right = -1; + $bottom = -1; + + for ($y = 0; $y < $this->height; ++$y) { + for ($x32 = 0; $x32 < $this->rowSize; ++$x32) { + $bits = $this->bits[$y * $this->rowSize + $x32]; + + if (0 !== $bits) { + if ($y < $top) { + $top = $y; + } + + if ($y > $bottom) { + $bottom = $y; + } + + if ($x32 * 32 < $left) { + $bit = 0; + + while (($bits << (31 - $bit)) === 0) { + $bit++; + } + + if (($x32 * 32 + $bit) < $left) { + $left = $x32 * 32 + $bit; + } + } + } + + if ($x32 * 32 + 31 > $right) { + $bit = 31; + + while (0 === BitUtils::unsignedRightShift($bits, $bit)) { + --$bit; + } + + if (($x32 * 32 + $bit) > $right) { + $right = $x32 * 32 + $bit; + } + } + } + } + + $width = $right - $left; + $height = $bottom - $top; + + if ($width < 0 || $height < 0) { + return null; + } + + return [$left, $top, $width, $height]; + } + + /** + * Gets the most top left set bit. + * + * This is useful in detecting a corner of a 'pure' barcode. + * + * @return int[]|null + */ + public function getTopLeftOnBit() : ?array + { + $bitsOffset = 0; + + while ($bitsOffset < count($this->bits) && 0 === $this->bits[$bitsOffset]) { + ++$bitsOffset; + } + + if (count($this->bits) === $bitsOffset) { + return null; + } + + $x = intdiv($bitsOffset, $this->rowSize); + $y = ($bitsOffset % $this->rowSize) << 5; + + $bits = $this->bits[$bitsOffset]; + $bit = 0; + + while (0 === ($bits << (31 - $bit))) { + ++$bit; + } + + $x += $bit; + + return [$x, $y]; + } + + /** + * Gets the most bottom right set bit. + * + * This is useful in detecting a corner of a 'pure' barcode. + * + * @return int[]|null + */ + public function getBottomRightOnBit() : ?array + { + $bitsOffset = count($this->bits) - 1; + + while ($bitsOffset >= 0 && 0 === $this->bits[$bitsOffset]) { + --$bitsOffset; + } + + if ($bitsOffset < 0) { + return null; + } + + $x = intdiv($bitsOffset, $this->rowSize); + $y = ($bitsOffset % $this->rowSize) << 5; + + $bits = $this->bits[$bitsOffset]; + $bit = 0; + + while (0 === BitUtils::unsignedRightShift($bits, $bit)) { + --$bit; + } + + $x += $bit; + + return [$x, $y]; + } + + /** + * Gets the width of the matrix, + */ + public function getWidth() : int + { + return $this->width; + } + + /** + * Gets the height of the matrix. + */ + public function getHeight() : int + { + return $this->height; + } +} diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/src/Common/BitUtils.php b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Common/BitUtils.php new file mode 100644 index 00000000..0c575b49 --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Common/BitUtils.php @@ -0,0 +1,41 @@ +>>" in other + * languages. + */ + public static function unsignedRightShift(int $a, int $b) : int + { + return ( + $a >= 0 + ? $a >> $b + : (($a & 0x7fffffff) >> $b) | (0x40000000 >> ($b - 1)) + ); + } + + /** + * Gets the number of trailing zeros. + */ + public static function numberOfTrailingZeros(int $i) : int + { + $lastPos = strrpos(str_pad(decbin($i), 32, '0', STR_PAD_LEFT), '1'); + return $lastPos === false ? 32 : 31 - $lastPos; + } +} diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/src/Common/CharacterSetEci.php b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Common/CharacterSetEci.php new file mode 100644 index 00000000..6dfff179 --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Common/CharacterSetEci.php @@ -0,0 +1,180 @@ +|null + */ + private static $valueToEci; + + /** + * @var array|null + */ + private static $nameToEci; + + public function __construct(array $values, string ...$otherEncodingNames) + { + $this->values = $values; + $this->otherEncodingNames = $otherEncodingNames; + } + + /** + * Returns the primary value. + */ + public function getValue() : int + { + return $this->values[0]; + } + + /** + * Gets character set ECI by value. + * + * Returns the representing ECI of a given value, or null if it is legal but unsupported. + * + * @throws InvalidArgumentException if value is not between 0 and 900 + */ + public static function getCharacterSetEciByValue(int $value) : ?self + { + if ($value < 0 || $value >= 900) { + throw new InvalidArgumentException('Value must be between 0 and 900'); + } + + $valueToEci = self::valueToEci(); + + if (! array_key_exists($value, $valueToEci)) { + return null; + } + + return $valueToEci[$value]; + } + + /** + * Returns character set ECI by name. + * + * Returns the representing ECI of a given name, or null if it is legal but unsupported + */ + public static function getCharacterSetEciByName(string $name) : ?self + { + $nameToEci = self::nameToEci(); + $name = strtolower($name); + + if (! array_key_exists($name, $nameToEci)) { + return null; + } + + return $nameToEci[$name]; + } + + private static function valueToEci() : array + { + if (null !== self::$valueToEci) { + return self::$valueToEci; + } + + self::$valueToEci = []; + + foreach (self::values() as $eci) { + foreach ($eci->values as $value) { + self::$valueToEci[$value] = $eci; + } + } + + return self::$valueToEci; + } + + private static function nameToEci() : array + { + if (null !== self::$nameToEci) { + return self::$nameToEci; + } + + self::$nameToEci = []; + + foreach (self::values() as $eci) { + self::$nameToEci[strtolower($eci->name())] = $eci; + + foreach ($eci->otherEncodingNames as $name) { + self::$nameToEci[strtolower($name)] = $eci; + } + } + + return self::$nameToEci; + } +} diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/src/Common/EcBlock.php b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Common/EcBlock.php new file mode 100644 index 00000000..a9a1d07d --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Common/EcBlock.php @@ -0,0 +1,49 @@ +count = $count; + $this->dataCodewords = $dataCodewords; + } + + /** + * Returns how many times the block is used. + */ + public function getCount() : int + { + return $this->count; + } + + /** + * Returns the number of data codewords. + */ + public function getDataCodewords() : int + { + return $this->dataCodewords; + } +} diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/src/Common/EcBlocks.php b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Common/EcBlocks.php new file mode 100644 index 00000000..172b5f27 --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Common/EcBlocks.php @@ -0,0 +1,74 @@ +ecCodewordsPerBlock = $ecCodewordsPerBlock; + $this->ecBlocks = $ecBlocks; + } + + /** + * Returns the number of EC codewords per block. + */ + public function getEcCodewordsPerBlock() : int + { + return $this->ecCodewordsPerBlock; + } + + /** + * Returns the total number of EC block appearances. + */ + public function getNumBlocks() : int + { + $total = 0; + + foreach ($this->ecBlocks as $ecBlock) { + $total += $ecBlock->getCount(); + } + + return $total; + } + + /** + * Returns the total count of EC codewords. + */ + public function getTotalEcCodewords() : int + { + return $this->ecCodewordsPerBlock * $this->getNumBlocks(); + } + + /** + * Returns the EC blocks included in this collection. + * + * @return EcBlock[] + */ + public function getEcBlocks() : array + { + return $this->ecBlocks; + } +} diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/src/Common/ErrorCorrectionLevel.php b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Common/ErrorCorrectionLevel.php new file mode 100644 index 00000000..9bbf4406 --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Common/ErrorCorrectionLevel.php @@ -0,0 +1,63 @@ +bits = $bits; + } + + /** + * @throws OutOfBoundsException if number of bits is invalid + */ + public static function forBits(int $bits) : self + { + switch ($bits) { + case 0: + return self::M(); + + case 1: + return self::L(); + + case 2: + return self::H(); + + case 3: + return self::Q(); + } + + throw new OutOfBoundsException('Invalid number of bits'); + } + + /** + * Returns the two bits used to encode this error correction level. + */ + public function getBits() : int + { + return $this->bits; + } +} diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/src/Common/FormatInformation.php b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Common/FormatInformation.php new file mode 100644 index 00000000..53e35419 --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Common/FormatInformation.php @@ -0,0 +1,203 @@ +ecLevel = ErrorCorrectionLevel::forBits(($formatInfo >> 3) & 0x3); + $this->dataMask = $formatInfo & 0x7; + } + + /** + * Checks how many bits are different between two integers. + */ + public static function numBitsDiffering(int $a, int $b) : int + { + $a ^= $b; + + return ( + self::BITS_SET_IN_HALF_BYTE[$a & 0xf] + + self::BITS_SET_IN_HALF_BYTE[(BitUtils::unsignedRightShift($a, 4) & 0xf)] + + self::BITS_SET_IN_HALF_BYTE[(BitUtils::unsignedRightShift($a, 8) & 0xf)] + + self::BITS_SET_IN_HALF_BYTE[(BitUtils::unsignedRightShift($a, 12) & 0xf)] + + self::BITS_SET_IN_HALF_BYTE[(BitUtils::unsignedRightShift($a, 16) & 0xf)] + + self::BITS_SET_IN_HALF_BYTE[(BitUtils::unsignedRightShift($a, 20) & 0xf)] + + self::BITS_SET_IN_HALF_BYTE[(BitUtils::unsignedRightShift($a, 24) & 0xf)] + + self::BITS_SET_IN_HALF_BYTE[(BitUtils::unsignedRightShift($a, 28) & 0xf)] + ); + } + + /** + * Decodes format information. + */ + public static function decodeFormatInformation(int $maskedFormatInfo1, int $maskedFormatInfo2) : ?self + { + $formatInfo = self::doDecodeFormatInformation($maskedFormatInfo1, $maskedFormatInfo2); + + if (null !== $formatInfo) { + return $formatInfo; + } + + // Should return null, but, some QR codes apparently do not mask this info. Try again by actually masking the + // pattern first. + return self::doDecodeFormatInformation( + $maskedFormatInfo1 ^ self::FORMAT_INFO_MASK_QR, + $maskedFormatInfo2 ^ self::FORMAT_INFO_MASK_QR + ); + } + + /** + * Internal method for decoding format information. + */ + private static function doDecodeFormatInformation(int $maskedFormatInfo1, int $maskedFormatInfo2) : ?self + { + $bestDifference = PHP_INT_MAX; + $bestFormatInfo = 0; + + foreach (self::FORMAT_INFO_DECODE_LOOKUP as $decodeInfo) { + $targetInfo = $decodeInfo[0]; + + if ($targetInfo === $maskedFormatInfo1 || $targetInfo === $maskedFormatInfo2) { + // Found an exact match + return new self($decodeInfo[1]); + } + + $bitsDifference = self::numBitsDiffering($maskedFormatInfo1, $targetInfo); + + if ($bitsDifference < $bestDifference) { + $bestFormatInfo = $decodeInfo[1]; + $bestDifference = $bitsDifference; + } + + if ($maskedFormatInfo1 !== $maskedFormatInfo2) { + // Also try the other option + $bitsDifference = self::numBitsDiffering($maskedFormatInfo2, $targetInfo); + + if ($bitsDifference < $bestDifference) { + $bestFormatInfo = $decodeInfo[1]; + $bestDifference = $bitsDifference; + } + } + } + + // Hamming distance of the 32 masked codes is 7, by construction, so <= 3 bits differing means we found a match. + if ($bestDifference <= 3) { + return new self($bestFormatInfo); + } + + return null; + } + + /** + * Returns the error correction level. + */ + public function getErrorCorrectionLevel() : ErrorCorrectionLevel + { + return $this->ecLevel; + } + + /** + * Returns the data mask. + */ + public function getDataMask() : int + { + return $this->dataMask; + } + + /** + * Hashes the code of the EC level. + */ + public function hashCode() : int + { + return ($this->ecLevel->getBits() << 3) | $this->dataMask; + } + + /** + * Verifies if this instance equals another one. + */ + public function equals(self $other) : bool + { + return ( + $this->ecLevel === $other->ecLevel + && $this->dataMask === $other->dataMask + ); + } +} diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/src/Common/Mode.php b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Common/Mode.php new file mode 100644 index 00000000..51e6c9a8 --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Common/Mode.php @@ -0,0 +1,76 @@ +characterCountBitsForVersions = $characterCountBitsForVersions; + $this->bits = $bits; + } + + /** + * Returns the number of bits used in a specific QR code version. + */ + public function getCharacterCountBits(Version $version) : int + { + $number = $version->getVersionNumber(); + + if ($number <= 9) { + $offset = 0; + } elseif ($number <= 26) { + $offset = 1; + } else { + $offset = 2; + } + + return $this->characterCountBitsForVersions[$offset]; + } + + /** + * Returns the four bits used to encode this mode. + */ + public function getBits() : int + { + return $this->bits; + } +} diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/src/Common/ReedSolomonCodec.php b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Common/ReedSolomonCodec.php new file mode 100644 index 00000000..a5aad0b5 --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Common/ReedSolomonCodec.php @@ -0,0 +1,468 @@ + 8) { + throw new InvalidArgumentException('Symbol size must be between 0 and 8'); + } + + if ($firstRoot < 0 || $firstRoot >= (1 << $symbolSize)) { + throw new InvalidArgumentException('First root must be between 0 and ' . (1 << $symbolSize)); + } + + if ($numRoots < 0 || $numRoots >= (1 << $symbolSize)) { + throw new InvalidArgumentException('Num roots must be between 0 and ' . (1 << $symbolSize)); + } + + if ($padding < 0 || $padding >= ((1 << $symbolSize) - 1 - $numRoots)) { + throw new InvalidArgumentException( + 'Padding must be between 0 and ' . ((1 << $symbolSize) - 1 - $numRoots) + ); + } + + $this->symbolSize = $symbolSize; + $this->blockSize = (1 << $symbolSize) - 1; + $this->padding = $padding; + $this->alphaTo = SplFixedArray::fromArray(array_fill(0, $this->blockSize + 1, 0), false); + $this->indexOf = SplFixedArray::fromArray(array_fill(0, $this->blockSize + 1, 0), false); + + // Generate galous field lookup table + $this->indexOf[0] = $this->blockSize; + $this->alphaTo[$this->blockSize] = 0; + + $sr = 1; + + for ($i = 0; $i < $this->blockSize; ++$i) { + $this->indexOf[$sr] = $i; + $this->alphaTo[$i] = $sr; + + $sr <<= 1; + + if ($sr & (1 << $symbolSize)) { + $sr ^= $gfPoly; + } + + $sr &= $this->blockSize; + } + + if (1 !== $sr) { + throw new RuntimeException('Field generator polynomial is not primitive'); + } + + // Form RS code generator polynomial from its roots + $this->generatorPoly = SplFixedArray::fromArray(array_fill(0, $numRoots + 1, 0), false); + $this->firstRoot = $firstRoot; + $this->primitive = $primitive; + $this->numRoots = $numRoots; + + // Find prim-th root of 1, used in decoding + for ($iPrimitive = 1; ($iPrimitive % $primitive) !== 0; $iPrimitive += $this->blockSize) { + } + + $this->iPrimitive = intdiv($iPrimitive, $primitive); + + $this->generatorPoly[0] = 1; + + for ($i = 0, $root = $firstRoot * $primitive; $i < $numRoots; ++$i, $root += $primitive) { + $this->generatorPoly[$i + 1] = 1; + + for ($j = $i; $j > 0; $j--) { + if ($this->generatorPoly[$j] !== 0) { + $this->generatorPoly[$j] = $this->generatorPoly[$j - 1] ^ $this->alphaTo[ + $this->modNn($this->indexOf[$this->generatorPoly[$j]] + $root) + ]; + } else { + $this->generatorPoly[$j] = $this->generatorPoly[$j - 1]; + } + } + + $this->generatorPoly[$j] = $this->alphaTo[$this->modNn($this->indexOf[$this->generatorPoly[0]] + $root)]; + } + + // Convert generator poly to index form for quicker encoding + for ($i = 0; $i <= $numRoots; ++$i) { + $this->generatorPoly[$i] = $this->indexOf[$this->generatorPoly[$i]]; + } + } + + /** + * Encodes data and writes result back into parity array. + */ + public function encode(SplFixedArray $data, SplFixedArray $parity) : void + { + for ($i = 0; $i < $this->numRoots; ++$i) { + $parity[$i] = 0; + } + + $iterations = $this->blockSize - $this->numRoots - $this->padding; + + for ($i = 0; $i < $iterations; ++$i) { + $feedback = $this->indexOf[$data[$i] ^ $parity[0]]; + + if ($feedback !== $this->blockSize) { + // Feedback term is non-zero + $feedback = $this->modNn($this->blockSize - $this->generatorPoly[$this->numRoots] + $feedback); + + for ($j = 1; $j < $this->numRoots; ++$j) { + $parity[$j] = $parity[$j] ^ $this->alphaTo[ + $this->modNn($feedback + $this->generatorPoly[$this->numRoots - $j]) + ]; + } + } + + for ($j = 0; $j < $this->numRoots - 1; ++$j) { + $parity[$j] = $parity[$j + 1]; + } + + if ($feedback !== $this->blockSize) { + $parity[$this->numRoots - 1] = $this->alphaTo[$this->modNn($feedback + $this->generatorPoly[0])]; + } else { + $parity[$this->numRoots - 1] = 0; + } + } + } + + /** + * Decodes received data. + */ + public function decode(SplFixedArray $data, SplFixedArray $erasures = null) : ?int + { + // This speeds up the initialization a bit. + $numRootsPlusOne = SplFixedArray::fromArray(array_fill(0, $this->numRoots + 1, 0), false); + $numRoots = SplFixedArray::fromArray(array_fill(0, $this->numRoots, 0), false); + + $lambda = clone $numRootsPlusOne; + $b = clone $numRootsPlusOne; + $t = clone $numRootsPlusOne; + $omega = clone $numRootsPlusOne; + $root = clone $numRoots; + $loc = clone $numRoots; + + $numErasures = (null !== $erasures ? count($erasures) : 0); + + // Form the Syndromes; i.e., evaluate data(x) at roots of g(x) + $syndromes = SplFixedArray::fromArray(array_fill(0, $this->numRoots, $data[0]), false); + + for ($i = 1; $i < $this->blockSize - $this->padding; ++$i) { + for ($j = 0; $j < $this->numRoots; ++$j) { + if ($syndromes[$j] === 0) { + $syndromes[$j] = $data[$i]; + } else { + $syndromes[$j] = $data[$i] ^ $this->alphaTo[ + $this->modNn($this->indexOf[$syndromes[$j]] + ($this->firstRoot + $j) * $this->primitive) + ]; + } + } + } + + // Convert syndromes to index form, checking for nonzero conditions + $syndromeError = 0; + + for ($i = 0; $i < $this->numRoots; ++$i) { + $syndromeError |= $syndromes[$i]; + $syndromes[$i] = $this->indexOf[$syndromes[$i]]; + } + + if (! $syndromeError) { + // If syndrome is zero, data[] is a codeword and there are no errors to correct, so return data[] + // unmodified. + return 0; + } + + $lambda[0] = 1; + + if ($numErasures > 0) { + // Init lambda to be the erasure locator polynomial + $lambda[1] = $this->alphaTo[$this->modNn($this->primitive * ($this->blockSize - 1 - $erasures[0]))]; + + for ($i = 1; $i < $numErasures; ++$i) { + $u = $this->modNn($this->primitive * ($this->blockSize - 1 - $erasures[$i])); + + for ($j = $i + 1; $j > 0; --$j) { + $tmp = $this->indexOf[$lambda[$j - 1]]; + + if ($tmp !== $this->blockSize) { + $lambda[$j] = $lambda[$j] ^ $this->alphaTo[$this->modNn($u + $tmp)]; + } + } + } + } + + for ($i = 0; $i <= $this->numRoots; ++$i) { + $b[$i] = $this->indexOf[$lambda[$i]]; + } + + // Begin Berlekamp-Massey algorithm to determine error+erasure locator polynomial + $r = $numErasures; + $el = $numErasures; + + while (++$r <= $this->numRoots) { + // Compute discrepancy at the r-th step in poly form + $discrepancyR = 0; + + for ($i = 0; $i < $r; ++$i) { + if ($lambda[$i] !== 0 && $syndromes[$r - $i - 1] !== $this->blockSize) { + $discrepancyR ^= $this->alphaTo[ + $this->modNn($this->indexOf[$lambda[$i]] + $syndromes[$r - $i - 1]) + ]; + } + } + + $discrepancyR = $this->indexOf[$discrepancyR]; + + if ($discrepancyR === $this->blockSize) { + $tmp = $b->toArray(); + array_unshift($tmp, $this->blockSize); + array_pop($tmp); + $b = SplFixedArray::fromArray($tmp, false); + continue; + } + + $t[0] = $lambda[0]; + + for ($i = 0; $i < $this->numRoots; ++$i) { + if ($b[$i] !== $this->blockSize) { + $t[$i + 1] = $lambda[$i + 1] ^ $this->alphaTo[$this->modNn($discrepancyR + $b[$i])]; + } else { + $t[$i + 1] = $lambda[$i + 1]; + } + } + + if (2 * $el <= $r + $numErasures - 1) { + $el = $r + $numErasures - $el; + + for ($i = 0; $i <= $this->numRoots; ++$i) { + $b[$i] = ( + $lambda[$i] === 0 + ? $this->blockSize + : $this->modNn($this->indexOf[$lambda[$i]] - $discrepancyR + $this->blockSize) + ); + } + } else { + $tmp = $b->toArray(); + array_unshift($tmp, $this->blockSize); + array_pop($tmp); + $b = SplFixedArray::fromArray($tmp, false); + } + + $lambda = clone $t; + } + + // Convert lambda to index form and compute deg(lambda(x)) + $degLambda = 0; + + for ($i = 0; $i <= $this->numRoots; ++$i) { + $lambda[$i] = $this->indexOf[$lambda[$i]]; + + if ($lambda[$i] !== $this->blockSize) { + $degLambda = $i; + } + } + + // Find roots of the error+erasure locator polynomial by Chien search. + $reg = clone $lambda; + $reg[0] = 0; + $count = 0; + $i = 1; + + for ($k = $this->iPrimitive - 1; $i <= $this->blockSize; ++$i, $k = $this->modNn($k + $this->iPrimitive)) { + $q = 1; + + for ($j = $degLambda; $j > 0; $j--) { + if ($reg[$j] !== $this->blockSize) { + $reg[$j] = $this->modNn($reg[$j] + $j); + $q ^= $this->alphaTo[$reg[$j]]; + } + } + + if ($q !== 0) { + // Not a root + continue; + } + + // Store root (index-form) and error location number + $root[$count] = $i; + $loc[$count] = $k; + + if (++$count === $degLambda) { + break; + } + } + + if ($degLambda !== $count) { + // deg(lambda) unequal to number of roots: uncorrectable error detected + return null; + } + + // Compute err+eras evaluate poly omega(x) = s(x)*lambda(x) (modulo x**numRoots). In index form. Also find + // deg(omega). + $degOmega = $degLambda - 1; + + for ($i = 0; $i <= $degOmega; ++$i) { + $tmp = 0; + + for ($j = $i; $j >= 0; --$j) { + if ($syndromes[$i - $j] !== $this->blockSize && $lambda[$j] !== $this->blockSize) { + $tmp ^= $this->alphaTo[$this->modNn($syndromes[$i - $j] + $lambda[$j])]; + } + } + + $omega[$i] = $this->indexOf[$tmp]; + } + + // Compute error values in poly-form. num1 = omega(inv(X(l))), num2 = inv(X(l))**(firstRoot-1) and + // den = lambda_pr(inv(X(l))) all in poly form. + for ($j = $count - 1; $j >= 0; --$j) { + $num1 = 0; + + for ($i = $degOmega; $i >= 0; $i--) { + if ($omega[$i] !== $this->blockSize) { + $num1 ^= $this->alphaTo[$this->modNn($omega[$i] + $i * $root[$j])]; + } + } + + $num2 = $this->alphaTo[$this->modNn($root[$j] * ($this->firstRoot - 1) + $this->blockSize)]; + $den = 0; + + // lambda[i+1] for i even is the formal derivativelambda_pr of lambda[i] + for ($i = min($degLambda, $this->numRoots - 1) & ~1; $i >= 0; $i -= 2) { + if ($lambda[$i + 1] !== $this->blockSize) { + $den ^= $this->alphaTo[$this->modNn($lambda[$i + 1] + $i * $root[$j])]; + } + } + + // Apply error to data + if ($num1 !== 0 && $loc[$j] >= $this->padding) { + $data[$loc[$j] - $this->padding] = $data[$loc[$j] - $this->padding] ^ ( + $this->alphaTo[ + $this->modNn( + $this->indexOf[$num1] + $this->indexOf[$num2] + $this->blockSize - $this->indexOf[$den] + ) + ] + ); + } + } + + if (null !== $erasures) { + if (count($erasures) < $count) { + $erasures->setSize($count); + } + + for ($i = 0; $i < $count; $i++) { + $erasures[$i] = $loc[$i]; + } + } + + return $count; + } + + /** + * Computes $x % GF_SIZE, where GF_SIZE is 2**GF_BITS - 1, without a slow divide. + */ + private function modNn(int $x) : int + { + while ($x >= $this->blockSize) { + $x -= $this->blockSize; + $x = ($x >> $this->symbolSize) + ($x & $this->blockSize); + } + + return $x; + } +} diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/src/Common/Version.php b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Common/Version.php new file mode 100644 index 00000000..917d048d --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Common/Version.php @@ -0,0 +1,596 @@ +|null + */ + private static $versions; + + /** + * @param int[] $alignmentPatternCenters + */ + private function __construct( + int $versionNumber, + array $alignmentPatternCenters, + EcBlocks ...$ecBlocks + ) { + $this->versionNumber = $versionNumber; + $this->alignmentPatternCenters = $alignmentPatternCenters; + $this->ecBlocks = $ecBlocks; + + $totalCodewords = 0; + $ecCodewords = $ecBlocks[0]->getEcCodewordsPerBlock(); + + foreach ($ecBlocks[0]->getEcBlocks() as $ecBlock) { + $totalCodewords += $ecBlock->getCount() * ($ecBlock->getDataCodewords() + $ecCodewords); + } + + $this->totalCodewords = $totalCodewords; + } + + /** + * Returns the version number. + */ + public function getVersionNumber() : int + { + return $this->versionNumber; + } + + /** + * Returns the alignment pattern centers. + * + * @return int[] + */ + public function getAlignmentPatternCenters() : array + { + return $this->alignmentPatternCenters; + } + + /** + * Returns the total number of codewords. + */ + public function getTotalCodewords() : int + { + return $this->totalCodewords; + } + + /** + * Calculates the dimension for the current version. + */ + public function getDimensionForVersion() : int + { + return 17 + 4 * $this->versionNumber; + } + + /** + * Returns the number of EC blocks for a specific EC level. + */ + public function getEcBlocksForLevel(ErrorCorrectionLevel $ecLevel) : EcBlocks + { + return $this->ecBlocks[$ecLevel->ordinal()]; + } + + /** + * Gets a provisional version number for a specific dimension. + * + * @throws InvalidArgumentException if dimension is not 1 mod 4 + */ + public static function getProvisionalVersionForDimension(int $dimension) : self + { + if (1 !== $dimension % 4) { + throw new InvalidArgumentException('Dimension is not 1 mod 4'); + } + + return self::getVersionForNumber(intdiv($dimension - 17, 4)); + } + + /** + * Gets a version instance for a specific version number. + * + * @throws InvalidArgumentException if version number is out of range + */ + public static function getVersionForNumber(int $versionNumber) : self + { + if ($versionNumber < 1 || $versionNumber > 40) { + throw new InvalidArgumentException('Version number must be between 1 and 40'); + } + + return self::versions()[$versionNumber - 1]; + } + + /** + * Decodes version information from an integer and returns the version. + */ + public static function decodeVersionInformation(int $versionBits) : ?self + { + $bestDifference = PHP_INT_MAX; + $bestVersion = 0; + + foreach (self::VERSION_DECODE_INFO as $i => $targetVersion) { + if ($targetVersion === $versionBits) { + return self::getVersionForNumber($i + 7); + } + + $bitsDifference = FormatInformation::numBitsDiffering($versionBits, $targetVersion); + + if ($bitsDifference < $bestDifference) { + $bestVersion = $i + 7; + $bestDifference = $bitsDifference; + } + } + + if ($bestDifference <= 3) { + return self::getVersionForNumber($bestVersion); + } + + return null; + } + + /** + * Builds the function pattern for the current version. + */ + public function buildFunctionPattern() : BitMatrix + { + $dimension = $this->getDimensionForVersion(); + $bitMatrix = new BitMatrix($dimension); + + // Top left finder pattern + separator + format + $bitMatrix->setRegion(0, 0, 9, 9); + // Top right finder pattern + separator + format + $bitMatrix->setRegion($dimension - 8, 0, 8, 9); + // Bottom left finder pattern + separator + format + $bitMatrix->setRegion(0, $dimension - 8, 9, 8); + + // Alignment patterns + $max = count($this->alignmentPatternCenters); + + for ($x = 0; $x < $max; ++$x) { + $i = $this->alignmentPatternCenters[$x] - 2; + + for ($y = 0; $y < $max; ++$y) { + if (($x === 0 && ($y === 0 || $y === $max - 1)) || ($x === $max - 1 && $y === 0)) { + // No alignment patterns near the three finder paterns + continue; + } + + $bitMatrix->setRegion($this->alignmentPatternCenters[$y] - 2, $i, 5, 5); + } + } + + // Vertical timing pattern + $bitMatrix->setRegion(6, 9, 1, $dimension - 17); + // Horizontal timing pattern + $bitMatrix->setRegion(9, 6, $dimension - 17, 1); + + if ($this->versionNumber > 6) { + // Version info, top right + $bitMatrix->setRegion($dimension - 11, 0, 3, 6); + // Version info, bottom left + $bitMatrix->setRegion(0, $dimension - 11, 6, 3); + } + + return $bitMatrix; + } + + /** + * Returns a string representation for the version. + */ + public function __toString() : string + { + return (string) $this->versionNumber; + } + + /** + * Build and cache a specific version. + * + * See ISO 18004:2006 6.5.1 Table 9. + * + * @return array + */ + private static function versions() : array + { + if (null !== self::$versions) { + return self::$versions; + } + + return self::$versions = [ + new self( + 1, + [], + new EcBlocks(7, new EcBlock(1, 19)), + new EcBlocks(10, new EcBlock(1, 16)), + new EcBlocks(13, new EcBlock(1, 13)), + new EcBlocks(17, new EcBlock(1, 9)) + ), + new self( + 2, + [6, 18], + new EcBlocks(10, new EcBlock(1, 34)), + new EcBlocks(16, new EcBlock(1, 28)), + new EcBlocks(22, new EcBlock(1, 22)), + new EcBlocks(28, new EcBlock(1, 16)) + ), + new self( + 3, + [6, 22], + new EcBlocks(15, new EcBlock(1, 55)), + new EcBlocks(26, new EcBlock(1, 44)), + new EcBlocks(18, new EcBlock(2, 17)), + new EcBlocks(22, new EcBlock(2, 13)) + ), + new self( + 4, + [6, 26], + new EcBlocks(20, new EcBlock(1, 80)), + new EcBlocks(18, new EcBlock(2, 32)), + new EcBlocks(26, new EcBlock(3, 24)), + new EcBlocks(16, new EcBlock(4, 9)) + ), + new self( + 5, + [6, 30], + new EcBlocks(26, new EcBlock(1, 108)), + new EcBlocks(24, new EcBlock(2, 43)), + new EcBlocks(18, new EcBlock(2, 15), new EcBlock(2, 16)), + new EcBlocks(22, new EcBlock(2, 11), new EcBlock(2, 12)) + ), + new self( + 6, + [6, 34], + new EcBlocks(18, new EcBlock(2, 68)), + new EcBlocks(16, new EcBlock(4, 27)), + new EcBlocks(24, new EcBlock(4, 19)), + new EcBlocks(28, new EcBlock(4, 15)) + ), + new self( + 7, + [6, 22, 38], + new EcBlocks(20, new EcBlock(2, 78)), + new EcBlocks(18, new EcBlock(4, 31)), + new EcBlocks(18, new EcBlock(2, 14), new EcBlock(4, 15)), + new EcBlocks(26, new EcBlock(4, 13), new EcBlock(1, 14)) + ), + new self( + 8, + [6, 24, 42], + new EcBlocks(24, new EcBlock(2, 97)), + new EcBlocks(22, new EcBlock(2, 38), new EcBlock(2, 39)), + new EcBlocks(22, new EcBlock(4, 18), new EcBlock(2, 19)), + new EcBlocks(26, new EcBlock(4, 14), new EcBlock(2, 15)) + ), + new self( + 9, + [6, 26, 46], + new EcBlocks(30, new EcBlock(2, 116)), + new EcBlocks(22, new EcBlock(3, 36), new EcBlock(2, 37)), + new EcBlocks(20, new EcBlock(4, 16), new EcBlock(4, 17)), + new EcBlocks(24, new EcBlock(4, 12), new EcBlock(4, 13)) + ), + new self( + 10, + [6, 28, 50], + new EcBlocks(18, new EcBlock(2, 68), new EcBlock(2, 69)), + new EcBlocks(26, new EcBlock(4, 43), new EcBlock(1, 44)), + new EcBlocks(24, new EcBlock(6, 19), new EcBlock(2, 20)), + new EcBlocks(28, new EcBlock(6, 15), new EcBlock(2, 16)) + ), + new self( + 11, + [6, 30, 54], + new EcBlocks(20, new EcBlock(4, 81)), + new EcBlocks(30, new EcBlock(1, 50), new EcBlock(4, 51)), + new EcBlocks(28, new EcBlock(4, 22), new EcBlock(4, 23)), + new EcBlocks(24, new EcBlock(3, 12), new EcBlock(8, 13)) + ), + new self( + 12, + [6, 32, 58], + new EcBlocks(24, new EcBlock(2, 92), new EcBlock(2, 93)), + new EcBlocks(22, new EcBlock(6, 36), new EcBlock(2, 37)), + new EcBlocks(26, new EcBlock(4, 20), new EcBlock(6, 21)), + new EcBlocks(28, new EcBlock(7, 14), new EcBlock(4, 15)) + ), + new self( + 13, + [6, 34, 62], + new EcBlocks(26, new EcBlock(4, 107)), + new EcBlocks(22, new EcBlock(8, 37), new EcBlock(1, 38)), + new EcBlocks(24, new EcBlock(8, 20), new EcBlock(4, 21)), + new EcBlocks(22, new EcBlock(12, 11), new EcBlock(4, 12)) + ), + new self( + 14, + [6, 26, 46, 66], + new EcBlocks(30, new EcBlock(3, 115), new EcBlock(1, 116)), + new EcBlocks(24, new EcBlock(4, 40), new EcBlock(5, 41)), + new EcBlocks(20, new EcBlock(11, 16), new EcBlock(5, 17)), + new EcBlocks(24, new EcBlock(11, 12), new EcBlock(5, 13)) + ), + new self( + 15, + [6, 26, 48, 70], + new EcBlocks(22, new EcBlock(5, 87), new EcBlock(1, 88)), + new EcBlocks(24, new EcBlock(5, 41), new EcBlock(5, 42)), + new EcBlocks(30, new EcBlock(5, 24), new EcBlock(7, 25)), + new EcBlocks(24, new EcBlock(11, 12), new EcBlock(7, 13)) + ), + new self( + 16, + [6, 26, 50, 74], + new EcBlocks(24, new EcBlock(5, 98), new EcBlock(1, 99)), + new EcBlocks(28, new EcBlock(7, 45), new EcBlock(3, 46)), + new EcBlocks(24, new EcBlock(15, 19), new EcBlock(2, 20)), + new EcBlocks(30, new EcBlock(3, 15), new EcBlock(13, 16)) + ), + new self( + 17, + [6, 30, 54, 78], + new EcBlocks(28, new EcBlock(1, 107), new EcBlock(5, 108)), + new EcBlocks(28, new EcBlock(10, 46), new EcBlock(1, 47)), + new EcBlocks(28, new EcBlock(1, 22), new EcBlock(15, 23)), + new EcBlocks(28, new EcBlock(2, 14), new EcBlock(17, 15)) + ), + new self( + 18, + [6, 30, 56, 82], + new EcBlocks(30, new EcBlock(5, 120), new EcBlock(1, 121)), + new EcBlocks(26, new EcBlock(9, 43), new EcBlock(4, 44)), + new EcBlocks(28, new EcBlock(17, 22), new EcBlock(1, 23)), + new EcBlocks(28, new EcBlock(2, 14), new EcBlock(19, 15)) + ), + new self( + 19, + [6, 30, 58, 86], + new EcBlocks(28, new EcBlock(3, 113), new EcBlock(4, 114)), + new EcBlocks(26, new EcBlock(3, 44), new EcBlock(11, 45)), + new EcBlocks(26, new EcBlock(17, 21), new EcBlock(4, 22)), + new EcBlocks(26, new EcBlock(9, 13), new EcBlock(16, 14)) + ), + new self( + 20, + [6, 34, 62, 90], + new EcBlocks(28, new EcBlock(3, 107), new EcBlock(5, 108)), + new EcBlocks(26, new EcBlock(3, 41), new EcBlock(13, 42)), + new EcBlocks(30, new EcBlock(15, 24), new EcBlock(5, 25)), + new EcBlocks(28, new EcBlock(15, 15), new EcBlock(10, 16)) + ), + new self( + 21, + [6, 28, 50, 72, 94], + new EcBlocks(28, new EcBlock(4, 116), new EcBlock(4, 117)), + new EcBlocks(26, new EcBlock(17, 42)), + new EcBlocks(28, new EcBlock(17, 22), new EcBlock(6, 23)), + new EcBlocks(30, new EcBlock(19, 16), new EcBlock(6, 17)) + ), + new self( + 22, + [6, 26, 50, 74, 98], + new EcBlocks(28, new EcBlock(2, 111), new EcBlock(7, 112)), + new EcBlocks(28, new EcBlock(17, 46)), + new EcBlocks(30, new EcBlock(7, 24), new EcBlock(16, 25)), + new EcBlocks(24, new EcBlock(34, 13)) + ), + new self( + 23, + [6, 30, 54, 78, 102], + new EcBlocks(30, new EcBlock(4, 121), new EcBlock(5, 122)), + new EcBlocks(28, new EcBlock(4, 47), new EcBlock(14, 48)), + new EcBlocks(30, new EcBlock(11, 24), new EcBlock(14, 25)), + new EcBlocks(30, new EcBlock(16, 15), new EcBlock(14, 16)) + ), + new self( + 24, + [6, 28, 54, 80, 106], + new EcBlocks(30, new EcBlock(6, 117), new EcBlock(4, 118)), + new EcBlocks(28, new EcBlock(6, 45), new EcBlock(14, 46)), + new EcBlocks(30, new EcBlock(11, 24), new EcBlock(16, 25)), + new EcBlocks(30, new EcBlock(30, 16), new EcBlock(2, 17)) + ), + new self( + 25, + [6, 32, 58, 84, 110], + new EcBlocks(26, new EcBlock(8, 106), new EcBlock(4, 107)), + new EcBlocks(28, new EcBlock(8, 47), new EcBlock(13, 48)), + new EcBlocks(30, new EcBlock(7, 24), new EcBlock(22, 25)), + new EcBlocks(30, new EcBlock(22, 15), new EcBlock(13, 16)) + ), + new self( + 26, + [6, 30, 58, 86, 114], + new EcBlocks(28, new EcBlock(10, 114), new EcBlock(2, 115)), + new EcBlocks(28, new EcBlock(19, 46), new EcBlock(4, 47)), + new EcBlocks(28, new EcBlock(28, 22), new EcBlock(6, 23)), + new EcBlocks(30, new EcBlock(33, 16), new EcBlock(4, 17)) + ), + new self( + 27, + [6, 34, 62, 90, 118], + new EcBlocks(30, new EcBlock(8, 122), new EcBlock(4, 123)), + new EcBlocks(28, new EcBlock(22, 45), new EcBlock(3, 46)), + new EcBlocks(30, new EcBlock(8, 23), new EcBlock(26, 24)), + new EcBlocks(30, new EcBlock(12, 15), new EcBlock(28, 16)) + ), + new self( + 28, + [6, 26, 50, 74, 98, 122], + new EcBlocks(30, new EcBlock(3, 117), new EcBlock(10, 118)), + new EcBlocks(28, new EcBlock(3, 45), new EcBlock(23, 46)), + new EcBlocks(30, new EcBlock(4, 24), new EcBlock(31, 25)), + new EcBlocks(30, new EcBlock(11, 15), new EcBlock(31, 16)) + ), + new self( + 29, + [6, 30, 54, 78, 102, 126], + new EcBlocks(30, new EcBlock(7, 116), new EcBlock(7, 117)), + new EcBlocks(28, new EcBlock(21, 45), new EcBlock(7, 46)), + new EcBlocks(30, new EcBlock(1, 23), new EcBlock(37, 24)), + new EcBlocks(30, new EcBlock(19, 15), new EcBlock(26, 16)) + ), + new self( + 30, + [6, 26, 52, 78, 104, 130], + new EcBlocks(30, new EcBlock(5, 115), new EcBlock(10, 116)), + new EcBlocks(28, new EcBlock(19, 47), new EcBlock(10, 48)), + new EcBlocks(30, new EcBlock(15, 24), new EcBlock(25, 25)), + new EcBlocks(30, new EcBlock(23, 15), new EcBlock(25, 16)) + ), + new self( + 31, + [6, 30, 56, 82, 108, 134], + new EcBlocks(30, new EcBlock(13, 115), new EcBlock(3, 116)), + new EcBlocks(28, new EcBlock(2, 46), new EcBlock(29, 47)), + new EcBlocks(30, new EcBlock(42, 24), new EcBlock(1, 25)), + new EcBlocks(30, new EcBlock(23, 15), new EcBlock(28, 16)) + ), + new self( + 32, + [6, 34, 60, 86, 112, 138], + new EcBlocks(30, new EcBlock(17, 115)), + new EcBlocks(28, new EcBlock(10, 46), new EcBlock(23, 47)), + new EcBlocks(30, new EcBlock(10, 24), new EcBlock(35, 25)), + new EcBlocks(30, new EcBlock(19, 15), new EcBlock(35, 16)) + ), + new self( + 33, + [6, 30, 58, 86, 114, 142], + new EcBlocks(30, new EcBlock(17, 115), new EcBlock(1, 116)), + new EcBlocks(28, new EcBlock(14, 46), new EcBlock(21, 47)), + new EcBlocks(30, new EcBlock(29, 24), new EcBlock(19, 25)), + new EcBlocks(30, new EcBlock(11, 15), new EcBlock(46, 16)) + ), + new self( + 34, + [6, 34, 62, 90, 118, 146], + new EcBlocks(30, new EcBlock(13, 115), new EcBlock(6, 116)), + new EcBlocks(28, new EcBlock(14, 46), new EcBlock(23, 47)), + new EcBlocks(30, new EcBlock(44, 24), new EcBlock(7, 25)), + new EcBlocks(30, new EcBlock(59, 16), new EcBlock(1, 17)) + ), + new self( + 35, + [6, 30, 54, 78, 102, 126, 150], + new EcBlocks(30, new EcBlock(12, 121), new EcBlock(7, 122)), + new EcBlocks(28, new EcBlock(12, 47), new EcBlock(26, 48)), + new EcBlocks(30, new EcBlock(39, 24), new EcBlock(14, 25)), + new EcBlocks(30, new EcBlock(22, 15), new EcBlock(41, 16)) + ), + new self( + 36, + [6, 24, 50, 76, 102, 128, 154], + new EcBlocks(30, new EcBlock(6, 121), new EcBlock(14, 122)), + new EcBlocks(28, new EcBlock(6, 47), new EcBlock(34, 48)), + new EcBlocks(30, new EcBlock(46, 24), new EcBlock(10, 25)), + new EcBlocks(30, new EcBlock(2, 15), new EcBlock(64, 16)) + ), + new self( + 37, + [6, 28, 54, 80, 106, 132, 158], + new EcBlocks(30, new EcBlock(17, 122), new EcBlock(4, 123)), + new EcBlocks(28, new EcBlock(29, 46), new EcBlock(14, 47)), + new EcBlocks(30, new EcBlock(49, 24), new EcBlock(10, 25)), + new EcBlocks(30, new EcBlock(24, 15), new EcBlock(46, 16)) + ), + new self( + 38, + [6, 32, 58, 84, 110, 136, 162], + new EcBlocks(30, new EcBlock(4, 122), new EcBlock(18, 123)), + new EcBlocks(28, new EcBlock(13, 46), new EcBlock(32, 47)), + new EcBlocks(30, new EcBlock(48, 24), new EcBlock(14, 25)), + new EcBlocks(30, new EcBlock(42, 15), new EcBlock(32, 16)) + ), + new self( + 39, + [6, 26, 54, 82, 110, 138, 166], + new EcBlocks(30, new EcBlock(20, 117), new EcBlock(4, 118)), + new EcBlocks(28, new EcBlock(40, 47), new EcBlock(7, 48)), + new EcBlocks(30, new EcBlock(43, 24), new EcBlock(22, 25)), + new EcBlocks(30, new EcBlock(10, 15), new EcBlock(67, 16)) + ), + new self( + 40, + [6, 30, 58, 86, 114, 142, 170], + new EcBlocks(30, new EcBlock(19, 118), new EcBlock(6, 119)), + new EcBlocks(28, new EcBlock(18, 47), new EcBlock(31, 48)), + new EcBlocks(30, new EcBlock(34, 24), new EcBlock(34, 25)), + new EcBlocks(30, new EcBlock(20, 15), new EcBlock(61, 16)) + ), + ]; + } +} diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/src/Encoder/BlockPair.php b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Encoder/BlockPair.php new file mode 100644 index 00000000..be54afaa --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Encoder/BlockPair.php @@ -0,0 +1,58 @@ + + */ + private $dataBytes; + + /** + * Error correction bytes in the block. + * + * @var SplFixedArray + */ + private $errorCorrectionBytes; + + /** + * Creates a new block pair. + * + * @param SplFixedArray $data + * @param SplFixedArray $errorCorrection + */ + public function __construct(SplFixedArray $data, SplFixedArray $errorCorrection) + { + $this->dataBytes = $data; + $this->errorCorrectionBytes = $errorCorrection; + } + + /** + * Gets the data bytes. + * + * @return SplFixedArray + */ + public function getDataBytes() : SplFixedArray + { + return $this->dataBytes; + } + + /** + * Gets the error correction bytes. + * + * @return SplFixedArray + */ + public function getErrorCorrectionBytes() : SplFixedArray + { + return $this->errorCorrectionBytes; + } +} diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/src/Encoder/ByteMatrix.php b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Encoder/ByteMatrix.php new file mode 100644 index 00000000..b58cc0ab --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Encoder/ByteMatrix.php @@ -0,0 +1,150 @@ +> + */ + private $bytes; + + /** + * Width of the matrix. + * + * @var int + */ + private $width; + + /** + * Height of the matrix. + * + * @var int + */ + private $height; + + public function __construct(int $width, int $height) + { + $this->height = $height; + $this->width = $width; + $this->bytes = new SplFixedArray($height); + + for ($y = 0; $y < $height; ++$y) { + $this->bytes[$y] = SplFixedArray::fromArray(array_fill(0, $width, 0)); + } + } + + /** + * Gets the width of the matrix. + */ + public function getWidth() : int + { + return $this->width; + } + + /** + * Gets the height of the matrix. + */ + public function getHeight() : int + { + return $this->height; + } + + /** + * Gets the internal representation of the matrix. + * + * @return SplFixedArray> + */ + public function getArray() : SplFixedArray + { + return $this->bytes; + } + + /** + * @return Traversable + */ + public function getBytes() : Traversable + { + foreach ($this->bytes as $row) { + foreach ($row as $byte) { + yield $byte; + } + } + } + + /** + * Gets the byte for a specific position. + */ + public function get(int $x, int $y) : int + { + return $this->bytes[$y][$x]; + } + + /** + * Sets the byte for a specific position. + */ + public function set(int $x, int $y, int $value) : void + { + $this->bytes[$y][$x] = $value; + } + + /** + * Clears the matrix with a specific value. + */ + public function clear(int $value) : void + { + for ($y = 0; $y < $this->height; ++$y) { + for ($x = 0; $x < $this->width; ++$x) { + $this->bytes[$y][$x] = $value; + } + } + } + + public function __clone() + { + $this->bytes = clone $this->bytes; + + foreach ($this->bytes as $index => $row) { + $this->bytes[$index] = clone $row; + } + } + + /** + * Returns a string representation of the matrix. + */ + public function __toString() : string + { + $result = ''; + + for ($y = 0; $y < $this->height; $y++) { + for ($x = 0; $x < $this->width; $x++) { + switch ($this->bytes[$y][$x]) { + case 0: + $result .= ' 0'; + break; + + case 1: + $result .= ' 1'; + break; + + default: + $result .= ' '; + break; + } + } + + $result .= "\n"; + } + + return $result; + } +} diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/src/Encoder/Encoder.php b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Encoder/Encoder.php new file mode 100644 index 00000000..4345f570 --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Encoder/Encoder.php @@ -0,0 +1,652 @@ +getSize() + + $mode->getCharacterCountBits(Version::getVersionForNumber(1)) + + $dataBits->getSize(); + $provisionalVersion = self::chooseVersion($provisionalBitsNeeded, $ecLevel); + + // Use that guess to calculate the right version. I am still not sure + // this works in 100% of cases. + $bitsNeeded = $headerBits->getSize() + + $mode->getCharacterCountBits($provisionalVersion) + + $dataBits->getSize(); + $version = self::chooseVersion($bitsNeeded, $ecLevel); + + $headerAndDataBits = new BitArray(); + $headerAndDataBits->appendBitArray($headerBits); + + // Find "length" of main segment and write it. + $numLetters = (Mode::BYTE() === $mode ? $dataBits->getSizeInBytes() : strlen($content)); + self::appendLengthInfo($numLetters, $version, $mode, $headerAndDataBits); + + // Put data together into the overall payload. + $headerAndDataBits->appendBitArray($dataBits); + $ecBlocks = $version->getEcBlocksForLevel($ecLevel); + $numDataBytes = $version->getTotalCodewords() - $ecBlocks->getTotalEcCodewords(); + + // Terminate the bits properly. + self::terminateBits($numDataBytes, $headerAndDataBits); + + // Interleave data bits with error correction code. + $finalBits = self::interleaveWithEcBytes( + $headerAndDataBits, + $version->getTotalCodewords(), + $numDataBytes, + $ecBlocks->getNumBlocks() + ); + + // Choose the mask pattern. + $dimension = $version->getDimensionForVersion(); + $matrix = new ByteMatrix($dimension, $dimension); + $maskPattern = self::chooseMaskPattern($finalBits, $ecLevel, $version, $matrix); + + // Build the matrix. + MatrixUtil::buildMatrix($finalBits, $ecLevel, $version, $maskPattern, $matrix); + + return new QrCode($mode, $ecLevel, $version, $maskPattern, $matrix); + } + + /** + * Gets the alphanumeric code for a byte. + */ + private static function getAlphanumericCode(int $code) : int + { + if (isset(self::ALPHANUMERIC_TABLE[$code])) { + return self::ALPHANUMERIC_TABLE[$code]; + } + + return -1; + } + + /** + * Chooses the best mode for a given content. + */ + private static function chooseMode(string $content, string $encoding = null) : Mode + { + if (null !== $encoding && 0 === strcasecmp($encoding, 'SHIFT-JIS')) { + return self::isOnlyDoubleByteKanji($content) ? Mode::KANJI() : Mode::BYTE(); + } + + $hasNumeric = false; + $hasAlphanumeric = false; + $contentLength = strlen($content); + + for ($i = 0; $i < $contentLength; ++$i) { + $char = $content[$i]; + + if (ctype_digit($char)) { + $hasNumeric = true; + } elseif (-1 !== self::getAlphanumericCode(ord($char))) { + $hasAlphanumeric = true; + } else { + return Mode::BYTE(); + } + } + + if ($hasAlphanumeric) { + return Mode::ALPHANUMERIC(); + } elseif ($hasNumeric) { + return Mode::NUMERIC(); + } + + return Mode::BYTE(); + } + + /** + * Calculates the mask penalty for a matrix. + */ + private static function calculateMaskPenalty(ByteMatrix $matrix) : int + { + return ( + MaskUtil::applyMaskPenaltyRule1($matrix) + + MaskUtil::applyMaskPenaltyRule2($matrix) + + MaskUtil::applyMaskPenaltyRule3($matrix) + + MaskUtil::applyMaskPenaltyRule4($matrix) + ); + } + + /** + * Checks if content only consists of double-byte kanji characters. + */ + private static function isOnlyDoubleByteKanji(string $content) : bool + { + $bytes = @iconv('utf-8', 'SHIFT-JIS', $content); + + if (false === $bytes) { + return false; + } + + $length = strlen($bytes); + + if (0 !== $length % 2) { + return false; + } + + for ($i = 0; $i < $length; $i += 2) { + $byte = $bytes[$i] & 0xff; + + if (($byte < 0x81 || $byte > 0x9f) && $byte < 0xe0 || $byte > 0xeb) { + return false; + } + } + + return true; + } + + /** + * Chooses the best mask pattern for a matrix. + */ + private static function chooseMaskPattern( + BitArray $bits, + ErrorCorrectionLevel $ecLevel, + Version $version, + ByteMatrix $matrix + ) : int { + $minPenalty = PHP_INT_MAX; + $bestMaskPattern = -1; + + for ($maskPattern = 0; $maskPattern < QrCode::NUM_MASK_PATTERNS; ++$maskPattern) { + MatrixUtil::buildMatrix($bits, $ecLevel, $version, $maskPattern, $matrix); + $penalty = self::calculateMaskPenalty($matrix); + + if ($penalty < $minPenalty) { + $minPenalty = $penalty; + $bestMaskPattern = $maskPattern; + } + } + + return $bestMaskPattern; + } + + /** + * Chooses the best version for the input. + * + * @throws WriterException if data is too big + */ + private static function chooseVersion(int $numInputBits, ErrorCorrectionLevel $ecLevel) : Version + { + for ($versionNum = 1; $versionNum <= 40; ++$versionNum) { + $version = Version::getVersionForNumber($versionNum); + $numBytes = $version->getTotalCodewords(); + + $ecBlocks = $version->getEcBlocksForLevel($ecLevel); + $numEcBytes = $ecBlocks->getTotalEcCodewords(); + + $numDataBytes = $numBytes - $numEcBytes; + $totalInputBytes = intdiv($numInputBits + 8, 8); + + if ($numDataBytes >= $totalInputBytes) { + return $version; + } + } + + throw new WriterException('Data too big'); + } + + /** + * Terminates the bits in a bit array. + * + * @throws WriterException if data bits cannot fit in the QR code + * @throws WriterException if bits size does not equal the capacity + */ + private static function terminateBits(int $numDataBytes, BitArray $bits) : void + { + $capacity = $numDataBytes << 3; + + if ($bits->getSize() > $capacity) { + throw new WriterException('Data bits cannot fit in the QR code'); + } + + for ($i = 0; $i < 4 && $bits->getSize() < $capacity; ++$i) { + $bits->appendBit(false); + } + + $numBitsInLastByte = $bits->getSize() & 0x7; + + if ($numBitsInLastByte > 0) { + for ($i = $numBitsInLastByte; $i < 8; ++$i) { + $bits->appendBit(false); + } + } + + $numPaddingBytes = $numDataBytes - $bits->getSizeInBytes(); + + for ($i = 0; $i < $numPaddingBytes; ++$i) { + $bits->appendBits(0 === ($i & 0x1) ? 0xec : 0x11, 8); + } + + if ($bits->getSize() !== $capacity) { + throw new WriterException('Bits size does not equal capacity'); + } + } + + /** + * Gets number of data- and EC bytes for a block ID. + * + * @return int[] + * @throws WriterException if block ID is too large + * @throws WriterException if EC bytes mismatch + * @throws WriterException if RS blocks mismatch + * @throws WriterException if total bytes mismatch + */ + private static function getNumDataBytesAndNumEcBytesForBlockId( + int $numTotalBytes, + int $numDataBytes, + int $numRsBlocks, + int $blockId + ) : array { + if ($blockId >= $numRsBlocks) { + throw new WriterException('Block ID too large'); + } + + $numRsBlocksInGroup2 = $numTotalBytes % $numRsBlocks; + $numRsBlocksInGroup1 = $numRsBlocks - $numRsBlocksInGroup2; + $numTotalBytesInGroup1 = intdiv($numTotalBytes, $numRsBlocks); + $numTotalBytesInGroup2 = $numTotalBytesInGroup1 + 1; + $numDataBytesInGroup1 = intdiv($numDataBytes, $numRsBlocks); + $numDataBytesInGroup2 = $numDataBytesInGroup1 + 1; + $numEcBytesInGroup1 = $numTotalBytesInGroup1 - $numDataBytesInGroup1; + $numEcBytesInGroup2 = $numTotalBytesInGroup2 - $numDataBytesInGroup2; + + if ($numEcBytesInGroup1 !== $numEcBytesInGroup2) { + throw new WriterException('EC bytes mismatch'); + } + + if ($numRsBlocks !== $numRsBlocksInGroup1 + $numRsBlocksInGroup2) { + throw new WriterException('RS blocks mismatch'); + } + + if ($numTotalBytes !== + (($numDataBytesInGroup1 + $numEcBytesInGroup1) * $numRsBlocksInGroup1) + + (($numDataBytesInGroup2 + $numEcBytesInGroup2) * $numRsBlocksInGroup2) + ) { + throw new WriterException('Total bytes mismatch'); + } + + if ($blockId < $numRsBlocksInGroup1) { + return [$numDataBytesInGroup1, $numEcBytesInGroup1]; + } else { + return [$numDataBytesInGroup2, $numEcBytesInGroup2]; + } + } + + /** + * Interleaves data with EC bytes. + * + * @throws WriterException if number of bits and data bytes does not match + * @throws WriterException if data bytes does not match offset + * @throws WriterException if an interleaving error occurs + */ + private static function interleaveWithEcBytes( + BitArray $bits, + int $numTotalBytes, + int $numDataBytes, + int $numRsBlocks + ) : BitArray { + if ($bits->getSizeInBytes() !== $numDataBytes) { + throw new WriterException('Number of bits and data bytes does not match'); + } + + $dataBytesOffset = 0; + $maxNumDataBytes = 0; + $maxNumEcBytes = 0; + + $blocks = new SplFixedArray($numRsBlocks); + + for ($i = 0; $i < $numRsBlocks; ++$i) { + list($numDataBytesInBlock, $numEcBytesInBlock) = self::getNumDataBytesAndNumEcBytesForBlockId( + $numTotalBytes, + $numDataBytes, + $numRsBlocks, + $i + ); + + $size = $numDataBytesInBlock; + $dataBytes = $bits->toBytes(8 * $dataBytesOffset, $size); + $ecBytes = self::generateEcBytes($dataBytes, $numEcBytesInBlock); + $blocks[$i] = new BlockPair($dataBytes, $ecBytes); + + $maxNumDataBytes = max($maxNumDataBytes, $size); + $maxNumEcBytes = max($maxNumEcBytes, count($ecBytes)); + $dataBytesOffset += $numDataBytesInBlock; + } + + if ($numDataBytes !== $dataBytesOffset) { + throw new WriterException('Data bytes does not match offset'); + } + + $result = new BitArray(); + + for ($i = 0; $i < $maxNumDataBytes; ++$i) { + foreach ($blocks as $block) { + $dataBytes = $block->getDataBytes(); + + if ($i < count($dataBytes)) { + $result->appendBits($dataBytes[$i], 8); + } + } + } + + for ($i = 0; $i < $maxNumEcBytes; ++$i) { + foreach ($blocks as $block) { + $ecBytes = $block->getErrorCorrectionBytes(); + + if ($i < count($ecBytes)) { + $result->appendBits($ecBytes[$i], 8); + } + } + } + + if ($numTotalBytes !== $result->getSizeInBytes()) { + throw new WriterException( + 'Interleaving error: ' . $numTotalBytes . ' and ' . $result->getSizeInBytes() . ' differ' + ); + } + + return $result; + } + + /** + * Generates EC bytes for given data. + * + * @param SplFixedArray $dataBytes + * @return SplFixedArray + */ + private static function generateEcBytes(SplFixedArray $dataBytes, int $numEcBytesInBlock) : SplFixedArray + { + $numDataBytes = count($dataBytes); + $toEncode = new SplFixedArray($numDataBytes + $numEcBytesInBlock); + + for ($i = 0; $i < $numDataBytes; $i++) { + $toEncode[$i] = $dataBytes[$i] & 0xff; + } + + $ecBytes = new SplFixedArray($numEcBytesInBlock); + $codec = self::getCodec($numDataBytes, $numEcBytesInBlock); + $codec->encode($toEncode, $ecBytes); + + return $ecBytes; + } + + /** + * Gets an RS codec and caches it. + */ + private static function getCodec(int $numDataBytes, int $numEcBytesInBlock) : ReedSolomonCodec + { + $cacheId = $numDataBytes . '-' . $numEcBytesInBlock; + + if (isset(self::$codecs[$cacheId])) { + return self::$codecs[$cacheId]; + } + + return self::$codecs[$cacheId] = new ReedSolomonCodec( + 8, + 0x11d, + 0, + 1, + $numEcBytesInBlock, + 255 - $numDataBytes - $numEcBytesInBlock + ); + } + + /** + * Appends mode information to a bit array. + */ + private static function appendModeInfo(Mode $mode, BitArray $bits) : void + { + $bits->appendBits($mode->getBits(), 4); + } + + /** + * Appends length information to a bit array. + * + * @throws WriterException if num letters is bigger than expected + */ + private static function appendLengthInfo(int $numLetters, Version $version, Mode $mode, BitArray $bits) : void + { + $numBits = $mode->getCharacterCountBits($version); + + if ($numLetters >= (1 << $numBits)) { + throw new WriterException($numLetters . ' is bigger than ' . ((1 << $numBits) - 1)); + } + + $bits->appendBits($numLetters, $numBits); + } + + /** + * Appends bytes to a bit array in a specific mode. + * + * @throws WriterException if an invalid mode was supplied + */ + private static function appendBytes(string $content, Mode $mode, BitArray $bits, string $encoding) : void + { + switch ($mode) { + case Mode::NUMERIC(): + self::appendNumericBytes($content, $bits); + break; + + case Mode::ALPHANUMERIC(): + self::appendAlphanumericBytes($content, $bits); + break; + + case Mode::BYTE(): + self::append8BitBytes($content, $bits, $encoding); + break; + + case Mode::KANJI(): + self::appendKanjiBytes($content, $bits); + break; + + default: + throw new WriterException('Invalid mode: ' . $mode); + } + } + + /** + * Appends numeric bytes to a bit array. + */ + private static function appendNumericBytes(string $content, BitArray $bits) : void + { + $length = strlen($content); + $i = 0; + + while ($i < $length) { + $num1 = (int) $content[$i]; + + if ($i + 2 < $length) { + // Encode three numeric letters in ten bits. + $num2 = (int) $content[$i + 1]; + $num3 = (int) $content[$i + 2]; + $bits->appendBits($num1 * 100 + $num2 * 10 + $num3, 10); + $i += 3; + } elseif ($i + 1 < $length) { + // Encode two numeric letters in seven bits. + $num2 = (int) $content[$i + 1]; + $bits->appendBits($num1 * 10 + $num2, 7); + $i += 2; + } else { + // Encode one numeric letter in four bits. + $bits->appendBits($num1, 4); + ++$i; + } + } + } + + /** + * Appends alpha-numeric bytes to a bit array. + * + * @throws WriterException if an invalid alphanumeric code was found + */ + private static function appendAlphanumericBytes(string $content, BitArray $bits) : void + { + $length = strlen($content); + $i = 0; + + while ($i < $length) { + $code1 = self::getAlphanumericCode(ord($content[$i])); + + if (-1 === $code1) { + throw new WriterException('Invalid alphanumeric code'); + } + + if ($i + 1 < $length) { + $code2 = self::getAlphanumericCode(ord($content[$i + 1])); + + if (-1 === $code2) { + throw new WriterException('Invalid alphanumeric code'); + } + + // Encode two alphanumeric letters in 11 bits. + $bits->appendBits($code1 * 45 + $code2, 11); + $i += 2; + } else { + // Encode one alphanumeric letter in six bits. + $bits->appendBits($code1, 6); + ++$i; + } + } + } + + /** + * Appends regular 8-bit bytes to a bit array. + * + * @throws WriterException if content cannot be encoded to target encoding + */ + private static function append8BitBytes(string $content, BitArray $bits, string $encoding) : void + { + $bytes = @iconv('utf-8', $encoding, $content); + + if (false === $bytes) { + throw new WriterException('Could not encode content to ' . $encoding); + } + + $length = strlen($bytes); + + for ($i = 0; $i < $length; $i++) { + $bits->appendBits(ord($bytes[$i]), 8); + } + } + + /** + * Appends KANJI bytes to a bit array. + * + * @throws WriterException if content does not seem to be encoded in SHIFT-JIS + * @throws WriterException if an invalid byte sequence occurs + */ + private static function appendKanjiBytes(string $content, BitArray $bits) : void + { + if (strlen($content) % 2 > 0) { + // We just do a simple length check here. The for loop will check + // individual characters. + throw new WriterException('Content does not seem to be encoded in SHIFT-JIS'); + } + + $length = strlen($content); + + for ($i = 0; $i < $length; $i += 2) { + $byte1 = ord($content[$i]) & 0xff; + $byte2 = ord($content[$i + 1]) & 0xff; + $code = ($byte1 << 8) | $byte2; + + if ($code >= 0x8140 && $code <= 0x9ffc) { + $subtracted = $code - 0x8140; + } elseif ($code >= 0xe040 && $code <= 0xebbf) { + $subtracted = $code - 0xc140; + } else { + throw new WriterException('Invalid byte sequence'); + } + + $encoded = (($subtracted >> 8) * 0xc0) + ($subtracted & 0xff); + + $bits->appendBits($encoded, 13); + } + } + + /** + * Appends ECI information to a bit array. + */ + private static function appendEci(CharacterSetEci $eci, BitArray $bits) : void + { + $mode = Mode::ECI(); + $bits->appendBits($mode->getBits(), 4); + $bits->appendBits($eci->getValue(), 8); + } +} diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/src/Encoder/MaskUtil.php b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Encoder/MaskUtil.php new file mode 100644 index 00000000..3baddbd9 --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Encoder/MaskUtil.php @@ -0,0 +1,271 @@ +getArray(); + $width = $matrix->getWidth(); + $height = $matrix->getHeight(); + + for ($y = 0; $y < $height - 1; ++$y) { + for ($x = 0; $x < $width - 1; ++$x) { + $value = $array[$y][$x]; + + if ($value === $array[$y][$x + 1] + && $value === $array[$y + 1][$x] + && $value === $array[$y + 1][$x + 1] + ) { + ++$penalty; + } + } + } + + return self::N2 * $penalty; + } + + /** + * Applies mask penalty rule 3 and returns the penalty. + * + * Finds consecutive cells of 00001011101 or 10111010000, and gives penalty + * to them. If we find patterns like 000010111010000, we give penalties + * twice (i.e. 40 * 2). + */ + public static function applyMaskPenaltyRule3(ByteMatrix $matrix) : int + { + $penalty = 0; + $array = $matrix->getArray(); + $width = $matrix->getWidth(); + $height = $matrix->getHeight(); + + for ($y = 0; $y < $height; ++$y) { + for ($x = 0; $x < $width; ++$x) { + if ($x + 6 < $width + && 1 === $array[$y][$x] + && 0 === $array[$y][$x + 1] + && 1 === $array[$y][$x + 2] + && 1 === $array[$y][$x + 3] + && 1 === $array[$y][$x + 4] + && 0 === $array[$y][$x + 5] + && 1 === $array[$y][$x + 6] + && ( + ( + $x + 10 < $width + && 0 === $array[$y][$x + 7] + && 0 === $array[$y][$x + 8] + && 0 === $array[$y][$x + 9] + && 0 === $array[$y][$x + 10] + ) + || ( + $x - 4 >= 0 + && 0 === $array[$y][$x - 1] + && 0 === $array[$y][$x - 2] + && 0 === $array[$y][$x - 3] + && 0 === $array[$y][$x - 4] + ) + ) + ) { + $penalty += self::N3; + } + + if ($y + 6 < $height + && 1 === $array[$y][$x] + && 0 === $array[$y + 1][$x] + && 1 === $array[$y + 2][$x] + && 1 === $array[$y + 3][$x] + && 1 === $array[$y + 4][$x] + && 0 === $array[$y + 5][$x] + && 1 === $array[$y + 6][$x] + && ( + ( + $y + 10 < $height + && 0 === $array[$y + 7][$x] + && 0 === $array[$y + 8][$x] + && 0 === $array[$y + 9][$x] + && 0 === $array[$y + 10][$x] + ) + || ( + $y - 4 >= 0 + && 0 === $array[$y - 1][$x] + && 0 === $array[$y - 2][$x] + && 0 === $array[$y - 3][$x] + && 0 === $array[$y - 4][$x] + ) + ) + ) { + $penalty += self::N3; + } + } + } + + return $penalty; + } + + /** + * Applies mask penalty rule 4 and returns the penalty. + * + * Calculates the ratio of dark cells and gives penalty if the ratio is far + * from 50%. It gives 10 penalty for 5% distance. + */ + public static function applyMaskPenaltyRule4(ByteMatrix $matrix) : int + { + $numDarkCells = 0; + + $array = $matrix->getArray(); + $width = $matrix->getWidth(); + $height = $matrix->getHeight(); + + for ($y = 0; $y < $height; ++$y) { + $arrayY = $array[$y]; + + for ($x = 0; $x < $width; ++$x) { + if (1 === $arrayY[$x]) { + ++$numDarkCells; + } + } + } + + $numTotalCells = $height * $width; + $darkRatio = $numDarkCells / $numTotalCells; + $fixedPercentVariances = (int) (abs($darkRatio - 0.5) * 20); + + return $fixedPercentVariances * self::N4; + } + + /** + * Returns the mask bit for "getMaskPattern" at "x" and "y". + * + * See 8.8 of JISX0510:2004 for mask pattern conditions. + * + * @throws InvalidArgumentException if an invalid mask pattern was supplied + */ + public static function getDataMaskBit(int $maskPattern, int $x, int $y) : bool + { + switch ($maskPattern) { + case 0: + $intermediate = ($y + $x) & 0x1; + break; + + case 1: + $intermediate = $y & 0x1; + break; + + case 2: + $intermediate = $x % 3; + break; + + case 3: + $intermediate = ($y + $x) % 3; + break; + + case 4: + $intermediate = (BitUtils::unsignedRightShift($y, 1) + ($x / 3)) & 0x1; + break; + + case 5: + $temp = $y * $x; + $intermediate = ($temp & 0x1) + ($temp % 3); + break; + + case 6: + $temp = $y * $x; + $intermediate = (($temp & 0x1) + ($temp % 3)) & 0x1; + break; + + case 7: + $temp = $y * $x; + $intermediate = (($temp % 3) + (($y + $x) & 0x1)) & 0x1; + break; + + default: + throw new InvalidArgumentException('Invalid mask pattern: ' . $maskPattern); + } + + return 0 == $intermediate; + } + + /** + * Helper function for applyMaskPenaltyRule1. + * + * We need this for doing this calculation in both vertical and horizontal + * orders respectively. + */ + private static function applyMaskPenaltyRule1Internal(ByteMatrix $matrix, bool $isHorizontal) : int + { + $penalty = 0; + $iLimit = $isHorizontal ? $matrix->getHeight() : $matrix->getWidth(); + $jLimit = $isHorizontal ? $matrix->getWidth() : $matrix->getHeight(); + $array = $matrix->getArray(); + + for ($i = 0; $i < $iLimit; ++$i) { + $numSameBitCells = 0; + $prevBit = -1; + + for ($j = 0; $j < $jLimit; $j++) { + $bit = $isHorizontal ? $array[$i][$j] : $array[$j][$i]; + + if ($bit === $prevBit) { + ++$numSameBitCells; + } else { + if ($numSameBitCells >= 5) { + $penalty += self::N1 + ($numSameBitCells - 5); + } + + $numSameBitCells = 1; + $prevBit = $bit; + } + } + + if ($numSameBitCells >= 5) { + $penalty += self::N1 + ($numSameBitCells - 5); + } + } + + return $penalty; + } +} diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/src/Encoder/MatrixUtil.php b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Encoder/MatrixUtil.php new file mode 100644 index 00000000..0967e298 --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Encoder/MatrixUtil.php @@ -0,0 +1,513 @@ +clear(-1); + } + + /** + * Builds a complete matrix. + */ + public static function buildMatrix( + BitArray $dataBits, + ErrorCorrectionLevel $level, + Version $version, + int $maskPattern, + ByteMatrix $matrix + ) : void { + self::clearMatrix($matrix); + self::embedBasicPatterns($version, $matrix); + self::embedTypeInfo($level, $maskPattern, $matrix); + self::maybeEmbedVersionInfo($version, $matrix); + self::embedDataBits($dataBits, $maskPattern, $matrix); + } + + /** + * Removes the position detection patterns from a matrix. + * + * This can be useful if you need to render those patterns separately. + */ + public static function removePositionDetectionPatterns(ByteMatrix $matrix) : void + { + $pdpWidth = count(self::POSITION_DETECTION_PATTERN[0]); + + self::removePositionDetectionPattern(0, 0, $matrix); + self::removePositionDetectionPattern($matrix->getWidth() - $pdpWidth, 0, $matrix); + self::removePositionDetectionPattern(0, $matrix->getWidth() - $pdpWidth, $matrix); + } + + /** + * Embeds type information into a matrix. + */ + private static function embedTypeInfo(ErrorCorrectionLevel $level, int $maskPattern, ByteMatrix $matrix) : void + { + $typeInfoBits = new BitArray(); + self::makeTypeInfoBits($level, $maskPattern, $typeInfoBits); + + $typeInfoBitsSize = $typeInfoBits->getSize(); + + for ($i = 0; $i < $typeInfoBitsSize; ++$i) { + $bit = $typeInfoBits->get($typeInfoBitsSize - 1 - $i); + + $x1 = self::TYPE_INFO_COORDINATES[$i][0]; + $y1 = self::TYPE_INFO_COORDINATES[$i][1]; + + $matrix->set($x1, $y1, (int) $bit); + + if ($i < 8) { + $x2 = $matrix->getWidth() - $i - 1; + $y2 = 8; + } else { + $x2 = 8; + $y2 = $matrix->getHeight() - 7 + ($i - 8); + } + + $matrix->set($x2, $y2, (int) $bit); + } + } + + /** + * Generates type information bits and appends them to a bit array. + * + * @throws RuntimeException if bit array resulted in invalid size + */ + private static function makeTypeInfoBits(ErrorCorrectionLevel $level, int $maskPattern, BitArray $bits) : void + { + $typeInfo = ($level->getBits() << 3) | $maskPattern; + $bits->appendBits($typeInfo, 5); + + $bchCode = self::calculateBchCode($typeInfo, self::TYPE_INFO_POLY); + $bits->appendBits($bchCode, 10); + + $maskBits = new BitArray(); + $maskBits->appendBits(self::TYPE_INFO_MASK_PATTERN, 15); + $bits->xorBits($maskBits); + + if (15 !== $bits->getSize()) { + throw new RuntimeException('Bit array resulted in invalid size: ' . $bits->getSize()); + } + } + + /** + * Embeds version information if required. + */ + private static function maybeEmbedVersionInfo(Version $version, ByteMatrix $matrix) : void + { + if ($version->getVersionNumber() < 7) { + return; + } + + $versionInfoBits = new BitArray(); + self::makeVersionInfoBits($version, $versionInfoBits); + + $bitIndex = 6 * 3 - 1; + + for ($i = 0; $i < 6; ++$i) { + for ($j = 0; $j < 3; ++$j) { + $bit = $versionInfoBits->get($bitIndex); + --$bitIndex; + + $matrix->set($i, $matrix->getHeight() - 11 + $j, (int) $bit); + $matrix->set($matrix->getHeight() - 11 + $j, $i, (int) $bit); + } + } + } + + /** + * Generates version information bits and appends them to a bit array. + * + * @throws RuntimeException if bit array resulted in invalid size + */ + private static function makeVersionInfoBits(Version $version, BitArray $bits) : void + { + $bits->appendBits($version->getVersionNumber(), 6); + + $bchCode = self::calculateBchCode($version->getVersionNumber(), self::VERSION_INFO_POLY); + $bits->appendBits($bchCode, 12); + + if (18 !== $bits->getSize()) { + throw new RuntimeException('Bit array resulted in invalid size: ' . $bits->getSize()); + } + } + + /** + * Calculates the BCH code for a value and a polynomial. + */ + private static function calculateBchCode(int $value, int $poly) : int + { + $msbSetInPoly = self::findMsbSet($poly); + $value <<= $msbSetInPoly - 1; + + while (self::findMsbSet($value) >= $msbSetInPoly) { + $value ^= $poly << (self::findMsbSet($value) - $msbSetInPoly); + } + + return $value; + } + + /** + * Finds and MSB set. + */ + private static function findMsbSet(int $value) : int + { + $numDigits = 0; + + while (0 !== $value) { + $value >>= 1; + ++$numDigits; + } + + return $numDigits; + } + + /** + * Embeds basic patterns into a matrix. + */ + private static function embedBasicPatterns(Version $version, ByteMatrix $matrix) : void + { + self::embedPositionDetectionPatternsAndSeparators($matrix); + self::embedDarkDotAtLeftBottomCorner($matrix); + self::maybeEmbedPositionAdjustmentPatterns($version, $matrix); + self::embedTimingPatterns($matrix); + } + + /** + * Embeds position detection patterns and separators into a byte matrix. + */ + private static function embedPositionDetectionPatternsAndSeparators(ByteMatrix $matrix) : void + { + $pdpWidth = count(self::POSITION_DETECTION_PATTERN[0]); + + self::embedPositionDetectionPattern(0, 0, $matrix); + self::embedPositionDetectionPattern($matrix->getWidth() - $pdpWidth, 0, $matrix); + self::embedPositionDetectionPattern(0, $matrix->getWidth() - $pdpWidth, $matrix); + + $hspWidth = 8; + + self::embedHorizontalSeparationPattern(0, $hspWidth - 1, $matrix); + self::embedHorizontalSeparationPattern($matrix->getWidth() - $hspWidth, $hspWidth - 1, $matrix); + self::embedHorizontalSeparationPattern(0, $matrix->getWidth() - $hspWidth, $matrix); + + $vspSize = 7; + + self::embedVerticalSeparationPattern($vspSize, 0, $matrix); + self::embedVerticalSeparationPattern($matrix->getHeight() - $vspSize - 1, 0, $matrix); + self::embedVerticalSeparationPattern($vspSize, $matrix->getHeight() - $vspSize, $matrix); + } + + /** + * Embeds a single position detection pattern into a byte matrix. + */ + private static function embedPositionDetectionPattern(int $xStart, int $yStart, ByteMatrix $matrix) : void + { + for ($y = 0; $y < 7; ++$y) { + for ($x = 0; $x < 7; ++$x) { + $matrix->set($xStart + $x, $yStart + $y, self::POSITION_DETECTION_PATTERN[$y][$x]); + } + } + } + + private static function removePositionDetectionPattern(int $xStart, int $yStart, ByteMatrix $matrix) : void + { + for ($y = 0; $y < 7; ++$y) { + for ($x = 0; $x < 7; ++$x) { + $matrix->set($xStart + $x, $yStart + $y, 0); + } + } + } + + /** + * Embeds a single horizontal separation pattern. + * + * @throws RuntimeException if a byte was already set + */ + private static function embedHorizontalSeparationPattern(int $xStart, int $yStart, ByteMatrix $matrix) : void + { + for ($x = 0; $x < 8; $x++) { + if (-1 !== $matrix->get($xStart + $x, $yStart)) { + throw new RuntimeException('Byte already set'); + } + + $matrix->set($xStart + $x, $yStart, 0); + } + } + + /** + * Embeds a single vertical separation pattern. + * + * @throws RuntimeException if a byte was already set + */ + private static function embedVerticalSeparationPattern(int $xStart, int $yStart, ByteMatrix $matrix) : void + { + for ($y = 0; $y < 7; $y++) { + if (-1 !== $matrix->get($xStart, $yStart + $y)) { + throw new RuntimeException('Byte already set'); + } + + $matrix->set($xStart, $yStart + $y, 0); + } + } + + /** + * Embeds a dot at the left bottom corner. + * + * @throws RuntimeException if a byte was already set to 0 + */ + private static function embedDarkDotAtLeftBottomCorner(ByteMatrix $matrix) : void + { + if (0 === $matrix->get(8, $matrix->getHeight() - 8)) { + throw new RuntimeException('Byte already set to 0'); + } + + $matrix->set(8, $matrix->getHeight() - 8, 1); + } + + /** + * Embeds position adjustment patterns if required. + */ + private static function maybeEmbedPositionAdjustmentPatterns(Version $version, ByteMatrix $matrix) : void + { + if ($version->getVersionNumber() < 2) { + return; + } + + $index = $version->getVersionNumber() - 1; + + $coordinates = self::POSITION_ADJUSTMENT_PATTERN_COORDINATE_TABLE[$index]; + $numCoordinates = count($coordinates); + + for ($i = 0; $i < $numCoordinates; ++$i) { + for ($j = 0; $j < $numCoordinates; ++$j) { + $y = $coordinates[$i]; + $x = $coordinates[$j]; + + if (null === $x || null === $y) { + continue; + } + + if (-1 === $matrix->get($x, $y)) { + self::embedPositionAdjustmentPattern($x - 2, $y - 2, $matrix); + } + } + } + } + + /** + * Embeds a single position adjustment pattern. + */ + private static function embedPositionAdjustmentPattern(int $xStart, int $yStart, ByteMatrix $matrix) : void + { + for ($y = 0; $y < 5; $y++) { + for ($x = 0; $x < 5; $x++) { + $matrix->set($xStart + $x, $yStart + $y, self::POSITION_ADJUSTMENT_PATTERN[$y][$x]); + } + } + } + + /** + * Embeds timing patterns into a matrix. + */ + private static function embedTimingPatterns(ByteMatrix $matrix) : void + { + $matrixWidth = $matrix->getWidth(); + + for ($i = 8; $i < $matrixWidth - 8; ++$i) { + $bit = ($i + 1) % 2; + + if (-1 === $matrix->get($i, 6)) { + $matrix->set($i, 6, $bit); + } + + if (-1 === $matrix->get(6, $i)) { + $matrix->set(6, $i, $bit); + } + } + } + + /** + * Embeds "dataBits" using "getMaskPattern". + * + * For debugging purposes, it skips masking process if "getMaskPattern" is -1. See 8.7 of JISX0510:2004 (p.38) for + * how to embed data bits. + * + * @throws WriterException if not all bits could be consumed + */ + private static function embedDataBits(BitArray $dataBits, int $maskPattern, ByteMatrix $matrix) : void + { + $bitIndex = 0; + $direction = -1; + + // Start from the right bottom cell. + $x = $matrix->getWidth() - 1; + $y = $matrix->getHeight() - 1; + + while ($x > 0) { + // Skip vertical timing pattern. + if (6 === $x) { + --$x; + } + + while ($y >= 0 && $y < $matrix->getHeight()) { + for ($i = 0; $i < 2; $i++) { + $xx = $x - $i; + + // Skip the cell if it's not empty. + if (-1 !== $matrix->get($xx, $y)) { + continue; + } + + if ($bitIndex < $dataBits->getSize()) { + $bit = $dataBits->get($bitIndex); + ++$bitIndex; + } else { + // Padding bit. If there is no bit left, we'll fill the + // left cells with 0, as described in 8.4.9 of + // JISX0510:2004 (p. 24). + $bit = false; + } + + // Skip masking if maskPattern is -1. + if (-1 !== $maskPattern && MaskUtil::getDataMaskBit($maskPattern, $xx, $y)) { + $bit = ! $bit; + } + + $matrix->set($xx, $y, (int) $bit); + } + + $y += $direction; + } + + $direction = -$direction; + $y += $direction; + $x -= 2; + } + + // All bits should be consumed + if ($dataBits->getSize() !== $bitIndex) { + throw new WriterException('Not all bits consumed (' . $bitIndex . ' out of ' . $dataBits->getSize() .')'); + } + } +} diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/src/Encoder/QrCode.php b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Encoder/QrCode.php new file mode 100644 index 00000000..f568e88c --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Encoder/QrCode.php @@ -0,0 +1,141 @@ +mode = $mode; + $this->errorCorrectionLevel = $errorCorrectionLevel; + $this->version = $version; + $this->maskPattern = $maskPattern; + $this->matrix = $matrix; + } + + /** + * Gets the mode. + */ + public function getMode() : Mode + { + return $this->mode; + } + + /** + * Gets the EC level. + */ + public function getErrorCorrectionLevel() : ErrorCorrectionLevel + { + return $this->errorCorrectionLevel; + } + + /** + * Gets the version. + */ + public function getVersion() : Version + { + return $this->version; + } + + /** + * Gets the mask pattern. + */ + public function getMaskPattern() : int + { + return $this->maskPattern; + } + + /** + * Gets the matrix. + * + * @return ByteMatrix + */ + public function getMatrix() + { + return $this->matrix; + } + + /** + * Validates whether a mask pattern is valid. + */ + public static function isValidMaskPattern(int $maskPattern) : bool + { + return $maskPattern > 0 && $maskPattern < self::NUM_MASK_PATTERNS; + } + + /** + * Returns a string representation of the QR code. + */ + public function __toString() : string + { + $result = "<<\n" + . ' mode: ' . $this->mode . "\n" + . ' ecLevel: ' . $this->errorCorrectionLevel . "\n" + . ' version: ' . $this->version . "\n" + . ' maskPattern: ' . $this->maskPattern . "\n"; + + if ($this->matrix === null) { + $result .= " matrix: null\n"; + } else { + $result .= " matrix:\n"; + $result .= $this->matrix; + } + + $result .= ">>\n"; + + return $result; + } +} diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/src/Exception/ExceptionInterface.php b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Exception/ExceptionInterface.php new file mode 100644 index 00000000..6f70c205 --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Exception/ExceptionInterface.php @@ -0,0 +1,10 @@ + 100) { + throw new Exception\InvalidArgumentException('Alpha must be between 0 and 100'); + } + + $this->alpha = $alpha; + $this->baseColor = $baseColor; + } + + public function getAlpha() : int + { + return $this->alpha; + } + + public function getBaseColor() : ColorInterface + { + return $this->baseColor; + } + + public function toRgb() : Rgb + { + return $this->baseColor->toRgb(); + } + + public function toCmyk() : Cmyk + { + return $this->baseColor->toCmyk(); + } + + public function toGray() : Gray + { + return $this->baseColor->toGray(); + } +} diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Color/Cmyk.php b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Color/Cmyk.php new file mode 100644 index 00000000..d6de390a --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Color/Cmyk.php @@ -0,0 +1,103 @@ + 100) { + throw new Exception\InvalidArgumentException('Cyan must be between 0 and 100'); + } + + if ($magenta < 0 || $magenta > 100) { + throw new Exception\InvalidArgumentException('Magenta must be between 0 and 100'); + } + + if ($yellow < 0 || $yellow > 100) { + throw new Exception\InvalidArgumentException('Yellow must be between 0 and 100'); + } + + if ($black < 0 || $black > 100) { + throw new Exception\InvalidArgumentException('Black must be between 0 and 100'); + } + + $this->cyan = $cyan; + $this->magenta = $magenta; + $this->yellow = $yellow; + $this->black = $black; + } + + public function getCyan() : int + { + return $this->cyan; + } + + public function getMagenta() : int + { + return $this->magenta; + } + + public function getYellow() : int + { + return $this->yellow; + } + + public function getBlack() : int + { + return $this->black; + } + + public function toRgb() : Rgb + { + $k = $this->black / 100; + $c = (-$k * $this->cyan + $k * 100 + $this->cyan) / 100; + $m = (-$k * $this->magenta + $k * 100 + $this->magenta) / 100; + $y = (-$k * $this->yellow + $k * 100 + $this->yellow) / 100; + + return new Rgb( + (int) (-$c * 255 + 255), + (int) (-$m * 255 + 255), + (int) (-$y * 255 + 255) + ); + } + + public function toCmyk() : Cmyk + { + return $this; + } + + public function toGray() : Gray + { + return $this->toRgb()->toGray(); + } +} diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Color/ColorInterface.php b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Color/ColorInterface.php new file mode 100644 index 00000000..b50d1cac --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Color/ColorInterface.php @@ -0,0 +1,22 @@ + 100) { + throw new Exception\InvalidArgumentException('Gray must be between 0 and 100'); + } + + $this->gray = (int) $gray; + } + + public function getGray() : int + { + return $this->gray; + } + + public function toRgb() : Rgb + { + return new Rgb((int) ($this->gray * 2.55), (int) ($this->gray * 2.55), (int) ($this->gray * 2.55)); + } + + public function toCmyk() : Cmyk + { + return new Cmyk(0, 0, 0, 100 - $this->gray); + } + + public function toGray() : Gray + { + return $this; + } +} diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Color/Rgb.php b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Color/Rgb.php new file mode 100644 index 00000000..79354062 --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Color/Rgb.php @@ -0,0 +1,88 @@ + 255) { + throw new Exception\InvalidArgumentException('Red must be between 0 and 255'); + } + + if ($green < 0 || $green > 255) { + throw new Exception\InvalidArgumentException('Green must be between 0 and 255'); + } + + if ($blue < 0 || $blue > 255) { + throw new Exception\InvalidArgumentException('Blue must be between 0 and 255'); + } + + $this->red = $red; + $this->green = $green; + $this->blue = $blue; + } + + public function getRed() : int + { + return $this->red; + } + + public function getGreen() : int + { + return $this->green; + } + + public function getBlue() : int + { + return $this->blue; + } + + public function toRgb() : Rgb + { + return $this; + } + + public function toCmyk() : Cmyk + { + $c = 1 - ($this->red / 255); + $m = 1 - ($this->green / 255); + $y = 1 - ($this->blue / 255); + $k = min($c, $m, $y); + + return new Cmyk( + (int) (100 * ($c - $k) / (1 - $k)), + (int) (100 * ($m - $k) / (1 - $k)), + (int) (100 * ($y - $k) / (1 - $k)), + (int) (100 * $k) + ); + } + + public function toGray() : Gray + { + return new Gray((int) (($this->red * 0.21 + $this->green * 0.71 + $this->blue * 0.07) / 2.55)); + } +} diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Eye/CompositeEye.php b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Eye/CompositeEye.php new file mode 100644 index 00000000..a3e19095 --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Eye/CompositeEye.php @@ -0,0 +1,38 @@ +externalEye = $externalEye; + $this->internalEye = $internalEye; + } + + public function getExternalPath() : Path + { + return $this->externalEye->getExternalPath(); + } + + public function getInternalPath() : Path + { + return $this->externalEye->getInternalPath(); + } +} diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Eye/EyeInterface.php b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Eye/EyeInterface.php new file mode 100644 index 00000000..ab68f3cd --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Eye/EyeInterface.php @@ -0,0 +1,26 @@ +module = $module; + } + + public function getExternalPath() : Path + { + $matrix = new ByteMatrix(7, 7); + + for ($x = 0; $x < 7; ++$x) { + $matrix->set($x, 0, 1); + $matrix->set($x, 6, 1); + } + + for ($y = 1; $y < 6; ++$y) { + $matrix->set(0, $y, 1); + $matrix->set(6, $y, 1); + } + + return $this->module->createPath($matrix)->translate(-3.5, -3.5); + } + + public function getInternalPath() : Path + { + $matrix = new ByteMatrix(3, 3); + + for ($x = 0; $x < 3; ++$x) { + for ($y = 0; $y < 3; ++$y) { + $matrix->set($x, $y, 1); + } + } + + return $this->module->createPath($matrix)->translate(-1.5, -1.5); + } +} diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Eye/SimpleCircleEye.php b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Eye/SimpleCircleEye.php new file mode 100644 index 00000000..64d54ee2 --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Eye/SimpleCircleEye.php @@ -0,0 +1,54 @@ +move(-3.5, -3.5) + ->line(3.5, -3.5) + ->line(3.5, 3.5) + ->line(-3.5, 3.5) + ->close() + ->move(-2.5, -2.5) + ->line(-2.5, 2.5) + ->line(2.5, 2.5) + ->line(2.5, -2.5) + ->close() + ; + } + + public function getInternalPath() : Path + { + return (new Path()) + ->move(1.5, 0) + ->ellipticArc(1.5, 1.5, 0., false, true, 0., 1.5) + ->ellipticArc(1.5, 1.5, 0., false, true, -1.5, 0.) + ->ellipticArc(1.5, 1.5, 0., false, true, 0., -1.5) + ->ellipticArc(1.5, 1.5, 0., false, true, 1.5, 0.) + ->close() + ; + } +} diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Eye/SquareEye.php b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Eye/SquareEye.php new file mode 100644 index 00000000..a3892b47 --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Eye/SquareEye.php @@ -0,0 +1,53 @@ +move(-3.5, -3.5) + ->line(3.5, -3.5) + ->line(3.5, 3.5) + ->line(-3.5, 3.5) + ->close() + ->move(-2.5, -2.5) + ->line(-2.5, 2.5) + ->line(2.5, 2.5) + ->line(2.5, -2.5) + ->close() + ; + } + + public function getInternalPath() : Path + { + return (new Path()) + ->move(-1.5, -1.5) + ->line(1.5, -1.5) + ->line(1.5, 1.5) + ->line(-1.5, 1.5) + ->close() + ; + } +} diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Image/EpsImageBackEnd.php b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Image/EpsImageBackEnd.php new file mode 100644 index 00000000..b581b540 --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Image/EpsImageBackEnd.php @@ -0,0 +1,376 @@ +eps = "%!PS-Adobe-3.0 EPSF-3.0\n" + . "%%Creator: BaconQrCode\n" + . sprintf("%%%%BoundingBox: 0 0 %d %d \n", $size, $size) + . "%%BeginProlog\n" + . "save\n" + . "50 dict begin\n" + . "/q { gsave } bind def\n" + . "/Q { grestore } bind def\n" + . "/s { scale } bind def\n" + . "/t { translate } bind def\n" + . "/r { rotate } bind def\n" + . "/n { newpath } bind def\n" + . "/m { moveto } bind def\n" + . "/l { lineto } bind def\n" + . "/c { curveto } bind def\n" + . "/z { closepath } bind def\n" + . "/f { eofill } bind def\n" + . "/rgb { setrgbcolor } bind def\n" + . "/cmyk { setcmykcolor } bind def\n" + . "/gray { setgray } bind def\n" + . "%%EndProlog\n" + . "1 -1 s\n" + . sprintf("0 -%d t\n", $size); + + if ($backgroundColor instanceof Alpha && 0 === $backgroundColor->getAlpha()) { + return; + } + + $this->eps .= wordwrap( + '0 0 m' + . sprintf(' %s 0 l', (string) $size) + . sprintf(' %s %s l', (string) $size, (string) $size) + . sprintf(' 0 %s l', (string) $size) + . ' z' + . ' ' .$this->getColorSetString($backgroundColor) . " f\n", + 75, + "\n " + ); + } + + public function scale(float $size) : void + { + if (null === $this->eps) { + throw new RuntimeException('No image has been started'); + } + + $this->eps .= sprintf("%1\$s %1\$s s\n", round($size, self::PRECISION)); + } + + public function translate(float $x, float $y) : void + { + if (null === $this->eps) { + throw new RuntimeException('No image has been started'); + } + + $this->eps .= sprintf("%s %s t\n", round($x, self::PRECISION), round($y, self::PRECISION)); + } + + public function rotate(int $degrees) : void + { + if (null === $this->eps) { + throw new RuntimeException('No image has been started'); + } + + $this->eps .= sprintf("%d r\n", $degrees); + } + + public function push() : void + { + if (null === $this->eps) { + throw new RuntimeException('No image has been started'); + } + + $this->eps .= "q\n"; + } + + public function pop() : void + { + if (null === $this->eps) { + throw new RuntimeException('No image has been started'); + } + + $this->eps .= "Q\n"; + } + + public function drawPathWithColor(Path $path, ColorInterface $color) : void + { + if (null === $this->eps) { + throw new RuntimeException('No image has been started'); + } + + $fromX = 0; + $fromY = 0; + $this->eps .= wordwrap( + 'n ' + . $this->drawPathOperations($path, $fromX, $fromY) + . ' ' . $this->getColorSetString($color) . " f\n", + 75, + "\n " + ); + } + + public function drawPathWithGradient( + Path $path, + Gradient $gradient, + float $x, + float $y, + float $width, + float $height + ) : void { + if (null === $this->eps) { + throw new RuntimeException('No image has been started'); + } + + $fromX = 0; + $fromY = 0; + $this->eps .= wordwrap( + 'q n ' . $this->drawPathOperations($path, $fromX, $fromY) . "\n", + 75, + "\n " + ); + + $this->createGradientFill($gradient, $x, $y, $width, $height); + } + + public function done() : string + { + if (null === $this->eps) { + throw new RuntimeException('No image has been started'); + } + + $this->eps .= "%%TRAILER\nend restore\n%%EOF"; + $blob = $this->eps; + $this->eps = null; + + return $blob; + } + + private function drawPathOperations(Iterable $ops, &$fromX, &$fromY) : string + { + $pathData = []; + + foreach ($ops as $op) { + switch (true) { + case $op instanceof Move: + $fromX = $toX = round($op->getX(), self::PRECISION); + $fromY = $toY = round($op->getY(), self::PRECISION); + $pathData[] = sprintf('%s %s m', $toX, $toY); + break; + + case $op instanceof Line: + $fromX = $toX = round($op->getX(), self::PRECISION); + $fromY = $toY = round($op->getY(), self::PRECISION); + $pathData[] = sprintf('%s %s l', $toX, $toY); + break; + + case $op instanceof EllipticArc: + $pathData[] = $this->drawPathOperations($op->toCurves($fromX, $fromY), $fromX, $fromY); + break; + + case $op instanceof Curve: + $x1 = round($op->getX1(), self::PRECISION); + $y1 = round($op->getY1(), self::PRECISION); + $x2 = round($op->getX2(), self::PRECISION); + $y2 = round($op->getY2(), self::PRECISION); + $fromX = $x3 = round($op->getX3(), self::PRECISION); + $fromY = $y3 = round($op->getY3(), self::PRECISION); + $pathData[] = sprintf('%s %s %s %s %s %s c', $x1, $y1, $x2, $y2, $x3, $y3); + break; + + case $op instanceof Close: + $pathData[] = 'z'; + break; + + default: + throw new RuntimeException('Unexpected draw operation: ' . get_class($op)); + } + } + + return implode(' ', $pathData); + } + + private function createGradientFill(Gradient $gradient, float $x, float $y, float $width, float $height) : void + { + $startColor = $gradient->getStartColor(); + $endColor = $gradient->getEndColor(); + + if ($startColor instanceof Alpha) { + $startColor = $startColor->getBaseColor(); + } + + $startColorType = get_class($startColor); + + if (! in_array($startColorType, [Rgb::class, Cmyk::class, Gray::class])) { + $startColorType = Cmyk::class; + $startColor = $startColor->toCmyk(); + } + + if (get_class($endColor) !== $startColorType) { + switch ($startColorType) { + case Cmyk::class: + $endColor = $endColor->toCmyk(); + break; + + case Rgb::class: + $endColor = $endColor->toRgb(); + break; + + case Gray::class: + $endColor = $endColor->toGray(); + break; + } + } + + $this->eps .= "eoclip\n<<\n"; + + if ($gradient->getType() === GradientType::RADIAL()) { + $this->eps .= " /ShadingType 3\n"; + } else { + $this->eps .= " /ShadingType 2\n"; + } + + $this->eps .= " /Extend [ true true ]\n" + . " /AntiAlias true\n"; + + switch ($startColorType) { + case Cmyk::class: + $this->eps .= " /ColorSpace /DeviceCMYK\n"; + break; + + case Rgb::class: + $this->eps .= " /ColorSpace /DeviceRGB\n"; + break; + + case Gray::class: + $this->eps .= " /ColorSpace /DeviceGray\n"; + break; + } + + switch ($gradient->getType()) { + case GradientType::HORIZONTAL(): + $this->eps .= sprintf( + " /Coords [ %s %s %s %s ]\n", + round($x, self::PRECISION), + round($y, self::PRECISION), + round($x + $width, self::PRECISION), + round($y, self::PRECISION) + ); + break; + + case GradientType::VERTICAL(): + $this->eps .= sprintf( + " /Coords [ %s %s %s %s ]\n", + round($x, self::PRECISION), + round($y, self::PRECISION), + round($x, self::PRECISION), + round($y + $height, self::PRECISION) + ); + break; + + case GradientType::DIAGONAL(): + $this->eps .= sprintf( + " /Coords [ %s %s %s %s ]\n", + round($x, self::PRECISION), + round($y, self::PRECISION), + round($x + $width, self::PRECISION), + round($y + $height, self::PRECISION) + ); + break; + + case GradientType::INVERSE_DIAGONAL(): + $this->eps .= sprintf( + " /Coords [ %s %s %s %s ]\n", + round($x, self::PRECISION), + round($y + $height, self::PRECISION), + round($x + $width, self::PRECISION), + round($y, self::PRECISION) + ); + break; + + case GradientType::RADIAL(): + $centerX = ($x + $width) / 2; + $centerY = ($y + $height) / 2; + + $this->eps .= sprintf( + " /Coords [ %s %s 0 %s %s %s ]\n", + round($centerX, self::PRECISION), + round($centerY, self::PRECISION), + round($centerX, self::PRECISION), + round($centerY, self::PRECISION), + round(max($width, $height) / 2, self::PRECISION) + ); + break; + } + + $this->eps .= " /Function\n" + . " <<\n" + . " /FunctionType 2\n" + . " /Domain [ 0 1 ]\n" + . sprintf(" /C0 [ %s ]\n", $this->getColorString($startColor)) + . sprintf(" /C1 [ %s ]\n", $this->getColorString($endColor)) + . " /N 1\n" + . " >>\n>>\nshfill\nQ\n"; + } + + private function getColorSetString(ColorInterface $color) : string + { + if ($color instanceof Rgb) { + return $this->getColorString($color) . ' rgb'; + } + + if ($color instanceof Cmyk) { + return $this->getColorString($color) . ' cmyk'; + } + + if ($color instanceof Gray) { + return $this->getColorString($color) . ' gray'; + } + + return $this->getColorSetString($color->toCmyk()); + } + + private function getColorString(ColorInterface $color) : string + { + if ($color instanceof Rgb) { + return sprintf('%s %s %s', $color->getRed() / 255, $color->getGreen() / 255, $color->getBlue() / 255); + } + + if ($color instanceof Cmyk) { + return sprintf( + '%s %s %s %s', + $color->getCyan() / 100, + $color->getMagenta() / 100, + $color->getYellow() / 100, + $color->getBlack() / 100 + ); + } + + if ($color instanceof Gray) { + return sprintf('%s', $color->getGray() / 100); + } + + return $this->getColorString($color->toCmyk()); + } +} diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Image/ImageBackEndInterface.php b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Image/ImageBackEndInterface.php new file mode 100644 index 00000000..0935819a --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Image/ImageBackEndInterface.php @@ -0,0 +1,87 @@ +imageFormat = $imageFormat; + $this->compressionQuality = $compressionQuality; + } + + public function new(int $size, ColorInterface $backgroundColor) : void + { + $this->image = new Imagick(); + $this->image->newImage($size, $size, $this->getColorPixel($backgroundColor)); + $this->image->setImageFormat($this->imageFormat); + $this->image->setCompressionQuality($this->compressionQuality); + $this->draw = new ImagickDraw(); + $this->gradientCount = 0; + $this->matrices = [new TransformationMatrix()]; + $this->matrixIndex = 0; + } + + public function scale(float $size) : void + { + if (null === $this->draw) { + throw new RuntimeException('No image has been started'); + } + + $this->draw->scale($size, $size); + $this->matrices[$this->matrixIndex] = $this->matrices[$this->matrixIndex] + ->multiply(TransformationMatrix::scale($size)); + } + + public function translate(float $x, float $y) : void + { + if (null === $this->draw) { + throw new RuntimeException('No image has been started'); + } + + $this->draw->translate($x, $y); + $this->matrices[$this->matrixIndex] = $this->matrices[$this->matrixIndex] + ->multiply(TransformationMatrix::translate($x, $y)); + } + + public function rotate(int $degrees) : void + { + if (null === $this->draw) { + throw new RuntimeException('No image has been started'); + } + + $this->draw->rotate($degrees); + $this->matrices[$this->matrixIndex] = $this->matrices[$this->matrixIndex] + ->multiply(TransformationMatrix::rotate($degrees)); + } + + public function push() : void + { + if (null === $this->draw) { + throw new RuntimeException('No image has been started'); + } + + $this->draw->push(); + $this->matrices[++$this->matrixIndex] = $this->matrices[$this->matrixIndex - 1]; + } + + public function pop() : void + { + if (null === $this->draw) { + throw new RuntimeException('No image has been started'); + } + + $this->draw->pop(); + unset($this->matrices[$this->matrixIndex--]); + } + + public function drawPathWithColor(Path $path, ColorInterface $color) : void + { + if (null === $this->draw) { + throw new RuntimeException('No image has been started'); + } + + $this->draw->setFillColor($this->getColorPixel($color)); + $this->drawPath($path); + } + + public function drawPathWithGradient( + Path $path, + Gradient $gradient, + float $x, + float $y, + float $width, + float $height + ) : void { + if (null === $this->draw) { + throw new RuntimeException('No image has been started'); + } + + $this->draw->setFillPatternURL('#' . $this->createGradientFill($gradient, $x, $y, $width, $height)); + $this->drawPath($path); + } + + public function done() : string + { + if (null === $this->draw) { + throw new RuntimeException('No image has been started'); + } + + $this->image->drawImage($this->draw); + $blob = $this->image->getImageBlob(); + $this->draw->clear(); + $this->image->clear(); + $this->draw = null; + $this->image = null; + $this->gradientCount = null; + + return $blob; + } + + private function drawPath(Path $path) : void + { + $this->draw->pathStart(); + + foreach ($path as $op) { + switch (true) { + case $op instanceof Move: + $this->draw->pathMoveToAbsolute($op->getX(), $op->getY()); + break; + + case $op instanceof Line: + $this->draw->pathLineToAbsolute($op->getX(), $op->getY()); + break; + + case $op instanceof EllipticArc: + $this->draw->pathEllipticArcAbsolute( + $op->getXRadius(), + $op->getYRadius(), + $op->getXAxisAngle(), + $op->isLargeArc(), + $op->isSweep(), + $op->getX(), + $op->getY() + ); + break; + + case $op instanceof Curve: + $this->draw->pathCurveToAbsolute( + $op->getX1(), + $op->getY1(), + $op->getX2(), + $op->getY2(), + $op->getX3(), + $op->getY3() + ); + break; + + case $op instanceof Close: + $this->draw->pathClose(); + break; + + default: + throw new RuntimeException('Unexpected draw operation: ' . get_class($op)); + } + } + + $this->draw->pathFinish(); + } + + private function createGradientFill(Gradient $gradient, float $x, float $y, float $width, float $height) : string + { + list($width, $height) = $this->matrices[$this->matrixIndex]->apply($x + $width, $y + $height); + list($x, $y) = $this->matrices[$this->matrixIndex]->apply($x, $y); + $width -= $x; + $height -= $y; + + $startColor = $this->getColorPixel($gradient->getStartColor())->getColorAsString(); + $endColor = $this->getColorPixel($gradient->getEndColor())->getColorAsString(); + $gradientImage = new Imagick(); + + switch ($gradient->getType()) { + case GradientType::HORIZONTAL(): + $gradientImage->newPseudoImage((int) $height, (int) $width, sprintf( + 'gradient:%s-%s', + $startColor, + $endColor + )); + $gradientImage->rotateImage('transparent', -90); + break; + + case GradientType::VERTICAL(): + $gradientImage->newPseudoImage((int) $width, (int) $height, sprintf( + 'gradient:%s-%s', + $startColor, + $endColor + )); + break; + + case GradientType::DIAGONAL(): + case GradientType::INVERSE_DIAGONAL(): + $gradientImage->newPseudoImage((int) ($width * sqrt(2)), (int) ($height * sqrt(2)), sprintf( + 'gradient:%s-%s', + $startColor, + $endColor + )); + + if (GradientType::DIAGONAL() === $gradient->getType()) { + $gradientImage->rotateImage('transparent', -45); + } else { + $gradientImage->rotateImage('transparent', -135); + } + + $rotatedWidth = $gradientImage->getImageWidth(); + $rotatedHeight = $gradientImage->getImageHeight(); + + $gradientImage->setImagePage($rotatedWidth, $rotatedHeight, 0, 0); + $gradientImage->cropImage( + intdiv($rotatedWidth, 2) - 2, + intdiv($rotatedHeight, 2) - 2, + intdiv($rotatedWidth, 4) + 1, + intdiv($rotatedWidth, 4) + 1 + ); + break; + + case GradientType::RADIAL(): + $gradientImage->newPseudoImage((int) $width, (int) $height, sprintf( + 'radial-gradient:%s-%s', + $startColor, + $endColor + )); + break; + } + + $id = sprintf('g%d', ++$this->gradientCount); + $this->draw->pushPattern($id, 0, 0, $x + $width, $y + $height); + $this->draw->composite(Imagick::COMPOSITE_COPY, $x, $y, $width, $height, $gradientImage); + $this->draw->popPattern(); + return $id; + } + + private function getColorPixel(ColorInterface $color) : ImagickPixel + { + $alpha = 100; + + if ($color instanceof Alpha) { + $alpha = $color->getAlpha(); + $color = $color->getBaseColor(); + } + + if ($color instanceof Rgb) { + return new ImagickPixel(sprintf( + 'rgba(%d, %d, %d, %F)', + $color->getRed(), + $color->getGreen(), + $color->getBlue(), + $alpha / 100 + )); + } + + if ($color instanceof Cmyk) { + return new ImagickPixel(sprintf( + 'cmyka(%d, %d, %d, %d, %F)', + $color->getCyan(), + $color->getMagenta(), + $color->getYellow(), + $color->getBlack(), + $alpha / 100 + )); + } + + if ($color instanceof Gray) { + return new ImagickPixel(sprintf( + 'graya(%d%%, %F)', + $color->getGray(), + $alpha / 100 + )); + } + + return $this->getColorPixel(new Alpha($alpha, $color->toRgb())); + } +} diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Image/SvgImageBackEnd.php b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Image/SvgImageBackEnd.php new file mode 100644 index 00000000..714da6eb --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Image/SvgImageBackEnd.php @@ -0,0 +1,369 @@ +xmlWriter = new XMLWriter(); + $this->xmlWriter->openMemory(); + + $this->xmlWriter->startDocument('1.0', 'UTF-8'); + $this->xmlWriter->startElement('svg'); + $this->xmlWriter->writeAttribute('xmlns', 'http://www.w3.org/2000/svg'); + $this->xmlWriter->writeAttribute('version', '1.1'); + $this->xmlWriter->writeAttribute('width', (string) $size); + $this->xmlWriter->writeAttribute('height', (string) $size); + $this->xmlWriter->writeAttribute('viewBox', '0 0 '. $size . ' ' . $size); + + $this->gradientCount = 0; + $this->currentStack = 0; + $this->stack[0] = 0; + + $alpha = 1; + + if ($backgroundColor instanceof Alpha) { + $alpha = $backgroundColor->getAlpha() / 100; + } + + if (0 === $alpha) { + return; + } + + $this->xmlWriter->startElement('rect'); + $this->xmlWriter->writeAttribute('x', '0'); + $this->xmlWriter->writeAttribute('y', '0'); + $this->xmlWriter->writeAttribute('width', (string) $size); + $this->xmlWriter->writeAttribute('height', (string) $size); + $this->xmlWriter->writeAttribute('fill', $this->getColorString($backgroundColor)); + + if ($alpha < 1) { + $this->xmlWriter->writeAttribute('fill-opacity', (string) $alpha); + } + + $this->xmlWriter->endElement(); + } + + public function scale(float $size) : void + { + if (null === $this->xmlWriter) { + throw new RuntimeException('No image has been started'); + } + + $this->xmlWriter->startElement('g'); + $this->xmlWriter->writeAttribute( + 'transform', + sprintf('scale(%s)', round($size, self::PRECISION)) + ); + ++$this->stack[$this->currentStack]; + } + + public function translate(float $x, float $y) : void + { + if (null === $this->xmlWriter) { + throw new RuntimeException('No image has been started'); + } + + $this->xmlWriter->startElement('g'); + $this->xmlWriter->writeAttribute( + 'transform', + sprintf('translate(%s,%s)', round($x, self::PRECISION), round($y, self::PRECISION)) + ); + ++$this->stack[$this->currentStack]; + } + + public function rotate(int $degrees) : void + { + if (null === $this->xmlWriter) { + throw new RuntimeException('No image has been started'); + } + + $this->xmlWriter->startElement('g'); + $this->xmlWriter->writeAttribute('transform', sprintf('rotate(%d)', $degrees)); + ++$this->stack[$this->currentStack]; + } + + public function push() : void + { + if (null === $this->xmlWriter) { + throw new RuntimeException('No image has been started'); + } + + $this->xmlWriter->startElement('g'); + $this->stack[] = 1; + ++$this->currentStack; + } + + public function pop() : void + { + if (null === $this->xmlWriter) { + throw new RuntimeException('No image has been started'); + } + + for ($i = 0; $i < $this->stack[$this->currentStack]; ++$i) { + $this->xmlWriter->endElement(); + } + + array_pop($this->stack); + --$this->currentStack; + } + + public function drawPathWithColor(Path $path, ColorInterface $color) : void + { + if (null === $this->xmlWriter) { + throw new RuntimeException('No image has been started'); + } + + $alpha = 1; + + if ($color instanceof Alpha) { + $alpha = $color->getAlpha() / 100; + } + + $this->startPathElement($path); + $this->xmlWriter->writeAttribute('fill', $this->getColorString($color)); + + if ($alpha < 1) { + $this->xmlWriter->writeAttribute('fill-opacity', (string) $alpha); + } + + $this->xmlWriter->endElement(); + } + + public function drawPathWithGradient( + Path $path, + Gradient $gradient, + float $x, + float $y, + float $width, + float $height + ) : void { + if (null === $this->xmlWriter) { + throw new RuntimeException('No image has been started'); + } + + $gradientId = $this->createGradientFill($gradient, $x, $y, $width, $height); + $this->startPathElement($path); + $this->xmlWriter->writeAttribute('fill', 'url(#' . $gradientId . ')'); + $this->xmlWriter->endElement(); + } + + public function done() : string + { + if (null === $this->xmlWriter) { + throw new RuntimeException('No image has been started'); + } + + foreach ($this->stack as $openElements) { + for ($i = $openElements; $i > 0; --$i) { + $this->xmlWriter->endElement(); + } + } + + $this->xmlWriter->endDocument(); + $blob = $this->xmlWriter->outputMemory(true); + $this->xmlWriter = null; + $this->stack = null; + $this->currentStack = null; + $this->gradientCount = null; + + return $blob; + } + + private function startPathElement(Path $path) : void + { + $pathData = []; + + foreach ($path as $op) { + switch (true) { + case $op instanceof Move: + $pathData[] = sprintf( + 'M%s %s', + round($op->getX(), self::PRECISION), + round($op->getY(), self::PRECISION) + ); + break; + + case $op instanceof Line: + $pathData[] = sprintf( + 'L%s %s', + round($op->getX(), self::PRECISION), + round($op->getY(), self::PRECISION) + ); + break; + + case $op instanceof EllipticArc: + $pathData[] = sprintf( + 'A%s %s %s %u %u %s %s', + round($op->getXRadius(), self::PRECISION), + round($op->getYRadius(), self::PRECISION), + round($op->getXAxisAngle(), self::PRECISION), + $op->isLargeArc(), + $op->isSweep(), + round($op->getX(), self::PRECISION), + round($op->getY(), self::PRECISION) + ); + break; + + case $op instanceof Curve: + $pathData[] = sprintf( + 'C%s %s %s %s %s %s', + round($op->getX1(), self::PRECISION), + round($op->getY1(), self::PRECISION), + round($op->getX2(), self::PRECISION), + round($op->getY2(), self::PRECISION), + round($op->getX3(), self::PRECISION), + round($op->getY3(), self::PRECISION) + ); + break; + + case $op instanceof Close: + $pathData[] = 'Z'; + break; + + default: + throw new RuntimeException('Unexpected draw operation: ' . get_class($op)); + } + } + + $this->xmlWriter->startElement('path'); + $this->xmlWriter->writeAttribute('fill-rule', 'evenodd'); + $this->xmlWriter->writeAttribute('d', implode('', $pathData)); + } + + private function createGradientFill(Gradient $gradient, float $x, float $y, float $width, float $height) : string + { + $this->xmlWriter->startElement('defs'); + + $startColor = $gradient->getStartColor(); + $endColor = $gradient->getEndColor(); + + if ($gradient->getType() === GradientType::RADIAL()) { + $this->xmlWriter->startElement('radialGradient'); + } else { + $this->xmlWriter->startElement('linearGradient'); + } + + $this->xmlWriter->writeAttribute('gradientUnits', 'userSpaceOnUse'); + + switch ($gradient->getType()) { + case GradientType::HORIZONTAL(): + $this->xmlWriter->writeAttribute('x1', (string) round($x, self::PRECISION)); + $this->xmlWriter->writeAttribute('y1', (string) round($y, self::PRECISION)); + $this->xmlWriter->writeAttribute('x2', (string) round($x + $width, self::PRECISION)); + $this->xmlWriter->writeAttribute('y2', (string) round($y, self::PRECISION)); + break; + + case GradientType::VERTICAL(): + $this->xmlWriter->writeAttribute('x1', (string) round($x, self::PRECISION)); + $this->xmlWriter->writeAttribute('y1', (string) round($y, self::PRECISION)); + $this->xmlWriter->writeAttribute('x2', (string) round($x, self::PRECISION)); + $this->xmlWriter->writeAttribute('y2', (string) round($y + $height, self::PRECISION)); + break; + + case GradientType::DIAGONAL(): + $this->xmlWriter->writeAttribute('x1', (string) round($x, self::PRECISION)); + $this->xmlWriter->writeAttribute('y1', (string) round($y, self::PRECISION)); + $this->xmlWriter->writeAttribute('x2', (string) round($x + $width, self::PRECISION)); + $this->xmlWriter->writeAttribute('y2', (string) round($y + $height, self::PRECISION)); + break; + + case GradientType::INVERSE_DIAGONAL(): + $this->xmlWriter->writeAttribute('x1', (string) round($x, self::PRECISION)); + $this->xmlWriter->writeAttribute('y1', (string) round($y + $height, self::PRECISION)); + $this->xmlWriter->writeAttribute('x2', (string) round($x + $width, self::PRECISION)); + $this->xmlWriter->writeAttribute('y2', (string) round($y, self::PRECISION)); + break; + + case GradientType::RADIAL(): + $this->xmlWriter->writeAttribute('cx', (string) round(($x + $width) / 2, self::PRECISION)); + $this->xmlWriter->writeAttribute('cy', (string) round(($y + $height) / 2, self::PRECISION)); + $this->xmlWriter->writeAttribute('r', (string) round(max($width, $height) / 2, self::PRECISION)); + break; + } + + $id = sprintf('g%d', ++$this->gradientCount); + $this->xmlWriter->writeAttribute('id', $id); + + $this->xmlWriter->startElement('stop'); + $this->xmlWriter->writeAttribute('offset', '0%'); + $this->xmlWriter->writeAttribute('stop-color', $this->getColorString($startColor)); + + if ($startColor instanceof Alpha) { + $this->xmlWriter->writeAttribute('stop-opacity', $startColor->getAlpha()); + } + + $this->xmlWriter->endElement(); + + $this->xmlWriter->startElement('stop'); + $this->xmlWriter->writeAttribute('offset', '100%'); + $this->xmlWriter->writeAttribute('stop-color', $this->getColorString($endColor)); + + if ($endColor instanceof Alpha) { + $this->xmlWriter->writeAttribute('stop-opacity', $endColor->getAlpha()); + } + + $this->xmlWriter->endElement(); + + $this->xmlWriter->endElement(); + $this->xmlWriter->endElement(); + + return $id; + } + + private function getColorString(ColorInterface $color) : string + { + $color = $color->toRgb(); + + return sprintf( + '#%02x%02x%02x', + $color->getRed(), + $color->getGreen(), + $color->getBlue() + ); + } +} diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Image/TransformationMatrix.php b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Image/TransformationMatrix.php new file mode 100644 index 00000000..b41ee097 --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Image/TransformationMatrix.php @@ -0,0 +1,67 @@ +values = [1, 0, 0, 1, 0, 0]; + } + + public function multiply(self $other) : self + { + $matrix = new self(); + $matrix->values[0] = $this->values[0] * $other->values[0] + $this->values[2] * $other->values[1]; + $matrix->values[1] = $this->values[1] * $other->values[0] + $this->values[3] * $other->values[1]; + $matrix->values[2] = $this->values[0] * $other->values[2] + $this->values[2] * $other->values[3]; + $matrix->values[3] = $this->values[1] * $other->values[2] + $this->values[3] * $other->values[3]; + $matrix->values[4] = $this->values[0] * $other->values[4] + $this->values[2] * $other->values[5] + + $this->values[4]; + $matrix->values[5] = $this->values[1] * $other->values[4] + $this->values[3] * $other->values[5] + + $this->values[5]; + + return $matrix; + } + + public static function scale(float $size) : self + { + $matrix = new self(); + $matrix->values = [$size, 0, 0, $size, 0, 0]; + return $matrix; + } + + public static function translate(float $x, float $y) : self + { + $matrix = new self(); + $matrix->values = [1, 0, 0, 1, $x, $y]; + return $matrix; + } + + public static function rotate(int $degrees) : self + { + $matrix = new self(); + $matrix->values = [cos($degrees), sin($degrees), -sin($degrees), cos($degrees), 0, 0]; + return $matrix; + } + + + /** + * Applies this matrix onto a point and returns the resulting viewport point. + * + * @return float[] + */ + public function apply(float $x, float $y) : array + { + return [ + $x * $this->values[0] + $y * $this->values[2] + $this->values[4], + $x * $this->values[2] + $x * $this->values[3] + $this->values[5], + ]; + } +} diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/ImageRenderer.php b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/ImageRenderer.php new file mode 100644 index 00000000..ab16276c --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/ImageRenderer.php @@ -0,0 +1,152 @@ +rendererStyle = $rendererStyle; + $this->imageBackEnd = $imageBackEnd; + } + + /** + * @throws InvalidArgumentException if matrix width doesn't match height + */ + public function render(QrCode $qrCode) : string + { + $size = $this->rendererStyle->getSize(); + $margin = $this->rendererStyle->getMargin(); + $matrix = $qrCode->getMatrix(); + $matrixSize = $matrix->getWidth(); + + if ($matrixSize !== $matrix->getHeight()) { + throw new InvalidArgumentException('Matrix must have the same width and height'); + } + + $totalSize = $matrixSize + ($margin * 2); + $moduleSize = $size / $totalSize; + $fill = $this->rendererStyle->getFill(); + + $this->imageBackEnd->new($size, $fill->getBackgroundColor()); + $this->imageBackEnd->scale((float) $moduleSize); + $this->imageBackEnd->translate((float) $margin, (float) $margin); + + $module = $this->rendererStyle->getModule(); + $moduleMatrix = clone $matrix; + MatrixUtil::removePositionDetectionPatterns($moduleMatrix); + $modulePath = $this->drawEyes($matrixSize, $module->createPath($moduleMatrix)); + + if ($fill->hasGradientFill()) { + $this->imageBackEnd->drawPathWithGradient( + $modulePath, + $fill->getForegroundGradient(), + 0, + 0, + $matrixSize, + $matrixSize + ); + } else { + $this->imageBackEnd->drawPathWithColor($modulePath, $fill->getForegroundColor()); + } + + return $this->imageBackEnd->done(); + } + + private function drawEyes(int $matrixSize, Path $modulePath) : Path + { + $fill = $this->rendererStyle->getFill(); + + $eye = $this->rendererStyle->getEye(); + $externalPath = $eye->getExternalPath(); + $internalPath = $eye->getInternalPath(); + + $modulePath = $this->drawEye( + $externalPath, + $internalPath, + $fill->getTopLeftEyeFill(), + 3.5, + 3.5, + 0, + $modulePath + ); + $modulePath = $this->drawEye( + $externalPath, + $internalPath, + $fill->getTopRightEyeFill(), + $matrixSize - 3.5, + 3.5, + 90, + $modulePath + ); + $modulePath = $this->drawEye( + $externalPath, + $internalPath, + $fill->getBottomLeftEyeFill(), + 3.5, + $matrixSize - 3.5, + -90, + $modulePath + ); + + return $modulePath; + } + + private function drawEye( + Path $externalPath, + Path $internalPath, + EyeFill $fill, + float $xTranslation, + float $yTranslation, + int $rotation, + Path $modulePath + ) : Path { + if ($fill->inheritsBothColors()) { + return $modulePath + ->append($externalPath->translate($xTranslation, $yTranslation)) + ->append($internalPath->translate($xTranslation, $yTranslation)); + } + + $this->imageBackEnd->push(); + $this->imageBackEnd->translate($xTranslation, $yTranslation); + + if (0 !== $rotation) { + $this->imageBackEnd->rotate($rotation); + } + + if ($fill->inheritsExternalColor()) { + $modulePath = $modulePath->append($externalPath->translate($xTranslation, $yTranslation)); + } else { + $this->imageBackEnd->drawPathWithColor($externalPath, $fill->getExternalColor()); + } + + if ($fill->inheritsInternalColor()) { + $modulePath = $modulePath->append($internalPath->translate($xTranslation, $yTranslation)); + } else { + $this->imageBackEnd->drawPathWithColor($internalPath, $fill->getInternalColor()); + } + + $this->imageBackEnd->pop(); + + return $modulePath; + } +} diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Module/DotsModule.php b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Module/DotsModule.php new file mode 100644 index 00000000..f536e5ab --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Module/DotsModule.php @@ -0,0 +1,63 @@ + 1) { + throw new InvalidArgumentException('Size must between 0 (exclusive) and 1 (inclusive)'); + } + + $this->size = $size; + } + + public function createPath(ByteMatrix $matrix) : Path + { + $width = $matrix->getWidth(); + $height = $matrix->getHeight(); + $path = new Path(); + $halfSize = $this->size / 2; + $margin = (1 - $this->size) / 2; + + for ($y = 0; $y < $height; ++$y) { + for ($x = 0; $x < $width; ++$x) { + if (! $matrix->get($x, $y)) { + continue; + } + + $pathX = $x + $margin; + $pathY = $y + $margin; + + $path = $path + ->move($pathX + $this->size, $pathY + $halfSize) + ->ellipticArc($halfSize, $halfSize, 0, false, true, $pathX + $halfSize, $pathY + $this->size) + ->ellipticArc($halfSize, $halfSize, 0, false, true, $pathX, $pathY + $halfSize) + ->ellipticArc($halfSize, $halfSize, 0, false, true, $pathX + $halfSize, $pathY) + ->ellipticArc($halfSize, $halfSize, 0, false, true, $pathX + $this->size, $pathY + $halfSize) + ->close() + ; + } + } + + return $path; + } +} diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Module/EdgeIterator/Edge.php b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Module/EdgeIterator/Edge.php new file mode 100644 index 00000000..90482f21 --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Module/EdgeIterator/Edge.php @@ -0,0 +1,100 @@ + + */ + private $points = []; + + /** + * @var array|null + */ + private $simplifiedPoints; + + /** + * @var int + */ + private $minX = PHP_INT_MAX; + + /** + * @var int + */ + private $minY = PHP_INT_MAX; + + /** + * @var int + */ + private $maxX = -1; + + /** + * @var int + */ + private $maxY = -1; + + public function __construct(bool $positive) + { + $this->positive = $positive; + } + + public function addPoint(int $x, int $y) : void + { + $this->points[] = [$x, $y]; + $this->minX = min($this->minX, $x); + $this->minY = min($this->minY, $y); + $this->maxX = max($this->maxX, $x); + $this->maxY = max($this->maxY, $y); + } + + public function isPositive() : bool + { + return $this->positive; + } + + /** + * @return array + */ + public function getPoints() : array + { + return $this->points; + } + + public function getMaxX() : int + { + return $this->maxX; + } + + public function getSimplifiedPoints() : array + { + if (null !== $this->simplifiedPoints) { + return $this->simplifiedPoints; + } + + $points = []; + $length = count($this->points); + + for ($i = 0; $i < $length; ++$i) { + $previousPoint = $this->points[(0 === $i ? $length : $i) - 1]; + $nextPoint = $this->points[($length - 1 === $i ? -1 : $i) + 1]; + $currentPoint = $this->points[$i]; + + if (($previousPoint[0] === $currentPoint[0] && $currentPoint[0] === $nextPoint[0]) + || ($previousPoint[1] === $currentPoint[1] && $currentPoint[1] === $nextPoint[1]) + ) { + continue; + } + + $points[] = $currentPoint; + } + + return $this->simplifiedPoints = $points; + } +} diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Module/EdgeIterator/EdgeIterator.php b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Module/EdgeIterator/EdgeIterator.php new file mode 100644 index 00000000..af52d525 --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Module/EdgeIterator/EdgeIterator.php @@ -0,0 +1,169 @@ +bytes = iterator_to_array($matrix->getBytes()); + $this->size = count($this->bytes); + $this->width = $matrix->getWidth(); + $this->height = $matrix->getHeight(); + } + + /** + * @return Edge[] + */ + public function getIterator() : Traversable + { + $originalBytes = $this->bytes; + $point = $this->findNext(0, 0); + + while (null !== $point) { + $edge = $this->findEdge($point[0], $point[1]); + $this->xorEdge($edge); + + yield $edge; + + $point = $this->findNext($point[0], $point[1]); + } + + $this->bytes = $originalBytes; + } + + /** + * @return int[]|null + */ + private function findNext(int $x, int $y) : ?array + { + $i = $this->width * $y + $x; + + while ($i < $this->size && 1 !== $this->bytes[$i]) { + ++$i; + } + + if ($i < $this->size) { + return $this->pointOf($i); + } + + return null; + } + + private function findEdge(int $x, int $y) : Edge + { + $edge = new Edge($this->isSet($x, $y)); + $startX = $x; + $startY = $y; + $dirX = 0; + $dirY = 1; + + while (true) { + $edge->addPoint($x, $y); + $x += $dirX; + $y += $dirY; + + if ($x === $startX && $y === $startY) { + break; + } + + $left = $this->isSet($x + ($dirX + $dirY - 1 ) / 2, $y + ($dirY - $dirX - 1) / 2); + $right = $this->isSet($x + ($dirX - $dirY - 1) / 2, $y + ($dirY + $dirX - 1) / 2); + + if ($right && ! $left) { + $tmp = $dirX; + $dirX = -$dirY; + $dirY = $tmp; + } elseif ($right) { + $tmp = $dirX; + $dirX = -$dirY; + $dirY = $tmp; + } elseif (! $left) { + $tmp = $dirX; + $dirX = $dirY; + $dirY = -$tmp; + } + } + + return $edge; + } + + private function xorEdge(Edge $path) : void + { + $points = $path->getPoints(); + $y1 = $points[0][1]; + $length = count($points); + $maxX = $path->getMaxX(); + + for ($i = 1; $i < $length; ++$i) { + $y = $points[$i][1]; + + if ($y === $y1) { + continue; + } + + $x = $points[$i][0]; + $minY = min($y1, $y); + + for ($j = $x; $j < $maxX; ++$j) { + $this->flip($j, $minY); + } + + $y1 = $y; + } + } + + private function isSet(int $x, int $y) : bool + { + return ( + $x >= 0 + && $x < $this->width + && $y >= 0 + && $y < $this->height + ) && 1 === $this->bytes[$this->width * $y + $x]; + } + + /** + * @return int[] + */ + private function pointOf(int $i) : array + { + $y = intdiv($i, $this->width); + return [$i - $y * $this->width, $y]; + } + + private function flip(int $x, int $y) : void + { + $this->bytes[$this->width * $y + $x] = ( + $this->isSet($x, $y) ? 0 : 1 + ); + } +} diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Module/ModuleInterface.php b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Module/ModuleInterface.php new file mode 100644 index 00000000..0ccb0e0f --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Module/ModuleInterface.php @@ -0,0 +1,18 @@ + 1) { + throw new InvalidArgumentException('Intensity must between 0 (exclusive) and 1 (inclusive)'); + } + + $this->intensity = $intensity / 2; + } + + public function createPath(ByteMatrix $matrix) : Path + { + $path = new Path(); + + foreach (new EdgeIterator($matrix) as $edge) { + $points = $edge->getSimplifiedPoints(); + $length = count($points); + + $currentPoint = $points[0]; + $nextPoint = $points[1]; + $horizontal = ($currentPoint[1] === $nextPoint[1]); + + if ($horizontal) { + $right = $nextPoint[0] > $currentPoint[0]; + $path = $path->move( + $currentPoint[0] + ($right ? $this->intensity : -$this->intensity), + $currentPoint[1] + ); + } else { + $up = $nextPoint[0] < $currentPoint[0]; + $path = $path->move( + $currentPoint[0], + $currentPoint[1] + ($up ? -$this->intensity : $this->intensity) + ); + } + + for ($i = 1; $i <= $length; ++$i) { + if ($i === $length) { + $previousPoint = $points[$length - 1]; + $currentPoint = $points[0]; + $nextPoint = $points[1]; + } else { + $previousPoint = $points[(0 === $i ? $length : $i) - 1]; + $currentPoint = $points[$i]; + $nextPoint = $points[($length - 1 === $i ? -1 : $i) + 1]; + } + + $horizontal = ($previousPoint[1] === $currentPoint[1]); + + if ($horizontal) { + $right = $previousPoint[0] < $currentPoint[0]; + $up = $nextPoint[1] < $currentPoint[1]; + $sweep = ($up xor $right); + + if ($this->intensity < 0.5 + || ($right && $previousPoint[0] !== $currentPoint[0] - 1) + || (! $right && $previousPoint[0] - 1 !== $currentPoint[0]) + ) { + $path = $path->line( + $currentPoint[0] + ($right ? -$this->intensity : $this->intensity), + $currentPoint[1] + ); + } + + $path = $path->ellipticArc( + $this->intensity, + $this->intensity, + 0, + false, + $sweep, + $currentPoint[0], + $currentPoint[1] + ($up ? -$this->intensity : $this->intensity) + ); + } else { + $up = $previousPoint[1] > $currentPoint[1]; + $right = $nextPoint[0] > $currentPoint[0]; + $sweep = ! ($up xor $right); + + if ($this->intensity < 0.5 + || ($up && $previousPoint[1] !== $currentPoint[1] + 1) + || (! $up && $previousPoint[0] + 1 !== $currentPoint[0]) + ) { + $path = $path->line( + $currentPoint[0], + $currentPoint[1] + ($up ? $this->intensity : -$this->intensity) + ); + } + + $path = $path->ellipticArc( + $this->intensity, + $this->intensity, + 0, + false, + $sweep, + $currentPoint[0] + ($right ? $this->intensity : -$this->intensity), + $currentPoint[1] + ); + } + } + + $path = $path->close(); + } + + return $path; + } +} diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Module/SquareModule.php b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Module/SquareModule.php new file mode 100644 index 00000000..9ab46076 --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Module/SquareModule.php @@ -0,0 +1,47 @@ +getSimplifiedPoints(); + $length = count($points); + $path = $path->move($points[0][0], $points[0][1]); + + for ($i = 1; $i < $length; ++$i) { + $path = $path->line($points[$i][0], $points[$i][1]); + } + + $path = $path->close(); + } + + return $path; + } +} diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Path/Close.php b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Path/Close.php new file mode 100644 index 00000000..b07feb02 --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Path/Close.php @@ -0,0 +1,29 @@ +x1 = $x1; + $this->y1 = $y1; + $this->x2 = $x2; + $this->y2 = $y2; + $this->x3 = $x3; + $this->y3 = $y3; + } + + public function getX1() : float + { + return $this->x1; + } + + public function getY1() : float + { + return $this->y1; + } + + public function getX2() : float + { + return $this->x2; + } + + public function getY2() : float + { + return $this->y2; + } + + public function getX3() : float + { + return $this->x3; + } + + public function getY3() : float + { + return $this->y3; + } + + /** + * @return self + */ + public function translate(float $x, float $y) : OperationInterface + { + return new self( + $this->x1 + $x, + $this->y1 + $y, + $this->x2 + $x, + $this->y2 + $y, + $this->x3 + $x, + $this->y3 + $y + ); + } +} diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Path/EllipticArc.php b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Path/EllipticArc.php new file mode 100644 index 00000000..eff7deb4 --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Path/EllipticArc.php @@ -0,0 +1,278 @@ +xRadius = abs($xRadius); + $this->yRadius = abs($yRadius); + $this->xAxisAngle = $xAxisAngle % 360; + $this->largeArc = $largeArc; + $this->sweep = $sweep; + $this->x = $x; + $this->y = $y; + } + + public function getXRadius() : float + { + return $this->xRadius; + } + + public function getYRadius() : float + { + return $this->yRadius; + } + + public function getXAxisAngle() : float + { + return $this->xAxisAngle; + } + + public function isLargeArc() : bool + { + return $this->largeArc; + } + + public function isSweep() : bool + { + return $this->sweep; + } + + public function getX() : float + { + return $this->x; + } + + public function getY() : float + { + return $this->y; + } + + /** + * @return self + */ + public function translate(float $x, float $y) : OperationInterface + { + return new self( + $this->xRadius, + $this->yRadius, + $this->xAxisAngle, + $this->largeArc, + $this->sweep, + $this->x + $x, + $this->y + $y + ); + } + + /** + * Converts the elliptic arc to multiple curves. + * + * Since not all image back ends support elliptic arcs, this method allows to convert the arc into multiple curves + * resembling the same result. + * + * @see https://mortoray.com/2017/02/16/rendering-an-svg-elliptical-arc-as-bezier-curves/ + * @return array + */ + public function toCurves(float $fromX, float $fromY) : array + { + if (sqrt(($fromX - $this->x) ** 2 + ($fromY - $this->y) ** 2) < self::ZERO_TOLERANCE) { + return []; + } + + if ($this->xRadius < self::ZERO_TOLERANCE || $this->yRadius < self::ZERO_TOLERANCE) { + return [new Line($this->x, $this->y)]; + } + + return $this->createCurves($fromX, $fromY); + } + + /** + * @return Curve[] + */ + private function createCurves(float $fromX, $fromY) : array + { + $xAngle = deg2rad($this->xAxisAngle); + list($centerX, $centerY, $radiusX, $radiusY, $startAngle, $deltaAngle) = + $this->calculateCenterPointParameters($fromX, $fromY, $xAngle); + + $s = $startAngle; + $e = $s + $deltaAngle; + $sign = ($e < $s) ? -1 : 1; + $remain = abs($e - $s); + $p1 = self::point($centerX, $centerY, $radiusX, $radiusY, $xAngle, $s); + $curves = []; + + while ($remain > self::ZERO_TOLERANCE) { + $step = min($remain, pi() / 2); + $signStep = $step * $sign; + $p2 = self::point($centerX, $centerY, $radiusX, $radiusY, $xAngle, $s + $signStep); + + $alphaT = tan($signStep / 2); + $alpha = sin($signStep) * (sqrt(4 + 3 * $alphaT ** 2) - 1) / 3; + $d1 = self::derivative($radiusX, $radiusY, $xAngle, $s); + $d2 = self::derivative($radiusX, $radiusY, $xAngle, $s + $signStep); + + $curves[] = new Curve( + $p1[0] + $alpha * $d1[0], + $p1[1] + $alpha * $d1[1], + $p2[0] - $alpha * $d2[0], + $p2[1] - $alpha * $d2[1], + $p2[0], + $p2[1] + ); + + $s += $signStep; + $remain -= $step; + $p1 = $p2; + } + + return $curves; + } + + /** + * @return float[] + */ + private function calculateCenterPointParameters(float $fromX, float $fromY, float $xAngle) + { + $rX = $this->xRadius; + $rY = $this->yRadius; + + // F.6.5.1 + $dx2 = ($fromX - $this->x) / 2; + $dy2 = ($fromY - $this->y) / 2; + $x1p = cos($xAngle) * $dx2 + sin($xAngle) * $dy2; + $y1p = -sin($xAngle) * $dx2 + cos($xAngle) * $dy2; + + // F.6.5.2 + $rxs = $rX ** 2; + $rys = $rY ** 2; + $x1ps = $x1p ** 2; + $y1ps = $y1p ** 2; + $cr = $x1ps / $rxs + $y1ps / $rys; + + if ($cr > 1) { + $s = sqrt($cr); + $rX *= $s; + $rY *= $s; + $rxs = $rX ** 2; + $rys = $rY ** 2; + } + + $dq = ($rxs * $y1ps + $rys * $x1ps); + $pq = ($rxs * $rys - $dq) / $dq; + $q = sqrt(max(0, $pq)); + + if ($this->largeArc === $this->sweep) { + $q = -$q; + } + + $cxp = $q * $rX * $y1p / $rY; + $cyp = -$q * $rY * $x1p / $rX; + + // F.6.5.3 + $cx = cos($xAngle) * $cxp - sin($xAngle) * $cyp + ($fromX + $this->x) / 2; + $cy = sin($xAngle) * $cxp + cos($xAngle) * $cyp + ($fromY + $this->y) / 2; + + // F.6.5.5 + $theta = self::angle(1, 0, ($x1p - $cxp) / $rX, ($y1p - $cyp) / $rY); + + // F.6.5.6 + $delta = self::angle(($x1p - $cxp) / $rX, ($y1p - $cyp) / $rY, (-$x1p - $cxp) / $rX, (-$y1p - $cyp) / $rY); + $delta = fmod($delta, pi() * 2); + + if (! $this->sweep) { + $delta -= 2 * pi(); + } + + return [$cx, $cy, $rX, $rY, $theta, $delta]; + } + + private static function angle(float $ux, float $uy, float $vx, float $vy) : float + { + // F.6.5.4 + $dot = $ux * $vx + $uy * $vy; + $length = sqrt($ux ** 2 + $uy ** 2) * sqrt($vx ** 2 + $vy ** 2); + $angle = acos(min(1, max(-1, $dot / $length))); + + if (($ux * $vy - $uy * $vx) < 0) { + return -$angle; + } + + return $angle; + } + + /** + * @return float[] + */ + private static function point( + float $centerX, + float $centerY, + float $radiusX, + float $radiusY, + float $xAngle, + float $angle + ) : array { + return [ + $centerX + $radiusX * cos($xAngle) * cos($angle) - $radiusY * sin($xAngle) * sin($angle), + $centerY + $radiusX * sin($xAngle) * cos($angle) + $radiusY * cos($xAngle) * sin($angle), + ]; + } + + /** + * @return float[] + */ + private static function derivative(float $radiusX, float $radiusY, float $xAngle, float $angle) : array + { + return [ + -$radiusX * cos($xAngle) * sin($angle) - $radiusY * sin($xAngle) * cos($angle), + -$radiusX * sin($xAngle) * sin($angle) + $radiusY * cos($xAngle) * cos($angle), + ]; + } +} diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Path/Line.php b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Path/Line.php new file mode 100644 index 00000000..3149a39b --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Path/Line.php @@ -0,0 +1,41 @@ +x = $x; + $this->y = $y; + } + + public function getX() : float + { + return $this->x; + } + + public function getY() : float + { + return $this->y; + } + + /** + * @return self + */ + public function translate(float $x, float $y) : OperationInterface + { + return new self($this->x + $x, $this->y + $y); + } +} diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Path/Move.php b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Path/Move.php new file mode 100644 index 00000000..007b77c7 --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Path/Move.php @@ -0,0 +1,41 @@ +x = $x; + $this->y = $y; + } + + public function getX() : float + { + return $this->x; + } + + public function getY() : float + { + return $this->y; + } + + /** + * @return self + */ + public function translate(float $x, float $y) : OperationInterface + { + return new self($this->x + $x, $this->x + $y); + } +} diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Path/OperationInterface.php b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Path/OperationInterface.php new file mode 100644 index 00000000..a5fa0edc --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Path/OperationInterface.php @@ -0,0 +1,12 @@ +operations[] = new Move($x, $y); + return $path; + } + + /** + * Draws a line from the current position to another position. + */ + public function line(float $x, float $y) : self + { + $path = clone $this; + $path->operations[] = new Line($x, $y); + return $path; + } + + /** + * Draws an elliptic arc from the current position to another position. + */ + public function ellipticArc( + float $xRadius, + float $yRadius, + float $xAxisRotation, + bool $largeArc, + bool $sweep, + float $x, + float $y + ) : self { + $path = clone $this; + $path->operations[] = new EllipticArc($xRadius, $yRadius, $xAxisRotation, $largeArc, $sweep, $x, $y); + return $path; + } + + /** + * Draws a curve from the current position to another position. + */ + public function curve(float $x1, float $y1, float $x2, float $y2, float $x3, float $y3) : self + { + $path = clone $this; + $path->operations[] = new Curve($x1, $y1, $x2, $y2, $x3, $y3); + return $path; + } + + /** + * Closes a sub-path. + */ + public function close() : self + { + $path = clone $this; + $path->operations[] = Close::instance(); + return $path; + } + + /** + * Appends another path to this one. + */ + public function append(self $other) : self + { + $path = clone $this; + $path->operations = array_merge($this->operations, $other->operations); + return $path; + } + + public function translate(float $x, float $y) : self + { + $path = new self(); + + foreach ($this->operations as $operation) { + $path->operations[] = $operation->translate($x, $y); + } + + return $path; + } + + /** + * @return OperationInterface[]|Traversable + */ + public function getIterator() : Traversable + { + foreach ($this->operations as $operation) { + yield $operation; + } + } +} diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/PlainTextRenderer.php b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/PlainTextRenderer.php new file mode 100644 index 00000000..8aa76528 --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/PlainTextRenderer.php @@ -0,0 +1,86 @@ +margin = $margin; + } + + /** + * @throws InvalidArgumentException if matrix width doesn't match height + */ + public function render(QrCode $qrCode) : string + { + $matrix = $qrCode->getMatrix(); + $matrixSize = $matrix->getWidth(); + + if ($matrixSize !== $matrix->getHeight()) { + throw new InvalidArgumentException('Matrix must have the same width and height'); + } + + $rows = $matrix->getArray()->toArray(); + + if (0 !== $matrixSize % 2) { + $rows[] = array_fill(0, $matrixSize, 0); + } + + $horizontalMargin = str_repeat(self::EMPTY_BLOCK, $this->margin); + $result = str_repeat("\n", (int) ceil($this->margin / 2)); + + for ($i = 0; $i < $matrixSize; $i += 2) { + $result .= $horizontalMargin; + + $upperRow = $rows[$i]; + $lowerRow = $rows[$i + 1]; + + for ($j = 0; $j < $matrixSize; ++$j) { + $upperBit = $upperRow[$j]; + $lowerBit = $lowerRow[$j]; + + if ($upperBit) { + $result .= $lowerBit ? self::FULL_BLOCK : self::UPPER_HALF_BLOCK; + } else { + $result .= $lowerBit ? self::LOWER_HALF_BLOCK : self::EMPTY_BLOCK; + } + } + + $result .= $horizontalMargin . "\n"; + } + + $result .= str_repeat("\n", (int) ceil($this->margin / 2)); + + return $result; + } +} diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/RendererInterface.php b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/RendererInterface.php new file mode 100644 index 00000000..b0aae390 --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/RendererInterface.php @@ -0,0 +1,11 @@ +externalColor = $externalColor; + $this->internalColor = $internalColor; + } + + public static function uniform(ColorInterface $color) : self + { + return new self($color, $color); + } + + public static function inherit() : self + { + return self::$inherit ?: self::$inherit = new self(null, null); + } + + public function inheritsBothColors() : bool + { + return null === $this->externalColor && null === $this->internalColor; + } + + public function inheritsExternalColor() : bool + { + return null === $this->externalColor; + } + + public function inheritsInternalColor() : bool + { + return null === $this->internalColor; + } + + public function getExternalColor() : ColorInterface + { + if (null === $this->externalColor) { + throw new RuntimeException('External eye color inherits foreground color'); + } + + return $this->externalColor; + } + + public function getInternalColor() : ColorInterface + { + if (null === $this->internalColor) { + throw new RuntimeException('Internal eye color inherits foreground color'); + } + + return $this->internalColor; + } +} diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/RendererStyle/Fill.php b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/RendererStyle/Fill.php new file mode 100644 index 00000000..d54268e6 --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/RendererStyle/Fill.php @@ -0,0 +1,168 @@ +backgroundColor = $backgroundColor; + $this->foregroundColor = $foregroundColor; + $this->foregroundGradient = $foregroundGradient; + $this->topLeftEyeFill = $topLeftEyeFill; + $this->topRightEyeFill = $topRightEyeFill; + $this->bottomLeftEyeFill = $bottomLeftEyeFill; + } + + public static function default() : self + { + return self::$default ?: self::$default = self::uniformColor(new Gray(100), new Gray(0)); + } + + public static function withForegroundColor( + ColorInterface $backgroundColor, + ColorInterface $foregroundColor, + EyeFill $topLeftEyeFill, + EyeFill $topRightEyeFill, + EyeFill $bottomLeftEyeFill + ) : self { + return new self( + $backgroundColor, + $foregroundColor, + null, + $topLeftEyeFill, + $topRightEyeFill, + $bottomLeftEyeFill + ); + } + + public static function withForegroundGradient( + ColorInterface $backgroundColor, + Gradient $foregroundGradient, + EyeFill $topLeftEyeFill, + EyeFill $topRightEyeFill, + EyeFill $bottomLeftEyeFill + ) : self { + return new self( + $backgroundColor, + null, + $foregroundGradient, + $topLeftEyeFill, + $topRightEyeFill, + $bottomLeftEyeFill + ); + } + + public static function uniformColor(ColorInterface $backgroundColor, ColorInterface $foregroundColor) : self + { + return new self( + $backgroundColor, + $foregroundColor, + null, + EyeFill::inherit(), + EyeFill::inherit(), + EyeFill::inherit() + ); + } + + public static function uniformGradient(ColorInterface $backgroundColor, Gradient $foregroundGradient) : self + { + return new self( + $backgroundColor, + null, + $foregroundGradient, + EyeFill::inherit(), + EyeFill::inherit(), + EyeFill::inherit() + ); + } + + public function hasGradientFill() : bool + { + return null !== $this->foregroundGradient; + } + + public function getBackgroundColor() : ColorInterface + { + return $this->backgroundColor; + } + + public function getForegroundColor() : ColorInterface + { + if (null === $this->foregroundColor) { + throw new RuntimeException('Fill uses a gradient, thus no foreground color is available'); + } + + return $this->foregroundColor; + } + + public function getForegroundGradient() : Gradient + { + if (null === $this->foregroundGradient) { + throw new RuntimeException('Fill uses a single color, thus no foreground gradient is available'); + } + + return $this->foregroundGradient; + } + + public function getTopLeftEyeFill() : EyeFill + { + return $this->topLeftEyeFill; + } + + public function getTopRightEyeFill() : EyeFill + { + return $this->topRightEyeFill; + } + + public function getBottomLeftEyeFill() : EyeFill + { + return $this->bottomLeftEyeFill; + } +} diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/RendererStyle/Gradient.php b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/RendererStyle/Gradient.php new file mode 100644 index 00000000..3813dfd1 --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/RendererStyle/Gradient.php @@ -0,0 +1,46 @@ +startColor = $startColor; + $this->endColor = $endColor; + $this->type = $type; + } + + public function getStartColor() : ColorInterface + { + return $this->startColor; + } + + public function getEndColor() : ColorInterface + { + return $this->endColor; + } + + public function getType() : GradientType + { + return $this->type; + } +} diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/RendererStyle/GradientType.php b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/RendererStyle/GradientType.php new file mode 100644 index 00000000..c1ca7547 --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/RendererStyle/GradientType.php @@ -0,0 +1,22 @@ +margin = $margin; + $this->size = $size; + $this->module = $module ?: SquareModule::instance(); + $this->eye = $eye ?: new ModuleEye($this->module); + $this->fill = $fill ?: Fill::default(); + } + + public function withSize(int $size) : self + { + $style = clone $this; + $style->size = $size; + return $style; + } + + public function withMargin(int $margin) : self + { + $style = clone $this; + $style->margin = $margin; + return $style; + } + + public function getSize() : int + { + return $this->size; + } + + public function getMargin() : int + { + return $this->margin; + } + + public function getModule() : ModuleInterface + { + return $this->module; + } + + public function getEye() : EyeInterface + { + return $this->eye; + } + + public function getFill() : Fill + { + return $this->fill; + } +} diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/src/Writer.php b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Writer.php new file mode 100644 index 00000000..66889010 --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/src/Writer.php @@ -0,0 +1,68 @@ +renderer = $renderer; + } + + /** + * Writes QR code and returns it as string. + * + * Content is a string which *should* be encoded in UTF-8, in case there are + * non ASCII-characters present. + * + * @throws InvalidArgumentException if the content is empty + */ + public function writeString( + string $content, + string $encoding = Encoder::DEFAULT_BYTE_MODE_ECODING, + ?ErrorCorrectionLevel $ecLevel = null + ) : string { + if (strlen($content) === 0) { + throw new InvalidArgumentException('Found empty contents'); + } + + if (null === $ecLevel) { + $ecLevel = ErrorCorrectionLevel::L(); + } + + return $this->renderer->render(Encoder::encode($content, $ecLevel, $encoding)); + } + + /** + * Writes QR code to a file. + * + * @see Writer::writeString() + */ + public function writeFile( + string $content, + string $filename, + string $encoding = Encoder::DEFAULT_BYTE_MODE_ECODING, + ?ErrorCorrectionLevel $ecLevel = null + ) : void { + file_put_contents($filename, $this->writeString($content, $encoding, $ecLevel)); + } +} diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Common/BitArrayTest.php b/user/plugins/login/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Common/BitArrayTest.php new file mode 100644 index 00000000..81bcbce6 --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Common/BitArrayTest.php @@ -0,0 +1,201 @@ +assertFalse($array->get($i)); + $array->set($i); + $this->assertTrue($array->get($i)); + } + } + + public function testGetNextSet1() + { + $array = new BitArray(32); + + for ($i = 0; $i < $array->getSize(); $i++) { + $this->assertEquals($i, 32, '', $array->getNextSet($i)); + } + + $array = new BitArray(33); + + for ($i = 0; $i < $array->getSize(); $i++) { + $this->assertEquals($i, 33, '', $array->getNextSet($i)); + } + } + + public function testGetNextSet2() + { + $array = new BitArray(33); + + for ($i = 0; $i < $array->getSize(); $i++) { + $this->assertEquals($i, $i <= 31 ? 31 : 33, '', $array->getNextSet($i)); + } + + $array = new BitArray(33); + + for ($i = 0; $i < $array->getSize(); $i++) { + $this->assertEquals($i, 32, '', $array->getNextSet($i)); + } + } + + public function testGetNextSet3() + { + $array = new BitArray(63); + $array->set(31); + $array->set(32); + + for ($i = 0; $i < $array->getSize(); $i++) { + if ($i <= 31) { + $expected = 31; + } elseif ($i <= 32) { + $expected = 32; + } else { + $expected = 63; + } + + $this->assertEquals($i, $expected, '', $array->getNextSet($i)); + } + } + + public function testGetNextSet4() + { + $array = new BitArray(63); + $array->set(33); + $array->set(40); + + for ($i = 0; $i < $array->getSize(); $i++) { + if ($i <= 33) { + $expected = 33; + } elseif ($i <= 40) { + $expected = 40; + } else { + $expected = 63; + } + + $this->assertEquals($i, $expected, '', $array->getNextSet($i)); + } + } + + public function testGetNextSet5() + { + if (defined('MT_RAND_PHP')) { + mt_srand(0xdeadbeef, MT_RAND_PHP); + } else { + mt_srand(0xdeadbeef); + } + + for ($i = 0; $i < 10; $i++) { + $array = new BitArray(mt_rand(1, 100)); + $numSet = mt_rand(0, 19); + + for ($j = 0; $j < $numSet; $j++) { + $array->set(mt_rand(0, $array->getSize() - 1)); + } + + $numQueries = mt_rand(0, 19); + + for ($j = 0; $j < $numQueries; $j++) { + $query = mt_rand(0, $array->getSize() - 1); + $expected = $query; + + while ($expected < $array->getSize() && !$array->get($expected)) { + $expected++; + } + + $actual = $array->getNextSet($query); + + if ($actual !== $expected) { + $array->getNextSet($query); + } + + $this->assertEquals($expected, $actual); + } + } + } + + public function testSetBulk() + { + $array = new BitArray(64); + $array->setBulk(32, 0xFFFF0000); + + for ($i = 0; $i < 48; $i++) { + $this->assertFalse($array->get($i)); + } + + for ($i = 48; $i < 64; $i++) { + $this->assertTrue($array->get($i)); + } + } + + public function testClear() + { + $array = new BitArray(32); + + for ($i = 0; $i < 32; $i++) { + $array->set($i); + } + + $array->clear(); + + for ($i = 0; $i < 32; $i++) { + $this->assertFalse($array->get($i)); + } + } + + public function testGetArray() + { + $array = new BitArray(64); + $array->set(0); + $array->set(63); + + $ints = $array->getBitArray(); + + $this->assertEquals(1, $ints[0]); + $this->assertEquals(0x80000000, $ints[1]); + } + + public function testIsRange() + { + $array = new BitArray(64); + $this->assertTrue($array->isRange(0, 64, false)); + $this->assertFalse($array->isRange(0, 64, true)); + + $array->set(32); + $this->assertTrue($array->isRange(32, 33, true)); + + $array->set(31); + $this->assertTrue($array->isRange(31, 33, true)); + + $array->set(34); + $this->assertFalse($array->isRange(31, 35, true)); + + for ($i = 0; $i < 31; $i++) { + $array->set($i); + } + + $this->assertTrue($array->isRange(0, 33, true)); + + for ($i = 33; $i < 64; $i++) { + $array->set($i); + } + + $this->assertTrue($array->isRange(0, 64, true)); + $this->assertFalse($array->isRange(0, 64, false)); + } +} \ No newline at end of file diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Common/BitMatrixTest.php b/user/plugins/login/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Common/BitMatrixTest.php new file mode 100644 index 00000000..89a58812 --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Common/BitMatrixTest.php @@ -0,0 +1,119 @@ +assertEquals(33, $matrix->getHeight()); + + for ($y = 0; $y < 33; $y++) { + for ($x = 0; $x < 33; $x++) { + if ($y * $x % 3 === 0) { + $matrix->set($x, $y); + } + } + } + + for ($y = 0; $y < 33; $y++) { + for ($x = 0; $x < 33; $x++) { + $this->assertEquals($x * $y % 3 === 0, $matrix->get($x, $y)); + } + } + } + + public function testSetRegion() + { + $matrix = new BitMatrix(5); + $matrix->setRegion(1, 1, 3, 3); + + for ($y = 0; $y < 5; $y++) { + for ($x = 0; $x < 5; $x++) { + $this->assertEquals($y >= 1 && $y <= 3 && $x >= 1 && $x <= 3, $matrix->get($x, $y)); + } + } + } + + public function testRectangularMatrix() + { + $matrix = new BitMatrix(75, 20); + $this->assertEquals(75, $matrix->getWidth()); + $this->assertEquals(20, $matrix->getHeight()); + + $matrix->set(10, 0); + $matrix->set(11, 1); + $matrix->set(50, 2); + $matrix->set(51, 3); + $matrix->flip(74, 4); + $matrix->flip(0, 5); + + $this->assertTrue($matrix->get(10, 0)); + $this->assertTrue($matrix->get(11, 1)); + $this->assertTrue($matrix->get(50, 2)); + $this->assertTrue($matrix->get(51, 3)); + $this->assertTrue($matrix->get(74, 4)); + $this->assertTrue($matrix->get(0, 5)); + + $matrix->flip(50, 2); + $matrix->flip(51, 3); + + $this->assertFalse($matrix->get(50, 2)); + $this->assertFalse($matrix->get(51, 3)); + } + + public function testRectangularSetRegion() + { + $matrix = new BitMatrix(320, 240); + $this->assertEquals(320, $matrix->getWidth()); + $this->assertEquals(240, $matrix->getHeight()); + + $matrix->setRegion(105, 22, 80, 12); + + for ($y = 0; $y < 240; $y++) { + for ($x = 0; $x < 320; $x++) { + $this->assertEquals($y >= 22 && $y < 34 && $x >= 105 && $x < 185, $matrix->get($x, $y)); + } + } + } + + public function testGetRow() + { + $matrix = new BitMatrix(102, 5); + + for ($x = 0; $x < 102; $x++) { + if ($x & 3 === 0) { + $matrix->set($x, 2); + } + } + + $array1 = $matrix->getRow(2, null); + $this->assertEquals(102, $array1->getSize()); + + $array2 = new BitArray(60); + $array2 = $matrix->getRow(2, $array2); + $this->assertEquals(102, $array2->getSize()); + + $array3 = new BitArray(200); + $array3 = $matrix->getRow(2, $array3); + $this->assertEquals(200, $array3->getSize()); + + for ($x = 0; $x < 102; $x++) { + $on = ($x & 3 === 0); + + $this->assertEquals($on, $array1->get($x)); + $this->assertEquals($on, $array2->get($x)); + $this->assertEquals($on, $array3->get($x)); + } + } +} \ No newline at end of file diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Common/BitUtilsTest.php b/user/plugins/login/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Common/BitUtilsTest.php new file mode 100644 index 00000000..b80ff7df --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Common/BitUtilsTest.php @@ -0,0 +1,30 @@ +assertEquals(1, BitUtils::unsignedRightShift(1, 0)); + $this->assertEquals(1, BitUtils::unsignedRightShift(10, 3)); + $this->assertEquals(536870910, BitUtils::unsignedRightShift(-10, 3)); + } + + public function testNumberOfTrailingZeros() + { + $this->assertEquals(32, BitUtils::numberOfTrailingZeros(0)); + $this->assertEquals(1, BitUtils::numberOfTrailingZeros(10)); + $this->assertEquals(0, BitUtils::numberOfTrailingZeros(15)); + $this->assertEquals(2, BitUtils::numberOfTrailingZeros(20)); + } +} \ No newline at end of file diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Common/ErrorCorrectionLevelTest.php b/user/plugins/login/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Common/ErrorCorrectionLevelTest.php new file mode 100644 index 00000000..736e995d --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Common/ErrorCorrectionLevelTest.php @@ -0,0 +1,40 @@ +assertEquals(0x0, ErrorCorrectionLevel::M); + $this->assertEquals(0x1, ErrorCorrectionLevel::L); + $this->assertEquals(0x2, ErrorCorrectionLevel::H); + $this->assertEquals(0x3, ErrorCorrectionLevel::Q); + } + + public function testInvalidErrorCorrectionLevelThrowsException() + { + $this->setExpectedException( + 'BaconQrCode\Exception\UnexpectedValueException', + 'Value not a const in enum BaconQrCode\Common\ErrorCorrectionLevel' + ); + new ErrorCorrectionLevel(4); + } +} \ No newline at end of file diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Common/FormatInformationTest.php b/user/plugins/login/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Common/FormatInformationTest.php new file mode 100644 index 00000000..5f6ee58c --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Common/FormatInformationTest.php @@ -0,0 +1,104 @@ +unmaskedTestFormatInfo = $this->maskedTestFormatInfo ^ 0x5412; + } + + + public function testBitsDiffering() + { + $this->assertEquals(0, FormatInformation::numBitsDiffering(1, 1)); + $this->assertEquals(1, FormatInformation::numBitsDiffering(0, 2)); + $this->assertEquals(2, FormatInformation::numBitsDiffering(1, 2)); + $this->assertEquals(32, FormatInformation::numBitsDiffering(-1, 0)); + } + + public function testDecode() + { + $expected = FormatInformation::decodeFormatInformation( + $this->maskedTestFormatInfo, + $this->maskedTestFormatInfo + ); + + $this->assertNotNull($expected); + $this->assertEquals(7, $expected->getDataMask()); + $this->assertEquals(ErrorCorrectionLevel::Q, $expected->getErrorCorrectionLevel()->get()); + + $this->assertEquals( + $expected, + FormatInformation::decodeFormatInformation( + $this->unmaskedTestFormatInfo, + $this->maskedTestFormatInfo + ) + ); + } + + public function testDecodeWithBitDifference() + { + $expected = FormatInformation::decodeFormatInformation( + $this->maskedTestFormatInfo, + $this->maskedTestFormatInfo + ); + + $this->assertEquals( + $expected, + FormatInformation::decodeFormatInformation( + $this->maskedTestFormatInfo ^ 0x1, + $this->maskedTestFormatInfo ^ 0x1 + ) + ); + $this->assertEquals( + $expected, + FormatInformation::decodeFormatInformation( + $this->maskedTestFormatInfo ^ 0x3, + $this->maskedTestFormatInfo ^ 0x3 + ) + ); + $this->assertEquals( + $expected, + FormatInformation::decodeFormatInformation( + $this->maskedTestFormatInfo ^ 0x7, + $this->maskedTestFormatInfo ^ 0x7 + ) + ); + $this->assertNull( + FormatInformation::decodeFormatInformation( + $this->maskedTestFormatInfo ^ 0xf, + $this->maskedTestFormatInfo ^ 0xf + ) + ); + } + + public function testDecodeWithMisRead() + { + $expected = FormatInformation::decodeFormatInformation( + $this->maskedTestFormatInfo, + $this->maskedTestFormatInfo + ); + + $this->assertEquals( + $expected, + FormatInformation::decodeFormatInformation( + $this->maskedTestFormatInfo ^ 0x3, + $this->maskedTestFormatInfo ^ 0xf + ) + ); + } +} \ No newline at end of file diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Common/ModeTest.php b/user/plugins/login/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Common/ModeTest.php new file mode 100644 index 00000000..4daab7c3 --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Common/ModeTest.php @@ -0,0 +1,42 @@ +assertEquals(0x0, Mode::TERMINATOR); + $this->assertEquals(0x1, Mode::NUMERIC); + $this->assertEquals(0x2, Mode::ALPHANUMERIC); + $this->assertEquals(0x4, Mode::BYTE); + $this->assertEquals(0x8, Mode::KANJI); + } + + public function testInvalidModeThrowsException() + { + $this->setExpectedException( + 'BaconQrCode\Exception\UnexpectedValueException', + 'Value not a const in enum BaconQrCode\Common\Mode' + ); + new Mode(10); + } +} \ No newline at end of file diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Common/ReedSolomonCodecTest.php b/user/plugins/login/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Common/ReedSolomonCodecTest.php new file mode 100644 index 00000000..604641a0 --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Common/ReedSolomonCodecTest.php @@ -0,0 +1,111 @@ +encode($block, $parity); + + // Copy parity into test blocks + for ($i = 0; $i < $numRoots; $i++) { + $block[$i + $dataSize] = $parity[$i]; + $tBlock[$i + $dataSize] = $parity[$i]; + } + + // Seed with errors + for ($i = 0; $i < $errors; $i++) { + $errorValue = mt_rand(1, $blockSize); + + do { + $errorLocation = mt_rand(0, $blockSize); + } while ($errorLocations[$errorLocation] !== 0); + + $errorLocations[$errorLocation] = 1; + + if (mt_rand(0, 1)) { + $erasures[] = $errorLocation; + } + + $tBlock[$errorLocation] ^= $errorValue; + } + + $erasures = SplFixedArray::fromArray($erasures, false); + + // Decode the errored block + $foundErrors = $codec->decode($tBlock, $erasures); + + if ($errors > 0 && $foundErrors === null) { + $this->assertEquals($block, $tBlock, 'Decoder failed to correct errors'); + } + + $this->assertEquals($errors, $foundErrors, 'Found errors do not equal expected errors'); + + for ($i = 0; $i < $foundErrors; $i++) { + if ($errorLocations[$erasures[$i]] === 0) { + $this->fail(sprintf('Decoder indicates error in location %d without error', $erasures[$i])); + } + } + + $this->assertEquals($block, $tBlock, 'Decoder did not correct errors'); + } + } +} \ No newline at end of file diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Common/VersionTest.php b/user/plugins/login/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Common/VersionTest.php new file mode 100644 index 00000000..8b3fc01f --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Common/VersionTest.php @@ -0,0 +1,88 @@ +assertNotNull($version); + $this->assertEquals($versionNumber, $version->getVersionNumber()); + $this->assertNotNull($version->getAlignmentPatternCenters()); + + if ($versionNumber > 1) { + $this->assertTrue(count($version->getAlignmentPatternCenters()) > 0); + } + + $this->assertEquals($dimension, $version->getDimensionForVersion()); + $this->assertNotNull($version->getEcBlocksForLevel(new ErrorCorrectionLevel(ErrorCorrectionLevel::H))); + $this->assertNotNull($version->getEcBlocksForLevel(new ErrorCorrectionLevel(ErrorCorrectionLevel::L))); + $this->assertNotNull($version->getEcBlocksForLevel(new ErrorCorrectionLevel(ErrorCorrectionLevel::M))); + $this->assertNotNull($version->getEcBlocksForLevel(new ErrorCorrectionLevel(ErrorCorrectionLevel::Q))); + $this->assertNotNull($version->buildFunctionPattern()); + } + + /** + * @dataProvider versionProvider + * @param integer $versionNumber + * @param integer $dimension + */ + public function testGetProvisionalVersionForDimension($versionNumber, $dimension) + { + $this->assertEquals( + $versionNumber, + Version::getProvisionalVersionForDimension($dimension)->getVersionNumber() + ); + } + + /** + * @dataProvider decodeInformationProvider + * @param integer $expectedVersion + * @param integer $mask + */ + public function testDecodeVersionInformation($expectedVersion, $mask) + { + $version = Version::decodeVersionInformation($mask); + $this->assertNotNull($version); + $this->assertEquals($expectedVersion, $version->getVersionNumber()); + } +} \ No newline at end of file diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Encoder/EncoderTest.php b/user/plugins/login/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Encoder/EncoderTest.php new file mode 100644 index 00000000..31cdaa4e --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Encoder/EncoderTest.php @@ -0,0 +1,468 @@ +getMethods(ReflectionMethod::IS_STATIC) as $method) { + $method->setAccessible(true); + $this->methods[$method->getName()] = $method; + } + } + + public function testGetAlphanumericCode() + { + // The first ten code points are numbers. + for ($i = 0; $i < 10; $i++) { + $this->assertEquals($i, $this->methods['getAlphanumericCode']->invoke(null, ord('0') + $i)); + } + + // The next 26 code points are capital alphabet letters. + for ($i = 10; $i < 36; $i++) { + // The first ten code points are numbers + $this->assertEquals($i, $this->methods['getAlphanumericCode']->invoke(null, ord('A') + $i - 10)); + } + + // Others are symbol letters. + $this->assertEquals(36, $this->methods['getAlphanumericCode']->invoke(null, ' ')); + $this->assertEquals(37, $this->methods['getAlphanumericCode']->invoke(null, '$')); + $this->assertEquals(38, $this->methods['getAlphanumericCode']->invoke(null, '%')); + $this->assertEquals(39, $this->methods['getAlphanumericCode']->invoke(null, '*')); + $this->assertEquals(40, $this->methods['getAlphanumericCode']->invoke(null, '+')); + $this->assertEquals(41, $this->methods['getAlphanumericCode']->invoke(null, '-')); + $this->assertEquals(42, $this->methods['getAlphanumericCode']->invoke(null, '.')); + $this->assertEquals(43, $this->methods['getAlphanumericCode']->invoke(null, '/')); + $this->assertEquals(44, $this->methods['getAlphanumericCode']->invoke(null, ':')); + + // Should return -1 for other letters. + $this->assertEquals(-1, $this->methods['getAlphanumericCode']->invoke(null, 'a')); + $this->assertEquals(-1, $this->methods['getAlphanumericCode']->invoke(null, '#')); + $this->assertEquals(-1, $this->methods['getAlphanumericCode']->invoke(null, "\0")); + } + + public function testChooseMode() + { + // Numeric mode + $this->assertSame(Mode::NUMERIC, $this->methods['chooseMode']->invoke(null, '0')->get()); + $this->assertSame(Mode::NUMERIC, $this->methods['chooseMode']->invoke(null, '0123456789')->get()); + + // Alphanumeric mode + $this->assertSame(Mode::ALPHANUMERIC, $this->methods['chooseMode']->invoke(null, 'A')->get()); + $this->assertSame(Mode::ALPHANUMERIC, $this->methods['chooseMode']->invoke(null, '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:')->get()); + + // 8-bit byte mode + $this->assertSame(Mode::BYTE, $this->methods['chooseMode']->invoke(null, 'a')->get()); + $this->assertSame(Mode::BYTE, $this->methods['chooseMode']->invoke(null, '#')->get()); + $this->assertSame(Mode::BYTE, $this->methods['chooseMode']->invoke(null, '')->get()); + + // AIUE in Hiragana in SHIFT-JIS + $this->assertSame(Mode::BYTE, $this->methods['chooseMode']->invoke(null, "\x8\xa\x8\xa\x8\xa\x8\xa6")->get()); + + // Nihon in Kanji in SHIFT-JIS + $this->assertSame(Mode::BYTE, $this->methods['chooseMode']->invoke(null, "\x9\xf\x9\x7b")->get()); + + // Sou-Utso-Byou in Kanji in SHIFT-JIS + $this->assertSame(Mode::BYTE, $this->methods['chooseMode']->invoke(null, "\xe\x4\x9\x5\x9\x61")->get()); + } + + public function testEncode() + { + $qrCode = Encoder::encode('ABCDEF', new ErrorCorrectionLevel(ErrorCorrectionLevel::H)); + $expected = "<<\n" + . " mode: ALPHANUMERIC\n" + . " ecLevel: H\n" + . " version: 1\n" + . " maskPattern: 0\n" + . " matrix:\n" + . " 1 1 1 1 1 1 1 0 1 1 1 1 0 0 1 1 1 1 1 1 1\n" + . " 1 0 0 0 0 0 1 0 0 1 1 1 0 0 1 0 0 0 0 0 1\n" + . " 1 0 1 1 1 0 1 0 0 1 0 1 1 0 1 0 1 1 1 0 1\n" + . " 1 0 1 1 1 0 1 0 1 1 1 0 1 0 1 0 1 1 1 0 1\n" + . " 1 0 1 1 1 0 1 0 0 1 1 1 0 0 1 0 1 1 1 0 1\n" + . " 1 0 0 0 0 0 1 0 0 1 0 0 0 0 1 0 0 0 0 0 1\n" + . " 1 1 1 1 1 1 1 0 1 0 1 0 1 0 1 1 1 1 1 1 1\n" + . " 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0\n" + . " 0 0 1 0 1 1 1 0 1 1 0 0 1 1 0 0 0 1 0 0 1\n" + . " 1 0 1 1 1 0 0 1 0 0 0 1 0 1 0 0 0 0 0 0 0\n" + . " 0 0 1 1 0 0 1 0 1 0 0 0 1 0 1 0 1 0 1 1 0\n" + . " 1 1 0 1 0 1 0 1 1 1 0 1 0 1 0 0 0 0 0 1 0\n" + . " 0 0 1 1 0 1 1 1 1 0 0 0 1 0 1 0 1 1 1 1 0\n" + . " 0 0 0 0 0 0 0 0 1 0 0 1 1 1 0 1 0 1 0 0 0\n" + . " 1 1 1 1 1 1 1 0 0 0 1 0 1 0 1 1 0 0 0 0 1\n" + . " 1 0 0 0 0 0 1 0 1 1 1 1 0 1 0 1 1 1 1 0 1\n" + . " 1 0 1 1 1 0 1 0 1 0 1 1 0 1 0 1 0 0 0 0 1\n" + . " 1 0 1 1 1 0 1 0 0 1 1 0 1 1 1 1 0 1 0 1 0\n" + . " 1 0 1 1 1 0 1 0 1 0 0 0 1 0 1 0 1 1 1 0 1\n" + . " 1 0 0 0 0 0 1 0 0 1 1 0 1 1 0 1 0 0 0 1 1\n" + . " 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 1 0 1 0 1\n" + . ">>\n"; + + $this->assertEquals($expected, $qrCode->__toString()); + } + + public function testSimpleUtf8Eci() + { + $qrCode = Encoder::encode('hello', new ErrorCorrectionLevel(ErrorCorrectionLevel::H), 'utf-8'); + $expected = "<<\n" + . " mode: BYTE\n" + . " ecLevel: H\n" + . " version: 1\n" + . " maskPattern: 3\n" + . " matrix:\n" + . " 1 1 1 1 1 1 1 0 0 0 0 0 0 0 1 1 1 1 1 1 1\n" + . " 1 0 0 0 0 0 1 0 0 0 1 0 1 0 1 0 0 0 0 0 1\n" + . " 1 0 1 1 1 0 1 0 0 1 0 1 0 0 1 0 1 1 1 0 1\n" + . " 1 0 1 1 1 0 1 0 0 1 1 0 1 0 1 0 1 1 1 0 1\n" + . " 1 0 1 1 1 0 1 0 1 0 1 0 1 0 1 0 1 1 1 0 1\n" + . " 1 0 0 0 0 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1\n" + . " 1 1 1 1 1 1 1 0 1 0 1 0 1 0 1 1 1 1 1 1 1\n" + . " 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0\n" + . " 0 0 1 1 0 0 1 1 1 1 0 0 0 1 1 0 1 0 0 0 0\n" + . " 0 0 1 1 1 0 0 0 0 0 1 1 0 0 0 1 0 1 1 1 0\n" + . " 0 1 0 1 0 1 1 1 0 1 0 1 0 0 0 0 0 1 1 1 1\n" + . " 1 1 0 0 1 0 0 1 1 0 0 1 1 1 1 0 1 0 1 1 0\n" + . " 0 0 0 0 1 0 1 1 1 1 0 0 0 0 0 1 0 0 1 0 0\n" + . " 0 0 0 0 0 0 0 0 1 1 1 1 0 0 1 1 1 0 0 0 1\n" + . " 1 1 1 1 1 1 1 0 1 1 1 0 1 0 1 1 0 0 1 0 0\n" + . " 1 0 0 0 0 0 1 0 0 0 1 0 0 1 1 1 1 1 1 0 1\n" + . " 1 0 1 1 1 0 1 0 0 1 0 0 0 0 1 1 0 0 0 0 0\n" + . " 1 0 1 1 1 0 1 0 1 1 1 0 1 0 0 0 1 1 0 0 0\n" + . " 1 0 1 1 1 0 1 0 1 1 0 0 0 1 0 0 1 0 0 0 0\n" + . " 1 0 0 0 0 0 1 0 0 0 0 1 1 0 1 0 1 0 1 1 0\n" + . " 1 1 1 1 1 1 1 0 0 1 0 1 1 1 0 1 1 0 0 0 0\n" + . ">>\n"; + + $this->assertEquals($expected, $qrCode->__toString()); + } + + public function testAppendModeInfo() + { + $bits = new BitArray(); + $this->methods['appendModeInfo']->invoke(null, new Mode(Mode::NUMERIC), $bits); + $this->assertEquals(' ...X', $bits->__toString()); + } + + public function testAppendLengthInfo() + { + // 1 letter (1/1), 10 bits. + $bits = new BitArray(); + $this->methods['appendLengthInfo']->invoke( + null, + 1, + Version::getVersionForNumber(1), + new Mode(Mode::NUMERIC), + $bits + ); + $this->assertEquals(' ........ .X', $bits->__toString()); + + // 2 letters (2/1), 11 bits. + $bits = new BitArray(); + $this->methods['appendLengthInfo']->invoke( + null, + 2, + Version::getVersionForNumber(10), + new Mode(Mode::ALPHANUMERIC), + $bits + ); + $this->assertEquals(' ........ .X.', $bits->__toString()); + + // 255 letters (255/1), 16 bits. + $bits = new BitArray(); + $this->methods['appendLengthInfo']->invoke( + null, + 255, + Version::getVersionForNumber(27), + new Mode(Mode::BYTE), + $bits + ); + $this->assertEquals(' ........ XXXXXXXX', $bits->__toString()); + + // 512 letters (1024/2), 12 bits. + $bits = new BitArray(); + $this->methods['appendLengthInfo']->invoke( + null, + 512, + Version::getVersionForNumber(40), + new Mode(Mode::KANJI), + $bits + ); + $this->assertEquals(' ..X..... ....', $bits->__toString()); + } + + public function testAppendBytes() + { + // Should use appendNumericBytes. + // 1 = 01 = 0001 in 4 bits. + $bits = new BitArray(); + $this->methods['appendBytes']->invoke( + null, + '1', + new Mode(Mode::NUMERIC), + $bits, + Encoder::DEFAULT_BYTE_MODE_ECODING + ); + $this->assertEquals(' ...X', $bits->__toString()); + + // Should use appendAlphaNumericBytes. + // A = 10 = 0xa = 001010 in 6 bits. + $bits = new BitArray(); + $this->methods['appendBytes']->invoke( + null, + 'A', + new Mode(Mode::ALPHANUMERIC), + $bits, + Encoder::DEFAULT_BYTE_MODE_ECODING + ); + $this->assertEquals(' ..X.X.', $bits->__toString()); + + // Should use append8BitBytes. + // 0x61, 0x62, 0x63 + $bits = new BitArray(); + $this->methods['appendBytes']->invoke( + null, + 'abc', + new Mode(Mode::BYTE), + $bits, + Encoder::DEFAULT_BYTE_MODE_ECODING + ); + $this->assertEquals(' .XX....X .XX...X. .XX...XX', $bits->__toString()); + + // Should use appendKanjiBytes. + // 0x93, 0x5f + $bits = new BitArray(); + $this->methods['appendBytes']->invoke( + null, + "\x93\x5f", + new Mode(Mode::KANJI), + $bits, + Encoder::DEFAULT_BYTE_MODE_ECODING + ); + $this->assertEquals(' .XX.XX.. XXXXX', $bits->__toString()); + + // Lower letters such as 'a' cannot be encoded in alphanumeric mode. + $this->setExpectedException( + 'BaconQrCode\Exception\WriterException', + 'Invalid alphanumeric code' + ); + $this->methods['appendBytes']->invoke( + null, + "a", + new Mode(Mode::ALPHANUMERIC), + $bits, + Encoder::DEFAULT_BYTE_MODE_ECODING + ); + } + + public function testTerminateBits() + { + $bits = new BitArray(); + $this->methods['terminateBits']->invoke(null, 0, $bits); + $this->assertEquals('', $bits->__toString()); + + $bits = new BitArray(); + $this->methods['terminateBits']->invoke(null, 1, $bits); + $this->assertEquals(' ........', $bits->__toString()); + + $bits = new BitArray(); + $bits->appendBits(0, 3); + $this->methods['terminateBits']->invoke(null, 1, $bits); + $this->assertEquals(' ........', $bits->__toString()); + + $bits = new BitArray(); + $bits->appendBits(0, 5); + $this->methods['terminateBits']->invoke(null, 1, $bits); + $this->assertEquals(' ........', $bits->__toString()); + + $bits = new BitArray(); + $bits->appendBits(0, 8); + $this->methods['terminateBits']->invoke(null, 1, $bits); + $this->assertEquals(' ........', $bits->__toString()); + + $bits = new BitArray(); + $this->methods['terminateBits']->invoke(null, 2, $bits); + $this->assertEquals(' ........ XXX.XX..', $bits->__toString()); + + $bits = new BitArray(); + $bits->appendBits(0, 1); + $this->methods['terminateBits']->invoke(null, 3, $bits); + $this->assertEquals(' ........ XXX.XX.. ...X...X', $bits->__toString()); + } + + public function testGetNumDataBytesAndNumEcBytesForBlockId() + { + // Version 1-H. + list($numDataBytes, $numEcBytes) = $this->methods['getNumDataBytesAndNumEcBytesForBlockId']->invoke(null, 26, 9, 1, 0); + $this->assertEquals(9, $numDataBytes); + $this->assertEquals(17, $numEcBytes); + + // Version 3-H. 2 blocks. + list($numDataBytes, $numEcBytes) = $this->methods['getNumDataBytesAndNumEcBytesForBlockId']->invoke(null, 70, 26, 2, 0); + $this->assertEquals(13, $numDataBytes); + $this->assertEquals(22, $numEcBytes); + list($numDataBytes, $numEcBytes) = $this->methods['getNumDataBytesAndNumEcBytesForBlockId']->invoke(null, 70, 26, 2, 1); + $this->assertEquals(13, $numDataBytes); + $this->assertEquals(22, $numEcBytes); + + // Version 7-H. (4 + 1) blocks. + list($numDataBytes, $numEcBytes) = $this->methods['getNumDataBytesAndNumEcBytesForBlockId']->invoke(null, 196, 66, 5, 0); + $this->assertEquals(13, $numDataBytes); + $this->assertEquals(26, $numEcBytes); + list($numDataBytes, $numEcBytes) = $this->methods['getNumDataBytesAndNumEcBytesForBlockId']->invoke(null, 196, 66, 5, 4); + $this->assertEquals(14, $numDataBytes); + $this->assertEquals(26, $numEcBytes); + + // Version 40-H. (20 + 61) blocks. + list($numDataBytes, $numEcBytes) = $this->methods['getNumDataBytesAndNumEcBytesForBlockId']->invoke(null, 3706, 1276, 81, 0); + $this->assertEquals(15, $numDataBytes); + $this->assertEquals(30, $numEcBytes); + list($numDataBytes, $numEcBytes) = $this->methods['getNumDataBytesAndNumEcBytesForBlockId']->invoke(null, 3706, 1276, 81, 20); + $this->assertEquals(16, $numDataBytes); + $this->assertEquals(30, $numEcBytes); + list($numDataBytes, $numEcBytes) = $this->methods['getNumDataBytesAndNumEcBytesForBlockId']->invoke(null, 3706, 1276, 81, 80); + $this->assertEquals(16, $numDataBytes); + $this->assertEquals(30, $numEcBytes); + } + + public function testInterleaveWithEcBytes() + { + $dataBytes = SplFixedArray::fromArray(array(32, 65, 205, 69, 41, 220, 46, 128, 236), false); + $in = new BitArray(); + + foreach ($dataBytes as $dataByte) { + $in->appendBits($dataByte, 8); + } + + $outBits = $this->methods['interleaveWithEcBytes']->invoke(null, $in, 26, 9, 1); + $expected = SplFixedArray::fromArray(array( + // Data bytes. + 32, 65, 205, 69, 41, 220, 46, 128, 236, + // Error correction bytes. + 42, 159, 74, 221, 244, 169, 239, 150, 138, 70, 237, 85, 224, 96, 74, 219, 61, + ), false); + + $out = $outBits->toBytes(0, count($expected)); + + $this->assertEquals($expected, $out); + } + + public function testAppendNumericBytes() + { + // 1 = 01 = 0001 in 4 bits. + $bits = new BitArray(); + $this->methods['appendNumericBytes']->invoke(null, '1', $bits); + $this->assertEquals(' ...X', $bits->__toString()); + + // 12 = 0xc = 0001100 in 7 bits. + $bits = new BitArray(); + $this->methods['appendNumericBytes']->invoke(null, '12', $bits); + $this->assertEquals(' ...XX..', $bits->__toString()); + + // 123 = 0x7b = 0001111011 in 10 bits. + $bits = new BitArray(); + $this->methods['appendNumericBytes']->invoke(null, '123', $bits); + $this->assertEquals(' ...XXXX. XX', $bits->__toString()); + + // 1234 = "123" + "4" = 0001111011 + 0100 in 14 bits. + $bits = new BitArray(); + $this->methods['appendNumericBytes']->invoke(null, '1234', $bits); + $this->assertEquals(' ...XXXX. XX.X..', $bits->__toString()); + + // Empty + $bits = new BitArray(); + $this->methods['appendNumericBytes']->invoke(null, '', $bits); + $this->assertEquals('', $bits->__toString()); + } + + public function testAppendAlphanumericBytes() + { + $bits = new BitArray(); + $this->methods['appendAlphanumericBytes']->invoke(null, 'A', $bits); + $this->assertEquals(' ..X.X.', $bits->__toString()); + + $bits = new BitArray(); + $this->methods['appendAlphanumericBytes']->invoke(null, 'AB', $bits); + $this->assertEquals(' ..XXX..X X.X', $bits->__toString()); + + $bits = new BitArray(); + $this->methods['appendAlphanumericBytes']->invoke(null, 'ABC', $bits); + $this->assertEquals(' ..XXX..X X.X..XX. .', $bits->__toString()); + + // Empty + $bits = new BitArray(); + $this->methods['appendAlphanumericBytes']->invoke(null, '', $bits); + $this->assertEquals('', $bits->__toString()); + + // Invalid data + $this->setExpectedException('BaconQrCode\Exception\WriterException', 'Invalid alphanumeric code'); + $bits = new BitArray(); + $this->methods['appendAlphanumericBytes']->invoke(null, 'abc', $bits); + } + + public function testAppend8BitBytes() + { + // 0x61, 0x62, 0x63 + $bits = new BitArray(); + $this->methods['append8BitBytes']->invoke(null, 'abc', $bits, Encoder::DEFAULT_BYTE_MODE_ECODING); + $this->assertEquals(' .XX....X .XX...X. .XX...XX', $bits->__toString()); + + // Empty + $bits = new BitArray(); + $this->methods['append8BitBytes']->invoke(null, '', $bits, Encoder::DEFAULT_BYTE_MODE_ECODING); + $this->assertEquals('', $bits->__toString()); + } + + public function testAppendKanjiBytes() + { + // Numbers are from page 21 of JISX0510:2004 + $bits = new BitArray(); + $this->methods['appendKanjiBytes']->invoke(null, "\x93\x5f", $bits); + $this->assertEquals(' .XX.XX.. XXXXX', $bits->__toString()); + + $this->methods['appendKanjiBytes']->invoke(null, "\xe4\xaa", $bits); + $this->assertEquals(' .XX.XX.. XXXXXXX. X.X.X.X. X.', $bits->__toString()); + } + + public function testGenerateEcBytes() + { + // Numbers are from http://www.swetake.com/qr/qr3.html and + // http://www.swetake.com/qr/qr9.html + $dataBytes = SplFixedArray::fromArray(array(32, 65, 205, 69, 41, 220, 46, 128, 236), false); + $ecBytes = $this->methods['generateEcBytes']->invoke(null, $dataBytes, 17); + $expected = SplFixedArray::fromArray(array(42, 159, 74, 221, 244, 169, 239, 150, 138, 70, 237, 85, 224, 96, 74, 219, 61), false); + $this->assertEquals($expected, $ecBytes); + + $dataBytes = SplFixedArray::fromArray(array(67, 70, 22, 38, 54, 70, 86, 102, 118, 134, 150, 166, 182, 198, 214), false); + $ecBytes = $this->methods['generateEcBytes']->invoke(null, $dataBytes, 18); + $expected = SplFixedArray::fromArray(array(175, 80, 155, 64, 178, 45, 214, 233, 65, 209, 12, 155, 117, 31, 140, 214, 27, 187), false); + $this->assertEquals($expected, $ecBytes); + + // High-order zero coefficient case. + $dataBytes = SplFixedArray::fromArray(array(32, 49, 205, 69, 42, 20, 0, 236, 17), false); + $ecBytes = $this->methods['generateEcBytes']->invoke(null, $dataBytes, 17); + $expected = SplFixedArray::fromArray(array(0, 3, 130, 179, 194, 0, 55, 211, 110, 79, 98, 72, 170, 96, 211, 137, 213), false); + $this->assertEquals($expected, $ecBytes); + } +} \ No newline at end of file diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Encoder/MaskUtilTest.php b/user/plugins/login/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Encoder/MaskUtilTest.php new file mode 100644 index 00000000..a5c38656 --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Encoder/MaskUtilTest.php @@ -0,0 +1,281 @@ +fail('Data mask bit did not match'); + } + } + } + } + + public function testApplyMaskPenaltyRule1() + { + $matrix = new ByteMatrix(4, 1); + $matrix->set(0, 0, 0); + $matrix->set(1, 0, 0); + $matrix->set(2, 0, 0); + $matrix->set(3, 0, 0); + + $this->assertEquals(0, MaskUtil::applyMaskPenaltyRule1($matrix)); + + // Horizontal + $matrix = new ByteMatrix(6, 1); + $matrix->set(0, 0, 0); + $matrix->set(1, 0, 0); + $matrix->set(2, 0, 0); + $matrix->set(3, 0, 0); + $matrix->set(4, 0, 0); + $matrix->set(5, 0, 1); + $this->assertEquals(3, MaskUtil::applyMaskPenaltyRule1($matrix)); + $matrix->set(5, 0, 0); + $this->assertEquals(4, MaskUtil::applyMaskPenaltyRule1($matrix)); + + // Vertical + $matrix = new ByteMatrix(1, 6); + $matrix->set(0, 0, 0); + $matrix->set(0, 1, 0); + $matrix->set(0, 2, 0); + $matrix->set(0, 3, 0); + $matrix->set(0, 4, 0); + $matrix->set(0, 5, 1); + $this->assertEquals(3, MaskUtil::applyMaskPenaltyRule1($matrix)); + $matrix->set(0, 5, 0); + $this->assertEquals(4, MaskUtil::applyMaskPenaltyRule1($matrix)); + } + + public function testApplyMaskPenaltyRule2() + { + $matrix = new ByteMatrix(1, 1); + $matrix->set(0, 0, 0); + $this->assertEquals(0, MaskUtil::applyMaskPenaltyRule2($matrix)); + + $matrix = new ByteMatrix(2, 2); + $matrix->set(0, 0, 0); + $matrix->set(1, 0, 0); + $matrix->set(0, 1, 0); + $matrix->set(1, 1, 1); + $this->assertEquals(0, MaskUtil::applyMaskPenaltyRule2($matrix)); + + $matrix = new ByteMatrix(2, 2); + $matrix->set(0, 0, 0); + $matrix->set(1, 0, 0); + $matrix->set(0, 1, 0); + $matrix->set(1, 1, 0); + $this->assertEquals(3, MaskUtil::applyMaskPenaltyRule2($matrix)); + + $matrix = new ByteMatrix(3, 3); + $matrix->set(0, 0, 0); + $matrix->set(1, 0, 0); + $matrix->set(2, 0, 0); + $matrix->set(0, 1, 0); + $matrix->set(1, 1, 0); + $matrix->set(2, 1, 0); + $matrix->set(0, 2, 0); + $matrix->set(1, 2, 0); + $matrix->set(2, 2, 0); + $this->assertEquals(3 * 4, MaskUtil::applyMaskPenaltyRule2($matrix)); + } + + public function testApplyMaskPenalty3() + { + // Horizontal 00001011101 + $matrix = new ByteMatrix(11, 1); + $matrix->set(0, 0, 0); + $matrix->set(1, 0, 0); + $matrix->set(2, 0, 0); + $matrix->set(3, 0, 0); + $matrix->set(4, 0, 1); + $matrix->set(5, 0, 0); + $matrix->set(6, 0, 1); + $matrix->set(7, 0, 1); + $matrix->set(8, 0, 1); + $matrix->set(9, 0, 0); + $matrix->set(10, 0, 1); + $this->assertEquals(40, MaskUtil::applyMaskPenaltyRule3($matrix)); + + // Horizontal 10111010000 + $matrix = new ByteMatrix(11, 1); + $matrix->set(0, 0, 1); + $matrix->set(1, 0, 0); + $matrix->set(2, 0, 1); + $matrix->set(3, 0, 1); + $matrix->set(4, 0, 1); + $matrix->set(5, 0, 0); + $matrix->set(6, 0, 1); + $matrix->set(7, 0, 0); + $matrix->set(8, 0, 0); + $matrix->set(9, 0, 0); + $matrix->set(10, 0, 0); + $this->assertEquals(40, MaskUtil::applyMaskPenaltyRule3($matrix)); + + // Vertical 00001011101 + $matrix = new ByteMatrix(1, 11); + $matrix->set(0, 0, 0); + $matrix->set(0, 1, 0); + $matrix->set(0, 2, 0); + $matrix->set(0, 3, 0); + $matrix->set(0, 4, 1); + $matrix->set(0, 5, 0); + $matrix->set(0, 6, 1); + $matrix->set(0, 7, 1); + $matrix->set(0, 8, 1); + $matrix->set(0, 9, 0); + $matrix->set(0, 10, 1); + $this->assertEquals(40, MaskUtil::applyMaskPenaltyRule3($matrix)); + + // Vertical 10111010000 + $matrix = new ByteMatrix(1, 11); + $matrix->set(0, 0, 1); + $matrix->set(0, 1, 0); + $matrix->set(0, 2, 1); + $matrix->set(0, 3, 1); + $matrix->set(0, 4, 1); + $matrix->set(0, 5, 0); + $matrix->set(0, 6, 1); + $matrix->set(0, 7, 0); + $matrix->set(0, 8, 0); + $matrix->set(0, 9, 0); + $matrix->set(0, 10, 0); + $this->assertEquals(40, MaskUtil::applyMaskPenaltyRule3($matrix)); + } + + public function testApplyMaskPenaltyRule4() + { + // Dark cell ratio = 0% + $matrix = new ByteMatrix(1, 1); + $matrix->set(0, 0, 0); + $this->assertEquals(100, MaskUtil::applyMaskPenaltyRule4($matrix)); + + // Dark cell ratio = 5% + $matrix = new ByteMatrix(2, 1); + $matrix->set(0, 0, 0); + $matrix->set(0, 0, 1); + $this->assertEquals(0, MaskUtil::applyMaskPenaltyRule4($matrix)); + + // Dark cell ratio = 66.67% + $matrix = new ByteMatrix(6, 1); + $matrix->set(0, 0, 0); + $matrix->set(1, 0, 1); + $matrix->set(2, 0, 1); + $matrix->set(3, 0, 1); + $matrix->set(4, 0, 1); + $matrix->set(5, 0, 0); + $this->assertEquals(30, MaskUtil::applyMaskPenaltyRule4($matrix)); + } +} \ No newline at end of file diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Encoder/MatrixUtilTest.php b/user/plugins/login/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Encoder/MatrixUtilTest.php new file mode 100644 index 00000000..bf3544f0 --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Encoder/MatrixUtilTest.php @@ -0,0 +1,336 @@ +getMethods(ReflectionMethod::IS_STATIC) as $method) { + $method->setAccessible(true); + $this->methods[$method->getName()] = $method; + } + } + + public function testToString() + { + $matrix= new ByteMatrix(3, 3); + $matrix->set(0, 0, 0); + $matrix->set(1, 0, 1); + $matrix->set(2, 0, 0); + $matrix->set(0, 1, 1); + $matrix->set(1, 1, 0); + $matrix->set(2, 1, 1); + $matrix->set(0, 2, -1); + $matrix->set(1, 2, -1); + $matrix->set(2, 2, -1); + + $expected = " 0 1 0\n 1 0 1\n \n"; + $this->assertEquals($expected, $matrix->__toString()); + } + + public function testClearMatrix() + { + $matrix = new ByteMatrix(2, 2); + MatrixUtil::clearMatrix($matrix); + + $this->assertEquals(-1, $matrix->get(0, 0)); + $this->assertEquals(-1, $matrix->get(1, 0)); + $this->assertEquals(-1, $matrix->get(0, 1)); + $this->assertEquals(-1, $matrix->get(1, 1)); + } + + public function testEmbedBasicPatterns1() + { + $matrix = new ByteMatrix(21, 21); + MatrixUtil::clearMatrix($matrix); + $this->methods['embedBasicPatterns']->invoke( + null, + Version::getVersionForNumber(1), + $matrix + ); + $expected = " 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1\n" + . " 1 0 0 0 0 0 1 0 0 1 0 0 0 0 0 1\n" + . " 1 0 1 1 1 0 1 0 0 1 0 1 1 1 0 1\n" + . " 1 0 1 1 1 0 1 0 0 1 0 1 1 1 0 1\n" + . " 1 0 1 1 1 0 1 0 0 1 0 1 1 1 0 1\n" + . " 1 0 0 0 0 0 1 0 0 1 0 0 0 0 0 1\n" + . " 1 1 1 1 1 1 1 0 1 0 1 0 1 0 1 1 1 1 1 1 1\n" + . " 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" + . " 1 \n" + . " 0 \n" + . " 1 \n" + . " 0 \n" + . " 1 \n" + . " 0 0 0 0 0 0 0 0 1 \n" + . " 1 1 1 1 1 1 1 0 \n" + . " 1 0 0 0 0 0 1 0 \n" + . " 1 0 1 1 1 0 1 0 \n" + . " 1 0 1 1 1 0 1 0 \n" + . " 1 0 1 1 1 0 1 0 \n" + . " 1 0 0 0 0 0 1 0 \n" + . " 1 1 1 1 1 1 1 0 \n"; + + $this->assertEquals($expected, $matrix->__toString()); + } + + public function testEmbedBasicPatterns2() + { + $matrix = new ByteMatrix(25, 25); + MatrixUtil::clearMatrix($matrix); + $this->methods['embedBasicPatterns']->invoke( + null, + Version::getVersionForNumber(2), + $matrix + ); + $expected = " 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1\n" + . " 1 0 0 0 0 0 1 0 0 1 0 0 0 0 0 1\n" + . " 1 0 1 1 1 0 1 0 0 1 0 1 1 1 0 1\n" + . " 1 0 1 1 1 0 1 0 0 1 0 1 1 1 0 1\n" + . " 1 0 1 1 1 0 1 0 0 1 0 1 1 1 0 1\n" + . " 1 0 0 0 0 0 1 0 0 1 0 0 0 0 0 1\n" + . " 1 1 1 1 1 1 1 0 1 0 1 0 1 0 1 0 1 0 1 1 1 1 1 1 1\n" + . " 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" + . " 1 \n" + . " 0 \n" + . " 1 \n" + . " 0 \n" + . " 1 \n" + . " 0 \n" + . " 1 \n" + . " 0 \n" + . " 1 1 1 1 1 1 \n" + . " 0 0 0 0 0 0 0 0 1 1 0 0 0 1 \n" + . " 1 1 1 1 1 1 1 0 1 0 1 0 1 \n" + . " 1 0 0 0 0 0 1 0 1 0 0 0 1 \n" + . " 1 0 1 1 1 0 1 0 1 1 1 1 1 \n" + . " 1 0 1 1 1 0 1 0 \n" + . " 1 0 1 1 1 0 1 0 \n" + . " 1 0 0 0 0 0 1 0 \n" + . " 1 1 1 1 1 1 1 0 \n"; + + $this->assertEquals($expected, $matrix->__toString()); + } + + public function testEmbedTypeInfo() + { + $matrix = new ByteMatrix(21, 21); + MatrixUtil::clearMatrix($matrix); + $this->methods['embedTypeInfo']->invoke( + null, + new ErrorCorrectionLevel(ErrorCorrectionLevel::M), + 5, + $matrix + ); + $expected = " 0 \n" + . " 1 \n" + . " 1 \n" + . " 1 \n" + . " 0 \n" + . " 0 \n" + . " \n" + . " 1 \n" + . " 1 0 0 0 0 0 0 1 1 1 0 0 1 1 1 0\n" + . " \n" + . " \n" + . " \n" + . " \n" + . " \n" + . " 0 \n" + . " 0 \n" + . " 0 \n" + . " 0 \n" + . " 0 \n" + . " 0 \n" + . " 1 \n"; + + $this->assertEquals($expected, $matrix->__toString()); + } + + public function testEmbedVersionInfo() + { + $matrix = new ByteMatrix(21, 21); + MatrixUtil::clearMatrix($matrix); + $this->methods['maybeEmbedVersionInfo']->invoke( + null, + Version::getVersionForNumber(7), + $matrix + ); + $expected = " 0 0 1 \n" + . " 0 1 0 \n" + . " 0 1 0 \n" + . " 0 1 1 \n" + . " 1 1 1 \n" + . " 0 0 0 \n" + . " \n" + . " \n" + . " \n" + . " \n" + . " 0 0 0 0 1 0 \n" + . " 0 1 1 1 1 0 \n" + . " 1 0 0 1 1 0 \n" + . " \n" + . " \n" + . " \n" + . " \n" + . " \n" + . " \n" + . " \n" + . " \n"; + + $this->assertEquals($expected, $matrix->__toString()); + } + + public function testEmbedDataBits() + { + $matrix = new ByteMatrix(21, 21); + MatrixUtil::clearMatrix($matrix); + $this->methods['embedBasicPatterns']->invoke( + null, + Version::getVersionForNumber(1), + $matrix + ); + + $bits = new BitArray(); + $this->methods['embedDataBits']->invoke( + null, + $bits, + -1, + $matrix + ); + + $expected = " 1 1 1 1 1 1 1 0 0 0 0 0 0 0 1 1 1 1 1 1 1\n" + . " 1 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 1\n" + . " 1 0 1 1 1 0 1 0 0 0 0 0 0 0 1 0 1 1 1 0 1\n" + . " 1 0 1 1 1 0 1 0 0 0 0 0 0 0 1 0 1 1 1 0 1\n" + . " 1 0 1 1 1 0 1 0 0 0 0 0 0 0 1 0 1 1 1 0 1\n" + . " 1 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 1\n" + . " 1 1 1 1 1 1 1 0 1 0 1 0 1 0 1 1 1 1 1 1 1\n" + . " 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" + . " 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" + . " 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" + . " 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" + . " 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" + . " 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" + . " 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0\n" + . " 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" + . " 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" + . " 1 0 1 1 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" + . " 1 0 1 1 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" + . " 1 0 1 1 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" + . " 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" + . " 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n"; + + $this->assertEquals($expected, $matrix->__toString()); + } + + public function testBuildMatrix() + { + $bytes = array( + 32, 65, 205, 69, 41, 220, 46, 128, 236, 42, 159, 74, 221, 244, 169, + 239, 150, 138, 70, 237, 85, 224, 96, 74, 219 , 61 + ); + $bits = new BitArray(); + + foreach ($bytes as $byte) { + $bits->appendBits($byte, 8); + } + + $matrix = new ByteMatrix(21, 21); + MatrixUtil::buildMatrix( + $bits, + new ErrorCorrectionLevel(ErrorCorrectionLevel::H), + Version::getVersionForNumber(1), + 3, + $matrix + ); + + $expected = " 1 1 1 1 1 1 1 0 0 1 1 0 0 0 1 1 1 1 1 1 1\n" + . " 1 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 1\n" + . " 1 0 1 1 1 0 1 0 0 0 0 1 0 0 1 0 1 1 1 0 1\n" + . " 1 0 1 1 1 0 1 0 0 1 1 0 0 0 1 0 1 1 1 0 1\n" + . " 1 0 1 1 1 0 1 0 1 1 0 0 1 0 1 0 1 1 1 0 1\n" + . " 1 0 0 0 0 0 1 0 0 0 1 1 1 0 1 0 0 0 0 0 1\n" + . " 1 1 1 1 1 1 1 0 1 0 1 0 1 0 1 1 1 1 1 1 1\n" + . " 0 0 0 0 0 0 0 0 1 1 0 1 1 0 0 0 0 0 0 0 0\n" + . " 0 0 1 1 0 0 1 1 1 0 0 1 1 1 1 0 1 0 0 0 0\n" + . " 1 0 1 0 1 0 0 0 0 0 1 1 1 0 0 1 0 1 1 1 0\n" + . " 1 1 1 1 0 1 1 0 1 0 1 1 1 0 0 1 1 1 0 1 0\n" + . " 1 0 1 0 1 1 0 1 1 1 0 0 1 1 1 0 0 1 0 1 0\n" + . " 0 0 1 0 0 1 1 1 0 0 0 0 0 0 1 0 1 1 1 1 1\n" + . " 0 0 0 0 0 0 0 0 1 1 0 1 0 0 0 0 0 1 0 1 1\n" + . " 1 1 1 1 1 1 1 0 1 1 1 1 0 0 0 0 1 0 1 1 0\n" + . " 1 0 0 0 0 0 1 0 0 0 0 1 0 1 1 1 0 0 0 0 0\n" + . " 1 0 1 1 1 0 1 0 0 1 0 0 1 1 0 0 1 0 0 1 1\n" + . " 1 0 1 1 1 0 1 0 1 1 0 1 0 0 0 0 0 1 1 1 0\n" + . " 1 0 1 1 1 0 1 0 1 1 1 1 0 0 0 0 1 1 1 0 0\n" + . " 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 1 0 0\n" + . " 1 1 1 1 1 1 1 0 0 0 1 1 1 1 1 0 1 0 0 1 0\n"; + + $this->assertEquals($expected, $matrix->__toString()); + } + + public function testFindMsbSet() + { + $this->assertEquals(0, $this->methods['findMsbSet']->invoke(null, 0)); + $this->assertEquals(1, $this->methods['findMsbSet']->invoke(null, 1)); + $this->assertEquals(8, $this->methods['findMsbSet']->invoke(null, 0x80)); + $this->assertEquals(32, $this->methods['findMsbSet']->invoke(null, 0x80000000)); + } + + public function testCalculateBchCode() + { + // Encoding of type information. + // From Appendix C in JISX0510:2004 (p 65) + $this->assertEquals(0xdc, $this->methods['calculateBchCode']->invoke(null, 5, 0x537)); + // From http://www.swetake.com/qr/qr6.html + $this->assertEquals(0x1c2, $this->methods['calculateBchCode']->invoke(null, 0x13, 0x537)); + // From http://www.swetake.com/qr/qr11.html + $this->assertEquals(0x214, $this->methods['calculateBchCode']->invoke(null, 0x1b, 0x537)); + + // Encoding of version information. + // From Appendix D in JISX0510:2004 (p 68) + $this->assertEquals(0xc94, $this->methods['calculateBchCode']->invoke(null, 7, 0x1f25)); + $this->assertEquals(0x5bc, $this->methods['calculateBchCode']->invoke(null, 8, 0x1f25)); + $this->assertEquals(0xa99, $this->methods['calculateBchCode']->invoke(null, 9, 0x1f25)); + $this->assertEquals(0x4d3, $this->methods['calculateBchCode']->invoke(null, 10, 0x1f25)); + $this->assertEquals(0x9a6, $this->methods['calculateBchCode']->invoke(null, 20, 0x1f25)); + $this->assertEquals(0xd75, $this->methods['calculateBchCode']->invoke(null, 30, 0x1f25)); + $this->assertEquals(0xc69, $this->methods['calculateBchCode']->invoke(null, 40, 0x1f25)); + } + + public function testMakeVersionInfoBits() + { + // From Appendix D in JISX0510:2004 (p 68) + $bits = new BitArray(); + $this->methods['makeVersionInfoBits']->invoke(null, Version::getVersionForNumber(7), $bits); + $this->assertEquals(' ...XXXXX ..X..X.X ..', $bits->__toString()); + } + + public function testMakeTypeInfoBits() + { + // From Appendix D in JISX0510:2004 (p 68) + $bits = new BitArray(); + $this->methods['makeTypeInfoBits']->invoke(null, new ErrorCorrectionLevel(ErrorCorrectionLevel::M), 5, $bits); + $this->assertEquals(' X......X X..XXX.', $bits->__toString()); + } +} \ No newline at end of file diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Renderer/Text/HtmlTest.php b/user/plugins/login/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Renderer/Text/HtmlTest.php new file mode 100644 index 00000000..0c69dd2e --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Renderer/Text/HtmlTest.php @@ -0,0 +1,99 @@ +renderer = new Html(); + $this->writer = new Writer($this->renderer); + } + + public function testBasicRender() + { + $content = 'foobar'; + $expected = + '
                                                            ' .
                                                            +            "                       \n" .
                                                            +            " ███████ █████ ███████ \n" .
                                                            +            " █     █  █ █  █     █ \n" .
                                                            +            " █ ███ █  ██   █ ███ █ \n" .
                                                            +            " █ ███ █  ███  █ ███ █ \n" .
                                                            +            " █ ███ █   █ █ █ ███ █ \n" .
                                                            +            " █     █    ██ █     █ \n" .
                                                            +            " ███████ █ █ █ ███████ \n" .
                                                            +            "         █████         \n" .
                                                            +            " ██ ██ █  ██ █ █     █ \n" .
                                                            +            "    ██    ██ █ █ ██    \n" .
                                                            +            "  ████████ █  ██ █  ██ \n" .
                                                            +            "           ██      █ █ \n" .
                                                            +            "  ██  ███  █   █  █  █ \n" .
                                                            +            "         █ ███    █ █  \n" .
                                                            +            " ███████  ██ ██████    \n" .
                                                            +            " █     █   ████   ██   \n" .
                                                            +            " █ ███ █ ██ ██ ██ █ ██ \n" .
                                                            +            " █ ███ █ ██ ██  █ ██   \n" .
                                                            +            " █ ███ █   █   █ ██ ██ \n" .
                                                            +            " █     █ ███  ███ ████ \n" .
                                                            +            " ███████ ████   ██     \n" .
                                                            +            "                       \n" .
                                                            +            '
                                                            ' + ; + + $qrCode = Encoder::encode( + $content, + new ErrorCorrectionLevel(ErrorCorrectionLevel::L), + Encoder::DEFAULT_BYTE_MODE_ECODING + ); + $this->assertEquals($expected, $this->renderer->render($qrCode)); + } + + public function testSetStyle() + { + $content = 'foobar'; + $qrCode = Encoder::encode( + $content, + new ErrorCorrectionLevel(ErrorCorrectionLevel::L), + Encoder::DEFAULT_BYTE_MODE_ECODING + ); + $this->renderer->setStyle('bar'); + $this->assertEquals('bar', $this->renderer->getStyle()); + $this->assertStringMatchesFormat('%astyle="bar"%a', $this->renderer->render($qrCode)); + } + + public function testSetClass() + { + $content = 'foobar'; + $qrCode = Encoder::encode( + $content, + new ErrorCorrectionLevel(ErrorCorrectionLevel::L), + Encoder::DEFAULT_BYTE_MODE_ECODING + ); + $this->renderer->setClass('bar'); + $this->assertEquals('bar', $this->renderer->getClass()); + $this->assertStringMatchesFormat('%aclass="bar"%a', $this->renderer->render($qrCode)); + } +} diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Renderer/Text/TextTest.php b/user/plugins/login/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Renderer/Text/TextTest.php new file mode 100644 index 00000000..d94e8e5d --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Renderer/Text/TextTest.php @@ -0,0 +1,149 @@ +renderer = new Plain(); + $this->writer = new Writer($this->renderer); + } + + public function testBasicRender() + { + $content = 'foobar'; + $expected = + " \n" . + " ███████ █████ ███████ \n" . + " █ █ █ █ █ █ \n" . + " █ ███ █ ██ █ ███ █ \n" . + " █ ███ █ ███ █ ███ █ \n" . + " █ ███ █ █ █ █ ███ █ \n" . + " █ █ ██ █ █ \n" . + " ███████ █ █ █ ███████ \n" . + " █████ \n" . + " ██ ██ █ ██ █ █ █ \n" . + " ██ ██ █ █ ██ \n" . + " ████████ █ ██ █ ██ \n" . + " ██ █ █ \n" . + " ██ ███ █ █ █ █ \n" . + " █ ███ █ █ \n" . + " ███████ ██ ██████ \n" . + " █ █ ████ ██ \n" . + " █ ███ █ ██ ██ ██ █ ██ \n" . + " █ ███ █ ██ ██ █ ██ \n" . + " █ ███ █ █ █ ██ ██ \n" . + " █ █ ███ ███ ████ \n" . + " ███████ ████ ██ \n" . + " \n" + ; + + $qrCode = Encoder::encode( + $content, + new ErrorCorrectionLevel(ErrorCorrectionLevel::L), + Encoder::DEFAULT_BYTE_MODE_ECODING + ); + $this->assertEquals($expected, $this->renderer->render($qrCode)); + } + + public function testBasicRenderNoMargins() + { + $content = 'foobar'; + $expected = + "███████ █████ ███████\n" . + "█ █ █ █ █ █\n" . + "█ ███ █ ██ █ ███ █\n" . + "█ ███ █ ███ █ ███ █\n" . + "█ ███ █ █ █ █ ███ █\n" . + "█ █ ██ █ █\n" . + "███████ █ █ █ ███████\n" . + " █████ \n" . + "██ ██ █ ██ █ █ █\n" . + " ██ ██ █ █ ██ \n" . + " ████████ █ ██ █ ██\n" . + " ██ █ █\n" . + " ██ ███ █ █ █ █\n" . + " █ ███ █ █ \n" . + "███████ ██ ██████ \n" . + "█ █ ████ ██ \n" . + "█ ███ █ ██ ██ ██ █ ██\n" . + "█ ███ █ ██ ██ █ ██ \n" . + "█ ███ █ █ █ ██ ██\n" . + "█ █ ███ ███ ████\n" . + "███████ ████ ██ \n" + ; + + $qrCode = Encoder::encode( + $content, + new ErrorCorrectionLevel(ErrorCorrectionLevel::L), + Encoder::DEFAULT_BYTE_MODE_ECODING + ); + $this->renderer->setMargin(0); + $this->assertEquals(0, $this->renderer->getMargin()); + $this->assertEquals($expected, $this->renderer->render($qrCode)); + } + + public function testBasicRenderCustomChar() + { + $content = 'foobar'; + $expected = + "-----------------------\n" . + "-#######-#####-#######-\n" . + "-#-----#--#-#--#-----#-\n" . + "-#-###-#--##---#-###-#-\n" . + "-#-###-#--###--#-###-#-\n" . + "-#-###-#---#-#-#-###-#-\n" . + "-#-----#----##-#-----#-\n" . + "-#######-#-#-#-#######-\n" . + "---------#####---------\n" . + "-##-##-#--##-#-#-----#-\n" . + "----##----##-#-#-##----\n" . + "--########-#--##-#--##-\n" . + "-----------##------#-#-\n" . + "--##--###--#---#--#--#-\n" . + "---------#-###----#-#--\n" . + "-#######--##-######----\n" . + "-#-----#---####---##---\n" . + "-#-###-#-##-##-##-#-##-\n" . + "-#-###-#-##-##--#-##---\n" . + "-#-###-#---#---#-##-##-\n" . + "-#-----#-###--###-####-\n" . + "-#######-####---##-----\n" . + "-----------------------\n" + ; + + $qrCode = Encoder::encode( + $content, + new ErrorCorrectionLevel(ErrorCorrectionLevel::L), + Encoder::DEFAULT_BYTE_MODE_ECODING + ); + $this->renderer->setFullBlock('#'); + $this->renderer->setEmptyBlock('-'); + $this->assertEquals('#', $this->renderer->getFullBlock()); + $this->assertEquals('-', $this->renderer->getEmptyBlock()); + $this->assertEquals($expected, $this->renderer->render($qrCode)); + } +} diff --git a/user/plugins/login/vendor/bacon/bacon-qr-code/tests/bootstrap.php b/user/plugins/login/vendor/bacon/bacon-qr-code/tests/bootstrap.php new file mode 100644 index 00000000..05a49415 --- /dev/null +++ b/user/plugins/login/vendor/bacon/bacon-qr-code/tests/bootstrap.php @@ -0,0 +1,10 @@ + + + + . + + + + ../src/ + + + diff --git a/user/plugins/login/vendor/birke/rememberme/LICENSE b/user/plugins/login/vendor/birke/rememberme/LICENSE new file mode 100644 index 00000000..51bca9f4 --- /dev/null +++ b/user/plugins/login/vendor/birke/rememberme/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014 by Gabriel Birke + +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. \ No newline at end of file diff --git a/user/plugins/login/vendor/birke/rememberme/README.md b/user/plugins/login/vendor/birke/rememberme/README.md new file mode 100644 index 00000000..4769e1f2 --- /dev/null +++ b/user/plugins/login/vendor/birke/rememberme/README.md @@ -0,0 +1,40 @@ +# Secure "Remember Me" +This library implements the best practices for implementing a secure +"Remember Me" functionality on web sites. Login information and unique secure +tokens are stored in a cookie. If the user visits the site, the login information +from the cookie is compared to information stored on the server. If the tokens +match, the user is logged in. A user can have login cookies on several +computers/browsers. + +This library is heavily inspired by Barry Jaspan's article +"[Improved Persistent Login Cookie Best Practice][1]". The library protects +against the following attack scenarios: + + - The computer of a user is stolen or compromised, enabling the attacker to log + in with the existing "Remember Me" cookie. The user knows this has happened. + The user can remotely invalidate all login cookies. + - An attacker has obtained the "Remember Me" cookie and has logged in with it. + The user does not know this. The next time he tries to log in with the cookie + that was stolen, he gets a warning and all login cookies are invalidated. + - An attacker has obtained the database of login tokens from the server. The + stored tokens are hashed so he can't use them without computational effort + (rainbow tables or brute force). + +## Installation + + composer require birke/rememberme + +## Usage example +See the `example` directory for an example. + +## Improving security +The generated tokens are pseudo-random and the storage classes use the SHA1 algorithm +to hash them. If you need better security than that, overwrite the +`Authenticator::generateToken` method to generate a truly random token. If you are +using PHP >=5.5 you can use the "[password_hash][2]" and "[password_verify][3]" functions. +On lower PHP versions you could use the [userland implementations][4] of these functions. + +[1]: http://jaspan.com/improved%5Fpersistent%5Flogin%5Fcookie%5Fbest%5Fpractice +[2]: http://www.php.net/manual/en/function.password-hash.php +[3]: http://www.php.net/manual/en/function.password-verify.php +[4]: https://github.com/ircmaxell/password_compat diff --git a/user/plugins/login/vendor/birke/rememberme/composer.json b/user/plugins/login/vendor/birke/rememberme/composer.json new file mode 100644 index 00000000..d05a6d5e --- /dev/null +++ b/user/plugins/login/vendor/birke/rememberme/composer.json @@ -0,0 +1,24 @@ +{ + "name": "birke/rememberme", + "version": "1.0.5", + "description": "Secure \"Remember Me\" functionality", + "keywords": [ "cookie", "remember", "security"], + "homepage": "https://github.com/gbirke/rememberme", + "license": "MIT", + "authors": [ + { + "name": "Gabriel Birke", + "email": "gb@birke-software.de" + } + ], + "minimum-stability": "stable", + "autoload": { + "psr-4": {"Birke\\": "src/"} + }, + "require": { + "paragonie/random_compat": "^1.1.4" + }, + "require-dev": { + "phpunit/phpunit": "4.*" + } +} diff --git a/user/plugins/login/vendor/birke/rememberme/example/action.php b/user/plugins/login/vendor/birke/rememberme/example/action.php new file mode 100644 index 00000000..0a7ea94a --- /dev/null +++ b/user/plugins/login/vendor/birke/rememberme/example/action.php @@ -0,0 +1,119 @@ +clearCookie($_SESSION['username']); + redirect(true); + } + + if(!empty($_GET['completelogout'])) { + $storage->cleanAllTriplets($_SESSION['username']); + redirect(true); + } + + // Check, if the Rememberme cookie exists and is still valid. + // If not, we log out the current session + if(!empty($_COOKIE[$rememberMe->getCookieName()]) && !$rememberMe->cookieIsValid()) { + redirect(true); + } + + // User is still logged in - show content + $content = tpl("user_is_logged_in"); +} +// If we are not logged in, try to log in via Rememberme cookie +else { + // If we can present the correct tokens from the cookie, we are logged in + $loginresult = $rememberMe->login(); + if($loginresult) { + $_SESSION['username'] = $loginresult; + // There is a chance that an attacker has stolen the login token, so we store + // the fact that the user was logged in via RememberMe (instead of login form) + $_SESSION['remembered_by_cookie'] = true; + redirect(); + } + else { + // If $rememberMe returned false, check if the token was invalid + if($rememberMe->loginTokenWasInvalid()) { + $content = tpl("cookie_was_stolen"); + } + // $rememberMe returned false because of invalid/missing Rememberme cookie - normal login process + else { + if(!empty($_POST)) { + if($username == $_POST['username'] && $password == $_POST['password']) { + session_regenerate_id(); + $_SESSION['username'] = $username; + // If the user wants to be remembered, create Rememberme cookie + if(!empty($_POST['rememberme'])) { + $rememberMe->createCookie($username); + } + else { + $rememberMe->clearCookie(); + } + redirect(); + } + else { + $content = tpl("login", "Invalid credentials"); + } + } + else { + $content = tpl("login"); + } + } + } +} + +// template function for including content, nothing interesting +function tpl($template, $msg="") { + $fn = __DIR__ . DIRECTORY_SEPARATOR . "templates" . DIRECTORY_SEPARATOR . $template . ".php"; + if(file_exists($fn)) { + ob_start(); + include $fn; + return ob_get_clean(); + } + else { + return "Template $fn not found"; + } +} \ No newline at end of file diff --git a/user/plugins/login/vendor/birke/rememberme/example/css/style.css b/user/plugins/login/vendor/birke/rememberme/example/css/style.css new file mode 100644 index 00000000..ded83714 --- /dev/null +++ b/user/plugins/login/vendor/birke/rememberme/example/css/style.css @@ -0,0 +1,157 @@ +/* HTML5 ✰ Boilerplate */ + +html, body, div, span, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, +abbr, address, cite, code, del, dfn, em, img, ins, kbd, q, samp, +small, strong, sub, sup, var, b, i, dl, dt, dd, ol, ul, li, +fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, +article, aside, canvas, details, figcaption, figure, footer, header, hgroup, +menu, nav, section, summary, time, mark, audio, video { + margin:0; + padding:0; + border:0; + outline:0; + font-size:100%; + vertical-align:baseline; + background:transparent; +} +article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section { + display:block; +} +nav ul { list-style:none; } +blockquote, q { quotes:none; } +blockquote:before, blockquote:after, +q:before, q:after { content:''; content:none; } +a { margin:0; padding:0; font-size:100%; vertical-align:baseline; background:transparent; } +ins { background-color:#ff9; color:#000; text-decoration:none; } +mark { background-color:#ff9; color:#000; font-style:italic; font-weight:bold; } +del { text-decoration: line-through; } +abbr[title], dfn[title] { border-bottom:1px dotted; cursor:help; } +table { border-collapse:collapse; border-spacing:0; } +hr { display:block; height:1px; border:0; border-top:1px solid #ccc; margin:1em 0; padding:0; } +input, select { vertical-align:middle; } + + +body { font:13px/1.231 sans-serif; *font-size:small; } +select, input, textarea, button { font:99% sans-serif; } +pre, code, kbd, samp { font-family: monospace, sans-serif; } + +body, select, input, textarea { color: #444; } +h1,h2,h3,h4,h5,h6 { font-weight: bold; } +html { overflow-y: scroll; } + +a:hover, a:active { outline: none; } +a, a:active, a:visited { color: #607890; } +a:hover { color: #036; } + +ul, ol { margin-left: 1.8em; } +ol { list-style-type: decimal; } + +nav ul, nav li { margin: 0; } +small { font-size: 85%; } +strong, th { font-weight: bold; } +td, td img { vertical-align: top; } +sub { vertical-align: sub; font-size: smaller; } +sup { vertical-align: super; font-size: smaller; } +pre { padding: 15px; white-space: pre; white-space: pre-wrap; white-space: pre-line; word-wrap: break-word; } +textarea { overflow: auto; } +.ie6 legend, .ie7 legend { margin-left: -7px; } +input[type="radio"] { vertical-align: text-bottom; } +input[type="checkbox"] { vertical-align: bottom; } +.ie7 input[type="checkbox"] { vertical-align: baseline; } +.ie6 input { vertical-align: text-bottom; } +label, input[type=button], input[type=submit], button { cursor: pointer; } +button, input, select, textarea { margin: 0; } +input:valid, textarea:valid { } +input:invalid, textarea:invalid { border-radius: 1px; -moz-box-shadow: 0px 0px 5px red; -webkit-box-shadow: 0px 0px 5px red; box-shadow: 0px 0px 5px red; } +.no-boxshadow input:invalid, +.no-boxshadow textarea:invalid { background-color: #f0dddd; } + +::-moz-selection{ background: #FF5E99; color:#fff; text-shadow: none; } +::selection { background:#FF5E99; color:#fff; text-shadow: none; } +a:link { -webkit-tap-highlight-color: #FF5E99; } + +button { width: auto; overflow: visible; } +.ie7 img { -ms-interpolation-mode: bicubic; } + +.ir { display: block; text-indent: -999em; overflow: hidden; background-repeat: no-repeat; text-align: left; direction: ltr; } +.hidden { display: none; visibility: hidden; } +.visuallyhidden { position: absolute !important; clip: rect(1px 1px 1px 1px); clip: rect(1px, 1px, 1px, 1px); } +.invisible { visibility: hidden; } +.clearfix:before, .clearfix:after { content: "\0020"; display: block; height: 0; visibility: hidden; } +.clearfix:after { clear: both; } +.clearfix { zoom: 1; } + + + /* Primary Styles + Author: + */ + + +h1 { + width:800px; + margin:50px auto; + text-align:center; + font-size:200%; + font-weight:bold; +} + +#main { + width:800px; + margin:50px auto; +} + +label { + display:inline-block; + width:8em; +} + +input { + margin:5px; +} + +p { + margin-bottom:1em; +} + +ol { + margin-bottom:1em; + padding-left:1.5em; +} + + + + + + + + + + +@media all and (orientation:portrait) { + +} + +@media all and (orientation:landscape) { + +} + +@media screen and (max-device-width: 480px) { + + + /* html { -webkit-text-size-adjust:none; -ms-text-size-adjust:none; } */ +} + +@media print { + * { background: transparent !important; color: #444 !important; text-shadow: none !important; } + a, a:visited { color: #444 !important; text-decoration: underline; } + a:after { content: " (" attr(href) ")"; } + abbr:after { content: " (" attr(title) ")"; } + .ir a:after { content: ""; } + pre, blockquote { border: 1px solid #999; page-break-inside: avoid; } + thead { display: table-header-group; } + tr, img { page-break-inside: avoid; } + @page { margin: 0.5cm; } + p, h2, h3 { orphans: 3; widows: 3; } + h2, h3{ page-break-after: avoid; } +} + diff --git a/user/plugins/login/vendor/birke/rememberme/example/index.php b/user/plugins/login/vendor/birke/rememberme/example/index.php new file mode 100644 index 00000000..b79a8299 --- /dev/null +++ b/user/plugins/login/vendor/birke/rememberme/example/index.php @@ -0,0 +1,42 @@ + + + + + + + + + + + + Rememberme PHP library test + + + + + + + +
                                                            +
                                                            +

                                                            Rememberme PHP library test

                                                            +
                                                            + +
                                                            + +
                                                            + +
                                                            + +
                                                            +
                                                            + + + \ No newline at end of file diff --git a/user/plugins/login/vendor/birke/rememberme/example/templates/cookie_was_stolen.php b/user/plugins/login/vendor/birke/rememberme/example/templates/cookie_was_stolen.php new file mode 100644 index 00000000..7f2c699f --- /dev/null +++ b/user/plugins/login/vendor/birke/rememberme/example/templates/cookie_was_stolen.php @@ -0,0 +1,4 @@ +

                                                            Someone else has used your login information to acccess this page!
                                                            + All sessions were logged out.
                                                            + Please log in with your credentials and check your data.

                                                            +

                                                            To login form

                                                            \ No newline at end of file diff --git a/user/plugins/login/vendor/birke/rememberme/example/templates/login.php b/user/plugins/login/vendor/birke/rememberme/example/templates/login.php new file mode 100644 index 00000000..0d516d74 --- /dev/null +++ b/user/plugins/login/vendor/birke/rememberme/example/templates/login.php @@ -0,0 +1,14 @@ +$msg

                                                            "; ?> + +

                                                            This is the demo for logging in with the Rememberme Library.
                                                            + You are seeing this form because you have no active "Remember me" cookie and no + credentials stored in the session. +

                                                            +

                                                            Please log in with the username and password demo

                                                            + +
                                                            +
                                                            +
                                                            + Remember me
                                                            + +
                                                            \ No newline at end of file diff --git a/user/plugins/login/vendor/birke/rememberme/example/templates/user_is_logged_in.php b/user/plugins/login/vendor/birke/rememberme/example/templates/user_is_logged_in.php new file mode 100644 index 00000000..edda89a0 --- /dev/null +++ b/user/plugins/login/vendor/birke/rememberme/example/templates/user_is_logged_in.php @@ -0,0 +1,31 @@ +

                                                            You are logged in as

                                                            +

                                                            Your session ID is

                                                            + +

                                                            The remember me cookie is active. + Cookie value is

                                                            + +

                                                            The remember me cookie is not active.

                                                            + + +

                                                            You were logged in with the "Remember me" cookie. In a real application + you should ask the user for his credentials before allowing him anything + "dangerous" like changing the login information, accessing sensitive data + or making a payment.

                                                            + +

                                                            If you want to test the warning when a possible identity theft is detected, try the following steps:

                                                            +
                                                              +
                                                            1. Login to this page with a non-Firefox Browser. In the following steps I + will call that browser "Chrome" :)
                                                              + Make sure to check the "Remember me" checkbox when logging in.
                                                            2. +
                                                            3. Copy the cookie value from above into the clipboard.
                                                            4. +
                                                            5. Quit Chrome to end the session.
                                                            6. +
                                                            7. Start Firefox and install the Firecookie extension if needed.
                                                            8. +
                                                            9. Show this page. If you see this text, log out. You should see the login form.
                                                            10. +
                                                            11. Create the PHP_REMEMBERME cookie with the value you copied.
                                                            12. +
                                                            13. Refresh the page - you are now logged in and should see this text. You have stolen the login credential from Chrome!
                                                            14. +
                                                            15. Start Chrome and try to show this page - you should get a warning instead of the login dialog.
                                                            16. +
                                                            17. Refresh this page in Firefox - You are logged out.
                                                            18. +
                                                            +

                                                            Log out in this browser window.

                                                            +

                                                            Log out from all + sessions in all browser windows where the "Remember me" cookie is active.

                                                            \ No newline at end of file diff --git a/user/plugins/login/vendor/birke/rememberme/example/tokens/.gitkeep b/user/plugins/login/vendor/birke/rememberme/example/tokens/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/user/plugins/login/vendor/birke/rememberme/phpunit.xml b/user/plugins/login/vendor/birke/rememberme/phpunit.xml new file mode 100644 index 00000000..c5304c6b --- /dev/null +++ b/user/plugins/login/vendor/birke/rememberme/phpunit.xml @@ -0,0 +1,7 @@ + + + + test + + + \ No newline at end of file diff --git a/user/plugins/login/vendor/birke/rememberme/src/Rememberme/Authenticator.php b/user/plugins/login/vendor/birke/rememberme/src/Rememberme/Authenticator.php new file mode 100644 index 00000000..5a2b4b45 --- /dev/null +++ b/user/plugins/login/vendor/birke/rememberme/src/Rememberme/Authenticator.php @@ -0,0 +1,293 @@ +storage = $storage; + $this->cookie = new Cookie(); + } + + /** + * Check Credentials from cookie. Returns false if login was not successful, credential string if it was successful + * @return bool|string + */ + public function login() + { + $cookieValues = $this->getCookieValues(); + + if (!$cookieValues) { + return false; + } + + $loginResult = false; + + switch ($this->storage->findTriplet($cookieValues[0], $cookieValues[1] . $this->salt, $cookieValues[2] . $this->salt)) { + + case Storage\StorageInterface::TRIPLET_FOUND: + $expire = time() + $this->expireTime; + $newToken = $this->createToken(); + $this->storage->replaceTriplet($cookieValues[0], $newToken . $this->salt, $cookieValues[2] . $this->salt, $expire); + $this->cookie->setCookie($this->cookieName, implode("|", array($cookieValues[0], $newToken, $cookieValues[2])), $expire); + $loginResult = $cookieValues[0]; + break; + + case Storage\StorageInterface::TRIPLET_INVALID: + $this->cookie->setCookie($this->cookieName, "", time() - $this->expireTime); + $this->lastLoginTokenWasInvalid = true; + + if ($this->cleanStoredTokensOnInvalidResult) { + $this->storage->cleanAllTriplets($cookieValues[0]); + } + + break; + } + return $loginResult; + } + + /** + * @return bool + */ + public function cookieIsValid() + { + $cookieValues = $this->getCookieValues(); + + if (!$cookieValues) { + return false; + } + + $state = $this->storage->findTriplet($cookieValues[0], $cookieValues[1] . $this->salt, $cookieValues[2] . $this->salt); + return $state == Storage\StorageInterface::TRIPLET_FOUND; + } + + /** + * @param $credential + * @return $this + */ + public function createCookie($credential) + { + $newToken = $this->createToken(); + $newPersistentToken = $this->createToken(); + + $expire = time() + $this->expireTime; + + $this->storage->storeTriplet($credential, $newToken . $this->salt, $newPersistentToken . $this->salt, $expire); + $this->cookie->setCookie($this->cookieName, implode("|", array($credential, $newToken, $newPersistentToken)), $expire); + + return $this; + } + + /** + * Expire the rememberme cookie, unset $_COOKIE[$this->cookieName] value and + * remove current login triplet from storage. + * @param boolean $clearFromStorage + * @return boolean + */ + public function clearCookie($clearFromStorage = true) + { + if (empty($_COOKIE[$this->cookieName])) { + return false; + } + + $cookieValues = explode("|", $_COOKIE[$this->cookieName], 3); + + $this->cookie->setCookie($this->cookieName, "", time() - $this->expireTime); + + unset($_COOKIE[$this->cookieName]); + + if (!$clearFromStorage) { + return true; + } + + if (count($cookieValues) < 3) { + return false; + } + + $this->storage->cleanTriplet($cookieValues[0], $cookieValues[2] . $this->salt); + + return true; + } + + /** + * @return string + */ + public function getCookieName() + { + return $this->cookieName; + } + + /** + * @param $name + * @return $this + */ + public function setCookieName($name) + { + $this->cookieName = $name; + return $this; + } + + /** + * @param Cookie $cookie + * @return $this + */ + public function setCookie(Cookie $cookie) + { + $this->cookie = $cookie; + return $this; + } + + /** + * @return bool + */ + public function loginTokenWasInvalid() + { + return $this->lastLoginTokenWasInvalid; + } + + /** + * @return Cookie + */ + public function getCookie() + { + return $this->cookie; + } + + /** + * @param $state + * @return Authenticator + */ + public function setCleanStoredTokensOnInvalidResult($state) + { + $this->cleanStoredTokensOnInvalidResult = $state; + return $this; + } + + /** + * @return bool + */ + public function getCleanStoredTokensOnInvalidResult() + { + return $this->cleanStoredTokensOnInvalidResult; + } + + /** + * Create a pseudo-random token. + * + * The token is pseudo-random. If you need better security, read from /dev/urandom + */ + protected function createToken() + { + return bin2hex(random_bytes(32)); + } + + /** + * @return array + */ + protected function getCookieValues() + { + // Cookie was not sent with incoming request + if (empty($_COOKIE[$this->cookieName])) { + return array(); + } + + $cookieValues = explode("|", $_COOKIE[$this->cookieName], 3); + + if (count($cookieValues) < 3) { + return array(); + } + + return $cookieValues; + } + + /** + * Return how many seconds in the future that the cookie will expire + * @return int + */ + public function getExpireTime() + { + return $this->expireTime; + } + + /** + * @param int $expireTime How many seconds in the future the cookie will expire + * + * Default is 604800 (1 week) + * + * @return Authenticator + */ + public function setExpireTime($expireTime) + { + $this->expireTime = $expireTime; + + return $this; + } + + /** + * + * @return string + */ + public function getSalt() + { + return $this->salt; + } + + /** + * The salt is additional information that is added to the tokens to make + * them more unqiue and secure. The salt is not stored in the cookie and + * should not saved in the storage. + * + * For example, to bind a token to an IP address use $_SERVER['REMOTE_ADDR']. + * To bind a token to the browser (user agent), use $_SERVER['HTTP_USER_AGENT]. + * You could also use a long random string that is uniqe to your application. + * @param string $salt + */ + public function setSalt($salt) + { + $this->salt = $salt; + } +} diff --git a/user/plugins/login/vendor/birke/rememberme/src/Rememberme/Cookie.php b/user/plugins/login/vendor/birke/rememberme/src/Rememberme/Cookie.php new file mode 100644 index 00000000..a1031e97 --- /dev/null +++ b/user/plugins/login/vendor/birke/rememberme/src/Rememberme/Cookie.php @@ -0,0 +1,104 @@ +path, $this->domain, $this->secure, $this->httpOnly); + } + + /** + * @return string + */ + public function getPath() + { + return $this->path; + } + + /** + * @param $path + */ + public function setPath($path) + { + $this->path = $path; + } + + /** + * @return string + */ + public function getDomain() + { + return $this->domain; + } + + /** + * @param $domain + */ + public function setDomain($domain) + { + $this->domain = $domain; + } + + /** + * @return bool + */ + public function getSecure() + { + return $this->secure; + } + + /** + * @param $secure + */ + public function setSecure($secure) + { + $this->secure = $secure; + } + + /** + * @return bool + */ + public function getHttpOnly() + { + return $this->httpOnly; + } + + /** + * @param $httponly + */ + public function setHttpOnly($httponly) + { + $this->httpOnly = $httponly; + } +} diff --git a/user/plugins/login/vendor/birke/rememberme/src/Rememberme/Storage/DB.php b/user/plugins/login/vendor/birke/rememberme/src/Rememberme/Storage/DB.php new file mode 100644 index 00000000..d8f9dab7 --- /dev/null +++ b/user/plugins/login/vendor/birke/rememberme/src/Rememberme/Storage/DB.php @@ -0,0 +1,145 @@ + $value) { + $setter = "set" . ucfirst($prop); + if (method_exists($this, $setter)) { + $this->$setter($value); + } + } + } + + /** + * @return string + */ + public function getTableName() + { + return $this->tableName; + } + + /** + * @param $tableName + * @return $this + */ + public function setTableName($tableName) + { + $this->tableName = $tableName; + return $this; + } + + /** + * @return string + */ + public function getCredentialColumn() + { + return $this->credentialColumn; + } + + /** + * @param $credentialColumn + * @return $this + */ + public function setCredentialColumn($credentialColumn) + { + $this->credentialColumn = $credentialColumn; + return $this; + } + + /** + * @return string + */ + public function getTokenColumn() + { + return $this->tokenColumn; + } + + /** + * @param $tokenColumn + * @return $this + */ + public function setTokenColumn($tokenColumn) + { + $this->tokenColumn = $tokenColumn; + return $this; + } + + /** + * @return string + */ + public function getPersistentTokenColumn() + { + return $this->persistentTokenColumn; + } + + /** + * @param $persistentTokenColumn + * @return $this + */ + public function setPersistentTokenColumn($persistentTokenColumn) + { + $this->persistentTokenColumn = $persistentTokenColumn; + return $this; + } + + /** + * @return string + */ + public function getExpiresColumn() + { + return $this->expiresColumn; + } + + /** + * @param $expiresColumn + * @return $this + */ + public function setExpiresColumn($expiresColumn) + { + $this->expiresColumn = $expiresColumn; + return $this; + } +} diff --git a/user/plugins/login/vendor/birke/rememberme/src/Rememberme/Storage/File.php b/user/plugins/login/vendor/birke/rememberme/src/Rememberme/Storage/File.php new file mode 100644 index 00000000..23c5cb57 --- /dev/null +++ b/user/plugins/login/vendor/birke/rememberme/src/Rememberme/Storage/File.php @@ -0,0 +1,119 @@ +path = $path; + $this->suffix = $suffix; + } + + /** + * @param mixed $credential + * @param string $token + * @param string $persistentToken + * @return int + */ + public function findTriplet($credential, $token, $persistentToken) + { + // Hash the tokens, because they can contain a salt and can be accessed in the file system + $persistentToken = sha1($persistentToken); + $token = sha1($token); + $fn = $this->getFilename($credential, $persistentToken); + + if (!file_exists($fn)) { + return self::TRIPLET_NOT_FOUND; + } + + $fileToken = trim(file_get_contents($fn)); + + if ($fileToken == $token) { + return self::TRIPLET_FOUND; + } + + return self::TRIPLET_INVALID; + } + + /** + * @param mixed $credential + * @param string $token + * @param string $persistentToken + * @param int $expire + * @return $this + */ + public function storeTriplet($credential, $token, $persistentToken, $expire = 0) + { + // Hash the tokens, because they can contain a salt and can be accessed in the file system + $persistentToken = sha1($persistentToken); + $token = sha1($token); + $fn = $this->getFilename($credential, $persistentToken); + file_put_contents($fn, $token); + return $this; + } + + /** + * @param mixed $credential + * @param string $persistentToken + */ + public function cleanTriplet($credential, $persistentToken) + { + $persistentToken = sha1($persistentToken); + $fn = $this->getFilename($credential, $persistentToken); + + if (file_exists($fn)) { + unlink($fn); + } + } + + /** + * Replace current token after successful authentication + * @param $credential + * @param $token + * @param $persistentToken + * @param int $expire + */ + public function replaceTriplet($credential, $token, $persistentToken, $expire = 0) + { + $this->cleanTriplet($credential, $persistentToken); + $this->storeTriplet($credential, $token, $persistentToken, $expire); + } + + /** + * @param $credential + */ + public function cleanAllTriplets($credential) + { + foreach (glob($this->path . DIRECTORY_SEPARATOR . $credential . ".*" . $this->suffix) as $file) { + unlink($file); + } + } + + /** + * @param $credential + * @param $persistentToken + * @return string + */ + protected function getFilename($credential, $persistentToken) + { + return $this->path . DIRECTORY_SEPARATOR . $credential . "." . $persistentToken . $this->suffix; + } +} diff --git a/user/plugins/login/vendor/birke/rememberme/src/Rememberme/Storage/PDO.php b/user/plugins/login/vendor/birke/rememberme/src/Rememberme/Storage/PDO.php new file mode 100644 index 00000000..e4945133 --- /dev/null +++ b/user/plugins/login/vendor/birke/rememberme/src/Rememberme/Storage/PDO.php @@ -0,0 +1,121 @@ +tokenColumn}, 1, -1) AS token_match " . + "FROM {$this->tableName} WHERE {$this->credentialColumn} = ? " . + "AND {$this->persistentTokenColumn} = SHA1(?) AND {$this->expiresColumn} > NOW() LIMIT 1"; + + $query = $this->connection->prepare($sql); + $query->execute(array($token, $credential, $persistentToken)); + + $result = $query->fetchColumn(); + + if (!$result) { + return self::TRIPLET_NOT_FOUND; + } elseif ($result == 1) { + return self::TRIPLET_FOUND; + } + + return self::TRIPLET_INVALID; + } + + /** + * @param mixed $credential + * @param string $token + * @param string $persistentToken + * @param int $expire + */ + public function storeTriplet($credential, $token, $persistentToken, $expire = 0) + { + $sql = "INSERT INTO {$this->tableName}({$this->credentialColumn}, " . + "{$this->tokenColumn}, {$this->persistentTokenColumn}, " . + "{$this->expiresColumn}) VALUES(?, SHA1(?), SHA1(?), ?)"; + + $query = $this->connection->prepare($sql); + $query->execute(array($credential, $token, $persistentToken, date("Y-m-d H:i:s", $expire))); + } + + /** + * @param mixed $credential + * @param string $persistentToken + */ + public function cleanTriplet($credential, $persistentToken) + { + $sql = "DELETE FROM {$this->tableName} WHERE {$this->credentialColumn} = ? " + . "AND {$this->persistentTokenColumn} = SHA1(?)"; + + $query = $this->connection->prepare($sql); + $query->execute(array($credential, $persistentToken)); + } + + /** + * Replace current token after successful authentication + * @param $credential + * @param $token + * @param $persistentToken + * @param int $expire + */ + public function replaceTriplet($credential, $token, $persistentToken, $expire = 0) + { + try { + $this->connection->beginTransaction(); + $this->cleanTriplet($credential, $persistentToken); + $this->storeTriplet($credential, $token, $persistentToken, $expire); + $this->connection->commit(); + } + catch (\PDOException $e) { + $this->connection->rollBack(); + throw $e; + } + } + + /** + * @param $credential + */ + public function cleanAllTriplets($credential) + { + $sql = "DELETE FROM {$this->tableName} WHERE {$this->credentialColumn} = ? "; + + $query = $this->connection->prepare($sql); + $query->execute(array($credential)); + } + + /** + * @return \PDO + */ + public function getConnection() + { + return $this->connection; + } + + /** + * @param PDO $connection + */ + public function setConnection(\PDO $connection) + { + $this->connection = $connection; + } +} diff --git a/user/plugins/login/vendor/birke/rememberme/src/Rememberme/Storage/StorageInterface.php b/user/plugins/login/vendor/birke/rememberme/src/Rememberme/Storage/StorageInterface.php new file mode 100644 index 00000000..94163b0c --- /dev/null +++ b/user/plugins/login/vendor/birke/rememberme/src/Rememberme/Storage/StorageInterface.php @@ -0,0 +1,66 @@ +assertEquals('', $cookie->getPath()); + $this->assertEquals('', $cookie->getDomain()); + $this->assertFalse($cookie->getSecure()); + $this->assertTrue($cookie->getHttpOnly()); + } + + public function testSetters() + { + $cookie = new \Birke\Rememberme\Cookie(); + + $cookie->setPath('/test'); + $this->assertEquals('/test', $cookie->getPath()); + + $cookie->setDomain('www.foo.com'); + $this->assertEquals('www.foo.com', $cookie->getDomain()); + + $cookie->setSecure(true); + $this->assertTrue($cookie->getSecure()); + + $cookie->setHttpOnly(false); + $this->assertFalse($cookie->getHttpOnly()); + } +} diff --git a/user/plugins/login/vendor/birke/rememberme/test/RemembermeTest.php b/user/plugins/login/vendor/birke/rememberme/test/RemembermeTest.php new file mode 100644 index 00000000..5ec58a79 --- /dev/null +++ b/user/plugins/login/vendor/birke/rememberme/test/RemembermeTest.php @@ -0,0 +1,352 @@ +storage = $this->getMockBuilder(\Birke\Rememberme\Storage\StorageInterface::class)->getMock(); + $this->rememberme = new Birke\Rememberme\Authenticator($this->storage); + + $this->cookie = $this->getMockBuilder(\Birke\Rememberme\Cookie::class)->setMethods(['setcookie'])->getMock(); + + $this->rememberme->setCookie($this->cookie); + + $_COOKIE = array(); + } + + /* Basic cases */ + + public function testReturnFalseIfNoCookieExists() + { + $this->assertFalse($this->rememberme->login()); + } + + public function testReturnFalseIfCookieIsInvalid() + { + $_COOKIE = array($this->rememberme->getCookieName() => "DUMMY"); + $this->assertFalse($this->rememberme->login()); + $_COOKIE = array($this->rememberme->getCookieName() => $this->userid."|a"); + $this->assertFalse($this->rememberme->login()); + } + + public function testLoginTriesToFindTripletWithValuesFromCookie() { + $_COOKIE[$this->rememberme->getCookieName()] = implode("|", array( + $this->userid, $this->validToken, $this->validPersistentToken)); + $this->storage->expects($this->once()) + ->method("findTriplet") + ->with($this->equalTo($this->userid), $this->equalTo($this->validToken), $this->equalTo($this->validPersistentToken)); + $this->rememberme->login(); + } + + /* Success cases */ + + public function testReturnTrueIfTripletIsFound() { + $_COOKIE[$this->rememberme->getCookieName()] = implode("|", array( + $this->userid, $this->validToken, $this->validPersistentToken)); + + $this->storage->expects($this->once()) + ->method("findTriplet") + ->will($this->returnValue(Birke\Rememberme\Storage\StorageInterface::TRIPLET_FOUND)); + $this->assertEquals($this->userid, $this->rememberme->login()); + } + + public function testStoreNewTripletInCookieIfTripletIsFound() { + $oldcookieValue = implode("|", array( + $this->userid, $this->validToken, $this->validPersistentToken)); + $_COOKIE[$this->rememberme->getCookieName()] = $oldcookieValue; + $this->storage->expects($this->once()) + ->method("findTriplet") + ->will($this->returnValue(Birke\Rememberme\Storage\StorageInterface::TRIPLET_FOUND)); + $this->cookie->expects($this->once()) + ->method("setcookie") + ->with( + $this->anything(), + $this->logicalAnd( + $this->matchesRegularExpression('/^'.$this->userid.'\|[a-f0-9]{32,}\|'.$this->validPersistentToken.'$/'), + $this->logicalNot($this->equalTo($oldcookieValue)) + ) + ); + $this->rememberme->login(); + } + + public function testReplaceTripletInStorageIfTripletIsFound() { + $_COOKIE[$this->rememberme->getCookieName()] = implode("|", array( + $this->userid, $this->validToken, $this->validPersistentToken)); + $this->storage->expects($this->once()) + ->method("findTriplet") + ->will($this->returnValue(Birke\Rememberme\Storage\StorageInterface::TRIPLET_FOUND)); + $this->storage->expects($this->once()) + ->method("replaceTriplet") + ->with( + $this->equalTo($this->userid), + $this->logicalAnd( + $this->matchesRegularExpression('/^[a-f0-9]{32,}$/'), + $this->logicalNot($this->equalTo($this->validToken)) + ), + $this->equalTo($this->validPersistentToken) + ); + $this->rememberme->login(); + } + + public function testCookieContainsUserIDAndHexTokensIfTripletIsFound() + { + $_COOKIE[$this->rememberme->getCookieName()] = implode("|", array( + $this->userid, $this->validToken, $this->validPersistentToken)); + $this->storage->expects($this->once()) + ->method("findTriplet") + ->will($this->returnValue(Birke\Rememberme\Storage\StorageInterface::TRIPLET_FOUND)); + $this->cookie->expects($this->once()) + ->method("setcookie") + ->with($this->anything(), + $this->matchesRegularExpression('/^'.$this->userid.'\|[a-f0-9]{32,}\|[a-f0-9]{32,}$/') + ); + $this->rememberme->login(); + } + + public function testCookieContainsNewTokenIfTripletIsFound() + { + $oldcookieValue = implode("|", array( + $this->userid, $this->validToken, $this->validPersistentToken)); + $_COOKIE[$this->rememberme->getCookieName()] = $oldcookieValue; + $this->storage->expects($this->once()) + ->method("findTriplet") + ->will($this->returnValue(Birke\Rememberme\Storage\StorageInterface::TRIPLET_FOUND)); + $this->cookie->expects($this->once()) + ->method("setcookie") + ->with($this->anything(), + $this->logicalAnd( + $this->matchesRegularExpression('/^'.$this->userid.'\|[a-f0-9]{32,}\|'.$this->validPersistentToken.'$/'), + $this->logicalNot($this->equalTo($oldcookieValue)) + ) + ); + $this->rememberme->login(); + } + + public function testCookieExpiryIsInTheFutureIfTripletIsFound() + { + $oldcookieValue = implode("|", array( + $this->userid, $this->validToken, $this->validPersistentToken)); + $_COOKIE[$this->rememberme->getCookieName()] = $oldcookieValue; + $now = time(); + $this->storage->expects($this->once()) + ->method("findTriplet") + ->will($this->returnValue(Birke\Rememberme\Storage\StorageInterface::TRIPLET_FOUND)); + $this->cookie->expects($this->once()) + ->method("setcookie") + ->with($this->anything(), $this->anything(), $this->greaterThan($now)); + $this->rememberme->login(); + } + + /* Failure Cases */ + + public function testFalseIfTripletIsNotFound() { + $_COOKIE[$this->rememberme->getCookieName()] = implode("|", array( + $this->userid, $this->validToken, $this->validPersistentToken)); + + $this->storage->expects($this->once()) + ->method("findTriplet") + ->will($this->returnValue(Birke\Rememberme\Storage\StorageInterface::TRIPLET_NOT_FOUND)); + $this->assertFalse($this->rememberme->login()); + } + + public function testFalseIfTripletIsInvalid() { + $_COOKIE[$this->rememberme->getCookieName()] = implode("|", array( + $this->userid, $this->invalidToken, $this->validPersistentToken)); + + $this->storage->expects($this->once()) + ->method("findTriplet") + ->will($this->returnValue(Birke\Rememberme\Storage\StorageInterface::TRIPLET_INVALID)); + $this->assertFalse($this->rememberme->login()); + } + + public function testCookieIsExpiredIfTripletIsInvalid() { + $_COOKIE[$this->rememberme->getCookieName()] = implode("|", array( + $this->userid, $this->invalidToken, $this->validPersistentToken)); + $now = time(); + $this->storage->expects($this->once()) + ->method("findTriplet") + ->will($this->returnValue(Birke\Rememberme\Storage\StorageInterface::TRIPLET_INVALID)); + $this->cookie->expects($this->once()) + ->method("setcookie") + ->with($this->anything(), $this->anything(), $this->lessThan($now)); + $this->rememberme->login(); + } + + public function testAllStoredTokensAreClearedIfTripletIsInvalid() { + $_COOKIE[$this->rememberme->getCookieName()] = implode("|", array( + $this->userid, $this->invalidToken, $this->validPersistentToken)); + $this->storage->expects($this->any()) + ->method("findTriplet") + ->will($this->returnValue(Birke\Rememberme\Storage\StorageInterface::TRIPLET_INVALID)); + $this->storage->expects($this->once()) + ->method("cleanAllTriplets") + ->with($this->equalTo($this->userid)); + $this->rememberme->setCleanStoredTokensOnInvalidResult(true); + $this->rememberme->login(); + $this->rememberme->setCleanStoredTokensOnInvalidResult(false); + $this->rememberme->login(); + } + + public function testInvalidTripletStateIsStored() { + $_COOKIE[$this->rememberme->getCookieName()] = implode("|", array( + $this->userid, $this->invalidToken, $this->validPersistentToken)); + + $this->storage->expects($this->once()) + ->method("findTriplet") + ->will($this->returnValue(Birke\Rememberme\Storage\StorageInterface::TRIPLET_INVALID)); + $this->assertFalse($this->rememberme->loginTokenWasInvalid()); + $this->rememberme->login(); + $this->assertTrue($this->rememberme->loginTokenWasInvalid()); + } + + /* Cookie tests */ + + public function testCookieNameCanBeSet() { + $cookieName = "myCustomName"; + $this->rememberme->setCookieName($cookieName); + $_COOKIE[$cookieName] = implode("|", array($this->userid, $this->validToken, $this->validPersistentToken)); + $this->storage->expects($this->once()) + ->method("findTriplet") + ->will($this->returnValue(Birke\Rememberme\Storage\StorageInterface::TRIPLET_FOUND)); + $this->cookie->expects($this->once()) + ->method("setcookie") + ->with($this->equalTo($cookieName)); + $this->assertEquals($this->userid, $this->rememberme->login()); + } + + public function testCookieIsSetToConfiguredExpiryDate() { + $_COOKIE[$this->rememberme->getCookieName()] = implode("|", array( + $this->userid, $this->validToken, $this->validPersistentToken)); + $now = time(); + $expireTime = 31556926; // 1 year + $this->rememberme->setExpireTime($expireTime); + $this->storage->expects($this->once()) + ->method("findTriplet") + ->will($this->returnValue(Birke\Rememberme\Storage\StorageInterface::TRIPLET_FOUND)); + $this->cookie->expects($this->once()) + ->method("setcookie") + ->with($this->anything(), $this->anything(), $this->equalTo($now+$expireTime, 10)); + $this->rememberme->login(); + } + + /* Salting test */ + + public function testSaltIsAddedToTokensOnLogin() { + $salt = "Mozilla Firefox 4.0"; + $_COOKIE[$this->rememberme->getCookieName()] = implode("|", array( + $this->userid, $this->validToken, $this->validPersistentToken)); + $this->storage->expects($this->once()) + ->method("findTriplet") + ->with($this->equalTo($this->userid), $this->equalTo($this->validToken.$salt), $this->equalTo($this->validPersistentToken.$salt)) + ->will($this->returnValue(Birke\Rememberme\Storage\StorageInterface::TRIPLET_FOUND)); + $this->storage->expects($this->once()) + ->method("replaceTriplet") + ->with( + $this->equalTo($this->userid), + $this->matchesRegularExpression('/^[a-f0-9]{32,}'.preg_quote($salt)."$/"), + $this->equalTo($this->validPersistentToken.$salt) + ); + $this->rememberme->setSalt($salt); + $this->rememberme->login(); + } + + public function testSaltIsAddedToTokensOnCookieIsValid() { + $salt = "Mozilla Firefox 4.0"; + $_COOKIE[$this->rememberme->getCookieName()] = implode("|", array( + $this->userid, $this->validToken, $this->validPersistentToken)); + $this->storage->expects($this->once()) + ->method("findTriplet") + ->with($this->equalTo($this->userid), $this->equalTo($this->validToken.$salt), $this->equalTo($this->validPersistentToken.$salt)); + $this->rememberme->setSalt($salt); + $this->rememberme->cookieIsValid($this->userid); + } + + public function testSaltIsAddedToTokensOnCreateCookie() { + $salt = "Mozilla Firefox 4.0"; + $testExpr = '/^[a-f0-9]{32,}'.preg_quote($salt).'$/'; + $this->storage->expects($this->once()) + ->method("storeTriplet") + ->with( + $this->equalTo($this->userid), + $this->matchesRegularExpression($testExpr), + $this->matchesRegularExpression($testExpr) + ); + $this->rememberme->setSalt($salt); + $this->rememberme->createCookie($this->userid); + } + + public function testSaltIsAddedToTokensOnClearCookie() { + $salt = "Mozilla Firefox 4.0"; + $_COOKIE[$this->rememberme->getCookieName()] = implode("|", array( + $this->userid, $this->validToken, $this->validPersistentToken)); + $this->storage->expects($this->once()) + ->method("cleanTriplet") + ->with( + $this->equalTo($this->userid), + $this->equalTo($this->validPersistentToken.$salt) + ); + $this->rememberme->setSalt($salt); + $this->rememberme->clearCookie(true); + } + + /* Other functions */ + + public function testCreateCookieCreatesCookieAndStoresTriplets() { + $now = time(); + $this->cookie->expects($this->once()) + ->method("setcookie") + ->with( + $this->equalTo($this->rememberme->getCookieName()), + $this->matchesRegularExpression('/^'.$this->userid.'\|[a-f0-9]{32,}\|[a-f0-9]{32,}$/'), + $this->greaterThan($now) + ); + $testExpr = '/^[a-f0-9]{32,}$/'; + $this->storage->expects($this->once()) + ->method("storeTriplet") + ->with( + $this->equalTo($this->userid), + $this->matchesRegularExpression($testExpr), + $this->matchesRegularExpression($testExpr) + ); + $this->rememberme->createCookie($this->userid); + } + + public function testClearCookieExpiresCookieAndDeletesTriplet() { + $_COOKIE[$this->rememberme->getCookieName()] = implode("|", array( + $this->userid, $this->validToken, $this->validPersistentToken)); + $now = time(); + $this->cookie->expects($this->once()) + ->method("setcookie") + ->with( + $this->equalTo($this->rememberme->getCookieName()), + $this->anything(), + $this->lessThan($now) + ); + $this->storage->expects($this->once()) + ->method("cleanTriplet") + ->with( + $this->equalTo($this->userid), + $this->equalTo($this->validPersistentToken) + ); + $this->rememberme->clearCookie(true); + } +} diff --git a/user/plugins/login/vendor/birke/rememberme/test/Storage/PDO.php b/user/plugins/login/vendor/birke/rememberme/test/Storage/PDO.php new file mode 100644 index 00000000..462bf2fe --- /dev/null +++ b/user/plugins/login/vendor/birke/rememberme/test/Storage/PDO.php @@ -0,0 +1,98 @@ +pdo = new PDO('mysql:host=localhost;dbname=test', 'webuser', ''); + return $this->createDefaultDBConnection($this->pdo, 'test'); + } + + protected function getDataSet() + { + return $this->createFlatXMLDataSet(dirname(__FILE__).'/tokens.xml'); + } + + protected function setUp() { + parent::setUp(); + $this->storage = new Rememberme_Storage_PDO(array( + 'connection' => $this->pdo, + 'tableName' => 'tokens', + 'credentialColumn' => 'credential', + 'tokenColumn' => 'token', + 'persistentTokenColumn' => 'persistent_token', + 'expiresColumn' => 'expires' + )); + } + + public function testFindTripletReturnsFoundIfDataMatches() { + $result = $this->storage->findTriplet($this->userid, $this->validToken, $this->validPersistentToken); + $this->assertEquals(Rememberme_Storage_StorageInterface::TRIPLET_FOUND, $result); + } + + public function testFindTripletReturnsNotFoundIfNoDataMatches() { + $this->pdo->exec("TRUNCATE tokens"); + $result = $this->storage->findTriplet($this->userid, $this->validToken, $this->validPersistentToken); + $this->assertEquals(Rememberme_Storage_StorageInterface::TRIPLET_NOT_FOUND, $result); + } + + public function testFindTripletReturnsInvalidTokenIfTokenIsInvalid() { + $result = $this->storage->findTriplet($this->userid, $this->invalidToken, $this->validPersistentToken); + $this->assertEquals(Rememberme_Storage_StorageInterface::TRIPLET_INVALID, $result); + } + + public function testStoreTripletSavesValuesIntoDatabase() { + $this->pdo->exec("TRUNCATE tokens"); + $this->storage->storeTriplet($this->userid, $this->validToken, $this->validPersistentToken, $this->expireTS); + $result = $this->pdo->query("SELECT credential,token,persistent_token, expires FROM tokens"); + $row = $result->fetch(PDO::FETCH_NUM); + $this->assertEquals(array($this->userid, $this->validDBToken, $this->validDBPersistentToken, $this->expire), $row); + $this->assertFalse($result->fetch()); + } + + public function testCleanTripletRemovesEntryFromDatabase() { + $this->storage->cleanTriplet($this->userid, $this->validPersistentToken); + $this->assertEquals(0, $this->pdo->query("SELECT COUNT(*) FROM tokens")->fetchColumn()); + } + + public function testCleanAllTripletsRemovesAllEntriesWithMatchingCredentialsFromDatabase() { + $this->pdo->exec("INSERT INTO tokens VALUES ('{$this->userid}', 'dummy', 'dummy', NOW())"); + $this->storage->cleanAllTriplets($this->userid); + $this->assertEquals(0, $this->pdo->query("SELECT COUNT(*) FROM tokens")->fetchColumn()); + } + +} +?> diff --git a/user/plugins/login/vendor/birke/rememberme/test/Storage/tokens.xml b/user/plugins/login/vendor/birke/rememberme/test/Storage/tokens.xml new file mode 100644 index 00000000..a581ee71 --- /dev/null +++ b/user/plugins/login/vendor/birke/rememberme/test/Storage/tokens.xml @@ -0,0 +1,8 @@ + + + + diff --git a/user/plugins/login/vendor/birke/rememberme/test/bootstrap.php b/user/plugins/login/vendor/birke/rememberme/test/bootstrap.php new file mode 100644 index 00000000..c53f2ef8 --- /dev/null +++ b/user/plugins/login/vendor/birke/rememberme/test/bootstrap.php @@ -0,0 +1,3 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer\Autoload; + +/** + * ClassLoader implements a PSR-0, PSR-4 and classmap class loader. + * + * $loader = new \Composer\Autoload\ClassLoader(); + * + * // register classes with namespaces + * $loader->add('Symfony\Component', __DIR__.'/component'); + * $loader->add('Symfony', __DIR__.'/framework'); + * + * // activate the autoloader + * $loader->register(); + * + * // to enable searching the include path (eg. for PEAR packages) + * $loader->setUseIncludePath(true); + * + * In this example, if you try to use a class in the Symfony\Component + * namespace or one of its children (Symfony\Component\Console for instance), + * the autoloader will first look for the class under the component/ + * directory, and it will then fallback to the framework/ directory if not + * found before giving up. + * + * This class is loosely based on the Symfony UniversalClassLoader. + * + * @author Fabien Potencier + * @author Jordi Boggiano + * @see http://www.php-fig.org/psr/psr-0/ + * @see http://www.php-fig.org/psr/psr-4/ + */ +class ClassLoader +{ + // PSR-4 + private $prefixLengthsPsr4 = array(); + private $prefixDirsPsr4 = array(); + private $fallbackDirsPsr4 = array(); + + // PSR-0 + private $prefixesPsr0 = array(); + private $fallbackDirsPsr0 = array(); + + private $useIncludePath = false; + private $classMap = array(); + private $classMapAuthoritative = false; + private $missingClasses = array(); + private $apcuPrefix; + + public function getPrefixes() + { + if (!empty($this->prefixesPsr0)) { + return call_user_func_array('array_merge', $this->prefixesPsr0); + } + + return array(); + } + + public function getPrefixesPsr4() + { + return $this->prefixDirsPsr4; + } + + public function getFallbackDirs() + { + return $this->fallbackDirsPsr0; + } + + public function getFallbackDirsPsr4() + { + return $this->fallbackDirsPsr4; + } + + public function getClassMap() + { + return $this->classMap; + } + + /** + * @param array $classMap Class to filename map + */ + public function addClassMap(array $classMap) + { + if ($this->classMap) { + $this->classMap = array_merge($this->classMap, $classMap); + } else { + $this->classMap = $classMap; + } + } + + /** + * Registers a set of PSR-0 directories for a given prefix, either + * appending or prepending to the ones previously set for this prefix. + * + * @param string $prefix The prefix + * @param array|string $paths The PSR-0 root directories + * @param bool $prepend Whether to prepend the directories + */ + public function add($prefix, $paths, $prepend = false) + { + if (!$prefix) { + if ($prepend) { + $this->fallbackDirsPsr0 = array_merge( + (array) $paths, + $this->fallbackDirsPsr0 + ); + } else { + $this->fallbackDirsPsr0 = array_merge( + $this->fallbackDirsPsr0, + (array) $paths + ); + } + + return; + } + + $first = $prefix[0]; + if (!isset($this->prefixesPsr0[$first][$prefix])) { + $this->prefixesPsr0[$first][$prefix] = (array) $paths; + + return; + } + if ($prepend) { + $this->prefixesPsr0[$first][$prefix] = array_merge( + (array) $paths, + $this->prefixesPsr0[$first][$prefix] + ); + } else { + $this->prefixesPsr0[$first][$prefix] = array_merge( + $this->prefixesPsr0[$first][$prefix], + (array) $paths + ); + } + } + + /** + * Registers a set of PSR-4 directories for a given namespace, either + * appending or prepending to the ones previously set for this namespace. + * + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param array|string $paths The PSR-4 base directories + * @param bool $prepend Whether to prepend the directories + * + * @throws \InvalidArgumentException + */ + public function addPsr4($prefix, $paths, $prepend = false) + { + if (!$prefix) { + // Register directories for the root namespace. + if ($prepend) { + $this->fallbackDirsPsr4 = array_merge( + (array) $paths, + $this->fallbackDirsPsr4 + ); + } else { + $this->fallbackDirsPsr4 = array_merge( + $this->fallbackDirsPsr4, + (array) $paths + ); + } + } elseif (!isset($this->prefixDirsPsr4[$prefix])) { + // Register directories for a new namespace. + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = (array) $paths; + } elseif ($prepend) { + // Prepend directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + (array) $paths, + $this->prefixDirsPsr4[$prefix] + ); + } else { + // Append directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + $this->prefixDirsPsr4[$prefix], + (array) $paths + ); + } + } + + /** + * Registers a set of PSR-0 directories for a given prefix, + * replacing any others previously set for this prefix. + * + * @param string $prefix The prefix + * @param array|string $paths The PSR-0 base directories + */ + public function set($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr0 = (array) $paths; + } else { + $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths; + } + } + + /** + * Registers a set of PSR-4 directories for a given namespace, + * replacing any others previously set for this namespace. + * + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param array|string $paths The PSR-4 base directories + * + * @throws \InvalidArgumentException + */ + public function setPsr4($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr4 = (array) $paths; + } else { + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = (array) $paths; + } + } + + /** + * Turns on searching the include path for class files. + * + * @param bool $useIncludePath + */ + public function setUseIncludePath($useIncludePath) + { + $this->useIncludePath = $useIncludePath; + } + + /** + * Can be used to check if the autoloader uses the include path to check + * for classes. + * + * @return bool + */ + public function getUseIncludePath() + { + return $this->useIncludePath; + } + + /** + * Turns off searching the prefix and fallback directories for classes + * that have not been registered with the class map. + * + * @param bool $classMapAuthoritative + */ + public function setClassMapAuthoritative($classMapAuthoritative) + { + $this->classMapAuthoritative = $classMapAuthoritative; + } + + /** + * Should class lookup fail if not found in the current class map? + * + * @return bool + */ + public function isClassMapAuthoritative() + { + return $this->classMapAuthoritative; + } + + /** + * APCu prefix to use to cache found/not-found classes, if the extension is enabled. + * + * @param string|null $apcuPrefix + */ + public function setApcuPrefix($apcuPrefix) + { + $this->apcuPrefix = function_exists('apcu_fetch') && ini_get('apc.enabled') ? $apcuPrefix : null; + } + + /** + * The APCu prefix in use, or null if APCu caching is not enabled. + * + * @return string|null + */ + public function getApcuPrefix() + { + return $this->apcuPrefix; + } + + /** + * Registers this instance as an autoloader. + * + * @param bool $prepend Whether to prepend the autoloader or not + */ + public function register($prepend = false) + { + spl_autoload_register(array($this, 'loadClass'), true, $prepend); + } + + /** + * Unregisters this instance as an autoloader. + */ + public function unregister() + { + spl_autoload_unregister(array($this, 'loadClass')); + } + + /** + * Loads the given class or interface. + * + * @param string $class The name of the class + * @return bool|null True if loaded, null otherwise + */ + public function loadClass($class) + { + if ($file = $this->findFile($class)) { + includeFile($file); + + return true; + } + } + + /** + * Finds the path to the file where the class is defined. + * + * @param string $class The name of the class + * + * @return string|false The path if found, false otherwise + */ + public function findFile($class) + { + // class map lookup + if (isset($this->classMap[$class])) { + return $this->classMap[$class]; + } + if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) { + return false; + } + if (null !== $this->apcuPrefix) { + $file = apcu_fetch($this->apcuPrefix.$class, $hit); + if ($hit) { + return $file; + } + } + + $file = $this->findFileWithExtension($class, '.php'); + + // Search for Hack files if we are running on HHVM + if (false === $file && defined('HHVM_VERSION')) { + $file = $this->findFileWithExtension($class, '.hh'); + } + + if (null !== $this->apcuPrefix) { + apcu_add($this->apcuPrefix.$class, $file); + } + + if (false === $file) { + // Remember that this class does not exist. + $this->missingClasses[$class] = true; + } + + return $file; + } + + private function findFileWithExtension($class, $ext) + { + // PSR-4 lookup + $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext; + + $first = $class[0]; + if (isset($this->prefixLengthsPsr4[$first])) { + $subPath = $class; + while (false !== $lastPos = strrpos($subPath, '\\')) { + $subPath = substr($subPath, 0, $lastPos); + $search = $subPath.'\\'; + if (isset($this->prefixDirsPsr4[$search])) { + $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1); + foreach ($this->prefixDirsPsr4[$search] as $dir) { + if (file_exists($file = $dir . $pathEnd)) { + return $file; + } + } + } + } + } + + // PSR-4 fallback dirs + foreach ($this->fallbackDirsPsr4 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) { + return $file; + } + } + + // PSR-0 lookup + if (false !== $pos = strrpos($class, '\\')) { + // namespaced class name + $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1) + . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR); + } else { + // PEAR-like class name + $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext; + } + + if (isset($this->prefixesPsr0[$first])) { + foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) { + if (0 === strpos($class, $prefix)) { + foreach ($dirs as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + } + } + } + + // PSR-0 fallback dirs + foreach ($this->fallbackDirsPsr0 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + + // PSR-0 include paths. + if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { + return $file; + } + + return false; + } +} + +/** + * Scope isolated include. + * + * Prevents access to $this/self from included files. + */ +function includeFile($file) +{ + include $file; +} diff --git a/user/plugins/login/vendor/composer/LICENSE b/user/plugins/login/vendor/composer/LICENSE new file mode 100644 index 00000000..f27399a0 --- /dev/null +++ b/user/plugins/login/vendor/composer/LICENSE @@ -0,0 +1,21 @@ + +Copyright (c) Nils Adermann, Jordi Boggiano + +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. + diff --git a/user/plugins/login/vendor/composer/autoload_classmap.php b/user/plugins/login/vendor/composer/autoload_classmap.php new file mode 100644 index 00000000..7a91153b --- /dev/null +++ b/user/plugins/login/vendor/composer/autoload_classmap.php @@ -0,0 +1,9 @@ + $vendorDir . '/paragonie/random_compat/lib/random.php', +); diff --git a/user/plugins/login/vendor/composer/autoload_namespaces.php b/user/plugins/login/vendor/composer/autoload_namespaces.php new file mode 100644 index 00000000..c3a2bfe0 --- /dev/null +++ b/user/plugins/login/vendor/composer/autoload_namespaces.php @@ -0,0 +1,10 @@ + array($vendorDir . '/bacon/bacon-qr-code/src'), +); diff --git a/user/plugins/login/vendor/composer/autoload_psr4.php b/user/plugins/login/vendor/composer/autoload_psr4.php new file mode 100644 index 00000000..461a84b7 --- /dev/null +++ b/user/plugins/login/vendor/composer/autoload_psr4.php @@ -0,0 +1,12 @@ + array($vendorDir . '/robthree/twofactorauth/lib'), + 'Grav\\Plugin\\Login\\' => array($baseDir . '/classes'), + 'Birke\\' => array($vendorDir . '/birke/rememberme/src'), +); diff --git a/user/plugins/login/vendor/composer/autoload_real.php b/user/plugins/login/vendor/composer/autoload_real.php new file mode 100644 index 00000000..6a282d75 --- /dev/null +++ b/user/plugins/login/vendor/composer/autoload_real.php @@ -0,0 +1,70 @@ += 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded()); + if ($useStaticLoader) { + require_once __DIR__ . '/autoload_static.php'; + + call_user_func(\Composer\Autoload\ComposerStaticIniteed5e5cf0aa1e2139f2db7445511e366::getInitializer($loader)); + } else { + $map = require __DIR__ . '/autoload_namespaces.php'; + foreach ($map as $namespace => $path) { + $loader->set($namespace, $path); + } + + $map = require __DIR__ . '/autoload_psr4.php'; + foreach ($map as $namespace => $path) { + $loader->setPsr4($namespace, $path); + } + + $classMap = require __DIR__ . '/autoload_classmap.php'; + if ($classMap) { + $loader->addClassMap($classMap); + } + } + + $loader->register(true); + + if ($useStaticLoader) { + $includeFiles = Composer\Autoload\ComposerStaticIniteed5e5cf0aa1e2139f2db7445511e366::$files; + } else { + $includeFiles = require __DIR__ . '/autoload_files.php'; + } + foreach ($includeFiles as $fileIdentifier => $file) { + composerRequireeed5e5cf0aa1e2139f2db7445511e366($fileIdentifier, $file); + } + + return $loader; + } +} + +function composerRequireeed5e5cf0aa1e2139f2db7445511e366($fileIdentifier, $file) +{ + if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { + require $file; + + $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true; + } +} diff --git a/user/plugins/login/vendor/composer/autoload_static.php b/user/plugins/login/vendor/composer/autoload_static.php new file mode 100644 index 00000000..b9badf98 --- /dev/null +++ b/user/plugins/login/vendor/composer/autoload_static.php @@ -0,0 +1,62 @@ + __DIR__ . '/..' . '/paragonie/random_compat/lib/random.php', + ); + + public static $prefixLengthsPsr4 = array ( + 'R' => + array ( + 'RobThree\\Auth\\' => 14, + ), + 'G' => + array ( + 'Grav\\Plugin\\Login\\' => 18, + ), + 'B' => + array ( + 'Birke\\' => 6, + ), + ); + + public static $prefixDirsPsr4 = array ( + 'RobThree\\Auth\\' => + array ( + 0 => __DIR__ . '/..' . '/robthree/twofactorauth/lib', + ), + 'Grav\\Plugin\\Login\\' => + array ( + 0 => __DIR__ . '/../..' . '/classes', + ), + 'Birke\\' => + array ( + 0 => __DIR__ . '/..' . '/birke/rememberme/src', + ), + ); + + public static $prefixesPsr0 = array ( + 'B' => + array ( + 'BaconQrCode' => + array ( + 0 => __DIR__ . '/..' . '/bacon/bacon-qr-code/src', + ), + ), + ); + + public static function getInitializer(ClassLoader $loader) + { + return \Closure::bind(function () use ($loader) { + $loader->prefixLengthsPsr4 = ComposerStaticIniteed5e5cf0aa1e2139f2db7445511e366::$prefixLengthsPsr4; + $loader->prefixDirsPsr4 = ComposerStaticIniteed5e5cf0aa1e2139f2db7445511e366::$prefixDirsPsr4; + $loader->prefixesPsr0 = ComposerStaticIniteed5e5cf0aa1e2139f2db7445511e366::$prefixesPsr0; + + }, null, ClassLoader::class); + } +} diff --git a/user/plugins/login/vendor/composer/installed.json b/user/plugins/login/vendor/composer/installed.json new file mode 100644 index 00000000..caddc63d --- /dev/null +++ b/user/plugins/login/vendor/composer/installed.json @@ -0,0 +1,200 @@ +[ + { + "name": "bacon/bacon-qr-code", + "version": "1.0.3", + "version_normalized": "1.0.3.0", + "source": { + "type": "git", + "url": "https://github.com/Bacon/BaconQrCode.git", + "reference": "5a91b62b9d37cee635bbf8d553f4546057250bee" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Bacon/BaconQrCode/zipball/5a91b62b9d37cee635bbf8d553f4546057250bee", + "reference": "5a91b62b9d37cee635bbf8d553f4546057250bee", + "shasum": "" + }, + "require": { + "ext-iconv": "*", + "php": "^5.4|^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8" + }, + "suggest": { + "ext-gd": "to generate QR code images" + }, + "time": "2017-10-17T09:59:25+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-0": { + "BaconQrCode": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-2-Clause" + ], + "authors": [ + { + "name": "Ben Scholzen 'DASPRiD'", + "email": "mail@dasprids.de", + "homepage": "http://www.dasprids.de", + "role": "Developer" + } + ], + "description": "BaconQrCode is a QR code generator for PHP.", + "homepage": "https://github.com/Bacon/BaconQrCode" + }, + { + "name": "birke/rememberme", + "version": "1.0.5", + "version_normalized": "1.0.5.0", + "source": { + "type": "git", + "url": "https://github.com/gbirke/rememberme.git", + "reference": "810473852eb4823098e47e23376a19b77ba0c165" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/gbirke/rememberme/zipball/810473852eb4823098e47e23376a19b77ba0c165", + "reference": "810473852eb4823098e47e23376a19b77ba0c165", + "shasum": "" + }, + "require": { + "paragonie/random_compat": "^1.1.4" + }, + "require-dev": { + "phpunit/phpunit": "4.*" + }, + "time": "2017-02-12T12:43:00+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Birke\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gabriel Birke", + "email": "gb@birke-software.de" + } + ], + "description": "Secure \"Remember Me\" functionality", + "homepage": "https://github.com/gbirke/rememberme", + "keywords": [ + "cookie", + "remember", + "security" + ] + }, + { + "name": "paragonie/random_compat", + "version": "v1.4.3", + "version_normalized": "1.4.3.0", + "source": { + "type": "git", + "url": "https://github.com/paragonie/random_compat.git", + "reference": "9b3899e3c3ddde89016f576edb8c489708ad64cd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/paragonie/random_compat/zipball/9b3899e3c3ddde89016f576edb8c489708ad64cd", + "reference": "9b3899e3c3ddde89016f576edb8c489708ad64cd", + "shasum": "" + }, + "require": { + "php": ">=5.2.0" + }, + "require-dev": { + "phpunit/phpunit": "4.*|5.*" + }, + "suggest": { + "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes." + }, + "time": "2018-04-04T21:48:54+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "files": [ + "lib/random.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Paragon Initiative Enterprises", + "email": "security@paragonie.com", + "homepage": "https://paragonie.com" + } + ], + "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7", + "keywords": [ + "csprng", + "pseudorandom", + "random" + ] + }, + { + "name": "robthree/twofactorauth", + "version": "1.6.1", + "version_normalized": "1.6.1.0", + "source": { + "type": "git", + "url": "https://github.com/RobThree/TwoFactorAuth.git", + "reference": "a77e7d822343bb88112baef808839cfae7bc5abb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/RobThree/TwoFactorAuth/zipball/a77e7d822343bb88112baef808839cfae7bc5abb", + "reference": "a77e7d822343bb88112baef808839cfae7bc5abb", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": "@stable" + }, + "time": "2017-11-06T17:55:56+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "RobThree\\Auth\\": "lib" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Rob Janssen", + "homepage": "http://robiii.me", + "role": "Developer" + } + ], + "description": "Two Factor Authentication", + "homepage": "https://github.com/RobThree/TwoFactorAuth", + "keywords": [ + "Authentication", + "MFA", + "Multi Factor Authentication", + "Two Factor Authentication", + "authenticator", + "authy", + "php", + "tfa" + ] + } +] diff --git a/user/plugins/login/vendor/dasprid/enum/.coveralls.yml b/user/plugins/login/vendor/dasprid/enum/.coveralls.yml new file mode 100644 index 00000000..bc71b62f --- /dev/null +++ b/user/plugins/login/vendor/dasprid/enum/.coveralls.yml @@ -0,0 +1,2 @@ +coverage_clover: clover.xml +json_path: coveralls-upload.json diff --git a/user/plugins/login/vendor/dasprid/enum/README.md b/user/plugins/login/vendor/dasprid/enum/README.md new file mode 100644 index 00000000..9e9ca127 --- /dev/null +++ b/user/plugins/login/vendor/dasprid/enum/README.md @@ -0,0 +1,164 @@ +# PHP 7.1 enums + +[![Build Status](https://travis-ci.org/DASPRiD/Enum.svg?branch=master)](https://travis-ci.org/DASPRiD/Enum) +[![Coverage Status](https://coveralls.io/repos/github/DASPRiD/Enum/badge.svg?branch=master)](https://coveralls.io/github/DASPRiD/Enum?branch=master) +[![Latest Stable Version](https://poser.pugx.org/dasprid/enum/v/stable)](https://packagist.org/packages/dasprid/enum) +[![Total Downloads](https://poser.pugx.org/dasprid/enum/downloads)](https://packagist.org/packages/dasprid/enum) +[![License](https://poser.pugx.org/dasprid/enum/license)](https://packagist.org/packages/dasprid/enum) + +It is a well known fact that PHP is missing a basic enum type, ignoring the rather incomplete `SplEnum` implementation +which is only available as a PECL extension. There are also quite a few other userland enum implementations around, +but all of them have one or another compromise. This library tries to close that gap as far as PHP allows it to. + +## Usage + +### Basics + +At its core, there is the `DASPRiD\Enum\AbstractEnum` class, which by default will work with constants like any other +enum implementation you might know. The first clear difference is that you should define all the constants as protected +(so nobody outside your class can read them but the `AbstractEnum` can still do so). The other even mightier difference +is that, for simple enums, the value of the constant doesn't matter at all. Let's have a look at a simple example: + +```php +use DASPRiD\Enum\AbstractEnum; + +/** + * @method static self MONDAY() + * @method static self TUESDAY() + * @method static self WEDNESDAY() + * @method static self THURSDAY() + * @method static self FRIDAY() + * @method static self SATURDAY() + * @method static self SUNDAY() + */ +final class WeekDay extends AbstractEnum +{ + protected const MONDAY = null; + protected const TUESDAY = null; + protected const WEDNESDAY = null; + protected const THURSDAY = null; + protected const FRIDAY = null; + protected const SATURDAY = null; + protected const SUNDAY = null; +} +``` + +If you need to provide constants for either internal use or public use, you can mark them as either private or public, +in which case they will be ignored by the enum, which only considers protected constants as valid values. As you can +see, we specifically defined the generated magic methods in a class level doc block, so anyone using this class will +automatically have proper auto-completion in their IDE. Now since you have defined the enum, you can simply use it like +that: + +```php +function tellItLikeItIs(WeekDay $weekDay) +{ + switch ($weekDay) { + case WeekDay::MONDAY(): + echo 'Mondays are bad.'; + break; + + case WeekDay::FRIDAY(): + echo 'Fridays are better.'; + break; + + case WeekDay::SATURDAY(): + case WeekDay::SUNDAY(): + echo 'Weekends are best.'; + break; + + default: + echo 'Midweek days are so-so.'; + } +} + +tellItLikeItIs(WeekDay::MONDAY()); +tellItLikeItIs(WeekDay::WEDNESDAY()); +tellItLikeItIs(WeekDay::FRIDAY()); +tellItLikeItIs(WeekDay::SATURDAY()); +tellItLikeItIs(WeekDay::SUNDAY()); +``` + +### More complex example + +Of course, all enums are singletons, which are not cloneable or serializable. Thus you can be sure that there is always +just one instance of the same type. Of course, the values of constants are not completely useless, let's have a look at +a more complex example: + +```php +use DASPRiD\Enum\AbstractEnum; + +/** + * @method static self MERCURY() + * @method static self VENUS() + * @method static self EARTH() + * @method static self MARS() + * @method static self JUPITER() + * @method static self SATURN() + * @method static self URANUS() + * @method static self NEPTUNE() + */ +final class Planet extends AbstractEnum +{ + protected const MERCURY = [3.303e+23, 2.4397e6]; + protected const VENUS = [4.869e+24, 6.0518e6]; + protected const EARTH = [5.976e+24, 6.37814e6]; + protected const MARS = [6.421e+23, 3.3972e6]; + protected const JUPITER = [1.9e+27, 7.1492e7]; + protected const SATURN = [5.688e+26, 6.0268e7]; + protected const URANUS = [8.686e+25, 2.5559e7]; + protected const NEPTUNE = [1.024e+26, 2.4746e7]; + + /** + * Universal gravitational constant. + * + * @var float + */ + private const G = 6.67300E-11; + + /** + * Mass in kilograms. + * + * @var float + */ + private $mass; + + /** + * Radius in meters. + * + * @var float + */ + private $radius; + + protected function __construct(float $mass, float $radius) + { + $this->mass = $mass; + $this->radius = $radius; + } + + public function mass() : float + { + return $this->mass; + } + + public function radius() : float + { + return $this->radius; + } + + public function surfaceGravity() : float + { + return self::G * $this->mass / ($this->radius * $this->radius); + } + + public function surfaceWeight(float $otherMass) : float + { + return $otherMass * $this->surfaceGravity(); + } +} + +$myMass = 80; + +foreach (Planet::values() as $planet) { + printf("Your weight on %s is %f\n", $planet, $planet->surfaceWeight($myMass)); +} +``` diff --git a/user/plugins/login/vendor/dasprid/enum/composer.json b/user/plugins/login/vendor/dasprid/enum/composer.json new file mode 100644 index 00000000..41184d31 --- /dev/null +++ b/user/plugins/login/vendor/dasprid/enum/composer.json @@ -0,0 +1,30 @@ +{ + "name": "dasprid/enum", + "description": "PHP 7.1 enum implementation", + "license": "BSD-2-Clause", + "authors": [ + { + "name": "Ben Scholzen 'DASPRiD'", + "homepage": "https://dasprids.de/", + "email": "mail@dasprids.de" + } + ], + "keywords": [ + "enum", + "map" + ], + "require-dev": { + "phpunit/phpunit": "^6.4", + "squizlabs/php_codesniffer": "^3.1" + }, + "autoload": { + "psr-4": { + "DASPRiD\\Enum\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "DASPRiD\\EnumTest\\": "test/" + } + } +} diff --git a/user/plugins/login/vendor/dasprid/enum/phpcs.xml b/user/plugins/login/vendor/dasprid/enum/phpcs.xml new file mode 100644 index 00000000..a184db89 --- /dev/null +++ b/user/plugins/login/vendor/dasprid/enum/phpcs.xml @@ -0,0 +1,30 @@ + + + Enum coding standard + + + + + + + + + + + + + + + + + + + + + + + + + src + test + diff --git a/user/plugins/login/vendor/dasprid/enum/phpunit.xml.dist b/user/plugins/login/vendor/dasprid/enum/phpunit.xml.dist new file mode 100644 index 00000000..307a4309 --- /dev/null +++ b/user/plugins/login/vendor/dasprid/enum/phpunit.xml.dist @@ -0,0 +1,17 @@ + + + + + ./test + + + + + + src + + + diff --git a/user/plugins/login/vendor/dasprid/enum/src/AbstractEnum.php b/user/plugins/login/vendor/dasprid/enum/src/AbstractEnum.php new file mode 100644 index 00000000..bc36119f --- /dev/null +++ b/user/plugins/login/vendor/dasprid/enum/src/AbstractEnum.php @@ -0,0 +1,241 @@ +> + */ + private static $values = []; + + /** + * @var array + */ + private static $allValuesLoaded = []; + + /** + * @var array + */ + private static $constants = []; + + /** + * The constructor is private by default to avoid arbitrary enum creation. + * + * When creating your own constructor for a parameterized enum, make sure to declare it as protected, so that + * the static methods are able to construct it. Avoid making it public, as that would allow creation of + * non-singleton enum instances. + */ + private function __construct() + { + } + + /** + * Magic getter which forwards all calls to {@see self::valueOf()}. + * + * @return static + */ + final public static function __callStatic(string $name, array $arguments) : self + { + return static::valueOf($name); + } + + /** + * Returns an enum with the specified name. + * + * The name must match exactly an identifier used to declare an enum in this type (extraneous whitespace characters + * are not permitted). + * + * @return static + * @throws IllegalArgumentException if the enum has no constant with the specified name + */ + final public static function valueOf(string $name) : self + { + if (isset(self::$values[static::class][$name])) { + return self::$values[static::class][$name]; + } + + $constants = self::constants(); + + if (array_key_exists($name, $constants)) { + return self::createValue($name, $constants[$name][0], $constants[$name][1]); + } + + throw new IllegalArgumentException(sprintf('No enum constant %s::%s', static::class, $name)); + } + + /** + * @return static + */ + final private static function createValue(string $name, int $ordinal, array $arguments) : self + { + $instance = new static(...$arguments); + $instance->name = $name; + $instance->ordinal = $ordinal; + self::$values[static::class][$name] = $instance; + return $instance; + } + + /** + * Obtains all possible types defined by this enum. + * + * @return static[] + */ + final public static function values() : array + { + if (isset(self::$allValuesLoaded[static::class])) { + return self::$values[static::class]; + } + + if (! isset(self::$values[static::class])) { + self::$values[static::class] = []; + } + + foreach (self::constants() as $name => $constant) { + if (array_key_exists($name, self::$values[static::class])) { + continue; + } + + static::createValue($name, $constant[0], $constant[1]); + } + + uasort(self::$values[static::class], function (self $a, self $b) { + return $a->ordinal() <=> $b->ordinal(); + }); + + self::$allValuesLoaded[static::class] = true; + return self::$values[static::class]; + } + + final private static function constants() : array + { + if (isset(self::$constants[static::class])) { + return self::$constants[static::class]; + } + + self::$constants[static::class] = []; + $reflectionClass = new ReflectionClass(static::class); + $ordinal = -1; + + foreach ($reflectionClass->getReflectionConstants() as $reflectionConstant) { + if (! $reflectionConstant->isProtected()) { + continue; + } + + $value = $reflectionConstant->getValue(); + + self::$constants[static::class][$reflectionConstant->name] = [ + ++$ordinal, + is_array($value) ? $value : [] + ]; + } + + return self::$constants[static::class]; + } + + /** + * Returns the name of this enum constant, exactly as declared in its enum declaration. + * + * Most programmers should use the {@see self::__toString()} method in preference to this one, as the toString + * method may return a more user-friendly name. This method is designed primarily for use in specialized situations + * where correctness depends on getting the exact name, which will not vary from release to release. + */ + final public function name() : string + { + return $this->name; + } + + /** + * Returns the ordinal of this enumeration constant (its position in its enum declaration, where the initial + * constant is assigned an ordinal of zero). + * + * Most programmers will have no use for this method. It is designed for use by sophisticated enum-based data + * structures. + */ + final public function ordinal() : int + { + return $this->ordinal; + } + + /** + * Compares this enum with the specified object for order. + * + * Returns negative integer, zero or positive integer as this object is less than, equal to or greater than the + * specified object. + * + * Enums are only comparable to other enums of the same type. The natural order implemented by this method is the + * order in which the constants are declared. + * + * @throws MismatchException if the passed enum is not of the same type + */ + final public function compareTo(self $other) : int + { + if (! $other instanceof static) { + throw new MismatchException(sprintf( + 'The passed enum %s is not of the same type as %s', + get_class($other), + static::class + )); + } + + return $this->ordinal - $other->ordinal; + } + + /** + * Forbid cloning enums. + * + * @throws CloneNotSupportedException + */ + final public function __clone() + { + throw new CloneNotSupportedException(); + } + + /** + * Forbid serializing enums. + * + * @throws SerializeNotSupportedException + */ + final public function __sleep() : void + { + throw new SerializeNotSupportedException(); + } + + /** + * Forbid unserializing enums. + * + * @throws UnserializeNotSupportedException + */ + final public function __wakeup() : void + { + throw new UnserializeNotSupportedException(); + } + + /** + * Turns the enum into a string representation. + * + * You may override this method to give a more user-friendly version. + */ + public function __toString() : string + { + return $this->name; + } +} diff --git a/user/plugins/login/vendor/dasprid/enum/src/EnumMap.php b/user/plugins/login/vendor/dasprid/enum/src/EnumMap.php new file mode 100644 index 00000000..77c5f352 --- /dev/null +++ b/user/plugins/login/vendor/dasprid/enum/src/EnumMap.php @@ -0,0 +1,375 @@ + + */ + private $keyUniverse; + + /** + * Array representation of this map. The ith element is the value to which universe[i] is currently mapped, or null + * if it isn't mapped to anything, or NullValue if it's mapped to null. + * + * @var array + */ + private $values; + + /** + * @var int + */ + private $size = 0; + + /** + * Creates a new enum map. + * + * @param string $keyType the type of the keys, must extend AbstractEnum + * @param string $valueType the type of the values + * @param bool $allowNullValues whether to allow null values + * @throws IllegalArgumentException when key type does not extend AbstractEnum + */ + public function __construct(string $keyType, string $valueType, bool $allowNullValues) + { + if (! is_subclass_of($keyType, AbstractEnum::class)) { + throw new IllegalArgumentException(sprintf( + 'Class %s does not extend %s', + $keyType, + AbstractEnum::class + )); + } + + $this->keyType = $keyType; + $this->valueType = $valueType; + $this->allowNullValues = $allowNullValues; + $this->keyUniverse = $keyType::values(); + $this->values = array_fill(0, count($this->keyUniverse), null); + } + + /** + * Checks whether the map types match the supplied ones. + * + * You should call this method when an EnumMap is passed to you and you want to ensure that it's made up of the + * correct types. + * + * @throws ExpectationException when supplied key type mismatches local key type + * @throws ExpectationException when supplied value type mismatches local value type + * @throws ExpectationException when the supplied map allows null values, abut should not + */ + public function expect(string $keyType, string $valueType, bool $allowNullValues) : void + { + if ($keyType !== $this->keyType) { + throw new ExpectationException(sprintf( + 'Callee expected an EnumMap with key type %s, but got %s', + $keyType, + $this->keyType + )); + } + + if ($valueType !== $this->valueType) { + throw new ExpectationException(sprintf( + 'Callee expected an EnumMap with value type %s, but got %s', + $keyType, + $this->keyType + )); + } + + if ($allowNullValues !== $this->allowNullValues) { + throw new ExpectationException(sprintf( + 'Callee expected an EnumMap with nullable flag %s, but got %s', + ($allowNullValues ? 'true' : 'false'), + ($this->allowNullValues ? 'true' : 'false') + )); + } + } + + /** + * Returns the number of key-value mappings in this map. + */ + public function size() : int + { + return $this->size; + } + + /** + * Returns true if this map maps one or more keys to the specified value. + */ + public function containsValue($value) : bool + { + return in_array($this->maskNull($value), $this->values, true); + } + + /** + * Returns true if this map contains a mapping for the specified key. + */ + public function containsKey(AbstractEnum $key) : bool + { + $this->checkKeyType($key); + return null !== $this->values[$key->ordinal()]; + } + + /** + * Returns the value to which the specified key is mapped, or null if this map contains no mapping for the key. + * + * More formally, if this map contains a mapping from a key to a value, then this method returns the value; + * otherwise it returns null (there can be at most one such mapping). + * + * A return value of null does not necessarily indicate that the map contains no mapping for the key; it's also + * possible that hte map explicitly maps the key to null. The {@see self::containsKey()} operation may be used to + * distinguish these two cases. + * + * @return mixed + */ + public function get(AbstractEnum $key) + { + $this->checkKeyType($key); + return $this->unmaskNull($this->values[$key->ordinal()]); + } + + /** + * Associates the specified value with the specified key in this map. + * + * If the map previously contained a mapping for this key, the old value is replaced. + * + * @return mixed the previous value associated with the specified key, or null if there was no mapping for the key. + * (a null return can also indicate that the map previously associated null with the specified key.) + * @throws IllegalArgumentException when the passed values does not match the internal value type + */ + public function put(AbstractEnum $key, $value) + { + $this->checkKeyType($key); + + if (! $this->isValidValue($value)) { + throw new IllegalArgumentException(sprintf('Value is not of type %s', $this->valueType)); + } + + $index = $key->ordinal(); + $oldValue = $this->values[$index]; + $this->values[$index] = $this->maskNull($value); + + if (null === $oldValue) { + ++$this->size; + } + + return $this->unmaskNull($oldValue); + } + + /** + * Removes the mapping for this key frm this map if present. + * + * @return mixed the previous value associated with the specified key, or null if there was no mapping for the key. + * (a null return can also indicate that the map previously associated null with the specified key.) + */ + public function remove(AbstractEnum $key) + { + $this->checkKeyType($key); + + $index = $key->ordinal(); + $oldValue = $this->values[$index]; + $this->values[$index] = null; + + if (null !== $oldValue) { + --$this->size; + } + + return $this->unmaskNull($oldValue); + } + + /** + * Removes all mappings from this map. + */ + public function clear() : void + { + $this->values = array_fill(0, count($this->keyUniverse), null); + $this->size = 0; + } + + /** + * Compares the specified map with this map for quality. + * + * Returns true if the two maps represent the same mappings. + */ + public function equals(self $other) : bool + { + if ($this === $other) { + return true; + } + + if ($this->size !== $other->size) { + return false; + } + + return $this->values === $other->values; + } + + /** + * Returns the values contained in this map. + * + * The array will contain the values in the order their corresponding keys appear in the map, which is their natural + * order (the order in which the num constants are declared). + */ + public function values() : array + { + return array_values(array_map(function ($value) { + return $this->unmaskNull($value); + }, array_filter($this->values, function ($value) : bool { + return null !== $value; + }))); + } + + public function serialize() : string + { + $values = []; + + foreach ($this->values as $ordinal => $value) { + if (null === $value) { + continue; + } + + $values[$ordinal] = $this->unmaskNull($value); + } + + return serialize([ + 'keyType' => $this->keyType, + 'valueType' => $this->valueType, + 'allowNullValues' => $this->allowNullValues, + 'values' => $values, + ]); + } + + public function unserialize($serialized) : void + { + $data = unserialize($serialized); + $this->__construct($data['keyType'], $data['valueType'], $data['allowNullValues']); + + foreach ($this->keyUniverse as $key) { + if (array_key_exists($key->ordinal(), $data['values'])) { + $this->put($key, $data['values'][$key->ordinal()]); + } + } + } + + public function getIterator() : Traversable + { + foreach ($this->keyUniverse as $key) { + if (null === $this->values[$key->ordinal()]) { + continue; + } + + yield $key => $this->unmaskNull($this->values[$key->ordinal()]); + } + } + + private function maskNull($value) + { + if (null === $value) { + return NullValue::instance(); + } + + return $value; + } + + private function unmaskNull($value) + { + if ($value instanceof NullValue) { + return null; + } + + return $value; + } + + /** + * @throws IllegalArgumentException when the passed key does not match the internal key type + */ + private function checkKeyType(AbstractEnum $key) : void + { + if (get_class($key) !== $this->keyType) { + throw new IllegalArgumentException(sprintf( + 'Object of type %s is not the same type as %s', + get_class($key), + $this->keyType + )); + } + } + + private function isValidValue($value) : bool + { + if (null === $value) { + if ($this->allowNullValues) { + return true; + } + + return false; + } + + switch ($this->valueType) { + case 'mixed': + return true; + + case 'bool': + case 'boolean': + return is_bool($value); + + case 'int': + case 'integer': + return is_int($value); + + case 'float': + case 'double': + return is_float($value); + + case 'string': + return is_string($value); + + case 'object': + return is_object($value); + + case 'array': + return is_array($value); + } + + return $value instanceof $this->valueType; + } +} diff --git a/user/plugins/login/vendor/dasprid/enum/src/Exception/CloneNotSupportedException.php b/user/plugins/login/vendor/dasprid/enum/src/Exception/CloneNotSupportedException.php new file mode 100644 index 00000000..4b37dbeb --- /dev/null +++ b/user/plugins/login/vendor/dasprid/enum/src/Exception/CloneNotSupportedException.php @@ -0,0 +1,10 @@ +getProperty('constants'); + $constantsProperty->setAccessible(true); + $constantsProperty->setValue([]); + + $valuesProperty = $reflectionClass->getProperty('values'); + $valuesProperty->setAccessible(true); + $valuesProperty->setValue([]); + + $allValuesLoadedProperty = $reflectionClass->getProperty('allValuesLoaded'); + $allValuesLoadedProperty->setAccessible(true); + $allValuesLoadedProperty->setValue([]); + } + + public function testToString() : void + { + $weekday = WeekDay::FRIDAY(); + self::assertSame('FRIDAY', (string) $weekday); + } + + public function testName() : void + { + $this->assertSame('WEDNESDAY', WeekDay::WEDNESDAY()->name()); + } + + public function testOrdinal() : void + { + $this->assertSame(2, WeekDay::WEDNESDAY()->ordinal()); + } + + public function testSameInstanceIsReturned() : void + { + self::assertSame(WeekDay::FRIDAY(), WeekDay::FRIDAY()); + } + + public static function testValueOf() : void + { + self::assertSame(WeekDay::FRIDAY(), WeekDay::valueOf('FRIDAY')); + } + + public function testValueOfInvalidConstant() : void + { + $this->expectException(IllegalArgumentException::class); + WeekDay::valueOf('CATURDAY'); + } + + public function testExceptionOnCloneAttempt() : void + { + $this->expectException(CloneNotSupportedException::class); + clone WeekDay::FRIDAY(); + } + + public function testExceptionOnSerializeAttempt() : void + { + $this->expectException(SerializeNotSupportedException::class); + serialize(WeekDay::FRIDAY()); + } + + public function testExceptionOnUnserializeAttempt() : void + { + $this->expectException(UnserializeNotSupportedException::class); + unserialize('O:24:"DASPRiD\\EnumTest\\WeekDay":0:{}'); + } + + public function testReturnValueOfValuesIsSortedByOrdinal() : void + { + // Initialize some week days out of order + WeekDay::SATURDAY(); + WeekDay::TUESDAY(); + + $ordinals = array_values(array_map(function (WeekDay $weekDay) : int { + return $weekDay->ordinal(); + }, WeekDay::values())); + + self::assertSame([0, 1, 2, 3, 4, 5, 6], $ordinals); + + $cachedOrdinals = array_values(array_map(function (WeekDay $weekDay) : int { + return $weekDay->ordinal(); + }, WeekDay::values())); + $this->assertSame($ordinals, $cachedOrdinals); + } + + public function testCompareTo() : void + { + $this->assertSame(-4, WeekDay::WEDNESDAY()->compareTo(WeekDay::SUNDAY())); + $this->assertSame(4, WeekDay::SUNDAY()->compareTo(WeekDay::WEDNESDAY())); + $this->assertSame(0, WeekDay::WEDNESDAY()->compareTo(WeekDay::WEDNESDAY())); + } + + public function testCompareToWrongEnum() : void + { + $this->expectException(MismatchException::class); + WeekDay::MONDAY()->compareTo(Planet::EARTH()); + } + + public function testParameterizedEnum() : void + { + $planet = Planet::EARTH(); + $this->assertSame(5.976e+24, $planet->mass()); + $this->assertSame(6.37814e6, $planet->radius()); + } +} diff --git a/user/plugins/login/vendor/dasprid/enum/test/EnumMapTest.php b/user/plugins/login/vendor/dasprid/enum/test/EnumMapTest.php new file mode 100644 index 00000000..d51a86cc --- /dev/null +++ b/user/plugins/login/vendor/dasprid/enum/test/EnumMapTest.php @@ -0,0 +1,243 @@ +expectException(IllegalArgumentException::class); + new EnumMap(stdClass::class, 'string', false); + } + + public function testUnexpectedKeyType() : void + { + $this->expectException(ExpectationException::class); + $map = new EnumMap(WeekDay::class, 'string', false); + $map->expect(Planet::class, 'string', false); + } + + public function testUnexpectedValueType() : void + { + $this->expectException(ExpectationException::class); + $map = new EnumMap(WeekDay::class, 'string', false); + $map->expect(WeekDay::class, 'int', false); + } + + public function testUnexpectedNullableValueType() : void + { + $this->expectException(ExpectationException::class); + $map = new EnumMap(WeekDay::class, 'string', true); + $map->expect(WeekDay::class, 'string', false); + } + + public function testExpectedTypes() : void + { + $map = new EnumMap(WeekDay::class, 'string', true); + $map->expect(WeekDay::class, 'string', true); + $this->addToAssertionCount(1); + } + + public function testSize() : void + { + $map = new EnumMap(WeekDay::class, 'string', true); + $this->assertSame(0, $map->size()); + $map->put(WeekDay::MONDAY(), 'foo'); + $this->assertSame(1, $map->size()); + } + + public function testContainsValue() : void + { + $map = new EnumMap(WeekDay::class, 'string', true); + $this->assertFalse($map->containsValue('foo')); + $map->put(WeekDay::TUESDAY(), 'foo'); + $this->assertTrue($map->containsValue('foo')); + $this->assertFalse($map->containsValue(null)); + $map->put(WeekDay::WEDNESDAY(), null); + $this->assertTrue($map->containsValue(null)); + } + + public function testContainsKey() : void + { + $map = new EnumMap(WeekDay::class, 'string', true); + $this->assertFalse($map->containsKey(WeekDay::TUESDAY())); + $map->put(WeekDay::TUESDAY(), 'foo'); + $this->assertTrue($map->containsKey(WeekDay::TUESDAY())); + $map->put(WeekDay::WEDNESDAY(), null); + $this->assertTrue($map->containsKey(WeekDay::WEDNESDAY())); + } + + public function testPutAndGet() : void + { + $map = new EnumMap(WeekDay::class, 'string', true); + $map->put(WeekDay::TUESDAY(), 'foo'); + $map->put(WeekDay::FRIDAY(), null); + $this->assertSame('foo', $map->get(WeekDay::TUESDAY())); + $this->assertSame(null, $map->get(WeekDay::WEDNESDAY())); + $this->assertSame(null, $map->get(WeekDay::FRIDAY())); + } + + public function testPutInvalidKey() : void + { + $this->expectException(IllegalArgumentException::class); + $map = new EnumMap(WeekDay::class, 'string', true); + $map->put(Planet::MARS(), 'foo'); + } + + public function invalidValues() : array + { + return [ + ['bool', null, false], + ['bool', 0], + ['boolean', 0], + ['int', 2.4], + ['integer', 5.3], + ['float', 3], + ['double', 7], + ['string', 1], + ['object', 1], + ['array', 1], + [stdClass::class, 1], + ]; + } + + /** + * @dataProvider invalidValues + * @param mixed $value + */ + public function testPutInvalidValue(string $valueType, $value, bool $allowNull = true) : void + { + $this->expectException(IllegalArgumentException::class); + $map = new EnumMap(WeekDay::class, $valueType, $allowNull); + $map->put(WeekDay::TUESDAY(), $value); + } + + public function validValues() : array + { + return [ + ['bool', null], + ['mixed', 'foo'], + ['mixed', 1], + ['mixed', new stdClass()], + ['bool', true], + ['boolean', false], + ['int', 1], + ['integer', 4], + ['float', 2.5], + ['double', 6.4], + ['string', 'foo'], + ['object', new stdClass()], + ['array', ['foo']], + [stdClass::class, new stdClass()], + ]; + } + + /** + * @dataProvider validValues + * @param mixed $value + */ + public function testPutValidValue(string $valueType, $value, bool $allowNull = true) : void + { + $map = new EnumMap(WeekDay::class, $valueType, $allowNull); + $map->put(WeekDay::TUESDAY(), $value); + $this->addToAssertionCount(1); + } + + public function testRemove() : void + { + $map = new EnumMap(WeekDay::class, 'string', true); + $map->put(WeekDay::TUESDAY(), 'foo'); + $map->remove(WeekDay::TUESDAY()); + $map->remove(WeekDay::WEDNESDAY()); + $this->assertSame(null, $map->get(WeekDay::TUESDAY())); + $this->assertSame(0, $map->size()); + } + + public function testClear() : void + { + $map = new EnumMap(WeekDay::class, 'string', true); + $map->put(WeekDay::TUESDAY(), 'foo'); + $map->clear(); + $this->assertSame(null, $map->get(WeekDay::TUESDAY())); + $this->assertSame(0, $map->size()); + } + + public function testEqualsWithSameInstance() : void + { + $map = new EnumMap(WeekDay::class, 'string', true); + $this->assertTrue($map->equals($map)); + } + + public function testEqualsWithDifferentSize() : void + { + $mapA = new EnumMap(WeekDay::class, 'string', true); + $mapB = new EnumMap(WeekDay::class, 'string', true); + $mapB->put(WeekDay::MONDAY(), 'foo'); + + $this->assertFalse($mapA->equals($mapB)); + } + + public function testEqualsWithDifferentValues() : void + { + $mapA = new EnumMap(WeekDay::class, 'string', true); + $mapA->put(WeekDay::MONDAY(), 'foo'); + $mapB = new EnumMap(WeekDay::class, 'string', true); + $mapB->put(WeekDay::MONDAY(), 'bar'); + + $this->assertFalse($mapA->equals($mapB)); + } + + public function testEqualsWithDifferentConstants() : void + { + $mapA = new EnumMap(WeekDay::class, 'string', true); + $mapA->put(WeekDay::MONDAY(), 'foo'); + $mapB = new EnumMap(WeekDay::class, 'string', true); + $mapB->put(WeekDay::TUESDAY(), 'foo'); + + $this->assertFalse($mapA->equals($mapB)); + } + + public function testValues() : void + { + $map = new EnumMap(WeekDay::class, 'string', true); + $this->assertSame([], $map->values()); + + $map->put(WeekDay::FRIDAY(), 'foo'); + $map->put(WeekDay::TUESDAY(), 'bar'); + $map->put(WeekDay::SUNDAY(), null); + + $this->assertSame(['bar', 'foo', null], $map->values()); + } + + public function testSerializeAndUnserialize() : void + { + $mapA = new EnumMap(WeekDay::class, 'string', true); + $mapA->put(WeekDay::MONDAY(), 'foo'); + $mapB = unserialize(serialize($mapA)); + + $this->assertTrue($mapA->equals($mapB)); + } + + public function testIterator() : void + { + $map = new EnumMap(WeekDay::class, 'string', true); + $map->put(WeekDay::FRIDAY(), 'foo'); + $map->put(WeekDay::TUESDAY(), 'bar'); + $map->put(WeekDay::SUNDAY(), null); + + $result = []; + + foreach ($map as $key => $value) { + $result[$key->ordinal()] = $value; + } + + $this->assertSame([1 => 'bar', 4 => 'foo', 6 => null], $result); + } +} diff --git a/user/plugins/login/vendor/dasprid/enum/test/NullValueTest.php b/user/plugins/login/vendor/dasprid/enum/test/NullValueTest.php new file mode 100644 index 00000000..9f706402 --- /dev/null +++ b/user/plugins/login/vendor/dasprid/enum/test/NullValueTest.php @@ -0,0 +1,31 @@ +expectException(CloneNotSupportedException::class); + clone NullValue::instance(); + } + + public function testExceptionOnSerializeAttempt() : void + { + $this->expectException(SerializeNotSupportedException::class); + serialize(NullValue::instance()); + } + + public function testExceptionOnUnserializeAttempt() : void + { + $this->expectException(UnserializeNotSupportedException::class); + unserialize('O:22:"DASPRiD\\Enum\\NullValue":0:{}'); + } +} diff --git a/user/plugins/login/vendor/dasprid/enum/test/Planet.php b/user/plugins/login/vendor/dasprid/enum/test/Planet.php new file mode 100644 index 00000000..3c44c1d2 --- /dev/null +++ b/user/plugins/login/vendor/dasprid/enum/test/Planet.php @@ -0,0 +1,73 @@ +mass = $mass; + $this->radius = $radius; + } + + public function mass() : float + { + return $this->mass; + } + + public function radius() : float + { + return $this->radius; + } + + public function surfaceGravity() : float + { + return self::G * $this->mass / ($this->radius * $this->radius); + } + + public function surfaceWeight(float $otherMass) : float + { + return $otherMass * $this->surfaceGravity(); + } +} diff --git a/user/plugins/login/vendor/dasprid/enum/test/WeekDay.php b/user/plugins/login/vendor/dasprid/enum/test/WeekDay.php new file mode 100644 index 00000000..70b8db5a --- /dev/null +++ b/user/plugins/login/vendor/dasprid/enum/test/WeekDay.php @@ -0,0 +1,26 @@ + PHP_INT_MAX` logic with `$range <= PHP_INT_MAX` (thanks + [@oittaa](https://github.com/oittaa) and [@CodesInChaos](https://github.com/CodesInChaos)) +* `tests/phpunit.sh` now also runs the tests with `mbstring.func_overload` and + `open_basedir` +* Style consistency, whitespace cleanup, more meaningful variable names + +### Version 0.9.1 (pre-release) - 2015-07-09 + +* Return random values on integer ranges > `PHP_INT_MAX` (thanks [@CodesInChaos](https://github.com/CodesInChaos)) +* Determined CSPRNG preference: + 1. `mcrypt_create_iv()` with `MCRYPT_DEV_URANDOM` + 2. `/dev/arandom` + 3. `/dev/urandom` + 4. `openssl_random_pseudo_bytes()` +* Optimized backend selection (thanks [@lt](https://github.com/lt)) +* Fix #3 (thanks [@scottchiefbaker](https://github.com/scottchiefbaker)) + +### Version 0.9.0 (pre-release) - 2015-07-07 + +This should be a sane polyfill for PHP 7's `random_bytes()` and `random_int()`. +We hesitate to call it production ready until it has received sufficient third +party review. \ No newline at end of file diff --git a/user/plugins/login/vendor/paragonie/random_compat/LICENSE b/user/plugins/login/vendor/paragonie/random_compat/LICENSE new file mode 100644 index 00000000..45c7017d --- /dev/null +++ b/user/plugins/login/vendor/paragonie/random_compat/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2015 Paragon Initiative Enterprises + +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. + diff --git a/user/plugins/login/vendor/paragonie/random_compat/RATIONALE.md b/user/plugins/login/vendor/paragonie/random_compat/RATIONALE.md new file mode 100644 index 00000000..a6e73072 --- /dev/null +++ b/user/plugins/login/vendor/paragonie/random_compat/RATIONALE.md @@ -0,0 +1,42 @@ +## Rationale (Design Decisions) + +### Reasoning Behind the Order of Preferred Random Data Sources + +The order is: + + 1. `libsodium if available` + 2. `fread() /dev/urandom if available` + 3. `mcrypt_create_iv($bytes, MCRYPT_DEV_URANDOM)` + 4. `COM('CAPICOM.Utilities.1')->GetRandom()` + 5. `openssl_random_pseudo_bytes()` + +If libsodium is available, we get random data from it. This is the preferred +method on all OSes, but libsodium is not very widely installed, so other +fallbacks are available. + +Next, we read `/dev/urandom` (if it exists). This is the preferred file to read +for random data for cryptographic purposes for BSD and Linux. This step +is skipped on Windows, because someone could create a `C:\dev\urandom` +file and PHP would helpfully (but insecurely) return bytes from it. + +Despite [strongly urging people not to use mcrypt in their projects](https://paragonie.com/blog/2015/05/if-you-re-typing-word-mcrypt-into-your-code-you-re-doing-it-wrong) +(because libmcrypt is abandonware and the API puts too much responsibility on the +implementor) we prioritize `mcrypt_create_iv()` with `MCRYPT_DEV_URANDOM` above +the remaining implementations. + +The reason is simple: `mcrypt_create_iv()` is part of PHP's `ext/mcrypt` code, +and is not part `libmcrypt`. It actually does the right thing: + + * On Unix-based operating systems, it reads from `/dev/urandom` which + (unlike `/dev/random`) is the sane and correct thing to do. + * On Windows, it reads from `CryptGenRandom`, which is an exclusively Windows + way to get random bytes. + +If we're on Windows and don't have access to `mcrypt`, we use `CAPICOM.Utilities.1`. + +Finally, we use `openssl_random_pseudo_bytes()` **as a last resort**, due to +[PHP bug #70014](https://bugs.php.net/bug.php?id=70014). Internally, this +function calls `RAND_pseudo_bytes()`, which has been [deprecated](https://github.com/paragonie/random_compat/issues/5) +by the OpenSSL team. Furthermore, [it might silently return weak random data](https://github.com/paragonie/random_compat/issues/6#issuecomment-119564973) +if it is called before OpenSSL's **userspace** CSPRNG is seeded. Also, +[you want the OS CSPRNG, not a userspace CSPRNG](http://sockpuppet.org/blog/2014/02/25/safely-generate-random-numbers/). diff --git a/user/plugins/login/vendor/paragonie/random_compat/README.md b/user/plugins/login/vendor/paragonie/random_compat/README.md new file mode 100644 index 00000000..63c6d715 --- /dev/null +++ b/user/plugins/login/vendor/paragonie/random_compat/README.md @@ -0,0 +1,176 @@ +# random_compat + +[![Build Status](https://travis-ci.org/paragonie/random_compat.svg?branch=v1.x)](https://travis-ci.org/paragonie/random_compat) +[![Scrutinizer](https://scrutinizer-ci.com/g/paragonie/random_compat/badges/quality-score.png?b=v1.x)](https://scrutinizer-ci.com/g/paragonie/random_compat) + +PHP 5.x polyfill for `random_bytes()` and `random_int()` created and maintained +by [Paragon Initiative Enterprises](https://paragonie.com). + +Although this library *should* function in earlier versions of PHP, we will only +consider issues relevant to [supported PHP versions](https://secure.php.net/supported-versions.php). +**If you are using an unsupported version of PHP, please upgrade as soon as possible.** + +## Important + +Although this library has been examined by some security experts in the PHP +community, there will always be a chance that we overlooked something. Please +ask your favorite trusted hackers to hammer it for implementation errors and +bugs before even thinking about deploying it in production. + +**Do not use the master branch, use a [stable release](https://github.com/paragonie/random_compat/releases/latest).** + +For the background of this library, please refer to our blog post on +[Generating Random Integers and Strings in PHP](https://paragonie.com/blog/2015/07/how-safely-generate-random-strings-and-integers-in-php). + +### Usability Notice + +If PHP cannot safely generate random data, this library will throw an `Exception`. +It will never fall back to insecure random data. If this keeps happening, upgrade +to a newer version of PHP immediately. + +## Installing + +**With [Composer](https://getcomposer.org):** + + composer require paragonie/random_compat + +**Signed PHP Archive:** + +As of version 1.2.0, we also ship an ECDSA-signed PHP Archive with each stable +release on Github. + +1. Download [the `.phar`, `.phar.pubkey`, and `.phar.pubkey.asc`](https://github.com/paragonie/random_compat/releases/latest) files. +2. (**Recommended** but not required) Verify the PGP signature of `.phar.pubkey` + (contained within the `.asc` file) using the [PGP public key for Paragon Initiative Enterprises](https://paragonie.com/static/gpg-public-key.txt). +3. Extract both `.phar` and `.phar.pubkey` files to the same directory. +4. `require_once "/path/to/random_compat.phar";` +5. When a new version is released, you only need to replace the `.phar` file; + the `.pubkey` will not change (unless our signing key is ever compromised). + +**Manual Installation:** + +1. Download [a stable release](https://github.com/paragonie/random_compat/releases/latest). +2. Extract the files into your project. +3. `require_once "/path/to/random_compat/lib/random.php";` + +## Usage + +This library exposes the [CSPRNG functions added in PHP 7](https://secure.php.net/manual/en/ref.csprng.php) +for use in PHP 5 projects. Their behavior should be identical. + +### Generate a string of random bytes + +```php +try { + $string = random_bytes(32); +} catch (TypeError $e) { + // Well, it's an integer, so this IS unexpected. + die("An unexpected error has occurred"); +} catch (Error $e) { + // This is also unexpected because 32 is a reasonable integer. + die("An unexpected error has occurred"); +} catch (Exception $e) { + // If you get this message, the CSPRNG failed hard. + die("Could not generate a random string. Is our OS secure?"); +} + +var_dump(bin2hex($string)); +// string(64) "5787c41ae124b3b9363b7825104f8bc8cf27c4c3036573e5f0d4a91ad2eeac6f" +``` + +### Generate a random integer between two given integers (inclusive) + +```php +try { + $int = random_int(0,255); + +} catch (TypeError $e) { + // Well, it's an integer, so this IS unexpected. + die("An unexpected error has occurred"); +} catch (Error $e) { + // This is also unexpected because 0 and 255 are both reasonable integers. + die("An unexpected error has occurred"); +} catch (Exception $e) { + // If you get this message, the CSPRNG failed hard. + die("Could not generate a random string. Is our OS secure?"); +} + +var_dump($int); +// int(47) +``` + +### Exception handling + +When handling exceptions and errors you must account for differences between +PHP 5 and PHP7. + +The differences: + +* Catching `Error` works, so long as it is caught before `Exception`. +* Catching `Exception` has different behavior, without previously catching `Error`. +* There is *no* portable way to catch all errors/exceptions. + +#### Our recommendation + +**Always** catch `Error` before `Exception`. + +#### Example + +```php +try { + return random_int(1, $userInput); +} catch (TypeError $e) { + // This is okay, so long as `Error` is caught before `Exception`. + throw new Exception('Please enter a number!'); +} catch (Error $e) { + // This is required, if you do not need to do anything just rethrow. + throw $e; +} catch (Exception $e) { + // This is optional and maybe omitted if you do not want to handle errors + // during generation. + throw new InternalServerErrorException( + 'Oops, our server is bust and cannot generate any random data.', + 500, + $e + ); +} +``` + +## Contributors + +This project would not be anywhere near as excellent as it is today if it +weren't for the contributions of the following individuals: + +* [@AndrewCarterUK (Andrew Carter)](https://github.com/AndrewCarterUK) +* [@asgrim (James Titcumb)](https://github.com/asgrim) +* [@bcremer (Benjamin Cremer)](https://github.com/bcremer) +* [@CodesInChaos (Christian Winnerlein)](https://github.com/CodesInChaos) +* [@chriscct7 (Chris Christoff)](https://github.com/chriscct7) +* [@cs278 (Chris Smith)](https://github.com/cs278) +* [@cweagans (Cameron Eagans)](https://github.com/cweagans) +* [@dd32 (Dion Hulse)](https://github.com/dd32) +* [@geggleto (Glenn Eggleton)](https://github.com/geggleto) +* [@ircmaxell (Anthony Ferrara)](https://github.com/ircmaxell) +* [@jedisct1 (Frank Denis)](https://github.com/jedisct1) +* [@juliangut (Julián Gutiérrez)](https://github.com/juliangut) +* [@kelunik (Niklas Keller)](https://github.com/kelunik) +* [@lt (Leigh)](https://github.com/lt) +* [@MasonM (Mason Malone)](https://github.com/MasonM) +* [@mmeyer2k (Michael M)](https://github.com/mmeyer2k) +* [@narfbg (Andrey Andreev)](https://github.com/narfbg) +* [@nicolas-grekas (Nicolas Grekas)](https://github.com/nicolas-grekas) +* [@oittaa](https://github.com/oittaa) +* [@oucil (Kevin Farley)](https://github.com/oucil) +* [@redragonx (Stephen Chavez)](https://github.com/redragonx) +* [@rchouinard (Ryan Chouinard)](https://github.com/rchouinard) +* [@SammyK (Sammy Kaye Powers)](https://github.com/SammyK) +* [@scottchiefbaker (Scott Baker)](https://github.com/scottchiefbaker) +* [@skyosev (Stoyan Kyosev)](https://github.com/skyosev) +* [@stof (Christophe Coevoet)](https://github.com/stof) +* [@teohhanhui (Teoh Han Hui)](https://github.com/teohhanhui) +* [@tom-- (Tom Worster)](https://github.com/tom--) +* [@tsyr2ko](https://github.com/tsyr2ko) +* [@trowski (Aaron Piotrowski)](https://github.com/trowski) +* [@twistor (Chris Lepannen)](https://github.com/twistor) +* [@voku (Lars Moelleken)](https://github.com/voku) +* [@xabbuh (Christian Flothmann)](https://github.com/xabbuh) diff --git a/user/plugins/login/vendor/paragonie/random_compat/SECURITY.md b/user/plugins/login/vendor/paragonie/random_compat/SECURITY.md new file mode 100644 index 00000000..8f731b38 --- /dev/null +++ b/user/plugins/login/vendor/paragonie/random_compat/SECURITY.md @@ -0,0 +1,108 @@ +# An Invitation to Security Researchers + +Every company says they take security "very seriously." Rather than bore anyone +with banal boilerplate, here are some quick answers followed by detailed +elaboration. If you have any questions about our policies, please email them to +`scott@paragonie.com`. + +## Quick Answers + +* There is no compulsion to disclose vulnerabilities privately, but we + appreciate a head's up. +* `security@paragonie.com` will get your reports to the right person. Our GPG + fingerprint, should you decide to encrypt your report, is + `7F52 D5C6 1D12 55C7 3136 2E82 6B97 A1C2 8264 04DA`. + +* **YES**, we will reward security researchers who disclose vulnerabilities in + our software. +* In most cases, **No Proof-of-Concept Required.** + +## How to Report a Security Bug to Paragon Initiative Enterprises + +### There is no compulsion to disclose privately. + +We believe vulnerability disclosure style is a personal choice and enjoy working +with a diverse community. We understand and appreciate the importance of Full +Disclosure in the history and practice of security research. + +We would *like* to know about high-severity bugs before they become public +knowledge, so we can fix them in a timely manner, but **we do not believe in +threatening researchers or trying to enforce vulnerability embargoes**. + +Ultimately, if you discover a security-affecting vulnerability, what you do with +it is your choice. We would like to work with people, and to celebrate and +reward their skill, experience, and dedication. We appreciate being informed of +our mistakes so we can learn from them and build a better product. Our goal is +to empower the community. + +### Where to Send Security Vulnerabilities + +Our security email address is `security@paragonie.com`. Also feel free to open a +new issue on Github if you want to disclose publicly. + +``` +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG + +mQENBFUgwRUBCADcIpqNwyYc5UmY/tpx1sF/rQ3knR1YNXYZThzFV+Gmqhp1fDH5 +qBs9foh1xwI6O7knWmQngnf/nBumI3x6xj7PuOdEZUh2FwCG/VWnglW8rKmoHzHA +ivjiu9SLnPIPAgHSHeh2XD7q3Ndm3nenbjAiRFNl2iXcwA2cTQp9Mmfw9vVcw0G0 +z1o0G3s8cC8ZS6flFySIervvfSRWj7A1acI5eE3+AH/qXJRdEJ+9J8OB65p1JMfk +6+fWgOB1XZxMpz70S0rW6IX38WDSRhEK2fXyZJAJjyt+YGuzjZySNSoQR/V6vNYn +syrNPCJ2i5CgZQxAkyBBcr7koV9RIhPRzct/ABEBAAG0IVNlY3VyaXR5IDxzZWN1 +cml0eUBwYXJhZ29uaWUuY29tPokBOQQTAQIAIwUCVSDBFQIbAwcLCQgHAwIBBhUI +AgkKCwQWAgMBAh4BAheAAAoJEGuXocKCZATat2YIAIoejNFEQ2c1iaOEtSuB7Pn/ +WLbsDsHNLDKOV+UnfaCjv/vL7D+5NMChFCi2frde/NQb2TsjqmIH+V+XbnJtlrXD +Vj7yvMVal+Jqjwj7v4eOEWcKVcFZk+9cfUgh7t92T2BMX58RpgZF0IQZ6Z1R3FfC +9Ub4X6ykW+te1q0/4CoRycniwmlQi6iGSr99LQ5pfJq2Qlmz/luTZ0UX0h575T7d +cp2T1sX/zFRk/fHeANWSksipdDBjAXR7NMnYZgw2HghEdFk/xRDY7K1NRWNZBf05 +WrMHmh6AIVJiWZvI175URxEe268hh+wThBhXQHMhFNJM1qPIuzb4WogxM3UUD7m5 +AQ0EVSDBFQEIALNkpzSuJsHAHh79sc0AYWztdUe2MzyofQbbOnOCpWZebYsC3EXU +335fIg59k0m6f+O7GmEZzzIv5v0i99GS1R8CJm6FvhGqtH8ZqmOGbc71WdJSiNVE +0kpQoJlVzRbig6ZyyjzrggbM1eh5OXOk5pw4+23FFEdw7JWU0HJS2o71r1hwp05Z +vy21kcUEobz/WWQQyGS0Neo7PJn+9KS6wOxXul/UE0jct/5f7KLMdWMJ1VgniQmm +hjvkHLPSICteqCI04RfcmMseW9gueHQXeUu1SNIvsWa2MhxjeBej3pDnrZWszKwy +gF45GO9/v4tkIXNMy5J1AtOyRgQ3IUMqp8EAEQEAAYkBHwQYAQIACQUCVSDBFQIb +DAAKCRBrl6HCgmQE2jnIB/4/xFz8InpM7eybnBOAir3uGcYfs3DOmaKn7qWVtGzv +rKpQPYnVtlU2i6Z5UO4c4jDLT/8Xm1UDz3Lxvqt4xCaDwJvBZexU5BMK8l5DvOzH +6o6P2L1UDu6BvmPXpVZz7/qUhOnyf8VQg/dAtYF4/ax19giNUpI5j5o5mX5w80Rx +qSXV9NdSL4fdjeG1g/xXv2luhoV53T1bsycI3wjk/x5tV+M2KVhZBvvuOm/zhJje +oLWp0saaESkGXIXqurj6gZoujJvSvzl0n9F9VwqMEizDUfrXgtD1siQGhP0sVC6q +ha+F/SAEJ0jEquM4TfKWWU2S5V5vgPPpIQSYRnhQW4b1 +=xJPW +-----END PGP PUBLIC KEY BLOCK----- +``` + +### We Will Reward Security Researchers + +**This process has not been formalized; nor have dollar amounts been +discussed.** + +However, if you report a valid security-affecting bug, we will compensate you +for the time spent finding the vulnerability and reward you for being a good +neighbor. + +#### What does a "valid" bug mean? + +There are two sides to this: + +1. Some have spammed projects with invalid bug reports hoping to collect + bounties for pressing a button and running an automated analysis tool. This + is not cool. +2. There is a potential for the developers of a project to declare all security + bug reports as invalid to save money. + +Our team members have an established history of reporting vulnerabilities to +large open source projects. **We aren't in the business of ripping people off.** +When in doubt, our policy is to err on the side of generosity. + +### No Proof-of-Concept Required + +We might ask for one if we feel we do not understand some of the details +pertaining to a specific vulnerability. We certainly appreciate them if you +include them in your report, but we believe **the burden lies with the developer +to prove their software *is* secure** rather than with the researcher to prove +that it isn't. + +In our experience, most bugs are simpler to fix than they are to exploit. + diff --git a/user/plugins/login/vendor/paragonie/random_compat/build-phar.sh b/user/plugins/login/vendor/paragonie/random_compat/build-phar.sh new file mode 100644 index 00000000..b4a5ba31 --- /dev/null +++ b/user/plugins/login/vendor/paragonie/random_compat/build-phar.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +basedir=$( dirname $( readlink -f ${BASH_SOURCE[0]} ) ) + +php -dphar.readonly=0 "$basedir/other/build_phar.php" $* \ No newline at end of file diff --git a/user/plugins/login/vendor/paragonie/random_compat/composer.json b/user/plugins/login/vendor/paragonie/random_compat/composer.json new file mode 100644 index 00000000..d363f4c8 --- /dev/null +++ b/user/plugins/login/vendor/paragonie/random_compat/composer.json @@ -0,0 +1,35 @@ +{ + "name": "paragonie/random_compat", + "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7", + "keywords": [ + "csprng", + "random", + "pseudorandom" + ], + "license": "MIT", + "type": "library", + "authors": [ + { + "name": "Paragon Initiative Enterprises", + "email": "security@paragonie.com", + "homepage": "https://paragonie.com" + } + ], + "support": { + "issues": "https://github.com/paragonie/random_compat/issues", + "email": "info@paragonie.com", + "source": "https://github.com/paragonie/random_compat" + }, + "require": { + "php": ">=5.2.0" + }, + "require-dev": { + "phpunit/phpunit": "4.*|5.*" + }, + "suggest": { + "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes." + }, + "autoload": { + "files": ["lib/random.php"] + } +} diff --git a/user/plugins/login/vendor/paragonie/random_compat/dist/random_compat.phar.pubkey b/user/plugins/login/vendor/paragonie/random_compat/dist/random_compat.phar.pubkey new file mode 100644 index 00000000..eb50ebfc --- /dev/null +++ b/user/plugins/login/vendor/paragonie/random_compat/dist/random_compat.phar.pubkey @@ -0,0 +1,5 @@ +-----BEGIN PUBLIC KEY----- +MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEEd+wCqJDrx5B4OldM0dQE0ZMX+lx1ZWm +pui0SUqD4G29L3NGsz9UhJ/0HjBdbnkhIK5xviT0X5vtjacF6ajgcCArbTB+ds+p ++h7Q084NuSuIpNb6YPfoUFgC/CL9kAoc +-----END PUBLIC KEY----- diff --git a/user/plugins/login/vendor/paragonie/random_compat/dist/random_compat.phar.pubkey.asc b/user/plugins/login/vendor/paragonie/random_compat/dist/random_compat.phar.pubkey.asc new file mode 100644 index 00000000..6a1d7f30 --- /dev/null +++ b/user/plugins/login/vendor/paragonie/random_compat/dist/random_compat.phar.pubkey.asc @@ -0,0 +1,11 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v2.0.22 (MingW32) + +iQEcBAABAgAGBQJWtW1hAAoJEGuXocKCZATaJf0H+wbZGgskK1dcRTsuVJl9IWip +QwGw/qIKI280SD6/ckoUMxKDCJiFuPR14zmqnS36k7N5UNPnpdTJTS8T11jttSpg +1LCmgpbEIpgaTah+cELDqFCav99fS+bEiAL5lWDAHBTE/XPjGVCqeehyPYref4IW +NDBIEsvnHPHPLsn6X5jq4+Yj5oUixgxaMPiR+bcO4Sh+RzOVB6i2D0upWfRXBFXA +NNnsg9/zjvoC7ZW73y9uSH+dPJTt/Vgfeiv52/v41XliyzbUyLalf02GNPY+9goV +JHG1ulEEBJOCiUD9cE1PUIJwHA/HqyhHIvV350YoEFiHl8iSwm7SiZu5kPjaq74= +=B6+8 +-----END PGP SIGNATURE----- diff --git a/user/plugins/login/vendor/paragonie/random_compat/lib/byte_safe_strings.php b/user/plugins/login/vendor/paragonie/random_compat/lib/byte_safe_strings.php new file mode 100644 index 00000000..6de294f8 --- /dev/null +++ b/user/plugins/login/vendor/paragonie/random_compat/lib/byte_safe_strings.php @@ -0,0 +1,181 @@ + RandomCompat_strlen($binary_string)) { + return ''; + } + + return (string) mb_substr($binary_string, $start, $length, '8bit'); + } + + } else { + + /** + * substr() implementation that isn't brittle to mbstring.func_overload + * + * This version just uses the default substr() + * + * @param string $binary_string + * @param int $start + * @param int $length (optional) + * + * @throws TypeError + * + * @return string + */ + function RandomCompat_substr($binary_string, $start, $length = null) + { + if (!is_string($binary_string)) { + throw new TypeError( + 'RandomCompat_substr(): First argument should be a string' + ); + } + + if (!is_int($start)) { + throw new TypeError( + 'RandomCompat_substr(): Second argument should be an integer' + ); + } + + if ($length !== null) { + if (!is_int($length)) { + throw new TypeError( + 'RandomCompat_substr(): Third argument should be an integer, or omitted' + ); + } + + return (string) substr($binary_string, $start, $length); + } + + return (string) substr($binary_string, $start); + } + } +} diff --git a/user/plugins/login/vendor/paragonie/random_compat/lib/cast_to_int.php b/user/plugins/login/vendor/paragonie/random_compat/lib/cast_to_int.php new file mode 100644 index 00000000..dc4048c9 --- /dev/null +++ b/user/plugins/login/vendor/paragonie/random_compat/lib/cast_to_int.php @@ -0,0 +1,74 @@ + operators might accidentally let a float + * through. + * + * @param int|float $number The number we want to convert to an int + * @param boolean $fail_open Set to true to not throw an exception + * + * @return float|int + * + * @throws TypeError + */ + function RandomCompat_intval($number, $fail_open = false) + { + if (is_int($number) || is_float($number)) { + $number += 0; + } elseif (is_numeric($number)) { + $number += 0; + } + + if ( + is_float($number) + && + $number > ~PHP_INT_MAX + && + $number < PHP_INT_MAX + ) { + $number = (int) $number; + } + + if (is_int($number)) { + return (int) $number; + } elseif (!$fail_open) { + throw new TypeError( + 'Expected an integer.' + ); + } + return $number; + } +} diff --git a/user/plugins/login/vendor/paragonie/random_compat/lib/error_polyfill.php b/user/plugins/login/vendor/paragonie/random_compat/lib/error_polyfill.php new file mode 100644 index 00000000..17ece7b2 --- /dev/null +++ b/user/plugins/login/vendor/paragonie/random_compat/lib/error_polyfill.php @@ -0,0 +1,49 @@ += 70000) { + return; +} + +if (!defined('RANDOM_COMPAT_READ_BUFFER')) { + define('RANDOM_COMPAT_READ_BUFFER', 8); +} + +$RandomCompatDIR = dirname(__FILE__); + +require_once $RandomCompatDIR . '/byte_safe_strings.php'; +require_once $RandomCompatDIR . '/cast_to_int.php'; +require_once $RandomCompatDIR . '/error_polyfill.php'; + +if (!is_callable('random_bytes')) { + /** + * PHP 5.2.0 - 5.6.x way to implement random_bytes() + * + * We use conditional statements here to define the function in accordance + * to the operating environment. It's a micro-optimization. + * + * In order of preference: + * 1. Use libsodium if available. + * 2. fread() /dev/urandom if available (never on Windows) + * 3. mcrypt_create_iv($bytes, MCRYPT_DEV_URANDOM) + * 4. COM('CAPICOM.Utilities.1')->GetRandom() + * + * See RATIONALE.md for our reasoning behind this particular order + */ + if (extension_loaded('libsodium')) { + // See random_bytes_libsodium.php + if (PHP_VERSION_ID >= 50300 && is_callable('\\Sodium\\randombytes_buf')) { + require_once $RandomCompatDIR . '/random_bytes_libsodium.php'; + } elseif (method_exists('Sodium', 'randombytes_buf')) { + require_once $RandomCompatDIR . '/random_bytes_libsodium_legacy.php'; + } + } + + /** + * Reading directly from /dev/urandom: + */ + if (DIRECTORY_SEPARATOR === '/') { + // DIRECTORY_SEPARATOR === '/' on Unix-like OSes -- this is a fast + // way to exclude Windows. + $RandomCompatUrandom = true; + $RandomCompat_basedir = ini_get('open_basedir'); + + if (!empty($RandomCompat_basedir)) { + $RandomCompat_open_basedir = explode( + PATH_SEPARATOR, + strtolower($RandomCompat_basedir) + ); + $RandomCompatUrandom = (array() !== array_intersect( + array('/dev', '/dev/', '/dev/urandom'), + $RandomCompat_open_basedir + )); + $RandomCompat_open_basedir = null; + } + + if ( + !is_callable('random_bytes') + && + $RandomCompatUrandom + && + @is_readable('/dev/urandom') + ) { + // Error suppression on is_readable() in case of an open_basedir + // or safe_mode failure. All we care about is whether or not we + // can read it at this point. If the PHP environment is going to + // panic over trying to see if the file can be read in the first + // place, that is not helpful to us here. + + // See random_bytes_dev_urandom.php + require_once $RandomCompatDIR . '/random_bytes_dev_urandom.php'; + } + // Unset variables after use + $RandomCompat_basedir = null; + } else { + $RandomCompatUrandom = false; + } + + /** + * mcrypt_create_iv() + * + * We only want to use mcypt_create_iv() if: + * + * - random_bytes() hasn't already been defined + * - the mcrypt extensions is loaded + * - One of these two conditions is true: + * - We're on Windows (DIRECTORY_SEPARATOR !== '/') + * - We're not on Windows and /dev/urandom is readabale + * (i.e. we're not in a chroot jail) + * - Special case: + * - If we're not on Windows, but the PHP version is between + * 5.6.10 and 5.6.12, we don't want to use mcrypt. It will + * hang indefinitely. This is bad. + * - If we're on Windows, we want to use PHP >= 5.3.7 or else + * we get insufficient entropy errors. + */ + if ( + !is_callable('random_bytes') + && + // Windows on PHP < 5.3.7 is broken, but non-Windows is not known to be. + (DIRECTORY_SEPARATOR === '/' || PHP_VERSION_ID >= 50307) + && + // Prevent this code from hanging indefinitely on non-Windows; + // see https://bugs.php.net/bug.php?id=69833 + ( + DIRECTORY_SEPARATOR !== '/' || + (PHP_VERSION_ID <= 50609 || PHP_VERSION_ID >= 50613) + ) + && + extension_loaded('mcrypt') + ) { + // See random_bytes_mcrypt.php + require_once $RandomCompatDIR . '/random_bytes_mcrypt.php'; + } + $RandomCompatUrandom = null; + + /** + * This is a Windows-specific fallback, for when the mcrypt extension + * isn't loaded. + */ + if ( + !is_callable('random_bytes') + && + extension_loaded('com_dotnet') + && + class_exists('COM') + ) { + $RandomCompat_disabled_classes = preg_split( + '#\s*,\s*#', + strtolower(ini_get('disable_classes')) + ); + + if (!in_array('com', $RandomCompat_disabled_classes)) { + try { + $RandomCompatCOMtest = new COM('CAPICOM.Utilities.1'); + if (method_exists($RandomCompatCOMtest, 'GetRandom')) { + // See random_bytes_com_dotnet.php + require_once $RandomCompatDIR . '/random_bytes_com_dotnet.php'; + } + } catch (com_exception $e) { + // Don't try to use it. + } + } + $RandomCompat_disabled_classes = null; + $RandomCompatCOMtest = null; + } + + /** + * openssl_random_pseudo_bytes() + */ + if ( + ( + // Unix-like with PHP >= 5.3.0 or + ( + DIRECTORY_SEPARATOR === '/' + && + PHP_VERSION_ID >= 50300 + ) + || + // Windows with PHP >= 5.4.1 + PHP_VERSION_ID >= 50401 + ) + && + !function_exists('random_bytes') + && + extension_loaded('openssl') + ) { + // See random_bytes_openssl.php + require_once $RandomCompatDIR . '/random_bytes_openssl.php'; + } + + /** + * throw new Exception + */ + if (!is_callable('random_bytes')) { + /** + * We don't have any more options, so let's throw an exception right now + * and hope the developer won't let it fail silently. + * + * @param mixed $length + * @return void + * @throws Exception + */ + function random_bytes($length) + { + unset($length); // Suppress "variable not used" warnings. + throw new Exception( + 'There is no suitable CSPRNG installed on your system' + ); + } + } +} + +if (!is_callable('random_int')) { + require_once $RandomCompatDIR . '/random_int.php'; +} + +$RandomCompatDIR = null; diff --git a/user/plugins/login/vendor/paragonie/random_compat/lib/random_bytes_com_dotnet.php b/user/plugins/login/vendor/paragonie/random_compat/lib/random_bytes_com_dotnet.php new file mode 100644 index 00000000..28cc56ac --- /dev/null +++ b/user/plugins/login/vendor/paragonie/random_compat/lib/random_bytes_com_dotnet.php @@ -0,0 +1,88 @@ +GetRandom($bytes, 0)); + if (RandomCompat_strlen($buf) >= $bytes) { + /** + * Return our random entropy buffer here: + */ + return RandomCompat_substr($buf, 0, $bytes); + } + ++$execCount; + } while ($execCount < $bytes); + + /** + * If we reach here, PHP has failed us. + */ + throw new Exception( + 'Could not gather sufficient random data' + ); + } +} diff --git a/user/plugins/login/vendor/paragonie/random_compat/lib/random_bytes_dev_urandom.php b/user/plugins/login/vendor/paragonie/random_compat/lib/random_bytes_dev_urandom.php new file mode 100644 index 00000000..8bf70341 --- /dev/null +++ b/user/plugins/login/vendor/paragonie/random_compat/lib/random_bytes_dev_urandom.php @@ -0,0 +1,150 @@ + 0); + + /** + * Is our result valid? + */ + if ($buf !== false) { + if (RandomCompat_strlen($buf) === $bytes) { + /** + * Return our random entropy buffer here: + */ + return $buf; + } + } + } + + /** + * If we reach here, PHP has failed us. + */ + throw new Exception( + 'Error reading from source device' + ); + } +} diff --git a/user/plugins/login/vendor/paragonie/random_compat/lib/random_bytes_libsodium.php b/user/plugins/login/vendor/paragonie/random_compat/lib/random_bytes_libsodium.php new file mode 100644 index 00000000..7d32b21f --- /dev/null +++ b/user/plugins/login/vendor/paragonie/random_compat/lib/random_bytes_libsodium.php @@ -0,0 +1,88 @@ + 2147483647) { + $buf = ''; + for ($i = 0; $i < $bytes; $i += 1073741824) { + $n = ($bytes - $i) > 1073741824 + ? 1073741824 + : $bytes - $i; + $buf .= \Sodium\randombytes_buf($n); + } + } else { + $buf = \Sodium\randombytes_buf($bytes); + } + + if ($buf !== false) { + if (RandomCompat_strlen($buf) === $bytes) { + return $buf; + } + } + + /** + * If we reach here, PHP has failed us. + */ + throw new Exception( + 'Could not gather sufficient random data' + ); + } +} diff --git a/user/plugins/login/vendor/paragonie/random_compat/lib/random_bytes_libsodium_legacy.php b/user/plugins/login/vendor/paragonie/random_compat/lib/random_bytes_libsodium_legacy.php new file mode 100644 index 00000000..ba93c403 --- /dev/null +++ b/user/plugins/login/vendor/paragonie/random_compat/lib/random_bytes_libsodium_legacy.php @@ -0,0 +1,92 @@ + 2147483647) { + for ($i = 0; $i < $bytes; $i += 1073741824) { + $n = ($bytes - $i) > 1073741824 + ? 1073741824 + : $bytes - $i; + $buf .= Sodium::randombytes_buf($n); + } + } else { + $buf .= Sodium::randombytes_buf($bytes); + } + + if (is_string($buf)) { + if (RandomCompat_strlen($buf) === $bytes) { + return $buf; + } + } + + /** + * If we reach here, PHP has failed us. + */ + throw new Exception( + 'Could not gather sufficient random data' + ); + } +} diff --git a/user/plugins/login/vendor/paragonie/random_compat/lib/random_bytes_mcrypt.php b/user/plugins/login/vendor/paragonie/random_compat/lib/random_bytes_mcrypt.php new file mode 100644 index 00000000..3bce91a5 --- /dev/null +++ b/user/plugins/login/vendor/paragonie/random_compat/lib/random_bytes_mcrypt.php @@ -0,0 +1,77 @@ + operators might accidentally let a float + * through. + */ + + try { + $min = RandomCompat_intval($min); + } catch (TypeError $ex) { + throw new TypeError( + 'random_int(): $min must be an integer' + ); + } + + try { + $max = RandomCompat_intval($max); + } catch (TypeError $ex) { + throw new TypeError( + 'random_int(): $max must be an integer' + ); + } + + /** + * Now that we've verified our weak typing system has given us an integer, + * let's validate the logic then we can move forward with generating random + * integers along a given range. + */ + if ($min > $max) { + throw new Error( + 'Minimum value must be less than or equal to the maximum value' + ); + } + + if ($max === $min) { + return $min; + } + + /** + * Initialize variables to 0 + * + * We want to store: + * $bytes => the number of random bytes we need + * $mask => an integer bitmask (for use with the &) operator + * so we can minimize the number of discards + */ + $attempts = $bits = $bytes = $mask = $valueShift = 0; + + /** + * At this point, $range is a positive number greater than 0. It might + * overflow, however, if $max - $min > PHP_INT_MAX. PHP will cast it to + * a float and we will lose some precision. + */ + $range = $max - $min; + + /** + * Test for integer overflow: + */ + if (!is_int($range)) { + + /** + * Still safely calculate wider ranges. + * Provided by @CodesInChaos, @oittaa + * + * @ref https://gist.github.com/CodesInChaos/03f9ea0b58e8b2b8d435 + * + * We use ~0 as a mask in this case because it generates all 1s + * + * @ref https://eval.in/400356 (32-bit) + * @ref http://3v4l.org/XX9r5 (64-bit) + */ + $bytes = PHP_INT_SIZE; + $mask = ~0; + + } else { + + /** + * $bits is effectively ceil(log($range, 2)) without dealing with + * type juggling + */ + while ($range > 0) { + if ($bits % 8 === 0) { + ++$bytes; + } + ++$bits; + $range >>= 1; + $mask = $mask << 1 | 1; + } + $valueShift = $min; + } + + $val = 0; + /** + * Now that we have our parameters set up, let's begin generating + * random integers until one falls between $min and $max + */ + do { + /** + * The rejection probability is at most 0.5, so this corresponds + * to a failure probability of 2^-128 for a working RNG + */ + if ($attempts > 128) { + throw new Exception( + 'random_int: RNG is broken - too many rejections' + ); + } + + /** + * Let's grab the necessary number of random bytes + */ + $randomByteString = random_bytes($bytes); + + /** + * Let's turn $randomByteString into an integer + * + * This uses bitwise operators (<< and |) to build an integer + * out of the values extracted from ord() + * + * Example: [9F] | [6D] | [32] | [0C] => + * 159 + 27904 + 3276800 + 201326592 => + * 204631455 + */ + $val &= 0; + for ($i = 0; $i < $bytes; ++$i) { + $val |= ord($randomByteString[$i]) << ($i * 8); + } + + /** + * Apply mask + */ + $val &= $mask; + $val += $valueShift; + + ++$attempts; + /** + * If $val overflows to a floating point number, + * ... or is larger than $max, + * ... or smaller than $min, + * then try again. + */ + } while (!is_int($val) || $val > $max || $val < $min); + + return (int)$val; + } +} diff --git a/user/plugins/login/vendor/paragonie/random_compat/other/build_phar.php b/user/plugins/login/vendor/paragonie/random_compat/other/build_phar.php new file mode 100644 index 00000000..70ef4b2e --- /dev/null +++ b/user/plugins/login/vendor/paragonie/random_compat/other/build_phar.php @@ -0,0 +1,57 @@ +buildFromDirectory(dirname(__DIR__).'/lib'); +rename( + dirname(__DIR__).'/lib/index.php', + dirname(__DIR__).'/lib/random.php' +); + +/** + * If we pass an (optional) path to a private key as a second argument, we will + * sign the Phar with OpenSSL. + * + * If you leave this out, it will produce an unsigned .phar! + */ +if ($argc > 1) { + if (!@is_readable($argv[1])) { + echo 'Could not read the private key file:', $argv[1], "\n"; + exit(255); + } + $pkeyFile = file_get_contents($argv[1]); + + $private = openssl_get_privatekey($pkeyFile); + if ($private !== false) { + $pkey = ''; + openssl_pkey_export($private, $pkey); + $phar->setSignatureAlgorithm(Phar::OPENSSL, $pkey); + + /** + * Save the corresponding public key to the file + */ + if (!@is_readable($dist.'/random_compat.phar.pubkey')) { + $details = openssl_pkey_get_details($private); + file_put_contents( + $dist.'/random_compat.phar.pubkey', + $details['key'] + ); + } + } else { + echo 'An error occurred reading the private key from OpenSSL.', "\n"; + exit(255); + } +} diff --git a/user/plugins/login/vendor/paragonie/random_compat/other/ide_stubs/COM.php b/user/plugins/login/vendor/paragonie/random_compat/other/ide_stubs/COM.php new file mode 100644 index 00000000..4ba4bb31 --- /dev/null +++ b/user/plugins/login/vendor/paragonie/random_compat/other/ide_stubs/COM.php @@ -0,0 +1,20 @@ + + + + + + + + + + + diff --git a/user/plugins/login/vendor/robthree/twofactorauth/LICENSE b/user/plugins/login/vendor/robthree/twofactorauth/LICENSE new file mode 100644 index 00000000..75a96312 --- /dev/null +++ b/user/plugins/login/vendor/robthree/twofactorauth/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2014-2015 Rob Janssen + +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. + diff --git a/user/plugins/login/vendor/robthree/twofactorauth/README.md b/user/plugins/login/vendor/robthree/twofactorauth/README.md new file mode 100644 index 00000000..ba6cfeab --- /dev/null +++ b/user/plugins/login/vendor/robthree/twofactorauth/README.md @@ -0,0 +1,197 @@ +# ![Logo](https://raw.githubusercontent.com/RobThree/TwoFactorAuth/master/logo.png) PHP library for Two Factor Authentication + +[![Build status](https://img.shields.io/travis/RobThree/TwoFactorAuth.svg?style=flat-square)](https://travis-ci.org/RobThree/TwoFactorAuth/) [![Latest Stable Version](https://img.shields.io/packagist/v/robthree/twofactorauth.svg?style=flat-square)](https://packagist.org/packages/robthree/twofactorauth) [![License](https://img.shields.io/packagist/l/robthree/twofactorauth.svg?style=flat-square)](LICENSE) [![Downloads](https://img.shields.io/packagist/dt/robthree/twofactorauth.svg?style=flat-square)](https://packagist.org/packages/robthree/twofactorauth) [![HHVM Status](https://img.shields.io/hhvm/RobThree/TwoFactorAuth.svg?style=flat-square)](http://hhvm.h4cc.de/package/robthree/twofactorauth) [![Code Climate](https://img.shields.io/codeclimate/github/RobThree/TwoFactorAuth.svg?style=flat-square)](https://codeclimate.com/github/RobThree/TwoFactorAuth) [![PayPal donate button](http://img.shields.io/badge/paypal-donate-orange.svg?style=flat-square)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=6MB5M2SQLP636 "Keep me off the streets") + +PHP library for [two-factor (or multi-factor) authentication](http://en.wikipedia.org/wiki/Multi-factor_authentication) using [TOTP](http://en.wikipedia.org/wiki/Time-based_One-time_Password_Algorithm) and [QR-codes](http://en.wikipedia.org/wiki/QR_code). Inspired by, based on but most importantly an *improvement* on '[PHPGangsta/GoogleAuthenticator](https://github.com/PHPGangsta/GoogleAuthenticator)'. There's a [.Net implementation](https://github.com/RobThree/TwoFactorAuth.Net) of this library as well. + +

                                                            + +

                                                            + +## Requirements + +* Tested on PHP 5.3, 5.4, 5.5 and 5.6, 7.0, 7.1 and HHVM +* [cURL](http://php.net/manual/en/book.curl.php) when using the provided `GoogleQRCodeProvider` (default), `QRServerProvider` or `QRicketProvider` but you can also provide your own QR-code provider. +* [random_bytes()](http://php.net/manual/en/function.random-bytes.php), [MCrypt](http://php.net/manual/en/book.mcrypt.php), [OpenSSL](http://php.net/manual/en/book.openssl.php) or [Hash](http://php.net/manual/en/book.hash.php) depending on which built-in RNG you use (TwoFactorAuth will try to 'autodetect' and use the best available); however: feel free to provide your own (CS)RNG. + +## Installation + +Run the following command: + +`php composer.phar require robthree/twofactorauth` + +## Quick start + +If you want to hit the ground running then have a look at the [demo](demo/demo.php). It's very simple and easy! + +## Usage + +Here are some code snippets that should help you get started... + +````php +// Create a TwoFactorAuth instance +$tfa = new RobThree\Auth\TwoFactorAuth('My Company'); +```` + +The TwoFactorAuth class constructor accepts 7 parameters (all optional): + +Parameter | Default value | Use +------------------|---------------|-------------------------------------------------- +`$issuer` | `null` | Will be displayed in the app as issuer name +`$digits` | `6` | The number of digits the resulting codes will be +`$period` | `30` | The number of seconds a code will be valid +`$algorithm` | `sha1` | The algorithm used +`$qrcodeprovider` | `null` | QR-code provider (more on this later) +`$rngprovider` | `null` | Random Number Generator provider (more on this later) +`$timeprovider` | `null` | Time provider (more on this later) + +These parameters are all '`write once`'; the class will, for it's lifetime, use these values when generating / calculating codes. The number of digits, the period and algorithm are all set to values Google's Authticator app uses (and supports). You may specify `8` digits, a period of `45` seconds and the `sha256` algorithm but the authenticator app (be it Google's implementation, Authy or any other app) may or may not support these values. Your mileage may vary; keep it on the safe side if you don't control which app your audience uses. + +### Step 1: Set up secret shared key + +When a user wants to setup two-factor auth (or, more correctly, multi-factor auth) you need to create a secret. This will be your **shared secret**. This secret will need to be entered by the user in their app. This can be done manually, in which case you simply display the secret and have the user type it in the app: + +````php +$secret = $tfa->createSecret(); +```` + +The `createSecret()` method accepts two arguments: `$bits` (default: `80`) and `$requirecryptosecure` (default: `true`). The former is the number of bits generated for the shared secret. Make sure this argument is a multiple of 8 and, again, keep in mind that not all combinations may be supported by all apps. Google authenticator seems happy with 80 and 160, the default is set to 80 because that's what most sites (that I know of) currently use; however a value of 160 or higher is recommended (see [RFC 4226 - Algorithm Requirements](https://tools.ietf.org/html/rfc4226#section-4)). The latter is used to ensure that the secret is cryptographically secure; if you don't care very much for cryptographically secure secrets you can specify `false` and use a **non**-cryptographically secure RNG provider. + +````php +// Display shared secret +

                                                            Please enter the following code in your app: ''

                                                            +```` + +Another, more user-friendly, way to get the shared secret into the app is to generate a [QR-code](http://en.wikipedia.org/wiki/QR_code) which can be scanned by the app. To generate these QR codes you can use any one of the built-in `QRProvider` classes: + +1. `GoogleQRCodeProvider` (default) +2. `QRServerProvider` +3. `QRicketProvider` + +...or implement your own provider. To implement your own provider all you need to do is implement the `IQRCodeProvider` interface. You can use the built-in providers mentioned before to serve as an example or read the next chapter in this file. The built-in classes all use a 3rd (e.g. external) party (Google, QRServer and QRicket) for the hard work of generating QR-codes (note: each of these services might at some point not be available or impose limitations to the number of codes generated per day, hour etc.). You could, however, easily use a project like [PHP QR Code](http://phpqrcode.sourceforge.net/) (or one of the [many others](https://packagist.org/search/?q=qr)) to generate your QR-codes without depending on external sources. Later on we'll [demonstrate](#qr-code-providers) how to do this. + +The built-in providers all have some provider-specific 'tweaks' you can 'apply'. Some provide support for different colors, others may let you specify the desired image-format etc. What they all have in common is that they return a QR-code as binary blob which, in turn, will be turned into a [data URI](http://en.wikipedia.org/wiki/Data_URI_scheme) by the `TwoFactorAuth` class. This makes it easy for you to display the image without requiring extra 'roundtrips' from browser to server and vice versa. + +````php +// Display QR code to user +

                                                            Scan the following image with your app:

                                                            +

                                                            +```` + +When outputting a QR-code you can choose a `$label` for the user (which, when entering a shared secret manually, will have to be chosen by the user). This label may be an empty string or `null`. Also a `$size` may be specified (in pixels, width == height) for which we use a default value of `200`. + +### Step 2: Verify secret shared key + +When the shared secret is added to the app, the app will be ready to start generating codes which 'expire' each '`$period`' number of seconds. To make sure the secret was entered, or scanned, correctly you need to verify this by having the user enter a generated code. To check if the generated code is valid you call the `verifyCode()` method: + +````php +// Verify code +$result = $tfa->verifyCode($_SESSION['secret'], $_POST['verification']); +```` + +`verifyCode()` will return either `true` (the code was valid) or `false` (the code was invalid; no points for you!). You may need to store `$secret` in a `$_SESSION` or other persistent storage between requests. The `verifyCode()` accepts, aside from `$secret` and `$code`, two more parameters. The first being `$discrepancy`. Since TOTP codes are based on time("slices") it is very important that the server (but also client) have a correct date/time. But because the two *may* differ a bit we usually allow a certain amount of leeway. Because generated codes are valid for a specific period (remember the `$period` parameter in the `TwoFactorAuth`'s constructor?) we usually check the period directly before and the period directly after the current time when validating codes. So when the current time is `14:34:21`, which results in a 'current timeslice' of `14:34:00` to `14:34:30` we also calculate/verify the codes for `14:33:30` to `14:34:00` and for `14:34:30` to `14:35:00`. This gives us a 'window' of `14:33:30` to `14:35:00`. The `$discrepancy` parameter specifies how many periods (or: timeslices) we check in either direction of the current time. The default `$discrepancy` of `1` results in (max.) 3 period checks: -1, current and +1 period. A `$discrepancy` of `4` would result in a larger window (or: bigger time difference between client and server) of -4, -3, -2, -1, current, +1, +2, +3 and +4 periods. + +The second parameter `$time` allows you to check a code for a specific point in time. This parameter has no real practical use but can be handy for unittesting etc. The default value, `null`, means: use the current time. + +### Step 3: Store `$secret` with user and we're done! + +Ok, so now the code has been verified and found to be correct. Now we can store the `$secret` with our user in our database (or elsewhere) and whenever the user begins a new session we ask for a code generated by the authentication app of their choice. All we need to do is call `verifyCode()` again with the shared secret and the entered code and we know if the user is legit or not. + +Simple as 1-2-3. + +All we need is 3 methods and a constructor: + +````php +public function __construct( + $issuer = null, + $digits = 6, + $period = 30, + $algorithm = 'sha1', + RobThree\Auth\Providers\Qr\IQRCodeProvider $qrcodeprovider = null, + RobThree\Auth\Providers\Rng\IRNGProvider $rngprovider = null +); +public function createSecret($bits = 80, $requirecryptosecure = true): string; +public function getQRCodeImageAsDataUri($label, $secret, $size = 200): string; +public function verifyCode($secret, $code, $discrepancy = 1, $time = null): bool; +```` + +### QR-code providers + +As mentioned before, this library comes with three 'built-in' QR-code providers. This chapter will touch the subject a bit but most of it should be self-explanatory. The `TwoFactorAuth`-class accepts a `$qrcodeprovider` parameter which lets you specify a built-in or custom QR-code provider. All three built-in providers do a simple HTTP request to retrieve an image using cURL and implement the [`IQRCodeProvider`](lib/Providers/Qr/IQRCodeProvider.php) interface which is all you need to implement to write your own QR-code provider. + +The default provider is the [`GoogleQRCodeProvider`](lib/Providers/Qr/GoogleQRCodeProvider.php) which uses the [Google Chart Tools](https://developers.google.com/chart/infographics/docs/qr_codes) to render QR-codes. Then we have the [`QRServerProvider`](lib/Providers/Qr/QRServerProvider.php) which uses the [goqr.me API](http://goqr.me/api/doc/create-qr-code/) and finally we have the [`QRicketProvider`](lib/Providers/Qr/QRicketProvider.php) which uses the [QRickit API](http://qrickit.com/qrickit_apps/qrickit_api.php). All three inherit from a common (abstract) baseclass named [`BaseHTTPQRCodeProvider`](lib/Providers/Qr/BaseHTTPQRCodeProvider.php) because all three share the same functionality: retrieve an image from a 3rd party over HTTP. All three classes have constructors that allow you to tweak some settings and most, if not all, arguments should speak for themselves. If you're not sure which values are supported, click the links in this paragraph for documentation on the API's that are utilized by these classes. + +If you don't like any of the built-in classes because you don't want to rely on external resources for example or because you're paranoid about sending the TOTP secret to these 3rd parties (which is useless to them since they miss *at least one* other factor in the [MFA process](http://en.wikipedia.org/wiki/Multi-factor_authentication)), feel tree to implement your own. The `IQRCodeProvider` interface couldn't be any simpler. All you need to do is implement 2 methods: + +````php +getMimeType(); +getQRCodeImage($qrtext, $size); +```` + +The `getMimeType()` method should return the [MIME type](http://en.wikipedia.org/wiki/Internet_media_type) of the image that is returned by our implementation of `getQRCodeImage()`. In this example it's simply `image/png`. The `getQRCodeImage()` method is passed two arguments: `$qrtext` and `$size`. The latter, `$size`, is simply the width/height in pixels of the image desired by the caller. The first, `$qrtext` is the text that should be encoded in the QR-code. An example of such a text would be: + +`otpauth://totp/LABEL:alice@google.com?secret=JBSWY3DPEHPK3PXP&issuer=ISSUER` + +All you need to do is return the QR-code as binary image data and you're done. All parts of the `$qrtext` have been escaped for you (but note: you *may* need to escape the entire `$qrtext` just once more when passing the data to another server as GET-parameter). + +Let's see if we can use [PHP QR Code](http://phpqrcode.sourceforge.net/) to implement our own, custom, no-3rd-parties-allowed-here, provider. We start with downloading the [required (single) file](https://github.com/t0k4rt/phpqrcode/blob/master/phpqrcode.php) and putting it in the directory where `TwoFactorAuth.php` is located as well. Now let's implement the provider: create another file named `myprovider.php` in the `Providers\Qr` directory and paste in this content: + +````php +createSecret(); +?> +

                                                            +```` + +Voilà. Couldn't make it any simpler. + +### RNG providers + +This library also comes with three 'built-in' RNG providers ([Random Number Generator](https://en.wikipedia.org/wiki/Random_number_generation)). The RNG provider generates a number of random bytes and returns these bytes as a string. These values are then used to create the secret. By default (no RNG provider specified) TwoFactorAuth will try to determine the best available RNG provider to use. It will, by default, try to use the [`CSRNGProvider`](lib/Providers/Rng/CSRNGProvider.php) for PHP7+ or the [`MCryptRNGProvider`](lib/Providers/Rng/MCryptRNGProvider.php); if this is not available/supported for any reason it will try to use the [`OpenSSLRNGProvider`](lib/Providers/Rng/OpenSSLRNGProvider.php) and if that is also not available/supported it will try to use the final RNG provider: [`HashRNGProvider`](lib/Providers/Rng/HashRNGProvider.php). Each of these providers use their own method of generating a random sequence of bytes. The first three (`CSRNGProvider`, `OpenSSLRNGProvider` and `MCryptRNGProvider`) return a [cryptographically secure](https://en.wikipedia.org/wiki/Cryptographically_secure_pseudorandom_number_generator) sequence of random bytes whereas the `HashRNGProvider` returns a **non-cryptographically secure** sequence. + +You can easily implement your own `RNGProvider` by simply implementing the `IRNGProvider` interface. Each of the 'built-in' RNG providers have some constructor parameters that allow you to 'tweak' some of the settings to use when creating the random bytes such as which source to use (`MCryptRNGProvider`) or which hashing algorithm (`HashRNGProvider`). I encourage you to have a look at some of the ['built-in' RNG providers](lib/Providers/Rng) for details and the [`IRNGProvider` interface](lib/Providers/Rng/IRNGProvider.php). + +### Time providers + +Another set of providers in this library are the Time Providers; this library provides three 'built-in' ones. The default Time Provider used is the [`LocalMachineTimeProvider`](lib/Providers/Time/LocalMachineTimeProvider.php); this provider simply returns the output of `Time()` and is *highly recommended* as default provider. The [`HttpTimeProvider`](lib/Providers/Time/HttpTimeProvider.php) executes a `HEAD` request against a given webserver (default: google.com) and tries to extract the `Date:`-HTTP header and returns it's date. Other url's/domains can be used by specifying the url in the constructor. The final Time Provider is the [`ConvertUnixTimeDotComTimeProvider`](lib/Providers/Time/ConvertUnixTimeDotComTimeProvider.php) which does a HTTP request to `convert-unix-time.com/api` and decodes the `JSON` result to retrieve the time. + +You can easily implement your own `TimeProvider` by simply implementing the `ITimeProvider` interface. + +As to *why* these Time Providers are implemented: it allows the TwoFactorAuth library to ensure the hosts time is correct (or rather: within a margin). You can use the `ensureCorrectTime()` method to ensure the hosts time is correct. By default this method will compare the hosts time (returned by calling `time()` on the `LocalMachineTimeProvider`) to Google's and convert-unix-time.com's current time. You can pass an array of `ITimeProvider`s and specify the `leniency` (second argument) allowed (default: 5 seconds). The method will throw when the TwoFactorAuth's timeprovider (which can be any `ITimeProvider`, see constructor) differs more than the given amount of seconds from any of the given `ITimeProviders`. We advise to call this method sparingly when relying on 3rd parties (which both the `HttpTimeProvider` and `ConvertUnixTimeDotComTimeProvider` do) or, if you need to ensure time is correct on a (very) regular basis to implement an `ITimeProvider` that is more efficient than the 'built-in' ones (like use a GPS signal). The `ensureCorrectTime()` method is mostly to be used to make sure the server is configured correctly. + +## Integrations + +- [CakePHP 3](https://github.com/andrej-griniuk/cakephp-two-factor-auth) + +## License + +Licensed under MIT license. See [LICENSE](https://raw.githubusercontent.com/RobThree/TwoFactorAuth/master/LICENSE) for details. + +[Logo / icon](http://www.iconmay.com/Simple/Travel_and_Tourism_Part_2/luggage_lock_safety_baggage_keys_cylinder_lock_hotel_travel_tourism_luggage_lock_icon_465) under CC0 1.0 Universal (CC0 1.0) Public Domain Dedication ([Archived page](http://riii.nl/tm7ap)) diff --git a/user/plugins/login/vendor/robthree/twofactorauth/TwoFactorAuth.phpproj b/user/plugins/login/vendor/robthree/twofactorauth/TwoFactorAuth.phpproj new file mode 100644 index 00000000..7fa2a58e --- /dev/null +++ b/user/plugins/login/vendor/robthree/twofactorauth/TwoFactorAuth.phpproj @@ -0,0 +1,69 @@ + + + + Debug + TwoFactorAuth + {e569f53a-a604-4579-91ce-4e35b27da47b} + TwoFactorAuth + Library + {A0786B88-2ADB-4C21-ABE8-AA2D79766269} + False + PHPDev + None + True + 41315 + localhost + http://localhost:41315/ + PHP + 7.0 + + + true + + + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/user/plugins/login/vendor/robthree/twofactorauth/TwoFactorAuth.sln b/user/plugins/login/vendor/robthree/twofactorauth/TwoFactorAuth.sln new file mode 100644 index 00000000..df901f6a --- /dev/null +++ b/user/plugins/login/vendor/robthree/twofactorauth/TwoFactorAuth.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0.30723.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{A0786B88-2ADB-4C21-ABE8-AA2D79766269}") = "TwoFactorAuth", "TwoFactorAuth.phpproj", "{E569F53A-A604-4579-91CE-4E35B27DA47B}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E569F53A-A604-4579-91CE-4E35B27DA47B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E569F53A-A604-4579-91CE-4E35B27DA47B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E569F53A-A604-4579-91CE-4E35B27DA47B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E569F53A-A604-4579-91CE-4E35B27DA47B}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/user/plugins/login/vendor/robthree/twofactorauth/composer.json b/user/plugins/login/vendor/robthree/twofactorauth/composer.json new file mode 100644 index 00000000..1ea66ab0 --- /dev/null +++ b/user/plugins/login/vendor/robthree/twofactorauth/composer.json @@ -0,0 +1,36 @@ +{ + "name": "robthree/twofactorauth", + "description": "Two Factor Authentication", + "version": "1.6.1", + "type": "library", + "keywords": [ "Authentication", "Two Factor Authentication", "Multi Factor Authentication", "TFA", "MFA", "PHP", "Authenticator", "Authy" ], + "homepage": "https://github.com/RobThree/TwoFactorAuth", + "license": "MIT", + "authors": [ + { + "name": "Rob Janssen", + "homepage": "http://robiii.me", + "role": "Developer" + } + ], + "support": { + "issues": "https://github.com/RobThree/TwoFactorAuth/issues", + "source": "https://github.com/RobThree/TwoFactorAuth" + }, + "require": { + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": "@stable" + }, + "autoload": { + "psr-4": { + "RobThree\\Auth\\": "lib" + } + }, + "autoload-dev": { + "psr-4": { + "RobThree\\Auth\\Test\\": "tests" + } + } +} diff --git a/user/plugins/login/vendor/robthree/twofactorauth/composer.lock b/user/plugins/login/vendor/robthree/twofactorauth/composer.lock new file mode 100644 index 00000000..63df9377 --- /dev/null +++ b/user/plugins/login/vendor/robthree/twofactorauth/composer.lock @@ -0,0 +1,980 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", + "This file is @generated automatically" + ], + "content-hash": "9647de85f54ba6db237f5ff42ff85a1f", + "packages": [], + "packages-dev": [ + { + "name": "doctrine/instantiator", + "version": "1.0.5", + "source": { + "type": "git", + "url": "https://github.com/doctrine/instantiator.git", + "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/8e884e78f9f0eb1329e445619e04456e64d8051d", + "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d", + "shasum": "" + }, + "require": { + "php": ">=5.3,<8.0-DEV" + }, + "require-dev": { + "athletic/athletic": "~0.1.8", + "ext-pdo": "*", + "ext-phar": "*", + "phpunit/phpunit": "~4.0", + "squizlabs/php_codesniffer": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com", + "homepage": "http://ocramius.github.com/" + } + ], + "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", + "homepage": "https://github.com/doctrine/instantiator", + "keywords": [ + "constructor", + "instantiate" + ], + "time": "2015-06-14T21:17:01+00:00" + }, + { + "name": "phpdocumentor/reflection-docblock", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", + "reference": "d68dbdc53dc358a816f00b300704702b2eaff7b8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/d68dbdc53dc358a816f00b300704702b2eaff7b8", + "reference": "d68dbdc53dc358a816f00b300704702b2eaff7b8", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "suggest": { + "dflydev/markdown": "~1.0", + "erusev/parsedown": "~1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-0": { + "phpDocumentor": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "mike.vanriel@naenius.com" + } + ], + "time": "2015-02-03T12:10:50+00:00" + }, + { + "name": "phpspec/prophecy", + "version": "v1.6.2", + "source": { + "type": "git", + "url": "https://github.com/phpspec/prophecy.git", + "reference": "6c52c2722f8460122f96f86346600e1077ce22cb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/6c52c2722f8460122f96f86346600e1077ce22cb", + "reference": "6c52c2722f8460122f96f86346600e1077ce22cb", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.0.2", + "php": "^5.3|^7.0", + "phpdocumentor/reflection-docblock": "^2.0|^3.0.2", + "sebastian/comparator": "^1.1", + "sebastian/recursion-context": "^1.0|^2.0" + }, + "require-dev": { + "phpspec/phpspec": "^2.0", + "phpunit/phpunit": "^4.8 || ^5.6.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.6.x-dev" + } + }, + "autoload": { + "psr-0": { + "Prophecy\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Konstantin Kudryashov", + "email": "ever.zet@gmail.com", + "homepage": "http://everzet.com" + }, + { + "name": "Marcello Duarte", + "email": "marcello.duarte@gmail.com" + } + ], + "description": "Highly opinionated mocking framework for PHP 5.3+", + "homepage": "https://github.com/phpspec/prophecy", + "keywords": [ + "Double", + "Dummy", + "fake", + "mock", + "spy", + "stub" + ], + "time": "2016-11-21T14:58:47+00:00" + }, + { + "name": "phpunit/php-code-coverage", + "version": "2.2.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/eabf68b476ac7d0f73793aada060f1c1a9bf8979", + "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "phpunit/php-file-iterator": "~1.3", + "phpunit/php-text-template": "~1.2", + "phpunit/php-token-stream": "~1.3", + "sebastian/environment": "^1.3.2", + "sebastian/version": "~1.0" + }, + "require-dev": { + "ext-xdebug": ">=2.1.4", + "phpunit/phpunit": "~4" + }, + "suggest": { + "ext-dom": "*", + "ext-xdebug": ">=2.2.1", + "ext-xmlwriter": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.2.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "coverage", + "testing", + "xunit" + ], + "time": "2015-10-06T15:47:00+00:00" + }, + { + "name": "phpunit/php-file-iterator", + "version": "1.4.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "3cc8f69b3028d0f96a9078e6295d86e9bf019be5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/3cc8f69b3028d0f96a9078e6295d86e9bf019be5", + "reference": "3cc8f69b3028d0f96a9078e6295d86e9bf019be5", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "filesystem", + "iterator" + ], + "time": "2016-10-03T07:40:28+00:00" + }, + { + "name": "phpunit/php-text-template", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "time": "2015-06-21T13:50:34+00:00" + }, + { + "name": "phpunit/php-timer", + "version": "1.0.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "38e9124049cf1a164f1e4537caf19c99bf1eb260" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/38e9124049cf1a164f1e4537caf19c99bf1eb260", + "reference": "38e9124049cf1a164f1e4537caf19c99bf1eb260", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4|~5" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "time": "2016-05-12T18:03:57+00:00" + }, + { + "name": "phpunit/php-token-stream", + "version": "1.4.9", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-token-stream.git", + "reference": "3b402f65a4cc90abf6e1104e388b896ce209631b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/3b402f65a4cc90abf6e1104e388b896ce209631b", + "reference": "3b402f65a4cc90abf6e1104e388b896ce209631b", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Wrapper around PHP's tokenizer extension.", + "homepage": "https://github.com/sebastianbergmann/php-token-stream/", + "keywords": [ + "tokenizer" + ], + "time": "2016-11-15T14:06:22+00:00" + }, + { + "name": "phpunit/phpunit", + "version": "4.8.35", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "791b1a67c25af50e230f841ee7a9c6eba507dc87" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/791b1a67c25af50e230f841ee7a9c6eba507dc87", + "reference": "791b1a67c25af50e230f841ee7a9c6eba507dc87", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-json": "*", + "ext-pcre": "*", + "ext-reflection": "*", + "ext-spl": "*", + "php": ">=5.3.3", + "phpspec/prophecy": "^1.3.1", + "phpunit/php-code-coverage": "~2.1", + "phpunit/php-file-iterator": "~1.4", + "phpunit/php-text-template": "~1.2", + "phpunit/php-timer": "^1.0.6", + "phpunit/phpunit-mock-objects": "~2.3", + "sebastian/comparator": "~1.2.2", + "sebastian/diff": "~1.2", + "sebastian/environment": "~1.3", + "sebastian/exporter": "~1.2", + "sebastian/global-state": "~1.0", + "sebastian/version": "~1.0", + "symfony/yaml": "~2.1|~3.0" + }, + "suggest": { + "phpunit/php-invoker": "~1.1" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.8.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "time": "2017-02-06T05:18:07+00:00" + }, + { + "name": "phpunit/phpunit-mock-objects", + "version": "2.3.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", + "reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/ac8e7a3db35738d56ee9a76e78a4e03d97628983", + "reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.0.2", + "php": ">=5.3.3", + "phpunit/php-text-template": "~1.2", + "sebastian/exporter": "~1.2" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "suggest": { + "ext-soap": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.3.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Mock Object library for PHPUnit", + "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", + "keywords": [ + "mock", + "xunit" + ], + "time": "2015-10-02T06:51:40+00:00" + }, + { + "name": "sebastian/comparator", + "version": "1.2.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "2b7424b55f5047b47ac6e5ccb20b2aea4011d9be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/2b7424b55f5047b47ac6e5ccb20b2aea4011d9be", + "reference": "2b7424b55f5047b47ac6e5ccb20b2aea4011d9be", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "sebastian/diff": "~1.2", + "sebastian/exporter": "~1.2 || ~2.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "http://www.github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], + "time": "2017-01-29T09:50:25+00:00" + }, + { + "name": "sebastian/diff", + "version": "1.4.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "13edfd8706462032c2f52b4b862974dd46b71c9e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/13edfd8706462032c2f52b4b862974dd46b71c9e", + "reference": "13edfd8706462032c2f52b4b862974dd46b71c9e", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.8" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Diff implementation", + "homepage": "https://github.com/sebastianbergmann/diff", + "keywords": [ + "diff" + ], + "time": "2015-12-08T07:14:41+00:00" + }, + { + "name": "sebastian/environment", + "version": "1.3.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "be2c607e43ce4c89ecd60e75c6a85c126e754aea" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/be2c607e43ce4c89ecd60e75c6a85c126e754aea", + "reference": "be2c607e43ce4c89ecd60e75c6a85c126e754aea", + "shasum": "" + }, + "require": { + "php": "^5.3.3 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8 || ^5.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "http://www.github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], + "time": "2016-08-18T05:49:44+00:00" + }, + { + "name": "sebastian/exporter", + "version": "1.2.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "42c4c2eec485ee3e159ec9884f95b431287edde4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/42c4c2eec485ee3e159ec9884f95b431287edde4", + "reference": "42c4c2eec485ee3e159ec9884f95b431287edde4", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "sebastian/recursion-context": "~1.0" + }, + "require-dev": { + "ext-mbstring": "*", + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "http://www.github.com/sebastianbergmann/exporter", + "keywords": [ + "export", + "exporter" + ], + "time": "2016-06-17T09:04:28+00:00" + }, + { + "name": "sebastian/global-state", + "version": "1.1.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bc37d50fea7d017d3d340f230811c9f1d7280af4", + "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.2" + }, + "suggest": { + "ext-uopz": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Snapshotting of global state", + "homepage": "http://www.github.com/sebastianbergmann/global-state", + "keywords": [ + "global state" + ], + "time": "2015-10-12T03:26:01+00:00" + }, + { + "name": "sebastian/recursion-context", + "version": "1.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "913401df809e99e4f47b27cdd781f4a258d58791" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/913401df809e99e4f47b27cdd781f4a258d58791", + "reference": "913401df809e99e4f47b27cdd781f4a258d58791", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides functionality to recursively process PHP variables", + "homepage": "http://www.github.com/sebastianbergmann/recursion-context", + "time": "2015-11-11T19:50:13+00:00" + }, + { + "name": "sebastian/version", + "version": "1.0.6", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/58b3a85e7999757d6ad81c787a1fbf5ff6c628c6", + "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6", + "shasum": "" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "time": "2015-06-21T13:59:46+00:00" + }, + { + "name": "symfony/yaml", + "version": "v2.8.17", + "source": { + "type": "git", + "url": "https://github.com/symfony/yaml.git", + "reference": "322a8c2dfbca15ad6b1b27e182899f98ec0e0153" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/yaml/zipball/322a8c2dfbca15ad6b1b27e182899f98ec0e0153", + "reference": "322a8c2dfbca15ad6b1b27e182899f98ec0e0153", + "shasum": "" + }, + "require": { + "php": ">=5.3.9" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.8-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Yaml\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Yaml Component", + "homepage": "https://symfony.com", + "time": "2017-01-21T16:40:50+00:00" + } + ], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": { + "phpunit/phpunit": 0 + }, + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "php": ">=5.3.0" + }, + "platform-dev": [] +} diff --git a/user/plugins/login/vendor/robthree/twofactorauth/demo/demo.php b/user/plugins/login/vendor/robthree/twofactorauth/demo/demo.php new file mode 100644 index 00000000..996dd928 --- /dev/null +++ b/user/plugins/login/vendor/robthree/twofactorauth/demo/demo.php @@ -0,0 +1,35 @@ + + + + Demo + + +
                                                              + First create a secret and associate it with a user'; + $secret = $tfa->createSecret(160); // Though the default is an 80 bits secret (for backwards compatibility reasons) we recommend creating 160+ bits secrets (see RFC 4226 - Algorithm Requirements) + echo '
                                                            1. Next create a QR code and let the user scan it:

                                                              ...or display the secret to the user for manual entry: ' . chunk_split($secret, 4, ' '); + $code = $tfa->getCode($secret); + echo '
                                                            2. Next, have the user verify the code; at this time the code displayed by a 2FA-app would be: ' . $code . ' (but that changes periodically)'; + echo '
                                                            3. When the code checks out, 2FA can be / is enabled; store (encrypted?) secret with user and have the user verify a code each time a new session is started.'; + echo '
                                                            4. When aforementioned code (' . $code . ') was entered, the result would be: ' . (($tfa->verifyCode($secret, $code) === true) ? 'OK' : 'FAIL'); + ?> +
                                                            +

                                                            Note: Make sure your server-time is NTP-synced! Depending on the $discrepancy allowed your time cannot drift too much from the users' time!

                                                            + ensureCorrectTime(); + echo 'Your hosts time seems to be correct / within margin'; + } catch (RobThree\Auth\TwoFactorAuthException $ex) { + echo 'Warning: Your hosts time seems to be off: ' . $ex->getMessage(); + } + ?> + + diff --git a/user/plugins/login/vendor/robthree/twofactorauth/demo/loader.php b/user/plugins/login/vendor/robthree/twofactorauth/demo/loader.php new file mode 100644 index 00000000..208f24d4 --- /dev/null +++ b/user/plugins/login/vendor/robthree/twofactorauth/demo/loader.php @@ -0,0 +1,50 @@ +=0;$i--) { + static::$parentPath = dirname(static::$parentPath); + } + static::$paths = array(); + static::$files = array(__FILE__); + } + + public static function register($path,$namespace) { + if (!static::$initialized) static::initialize(); + static::$paths[$namespace] = trim($path,DIRECTORY_SEPARATOR); + } + + public static function load($class) { + if (class_exists($class,false)) return; + if (!static::$initialized) static::initialize(); + + foreach (static::$paths as $namespace => $path) { + if (!$namespace || $namespace.static::$nsChar === substr($class, 0, strlen($namespace.static::$nsChar))) { + + $fileName = substr($class,strlen($namespace.static::$nsChar)-1); + $fileName = str_replace(static::$nsChar, DIRECTORY_SEPARATOR, ltrim($fileName,static::$nsChar)); + $fileName = static::$parentPath.DIRECTORY_SEPARATOR.$path.DIRECTORY_SEPARATOR.$fileName.'.php'; + + if (file_exists($fileName)) { + include $fileName; + return true; + } + } + } + return false; + } +} + +spl_autoload_register(array('Loader', 'load')); \ No newline at end of file diff --git a/user/plugins/login/vendor/robthree/twofactorauth/lib/Providers/Qr/BaseHTTPQRCodeProvider.php b/user/plugins/login/vendor/robthree/twofactorauth/lib/Providers/Qr/BaseHTTPQRCodeProvider.php new file mode 100644 index 00000000..5cb3adda --- /dev/null +++ b/user/plugins/login/vendor/robthree/twofactorauth/lib/Providers/Qr/BaseHTTPQRCodeProvider.php @@ -0,0 +1,27 @@ + $url, + CURLOPT_RETURNTRANSFER => true, + CURLOPT_CONNECTTIMEOUT => 10, + CURLOPT_DNS_CACHE_TIMEOUT => 10, + CURLOPT_TIMEOUT => 10, + CURLOPT_SSL_VERIFYPEER => $this->verifyssl, + CURLOPT_USERAGENT => 'TwoFactorAuth' + )); + $data = curl_exec($curlhandle); + + curl_close($curlhandle); + return $data; + } +} \ No newline at end of file diff --git a/user/plugins/login/vendor/robthree/twofactorauth/lib/Providers/Qr/GoogleQRCodeProvider.php b/user/plugins/login/vendor/robthree/twofactorauth/lib/Providers/Qr/GoogleQRCodeProvider.php new file mode 100644 index 00000000..19e086b7 --- /dev/null +++ b/user/plugins/login/vendor/robthree/twofactorauth/lib/Providers/Qr/GoogleQRCodeProvider.php @@ -0,0 +1,39 @@ +verifyssl = $verifyssl; + + $this->errorcorrectionlevel = $errorcorrectionlevel; + $this->margin = $margin; + } + + public function getMimeType() + { + return 'image/png'; + } + + public function getQRCodeImage($qrtext, $size) + { + return $this->getContent($this->getUrl($qrtext, $size)); + } + + public function getUrl($qrtext, $size) + { + return 'https://chart.googleapis.com/chart?cht=qr' + . '&chs=' . $size . 'x' . $size + . '&chld=' . $this->errorcorrectionlevel . '|' . $this->margin + . '&chl=' . rawurlencode($qrtext); + } +} \ No newline at end of file diff --git a/user/plugins/login/vendor/robthree/twofactorauth/lib/Providers/Qr/IQRCodeProvider.php b/user/plugins/login/vendor/robthree/twofactorauth/lib/Providers/Qr/IQRCodeProvider.php new file mode 100644 index 00000000..83ed67ba --- /dev/null +++ b/user/plugins/login/vendor/robthree/twofactorauth/lib/Providers/Qr/IQRCodeProvider.php @@ -0,0 +1,9 @@ +verifyssl = $verifyssl; + + $this->errorcorrectionlevel = $errorcorrectionlevel; + $this->margin = $margin; + $this->qzone = $qzone; + $this->bgcolor = $bgcolor; + $this->color = $color; + $this->format = $format; + } + + public function getMimeType() + { + switch (strtolower($this->format)) + { + case 'png': + return 'image/png'; + case 'gif': + return 'image/gif'; + case 'jpg': + case 'jpeg': + return 'image/jpeg'; + case 'svg': + return 'image/svg+xml'; + case 'eps': + return 'application/postscript'; + } + throw new \QRException(sprintf('Unknown MIME-type: %s', $this->format)); + } + + public function getQRCodeImage($qrtext, $size) + { + return $this->getContent($this->getUrl($qrtext, $size)); + } + + private function decodeColor($value) + { + return vsprintf('%d-%d-%d', sscanf($value, "%02x%02x%02x")); + } + + public function getUrl($qrtext, $size) + { + return 'https://api.qrserver.com/v1/create-qr-code/' + . '?size=' . $size . 'x' . $size + . '&ecc=' . strtoupper($this->errorcorrectionlevel) + . '&margin=' . $this->margin + . '&qzone=' . $this->qzone + . '&bgcolor=' . $this->decodeColor($this->bgcolor) + . '&color=' . $this->decodeColor($this->color) + . '&format=' . strtolower($this->format) + . '&data=' . rawurlencode($qrtext); + } +} \ No newline at end of file diff --git a/user/plugins/login/vendor/robthree/twofactorauth/lib/Providers/Qr/QRicketProvider.php b/user/plugins/login/vendor/robthree/twofactorauth/lib/Providers/Qr/QRicketProvider.php new file mode 100644 index 00000000..59e27ccd --- /dev/null +++ b/user/plugins/login/vendor/robthree/twofactorauth/lib/Providers/Qr/QRicketProvider.php @@ -0,0 +1,54 @@ +verifyssl = false; + + $this->errorcorrectionlevel = $errorcorrectionlevel; + $this->bgcolor = $bgcolor; + $this->color = $color; + $this->format = $format; + } + + public function getMimeType() + { + switch (strtolower($this->format)) + { + case 'p': + return 'image/png'; + case 'g': + return 'image/gif'; + case 'j': + return 'image/jpeg'; + } + throw new \QRException(sprintf('Unknown MIME-type: %s', $this->format)); + } + + public function getQRCodeImage($qrtext, $size) + { + return $this->getContent($this->getUrl($qrtext, $size)); + } + + public function getUrl($qrtext, $size) + { + return 'http://qrickit.com/api/qr' + . '?qrsize=' . $size + . '&e=' . strtolower($this->errorcorrectionlevel) + . '&bgdcolor=' . $this->bgcolor + . '&fgdcolor=' . $this->color + . '&t=' . strtolower($this->format) + . '&d=' . rawurlencode($qrtext); + } +} \ No newline at end of file diff --git a/user/plugins/login/vendor/robthree/twofactorauth/lib/Providers/Rng/CSRNGProvider.php b/user/plugins/login/vendor/robthree/twofactorauth/lib/Providers/Rng/CSRNGProvider.php new file mode 100644 index 00000000..8dba7fc9 --- /dev/null +++ b/user/plugins/login/vendor/robthree/twofactorauth/lib/Providers/Rng/CSRNGProvider.php @@ -0,0 +1,14 @@ +algorithm = $algorithm; + } + + public function getRandomBytes($bytecount) { + $result = ''; + $hash = mt_rand(); + for ($i = 0; $i < $bytecount; $i++) { + $hash = hash($this->algorithm, $hash.mt_rand(), true); + $result .= $hash[mt_rand(0, sizeof($hash))]; + } + return $result; + } + + public function isCryptographicallySecure() { + return false; + } +} diff --git a/user/plugins/login/vendor/robthree/twofactorauth/lib/Providers/Rng/IRNGProvider.php b/user/plugins/login/vendor/robthree/twofactorauth/lib/Providers/Rng/IRNGProvider.php new file mode 100644 index 00000000..6be28006 --- /dev/null +++ b/user/plugins/login/vendor/robthree/twofactorauth/lib/Providers/Rng/IRNGProvider.php @@ -0,0 +1,9 @@ +source = $source; + } + + public function getRandomBytes($bytecount) { + $result = mcrypt_create_iv($bytecount, $this->source); + if ($result === false) + throw new \RNGException('mcrypt_create_iv returned an invalid value'); + return $result; + } + + public function isCryptographicallySecure() { + return true; + } +} \ No newline at end of file diff --git a/user/plugins/login/vendor/robthree/twofactorauth/lib/Providers/Rng/OpenSSLRNGProvider.php b/user/plugins/login/vendor/robthree/twofactorauth/lib/Providers/Rng/OpenSSLRNGProvider.php new file mode 100644 index 00000000..dc66c64a --- /dev/null +++ b/user/plugins/login/vendor/robthree/twofactorauth/lib/Providers/Rng/OpenSSLRNGProvider.php @@ -0,0 +1,25 @@ +requirestrong = $requirestrong; + } + + public function getRandomBytes($bytecount) { + $result = openssl_random_pseudo_bytes($bytecount, $crypto_strong); + if ($this->requirestrong && ($crypto_strong === false)) + throw new \RNGException('openssl_random_pseudo_bytes returned non-cryptographically strong value'); + if ($result === false) + throw new \RNGException('openssl_random_pseudo_bytes returned an invalid value'); + return $result; + } + + public function isCryptographicallySecure() { + return $this->requirestrong; + } +} \ No newline at end of file diff --git a/user/plugins/login/vendor/robthree/twofactorauth/lib/Providers/Rng/RNGException.php b/user/plugins/login/vendor/robthree/twofactorauth/lib/Providers/Rng/RNGException.php new file mode 100644 index 00000000..eb5e913d --- /dev/null +++ b/user/plugins/login/vendor/robthree/twofactorauth/lib/Providers/Rng/RNGException.php @@ -0,0 +1,5 @@ +timestamp)) + throw new \TimeException('Unable to retrieve time from convert-unix-time.com'); + return $json->timestamp; + } +} \ No newline at end of file diff --git a/user/plugins/login/vendor/robthree/twofactorauth/lib/Providers/Time/HttpTimeProvider.php b/user/plugins/login/vendor/robthree/twofactorauth/lib/Providers/Time/HttpTimeProvider.php new file mode 100644 index 00000000..8e7806e2 --- /dev/null +++ b/user/plugins/login/vendor/robthree/twofactorauth/lib/Providers/Time/HttpTimeProvider.php @@ -0,0 +1,54 @@ +url = $url; + $this->expectedtimeformat = $expectedtimeformat; + $this->options = $options; + if ($this->options === null) { + $this->options = array( + 'http' => array( + 'method' => 'HEAD', + 'follow_location' => false, + 'ignore_errors' => true, + 'max_redirects' => 0, + 'request_fulluri' => true, + 'header' => array( + 'Connection: close', + 'User-agent: TwoFactorAuth HttpTimeProvider (https://github.com/RobThree/TwoFactorAuth)', + 'Cache-Control: no-cache' + ) + ) + ); + } + } + + public function getTime() { + try { + $context = stream_context_create($this->options); + $fd = fopen($this->url, 'rb', false, $context); + $headers = stream_get_meta_data($fd); + fclose($fd); + + foreach ($headers['wrapper_data'] as $h) { + if (strcasecmp(substr($h, 0, 5), 'Date:') === 0) + return \DateTime::createFromFormat($this->expectedtimeformat, trim(substr($h,5)))->getTimestamp(); + } + throw new \TimeException(sprintf('Unable to retrieve time from %s (Invalid or no "Date:" header found)', $this->url)); + } + catch (Exception $ex) { + throw new \TimeException(sprintf('Unable to retrieve time from %s (%s)', $this->url, $ex->getMessage())); + } + } +} \ No newline at end of file diff --git a/user/plugins/login/vendor/robthree/twofactorauth/lib/Providers/Time/ITimeProvider.php b/user/plugins/login/vendor/robthree/twofactorauth/lib/Providers/Time/ITimeProvider.php new file mode 100644 index 00000000..a3b87a20 --- /dev/null +++ b/user/plugins/login/vendor/robthree/twofactorauth/lib/Providers/Time/ITimeProvider.php @@ -0,0 +1,8 @@ +issuer = $issuer; + if (!is_int($digits) || $digits <= 0) + throw new TwoFactorAuthException('Digits must be int > 0'); + $this->digits = $digits; + + if (!is_int($period) || $period <= 0) + throw new TwoFactorAuthException('Period must be int > 0'); + $this->period = $period; + + $algorithm = strtolower(trim($algorithm)); + if (!in_array($algorithm, self::$_supportedalgos)) + throw new TwoFactorAuthException('Unsupported algorithm: ' . $algorithm); + $this->algorithm = $algorithm; + $this->qrcodeprovider = $qrcodeprovider; + $this->rngprovider = $rngprovider; + $this->timeprovider = $timeprovider; + + self::$_base32 = str_split(self::$_base32dict); + self::$_base32lookup = array_flip(self::$_base32); + } + + /** + * Create a new secret + */ + public function createSecret($bits = 80, $requirecryptosecure = true) + { + $secret = ''; + $bytes = ceil($bits / 5); //We use 5 bits of each byte (since we have a 32-character 'alphabet' / BASE32) + $rngprovider = $this->getRngprovider(); + if ($requirecryptosecure && !$rngprovider->isCryptographicallySecure()) + throw new TwoFactorAuthException('RNG provider is not cryptographically secure'); + $rnd = $rngprovider->getRandomBytes($bytes); + for ($i = 0; $i < $bytes; $i++) + $secret .= self::$_base32[ord($rnd[$i]) & 31]; //Mask out left 3 bits for 0-31 values + return $secret; + } + + /** + * Calculate the code with given secret and point in time + */ + public function getCode($secret, $time = null) + { + $secretkey = $this->base32Decode($secret); + + $timestamp = "\0\0\0\0" . pack('N*', $this->getTimeSlice($this->getTime($time))); // Pack time into binary string + $hashhmac = hash_hmac($this->algorithm, $timestamp, $secretkey, true); // Hash it with users secret key + $hashpart = substr($hashhmac, ord(substr($hashhmac, -1)) & 0x0F, 4); // Use last nibble of result as index/offset and grab 4 bytes of the result + $value = unpack('N', $hashpart); // Unpack binary value + $value = $value[1] & 0x7FFFFFFF; // Drop MSB, keep only 31 bits + + return str_pad($value % pow(10, $this->digits), $this->digits, '0', STR_PAD_LEFT); + } + + /** + * Check if the code is correct. This will accept codes starting from ($discrepancy * $period) sec ago to ($discrepancy * period) sec from now + */ + public function verifyCode($secret, $code, $discrepancy = 1, $time = null) + { + $result = false; + $timetamp = $this->getTime($time); + + // To keep safe from timing-attachs we iterate *all* possible codes even though we already may have verified a code is correct + for ($i = -$discrepancy; $i <= $discrepancy; $i++) + $result |= $this->codeEquals($this->getCode($secret, $timetamp + ($i * $this->period)), $code); + + return (bool)$result; + } + + /** + * Timing-attack safe comparison of 2 codes (see http://blog.ircmaxell.com/2014/11/its-all-about-time.html) + */ + private function codeEquals($safe, $user) { + if (function_exists('hash_equals')) { + return hash_equals($safe, $user); + } + // In general, it's not possible to prevent length leaks. So it's OK to leak the length. The important part is that + // we don't leak information about the difference of the two strings. + if (strlen($safe)===strlen($user)) { + $result = 0; + for ($i = 0; $i < strlen($safe); $i++) + $result |= (ord($safe[$i]) ^ ord($user[$i])); + return $result === 0; + } + return false; + } + + /** + * Get data-uri of QRCode + */ + public function getQRCodeImageAsDataUri($label, $secret, $size = 200) + { + if (!is_int($size) || $size <= 0) + throw new TwoFactorAuthException('Size must be int > 0'); + + $qrcodeprovider = $this->getQrCodeProvider(); + return 'data:' + . $qrcodeprovider->getMimeType() + . ';base64,' + . base64_encode($qrcodeprovider->getQRCodeImage($this->getQRText($label, $secret), $size)); + } + + /** + * Compare default timeprovider with specified timeproviders and ensure the time is within the specified number of seconds (leniency) + */ + public function ensureCorrectTime(array $timeproviders = null, $leniency = 5) + { + if ($timeproviders != null && !is_array($timeproviders)) + throw new TwoFactorAuthException('No timeproviders specified'); + + if ($timeproviders == null) + $timeproviders = array( + new Providers\Time\ConvertUnixTimeDotComTimeProvider(), + new Providers\Time\HttpTimeProvider() + ); + + // Get default time provider + $timeprovider = $this->getTimeProvider(); + + // Iterate specified time providers + foreach ($timeproviders as $t) { + if (!($t instanceof ITimeProvider)) + throw new TwoFactorAuthException('Object does not implement ITimeProvider'); + + // Get time from default time provider and compare to specific time provider and throw if time difference is more than specified number of seconds leniency + if (abs($timeprovider->getTime() - $t->getTime()) > $leniency) + throw new TwoFactorAuthException(sprintf('Time for timeprovider is off by more than %d seconds when compared to %s', $leniency, get_class($t))); + } + } + + private function getTime($time) + { + return ($time === null) ? $this->getTimeProvider()->getTime() : $time; + } + + private function getTimeSlice($time = null, $offset = 0) + { + return (int)floor($time / $this->period) + ($offset * $this->period); + } + + /** + * Builds a string to be encoded in a QR code + */ + public function getQRText($label, $secret) + { + return 'otpauth://totp/' . rawurlencode($label) + . '?secret=' . rawurlencode($secret) + . '&issuer=' . rawurlencode($this->issuer) + . '&period=' . intval($this->period) + . '&algorithm=' . rawurlencode(strtoupper($this->algorithm)) + . '&digits=' . intval($this->digits); + } + + private function base32Decode($value) + { + if (strlen($value)==0) return ''; + + if (preg_match('/[^'.preg_quote(self::$_base32dict).']/', $value) !== 0) + throw new TwoFactorAuthException('Invalid base32 string'); + + $buffer = ''; + foreach (str_split($value) as $char) + { + if ($char !== '=') + $buffer .= str_pad(decbin(self::$_base32lookup[$char]), 5, 0, STR_PAD_LEFT); + } + $length = strlen($buffer); + $blocks = trim(chunk_split(substr($buffer, 0, $length - ($length % 8)), 8, ' ')); + + $output = ''; + foreach (explode(' ', $blocks) as $block) + $output .= chr(bindec(str_pad($block, 8, 0, STR_PAD_RIGHT))); + return $output; + } + + /** + * @return IQRCodeProvider + * @throws TwoFactorAuthException + */ + public function getQrCodeProvider() + { + // Set default QR Code provider if none was specified + if (null === $this->qrcodeprovider) { + return $this->qrcodeprovider = new Providers\Qr\GoogleQRCodeProvider(); + } + return $this->qrcodeprovider; + } + + /** + * @return IRNGProvider + * @throws TwoFactorAuthException + */ + public function getRngprovider() + { + if (null !== $this->rngprovider) { + return $this->rngprovider; + } + if (function_exists('random_bytes')) { + return $this->rngprovider = new Providers\Rng\CSRNGProvider(); + } + if (function_exists('mcrypt_create_iv')) { + return $this->rngprovider = new Providers\Rng\MCryptRNGProvider(); + } + if (function_exists('openssl_random_pseudo_bytes')) { + return $this->rngprovider = new Providers\Rng\OpenSSLRNGProvider(); + } + if (function_exists('hash')) { + return $this->rngprovider = new Providers\Rng\HashRNGProvider(); + } + throw new TwoFactorAuthException('Unable to find a suited RNGProvider'); + } + + /** + * @return ITimeProvider + * @throws TwoFactorAuthException + */ + public function getTimeProvider() + { + // Set default time provider if none was specified + if (null === $this->timeprovider) { + return $this->timeprovider = new Providers\Time\LocalMachineTimeProvider(); + } + return $this->timeprovider; + } +} \ No newline at end of file diff --git a/user/plugins/login/vendor/robthree/twofactorauth/lib/TwoFactorAuthException.php b/user/plugins/login/vendor/robthree/twofactorauth/lib/TwoFactorAuthException.php new file mode 100644 index 00000000..af51b748 --- /dev/null +++ b/user/plugins/login/vendor/robthree/twofactorauth/lib/TwoFactorAuthException.php @@ -0,0 +1,7 @@ +assertEquals('543160', $tfa->getCode('VMR466AB62ZBOKHE', 1426847216)); + $this->assertEquals('538532', $tfa->getCode('VMR466AB62ZBOKHE', 0)); + } + + /** + * @expectedException \RobThree\Auth\TwoFactorAuthException + */ + public function testCreateSecretThrowsOnInsecureRNGProvider() { + $rng = new TestRNGProvider(); + + $tfa = new TwoFactorAuth('Test', 6, 30, 'sha1', null, $rng); + $tfa->createSecret(); + } + + public function testCreateSecretOverrideSecureDoesNotThrowOnInsecureRNG() { + $rng = new TestRNGProvider(); + + $tfa = new TwoFactorAuth('Test', 6, 30, 'sha1', null, $rng); + $this->assertEquals('ABCDEFGHIJKLMNOP', $tfa->createSecret(80, false)); + } + + public function testCreateSecretDoesNotThrowOnSecureRNGProvider() { + $rng = new TestRNGProvider(true); + + $tfa = new TwoFactorAuth('Test', 6, 30, 'sha1', null, $rng); + $this->assertEquals('ABCDEFGHIJKLMNOP', $tfa->createSecret()); + } + + public function testCreateSecretGeneratesDesiredAmountOfEntropy() { + $rng = new TestRNGProvider(true); + + $tfa = new TwoFactorAuth('Test', 6, 30, 'sha1', null, $rng); + $this->assertEquals('A', $tfa->createSecret(5)); + $this->assertEquals('AB', $tfa->createSecret(6)); + $this->assertEquals('ABCDEFGHIJKLMNOPQRSTUVWXYZ', $tfa->createSecret(128)); + $this->assertEquals('ABCDEFGHIJKLMNOPQRSTUVWXYZ234567', $tfa->createSecret(160)); + $this->assertEquals('ABCDEFGHIJKLMNOPQRSTUVWXYZ234567ABCDEFGHIJKLMNOPQRSTUVWXYZ234567', $tfa->createSecret(320)); + $this->assertEquals('ABCDEFGHIJKLMNOPQRSTUVWXYZ234567ABCDEFGHIJKLMNOPQRSTUVWXYZ234567A', $tfa->createSecret(321)); + } + + public function testEnsureCorrectTimeDoesNotThrowForCorrectTime() { + $tpr1 = new TestTimeProvider(123); + $tpr2 = new TestTimeProvider(128); + + $tfa = new TwoFactorAuth('Test', 6, 30, 'sha1', null, null, $tpr1); + $tfa->ensureCorrectTime(array($tpr2)); // 128 - 123 = 5 => within default leniency + } + + /** + * @expectedException \RobThree\Auth\TwoFactorAuthException + */ + public function testEnsureCorrectTimeThrowsOnIncorrectTime() { + $tpr1 = new TestTimeProvider(123); + $tpr2 = new TestTimeProvider(124); + + $tfa = new TwoFactorAuth('Test', 6, 30, 'sha1', null, null, $tpr1); + $tfa->ensureCorrectTime(array($tpr2), 0); // We force a leniency of 0, 124-123 = 1 so this should throw + } + + + public function testEnsureDefaultTimeProviderReturnsCorrectTime() { + $tfa = new TwoFactorAuth('Test', 6, 30, 'sha1'); + $tfa->ensureCorrectTime(array(new TestTimeProvider(time())), 1); // Use a leniency of 1, should the time change between both time() calls + } + + public function testEnsureAllTimeProvidersReturnCorrectTime() { + $tfa = new TwoFactorAuth('Test', 6, 30, 'sha1'); + $tfa->ensureCorrectTime(array( + new RobThree\Auth\Providers\Time\ConvertUnixTimeDotComTimeProvider(), + new RobThree\Auth\Providers\Time\HttpTimeProvider(), // Uses google.com by default + new RobThree\Auth\Providers\Time\HttpTimeProvider('https://github.com'), + new RobThree\Auth\Providers\Time\HttpTimeProvider('https://yahoo.com'), + )); + } + + public function testVerifyCodeWorksCorrectly() { + + $tfa = new TwoFactorAuth('Test', 6, 30); + $this->assertEquals(true , $tfa->verifyCode('VMR466AB62ZBOKHE', '543160', 1, 1426847190)); + $this->assertEquals(true , $tfa->verifyCode('VMR466AB62ZBOKHE', '543160', 0, 1426847190 + 29)); //Test discrepancy + $this->assertEquals(false, $tfa->verifyCode('VMR466AB62ZBOKHE', '543160', 0, 1426847190 + 30)); //Test discrepancy + $this->assertEquals(false, $tfa->verifyCode('VMR466AB62ZBOKHE', '543160', 0, 1426847190 - 1)); //Test discrepancy + + $this->assertEquals(true , $tfa->verifyCode('VMR466AB62ZBOKHE', '543160', 1, 1426847205 + 0)); //Test discrepancy + $this->assertEquals(true , $tfa->verifyCode('VMR466AB62ZBOKHE', '543160', 1, 1426847205 + 35)); //Test discrepancy + $this->assertEquals(true , $tfa->verifyCode('VMR466AB62ZBOKHE', '543160', 1, 1426847205 - 35)); //Test discrepancy + + $this->assertEquals(false, $tfa->verifyCode('VMR466AB62ZBOKHE', '543160', 1, 1426847205 + 65)); //Test discrepancy + $this->assertEquals(false, $tfa->verifyCode('VMR466AB62ZBOKHE', '543160', 1, 1426847205 - 65)); //Test discrepancy + + $this->assertEquals(true , $tfa->verifyCode('VMR466AB62ZBOKHE', '543160', 2, 1426847205 + 65)); //Test discrepancy + $this->assertEquals(true , $tfa->verifyCode('VMR466AB62ZBOKHE', '543160', 2, 1426847205 - 65)); //Test discrepancy + } + + public function testTotpUriIsCorrect() { + $qr = new TestQrProvider(); + + $tfa = new TwoFactorAuth('Test&Issuer', 6, 30, 'sha1', $qr); + $data = $this->DecodeDataUri($tfa->getQRCodeImageAsDataUri('Test&Label', 'VMR466AB62ZBOKHE')); + $this->assertEquals('test/test', $data['mimetype']); + $this->assertEquals('base64', $data['encoding']); + $this->assertEquals('otpauth://totp/Test%26Label?secret=VMR466AB62ZBOKHE&issuer=Test%26Issuer&period=30&algorithm=SHA1&digits=6@200', $data['data']); + } + + /** + * @expectedException \RobThree\Auth\TwoFactorAuthException + */ + public function testGetQRCodeImageAsDataUriThrowsOnInvalidSize() { + $qr = new TestQrProvider(); + + $tfa = new TwoFactorAuth('Test', 6, 30, 'sha1', $qr); + $tfa->getQRCodeImageAsDataUri('Test', 'VMR466AB62ZBOKHE', 0); + } + + /** + * @expectedException \RobThree\Auth\TwoFactorAuthException + */ + public function testGetCodeThrowsOnInvalidBase32String1() { + $tfa = new TwoFactorAuth('Test'); + $tfa->getCode('FOO1BAR8BAZ9'); //1, 8 & 9 are invalid chars + } + + /** + * @expectedException \RobThree\Auth\TwoFactorAuthException + */ + public function testGetCodeThrowsOnInvalidBase32String2() { + $tfa = new TwoFactorAuth('Test'); + $tfa->getCode('mzxw6==='); //Lowercase + } + + public function testKnownBase32DecodeTestVectors() { + // We usually don't test internals (e.g. privates) but since we rely heavily on base32 decoding and don't want + // to expose this method nor do we want to give people the possibility of implementing / providing their own base32 + // decoding/decoder (as we do with Rng/QR providers for example) we simply test the private base32Decode() method + // with some known testvectors **only** to ensure base32 decoding works correctly following RFC's so there won't + // be any bugs hiding in there. We **could** 'fool' ourselves by calling the public getCode() method (which uses + // base32decode internally) and then make sure getCode's output (in digits) equals expected output since that would + // mean the base32Decode() works as expected but that **could** hide some subtle bug(s) in decoding the base32 string. + + // "In general, you don't want to break any encapsulation for the sake of testing (or as Mom used to say, "don't + // expose your privates!"). Most of the time, you should be able to test a class by exercising its public methods." + // Dave Thomas and Andy Hunt -- "Pragmatic Unit Testing + $tfa = new TwoFactorAuth('Test'); + + $method = new ReflectionMethod('RobThree\Auth\TwoFactorAuth', 'base32Decode'); + $method->setAccessible(true); + + // Test vectors from: https://tools.ietf.org/html/rfc4648#page-12 + $this->assertEquals('', $method->invoke($tfa, '')); + $this->assertEquals('f', $method->invoke($tfa, 'MY======')); + $this->assertEquals('fo', $method->invoke($tfa, 'MZXQ====')); + $this->assertEquals('foo', $method->invoke($tfa, 'MZXW6===')); + $this->assertEquals('foob', $method->invoke($tfa, 'MZXW6YQ=')); + $this->assertEquals('fooba', $method->invoke($tfa, 'MZXW6YTB')); + $this->assertEquals('foobar', $method->invoke($tfa, 'MZXW6YTBOI======')); + } + + public function testKnownBase32DecodeUnpaddedTestVectors() { + // See testKnownBase32DecodeTestVectors() for the rationale behind testing the private base32Decode() method. + // This test ensures that strings without the padding-char ('=') are also decoded correctly. + // https://tools.ietf.org/html/rfc4648#page-4: + // "In some circumstances, the use of padding ("=") in base-encoded data is not required or used." + $tfa = new TwoFactorAuth('Test'); + + $method = new ReflectionMethod('RobThree\Auth\TwoFactorAuth', 'base32Decode'); + $method->setAccessible(true); + + // Test vectors from: https://tools.ietf.org/html/rfc4648#page-12 + $this->assertEquals('', $method->invoke($tfa, '')); + $this->assertEquals('f', $method->invoke($tfa, 'MY')); + $this->assertEquals('fo', $method->invoke($tfa, 'MZXQ')); + $this->assertEquals('foo', $method->invoke($tfa, 'MZXW6')); + $this->assertEquals('foob', $method->invoke($tfa, 'MZXW6YQ')); + $this->assertEquals('fooba', $method->invoke($tfa, 'MZXW6YTB')); + $this->assertEquals('foobar', $method->invoke($tfa, 'MZXW6YTBOI')); + } + + + public function testKnownTestVectors_sha1() { + //Known test vectors for SHA1: https://tools.ietf.org/html/rfc6238#page-15 + $secret = 'GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ'; //== base32encode('12345678901234567890') + $tfa = new TwoFactorAuth('Test', 8, 30, 'sha1'); + $this->assertEquals('94287082', $tfa->getCode($secret, 59)); + $this->assertEquals('07081804', $tfa->getCode($secret, 1111111109)); + $this->assertEquals('14050471', $tfa->getCode($secret, 1111111111)); + $this->assertEquals('89005924', $tfa->getCode($secret, 1234567890)); + $this->assertEquals('69279037', $tfa->getCode($secret, 2000000000)); + $this->assertEquals('65353130', $tfa->getCode($secret, 20000000000)); + } + + public function testKnownTestVectors_sha256() { + //Known test vectors for SHA256: https://tools.ietf.org/html/rfc6238#page-15 + $secret = 'GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQGEZA'; //== base32encode('12345678901234567890123456789012') + $tfa = new TwoFactorAuth('Test', 8, 30, 'sha256'); + $this->assertEquals('46119246', $tfa->getCode($secret, 59)); + $this->assertEquals('68084774', $tfa->getCode($secret, 1111111109)); + $this->assertEquals('67062674', $tfa->getCode($secret, 1111111111)); + $this->assertEquals('91819424', $tfa->getCode($secret, 1234567890)); + $this->assertEquals('90698825', $tfa->getCode($secret, 2000000000)); + $this->assertEquals('77737706', $tfa->getCode($secret, 20000000000)); + } + + public function testKnownTestVectors_sha512() { + //Known test vectors for SHA512: https://tools.ietf.org/html/rfc6238#page-15 + $secret = 'GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQGEZDGNA'; //== base32encode('1234567890123456789012345678901234567890123456789012345678901234') + $tfa = new TwoFactorAuth('Test', 8, 30, 'sha512'); + $this->assertEquals('90693936', $tfa->getCode($secret, 59)); + $this->assertEquals('25091201', $tfa->getCode($secret, 1111111109)); + $this->assertEquals('99943326', $tfa->getCode($secret, 1111111111)); + $this->assertEquals('93441116', $tfa->getCode($secret, 1234567890)); + $this->assertEquals('38618901', $tfa->getCode($secret, 2000000000)); + $this->assertEquals('47863826', $tfa->getCode($secret, 20000000000)); + } + + /** + * @requires function random_bytes + */ + public function testCSRNGProvidersReturnExpectedNumberOfBytes() { + $rng = new \RobThree\Auth\Providers\Rng\CSRNGProvider(); + foreach ($this->getRngTestLengths() as $l) + $this->assertEquals($l, strlen($rng->getRandomBytes($l))); + $this->assertEquals(true, $rng->isCryptographicallySecure()); + } + + /** + * @requires function hash_algos + * @requires function hash + */ + public function testHashRNGProvidersReturnExpectedNumberOfBytes() { + $rng = new \RobThree\Auth\Providers\Rng\HashRNGProvider(); + foreach ($this->getRngTestLengths() as $l) + $this->assertEquals($l, strlen($rng->getRandomBytes($l))); + $this->assertEquals(false, $rng->isCryptographicallySecure()); + } + + /** + * @requires function mcrypt_create_iv + */ + public function testMCryptRNGProvidersReturnExpectedNumberOfBytes() { + $rng = new \RobThree\Auth\Providers\Rng\MCryptRNGProvider(); + foreach ($this->getRngTestLengths() as $l) + $this->assertEquals($l, strlen($rng->getRandomBytes($l))); + $this->assertEquals(true, $rng->isCryptographicallySecure()); + } + + /** + * @requires function openssl_random_pseudo_bytes + */ + public function testStrongOpenSSLRNGProvidersReturnExpectedNumberOfBytes() { + $rng = new \RobThree\Auth\Providers\Rng\OpenSSLRNGProvider(true); + foreach ($this->getRngTestLengths() as $l) + $this->assertEquals($l, strlen($rng->getRandomBytes($l))); + $this->assertEquals(true, $rng->isCryptographicallySecure()); + } + + /** + * @requires function openssl_random_pseudo_bytes + */ + public function testNonStrongOpenSSLRNGProvidersReturnExpectedNumberOfBytes() { + $rng = new \RobThree\Auth\Providers\Rng\OpenSSLRNGProvider(false); + foreach ($this->getRngTestLengths() as $l) + $this->assertEquals($l, strlen($rng->getRandomBytes($l))); + $this->assertEquals(false, $rng->isCryptographicallySecure()); + } + + + private function getRngTestLengths() { + return array(1, 16, 32, 256); + } + + private function DecodeDataUri($datauri) { + if (preg_match('/data:(?P[\w\.\-\/]+);(?P\w+),(?P.*)/', $datauri, $m) === 1) { + return array( + 'mimetype' => $m['mimetype'], + 'encoding' => $m['encoding'], + 'data' => base64_decode($m['data']) + ); + } + return null; + } +} + +class TestRNGProvider implements IRNGProvider { + private $isSecure; + + function __construct($isSecure = false) { + $this->isSecure = $isSecure; + } + + public function getRandomBytes($bytecount) { + $result = ''; + for ($i=0; $i<$bytecount; $i++) + $result.=chr($i); + return $result; + + } + + public function isCryptographicallySecure() { + return $this->isSecure; + } +} + +class TestQrProvider implements IQRCodeProvider { + public function getQRCodeImage($qrtext, $size) { + return $qrtext . '@' . $size; + } + + public function getMimeType() { + return 'test/test'; + } +} + +class TestTimeProvider implements ITimeProvider { + private $time; + + function __construct($time) { + $this->time = $time; + } + + public function getTime() { + return $this->time; + } +} \ No newline at end of file diff --git a/user/plugins/markdown-notices/CHANGELOG.md b/user/plugins/markdown-notices/CHANGELOG.md new file mode 100644 index 00000000..0eab9284 --- /dev/null +++ b/user/plugins/markdown-notices/CHANGELOG.md @@ -0,0 +1,30 @@ +# v1.0.4 +## 09/10/2019 + +1. [](#improved) + * Reverted PR#10 which was breaking multiline notices and also unintentionally marking up notices with `!` in paragraphs + +# v1.0.3 +## 08/16/2019 + +1. [](#improved) + * Fixed issue where PR#10 clobbered PR#9 + +# v1.0.2 +## 08/11/2019 + +1. [](#new) + * Ability to specify your own base classes [#9](https://github.com/getgrav/grav-plugin-markdown-notices/pull/9) + * Allow adding inline notices inside tables [#10](https://github.com/getgrav/grav-plugin-markdown-notices/pull/10) + +# v1.0.1 +## 03/09/2018 + +1. [](#improved) + * Updated blueprint file + +# v1.0.0 +## 12/22/2015 + +1. [](#new) + * ChangeLog started... diff --git a/user/plugins/markdown-notices/LICENSE b/user/plugins/markdown-notices/LICENSE new file mode 100644 index 00000000..4bb70928 --- /dev/null +++ b/user/plugins/markdown-notices/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2016 Grav + +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. diff --git a/user/plugins/markdown-notices/README.md b/user/plugins/markdown-notices/README.md new file mode 100644 index 00000000..00f9cb6f --- /dev/null +++ b/user/plugins/markdown-notices/README.md @@ -0,0 +1,62 @@ +# Grav Markdown Notices Plugin + +The **markdown-notices plugin** for [Grav](http://github.com/getgrav/grav) allows generation of notice blocks of text via markdown: + +![](assets/screenshot.png) + +# Installation + +This plugin is easy to install with GPM. + +``` +$ bin/gpm install markdown-notices +``` + +# Configuration + +Simply copy the `user/plugins/markdown-notices/markdown-notices.yaml` into `user/config/plugins/markdown-notices.yaml` and make your modifications. + +``` +enabled: true +built_in_css: true +base_classes: 'notices' +level_classes: [yellow, red, blue, green] +``` + +# Examples + +Using one level of `!` + +``` +! Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris feugiat quam erat, ut iaculis diam posuere nec. +! Vestibulum eu condimentum urna. Vestibulum feugiat odio ut sodales porta. Donec sit amet ante mi. Donec lobortis +! orci dolor. Donec tristique volutpat ultricies. Nullam tempus, enim sit amet fringilla facilisis, ipsum ex +! tincidunt ipsum, vel placerat sem sem vitae risus. Aenean posuere sed purus nec pretium. +``` + +You will output the following HTML + +``` +
                                                            +

                                                            + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris feugiat quam erat, ut iaculis diam posuere nec. + Vestibulum eu condimentum urna. Vestibulum feugiat odio ut sodales porta. Donec sit amet ante mi. Donec lobortis + orci dolor. Donec tristique volutpat ultricies. Nullam tempus, enim sit amet fringilla facilisis, ipsum ex + tincidunt ipsum, vel placerat sem sem vitae risus. Aenean posuere sed purus nec pretium. +

                                                            +
                                                            +``` + +The `notices` class determined by the `base_classes` and `yellow` class is determined by the `level_classes` in the configuration. You can customize this as you need. + +``` +!! Lorem ipsum dolor sit amet, **consectetur adipiscing** elit. Mauris feugiat quam erat, ut iaculis diam posuere nec. +!! +!! * List item a +!! * List item b +!! +!! orci dolor. Donec tristique volutpat ultricies. Nullam tempus, enim sit amet fringilla facilisis, ipsum ex +!! tincidunt ipsum, vel placerat sem sem vitae risus. Aenean posuere sed purus nec pretium. +``` + +Two levels of `!!` will use the second level class etc. You can also use complex markdown inside the notices. diff --git a/user/plugins/markdown-notices/assets/notices.css b/user/plugins/markdown-notices/assets/notices.css new file mode 100644 index 00000000..93c3a856 --- /dev/null +++ b/user/plugins/markdown-notices/assets/notices.css @@ -0,0 +1,32 @@ +.notices { + padding: 1px 1px 1px 30px; + margin: 15px 0; +} + +.notices p { + +} + +.notices.yellow { + border-left: 10px solid #f0ad4e; + background: #fcf8f2; + color: #df8a13; +} + +.notices.red { + border-left: 10px solid #d9534f; + background: #fdf7f7; + color: #b52b27; +} + +.notices.blue { + border-left: 10px solid #5bc0de; + background: #f4f8fa; + color: #28a1c5; +} + +.notices.green { + border-left: 10px solid #5cb85c; + background: #f1f9f1; + color: #3d8b3d; +} \ No newline at end of file diff --git a/user/plugins/markdown-notices/assets/screenshot.png b/user/plugins/markdown-notices/assets/screenshot.png new file mode 100644 index 00000000..cf27677a Binary files /dev/null and b/user/plugins/markdown-notices/assets/screenshot.png differ diff --git a/user/plugins/markdown-notices/blueprints.yaml b/user/plugins/markdown-notices/blueprints.yaml new file mode 100644 index 00000000..9f1db5e7 --- /dev/null +++ b/user/plugins/markdown-notices/blueprints.yaml @@ -0,0 +1,55 @@ +name: 'Markdown Notices' +version: 1.0.4 +description: 'Adds the ability to render notices blocks in Markdown' +icon: asterisk +author: + name: Team Grav + email: devs@getgrav.org + url: http://getgrav.org +homepage: https://github.com/getgrav/grav-plugin-markdown-notices +license: MIT + +form: + validation: strict + fields: + enabled: + type: toggle + label: PLUGIN_ADMIN.PLUGIN_STATUS + highlight: 1 + default: 0 + options: + 1: PLUGIN_ADMIN.ENABLED + 0: PLUGIN_ADMIN.DISABLED + validate: + type: bool + + built_in_css: + type: toggle + label: PLUGIN_MARKDOWN_NOTICES.USE_BUILT_IN_CSS + highlight: 1 + default: 1 + options: + 1: PLUGIN_ADMIN.ENABLED + 0: PLUGIN_ADMIN.DISABLED + validate: + type: bool + + base_classes: + type: selectize + label: PLUGIN_MARKDOWN_NOTICES.BASE_CLASSES + size: large + placeholder: PLUGIN_MARKDOWN_NOTICES.BASE_CLASSES_PLACEHOLDER + help: PLUGIN_MARKDOWN_NOTICES.BASE_CLASSES_HELP + classes: fancy + validate: + type: string + + level_classes: + type: selectize + label: PLUGIN_MARKDOWN_NOTICES.LEVEL_CLASSES + size: large + placeholder: PLUGIN_MARKDOWN_NOTICES.LEVEL_CLASSES_PLACEHOLDER + help: PLUGIN_MARKDOWN_NOTICES.LEVEL_CLASSES_HELP + classes: fancy + validate: + type: commalist diff --git a/user/plugins/markdown-notices/languages.yaml b/user/plugins/markdown-notices/languages.yaml new file mode 100644 index 00000000..dbee7598 --- /dev/null +++ b/user/plugins/markdown-notices/languages.yaml @@ -0,0 +1,29 @@ +en: + PLUGIN_MARKDOWN_NOTICES: + USE_BUILT_IN_CSS: 'Use built-in CSS' + BASE_CLASSES: 'Base classes' + BASE_CLASSES_HELP: 'These classes will be added before the class level' + BASE_CLASSES_PLACEHOLDER: 'e.g. notices' + LEVEL_CLASSES: 'Level classes' + LEVEL_CLASSES_HELP: 'The classes to use for each level of notices depth' + LEVEL_CLASSES_PLACEHOLDER: 'e.g. yellow, red, blue, green' + +ru: + PLUGIN_MARKDOWN_NOTICES: + USE_BUILT_IN_CSS: 'Использовать встроенный CSS' + BASE_CLASSES: 'Базовые классы' + BASE_CLASSES_HELP: 'Эти классы будут добавлены до уровня класса' + BASE_CLASSES_PLACEHOLDER: 'например notices' + LEVEL_CLASSES: 'Классы уровней' + LEVEL_CLASSES_HELP: 'Эти классы используются на каждом уровне глубины уведомлений' + LEVEL_CLASSES_PLACEHOLDER: 'например yellow, red, blue, green' + +uk: + PLUGIN_MARKDOWN_NOTICES: + USE_BUILT_IN_CSS: 'Використовувати вбудований CSS' + BASE_CLASSES: 'Базові класи' + BASE_CLASSES_HELP: 'Ці класи будуть додані до рівня класу' + BASE_CLASSES_PLACEHOLDER: 'наприклад notices' + LEVEL_CLASSES: 'Класи рівнів' + LEVEL_CLASSES_HELP: 'Ці класи використовуються на кожному рівні глибини повідомлень' + LEVEL_CLASSES_PLACEHOLDER: 'наприклад yellow, red, blue, green' diff --git a/user/plugins/markdown-notices/markdown-notices.php b/user/plugins/markdown-notices/markdown-notices.php new file mode 100644 index 00000000..abd6b34f --- /dev/null +++ b/user/plugins/markdown-notices/markdown-notices.php @@ -0,0 +1,84 @@ + ['onMarkdownInitialized', 0], + 'onTwigSiteVariables' => ['onTwigSiteVariables', 0] + ]; + } + + public function onMarkdownInitialized(Event $event) + { + $markdown = $event['markdown']; + + $markdown->addBlockType('!', 'Notices', true, false); + + $markdown->blockNotices = function($Line) { + + $this->level_classes = $this->config->get('plugins.markdown-notices.level_classes'); + $this->base_classes = $this->config->get('plugins.markdown-notices.base_classes'); + + if (preg_match('/^(!{1,'.count($this->level_classes).'})[ ]+(.*)/', $Line['text'], $matches)) + { + $level = strlen($matches[1]) - 1; + + // if we have more levels than we support + if ($level > count($this->level_classes)-1) + { + return; + } + + $text = $matches[2]; + $base_classes = (empty($this->base_classes)) ? '' : str_replace(',', ' ', $this->base_classes) . ' '; + + $Block = [ + 'element' => [ + 'name' => 'div', + 'handler' => 'lines', + 'attributes' => [ + 'class' => $base_classes . $this->level_classes[$level], + ], + 'text' => (array) $text, + ], + ]; + + return $Block; + } + }; + + $markdown->blockNoticesContinue = function($Line, array $Block) { + if (isset($Block['interrupted'])) + { + return; + } + + if ($Line['text'][0] === '!' and preg_match('/^(!{1,'.count($this->level_classes).'})(.*)/', $Line['text'], $matches)) + { + $Block['element']['text'] []= ltrim($matches[2]); + + return $Block; + } + }; + } + + public function onTwigSiteVariables() + { + if ($this->config->get('plugins.markdown-notices.built_in_css')) { + $this->grav['assets'] + ->add('plugin://markdown-notices/assets/notices.css'); + } + } +} diff --git a/user/plugins/markdown-notices/markdown-notices.yaml b/user/plugins/markdown-notices/markdown-notices.yaml new file mode 100644 index 00000000..2e15749c --- /dev/null +++ b/user/plugins/markdown-notices/markdown-notices.yaml @@ -0,0 +1,4 @@ +enabled: true +built_in_css: true +base_classes: 'notices' +level_classes: [yellow, red, blue, green] diff --git a/user/plugins/problems/CHANGELOG.md b/user/plugins/problems/CHANGELOG.md new file mode 100644 index 00000000..4a748067 --- /dev/null +++ b/user/plugins/problems/CHANGELOG.md @@ -0,0 +1,143 @@ +# v2.0.3 +## 05/09/2019 + +1. [](#new) + * Code cleanup + * Pass `phpstan` tests + * Added `ru` and `uk` translations [#23](https://github.com/getgrav/grav-plugin-problems/pull/23) + +# v2.0.2 +## 12/16/2018 + +1. [](#bugfix) + * Fixed an issue with checker not being initialized on Fatal Error + +# v2.0.1 +## 12/07/2018 + +1. [](#new) + * Added support for admin reporting available in Grav 1.6 +1. [](#bugfix) + * Fixed issue with twig auto-escaping + * Fixed problems plugin potentially breaking CLI command if plugins get initialized + +# v2.0.0 +## 09/30/2018 + +1. [](#new) + * Completely rewritten to be much more flexible + * New _class_ based problems architecture for unified problem definition and reporting + * New `onProblemsInitialized()` plugin event for 3rd party plugins to add their own problem checks + * New more intuitive theme based on Spectre.css to display problems + * Storage of problem state to allow for displaying in admin plugin + * Now with 3 states `critical`, `warning`, and `notice`. Only critical will stop the site working. + * Added some new PHP module checks + * Added a new `umask` permission check +1. [](#improved) + * Implemented extra image checks [#17](https://github.com/getgrav/grav-plugin-problems/pull/17) + +# v1.4.7 +## 05/16/2017 + +1. [](#improved) + * Added check for Exif module if this feature is enabled + +# v1.4.6 +## 02/17/2017 + +1. [](#improved) + * Return 500 error code if there is a problem instead of 200 [https://github.com/getgrav/grav/issues/1291](https://github.com/getgrav/grav/issues/1291) + +# v1.4.5 +## 09/14/2016 + +1. [](#bugfix) + * Show the correct status for the Zip extension check + +# v1.4.4 +## 09/08/2016 + +1. [](#new) + * Added check for new root folder `tmp` and try to create if missing +1. [](#bugfix) + * Fixed Whoops error if `backup` folder doesn't exist and cannot be created + +# v1.4.3 +## 05/27/2016 + +1. [](#new) + * Reverted compression checks + +# v1.4.2 +## 05/23/2016 + +1. [](#new) + * Check for compression issues + +# v1.4.1 +## 05/03/2016 + +1. [](#new) + * Added a check for XML support in PHP +1. [](#improved) + * Use common language strings in blueprints + +# v1.4.0 +## 01/06/2016 + +1. [](#improved) + * Avoid generating errors on .DS_Store files added to the bin/ folder by OSX + * Removed executable checks for bin/* commands. Going to document instead. + +# v1.3.3 +## 12/09/2015 + +1. [](#new) + * Set minimum PHP requirements to 5.5.9 +1. [](#improved) + * Ensure problems plugin runs before admin + +# v1.3.2 +## 12/09/2015 + +1. [](#improved) + * Skip windows platforms for executable permissions check + * Removed mod_headers from required Apache modules check + +# v1.3.1 +## 12/07/2015 + +1. [](#improved) + * Added executable check on `/bin/` files + +# v1.3.0 +## 12/07/2015 + +1. [](#improved) + * Added check for PHP `OpenSSL`, `Mbstring` and `Curl` are installed + * Added check to ensure `mod_rewrite` and `mod_headers` are installed if running Apache + +# v1.2.0 +## 08/25/2015 + +1. [](#improved) + * Added blueprints for Grav Admin plugin + +# v1.1.6 +## 06/16/2015 + +2. [](#new) + * Try to create missing `backup` folder if it is missing + +# v1.1.5 +## 05/09/2015 + +2. [](#new) + * Added check for `backup` folder for Grav > 0.9.27 + +# v1.1.4 +## 04/26/2015 + +2. [](#new) + * Changelog started + diff --git a/user/plugins/problems/LICENSE b/user/plugins/problems/LICENSE new file mode 100644 index 00000000..484793ad --- /dev/null +++ b/user/plugins/problems/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014 Grav + +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. diff --git a/user/plugins/problems/README.md b/user/plugins/problems/README.md new file mode 100644 index 00000000..ad7fd6f8 --- /dev/null +++ b/user/plugins/problems/README.md @@ -0,0 +1,92 @@ +# Grav Problems Plugin + +[![PHPStan](https://img.shields.io/badge/PHPStan-enabled-brightgreen.svg?style=flat)](https://github.com/phpstan/phpstan) + +![Problems](assets/readme_1.jpg) + +`Problems` is a [Grav](http://github.com/getgrav/grav) Plugin and allows to detect issues. + +This plugin is included in any package distributed that contains Grav. If you decide to clone Grav from GitHub, you will most likely want to install this. + +# Installation + +Installing the Problems plugin can be done in one of two ways. Our GPM (Grav Package Manager) installation method enables you to quickly and easily install the plugin with a simple terminal command, while the manual method enables you to do so via a zip file. + +## GPM Installation (Preferred) + +The simplest way to install this plugin is via the [Grav Package Manager (GPM)](http://learn.getgrav.org/advanced/grav-gpm) through your system's Terminal (also called the command line). From the root of your Grav install type: + + bin/gpm install problems + +This will install the Problems plugin into your `/user/plugins` directory within Grav. Its files can be found under `/your/site/grav/user/plugins/problems`. + +## Manual Installation + +To install this plugin, just download the zip version of this repository and unzip it under `/your/site/grav/user/plugins`. Then, rename the folder to `problems`. You can find these files either on [GitHub](https://github.com/getgrav/grav-plugin-problems) or via [GetGrav.org](http://getgrav.org/downloads/plugins#extras). + +You should now have all the plugin files under + + /your/site/grav/user/plugins/problems + +> NOTE: This plugin is a modular component for Grav which requires [Grav](http://github.com/getgrav/grav), the [Error](https://github.com/getgrav/grav-plugin-error) and [Problems](https://github.com/getgrav/grav-plugin-problems) plugins, and a theme to be installed in order to operate. + +# Usage + +`Problems` runs in the background and most of the time you will not know it is there. Although as soon as an issue is caught, the plugin will let you know. + +`Problems` checks for the following common issues: + +| Check | Description | +| :-------------- | :-------------------------------------------------------------------------------- | +| Apache | `mod_rewrite` is enabled if you are running an Apache server. | +| PHP Version | PHP version being run by the server meets or exceeds Grav's minimum requirements. | +| PHP Modules | PHP GD library is installed. | +| | PHP Curl library is installed. | +| | PHP Ctype library is installed | +| | PHP Dom is library installed | +| | PHP OpenSSL library is installed | +| | PHP XML library is installed | +| | PHP Zip library is installed | +| | PHP Exif library is installed if Exif support is enabled | +| | PHP OpenSSL library is installed. | +| | PHP Mbstring library is installed. | +| Essential Files | `.htaccess` file in Grav's root directory. | +| | Checks that all the files in the `bin/` folder are exectuable. | +| | `/cache` folder's existence and verifies that it is writeable. | +| | `/logs` folder's existence and verifies that it is writeable. | +| | `/images` folder's existence and verifies that it is writeable. | +| | `/assets` folder's existence and verifies that it is writeable. | +| | `/system` folder's existence. | +| | `/tmp` folder's existence. | +| | `/user/data` folder's existence and verifies that it is writeable. | +| | `/user/images` folder's existence. | +| | `/user/config` folder's existence. | +| | **Error** plugin is installed in `/user/plugins/error`. | +| | `/user/plugins` folder's existence. | +| | `/user/themes` folder's existence. | +| | `/vendor` folder's existence. | + +If an issue is discovered, you will be greeted with a page that lists these checks and whether or not your install passed or failed them. Green checks mean it passed, and a red x indicates that the there is something amiss with the item. + +Problems uses the cache as refresh indicator. That means that if nothing has changed anywhere, the plugin will just skip its validation tests altogether. + +If a change is caught and the cache is refreshed, the plugin will loop through its validation tests and making sure nothing is out of place. + +`Problems` gets also triggered if any fatal exception is caught. + +# CLI Command + +Problems 2.0 comes with a handy CLI command so you can run the checks at any time + +```bash +bin/plugin problems check +``` + +You should see some output like this: + + +![](assets/cli.png) + +# Extending Plugins + +You can also extend the problems plugin via the `onProblemsInitialized()` event. The event includes an array of Problems. Simply create your own Problems class that extends the `Grav\Plugin\Problems\Base\Problem` class and add it to the array. diff --git a/user/plugins/problems/assets/cli.png b/user/plugins/problems/assets/cli.png new file mode 100644 index 00000000..8c031a7b Binary files /dev/null and b/user/plugins/problems/assets/cli.png differ diff --git a/user/plugins/problems/assets/code-3.svg b/user/plugins/problems/assets/code-3.svg new file mode 100644 index 00000000..6939743f --- /dev/null +++ b/user/plugins/problems/assets/code-3.svg @@ -0,0 +1,11 @@ + + + + + + diff --git a/user/plugins/problems/assets/grav-logo.svg b/user/plugins/problems/assets/grav-logo.svg new file mode 100644 index 00000000..845a9944 --- /dev/null +++ b/user/plugins/problems/assets/grav-logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/plugins/problems/assets/heart.svg b/user/plugins/problems/assets/heart.svg new file mode 100644 index 00000000..ec70097e --- /dev/null +++ b/user/plugins/problems/assets/heart.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/user/plugins/problems/assets/readme_1.jpg b/user/plugins/problems/assets/readme_1.jpg new file mode 100644 index 00000000..da4c032d Binary files /dev/null and b/user/plugins/problems/assets/readme_1.jpg differ diff --git a/user/plugins/problems/blueprints.yaml b/user/plugins/problems/blueprints.yaml new file mode 100644 index 00000000..cefc5db2 --- /dev/null +++ b/user/plugins/problems/blueprints.yaml @@ -0,0 +1,38 @@ +name: Problems +version: 2.0.3 +description: Detects and reports problems found in the site. +icon: exclamation-circle +author: + name: Team Grav + email: devs@getgrav.org + url: http://getgrav.org +homepage: https://github.com/getgrav/grav-plugin-problems +keywords: problems, plugin, detector, assistant, required +bugs: https://github.com/getgrav/grav-plugin-problems/issues +license: MIT + +form: + validation: strict + fields: + enabled: + type: toggle + label: PLUGIN_ADMIN.PLUGIN_STATUS + highlight: 1 + default: 0 + options: + 1: PLUGIN_ADMIN.ENABLED + 0: PLUGIN_ADMIN.DISABLED + validate: + type: bool + + built_in_css: + type: toggle + label: PLUGIN_PROBLEMS.BUILTIN_CSS + help: PLUGIN_PROBLEMS.BUILTIN_CSS_HELP + highlight: 1 + default: 1 + options: + 1: PLUGIN_ADMIN.ENABLED + 0: PLUGIN_ADMIN.DISABLED + validate: + type: bool diff --git a/user/plugins/problems/classes/Problems/Apache.php b/user/plugins/problems/classes/Problems/Apache.php new file mode 100644 index 00000000..5695726d --- /dev/null +++ b/user/plugins/problems/classes/Problems/Apache.php @@ -0,0 +1,54 @@ +id = 'Apache Modules'; + $this->class = get_class($this); + $this->order = 1; + $this->level = Problem::LEVEL_CRITICAL; + $this->status = true; + $this->help = 'https://learn.getgrav.org/basics/requirements#apache-requirements'; + } + + public function process() + { + // Perform some Apache checks + if (function_exists('apache_get_modules') && strpos(PHP_SAPI, 'apache') !== false) { + + $require_apache_modules = ['mod_rewrite']; + $apache_modules = apache_get_modules(); + + $apache_errors = []; + $apache_success = []; + + foreach ($require_apache_modules as $module) { + if (in_array($module, $apache_modules, true)) { + $apache_success[$module] = 'module required but not enabled'; + } else { + $apache_errors[$module] = 'module is not installed or enabled'; + } + } + + if (empty($apache_errors)) { + $this->status = true; + $this->msg = 'All modules look good!'; + } else { + $this->status = false; + $this->msg = 'There were problems with required modules:'; + } + + $this->details = ['errors' => $apache_errors, 'success' => $apache_success]; + } else { + $this->msg = 'Apache not installed, skipping...'; + } + + return $this; + } +} + diff --git a/user/plugins/problems/classes/Problems/Base/Problem.php b/user/plugins/problems/classes/Problems/Base/Problem.php new file mode 100644 index 00000000..7e69440d --- /dev/null +++ b/user/plugins/problems/classes/Problems/Base/Problem.php @@ -0,0 +1,87 @@ +set_object_vars($data); + } + + public function process() + { + return $this; + } + + public function getId() + { + return $this->id; + } + + public function getOrder() + { + return $this->order; + } + + public function getLevel() + { + return $this->level; + } + + public function getStatus() + { + return $this->status; + } + + public function getMsg() + { + return $this->msg; + } + + public function getDetails() + { + return $this->details; + } + + public function getHelp() + { + return $this->help; + } + + public function getClass() + { + return $this->class; + } + + public function toArray() + { + return get_object_vars($this); + } + + public function jsonSerialize() + { + $this->toArray(); + } + + protected function set_object_vars(array $vars) + { + $has = get_object_vars($this); + foreach ($has as $name => $oldValue) { + $this->{$name} = isset($vars[$name]) ? $vars[$name] : NULL; + } + } +} \ No newline at end of file diff --git a/user/plugins/problems/classes/Problems/Base/ProblemChecker.php b/user/plugins/problems/classes/Problems/Base/ProblemChecker.php new file mode 100644 index 00000000..85af7241 --- /dev/null +++ b/user/plugins/problems/classes/Problems/Base/ProblemChecker.php @@ -0,0 +1,130 @@ +status_file = CACHE_DIR . $this::PROBLEMS_PREFIX . $cache->getKey() . '.json'; + } + + public function load() + { + if ($this->statusFileExists()) { + $json = file_get_contents($this->status_file) ?: ''; + $data = json_decode($json, true); + if (!is_array($data)) { + return false; + } + + foreach ($data as $problem) { + $class = $problem['class']; + $this->problems[] = new $class($problem); + } + } + + return true; + } + + public function getStatusFile() + { + return $this->status_file; + } + + public function statusFileExists() + { + return file_exists($this->status_file); + } + + + public function storeStatusFile() + { + $problems = $this->getProblemsSerializable(); + $json = json_encode($problems); + file_put_contents($this->status_file, $json); + } + + public function check($problems_dir = null) + { + $problems_dir = $problems_dir ?: dirname(__DIR__); + $problems = []; + $problems_found = false; + + foreach (new \DirectoryIterator($problems_dir) as $file) { + if ($file->isDot() || $file->isDir()) { + continue; + } + $classname = 'Grav\\Plugin\\Problems\\' . $file->getBasename('.php'); + /** @var Problem $problem */ + $problem = new $classname(); + $problems[$problem->getId()] = $problem; + } + + // Fire event to allow other plugins to add problems + Grav::instance()->fireEvent('onProblemsInitialized', new Event(['problems' => $problems])); + + // Get the problems in order + usort($problems, function($a, $b) { + /** @var Problem $a */ + /** @var Problem $b */ + return $b->getOrder() - $a->getOrder(); + }); + + // run the process methods in new order + foreach ($problems as $problem) { + $problem->process(); + if ($problem->getStatus() === false && $problem->getLevel() === Problem::LEVEL_CRITICAL) { + $problems_found = true; + } + } + + $this->problems = $problems; + + return $problems_found; + } + + public function getProblems() + { + if (empty($this->problems)) { + $this->check(); + } + + $problems = $this->problems; + + // Put the failed ones first + usort($problems, function($a, $b) { + /** @var Problem $a */ + /** @var Problem $b */ + return $a->getStatus() - $b->getStatus(); + }); + + return $problems; + } + + public function getProblemsSerializable() + { + if (empty($this->problems)) { + $this->getProblems(); + } + + $problems = []; + foreach ($this->problems as $problem) { + $problems[] = $problem->toArray(); + } + return $problems; + } + +} \ No newline at end of file diff --git a/user/plugins/problems/classes/Problems/EssentialFolders.php b/user/plugins/problems/classes/Problems/EssentialFolders.php new file mode 100644 index 00000000..7dae1dec --- /dev/null +++ b/user/plugins/problems/classes/Problems/EssentialFolders.php @@ -0,0 +1,66 @@ +id = 'Essential Folders'; + $this->class = get_class($this); + $this->order = 100; + $this->level = Problem::LEVEL_CRITICAL; + $this->status = false; + $this->help = 'https://learn.getgrav.org/basics/folder-structure'; + } + + public function process() + { + $essential_folders = [ + 'backup' => true, + 'cache' => true, + 'logs' => true, + 'images' => true, + 'assets' => true, + 'system' => false, + 'user/data' => true, + 'user/pages' => false, + 'user/config' => false, + 'user/plugins/error' => false, + 'user/plugins' => false, + 'user/themes' => false, + 'vendor' => false, + 'tmp' => true, + ]; + + // Check for essential files & perms + $file_errors = []; + $file_success = []; + + foreach ($essential_folders as $file => $check_writable) { + $file_path = ROOT_DIR . $file; + + if (!file_exists($file_path)) { + $file_errors[$file_path] = 'does not exist'; + } elseif ($check_writable && !is_writable($file_path)) { + $file_errors[$file_path] = 'exists but is not writeable'; + } else { + $file_success[$file_path] = 'exists and is writable'; + } + } + + if (empty($file_errors)) { + $this->status = true; + $this->msg = 'All folders look good!'; + } else { + $this->status = false; + $this->msg = 'There were problems with required folders:'; + } + + $this->details = ['errors' => $file_errors, 'success' => $file_success]; + + return $this; + } +} \ No newline at end of file diff --git a/user/plugins/problems/classes/Problems/PHPModules.php b/user/plugins/problems/classes/Problems/PHPModules.php new file mode 100644 index 00000000..a6c107a5 --- /dev/null +++ b/user/plugins/problems/classes/Problems/PHPModules.php @@ -0,0 +1,133 @@ +id = 'PHP Modules'; + $this->class = get_class($this); + $this->order = 101; + $this->level = Problem::LEVEL_CRITICAL; + $this->status = false; + $this->help = 'https://learn.getgrav.org/basics/requirements#php-requirements'; + } + + public function process() + { + $modules_errors = []; + $modules_success = []; + + // Check for PHP CURL library + $msg = 'PHP Curl (Data Transfer Library) is %s installed'; + if (function_exists('curl_version')) { + $modules_success['curl'] = sprintf($msg, 'successfully'); + } else { + $modules_errors['curl'] = sprintf($msg, 'required but not'); + } + + // Check for PHP Ctype library + $msg = 'PHP Ctype is %s installed'; + if (function_exists('ctype_print')) { + $modules_success['ctype'] = sprintf($msg, 'successfully'); + } else { + $modules_errors['ctype'] = sprintf($msg, 'required but not'); + } + + // Check for PHP Dom library + $msg = 'PHP DOM is %s installed'; + if (class_exists('DOMDocument')) { + $modules_success['dom'] = sprintf($msg, 'successfully'); + } else { + $modules_errors['dom'] = sprintf($msg, 'required but not'); + } + + // Check for GD library + $msg = 'PHP GD (Image Manipulation Library) is %s installed'; + if (defined('GD_VERSION') && function_exists('gd_info')) { + + $msg = $modules_success['gd'] = sprintf($msg, 'successfully'); + + // Extra checks for Image support + $ginfo = gd_info(); + $gda = array('PNG Support', 'JPEG Support', 'FreeType Support', 'GIF Read Support'); + $gda_msg = ''; + $problems_found = false; + + foreach ($gda as $image_type) { + if (!$ginfo[$image_type]) { + $problems_found = true; + $gda_msg = "missing $image_type, but is "; + break; + } + } + + if ($problems_found) { + $msg .= ' but missing ' . $gda_msg; + } + + $modules_success['gd'] = $msg; + } else { + $modules_errors['gd'] = sprintf($msg, 'required but not'); + } + + // Check for PHP MbString library + $msg = 'PHP Mbstring (Multibyte String Library) is %s installed'; + if (extension_loaded('mbstring')) { + $modules_success['mbstring'] = sprintf($msg, 'successfully'); + } else { + $modules_errors['mbstring'] = sprintf($msg, 'required but not'); + } + + // Check for PHP Open SSL library + $msg = 'PHP OpenSSL (Secure Sockets Library) is %s installed'; + if (defined('OPENSSL_VERSION_TEXT') && extension_loaded('openssl')) { + $modules_success['openssl'] = sprintf($msg, 'successfully'); + } else { + $modules_errors['openssl'] = sprintf($msg, 'required but not'); + } + + // Check for PHP XML library + $msg = 'PHP XML Library is %s installed'; + if (extension_loaded('xml')) { + $modules_success['xml'] = sprintf($msg, 'successfully'); + } else { + $modules_errors['xml'] = sprintf($msg, 'required but not'); + } + + // Check for PHP Zip library + $msg = 'PHP Zip extension is %s installed'; + if (extension_loaded('zip')) { + $modules_success['zip'] = sprintf($msg, 'successfully'); + } else { + $modules_errors['zip'] = sprintf($msg, 'required but not'); + } + + // Check Exif if enabled + if (Grav::instance()['config']->get('system.media.auto_metadata_exif')) { + $msg = 'PHP Exif (Exchangeable Image File Format) is %s installed'; + if (extension_loaded('exif')) { + $modules_success['exif'] = sprintf($msg, 'successfully'); + } else { + $modules_errors['exif'] = sprintf($msg, 'required but not'); + } + } + + if (empty($modules_errors)) { + $this->status = true; + $this->msg = 'All modules look good!'; + } else { + $this->status = false; + $this->msg = 'There were problems with required modules:'; + } + + $this->details = ['errors' => $modules_errors, 'success' => $modules_success]; + + return $this; + } +} + diff --git a/user/plugins/problems/classes/Problems/PHPVersion.php b/user/plugins/problems/classes/Problems/PHPVersion.php new file mode 100644 index 00000000..8eb095c8 --- /dev/null +++ b/user/plugins/problems/classes/Problems/PHPVersion.php @@ -0,0 +1,36 @@ +id = 'PHP Minimum Version'; + $this->class = get_class($this); + $this->order = 102; + $this->level = Problem::LEVEL_CRITICAL; + $this->status = false; + $this->help = 'https://getgrav.org/blog/raising-php-requirements-2018'; + } + + public function process() + { + $min_php_version = defined('GRAV_PHP_MIN') ? GRAV_PHP_MIN : '5.6.4'; + $your_php_version = PHP_VERSION; + + $msg = 'Your PHP %s is %s than the minimum of %s required'; + + // Check PHP version + if (version_compare($your_php_version, $min_php_version, '<')) { + $this->msg = sprintf($msg, $your_php_version, 'less', $min_php_version); + } else { + $this->msg = sprintf($msg, $your_php_version, 'greater', $min_php_version); + $this->status = true; + } + + return $this; + } +} \ No newline at end of file diff --git a/user/plugins/problems/classes/Problems/Permissions.php b/user/plugins/problems/classes/Problems/Permissions.php new file mode 100644 index 00000000..9e9c135c --- /dev/null +++ b/user/plugins/problems/classes/Problems/Permissions.php @@ -0,0 +1,35 @@ +id = 'Permissions Setup'; + $this->class = get_class($this); + $this->order = -1; + $this->level = Problem::LEVEL_WARNING; + $this->status = false; + $this->help = 'https://learn.getgrav.org/troubleshooting/permissions'; + } + + public function process() + { + umask($umask = umask(022)); + + $msg = 'Your default file umask is %s which %s'; + + if (($umask & 2) !== 2) { + $this->msg = sprintf($msg, decoct($umask), 'is potentially dangerous'); + $this->status = false; + } else { + $this->msg = sprintf($msg, decoct($umask), 'looks good!'); + $this->status = true; + } + + return $this; + } +} \ No newline at end of file diff --git a/user/plugins/problems/cli/CheckCommand.php b/user/plugins/problems/cli/CheckCommand.php new file mode 100644 index 00000000..a4f778b7 --- /dev/null +++ b/user/plugins/problems/cli/CheckCommand.php @@ -0,0 +1,102 @@ +setName('check') + ->setDescription('Check Problems') + ->setHelp('The problems command allows you display any potential problems with your Grav setup') + ; + } + + /** + * @return int|null|void + */ + protected function serve() + { + $io = new SymfonyStyle($this->input, $this->output); + + $plugin_dir = realpath(dirname(__DIR__)); + $problems_dir = $plugin_dir . '/classes/Problems'; + + require $plugin_dir . '/vendor/autoload.php'; + + $checker = new ProblemChecker(); + $checker->check($problems_dir); + + $problems = $checker->getProblems(); + + $io->title('Grav Problems'); + + $table = new Table($this->output); + $table->setStyle('default'); + $headers = ['ID', 'Status', 'Level', 'Message']; + $rows = []; + + /** @var Problem $problem */ + foreach ($problems as $problem) { + $rows[] = new TableSeparator(); + + $rows[] = [ + $problem->getStatus() ? $problem->getId() : '' . $problem->getId() . '' , + $problem->getStatus() ? 'success' : 'error', + $problem->getLevel() === 'critical' ? '' . $problem->getLevel() . '' : '' .$problem->getLevel() . '', + strip_tags($problem->getMsg()), + ]; + + $details = $problem->getDetails(); + + if (is_array($details)) { + + $errors_row = []; + $success_row = []; + + if (isset($details['errors'])) { + foreach ($details['errors'] as $key => $value) { + $errors_row[] = " {$key} → {$value}"; + } + } + + if (isset($details['success'])) { + foreach ($details['success'] as $key => $value) { + $success_row[] = " {$key} → {$value}"; + } + } + + foreach($errors_row as $e_row) { + $rows[] = ['', new TableCell($e_row, array('colspan' => 3)), ]; + } + + foreach($success_row as $e_row) { + $rows[] = ['', new TableCell($e_row, array('colspan' => 3)), ]; + } + } + } + + if (!empty($rows)) { + $table->setHeaders($headers); + $table->setRows($rows); + $table->render(); + } else { + $io->text('did not find anything to check...'); + } + } +} + diff --git a/user/plugins/problems/composer.json b/user/plugins/problems/composer.json new file mode 100644 index 00000000..88cbef79 --- /dev/null +++ b/user/plugins/problems/composer.json @@ -0,0 +1,32 @@ +{ + "name": "getgrav/grav-plugin-problems", + "type": "grav-plugin", + "description": "Problem detection and reporting plugin for Grav CMS", + "keywords": ["grav", "plugin", "problems", "detector", "assistant"], + "homepage": "https://github.com/getgrav/grav-plugin-problems", + "license": "MIT", + "authors": [ + { + "name": "Team Grav", + "email": "devs@getgrav.org", + "homepage": "https://getgrav.org", + "role": "Developer" + } + ], + "support": { + "issues": "https://github.com/getgrav/grav-plugin-problems/issues", + "irc": "https://chat.getgrav.org", + "forum": "https://getgrav.org/forum", + "docs": "https://github.com/getgrav/grav-plugin-problems/blob/master/README.md" + }, + "autoload": { + "psr-4": { + "Grav\\Plugin\\": "classes/", + "Grav\\Plugin\\Console\\": "cli/" + }, + "classmap": ["problems.php"] + }, + "require": { + "ext-json": "*" + } +} \ No newline at end of file diff --git a/user/plugins/problems/css/admin.css b/user/plugins/problems/css/admin.css new file mode 100644 index 00000000..792dcf87 --- /dev/null +++ b/user/plugins/problems/css/admin.css @@ -0,0 +1,51 @@ +#admin-main .admin-block .report-output h1 { margin-top: 2rem; } + +#admin-main .admin-block .report-output .toast .btn { float: right; margin-top: -2px; margin-right: 0.5rem; color: #fff; font-size: 90%; padding: 2px 7px; border-radius: 3px; border: 1px solid #29b739; background-color: #2bc03c; } + +#admin-main .admin-block .report-output .toast .btn:hover { border-color: #27af37; background-color: #29b739; } + +#admin-main .admin-block .report-output .toast .btn.btn-error { border: 1px solid #f2403f; background-color: #f34a49; } + +#admin-main .admin-block .report-output .toast .btn.btn-error:hover { border-color: #f23735; background-color: #f2403f; } + +#admin-main .admin-block .report-output .toast .btn.btn-warning { border: 1px solid #ff7702; background-color: #ff7d0c; } + +#admin-main .admin-block .report-output .toast .btn.btn-warning:hover { border-color: #f67300; background-color: #ff7702; } + +.report-output ul.problems { margin: 1rem 0; list-style: none; padding: 0; background-color: #f7f7f7; } + +.report-output ul.problems h5 { margin: 0; } + +.report-output ul.problems li.menu { margin-bottom: 1rem; box-shadow: 0 10px 20px -10px rgba(0, 0, 0, 0.2); } + +.report-output ul.problems .toast { font-size: 1rem; padding: 0.5rem 1.5rem; color: #fff; } + +.report-output ul.problems .toast.toast-success { background-color: #2ECC40; } + +.report-output ul.problems .toast.toast-error { background-color: #F45857; } + +.report-output ul.problems .toast.toast-warning { background-color: #FF851B; } + +.report-output ul.problems .toast .btn { margin-left: 1rem; text-decoration: none !important; } + +.report-output ul.problems .toast .btn i { margin-right: 0.3rem; } + +.report-output ul.problems ul.details { list-style: none; padding-left: 0; padding-bottom: 1rem; background-color: #fff; } + +.report-output ul.problems ul.details li { padding-left: 1.5rem; padding-right: 1.5rem; } + +.report-output ul.problems ul.details code { font-size: 90%; line-height: 1.2; padding: .1rem .2rem; color: #288fed; border-radius: .1rem; background: #f0f7fe; vertical-align: middle; } + +.report-output ul.problems ul.details .menu-item { margin-top: .5rem !important; border-top: 1px solid #f7f7f7; padding-top: 0.5rem; } + +.report-output ul.problems ul.details .menu-item:first-child { border: none; } + +.report-output ul.problems ul.details .menu-badge { padding: 0; display: inline; float: right; } + +.report-output ul.problems ul.details .menu-badge .label { font-size: 1rem; height: 1.5rem; width: 1.5rem; line-height: 1.5rem; border-radius: 3px; } + +.report-output ul.problems ul.details .menu-badge .label.label-success { background: #2ECC40; } + +.report-output ul.problems ul.details .menu-badge .label.label-error { background: #F45857; } + +/*# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWRtaW4uY3NzIiwic291cmNlcyI6WyJhZG1pbi5zY3NzIiwiX3ZhcmlhYmxlcy5zY3NzIl0sInNvdXJjZXNDb250ZW50IjpbIkBpbXBvcnQgXCJ2YXJpYWJsZXNcIjtcblxuJGVycm9yLWNvbG9yOiAjRjQ1ODU3O1xuXG4ucmVwb3J0LW91dHB1dCB7XG5cbiAgI2FkbWluLW1haW4gLmFkbWluLWJsb2NrICYge1xuICAgIGgxIHtcbiAgICAgIG1hcmdpbi10b3A6IDJyZW07XG4gICAgfVxuXG4gICAgLnRvYXN0IHtcbiAgICAgIC5idG4ge1xuICAgICAgICBmbG9hdDogcmlnaHQ7XG4gICAgICAgIG1hcmdpbi10b3A6IC0ycHg7XG4gICAgICAgIG1hcmdpbi1yaWdodDogMC41cmVtO1xuXG5cbiAgICAgICAgY29sb3I6ICRsaWdodC1jb2xvcjtcbiAgICAgICAgZm9udC1zaXplOiA5MCU7XG4gICAgICAgIHBhZGRpbmc6IDJweCA3cHg7XG4gICAgICAgIGJvcmRlci1yYWRpdXM6IDNweDtcblxuICAgICAgICBib3JkZXI6IDFweCBzb2xpZCBkYXJrZW4oJHN1Y2Nlc3MtY29sb3IsIDUlKTtcbiAgICAgICAgYmFja2dyb3VuZC1jb2xvcjogZGFya2VuKCRzdWNjZXNzLWNvbG9yLCAzJSk7XG5cbiAgICAgICAgJjpob3ZlciB7XG4gICAgICAgICAgYm9yZGVyLWNvbG9yOiBkYXJrZW4oJHN1Y2Nlc3MtY29sb3IsIDclKTtcbiAgICAgICAgICBiYWNrZ3JvdW5kLWNvbG9yOiBkYXJrZW4oJHN1Y2Nlc3MtY29sb3IsIDUlKTtcbiAgICAgICAgfVxuXG4gICAgICAgICYuYnRuLWVycm9yIHtcbiAgICAgICAgICBib3JkZXI6IDFweCBzb2xpZCBkYXJrZW4oJGVycm9yLWNvbG9yLCA1JSk7XG4gICAgICAgICAgYmFja2dyb3VuZC1jb2xvcjogZGFya2VuKCRlcnJvci1jb2xvciwgMyUpO1xuXG4gICAgICAgICAgJjpob3ZlciB7XG4gICAgICAgICAgICBib3JkZXItY29sb3I6IGRhcmtlbigkZXJyb3ItY29sb3IsIDclKTtcbiAgICAgICAgICAgIGJhY2tncm91bmQtY29sb3I6IGRhcmtlbigkZXJyb3ItY29sb3IsIDUlKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICAmLmJ0bi13YXJuaW5nIHtcbiAgICAgICAgICBib3JkZXI6IDFweCBzb2xpZCBkYXJrZW4oJHdhcm5pbmctY29sb3IsIDUlKTtcbiAgICAgICAgICBiYWNrZ3JvdW5kLWNvbG9yOiBkYXJrZW4oJHdhcm5pbmctY29sb3IsIDMlKTtcblxuICAgICAgICAgICY6aG92ZXIge1xuICAgICAgICAgICAgYm9yZGVyLWNvbG9yOiBkYXJrZW4oJHdhcm5pbmctY29sb3IsIDclKTtcbiAgICAgICAgICAgIGJhY2tncm91bmQtY29sb3I6IGRhcmtlbigkd2FybmluZy1jb2xvciwgNSUpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIHVsLnByb2JsZW1zIHtcblxuICAgIG1hcmdpbjogMXJlbSAwO1xuICAgIGxpc3Qtc3R5bGU6IG5vbmU7XG4gICAgcGFkZGluZzogMDtcbiAgICBiYWNrZ3JvdW5kLWNvbG9yOiAjZjdmN2Y3O1xuXG4gICAgaDUge1xuICAgICAgbWFyZ2luOiAwO1xuICAgIH1cblxuICAgIGxpLm1lbnUge1xuICAgICAgbWFyZ2luLWJvdHRvbTogMXJlbTtcbiAgICAgIGJveC1zaGFkb3c6IDAgMTBweCAyMHB4IC0xMHB4IHJnYmEoMCwwLDAsMC4yKTtcbiAgICB9XG5cbiAgICAudG9hc3Qge1xuICAgICAgZm9udC1zaXplOiAxcmVtO1xuICAgICAgcGFkZGluZzogMC41cmVtIDEuNXJlbTtcbiAgICAgIGNvbG9yOiAkbGlnaHQtY29sb3I7XG5cbiAgICAgICYudG9hc3Qtc3VjY2VzcyB7XG4gICAgICAgIGJhY2tncm91bmQtY29sb3I6ICRzdWNjZXNzLWNvbG9yO1xuICAgICAgfVxuXG4gICAgICAmLnRvYXN0LWVycm9yIHtcbiAgICAgICAgYmFja2dyb3VuZC1jb2xvcjogJGVycm9yLWNvbG9yO1xuICAgICAgfVxuXG4gICAgICAmLnRvYXN0LXdhcm5pbmcge1xuICAgICAgICBiYWNrZ3JvdW5kLWNvbG9yOiAkd2FybmluZy1jb2xvcjtcbiAgICAgIH1cblxuICAgICAgLmJ0biB7XG4gICAgICAgIG1hcmdpbi1sZWZ0OiAxcmVtO1xuICAgICAgICB0ZXh0LWRlY29yYXRpb246IG5vbmUgIWltcG9ydGFudDtcbiAgICAgICAgaSB7XG4gICAgICAgICAgbWFyZ2luLXJpZ2h0OiAwLjNyZW07XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICB1bC5kZXRhaWxzIHtcbiAgICAgIGxpc3Qtc3R5bGU6IG5vbmU7XG4gICAgICBwYWRkaW5nLWxlZnQ6IDA7XG4gICAgICBwYWRkaW5nLWJvdHRvbTogMXJlbTtcbiAgICAgIGJhY2tncm91bmQtY29sb3I6ICNmZmY7XG5cbiAgICAgIGxpIHtcbiAgICAgICAgcGFkZGluZy1sZWZ0OiAxLjVyZW07XG4gICAgICAgIHBhZGRpbmctcmlnaHQ6IDEuNXJlbTtcbiAgICAgIH1cblxuICAgICAgY29kZSB7XG4gICAgICAgIGZvbnQtc2l6ZTogOTAlO1xuICAgICAgICBsaW5lLWhlaWdodDogMS4yO1xuICAgICAgICBwYWRkaW5nOiAuMXJlbSAuMnJlbTtcbiAgICAgICAgY29sb3I6ICMyODhmZWQ7XG4gICAgICAgIGJvcmRlci1yYWRpdXM6IC4xcmVtO1xuICAgICAgICBiYWNrZ3JvdW5kOiAjZjBmN2ZlO1xuICAgICAgICB2ZXJ0aWNhbC1hbGlnbjogbWlkZGxlO1xuICAgICAgfVxuXG4gICAgICAubWVudS1pdGVtIHtcbiAgICAgICAgbWFyZ2luLXRvcDogLjVyZW0gIWltcG9ydGFudDtcbiAgICAgICAgYm9yZGVyLXRvcDogMXB4IHNvbGlkICNmN2Y3Zjc7XG4gICAgICAgIHBhZGRpbmctdG9wOiAwLjVyZW07XG5cbiAgICAgICAgJjpmaXJzdC1jaGlsZCB7XG4gICAgICAgICAgYm9yZGVyOiBub25lO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIC5tZW51LWJhZGdlIHtcbiAgICAgICAgcGFkZGluZzogMDtcbiAgICAgICAgZGlzcGxheTogaW5saW5lO1xuICAgICAgICBmbG9hdDogcmlnaHQ7XG5cbiAgICAgICAgLmxhYmVsIHtcbiAgICAgICAgICBmb250LXNpemU6IDFyZW07XG4gICAgICAgICAgaGVpZ2h0OiAxLjVyZW07XG4gICAgICAgICAgd2lkdGg6IDEuNXJlbTtcbiAgICAgICAgICBsaW5lLWhlaWdodDogMS41cmVtO1xuICAgICAgICAgIGJvcmRlci1yYWRpdXM6IDNweDtcblxuICAgICAgICAgICYubGFiZWwtc3VjY2VzcyB7XG4gICAgICAgICAgICBiYWNrZ3JvdW5kOiAkc3VjY2Vzcy1jb2xvcjtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICAmLmxhYmVsLWVycm9yIHtcbiAgICAgICAgICAgIGJhY2tncm91bmQ6ICRlcnJvci1jb2xvcjtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gIH1cbn0iLCIvLyBDb3JlIHZhcmlhYmxlc1xuJHZlcnNpb246IFwiMC41LjNcIjtcblxuLy8gQ29yZSBmZWF0dXJlc1xuJHJ0bDogZmFsc2UgIWRlZmF1bHQ7XG5cbi8vIENvcmUgY29sb3JzXG4kcHJpbWFyeS1jb2xvcjogIzAwNzREOSAhZGVmYXVsdDtcbiRwcmltYXJ5LWNvbG9yLWRhcms6IGRhcmtlbigkcHJpbWFyeS1jb2xvciwgMyUpICFkZWZhdWx0O1xuJHByaW1hcnktY29sb3ItbGlnaHQ6IGxpZ2h0ZW4oJHByaW1hcnktY29sb3IsIDMlKSAhZGVmYXVsdDtcbiRzZWNvbmRhcnktY29sb3I6IGxpZ2h0ZW4oJHByaW1hcnktY29sb3IsIDM3LjUlKSAhZGVmYXVsdDtcbiRzZWNvbmRhcnktY29sb3ItZGFyazogZGFya2VuKCRzZWNvbmRhcnktY29sb3IsIDMlKSAhZGVmYXVsdDtcbiRzZWNvbmRhcnktY29sb3ItbGlnaHQ6IGxpZ2h0ZW4oJHNlY29uZGFyeS1jb2xvciwgMyUpICFkZWZhdWx0O1xuXG4vLyBHcmF5IGNvbG9yc1xuJGRhcmstY29sb3I6ICM0NTRkNWQgIWRlZmF1bHQ7XG4kbGlnaHQtY29sb3I6ICNmZmYgIWRlZmF1bHQ7XG4kZ3JheS1jb2xvcjogbGlnaHRlbigkZGFyay1jb2xvciwgNDAlKSAhZGVmYXVsdDtcbiRncmF5LWNvbG9yLWRhcms6IGRhcmtlbigkZ3JheS1jb2xvciwgMjUlKSAhZGVmYXVsdDtcbiRncmF5LWNvbG9yLWxpZ2h0OiBsaWdodGVuKCRncmF5LWNvbG9yLCAyMCUpICFkZWZhdWx0O1xuXG4kYm9yZGVyLWNvbG9yOiBsaWdodGVuKCRkYXJrLWNvbG9yLCA2MCUpICFkZWZhdWx0O1xuJGJvcmRlci1jb2xvci1kYXJrOiBkYXJrZW4oJGJvcmRlci1jb2xvciwgMTAlKSAhZGVmYXVsdDtcbiRiZy1jb2xvcjogbGlnaHRlbigkZGFyay1jb2xvciwgNjYlKSAhZGVmYXVsdDtcbiRiZy1jb2xvci1kYXJrOiBkYXJrZW4oJGJnLWNvbG9yLCAzJSkgIWRlZmF1bHQ7XG4kYmctY29sb3ItbGlnaHQ6ICRsaWdodC1jb2xvciAhZGVmYXVsdDtcblxuLy8gQ29udHJvbCBjb2xvcnNcbiRzdWNjZXNzLWNvbG9yOiAjMkVDQzQwICFkZWZhdWx0O1xuJHdhcm5pbmctY29sb3I6ICNGRjg1MUIgIWRlZmF1bHQ7XG4kZXJyb3ItY29sb3I6ICNGRjQxMzYgIWRlZmF1bHQ7XG5cbi8vIE90aGVyIGNvbG9yc1xuJGNvZGUtY29sb3I6ICMyODhGRUQgIWRlZmF1bHQ7XG4kaGlnaGxpZ2h0LWNvbG9yOiAjZmZlOWIzICFkZWZhdWx0O1xuJGJvZHktYmc6ICRiZy1jb2xvci1saWdodCAhZGVmYXVsdDtcbiRib2R5LWZvbnQtY29sb3I6IGxpZ2h0ZW4oJGRhcmstY29sb3IsIDUlKSAhZGVmYXVsdDtcbiRsaW5rLWNvbG9yOiAkcHJpbWFyeS1jb2xvciAhZGVmYXVsdDtcbiRsaW5rLWNvbG9yLWRhcms6IGRhcmtlbigkbGluay1jb2xvciwgMTAlKSAhZGVmYXVsdDtcbiRsaW5rLWNvbG9yLWxpZ2h0OiBsaWdodGVuKCRsaW5rLWNvbG9yLCAxMCUpICFkZWZhdWx0O1xuXG4vLyBGb250c1xuLy8gQ3JlZGl0OiBodHRwczovL3d3dy5zbWFzaGluZ21hZ2F6aW5lLmNvbS8yMDE1LzExL3VzaW5nLXN5c3RlbS11aS1mb250cy1wcmFjdGljYWwtZ3VpZGUvXG4kYmFzZS1mb250LWZhbWlseTogLWFwcGxlLXN5c3RlbSwgc3lzdGVtLXVpLCBCbGlua01hY1N5c3RlbUZvbnQsIFwiU2Vnb2UgVUlcIiwgUm9ib3RvICFkZWZhdWx0O1xuJG1vbm8tZm9udC1mYW1pbHk6IFwiU0YgTW9ub1wiLCBcIlNlZ29lIFVJIE1vbm9cIiwgXCJSb2JvdG8gTW9ub1wiLCBNZW5sbywgQ291cmllciwgbW9ub3NwYWNlICFkZWZhdWx0O1xuJGZhbGxiYWNrLWZvbnQtZmFtaWx5OiBcIkhlbHZldGljYSBOZXVlXCIsIHNhbnMtc2VyaWYgIWRlZmF1bHQ7XG4kY2prLXpoLWhhbnMtZm9udC1mYW1pbHk6ICRiYXNlLWZvbnQtZmFtaWx5LCBcIlBpbmdGYW5nIFNDXCIsIFwiSGlyYWdpbm8gU2FucyBHQlwiLCBcIk1pY3Jvc29mdCBZYUhlaVwiLCAkZmFsbGJhY2stZm9udC1mYW1pbHkgIWRlZmF1bHQ7XG4kY2prLXpoLWhhbnQtZm9udC1mYW1pbHk6ICRiYXNlLWZvbnQtZmFtaWx5LCBcIlBpbmdGYW5nIFRDXCIsIFwiSGlyYWdpbm8gU2FucyBDTlNcIiwgXCJNaWNyb3NvZnQgSmhlbmdIZWlcIiwgJGZhbGxiYWNrLWZvbnQtZmFtaWx5ICFkZWZhdWx0O1xuJGNqay1qcC1mb250LWZhbWlseTogJGJhc2UtZm9udC1mYW1pbHksIFwiSGlyYWdpbm8gU2Fuc1wiLCBcIkhpcmFnaW5vIEtha3UgR290aGljIFByb1wiLCBcIll1IEdvdGhpY1wiLCBZdUdvdGhpYywgTWVpcnlvLCAkZmFsbGJhY2stZm9udC1mYW1pbHkgIWRlZmF1bHQ7XG4kY2prLWtvLWZvbnQtZmFtaWx5OiAkYmFzZS1mb250LWZhbWlseSwgXCJNYWxndW4gR290aGljXCIsICRmYWxsYmFjay1mb250LWZhbWlseSAhZGVmYXVsdDtcbiRib2R5LWZvbnQtZmFtaWx5OiAkYmFzZS1mb250LWZhbWlseSwgJGZhbGxiYWNrLWZvbnQtZmFtaWx5ICFkZWZhdWx0O1xuXG4vLyBVbml0IHNpemVzXG4kdW5pdC1vOiAuMDVyZW0gIWRlZmF1bHQ7XG4kdW5pdC1oOiAuMXJlbSAhZGVmYXVsdDtcbiR1bml0LTE6IC4ycmVtICFkZWZhdWx0O1xuJHVuaXQtMjogLjRyZW0gIWRlZmF1bHQ7XG4kdW5pdC0zOiAuNnJlbSAhZGVmYXVsdDtcbiR1bml0LTQ6IC44cmVtICFkZWZhdWx0O1xuJHVuaXQtNTogMXJlbSAhZGVmYXVsdDtcbiR1bml0LTY6IDEuMnJlbSAhZGVmYXVsdDtcbiR1bml0LTc6IDEuNHJlbSAhZGVmYXVsdDtcbiR1bml0LTg6IDEuNnJlbSAhZGVmYXVsdDtcbiR1bml0LTk6IDEuOHJlbSAhZGVmYXVsdDtcbiR1bml0LTEwOiAycmVtICFkZWZhdWx0O1xuJHVuaXQtMTI6IDIuNHJlbSAhZGVmYXVsdDtcbiR1bml0LTE2OiAzLjJyZW0gIWRlZmF1bHQ7XG5cbi8vIEZvbnQgc2l6ZXNcbiRodG1sLWZvbnQtc2l6ZTogMjBweCAhZGVmYXVsdDtcbiRodG1sLWxpbmUtaGVpZ2h0OiAxLjUgIWRlZmF1bHQ7XG4kZm9udC1zaXplOiAuOHJlbSAhZGVmYXVsdDtcbiRmb250LXNpemUtc206IC43cmVtICFkZWZhdWx0O1xuJGZvbnQtc2l6ZS1sZzogLjlyZW0gIWRlZmF1bHQ7XG4kbGluZS1oZWlnaHQ6IDEuMnJlbSAhZGVmYXVsdDtcblxuLy8gU2l6ZXNcbiRsYXlvdXQtc3BhY2luZzogJHVuaXQtMiAhZGVmYXVsdDtcbiRsYXlvdXQtc3BhY2luZy1zbTogJHVuaXQtMSAhZGVmYXVsdDtcbiRsYXlvdXQtc3BhY2luZy1sZzogJHVuaXQtNCAhZGVmYXVsdDtcbiRib3JkZXItcmFkaXVzOiAkdW5pdC1oICFkZWZhdWx0O1xuJGJvcmRlci13aWR0aDogJHVuaXQtbyAhZGVmYXVsdDtcbiRib3JkZXItd2lkdGgtbGc6ICR1bml0LWggIWRlZmF1bHQ7XG4kY29udHJvbC1zaXplOiAkdW5pdC05ICFkZWZhdWx0O1xuJGNvbnRyb2wtc2l6ZS1zbTogJHVuaXQtNyAhZGVmYXVsdDtcbiRjb250cm9sLXNpemUtbGc6ICR1bml0LTEwICFkZWZhdWx0O1xuJGNvbnRyb2wtcGFkZGluZy14OiAkdW5pdC0yICFkZWZhdWx0O1xuJGNvbnRyb2wtcGFkZGluZy14LXNtOiAkdW5pdC0yICogLjc1ICFkZWZhdWx0O1xuJGNvbnRyb2wtcGFkZGluZy14LWxnOiAkdW5pdC0yICogMS41ICFkZWZhdWx0O1xuJGNvbnRyb2wtcGFkZGluZy15OiAoJGNvbnRyb2wtc2l6ZSAtICRsaW5lLWhlaWdodCkgLyAyIC0gJGJvcmRlci13aWR0aCAhZGVmYXVsdDtcbiRjb250cm9sLXBhZGRpbmcteS1zbTogKCRjb250cm9sLXNpemUtc20gLSAkbGluZS1oZWlnaHQpIC8gMiAtICRib3JkZXItd2lkdGggIWRlZmF1bHQ7XG4kY29udHJvbC1wYWRkaW5nLXktbGc6ICgkY29udHJvbC1zaXplLWxnIC0gJGxpbmUtaGVpZ2h0KSAvIDIgLSAkYm9yZGVyLXdpZHRoICFkZWZhdWx0O1xuJGNvbnRyb2wtaWNvbi1zaXplOiAuOHJlbSAhZGVmYXVsdDtcblxuJGNvbnRyb2wtd2lkdGgteHM6IDE4MHB4ICFkZWZhdWx0O1xuJGNvbnRyb2wtd2lkdGgtc206IDMyMHB4ICFkZWZhdWx0O1xuJGNvbnRyb2wtd2lkdGgtbWQ6IDY0MHB4ICFkZWZhdWx0O1xuJGNvbnRyb2wtd2lkdGgtbGc6IDk2MHB4ICFkZWZhdWx0O1xuJGNvbnRyb2wtd2lkdGgteGw6IDEyODBweCAhZGVmYXVsdDtcblxuLy8gUmVzcG9uc2l2ZSBicmVha3BvaW50c1xuJHNpemUteHM6IDQ4MHB4ICFkZWZhdWx0O1xuJHNpemUtc206IDYwMHB4ICFkZWZhdWx0O1xuJHNpemUtbWQ6IDg0MHB4ICFkZWZhdWx0O1xuJHNpemUtbGc6IDk2MHB4ICFkZWZhdWx0O1xuJHNpemUteGw6IDEyODBweCAhZGVmYXVsdDtcbiRzaXplLTJ4OiAxNDQwcHggIWRlZmF1bHQ7XG5cbiRyZXNwb25zaXZlLWJyZWFrcG9pbnQ6ICRzaXplLXhzICFkZWZhdWx0O1xuXG4vLyBaLWluZGV4XG4kemluZGV4LTA6IDEgIWRlZmF1bHQ7XG4kemluZGV4LTE6IDEwMCAhZGVmYXVsdDtcbiR6aW5kZXgtMjogMjAwICFkZWZhdWx0O1xuJHppbmRleC0zOiAzMDAgIWRlZmF1bHQ7XG4kemluZGV4LTQ6IDQwMCAhZGVmYXVsdDtcbiJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFNRSxBQUNFLFdBRFMsQ0FBQyxZQUFZLENBRjFCLGNBQWMsQ0FHVixFQUFFLENBQUMsRUFDRCxVQUFVLEVBQUUsSUFBSSxHQUNqQjs7QUFISCxBQU1JLFdBTk8sQ0FBQyxZQUFZLENBRjFCLGNBQWMsQ0FPVixNQUFNLENBQ0osSUFBSSxDQUFDLEVBQ0gsS0FBSyxFQUFFLEtBQUssRUFDWixVQUFVLEVBQUUsSUFBSSxFQUNoQixZQUFZLEVBQUUsTUFBTSxFQUdwQixLQUFLLEVDRkMsSUFBSSxFREdWLFNBQVMsRUFBRSxHQUFHLEVBQ2QsT0FBTyxFQUFFLE9BQU8sRUFDaEIsYUFBYSxFQUFFLEdBQUcsRUFFbEIsTUFBTSxFQUFFLEdBQUcsQ0FBQyxLQUFLLENBQUMsT0FBMEIsRUFDNUMsZ0JBQWdCLEVBQUUsT0FBMEIsR0EwQjdDOztBQTVDTCxBQW9CTSxXQXBCSyxDQUFDLFlBQVksQ0FGMUIsY0FBYyxDQU9WLE1BQU0sQ0FDSixJQUFJLEFBY0QsTUFBTSxDQUFDLEVBQ04sWUFBWSxFQUFFLE9BQTBCLEVBQ3hDLGdCQUFnQixFQUFFLE9BQTBCLEdBQzdDOztBQXZCUCxBQXlCTSxXQXpCSyxDQUFDLFlBQVksQ0FGMUIsY0FBYyxDQU9WLE1BQU0sQ0FDSixJQUFJLEFBbUJELFVBQVUsQ0FBQyxFQUNWLE1BQU0sRUFBRSxHQUFHLENBQUMsS0FBSyxDQUFDLE9BQXdCLEVBQzFDLGdCQUFnQixFQUFFLE9BQXdCLEdBTTNDOztBQWpDUCxBQTZCUSxXQTdCRyxDQUFDLFlBQVksQ0FGMUIsY0FBYyxDQU9WLE1BQU0sQ0FDSixJQUFJLEFBbUJELFVBQVUsQUFJUixNQUFNLENBQUMsRUFDTixZQUFZLEVBQUUsT0FBd0IsRUFDdEMsZ0JBQWdCLEVBQUUsT0FBd0IsR0FDM0M7O0FBaENULEFBbUNNLFdBbkNLLENBQUMsWUFBWSxDQUYxQixjQUFjLENBT1YsTUFBTSxDQUNKLElBQUksQUE2QkQsWUFBWSxDQUFDLEVBQ1osTUFBTSxFQUFFLEdBQUcsQ0FBQyxLQUFLLENBQUMsT0FBMEIsRUFDNUMsZ0JBQWdCLEVBQUUsT0FBMEIsR0FNN0M7O0FBM0NQLEFBdUNRLFdBdkNHLENBQUMsWUFBWSxDQUYxQixjQUFjLENBT1YsTUFBTSxDQUNKLElBQUksQUE2QkQsWUFBWSxBQUlWLE1BQU0sQ0FBQyxFQUNOLFlBQVksRUFBRSxPQUEwQixFQUN4QyxnQkFBZ0IsRUFBRSxPQUEwQixHQUM3Qzs7QUE1Q1gsQUFrREUsY0FsRFksQ0FrRFosRUFBRSxBQUFBLFNBQVMsQ0FBQyxFQUVWLE1BQU0sRUFBRSxNQUFNLEVBQ2QsVUFBVSxFQUFFLElBQUksRUFDaEIsT0FBTyxFQUFFLENBQUMsRUFDVixnQkFBZ0IsRUFBRSxPQUFPLEdBMEYxQjs7QUFqSkgsQUF5REksY0F6RFUsQ0FrRFosRUFBRSxBQUFBLFNBQVMsQ0FPVCxFQUFFLENBQUMsRUFDRCxNQUFNLEVBQUUsQ0FBQyxHQUNWOztBQTNETCxBQTZESSxjQTdEVSxDQWtEWixFQUFFLEFBQUEsU0FBUyxDQVdULEVBQUUsQUFBQSxLQUFLLENBQUMsRUFDTixhQUFhLEVBQUUsSUFBSSxFQUNuQixVQUFVLEVBQUUsQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUUsS0FBSSxDQUFDLGtCQUFlLEdBQzlDOztBQWhFTCxBQWtFSSxjQWxFVSxDQWtEWixFQUFFLEFBQUEsU0FBUyxDQWdCVCxNQUFNLENBQUMsRUFDTCxTQUFTLEVBQUUsSUFBSSxFQUNmLE9BQU8sRUFBRSxhQUFhLEVBQ3RCLEtBQUssRUN6REcsSUFBSSxHRDhFYjs7QUExRkwsQUF1RU0sY0F2RVEsQ0FrRFosRUFBRSxBQUFBLFNBQVMsQ0FnQlQsTUFBTSxBQUtILGNBQWMsQ0FBQyxFQUNkLGdCQUFnQixFQ2hEUixPQUFPLEdEaURoQjs7QUF6RVAsQUEyRU0sY0EzRVEsQ0FrRFosRUFBRSxBQUFBLFNBQVMsQ0FnQlQsTUFBTSxBQVNILFlBQVksQ0FBQyxFQUNaLGdCQUFnQixFQTlFVixPQUFPLEdBK0VkOztBQTdFUCxBQStFTSxjQS9FUSxDQWtEWixFQUFFLEFBQUEsU0FBUyxDQWdCVCxNQUFNLEFBYUgsY0FBYyxDQUFDLEVBQ2QsZ0JBQWdCLEVDdkRSLE9BQU8sR0R3RGhCOztBQWpGUCxBQW1GTSxjQW5GUSxDQWtEWixFQUFFLEFBQUEsU0FBUyxDQWdCVCxNQUFNLENBaUJKLElBQUksQ0FBQyxFQUNILFdBQVcsRUFBRSxJQUFJLEVBQ2pCLGVBQWUsRUFBRSxlQUFlLEdBSWpDOztBQXpGUCxBQXNGUSxjQXRGTSxDQWtEWixFQUFFLEFBQUEsU0FBUyxDQWdCVCxNQUFNLENBaUJKLElBQUksQ0FHRixDQUFDLENBQUMsRUFDQSxZQUFZLEVBQUUsTUFBTSxHQUNyQjs7QUF4RlQsQUE0RkksY0E1RlUsQ0FrRFosRUFBRSxBQUFBLFNBQVMsQ0EwQ1QsRUFBRSxBQUFBLFFBQVEsQ0FBQyxFQUNULFVBQVUsRUFBRSxJQUFJLEVBQ2hCLFlBQVksRUFBRSxDQUFDLEVBQ2YsY0FBYyxFQUFFLElBQUksRUFDcEIsZ0JBQWdCLEVBQUUsSUFBSSxHQWdEdkI7O0FBaEpMLEFBa0dNLGNBbEdRLENBa0RaLEVBQUUsQUFBQSxTQUFTLENBMENULEVBQUUsQUFBQSxRQUFRLENBTVIsRUFBRSxDQUFDLEVBQ0QsWUFBWSxFQUFFLE1BQU0sRUFDcEIsYUFBYSxFQUFFLE1BQU0sR0FDdEI7O0FBckdQLEFBdUdNLGNBdkdRLENBa0RaLEVBQUUsQUFBQSxTQUFTLENBMENULEVBQUUsQUFBQSxRQUFRLENBV1IsSUFBSSxDQUFDLEVBQ0gsU0FBUyxFQUFFLEdBQUcsRUFDZCxXQUFXLEVBQUUsR0FBRyxFQUNoQixPQUFPLEVBQUUsV0FBVyxFQUNwQixLQUFLLEVBQUUsT0FBTyxFQUNkLGFBQWEsRUFBRSxLQUFLLEVBQ3BCLFVBQVUsRUFBRSxPQUFPLEVBQ25CLGNBQWMsRUFBRSxNQUFNLEdBQ3ZCOztBQS9HUCxBQWlITSxjQWpIUSxDQWtEWixFQUFFLEFBQUEsU0FBUyxDQTBDVCxFQUFFLEFBQUEsUUFBUSxDQXFCUixVQUFVLENBQUMsRUFDVCxVQUFVLEVBQUUsZ0JBQWdCLEVBQzVCLFVBQVUsRUFBRSxpQkFBaUIsRUFDN0IsV0FBVyxFQUFFLE1BQU0sR0FLcEI7O0FBekhQLEFBc0hRLGNBdEhNLENBa0RaLEVBQUUsQUFBQSxTQUFTLENBMENULEVBQUUsQUFBQSxRQUFRLENBcUJSLFVBQVUsQUFLUCxZQUFZLENBQUMsRUFDWixNQUFNLEVBQUUsSUFBSSxHQUNiOztBQXhIVCxBQTJITSxjQTNIUSxDQWtEWixFQUFFLEFBQUEsU0FBUyxDQTBDVCxFQUFFLEFBQUEsUUFBUSxDQStCUixXQUFXLENBQUMsRUFDVixPQUFPLEVBQUUsQ0FBQyxFQUNWLE9BQU8sRUFBRSxNQUFNLEVBQ2YsS0FBSyxFQUFFLEtBQUssR0FpQmI7O0FBL0lQLEFBZ0lRLGNBaElNLENBa0RaLEVBQUUsQUFBQSxTQUFTLENBMENULEVBQUUsQUFBQSxRQUFRLENBK0JSLFdBQVcsQ0FLVCxNQUFNLENBQUMsRUFDTCxTQUFTLEVBQUUsSUFBSSxFQUNmLE1BQU0sRUFBRSxNQUFNLEVBQ2QsS0FBSyxFQUFFLE1BQU0sRUFDYixXQUFXLEVBQUUsTUFBTSxFQUNuQixhQUFhLEVBQUUsR0FBRyxHQVNuQjs7QUE5SVQsQUF1SVUsY0F2SUksQ0FrRFosRUFBRSxBQUFBLFNBQVMsQ0EwQ1QsRUFBRSxBQUFBLFFBQVEsQ0ErQlIsV0FBVyxDQUtULE1BQU0sQUFPSCxjQUFjLENBQUMsRUFDZCxVQUFVLEVDaEhOLE9BQU8sR0RpSFo7O0FBeklYLEFBMklVLGNBM0lJLENBa0RaLEVBQUUsQUFBQSxTQUFTLENBMENULEVBQUUsQUFBQSxRQUFRLENBK0JSLFdBQVcsQ0FLVCxNQUFNLEFBV0gsWUFBWSxDQUFDLEVBQ1osVUFBVSxFQTlJUixPQUFPLEdBK0lWIn0= */ diff --git a/user/plugins/problems/css/admin.min.css b/user/plugins/problems/css/admin.min.css new file mode 100644 index 00000000..5212b248 --- /dev/null +++ b/user/plugins/problems/css/admin.min.css @@ -0,0 +1 @@ +#admin-main .admin-block .report-output h1{margin-top:2rem}#admin-main .admin-block .report-output .toast .btn{font-size:90%;float:right;margin-top:-2px;margin-right:.5rem;padding:2px 7px;color:#fff;border:1px solid #29b739;border-radius:3px;background-color:#2bc03c}#admin-main .admin-block .report-output .toast .btn:hover{border-color:#27af37;background-color:#29b739}#admin-main .admin-block .report-output .toast .btn.btn-error{border:1px solid #f2403f;background-color:#f34a49}#admin-main .admin-block .report-output .toast .btn.btn-error:hover{border-color:#f23735;background-color:#f2403f}#admin-main .admin-block .report-output .toast .btn.btn-warning{border:1px solid #ff7702;background-color:#ff7d0c}#admin-main .admin-block .report-output .toast .btn.btn-warning:hover{border-color:#f67300;background-color:#ff7702}.report-output ul.problems{margin:1rem 0;padding:0;list-style:none;background-color:#f7f7f7}.report-output ul.problems h5{margin:0}.report-output ul.problems li.menu{margin-bottom:1rem;box-shadow:0 10px 20px -10px rgba(0,0,0,.2)}.report-output ul.problems .toast{font-size:1rem;padding:.5rem 1.5rem;color:#fff}.report-output ul.problems .toast.toast-success{background-color:#2ecc40}.report-output ul.problems .toast.toast-error{background-color:#f45857}.report-output ul.problems .toast.toast-warning{background-color:#ff851b}.report-output ul.problems .toast .btn{margin-left:1rem;text-decoration:none!important}.report-output ul.problems .toast .btn i{margin-right:.3rem}.report-output ul.problems ul.details{padding-bottom:1rem;padding-left:0;list-style:none;background-color:#fff}.report-output ul.problems ul.details li{padding-right:1.5rem;padding-left:1.5rem}.report-output ul.problems ul.details code{font-size:90%;line-height:1.2;padding:.1rem .2rem;vertical-align:middle;color:#288fed;border-radius:.1rem;background:#f0f7fe}.report-output ul.problems ul.details .menu-item{margin-top:.5rem!important;padding-top:.5rem;border-top:1px solid #f7f7f7}.report-output ul.problems ul.details .menu-item:first-child{border:none}.report-output ul.problems ul.details .menu-badge{display:inline;float:right;padding:0}.report-output ul.problems ul.details .menu-badge .label{font-size:1rem;line-height:1.5rem;width:1.5rem;height:1.5rem;border-radius:3px}.report-output ul.problems ul.details .menu-badge .label.label-success{background:#2ecc40}.report-output ul.problems ul.details .menu-badge .label.label-error{background:#f45857} \ No newline at end of file diff --git a/user/plugins/problems/css/spectre-icons.css b/user/plugins/problems/css/spectre-icons.css new file mode 100644 index 00000000..f4b0fddf --- /dev/null +++ b/user/plugins/problems/css/spectre-icons.css @@ -0,0 +1,168 @@ +/*! Spectre.css Icons v0.5.3 | MIT License | github.com/picturepan2/spectre */ +.icon { box-sizing: border-box; display: inline-block; font-size: inherit; font-style: normal; height: 1em; position: relative; text-indent: -9999px; vertical-align: middle; width: 1em; } + +.icon::before, .icon::after { display: block; left: 50%; position: absolute; top: 50%; transform: translate(-50%, -50%); } + +.icon.icon-2x { font-size: 1.6rem; } + +.icon.icon-3x { font-size: 2.4rem; } + +.icon.icon-4x { font-size: 3.2rem; } + +.accordion .icon, .btn .icon, .toast .icon, .menu .icon { vertical-align: -10%; } + +.btn-lg .icon { vertical-align: -15%; } + +.icon-arrow-down::before, .icon-arrow-left::before, .icon-arrow-right::before, .icon-arrow-up::before, .icon-downward::before, .icon-back::before, .icon-forward::before, .icon-upward::before { border: 0.1rem solid currentColor; border-bottom: 0; border-right: 0; content: ""; height: .65em; width: .65em; } + +.icon-arrow-down::before { transform: translate(-50%, -75%) rotate(225deg); } + +.icon-arrow-left::before { transform: translate(-25%, -50%) rotate(-45deg); } + +.icon-arrow-right::before { transform: translate(-75%, -50%) rotate(135deg); } + +.icon-arrow-up::before { transform: translate(-50%, -25%) rotate(45deg); } + +.icon-back::after, .icon-forward::after { background: currentColor; content: ""; height: 0.1rem; width: .8em; } + +.icon-downward::after, .icon-upward::after { background: currentColor; content: ""; height: .8em; width: 0.1rem; } + +.icon-back::after { left: 55%; } + +.icon-back::before { transform: translate(-50%, -50%) rotate(-45deg); } + +.icon-downward::after { top: 45%; } + +.icon-downward::before { transform: translate(-50%, -50%) rotate(-135deg); } + +.icon-forward::after { left: 45%; } + +.icon-forward::before { transform: translate(-50%, -50%) rotate(135deg); } + +.icon-upward::after { top: 55%; } + +.icon-upward::before { transform: translate(-50%, -50%) rotate(45deg); } + +.icon-caret::before { border-top: .3em solid currentColor; border-right: .3em solid transparent; border-left: .3em solid transparent; content: ""; height: 0; transform: translate(-50%, -25%); width: 0; } + +.icon-menu::before { background: currentColor; box-shadow: 0 -.35em, 0 .35em; content: ""; height: 0.1rem; width: 100%; } + +.icon-apps::before { background: currentColor; box-shadow: -.35em -.35em, -.35em 0, -.35em .35em, 0 -.35em, 0 .35em, .35em -.35em, .35em 0, .35em .35em; content: ""; height: 3px; width: 3px; } + +.icon-resize-horiz::before, .icon-resize-horiz::after, .icon-resize-vert::before, .icon-resize-vert::after { border: 0.1rem solid currentColor; border-bottom: 0; border-right: 0; content: ""; height: .45em; width: .45em; } + +.icon-resize-horiz::before, .icon-resize-vert::before { transform: translate(-50%, -90%) rotate(45deg); } + +.icon-resize-horiz::after, .icon-resize-vert::after { transform: translate(-50%, -10%) rotate(225deg); } + +.icon-resize-horiz::before { transform: translate(-90%, -50%) rotate(-45deg); } + +.icon-resize-horiz::after { transform: translate(-10%, -50%) rotate(135deg); } + +.icon-more-horiz::before, .icon-more-vert::before { background: currentColor; box-shadow: -.4em 0, .4em 0; border-radius: 50%; content: ""; height: 3px; width: 3px; } + +.icon-more-vert::before { box-shadow: 0 -.4em, 0 .4em; } + +.icon-plus::before, .icon-minus::before, .icon-cross::before { background: currentColor; content: ""; height: 0.1rem; width: 100%; } + +.icon-plus::after, .icon-cross::after { background: currentColor; content: ""; height: 100%; width: 0.1rem; } + +.icon-cross::before { width: 100%; } + +.icon-cross::after { height: 100%; } + +.icon-cross::before, .icon-cross::after { transform: translate(-50%, -50%) rotate(45deg); } + +.icon-check::before { border: 0.1rem solid currentColor; border-right: 0; border-top: 0; content: ""; height: .5em; width: .9em; transform: translate(-50%, -75%) rotate(-45deg); } + +.icon-stop { border: 0.1rem solid currentColor; border-radius: 50%; } + +.icon-stop::before { background: currentColor; content: ""; height: 0.1rem; transform: translate(-50%, -50%) rotate(45deg); width: 1em; } + +.icon-shutdown { border: 0.1rem solid currentColor; border-radius: 50%; border-top-color: transparent; } + +.icon-shutdown::before { background: currentColor; content: ""; height: .5em; top: .1em; width: 0.1rem; } + +.icon-refresh::before { border: 0.1rem solid currentColor; border-radius: 50%; border-right-color: transparent; content: ""; height: 1em; width: 1em; } + +.icon-refresh::after { border: .2em solid currentColor; border-top-color: transparent; border-left-color: transparent; content: ""; height: 0; left: 80%; top: 20%; width: 0; } + +.icon-search::before { border: 0.1rem solid currentColor; border-radius: 50%; content: ""; height: .75em; left: 5%; top: 5%; transform: translate(0, 0) rotate(45deg); width: .75em; } + +.icon-search::after { background: currentColor; content: ""; height: 0.1rem; left: 80%; top: 80%; transform: translate(-50%, -50%) rotate(45deg); width: .4em; } + +.icon-edit::before { border: 0.1rem solid currentColor; content: ""; height: .4em; transform: translate(-40%, -60%) rotate(-45deg); width: .85em; } + +.icon-edit::after { border: .15em solid currentColor; border-top-color: transparent; border-right-color: transparent; content: ""; height: 0; left: 5%; top: 95%; transform: translate(0, -100%); width: 0; } + +.icon-delete::before { border: 0.1rem solid currentColor; border-bottom-left-radius: 0.1rem; border-bottom-right-radius: 0.1rem; border-top: 0; content: ""; height: .75em; top: 60%; width: .75em; } + +.icon-delete::after { background: currentColor; box-shadow: -.25em .2em, .25em .2em; content: ""; height: 0.1rem; top: 0.05rem; width: .5em; } + +.icon-share { border: 0.1rem solid currentColor; border-radius: 0.1rem; border-right: 0; border-top: 0; } + +.icon-share::before { border: 0.1rem solid currentColor; border-left: 0; border-top: 0; content: ""; height: .4em; left: 100%; top: .25em; transform: translate(-125%, -50%) rotate(-45deg); width: .4em; } + +.icon-share::after { border: 0.1rem solid currentColor; border-bottom: 0; border-right: 0; border-radius: 75% 0; content: ""; height: .5em; width: .6em; } + +.icon-flag::before { background: currentColor; content: ""; height: 1em; left: 15%; width: 0.1rem; } + +.icon-flag::after { border: 0.1rem solid currentColor; border-bottom-right-radius: 0.1rem; border-left: 0; border-top-right-radius: 0.1rem; content: ""; height: .65em; top: 35%; left: 60%; width: .8em; } + +.icon-bookmark::before { border: 0.1rem solid currentColor; border-bottom: 0; border-top-left-radius: 0.1rem; border-top-right-radius: 0.1rem; content: ""; height: .9em; width: .8em; } + +.icon-bookmark::after { border: 0.1rem solid currentColor; border-bottom: 0; border-left: 0; border-radius: 0.1rem; content: ""; height: .5em; transform: translate(-50%, 35%) rotate(-45deg) skew(15deg, 15deg); width: .5em; } + +.icon-download, .icon-upload { border-bottom: 0.1rem solid currentColor; } + +.icon-download::before, .icon-upload::before { border: 0.1rem solid currentColor; border-bottom: 0; border-right: 0; content: ""; height: .5em; width: .5em; transform: translate(-50%, -60%) rotate(-135deg); } + +.icon-download::after, .icon-upload::after { background: currentColor; content: ""; height: .6em; top: 40%; width: 0.1rem; } + +.icon-upload::before { transform: translate(-50%, -60%) rotate(45deg); } + +.icon-upload::after { top: 50%; } + +.icon-time { border: 0.1rem solid currentColor; border-radius: 50%; } + +.icon-time::before { background: currentColor; content: ""; height: .4em; transform: translate(-50%, -75%); width: 0.1rem; } + +.icon-time::after { background: currentColor; content: ""; height: .3em; transform: translate(-50%, -75%) rotate(90deg); transform-origin: 50% 90%; width: 0.1rem; } + +.icon-mail::before { border: 0.1rem solid currentColor; border-radius: 0.1rem; content: ""; height: .8em; width: 1em; } + +.icon-mail::after { border: 0.1rem solid currentColor; border-right: 0; border-top: 0; content: ""; height: .5em; transform: translate(-50%, -90%) rotate(-45deg) skew(10deg, 10deg); width: .5em; } + +.icon-people::before { border: 0.1rem solid currentColor; border-radius: 50%; content: ""; height: .45em; top: 25%; width: .45em; } + +.icon-people::after { border: 0.1rem solid currentColor; border-radius: 50% 50% 0 0; content: ""; height: .4em; top: 75%; width: .9em; } + +.icon-message { border: 0.1rem solid currentColor; border-bottom: 0; border-radius: 0.1rem; border-right: 0; } + +.icon-message::before { border: 0.1rem solid currentColor; border-bottom-right-radius: 0.1rem; border-left: 0; border-top: 0; content: ""; height: .8em; left: 65%; top: 40%; width: .7em; } + +.icon-message::after { background: currentColor; border-radius: 0.1rem; content: ""; height: .3em; left: 10%; top: 100%; transform: translate(0, -90%) rotate(45deg); width: 0.1rem; } + +.icon-photo { border: 0.1rem solid currentColor; border-radius: 0.1rem; } + +.icon-photo::before { border: 0.1rem solid currentColor; border-radius: 50%; content: ""; height: .25em; left: 35%; top: 35%; width: .25em; } + +.icon-photo::after { border: 0.1rem solid currentColor; border-bottom: 0; border-left: 0; content: ""; height: .5em; left: 60%; transform: translate(-50%, 25%) rotate(-45deg); width: .5em; } + +.icon-link::before, .icon-link::after { border: 0.1rem solid currentColor; border-radius: 5em 0 0 5em; border-right: 0; content: ""; height: .5em; width: .75em; } + +.icon-link::before { transform: translate(-70%, -45%) rotate(-45deg); } + +.icon-link::after { transform: translate(-30%, -55%) rotate(135deg); } + +.icon-location::before { border: 0.1rem solid currentColor; border-radius: 50% 50% 50% 0; content: ""; height: .8em; transform: translate(-50%, -60%) rotate(-45deg); width: .8em; } + +.icon-location::after { border: 0.1rem solid currentColor; border-radius: 50%; content: ""; height: .2em; transform: translate(-50%, -80%); width: .2em; } + +.icon-emoji { border: 0.1rem solid currentColor; border-radius: 50%; } + +.icon-emoji::before { border-radius: 50%; box-shadow: -.17em -.15em, .17em -.15em; content: ""; height: .1em; width: .1em; } + +.icon-emoji::after { border: 0.1rem solid currentColor; border-bottom-color: transparent; border-radius: 50%; border-right-color: transparent; content: ""; height: .5em; transform: translate(-50%, -40%) rotate(-135deg); width: .5em; } + +/*# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3BlY3RyZS1pY29ucy5jc3MiLCJzb3VyY2VzIjpbInNwZWN0cmUtaWNvbnMuc2NzcyIsIl92YXJpYWJsZXMuc2NzcyIsIl9taXhpbnMuc2NzcyIsIm1peGlucy9fYXZhdGFyLnNjc3MiLCJtaXhpbnMvX2J1dHRvbi5zY3NzIiwibWl4aW5zL19jbGVhcmZpeC5zY3NzIiwibWl4aW5zL19jb2xvci5zY3NzIiwibWl4aW5zL19sYWJlbC5zY3NzIiwibWl4aW5zL19wb3NpdGlvbi5zY3NzIiwibWl4aW5zL19zaGFkb3cuc2NzcyIsIm1peGlucy9fdGV4dC5zY3NzIiwibWl4aW5zL190b2FzdC5zY3NzIiwibWl4aW5zL190cmFuc2l0aW9uLnNjc3MiLCJpY29ucy9faWNvbnMtY29yZS5zY3NzIiwiaWNvbnMvX2ljb25zLW5hdmlnYXRpb24uc2NzcyIsImljb25zL19pY29ucy1hY3Rpb24uc2NzcyIsImljb25zL19pY29ucy1vYmplY3Quc2NzcyJdLCJzb3VyY2VzQ29udGVudCI6WyIvLyBWYXJpYWJsZXMgYW5kIG1peGluc1xuQGltcG9ydCBcInZhcmlhYmxlc1wiO1xuQGltcG9ydCBcIm1peGluc1wiO1xuXG4vKiEgU3BlY3RyZS5jc3MgSWNvbnMgdiN7JHZlcnNpb259IHwgTUlUIExpY2Vuc2UgfCBnaXRodWIuY29tL3BpY3R1cmVwYW4yL3NwZWN0cmUgKi9cbi8vIEljb25zXG5AaW1wb3J0IFwiaWNvbnMvaWNvbnMtY29yZVwiO1xuQGltcG9ydCBcImljb25zL2ljb25zLW5hdmlnYXRpb25cIjtcbkBpbXBvcnQgXCJpY29ucy9pY29ucy1hY3Rpb25cIjtcbkBpbXBvcnQgXCJpY29ucy9pY29ucy1vYmplY3RcIjtcbiIsIi8vIENvcmUgdmFyaWFibGVzXG4kdmVyc2lvbjogXCIwLjUuM1wiO1xuXG4vLyBDb3JlIGZlYXR1cmVzXG4kcnRsOiBmYWxzZSAhZGVmYXVsdDtcblxuLy8gQ29yZSBjb2xvcnNcbiRwcmltYXJ5LWNvbG9yOiAjMDA3NEQ5ICFkZWZhdWx0O1xuJHByaW1hcnktY29sb3ItZGFyazogZGFya2VuKCRwcmltYXJ5LWNvbG9yLCAzJSkgIWRlZmF1bHQ7XG4kcHJpbWFyeS1jb2xvci1saWdodDogbGlnaHRlbigkcHJpbWFyeS1jb2xvciwgMyUpICFkZWZhdWx0O1xuJHNlY29uZGFyeS1jb2xvcjogbGlnaHRlbigkcHJpbWFyeS1jb2xvciwgMzcuNSUpICFkZWZhdWx0O1xuJHNlY29uZGFyeS1jb2xvci1kYXJrOiBkYXJrZW4oJHNlY29uZGFyeS1jb2xvciwgMyUpICFkZWZhdWx0O1xuJHNlY29uZGFyeS1jb2xvci1saWdodDogbGlnaHRlbigkc2Vjb25kYXJ5LWNvbG9yLCAzJSkgIWRlZmF1bHQ7XG5cbi8vIEdyYXkgY29sb3JzXG4kZGFyay1jb2xvcjogIzQ1NGQ1ZCAhZGVmYXVsdDtcbiRsaWdodC1jb2xvcjogI2ZmZiAhZGVmYXVsdDtcbiRncmF5LWNvbG9yOiBsaWdodGVuKCRkYXJrLWNvbG9yLCA0MCUpICFkZWZhdWx0O1xuJGdyYXktY29sb3ItZGFyazogZGFya2VuKCRncmF5LWNvbG9yLCAyNSUpICFkZWZhdWx0O1xuJGdyYXktY29sb3ItbGlnaHQ6IGxpZ2h0ZW4oJGdyYXktY29sb3IsIDIwJSkgIWRlZmF1bHQ7XG5cbiRib3JkZXItY29sb3I6IGxpZ2h0ZW4oJGRhcmstY29sb3IsIDYwJSkgIWRlZmF1bHQ7XG4kYm9yZGVyLWNvbG9yLWRhcms6IGRhcmtlbigkYm9yZGVyLWNvbG9yLCAxMCUpICFkZWZhdWx0O1xuJGJnLWNvbG9yOiBsaWdodGVuKCRkYXJrLWNvbG9yLCA2NiUpICFkZWZhdWx0O1xuJGJnLWNvbG9yLWRhcms6IGRhcmtlbigkYmctY29sb3IsIDMlKSAhZGVmYXVsdDtcbiRiZy1jb2xvci1saWdodDogJGxpZ2h0LWNvbG9yICFkZWZhdWx0O1xuXG4vLyBDb250cm9sIGNvbG9yc1xuJHN1Y2Nlc3MtY29sb3I6ICMyRUNDNDAgIWRlZmF1bHQ7XG4kd2FybmluZy1jb2xvcjogI0ZGODUxQiAhZGVmYXVsdDtcbiRlcnJvci1jb2xvcjogI0ZGNDEzNiAhZGVmYXVsdDtcblxuLy8gT3RoZXIgY29sb3JzXG4kY29kZS1jb2xvcjogIzI4OEZFRCAhZGVmYXVsdDtcbiRoaWdobGlnaHQtY29sb3I6ICNmZmU5YjMgIWRlZmF1bHQ7XG4kYm9keS1iZzogJGJnLWNvbG9yLWxpZ2h0ICFkZWZhdWx0O1xuJGJvZHktZm9udC1jb2xvcjogbGlnaHRlbigkZGFyay1jb2xvciwgNSUpICFkZWZhdWx0O1xuJGxpbmstY29sb3I6ICRwcmltYXJ5LWNvbG9yICFkZWZhdWx0O1xuJGxpbmstY29sb3ItZGFyazogZGFya2VuKCRsaW5rLWNvbG9yLCAxMCUpICFkZWZhdWx0O1xuJGxpbmstY29sb3ItbGlnaHQ6IGxpZ2h0ZW4oJGxpbmstY29sb3IsIDEwJSkgIWRlZmF1bHQ7XG5cbi8vIEZvbnRzXG4vLyBDcmVkaXQ6IGh0dHBzOi8vd3d3LnNtYXNoaW5nbWFnYXppbmUuY29tLzIwMTUvMTEvdXNpbmctc3lzdGVtLXVpLWZvbnRzLXByYWN0aWNhbC1ndWlkZS9cbiRiYXNlLWZvbnQtZmFtaWx5OiAtYXBwbGUtc3lzdGVtLCBzeXN0ZW0tdWksIEJsaW5rTWFjU3lzdGVtRm9udCwgXCJTZWdvZSBVSVwiLCBSb2JvdG8gIWRlZmF1bHQ7XG4kbW9uby1mb250LWZhbWlseTogXCJTRiBNb25vXCIsIFwiU2Vnb2UgVUkgTW9ub1wiLCBcIlJvYm90byBNb25vXCIsIE1lbmxvLCBDb3VyaWVyLCBtb25vc3BhY2UgIWRlZmF1bHQ7XG4kZmFsbGJhY2stZm9udC1mYW1pbHk6IFwiSGVsdmV0aWNhIE5ldWVcIiwgc2Fucy1zZXJpZiAhZGVmYXVsdDtcbiRjamstemgtaGFucy1mb250LWZhbWlseTogJGJhc2UtZm9udC1mYW1pbHksIFwiUGluZ0ZhbmcgU0NcIiwgXCJIaXJhZ2lubyBTYW5zIEdCXCIsIFwiTWljcm9zb2Z0IFlhSGVpXCIsICRmYWxsYmFjay1mb250LWZhbWlseSAhZGVmYXVsdDtcbiRjamstemgtaGFudC1mb250LWZhbWlseTogJGJhc2UtZm9udC1mYW1pbHksIFwiUGluZ0ZhbmcgVENcIiwgXCJIaXJhZ2lubyBTYW5zIENOU1wiLCBcIk1pY3Jvc29mdCBKaGVuZ0hlaVwiLCAkZmFsbGJhY2stZm9udC1mYW1pbHkgIWRlZmF1bHQ7XG4kY2prLWpwLWZvbnQtZmFtaWx5OiAkYmFzZS1mb250LWZhbWlseSwgXCJIaXJhZ2lubyBTYW5zXCIsIFwiSGlyYWdpbm8gS2FrdSBHb3RoaWMgUHJvXCIsIFwiWXUgR290aGljXCIsIFl1R290aGljLCBNZWlyeW8sICRmYWxsYmFjay1mb250LWZhbWlseSAhZGVmYXVsdDtcbiRjamsta28tZm9udC1mYW1pbHk6ICRiYXNlLWZvbnQtZmFtaWx5LCBcIk1hbGd1biBHb3RoaWNcIiwgJGZhbGxiYWNrLWZvbnQtZmFtaWx5ICFkZWZhdWx0O1xuJGJvZHktZm9udC1mYW1pbHk6ICRiYXNlLWZvbnQtZmFtaWx5LCAkZmFsbGJhY2stZm9udC1mYW1pbHkgIWRlZmF1bHQ7XG5cbi8vIFVuaXQgc2l6ZXNcbiR1bml0LW86IC4wNXJlbSAhZGVmYXVsdDtcbiR1bml0LWg6IC4xcmVtICFkZWZhdWx0O1xuJHVuaXQtMTogLjJyZW0gIWRlZmF1bHQ7XG4kdW5pdC0yOiAuNHJlbSAhZGVmYXVsdDtcbiR1bml0LTM6IC42cmVtICFkZWZhdWx0O1xuJHVuaXQtNDogLjhyZW0gIWRlZmF1bHQ7XG4kdW5pdC01OiAxcmVtICFkZWZhdWx0O1xuJHVuaXQtNjogMS4ycmVtICFkZWZhdWx0O1xuJHVuaXQtNzogMS40cmVtICFkZWZhdWx0O1xuJHVuaXQtODogMS42cmVtICFkZWZhdWx0O1xuJHVuaXQtOTogMS44cmVtICFkZWZhdWx0O1xuJHVuaXQtMTA6IDJyZW0gIWRlZmF1bHQ7XG4kdW5pdC0xMjogMi40cmVtICFkZWZhdWx0O1xuJHVuaXQtMTY6IDMuMnJlbSAhZGVmYXVsdDtcblxuLy8gRm9udCBzaXplc1xuJGh0bWwtZm9udC1zaXplOiAyMHB4ICFkZWZhdWx0O1xuJGh0bWwtbGluZS1oZWlnaHQ6IDEuNSAhZGVmYXVsdDtcbiRmb250LXNpemU6IC44cmVtICFkZWZhdWx0O1xuJGZvbnQtc2l6ZS1zbTogLjdyZW0gIWRlZmF1bHQ7XG4kZm9udC1zaXplLWxnOiAuOXJlbSAhZGVmYXVsdDtcbiRsaW5lLWhlaWdodDogMS4ycmVtICFkZWZhdWx0O1xuXG4vLyBTaXplc1xuJGxheW91dC1zcGFjaW5nOiAkdW5pdC0yICFkZWZhdWx0O1xuJGxheW91dC1zcGFjaW5nLXNtOiAkdW5pdC0xICFkZWZhdWx0O1xuJGxheW91dC1zcGFjaW5nLWxnOiAkdW5pdC00ICFkZWZhdWx0O1xuJGJvcmRlci1yYWRpdXM6ICR1bml0LWggIWRlZmF1bHQ7XG4kYm9yZGVyLXdpZHRoOiAkdW5pdC1vICFkZWZhdWx0O1xuJGJvcmRlci13aWR0aC1sZzogJHVuaXQtaCAhZGVmYXVsdDtcbiRjb250cm9sLXNpemU6ICR1bml0LTkgIWRlZmF1bHQ7XG4kY29udHJvbC1zaXplLXNtOiAkdW5pdC03ICFkZWZhdWx0O1xuJGNvbnRyb2wtc2l6ZS1sZzogJHVuaXQtMTAgIWRlZmF1bHQ7XG4kY29udHJvbC1wYWRkaW5nLXg6ICR1bml0LTIgIWRlZmF1bHQ7XG4kY29udHJvbC1wYWRkaW5nLXgtc206ICR1bml0LTIgKiAuNzUgIWRlZmF1bHQ7XG4kY29udHJvbC1wYWRkaW5nLXgtbGc6ICR1bml0LTIgKiAxLjUgIWRlZmF1bHQ7XG4kY29udHJvbC1wYWRkaW5nLXk6ICgkY29udHJvbC1zaXplIC0gJGxpbmUtaGVpZ2h0KSAvIDIgLSAkYm9yZGVyLXdpZHRoICFkZWZhdWx0O1xuJGNvbnRyb2wtcGFkZGluZy15LXNtOiAoJGNvbnRyb2wtc2l6ZS1zbSAtICRsaW5lLWhlaWdodCkgLyAyIC0gJGJvcmRlci13aWR0aCAhZGVmYXVsdDtcbiRjb250cm9sLXBhZGRpbmcteS1sZzogKCRjb250cm9sLXNpemUtbGcgLSAkbGluZS1oZWlnaHQpIC8gMiAtICRib3JkZXItd2lkdGggIWRlZmF1bHQ7XG4kY29udHJvbC1pY29uLXNpemU6IC44cmVtICFkZWZhdWx0O1xuXG4kY29udHJvbC13aWR0aC14czogMTgwcHggIWRlZmF1bHQ7XG4kY29udHJvbC13aWR0aC1zbTogMzIwcHggIWRlZmF1bHQ7XG4kY29udHJvbC13aWR0aC1tZDogNjQwcHggIWRlZmF1bHQ7XG4kY29udHJvbC13aWR0aC1sZzogOTYwcHggIWRlZmF1bHQ7XG4kY29udHJvbC13aWR0aC14bDogMTI4MHB4ICFkZWZhdWx0O1xuXG4vLyBSZXNwb25zaXZlIGJyZWFrcG9pbnRzXG4kc2l6ZS14czogNDgwcHggIWRlZmF1bHQ7XG4kc2l6ZS1zbTogNjAwcHggIWRlZmF1bHQ7XG4kc2l6ZS1tZDogODQwcHggIWRlZmF1bHQ7XG4kc2l6ZS1sZzogOTYwcHggIWRlZmF1bHQ7XG4kc2l6ZS14bDogMTI4MHB4ICFkZWZhdWx0O1xuJHNpemUtMng6IDE0NDBweCAhZGVmYXVsdDtcblxuJHJlc3BvbnNpdmUtYnJlYWtwb2ludDogJHNpemUteHMgIWRlZmF1bHQ7XG5cbi8vIFotaW5kZXhcbiR6aW5kZXgtMDogMSAhZGVmYXVsdDtcbiR6aW5kZXgtMTogMTAwICFkZWZhdWx0O1xuJHppbmRleC0yOiAyMDAgIWRlZmF1bHQ7XG4kemluZGV4LTM6IDMwMCAhZGVmYXVsdDtcbiR6aW5kZXgtNDogNDAwICFkZWZhdWx0O1xuIiwiLy8gTWl4aW5zXG5AaW1wb3J0IFwibWl4aW5zL2F2YXRhclwiO1xuQGltcG9ydCBcIm1peGlucy9idXR0b25cIjtcbkBpbXBvcnQgXCJtaXhpbnMvY2xlYXJmaXhcIjtcbkBpbXBvcnQgXCJtaXhpbnMvY29sb3JcIjtcbkBpbXBvcnQgXCJtaXhpbnMvbGFiZWxcIjtcbkBpbXBvcnQgXCJtaXhpbnMvcG9zaXRpb25cIjtcbkBpbXBvcnQgXCJtaXhpbnMvc2hhZG93XCI7XG5AaW1wb3J0IFwibWl4aW5zL3RleHRcIjtcbkBpbXBvcnQgXCJtaXhpbnMvdG9hc3RcIjtcbkBpbXBvcnQgXCJtaXhpbnMvdHJhbnNpdGlvblwiO1xuIiwiLy8gQXZhdGFyIG1peGluXG5AbWl4aW4gYXZhdGFyLWJhc2UoJHNpemU6ICR1bml0LTgpIHtcbiAgZm9udC1zaXplOiAkc2l6ZSAvIDI7XG4gIGhlaWdodDogJHNpemU7XG4gIHdpZHRoOiAkc2l6ZTtcbn1cbiIsIi8vIEJ1dHRvbiB2YXJpYW50IG1peGluXG5AbWl4aW4gYnV0dG9uLXZhcmlhbnQoJGNvbG9yOiAkcHJpbWFyeS1jb2xvcikge1xuICBiYWNrZ3JvdW5kOiAkY29sb3I7XG4gIGJvcmRlci1jb2xvcjogZGFya2VuKCRjb2xvciwgMyUpO1xuICBjb2xvcjogJGxpZ2h0LWNvbG9yO1xuICAmOmZvY3VzIHtcbiAgICBAaW5jbHVkZSBjb250cm9sLXNoYWRvdygkY29sb3IpO1xuICB9XG4gICY6Zm9jdXMsXG4gICY6aG92ZXIge1xuICAgIGJhY2tncm91bmQ6IGRhcmtlbigkY29sb3IsIDIlKTtcbiAgICBib3JkZXItY29sb3I6IGRhcmtlbigkY29sb3IsIDUlKTtcbiAgICBjb2xvcjogJGxpZ2h0LWNvbG9yO1xuICB9XG4gICY6YWN0aXZlLFxuICAmLmFjdGl2ZSB7XG4gICAgYmFja2dyb3VuZDogZGFya2VuKCRjb2xvciwgNyUpO1xuICAgIGJvcmRlci1jb2xvcjogZGFya2VuKCRjb2xvciwgMTAlKTtcbiAgICBjb2xvcjogJGxpZ2h0LWNvbG9yO1xuICB9XG4gICYubG9hZGluZyB7XG4gICAgJjo6YWZ0ZXIge1xuICAgICAgYm9yZGVyLWJvdHRvbS1jb2xvcjogJGxpZ2h0LWNvbG9yO1xuICAgICAgYm9yZGVyLWxlZnQtY29sb3I6ICRsaWdodC1jb2xvcjtcbiAgICB9XG4gIH1cbn1cblxuQG1peGluIGJ1dHRvbi1vdXRsaW5lLXZhcmlhbnQoJGNvbG9yOiAkcHJpbWFyeS1jb2xvcikge1xuICBiYWNrZ3JvdW5kOiAkbGlnaHQtY29sb3I7XG4gIGJvcmRlci1jb2xvcjogJGNvbG9yO1xuICBjb2xvcjogJGNvbG9yO1xuICAmOmZvY3VzIHtcbiAgICBAaW5jbHVkZSBjb250cm9sLXNoYWRvdygkY29sb3IpO1xuICB9XG4gICY6Zm9jdXMsXG4gICY6aG92ZXIge1xuICAgIGJhY2tncm91bmQ6IGxpZ2h0ZW4oJGNvbG9yLCA1MCUpO1xuICAgIGJvcmRlci1jb2xvcjogZGFya2VuKCRjb2xvciwgMiUpO1xuICAgIGNvbG9yOiAkY29sb3I7XG4gIH1cbiAgJjphY3RpdmUsXG4gICYuYWN0aXZlIHtcbiAgICBiYWNrZ3JvdW5kOiAkY29sb3I7XG4gICAgYm9yZGVyLWNvbG9yOiBkYXJrZW4oJGNvbG9yLCA1JSk7XG4gICAgY29sb3I6ICRsaWdodC1jb2xvcjtcbiAgfVxuICAmLmxvYWRpbmcge1xuICAgICY6OmFmdGVyIHtcbiAgICAgIGJvcmRlci1ib3R0b20tY29sb3I6ICRjb2xvcjtcbiAgICAgIGJvcmRlci1sZWZ0LWNvbG9yOiAkY29sb3I7XG4gICAgfVxuICB9XG59XG4iLCIvLyBDbGVhcmZpeCBtaXhpblxuQG1peGluIGNsZWFyZml4KCkge1xuICAmOjphZnRlciB7XG4gICAgY2xlYXI6IGJvdGg7XG4gICAgY29udGVudDogXCJcIjtcbiAgICBkaXNwbGF5OiB0YWJsZTtcbiAgfVxufVxuIiwiLy8gQmFja2dyb3VuZCBjb2xvciB1dGlsaXR5IG1peGluXG5AbWl4aW4gYmctY29sb3ItdmFyaWFudCgkbmFtZTogXCIuYmctcHJpbWFyeVwiLCAkY29sb3I6ICRwcmltYXJ5LWNvbG9yKSB7XG4gICN7JG5hbWV9IHtcbiAgICBiYWNrZ3JvdW5kOiAkY29sb3I7XG5cbiAgICBAaWYgKGxpZ2h0bmVzcygkY29sb3IpIDwgNjApIHtcbiAgICAgIGNvbG9yOiAkbGlnaHQtY29sb3I7XG4gICAgfVxuICB9XG59XG5cbi8vIFRleHQgY29sb3IgdXRpbGl0eSBtaXhpblxuQG1peGluIHRleHQtY29sb3ItdmFyaWFudCgkbmFtZTogXCIudGV4dC1wcmltYXJ5XCIsICRjb2xvcjogJHByaW1hcnktY29sb3IpIHtcbiAgI3skbmFtZX0ge1xuICAgIGNvbG9yOiAkY29sb3I7XG4gIH1cblxuICBhI3skbmFtZX0ge1xuICAgICY6Zm9jdXMsXG4gICAgJjpob3ZlciB7XG4gICAgICBjb2xvcjogZGFya2VuKCRjb2xvciwgNSUpO1xuICAgIH1cbiAgICAmOnZpc2l0ZWQge1xuICAgICAgY29sb3I6IGxpZ2h0ZW4oJGNvbG9yLCA1JSk7XG4gICAgfVxuICB9XG59XG4iLCIvLyBMYWJlbCBiYXNlIHN0eWxlXG5AbWl4aW4gbGFiZWwtYmFzZSgpIHtcbiAgYm9yZGVyLXJhZGl1czogJGJvcmRlci1yYWRpdXM7XG4gIGxpbmUtaGVpZ2h0OiAxLjI7XG4gIHBhZGRpbmc6IC4xcmVtIC4ycmVtO1xufVxuXG5AbWl4aW4gbGFiZWwtdmFyaWFudCgkY29sb3I6ICRsaWdodC1jb2xvciwgJGJnLWNvbG9yOiAkcHJpbWFyeS1jb2xvcikge1xuICBiYWNrZ3JvdW5kOiAkYmctY29sb3I7XG4gIGNvbG9yOiAkY29sb3I7XG59XG4iLCIvLyBNYXJnaW4gdXRpbGl0eSBtaXhpblxuQG1peGluIG1hcmdpbi12YXJpYW50KCRpZDogMSwgJHNpemU6ICR1bml0LTEpIHtcbiAgLm0tI3skaWR9IHtcbiAgICBtYXJnaW46ICRzaXplICFpbXBvcnRhbnQ7XG4gIH1cblxuICAubWItI3skaWR9IHtcbiAgICBtYXJnaW4tYm90dG9tOiAkc2l6ZSAhaW1wb3J0YW50O1xuICB9XG5cbiAgLm1sLSN7JGlkfSB7XG4gICAgbWFyZ2luLWxlZnQ6ICRzaXplICFpbXBvcnRhbnQ7XG4gIH1cblxuICAubXItI3skaWR9IHtcbiAgICBtYXJnaW4tcmlnaHQ6ICRzaXplICFpbXBvcnRhbnQ7XG4gIH1cblxuICAubXQtI3skaWR9IHtcbiAgICBtYXJnaW4tdG9wOiAkc2l6ZSAhaW1wb3J0YW50O1xuICB9XG5cbiAgLm14LSN7JGlkfSB7XG4gICAgbWFyZ2luLWxlZnQ6ICRzaXplICFpbXBvcnRhbnQ7XG4gICAgbWFyZ2luLXJpZ2h0OiAkc2l6ZSAhaW1wb3J0YW50O1xuICB9XG5cbiAgLm15LSN7JGlkfSB7XG4gICAgbWFyZ2luLWJvdHRvbTogJHNpemUgIWltcG9ydGFudDtcbiAgICBtYXJnaW4tdG9wOiAkc2l6ZSAhaW1wb3J0YW50O1xuICB9XG59XG5cbi8vIFBhZGRpbmcgdXRpbGl0eSBtaXhpblxuQG1peGluIHBhZGRpbmctdmFyaWFudCgkaWQ6IDEsICRzaXplOiAkdW5pdC0xKSB7XG4gIC5wLSN7JGlkfSB7XG4gICAgcGFkZGluZzogJHNpemUgIWltcG9ydGFudDtcbiAgfVxuXG4gIC5wYi0jeyRpZH0ge1xuICAgIHBhZGRpbmctYm90dG9tOiAkc2l6ZSAhaW1wb3J0YW50O1xuICB9XG5cbiAgLnBsLSN7JGlkfSB7XG4gICAgcGFkZGluZy1sZWZ0OiAkc2l6ZSAhaW1wb3J0YW50O1xuICB9XG5cbiAgLnByLSN7JGlkfSB7XG4gICAgcGFkZGluZy1yaWdodDogJHNpemUgIWltcG9ydGFudDtcbiAgfVxuXG4gIC5wdC0jeyRpZH0ge1xuICAgIHBhZGRpbmctdG9wOiAkc2l6ZSAhaW1wb3J0YW50O1xuICB9XG5cbiAgLnB4LSN7JGlkfSB7XG4gICAgcGFkZGluZy1sZWZ0OiAkc2l6ZSAhaW1wb3J0YW50O1xuICAgIHBhZGRpbmctcmlnaHQ6ICRzaXplICFpbXBvcnRhbnQ7XG4gIH1cbiAgXG4gIC5weS0jeyRpZH0ge1xuICAgIHBhZGRpbmctYm90dG9tOiAkc2l6ZSAhaW1wb3J0YW50O1xuICAgIHBhZGRpbmctdG9wOiAkc2l6ZSAhaW1wb3J0YW50O1xuICB9XG59XG4iLCIvLyBDb21wb25lbnQgZm9jdXMgc2hhZG93XG5AbWl4aW4gY29udHJvbC1zaGFkb3coJGNvbG9yOiAkcHJpbWFyeS1jb2xvcikge1xuICBib3gtc2hhZG93OiAwIDAgMCAuMXJlbSByZ2JhKCRjb2xvciwgLjIpO1xufVxuXG4vLyBTaGFkb3cgbWl4aW5cbkBtaXhpbiBzaGFkb3ctdmFyaWFudCgkb2Zmc2V0KSB7XG4gIGJveC1zaGFkb3c6IDAgJG9mZnNldCAoJG9mZnNldCArIC4wNXJlbSkgKiAyIHJnYmEoJGRhcmstY29sb3IsIC4zKTtcbn1cbiIsIi8vIFRleHQgRWxsaXBzaXNcbkBtaXhpbiB0ZXh0LWVsbGlwc2lzKCkge1xuICBvdmVyZmxvdzogaGlkZGVuO1xuICB0ZXh0LW92ZXJmbG93OiBlbGxpcHNpcztcbiAgd2hpdGUtc3BhY2U6IG5vd3JhcDtcbn1cbiIsIi8vIFRvYXN0IHZhcmlhbnQgbWl4aW5cbkBtaXhpbiB0b2FzdC12YXJpYW50KCRjb2xvcjogJGRhcmstY29sb3IpIHtcbiAgYmFja2dyb3VuZDogcmdiYSgkY29sb3IsIC45KTtcbiAgYm9yZGVyLWNvbG9yOiAkY29sb3I7XG59XG4iLCIvLyBDb21wb25lbnQgdHJhbnNpdGlvblxuQG1peGluIGNvbnRyb2wtdHJhbnNpdGlvbigpIHtcbiAgdHJhbnNpdGlvbjogYWxsIC4ycyBlYXNlO1xufVxuIiwiLy8gSWNvbiB2YXJpYWJsZXNcbiRpY29uLWJvcmRlci13aWR0aDogJGJvcmRlci13aWR0aC1sZztcbiRpY29uLXByZWZpeDogXCJpY29uXCI7XG5cbi8vIEljb24gYmFzZSBzdHlsZVxuLiN7JGljb24tcHJlZml4fSB7XG4gIGJveC1zaXppbmc6IGJvcmRlci1ib3g7XG4gIGRpc3BsYXk6IGlubGluZS1ibG9jaztcbiAgZm9udC1zaXplOiBpbmhlcml0O1xuICBmb250LXN0eWxlOiBub3JtYWw7XG4gIGhlaWdodDogMWVtO1xuICBwb3NpdGlvbjogcmVsYXRpdmU7XG4gIHRleHQtaW5kZW50OiAtOTk5OXB4O1xuICB2ZXJ0aWNhbC1hbGlnbjogbWlkZGxlO1xuICB3aWR0aDogMWVtO1xuICAmOjpiZWZvcmUsXG4gICY6OmFmdGVyIHtcbiAgICBkaXNwbGF5OiBibG9jaztcbiAgICBsZWZ0OiA1MCU7XG4gICAgcG9zaXRpb246IGFic29sdXRlO1xuICAgIHRvcDogNTAlO1xuICAgIHRyYW5zZm9ybTogdHJhbnNsYXRlKC01MCUsIC01MCUpO1xuICB9XG5cbiAgLy8gSWNvbiBzaXplc1xuICAmLmljb24tMngge1xuICAgIGZvbnQtc2l6ZTogMS42cmVtO1xuICB9XG5cbiAgJi5pY29uLTN4IHtcbiAgICBmb250LXNpemU6IDIuNHJlbTtcbiAgfVxuXG4gICYuaWNvbi00eCB7XG4gICAgZm9udC1zaXplOiAzLjJyZW07XG4gIH1cbn1cblxuLy8gQ29tcG9uZW50IGljb24gc3VwcG9ydFxuLmFjY29yZGlvbixcbi5idG4sXG4udG9hc3QsXG4ubWVudSB7XG4gIC4jeyRpY29uLXByZWZpeH0ge1xuICAgIHZlcnRpY2FsLWFsaWduOiAtMTAlO1xuICB9XG59XG5cbi5idG4tbGcge1xuICAuI3skaWNvbi1wcmVmaXh9IHtcbiAgICB2ZXJ0aWNhbC1hbGlnbjogLTE1JTtcbiAgfVxufVxuIiwiLy8gSWNvbiBhcnJvd3Ncbi5pY29uLWFycm93LWRvd24sXG4uaWNvbi1hcnJvdy1sZWZ0LFxuLmljb24tYXJyb3ctcmlnaHQsXG4uaWNvbi1hcnJvdy11cCxcbi5pY29uLWRvd253YXJkLFxuLmljb24tYmFjayxcbi5pY29uLWZvcndhcmQsXG4uaWNvbi11cHdhcmQge1xuICAmOjpiZWZvcmUge1xuICAgIGJvcmRlcjogJGljb24tYm9yZGVyLXdpZHRoIHNvbGlkIGN1cnJlbnRDb2xvcjtcbiAgICBib3JkZXItYm90dG9tOiAwO1xuICAgIGJvcmRlci1yaWdodDogMDtcbiAgICBjb250ZW50OiBcIlwiO1xuICAgIGhlaWdodDogLjY1ZW07XG4gICAgd2lkdGg6IC42NWVtO1xuICB9XG59XG5cbi5pY29uLWFycm93LWRvd24ge1xuICAmOjpiZWZvcmUge1xuICAgIHRyYW5zZm9ybTogdHJhbnNsYXRlKC01MCUsIC03NSUpIHJvdGF0ZSgyMjVkZWcpO1xuICB9XG59XG5cbi5pY29uLWFycm93LWxlZnQge1xuICAmOjpiZWZvcmUge1xuICAgIHRyYW5zZm9ybTogdHJhbnNsYXRlKC0yNSUsIC01MCUpIHJvdGF0ZSgtNDVkZWcpO1xuICB9XG59XG5cbi5pY29uLWFycm93LXJpZ2h0IHtcbiAgJjo6YmVmb3JlIHtcbiAgICB0cmFuc2Zvcm06IHRyYW5zbGF0ZSgtNzUlLCAtNTAlKSByb3RhdGUoMTM1ZGVnKTtcbiAgfVxufVxuXG4uaWNvbi1hcnJvdy11cCB7XG4gICY6OmJlZm9yZSB7XG4gICAgdHJhbnNmb3JtOiB0cmFuc2xhdGUoLTUwJSwgLTI1JSkgcm90YXRlKDQ1ZGVnKTtcbiAgfVxufVxuXG4uaWNvbi1iYWNrLFxuLmljb24tZm9yd2FyZCB7XG4gICY6OmFmdGVyIHtcbiAgICBiYWNrZ3JvdW5kOiBjdXJyZW50Q29sb3I7XG4gICAgY29udGVudDogXCJcIjtcbiAgICBoZWlnaHQ6ICRpY29uLWJvcmRlci13aWR0aDtcbiAgICB3aWR0aDogLjhlbTtcbiAgfVxufVxuXG4uaWNvbi1kb3dud2FyZCxcbi5pY29uLXVwd2FyZCB7XG4gICY6OmFmdGVyIHtcbiAgICBiYWNrZ3JvdW5kOiBjdXJyZW50Q29sb3I7XG4gICAgY29udGVudDogXCJcIjtcbiAgICBoZWlnaHQ6IC44ZW07XG4gICAgd2lkdGg6ICRpY29uLWJvcmRlci13aWR0aDtcbiAgfVxufVxuXG4uaWNvbi1iYWNrIHtcbiAgJjo6YWZ0ZXIge1xuICAgIGxlZnQ6IDU1JTtcbiAgfVxuICAmOjpiZWZvcmUge1xuICAgIHRyYW5zZm9ybTogdHJhbnNsYXRlKC01MCUsIC01MCUpIHJvdGF0ZSgtNDVkZWcpO1xuICB9XG59XG5cbi5pY29uLWRvd253YXJkIHtcbiAgJjo6YWZ0ZXIge1xuICAgIHRvcDogNDUlO1xuICB9XG4gICY6OmJlZm9yZSB7XG4gICAgdHJhbnNmb3JtOiB0cmFuc2xhdGUoLTUwJSwgLTUwJSkgcm90YXRlKC0xMzVkZWcpO1xuICB9XG59XG5cbi5pY29uLWZvcndhcmQge1xuICAmOjphZnRlciB7XG4gICAgbGVmdDogNDUlO1xuICB9XG4gICY6OmJlZm9yZSB7XG4gICAgdHJhbnNmb3JtOiB0cmFuc2xhdGUoLTUwJSwgLTUwJSkgcm90YXRlKDEzNWRlZyk7XG4gIH1cbn1cblxuLmljb24tdXB3YXJkIHtcbiAgJjo6YWZ0ZXIge1xuICAgIHRvcDogNTUlO1xuICB9XG4gICY6OmJlZm9yZSB7XG4gICAgdHJhbnNmb3JtOiB0cmFuc2xhdGUoLTUwJSwgLTUwJSkgcm90YXRlKDQ1ZGVnKTtcbiAgfVxufVxuXG4vLyBJY29uIGNhcmV0XG4uaWNvbi1jYXJldCB7XG4gICY6OmJlZm9yZSB7XG4gICAgYm9yZGVyLXRvcDogLjNlbSBzb2xpZCBjdXJyZW50Q29sb3I7XG4gICAgYm9yZGVyLXJpZ2h0OiAuM2VtIHNvbGlkIHRyYW5zcGFyZW50O1xuICAgIGJvcmRlci1sZWZ0OiAuM2VtIHNvbGlkIHRyYW5zcGFyZW50O1xuICAgIGNvbnRlbnQ6IFwiXCI7XG4gICAgaGVpZ2h0OiAwO1xuICAgIHRyYW5zZm9ybTogdHJhbnNsYXRlKC01MCUsIC0yNSUpO1xuICAgIHdpZHRoOiAwO1xuICB9XG59XG5cbi8vIEljb24gbWVudVxuLmljb24tbWVudSB7XG4gICY6OmJlZm9yZSB7XG4gICAgYmFja2dyb3VuZDogY3VycmVudENvbG9yO1xuICAgIGJveC1zaGFkb3c6IDAgLS4zNWVtLCAwIC4zNWVtO1xuICAgIGNvbnRlbnQ6IFwiXCI7XG4gICAgaGVpZ2h0OiAkaWNvbi1ib3JkZXItd2lkdGg7XG4gICAgd2lkdGg6IDEwMCU7XG4gIH1cbn1cblxuLy8gSWNvbiBhcHBzXG4uaWNvbi1hcHBzIHtcbiAgJjo6YmVmb3JlIHtcbiAgICBiYWNrZ3JvdW5kOiBjdXJyZW50Q29sb3I7XG4gICAgYm94LXNoYWRvdzogLS4zNWVtIC0uMzVlbSwgLS4zNWVtIDAsIC0uMzVlbSAuMzVlbSwgMCAtLjM1ZW0sIDAgLjM1ZW0sIC4zNWVtIC0uMzVlbSwgLjM1ZW0gMCwgLjM1ZW0gLjM1ZW07XG4gICAgY29udGVudDogXCJcIjtcbiAgICBoZWlnaHQ6IDNweDtcbiAgICB3aWR0aDogM3B4O1xuICB9XG59XG4iLCJcbi8vIEljb24gcmVzaXplXG4uaWNvbi1yZXNpemUtaG9yaXosXG4uaWNvbi1yZXNpemUtdmVydCB7XG4gICY6OmJlZm9yZSxcbiAgJjo6YWZ0ZXIge1xuICAgIGJvcmRlcjogJGljb24tYm9yZGVyLXdpZHRoIHNvbGlkIGN1cnJlbnRDb2xvcjtcbiAgICBib3JkZXItYm90dG9tOiAwO1xuICAgIGJvcmRlci1yaWdodDogMDtcbiAgICBjb250ZW50OiBcIlwiO1xuICAgIGhlaWdodDogLjQ1ZW07XG4gICAgd2lkdGg6IC40NWVtO1xuICB9XG4gICY6OmJlZm9yZSB7XG4gICAgdHJhbnNmb3JtOiB0cmFuc2xhdGUoLTUwJSwgLTkwJSkgcm90YXRlKDQ1ZGVnKTtcbiAgfVxuICAmOjphZnRlciB7XG4gICAgdHJhbnNmb3JtOiB0cmFuc2xhdGUoLTUwJSwgLTEwJSkgcm90YXRlKDIyNWRlZyk7XG4gIH1cbn1cblxuLmljb24tcmVzaXplLWhvcml6IHtcbiAgJjo6YmVmb3JlIHtcbiAgICB0cmFuc2Zvcm06IHRyYW5zbGF0ZSgtOTAlLCAtNTAlKSByb3RhdGUoLTQ1ZGVnKTtcbiAgfVxuICAmOjphZnRlciB7XG4gICAgdHJhbnNmb3JtOiB0cmFuc2xhdGUoLTEwJSwgLTUwJSkgcm90YXRlKDEzNWRlZyk7XG4gIH1cbn1cblxuLy8gSWNvbiBtb3JlXG4uaWNvbi1tb3JlLWhvcml6LFxuLmljb24tbW9yZS12ZXJ0IHtcbiAgJjo6YmVmb3JlIHtcbiAgICBiYWNrZ3JvdW5kOiBjdXJyZW50Q29sb3I7XG4gICAgYm94LXNoYWRvdzogLS40ZW0gMCwgLjRlbSAwO1xuICAgIGJvcmRlci1yYWRpdXM6IDUwJTtcbiAgICBjb250ZW50OiBcIlwiO1xuICAgIGhlaWdodDogM3B4O1xuICAgIHdpZHRoOiAzcHg7XG4gIH1cbn1cblxuLmljb24tbW9yZS12ZXJ0IHtcbiAgJjo6YmVmb3JlIHtcbiAgICBib3gtc2hhZG93OiAwIC0uNGVtLCAwIC40ZW07XG4gIH1cbn1cblxuLy8gSWNvbiBwbHVzLCBtaW51cywgY3Jvc3Ncbi5pY29uLXBsdXMsXG4uaWNvbi1taW51cyxcbi5pY29uLWNyb3NzIHtcbiAgJjo6YmVmb3JlIHtcbiAgICBiYWNrZ3JvdW5kOiBjdXJyZW50Q29sb3I7XG4gICAgY29udGVudDogXCJcIjtcbiAgICBoZWlnaHQ6ICRpY29uLWJvcmRlci13aWR0aDtcbiAgICB3aWR0aDogMTAwJTtcbiAgfVxufVxuXG4uaWNvbi1wbHVzLFxuLmljb24tY3Jvc3Mge1xuICAmOjphZnRlciB7XG4gICAgYmFja2dyb3VuZDogY3VycmVudENvbG9yO1xuICAgIGNvbnRlbnQ6IFwiXCI7XG4gICAgaGVpZ2h0OiAxMDAlO1xuICAgIHdpZHRoOiAkaWNvbi1ib3JkZXItd2lkdGg7XG4gIH1cbn1cblxuLmljb24tY3Jvc3Mge1xuICAmOjpiZWZvcmUge1xuICAgIHdpZHRoOiAxMDAlO1xuICB9XG4gICY6OmFmdGVyIHtcbiAgICBoZWlnaHQ6IDEwMCU7XG4gIH1cbiAgJjo6YmVmb3JlLFxuICAmOjphZnRlciB7XG4gICAgdHJhbnNmb3JtOiB0cmFuc2xhdGUoLTUwJSwgLTUwJSkgcm90YXRlKDQ1ZGVnKTtcbiAgfVxufVxuXG4vLyBJY29uIGNoZWNrXG4uaWNvbi1jaGVjayB7XG4gICY6OmJlZm9yZSB7XG4gICAgYm9yZGVyOiAkaWNvbi1ib3JkZXItd2lkdGggc29saWQgY3VycmVudENvbG9yO1xuICAgIGJvcmRlci1yaWdodDogMDtcbiAgICBib3JkZXItdG9wOiAwO1xuICAgIGNvbnRlbnQ6IFwiXCI7XG4gICAgaGVpZ2h0OiAuNWVtO1xuICAgIHdpZHRoOiAuOWVtO1xuICAgIHRyYW5zZm9ybTogdHJhbnNsYXRlKC01MCUsIC03NSUpIHJvdGF0ZSgtNDVkZWcpO1xuICB9XG59XG5cbi8vIEljb24gc3RvcFxuLmljb24tc3RvcCB7XG4gIGJvcmRlcjogJGljb24tYm9yZGVyLXdpZHRoIHNvbGlkIGN1cnJlbnRDb2xvcjtcbiAgYm9yZGVyLXJhZGl1czogNTAlO1xuICAmOjpiZWZvcmUge1xuICAgIGJhY2tncm91bmQ6IGN1cnJlbnRDb2xvcjtcbiAgICBjb250ZW50OiBcIlwiO1xuICAgIGhlaWdodDogJGljb24tYm9yZGVyLXdpZHRoO1xuICAgIHRyYW5zZm9ybTogdHJhbnNsYXRlKC01MCUsIC01MCUpIHJvdGF0ZSg0NWRlZyk7XG4gICAgd2lkdGg6IDFlbTtcbiAgfVxufVxuXG4vLyBJY29uIHNodXRkb3duXG4uaWNvbi1zaHV0ZG93biB7XG4gIGJvcmRlcjogJGljb24tYm9yZGVyLXdpZHRoIHNvbGlkIGN1cnJlbnRDb2xvcjtcbiAgYm9yZGVyLXJhZGl1czogNTAlO1xuICBib3JkZXItdG9wLWNvbG9yOiB0cmFuc3BhcmVudDtcbiAgJjo6YmVmb3JlIHtcbiAgICBiYWNrZ3JvdW5kOiBjdXJyZW50Q29sb3I7XG4gICAgY29udGVudDogXCJcIjtcbiAgICBoZWlnaHQ6IC41ZW07XG4gICAgdG9wOiAuMWVtO1xuICAgIHdpZHRoOiAkaWNvbi1ib3JkZXItd2lkdGg7XG4gIH1cbn1cblxuLy8gSWNvbiByZWZyZXNoXG4uaWNvbi1yZWZyZXNoIHtcbiAgJjo6YmVmb3JlIHtcbiAgICBib3JkZXI6ICRpY29uLWJvcmRlci13aWR0aCBzb2xpZCBjdXJyZW50Q29sb3I7XG4gICAgYm9yZGVyLXJhZGl1czogNTAlO1xuICAgIGJvcmRlci1yaWdodC1jb2xvcjogdHJhbnNwYXJlbnQ7XG4gICAgY29udGVudDogXCJcIjtcbiAgICBoZWlnaHQ6IDFlbTtcbiAgICB3aWR0aDogMWVtO1xuICB9XG4gICY6OmFmdGVyIHtcbiAgICBib3JkZXI6IC4yZW0gc29saWQgY3VycmVudENvbG9yO1xuICAgIGJvcmRlci10b3AtY29sb3I6IHRyYW5zcGFyZW50O1xuICAgIGJvcmRlci1sZWZ0LWNvbG9yOiB0cmFuc3BhcmVudDtcbiAgICBjb250ZW50OiBcIlwiO1xuICAgIGhlaWdodDogMDtcbiAgICBsZWZ0OiA4MCU7XG4gICAgdG9wOiAyMCU7XG4gICAgd2lkdGg6IDA7XG4gIH1cbn1cblxuLy8gSWNvbiBzZWFyY2hcbi5pY29uLXNlYXJjaCB7XG4gICY6OmJlZm9yZSB7XG4gICAgYm9yZGVyOiAkaWNvbi1ib3JkZXItd2lkdGggc29saWQgY3VycmVudENvbG9yO1xuICAgIGJvcmRlci1yYWRpdXM6IDUwJTtcbiAgICBjb250ZW50OiBcIlwiO1xuICAgIGhlaWdodDogLjc1ZW07XG4gICAgbGVmdDogNSU7XG4gICAgdG9wOiA1JTtcbiAgICB0cmFuc2Zvcm06IHRyYW5zbGF0ZSgwLCAwKSByb3RhdGUoNDVkZWcpO1xuICAgIHdpZHRoOiAuNzVlbTtcbiAgfVxuICAmOjphZnRlciB7XG4gICAgYmFja2dyb3VuZDogY3VycmVudENvbG9yO1xuICAgIGNvbnRlbnQ6IFwiXCI7XG4gICAgaGVpZ2h0OiAkaWNvbi1ib3JkZXItd2lkdGg7XG4gICAgbGVmdDogODAlO1xuICAgIHRvcDogODAlO1xuICAgIHRyYW5zZm9ybTogdHJhbnNsYXRlKC01MCUsIC01MCUpIHJvdGF0ZSg0NWRlZyk7XG4gICAgd2lkdGg6IC40ZW07XG4gIH1cbn1cblxuLy8gSWNvbiBlZGl0XG4uaWNvbi1lZGl0IHtcbiAgJjo6YmVmb3JlIHtcbiAgICBib3JkZXI6ICRpY29uLWJvcmRlci13aWR0aCBzb2xpZCBjdXJyZW50Q29sb3I7XG4gICAgY29udGVudDogXCJcIjtcbiAgICBoZWlnaHQ6IC40ZW07XG4gICAgdHJhbnNmb3JtOiB0cmFuc2xhdGUoLTQwJSwgLTYwJSkgcm90YXRlKC00NWRlZyk7XG4gICAgd2lkdGg6IC44NWVtO1xuICB9XG4gICY6OmFmdGVyIHtcbiAgICBib3JkZXI6IC4xNWVtIHNvbGlkIGN1cnJlbnRDb2xvcjtcbiAgICBib3JkZXItdG9wLWNvbG9yOiB0cmFuc3BhcmVudDtcbiAgICBib3JkZXItcmlnaHQtY29sb3I6IHRyYW5zcGFyZW50O1xuICAgIGNvbnRlbnQ6IFwiXCI7XG4gICAgaGVpZ2h0OiAwO1xuICAgIGxlZnQ6IDUlO1xuICAgIHRvcDogOTUlO1xuICAgIHRyYW5zZm9ybTogdHJhbnNsYXRlKDAsIC0xMDAlKTtcbiAgICB3aWR0aDogMDtcbiAgfVxufVxuXG4vLyBJY29uIGRlbGV0ZVxuLmljb24tZGVsZXRlIHtcbiAgJjo6YmVmb3JlIHtcbiAgICBib3JkZXI6ICRpY29uLWJvcmRlci13aWR0aCBzb2xpZCBjdXJyZW50Q29sb3I7XG4gICAgYm9yZGVyLWJvdHRvbS1sZWZ0LXJhZGl1czogJGJvcmRlci1yYWRpdXM7XG4gICAgYm9yZGVyLWJvdHRvbS1yaWdodC1yYWRpdXM6ICRib3JkZXItcmFkaXVzO1xuICAgIGJvcmRlci10b3A6IDA7XG4gICAgY29udGVudDogXCJcIjtcbiAgICBoZWlnaHQ6IC43NWVtO1xuICAgIHRvcDogNjAlO1xuICAgIHdpZHRoOiAuNzVlbTtcbiAgfVxuICAmOjphZnRlciB7XG4gICAgYmFja2dyb3VuZDogY3VycmVudENvbG9yO1xuICAgIGJveC1zaGFkb3c6IC0uMjVlbSAuMmVtLCAuMjVlbSAuMmVtO1xuICAgIGNvbnRlbnQ6IFwiXCI7XG4gICAgaGVpZ2h0OiAkaWNvbi1ib3JkZXItd2lkdGg7XG4gICAgdG9wOiAkaWNvbi1ib3JkZXItd2lkdGgvMjtcbiAgICB3aWR0aDogLjVlbTtcbiAgfVxufVxuXG4vLyBJY29uIHNoYXJlXG4uaWNvbi1zaGFyZSB7XG4gIGJvcmRlcjogJGljb24tYm9yZGVyLXdpZHRoIHNvbGlkIGN1cnJlbnRDb2xvcjtcbiAgYm9yZGVyLXJhZGl1czogJGJvcmRlci1yYWRpdXM7XG4gIGJvcmRlci1yaWdodDogMDtcbiAgYm9yZGVyLXRvcDogMDtcbiAgJjo6YmVmb3JlIHtcbiAgICBib3JkZXI6ICRpY29uLWJvcmRlci13aWR0aCBzb2xpZCBjdXJyZW50Q29sb3I7XG4gICAgYm9yZGVyLWxlZnQ6IDA7XG4gICAgYm9yZGVyLXRvcDogMDtcbiAgICBjb250ZW50OiBcIlwiO1xuICAgIGhlaWdodDogLjRlbTtcbiAgICBsZWZ0OiAxMDAlO1xuICAgIHRvcDogLjI1ZW07XG4gICAgdHJhbnNmb3JtOiB0cmFuc2xhdGUoLTEyNSUsIC01MCUpIHJvdGF0ZSgtNDVkZWcpO1xuICAgIHdpZHRoOiAuNGVtO1xuICB9XG4gICY6OmFmdGVyIHtcbiAgICBib3JkZXI6ICRpY29uLWJvcmRlci13aWR0aCBzb2xpZCBjdXJyZW50Q29sb3I7XG4gICAgYm9yZGVyLWJvdHRvbTogMDtcbiAgICBib3JkZXItcmlnaHQ6IDA7XG4gICAgYm9yZGVyLXJhZGl1czogNzUlIDA7XG4gICAgY29udGVudDogXCJcIjtcbiAgICBoZWlnaHQ6IC41ZW07XG4gICAgd2lkdGg6IC42ZW07XG4gIH1cbn1cblxuLy8gSWNvbiBmbGFnXG4uaWNvbi1mbGFnIHtcbiAgJjo6YmVmb3JlIHtcbiAgICBiYWNrZ3JvdW5kOiBjdXJyZW50Q29sb3I7XG4gICAgY29udGVudDogXCJcIjtcbiAgICBoZWlnaHQ6IDFlbTtcbiAgICBsZWZ0OiAxNSU7XG4gICAgd2lkdGg6ICRpY29uLWJvcmRlci13aWR0aDtcbiAgfVxuICAmOjphZnRlciB7XG4gICAgYm9yZGVyOiAkaWNvbi1ib3JkZXItd2lkdGggc29saWQgY3VycmVudENvbG9yO1xuICAgIGJvcmRlci1ib3R0b20tcmlnaHQtcmFkaXVzOiAkYm9yZGVyLXJhZGl1cztcbiAgICBib3JkZXItbGVmdDogMDtcbiAgICBib3JkZXItdG9wLXJpZ2h0LXJhZGl1czogJGJvcmRlci1yYWRpdXM7XG4gICAgY29udGVudDogXCJcIjtcbiAgICBoZWlnaHQ6IC42NWVtO1xuICAgIHRvcDogMzUlO1xuICAgIGxlZnQ6IDYwJTtcbiAgICB3aWR0aDogLjhlbTtcbiAgfVxufVxuXG4vLyBJY29uIGJvb2ttYXJrXG4uaWNvbi1ib29rbWFyayB7XG4gICY6OmJlZm9yZSB7XG4gICAgYm9yZGVyOiAkaWNvbi1ib3JkZXItd2lkdGggc29saWQgY3VycmVudENvbG9yO1xuICAgIGJvcmRlci1ib3R0b206IDA7XG4gICAgYm9yZGVyLXRvcC1sZWZ0LXJhZGl1czogJGJvcmRlci1yYWRpdXM7XG4gICAgYm9yZGVyLXRvcC1yaWdodC1yYWRpdXM6ICRib3JkZXItcmFkaXVzO1xuICAgIGNvbnRlbnQ6IFwiXCI7XG4gICAgaGVpZ2h0OiAuOWVtO1xuICAgIHdpZHRoOiAuOGVtO1xuICB9XG4gICY6OmFmdGVyIHtcbiAgICBib3JkZXI6ICRpY29uLWJvcmRlci13aWR0aCBzb2xpZCBjdXJyZW50Q29sb3I7XG4gICAgYm9yZGVyLWJvdHRvbTogMDtcbiAgICBib3JkZXItbGVmdDogMDtcbiAgICBib3JkZXItcmFkaXVzOiAkYm9yZGVyLXJhZGl1cztcbiAgICBjb250ZW50OiBcIlwiO1xuICAgIGhlaWdodDogLjVlbTtcbiAgICB0cmFuc2Zvcm06IHRyYW5zbGF0ZSgtNTAlLCAzNSUpIHJvdGF0ZSgtNDVkZWcpIHNrZXcoMTVkZWcsIDE1ZGVnKTtcbiAgICB3aWR0aDogLjVlbTtcbiAgfVxufVxuXG4vLyBJY29uIGRvd25sb2FkICYgdXBsb2FkXG4uaWNvbi1kb3dubG9hZCxcbi5pY29uLXVwbG9hZCB7XG4gIGJvcmRlci1ib3R0b206ICRpY29uLWJvcmRlci13aWR0aCBzb2xpZCBjdXJyZW50Q29sb3I7XG4gICY6OmJlZm9yZSB7XG4gICAgYm9yZGVyOiAkaWNvbi1ib3JkZXItd2lkdGggc29saWQgY3VycmVudENvbG9yO1xuICAgIGJvcmRlci1ib3R0b206IDA7XG4gICAgYm9yZGVyLXJpZ2h0OiAwO1xuICAgIGNvbnRlbnQ6IFwiXCI7XG4gICAgaGVpZ2h0OiAuNWVtO1xuICAgIHdpZHRoOiAuNWVtO1xuICAgIHRyYW5zZm9ybTogdHJhbnNsYXRlKC01MCUsIC02MCUpIHJvdGF0ZSgtMTM1ZGVnKTtcbiAgfVxuICAmOjphZnRlciB7XG4gICAgYmFja2dyb3VuZDogY3VycmVudENvbG9yO1xuICAgIGNvbnRlbnQ6IFwiXCI7XG4gICAgaGVpZ2h0OiAuNmVtO1xuICAgIHRvcDogNDAlO1xuICAgIHdpZHRoOiAkaWNvbi1ib3JkZXItd2lkdGg7XG4gIH1cbn1cblxuLmljb24tdXBsb2FkIHtcbiAgJjo6YmVmb3JlIHtcbiAgICB0cmFuc2Zvcm06IHRyYW5zbGF0ZSgtNTAlLCAtNjAlKSByb3RhdGUoNDVkZWcpO1xuICB9XG4gICY6OmFmdGVyIHtcbiAgICB0b3A6IDUwJTtcbiAgfVxufVxuIiwiLy8gSWNvbiB0aW1lXG4uaWNvbi10aW1lIHtcbiAgYm9yZGVyOiAkaWNvbi1ib3JkZXItd2lkdGggc29saWQgY3VycmVudENvbG9yO1xuICBib3JkZXItcmFkaXVzOiA1MCU7XG4gICY6OmJlZm9yZSB7XG4gICAgYmFja2dyb3VuZDogY3VycmVudENvbG9yO1xuICAgIGNvbnRlbnQ6IFwiXCI7XG4gICAgaGVpZ2h0OiAuNGVtO1xuICAgIHRyYW5zZm9ybTogdHJhbnNsYXRlKC01MCUsIC03NSUpO1xuICAgIHdpZHRoOiAkaWNvbi1ib3JkZXItd2lkdGg7XG4gIH1cbiAgJjo6YWZ0ZXIge1xuICAgIGJhY2tncm91bmQ6IGN1cnJlbnRDb2xvcjtcbiAgICBjb250ZW50OiBcIlwiO1xuICAgIGhlaWdodDogLjNlbTtcbiAgICB0cmFuc2Zvcm06IHRyYW5zbGF0ZSgtNTAlLCAtNzUlKSByb3RhdGUoOTBkZWcpO1xuICAgIHRyYW5zZm9ybS1vcmlnaW46IDUwJSA5MCU7XG4gICAgd2lkdGg6ICRpY29uLWJvcmRlci13aWR0aDtcbiAgfVxufVxuXG4vLyBJY29uIG1haWxcbi5pY29uLW1haWwge1xuICAmOjpiZWZvcmUge1xuICAgIGJvcmRlcjogJGljb24tYm9yZGVyLXdpZHRoIHNvbGlkIGN1cnJlbnRDb2xvcjtcbiAgICBib3JkZXItcmFkaXVzOiAkYm9yZGVyLXJhZGl1cztcbiAgICBjb250ZW50OiBcIlwiO1xuICAgIGhlaWdodDogLjhlbTtcbiAgICB3aWR0aDogMWVtO1xuICB9XG4gICY6OmFmdGVyIHtcbiAgICBib3JkZXI6ICRpY29uLWJvcmRlci13aWR0aCBzb2xpZCBjdXJyZW50Q29sb3I7XG4gICAgYm9yZGVyLXJpZ2h0OiAwO1xuICAgIGJvcmRlci10b3A6IDA7XG4gICAgY29udGVudDogXCJcIjtcbiAgICBoZWlnaHQ6IC41ZW07XG4gICAgdHJhbnNmb3JtOiB0cmFuc2xhdGUoLTUwJSwgLTkwJSkgcm90YXRlKC00NWRlZykgc2tldygxMGRlZywgMTBkZWcpO1xuICAgIHdpZHRoOiAuNWVtO1xuICB9XG59XG5cbi8vIEljb24gcGVvcGxlXG4uaWNvbi1wZW9wbGUge1xuICAmOjpiZWZvcmUge1xuICAgIGJvcmRlcjogJGljb24tYm9yZGVyLXdpZHRoIHNvbGlkIGN1cnJlbnRDb2xvcjtcbiAgICBib3JkZXItcmFkaXVzOiA1MCU7XG4gICAgY29udGVudDogXCJcIjtcbiAgICBoZWlnaHQ6IC40NWVtO1xuICAgIHRvcDogMjUlO1xuICAgIHdpZHRoOiAuNDVlbTtcbiAgfVxuICAmOjphZnRlciB7XG4gICAgYm9yZGVyOiAkaWNvbi1ib3JkZXItd2lkdGggc29saWQgY3VycmVudENvbG9yO1xuICAgIGJvcmRlci1yYWRpdXM6IDUwJSA1MCUgMCAwO1xuICAgIGNvbnRlbnQ6IFwiXCI7XG4gICAgaGVpZ2h0OiAuNGVtO1xuICAgIHRvcDogNzUlO1xuICAgIHdpZHRoOiAuOWVtO1xuICB9XG59XG5cbi8vIEljb24gbWVzc2FnZVxuLmljb24tbWVzc2FnZSB7XG4gIGJvcmRlcjogJGljb24tYm9yZGVyLXdpZHRoIHNvbGlkIGN1cnJlbnRDb2xvcjtcbiAgYm9yZGVyLWJvdHRvbTogMDtcbiAgYm9yZGVyLXJhZGl1czogJGJvcmRlci1yYWRpdXM7XG4gIGJvcmRlci1yaWdodDogMDtcbiAgJjo6YmVmb3JlIHtcbiAgICBib3JkZXI6ICRpY29uLWJvcmRlci13aWR0aCBzb2xpZCBjdXJyZW50Q29sb3I7XG4gICAgYm9yZGVyLWJvdHRvbS1yaWdodC1yYWRpdXM6ICRib3JkZXItcmFkaXVzO1xuICAgIGJvcmRlci1sZWZ0OiAwO1xuICAgIGJvcmRlci10b3A6IDA7XG4gICAgY29udGVudDogXCJcIjtcbiAgICBoZWlnaHQ6IC44ZW07XG4gICAgbGVmdDogNjUlO1xuICAgIHRvcDogNDAlO1xuICAgIHdpZHRoOiAuN2VtO1xuICB9XG4gICY6OmFmdGVyIHtcbiAgICBiYWNrZ3JvdW5kOiBjdXJyZW50Q29sb3I7XG4gICAgYm9yZGVyLXJhZGl1czogJGJvcmRlci1yYWRpdXM7XG4gICAgY29udGVudDogXCJcIjtcbiAgICBoZWlnaHQ6IC4zZW07XG4gICAgbGVmdDogMTAlO1xuICAgIHRvcDogMTAwJTtcbiAgICB0cmFuc2Zvcm06IHRyYW5zbGF0ZSgwLCAtOTAlKSByb3RhdGUoNDVkZWcpO1xuICAgIHdpZHRoOiAkaWNvbi1ib3JkZXItd2lkdGg7XG4gIH1cbn1cblxuLy8gSWNvbiBwaG90b1xuLmljb24tcGhvdG8ge1xuICBib3JkZXI6ICRpY29uLWJvcmRlci13aWR0aCBzb2xpZCBjdXJyZW50Q29sb3I7XG4gIGJvcmRlci1yYWRpdXM6ICRib3JkZXItcmFkaXVzO1xuICAmOjpiZWZvcmUge1xuICAgIGJvcmRlcjogJGljb24tYm9yZGVyLXdpZHRoIHNvbGlkIGN1cnJlbnRDb2xvcjtcbiAgICBib3JkZXItcmFkaXVzOiA1MCU7XG4gICAgY29udGVudDogXCJcIjtcbiAgICBoZWlnaHQ6IC4yNWVtO1xuICAgIGxlZnQ6IDM1JTtcbiAgICB0b3A6IDM1JTtcbiAgICB3aWR0aDogLjI1ZW07XG4gIH1cbiAgJjo6YWZ0ZXIge1xuICAgIGJvcmRlcjogJGljb24tYm9yZGVyLXdpZHRoIHNvbGlkIGN1cnJlbnRDb2xvcjtcbiAgICBib3JkZXItYm90dG9tOiAwO1xuICAgIGJvcmRlci1sZWZ0OiAwO1xuICAgIGNvbnRlbnQ6IFwiXCI7XG4gICAgaGVpZ2h0OiAuNWVtO1xuICAgIGxlZnQ6IDYwJTtcbiAgICB0cmFuc2Zvcm06IHRyYW5zbGF0ZSgtNTAlLCAyNSUpIHJvdGF0ZSgtNDVkZWcpO1xuICAgIHdpZHRoOiAuNWVtO1xuICB9XG59XG5cbi8vIEljb24gbGlua1xuLmljb24tbGluayB7XG4gICY6OmJlZm9yZSxcbiAgJjo6YWZ0ZXIge1xuICAgIGJvcmRlcjogJGljb24tYm9yZGVyLXdpZHRoIHNvbGlkIGN1cnJlbnRDb2xvcjtcbiAgICBib3JkZXItcmFkaXVzOiA1ZW0gMCAwIDVlbTtcbiAgICBib3JkZXItcmlnaHQ6IDA7XG4gICAgY29udGVudDogXCJcIjtcbiAgICBoZWlnaHQ6IC41ZW07XG4gICAgd2lkdGg6IC43NWVtO1xuICB9XG4gICY6OmJlZm9yZSB7XG4gICAgdHJhbnNmb3JtOiB0cmFuc2xhdGUoLTcwJSwgLTQ1JSkgcm90YXRlKC00NWRlZyk7XG4gIH1cbiAgJjo6YWZ0ZXIge1xuICAgIHRyYW5zZm9ybTogdHJhbnNsYXRlKC0zMCUsIC01NSUpIHJvdGF0ZSgxMzVkZWcpO1xuICB9XG59XG5cbi8vIEljb24gbG9jYXRpb25cbi5pY29uLWxvY2F0aW9uIHtcbiAgJjo6YmVmb3JlIHtcbiAgICBib3JkZXI6ICRpY29uLWJvcmRlci13aWR0aCBzb2xpZCBjdXJyZW50Q29sb3I7XG4gICAgYm9yZGVyLXJhZGl1czogNTAlIDUwJSA1MCUgMDtcbiAgICBjb250ZW50OiBcIlwiO1xuICAgIGhlaWdodDogLjhlbTtcbiAgICB0cmFuc2Zvcm06IHRyYW5zbGF0ZSgtNTAlLCAtNjAlKSByb3RhdGUoLTQ1ZGVnKTtcbiAgICB3aWR0aDogLjhlbTtcbiAgfVxuICAmOjphZnRlciB7XG4gICAgYm9yZGVyOiAkaWNvbi1ib3JkZXItd2lkdGggc29saWQgY3VycmVudENvbG9yO1xuICAgIGJvcmRlci1yYWRpdXM6IDUwJTtcbiAgICBjb250ZW50OiBcIlwiO1xuICAgIGhlaWdodDogLjJlbTtcbiAgICB0cmFuc2Zvcm06IHRyYW5zbGF0ZSgtNTAlLCAtODAlKTtcbiAgICB3aWR0aDogLjJlbTtcbiAgfVxufVxuXG4vLyBJY29uIGVtb2ppXG4uaWNvbi1lbW9qaSB7XG4gIGJvcmRlcjogJGljb24tYm9yZGVyLXdpZHRoIHNvbGlkIGN1cnJlbnRDb2xvcjtcbiAgYm9yZGVyLXJhZGl1czogNTAlO1xuICAmOjpiZWZvcmUge1xuICAgIGJvcmRlci1yYWRpdXM6IDUwJTtcbiAgICBib3gtc2hhZG93OiAtLjE3ZW0gLS4xNWVtLCAuMTdlbSAtLjE1ZW07XG4gICAgY29udGVudDogXCJcIjtcbiAgICBoZWlnaHQ6IC4xZW07XG4gICAgd2lkdGg6IC4xZW07XG4gIH1cbiAgJjo6YWZ0ZXIge1xuICAgIGJvcmRlcjogJGljb24tYm9yZGVyLXdpZHRoIHNvbGlkIGN1cnJlbnRDb2xvcjtcbiAgICBib3JkZXItYm90dG9tLWNvbG9yOiB0cmFuc3BhcmVudDtcbiAgICBib3JkZXItcmFkaXVzOiA1MCU7XG4gICAgYm9yZGVyLXJpZ2h0LWNvbG9yOiB0cmFuc3BhcmVudDtcbiAgICBjb250ZW50OiBcIlwiO1xuICAgIGhlaWdodDogLjVlbTtcbiAgICB0cmFuc2Zvcm06IHRyYW5zbGF0ZSgtNTAlLCAtNDAlKSByb3RhdGUoLTEzNWRlZyk7XG4gICAgd2lkdGg6IC41ZW07XG4gIH1cbn1cbiJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFJQSw4RUFBb0Y7QWFDcEYsQUFBQSxLQUFLLENBQVksRUFDZixVQUFVLEVBQUUsVUFBVSxFQUN0QixPQUFPLEVBQUUsWUFBWSxFQUNyQixTQUFTLEVBQUUsT0FBTyxFQUNsQixVQUFVLEVBQUUsTUFBTSxFQUNsQixNQUFNLEVBQUUsR0FBRyxFQUNYLFFBQVEsRUFBRSxRQUFRLEVBQ2xCLFdBQVcsRUFBRSxPQUFPLEVBQ3BCLGNBQWMsRUFBRSxNQUFNLEVBQ3RCLEtBQUssRUFBRSxHQUFHLEdBc0JYOztBQS9CRCxBQVVFLEtBVkcsQUFVRixRQUFRLEVBVlgsS0FBSyxBQVdGLE9BQU8sQ0FBQyxFQUNQLE9BQU8sRUFBRSxLQUFLLEVBQ2QsSUFBSSxFQUFFLEdBQUcsRUFDVCxRQUFRLEVBQUUsUUFBUSxFQUNsQixHQUFHLEVBQUUsR0FBRyxFQUNSLFNBQVMsRUFBRSxxQkFBcUIsR0FDakM7O0FBakJILEFBb0JFLEtBcEJHLEFBb0JGLFFBQVEsQ0FBQyxFQUNSLFNBQVMsRUFBRSxNQUFNLEdBQ2xCOztBQXRCSCxBQXdCRSxLQXhCRyxBQXdCRixRQUFRLENBQUMsRUFDUixTQUFTLEVBQUUsTUFBTSxHQUNsQjs7QUExQkgsQUE0QkUsS0E1QkcsQUE0QkYsUUFBUSxDQUFDLEVBQ1IsU0FBUyxFQUFFLE1BQU0sR0FDbEI7O0FBSUgsQUFJRSxVQUpRLENBSVIsS0FBSyxFQUhQLElBQUksQ0FHRixLQUFLLEVBRlAsTUFBTSxDQUVKLEtBQUssRUFEUCxLQUFLLENBQ0gsS0FBSyxDQUFZLEVBQ2YsY0FBYyxFQUFFLElBQUksR0FDckI7O0FBR0gsQUFDRSxPQURLLENBQ0wsS0FBSyxDQUFZLEVBQ2YsY0FBYyxFQUFFLElBQUksR0FDckI7O0FDbERILEFBUUUsZ0JBUmMsQUFRYixRQUFRLEVBUFgsZ0JBQWdCLEFBT2IsUUFBUSxFQU5YLGlCQUFpQixBQU1kLFFBQVEsRUFMWCxjQUFjLEFBS1gsUUFBUSxFQUpYLGNBQWMsQUFJWCxRQUFRLEVBSFgsVUFBVSxBQUdQLFFBQVEsRUFGWCxhQUFhLEFBRVYsUUFBUSxFQURYLFlBQVksQUFDVCxRQUFRLENBQUMsRUFDUixNQUFNLEViNENELE1BQUssQ2E1Q2lCLEtBQUssQ0FBQyxZQUFZLEVBQzdDLGFBQWEsRUFBRSxDQUFDLEVBQ2hCLFlBQVksRUFBRSxDQUFDLEVBQ2YsT0FBTyxFQUFFLEVBQUUsRUFDWCxNQUFNLEVBQUUsS0FBSyxFQUNiLEtBQUssRUFBRSxLQUFLLEdBQ2I7O0FBR0gsQUFDRSxnQkFEYyxBQUNiLFFBQVEsQ0FBQyxFQUNSLFNBQVMsRUFBRSxxQkFBcUIsQ0FBQyxjQUFjLEdBQ2hEOztBQUdILEFBQ0UsZ0JBRGMsQUFDYixRQUFRLENBQUMsRUFDUixTQUFTLEVBQUUscUJBQXFCLENBQUMsY0FBYyxHQUNoRDs7QUFHSCxBQUNFLGlCQURlLEFBQ2QsUUFBUSxDQUFDLEVBQ1IsU0FBUyxFQUFFLHFCQUFxQixDQUFDLGNBQWMsR0FDaEQ7O0FBR0gsQUFDRSxjQURZLEFBQ1gsUUFBUSxDQUFDLEVBQ1IsU0FBUyxFQUFFLHFCQUFxQixDQUFDLGFBQWEsR0FDL0M7O0FBR0gsQUFFRSxVQUZRLEFBRVAsT0FBTyxFQURWLGFBQWEsQUFDVixPQUFPLENBQUMsRUFDUCxVQUFVLEVBQUUsWUFBWSxFQUN4QixPQUFPLEVBQUUsRUFBRSxFQUNYLE1BQU0sRWJNRCxNQUFLLEVhTFYsS0FBSyxFQUFFLElBQUksR0FDWjs7QUFHSCxBQUVFLGNBRlksQUFFWCxPQUFPLEVBRFYsWUFBWSxBQUNULE9BQU8sQ0FBQyxFQUNQLFVBQVUsRUFBRSxZQUFZLEVBQ3hCLE9BQU8sRUFBRSxFQUFFLEVBQ1gsTUFBTSxFQUFFLElBQUksRUFDWixLQUFLLEViTEEsTUFBSyxHYU1YOztBQUdILEFBQ0UsVUFEUSxBQUNQLE9BQU8sQ0FBQyxFQUNQLElBQUksRUFBRSxHQUFHLEdBQ1Y7O0FBSEgsQUFJRSxVQUpRLEFBSVAsUUFBUSxDQUFDLEVBQ1IsU0FBUyxFQUFFLHFCQUFxQixDQUFDLGNBQWMsR0FDaEQ7O0FBR0gsQUFDRSxjQURZLEFBQ1gsT0FBTyxDQUFDLEVBQ1AsR0FBRyxFQUFFLEdBQUcsR0FDVDs7QUFISCxBQUlFLGNBSlksQUFJWCxRQUFRLENBQUMsRUFDUixTQUFTLEVBQUUscUJBQXFCLENBQUMsZUFBZSxHQUNqRDs7QUFHSCxBQUNFLGFBRFcsQUFDVixPQUFPLENBQUMsRUFDUCxJQUFJLEVBQUUsR0FBRyxHQUNWOztBQUhILEFBSUUsYUFKVyxBQUlWLFFBQVEsQ0FBQyxFQUNSLFNBQVMsRUFBRSxxQkFBcUIsQ0FBQyxjQUFjLEdBQ2hEOztBQUdILEFBQ0UsWUFEVSxBQUNULE9BQU8sQ0FBQyxFQUNQLEdBQUcsRUFBRSxHQUFHLEdBQ1Q7O0FBSEgsQUFJRSxZQUpVLEFBSVQsUUFBUSxDQUFDLEVBQ1IsU0FBUyxFQUFFLHFCQUFxQixDQUFDLGFBQWEsR0FDL0M7O0FBSUgsQUFDRSxXQURTLEFBQ1IsUUFBUSxDQUFDLEVBQ1IsVUFBVSxFQUFFLHVCQUF1QixFQUNuQyxZQUFZLEVBQUUsc0JBQXNCLEVBQ3BDLFdBQVcsRUFBRSxzQkFBc0IsRUFDbkMsT0FBTyxFQUFFLEVBQUUsRUFDWCxNQUFNLEVBQUUsQ0FBQyxFQUNULFNBQVMsRUFBRSxxQkFBcUIsRUFDaEMsS0FBSyxFQUFFLENBQUMsR0FDVDs7QUFJSCxBQUNFLFVBRFEsQUFDUCxRQUFRLENBQUMsRUFDUixVQUFVLEVBQUUsWUFBWSxFQUN4QixVQUFVLEVBQUUsaUJBQWlCLEVBQzdCLE9BQU8sRUFBRSxFQUFFLEVBQ1gsTUFBTSxFYmhFRCxNQUFLLEVhaUVWLEtBQUssRUFBRSxJQUFJLEdBQ1o7O0FBSUgsQUFDRSxVQURRLEFBQ1AsUUFBUSxDQUFDLEVBQ1IsVUFBVSxFQUFFLFlBQVksRUFDeEIsVUFBVSxFQUFFLDRGQUE0RixFQUN4RyxPQUFPLEVBQUUsRUFBRSxFQUNYLE1BQU0sRUFBRSxHQUFHLEVBQ1gsS0FBSyxFQUFFLEdBQUcsR0FDWDs7QUNqSUgsQUFFRSxrQkFGZ0IsQUFFZixRQUFRLEVBRlgsa0JBQWtCLEFBR2YsT0FBTyxFQUZWLGlCQUFpQixBQUNkLFFBQVEsRUFEWCxpQkFBaUIsQUFFZCxPQUFPLENBQUMsRUFDUCxNQUFNLEVkZ0RELE1BQUssQ2NoRGlCLEtBQUssQ0FBQyxZQUFZLEVBQzdDLGFBQWEsRUFBRSxDQUFDLEVBQ2hCLFlBQVksRUFBRSxDQUFDLEVBQ2YsT0FBTyxFQUFFLEVBQUUsRUFDWCxNQUFNLEVBQUUsS0FBSyxFQUNiLEtBQUssRUFBRSxLQUFLLEdBQ2I7O0FBVkgsQUFXRSxrQkFYZ0IsQUFXZixRQUFRLEVBVlgsaUJBQWlCLEFBVWQsUUFBUSxDQUFDLEVBQ1IsU0FBUyxFQUFFLHFCQUFxQixDQUFDLGFBQWEsR0FDL0M7O0FBYkgsQUFjRSxrQkFkZ0IsQUFjZixPQUFPLEVBYlYsaUJBQWlCLEFBYWQsT0FBTyxDQUFDLEVBQ1AsU0FBUyxFQUFFLHFCQUFxQixDQUFDLGNBQWMsR0FDaEQ7O0FBR0gsQUFDRSxrQkFEZ0IsQUFDZixRQUFRLENBQUMsRUFDUixTQUFTLEVBQUUscUJBQXFCLENBQUMsY0FBYyxHQUNoRDs7QUFISCxBQUlFLGtCQUpnQixBQUlmLE9BQU8sQ0FBQyxFQUNQLFNBQVMsRUFBRSxxQkFBcUIsQ0FBQyxjQUFjLEdBQ2hEOztBQUlILEFBRUUsZ0JBRmMsQUFFYixRQUFRLEVBRFgsZUFBZSxBQUNaLFFBQVEsQ0FBQyxFQUNSLFVBQVUsRUFBRSxZQUFZLEVBQ3hCLFVBQVUsRUFBRSxlQUFlLEVBQzNCLGFBQWEsRUFBRSxHQUFHLEVBQ2xCLE9BQU8sRUFBRSxFQUFFLEVBQ1gsTUFBTSxFQUFFLEdBQUcsRUFDWCxLQUFLLEVBQUUsR0FBRyxHQUNYOztBQUdILEFBQ0UsZUFEYSxBQUNaLFFBQVEsQ0FBQyxFQUNSLFVBQVUsRUFBRSxlQUFlLEdBQzVCOztBQUlILEFBR0UsVUFIUSxBQUdQLFFBQVEsRUFGWCxXQUFXLEFBRVIsUUFBUSxFQURYLFdBQVcsQUFDUixRQUFRLENBQUMsRUFDUixVQUFVLEVBQUUsWUFBWSxFQUN4QixPQUFPLEVBQUUsRUFBRSxFQUNYLE1BQU0sRWRGRCxNQUFLLEVjR1YsS0FBSyxFQUFFLElBQUksR0FDWjs7QUFHSCxBQUVFLFVBRlEsQUFFUCxPQUFPLEVBRFYsV0FBVyxBQUNSLE9BQU8sQ0FBQyxFQUNQLFVBQVUsRUFBRSxZQUFZLEVBQ3hCLE9BQU8sRUFBRSxFQUFFLEVBQ1gsTUFBTSxFQUFFLElBQUksRUFDWixLQUFLLEVkYkEsTUFBSyxHY2NYOztBQUdILEFBQ0UsV0FEUyxBQUNSLFFBQVEsQ0FBQyxFQUNSLEtBQUssRUFBRSxJQUFJLEdBQ1o7O0FBSEgsQUFJRSxXQUpTLEFBSVIsT0FBTyxDQUFDLEVBQ1AsTUFBTSxFQUFFLElBQUksR0FDYjs7QUFOSCxBQU9FLFdBUFMsQUFPUixRQUFRLEVBUFgsV0FBVyxBQVFSLE9BQU8sQ0FBQyxFQUNQLFNBQVMsRUFBRSxxQkFBcUIsQ0FBQyxhQUFhLEdBQy9DOztBQUlILEFBQ0UsV0FEUyxBQUNSLFFBQVEsQ0FBQyxFQUNSLE1BQU0sRWRqQ0QsTUFBSyxDY2lDaUIsS0FBSyxDQUFDLFlBQVksRUFDN0MsWUFBWSxFQUFFLENBQUMsRUFDZixVQUFVLEVBQUUsQ0FBQyxFQUNiLE9BQU8sRUFBRSxFQUFFLEVBQ1gsTUFBTSxFQUFFLElBQUksRUFDWixLQUFLLEVBQUUsSUFBSSxFQUNYLFNBQVMsRUFBRSxxQkFBcUIsQ0FBQyxjQUFjLEdBQ2hEOztBQUlILEFBQUEsVUFBVSxDQUFDLEVBQ1QsTUFBTSxFZDdDQyxNQUFLLENjNkNlLEtBQUssQ0FBQyxZQUFZLEVBQzdDLGFBQWEsRUFBRSxHQUFHLEdBUW5COztBQVZELEFBR0UsVUFIUSxBQUdQLFFBQVEsQ0FBQyxFQUNSLFVBQVUsRUFBRSxZQUFZLEVBQ3hCLE9BQU8sRUFBRSxFQUFFLEVBQ1gsTUFBTSxFZGxERCxNQUFLLEVjbURWLFNBQVMsRUFBRSxxQkFBcUIsQ0FBQyxhQUFhLEVBQzlDLEtBQUssRUFBRSxHQUFHLEdBQ1g7O0FBSUgsQUFBQSxjQUFjLENBQUMsRUFDYixNQUFNLEVkMURDLE1BQUssQ2MwRGUsS0FBSyxDQUFDLFlBQVksRUFDN0MsYUFBYSxFQUFFLEdBQUcsRUFDbEIsZ0JBQWdCLEVBQUUsV0FBVyxHQVE5Qjs7QUFYRCxBQUlFLGNBSlksQUFJWCxRQUFRLENBQUMsRUFDUixVQUFVLEVBQUUsWUFBWSxFQUN4QixPQUFPLEVBQUUsRUFBRSxFQUNYLE1BQU0sRUFBRSxJQUFJLEVBQ1osR0FBRyxFQUFFLElBQUksRUFDVCxLQUFLLEVkbEVBLE1BQUssR2NtRVg7O0FBSUgsQUFDRSxhQURXLEFBQ1YsUUFBUSxDQUFDLEVBQ1IsTUFBTSxFZHpFRCxNQUFLLENjeUVpQixLQUFLLENBQUMsWUFBWSxFQUM3QyxhQUFhLEVBQUUsR0FBRyxFQUNsQixrQkFBa0IsRUFBRSxXQUFXLEVBQy9CLE9BQU8sRUFBRSxFQUFFLEVBQ1gsTUFBTSxFQUFFLEdBQUcsRUFDWCxLQUFLLEVBQUUsR0FBRyxHQUNYOztBQVJILEFBU0UsYUFUVyxBQVNWLE9BQU8sQ0FBQyxFQUNQLE1BQU0sRUFBRSx1QkFBdUIsRUFDL0IsZ0JBQWdCLEVBQUUsV0FBVyxFQUM3QixpQkFBaUIsRUFBRSxXQUFXLEVBQzlCLE9BQU8sRUFBRSxFQUFFLEVBQ1gsTUFBTSxFQUFFLENBQUMsRUFDVCxJQUFJLEVBQUUsR0FBRyxFQUNULEdBQUcsRUFBRSxHQUFHLEVBQ1IsS0FBSyxFQUFFLENBQUMsR0FDVDs7QUFJSCxBQUNFLFlBRFUsQUFDVCxRQUFRLENBQUMsRUFDUixNQUFNLEVkL0ZELE1BQUssQ2MrRmlCLEtBQUssQ0FBQyxZQUFZLEVBQzdDLGFBQWEsRUFBRSxHQUFHLEVBQ2xCLE9BQU8sRUFBRSxFQUFFLEVBQ1gsTUFBTSxFQUFFLEtBQUssRUFDYixJQUFJLEVBQUUsRUFBRSxFQUNSLEdBQUcsRUFBRSxFQUFFLEVBQ1AsU0FBUyxFQUFFLGVBQWUsQ0FBQyxhQUFhLEVBQ3hDLEtBQUssRUFBRSxLQUFLLEdBQ2I7O0FBVkgsQUFXRSxZQVhVLEFBV1QsT0FBTyxDQUFDLEVBQ1AsVUFBVSxFQUFFLFlBQVksRUFDeEIsT0FBTyxFQUFFLEVBQUUsRUFDWCxNQUFNLEVkM0dELE1BQUssRWM0R1YsSUFBSSxFQUFFLEdBQUcsRUFDVCxHQUFHLEVBQUUsR0FBRyxFQUNSLFNBQVMsRUFBRSxxQkFBcUIsQ0FBQyxhQUFhLEVBQzlDLEtBQUssRUFBRSxJQUFJLEdBQ1o7O0FBSUgsQUFDRSxVQURRLEFBQ1AsUUFBUSxDQUFDLEVBQ1IsTUFBTSxFZHRIRCxNQUFLLENjc0hpQixLQUFLLENBQUMsWUFBWSxFQUM3QyxPQUFPLEVBQUUsRUFBRSxFQUNYLE1BQU0sRUFBRSxJQUFJLEVBQ1osU0FBUyxFQUFFLHFCQUFxQixDQUFDLGNBQWMsRUFDL0MsS0FBSyxFQUFFLEtBQUssR0FDYjs7QUFQSCxBQVFFLFVBUlEsQUFRUCxPQUFPLENBQUMsRUFDUCxNQUFNLEVBQUUsd0JBQXdCLEVBQ2hDLGdCQUFnQixFQUFFLFdBQVcsRUFDN0Isa0JBQWtCLEVBQUUsV0FBVyxFQUMvQixPQUFPLEVBQUUsRUFBRSxFQUNYLE1BQU0sRUFBRSxDQUFDLEVBQ1QsSUFBSSxFQUFFLEVBQUUsRUFDUixHQUFHLEVBQUUsR0FBRyxFQUNSLFNBQVMsRUFBRSxtQkFBbUIsRUFDOUIsS0FBSyxFQUFFLENBQUMsR0FDVDs7QUFJSCxBQUNFLFlBRFUsQUFDVCxRQUFRLENBQUMsRUFDUixNQUFNLEVkNUlELE1BQUssQ2M0SWlCLEtBQUssQ0FBQyxZQUFZLEVBQzdDLHlCQUF5QixFZDdJcEIsTUFBSyxFYzhJViwwQkFBMEIsRWQ5SXJCLE1BQUssRWMrSVYsVUFBVSxFQUFFLENBQUMsRUFDYixPQUFPLEVBQUUsRUFBRSxFQUNYLE1BQU0sRUFBRSxLQUFLLEVBQ2IsR0FBRyxFQUFFLEdBQUcsRUFDUixLQUFLLEVBQUUsS0FBSyxHQUNiOztBQVZILEFBV0UsWUFYVSxBQVdULE9BQU8sQ0FBQyxFQUNQLFVBQVUsRUFBRSxZQUFZLEVBQ3hCLFVBQVUsRUFBRSx1QkFBdUIsRUFDbkMsT0FBTyxFQUFFLEVBQUUsRUFDWCxNQUFNLEVkekpELE1BQUssRWMwSlYsR0FBRyxFQUFFLE9BQW9CLEVBQ3pCLEtBQUssRUFBRSxJQUFJLEdBQ1o7O0FBSUgsQUFBQSxXQUFXLENBQUMsRUFDVixNQUFNLEVkaktDLE1BQUssQ2NpS2UsS0FBSyxDQUFDLFlBQVksRUFDN0MsYUFBYSxFZGxLTixNQUFLLEVjbUtaLFlBQVksRUFBRSxDQUFDLEVBQ2YsVUFBVSxFQUFFLENBQUMsR0FxQmQ7O0FBekJELEFBS0UsV0FMUyxBQUtSLFFBQVEsQ0FBQyxFQUNSLE1BQU0sRWR0S0QsTUFBSyxDY3NLaUIsS0FBSyxDQUFDLFlBQVksRUFDN0MsV0FBVyxFQUFFLENBQUMsRUFDZCxVQUFVLEVBQUUsQ0FBQyxFQUNiLE9BQU8sRUFBRSxFQUFFLEVBQ1gsTUFBTSxFQUFFLElBQUksRUFDWixJQUFJLEVBQUUsSUFBSSxFQUNWLEdBQUcsRUFBRSxLQUFLLEVBQ1YsU0FBUyxFQUFFLHNCQUFzQixDQUFDLGNBQWMsRUFDaEQsS0FBSyxFQUFFLElBQUksR0FDWjs7QUFmSCxBQWdCRSxXQWhCUyxBQWdCUixPQUFPLENBQUMsRUFDUCxNQUFNLEVkakxELE1BQUssQ2NpTGlCLEtBQUssQ0FBQyxZQUFZLEVBQzdDLGFBQWEsRUFBRSxDQUFDLEVBQ2hCLFlBQVksRUFBRSxDQUFDLEVBQ2YsYUFBYSxFQUFFLEtBQUssRUFDcEIsT0FBTyxFQUFFLEVBQUUsRUFDWCxNQUFNLEVBQUUsSUFBSSxFQUNaLEtBQUssRUFBRSxJQUFJLEdBQ1o7O0FBSUgsQUFDRSxVQURRLEFBQ1AsUUFBUSxDQUFDLEVBQ1IsVUFBVSxFQUFFLFlBQVksRUFDeEIsT0FBTyxFQUFFLEVBQUUsRUFDWCxNQUFNLEVBQUUsR0FBRyxFQUNYLElBQUksRUFBRSxHQUFHLEVBQ1QsS0FBSyxFZGxNQSxNQUFLLEdjbU1YOztBQVBILEFBUUUsVUFSUSxBQVFQLE9BQU8sQ0FBQyxFQUNQLE1BQU0sRWRyTUQsTUFBSyxDY3FNaUIsS0FBSyxDQUFDLFlBQVksRUFDN0MsMEJBQTBCLEVkdE1yQixNQUFLLEVjdU1WLFdBQVcsRUFBRSxDQUFDLEVBQ2QsdUJBQXVCLEVkeE1sQixNQUFLLEVjeU1WLE9BQU8sRUFBRSxFQUFFLEVBQ1gsTUFBTSxFQUFFLEtBQUssRUFDYixHQUFHLEVBQUUsR0FBRyxFQUNSLElBQUksRUFBRSxHQUFHLEVBQ1QsS0FBSyxFQUFFLElBQUksR0FDWjs7QUFJSCxBQUNFLGNBRFksQUFDWCxRQUFRLENBQUMsRUFDUixNQUFNLEVkcE5ELE1BQUssQ2NvTmlCLEtBQUssQ0FBQyxZQUFZLEVBQzdDLGFBQWEsRUFBRSxDQUFDLEVBQ2hCLHNCQUFzQixFZHROakIsTUFBSyxFY3VOVix1QkFBdUIsRWR2TmxCLE1BQUssRWN3TlYsT0FBTyxFQUFFLEVBQUUsRUFDWCxNQUFNLEVBQUUsSUFBSSxFQUNaLEtBQUssRUFBRSxJQUFJLEdBQ1o7O0FBVEgsQUFVRSxjQVZZLEFBVVgsT0FBTyxDQUFDLEVBQ1AsTUFBTSxFZDdORCxNQUFLLENjNk5pQixLQUFLLENBQUMsWUFBWSxFQUM3QyxhQUFhLEVBQUUsQ0FBQyxFQUNoQixXQUFXLEVBQUUsQ0FBQyxFQUNkLGFBQWEsRWRoT1IsTUFBSyxFY2lPVixPQUFPLEVBQUUsRUFBRSxFQUNYLE1BQU0sRUFBRSxJQUFJLEVBQ1osU0FBUyxFQUFFLG9CQUFvQixDQUFDLGNBQWMsQ0FBQyxrQkFBa0IsRUFDakUsS0FBSyxFQUFFLElBQUksR0FDWjs7QUFJSCxBQUFBLGNBQWMsRUFDZCxZQUFZLENBQUMsRUFDWCxhQUFhLEVkM09OLE1BQUssQ2MyT3NCLEtBQUssQ0FBQyxZQUFZLEdBaUJyRDs7QUFuQkQsQUFHRSxjQUhZLEFBR1gsUUFBUSxFQUZYLFlBQVksQUFFVCxRQUFRLENBQUMsRUFDUixNQUFNLEVkN09ELE1BQUssQ2M2T2lCLEtBQUssQ0FBQyxZQUFZLEVBQzdDLGFBQWEsRUFBRSxDQUFDLEVBQ2hCLFlBQVksRUFBRSxDQUFDLEVBQ2YsT0FBTyxFQUFFLEVBQUUsRUFDWCxNQUFNLEVBQUUsSUFBSSxFQUNaLEtBQUssRUFBRSxJQUFJLEVBQ1gsU0FBUyxFQUFFLHFCQUFxQixDQUFDLGVBQWUsR0FDakQ7O0FBWEgsQUFZRSxjQVpZLEFBWVgsT0FBTyxFQVhWLFlBQVksQUFXVCxPQUFPLENBQUMsRUFDUCxVQUFVLEVBQUUsWUFBWSxFQUN4QixPQUFPLEVBQUUsRUFBRSxFQUNYLE1BQU0sRUFBRSxJQUFJLEVBQ1osR0FBRyxFQUFFLEdBQUcsRUFDUixLQUFLLEVkMVBBLE1BQUssR2MyUFg7O0FBR0gsQUFDRSxZQURVLEFBQ1QsUUFBUSxDQUFDLEVBQ1IsU0FBUyxFQUFFLHFCQUFxQixDQUFDLGFBQWEsR0FDL0M7O0FBSEgsQUFJRSxZQUpVLEFBSVQsT0FBTyxDQUFDLEVBQ1AsR0FBRyxFQUFFLEdBQUcsR0FDVDs7QUN6VEgsQUFBQSxVQUFVLENBQUMsRUFDVCxNQUFNLEVmb0RDLE1BQUssQ2VwRGUsS0FBSyxDQUFDLFlBQVksRUFDN0MsYUFBYSxFQUFFLEdBQUcsR0FnQm5COztBQWxCRCxBQUdFLFVBSFEsQUFHUCxRQUFRLENBQUMsRUFDUixVQUFVLEVBQUUsWUFBWSxFQUN4QixPQUFPLEVBQUUsRUFBRSxFQUNYLE1BQU0sRUFBRSxJQUFJLEVBQ1osU0FBUyxFQUFFLHFCQUFxQixFQUNoQyxLQUFLLEVmNkNBLE1BQUssR2U1Q1g7O0FBVEgsQUFVRSxVQVZRLEFBVVAsT0FBTyxDQUFDLEVBQ1AsVUFBVSxFQUFFLFlBQVksRUFDeEIsT0FBTyxFQUFFLEVBQUUsRUFDWCxNQUFNLEVBQUUsSUFBSSxFQUNaLFNBQVMsRUFBRSxxQkFBcUIsQ0FBQyxhQUFhLEVBQzlDLGdCQUFnQixFQUFFLE9BQU8sRUFDekIsS0FBSyxFZnFDQSxNQUFLLEdlcENYOztBQUlILEFBQ0UsVUFEUSxBQUNQLFFBQVEsQ0FBQyxFQUNSLE1BQU0sRWY4QkQsTUFBSyxDZTlCaUIsS0FBSyxDQUFDLFlBQVksRUFDN0MsYUFBYSxFZjZCUixNQUFLLEVlNUJWLE9BQU8sRUFBRSxFQUFFLEVBQ1gsTUFBTSxFQUFFLElBQUksRUFDWixLQUFLLEVBQUUsR0FBRyxHQUNYOztBQVBILEFBUUUsVUFSUSxBQVFQLE9BQU8sQ0FBQyxFQUNQLE1BQU0sRWZ1QkQsTUFBSyxDZXZCaUIsS0FBSyxDQUFDLFlBQVksRUFDN0MsWUFBWSxFQUFFLENBQUMsRUFDZixVQUFVLEVBQUUsQ0FBQyxFQUNiLE9BQU8sRUFBRSxFQUFFLEVBQ1gsTUFBTSxFQUFFLElBQUksRUFDWixTQUFTLEVBQUUscUJBQXFCLENBQUMsY0FBYyxDQUFDLGtCQUFrQixFQUNsRSxLQUFLLEVBQUUsSUFBSSxHQUNaOztBQUlILEFBQ0UsWUFEVSxBQUNULFFBQVEsQ0FBQyxFQUNSLE1BQU0sRWZVRCxNQUFLLENlVmlCLEtBQUssQ0FBQyxZQUFZLEVBQzdDLGFBQWEsRUFBRSxHQUFHLEVBQ2xCLE9BQU8sRUFBRSxFQUFFLEVBQ1gsTUFBTSxFQUFFLEtBQUssRUFDYixHQUFHLEVBQUUsR0FBRyxFQUNSLEtBQUssRUFBRSxLQUFLLEdBQ2I7O0FBUkgsQUFTRSxZQVRVLEFBU1QsT0FBTyxDQUFDLEVBQ1AsTUFBTSxFZkVELE1BQUssQ2VGaUIsS0FBSyxDQUFDLFlBQVksRUFDN0MsYUFBYSxFQUFFLFdBQVcsRUFDMUIsT0FBTyxFQUFFLEVBQUUsRUFDWCxNQUFNLEVBQUUsSUFBSSxFQUNaLEdBQUcsRUFBRSxHQUFHLEVBQ1IsS0FBSyxFQUFFLElBQUksR0FDWjs7QUFJSCxBQUFBLGFBQWEsQ0FBQyxFQUNaLE1BQU0sRWZUQyxNQUFLLENlU2UsS0FBSyxDQUFDLFlBQVksRUFDN0MsYUFBYSxFQUFFLENBQUMsRUFDaEIsYUFBYSxFZlhOLE1BQUssRWVZWixZQUFZLEVBQUUsQ0FBQyxHQXNCaEI7O0FBMUJELEFBS0UsYUFMVyxBQUtWLFFBQVEsQ0FBQyxFQUNSLE1BQU0sRWZkRCxNQUFLLENlY2lCLEtBQUssQ0FBQyxZQUFZLEVBQzdDLDBCQUEwQixFZmZyQixNQUFLLEVlZ0JWLFdBQVcsRUFBRSxDQUFDLEVBQ2QsVUFBVSxFQUFFLENBQUMsRUFDYixPQUFPLEVBQUUsRUFBRSxFQUNYLE1BQU0sRUFBRSxJQUFJLEVBQ1osSUFBSSxFQUFFLEdBQUcsRUFDVCxHQUFHLEVBQUUsR0FBRyxFQUNSLEtBQUssRUFBRSxJQUFJLEdBQ1o7O0FBZkgsQUFnQkUsYUFoQlcsQUFnQlYsT0FBTyxDQUFDLEVBQ1AsVUFBVSxFQUFFLFlBQVksRUFDeEIsYUFBYSxFZjFCUixNQUFLLEVlMkJWLE9BQU8sRUFBRSxFQUFFLEVBQ1gsTUFBTSxFQUFFLElBQUksRUFDWixJQUFJLEVBQUUsR0FBRyxFQUNULEdBQUcsRUFBRSxJQUFJLEVBQ1QsU0FBUyxFQUFFLGtCQUFrQixDQUFDLGFBQWEsRUFDM0MsS0FBSyxFZmhDQSxNQUFLLEdlaUNYOztBQUlILEFBQUEsV0FBVyxDQUFDLEVBQ1YsTUFBTSxFZnRDQyxNQUFLLENlc0NlLEtBQUssQ0FBQyxZQUFZLEVBQzdDLGFBQWEsRWZ2Q04sTUFBSyxHZTJEYjs7QUF0QkQsQUFHRSxXQUhTLEFBR1IsUUFBUSxDQUFDLEVBQ1IsTUFBTSxFZnpDRCxNQUFLLENleUNpQixLQUFLLENBQUMsWUFBWSxFQUM3QyxhQUFhLEVBQUUsR0FBRyxFQUNsQixPQUFPLEVBQUUsRUFBRSxFQUNYLE1BQU0sRUFBRSxLQUFLLEVBQ2IsSUFBSSxFQUFFLEdBQUcsRUFDVCxHQUFHLEVBQUUsR0FBRyxFQUNSLEtBQUssRUFBRSxLQUFLLEdBQ2I7O0FBWEgsQUFZRSxXQVpTLEFBWVIsT0FBTyxDQUFDLEVBQ1AsTUFBTSxFZmxERCxNQUFLLENla0RpQixLQUFLLENBQUMsWUFBWSxFQUM3QyxhQUFhLEVBQUUsQ0FBQyxFQUNoQixXQUFXLEVBQUUsQ0FBQyxFQUNkLE9BQU8sRUFBRSxFQUFFLEVBQ1gsTUFBTSxFQUFFLElBQUksRUFDWixJQUFJLEVBQUUsR0FBRyxFQUNULFNBQVMsRUFBRSxvQkFBb0IsQ0FBQyxjQUFjLEVBQzlDLEtBQUssRUFBRSxJQUFJLEdBQ1o7O0FBSUgsQUFDRSxVQURRLEFBQ1AsUUFBUSxFQURYLFVBQVUsQUFFUCxPQUFPLENBQUMsRUFDUCxNQUFNLEVmakVELE1BQUssQ2VpRWlCLEtBQUssQ0FBQyxZQUFZLEVBQzdDLGFBQWEsRUFBRSxXQUFXLEVBQzFCLFlBQVksRUFBRSxDQUFDLEVBQ2YsT0FBTyxFQUFFLEVBQUUsRUFDWCxNQUFNLEVBQUUsSUFBSSxFQUNaLEtBQUssRUFBRSxLQUFLLEdBQ2I7O0FBVEgsQUFVRSxVQVZRLEFBVVAsUUFBUSxDQUFDLEVBQ1IsU0FBUyxFQUFFLHFCQUFxQixDQUFDLGNBQWMsR0FDaEQ7O0FBWkgsQUFhRSxVQWJRLEFBYVAsT0FBTyxDQUFDLEVBQ1AsU0FBUyxFQUFFLHFCQUFxQixDQUFDLGNBQWMsR0FDaEQ7O0FBSUgsQUFDRSxjQURZLEFBQ1gsUUFBUSxDQUFDLEVBQ1IsTUFBTSxFZm5GRCxNQUFLLENlbUZpQixLQUFLLENBQUMsWUFBWSxFQUM3QyxhQUFhLEVBQUUsYUFBYSxFQUM1QixPQUFPLEVBQUUsRUFBRSxFQUNYLE1BQU0sRUFBRSxJQUFJLEVBQ1osU0FBUyxFQUFFLHFCQUFxQixDQUFDLGNBQWMsRUFDL0MsS0FBSyxFQUFFLElBQUksR0FDWjs7QUFSSCxBQVNFLGNBVFksQUFTWCxPQUFPLENBQUMsRUFDUCxNQUFNLEVmM0ZELE1BQUssQ2UyRmlCLEtBQUssQ0FBQyxZQUFZLEVBQzdDLGFBQWEsRUFBRSxHQUFHLEVBQ2xCLE9BQU8sRUFBRSxFQUFFLEVBQ1gsTUFBTSxFQUFFLElBQUksRUFDWixTQUFTLEVBQUUscUJBQXFCLEVBQ2hDLEtBQUssRUFBRSxJQUFJLEdBQ1o7O0FBSUgsQUFBQSxXQUFXLENBQUMsRUFDVixNQUFNLEVmdEdDLE1BQUssQ2VzR2UsS0FBSyxDQUFDLFlBQVksRUFDN0MsYUFBYSxFQUFFLEdBQUcsR0FrQm5COztBQXBCRCxBQUdFLFdBSFMsQUFHUixRQUFRLENBQUMsRUFDUixhQUFhLEVBQUUsR0FBRyxFQUNsQixVQUFVLEVBQUUsMkJBQTJCLEVBQ3ZDLE9BQU8sRUFBRSxFQUFFLEVBQ1gsTUFBTSxFQUFFLElBQUksRUFDWixLQUFLLEVBQUUsSUFBSSxHQUNaOztBQVRILEFBVUUsV0FWUyxBQVVSLE9BQU8sQ0FBQyxFQUNQLE1BQU0sRWZoSEQsTUFBSyxDZWdIaUIsS0FBSyxDQUFDLFlBQVksRUFDN0MsbUJBQW1CLEVBQUUsV0FBVyxFQUNoQyxhQUFhLEVBQUUsR0FBRyxFQUNsQixrQkFBa0IsRUFBRSxXQUFXLEVBQy9CLE9BQU8sRUFBRSxFQUFFLEVBQ1gsTUFBTSxFQUFFLElBQUksRUFDWixTQUFTLEVBQUUscUJBQXFCLENBQUMsZUFBZSxFQUNoRCxLQUFLLEVBQUUsSUFBSSxHQUNaIn0= */ diff --git a/user/plugins/problems/css/spectre-icons.min.css b/user/plugins/problems/css/spectre-icons.min.css new file mode 100644 index 00000000..02c44a49 --- /dev/null +++ b/user/plugins/problems/css/spectre-icons.min.css @@ -0,0 +1 @@ +/*! Spectre.css Icons v0.5.3 | MIT License | github.com/picturepan2/spectre */.icon{font-size:inherit;font-style:normal;position:relative;display:inline-block;box-sizing:border-box;width:1em;height:1em;vertical-align:middle;text-indent:-9999px}.icon::after,.icon::before{position:absolute;top:50%;left:50%;display:block;transform:translate(-50%,-50%)}.icon.icon-2x{font-size:1.6rem}.icon.icon-3x{font-size:2.4rem}.icon.icon-4x{font-size:3.2rem}.accordion .icon,.btn .icon,.menu .icon,.toast .icon{vertical-align:-10%}.btn-lg .icon{vertical-align:-15%}.icon-arrow-down::before,.icon-arrow-left::before,.icon-arrow-right::before,.icon-arrow-up::before,.icon-back::before,.icon-downward::before,.icon-forward::before,.icon-upward::before{width:.65em;height:.65em;content:'';border:.1rem solid currentColor;border-right:0;border-bottom:0}.icon-arrow-down::before{transform:translate(-50%,-75%) rotate(225deg)}.icon-arrow-left::before{transform:translate(-25%,-50%) rotate(-45deg)}.icon-arrow-right::before{transform:translate(-75%,-50%) rotate(135deg)}.icon-arrow-up::before{transform:translate(-50%,-25%) rotate(45deg)}.icon-back::after,.icon-forward::after{width:.8em;height:.1rem;content:'';background:currentColor}.icon-downward::after,.icon-upward::after{width:.1rem;height:.8em;content:'';background:currentColor}.icon-back::after{left:55%}.icon-back::before{transform:translate(-50%,-50%) rotate(-45deg)}.icon-downward::after{top:45%}.icon-downward::before{transform:translate(-50%,-50%) rotate(-135deg)}.icon-forward::after{left:45%}.icon-forward::before{transform:translate(-50%,-50%) rotate(135deg)}.icon-upward::after{top:55%}.icon-upward::before{transform:translate(-50%,-50%) rotate(45deg)}.icon-caret::before{width:0;height:0;content:'';transform:translate(-50%,-25%);border-top:.3em solid currentColor;border-right:.3em solid transparent;border-left:.3em solid transparent}.icon-menu::before{width:100%;height:.1rem;content:'';background:currentColor;box-shadow:0 -.35em,0 .35em}.icon-apps::before{width:3px;height:3px;content:'';background:currentColor;box-shadow:-.35em -.35em,-.35em 0,-.35em .35em,0 -.35em,0 .35em,.35em -.35em,.35em 0,.35em .35em}.icon-resize-horiz::after,.icon-resize-horiz::before,.icon-resize-vert::after,.icon-resize-vert::before{width:.45em;height:.45em;content:'';border:.1rem solid currentColor;border-right:0;border-bottom:0}.icon-resize-horiz::before,.icon-resize-vert::before{transform:translate(-50%,-90%) rotate(45deg)}.icon-resize-horiz::after,.icon-resize-vert::after{transform:translate(-50%,-10%) rotate(225deg)}.icon-resize-horiz::before{transform:translate(-90%,-50%) rotate(-45deg)}.icon-resize-horiz::after{transform:translate(-10%,-50%) rotate(135deg)}.icon-more-horiz::before,.icon-more-vert::before{width:3px;height:3px;content:'';border-radius:50%;background:currentColor;box-shadow:-.4em 0,.4em 0}.icon-more-vert::before{box-shadow:0 -.4em,0 .4em}.icon-cross::before,.icon-minus::before,.icon-plus::before{width:100%;height:.1rem;content:'';background:currentColor}.icon-cross::after,.icon-plus::after{width:.1rem;height:100%;content:'';background:currentColor}.icon-cross::before{width:100%}.icon-cross::after{height:100%}.icon-cross::after,.icon-cross::before{transform:translate(-50%,-50%) rotate(45deg)}.icon-check::before{width:.9em;height:.5em;content:'';transform:translate(-50%,-75%) rotate(-45deg);border:.1rem solid currentColor;border-top:0;border-right:0}.icon-stop{border:.1rem solid currentColor;border-radius:50%}.icon-stop::before{width:1em;height:.1rem;content:'';transform:translate(-50%,-50%) rotate(45deg);background:currentColor}.icon-shutdown{border:.1rem solid currentColor;border-top-color:transparent;border-radius:50%}.icon-shutdown::before{top:.1em;width:.1rem;height:.5em;content:'';background:currentColor}.icon-refresh::before{width:1em;height:1em;content:'';border:.1rem solid currentColor;border-right-color:transparent;border-radius:50%}.icon-refresh::after{top:20%;left:80%;width:0;height:0;content:'';border:.2em solid currentColor;border-top-color:transparent;border-left-color:transparent}.icon-search::before{top:5%;left:5%;width:.75em;height:.75em;content:'';transform:translate(0,0) rotate(45deg);border:.1rem solid currentColor;border-radius:50%}.icon-search::after{top:80%;left:80%;width:.4em;height:.1rem;content:'';transform:translate(-50%,-50%) rotate(45deg);background:currentColor}.icon-edit::before{width:.85em;height:.4em;content:'';transform:translate(-40%,-60%) rotate(-45deg);border:.1rem solid currentColor}.icon-edit::after{top:95%;left:5%;width:0;height:0;content:'';transform:translate(0,-100%);border:.15em solid currentColor;border-top-color:transparent;border-right-color:transparent}.icon-delete::before{top:60%;width:.75em;height:.75em;content:'';border:.1rem solid currentColor;border-top:0;border-bottom-right-radius:.1rem;border-bottom-left-radius:.1rem}.icon-delete::after{top:.05rem;width:.5em;height:.1rem;content:'';background:currentColor;box-shadow:-.25em .2em,.25em .2em}.icon-share{border:.1rem solid currentColor;border-top:0;border-right:0;border-radius:.1rem}.icon-share::before{top:.25em;left:100%;width:.4em;height:.4em;content:'';transform:translate(-125%,-50%) rotate(-45deg);border:.1rem solid currentColor;border-top:0;border-left:0}.icon-share::after{width:.6em;height:.5em;content:'';border:.1rem solid currentColor;border-right:0;border-bottom:0;border-radius:75% 0}.icon-flag::before{left:15%;width:.1rem;height:1em;content:'';background:currentColor}.icon-flag::after{top:35%;left:60%;width:.8em;height:.65em;content:'';border:.1rem solid currentColor;border-left:0;border-top-right-radius:.1rem;border-bottom-right-radius:.1rem}.icon-bookmark::before{width:.8em;height:.9em;content:'';border:.1rem solid currentColor;border-bottom:0;border-top-left-radius:.1rem;border-top-right-radius:.1rem}.icon-bookmark::after{width:.5em;height:.5em;content:'';transform:translate(-50%,35%) rotate(-45deg) skew(15deg,15deg);border:.1rem solid currentColor;border-bottom:0;border-left:0;border-radius:.1rem}.icon-download,.icon-upload{border-bottom:.1rem solid currentColor}.icon-download::before,.icon-upload::before{width:.5em;height:.5em;content:'';transform:translate(-50%,-60%) rotate(-135deg);border:.1rem solid currentColor;border-right:0;border-bottom:0}.icon-download::after,.icon-upload::after{top:40%;width:.1rem;height:.6em;content:'';background:currentColor}.icon-upload::before{transform:translate(-50%,-60%) rotate(45deg)}.icon-upload::after{top:50%}.icon-time{border:.1rem solid currentColor;border-radius:50%}.icon-time::before{width:.1rem;height:.4em;content:'';transform:translate(-50%,-75%);background:currentColor}.icon-time::after{width:.1rem;height:.3em;content:'';transform:translate(-50%,-75%) rotate(90deg);transform-origin:50% 90%;background:currentColor}.icon-mail::before{width:1em;height:.8em;content:'';border:.1rem solid currentColor;border-radius:.1rem}.icon-mail::after{width:.5em;height:.5em;content:'';transform:translate(-50%,-90%) rotate(-45deg) skew(10deg,10deg);border:.1rem solid currentColor;border-top:0;border-right:0}.icon-people::before{top:25%;width:.45em;height:.45em;content:'';border:.1rem solid currentColor;border-radius:50%}.icon-people::after{top:75%;width:.9em;height:.4em;content:'';border:.1rem solid currentColor;border-radius:50% 50% 0 0}.icon-message{border:.1rem solid currentColor;border-right:0;border-bottom:0;border-radius:.1rem}.icon-message::before{top:40%;left:65%;width:.7em;height:.8em;content:'';border:.1rem solid currentColor;border-top:0;border-left:0;border-bottom-right-radius:.1rem}.icon-message::after{top:100%;left:10%;width:.1rem;height:.3em;content:'';transform:translate(0,-90%) rotate(45deg);border-radius:.1rem;background:currentColor}.icon-photo{border:.1rem solid currentColor;border-radius:.1rem}.icon-photo::before{top:35%;left:35%;width:.25em;height:.25em;content:'';border:.1rem solid currentColor;border-radius:50%}.icon-photo::after{left:60%;width:.5em;height:.5em;content:'';transform:translate(-50%,25%) rotate(-45deg);border:.1rem solid currentColor;border-bottom:0;border-left:0}.icon-link::after,.icon-link::before{width:.75em;height:.5em;content:'';border:.1rem solid currentColor;border-right:0;border-radius:5em 0 0 5em}.icon-link::before{transform:translate(-70%,-45%) rotate(-45deg)}.icon-link::after{transform:translate(-30%,-55%) rotate(135deg)}.icon-location::before{width:.8em;height:.8em;content:'';transform:translate(-50%,-60%) rotate(-45deg);border:.1rem solid currentColor;border-radius:50% 50% 50% 0}.icon-location::after{width:.2em;height:.2em;content:'';transform:translate(-50%,-80%);border:.1rem solid currentColor;border-radius:50%}.icon-emoji{border:.1rem solid currentColor;border-radius:50%}.icon-emoji::before{width:.1em;height:.1em;content:'';border-radius:50%;box-shadow:-.17em -.15em,.17em -.15em}.icon-emoji::after{width:.5em;height:.5em;content:'';transform:translate(-50%,-40%) rotate(-135deg);border:.1rem solid currentColor;border-right-color:transparent;border-bottom-color:transparent;border-radius:50%} \ No newline at end of file diff --git a/user/plugins/problems/css/spectre.css b/user/plugins/problems/css/spectre.css new file mode 100644 index 00000000..9be56da6 --- /dev/null +++ b/user/plugins/problems/css/spectre.css @@ -0,0 +1,1278 @@ +/*! Spectre.css v0.5.3 | MIT License | github.com/picturepan2/spectre */ +/* Manually forked from Normalize.css */ +/* normalize.css v5.0.0 | MIT License | github.com/necolas/normalize.css */ +/** 1. Change the default font family in all browsers (opinionated). 2. Correct the line height in all browsers. 3. Prevent adjustments of font size after orientation changes in IE on Windows Phone and in iOS. */ +/* Document ========================================================================== */ +html { font-family: sans-serif; /* 1 */ -ms-text-size-adjust: 100%; /* 3 */ -webkit-text-size-adjust: 100%; /* 3 */ } + +/* Sections ========================================================================== */ +/** Remove the margin in all browsers (opinionated). */ +body { margin: 0; } + +/** Add the correct display in IE 9-. */ +article, aside, footer, header, nav, section { display: block; } + +/** Correct the font size and margin on `h1` elements within `section` and `article` contexts in Chrome, Firefox, and Safari. */ +h1 { font-size: 2em; margin: 0.67em 0; } + +/* Grouping content ========================================================================== */ +/** Add the correct display in IE 9-. 1. Add the correct display in IE. */ +figcaption, figure, main { /* 1 */ display: block; } + +/** Add the correct margin in IE 8 (removed). */ +/** 1. Add the correct box sizing in Firefox. 2. Show the overflow in Edge and IE. */ +hr { box-sizing: content-box; /* 1 */ height: 0; /* 1 */ overflow: visible; /* 2 */ } + +/** 1. Correct the inheritance and scaling of font size in all browsers. (removed) 2. Correct the odd `em` font sizing in all browsers. */ +/* Text-level semantics ========================================================================== */ +/** 1. Remove the gray background on active links in IE 10. 2. Remove gaps in links underline in iOS 8+ and Safari 8+. */ +a { background-color: transparent; /* 1 */ -webkit-text-decoration-skip: objects; /* 2 */ } + +/** Remove the outline on focused links when they are also active or hovered in all browsers (opinionated). */ +a:active, a:hover { outline-width: 0; } + +/** Modify default styling of address. */ +address { font-style: normal; } + +/** 1. Remove the bottom border in Firefox 39-. 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari. (removed) */ +/** Prevent the duplicate application of `bolder` by the next rule in Safari 6. */ +b, strong { font-weight: inherit; } + +/** Add the correct font weight in Chrome, Edge, and Safari. */ +b, strong { font-weight: bolder; } + +/** 1. Correct the inheritance and scaling of font size in all browsers. 2. Correct the odd `em` font sizing in all browsers. */ +code, kbd, pre, samp { font-family: "SF Mono", "Segoe UI Mono", "Roboto Mono", Menlo, Courier, monospace; /* 1 (changed) */ font-size: 1em; /* 2 */ } + +/** Add the correct font style in Android 4.3-. */ +dfn { font-style: italic; } + +/** Add the correct background and color in IE 9-. (Removed) */ +/** Add the correct font size in all browsers. */ +small { font-size: 80%; font-weight: 400; /* (added) */ } + +/** Prevent `sub` and `sup` elements from affecting the line height in all browsers. */ +sub, sup { font-size: 75%; line-height: 0; position: relative; vertical-align: baseline; } + +sub { bottom: -0.25em; } + +sup { top: -0.5em; } + +/* Embedded content ========================================================================== */ +/** Add the correct display in IE 9-. */ +audio, video { display: inline-block; } + +/** Add the correct display in iOS 4-7. */ +audio:not([controls]) { display: none; height: 0; } + +/** Remove the border on images inside links in IE 10-. */ +img { border-style: none; } + +/** Hide the overflow in IE. */ +svg:not(:root) { overflow: hidden; } + +/* Forms ========================================================================== */ +/** 1. Change the font styles in all browsers (opinionated). 2. Remove the margin in Firefox and Safari. */ +button, input, optgroup, select, textarea { font-family: inherit; /* 1 (changed) */ font-size: inherit; /* 1 (changed) */ line-height: inherit; /* 1 (changed) */ margin: 0; /* 2 */ } + +/** Show the overflow in IE. 1. Show the overflow in Edge. */ +button, input { /* 1 */ overflow: visible; } + +/** Remove the inheritance of text transform in Edge, Firefox, and IE. 1. Remove the inheritance of text transform in Firefox. */ +button, select { /* 1 */ text-transform: none; } + +/** 1. Prevent a WebKit bug where (2) destroys native `audio` and `video` controls in Android 4. 2. Correct the inability to style clickable types in iOS and Safari. */ +button, html [type="button"], [type="reset"], [type="submit"] { -webkit-appearance: button; /* 2 */ } + +/** Remove the inner border and padding in Firefox. */ +button::-moz-focus-inner, [type="button"]::-moz-focus-inner, [type="reset"]::-moz-focus-inner, [type="submit"]::-moz-focus-inner { border-style: none; padding: 0; } + +/** Restore the focus styles unset by the previous rule (removed). */ +/** Change the border, margin, and padding in all browsers (opinionated) (changed). */ +fieldset { border: 0; margin: 0; padding: 0; } + +/** 1. Correct the text wrapping in Edge and IE. 2. Correct the color inheritance from `fieldset` elements in IE. 3. Remove the padding so developers are not caught out when they zero out `fieldset` elements in all browsers. */ +legend { box-sizing: border-box; /* 1 */ color: inherit; /* 2 */ display: table; /* 1 */ max-width: 100%; /* 1 */ padding: 0; /* 3 */ white-space: normal; /* 1 */ } + +/** 1. Add the correct display in IE 9-. 2. Add the correct vertical alignment in Chrome, Firefox, and Opera. */ +progress { display: inline-block; /* 1 */ vertical-align: baseline; /* 2 */ } + +/** Remove the default vertical scrollbar in IE. */ +textarea { overflow: auto; } + +/** 1. Add the correct box sizing in IE 10-. 2. Remove the padding in IE 10-. */ +[type="checkbox"], [type="radio"] { box-sizing: border-box; /* 1 */ padding: 0; /* 2 */ } + +/** Correct the cursor style of increment and decrement buttons in Chrome. */ +[type="number"]::-webkit-inner-spin-button, [type="number"]::-webkit-outer-spin-button { height: auto; } + +/** 1. Correct the odd appearance in Chrome and Safari. 2. Correct the outline style in Safari. */ +[type="search"] { -webkit-appearance: textfield; /* 1 */ outline-offset: -2px; /* 2 */ } + +/** Remove the inner padding and cancel buttons in Chrome and Safari on macOS. */ +[type="search"]::-webkit-search-cancel-button, [type="search"]::-webkit-search-decoration { -webkit-appearance: none; } + +/** 1. Correct the inability to style clickable types in iOS and Safari. 2. Change font properties to `inherit` in Safari. */ +::-webkit-file-upload-button { -webkit-appearance: button; /* 1 */ font: inherit; /* 2 */ } + +/* Interactive ========================================================================== */ +/* Add the correct display in IE 9-. 1. Add the correct display in Edge, IE, and Firefox. */ +details, menu { display: block; } + +/* Add the correct display in all browsers. */ +summary { display: list-item; outline: none; } + +/* Scripting ========================================================================== */ +/** Add the correct display in IE 9-. */ +canvas { display: inline-block; } + +/** Add the correct display in IE. */ +template { display: none; } + +/* Hidden ========================================================================== */ +/** Add the correct display in IE 10-. */ +[hidden] { display: none; } + +*, *::before, *::after { box-sizing: inherit; } + +html { box-sizing: border-box; font-size: 20px; line-height: 1.5; -webkit-tap-highlight-color: transparent; } + +body { background: #fff; color: #50596c; font-family: -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", sans-serif; font-size: 0.8rem; overflow-x: hidden; text-rendering: optimizeLegibility; } + +a { color: #0074D9; outline: none; text-decoration: none; } + +a:focus { box-shadow: 0 0 0 0.1rem rgba(0, 116, 217, 0.2); } + +a:focus, a:hover, a:active, a.active { color: #0059a6; text-decoration: underline; } + +a:visited { color: #0d8eff; } + +h1, h2, h3, h4, h5, h6 { color: inherit; font-weight: 500; line-height: 1.2; margin-bottom: .5em; margin-top: 0; } + +.h1, .h2, .h3, .h4, .h5, .h6 { font-weight: 500; } + +h1, .h1 { font-size: 2rem; } + +h2, .h2 { font-size: 1.6rem; } + +h3, .h3 { font-size: 1.4rem; } + +h4, .h4 { font-size: 1.2rem; } + +h5, .h5 { font-size: 1rem; } + +h6, .h6 { font-size: .8rem; } + +p { margin: 0 0 1.2rem; } + +a, ins, u { -webkit-text-decoration-skip: ink edges; text-decoration-skip: ink edges; } + +abbr[title] { border-bottom: 0.05rem dotted; cursor: help; text-decoration: none; } + +kbd { border-radius: 0.1rem; line-height: 1.2; padding: .1rem .2rem; background: #454d5d; color: #fff; font-size: 0.7rem; } + +mark { background: #ffe9b3; color: #50596c; border-radius: 0.1rem; padding: .05rem; } + +blockquote { border-left: 0.1rem solid #e7e9ed; margin-left: 0; padding: 0.4rem 0.8rem; } + +blockquote p:last-child { margin-bottom: 0; } + +ul, ol { margin: 0.8rem 0 0.8rem 0.8rem; padding: 0; } + +ul ul, ul ol, ol ul, ol ol { margin: 0.8rem 0 0.8rem 0.8rem; } + +ul li, ol li { margin-top: 0.4rem; } + +ul { list-style: disc inside; } + +ul ul { list-style-type: circle; } + +ol { list-style: decimal inside; } + +ol ol { list-style-type: lower-alpha; } + +dl dt { font-weight: bold; } + +dl dd { margin: 0.4rem 0 0.8rem 0; } + +:lang(zh), :lang(zh-Hans) { font-family: -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", Roboto, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", sans-serif; } + +:lang(zh-Hant) { font-family: -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", Roboto, "PingFang TC", "Hiragino Sans CNS", "Microsoft JhengHei", "Helvetica Neue", sans-serif; } + +:lang(ja) { font-family: -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", Roboto, "Hiragino Sans", "Hiragino Kaku Gothic Pro", "Yu Gothic", YuGothic, Meiryo, "Helvetica Neue", sans-serif; } + +:lang(ko) { font-family: -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", Roboto, "Malgun Gothic", "Helvetica Neue", sans-serif; } + +:lang(zh) ins, :lang(zh) u, :lang(ja) ins, :lang(ja) u, .cjk ins, .cjk u { border-bottom: 0.05rem solid; text-decoration: none; } + +:lang(zh) del + del, :lang(zh) del + s, :lang(zh) ins + ins, :lang(zh) ins + u, :lang(zh) s + del, :lang(zh) s + s, :lang(zh) u + ins, :lang(zh) u + u, :lang(ja) del + del, :lang(ja) del + s, :lang(ja) ins + ins, :lang(ja) ins + u, :lang(ja) s + del, :lang(ja) s + s, :lang(ja) u + ins, :lang(ja) u + u, .cjk del + del, .cjk del + s, .cjk ins + ins, .cjk ins + u, .cjk s + del, .cjk s + s, .cjk u + ins, .cjk u + u { margin-left: .125em; } + +.table { border-collapse: collapse; border-spacing: 0; width: 100%; text-align: left; } + +.table.table-striped tbody tr:nth-of-type(odd) { background: #f8f9fa; } + +.table tbody tr.active, .table.table-striped tbody tr.active { background: #f0f1f4; } + +.table.table-hover tbody tr:hover { background: #f0f1f4; } + +.table.table-scroll { display: block; overflow-x: auto; padding-bottom: .75rem; white-space: nowrap; } + +.table td, .table th { border-bottom: 0.05rem solid #e7e9ed; padding: 0.6rem 0.4rem; } + +.table th { border-bottom-width: 0.1rem; } + +.btn { transition: all .2s ease; -webkit-appearance: none; -moz-appearance: none; appearance: none; background: #fff; border: 0.05rem solid #0074D9; border-radius: 0.1rem; color: #0074D9; cursor: pointer; display: inline-block; font-size: 0.8rem; height: 1.8rem; line-height: 1.2rem; outline: none; padding: 0.25rem 0.4rem; text-align: center; text-decoration: none; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; vertical-align: middle; white-space: nowrap; } + +.btn:focus { box-shadow: 0 0 0 0.1rem rgba(0, 116, 217, 0.2); } + +.btn:focus, .btn:hover { background: #99d0ff; border-color: #006cca; text-decoration: none; } + +.btn:active, .btn.active { background: #006cca; border-color: #005eb0; color: #fff; text-decoration: none; } + +.btn:active.loading::after, .btn.active.loading::after { border-bottom-color: #fff; border-left-color: #fff; } + +.btn[disabled], .btn:disabled, .btn.disabled { cursor: default; opacity: .5; pointer-events: none; } + +.btn.btn-primary { background: #0074D9; border-color: #006cca; color: #fff; } + +.btn.btn-primary:focus, .btn.btn-primary:hover { background: #0066c0; border-color: #005eb0; color: #fff; } + +.btn.btn-primary:active, .btn.btn-primary.active { background: #0061b5; border-color: #0059a6; color: #fff; } + +.btn.btn-primary.loading::after { border-bottom-color: #fff; border-left-color: #fff; } + +.btn.btn-success { background: #2ECC40; border-color: #2bc03c; color: #fff; } + +.btn.btn-success:focus { box-shadow: 0 0 0 0.1rem rgba(46, 204, 64, 0.2); } + +.btn.btn-success:focus, .btn.btn-success:hover { background: #2cc43d; border-color: #29b739; color: #fff; } + +.btn.btn-success:active, .btn.btn-success.active { background: #27af37; border-color: #25a233; color: #fff; } + +.btn.btn-success.loading::after { border-bottom-color: #fff; border-left-color: #fff; } + +.btn.btn-error { background: #FF4136; border-color: #ff3327; color: #fff; } + +.btn.btn-error:focus { box-shadow: 0 0 0 0.1rem rgba(255, 65, 54, 0.2); } + +.btn.btn-error:focus, .btn.btn-error:hover { background: #ff372c; border-color: #ff291d; color: #fff; } + +.btn.btn-error:active, .btn.btn-error.active { background: #ff1f12; border-color: #ff1103; color: #fff; } + +.btn.btn-error.loading::after { border-bottom-color: #fff; border-left-color: #fff; } + +.btn.btn-warning { background: #FF851B; border-color: #ff7d0c; color: #fff; } + +.btn.btn-warning:focus { box-shadow: 0 0 0 0.1rem rgba(255, 133, 27, 0.2); } + +.btn.btn-warning:focus, .btn.btn-warning:hover { background: #ff8011; border-color: #ff7702; color: #fff; } + +.btn.btn-warning:active, .btn.btn-warning.active { background: #f67300; border-color: #e76b00; color: #fff; } + +.btn.btn-warning.loading::after { border-bottom-color: #fff; border-left-color: #fff; } + +.btn.btn-link { background: transparent; border-color: transparent; color: #0074D9; } + +.btn.btn-link:focus, .btn.btn-link:hover, .btn.btn-link:active, .btn.btn-link.active { color: #0059a6; } + +.btn.btn-sm { font-size: 0.7rem; height: 1.4rem; padding: 0.05rem 0.3rem; } + +.btn.btn-lg { font-size: 0.9rem; height: 2rem; padding: 0.35rem 0.6rem; } + +.btn.btn-block { display: block; width: 100%; } + +.btn.btn-action { width: 1.8rem; padding-left: 0; padding-right: 0; } + +.btn.btn-action.btn-sm { width: 1.4rem; } + +.btn.btn-action.btn-lg { width: 2rem; } + +.btn.btn-clear { background: transparent; border: 0; color: currentColor; height: 0.8rem; line-height: 0.8rem; margin-left: 0.2rem; margin-right: -2px; opacity: 1; padding: 0; text-decoration: none; width: 0.8rem; } + +.btn.btn-clear:hover { opacity: .95; } + +.btn.btn-clear::before { content: "\2715"; } + +.btn-group { display: -ms-inline-flexbox; display: inline-flex; -ms-flex-wrap: wrap; flex-wrap: wrap; } + +.btn-group .btn { -ms-flex: 1 0 auto; flex: 1 0 auto; } + +.btn-group .btn:first-child:not(:last-child) { border-bottom-right-radius: 0; border-top-right-radius: 0; } + +.btn-group .btn:not(:first-child):not(:last-child) { border-radius: 0; margin-left: -0.05rem; } + +.btn-group .btn:last-child:not(:first-child) { border-bottom-left-radius: 0; border-top-left-radius: 0; margin-left: -0.05rem; } + +.btn-group .btn:focus, .btn-group .btn:hover, .btn-group .btn:active, .btn-group .btn.active { z-index: 1; } + +.btn-group.btn-group-block { display: -ms-flexbox; display: flex; } + +.btn-group.btn-group-block .btn { -ms-flex: 1 0 0px; flex: 1 0 0; } + +.form-group:not(:last-child) { margin-bottom: 0.4rem; } + +fieldset { margin-bottom: 0.8rem; } + +legend { font-size: 0.9rem; font-weight: 500; margin-bottom: 0.8rem; } + +.form-label { display: block; line-height: 1.2rem; padding: 0.3rem 0; } + +.form-label.label-sm { font-size: 0.7rem; padding: 0.1rem 0; } + +.form-label.label-lg { font-size: 0.9rem; padding: 0.4rem 0; } + +.form-input { transition: all .2s ease; -webkit-appearance: none; -moz-appearance: none; appearance: none; background: #fff; background-image: none; border: 0.05rem solid #caced7; border-radius: 0.1rem; color: #50596c; display: block; font-size: 0.8rem; height: 1.8rem; line-height: 1.2rem; max-width: 100%; outline: none; padding: 0.25rem 0.4rem; position: relative; width: 100%; } + +.form-input:focus { box-shadow: 0 0 0 0.1rem rgba(0, 116, 217, 0.2); border-color: #0074D9; } + +.form-input::-webkit-input-placeholder { color: #acb3c2; } + +.form-input:-ms-input-placeholder { color: #acb3c2; } + +.form-input::-ms-input-placeholder { color: #acb3c2; } + +.form-input::placeholder { color: #acb3c2; } + +.form-input.input-sm { font-size: 0.7rem; height: 1.4rem; padding: 0.05rem 0.3rem; } + +.form-input.input-lg { font-size: 0.9rem; height: 2rem; padding: 0.35rem 0.6rem; } + +.form-input.input-inline { display: inline-block; vertical-align: middle; width: auto; } + +.form-input[type="file"] { height: auto; } + +textarea.form-input { height: auto; } + +.form-input-hint { color: #acb3c2; font-size: 0.7rem; margin-top: 0.2rem; } + +.has-success .form-input-hint, .is-success + .form-input-hint { color: #2ECC40; } + +.has-error .form-input-hint, .is-error + .form-input-hint { color: #FF4136; } + +.form-select { -webkit-appearance: none; -moz-appearance: none; appearance: none; border: 0.05rem solid #caced7; border-radius: 0.1rem; color: inherit; font-size: 0.8rem; height: 1.8rem; line-height: 1.2rem; outline: none; padding: 0.25rem 0.4rem; vertical-align: middle; width: 100%; } + +.form-select[size], .form-select[multiple] { height: auto; } + +.form-select[size] option, .form-select[multiple] option { padding: 0.1rem 0.2rem; } + +.form-select:not([multiple]):not([size]) { background: #fff url("data:image/svg+xml;charset=utf8,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%204%205'%3E%3Cpath%20fill='%23667189'%20d='M2%200L0%202h4zm0%205L0%203h4z'/%3E%3C/svg%3E") no-repeat right 0.35rem center/0.4rem 0.5rem; padding-right: 1.2rem; } + +.form-select:focus { box-shadow: 0 0 0 0.1rem rgba(0, 116, 217, 0.2); border-color: #0074D9; } + +.form-select::-ms-expand { display: none; } + +.form-select.select-sm { font-size: 0.7rem; height: 1.4rem; padding: 0.05rem 1.1rem 0.05rem 0.3rem; } + +.form-select.select-lg { font-size: 0.9rem; height: 2rem; padding: 0.35rem 1.4rem 0.35rem 0.6rem; } + +.has-icon-left, .has-icon-right { position: relative; } + +.has-icon-left .form-icon, .has-icon-right .form-icon { height: 0.8rem; margin: 0 0.25rem; position: absolute; top: 50%; transform: translateY(-50%); width: 0.8rem; z-index: 2; } + +.has-icon-left .form-icon { left: 0.05rem; } + +.has-icon-left .form-input { padding-left: 1.3rem; } + +.has-icon-right .form-icon { right: 0.05rem; } + +.has-icon-right .form-input { padding-right: 1.3rem; } + +.form-checkbox, .form-radio, .form-switch { display: block; line-height: 1.2rem; margin: 0.2rem 0; min-height: 1.2rem; padding: 0.1rem 0.4rem 0.1rem 1.2rem; position: relative; } + +.form-checkbox input, .form-radio input, .form-switch input { clip: rect(0, 0, 0, 0); height: 1px; margin: -1px; overflow: hidden; position: absolute; width: 1px; } + +.form-checkbox input:focus + .form-icon, .form-radio input:focus + .form-icon, .form-switch input:focus + .form-icon { box-shadow: 0 0 0 0.1rem rgba(0, 116, 217, 0.2); border-color: #0074D9; } + +.form-checkbox input:checked + .form-icon, .form-radio input:checked + .form-icon, .form-switch input:checked + .form-icon { background: #0074D9; border-color: #0074D9; } + +.form-checkbox .form-icon, .form-radio .form-icon, .form-switch .form-icon { transition: all .2s ease; border: 0.05rem solid #caced7; cursor: pointer; display: inline-block; position: absolute; } + +.form-checkbox.input-sm, .form-radio.input-sm, .form-switch.input-sm { font-size: 0.7rem; margin: 0; } + +.form-checkbox.input-lg, .form-radio.input-lg, .form-switch.input-lg { font-size: 0.9rem; margin: 0.3rem 0; } + +.form-checkbox .form-icon, .form-radio .form-icon { background: #fff; height: 0.8rem; left: 0; top: 0.3rem; width: 0.8rem; } + +.form-checkbox input:active + .form-icon, .form-radio input:active + .form-icon { background: #f0f1f4; } + +.form-checkbox .form-icon { border-radius: 0.1rem; } + +.form-checkbox input:checked + .form-icon::before { background-clip: padding-box; border: 0.1rem solid #fff; border-left-width: 0; border-top-width: 0; content: ""; height: 12px; left: 50%; margin-left: -4px; margin-top: -8px; position: absolute; top: 50%; transform: rotate(45deg); width: 8px; } + +.form-checkbox input:indeterminate + .form-icon { background: #0074D9; border-color: #0074D9; } + +.form-checkbox input:indeterminate + .form-icon::before { background: #fff; content: ""; height: 2px; left: 50%; margin-left: -5px; margin-top: -1px; position: absolute; top: 50%; width: 10px; } + +.form-radio .form-icon { border-radius: 50%; } + +.form-radio input:checked + .form-icon::before { background: #fff; border-radius: 50%; content: ""; height: 4px; left: 50%; position: absolute; top: 50%; transform: translate(-50%, -50%); width: 4px; } + +.form-switch { padding-left: 2rem; } + +.form-switch .form-icon { background: #e7e9ed; background-clip: padding-box; border-radius: 0.45rem; height: 0.9rem; left: 0; top: 0.25rem; width: 1.6rem; } + +.form-switch .form-icon::before { transition: all .2s ease; background: #fff; border-radius: 50%; content: ""; display: block; height: 0.8rem; left: 0; position: absolute; top: 0; width: 0.8rem; } + +.form-switch input:checked + .form-icon::before { left: 14px; } + +.form-switch input:active + .form-icon::before { background: #f8f9fa; } + +.input-group { display: -ms-flexbox; display: flex; } + +.input-group .input-group-addon { background: #f8f9fa; border: 0.05rem solid #caced7; border-radius: 0.1rem; line-height: 1.2rem; padding: 0.25rem 0.4rem; white-space: nowrap; } + +.input-group .input-group-addon.addon-sm { font-size: 0.7rem; padding: 0.05rem 0.3rem; } + +.input-group .input-group-addon.addon-lg { font-size: 0.9rem; padding: 0.35rem 0.6rem; } + +.input-group .form-input, .input-group .form-select { -ms-flex: 1 1 auto; flex: 1 1 auto; width: 1%; } + +.input-group .input-group-btn { z-index: 1; } + +.input-group .form-input:first-child:not(:last-child), .input-group .form-select:first-child:not(:last-child), .input-group .input-group-addon:first-child:not(:last-child), .input-group .input-group-btn:first-child:not(:last-child) { border-bottom-right-radius: 0; border-top-right-radius: 0; } + +.input-group .form-input:not(:first-child):not(:last-child), .input-group .form-select:not(:first-child):not(:last-child), .input-group .input-group-addon:not(:first-child):not(:last-child), .input-group .input-group-btn:not(:first-child):not(:last-child) { border-radius: 0; margin-left: -0.05rem; } + +.input-group .form-input:last-child:not(:first-child), .input-group .form-select:last-child:not(:first-child), .input-group .input-group-addon:last-child:not(:first-child), .input-group .input-group-btn:last-child:not(:first-child) { border-bottom-left-radius: 0; border-top-left-radius: 0; margin-left: -0.05rem; } + +.input-group .form-input:focus, .input-group .form-select:focus, .input-group .input-group-addon:focus, .input-group .input-group-btn:focus { z-index: 2; } + +.input-group .form-select { width: auto; } + +.input-group.input-inline { display: -ms-inline-flexbox; display: inline-flex; } + +.has-success .form-input, .form-input.is-success, .has-success .form-select, .form-select.is-success { border-color: #2ECC40; } + +.has-success .form-input:focus, .form-input.is-success:focus, .has-success .form-select:focus, .form-select.is-success:focus { box-shadow: 0 0 0 0.1rem rgba(46, 204, 64, 0.2); } + +.has-error .form-input, .form-input.is-error, .has-error .form-select, .form-select.is-error { border-color: #FF4136; } + +.has-error .form-input:focus, .form-input.is-error:focus, .has-error .form-select:focus, .form-select.is-error:focus { box-shadow: 0 0 0 0.1rem rgba(255, 65, 54, 0.2); } + +.has-error .form-checkbox .form-icon, .form-checkbox.is-error .form-icon, .has-error .form-radio .form-icon, .form-radio.is-error .form-icon, .has-error .form-switch .form-icon, .form-switch.is-error .form-icon { border-color: #FF4136; } + +.has-error .form-checkbox input:checked + .form-icon, .form-checkbox.is-error input:checked + .form-icon, .has-error .form-radio input:checked + .form-icon, .form-radio.is-error input:checked + .form-icon, .has-error .form-switch input:checked + .form-icon, .form-switch.is-error input:checked + .form-icon { background: #FF4136; border-color: #FF4136; } + +.has-error .form-checkbox input:focus + .form-icon, .form-checkbox.is-error input:focus + .form-icon, .has-error .form-radio input:focus + .form-icon, .form-radio.is-error input:focus + .form-icon, .has-error .form-switch input:focus + .form-icon, .form-switch.is-error input:focus + .form-icon { box-shadow: 0 0 0 0.1rem rgba(255, 65, 54, 0.2); border-color: #FF4136; } + +.has-error .form-checkbox input:indeterminate + .form-icon, .form-checkbox.is-error input:indeterminate + .form-icon { background: #FF4136; border-color: #FF4136; } + +.form-input:not(:placeholder-shown):invalid { border-color: #FF4136; } + +.form-input:not(:placeholder-shown):invalid:focus { box-shadow: 0 0 0 0.1rem rgba(255, 65, 54, 0.2); } + +.form-input:not(:placeholder-shown):invalid + .form-input-hint { color: #FF4136; } + +.form-input:disabled, .form-input.disabled, .form-select:disabled, .form-select.disabled { background-color: #f0f1f4; cursor: not-allowed; opacity: .5; } + +.form-input[readonly] { background-color: #f8f9fa; } + +input:disabled + .form-icon, input.disabled + .form-icon { background: #f0f1f4; cursor: not-allowed; opacity: .5; } + +.form-switch input:disabled + .form-icon::before, .form-switch input.disabled + .form-icon::before { background: #fff; } + +.form-horizontal { padding: 0.4rem 0; } + +.form-horizontal .form-group { display: -ms-flexbox; display: flex; -ms-flex-wrap: wrap; flex-wrap: wrap; } + +.form-inline { display: inline-block; } + +.label { border-radius: 0.1rem; line-height: 1.2; padding: .1rem .2rem; background: #f0f1f4; color: #5b657a; display: inline-block; } + +.label.label-rounded { border-radius: 5rem; padding-left: .4rem; padding-right: .4rem; } + +.label.label-primary { background: #0074D9; color: #fff; } + +.label.label-secondary { background: #99d0ff; color: #0074D9; } + +.label.label-success { background: #2ECC40; color: #fff; } + +.label.label-warning { background: #FF851B; color: #fff; } + +.label.label-error { background: #FF4136; color: #fff; } + +code { border-radius: 0.1rem; line-height: 1.2; padding: .1rem .2rem; background: #f0f7fe; color: #288FED; font-size: 85%; } + +.code { border-radius: 0.1rem; color: #50596c; position: relative; } + +.code::before { color: #acb3c2; content: attr(data-lang); font-size: 0.7rem; position: absolute; right: 0.4rem; top: 0.1rem; } + +.code code { background: #f8f9fa; color: inherit; display: block; line-height: 1.5; overflow-x: auto; padding: 1rem; width: 100%; } + +.img-responsive { display: block; height: auto; max-width: 100%; } + +.img-fit-cover { object-fit: cover; } + +.img-fit-contain { object-fit: contain; } + +.video-responsive { display: block; overflow: hidden; padding: 0; position: relative; width: 100%; } + +.video-responsive::before { content: ""; display: block; padding-bottom: 56.25%; } + +.video-responsive iframe, .video-responsive object, .video-responsive embed { border: 0; bottom: 0; height: 100%; left: 0; position: absolute; right: 0; top: 0; width: 100%; } + +video.video-responsive { height: auto; max-width: 100%; } + +video.video-responsive::before { content: none; } + +.video-responsive-4-3::before { padding-bottom: 75%; } + +.video-responsive-1-1::before { padding-bottom: 100%; } + +.figure { margin: 0 0 0.4rem 0; } + +.figure .figure-caption { color: #667189; margin-top: 0.4rem; } + +.container { margin-left: auto; margin-right: auto; padding-left: 0.4rem; padding-right: 0.4rem; width: 100%; } + +.container.grid-xl { max-width: 1296px; } + +.container.grid-lg { max-width: 976px; } + +.container.grid-md { max-width: 856px; } + +.container.grid-sm { max-width: 616px; } + +.container.grid-xs { max-width: 496px; } + +.show-xs, .show-sm, .show-md, .show-lg, .show-xl { display: none !important; } + +.columns { display: -ms-flexbox; display: flex; -ms-flex-wrap: wrap; flex-wrap: wrap; margin-left: -0.4rem; margin-right: -0.4rem; } + +.columns.col-gapless { margin-left: 0; margin-right: 0; } + +.columns.col-gapless > .column { padding-left: 0; padding-right: 0; } + +.columns.col-oneline { -ms-flex-wrap: nowrap; flex-wrap: nowrap; overflow-x: auto; } + +.column { -ms-flex: 1; flex: 1; max-width: 100%; padding-left: 0.4rem; padding-right: 0.4rem; } + +.column.col-12, .column.col-11, .column.col-10, .column.col-9, .column.col-8, .column.col-7, .column.col-6, .column.col-5, .column.col-4, .column.col-3, .column.col-2, .column.col-1 { -ms-flex: none; flex: none; } + +.col-12 { width: 100%; } + +.col-11 { width: 91.66666667%; } + +.col-10 { width: 83.33333333%; } + +.col-9 { width: 75%; } + +.col-8 { width: 66.66666667%; } + +.col-7 { width: 58.33333333%; } + +.col-6 { width: 50%; } + +.col-5 { width: 41.66666667%; } + +.col-4 { width: 33.33333333%; } + +.col-3 { width: 25%; } + +.col-2 { width: 16.66666667%; } + +.col-1 { width: 8.33333333%; } + +.col-auto { -ms-flex: 0 0 auto; flex: 0 0 auto; max-width: none; width: auto; } + +.col-mx-auto { margin-left: auto; margin-right: auto; } + +.col-ml-auto { margin-left: auto; } + +.col-mr-auto { margin-right: auto; } + +@media (max-width: 1280px) { .col-xl-12, .col-xl-11, .col-xl-10, .col-xl-9, .col-xl-8, .col-xl-7, .col-xl-6, .col-xl-5, .col-xl-4, .col-xl-3, .col-xl-2, .col-xl-1 { -ms-flex: none; flex: none; } + .col-xl-12 { width: 100%; } + .col-xl-11 { width: 91.66666667%; } + .col-xl-10 { width: 83.33333333%; } + .col-xl-9 { width: 75%; } + .col-xl-8 { width: 66.66666667%; } + .col-xl-7 { width: 58.33333333%; } + .col-xl-6 { width: 50%; } + .col-xl-5 { width: 41.66666667%; } + .col-xl-4 { width: 33.33333333%; } + .col-xl-3 { width: 25%; } + .col-xl-2 { width: 16.66666667%; } + .col-xl-1 { width: 8.33333333%; } + .hide-xl { display: none !important; } + .show-xl { display: block !important; } } + +@media (max-width: 960px) { .col-lg-12, .col-lg-11, .col-lg-10, .col-lg-9, .col-lg-8, .col-lg-7, .col-lg-6, .col-lg-5, .col-lg-4, .col-lg-3, .col-lg-2, .col-lg-1 { -ms-flex: none; flex: none; } + .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%; } + .hide-lg { display: none !important; } + .show-lg { display: block !important; } } + +@media (max-width: 840px) { .col-md-12, .col-md-11, .col-md-10, .col-md-9, .col-md-8, .col-md-7, .col-md-6, .col-md-5, .col-md-4, .col-md-3, .col-md-2, .col-md-1 { -ms-flex: none; flex: none; } + .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%; } + .hide-md { display: none !important; } + .show-md { display: block !important; } } + +@media (max-width: 600px) { .col-sm-12, .col-sm-11, .col-sm-10, .col-sm-9, .col-sm-8, .col-sm-7, .col-sm-6, .col-sm-5, .col-sm-4, .col-sm-3, .col-sm-2, .col-sm-1 { -ms-flex: none; flex: none; } + .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%; } + .hide-sm { display: none !important; } + .show-sm { display: block !important; } } + +@media (max-width: 480px) { .col-xs-12, .col-xs-11, .col-xs-10, .col-xs-9, .col-xs-8, .col-xs-7, .col-xs-6, .col-xs-5, .col-xs-4, .col-xs-3, .col-xs-2, .col-xs-1 { -ms-flex: none; flex: none; } + .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%; } + .hide-xs { display: none !important; } + .show-xs { display: block !important; } } + +.navbar { -ms-flex-align: stretch; align-items: stretch; display: -ms-flexbox; display: flex; -ms-flex-wrap: wrap; flex-wrap: wrap; -ms-flex-pack: justify; justify-content: space-between; } + +.navbar .navbar-section { -ms-flex-align: center; align-items: center; display: -ms-flexbox; display: flex; -ms-flex: 1 0 0px; flex: 1 0 0; } + +.navbar .navbar-section:not(:first-child):last-child { -ms-flex-pack: end; justify-content: flex-end; } + +.navbar .navbar-center { -ms-flex-align: center; align-items: center; display: -ms-flexbox; display: flex; -ms-flex: 0 0 auto; flex: 0 0 auto; } + +.navbar .navbar-brand { font-size: 0.9rem; font-weight: 500; text-decoration: none; } + +.accordion input:checked ~ .accordion-header .icon, .accordion[open] .accordion-header .icon { transform: rotate(90deg); } + +.accordion input:checked ~ .accordion-body, .accordion[open] .accordion-body { max-height: 50rem; } + +.accordion .accordion-header { display: block; padding: 0.2rem 0.4rem; } + +.accordion .accordion-header .icon { transition: all .2s ease; } + +.accordion .accordion-body { margin-bottom: 0.4rem; max-height: 0; overflow: hidden; transition: max-height .2s ease; } + +summary.accordion-header::-webkit-details-marker { display: none; } + +.avatar { font-size: 0.8rem; height: 1.6rem; width: 1.6rem; background: #0074D9; border-radius: 50%; color: rgba(255, 255, 255, 0.85); display: inline-block; font-weight: 300; line-height: 1.25; margin: 0; position: relative; vertical-align: middle; } + +.avatar.avatar-xs { font-size: 0.4rem; height: 0.8rem; width: 0.8rem; } + +.avatar.avatar-sm { font-size: 0.6rem; height: 1.2rem; width: 1.2rem; } + +.avatar.avatar-lg { font-size: 1.2rem; height: 2.4rem; width: 2.4rem; } + +.avatar.avatar-xl { font-size: 1.6rem; height: 3.2rem; width: 3.2rem; } + +.avatar img { border-radius: 50%; height: 100%; position: relative; width: 100%; z-index: 1; } + +.avatar .avatar-icon, .avatar .avatar-presence { background: #fff; bottom: 14.64%; height: 50%; padding: 0.1rem; position: absolute; right: 14.64%; transform: translate(50%, 50%); width: 50%; z-index: 2; } + +.avatar .avatar-presence { background: #acb3c2; box-shadow: 0 0 0 0.1rem #fff; border-radius: 50%; height: .5em; width: .5em; } + +.avatar .avatar-presence.online { background: #2ECC40; } + +.avatar .avatar-presence.busy { background: #FF4136; } + +.avatar .avatar-presence.away { background: #FF851B; } + +.avatar[data-initial]::before { color: currentColor; content: attr(data-initial); left: 50%; position: absolute; top: 50%; transform: translate(-50%, -50%); z-index: 1; } + +.badge { position: relative; white-space: nowrap; } + +.badge[data-badge]::after, .badge:not([data-badge])::after { background: #0074D9; background-clip: padding-box; border-radius: .5rem; box-shadow: 0 0 0 0.1rem #fff; color: #fff; content: attr(data-badge); display: inline-block; transform: translate(-0.05rem, -0.5rem); } + +.badge[data-badge]::after { font-size: 0.7rem; height: .9rem; line-height: 1; min-width: .9rem; padding: .1rem .2rem; text-align: center; white-space: nowrap; } + +.badge:not([data-badge])::after, .badge[data-badge=""]::after { height: 6px; min-width: 6px; padding: 0; width: 6px; } + +.badge.btn::after { position: absolute; top: 0; right: 0; transform: translate(50%, -50%); } + +.badge.avatar::after { position: absolute; top: 14.64%; right: 14.64%; transform: translate(50%, -50%); z-index: 100; } + +.breadcrumb { list-style: none; margin: 0.2rem 0; padding: 0.2rem 0; } + +.breadcrumb .breadcrumb-item { color: #667189; display: inline-block; margin: 0; padding: 0.2rem 0; } + +.breadcrumb .breadcrumb-item:not(:last-child) { margin-right: 0.2rem; } + +.breadcrumb .breadcrumb-item:not(:last-child) a { color: #667189; } + +.breadcrumb .breadcrumb-item:not(:first-child)::before { color: #e7e9ed; content: "/"; padding-right: 0.4rem; } + +.bar { background: #f0f1f4; border-radius: 0.1rem; display: -ms-flexbox; display: flex; -ms-flex-wrap: nowrap; flex-wrap: nowrap; height: 0.8rem; width: 100%; } + +.bar.bar-sm { height: 0.2rem; } + +.bar .bar-item { background: #0074D9; color: #fff; display: block; font-size: 0.7rem; -ms-flex-negative: 0; flex-shrink: 0; line-height: 0.8rem; height: 100%; position: relative; text-align: center; width: 0; } + +.bar .bar-item:first-child { border-bottom-left-radius: 0.1rem; border-top-left-radius: 0.1rem; } + +.bar .bar-item:last-child { border-bottom-right-radius: 0.1rem; border-top-right-radius: 0.1rem; -ms-flex-negative: 1; flex-shrink: 1; } + +.bar-slider { height: 0.1rem; margin: 0.4rem 0; position: relative; } + +.bar-slider .bar-item { left: 0; padding: 0; position: absolute; } + +.bar-slider .bar-item:not(:last-child):first-child { background: #f0f1f4; z-index: 1; } + +.bar-slider .bar-slider-btn { background: #0074D9; border: 0; border-radius: 50%; height: 0.6rem; padding: 0; position: absolute; right: 0; top: 50%; transform: translate(50%, -50%); width: 0.6rem; } + +.bar-slider .bar-slider-btn:active { box-shadow: 0 0 0 0.1rem #0074D9; } + +.card { background: #fff; border: 0.05rem solid #e7e9ed; border-radius: 0.1rem; display: -ms-flexbox; display: flex; -ms-flex-direction: column; flex-direction: column; } + +.card .card-header, .card .card-body, .card .card-footer { padding: 0.8rem; padding-bottom: 0; } + +.card .card-header:last-child, .card .card-body:last-child, .card .card-footer:last-child { padding-bottom: 0.8rem; } + +.card .card-body { -ms-flex: 1 1 auto; flex: 1 1 auto; } + +.card .card-image { padding-top: 0.8rem; } + +.card .card-image:first-child { padding-top: 0; } + +.card .card-image:first-child img { border-top-left-radius: 0.1rem; border-top-right-radius: 0.1rem; } + +.card .card-image:last-child img { border-bottom-left-radius: 0.1rem; border-bottom-right-radius: 0.1rem; } + +.chip { -ms-flex-align: center; align-items: center; background: #f0f1f4; border-radius: 5rem; color: #667189; display: -ms-inline-flexbox; display: inline-flex; font-size: 90%; height: 1.2rem; line-height: 0.8rem; margin: 0.1rem; max-width: 100%; padding: 0.2rem 0.4rem; text-decoration: none; vertical-align: middle; } + +.chip.active { background: #0074D9; color: #fff; } + +.chip .avatar { margin-left: -0.4rem; margin-right: 0.2rem; } + +.chip .btn-clear { transform: scale(0.75); } + +.dropdown { display: inline-block; position: relative; } + +.dropdown .menu { animation: slide-down .15s ease 1; display: none; left: 0; max-height: 50vh; overflow-y: auto; position: absolute; top: 100%; } + +.dropdown.dropdown-right .menu { left: auto; right: 0; } + +.dropdown.active .menu, .dropdown .dropdown-toggle:focus + .menu, .dropdown .menu:hover { display: block; } + +.dropdown .btn-group .dropdown-toggle:nth-last-child(2) { border-bottom-right-radius: 0.1rem; border-top-right-radius: 0.1rem; } + +.empty { background: #f8f9fa; border-radius: 0.1rem; color: #667189; text-align: center; padding: 3.2rem 1.6rem; } + +.empty .empty-icon { margin-bottom: 0.8rem; } + +.empty .empty-title, .empty .empty-subtitle { margin: 0.4rem auto; } + +.empty .empty-action { margin-top: 0.8rem; } + +.menu { box-shadow: 0 0.05rem 0.2rem rgba(69, 77, 93, 0.3); background: #fff; border-radius: 0.1rem; list-style: none; margin: 0; min-width: 180px; padding: 0.4rem; transform: translateY(0.2rem); z-index: 300; } + +.menu.menu-nav { background: transparent; box-shadow: none; } + +.menu .menu-item { margin-top: 0; padding: 0 0.4rem; text-decoration: none; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; } + +.menu .menu-item > a { border-radius: 0.1rem; color: inherit; display: block; margin: 0 -0.4rem; padding: 0.2rem 0.4rem; text-decoration: none; } + +.menu .menu-item > a:focus, .menu .menu-item > a:hover { background: #99d0ff; color: #0074D9; } + +.menu .menu-item > a:active, .menu .menu-item > a.active { background: #99d0ff; color: #0074D9; } + +.menu .menu-item .form-checkbox, .menu .menu-item .form-radio, .menu .menu-item .form-switch { margin: 0.1rem 0; } + +.menu .menu-item + .menu-item { margin-top: 0.2rem; } + +.menu .menu-badge { float: right; padding: 0.2rem 0; } + +.menu .menu-badge .btn { margin-top: -0.1rem; } + +.modal { -ms-flex-align: center; align-items: center; bottom: 0; display: none; -ms-flex-pack: center; justify-content: center; left: 0; opacity: 0; overflow: hidden; padding: 0.4rem; position: fixed; right: 0; top: 0; } + +.modal:target, .modal.active { display: -ms-flexbox; display: flex; opacity: 1; z-index: 400; } + +.modal:target .modal-overlay, .modal.active .modal-overlay { background: rgba(248, 249, 250, 0.75); bottom: 0; cursor: default; display: block; left: 0; position: absolute; right: 0; top: 0; } + +.modal:target .modal-container, .modal.active .modal-container { animation: slide-down .2s ease 1; z-index: 1; } + +.modal.modal-sm .modal-container { max-width: 320px; padding: 0 0.4rem; } + +.modal.modal-lg .modal-overlay { background: #fff; } + +.modal.modal-lg .modal-container { box-shadow: none; max-width: 960px; } + +.modal-container { box-shadow: 0 0.2rem 0.5rem rgba(69, 77, 93, 0.3); background: #fff; border-radius: 0.1rem; display: -ms-flexbox; display: flex; -ms-flex-direction: column; flex-direction: column; max-height: 75vh; max-width: 640px; padding: 0 0.8rem; width: 100%; } + +.modal-container.modal-fullheight { max-height: 100vh; } + +.modal-container .modal-header { color: #454d5d; padding: 0.8rem; } + +.modal-container .modal-body { overflow-y: auto; padding: 0.8rem; position: relative; } + +.modal-container .modal-footer { padding: 0.8rem; text-align: right; } + +.nav { display: -ms-flexbox; display: flex; -ms-flex-direction: column; flex-direction: column; list-style: none; margin: 0.2rem 0; } + +.nav .nav-item a { color: #667189; padding: 0.2rem 0.4rem; text-decoration: none; } + +.nav .nav-item a:focus, .nav .nav-item a:hover { color: #0074D9; } + +.nav .nav-item.active > a { color: #50596c; font-weight: bold; } + +.nav .nav-item.active > a:focus, .nav .nav-item.active > a:hover { color: #0074D9; } + +.nav .nav { margin-bottom: 0.4rem; margin-left: 0.8rem; } + +.pagination { display: -ms-flexbox; display: flex; list-style: none; margin: 0.2rem 0; padding: 0.2rem 0; } + +.pagination .page-item { margin: 0.2rem 0.05rem; } + +.pagination .page-item span { display: inline-block; padding: 0.2rem 0.2rem; } + +.pagination .page-item a { border-radius: 0.1rem; color: #667189; display: inline-block; padding: 0.2rem 0.4rem; text-decoration: none; } + +.pagination .page-item a:focus, .pagination .page-item a:hover { color: #0074D9; } + +.pagination .page-item.disabled a { cursor: default; opacity: .5; pointer-events: none; } + +.pagination .page-item.active a { background: #0074D9; color: #fff; } + +.pagination .page-item.page-prev, .pagination .page-item.page-next { -ms-flex: 1 0 50%; flex: 1 0 50%; } + +.pagination .page-item.page-next { text-align: right; } + +.pagination .page-item .page-item-title { margin: 0; } + +.pagination .page-item .page-item-subtitle { margin: 0; opacity: .5; } + +.panel { border: 0.05rem solid #e7e9ed; border-radius: 0.1rem; display: -ms-flexbox; display: flex; -ms-flex-direction: column; flex-direction: column; } + +.panel .panel-header, .panel .panel-footer { -ms-flex: 0 0 auto; flex: 0 0 auto; padding: 0.8rem; } + +.panel .panel-nav { -ms-flex: 0 0 auto; flex: 0 0 auto; } + +.panel .panel-body { -ms-flex: 1 1 auto; flex: 1 1 auto; overflow-y: auto; padding: 0 0.8rem; } + +.popover { display: inline-block; position: relative; } + +.popover .popover-container { left: 50%; opacity: 0; padding: 0.4rem; position: absolute; top: 0; transform: translate(-50%, -50%) scale(0); transition: transform .2s ease; width: 320px; z-index: 300; } + +.popover *:focus + .popover-container, .popover:hover .popover-container { display: block; opacity: 1; transform: translate(-50%, -100%); } + +.popover.popover-right .popover-container { left: 100%; top: 50%; } + +.popover.popover-right *:focus + .popover-container, .popover.popover-right:hover .popover-container { transform: translate(0, -50%); } + +.popover.popover-bottom .popover-container { left: 50%; top: 100%; } + +.popover.popover-bottom *:focus + .popover-container, .popover.popover-bottom:hover .popover-container { transform: translate(-50%, 0); } + +.popover.popover-left .popover-container { left: 0; top: 50%; } + +.popover.popover-left *:focus + .popover-container, .popover.popover-left:hover .popover-container { transform: translate(-100%, -50%); } + +.popover .card { box-shadow: 0 0.2rem 0.5rem rgba(69, 77, 93, 0.3); border: 0; } + +.step { display: -ms-flexbox; display: flex; -ms-flex-wrap: nowrap; flex-wrap: nowrap; list-style: none; margin: 0.2rem 0; width: 100%; } + +.step .step-item { -ms-flex: 1 1 0px; flex: 1 1 0; margin-top: 0; min-height: 1rem; text-align: center; position: relative; } + +.step .step-item:not(:first-child)::before { background: #0074D9; content: ""; height: 2px; left: -50%; position: absolute; top: 9px; width: 100%; } + +.step .step-item a { color: #acb3c2; display: inline-block; padding: 20px 10px 0; text-decoration: none; } + +.step .step-item a::before { background: #0074D9; border: 0.1rem solid #fff; border-radius: 50%; content: ""; display: block; height: 0.6rem; left: 50%; position: absolute; top: 0.2rem; transform: translateX(-50%); width: 0.6rem; z-index: 1; } + +.step .step-item.active a::before { background: #fff; border: 0.1rem solid #0074D9; } + +.step .step-item.active ~ .step-item::before { background: #e7e9ed; } + +.step .step-item.active ~ .step-item a::before { background: #e7e9ed; } + +.tab { -ms-flex-align: center; align-items: center; border-bottom: 0.05rem solid #e7e9ed; display: -ms-flexbox; display: flex; -ms-flex-wrap: wrap; flex-wrap: wrap; list-style: none; margin: 0.2rem 0 0.15rem 0; } + +.tab .tab-item { margin-top: 0; } + +.tab .tab-item a { border-bottom: 0.1rem solid transparent; color: inherit; display: block; margin: 0 0.4rem 0 0; padding: 0.4rem 0.2rem 0.3rem 0.2rem; text-decoration: none; } + +.tab .tab-item a:focus, .tab .tab-item a:hover { color: #0074D9; } + +.tab .tab-item.active a, .tab .tab-item a.active { border-bottom-color: #0074D9; color: #0074D9; } + +.tab .tab-item.tab-action { -ms-flex: 1 0 auto; flex: 1 0 auto; text-align: right; } + +.tab .tab-item .btn-clear { margin-top: -0.2rem; } + +.tab.tab-block .tab-item { -ms-flex: 1 0 0px; flex: 1 0 0; text-align: center; } + +.tab.tab-block .tab-item a { margin: 0; } + +.tab.tab-block .tab-item .badge[data-badge]::after { position: absolute; right: 0.1rem; top: 0.1rem; transform: translate(0, 0); } + +.tab:not(.tab-block) .badge { padding-right: 0; } + +.tile { -ms-flex-line-pack: justify; align-content: space-between; -ms-flex-align: start; align-items: flex-start; display: -ms-flexbox; display: flex; } + +.tile .tile-icon, .tile .tile-action { -ms-flex: 0 0 auto; flex: 0 0 auto; } + +.tile .tile-content { -ms-flex: 1 1 auto; flex: 1 1 auto; } + +.tile .tile-content:not(:first-child) { padding-left: 0.4rem; } + +.tile .tile-content:not(:last-child) { padding-right: 0.4rem; } + +.tile .tile-title, .tile .tile-subtitle { line-height: 1.2rem; } + +.tile.tile-centered { -ms-flex-align: center; align-items: center; } + +.tile.tile-centered .tile-content { overflow: hidden; } + +.tile.tile-centered .tile-title, .tile.tile-centered .tile-subtitle { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; margin-bottom: 0; } + +.toast { background: rgba(69, 77, 93, 0.9); border-color: #454d5d; border: 0.05rem solid #454d5d; border-radius: 0.1rem; color: #fff; display: block; padding: 0.4rem; width: 100%; } + +.toast.toast-primary { background: rgba(0, 116, 217, 0.9); border-color: #0074D9; } + +.toast.toast-success { background: rgba(46, 204, 64, 0.9); border-color: #2ECC40; } + +.toast.toast-warning { background: rgba(255, 133, 27, 0.9); border-color: #FF851B; } + +.toast.toast-error { background: rgba(255, 65, 54, 0.9); border-color: #FF4136; } + +.toast a { color: #fff; text-decoration: underline; } + +.toast a:focus, .toast a:hover, .toast a:active, .toast a.active { opacity: .75; } + +.toast .btn-clear { margin: 4px -2px 4px 4px; } + +.tooltip { position: relative; } + +.tooltip::after { background: rgba(69, 77, 93, 0.9); border-radius: 0.1rem; bottom: 100%; color: #fff; content: attr(data-tooltip); display: block; font-size: 0.7rem; left: 50%; max-width: 320px; opacity: 0; overflow: hidden; padding: 0.2rem 0.4rem; pointer-events: none; position: absolute; text-overflow: ellipsis; transform: translate(-50%, 0.4rem); transition: all .2s ease; white-space: pre; z-index: 300; } + +.tooltip:focus::after, .tooltip:hover::after { opacity: 1; transform: translate(-50%, -0.2rem); } + +.tooltip[disabled], .tooltip.disabled { pointer-events: auto; } + +.tooltip.tooltip-right::after { bottom: 50%; left: 100%; transform: translate(-0.2rem, 50%); } + +.tooltip.tooltip-right:focus::after, .tooltip.tooltip-right:hover::after { transform: translate(0.2rem, 50%); } + +.tooltip.tooltip-bottom::after { bottom: auto; top: 100%; transform: translate(-50%, -0.4rem); } + +.tooltip.tooltip-bottom:focus::after, .tooltip.tooltip-bottom:hover::after { transform: translate(-50%, 0.2rem); } + +.tooltip.tooltip-left::after { bottom: 50%; left: auto; right: 100%; transform: translate(0.4rem, 50%); } + +.tooltip.tooltip-left:focus::after, .tooltip.tooltip-left:hover::after { transform: translate(-0.2rem, 50%); } + +body { padding: 2rem 0; } + +img.logo { width: 200px; margin-bottom: 1rem; } + +h1, h2 { font-weight: 700; } + +.footer { color: #acb3c2; margin-top: 2rem; } + +.footer img { height: 18px; vertical-align: middle; margin: 0 0.2rem; } + +.toast .btn { margin-left: 1rem; text-decoration: none !important; } + +.toast .btn i { margin-right: 0.3rem; } + +ul.problems { margin: 1rem 0; } + +ul.problems h5 { margin: 0; } + +ul.problems li.menu { margin-bottom: 1rem; } + +ul.problems li.menu .toast .btn { float: right; margin-top: -2px; } + +ul.details { margin: 0.5rem; list-style: none; font-size: 90%; } + +ul.details .menu-item { margin-top: .5rem !important; border-top: 1px solid #e7e9ed; padding-top: 0.5rem; } + +ul.details .menu-item:first-child { border: none; } + +ul.details .menu-badge { padding: 0; } + +@keyframes loading { 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } } + +@keyframes slide-down { 0% { opacity: 0; + transform: translateY(-1.6rem); } + 100% { opacity: 1; + transform: translateY(0); } } + +.text-primary { color: #0074D9; } + +a.text-primary:focus, a.text-primary:hover { color: #0066c0; } + +a.text-primary:visited { color: #0082f3; } + +.text-secondary { color: #8ac9ff; } + +a.text-secondary:focus, a.text-secondary:hover { color: #70bdff; } + +a.text-secondary:visited { color: #a3d4ff; } + +.text-gray { color: #acb3c2; } + +a.text-gray:focus, a.text-gray:hover { color: #9ea6b7; } + +a.text-gray:visited { color: #bbc1cd; } + +.text-light { color: #fff; } + +a.text-light:focus, a.text-light:hover { color: #f2f2f2; } + +a.text-light:visited { color: white; } + +.text-dark { color: #50596c; } + +a.text-dark:focus, a.text-dark:hover { color: #454d5d; } + +a.text-dark:visited { color: #5b657a; } + +.text-success { color: #2ECC40; } + +a.text-success:focus, a.text-success:hover { color: #29b739; } + +a.text-success:visited { color: #40d451; } + +.text-warning { color: #FF851B; } + +a.text-warning:focus, a.text-warning:hover { color: #ff7702; } + +a.text-warning:visited { color: #ff9335; } + +.text-error { color: #FF4136; } + +a.text-error:focus, a.text-error:hover { color: #ff291d; } + +a.text-error:visited { color: #ff5950; } + +.bg-primary { background: #0074D9; color: #fff; } + +.bg-secondary { background: #99d0ff; } + +.bg-dark { background: #454d5d; color: #fff; } + +.bg-gray { background: #f8f9fa; } + +.bg-success { background: #2ECC40; color: #fff; } + +.bg-warning { background: #FF851B; color: #fff; } + +.bg-error { background: #FF4136; } + +.c-hand { cursor: pointer; } + +.c-move { cursor: move; } + +.c-zoom-in { cursor: zoom-in; } + +.c-zoom-out { cursor: zoom-out; } + +.c-not-allowed { cursor: not-allowed; } + +.c-auto { cursor: auto; } + +.d-block { display: block; } + +.d-inline { display: inline; } + +.d-inline-block { display: inline-block; } + +.d-flex { display: -ms-flexbox; display: flex; } + +.d-inline-flex { display: -ms-inline-flexbox; display: inline-flex; } + +.d-none, .d-hide { display: none !important; } + +.d-visible { visibility: visible; } + +.d-invisible { visibility: hidden; } + +.text-hide { background: transparent; border: 0; color: transparent; font-size: 0; line-height: 0; text-shadow: none; } + +.text-assistive { border: 0; clip: rect(0, 0, 0, 0); height: 1px; margin: -1px; overflow: hidden; padding: 0; position: absolute; width: 1px; } + +.divider, .divider-vert { display: block; position: relative; } + +.divider[data-content]::after, .divider-vert[data-content]::after { background: #fff; color: #acb3c2; content: attr(data-content); display: inline-block; font-size: 0.7rem; padding: 0 0.4rem; transform: translateY(-0.65rem); } + +.divider { border-top: 0.05rem solid #e7e9ed; height: 0.05rem; margin: 0.4rem 0; } + +.divider[data-content] { margin: 0.8rem 0; } + +.divider-vert { display: block; padding: 0.8rem; } + +.divider-vert::before { border-left: 0.05rem solid #e7e9ed; bottom: 0.4rem; content: ""; display: block; left: 50%; position: absolute; top: 0.4rem; transform: translateX(-50%); } + +.divider-vert[data-content]::after { left: 50%; padding: 0.2rem 0; position: absolute; top: 50%; transform: translate(-50%, -50%); } + +.loading { color: transparent !important; min-height: 0.8rem; pointer-events: none; position: relative; } + +.loading::after { animation: loading 500ms infinite linear; border: 0.1rem solid #0074D9; border-radius: 50%; border-right-color: transparent; border-top-color: transparent; content: ""; display: block; height: 0.8rem; left: 50%; margin-left: -0.4rem; margin-top: -0.4rem; position: absolute; top: 50%; width: 0.8rem; z-index: 1; } + +.loading.loading-lg { min-height: 2rem; } + +.loading.loading-lg::after { height: 1.6rem; margin-left: -0.8rem; margin-top: -0.8rem; width: 1.6rem; } + +.clearfix::after, .container::after { clear: both; content: ""; display: table; } + +.float-left { float: left !important; } + +.float-right { float: right !important; } + +.relative { position: relative !important; } + +.absolute { position: absolute !important; } + +.fixed { position: fixed !important; } + +.centered { display: block; float: none; margin-left: auto; margin-right: auto; } + +.flex-centered { -ms-flex-align: center; align-items: center; display: -ms-flexbox; display: flex; -ms-flex-pack: center; justify-content: center; } + +.m-0 { margin: 0 !important; } + +.mb-0 { margin-bottom: 0 !important; } + +.ml-0 { margin-left: 0 !important; } + +.mr-0 { margin-right: 0 !important; } + +.mt-0 { margin-top: 0 !important; } + +.mx-0 { margin-left: 0 !important; margin-right: 0 !important; } + +.my-0 { margin-bottom: 0 !important; margin-top: 0 !important; } + +.m-1 { margin: 0.2rem !important; } + +.mb-1 { margin-bottom: 0.2rem !important; } + +.ml-1 { margin-left: 0.2rem !important; } + +.mr-1 { margin-right: 0.2rem !important; } + +.mt-1 { margin-top: 0.2rem !important; } + +.mx-1 { margin-left: 0.2rem !important; margin-right: 0.2rem !important; } + +.my-1 { margin-bottom: 0.2rem !important; margin-top: 0.2rem !important; } + +.m-2 { margin: 0.4rem !important; } + +.mb-2 { margin-bottom: 0.4rem !important; } + +.ml-2 { margin-left: 0.4rem !important; } + +.mr-2 { margin-right: 0.4rem !important; } + +.mt-2 { margin-top: 0.4rem !important; } + +.mx-2 { margin-left: 0.4rem !important; margin-right: 0.4rem !important; } + +.my-2 { margin-bottom: 0.4rem !important; margin-top: 0.4rem !important; } + +.p-0 { padding: 0 !important; } + +.pb-0 { padding-bottom: 0 !important; } + +.pl-0 { padding-left: 0 !important; } + +.pr-0 { padding-right: 0 !important; } + +.pt-0 { padding-top: 0 !important; } + +.px-0 { padding-left: 0 !important; padding-right: 0 !important; } + +.py-0 { padding-bottom: 0 !important; padding-top: 0 !important; } + +.p-1 { padding: 0.2rem !important; } + +.pb-1 { padding-bottom: 0.2rem !important; } + +.pl-1 { padding-left: 0.2rem !important; } + +.pr-1 { padding-right: 0.2rem !important; } + +.pt-1 { padding-top: 0.2rem !important; } + +.px-1 { padding-left: 0.2rem !important; padding-right: 0.2rem !important; } + +.py-1 { padding-bottom: 0.2rem !important; padding-top: 0.2rem !important; } + +.p-2 { padding: 0.4rem !important; } + +.pb-2 { padding-bottom: 0.4rem !important; } + +.pl-2 { padding-left: 0.4rem !important; } + +.pr-2 { padding-right: 0.4rem !important; } + +.pt-2 { padding-top: 0.4rem !important; } + +.px-2 { padding-left: 0.4rem !important; padding-right: 0.4rem !important; } + +.py-2 { padding-bottom: 0.4rem !important; padding-top: 0.4rem !important; } + +.s-rounded { border-radius: 0.1rem; } + +.s-circle { border-radius: 50%; } + +.text-left { text-align: left; } + +.text-right { text-align: right; } + +.text-center { text-align: center; } + +.text-justify { text-align: justify; } + +.text-lowercase { text-transform: lowercase; } + +.text-uppercase { text-transform: uppercase; } + +.text-capitalize { text-transform: capitalize; } + +.text-normal { font-weight: normal; } + +.text-bold { font-weight: bold; } + +.text-italic { font-style: italic; } + +.text-large { font-size: 1.2em; } + +.text-ellipsis { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } + +.text-clip { overflow: hidden; text-overflow: clip; white-space: nowrap; } + +.text-break { -webkit-hyphens: auto; -ms-hyphens: auto; hyphens: auto; word-break: break-word; word-wrap: break-word; } + +/*# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3BlY3RyZS5jc3MiLCJzb3VyY2VzIjpbInNwZWN0cmUuc2NzcyIsIl92YXJpYWJsZXMuc2NzcyIsIl9taXhpbnMuc2NzcyIsIm1peGlucy9fYXZhdGFyLnNjc3MiLCJtaXhpbnMvX2J1dHRvbi5zY3NzIiwibWl4aW5zL19jbGVhcmZpeC5zY3NzIiwibWl4aW5zL19jb2xvci5zY3NzIiwibWl4aW5zL19sYWJlbC5zY3NzIiwibWl4aW5zL19wb3NpdGlvbi5zY3NzIiwibWl4aW5zL19zaGFkb3cuc2NzcyIsIm1peGlucy9fdGV4dC5zY3NzIiwibWl4aW5zL190b2FzdC5zY3NzIiwibWl4aW5zL190cmFuc2l0aW9uLnNjc3MiLCJfbm9ybWFsaXplLnNjc3MiLCJfYmFzZS5zY3NzIiwiX3R5cG9ncmFwaHkuc2NzcyIsIl9hc2lhbi5zY3NzIiwiX3RhYmxlcy5zY3NzIiwiX2J1dHRvbnMuc2NzcyIsIl9mb3Jtcy5zY3NzIiwiX2xhYmVscy5zY3NzIiwiX2NvZGVzLnNjc3MiLCJfbWVkaWEuc2NzcyIsIl9sYXlvdXQuc2NzcyIsIl9uYXZiYXIuc2NzcyIsIl9hY2NvcmRpb25zLnNjc3MiLCJfYXZhdGFycy5zY3NzIiwiX2JhZGdlcy5zY3NzIiwiX2JyZWFkY3J1bWJzLnNjc3MiLCJfYmFycy5zY3NzIiwiX2NhcmRzLnNjc3MiLCJfY2hpcHMuc2NzcyIsIl9kcm9wZG93bnMuc2NzcyIsIl9lbXB0eS5zY3NzIiwiX21lbnVzLnNjc3MiLCJfbW9kYWxzLnNjc3MiLCJfbmF2cy5zY3NzIiwiX3BhZ2luYXRpb24uc2NzcyIsIl9wYW5lbHMuc2NzcyIsIl9wb3BvdmVycy5zY3NzIiwiX3N0ZXBzLnNjc3MiLCJfdGFicy5zY3NzIiwiX3RpbGVzLnNjc3MiLCJfdG9hc3RzLnNjc3MiLCJfdG9vbHRpcHMuc2NzcyIsIl9wcm9ibGVtcy5zY3NzIiwiX2FuaW1hdGlvbnMuc2NzcyIsIl91dGlsaXRpZXMuc2NzcyIsInV0aWxpdGllcy9fY29sb3JzLnNjc3MiLCJ1dGlsaXRpZXMvX2N1cnNvcnMuc2NzcyIsInV0aWxpdGllcy9fZGlzcGxheS5zY3NzIiwidXRpbGl0aWVzL19kaXZpZGVyLnNjc3MiLCJ1dGlsaXRpZXMvX2xvYWRpbmcuc2NzcyIsInV0aWxpdGllcy9fcG9zaXRpb24uc2NzcyIsInV0aWxpdGllcy9fc2hhcGVzLnNjc3MiLCJ1dGlsaXRpZXMvX3RleHQuc2NzcyJdLCJzb3VyY2VzQ29udGVudCI6WyIvLyBWYXJpYWJsZXMgYW5kIG1peGluc1xuQGltcG9ydCBcInZhcmlhYmxlc1wiO1xuQGltcG9ydCBcIm1peGluc1wiO1xuXG4vKiEgU3BlY3RyZS5jc3MgdiN7JHZlcnNpb259IHwgTUlUIExpY2Vuc2UgfCBnaXRodWIuY29tL3BpY3R1cmVwYW4yL3NwZWN0cmUgKi9cbi8vIFJlc2V0IGFuZCBkZXBlbmRlbmNpZXNcbkBpbXBvcnQgXCJub3JtYWxpemVcIjtcbkBpbXBvcnQgXCJiYXNlXCI7XG5cbi8vIEVsZW1lbnRzXG5AaW1wb3J0IFwidHlwb2dyYXBoeVwiO1xuQGltcG9ydCBcImFzaWFuXCI7XG5AaW1wb3J0IFwidGFibGVzXCI7XG5AaW1wb3J0IFwiYnV0dG9uc1wiO1xuQGltcG9ydCBcImZvcm1zXCI7XG5AaW1wb3J0IFwibGFiZWxzXCI7XG5AaW1wb3J0IFwiY29kZXNcIjtcbkBpbXBvcnQgXCJtZWRpYVwiO1xuXG4vLyBMYXlvdXRcbkBpbXBvcnQgXCJsYXlvdXRcIjtcbkBpbXBvcnQgXCJuYXZiYXJcIjtcblxuLy8gQ29tcG9uZW50c1xuQGltcG9ydCBcImFjY29yZGlvbnNcIjtcbkBpbXBvcnQgXCJhdmF0YXJzXCI7XG5AaW1wb3J0IFwiYmFkZ2VzXCI7XG5AaW1wb3J0IFwiYnJlYWRjcnVtYnNcIjtcbkBpbXBvcnQgXCJiYXJzXCI7XG5AaW1wb3J0IFwiY2FyZHNcIjtcbkBpbXBvcnQgXCJjaGlwc1wiO1xuQGltcG9ydCBcImRyb3Bkb3duc1wiO1xuQGltcG9ydCBcImVtcHR5XCI7XG5AaW1wb3J0IFwibWVudXNcIjtcbkBpbXBvcnQgXCJtb2RhbHNcIjtcbkBpbXBvcnQgXCJuYXZzXCI7XG5AaW1wb3J0IFwicGFnaW5hdGlvblwiO1xuQGltcG9ydCBcInBhbmVsc1wiO1xuQGltcG9ydCBcInBvcG92ZXJzXCI7XG5AaW1wb3J0IFwic3RlcHNcIjtcbkBpbXBvcnQgXCJ0YWJzXCI7XG5AaW1wb3J0IFwidGlsZXNcIjtcbkBpbXBvcnQgXCJ0b2FzdHNcIjtcbkBpbXBvcnQgXCJ0b29sdGlwc1wiO1xuXG4vLyBDdXN0b21cbkBpbXBvcnQgXCJwcm9ibGVtc1wiO1xuXG4vLyBVdGlsaXR5IGNsYXNzZXNcbkBpbXBvcnQgXCJhbmltYXRpb25zXCI7XG5AaW1wb3J0IFwidXRpbGl0aWVzXCI7XG4iLCIvLyBDb3JlIHZhcmlhYmxlc1xuJHZlcnNpb246IFwiMC41LjNcIjtcblxuLy8gQ29yZSBmZWF0dXJlc1xuJHJ0bDogZmFsc2UgIWRlZmF1bHQ7XG5cbi8vIENvcmUgY29sb3JzXG4kcHJpbWFyeS1jb2xvcjogIzAwNzREOSAhZGVmYXVsdDtcbiRwcmltYXJ5LWNvbG9yLWRhcms6IGRhcmtlbigkcHJpbWFyeS1jb2xvciwgMyUpICFkZWZhdWx0O1xuJHByaW1hcnktY29sb3ItbGlnaHQ6IGxpZ2h0ZW4oJHByaW1hcnktY29sb3IsIDMlKSAhZGVmYXVsdDtcbiRzZWNvbmRhcnktY29sb3I6IGxpZ2h0ZW4oJHByaW1hcnktY29sb3IsIDM3LjUlKSAhZGVmYXVsdDtcbiRzZWNvbmRhcnktY29sb3ItZGFyazogZGFya2VuKCRzZWNvbmRhcnktY29sb3IsIDMlKSAhZGVmYXVsdDtcbiRzZWNvbmRhcnktY29sb3ItbGlnaHQ6IGxpZ2h0ZW4oJHNlY29uZGFyeS1jb2xvciwgMyUpICFkZWZhdWx0O1xuXG4vLyBHcmF5IGNvbG9yc1xuJGRhcmstY29sb3I6ICM0NTRkNWQgIWRlZmF1bHQ7XG4kbGlnaHQtY29sb3I6ICNmZmYgIWRlZmF1bHQ7XG4kZ3JheS1jb2xvcjogbGlnaHRlbigkZGFyay1jb2xvciwgNDAlKSAhZGVmYXVsdDtcbiRncmF5LWNvbG9yLWRhcms6IGRhcmtlbigkZ3JheS1jb2xvciwgMjUlKSAhZGVmYXVsdDtcbiRncmF5LWNvbG9yLWxpZ2h0OiBsaWdodGVuKCRncmF5LWNvbG9yLCAyMCUpICFkZWZhdWx0O1xuXG4kYm9yZGVyLWNvbG9yOiBsaWdodGVuKCRkYXJrLWNvbG9yLCA2MCUpICFkZWZhdWx0O1xuJGJvcmRlci1jb2xvci1kYXJrOiBkYXJrZW4oJGJvcmRlci1jb2xvciwgMTAlKSAhZGVmYXVsdDtcbiRiZy1jb2xvcjogbGlnaHRlbigkZGFyay1jb2xvciwgNjYlKSAhZGVmYXVsdDtcbiRiZy1jb2xvci1kYXJrOiBkYXJrZW4oJGJnLWNvbG9yLCAzJSkgIWRlZmF1bHQ7XG4kYmctY29sb3ItbGlnaHQ6ICRsaWdodC1jb2xvciAhZGVmYXVsdDtcblxuLy8gQ29udHJvbCBjb2xvcnNcbiRzdWNjZXNzLWNvbG9yOiAjMkVDQzQwICFkZWZhdWx0O1xuJHdhcm5pbmctY29sb3I6ICNGRjg1MUIgIWRlZmF1bHQ7XG4kZXJyb3ItY29sb3I6ICNGRjQxMzYgIWRlZmF1bHQ7XG5cbi8vIE90aGVyIGNvbG9yc1xuJGNvZGUtY29sb3I6ICMyODhGRUQgIWRlZmF1bHQ7XG4kaGlnaGxpZ2h0LWNvbG9yOiAjZmZlOWIzICFkZWZhdWx0O1xuJGJvZHktYmc6ICRiZy1jb2xvci1saWdodCAhZGVmYXVsdDtcbiRib2R5LWZvbnQtY29sb3I6IGxpZ2h0ZW4oJGRhcmstY29sb3IsIDUlKSAhZGVmYXVsdDtcbiRsaW5rLWNvbG9yOiAkcHJpbWFyeS1jb2xvciAhZGVmYXVsdDtcbiRsaW5rLWNvbG9yLWRhcms6IGRhcmtlbigkbGluay1jb2xvciwgMTAlKSAhZGVmYXVsdDtcbiRsaW5rLWNvbG9yLWxpZ2h0OiBsaWdodGVuKCRsaW5rLWNvbG9yLCAxMCUpICFkZWZhdWx0O1xuXG4vLyBGb250c1xuLy8gQ3JlZGl0OiBodHRwczovL3d3dy5zbWFzaGluZ21hZ2F6aW5lLmNvbS8yMDE1LzExL3VzaW5nLXN5c3RlbS11aS1mb250cy1wcmFjdGljYWwtZ3VpZGUvXG4kYmFzZS1mb250LWZhbWlseTogLWFwcGxlLXN5c3RlbSwgc3lzdGVtLXVpLCBCbGlua01hY1N5c3RlbUZvbnQsIFwiU2Vnb2UgVUlcIiwgUm9ib3RvICFkZWZhdWx0O1xuJG1vbm8tZm9udC1mYW1pbHk6IFwiU0YgTW9ub1wiLCBcIlNlZ29lIFVJIE1vbm9cIiwgXCJSb2JvdG8gTW9ub1wiLCBNZW5sbywgQ291cmllciwgbW9ub3NwYWNlICFkZWZhdWx0O1xuJGZhbGxiYWNrLWZvbnQtZmFtaWx5OiBcIkhlbHZldGljYSBOZXVlXCIsIHNhbnMtc2VyaWYgIWRlZmF1bHQ7XG4kY2prLXpoLWhhbnMtZm9udC1mYW1pbHk6ICRiYXNlLWZvbnQtZmFtaWx5LCBcIlBpbmdGYW5nIFNDXCIsIFwiSGlyYWdpbm8gU2FucyBHQlwiLCBcIk1pY3Jvc29mdCBZYUhlaVwiLCAkZmFsbGJhY2stZm9udC1mYW1pbHkgIWRlZmF1bHQ7XG4kY2prLXpoLWhhbnQtZm9udC1mYW1pbHk6ICRiYXNlLWZvbnQtZmFtaWx5LCBcIlBpbmdGYW5nIFRDXCIsIFwiSGlyYWdpbm8gU2FucyBDTlNcIiwgXCJNaWNyb3NvZnQgSmhlbmdIZWlcIiwgJGZhbGxiYWNrLWZvbnQtZmFtaWx5ICFkZWZhdWx0O1xuJGNqay1qcC1mb250LWZhbWlseTogJGJhc2UtZm9udC1mYW1pbHksIFwiSGlyYWdpbm8gU2Fuc1wiLCBcIkhpcmFnaW5vIEtha3UgR290aGljIFByb1wiLCBcIll1IEdvdGhpY1wiLCBZdUdvdGhpYywgTWVpcnlvLCAkZmFsbGJhY2stZm9udC1mYW1pbHkgIWRlZmF1bHQ7XG4kY2prLWtvLWZvbnQtZmFtaWx5OiAkYmFzZS1mb250LWZhbWlseSwgXCJNYWxndW4gR290aGljXCIsICRmYWxsYmFjay1mb250LWZhbWlseSAhZGVmYXVsdDtcbiRib2R5LWZvbnQtZmFtaWx5OiAkYmFzZS1mb250LWZhbWlseSwgJGZhbGxiYWNrLWZvbnQtZmFtaWx5ICFkZWZhdWx0O1xuXG4vLyBVbml0IHNpemVzXG4kdW5pdC1vOiAuMDVyZW0gIWRlZmF1bHQ7XG4kdW5pdC1oOiAuMXJlbSAhZGVmYXVsdDtcbiR1bml0LTE6IC4ycmVtICFkZWZhdWx0O1xuJHVuaXQtMjogLjRyZW0gIWRlZmF1bHQ7XG4kdW5pdC0zOiAuNnJlbSAhZGVmYXVsdDtcbiR1bml0LTQ6IC44cmVtICFkZWZhdWx0O1xuJHVuaXQtNTogMXJlbSAhZGVmYXVsdDtcbiR1bml0LTY6IDEuMnJlbSAhZGVmYXVsdDtcbiR1bml0LTc6IDEuNHJlbSAhZGVmYXVsdDtcbiR1bml0LTg6IDEuNnJlbSAhZGVmYXVsdDtcbiR1bml0LTk6IDEuOHJlbSAhZGVmYXVsdDtcbiR1bml0LTEwOiAycmVtICFkZWZhdWx0O1xuJHVuaXQtMTI6IDIuNHJlbSAhZGVmYXVsdDtcbiR1bml0LTE2OiAzLjJyZW0gIWRlZmF1bHQ7XG5cbi8vIEZvbnQgc2l6ZXNcbiRodG1sLWZvbnQtc2l6ZTogMjBweCAhZGVmYXVsdDtcbiRodG1sLWxpbmUtaGVpZ2h0OiAxLjUgIWRlZmF1bHQ7XG4kZm9udC1zaXplOiAuOHJlbSAhZGVmYXVsdDtcbiRmb250LXNpemUtc206IC43cmVtICFkZWZhdWx0O1xuJGZvbnQtc2l6ZS1sZzogLjlyZW0gIWRlZmF1bHQ7XG4kbGluZS1oZWlnaHQ6IDEuMnJlbSAhZGVmYXVsdDtcblxuLy8gU2l6ZXNcbiRsYXlvdXQtc3BhY2luZzogJHVuaXQtMiAhZGVmYXVsdDtcbiRsYXlvdXQtc3BhY2luZy1zbTogJHVuaXQtMSAhZGVmYXVsdDtcbiRsYXlvdXQtc3BhY2luZy1sZzogJHVuaXQtNCAhZGVmYXVsdDtcbiRib3JkZXItcmFkaXVzOiAkdW5pdC1oICFkZWZhdWx0O1xuJGJvcmRlci13aWR0aDogJHVuaXQtbyAhZGVmYXVsdDtcbiRib3JkZXItd2lkdGgtbGc6ICR1bml0LWggIWRlZmF1bHQ7XG4kY29udHJvbC1zaXplOiAkdW5pdC05ICFkZWZhdWx0O1xuJGNvbnRyb2wtc2l6ZS1zbTogJHVuaXQtNyAhZGVmYXVsdDtcbiRjb250cm9sLXNpemUtbGc6ICR1bml0LTEwICFkZWZhdWx0O1xuJGNvbnRyb2wtcGFkZGluZy14OiAkdW5pdC0yICFkZWZhdWx0O1xuJGNvbnRyb2wtcGFkZGluZy14LXNtOiAkdW5pdC0yICogLjc1ICFkZWZhdWx0O1xuJGNvbnRyb2wtcGFkZGluZy14LWxnOiAkdW5pdC0yICogMS41ICFkZWZhdWx0O1xuJGNvbnRyb2wtcGFkZGluZy15OiAoJGNvbnRyb2wtc2l6ZSAtICRsaW5lLWhlaWdodCkgLyAyIC0gJGJvcmRlci13aWR0aCAhZGVmYXVsdDtcbiRjb250cm9sLXBhZGRpbmcteS1zbTogKCRjb250cm9sLXNpemUtc20gLSAkbGluZS1oZWlnaHQpIC8gMiAtICRib3JkZXItd2lkdGggIWRlZmF1bHQ7XG4kY29udHJvbC1wYWRkaW5nLXktbGc6ICgkY29udHJvbC1zaXplLWxnIC0gJGxpbmUtaGVpZ2h0KSAvIDIgLSAkYm9yZGVyLXdpZHRoICFkZWZhdWx0O1xuJGNvbnRyb2wtaWNvbi1zaXplOiAuOHJlbSAhZGVmYXVsdDtcblxuJGNvbnRyb2wtd2lkdGgteHM6IDE4MHB4ICFkZWZhdWx0O1xuJGNvbnRyb2wtd2lkdGgtc206IDMyMHB4ICFkZWZhdWx0O1xuJGNvbnRyb2wtd2lkdGgtbWQ6IDY0MHB4ICFkZWZhdWx0O1xuJGNvbnRyb2wtd2lkdGgtbGc6IDk2MHB4ICFkZWZhdWx0O1xuJGNvbnRyb2wtd2lkdGgteGw6IDEyODBweCAhZGVmYXVsdDtcblxuLy8gUmVzcG9uc2l2ZSBicmVha3BvaW50c1xuJHNpemUteHM6IDQ4MHB4ICFkZWZhdWx0O1xuJHNpemUtc206IDYwMHB4ICFkZWZhdWx0O1xuJHNpemUtbWQ6IDg0MHB4ICFkZWZhdWx0O1xuJHNpemUtbGc6IDk2MHB4ICFkZWZhdWx0O1xuJHNpemUteGw6IDEyODBweCAhZGVmYXVsdDtcbiRzaXplLTJ4OiAxNDQwcHggIWRlZmF1bHQ7XG5cbiRyZXNwb25zaXZlLWJyZWFrcG9pbnQ6ICRzaXplLXhzICFkZWZhdWx0O1xuXG4vLyBaLWluZGV4XG4kemluZGV4LTA6IDEgIWRlZmF1bHQ7XG4kemluZGV4LTE6IDEwMCAhZGVmYXVsdDtcbiR6aW5kZXgtMjogMjAwICFkZWZhdWx0O1xuJHppbmRleC0zOiAzMDAgIWRlZmF1bHQ7XG4kemluZGV4LTQ6IDQwMCAhZGVmYXVsdDtcbiIsIi8vIE1peGluc1xuQGltcG9ydCBcIm1peGlucy9hdmF0YXJcIjtcbkBpbXBvcnQgXCJtaXhpbnMvYnV0dG9uXCI7XG5AaW1wb3J0IFwibWl4aW5zL2NsZWFyZml4XCI7XG5AaW1wb3J0IFwibWl4aW5zL2NvbG9yXCI7XG5AaW1wb3J0IFwibWl4aW5zL2xhYmVsXCI7XG5AaW1wb3J0IFwibWl4aW5zL3Bvc2l0aW9uXCI7XG5AaW1wb3J0IFwibWl4aW5zL3NoYWRvd1wiO1xuQGltcG9ydCBcIm1peGlucy90ZXh0XCI7XG5AaW1wb3J0IFwibWl4aW5zL3RvYXN0XCI7XG5AaW1wb3J0IFwibWl4aW5zL3RyYW5zaXRpb25cIjtcbiIsIi8vIEF2YXRhciBtaXhpblxuQG1peGluIGF2YXRhci1iYXNlKCRzaXplOiAkdW5pdC04KSB7XG4gIGZvbnQtc2l6ZTogJHNpemUgLyAyO1xuICBoZWlnaHQ6ICRzaXplO1xuICB3aWR0aDogJHNpemU7XG59XG4iLCIvLyBCdXR0b24gdmFyaWFudCBtaXhpblxuQG1peGluIGJ1dHRvbi12YXJpYW50KCRjb2xvcjogJHByaW1hcnktY29sb3IpIHtcbiAgYmFja2dyb3VuZDogJGNvbG9yO1xuICBib3JkZXItY29sb3I6IGRhcmtlbigkY29sb3IsIDMlKTtcbiAgY29sb3I6ICRsaWdodC1jb2xvcjtcbiAgJjpmb2N1cyB7XG4gICAgQGluY2x1ZGUgY29udHJvbC1zaGFkb3coJGNvbG9yKTtcbiAgfVxuICAmOmZvY3VzLFxuICAmOmhvdmVyIHtcbiAgICBiYWNrZ3JvdW5kOiBkYXJrZW4oJGNvbG9yLCAyJSk7XG4gICAgYm9yZGVyLWNvbG9yOiBkYXJrZW4oJGNvbG9yLCA1JSk7XG4gICAgY29sb3I6ICRsaWdodC1jb2xvcjtcbiAgfVxuICAmOmFjdGl2ZSxcbiAgJi5hY3RpdmUge1xuICAgIGJhY2tncm91bmQ6IGRhcmtlbigkY29sb3IsIDclKTtcbiAgICBib3JkZXItY29sb3I6IGRhcmtlbigkY29sb3IsIDEwJSk7XG4gICAgY29sb3I6ICRsaWdodC1jb2xvcjtcbiAgfVxuICAmLmxvYWRpbmcge1xuICAgICY6OmFmdGVyIHtcbiAgICAgIGJvcmRlci1ib3R0b20tY29sb3I6ICRsaWdodC1jb2xvcjtcbiAgICAgIGJvcmRlci1sZWZ0LWNvbG9yOiAkbGlnaHQtY29sb3I7XG4gICAgfVxuICB9XG59XG5cbkBtaXhpbiBidXR0b24tb3V0bGluZS12YXJpYW50KCRjb2xvcjogJHByaW1hcnktY29sb3IpIHtcbiAgYmFja2dyb3VuZDogJGxpZ2h0LWNvbG9yO1xuICBib3JkZXItY29sb3I6ICRjb2xvcjtcbiAgY29sb3I6ICRjb2xvcjtcbiAgJjpmb2N1cyB7XG4gICAgQGluY2x1ZGUgY29udHJvbC1zaGFkb3coJGNvbG9yKTtcbiAgfVxuICAmOmZvY3VzLFxuICAmOmhvdmVyIHtcbiAgICBiYWNrZ3JvdW5kOiBsaWdodGVuKCRjb2xvciwgNTAlKTtcbiAgICBib3JkZXItY29sb3I6IGRhcmtlbigkY29sb3IsIDIlKTtcbiAgICBjb2xvcjogJGNvbG9yO1xuICB9XG4gICY6YWN0aXZlLFxuICAmLmFjdGl2ZSB7XG4gICAgYmFja2dyb3VuZDogJGNvbG9yO1xuICAgIGJvcmRlci1jb2xvcjogZGFya2VuKCRjb2xvciwgNSUpO1xuICAgIGNvbG9yOiAkbGlnaHQtY29sb3I7XG4gIH1cbiAgJi5sb2FkaW5nIHtcbiAgICAmOjphZnRlciB7XG4gICAgICBib3JkZXItYm90dG9tLWNvbG9yOiAkY29sb3I7XG4gICAgICBib3JkZXItbGVmdC1jb2xvcjogJGNvbG9yO1xuICAgIH1cbiAgfVxufVxuIiwiLy8gQ2xlYXJmaXggbWl4aW5cbkBtaXhpbiBjbGVhcmZpeCgpIHtcbiAgJjo6YWZ0ZXIge1xuICAgIGNsZWFyOiBib3RoO1xuICAgIGNvbnRlbnQ6IFwiXCI7XG4gICAgZGlzcGxheTogdGFibGU7XG4gIH1cbn1cbiIsIi8vIEJhY2tncm91bmQgY29sb3IgdXRpbGl0eSBtaXhpblxuQG1peGluIGJnLWNvbG9yLXZhcmlhbnQoJG5hbWU6IFwiLmJnLXByaW1hcnlcIiwgJGNvbG9yOiAkcHJpbWFyeS1jb2xvcikge1xuICAjeyRuYW1lfSB7XG4gICAgYmFja2dyb3VuZDogJGNvbG9yO1xuXG4gICAgQGlmIChsaWdodG5lc3MoJGNvbG9yKSA8IDYwKSB7XG4gICAgICBjb2xvcjogJGxpZ2h0LWNvbG9yO1xuICAgIH1cbiAgfVxufVxuXG4vLyBUZXh0IGNvbG9yIHV0aWxpdHkgbWl4aW5cbkBtaXhpbiB0ZXh0LWNvbG9yLXZhcmlhbnQoJG5hbWU6IFwiLnRleHQtcHJpbWFyeVwiLCAkY29sb3I6ICRwcmltYXJ5LWNvbG9yKSB7XG4gICN7JG5hbWV9IHtcbiAgICBjb2xvcjogJGNvbG9yO1xuICB9XG5cbiAgYSN7JG5hbWV9IHtcbiAgICAmOmZvY3VzLFxuICAgICY6aG92ZXIge1xuICAgICAgY29sb3I6IGRhcmtlbigkY29sb3IsIDUlKTtcbiAgICB9XG4gICAgJjp2aXNpdGVkIHtcbiAgICAgIGNvbG9yOiBsaWdodGVuKCRjb2xvciwgNSUpO1xuICAgIH1cbiAgfVxufVxuIiwiLy8gTGFiZWwgYmFzZSBzdHlsZVxuQG1peGluIGxhYmVsLWJhc2UoKSB7XG4gIGJvcmRlci1yYWRpdXM6ICRib3JkZXItcmFkaXVzO1xuICBsaW5lLWhlaWdodDogMS4yO1xuICBwYWRkaW5nOiAuMXJlbSAuMnJlbTtcbn1cblxuQG1peGluIGxhYmVsLXZhcmlhbnQoJGNvbG9yOiAkbGlnaHQtY29sb3IsICRiZy1jb2xvcjogJHByaW1hcnktY29sb3IpIHtcbiAgYmFja2dyb3VuZDogJGJnLWNvbG9yO1xuICBjb2xvcjogJGNvbG9yO1xufVxuIiwiLy8gTWFyZ2luIHV0aWxpdHkgbWl4aW5cbkBtaXhpbiBtYXJnaW4tdmFyaWFudCgkaWQ6IDEsICRzaXplOiAkdW5pdC0xKSB7XG4gIC5tLSN7JGlkfSB7XG4gICAgbWFyZ2luOiAkc2l6ZSAhaW1wb3J0YW50O1xuICB9XG5cbiAgLm1iLSN7JGlkfSB7XG4gICAgbWFyZ2luLWJvdHRvbTogJHNpemUgIWltcG9ydGFudDtcbiAgfVxuXG4gIC5tbC0jeyRpZH0ge1xuICAgIG1hcmdpbi1sZWZ0OiAkc2l6ZSAhaW1wb3J0YW50O1xuICB9XG5cbiAgLm1yLSN7JGlkfSB7XG4gICAgbWFyZ2luLXJpZ2h0OiAkc2l6ZSAhaW1wb3J0YW50O1xuICB9XG5cbiAgLm10LSN7JGlkfSB7XG4gICAgbWFyZ2luLXRvcDogJHNpemUgIWltcG9ydGFudDtcbiAgfVxuXG4gIC5teC0jeyRpZH0ge1xuICAgIG1hcmdpbi1sZWZ0OiAkc2l6ZSAhaW1wb3J0YW50O1xuICAgIG1hcmdpbi1yaWdodDogJHNpemUgIWltcG9ydGFudDtcbiAgfVxuXG4gIC5teS0jeyRpZH0ge1xuICAgIG1hcmdpbi1ib3R0b206ICRzaXplICFpbXBvcnRhbnQ7XG4gICAgbWFyZ2luLXRvcDogJHNpemUgIWltcG9ydGFudDtcbiAgfVxufVxuXG4vLyBQYWRkaW5nIHV0aWxpdHkgbWl4aW5cbkBtaXhpbiBwYWRkaW5nLXZhcmlhbnQoJGlkOiAxLCAkc2l6ZTogJHVuaXQtMSkge1xuICAucC0jeyRpZH0ge1xuICAgIHBhZGRpbmc6ICRzaXplICFpbXBvcnRhbnQ7XG4gIH1cblxuICAucGItI3skaWR9IHtcbiAgICBwYWRkaW5nLWJvdHRvbTogJHNpemUgIWltcG9ydGFudDtcbiAgfVxuXG4gIC5wbC0jeyRpZH0ge1xuICAgIHBhZGRpbmctbGVmdDogJHNpemUgIWltcG9ydGFudDtcbiAgfVxuXG4gIC5wci0jeyRpZH0ge1xuICAgIHBhZGRpbmctcmlnaHQ6ICRzaXplICFpbXBvcnRhbnQ7XG4gIH1cblxuICAucHQtI3skaWR9IHtcbiAgICBwYWRkaW5nLXRvcDogJHNpemUgIWltcG9ydGFudDtcbiAgfVxuXG4gIC5weC0jeyRpZH0ge1xuICAgIHBhZGRpbmctbGVmdDogJHNpemUgIWltcG9ydGFudDtcbiAgICBwYWRkaW5nLXJpZ2h0OiAkc2l6ZSAhaW1wb3J0YW50O1xuICB9XG4gIFxuICAucHktI3skaWR9IHtcbiAgICBwYWRkaW5nLWJvdHRvbTogJHNpemUgIWltcG9ydGFudDtcbiAgICBwYWRkaW5nLXRvcDogJHNpemUgIWltcG9ydGFudDtcbiAgfVxufVxuIiwiLy8gQ29tcG9uZW50IGZvY3VzIHNoYWRvd1xuQG1peGluIGNvbnRyb2wtc2hhZG93KCRjb2xvcjogJHByaW1hcnktY29sb3IpIHtcbiAgYm94LXNoYWRvdzogMCAwIDAgLjFyZW0gcmdiYSgkY29sb3IsIC4yKTtcbn1cblxuLy8gU2hhZG93IG1peGluXG5AbWl4aW4gc2hhZG93LXZhcmlhbnQoJG9mZnNldCkge1xuICBib3gtc2hhZG93OiAwICRvZmZzZXQgKCRvZmZzZXQgKyAuMDVyZW0pICogMiByZ2JhKCRkYXJrLWNvbG9yLCAuMyk7XG59XG4iLCIvLyBUZXh0IEVsbGlwc2lzXG5AbWl4aW4gdGV4dC1lbGxpcHNpcygpIHtcbiAgb3ZlcmZsb3c6IGhpZGRlbjtcbiAgdGV4dC1vdmVyZmxvdzogZWxsaXBzaXM7XG4gIHdoaXRlLXNwYWNlOiBub3dyYXA7XG59XG4iLCIvLyBUb2FzdCB2YXJpYW50IG1peGluXG5AbWl4aW4gdG9hc3QtdmFyaWFudCgkY29sb3I6ICRkYXJrLWNvbG9yKSB7XG4gIGJhY2tncm91bmQ6IHJnYmEoJGNvbG9yLCAuOSk7XG4gIGJvcmRlci1jb2xvcjogJGNvbG9yO1xufVxuIiwiLy8gQ29tcG9uZW50IHRyYW5zaXRpb25cbkBtaXhpbiBjb250cm9sLXRyYW5zaXRpb24oKSB7XG4gIHRyYW5zaXRpb246IGFsbCAuMnMgZWFzZTtcbn1cbiIsIi8qIE1hbnVhbGx5IGZvcmtlZCBmcm9tIE5vcm1hbGl6ZS5jc3MgKi9cbi8qIG5vcm1hbGl6ZS5jc3MgdjUuMC4wIHwgTUlUIExpY2Vuc2UgfCBnaXRodWIuY29tL25lY29sYXMvbm9ybWFsaXplLmNzcyAqL1xuXG4vKipcbiAqIDEuIENoYW5nZSB0aGUgZGVmYXVsdCBmb250IGZhbWlseSBpbiBhbGwgYnJvd3NlcnMgKG9waW5pb25hdGVkKS5cbiAqIDIuIENvcnJlY3QgdGhlIGxpbmUgaGVpZ2h0IGluIGFsbCBicm93c2Vycy5cbiAqIDMuIFByZXZlbnQgYWRqdXN0bWVudHMgb2YgZm9udCBzaXplIGFmdGVyIG9yaWVudGF0aW9uIGNoYW5nZXMgaW5cbiAqICAgIElFIG9uIFdpbmRvd3MgUGhvbmUgYW5kIGluIGlPUy5cbiAqL1xuXG4vKiBEb2N1bWVudFxuICAgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0gKi9cblxuaHRtbCB7XG4gIGZvbnQtZmFtaWx5OiBzYW5zLXNlcmlmOyAvKiAxICovXG4gIC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAvKiAzICovXG4gIC13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLyogMyAqL1xufVxuXG4vKiBTZWN0aW9uc1xuICAgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0gKi9cblxuLyoqXG4gKiBSZW1vdmUgdGhlIG1hcmdpbiBpbiBhbGwgYnJvd3NlcnMgKG9waW5pb25hdGVkKS5cbiAqL1xuXG5ib2R5IHtcbiAgbWFyZ2luOiAwO1xufVxuXG4vKipcbiAqIEFkZCB0aGUgY29ycmVjdCBkaXNwbGF5IGluIElFIDktLlxuICovXG5cbmFydGljbGUsXG5hc2lkZSxcbmZvb3RlcixcbmhlYWRlcixcbm5hdixcbnNlY3Rpb24ge1xuICBkaXNwbGF5OiBibG9jaztcbn1cblxuLyoqXG4gKiBDb3JyZWN0IHRoZSBmb250IHNpemUgYW5kIG1hcmdpbiBvbiBgaDFgIGVsZW1lbnRzIHdpdGhpbiBgc2VjdGlvbmAgYW5kXG4gKiBgYXJ0aWNsZWAgY29udGV4dHMgaW4gQ2hyb21lLCBGaXJlZm94LCBhbmQgU2FmYXJpLlxuICovXG5cbmgxIHtcbiAgZm9udC1zaXplOiAyZW07XG4gIG1hcmdpbjogMC42N2VtIDA7XG59XG5cbi8qIEdyb3VwaW5nIGNvbnRlbnRcbiAgID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09ICovXG5cbi8qKlxuICogQWRkIHRoZSBjb3JyZWN0IGRpc3BsYXkgaW4gSUUgOS0uXG4gKiAxLiBBZGQgdGhlIGNvcnJlY3QgZGlzcGxheSBpbiBJRS5cbiAqL1xuXG5maWdjYXB0aW9uLFxuZmlndXJlLFxubWFpbiB7IC8qIDEgKi9cbiAgZGlzcGxheTogYmxvY2s7XG59XG5cbi8qKlxuICogQWRkIHRoZSBjb3JyZWN0IG1hcmdpbiBpbiBJRSA4IChyZW1vdmVkKS5cbiAqL1xuXG4vKipcbiAqIDEuIEFkZCB0aGUgY29ycmVjdCBib3ggc2l6aW5nIGluIEZpcmVmb3guXG4gKiAyLiBTaG93IHRoZSBvdmVyZmxvdyBpbiBFZGdlIGFuZCBJRS5cbiAqL1xuXG5ociB7XG4gIGJveC1zaXppbmc6IGNvbnRlbnQtYm94OyAvKiAxICovXG4gIGhlaWdodDogMDsgLyogMSAqL1xuICBvdmVyZmxvdzogdmlzaWJsZTsgLyogMiAqL1xufVxuXG4vKipcbiAqIDEuIENvcnJlY3QgdGhlIGluaGVyaXRhbmNlIGFuZCBzY2FsaW5nIG9mIGZvbnQgc2l6ZSBpbiBhbGwgYnJvd3NlcnMuIChyZW1vdmVkKVxuICogMi4gQ29ycmVjdCB0aGUgb2RkIGBlbWAgZm9udCBzaXppbmcgaW4gYWxsIGJyb3dzZXJzLlxuICovXG5cbi8qIFRleHQtbGV2ZWwgc2VtYW50aWNzXG4gICA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSAqL1xuXG4vKipcbiAqIDEuIFJlbW92ZSB0aGUgZ3JheSBiYWNrZ3JvdW5kIG9uIGFjdGl2ZSBsaW5rcyBpbiBJRSAxMC5cbiAqIDIuIFJlbW92ZSBnYXBzIGluIGxpbmtzIHVuZGVybGluZSBpbiBpT1MgOCsgYW5kIFNhZmFyaSA4Ky5cbiAqL1xuXG5hIHtcbiAgYmFja2dyb3VuZC1jb2xvcjogdHJhbnNwYXJlbnQ7IC8qIDEgKi9cbiAgLXdlYmtpdC10ZXh0LWRlY29yYXRpb24tc2tpcDogb2JqZWN0czsgLyogMiAqL1xufVxuXG4vKipcbiAqIFJlbW92ZSB0aGUgb3V0bGluZSBvbiBmb2N1c2VkIGxpbmtzIHdoZW4gdGhleSBhcmUgYWxzbyBhY3RpdmUgb3IgaG92ZXJlZFxuICogaW4gYWxsIGJyb3dzZXJzIChvcGluaW9uYXRlZCkuXG4gKi9cblxuYTphY3RpdmUsXG5hOmhvdmVyIHtcbiAgb3V0bGluZS13aWR0aDogMDtcbn1cblxuLyoqXG4gKiBNb2RpZnkgZGVmYXVsdCBzdHlsaW5nIG9mIGFkZHJlc3MuXG4gKi9cblxuYWRkcmVzcyB7XG4gIGZvbnQtc3R5bGU6IG5vcm1hbDtcbn1cblxuLyoqXG4gKiAxLiBSZW1vdmUgdGhlIGJvdHRvbSBib3JkZXIgaW4gRmlyZWZveCAzOS0uXG4gKiAyLiBBZGQgdGhlIGNvcnJlY3QgdGV4dCBkZWNvcmF0aW9uIGluIENocm9tZSwgRWRnZSwgSUUsIE9wZXJhLCBhbmQgU2FmYXJpLiAocmVtb3ZlZClcbiAqL1xuXG4vKipcbiAqIFByZXZlbnQgdGhlIGR1cGxpY2F0ZSBhcHBsaWNhdGlvbiBvZiBgYm9sZGVyYCBieSB0aGUgbmV4dCBydWxlIGluIFNhZmFyaSA2LlxuICovXG5cbmIsXG5zdHJvbmcge1xuICBmb250LXdlaWdodDogaW5oZXJpdDtcbn1cblxuLyoqXG4gKiBBZGQgdGhlIGNvcnJlY3QgZm9udCB3ZWlnaHQgaW4gQ2hyb21lLCBFZGdlLCBhbmQgU2FmYXJpLlxuICovXG5cbmIsXG5zdHJvbmcge1xuICBmb250LXdlaWdodDogYm9sZGVyO1xufVxuXG4vKipcbiAqIDEuIENvcnJlY3QgdGhlIGluaGVyaXRhbmNlIGFuZCBzY2FsaW5nIG9mIGZvbnQgc2l6ZSBpbiBhbGwgYnJvd3NlcnMuXG4gKiAyLiBDb3JyZWN0IHRoZSBvZGQgYGVtYCBmb250IHNpemluZyBpbiBhbGwgYnJvd3NlcnMuXG4gKi9cblxuY29kZSxcbmtiZCxcbnByZSxcbnNhbXAge1xuICBmb250LWZhbWlseTogJG1vbm8tZm9udC1mYW1pbHk7IC8qIDEgKGNoYW5nZWQpICovXG4gIGZvbnQtc2l6ZTogMWVtOyAvKiAyICovXG59XG5cbi8qKlxuICogQWRkIHRoZSBjb3JyZWN0IGZvbnQgc3R5bGUgaW4gQW5kcm9pZCA0LjMtLlxuICovXG5cbmRmbiB7XG4gIGZvbnQtc3R5bGU6IGl0YWxpYztcbn1cblxuLyoqXG4gKiBBZGQgdGhlIGNvcnJlY3QgYmFja2dyb3VuZCBhbmQgY29sb3IgaW4gSUUgOS0uIChSZW1vdmVkKVxuICovXG5cbi8qKlxuICogQWRkIHRoZSBjb3JyZWN0IGZvbnQgc2l6ZSBpbiBhbGwgYnJvd3NlcnMuXG4gKi9cblxuc21hbGwge1xuICBmb250LXNpemU6IDgwJTtcbiAgZm9udC13ZWlnaHQ6IDQwMDsgLyogKGFkZGVkKSAqL1xufVxuXG4vKipcbiAqIFByZXZlbnQgYHN1YmAgYW5kIGBzdXBgIGVsZW1lbnRzIGZyb20gYWZmZWN0aW5nIHRoZSBsaW5lIGhlaWdodCBpblxuICogYWxsIGJyb3dzZXJzLlxuICovXG5cbnN1YixcbnN1cCB7XG4gIGZvbnQtc2l6ZTogNzUlO1xuICBsaW5lLWhlaWdodDogMDtcbiAgcG9zaXRpb246IHJlbGF0aXZlO1xuICB2ZXJ0aWNhbC1hbGlnbjogYmFzZWxpbmU7XG59XG5cbnN1YiB7XG4gIGJvdHRvbTogLTAuMjVlbTtcbn1cblxuc3VwIHtcbiAgdG9wOiAtMC41ZW07XG59XG5cbi8qIEVtYmVkZGVkIGNvbnRlbnRcbiAgID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09ICovXG5cbi8qKlxuICogQWRkIHRoZSBjb3JyZWN0IGRpc3BsYXkgaW4gSUUgOS0uXG4gKi9cblxuYXVkaW8sXG52aWRlbyB7XG4gIGRpc3BsYXk6IGlubGluZS1ibG9jaztcbn1cblxuLyoqXG4gKiBBZGQgdGhlIGNvcnJlY3QgZGlzcGxheSBpbiBpT1MgNC03LlxuICovXG5cbmF1ZGlvOm5vdChbY29udHJvbHNdKSB7XG4gIGRpc3BsYXk6IG5vbmU7XG4gIGhlaWdodDogMDtcbn1cblxuLyoqXG4gKiBSZW1vdmUgdGhlIGJvcmRlciBvbiBpbWFnZXMgaW5zaWRlIGxpbmtzIGluIElFIDEwLS5cbiAqL1xuXG5pbWcge1xuICBib3JkZXItc3R5bGU6IG5vbmU7XG59XG5cbi8qKlxuICogSGlkZSB0aGUgb3ZlcmZsb3cgaW4gSUUuXG4gKi9cblxuc3ZnOm5vdCg6cm9vdCkge1xuICBvdmVyZmxvdzogaGlkZGVuO1xufVxuXG4vKiBGb3Jtc1xuICAgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0gKi9cblxuLyoqXG4gKiAxLiBDaGFuZ2UgdGhlIGZvbnQgc3R5bGVzIGluIGFsbCBicm93c2VycyAob3BpbmlvbmF0ZWQpLlxuICogMi4gUmVtb3ZlIHRoZSBtYXJnaW4gaW4gRmlyZWZveCBhbmQgU2FmYXJpLlxuICovXG5cbmJ1dHRvbixcbmlucHV0LFxub3B0Z3JvdXAsXG5zZWxlY3QsXG50ZXh0YXJlYSB7XG4gIGZvbnQtZmFtaWx5OiBpbmhlcml0OyAvKiAxIChjaGFuZ2VkKSAqL1xuICBmb250LXNpemU6IGluaGVyaXQ7IC8qIDEgKGNoYW5nZWQpICovXG4gIGxpbmUtaGVpZ2h0OiBpbmhlcml0OyAvKiAxIChjaGFuZ2VkKSAqL1xuICBtYXJnaW46IDA7IC8qIDIgKi9cbn1cblxuLyoqXG4gKiBTaG93IHRoZSBvdmVyZmxvdyBpbiBJRS5cbiAqIDEuIFNob3cgdGhlIG92ZXJmbG93IGluIEVkZ2UuXG4gKi9cblxuYnV0dG9uLFxuaW5wdXQgeyAvKiAxICovXG4gIG92ZXJmbG93OiB2aXNpYmxlO1xufVxuXG4vKipcbiAqIFJlbW92ZSB0aGUgaW5oZXJpdGFuY2Ugb2YgdGV4dCB0cmFuc2Zvcm0gaW4gRWRnZSwgRmlyZWZveCwgYW5kIElFLlxuICogMS4gUmVtb3ZlIHRoZSBpbmhlcml0YW5jZSBvZiB0ZXh0IHRyYW5zZm9ybSBpbiBGaXJlZm94LlxuICovXG5cbmJ1dHRvbixcbnNlbGVjdCB7IC8qIDEgKi9cbiAgdGV4dC10cmFuc2Zvcm06IG5vbmU7XG59XG5cbi8qKlxuICogMS4gUHJldmVudCBhIFdlYktpdCBidWcgd2hlcmUgKDIpIGRlc3Ryb3lzIG5hdGl2ZSBgYXVkaW9gIGFuZCBgdmlkZW9gXG4gKiAgICBjb250cm9scyBpbiBBbmRyb2lkIDQuXG4gKiAyLiBDb3JyZWN0IHRoZSBpbmFiaWxpdHkgdG8gc3R5bGUgY2xpY2thYmxlIHR5cGVzIGluIGlPUyBhbmQgU2FmYXJpLlxuICovXG5cbmJ1dHRvbixcbmh0bWwgW3R5cGU9XCJidXR0b25cIl0sIC8qIDEgKi9cblt0eXBlPVwicmVzZXRcIl0sXG5bdHlwZT1cInN1Ym1pdFwiXSB7XG4gIC13ZWJraXQtYXBwZWFyYW5jZTogYnV0dG9uOyAvKiAyICovXG59XG5cbi8qKlxuICogUmVtb3ZlIHRoZSBpbm5lciBib3JkZXIgYW5kIHBhZGRpbmcgaW4gRmlyZWZveC5cbiAqL1xuXG5idXR0b246Oi1tb3otZm9jdXMtaW5uZXIsXG5bdHlwZT1cImJ1dHRvblwiXTo6LW1vei1mb2N1cy1pbm5lcixcblt0eXBlPVwicmVzZXRcIl06Oi1tb3otZm9jdXMtaW5uZXIsXG5bdHlwZT1cInN1Ym1pdFwiXTo6LW1vei1mb2N1cy1pbm5lciB7XG4gIGJvcmRlci1zdHlsZTogbm9uZTtcbiAgcGFkZGluZzogMDtcbn1cblxuLyoqXG4gKiBSZXN0b3JlIHRoZSBmb2N1cyBzdHlsZXMgdW5zZXQgYnkgdGhlIHByZXZpb3VzIHJ1bGUgKHJlbW92ZWQpLlxuICovXG5cblxuLyoqXG4gKiBDaGFuZ2UgdGhlIGJvcmRlciwgbWFyZ2luLCBhbmQgcGFkZGluZyBpbiBhbGwgYnJvd3NlcnMgKG9waW5pb25hdGVkKSAoY2hhbmdlZCkuXG4gKi9cblxuZmllbGRzZXQge1xuICBib3JkZXI6IDA7XG4gIG1hcmdpbjogMDtcbiAgcGFkZGluZzogMDtcbn1cblxuLyoqXG4gKiAxLiBDb3JyZWN0IHRoZSB0ZXh0IHdyYXBwaW5nIGluIEVkZ2UgYW5kIElFLlxuICogMi4gQ29ycmVjdCB0aGUgY29sb3IgaW5oZXJpdGFuY2UgZnJvbSBgZmllbGRzZXRgIGVsZW1lbnRzIGluIElFLlxuICogMy4gUmVtb3ZlIHRoZSBwYWRkaW5nIHNvIGRldmVsb3BlcnMgYXJlIG5vdCBjYXVnaHQgb3V0IHdoZW4gdGhleSB6ZXJvIG91dFxuICogICAgYGZpZWxkc2V0YCBlbGVtZW50cyBpbiBhbGwgYnJvd3NlcnMuXG4gKi9cblxubGVnZW5kIHtcbiAgYm94LXNpemluZzogYm9yZGVyLWJveDsgLyogMSAqL1xuICBjb2xvcjogaW5oZXJpdDsgLyogMiAqL1xuICBkaXNwbGF5OiB0YWJsZTsgLyogMSAqL1xuICBtYXgtd2lkdGg6IDEwMCU7IC8qIDEgKi9cbiAgcGFkZGluZzogMDsgLyogMyAqL1xuICB3aGl0ZS1zcGFjZTogbm9ybWFsOyAvKiAxICovXG59XG5cbi8qKlxuICogMS4gQWRkIHRoZSBjb3JyZWN0IGRpc3BsYXkgaW4gSUUgOS0uXG4gKiAyLiBBZGQgdGhlIGNvcnJlY3QgdmVydGljYWwgYWxpZ25tZW50IGluIENocm9tZSwgRmlyZWZveCwgYW5kIE9wZXJhLlxuICovXG5cbnByb2dyZXNzIHtcbiAgZGlzcGxheTogaW5saW5lLWJsb2NrOyAvKiAxICovXG4gIHZlcnRpY2FsLWFsaWduOiBiYXNlbGluZTsgLyogMiAqL1xufVxuXG4vKipcbiAqIFJlbW92ZSB0aGUgZGVmYXVsdCB2ZXJ0aWNhbCBzY3JvbGxiYXIgaW4gSUUuXG4gKi9cblxudGV4dGFyZWEge1xuICBvdmVyZmxvdzogYXV0bztcbn1cblxuLyoqXG4gKiAxLiBBZGQgdGhlIGNvcnJlY3QgYm94IHNpemluZyBpbiBJRSAxMC0uXG4gKiAyLiBSZW1vdmUgdGhlIHBhZGRpbmcgaW4gSUUgMTAtLlxuICovXG5cblt0eXBlPVwiY2hlY2tib3hcIl0sXG5bdHlwZT1cInJhZGlvXCJdIHtcbiAgYm94LXNpemluZzogYm9yZGVyLWJveDsgLyogMSAqL1xuICBwYWRkaW5nOiAwOyAvKiAyICovXG59XG5cbi8qKlxuICogQ29ycmVjdCB0aGUgY3Vyc29yIHN0eWxlIG9mIGluY3JlbWVudCBhbmQgZGVjcmVtZW50IGJ1dHRvbnMgaW4gQ2hyb21lLlxuICovXG5cblt0eXBlPVwibnVtYmVyXCJdOjotd2Via2l0LWlubmVyLXNwaW4tYnV0dG9uLFxuW3R5cGU9XCJudW1iZXJcIl06Oi13ZWJraXQtb3V0ZXItc3Bpbi1idXR0b24ge1xuICBoZWlnaHQ6IGF1dG87XG59XG5cbi8qKlxuICogMS4gQ29ycmVjdCB0aGUgb2RkIGFwcGVhcmFuY2UgaW4gQ2hyb21lIGFuZCBTYWZhcmkuXG4gKiAyLiBDb3JyZWN0IHRoZSBvdXRsaW5lIHN0eWxlIGluIFNhZmFyaS5cbiAqL1xuXG5bdHlwZT1cInNlYXJjaFwiXSB7XG4gIC13ZWJraXQtYXBwZWFyYW5jZTogdGV4dGZpZWxkOyAvKiAxICovXG4gIG91dGxpbmUtb2Zmc2V0OiAtMnB4OyAvKiAyICovXG59XG5cbi8qKlxuICogUmVtb3ZlIHRoZSBpbm5lciBwYWRkaW5nIGFuZCBjYW5jZWwgYnV0dG9ucyBpbiBDaHJvbWUgYW5kIFNhZmFyaSBvbiBtYWNPUy5cbiAqL1xuXG5bdHlwZT1cInNlYXJjaFwiXTo6LXdlYmtpdC1zZWFyY2gtY2FuY2VsLWJ1dHRvbixcblt0eXBlPVwic2VhcmNoXCJdOjotd2Via2l0LXNlYXJjaC1kZWNvcmF0aW9uIHtcbiAgLXdlYmtpdC1hcHBlYXJhbmNlOiBub25lO1xufVxuXG4vKipcbiAqIDEuIENvcnJlY3QgdGhlIGluYWJpbGl0eSB0byBzdHlsZSBjbGlja2FibGUgdHlwZXMgaW4gaU9TIGFuZCBTYWZhcmkuXG4gKiAyLiBDaGFuZ2UgZm9udCBwcm9wZXJ0aWVzIHRvIGBpbmhlcml0YCBpbiBTYWZhcmkuXG4gKi9cblxuOjotd2Via2l0LWZpbGUtdXBsb2FkLWJ1dHRvbiB7XG4gIC13ZWJraXQtYXBwZWFyYW5jZTogYnV0dG9uOyAvKiAxICovXG4gIGZvbnQ6IGluaGVyaXQ7IC8qIDIgKi9cbn1cblxuLyogSW50ZXJhY3RpdmVcbiAgID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09ICovXG5cbi8qXG4gKiBBZGQgdGhlIGNvcnJlY3QgZGlzcGxheSBpbiBJRSA5LS5cbiAqIDEuIEFkZCB0aGUgY29ycmVjdCBkaXNwbGF5IGluIEVkZ2UsIElFLCBhbmQgRmlyZWZveC5cbiAqL1xuXG5kZXRhaWxzLCAvKiAxICovXG5tZW51IHtcbiAgZGlzcGxheTogYmxvY2s7XG59XG5cbi8qXG4gKiBBZGQgdGhlIGNvcnJlY3QgZGlzcGxheSBpbiBhbGwgYnJvd3NlcnMuXG4gKi9cblxuc3VtbWFyeSB7XG4gIGRpc3BsYXk6IGxpc3QtaXRlbTtcbiAgb3V0bGluZTogbm9uZTtcbn1cblxuLyogU2NyaXB0aW5nXG4gICA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSAqL1xuXG4vKipcbiAqIEFkZCB0aGUgY29ycmVjdCBkaXNwbGF5IGluIElFIDktLlxuICovXG5cbmNhbnZhcyB7XG4gIGRpc3BsYXk6IGlubGluZS1ibG9jaztcbn1cblxuLyoqXG4gKiBBZGQgdGhlIGNvcnJlY3QgZGlzcGxheSBpbiBJRS5cbiAqL1xuXG50ZW1wbGF0ZSB7XG4gIGRpc3BsYXk6IG5vbmU7XG59XG5cbi8qIEhpZGRlblxuICAgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0gKi9cblxuLyoqXG4gKiBBZGQgdGhlIGNvcnJlY3QgZGlzcGxheSBpbiBJRSAxMC0uXG4gKi9cblxuW2hpZGRlbl0ge1xuICBkaXNwbGF5OiBub25lO1xufVxuIiwiLy8gQmFzZVxuKixcbio6OmJlZm9yZSxcbio6OmFmdGVyIHtcbiAgYm94LXNpemluZzogaW5oZXJpdDtcbn1cblxuaHRtbCB7XG4gIGJveC1zaXppbmc6IGJvcmRlci1ib3g7XG4gIGZvbnQtc2l6ZTogJGh0bWwtZm9udC1zaXplO1xuICBsaW5lLWhlaWdodDogJGh0bWwtbGluZS1oZWlnaHQ7XG4gIC13ZWJraXQtdGFwLWhpZ2hsaWdodC1jb2xvcjogdHJhbnNwYXJlbnQ7XG59XG5cbmJvZHkge1xuICBiYWNrZ3JvdW5kOiAkYm9keS1iZztcbiAgY29sb3I6ICRib2R5LWZvbnQtY29sb3I7XG4gIGZvbnQtZmFtaWx5OiAkYm9keS1mb250LWZhbWlseTtcbiAgZm9udC1zaXplOiAkZm9udC1zaXplO1xuICBvdmVyZmxvdy14OiBoaWRkZW47XG4gIHRleHQtcmVuZGVyaW5nOiBvcHRpbWl6ZUxlZ2liaWxpdHk7XG59XG5cbmEge1xuICBjb2xvcjogJGxpbmstY29sb3I7XG4gIG91dGxpbmU6IG5vbmU7XG4gIHRleHQtZGVjb3JhdGlvbjogbm9uZTtcblxuICAmOmZvY3VzIHtcbiAgICBAaW5jbHVkZSBjb250cm9sLXNoYWRvdygpO1xuICB9XG5cbiAgJjpmb2N1cyxcbiAgJjpob3ZlcixcbiAgJjphY3RpdmUsXG4gICYuYWN0aXZlIHtcbiAgICBjb2xvcjogJGxpbmstY29sb3ItZGFyaztcbiAgICB0ZXh0LWRlY29yYXRpb246IHVuZGVybGluZTtcbiAgfVxuXG4gICY6dmlzaXRlZCB7XG4gICAgY29sb3I6ICRsaW5rLWNvbG9yLWxpZ2h0O1xuICB9XG59XG4iLCIvLyBUeXBvZ3JhcGh5XG4vLyBIZWFkaW5nc1xuaDEsXG5oMixcbmgzLFxuaDQsXG5oNSxcbmg2IHtcbiAgY29sb3I6IGluaGVyaXQ7XG4gIGZvbnQtd2VpZ2h0OiA1MDA7XG4gIGxpbmUtaGVpZ2h0OiAxLjI7XG4gIG1hcmdpbi1ib3R0b206IC41ZW07XG4gIG1hcmdpbi10b3A6IDA7XG59XG4uaDEsXG4uaDIsXG4uaDMsXG4uaDQsXG4uaDUsXG4uaDYge1xuICBmb250LXdlaWdodDogNTAwO1xufVxuaDEsXG4uaDEge1xuICBmb250LXNpemU6IDJyZW07XG59XG5oMixcbi5oMiB7XG4gIGZvbnQtc2l6ZTogMS42cmVtO1xufVxuaDMsXG4uaDMge1xuICBmb250LXNpemU6IDEuNHJlbTtcbn1cbmg0LFxuLmg0IHtcbiAgZm9udC1zaXplOiAxLjJyZW07XG59XG5oNSxcbi5oNSB7XG4gIGZvbnQtc2l6ZTogMXJlbTtcbn1cbmg2LFxuLmg2IHtcbiAgZm9udC1zaXplOiAuOHJlbTtcbn1cblxuLy8gUGFyYWdyYXBoc1xucCB7XG4gIG1hcmdpbjogMCAwICRsaW5lLWhlaWdodDtcbn1cblxuLy8gU2VtYW50aWMgdGV4dCBlbGVtZW50c1xuYSxcbmlucyxcbnUge1xuICB0ZXh0LWRlY29yYXRpb24tc2tpcDogaW5rIGVkZ2VzO1xufVxuXG5hYmJyW3RpdGxlXSB7XG4gIGJvcmRlci1ib3R0b206ICRib3JkZXItd2lkdGggZG90dGVkO1xuICBjdXJzb3I6IGhlbHA7XG4gIHRleHQtZGVjb3JhdGlvbjogbm9uZTtcbn1cblxua2JkIHtcbiAgQGluY2x1ZGUgbGFiZWwtYmFzZSgpO1xuICBAaW5jbHVkZSBsYWJlbC12YXJpYW50KCRsaWdodC1jb2xvciwgJGRhcmstY29sb3IpO1xuICBmb250LXNpemU6ICRmb250LXNpemUtc207XG59XG5cbm1hcmsge1xuICBAaW5jbHVkZSBsYWJlbC12YXJpYW50KCRib2R5LWZvbnQtY29sb3IsICRoaWdobGlnaHQtY29sb3IpO1xuICBib3JkZXItcmFkaXVzOiAkYm9yZGVyLXJhZGl1cztcbiAgcGFkZGluZzogLjA1cmVtO1xufVxuXG4vLyBCbG9ja3F1b3RlXG5ibG9ja3F1b3RlIHtcbiAgYm9yZGVyLWxlZnQ6ICRib3JkZXItd2lkdGgtbGcgc29saWQgJGJvcmRlci1jb2xvcjtcbiAgbWFyZ2luLWxlZnQ6IDA7XG4gIHBhZGRpbmc6ICR1bml0LTIgJHVuaXQtNDtcblxuICBwOmxhc3QtY2hpbGQge1xuICAgIG1hcmdpbi1ib3R0b206IDA7XG4gIH1cbn1cblxuLy8gTGlzdHNcbnVsLFxub2wge1xuICBtYXJnaW46ICR1bml0LTQgMCAkdW5pdC00ICR1bml0LTQ7XG4gIHBhZGRpbmc6IDA7XG5cbiAgdWwsXG4gIG9sIHtcbiAgICBtYXJnaW46ICR1bml0LTQgMCAkdW5pdC00ICR1bml0LTQ7XG4gIH1cblxuICBsaSB7XG4gICAgbWFyZ2luLXRvcDogJHVuaXQtMjtcbiAgfVxufVxuXG51bCB7XG4gIGxpc3Qtc3R5bGU6IGRpc2MgaW5zaWRlO1xuXG4gIHVsIHtcbiAgICBsaXN0LXN0eWxlLXR5cGU6IGNpcmNsZTtcbiAgfVxufVxuXG5vbCB7XG4gIGxpc3Qtc3R5bGU6IGRlY2ltYWwgaW5zaWRlO1xuXG4gIG9sIHtcbiAgICBsaXN0LXN0eWxlLXR5cGU6IGxvd2VyLWFscGhhO1xuICB9XG59XG5cbmRsIHtcbiAgZHQge1xuICAgIGZvbnQtd2VpZ2h0OiBib2xkO1xuICB9XG4gIGRkIHtcbiAgICBtYXJnaW46ICR1bml0LTIgMCAkdW5pdC00IDA7XG4gIH1cbn1cbiIsIi8vIE9wdGltaXplZCBmb3IgRWFzdCBBc2lhbiBDSktcbjpsYW5nKHpoKSxcbjpsYW5nKHpoLUhhbnMpIHtcbiAgZm9udC1mYW1pbHk6ICRjamstemgtaGFucy1mb250LWZhbWlseTtcbn1cblxuOmxhbmcoemgtSGFudCkge1xuICBmb250LWZhbWlseTogJGNqay16aC1oYW50LWZvbnQtZmFtaWx5O1xufVxuXG46bGFuZyhqYSkge1xuICBmb250LWZhbWlseTogJGNqay1qcC1mb250LWZhbWlseTtcbn1cblxuOmxhbmcoa28pIHtcbiAgZm9udC1mYW1pbHk6ICRjamsta28tZm9udC1mYW1pbHk7XG59XG5cbjpsYW5nKHpoKSxcbjpsYW5nKGphKSxcbi5jamsge1xuICBpbnMsXG4gIHUge1xuICAgIGJvcmRlci1ib3R0b206ICRib3JkZXItd2lkdGggc29saWQ7XG4gICAgdGV4dC1kZWNvcmF0aW9uOiBub25lO1xuICB9XG5cbiAgZGVsICsgZGVsLFxuICBkZWwgKyBzLFxuICBpbnMgKyBpbnMsXG4gIGlucyArIHUsXG4gIHMgKyBkZWwsXG4gIHMgKyBzLFxuICB1ICsgaW5zLFxuICB1ICsgdSB7XG4gICAgbWFyZ2luLWxlZnQ6IC4xMjVlbTtcbiAgfVxufVxuIiwiLy8gVGFibGVzXG4udGFibGUge1xuICBib3JkZXItY29sbGFwc2U6IGNvbGxhcHNlO1xuICBib3JkZXItc3BhY2luZzogMDtcbiAgd2lkdGg6IDEwMCU7XG4gIEBpZiAkcnRsID09IHRydWUge1xuICAgIHRleHQtYWxpZ246IHJpZ2h0O1xuICB9IEBlbHNlIHtcbiAgICB0ZXh0LWFsaWduOiBsZWZ0O1xuICB9XG5cbiAgJi50YWJsZS1zdHJpcGVkIHtcbiAgICB0Ym9keSB7XG4gICAgICB0cjpudGgtb2YtdHlwZShvZGQpIHtcbiAgICAgICAgYmFja2dyb3VuZDogJGJnLWNvbG9yO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gICYsXG4gICYudGFibGUtc3RyaXBlZCB7XG4gICAgdGJvZHkge1xuICAgICAgdHIge1xuICAgICAgICAmLmFjdGl2ZSB7XG4gICAgICAgICAgYmFja2dyb3VuZDogJGJnLWNvbG9yLWRhcms7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAmLnRhYmxlLWhvdmVyIHtcbiAgICB0Ym9keSB7XG4gICAgICB0ciB7XG4gICAgICAgICY6aG92ZXIge1xuICAgICAgICAgIGJhY2tncm91bmQ6ICRiZy1jb2xvci1kYXJrO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLy8gVGFibGVzIHdpdGggaG9yaXpvbnRhbCBzY3JvbGxiYXJcbiAgJi50YWJsZS1zY3JvbGwge1xuICAgIGRpc3BsYXk6IGJsb2NrO1xuICAgIG92ZXJmbG93LXg6IGF1dG87XG4gICAgcGFkZGluZy1ib3R0b206IC43NXJlbTtcbiAgICB3aGl0ZS1zcGFjZTogbm93cmFwO1xuICB9XG5cbiAgdGQsXG4gIHRoIHtcbiAgICBib3JkZXItYm90dG9tOiAkYm9yZGVyLXdpZHRoIHNvbGlkICRib3JkZXItY29sb3I7XG4gICAgcGFkZGluZzogJHVuaXQtMyAkdW5pdC0yO1xuICB9XG4gIHRoIHtcbiAgICBib3JkZXItYm90dG9tLXdpZHRoOiAkYm9yZGVyLXdpZHRoLWxnO1xuICB9XG59XG4iLCIvLyBCdXR0b25zXG4uYnRuIHtcbiAgQGluY2x1ZGUgY29udHJvbC10cmFuc2l0aW9uKCk7XG4gIGFwcGVhcmFuY2U6IG5vbmU7XG4gIGJhY2tncm91bmQ6ICRiZy1jb2xvci1saWdodDtcbiAgYm9yZGVyOiAkYm9yZGVyLXdpZHRoIHNvbGlkICRwcmltYXJ5LWNvbG9yO1xuICBib3JkZXItcmFkaXVzOiAkYm9yZGVyLXJhZGl1cztcbiAgY29sb3I6ICRwcmltYXJ5LWNvbG9yO1xuICBjdXJzb3I6IHBvaW50ZXI7XG4gIGRpc3BsYXk6IGlubGluZS1ibG9jaztcbiAgZm9udC1zaXplOiAkZm9udC1zaXplO1xuICBoZWlnaHQ6ICRjb250cm9sLXNpemU7XG4gIGxpbmUtaGVpZ2h0OiAkbGluZS1oZWlnaHQ7XG4gIG91dGxpbmU6IG5vbmU7XG4gIHBhZGRpbmc6ICRjb250cm9sLXBhZGRpbmcteSAkY29udHJvbC1wYWRkaW5nLXg7XG4gIHRleHQtYWxpZ246IGNlbnRlcjtcbiAgdGV4dC1kZWNvcmF0aW9uOiBub25lO1xuICB1c2VyLXNlbGVjdDogbm9uZTtcbiAgdmVydGljYWwtYWxpZ246IG1pZGRsZTtcbiAgd2hpdGUtc3BhY2U6IG5vd3JhcDtcbiAgJjpmb2N1cyB7XG4gICAgQGluY2x1ZGUgY29udHJvbC1zaGFkb3coKTtcbiAgfVxuICAmOmZvY3VzLFxuICAmOmhvdmVyIHtcbiAgICBiYWNrZ3JvdW5kOiAkc2Vjb25kYXJ5LWNvbG9yO1xuICAgIGJvcmRlci1jb2xvcjogJHByaW1hcnktY29sb3ItZGFyaztcbiAgICB0ZXh0LWRlY29yYXRpb246IG5vbmU7XG4gIH1cbiAgJjphY3RpdmUsXG4gICYuYWN0aXZlIHtcbiAgICBiYWNrZ3JvdW5kOiAkcHJpbWFyeS1jb2xvci1kYXJrO1xuICAgIGJvcmRlci1jb2xvcjogZGFya2VuKCRwcmltYXJ5LWNvbG9yLWRhcmssIDUlKTtcbiAgICBjb2xvcjogJGxpZ2h0LWNvbG9yO1xuICAgIHRleHQtZGVjb3JhdGlvbjogbm9uZTtcbiAgICAmLmxvYWRpbmcge1xuICAgICAgJjo6YWZ0ZXIge1xuICAgICAgICBib3JkZXItYm90dG9tLWNvbG9yOiAkbGlnaHQtY29sb3I7XG4gICAgICAgIGJvcmRlci1sZWZ0LWNvbG9yOiAkbGlnaHQtY29sb3I7XG4gICAgICB9XG4gICAgfVxuICB9XG4gICZbZGlzYWJsZWRdLFxuICAmOmRpc2FibGVkLFxuICAmLmRpc2FibGVkIHtcbiAgICBjdXJzb3I6IGRlZmF1bHQ7XG4gICAgb3BhY2l0eTogLjU7XG4gICAgcG9pbnRlci1ldmVudHM6IG5vbmU7XG4gIH1cblxuICAvLyBCdXR0b24gUHJpbWFyeVxuICAmLmJ0bi1wcmltYXJ5IHtcbiAgICBiYWNrZ3JvdW5kOiAkcHJpbWFyeS1jb2xvcjtcbiAgICBib3JkZXItY29sb3I6ICRwcmltYXJ5LWNvbG9yLWRhcms7XG4gICAgY29sb3I6ICRsaWdodC1jb2xvcjtcbiAgICAmOmZvY3VzLFxuICAgICY6aG92ZXIge1xuICAgICAgYmFja2dyb3VuZDogZGFya2VuKCRwcmltYXJ5LWNvbG9yLWRhcmssIDIlKTtcbiAgICAgIGJvcmRlci1jb2xvcjogZGFya2VuKCRwcmltYXJ5LWNvbG9yLWRhcmssIDUlKTtcbiAgICAgIGNvbG9yOiAkbGlnaHQtY29sb3I7XG4gICAgfVxuICAgICY6YWN0aXZlLFxuICAgICYuYWN0aXZlIHtcbiAgICAgIGJhY2tncm91bmQ6IGRhcmtlbigkcHJpbWFyeS1jb2xvci1kYXJrLCA0JSk7XG4gICAgICBib3JkZXItY29sb3I6IGRhcmtlbigkcHJpbWFyeS1jb2xvci1kYXJrLCA3JSk7XG4gICAgICBjb2xvcjogJGxpZ2h0LWNvbG9yO1xuICAgIH1cbiAgICAmLmxvYWRpbmcge1xuICAgICAgJjo6YWZ0ZXIge1xuICAgICAgICBib3JkZXItYm90dG9tLWNvbG9yOiAkbGlnaHQtY29sb3I7XG4gICAgICAgIGJvcmRlci1sZWZ0LWNvbG9yOiAkbGlnaHQtY29sb3I7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLy8gQnV0dG9uIENvbG9yc1xuICAmLmJ0bi1zdWNjZXNzIHtcbiAgICBAaW5jbHVkZSBidXR0b24tdmFyaWFudCgkc3VjY2Vzcy1jb2xvcik7XG4gIH1cblxuICAmLmJ0bi1lcnJvciB7XG4gICAgQGluY2x1ZGUgYnV0dG9uLXZhcmlhbnQoJGVycm9yLWNvbG9yKTtcbiAgfVxuXG4gICYuYnRuLXdhcm5pbmcge1xuICAgIEBpbmNsdWRlIGJ1dHRvbi12YXJpYW50KCR3YXJuaW5nLWNvbG9yKTtcbiAgfVxuXG4gIC8vIEJ1dHRvbiBMaW5rXG4gICYuYnRuLWxpbmsge1xuICAgIGJhY2tncm91bmQ6IHRyYW5zcGFyZW50O1xuICAgIGJvcmRlci1jb2xvcjogdHJhbnNwYXJlbnQ7XG4gICAgY29sb3I6ICRsaW5rLWNvbG9yO1xuICAgICY6Zm9jdXMsXG4gICAgJjpob3ZlcixcbiAgICAmOmFjdGl2ZSxcbiAgICAmLmFjdGl2ZSB7XG4gICAgICBjb2xvcjogJGxpbmstY29sb3ItZGFyaztcbiAgICB9XG4gIH1cblxuICAvLyBCdXR0b24gU2l6ZXNcbiAgJi5idG4tc20ge1xuICAgIGZvbnQtc2l6ZTogJGZvbnQtc2l6ZS1zbTtcbiAgICBoZWlnaHQ6ICRjb250cm9sLXNpemUtc207XG4gICAgcGFkZGluZzogJGNvbnRyb2wtcGFkZGluZy15LXNtICRjb250cm9sLXBhZGRpbmcteC1zbTtcbiAgfVxuXG4gICYuYnRuLWxnIHtcbiAgICBmb250LXNpemU6ICRmb250LXNpemUtbGc7XG4gICAgaGVpZ2h0OiAkY29udHJvbC1zaXplLWxnO1xuICAgIHBhZGRpbmc6ICRjb250cm9sLXBhZGRpbmcteS1sZyAkY29udHJvbC1wYWRkaW5nLXgtbGc7XG4gIH1cblxuICAvLyBCdXR0b24gQmxvY2tcbiAgJi5idG4tYmxvY2sge1xuICAgIGRpc3BsYXk6IGJsb2NrO1xuICAgIHdpZHRoOiAxMDAlO1xuICB9XG5cbiAgLy8gQnV0dG9uIEFjdGlvblxuICAmLmJ0bi1hY3Rpb24ge1xuICAgIHdpZHRoOiAkY29udHJvbC1zaXplO1xuICAgIHBhZGRpbmctbGVmdDogMDtcbiAgICBwYWRkaW5nLXJpZ2h0OiAwO1xuXG4gICAgJi5idG4tc20ge1xuICAgICAgd2lkdGg6ICRjb250cm9sLXNpemUtc207XG4gICAgfVxuXG4gICAgJi5idG4tbGcge1xuICAgICAgd2lkdGg6ICRjb250cm9sLXNpemUtbGc7XG4gICAgfVxuICB9XG5cbiAgLy8gQnV0dG9uIENsZWFyXG4gICYuYnRuLWNsZWFyIHtcbiAgICBiYWNrZ3JvdW5kOiB0cmFuc3BhcmVudDtcbiAgICBib3JkZXI6IDA7XG4gICAgY29sb3I6IGN1cnJlbnRDb2xvcjtcbiAgICBoZWlnaHQ6ICR1bml0LTQ7XG4gICAgbGluZS1oZWlnaHQ6ICR1bml0LTQ7XG4gICAgbWFyZ2luLWxlZnQ6ICR1bml0LTE7XG4gICAgbWFyZ2luLXJpZ2h0OiAtMnB4O1xuICAgIG9wYWNpdHk6IDE7XG4gICAgcGFkZGluZzogMDtcbiAgICB0ZXh0LWRlY29yYXRpb246IG5vbmU7XG4gICAgd2lkdGg6ICR1bml0LTQ7XG5cbiAgICAmOmhvdmVyIHtcbiAgICAgIG9wYWNpdHk6IC45NTtcbiAgICB9XG5cbiAgICAmOjpiZWZvcmUge1xuICAgICAgY29udGVudDogXCJcXDI3MTVcIjtcbiAgICB9XG4gIH1cbn1cblxuLy8gQnV0dG9uIGdyb3Vwc1xuLmJ0bi1ncm91cCB7XG4gIGRpc3BsYXk6IGlubGluZS1mbGV4O1xuICBmbGV4LXdyYXA6IHdyYXA7XG5cbiAgLmJ0biB7XG4gICAgZmxleDogMSAwIGF1dG87XG4gICAgJjpmaXJzdC1jaGlsZDpub3QoOmxhc3QtY2hpbGQpIHtcbiAgICAgIGJvcmRlci1ib3R0b20tcmlnaHQtcmFkaXVzOiAwO1xuICAgICAgYm9yZGVyLXRvcC1yaWdodC1yYWRpdXM6IDA7XG4gICAgfVxuICAgICY6bm90KDpmaXJzdC1jaGlsZCk6bm90KDpsYXN0LWNoaWxkKSB7XG4gICAgICBib3JkZXItcmFkaXVzOiAwO1xuICAgICAgbWFyZ2luLWxlZnQ6IC0kYm9yZGVyLXdpZHRoO1xuICAgIH1cbiAgICAmOmxhc3QtY2hpbGQ6bm90KDpmaXJzdC1jaGlsZCkge1xuICAgICAgYm9yZGVyLWJvdHRvbS1sZWZ0LXJhZGl1czogMDtcbiAgICAgIGJvcmRlci10b3AtbGVmdC1yYWRpdXM6IDA7XG4gICAgICBtYXJnaW4tbGVmdDogLSRib3JkZXItd2lkdGg7XG4gICAgfVxuICAgICY6Zm9jdXMsXG4gICAgJjpob3ZlcixcbiAgICAmOmFjdGl2ZSxcbiAgICAmLmFjdGl2ZSB7XG4gICAgICB6LWluZGV4OiAkemluZGV4LTA7XG4gICAgfVxuICB9XG5cbiAgJi5idG4tZ3JvdXAtYmxvY2sge1xuICAgIGRpc3BsYXk6IGZsZXg7XG5cbiAgICAuYnRuIHtcbiAgICAgIGZsZXg6IDEgMCAwO1xuICAgIH1cbiAgfVxufVxuIiwiLy8gRm9ybXNcbi5mb3JtLWdyb3VwIHtcbiAgJjpub3QoOmxhc3QtY2hpbGQpIHtcbiAgICBtYXJnaW4tYm90dG9tOiAkbGF5b3V0LXNwYWNpbmc7XG4gIH1cbn1cblxuZmllbGRzZXQge1xuICBtYXJnaW4tYm90dG9tOiAkbGF5b3V0LXNwYWNpbmctbGc7XG59XG5cbmxlZ2VuZCB7XG4gIGZvbnQtc2l6ZTogJGZvbnQtc2l6ZS1sZztcbiAgZm9udC13ZWlnaHQ6IDUwMDtcbiAgbWFyZ2luLWJvdHRvbTogJGxheW91dC1zcGFjaW5nLWxnO1xufVxuXG4vLyBGb3JtIGVsZW1lbnQ6IExhYmVsXG4uZm9ybS1sYWJlbCB7XG4gIGRpc3BsYXk6IGJsb2NrO1xuICBsaW5lLWhlaWdodDogJGxpbmUtaGVpZ2h0O1xuICBwYWRkaW5nOiAkY29udHJvbC1wYWRkaW5nLXkgKyAkYm9yZGVyLXdpZHRoIDA7XG5cbiAgJi5sYWJlbC1zbSB7XG4gICAgZm9udC1zaXplOiAkZm9udC1zaXplLXNtO1xuICAgIHBhZGRpbmc6ICRjb250cm9sLXBhZGRpbmcteS1zbSArICRib3JkZXItd2lkdGggMDtcbiAgfVxuXG4gICYubGFiZWwtbGcge1xuICAgIGZvbnQtc2l6ZTogJGZvbnQtc2l6ZS1sZztcbiAgICBwYWRkaW5nOiAkY29udHJvbC1wYWRkaW5nLXktbGcgKyAkYm9yZGVyLXdpZHRoIDA7XG4gIH1cbn1cblxuLy8gRm9ybSBlbGVtZW50OiBJbnB1dFxuLmZvcm0taW5wdXQge1xuICBAaW5jbHVkZSBjb250cm9sLXRyYW5zaXRpb24oKTtcbiAgYXBwZWFyYW5jZTogbm9uZTtcbiAgYmFja2dyb3VuZDogJGJnLWNvbG9yLWxpZ2h0O1xuICBiYWNrZ3JvdW5kLWltYWdlOiBub25lO1xuICBib3JkZXI6ICRib3JkZXItd2lkdGggc29saWQgJGJvcmRlci1jb2xvci1kYXJrO1xuICBib3JkZXItcmFkaXVzOiAkYm9yZGVyLXJhZGl1cztcbiAgY29sb3I6ICRib2R5LWZvbnQtY29sb3I7XG4gIGRpc3BsYXk6IGJsb2NrO1xuICBmb250LXNpemU6ICRmb250LXNpemU7XG4gIGhlaWdodDogJGNvbnRyb2wtc2l6ZTtcbiAgbGluZS1oZWlnaHQ6ICRsaW5lLWhlaWdodDtcbiAgbWF4LXdpZHRoOiAxMDAlO1xuICBvdXRsaW5lOiBub25lO1xuICBwYWRkaW5nOiAkY29udHJvbC1wYWRkaW5nLXkgJGNvbnRyb2wtcGFkZGluZy14O1xuICBwb3NpdGlvbjogcmVsYXRpdmU7XG4gIHdpZHRoOiAxMDAlO1xuICAmOmZvY3VzIHtcbiAgICBAaW5jbHVkZSBjb250cm9sLXNoYWRvdygpO1xuICAgIGJvcmRlci1jb2xvcjogJHByaW1hcnktY29sb3I7XG4gIH1cbiAgJjo6cGxhY2Vob2xkZXIge1xuICAgIGNvbG9yOiAkZ3JheS1jb2xvcjtcbiAgfVxuXG4gIC8vIElucHV0IHNpemVzXG4gICYuaW5wdXQtc20ge1xuICAgIGZvbnQtc2l6ZTogJGZvbnQtc2l6ZS1zbTtcbiAgICBoZWlnaHQ6ICRjb250cm9sLXNpemUtc207XG4gICAgcGFkZGluZzogJGNvbnRyb2wtcGFkZGluZy15LXNtICRjb250cm9sLXBhZGRpbmcteC1zbTtcbiAgfVxuXG4gICYuaW5wdXQtbGcge1xuICAgIGZvbnQtc2l6ZTogJGZvbnQtc2l6ZS1sZztcbiAgICBoZWlnaHQ6ICRjb250cm9sLXNpemUtbGc7XG4gICAgcGFkZGluZzogJGNvbnRyb2wtcGFkZGluZy15LWxnICRjb250cm9sLXBhZGRpbmcteC1sZztcbiAgfVxuXG4gICYuaW5wdXQtaW5saW5lIHtcbiAgICBkaXNwbGF5OiBpbmxpbmUtYmxvY2s7XG4gICAgdmVydGljYWwtYWxpZ246IG1pZGRsZTtcbiAgICB3aWR0aDogYXV0bztcbiAgfVxuXG4gIC8vIElucHV0IHR5cGVzXG4gICZbdHlwZT1cImZpbGVcIl0ge1xuICAgIGhlaWdodDogYXV0bztcbiAgfVxufVxuXG4vLyBGb3JtIGVsZW1lbnQ6IFRleHRhcmVhXG50ZXh0YXJlYS5mb3JtLWlucHV0IHtcbiAgaGVpZ2h0OiBhdXRvO1xufVxuXG4vLyBGb3JtIGVsZW1lbnQ6IElucHV0IGhpbnRcbi5mb3JtLWlucHV0LWhpbnQge1xuICBjb2xvcjogJGdyYXktY29sb3I7XG4gIGZvbnQtc2l6ZTogJGZvbnQtc2l6ZS1zbTtcbiAgbWFyZ2luLXRvcDogJHVuaXQtMTtcblxuICAuaGFzLXN1Y2Nlc3MgJixcbiAgLmlzLXN1Y2Nlc3MgKyAmIHtcbiAgICBjb2xvcjogJHN1Y2Nlc3MtY29sb3I7XG4gIH1cblxuICAuaGFzLWVycm9yICYsXG4gIC5pcy1lcnJvciArICYge1xuICAgIGNvbG9yOiAkZXJyb3ItY29sb3I7XG4gIH1cbn1cblxuLy8gRm9ybSBlbGVtZW50OiBTZWxlY3Rcbi5mb3JtLXNlbGVjdCB7XG4gIGFwcGVhcmFuY2U6IG5vbmU7XG4gIGJvcmRlcjogJGJvcmRlci13aWR0aCBzb2xpZCAkYm9yZGVyLWNvbG9yLWRhcms7XG4gIGJvcmRlci1yYWRpdXM6ICRib3JkZXItcmFkaXVzO1xuICBjb2xvcjogaW5oZXJpdDtcbiAgZm9udC1zaXplOiAkZm9udC1zaXplO1xuICBoZWlnaHQ6ICRjb250cm9sLXNpemU7XG4gIGxpbmUtaGVpZ2h0OiAkbGluZS1oZWlnaHQ7XG4gIG91dGxpbmU6IG5vbmU7XG4gIHBhZGRpbmc6ICRjb250cm9sLXBhZGRpbmcteSAkY29udHJvbC1wYWRkaW5nLXg7XG4gIHZlcnRpY2FsLWFsaWduOiBtaWRkbGU7XG4gIHdpZHRoOiAxMDAlO1xuXG4gICZbc2l6ZV0sXG4gICZbbXVsdGlwbGVdIHtcbiAgICBoZWlnaHQ6IGF1dG87XG4gICAgXG4gICAgb3B0aW9uIHtcbiAgICAgIHBhZGRpbmc6ICR1bml0LWggJHVuaXQtMTtcbiAgICB9XG4gIH1cbiAgJjpub3QoW211bHRpcGxlXSk6bm90KFtzaXplXSkge1xuICAgIGJhY2tncm91bmQ6ICNmZmYgdXJsKFwiZGF0YTppbWFnZS9zdmcreG1sO2NoYXJzZXQ9dXRmOCwlM0NzdmclMjB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnJTIwdmlld0JveD0nMCUyMDAlMjA0JTIwNSclM0UlM0NwYXRoJTIwZmlsbD0nJTIzNjY3MTg5JyUyMGQ9J00yJTIwMEwwJTIwMmg0em0wJTIwNUwwJTIwM2g0eicvJTNFJTNDL3N2ZyUzRVwiKSBuby1yZXBlYXQgcmlnaHQgLjM1cmVtIGNlbnRlci8uNHJlbSAuNXJlbTtcbiAgICBwYWRkaW5nLXJpZ2h0OiAkY29udHJvbC1pY29uLXNpemUgKyAkY29udHJvbC1wYWRkaW5nLXg7XG4gIH1cbiAgJjpmb2N1cyB7XG4gICAgQGluY2x1ZGUgY29udHJvbC1zaGFkb3coKTtcbiAgICBib3JkZXItY29sb3I6ICRwcmltYXJ5LWNvbG9yO1xuICB9XG4gICY6Oi1tcy1leHBhbmQge1xuICAgIGRpc3BsYXk6IG5vbmU7XG4gIH1cblxuICAvLyBTZWxlY3Qgc2l6ZXNcbiAgJi5zZWxlY3Qtc20ge1xuICAgIGZvbnQtc2l6ZTogJGZvbnQtc2l6ZS1zbTtcbiAgICBoZWlnaHQ6ICRjb250cm9sLXNpemUtc207XG4gICAgcGFkZGluZzogJGNvbnRyb2wtcGFkZGluZy15LXNtICgkY29udHJvbC1pY29uLXNpemUgKyAkY29udHJvbC1wYWRkaW5nLXgtc20pICRjb250cm9sLXBhZGRpbmcteS1zbSAkY29udHJvbC1wYWRkaW5nLXgtc207XG4gIH1cblxuICAmLnNlbGVjdC1sZyB7XG4gICAgZm9udC1zaXplOiAkZm9udC1zaXplLWxnO1xuICAgIGhlaWdodDogJGNvbnRyb2wtc2l6ZS1sZztcbiAgICBwYWRkaW5nOiAkY29udHJvbC1wYWRkaW5nLXktbGcgKCRjb250cm9sLWljb24tc2l6ZSArICRjb250cm9sLXBhZGRpbmcteC1sZykgJGNvbnRyb2wtcGFkZGluZy15LWxnICRjb250cm9sLXBhZGRpbmcteC1sZztcbiAgfVxufVxuXG4vLyBGb3JtIEljb25zXG4uaGFzLWljb24tbGVmdCxcbi5oYXMtaWNvbi1yaWdodCB7XG4gIHBvc2l0aW9uOiByZWxhdGl2ZTtcblxuICAuZm9ybS1pY29uIHtcbiAgICBoZWlnaHQ6ICRjb250cm9sLWljb24tc2l6ZTtcbiAgICBtYXJnaW46IDAgJGNvbnRyb2wtcGFkZGluZy15O1xuICAgIHBvc2l0aW9uOiBhYnNvbHV0ZTtcbiAgICB0b3A6IDUwJTtcbiAgICB0cmFuc2Zvcm06IHRyYW5zbGF0ZVkoLTUwJSk7XG4gICAgd2lkdGg6ICRjb250cm9sLWljb24tc2l6ZTtcbiAgICB6LWluZGV4OiAkemluZGV4LTAgKyAxO1xuICB9XG59XG5cbi5oYXMtaWNvbi1sZWZ0IHtcbiAgLmZvcm0taWNvbiB7XG4gICAgbGVmdDogJGJvcmRlci13aWR0aDtcbiAgfVxuXG4gIC5mb3JtLWlucHV0IHtcbiAgICBwYWRkaW5nLWxlZnQ6ICRjb250cm9sLWljb24tc2l6ZSArICRjb250cm9sLXBhZGRpbmcteSAqIDI7XG4gIH1cbn1cblxuLmhhcy1pY29uLXJpZ2h0IHtcbiAgLmZvcm0taWNvbiB7XG4gICAgcmlnaHQ6ICRib3JkZXItd2lkdGg7XG4gIH1cblxuICAuZm9ybS1pbnB1dCB7XG4gICAgcGFkZGluZy1yaWdodDogJGNvbnRyb2wtaWNvbi1zaXplICsgJGNvbnRyb2wtcGFkZGluZy15ICogMjtcbiAgfVxufVxuXG4vLyBGb3JtIGVsZW1lbnQ6IENoZWNrYm94IGFuZCBSYWRpb1xuLmZvcm0tY2hlY2tib3gsXG4uZm9ybS1yYWRpbyxcbi5mb3JtLXN3aXRjaCB7XG4gIGRpc3BsYXk6IGJsb2NrO1xuICBsaW5lLWhlaWdodDogJGxpbmUtaGVpZ2h0O1xuICBtYXJnaW46ICgkY29udHJvbC1zaXplIC0gJGNvbnRyb2wtc2l6ZS1zbSkgLyAyIDA7XG4gIG1pbi1oZWlnaHQ6IDEuMnJlbTtcbiAgcGFkZGluZzogKCgkY29udHJvbC1zaXplLXNtIC0gJGxpbmUtaGVpZ2h0KSAvIDIpICRjb250cm9sLXBhZGRpbmcteCAoKCRjb250cm9sLXNpemUtc20gLSAkbGluZS1oZWlnaHQpIC8gMikgKCRjb250cm9sLWljb24tc2l6ZSArICRjb250cm9sLXBhZGRpbmcteCk7XG4gIHBvc2l0aW9uOiByZWxhdGl2ZTtcblxuICBpbnB1dCB7XG4gICAgY2xpcDogcmVjdCgwLCAwLCAwLCAwKTtcbiAgICBoZWlnaHQ6IDFweDtcbiAgICBtYXJnaW46IC0xcHg7XG4gICAgb3ZlcmZsb3c6IGhpZGRlbjtcbiAgICBwb3NpdGlvbjogYWJzb2x1dGU7XG4gICAgd2lkdGg6IDFweDtcbiAgICAmOmZvY3VzICsgLmZvcm0taWNvbiB7XG4gICAgICBAaW5jbHVkZSBjb250cm9sLXNoYWRvdygpO1xuICAgICAgYm9yZGVyLWNvbG9yOiAkcHJpbWFyeS1jb2xvcjtcbiAgICB9XG4gICAgJjpjaGVja2VkICsgLmZvcm0taWNvbiB7XG4gICAgICBiYWNrZ3JvdW5kOiAkcHJpbWFyeS1jb2xvcjtcbiAgICAgIGJvcmRlci1jb2xvcjogJHByaW1hcnktY29sb3I7XG4gICAgfVxuICB9XG5cbiAgLmZvcm0taWNvbiB7XG4gICAgQGluY2x1ZGUgY29udHJvbC10cmFuc2l0aW9uKCk7XG4gICAgYm9yZGVyOiAkYm9yZGVyLXdpZHRoIHNvbGlkICRib3JkZXItY29sb3ItZGFyaztcbiAgICBjdXJzb3I6IHBvaW50ZXI7XG4gICAgZGlzcGxheTogaW5saW5lLWJsb2NrO1xuICAgIHBvc2l0aW9uOiBhYnNvbHV0ZTtcbiAgfVxuXG4gIC8vIElucHV0IGNoZWNrYm94LCByYWRpbyBhbmQgc3dpdGNoIHNpemVzXG4gICYuaW5wdXQtc20ge1xuICAgIGZvbnQtc2l6ZTogJGZvbnQtc2l6ZS1zbTtcbiAgICBtYXJnaW46IDA7XG4gIH1cblxuICAmLmlucHV0LWxnIHtcbiAgICBmb250LXNpemU6ICRmb250LXNpemUtbGc7XG4gICAgbWFyZ2luOiAoJGNvbnRyb2wtc2l6ZS1sZyAtICRjb250cm9sLXNpemUtc20pIC8gMiAwO1xuICB9XG59XG5cbi5mb3JtLWNoZWNrYm94LFxuLmZvcm0tcmFkaW8ge1xuICAuZm9ybS1pY29uIHtcbiAgICBiYWNrZ3JvdW5kOiAkYmctY29sb3ItbGlnaHQ7XG4gICAgaGVpZ2h0OiAkY29udHJvbC1pY29uLXNpemU7XG4gICAgbGVmdDogMDtcbiAgICB0b3A6ICgkY29udHJvbC1zaXplLXNtIC0gJGNvbnRyb2wtaWNvbi1zaXplKSAvIDI7XG4gICAgd2lkdGg6ICRjb250cm9sLWljb24tc2l6ZTtcbiAgfVxuXG4gIGlucHV0IHtcbiAgICAmOmFjdGl2ZSArIC5mb3JtLWljb24ge1xuICAgICAgYmFja2dyb3VuZDogJGJnLWNvbG9yLWRhcms7XG4gICAgfVxuICB9XG59XG4uZm9ybS1jaGVja2JveCB7XG4gIC5mb3JtLWljb24ge1xuICAgIGJvcmRlci1yYWRpdXM6ICRib3JkZXItcmFkaXVzO1xuICB9XG5cbiAgaW5wdXQge1xuICAgICY6Y2hlY2tlZCArIC5mb3JtLWljb24ge1xuICAgICAgJjo6YmVmb3JlIHtcbiAgICAgICAgYmFja2dyb3VuZC1jbGlwOiBwYWRkaW5nLWJveDtcbiAgICAgICAgYm9yZGVyOiAkYm9yZGVyLXdpZHRoLWxnIHNvbGlkICRsaWdodC1jb2xvcjtcbiAgICAgICAgYm9yZGVyLWxlZnQtd2lkdGg6IDA7XG4gICAgICAgIGJvcmRlci10b3Atd2lkdGg6IDA7XG4gICAgICAgIGNvbnRlbnQ6IFwiXCI7XG4gICAgICAgIGhlaWdodDogMTJweDtcbiAgICAgICAgbGVmdDogNTAlO1xuICAgICAgICBtYXJnaW4tbGVmdDogLTRweDtcbiAgICAgICAgbWFyZ2luLXRvcDogLThweDtcbiAgICAgICAgcG9zaXRpb246IGFic29sdXRlO1xuICAgICAgICB0b3A6IDUwJTtcbiAgICAgICAgdHJhbnNmb3JtOiByb3RhdGUoNDVkZWcpO1xuICAgICAgICB3aWR0aDogOHB4O1xuICAgICAgfVxuICAgIH1cbiAgICAmOmluZGV0ZXJtaW5hdGUgKyAuZm9ybS1pY29uIHtcbiAgICAgIGJhY2tncm91bmQ6ICRwcmltYXJ5LWNvbG9yO1xuICAgICAgYm9yZGVyLWNvbG9yOiAkcHJpbWFyeS1jb2xvcjtcbiAgICAgICY6OmJlZm9yZSB7XG4gICAgICAgIGJhY2tncm91bmQ6ICRiZy1jb2xvci1saWdodDtcbiAgICAgICAgY29udGVudDogXCJcIjtcbiAgICAgICAgaGVpZ2h0OiAycHg7XG4gICAgICAgIGxlZnQ6IDUwJTtcbiAgICAgICAgbWFyZ2luLWxlZnQ6IC01cHg7XG4gICAgICAgIG1hcmdpbi10b3A6IC0xcHg7XG4gICAgICAgIHBvc2l0aW9uOiBhYnNvbHV0ZTtcbiAgICAgICAgdG9wOiA1MCU7XG4gICAgICAgIHdpZHRoOiAxMHB4O1xuICAgICAgfVxuICAgIH1cbiAgfVxufVxuLmZvcm0tcmFkaW8ge1xuICAuZm9ybS1pY29uIHtcbiAgICBib3JkZXItcmFkaXVzOiA1MCU7XG4gIH1cblxuICBpbnB1dCB7XG4gICAgJjpjaGVja2VkICsgLmZvcm0taWNvbiB7XG4gICAgICAmOjpiZWZvcmUge1xuICAgICAgICBiYWNrZ3JvdW5kOiAkYmctY29sb3ItbGlnaHQ7XG4gICAgICAgIGJvcmRlci1yYWRpdXM6IDUwJTtcbiAgICAgICAgY29udGVudDogXCJcIjtcbiAgICAgICAgaGVpZ2h0OiA0cHg7XG4gICAgICAgIGxlZnQ6IDUwJTtcbiAgICAgICAgcG9zaXRpb246IGFic29sdXRlO1xuICAgICAgICB0b3A6IDUwJTtcbiAgICAgICAgdHJhbnNmb3JtOiB0cmFuc2xhdGUoLTUwJSwgLTUwJSk7XG4gICAgICAgIHdpZHRoOiA0cHg7XG4gICAgICB9XG4gICAgfVxuICB9XG59XG5cbi8vIEZvcm0gZWxlbWVudDogU3dpdGNoXG4uZm9ybS1zd2l0Y2gge1xuICBwYWRkaW5nLWxlZnQ6ICgkdW5pdC04ICsgJGNvbnRyb2wtcGFkZGluZy14KTtcblxuICAuZm9ybS1pY29uIHtcbiAgICBiYWNrZ3JvdW5kOiAkZ3JheS1jb2xvci1saWdodDtcbiAgICBiYWNrZ3JvdW5kLWNsaXA6IHBhZGRpbmctYm94O1xuICAgIGJvcmRlci1yYWRpdXM6ICR1bml0LTIgKyAkYm9yZGVyLXdpZHRoO1xuICAgIGhlaWdodDogJHVuaXQtNCArICRib3JkZXItd2lkdGggKiAyO1xuICAgIGxlZnQ6IDA7XG4gICAgdG9wOiAoJGNvbnRyb2wtc2l6ZS1zbSAtICR1bml0LTQpIC8gMiAtICRib3JkZXItd2lkdGg7XG4gICAgd2lkdGg6ICR1bml0LTg7XG4gICAgJjo6YmVmb3JlIHtcbiAgICAgIEBpbmNsdWRlIGNvbnRyb2wtdHJhbnNpdGlvbigpO1xuICAgICAgYmFja2dyb3VuZDogJGJnLWNvbG9yLWxpZ2h0O1xuICAgICAgYm9yZGVyLXJhZGl1czogNTAlO1xuICAgICAgY29udGVudDogXCJcIjtcbiAgICAgIGRpc3BsYXk6IGJsb2NrO1xuICAgICAgaGVpZ2h0OiAkdW5pdC00O1xuICAgICAgbGVmdDogMDtcbiAgICAgIHBvc2l0aW9uOiBhYnNvbHV0ZTtcbiAgICAgIHRvcDogMDtcbiAgICAgIHdpZHRoOiAkdW5pdC00O1xuICAgIH1cbiAgfVxuXG4gIGlucHV0IHtcbiAgICAmOmNoZWNrZWQgKyAuZm9ybS1pY29uIHtcbiAgICAgICY6OmJlZm9yZSB7XG4gICAgICAgIGxlZnQ6IDE0cHg7XG4gICAgICB9XG4gICAgfVxuICAgICY6YWN0aXZlICsgLmZvcm0taWNvbiB7XG4gICAgICAmOjpiZWZvcmUge1xuICAgICAgICBiYWNrZ3JvdW5kOiAkYmctY29sb3I7XG4gICAgICB9XG4gICAgfVxuICB9XG59XG5cbi8vIEZvcm0gZWxlbWVudDogSW5wdXQgZ3JvdXBzXG4uaW5wdXQtZ3JvdXAge1xuICBkaXNwbGF5OiBmbGV4O1xuXG4gIC5pbnB1dC1ncm91cC1hZGRvbiB7XG4gICAgYmFja2dyb3VuZDogJGJnLWNvbG9yO1xuICAgIGJvcmRlcjogJGJvcmRlci13aWR0aCBzb2xpZCAkYm9yZGVyLWNvbG9yLWRhcms7XG4gICAgYm9yZGVyLXJhZGl1czogJGJvcmRlci1yYWRpdXM7XG4gICAgbGluZS1oZWlnaHQ6ICRsaW5lLWhlaWdodDtcbiAgICBwYWRkaW5nOiAkY29udHJvbC1wYWRkaW5nLXkgJGNvbnRyb2wtcGFkZGluZy14O1xuICAgIHdoaXRlLXNwYWNlOiBub3dyYXA7XG5cbiAgICAmLmFkZG9uLXNtIHtcbiAgICAgIGZvbnQtc2l6ZTogJGZvbnQtc2l6ZS1zbTtcbiAgICAgIHBhZGRpbmc6ICRjb250cm9sLXBhZGRpbmcteS1zbSAkY29udHJvbC1wYWRkaW5nLXgtc207XG4gICAgfVxuXG4gICAgJi5hZGRvbi1sZyB7XG4gICAgICBmb250LXNpemU6ICRmb250LXNpemUtbGc7XG4gICAgICBwYWRkaW5nOiAkY29udHJvbC1wYWRkaW5nLXktbGcgJGNvbnRyb2wtcGFkZGluZy14LWxnO1xuICAgIH1cbiAgfVxuXG4gIC5mb3JtLWlucHV0LFxuICAuZm9ybS1zZWxlY3Qge1xuICAgIGZsZXg6IDEgMSBhdXRvO1xuICAgIHdpZHRoOiAxJTtcbiAgfVxuXG4gIC5pbnB1dC1ncm91cC1idG4ge1xuICAgIHotaW5kZXg6ICR6aW5kZXgtMDtcbiAgfVxuXG4gIC5mb3JtLWlucHV0LFxuICAuZm9ybS1zZWxlY3QsXG4gIC5pbnB1dC1ncm91cC1hZGRvbixcbiAgLmlucHV0LWdyb3VwLWJ0biB7XG4gICAgJjpmaXJzdC1jaGlsZDpub3QoOmxhc3QtY2hpbGQpIHtcbiAgICAgIGJvcmRlci1ib3R0b20tcmlnaHQtcmFkaXVzOiAwO1xuICAgICAgYm9yZGVyLXRvcC1yaWdodC1yYWRpdXM6IDA7XG4gICAgfVxuICAgICY6bm90KDpmaXJzdC1jaGlsZCk6bm90KDpsYXN0LWNoaWxkKSB7XG4gICAgICBib3JkZXItcmFkaXVzOiAwO1xuICAgICAgbWFyZ2luLWxlZnQ6IC0kYm9yZGVyLXdpZHRoO1xuICAgIH1cbiAgICAmOmxhc3QtY2hpbGQ6bm90KDpmaXJzdC1jaGlsZCkge1xuICAgICAgYm9yZGVyLWJvdHRvbS1sZWZ0LXJhZGl1czogMDtcbiAgICAgIGJvcmRlci10b3AtbGVmdC1yYWRpdXM6IDA7XG4gICAgICBtYXJnaW4tbGVmdDogLSRib3JkZXItd2lkdGg7XG4gICAgfVxuICAgICY6Zm9jdXMge1xuICAgICAgei1pbmRleDogJHppbmRleC0wICsgMTtcbiAgICB9XG4gIH1cblxuICAuZm9ybS1zZWxlY3Qge1xuICAgIHdpZHRoOiBhdXRvO1xuICB9XG5cbiAgJi5pbnB1dC1pbmxpbmUge1xuICAgIGRpc3BsYXk6IGlubGluZS1mbGV4O1xuICB9XG59XG5cbi8vIEZvcm0gdmFsaWRhdGlvbiBzdGF0ZXNcbi5mb3JtLWlucHV0LFxuLmZvcm0tc2VsZWN0IHtcbiAgLmhhcy1zdWNjZXNzICYsXG4gICYuaXMtc3VjY2VzcyB7XG4gICAgYm9yZGVyLWNvbG9yOiAkc3VjY2Vzcy1jb2xvcjtcbiAgICAmOmZvY3VzIHtcbiAgICAgIEBpbmNsdWRlIGNvbnRyb2wtc2hhZG93KCRzdWNjZXNzLWNvbG9yKTtcbiAgICB9XG4gIH1cblxuICAuaGFzLWVycm9yICYsXG4gICYuaXMtZXJyb3Ige1xuICAgIGJvcmRlci1jb2xvcjogJGVycm9yLWNvbG9yO1xuICAgICY6Zm9jdXMge1xuICAgICAgQGluY2x1ZGUgY29udHJvbC1zaGFkb3coJGVycm9yLWNvbG9yKTtcbiAgICB9XG4gIH1cbn1cblxuLmZvcm0tY2hlY2tib3gsXG4uZm9ybS1yYWRpbyxcbi5mb3JtLXN3aXRjaCB7XG4gIC5oYXMtZXJyb3IgJixcbiAgJi5pcy1lcnJvciB7XG4gICAgLmZvcm0taWNvbiB7XG4gICAgICBib3JkZXItY29sb3I6ICRlcnJvci1jb2xvcjtcbiAgICB9XG4gICAgXG4gICAgaW5wdXQge1xuICAgICAgJjpjaGVja2VkICsgLmZvcm0taWNvbiB7XG4gICAgICAgIGJhY2tncm91bmQ6ICRlcnJvci1jb2xvcjtcbiAgICAgICAgYm9yZGVyLWNvbG9yOiAkZXJyb3ItY29sb3I7XG4gICAgICB9XG5cbiAgICAgICY6Zm9jdXMgKyAuZm9ybS1pY29uIHtcbiAgICAgICAgQGluY2x1ZGUgY29udHJvbC1zaGFkb3coJGVycm9yLWNvbG9yKTtcbiAgICAgICAgYm9yZGVyLWNvbG9yOiAkZXJyb3ItY29sb3I7XG4gICAgICB9XG4gICAgfVxuICB9XG59XG5cbi5mb3JtLWNoZWNrYm94IHtcbiAgLmhhcy1lcnJvciAmLFxuICAmLmlzLWVycm9yIHtcbiAgICBpbnB1dCB7XG4gICAgICAmOmluZGV0ZXJtaW5hdGUgKyAuZm9ybS1pY29uIHtcbiAgICAgICAgYmFja2dyb3VuZDogJGVycm9yLWNvbG9yO1xuICAgICAgICBib3JkZXItY29sb3I6ICRlcnJvci1jb2xvcjtcbiAgICAgIH1cbiAgICB9XG4gIH1cbn1cblxuLy8gdmFsaWRhdGlvbiBiYXNlZCBvbiA6cGxhY2Vob2xkZXItc2hvd24gKEVkZ2UgZG9lc24ndCBzdXBwb3J0IGl0IHlldClcbi5mb3JtLWlucHV0IHtcbiAgJjpub3QoOnBsYWNlaG9sZGVyLXNob3duKSB7XG4gICAgJjppbnZhbGlkIHtcbiAgICAgIGJvcmRlci1jb2xvcjogJGVycm9yLWNvbG9yO1xuICAgICAgJjpmb2N1cyB7XG4gICAgICAgIEBpbmNsdWRlIGNvbnRyb2wtc2hhZG93KCRlcnJvci1jb2xvcik7XG4gICAgICB9XG5cbiAgICAgICYgKyAuZm9ybS1pbnB1dC1oaW50IHtcbiAgICAgICAgY29sb3I6ICRlcnJvci1jb2xvcjtcbiAgICAgIH1cbiAgICB9XG4gIH1cbn1cblxuLy8gRm9ybSBkaXNhYmxlZCBhbmQgcmVhZG9ubHlcbi5mb3JtLWlucHV0LFxuLmZvcm0tc2VsZWN0IHtcbiAgJjpkaXNhYmxlZCxcbiAgJi5kaXNhYmxlZCB7XG4gICAgYmFja2dyb3VuZC1jb2xvcjogJGJnLWNvbG9yLWRhcms7XG4gICAgY3Vyc29yOiBub3QtYWxsb3dlZDtcbiAgICBvcGFjaXR5OiAuNTtcbiAgfVxufVxuXG4uZm9ybS1pbnB1dCB7XG4gICZbcmVhZG9ubHldIHtcbiAgICBiYWNrZ3JvdW5kLWNvbG9yOiAkYmctY29sb3I7XG4gIH1cbn1cblxuaW5wdXQge1xuICAmOmRpc2FibGVkLFxuICAmLmRpc2FibGVkIHtcbiAgICAmICsgLmZvcm0taWNvbiB7XG4gICAgICBiYWNrZ3JvdW5kOiAkYmctY29sb3ItZGFyaztcbiAgICAgIGN1cnNvcjogbm90LWFsbG93ZWQ7XG4gICAgICBvcGFjaXR5OiAuNTtcbiAgICB9XG4gIH1cbn1cblxuLmZvcm0tc3dpdGNoIHtcbiAgaW5wdXQge1xuICAgICY6ZGlzYWJsZWQsXG4gICAgJi5kaXNhYmxlZCB7XG4gICAgICAmICsgLmZvcm0taWNvbjo6YmVmb3JlIHtcbiAgICAgICAgYmFja2dyb3VuZDogJGJnLWNvbG9yLWxpZ2h0O1xuICAgICAgfVxuICAgIH1cbiAgfVxufVxuXG4vLyBGb3JtIGhvcml6b250YWxcbi5mb3JtLWhvcml6b250YWwge1xuICBwYWRkaW5nOiAkbGF5b3V0LXNwYWNpbmcgMDtcblxuICAuZm9ybS1ncm91cCB7XG4gICAgZGlzcGxheTogZmxleDtcbiAgICBmbGV4LXdyYXA6IHdyYXA7XG4gIH1cbn1cblxuLy8gRm9ybSBpbmxpbmVcbi5mb3JtLWlubGluZSB7XG4gIGRpc3BsYXk6IGlubGluZS1ibG9jaztcbn0iLCIvLyBMYWJlbHNcbi5sYWJlbCB7XG4gIEBpbmNsdWRlIGxhYmVsLWJhc2UoKTtcbiAgQGluY2x1ZGUgbGFiZWwtdmFyaWFudChsaWdodGVuKCRib2R5LWZvbnQtY29sb3IsIDUlKSwgJGJnLWNvbG9yLWRhcmspO1xuICBkaXNwbGF5OiBpbmxpbmUtYmxvY2s7XG5cbiAgLy8gTGFiZWwgcm91bmRlZFxuICAmLmxhYmVsLXJvdW5kZWQge1xuICAgIGJvcmRlci1yYWRpdXM6IDVyZW07XG4gICAgcGFkZGluZy1sZWZ0OiAuNHJlbTtcbiAgICBwYWRkaW5nLXJpZ2h0OiAuNHJlbTsgXG4gIH1cblxuICAvLyBMYWJlbCBjb2xvcnNcbiAgJi5sYWJlbC1wcmltYXJ5IHtcbiAgICBAaW5jbHVkZSBsYWJlbC12YXJpYW50KCRsaWdodC1jb2xvciwgJHByaW1hcnktY29sb3IpO1xuICB9XG5cbiAgJi5sYWJlbC1zZWNvbmRhcnkge1xuICAgIEBpbmNsdWRlIGxhYmVsLXZhcmlhbnQoJHByaW1hcnktY29sb3IsICRzZWNvbmRhcnktY29sb3IpO1xuICB9XG5cbiAgJi5sYWJlbC1zdWNjZXNzIHtcbiAgICBAaW5jbHVkZSBsYWJlbC12YXJpYW50KCRsaWdodC1jb2xvciwgJHN1Y2Nlc3MtY29sb3IpO1xuICB9XG5cbiAgJi5sYWJlbC13YXJuaW5nIHtcbiAgICBAaW5jbHVkZSBsYWJlbC12YXJpYW50KCRsaWdodC1jb2xvciwgJHdhcm5pbmctY29sb3IpO1xuICB9XG5cbiAgJi5sYWJlbC1lcnJvciB7XG4gICAgQGluY2x1ZGUgbGFiZWwtdmFyaWFudCgkbGlnaHQtY29sb3IsICRlcnJvci1jb2xvcik7XG4gIH1cbn1cbiIsIi8vIENvZGVzXG5jb2RlIHtcbiAgQGluY2x1ZGUgbGFiZWwtYmFzZSgpO1xuICBAaW5jbHVkZSBsYWJlbC12YXJpYW50KCRjb2RlLWNvbG9yLCBsaWdodGVuKCRjb2RlLWNvbG9yLCA0Mi41JSkpO1xuICBmb250LXNpemU6IDg1JTtcbn1cblxuLmNvZGUge1xuICBib3JkZXItcmFkaXVzOiAkYm9yZGVyLXJhZGl1cztcbiAgY29sb3I6ICRib2R5LWZvbnQtY29sb3I7XG4gIHBvc2l0aW9uOiByZWxhdGl2ZTtcblxuICAmOjpiZWZvcmUge1xuICAgIGNvbG9yOiAkZ3JheS1jb2xvcjtcbiAgICBjb250ZW50OiBhdHRyKGRhdGEtbGFuZyk7XG4gICAgZm9udC1zaXplOiAkZm9udC1zaXplLXNtO1xuICAgIHBvc2l0aW9uOiBhYnNvbHV0ZTtcbiAgICByaWdodDogJGxheW91dC1zcGFjaW5nO1xuICAgIHRvcDogJHVuaXQtaDtcbiAgfVxuXG4gIGNvZGUge1xuICAgIGJhY2tncm91bmQ6ICRiZy1jb2xvcjtcbiAgICBjb2xvcjogaW5oZXJpdDtcbiAgICBkaXNwbGF5OiBibG9jaztcbiAgICBsaW5lLWhlaWdodDogMS41O1xuICAgIG92ZXJmbG93LXg6IGF1dG87XG4gICAgcGFkZGluZzogMXJlbTtcbiAgICB3aWR0aDogMTAwJTtcbiAgfVxufVxuIiwiLy8gTWVkaWFcbi8vIEltYWdlIHJlc3BvbnNpdmVcbi5pbWctcmVzcG9uc2l2ZSB7XG4gIGRpc3BsYXk6IGJsb2NrO1xuICBoZWlnaHQ6IGF1dG87XG4gIG1heC13aWR0aDogMTAwJTtcbn1cblxuLy8gb2JqZWN0LWZpdCBzdXBwb3J0IGlzIGNvbWluZyB0byBNaWNyb3NvZnQgRWRnZVxuLy8gaHR0cHM6Ly9kZXZlbG9wZXIubWljcm9zb2Z0LmNvbS9lbi11cy9taWNyb3NvZnQtZWRnZS9wbGF0Zm9ybS9zdGF0dXMvb2JqZWN0Zml0YW5kb2JqZWN0cG9zaXRpb24vXG4uaW1nLWZpdC1jb3ZlciB7XG4gIG9iamVjdC1maXQ6IGNvdmVyO1xufVxuXG4uaW1nLWZpdC1jb250YWluIHtcbiAgb2JqZWN0LWZpdDogY29udGFpbjtcbn1cblxuLy8gVmlkZW8gcmVzcG9uc2l2ZVxuLnZpZGVvLXJlc3BvbnNpdmUge1xuICBkaXNwbGF5OiBibG9jaztcbiAgb3ZlcmZsb3c6IGhpZGRlbjtcbiAgcGFkZGluZzogMDtcbiAgcG9zaXRpb246IHJlbGF0aXZlO1xuICB3aWR0aDogMTAwJTtcbiAgJjo6YmVmb3JlIHtcbiAgICBjb250ZW50OiBcIlwiO1xuICAgIGRpc3BsYXk6IGJsb2NrO1xuICAgIHBhZGRpbmctYm90dG9tOiA1Ni4yNSU7IC8vIERlZmF1bHQgcmF0aW8gMTY6OSwgeW91IGNhbiBjYWxjdWxhdGUgdGhpcyB2YWx1ZSBieSBkaXZpZGluZyA5IGJ5IDE2XG4gIH1cblxuICBpZnJhbWUsXG4gIG9iamVjdCxcbiAgZW1iZWQge1xuICAgIGJvcmRlcjogMDtcbiAgICBib3R0b206IDA7XG4gICAgaGVpZ2h0OiAxMDAlO1xuICAgIGxlZnQ6IDA7XG4gICAgcG9zaXRpb246IGFic29sdXRlO1xuICAgIHJpZ2h0OiAwO1xuICAgIHRvcDogMDtcbiAgICB3aWR0aDogMTAwJTtcbiAgfVxufVxuXG52aWRlby52aWRlby1yZXNwb25zaXZlIHtcbiAgaGVpZ2h0OiBhdXRvO1xuICBtYXgtd2lkdGg6IDEwMCU7XG5cbiAgJjo6YmVmb3JlIHtcbiAgICBjb250ZW50OiBub25lO1xuICB9XG59XG5cbi52aWRlby1yZXNwb25zaXZlLTQtMyB7XG4gICY6OmJlZm9yZSB7XG4gICAgcGFkZGluZy1ib3R0b206IDc1JTsgLy8gUmF0aW8gNDozXG4gIH1cbn1cblxuLnZpZGVvLXJlc3BvbnNpdmUtMS0xIHtcbiAgJjo6YmVmb3JlIHtcbiAgICBwYWRkaW5nLWJvdHRvbTogMTAwJTsgLy8gUmF0aW8gMToxXG4gIH1cbn1cblxuLy8gRmlndXJlXG4uZmlndXJlIHtcbiAgbWFyZ2luOiAwIDAgJGxheW91dC1zcGFjaW5nIDA7XG5cbiAgLmZpZ3VyZS1jYXB0aW9uIHtcbiAgICBjb2xvcjogJGdyYXktY29sb3ItZGFyaztcbiAgICBtYXJnaW4tdG9wOiAkbGF5b3V0LXNwYWNpbmc7XG4gIH1cbn1cbiIsIi8vIExheW91dFxuLmNvbnRhaW5lciB7XG4gIG1hcmdpbi1sZWZ0OiBhdXRvO1xuICBtYXJnaW4tcmlnaHQ6IGF1dG87XG4gIHBhZGRpbmctbGVmdDogJGxheW91dC1zcGFjaW5nO1xuICBwYWRkaW5nLXJpZ2h0OiAkbGF5b3V0LXNwYWNpbmc7XG4gIHdpZHRoOiAxMDAlO1xuICBAZXh0ZW5kIC5jbGVhcmZpeDtcblxuICAkZ3JpZC1zcGFjaW5nOiAoJGxheW91dC1zcGFjaW5nIC8gKCRsYXlvdXQtc3BhY2luZyAqIDAgKyAxKSkgKiAkaHRtbC1mb250LXNpemU7XG5cbiAgJi5ncmlkLXhsIHtcbiAgICBtYXgtd2lkdGg6ICRncmlkLXNwYWNpbmcgKiAyICsgJHNpemUteGw7XG4gIH1cblxuICAmLmdyaWQtbGcge1xuICAgIG1heC13aWR0aDogJGdyaWQtc3BhY2luZyAqIDIgKyAkc2l6ZS1sZztcbiAgfVxuXG4gICYuZ3JpZC1tZCB7XG4gICAgbWF4LXdpZHRoOiAkZ3JpZC1zcGFjaW5nICogMiArICRzaXplLW1kO1xuICB9XG5cbiAgJi5ncmlkLXNtIHtcbiAgICBtYXgtd2lkdGg6ICRncmlkLXNwYWNpbmcgKiAyICsgJHNpemUtc207XG4gIH1cblxuICAmLmdyaWQteHMge1xuICAgIG1heC13aWR0aDogJGdyaWQtc3BhY2luZyAqIDIgKyAkc2l6ZS14cztcbiAgfVxufVxuXG4vLyBSZXNwb25zaXZlIGJyZWFrcG9pbnQgc3lzdGVtXG4uc2hvdy14cyxcbi5zaG93LXNtLFxuLnNob3ctbWQsXG4uc2hvdy1sZyxcbi5zaG93LXhsIHtcbiAgZGlzcGxheTogbm9uZSAhaW1wb3J0YW50O1xufVxuXG4vLyBSZXNwb25zaXZlIGdyaWQgc3lzdGVtXG4uY29sdW1ucyB7XG4gIGRpc3BsYXk6IGZsZXg7XG4gIGZsZXgtd3JhcDogd3JhcDtcbiAgbWFyZ2luLWxlZnQ6IC0kbGF5b3V0LXNwYWNpbmc7XG4gIG1hcmdpbi1yaWdodDogLSRsYXlvdXQtc3BhY2luZztcblxuICAmLmNvbC1nYXBsZXNzIHtcbiAgICBtYXJnaW4tbGVmdDogMDtcbiAgICBtYXJnaW4tcmlnaHQ6IDA7XG5cbiAgICAmID4gLmNvbHVtbiB7XG4gICAgICBwYWRkaW5nLWxlZnQ6IDA7XG4gICAgICBwYWRkaW5nLXJpZ2h0OiAwO1xuICAgIH1cbiAgfVxuICAmLmNvbC1vbmVsaW5lIHtcbiAgICBmbGV4LXdyYXA6IG5vd3JhcDtcbiAgICBvdmVyZmxvdy14OiBhdXRvO1xuICB9XG59XG4uY29sdW1uIHtcbiAgZmxleDogMTtcbiAgbWF4LXdpZHRoOiAxMDAlO1xuICBwYWRkaW5nLWxlZnQ6ICRsYXlvdXQtc3BhY2luZztcbiAgcGFkZGluZy1yaWdodDogJGxheW91dC1zcGFjaW5nO1xuXG4gICYuY29sLTEyLFxuICAmLmNvbC0xMSxcbiAgJi5jb2wtMTAsXG4gICYuY29sLTksXG4gICYuY29sLTgsXG4gICYuY29sLTcsXG4gICYuY29sLTYsXG4gICYuY29sLTUsXG4gICYuY29sLTQsXG4gICYuY29sLTMsXG4gICYuY29sLTIsXG4gICYuY29sLTEge1xuICAgIGZsZXg6IG5vbmU7XG4gIH1cbn1cbi5jb2wtMTIge1xuICB3aWR0aDogMTAwJTtcbn1cbi5jb2wtMTEge1xuICB3aWR0aDogOTEuNjY2NjY2NjclO1xufVxuLmNvbC0xMCB7XG4gIHdpZHRoOiA4My4zMzMzMzMzMyU7XG59XG4uY29sLTkge1xuICB3aWR0aDogNzUlO1xufVxuLmNvbC04IHtcbiAgd2lkdGg6IDY2LjY2NjY2NjY3JTtcbn1cbi5jb2wtNyB7XG4gIHdpZHRoOiA1OC4zMzMzMzMzMyU7XG59XG4uY29sLTYge1xuICB3aWR0aDogNTAlO1xufVxuLmNvbC01IHtcbiAgd2lkdGg6IDQxLjY2NjY2NjY3JTtcbn1cbi5jb2wtNCB7XG4gIHdpZHRoOiAzMy4zMzMzMzMzMyU7XG59XG4uY29sLTMge1xuICB3aWR0aDogMjUlO1xufVxuLmNvbC0yIHtcbiAgd2lkdGg6IDE2LjY2NjY2NjY3JTtcbn1cbi5jb2wtMSB7XG4gIHdpZHRoOiA4LjMzMzMzMzMzJTtcbn1cbi5jb2wtYXV0byB7XG4gIGZsZXg6IDAgMCBhdXRvO1xuICBtYXgtd2lkdGg6IG5vbmU7XG4gIHdpZHRoOiBhdXRvO1xufVxuLmNvbC1teC1hdXRvIHtcbiAgbWFyZ2luLWxlZnQ6IGF1dG87XG4gIG1hcmdpbi1yaWdodDogYXV0bztcbn1cbi5jb2wtbWwtYXV0byB7XG4gIG1hcmdpbi1sZWZ0OiBhdXRvO1xufVxuLmNvbC1tci1hdXRvIHtcbiAgbWFyZ2luLXJpZ2h0OiBhdXRvO1xufVxuQG1lZGlhIChtYXgtd2lkdGg6ICRzaXplLXhsKSB7XG4gIC5jb2wteGwtMTIsXG4gIC5jb2wteGwtMTEsXG4gIC5jb2wteGwtMTAsXG4gIC5jb2wteGwtOSxcbiAgLmNvbC14bC04LFxuICAuY29sLXhsLTcsXG4gIC5jb2wteGwtNixcbiAgLmNvbC14bC01LFxuICAuY29sLXhsLTQsXG4gIC5jb2wteGwtMyxcbiAgLmNvbC14bC0yLFxuICAuY29sLXhsLTEge1xuICAgIGZsZXg6IG5vbmU7XG4gIH1cbiAgLmNvbC14bC0xMiB7XG4gICAgd2lkdGg6IDEwMCU7XG4gIH1cbiAgLmNvbC14bC0xMSB7XG4gICAgd2lkdGg6IDkxLjY2NjY2NjY3JTtcbiAgfVxuICAuY29sLXhsLTEwIHtcbiAgICB3aWR0aDogODMuMzMzMzMzMzMlO1xuICB9XG4gIC5jb2wteGwtOSB7XG4gICAgd2lkdGg6IDc1JTtcbiAgfVxuICAuY29sLXhsLTgge1xuICAgIHdpZHRoOiA2Ni42NjY2NjY2NyU7XG4gIH1cbiAgLmNvbC14bC03IHtcbiAgICB3aWR0aDogNTguMzMzMzMzMzMlO1xuICB9XG4gIC5jb2wteGwtNiB7XG4gICAgd2lkdGg6IDUwJTtcbiAgfVxuICAuY29sLXhsLTUge1xuICAgIHdpZHRoOiA0MS42NjY2NjY2NyU7XG4gIH1cbiAgLmNvbC14bC00IHtcbiAgICB3aWR0aDogMzMuMzMzMzMzMzMlO1xuICB9XG4gIC5jb2wteGwtMyB7XG4gICAgd2lkdGg6IDI1JTtcbiAgfVxuICAuY29sLXhsLTIge1xuICAgIHdpZHRoOiAxNi42NjY2NjY2NyU7XG4gIH1cbiAgLmNvbC14bC0xIHtcbiAgICB3aWR0aDogOC4zMzMzMzMzMyU7XG4gIH1cbiAgLmhpZGUteGwge1xuICAgIGRpc3BsYXk6IG5vbmUgIWltcG9ydGFudDtcbiAgfVxuICAuc2hvdy14bCB7XG4gICAgZGlzcGxheTogYmxvY2sgIWltcG9ydGFudDtcbiAgfVxufVxuQG1lZGlhIChtYXgtd2lkdGg6ICRzaXplLWxnKSB7XG4gIC5jb2wtbGctMTIsXG4gIC5jb2wtbGctMTEsXG4gIC5jb2wtbGctMTAsXG4gIC5jb2wtbGctOSxcbiAgLmNvbC1sZy04LFxuICAuY29sLWxnLTcsXG4gIC5jb2wtbGctNixcbiAgLmNvbC1sZy01LFxuICAuY29sLWxnLTQsXG4gIC5jb2wtbGctMyxcbiAgLmNvbC1sZy0yLFxuICAuY29sLWxnLTEge1xuICAgIGZsZXg6IG5vbmU7XG4gIH1cbiAgLmNvbC1sZy0xMiB7XG4gICAgd2lkdGg6IDEwMCU7XG4gIH1cbiAgLmNvbC1sZy0xMSB7XG4gICAgd2lkdGg6IDkxLjY2NjY2NjY3JTtcbiAgfVxuICAuY29sLWxnLTEwIHtcbiAgICB3aWR0aDogODMuMzMzMzMzMzMlO1xuICB9XG4gIC5jb2wtbGctOSB7XG4gICAgd2lkdGg6IDc1JTtcbiAgfVxuICAuY29sLWxnLTgge1xuICAgIHdpZHRoOiA2Ni42NjY2NjY2NyU7XG4gIH1cbiAgLmNvbC1sZy03IHtcbiAgICB3aWR0aDogNTguMzMzMzMzMzMlO1xuICB9XG4gIC5jb2wtbGctNiB7XG4gICAgd2lkdGg6IDUwJTtcbiAgfVxuICAuY29sLWxnLTUge1xuICAgIHdpZHRoOiA0MS42NjY2NjY2NyU7XG4gIH1cbiAgLmNvbC1sZy00IHtcbiAgICB3aWR0aDogMzMuMzMzMzMzMzMlO1xuICB9XG4gIC5jb2wtbGctMyB7XG4gICAgd2lkdGg6IDI1JTtcbiAgfVxuICAuY29sLWxnLTIge1xuICAgIHdpZHRoOiAxNi42NjY2NjY2NyU7XG4gIH1cbiAgLmNvbC1sZy0xIHtcbiAgICB3aWR0aDogOC4zMzMzMzMzMyU7XG4gIH1cbiAgLmhpZGUtbGcge1xuICAgIGRpc3BsYXk6IG5vbmUgIWltcG9ydGFudDtcbiAgfVxuICAuc2hvdy1sZyB7XG4gICAgZGlzcGxheTogYmxvY2sgIWltcG9ydGFudDtcbiAgfVxufVxuQG1lZGlhIChtYXgtd2lkdGg6ICRzaXplLW1kKSB7XG4gIC5jb2wtbWQtMTIsXG4gIC5jb2wtbWQtMTEsXG4gIC5jb2wtbWQtMTAsXG4gIC5jb2wtbWQtOSxcbiAgLmNvbC1tZC04LFxuICAuY29sLW1kLTcsXG4gIC5jb2wtbWQtNixcbiAgLmNvbC1tZC01LFxuICAuY29sLW1kLTQsXG4gIC5jb2wtbWQtMyxcbiAgLmNvbC1tZC0yLFxuICAuY29sLW1kLTEge1xuICAgIGZsZXg6IG5vbmU7XG4gIH1cbiAgLmNvbC1tZC0xMiB7XG4gICAgd2lkdGg6IDEwMCU7XG4gIH1cbiAgLmNvbC1tZC0xMSB7XG4gICAgd2lkdGg6IDkxLjY2NjY2NjY3JTtcbiAgfVxuICAuY29sLW1kLTEwIHtcbiAgICB3aWR0aDogODMuMzMzMzMzMzMlO1xuICB9XG4gIC5jb2wtbWQtOSB7XG4gICAgd2lkdGg6IDc1JTtcbiAgfVxuICAuY29sLW1kLTgge1xuICAgIHdpZHRoOiA2Ni42NjY2NjY2NyU7XG4gIH1cbiAgLmNvbC1tZC03IHtcbiAgICB3aWR0aDogNTguMzMzMzMzMzMlO1xuICB9XG4gIC5jb2wtbWQtNiB7XG4gICAgd2lkdGg6IDUwJTtcbiAgfVxuICAuY29sLW1kLTUge1xuICAgIHdpZHRoOiA0MS42NjY2NjY2NyU7XG4gIH1cbiAgLmNvbC1tZC00IHtcbiAgICB3aWR0aDogMzMuMzMzMzMzMzMlO1xuICB9XG4gIC5jb2wtbWQtMyB7XG4gICAgd2lkdGg6IDI1JTtcbiAgfVxuICAuY29sLW1kLTIge1xuICAgIHdpZHRoOiAxNi42NjY2NjY2NyU7XG4gIH1cbiAgLmNvbC1tZC0xIHtcbiAgICB3aWR0aDogOC4zMzMzMzMzMyU7XG4gIH1cbiAgLmhpZGUtbWQge1xuICAgIGRpc3BsYXk6IG5vbmUgIWltcG9ydGFudDtcbiAgfVxuICAuc2hvdy1tZCB7XG4gICAgZGlzcGxheTogYmxvY2sgIWltcG9ydGFudDtcbiAgfVxufVxuQG1lZGlhIChtYXgtd2lkdGg6ICRzaXplLXNtKSB7XG4gIC5jb2wtc20tMTIsXG4gIC5jb2wtc20tMTEsXG4gIC5jb2wtc20tMTAsXG4gIC5jb2wtc20tOSxcbiAgLmNvbC1zbS04LFxuICAuY29sLXNtLTcsXG4gIC5jb2wtc20tNixcbiAgLmNvbC1zbS01LFxuICAuY29sLXNtLTQsXG4gIC5jb2wtc20tMyxcbiAgLmNvbC1zbS0yLFxuICAuY29sLXNtLTEge1xuICAgIGZsZXg6IG5vbmU7XG4gIH1cbiAgLmNvbC1zbS0xMiB7XG4gICAgd2lkdGg6IDEwMCU7XG4gIH1cbiAgLmNvbC1zbS0xMSB7XG4gICAgd2lkdGg6IDkxLjY2NjY2NjY3JTtcbiAgfVxuICAuY29sLXNtLTEwIHtcbiAgICB3aWR0aDogODMuMzMzMzMzMzMlO1xuICB9XG4gIC5jb2wtc20tOSB7XG4gICAgd2lkdGg6IDc1JTtcbiAgfVxuICAuY29sLXNtLTgge1xuICAgIHdpZHRoOiA2Ni42NjY2NjY2NyU7XG4gIH1cbiAgLmNvbC1zbS03IHtcbiAgICB3aWR0aDogNTguMzMzMzMzMzMlO1xuICB9XG4gIC5jb2wtc20tNiB7XG4gICAgd2lkdGg6IDUwJTtcbiAgfVxuICAuY29sLXNtLTUge1xuICAgIHdpZHRoOiA0MS42NjY2NjY2NyU7XG4gIH1cbiAgLmNvbC1zbS00IHtcbiAgICB3aWR0aDogMzMuMzMzMzMzMzMlO1xuICB9XG4gIC5jb2wtc20tMyB7XG4gICAgd2lkdGg6IDI1JTtcbiAgfVxuICAuY29sLXNtLTIge1xuICAgIHdpZHRoOiAxNi42NjY2NjY2NyU7XG4gIH1cbiAgLmNvbC1zbS0xIHtcbiAgICB3aWR0aDogOC4zMzMzMzMzMyU7XG4gIH1cbiAgLmhpZGUtc20ge1xuICAgIGRpc3BsYXk6IG5vbmUgIWltcG9ydGFudDtcbiAgfVxuICAuc2hvdy1zbSB7XG4gICAgZGlzcGxheTogYmxvY2sgIWltcG9ydGFudDtcbiAgfVxufVxuQG1lZGlhIChtYXgtd2lkdGg6ICRzaXplLXhzKSB7XG4gIC5jb2wteHMtMTIsXG4gIC5jb2wteHMtMTEsXG4gIC5jb2wteHMtMTAsXG4gIC5jb2wteHMtOSxcbiAgLmNvbC14cy04LFxuICAuY29sLXhzLTcsXG4gIC5jb2wteHMtNixcbiAgLmNvbC14cy01LFxuICAuY29sLXhzLTQsXG4gIC5jb2wteHMtMyxcbiAgLmNvbC14cy0yLFxuICAuY29sLXhzLTEge1xuICAgIGZsZXg6IG5vbmU7XG4gIH1cbiAgLmNvbC14cy0xMiB7XG4gICAgd2lkdGg6IDEwMCU7XG4gIH1cbiAgLmNvbC14cy0xMSB7XG4gICAgd2lkdGg6IDkxLjY2NjY2NjY3JTtcbiAgfVxuICAuY29sLXhzLTEwIHtcbiAgICB3aWR0aDogODMuMzMzMzMzMzMlO1xuICB9XG4gIC5jb2wteHMtOSB7XG4gICAgd2lkdGg6IDc1JTtcbiAgfVxuICAuY29sLXhzLTgge1xuICAgIHdpZHRoOiA2Ni42NjY2NjY2NyU7XG4gIH1cbiAgLmNvbC14cy03IHtcbiAgICB3aWR0aDogNTguMzMzMzMzMzMlO1xuICB9XG4gIC5jb2wteHMtNiB7XG4gICAgd2lkdGg6IDUwJTtcbiAgfVxuICAuY29sLXhzLTUge1xuICAgIHdpZHRoOiA0MS42NjY2NjY2NyU7XG4gIH1cbiAgLmNvbC14cy00IHtcbiAgICB3aWR0aDogMzMuMzMzMzMzMzMlO1xuICB9XG4gIC5jb2wteHMtMyB7XG4gICAgd2lkdGg6IDI1JTtcbiAgfVxuICAuY29sLXhzLTIge1xuICAgIHdpZHRoOiAxNi42NjY2NjY2NyU7XG4gIH1cbiAgLmNvbC14cy0xIHtcbiAgICB3aWR0aDogOC4zMzMzMzMzMyU7XG4gIH1cbiAgLmhpZGUteHMge1xuICAgIGRpc3BsYXk6IG5vbmUgIWltcG9ydGFudDtcbiAgfVxuICAuc2hvdy14cyB7XG4gICAgZGlzcGxheTogYmxvY2sgIWltcG9ydGFudDtcbiAgfVxufVxuIiwiLy8gTmF2YmFyXG4ubmF2YmFyIHtcbiAgYWxpZ24taXRlbXM6IHN0cmV0Y2g7XG4gIGRpc3BsYXk6IGZsZXg7XG4gIGZsZXgtd3JhcDogd3JhcDtcbiAganVzdGlmeS1jb250ZW50OiBzcGFjZS1iZXR3ZWVuO1xuXG4gIC5uYXZiYXItc2VjdGlvbiB7XG4gICAgYWxpZ24taXRlbXM6IGNlbnRlcjtcbiAgICBkaXNwbGF5OiBmbGV4O1xuICAgIGZsZXg6IDEgMCAwO1xuXG4gICAgJjpub3QoOmZpcnN0LWNoaWxkKTpsYXN0LWNoaWxkIHtcbiAgICAgIGp1c3RpZnktY29udGVudDogZmxleC1lbmQ7XG4gICAgfVxuICB9XG5cbiAgLm5hdmJhci1jZW50ZXIge1xuICAgIGFsaWduLWl0ZW1zOiBjZW50ZXI7XG4gICAgZGlzcGxheTogZmxleDtcbiAgICBmbGV4OiAwIDAgYXV0bztcbiAgfVxuXG4gIC5uYXZiYXItYnJhbmQge1xuICAgIGZvbnQtc2l6ZTogJGZvbnQtc2l6ZS1sZztcbiAgICBmb250LXdlaWdodDogNTAwO1xuICAgIHRleHQtZGVjb3JhdGlvbjogbm9uZTtcbiAgfVxufVxuIiwiLy8gQWNjb3JkaW9uc1xuLmFjY29yZGlvbiB7XG4gIGlucHV0OmNoZWNrZWQgfixcbiAgJltvcGVuXSB7XG4gICAgJiAuYWNjb3JkaW9uLWhlYWRlciB7XG4gICAgICAuaWNvbiB7XG4gICAgICAgIHRyYW5zZm9ybTogcm90YXRlKDkwZGVnKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAmIC5hY2NvcmRpb24tYm9keSB7XG4gICAgICBtYXgtaGVpZ2h0OiA1MHJlbTtcbiAgICB9XG4gIH1cblxuICAuYWNjb3JkaW9uLWhlYWRlciB7XG4gICAgZGlzcGxheTogYmxvY2s7XG4gICAgcGFkZGluZzogJHVuaXQtMSAkdW5pdC0yO1xuXG4gICAgLmljb24ge1xuICAgICAgdHJhbnNpdGlvbjogYWxsIC4ycyBlYXNlO1xuICAgIH1cbiAgfVxuXG4gIC5hY2NvcmRpb24tYm9keSB7XG4gICAgbWFyZ2luLWJvdHRvbTogJGxheW91dC1zcGFjaW5nO1xuICAgIG1heC1oZWlnaHQ6IDA7XG4gICAgb3ZlcmZsb3c6IGhpZGRlbjtcbiAgICB0cmFuc2l0aW9uOiBtYXgtaGVpZ2h0IC4ycyBlYXNlO1xuICB9XG59XG5cbi8vIFJlbW92ZSBkZWZhdWx0IGRldGFpbHMgbWFya2VyIGluIFdlYmtpdFxuc3VtbWFyeS5hY2NvcmRpb24taGVhZGVyIHtcbiAgJjo6LXdlYmtpdC1kZXRhaWxzLW1hcmtlciB7XG4gICAgZGlzcGxheTogbm9uZTtcbiAgfVxufVxuIiwiLy8gQXZhdGFyc1xuLmF2YXRhciB7XG4gIEBpbmNsdWRlIGF2YXRhci1iYXNlKCk7XG4gIGJhY2tncm91bmQ6ICRwcmltYXJ5LWNvbG9yO1xuICBib3JkZXItcmFkaXVzOiA1MCU7XG4gIGNvbG9yOiByZ2JhKCRsaWdodC1jb2xvciwgLjg1KTtcbiAgZGlzcGxheTogaW5saW5lLWJsb2NrO1xuICBmb250LXdlaWdodDogMzAwO1xuICBsaW5lLWhlaWdodDogMS4yNTtcbiAgbWFyZ2luOiAwO1xuICBwb3NpdGlvbjogcmVsYXRpdmU7XG4gIHZlcnRpY2FsLWFsaWduOiBtaWRkbGU7XG5cbiAgJi5hdmF0YXIteHMge1xuICAgIEBpbmNsdWRlIGF2YXRhci1iYXNlKCR1bml0LTQpO1xuICB9XG4gICYuYXZhdGFyLXNtIHtcbiAgICBAaW5jbHVkZSBhdmF0YXItYmFzZSgkdW5pdC02KTtcbiAgfVxuICAmLmF2YXRhci1sZyB7XG4gICAgQGluY2x1ZGUgYXZhdGFyLWJhc2UoJHVuaXQtMTIpO1xuICB9XG4gICYuYXZhdGFyLXhsIHtcbiAgICBAaW5jbHVkZSBhdmF0YXItYmFzZSgkdW5pdC0xNik7XG4gIH1cblxuICBpbWcge1xuICAgIGJvcmRlci1yYWRpdXM6IDUwJTtcbiAgICBoZWlnaHQ6IDEwMCU7XG4gICAgcG9zaXRpb246IHJlbGF0aXZlO1xuICAgIHdpZHRoOiAxMDAlO1xuICAgIHotaW5kZXg6ICR6aW5kZXgtMDtcbiAgfVxuXG4gIC5hdmF0YXItaWNvbixcbiAgLmF2YXRhci1wcmVzZW5jZSB7XG4gICAgYmFja2dyb3VuZDogJGJnLWNvbG9yLWxpZ2h0O1xuICAgIGJvdHRvbTogMTQuNjQlO1xuICAgIGhlaWdodDogNTAlO1xuICAgIHBhZGRpbmc6ICRib3JkZXItd2lkdGgtbGc7XG4gICAgcG9zaXRpb246IGFic29sdXRlO1xuICAgIHJpZ2h0OiAxNC42NCU7XG4gICAgdHJhbnNmb3JtOiB0cmFuc2xhdGUoNTAlLCA1MCUpO1xuICAgIHdpZHRoOiA1MCU7XG4gICAgei1pbmRleDogJHppbmRleC0wICsgMTtcbiAgfVxuXG4gIC5hdmF0YXItcHJlc2VuY2Uge1xuICAgIGJhY2tncm91bmQ6ICRncmF5LWNvbG9yO1xuICAgIGJveC1zaGFkb3c6IDAgMCAwICRib3JkZXItd2lkdGgtbGcgJGxpZ2h0LWNvbG9yO1xuICAgIGJvcmRlci1yYWRpdXM6IDUwJTtcbiAgICBoZWlnaHQ6IC41ZW07XG4gICAgd2lkdGg6IC41ZW07XG5cbiAgICAmLm9ubGluZSB7XG4gICAgICBiYWNrZ3JvdW5kOiAkc3VjY2Vzcy1jb2xvcjtcbiAgICB9XG5cbiAgICAmLmJ1c3kge1xuICAgICAgYmFja2dyb3VuZDogJGVycm9yLWNvbG9yO1xuICAgIH1cblxuICAgICYuYXdheSB7XG4gICAgICBiYWNrZ3JvdW5kOiAkd2FybmluZy1jb2xvcjtcbiAgICB9XG4gIH1cblxuICAmW2RhdGEtaW5pdGlhbF06OmJlZm9yZSB7XG4gICAgY29sb3I6IGN1cnJlbnRDb2xvcjtcbiAgICBjb250ZW50OiBhdHRyKGRhdGEtaW5pdGlhbCk7XG4gICAgbGVmdDogNTAlO1xuICAgIHBvc2l0aW9uOiBhYnNvbHV0ZTtcbiAgICB0b3A6IDUwJTtcbiAgICB0cmFuc2Zvcm06IHRyYW5zbGF0ZSgtNTAlLCAtNTAlKTtcbiAgICB6LWluZGV4OiAkemluZGV4LTA7XG4gIH1cbn0iLCIvLyBCYWRnZXNcbi5iYWRnZSB7XG4gIHBvc2l0aW9uOiByZWxhdGl2ZTtcbiAgd2hpdGUtc3BhY2U6IG5vd3JhcDtcblxuICAmW2RhdGEtYmFkZ2VdLFxuICAmOm5vdChbZGF0YS1iYWRnZV0pIHtcbiAgICAmOjphZnRlciB7XG4gICAgICBiYWNrZ3JvdW5kOiAkcHJpbWFyeS1jb2xvcjtcbiAgICAgIGJhY2tncm91bmQtY2xpcDogcGFkZGluZy1ib3g7XG4gICAgICBib3JkZXItcmFkaXVzOiAuNXJlbTtcbiAgICAgIGJveC1zaGFkb3c6IDAgMCAwIC4xcmVtICRiZy1jb2xvci1saWdodDtcbiAgICAgIGNvbG9yOiAkbGlnaHQtY29sb3I7XG4gICAgICBjb250ZW50OiBhdHRyKGRhdGEtYmFkZ2UpO1xuICAgICAgZGlzcGxheTogaW5saW5lLWJsb2NrO1xuICAgICAgdHJhbnNmb3JtOiB0cmFuc2xhdGUoLS4wNXJlbSwgLS41cmVtKTtcbiAgICB9XG4gIH1cbiAgJltkYXRhLWJhZGdlXSB7XG4gICAgJjo6YWZ0ZXIge1xuICAgICAgZm9udC1zaXplOiAkZm9udC1zaXplLXNtO1xuICAgICAgaGVpZ2h0OiAuOXJlbTtcbiAgICAgIGxpbmUtaGVpZ2h0OiAxO1xuICAgICAgbWluLXdpZHRoOiAuOXJlbTtcbiAgICAgIHBhZGRpbmc6IC4xcmVtIC4ycmVtO1xuICAgICAgdGV4dC1hbGlnbjogY2VudGVyO1xuICAgICAgd2hpdGUtc3BhY2U6IG5vd3JhcDtcbiAgICB9XG4gIH1cbiAgJjpub3QoW2RhdGEtYmFkZ2VdKSxcbiAgJltkYXRhLWJhZGdlPVwiXCJdIHtcbiAgICAmOjphZnRlciB7XG4gICAgICBoZWlnaHQ6IDZweDtcbiAgICAgIG1pbi13aWR0aDogNnB4O1xuICAgICAgcGFkZGluZzogMDtcbiAgICAgIHdpZHRoOiA2cHg7XG4gICAgfVxuICB9XG5cbiAgLy8gQmFkZ2VzIGZvciBCdXR0b25zXG4gICYuYnRuIHtcbiAgICAmOjphZnRlciB7XG4gICAgICBwb3NpdGlvbjogYWJzb2x1dGU7XG4gICAgICB0b3A6IDA7XG4gICAgICByaWdodDogMDtcbiAgICAgIHRyYW5zZm9ybTogdHJhbnNsYXRlKDUwJSwgLTUwJSk7XG4gICAgfVxuICB9XG5cbiAgLy8gQmFkZ2VzIGZvciBBdmF0YXJzXG4gICYuYXZhdGFyIHtcbiAgICAmOjphZnRlciB7XG4gICAgICBwb3NpdGlvbjogYWJzb2x1dGU7XG4gICAgICB0b3A6IDE0LjY0JTtcbiAgICAgIHJpZ2h0OiAxNC42NCU7XG4gICAgICB0cmFuc2Zvcm06IHRyYW5zbGF0ZSg1MCUsIC01MCUpO1xuICAgICAgei1pbmRleDogJHppbmRleC0xO1xuICAgIH1cbiAgfVxufVxuIiwiLy8gQnJlYWRjcnVtYnNcbi5icmVhZGNydW1iIHtcbiAgbGlzdC1zdHlsZTogbm9uZTtcbiAgbWFyZ2luOiAkdW5pdC0xIDA7XG4gIHBhZGRpbmc6ICR1bml0LTEgMDtcblxuICAuYnJlYWRjcnVtYi1pdGVtIHtcbiAgICBjb2xvcjogJGdyYXktY29sb3ItZGFyaztcbiAgICBkaXNwbGF5OiBpbmxpbmUtYmxvY2s7XG4gICAgbWFyZ2luOiAwO1xuICAgIHBhZGRpbmc6ICR1bml0LTEgMDtcblxuICAgICY6bm90KDpsYXN0LWNoaWxkKSB7XG4gICAgICBtYXJnaW4tcmlnaHQ6ICR1bml0LTE7XG5cbiAgICAgIGEge1xuICAgICAgICBjb2xvcjogJGdyYXktY29sb3ItZGFyaztcbiAgICAgIH1cbiAgICB9XG5cbiAgICAmOm5vdCg6Zmlyc3QtY2hpbGQpIHtcbiAgICAgICY6OmJlZm9yZSB7XG4gICAgICAgIGNvbG9yOiAkZ3JheS1jb2xvci1saWdodDtcbiAgICAgICAgY29udGVudDogXCIvXCI7XG4gICAgICAgIHBhZGRpbmctcmlnaHQ6ICR1bml0LTI7XG4gICAgICB9XG4gICAgfVxuICB9XG59XG4iLCIvLyBCYXJzXG4uYmFyIHtcbiAgYmFja2dyb3VuZDogJGJnLWNvbG9yLWRhcms7XG4gIGJvcmRlci1yYWRpdXM6ICRib3JkZXItcmFkaXVzO1xuICBkaXNwbGF5OiBmbGV4O1xuICBmbGV4LXdyYXA6IG5vd3JhcDtcbiAgaGVpZ2h0OiAkdW5pdC00O1xuICB3aWR0aDogMTAwJTtcblxuICAmLmJhci1zbSB7XG4gICAgaGVpZ2h0OiAkdW5pdC0xO1xuICB9XG5cbiAgLy8gVE9ETzogYXR0cigpIHN1cHBvcnRcbiAgLmJhci1pdGVtIHtcbiAgICBiYWNrZ3JvdW5kOiAkcHJpbWFyeS1jb2xvcjtcbiAgICBjb2xvcjogJGxpZ2h0LWNvbG9yO1xuICAgIGRpc3BsYXk6IGJsb2NrO1xuICAgIGZvbnQtc2l6ZTogJGZvbnQtc2l6ZS1zbTtcbiAgICBmbGV4LXNocmluazogMDtcbiAgICBsaW5lLWhlaWdodDogJHVuaXQtNDtcbiAgICBoZWlnaHQ6IDEwMCU7XG4gICAgcG9zaXRpb246IHJlbGF0aXZlO1xuICAgIHRleHQtYWxpZ246IGNlbnRlcjtcbiAgICB3aWR0aDogMDtcblxuICAgICY6Zmlyc3QtY2hpbGQge1xuICAgICAgYm9yZGVyLWJvdHRvbS1sZWZ0LXJhZGl1czogJGJvcmRlci1yYWRpdXM7XG4gICAgICBib3JkZXItdG9wLWxlZnQtcmFkaXVzOiAkYm9yZGVyLXJhZGl1cztcbiAgICB9XG4gICAgJjpsYXN0LWNoaWxkIHtcbiAgICAgIGJvcmRlci1ib3R0b20tcmlnaHQtcmFkaXVzOiAkYm9yZGVyLXJhZGl1cztcbiAgICAgIGJvcmRlci10b3AtcmlnaHQtcmFkaXVzOiAkYm9yZGVyLXJhZGl1cztcbiAgICAgIGZsZXgtc2hyaW5rOiAxO1xuICAgIH1cbiAgfVxufVxuXG4vLyBTbGlkZXIgYmFyXG4uYmFyLXNsaWRlciB7XG4gIGhlaWdodDogJGJvcmRlci13aWR0aC1sZztcbiAgbWFyZ2luOiAkbGF5b3V0LXNwYWNpbmcgMDtcbiAgcG9zaXRpb246IHJlbGF0aXZlO1xuXG4gIC5iYXItaXRlbSB7XG4gICAgbGVmdDogMDtcbiAgICBwYWRkaW5nOiAwO1xuICAgIHBvc2l0aW9uOiBhYnNvbHV0ZTtcbiAgICAmOm5vdCg6bGFzdC1jaGlsZCk6Zmlyc3QtY2hpbGQge1xuICAgICAgYmFja2dyb3VuZDogJGJnLWNvbG9yLWRhcms7XG4gICAgICB6LWluZGV4OiAkemluZGV4LTA7XG4gICAgfVxuICB9XG5cbiAgLmJhci1zbGlkZXItYnRuIHtcbiAgICBiYWNrZ3JvdW5kOiAkcHJpbWFyeS1jb2xvcjtcbiAgICBib3JkZXI6IDA7XG4gICAgYm9yZGVyLXJhZGl1czogNTAlO1xuICAgIGhlaWdodDogJHVuaXQtMztcbiAgICBwYWRkaW5nOiAwO1xuICAgIHBvc2l0aW9uOiBhYnNvbHV0ZTtcbiAgICByaWdodDogMDtcbiAgICB0b3A6IDUwJTtcbiAgICB0cmFuc2Zvcm06IHRyYW5zbGF0ZSg1MCUsIC01MCUpO1xuICAgIHdpZHRoOiAkdW5pdC0zO1xuXG4gICAgJjphY3RpdmUge1xuICAgICAgYm94LXNoYWRvdzogMCAwIDAgLjFyZW0gJHByaW1hcnktY29sb3I7XG4gICAgfVxuICB9XG59XG4iLCIvLyBDYXJkc1xuLmNhcmQge1xuICBiYWNrZ3JvdW5kOiAkYmctY29sb3ItbGlnaHQ7XG4gIGJvcmRlcjogJGJvcmRlci13aWR0aCBzb2xpZCAkYm9yZGVyLWNvbG9yO1xuICBib3JkZXItcmFkaXVzOiAkYm9yZGVyLXJhZGl1cztcbiAgZGlzcGxheTogZmxleDtcbiAgZmxleC1kaXJlY3Rpb246IGNvbHVtbjtcblxuICAuY2FyZC1oZWFkZXIsXG4gIC5jYXJkLWJvZHksXG4gIC5jYXJkLWZvb3RlciB7XG4gICAgcGFkZGluZzogJGxheW91dC1zcGFjaW5nLWxnO1xuICAgIHBhZGRpbmctYm90dG9tOiAwO1xuXG4gICAgJjpsYXN0LWNoaWxkIHtcbiAgICAgIHBhZGRpbmctYm90dG9tOiAkbGF5b3V0LXNwYWNpbmctbGc7XG4gICAgfVxuICB9XG5cbiAgLmNhcmQtYm9keSB7XG4gICAgZmxleDogMSAxIGF1dG87XG4gIH1cblxuICAuY2FyZC1pbWFnZSB7XG4gICAgcGFkZGluZy10b3A6ICRsYXlvdXQtc3BhY2luZy1sZztcblxuICAgICY6Zmlyc3QtY2hpbGQge1xuICAgICAgcGFkZGluZy10b3A6IDA7XG5cbiAgICAgIGltZyB7XG4gICAgICAgIGJvcmRlci10b3AtbGVmdC1yYWRpdXM6ICRib3JkZXItcmFkaXVzO1xuICAgICAgICBib3JkZXItdG9wLXJpZ2h0LXJhZGl1czogJGJvcmRlci1yYWRpdXM7XG4gICAgICB9XG4gICAgfVxuXG4gICAgJjpsYXN0LWNoaWxkIHtcbiAgICAgIGltZyB7XG4gICAgICAgIGJvcmRlci1ib3R0b20tbGVmdC1yYWRpdXM6ICRib3JkZXItcmFkaXVzO1xuICAgICAgICBib3JkZXItYm90dG9tLXJpZ2h0LXJhZGl1czogJGJvcmRlci1yYWRpdXM7XG4gICAgICB9XG4gICAgfVxuICB9XG59XG4iLCIvLyBDaGlwc1xuLmNoaXAge1xuICBhbGlnbi1pdGVtczogY2VudGVyO1xuICBiYWNrZ3JvdW5kOiAkYmctY29sb3ItZGFyaztcbiAgYm9yZGVyLXJhZGl1czogNXJlbTtcbiAgY29sb3I6ICRncmF5LWNvbG9yLWRhcms7XG4gIGRpc3BsYXk6IGlubGluZS1mbGV4O1xuICBmb250LXNpemU6IDkwJTtcbiAgaGVpZ2h0OiAkdW5pdC02O1xuICBsaW5lLWhlaWdodDogJHVuaXQtNDtcbiAgbWFyZ2luOiAkdW5pdC1oO1xuICBtYXgtd2lkdGg6IDEwMCU7XG4gIHBhZGRpbmc6ICR1bml0LTEgJHVuaXQtMjtcbiAgdGV4dC1kZWNvcmF0aW9uOiBub25lO1xuICB2ZXJ0aWNhbC1hbGlnbjogbWlkZGxlO1xuXG4gICYuYWN0aXZlIHtcbiAgICBiYWNrZ3JvdW5kOiAkcHJpbWFyeS1jb2xvcjtcbiAgICBjb2xvcjogJGxpZ2h0LWNvbG9yO1xuICB9XG5cbiAgLmF2YXRhciB7XG4gICAgbWFyZ2luLWxlZnQ6IC0kdW5pdC0yO1xuICAgIG1hcmdpbi1yaWdodDogJHVuaXQtMTtcbiAgfVxuXG4gIC5idG4tY2xlYXIge1xuICAgIHRyYW5zZm9ybTogc2NhbGUoLjc1KTtcbiAgfVxufVxuIiwiLy8gRHJvcGRvd25cbi5kcm9wZG93biB7XG4gIGRpc3BsYXk6IGlubGluZS1ibG9jaztcbiAgcG9zaXRpb246IHJlbGF0aXZlO1xuXG4gIC5tZW51IHtcbiAgICBhbmltYXRpb246IHNsaWRlLWRvd24gLjE1cyBlYXNlIDE7XG4gICAgZGlzcGxheTogbm9uZTtcbiAgICBsZWZ0OiAwO1xuICAgIG1heC1oZWlnaHQ6IDUwdmg7XG4gICAgb3ZlcmZsb3cteTogYXV0bztcbiAgICBwb3NpdGlvbjogYWJzb2x1dGU7XG4gICAgdG9wOiAxMDAlO1xuICB9XG5cbiAgJi5kcm9wZG93bi1yaWdodCB7XG4gICAgLm1lbnUge1xuICAgICAgbGVmdDogYXV0bztcbiAgICAgIHJpZ2h0OiAwO1xuICAgIH1cbiAgfVxuXG4gICYuYWN0aXZlIC5tZW51LFxuICAuZHJvcGRvd24tdG9nZ2xlOmZvY3VzICsgLm1lbnUsXG4gIC5tZW51OmhvdmVyIHtcbiAgICBkaXNwbGF5OiBibG9jaztcbiAgfVxuXG4gIC8vIEZpeCBkcm9wZG93bi10b2dnbGUgYm9yZGVyIHJhZGl1cyBpbiBidXR0b24gZ3JvdXBzXG4gIC5idG4tZ3JvdXAge1xuICAgIC5kcm9wZG93bi10b2dnbGU6bnRoLWxhc3QtY2hpbGQoMikge1xuICAgICAgYm9yZGVyLWJvdHRvbS1yaWdodC1yYWRpdXM6ICRib3JkZXItcmFkaXVzO1xuICAgICAgYm9yZGVyLXRvcC1yaWdodC1yYWRpdXM6ICRib3JkZXItcmFkaXVzO1xuICAgIH1cbiAgfVxufVxuIiwiLy8gRW1wdHkgc3RhdGVzIChvciBCbGFuayBzbGF0ZXMpXG4uZW1wdHkge1xuICBiYWNrZ3JvdW5kOiAkYmctY29sb3I7XG4gIGJvcmRlci1yYWRpdXM6ICRib3JkZXItcmFkaXVzO1xuICBjb2xvcjogJGdyYXktY29sb3ItZGFyaztcbiAgdGV4dC1hbGlnbjogY2VudGVyO1xuICBwYWRkaW5nOiAkdW5pdC0xNiAkdW5pdC04O1xuXG4gIC5lbXB0eS1pY29uIHtcbiAgICBtYXJnaW4tYm90dG9tOiAkbGF5b3V0LXNwYWNpbmctbGc7XG4gIH1cblxuICAuZW1wdHktdGl0bGUsXG4gIC5lbXB0eS1zdWJ0aXRsZSB7XG4gICAgbWFyZ2luOiAkbGF5b3V0LXNwYWNpbmcgYXV0bztcbiAgfVxuXG4gIC5lbXB0eS1hY3Rpb24ge1xuICAgIG1hcmdpbi10b3A6ICRsYXlvdXQtc3BhY2luZy1sZztcbiAgfVxufVxuIiwiLy8gTWVudXNcbi5tZW51IHtcbiAgQGluY2x1ZGUgc2hhZG93LXZhcmlhbnQoLjA1cmVtKTtcbiAgYmFja2dyb3VuZDogJGJnLWNvbG9yLWxpZ2h0O1xuICBib3JkZXItcmFkaXVzOiAkYm9yZGVyLXJhZGl1cztcbiAgbGlzdC1zdHlsZTogbm9uZTtcbiAgbWFyZ2luOiAwO1xuICBtaW4td2lkdGg6ICRjb250cm9sLXdpZHRoLXhzO1xuICBwYWRkaW5nOiAkdW5pdC0yO1xuICB0cmFuc2Zvcm06IHRyYW5zbGF0ZVkoJGxheW91dC1zcGFjaW5nLXNtKTtcbiAgei1pbmRleDogJHppbmRleC0zO1xuXG4gICYubWVudS1uYXYge1xuICAgIGJhY2tncm91bmQ6IHRyYW5zcGFyZW50O1xuICAgIGJveC1zaGFkb3c6IG5vbmU7XG4gIH1cblxuICAubWVudS1pdGVtIHtcbiAgICBtYXJnaW4tdG9wOiAwO1xuICAgIHBhZGRpbmc6IDAgJHVuaXQtMjtcbiAgICB0ZXh0LWRlY29yYXRpb246IG5vbmU7XG4gICAgdXNlci1zZWxlY3Q6IG5vbmU7XG5cbiAgICAmID4gYSB7XG4gICAgICBib3JkZXItcmFkaXVzOiAkYm9yZGVyLXJhZGl1cztcbiAgICAgIGNvbG9yOiBpbmhlcml0O1xuICAgICAgZGlzcGxheTogYmxvY2s7XG4gICAgICBtYXJnaW46IDAgKC0kdW5pdC0yKTtcbiAgICAgIHBhZGRpbmc6ICR1bml0LTEgJHVuaXQtMjtcbiAgICAgIHRleHQtZGVjb3JhdGlvbjogbm9uZTtcbiAgICAgICY6Zm9jdXMsXG4gICAgICAmOmhvdmVyIHtcbiAgICAgICAgYmFja2dyb3VuZDogJHNlY29uZGFyeS1jb2xvcjtcbiAgICAgICAgY29sb3I6ICRwcmltYXJ5LWNvbG9yO1xuICAgICAgfVxuICAgICAgJjphY3RpdmUsXG4gICAgICAmLmFjdGl2ZSB7XG4gICAgICAgIGJhY2tncm91bmQ6ICRzZWNvbmRhcnktY29sb3I7XG4gICAgICAgIGNvbG9yOiAkcHJpbWFyeS1jb2xvcjtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAuZm9ybS1jaGVja2JveCxcbiAgICAuZm9ybS1yYWRpbyxcbiAgICAuZm9ybS1zd2l0Y2gge1xuICAgICAgbWFyZ2luOiAkdW5pdC1oIDA7XG4gICAgfVxuXG4gICAgJiArIC5tZW51LWl0ZW0ge1xuICAgICAgbWFyZ2luLXRvcDogJHVuaXQtMTtcbiAgICB9XG4gIH1cblxuICAubWVudS1iYWRnZSB7XG4gICAgZmxvYXQ6IHJpZ2h0O1xuICAgIHBhZGRpbmc6ICR1bml0LTEgMDtcblxuICAgIC5idG4ge1xuICAgICAgbWFyZ2luLXRvcDogLSR1bml0LWg7XG4gICAgfVxuICB9XG59XG4iLCIvLyBNb2RhbHNcbi5tb2RhbCB7XG4gIGFsaWduLWl0ZW1zOiBjZW50ZXI7XG4gIGJvdHRvbTogMDtcbiAgZGlzcGxheTogbm9uZTtcbiAganVzdGlmeS1jb250ZW50OiBjZW50ZXI7XG4gIGxlZnQ6IDA7XG4gIG9wYWNpdHk6IDA7XG4gIG92ZXJmbG93OiBoaWRkZW47XG4gIHBhZGRpbmc6ICRsYXlvdXQtc3BhY2luZztcbiAgcG9zaXRpb246IGZpeGVkO1xuICByaWdodDogMDtcbiAgdG9wOiAwO1xuXG4gICY6dGFyZ2V0LFxuICAmLmFjdGl2ZSB7XG4gICAgZGlzcGxheTogZmxleDtcbiAgICBvcGFjaXR5OiAxO1xuICAgIHotaW5kZXg6ICR6aW5kZXgtNDtcblxuICAgIC5tb2RhbC1vdmVybGF5IHtcbiAgICAgIGJhY2tncm91bmQ6IHJnYmEoJGJnLWNvbG9yLCAuNzUpO1xuICAgICAgYm90dG9tOiAwO1xuICAgICAgY3Vyc29yOiBkZWZhdWx0O1xuICAgICAgZGlzcGxheTogYmxvY2s7XG4gICAgICBsZWZ0OiAwO1xuICAgICAgcG9zaXRpb246IGFic29sdXRlO1xuICAgICAgcmlnaHQ6IDA7XG4gICAgICB0b3A6IDA7XG4gICAgfVxuXG4gICAgLm1vZGFsLWNvbnRhaW5lciB7XG4gICAgICBhbmltYXRpb246IHNsaWRlLWRvd24gLjJzIGVhc2UgMTtcbiAgICAgIHotaW5kZXg6ICR6aW5kZXgtMDtcbiAgICB9XG4gIH1cblxuICAmLm1vZGFsLXNtIHtcbiAgICAubW9kYWwtY29udGFpbmVyIHtcbiAgICAgIG1heC13aWR0aDogJGNvbnRyb2wtd2lkdGgtc207XG4gICAgICBwYWRkaW5nOiAwICR1bml0LTI7XG4gICAgfVxuICB9XG5cbiAgJi5tb2RhbC1sZyB7XG4gICAgLm1vZGFsLW92ZXJsYXkge1xuICAgICAgYmFja2dyb3VuZDogJGJnLWNvbG9yLWxpZ2h0O1xuICAgIH1cblxuICAgIC5tb2RhbC1jb250YWluZXIge1xuICAgICAgYm94LXNoYWRvdzogbm9uZTtcbiAgICAgIG1heC13aWR0aDogJGNvbnRyb2wtd2lkdGgtbGc7XG4gICAgfVxuICB9XG59XG5cbi5tb2RhbC1jb250YWluZXIge1xuICBAaW5jbHVkZSBzaGFkb3ctdmFyaWFudCguMnJlbSk7XG4gIGJhY2tncm91bmQ6ICRiZy1jb2xvci1saWdodDtcbiAgYm9yZGVyLXJhZGl1czogJGJvcmRlci1yYWRpdXM7XG4gIGRpc3BsYXk6IGZsZXg7XG4gIGZsZXgtZGlyZWN0aW9uOiBjb2x1bW47XG4gIG1heC1oZWlnaHQ6IDc1dmg7XG4gIG1heC13aWR0aDogJGNvbnRyb2wtd2lkdGgtbWQ7XG4gIHBhZGRpbmc6IDAgJHVuaXQtNDtcbiAgd2lkdGg6IDEwMCU7XG5cbiAgJi5tb2RhbC1mdWxsaGVpZ2h0IHtcbiAgICBtYXgtaGVpZ2h0OiAxMDB2aDtcbiAgfVxuXG4gIC5tb2RhbC1oZWFkZXIge1xuICAgIGNvbG9yOiAkZGFyay1jb2xvcjtcbiAgICBwYWRkaW5nOiAkdW5pdC00O1xuICB9XG5cbiAgLm1vZGFsLWJvZHkge1xuICAgIG92ZXJmbG93LXk6IGF1dG87XG4gICAgcGFkZGluZzogJHVuaXQtNDtcbiAgICBwb3NpdGlvbjogcmVsYXRpdmU7XG4gIH1cblxuICAubW9kYWwtZm9vdGVyIHtcbiAgICBwYWRkaW5nOiAkdW5pdC00O1xuICAgIHRleHQtYWxpZ246IHJpZ2h0O1xuICB9XG59XG4iLCIvLyBOYXZzXG4ubmF2IHtcbiAgZGlzcGxheTogZmxleDtcbiAgZmxleC1kaXJlY3Rpb246IGNvbHVtbjtcbiAgbGlzdC1zdHlsZTogbm9uZTtcbiAgbWFyZ2luOiAkdW5pdC0xIDA7XG5cbiAgLm5hdi1pdGVtIHtcbiAgICBhIHtcbiAgICAgIGNvbG9yOiAkZ3JheS1jb2xvci1kYXJrO1xuICAgICAgcGFkZGluZzogJHVuaXQtMSAkdW5pdC0yO1xuICAgICAgdGV4dC1kZWNvcmF0aW9uOiBub25lO1xuICAgICAgJjpmb2N1cyxcbiAgICAgICY6aG92ZXIge1xuICAgICAgICBjb2xvcjogJHByaW1hcnktY29sb3I7XG4gICAgICB9XG4gICAgfVxuICAgICYuYWN0aXZlIHtcbiAgICAgICYgPiBhIHtcbiAgICAgICAgY29sb3I6IGRhcmtlbigkZ3JheS1jb2xvci1kYXJrLCAxMCUpO1xuICAgICAgICBmb250LXdlaWdodDogYm9sZDtcbiAgICAgICAgJjpmb2N1cyxcbiAgICAgICAgJjpob3ZlciB7XG4gICAgICAgICAgY29sb3I6ICRwcmltYXJ5LWNvbG9yO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgJiAubmF2IHtcbiAgICBtYXJnaW4tYm90dG9tOiAkdW5pdC0yO1xuICAgIG1hcmdpbi1sZWZ0OiAkdW5pdC00O1xuICB9XG59XG4iLCIvLyBQYWdpbmF0aW9uXG4ucGFnaW5hdGlvbiB7XG4gIGRpc3BsYXk6IGZsZXg7XG4gIGxpc3Qtc3R5bGU6IG5vbmU7XG4gIG1hcmdpbjogJHVuaXQtMSAwO1xuICBwYWRkaW5nOiAkdW5pdC0xIDA7XG5cbiAgLnBhZ2UtaXRlbSB7XG4gICAgbWFyZ2luOiAkdW5pdC0xICR1bml0LW87XG5cbiAgICBzcGFuIHtcbiAgICAgIGRpc3BsYXk6IGlubGluZS1ibG9jaztcbiAgICAgIHBhZGRpbmc6ICR1bml0LTEgJHVuaXQtMTtcbiAgICB9XG5cbiAgICBhIHtcbiAgICAgIGJvcmRlci1yYWRpdXM6ICRib3JkZXItcmFkaXVzO1xuICAgICAgY29sb3I6ICRncmF5LWNvbG9yLWRhcms7XG4gICAgICBkaXNwbGF5OiBpbmxpbmUtYmxvY2s7XG4gICAgICBwYWRkaW5nOiAkdW5pdC0xICR1bml0LTI7XG4gICAgICB0ZXh0LWRlY29yYXRpb246IG5vbmU7XG4gICAgICAmOmZvY3VzLFxuICAgICAgJjpob3ZlciB7XG4gICAgICAgIGNvbG9yOiAkcHJpbWFyeS1jb2xvcjtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAmLmRpc2FibGVkIHtcbiAgICAgIGEge1xuICAgICAgICBjdXJzb3I6IGRlZmF1bHQ7XG4gICAgICAgIG9wYWNpdHk6IC41O1xuICAgICAgICBwb2ludGVyLWV2ZW50czogbm9uZTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAmLmFjdGl2ZSB7XG4gICAgICBhIHtcbiAgICAgICAgYmFja2dyb3VuZDogJHByaW1hcnktY29sb3I7XG4gICAgICAgIGNvbG9yOiAkbGlnaHQtY29sb3I7XG4gICAgICB9XG4gICAgfVxuXG4gICAgJi5wYWdlLXByZXYsXG4gICAgJi5wYWdlLW5leHQge1xuICAgICAgZmxleDogMSAwIDUwJTtcbiAgICB9XG5cbiAgICAmLnBhZ2UtbmV4dCB7XG4gICAgICB0ZXh0LWFsaWduOiByaWdodDtcbiAgICB9XG5cbiAgICAucGFnZS1pdGVtLXRpdGxlIHtcbiAgICAgIG1hcmdpbjogMDtcbiAgICB9XG5cbiAgICAucGFnZS1pdGVtLXN1YnRpdGxlIHtcbiAgICAgIG1hcmdpbjogMDtcbiAgICAgIG9wYWNpdHk6IC41O1xuICAgIH1cbiAgfVxufVxuIiwiLy8gUGFuZWxzXG4ucGFuZWwge1xuICBib3JkZXI6ICRib3JkZXItd2lkdGggc29saWQgJGJvcmRlci1jb2xvcjtcbiAgYm9yZGVyLXJhZGl1czogJGJvcmRlci1yYWRpdXM7XG4gIGRpc3BsYXk6IGZsZXg7XG4gIGZsZXgtZGlyZWN0aW9uOiBjb2x1bW47XG5cbiAgLnBhbmVsLWhlYWRlcixcbiAgLnBhbmVsLWZvb3RlciB7XG4gICAgZmxleDogMCAwIGF1dG87XG4gICAgcGFkZGluZzogJGxheW91dC1zcGFjaW5nLWxnO1xuICB9XG5cbiAgLnBhbmVsLW5hdiB7XG4gICAgZmxleDogMCAwIGF1dG87XG4gIH1cblxuICAucGFuZWwtYm9keSB7XG4gICAgZmxleDogMSAxIGF1dG87XG4gICAgb3ZlcmZsb3cteTogYXV0bztcbiAgICBwYWRkaW5nOiAwICRsYXlvdXQtc3BhY2luZy1sZztcbiAgfVxufVxuIiwiLy8gUG9wb3ZlcnNcbi5wb3BvdmVyIHtcbiAgZGlzcGxheTogaW5saW5lLWJsb2NrO1xuICBwb3NpdGlvbjogcmVsYXRpdmU7XG5cbiAgLnBvcG92ZXItY29udGFpbmVyIHtcbiAgICBsZWZ0OiA1MCU7XG4gICAgb3BhY2l0eTogMDtcbiAgICBwYWRkaW5nOiAkbGF5b3V0LXNwYWNpbmc7XG4gICAgcG9zaXRpb246IGFic29sdXRlO1xuICAgIHRvcDogMDtcbiAgICB0cmFuc2Zvcm06IHRyYW5zbGF0ZSgtNTAlLCAtNTAlKSBzY2FsZSgwKTtcbiAgICB0cmFuc2l0aW9uOiB0cmFuc2Zvcm0gLjJzIGVhc2U7XG4gICAgd2lkdGg6ICRjb250cm9sLXdpZHRoLXNtO1xuICAgIHotaW5kZXg6ICR6aW5kZXgtMztcbiAgfVxuXG4gICo6Zm9jdXMgKyAucG9wb3Zlci1jb250YWluZXIsXG4gICY6aG92ZXIgLnBvcG92ZXItY29udGFpbmVyIHtcbiAgICBkaXNwbGF5OiBibG9jaztcbiAgICBvcGFjaXR5OiAxO1xuICAgIHRyYW5zZm9ybTogdHJhbnNsYXRlKC01MCUsIC0xMDAlKTtcbiAgfVxuXG4gICYucG9wb3Zlci1yaWdodCB7XG4gICAgLnBvcG92ZXItY29udGFpbmVyIHtcbiAgICAgIGxlZnQ6IDEwMCU7XG4gICAgICB0b3A6IDUwJTtcbiAgICB9XG5cbiAgICAqOmZvY3VzICsgLnBvcG92ZXItY29udGFpbmVyLFxuICAgICY6aG92ZXIgLnBvcG92ZXItY29udGFpbmVyIHtcbiAgICAgIHRyYW5zZm9ybTogdHJhbnNsYXRlKDAsIC01MCUpO1xuICAgIH1cbiAgfVxuXG4gICYucG9wb3Zlci1ib3R0b20ge1xuICAgIC5wb3BvdmVyLWNvbnRhaW5lciB7XG4gICAgICBsZWZ0OiA1MCU7XG4gICAgICB0b3A6IDEwMCU7XG4gICAgfVxuXG4gICAgKjpmb2N1cyArIC5wb3BvdmVyLWNvbnRhaW5lcixcbiAgICAmOmhvdmVyIC5wb3BvdmVyLWNvbnRhaW5lciB7XG4gICAgICB0cmFuc2Zvcm06IHRyYW5zbGF0ZSgtNTAlLCAwKTtcbiAgICB9XG4gIH1cblxuICAmLnBvcG92ZXItbGVmdCB7XG4gICAgLnBvcG92ZXItY29udGFpbmVyIHtcbiAgICAgIGxlZnQ6IDA7XG4gICAgICB0b3A6IDUwJTtcbiAgICB9XG5cbiAgICAqOmZvY3VzICsgLnBvcG92ZXItY29udGFpbmVyLFxuICAgICY6aG92ZXIgLnBvcG92ZXItY29udGFpbmVyIHtcbiAgICAgIHRyYW5zZm9ybTogdHJhbnNsYXRlKC0xMDAlLCAtNTAlKTtcbiAgICB9XG4gIH1cblxuICAuY2FyZCB7XG4gICAgQGluY2x1ZGUgc2hhZG93LXZhcmlhbnQoLjJyZW0pO1xuICAgIGJvcmRlcjogMDtcbiAgfVxufVxuIiwiLy8gU3RlcHNcbi5zdGVwIHtcbiAgZGlzcGxheTogZmxleDtcbiAgZmxleC13cmFwOiBub3dyYXA7XG4gIGxpc3Qtc3R5bGU6IG5vbmU7XG4gIG1hcmdpbjogJHVuaXQtMSAwO1xuICB3aWR0aDogMTAwJTtcblxuICAuc3RlcC1pdGVtIHtcbiAgICBmbGV4OiAxIDEgMDtcbiAgICBtYXJnaW4tdG9wOiAwO1xuICAgIG1pbi1oZWlnaHQ6IDFyZW07XG4gICAgdGV4dC1hbGlnbjogY2VudGVyO1xuICAgIHBvc2l0aW9uOiByZWxhdGl2ZTtcblxuICAgICY6bm90KDpmaXJzdC1jaGlsZCk6OmJlZm9yZSB7XG4gICAgICBiYWNrZ3JvdW5kOiAkcHJpbWFyeS1jb2xvcjtcbiAgICAgIGNvbnRlbnQ6IFwiXCI7XG4gICAgICBoZWlnaHQ6IDJweDtcbiAgICAgIGxlZnQ6IC01MCU7XG4gICAgICBwb3NpdGlvbjogYWJzb2x1dGU7XG4gICAgICB0b3A6IDlweDtcbiAgICAgIHdpZHRoOiAxMDAlO1xuICAgIH1cblxuICAgIGEge1xuICAgICAgY29sb3I6ICRncmF5LWNvbG9yO1xuICAgICAgZGlzcGxheTogaW5saW5lLWJsb2NrO1xuICAgICAgcGFkZGluZzogMjBweCAxMHB4IDA7XG4gICAgICB0ZXh0LWRlY29yYXRpb246IG5vbmU7XG5cbiAgICAgICY6OmJlZm9yZSB7XG4gICAgICAgIGJhY2tncm91bmQ6ICRwcmltYXJ5LWNvbG9yO1xuICAgICAgICBib3JkZXI6ICRib3JkZXItd2lkdGgtbGcgc29saWQgJGxpZ2h0LWNvbG9yO1xuICAgICAgICBib3JkZXItcmFkaXVzOiA1MCU7XG4gICAgICAgIGNvbnRlbnQ6IFwiXCI7XG4gICAgICAgIGRpc3BsYXk6IGJsb2NrO1xuICAgICAgICBoZWlnaHQ6ICR1bml0LTM7XG4gICAgICAgIGxlZnQ6IDUwJTtcbiAgICAgICAgcG9zaXRpb246IGFic29sdXRlO1xuICAgICAgICB0b3A6ICR1bml0LTE7XG4gICAgICAgIHRyYW5zZm9ybTogdHJhbnNsYXRlWCgtNTAlKTtcbiAgICAgICAgd2lkdGg6ICR1bml0LTM7XG4gICAgICAgIHotaW5kZXg6ICR6aW5kZXgtMDtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAmLmFjdGl2ZSB7XG4gICAgICBhIHtcbiAgICAgICAgJjo6YmVmb3JlIHtcbiAgICAgICAgICBiYWNrZ3JvdW5kOiAkbGlnaHQtY29sb3I7XG4gICAgICAgICAgYm9yZGVyOiAkYm9yZGVyLXdpZHRoLWxnIHNvbGlkICRwcmltYXJ5LWNvbG9yO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgICYgfiAuc3RlcC1pdGVtIHtcbiAgICAgICAgJjo6YmVmb3JlIHtcbiAgICAgICAgICBiYWNrZ3JvdW5kOiAkYm9yZGVyLWNvbG9yO1xuICAgICAgICB9XG5cbiAgICAgICAgYSB7XG5cbiAgICAgICAgICAmOjpiZWZvcmUge1xuICAgICAgICAgICAgYmFja2dyb3VuZDogJGdyYXktY29sb3ItbGlnaHQ7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICB9XG59XG4iLCIvLyBUYWJzXG4udGFiIHtcbiAgYWxpZ24taXRlbXM6IGNlbnRlcjtcbiAgYm9yZGVyLWJvdHRvbTogJGJvcmRlci13aWR0aCBzb2xpZCAkYm9yZGVyLWNvbG9yO1xuICBkaXNwbGF5OiBmbGV4O1xuICBmbGV4LXdyYXA6IHdyYXA7XG4gIGxpc3Qtc3R5bGU6IG5vbmU7XG4gIG1hcmdpbjogJHVuaXQtMSAwICgkdW5pdC0xIC0gJGJvcmRlci13aWR0aCkgMDtcblxuICAudGFiLWl0ZW0ge1xuICAgIG1hcmdpbi10b3A6IDA7XG5cbiAgICBhIHtcbiAgICAgIGJvcmRlci1ib3R0b206ICRib3JkZXItd2lkdGgtbGcgc29saWQgdHJhbnNwYXJlbnQ7XG4gICAgICBjb2xvcjogaW5oZXJpdDtcbiAgICAgIGRpc3BsYXk6IGJsb2NrO1xuICAgICAgbWFyZ2luOiAwICR1bml0LTIgMCAwO1xuICAgICAgcGFkZGluZzogJHVuaXQtMiAkdW5pdC0xICR1bml0LTIgLSAkYm9yZGVyLXdpZHRoLWxnICR1bml0LTE7XG4gICAgICB0ZXh0LWRlY29yYXRpb246IG5vbmU7XG4gICAgICAmOmZvY3VzLFxuICAgICAgJjpob3ZlciB7XG4gICAgICAgIGNvbG9yOiAkbGluay1jb2xvcjtcbiAgICAgIH1cbiAgICB9XG4gICAgJi5hY3RpdmUgYSxcbiAgICBhLmFjdGl2ZSB7XG4gICAgICBib3JkZXItYm90dG9tLWNvbG9yOiAkcHJpbWFyeS1jb2xvcjtcbiAgICAgIGNvbG9yOiAkbGluay1jb2xvcjtcbiAgICB9XG5cbiAgICAmLnRhYi1hY3Rpb24ge1xuICAgICAgZmxleDogMSAwIGF1dG87XG4gICAgICB0ZXh0LWFsaWduOiByaWdodDtcbiAgICB9XG5cbiAgICAuYnRuLWNsZWFyIHtcbiAgICAgIG1hcmdpbi10b3A6IC0kdW5pdC0xO1xuICAgIH1cbiAgfVxuXG4gICYudGFiLWJsb2NrIHtcbiAgICAudGFiLWl0ZW0ge1xuICAgICAgZmxleDogMSAwIDA7XG4gICAgICB0ZXh0LWFsaWduOiBjZW50ZXI7XG5cbiAgICAgIGEge1xuICAgICAgICBtYXJnaW46IDA7XG4gICAgICB9XG5cbiAgICAgIC5iYWRnZSB7XG4gICAgICAgICZbZGF0YS1iYWRnZV06OmFmdGVyIHtcbiAgICAgICAgICBwb3NpdGlvbjogYWJzb2x1dGU7XG4gICAgICAgICAgcmlnaHQ6ICR1bml0LWg7XG4gICAgICAgICAgdG9wOiAkdW5pdC1oO1xuICAgICAgICAgIHRyYW5zZm9ybTogdHJhbnNsYXRlKDAsIDApO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgJjpub3QoLnRhYi1ibG9jaykge1xuICAgIC5iYWRnZSB7XG4gICAgICBwYWRkaW5nLXJpZ2h0OiAwO1xuICAgIH1cbiAgfVxufVxuIiwiLy8gVGlsZXNcbi50aWxlIHtcbiAgYWxpZ24tY29udGVudDogc3BhY2UtYmV0d2VlbjtcbiAgYWxpZ24taXRlbXM6IGZsZXgtc3RhcnQ7XG4gIGRpc3BsYXk6IGZsZXg7XG5cbiAgLnRpbGUtaWNvbixcbiAgLnRpbGUtYWN0aW9uIHtcbiAgICBmbGV4OiAwIDAgYXV0bztcbiAgfVxuICAudGlsZS1jb250ZW50IHtcbiAgICBmbGV4OiAxIDEgYXV0bztcbiAgICAmOm5vdCg6Zmlyc3QtY2hpbGQpIHtcbiAgICAgIHBhZGRpbmctbGVmdDogJHVuaXQtMjtcbiAgICB9XG4gICAgJjpub3QoOmxhc3QtY2hpbGQpIHtcbiAgICAgIHBhZGRpbmctcmlnaHQ6ICR1bml0LTI7XG4gICAgfVxuICB9XG4gIC50aWxlLXRpdGxlLFxuICAudGlsZS1zdWJ0aXRsZSB7XG4gICAgbGluZS1oZWlnaHQ6ICRsaW5lLWhlaWdodDtcbiAgfVxuXG4gICYudGlsZS1jZW50ZXJlZCB7XG4gICAgYWxpZ24taXRlbXM6IGNlbnRlcjtcblxuICAgIC50aWxlLWNvbnRlbnQge1xuICAgICAgb3ZlcmZsb3c6IGhpZGRlbjtcbiAgICB9XG5cbiAgICAudGlsZS10aXRsZSxcbiAgICAudGlsZS1zdWJ0aXRsZSB7XG4gICAgICBAaW5jbHVkZSB0ZXh0LWVsbGlwc2lzKCk7XG4gICAgICBtYXJnaW4tYm90dG9tOiAwO1xuICAgIH1cbiAgfVxufVxuIiwiLy8gVG9hc3RzXG4udG9hc3Qge1xuICBAaW5jbHVkZSB0b2FzdC12YXJpYW50KCRkYXJrLWNvbG9yKTtcbiAgYm9yZGVyOiAkYm9yZGVyLXdpZHRoIHNvbGlkICRkYXJrLWNvbG9yO1xuICBib3JkZXItcmFkaXVzOiAkYm9yZGVyLXJhZGl1cztcbiAgY29sb3I6ICRsaWdodC1jb2xvcjtcbiAgZGlzcGxheTogYmxvY2s7XG4gIHBhZGRpbmc6ICRsYXlvdXQtc3BhY2luZztcbiAgd2lkdGg6IDEwMCU7XG5cbiAgJi50b2FzdC1wcmltYXJ5IHtcbiAgICBAaW5jbHVkZSB0b2FzdC12YXJpYW50KCRwcmltYXJ5LWNvbG9yKTtcbiAgfVxuXG4gICYudG9hc3Qtc3VjY2VzcyB7XG4gICAgQGluY2x1ZGUgdG9hc3QtdmFyaWFudCgkc3VjY2Vzcy1jb2xvcik7XG4gIH1cblxuICAmLnRvYXN0LXdhcm5pbmcge1xuICAgIEBpbmNsdWRlIHRvYXN0LXZhcmlhbnQoJHdhcm5pbmctY29sb3IpO1xuICB9XG5cbiAgJi50b2FzdC1lcnJvciB7XG4gICAgQGluY2x1ZGUgdG9hc3QtdmFyaWFudCgkZXJyb3ItY29sb3IpO1xuICB9XG5cbiAgYSB7XG4gICAgY29sb3I6ICRsaWdodC1jb2xvcjtcbiAgICB0ZXh0LWRlY29yYXRpb246IHVuZGVybGluZTtcbiAgICBcbiAgICAmOmZvY3VzLFxuICAgICY6aG92ZXIsXG4gICAgJjphY3RpdmUsXG4gICAgJi5hY3RpdmUge1xuICAgICAgb3BhY2l0eTogLjc1O1xuICAgIH1cbiAgfVxuXG4gIC5idG4tY2xlYXIge1xuICAgIG1hcmdpbjogNHB4IC0ycHggNHB4IDRweDtcbiAgfVxufVxuIiwiLy8gVG9vbHRpcHNcbi50b29sdGlwIHtcbiAgcG9zaXRpb246IHJlbGF0aXZlO1xuICAmOjphZnRlciB7XG4gICAgYmFja2dyb3VuZDogcmdiYSgkZGFyay1jb2xvciwgLjkpO1xuICAgIGJvcmRlci1yYWRpdXM6ICRib3JkZXItcmFkaXVzO1xuICAgIGJvdHRvbTogMTAwJTtcbiAgICBjb2xvcjogJGxpZ2h0LWNvbG9yO1xuICAgIGNvbnRlbnQ6IGF0dHIoZGF0YS10b29sdGlwKTtcbiAgICBkaXNwbGF5OiBibG9jaztcbiAgICBmb250LXNpemU6ICRmb250LXNpemUtc207XG4gICAgbGVmdDogNTAlO1xuICAgIG1heC13aWR0aDogJGNvbnRyb2wtd2lkdGgtc207XG4gICAgb3BhY2l0eTogMDtcbiAgICBvdmVyZmxvdzogaGlkZGVuO1xuICAgIHBhZGRpbmc6ICR1bml0LTEgJHVuaXQtMjtcbiAgICBwb2ludGVyLWV2ZW50czogbm9uZTtcbiAgICBwb3NpdGlvbjogYWJzb2x1dGU7XG4gICAgdGV4dC1vdmVyZmxvdzogZWxsaXBzaXM7XG4gICAgdHJhbnNmb3JtOiB0cmFuc2xhdGUoLTUwJSwgJHVuaXQtMik7XG4gICAgdHJhbnNpdGlvbjogYWxsIC4ycyBlYXNlO1xuICAgIHdoaXRlLXNwYWNlOiBwcmU7XG4gICAgei1pbmRleDogJHppbmRleC0zO1xuICB9XG4gICY6Zm9jdXMsXG4gICY6aG92ZXIge1xuICAgICY6OmFmdGVyIHtcbiAgICAgIG9wYWNpdHk6IDE7XG4gICAgICB0cmFuc2Zvcm06IHRyYW5zbGF0ZSgtNTAlLCAtJHVuaXQtMSk7XG4gICAgfVxuICB9XG4gICZbZGlzYWJsZWRdLFxuICAmLmRpc2FibGVkIHtcbiAgICBwb2ludGVyLWV2ZW50czogYXV0bztcbiAgfVxuXG4gICYudG9vbHRpcC1yaWdodCB7XG4gICAgJjo6YWZ0ZXIge1xuICAgICAgYm90dG9tOiA1MCU7XG4gICAgICBsZWZ0OiAxMDAlO1xuICAgICAgdHJhbnNmb3JtOiB0cmFuc2xhdGUoLSR1bml0LTEsIDUwJSk7XG4gICAgfVxuICAgICY6Zm9jdXMsXG4gICAgJjpob3ZlciB7XG4gICAgICAmOjphZnRlciB7XG4gICAgICAgIHRyYW5zZm9ybTogdHJhbnNsYXRlKCR1bml0LTEsIDUwJSk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgJi50b29sdGlwLWJvdHRvbSB7XG4gICAgJjo6YWZ0ZXIge1xuICAgICAgYm90dG9tOiBhdXRvO1xuICAgICAgdG9wOiAxMDAlO1xuICAgICAgdHJhbnNmb3JtOiB0cmFuc2xhdGUoLTUwJSwgLSR1bml0LTIpO1xuICAgIH1cbiAgICAmOmZvY3VzLFxuICAgICY6aG92ZXIge1xuICAgICAgJjo6YWZ0ZXIge1xuICAgICAgICB0cmFuc2Zvcm06IHRyYW5zbGF0ZSgtNTAlLCAkdW5pdC0xKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cbiAgXG4gICYudG9vbHRpcC1sZWZ0IHtcbiAgICAmOjphZnRlciB7XG4gICAgICBib3R0b206IDUwJTtcbiAgICAgIGxlZnQ6IGF1dG87XG4gICAgICByaWdodDogMTAwJTtcbiAgICAgIHRyYW5zZm9ybTogdHJhbnNsYXRlKCR1bml0LTIsIDUwJSk7XG4gICAgfVxuICAgICY6Zm9jdXMsXG4gICAgJjpob3ZlciB7XG4gICAgICAmOjphZnRlciB7XG4gICAgICAgIHRyYW5zZm9ybTogdHJhbnNsYXRlKC0kdW5pdC0xLCA1MCUpO1xuICAgICAgfVxuICAgIH1cbiAgfVxufVxuIiwiYm9keSB7XG4gIHBhZGRpbmc6IDJyZW0gMDtcbn1cblxuaW1nLmxvZ28ge1xuICB3aWR0aDogMjAwcHg7XG4gIG1hcmdpbi1ib3R0b206IDFyZW07XG59XG5cbmgxLCBoMiB7XG4gIGZvbnQtd2VpZ2h0OiA3MDA7XG59XG5cbi5mb290ZXIge1xuICBjb2xvcjogJGdyYXktY29sb3I7XG4gIG1hcmdpbi10b3A6IDJyZW07XG5cbiAgaW1nIHtcbiAgICBoZWlnaHQ6IDE4cHg7XG4gICAgdmVydGljYWwtYWxpZ246IG1pZGRsZTtcbiAgICBtYXJnaW46IDAgMC4ycmVtO1xuICB9XG59XG5cbi50b2FzdCB7XG4gIC5idG4ge1xuICAgIG1hcmdpbi1sZWZ0OiAxcmVtO1xuICAgIHRleHQtZGVjb3JhdGlvbjogbm9uZSAhaW1wb3J0YW50O1xuICAgIGkge1xuICAgICAgbWFyZ2luLXJpZ2h0OiAwLjNyZW07XG4gICAgfVxuICB9XG59XG5cbnVsLnByb2JsZW1zIHtcbiAgbWFyZ2luOiAxcmVtIDA7XG5cbiAgaDUge1xuICAgIG1hcmdpbjogMDtcbiAgfVxuXG4gIGxpLm1lbnUge1xuICAgIG1hcmdpbi1ib3R0b206IDFyZW07XG5cbiAgICAudG9hc3Qge1xuICAgICAgLmJ0biB7XG4gICAgICAgIGZsb2F0OiByaWdodDtcbiAgICAgICAgbWFyZ2luLXRvcDogLTJweDtcbiAgICAgIH1cbiAgICB9XG4gIH1cbn1cblxudWwuZGV0YWlscyB7XG4gIG1hcmdpbjogMC41cmVtO1xuICBsaXN0LXN0eWxlOiBub25lO1xuICBmb250LXNpemU6IDkwJTtcblxuICAubWVudS1pdGVtIHtcbiAgICBtYXJnaW4tdG9wOiAuNXJlbSAhaW1wb3J0YW50O1xuICAgIGJvcmRlci10b3A6IDFweCBzb2xpZCAkYm9yZGVyLWNvbG9yO1xuICAgIHBhZGRpbmctdG9wOiAwLjVyZW07XG5cbiAgICAmOmZpcnN0LWNoaWxkIHtcbiAgICAgIGJvcmRlcjogbm9uZTtcbiAgICB9XG4gIH1cblxuICAubWVudS1iYWRnZSB7XG4gICAgcGFkZGluZzogMDtcbiAgfVxufVxuIiwiLy8gQW5pbWF0aW9uc1xuQGtleWZyYW1lcyBsb2FkaW5nIHtcbiAgMCUge1xuICAgIHRyYW5zZm9ybTogcm90YXRlKDBkZWcpO1xuICB9XG4gIDEwMCUge1xuICAgIHRyYW5zZm9ybTogcm90YXRlKDM2MGRlZyk7XG4gIH1cbn1cblxuQGtleWZyYW1lcyBzbGlkZS1kb3duIHtcbiAgMCUge1xuICAgIG9wYWNpdHk6IDA7XG4gICAgdHJhbnNmb3JtOiB0cmFuc2xhdGVZKC0kdW5pdC04KTtcbiAgfVxuICAxMDAlIHtcbiAgICBvcGFjaXR5OiAxO1xuICAgIHRyYW5zZm9ybTogdHJhbnNsYXRlWSgwKTtcbiAgfVxufVxuIiwiQGltcG9ydCBcInV0aWxpdGllcy9jb2xvcnNcIjtcbkBpbXBvcnQgXCJ1dGlsaXRpZXMvY3Vyc29yc1wiO1xuQGltcG9ydCBcInV0aWxpdGllcy9kaXNwbGF5XCI7XG5AaW1wb3J0IFwidXRpbGl0aWVzL2RpdmlkZXJcIjtcbkBpbXBvcnQgXCJ1dGlsaXRpZXMvbG9hZGluZ1wiO1xuQGltcG9ydCBcInV0aWxpdGllcy9wb3NpdGlvblwiO1xuQGltcG9ydCBcInV0aWxpdGllcy9zaGFwZXNcIjtcbkBpbXBvcnQgXCJ1dGlsaXRpZXMvdGV4dFwiO1xuIiwiLy8gVGV4dCBjb2xvcnNcbkBpbmNsdWRlIHRleHQtY29sb3ItdmFyaWFudChcIi50ZXh0LXByaW1hcnlcIiwgJHByaW1hcnktY29sb3IpO1xuXG5AaW5jbHVkZSB0ZXh0LWNvbG9yLXZhcmlhbnQoXCIudGV4dC1zZWNvbmRhcnlcIiwgJHNlY29uZGFyeS1jb2xvci1kYXJrKTtcblxuQGluY2x1ZGUgdGV4dC1jb2xvci12YXJpYW50KFwiLnRleHQtZ3JheVwiLCAkZ3JheS1jb2xvcik7XG5cbkBpbmNsdWRlIHRleHQtY29sb3ItdmFyaWFudChcIi50ZXh0LWxpZ2h0XCIsICRsaWdodC1jb2xvcik7XG5cbkBpbmNsdWRlIHRleHQtY29sb3ItdmFyaWFudChcIi50ZXh0LWRhcmtcIiwgJGJvZHktZm9udC1jb2xvcik7XG5cbkBpbmNsdWRlIHRleHQtY29sb3ItdmFyaWFudChcIi50ZXh0LXN1Y2Nlc3NcIiwgJHN1Y2Nlc3MtY29sb3IpO1xuXG5AaW5jbHVkZSB0ZXh0LWNvbG9yLXZhcmlhbnQoXCIudGV4dC13YXJuaW5nXCIsICR3YXJuaW5nLWNvbG9yKTtcblxuQGluY2x1ZGUgdGV4dC1jb2xvci12YXJpYW50KFwiLnRleHQtZXJyb3JcIiwgJGVycm9yLWNvbG9yKTtcblxuLy8gQmFja2dyb3VuZCBjb2xvcnNcbkBpbmNsdWRlIGJnLWNvbG9yLXZhcmlhbnQoXCIuYmctcHJpbWFyeVwiLCAkcHJpbWFyeS1jb2xvcik7XG5cbkBpbmNsdWRlIGJnLWNvbG9yLXZhcmlhbnQoXCIuYmctc2Vjb25kYXJ5XCIsICRzZWNvbmRhcnktY29sb3IpO1xuXG5AaW5jbHVkZSBiZy1jb2xvci12YXJpYW50KFwiLmJnLWRhcmtcIiwgJGRhcmstY29sb3IpO1xuXG5AaW5jbHVkZSBiZy1jb2xvci12YXJpYW50KFwiLmJnLWdyYXlcIiwgJGJnLWNvbG9yKTtcblxuQGluY2x1ZGUgYmctY29sb3ItdmFyaWFudChcIi5iZy1zdWNjZXNzXCIsICRzdWNjZXNzLWNvbG9yKTtcblxuQGluY2x1ZGUgYmctY29sb3ItdmFyaWFudChcIi5iZy13YXJuaW5nXCIsICR3YXJuaW5nLWNvbG9yKTtcblxuQGluY2x1ZGUgYmctY29sb3ItdmFyaWFudChcIi5iZy1lcnJvclwiLCAkZXJyb3ItY29sb3IpO1xuIiwiLy8gQ3Vyc29yc1xuLmMtaGFuZCB7XG4gIGN1cnNvcjogcG9pbnRlcjtcbn1cblxuLmMtbW92ZSB7XG4gIGN1cnNvcjogbW92ZTtcbn1cblxuLmMtem9vbS1pbiB7XG4gIGN1cnNvcjogem9vbS1pbjtcbn1cblxuLmMtem9vbS1vdXQge1xuICBjdXJzb3I6IHpvb20tb3V0O1xufVxuXG4uYy1ub3QtYWxsb3dlZCB7XG4gIGN1cnNvcjogbm90LWFsbG93ZWQ7XG59XG5cbi5jLWF1dG8ge1xuICBjdXJzb3I6IGF1dG87XG59XG4iLCIvLyBEaXNwbGF5XG4uZC1ibG9jayB7XG4gIGRpc3BsYXk6IGJsb2NrO1xufVxuLmQtaW5saW5lIHtcbiAgZGlzcGxheTogaW5saW5lO1xufVxuLmQtaW5saW5lLWJsb2NrIHtcbiAgZGlzcGxheTogaW5saW5lLWJsb2NrO1xufVxuLmQtZmxleCB7XG4gIGRpc3BsYXk6IGZsZXg7XG59XG4uZC1pbmxpbmUtZmxleCB7XG4gIGRpc3BsYXk6IGlubGluZS1mbGV4O1xufVxuLmQtbm9uZSxcbi5kLWhpZGUge1xuICBkaXNwbGF5OiBub25lICFpbXBvcnRhbnQ7XG59XG4uZC12aXNpYmxlIHtcbiAgdmlzaWJpbGl0eTogdmlzaWJsZTtcbn1cbi5kLWludmlzaWJsZSB7XG4gIHZpc2liaWxpdHk6IGhpZGRlbjtcbn1cbi50ZXh0LWhpZGUge1xuICBiYWNrZ3JvdW5kOiB0cmFuc3BhcmVudDtcbiAgYm9yZGVyOiAwO1xuICBjb2xvcjogdHJhbnNwYXJlbnQ7XG4gIGZvbnQtc2l6ZTogMDtcbiAgbGluZS1oZWlnaHQ6IDA7XG4gIHRleHQtc2hhZG93OiBub25lO1xufVxuLnRleHQtYXNzaXN0aXZlIHtcbiAgYm9yZGVyOiAwO1xuICBjbGlwOiByZWN0KDAsMCwwLDApO1xuICBoZWlnaHQ6IDFweDtcbiAgbWFyZ2luOiAtMXB4O1xuICBvdmVyZmxvdzogaGlkZGVuO1xuICBwYWRkaW5nOiAwO1xuICBwb3NpdGlvbjogYWJzb2x1dGU7XG4gIHdpZHRoOiAxcHg7XG59XG4iLCIvLyBEaXZpZGVyXG4uZGl2aWRlcixcbi5kaXZpZGVyLXZlcnQge1xuICBkaXNwbGF5OiBibG9jaztcbiAgcG9zaXRpb246IHJlbGF0aXZlO1xuXG4gICZbZGF0YS1jb250ZW50XTo6YWZ0ZXIge1xuICAgIGJhY2tncm91bmQ6ICRiZy1jb2xvci1saWdodDtcbiAgICBjb2xvcjogJGdyYXktY29sb3I7XG4gICAgY29udGVudDogYXR0cihkYXRhLWNvbnRlbnQpO1xuICAgIGRpc3BsYXk6IGlubGluZS1ibG9jaztcbiAgICBmb250LXNpemU6ICRmb250LXNpemUtc207XG4gICAgcGFkZGluZzogMCAkdW5pdC0yO1xuICAgIHRyYW5zZm9ybTogdHJhbnNsYXRlWSgtJGZvbnQtc2l6ZS1zbSArICRib3JkZXItd2lkdGgpO1xuICB9XG59XG5cbi5kaXZpZGVyIHtcbiAgYm9yZGVyLXRvcDogJGJvcmRlci13aWR0aCBzb2xpZCAkYm9yZGVyLWNvbG9yO1xuICBoZWlnaHQ6ICRib3JkZXItd2lkdGg7XG4gIG1hcmdpbjogJHVuaXQtMiAwO1xuXG4gICZbZGF0YS1jb250ZW50XSB7XG4gICAgbWFyZ2luOiAkdW5pdC00IDA7XG4gIH1cbn1cblxuLmRpdmlkZXItdmVydCB7XG4gIGRpc3BsYXk6IGJsb2NrO1xuICBwYWRkaW5nOiAkdW5pdC00O1xuXG4gICY6OmJlZm9yZSB7XG4gICAgYm9yZGVyLWxlZnQ6ICRib3JkZXItd2lkdGggc29saWQgJGJvcmRlci1jb2xvcjtcbiAgICBib3R0b206ICR1bml0LTI7XG4gICAgY29udGVudDogXCJcIjtcbiAgICBkaXNwbGF5OiBibG9jaztcbiAgICBsZWZ0OiA1MCU7XG4gICAgcG9zaXRpb246IGFic29sdXRlO1xuICAgIHRvcDogJHVuaXQtMjtcbiAgICB0cmFuc2Zvcm06IHRyYW5zbGF0ZVgoLTUwJSk7XG4gIH1cblxuICAmW2RhdGEtY29udGVudF06OmFmdGVyIHtcbiAgICBsZWZ0OiA1MCU7XG4gICAgcGFkZGluZzogJHVuaXQtMSAwO1xuICAgIHBvc2l0aW9uOiBhYnNvbHV0ZTtcbiAgICB0b3A6IDUwJTtcbiAgICB0cmFuc2Zvcm06IHRyYW5zbGF0ZSgtNTAlLCAtNTAlKTtcbiAgfVxufVxuIiwiLy8gTG9hZGluZ1xuLmxvYWRpbmcge1xuICBjb2xvcjogdHJhbnNwYXJlbnQgIWltcG9ydGFudDtcbiAgbWluLWhlaWdodDogJHVuaXQtNDtcbiAgcG9pbnRlci1ldmVudHM6IG5vbmU7XG4gIHBvc2l0aW9uOiByZWxhdGl2ZTtcbiAgJjo6YWZ0ZXIge1xuICAgIGFuaW1hdGlvbjogbG9hZGluZyA1MDBtcyBpbmZpbml0ZSBsaW5lYXI7XG4gICAgYm9yZGVyOiAkYm9yZGVyLXdpZHRoLWxnIHNvbGlkICRwcmltYXJ5LWNvbG9yO1xuICAgIGJvcmRlci1yYWRpdXM6IDUwJTtcbiAgICBib3JkZXItcmlnaHQtY29sb3I6IHRyYW5zcGFyZW50O1xuICAgIGJvcmRlci10b3AtY29sb3I6IHRyYW5zcGFyZW50O1xuICAgIGNvbnRlbnQ6IFwiXCI7XG4gICAgZGlzcGxheTogYmxvY2s7XG4gICAgaGVpZ2h0OiAkdW5pdC00O1xuICAgIGxlZnQ6IDUwJTtcbiAgICBtYXJnaW4tbGVmdDogLSR1bml0LTI7XG4gICAgbWFyZ2luLXRvcDogLSR1bml0LTI7XG4gICAgcG9zaXRpb246IGFic29sdXRlO1xuICAgIHRvcDogNTAlO1xuICAgIHdpZHRoOiAkdW5pdC00O1xuICAgIHotaW5kZXg6ICR6aW5kZXgtMDtcbiAgfVxuXG4gICYubG9hZGluZy1sZyB7XG4gICAgbWluLWhlaWdodDogJHVuaXQtMTA7XG4gICAgJjo6YWZ0ZXIge1xuICAgICAgaGVpZ2h0OiAkdW5pdC04O1xuICAgICAgbWFyZ2luLWxlZnQ6IC0kdW5pdC00O1xuICAgICAgbWFyZ2luLXRvcDogLSR1bml0LTQ7XG4gICAgICB3aWR0aDogJHVuaXQtODtcbiAgICB9XG4gIH1cbn1cbiIsIi8vIFBvc2l0aW9uXG4uY2xlYXJmaXgge1xuICBAaW5jbHVkZSBjbGVhcmZpeCgpO1xufVxuXG4uZmxvYXQtbGVmdCB7XG4gIGZsb2F0OiBsZWZ0ICFpbXBvcnRhbnQ7XG59XG5cbi5mbG9hdC1yaWdodCB7XG4gIGZsb2F0OiByaWdodCAhaW1wb3J0YW50O1xufVxuXG4ucmVsYXRpdmUge1xuICBwb3NpdGlvbjogcmVsYXRpdmUgIWltcG9ydGFudDtcbn1cblxuLmFic29sdXRlIHtcbiAgcG9zaXRpb246IGFic29sdXRlICFpbXBvcnRhbnQ7XG59XG5cbi5maXhlZCB7XG4gIHBvc2l0aW9uOiBmaXhlZCAhaW1wb3J0YW50O1xufVxuXG4uY2VudGVyZWQge1xuICBkaXNwbGF5OiBibG9jaztcbiAgZmxvYXQ6IG5vbmU7XG4gIG1hcmdpbi1sZWZ0OiBhdXRvO1xuICBtYXJnaW4tcmlnaHQ6IGF1dG87XG59XG5cbi5mbGV4LWNlbnRlcmVkIHtcbiAgYWxpZ24taXRlbXM6IGNlbnRlcjtcbiAgZGlzcGxheTogZmxleDtcbiAganVzdGlmeS1jb250ZW50OiBjZW50ZXI7XG59XG5cbi8vIFNwYWNpbmdcbkBpbmNsdWRlIG1hcmdpbi12YXJpYW50KDAsIDApO1xuXG5AaW5jbHVkZSBtYXJnaW4tdmFyaWFudCgxLCAkdW5pdC0xKTtcblxuQGluY2x1ZGUgbWFyZ2luLXZhcmlhbnQoMiwgJHVuaXQtMik7XG5cbkBpbmNsdWRlIHBhZGRpbmctdmFyaWFudCgwLCAwKTtcblxuQGluY2x1ZGUgcGFkZGluZy12YXJpYW50KDEsICR1bml0LTEpO1xuXG5AaW5jbHVkZSBwYWRkaW5nLXZhcmlhbnQoMiwgJHVuaXQtMik7XG4iLCIvLyBTaGFwZXNcbi5zLXJvdW5kZWQge1xuICBib3JkZXItcmFkaXVzOiAkYm9yZGVyLXJhZGl1cztcbn1cblxuLnMtY2lyY2xlIHtcbiAgYm9yZGVyLXJhZGl1czogNTAlO1xufSIsIi8vIFRleHRcbi8vIFRleHQgYWxpZ25tZW50IHV0aWxpdGllc1xuLnRleHQtbGVmdCB7XG4gIHRleHQtYWxpZ246IGxlZnQ7XG59XG5cbi50ZXh0LXJpZ2h0IHtcbiAgdGV4dC1hbGlnbjogcmlnaHQ7XG59XG5cbi50ZXh0LWNlbnRlciB7XG4gIHRleHQtYWxpZ246IGNlbnRlcjtcbn1cblxuLnRleHQtanVzdGlmeSB7XG4gIHRleHQtYWxpZ246IGp1c3RpZnk7XG59XG5cbi8vIFRleHQgdHJhbnNmb3JtIHV0aWxpdGllc1xuLnRleHQtbG93ZXJjYXNlIHtcbiAgdGV4dC10cmFuc2Zvcm06IGxvd2VyY2FzZTtcbn1cblxuLnRleHQtdXBwZXJjYXNlIHtcbiAgdGV4dC10cmFuc2Zvcm06IHVwcGVyY2FzZTtcbn1cblxuLnRleHQtY2FwaXRhbGl6ZSB7XG4gIHRleHQtdHJhbnNmb3JtOiBjYXBpdGFsaXplO1xufVxuXG4vLyBUZXh0IHN0eWxlIHV0aWxpdGllc1xuLnRleHQtbm9ybWFsIHtcbiAgZm9udC13ZWlnaHQ6IG5vcm1hbDtcbn1cblxuLnRleHQtYm9sZCB7XG4gIGZvbnQtd2VpZ2h0OiBib2xkO1xufVxuXG4udGV4dC1pdGFsaWMge1xuICBmb250LXN0eWxlOiBpdGFsaWM7XG59XG5cbi50ZXh0LWxhcmdlIHtcbiAgZm9udC1zaXplOiAxLjJlbTtcbn1cblxuLy8gVGV4dCBvdmVyZmxvdyB1dGlsaXRpZXNcbi50ZXh0LWVsbGlwc2lzIHtcbiAgQGluY2x1ZGUgdGV4dC1lbGxpcHNpcygpO1xufVxuXG4udGV4dC1jbGlwIHtcbiAgb3ZlcmZsb3c6IGhpZGRlbjtcbiAgdGV4dC1vdmVyZmxvdzogY2xpcDtcbiAgd2hpdGUtc3BhY2U6IG5vd3JhcDtcbn1cblxuLnRleHQtYnJlYWsge1xuICBoeXBoZW5zOiBhdXRvO1xuICB3b3JkLWJyZWFrOiBicmVhay13b3JkO1xuICB3b3JkLXdyYXA6IGJyZWFrLXdvcmQ7XG59XG4iXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBSUEsd0VBQThFO0FhSjlFLHdDQUF3QztBQUN4QywyRUFBMkU7QUFFM0Usb05BS0c7QUFFSCx5RkFDZ0Y7QUFFaEYsQUFBQSxJQUFJLENBQUMsRUFDSCxXQUFXLEVBQUUsVUFBVSxFQUFFLE9BQU8sQ0FDaEMsb0JBQW9CLEVBQUUsSUFBSSxFQUFFLE9BQU8sQ0FDbkMsd0JBQXdCLEVBQUUsSUFBSSxFQUFFLE9BQU8sRUFDeEM7O0FBRUQseUZBQ2dGO0FBRWhGLHVEQUVHO0FBRUgsQUFBQSxJQUFJLENBQUMsRUFDSCxNQUFNLEVBQUUsQ0FBQyxHQUNWOztBQUVELHdDQUVHO0FBRUgsQUFBQSxPQUFPLEVBQ1AsS0FBSyxFQUNMLE1BQU0sRUFDTixNQUFNLEVBQ04sR0FBRyxFQUNILE9BQU8sQ0FBQyxFQUNOLE9BQU8sRUFBRSxLQUFLLEdBQ2Y7O0FBRUQsZ0lBR0c7QUFFSCxBQUFBLEVBQUUsQ0FBQyxFQUNELFNBQVMsRUFBRSxHQUFHLEVBQ2QsTUFBTSxFQUFFLFFBQVEsR0FDakI7O0FBRUQsaUdBQ2dGO0FBRWhGLDBFQUdHO0FBRUgsQUFBQSxVQUFVLEVBQ1YsTUFBTSxFQUNOLElBQUksQ0FBQyxFQUFFLE9BQU8sQ0FDWixPQUFPLEVBQUUsS0FBSyxHQUNmOztBQUVELGdEQUVHO0FBRUgscUZBR0c7QUFFSCxBQUFBLEVBQUUsQ0FBQyxFQUNELFVBQVUsRUFBRSxXQUFXLEVBQUUsT0FBTyxDQUNoQyxNQUFNLEVBQUUsQ0FBQyxFQUFFLE9BQU8sQ0FDbEIsUUFBUSxFQUFFLE9BQU8sRUFBRSxPQUFPLEVBQzNCOztBQUVELDBJQUdHO0FBRUgscUdBQ2dGO0FBRWhGLHlIQUdHO0FBRUgsQUFBQSxDQUFDLENBQUMsRUFDQSxnQkFBZ0IsRUFBRSxXQUFXLEVBQUUsT0FBTyxDQUN0Qyw0QkFBNEIsRUFBRSxPQUFPLEVBQUUsT0FBTyxFQUMvQzs7QUFFRCw4R0FHRztBQUVILEFBQUEsQ0FBQyxBQUFBLE9BQU8sRUFDUixDQUFDLEFBQUEsTUFBTSxDQUFDLEVBQ04sYUFBYSxFQUFFLENBQUMsR0FDakI7O0FBRUQseUNBRUc7QUFFSCxBQUFBLE9BQU8sQ0FBQyxFQUNOLFVBQVUsRUFBRSxNQUFNLEdBQ25COztBQUVELHVJQUdHO0FBRUgsa0ZBRUc7QUFFSCxBQUFBLENBQUMsRUFDRCxNQUFNLENBQUMsRUFDTCxXQUFXLEVBQUUsT0FBTyxHQUNyQjs7QUFFRCwrREFFRztBQVBILEFBQUEsQ0FBQyxFQUNELE1BQU0sQ0FTQyxFQUNMLFdBQVcsRUFBRSxNQUFNLEdBQ3BCOztBQUVELGdJQUdHO0FBRUgsQUFBQSxJQUFJLEVBQ0osR0FBRyxFQUNILEdBQUcsRUFDSCxJQUFJLENBQUMsRUFDSCxXQUFXLEVaMUdNLFNBQVMsRUFBRSxlQUFlLEVBQUUsYUFBYSxFQUFFLEtBQUssRUFBRSxPQUFPLEVBQUUsU0FBUyxFWTBHckQsaUJBQWlCLENBQ2pELFNBQVMsRUFBRSxHQUFHLEVBQUUsT0FBTyxFQUN4Qjs7QUFFRCxrREFFRztBQUVILEFBQUEsR0FBRyxDQUFDLEVBQ0YsVUFBVSxFQUFFLE1BQU0sR0FDbkI7O0FBRUQsK0RBRUc7QUFFSCxpREFFRztBQUVILEFBQUEsS0FBSyxDQUFDLEVBQ0osU0FBUyxFQUFFLEdBQUcsRUFDZCxXQUFXLEVBQUUsR0FBRyxFQUFFLGFBQWEsRUFDaEM7O0FBRUQsdUZBR0c7QUFFSCxBQUFBLEdBQUcsRUFDSCxHQUFHLENBQUMsRUFDRixTQUFTLEVBQUUsR0FBRyxFQUNkLFdBQVcsRUFBRSxDQUFDLEVBQ2QsUUFBUSxFQUFFLFFBQVEsRUFDbEIsY0FBYyxFQUFFLFFBQVEsR0FDekI7O0FBRUQsQUFBQSxHQUFHLENBQUMsRUFDRixNQUFNLEVBQUUsT0FBTyxHQUNoQjs7QUFFRCxBQUFBLEdBQUcsQ0FBQyxFQUNGLEdBQUcsRUFBRSxNQUFNLEdBQ1o7O0FBRUQsaUdBQ2dGO0FBRWhGLHdDQUVHO0FBRUgsQUFBQSxLQUFLLEVBQ0wsS0FBSyxDQUFDLEVBQ0osT0FBTyxFQUFFLFlBQVksR0FDdEI7O0FBRUQsMENBRUc7QUFFSCxBQUFBLEtBQUssQUFBQSxJQUFLLEVBQUEsQUFBQSxRQUFDLEFBQUEsR0FBVyxFQUNwQixPQUFPLEVBQUUsSUFBSSxFQUNiLE1BQU0sRUFBRSxDQUFDLEdBQ1Y7O0FBRUQsMERBRUc7QUFFSCxBQUFBLEdBQUcsQ0FBQyxFQUNGLFlBQVksRUFBRSxJQUFJLEdBQ25COztBQUVELCtCQUVHO0FBRUgsQUFBQSxHQUFHLEFBQUEsSUFBSyxDQUFBLEtBQUssRUFBRSxFQUNiLFFBQVEsRUFBRSxNQUFNLEdBQ2pCOztBQUVELHNGQUNnRjtBQUVoRiwyR0FHRztBQUVILEFBQUEsTUFBTSxFQUNOLEtBQUssRUFDTCxRQUFRLEVBQ1IsTUFBTSxFQUNOLFFBQVEsQ0FBQyxFQUNQLFdBQVcsRUFBRSxPQUFPLEVBQUUsaUJBQWlCLENBQ3ZDLFNBQVMsRUFBRSxPQUFPLEVBQUUsaUJBQWlCLENBQ3JDLFdBQVcsRUFBRSxPQUFPLEVBQUUsaUJBQWlCLENBQ3ZDLE1BQU0sRUFBRSxDQUFDLEVBQUUsT0FBTyxFQUNuQjs7QUFFRCw2REFHRztBQUVILEFBQUEsTUFBTSxFQUNOLEtBQUssQ0FBQyxFQUFFLE9BQU8sQ0FDYixRQUFRLEVBQUUsT0FBTyxHQUNsQjs7QUFFRCxpSUFHRztBQUVILEFBQUEsTUFBTSxFQUNOLE1BQU0sQ0FBQyxFQUFFLE9BQU8sQ0FDZCxjQUFjLEVBQUUsSUFBSSxHQUNyQjs7QUFFRCx3S0FJRztBQUVILEFBQUEsTUFBTSxFQUNOLElBQUksRUFBQyxBQUFBLElBQUMsQ0FBSyxRQUFRLEFBQWIsSUFDTixBQUFBLElBQUMsQ0FBSyxPQUFPLEFBQVosSUFDRCxBQUFBLElBQUMsQ0FBSyxRQUFRLEFBQWIsRUFBZSxFQUNkLGtCQUFrQixFQUFFLE1BQU0sRUFBRSxPQUFPLEVBQ3BDOztBQUVELHNEQUVHO0FBRUgsQUFBQSxNQUFNLEFBQUEsa0JBQWtCLEdBQ3hCLEFBQUEsSUFBQyxDQUFLLFFBQVEsQUFBYixDQUFjLGtCQUFrQixHQUNqQyxBQUFBLElBQUMsQ0FBSyxPQUFPLEFBQVosQ0FBYSxrQkFBa0IsR0FDaEMsQUFBQSxJQUFDLENBQUssUUFBUSxBQUFiLENBQWMsa0JBQWtCLENBQUMsRUFDaEMsWUFBWSxFQUFFLElBQUksRUFDbEIsT0FBTyxFQUFFLENBQUMsR0FDWDs7QUFFRCxxRUFFRztBQUdILHNGQUVHO0FBRUgsQUFBQSxRQUFRLENBQUMsRUFDUCxNQUFNLEVBQUUsQ0FBQyxFQUNULE1BQU0sRUFBRSxDQUFDLEVBQ1QsT0FBTyxFQUFFLENBQUMsR0FDWDs7QUFFRCxtT0FLRztBQUVILEFBQUEsTUFBTSxDQUFDLEVBQ0wsVUFBVSxFQUFFLFVBQVUsRUFBRSxPQUFPLENBQy9CLEtBQUssRUFBRSxPQUFPLEVBQUUsT0FBTyxDQUN2QixPQUFPLEVBQUUsS0FBSyxFQUFFLE9BQU8sQ0FDdkIsU0FBUyxFQUFFLElBQUksRUFBRSxPQUFPLENBQ3hCLE9BQU8sRUFBRSxDQUFDLEVBQUUsT0FBTyxDQUNuQixXQUFXLEVBQUUsTUFBTSxFQUFFLE9BQU8sRUFDN0I7O0FBRUQsZ0hBR0c7QUFFSCxBQUFBLFFBQVEsQ0FBQyxFQUNQLE9BQU8sRUFBRSxZQUFZLEVBQUUsT0FBTyxDQUM5QixjQUFjLEVBQUUsUUFBUSxFQUFFLE9BQU8sRUFDbEM7O0FBRUQsbURBRUc7QUFFSCxBQUFBLFFBQVEsQ0FBQyxFQUNQLFFBQVEsRUFBRSxJQUFJLEdBQ2Y7O0FBRUQsZ0ZBR0c7Q0FFSCxBQUFBLEFBQUEsSUFBQyxDQUFLLFVBQVUsQUFBZixJQUNELEFBQUEsSUFBQyxDQUFLLE9BQU8sQUFBWixFQUFjLEVBQ2IsVUFBVSxFQUFFLFVBQVUsRUFBRSxPQUFPLENBQy9CLE9BQU8sRUFBRSxDQUFDLEVBQUUsT0FBTyxFQUNwQjs7QUFFRCw2RUFFRztDQUVILEFBQUEsQUFBQSxJQUFDLENBQUssUUFBUSxBQUFiLENBQWMsMkJBQTJCLEdBQzFDLEFBQUEsSUFBQyxDQUFLLFFBQVEsQUFBYixDQUFjLDJCQUEyQixDQUFDLEVBQ3pDLE1BQU0sRUFBRSxJQUFJLEdBQ2I7O0FBRUQsa0dBR0c7Q0FFSCxBQUFBLEFBQUEsSUFBQyxDQUFLLFFBQVEsQUFBYixFQUFlLEVBQ2Qsa0JBQWtCLEVBQUUsU0FBUyxFQUFFLE9BQU8sQ0FDdEMsY0FBYyxFQUFFLElBQUksRUFBRSxPQUFPLEVBQzlCOztBQUVELGlGQUVHO0NBRUgsQUFBQSxBQUFBLElBQUMsQ0FBSyxRQUFRLEFBQWIsQ0FBYyw4QkFBOEIsR0FDN0MsQUFBQSxJQUFDLENBQUssUUFBUSxBQUFiLENBQWMsMkJBQTJCLENBQUMsRUFDekMsa0JBQWtCLEVBQUUsSUFBSSxHQUN6Qjs7QUFFRCw2SEFHRztBQUVILEFBQUEsNEJBQTRCLENBQUMsRUFDM0Isa0JBQWtCLEVBQUUsTUFBTSxFQUFFLE9BQU8sQ0FDbkMsSUFBSSxFQUFFLE9BQU8sRUFBRSxPQUFPLEVBQ3ZCOztBQUVELDRGQUNnRjtBQUVoRiw0RkFHRztBQUVILEFBQUEsT0FBTyxFQUNQLElBQUksQ0FBQyxFQUNILE9BQU8sRUFBRSxLQUFLLEdBQ2Y7O0FBRUQsOENBRUc7QUFFSCxBQUFBLE9BQU8sQ0FBQyxFQUNOLE9BQU8sRUFBRSxTQUFTLEVBQ2xCLE9BQU8sRUFBRSxJQUFJLEdBQ2Q7O0FBRUQsMEZBQ2dGO0FBRWhGLHdDQUVHO0FBRUgsQUFBQSxNQUFNLENBQUMsRUFDTCxPQUFPLEVBQUUsWUFBWSxHQUN0Qjs7QUFFRCxxQ0FFRztBQUVILEFBQUEsUUFBUSxDQUFDLEVBQ1AsT0FBTyxFQUFFLElBQUksR0FDZDs7QUFFRCx1RkFDZ0Y7QUFFaEYseUNBRUc7Q0FFSCxBQUFBLEFBQUEsTUFBQyxBQUFBLEVBQVEsRUFDUCxPQUFPLEVBQUUsSUFBSSxHQUNkOztBQzViRCxBQUFBLENBQUMsRUFDRCxDQUFDLEFBQUEsUUFBUSxFQUNULENBQUMsQUFBQSxPQUFPLENBQUMsRUFDUCxVQUFVLEVBQUUsT0FBTyxHQUNwQjs7QURRRCxBQUFBLElBQUksQ0NOQyxFQUNILFVBQVUsRUFBRSxVQUFVLEVBQ3RCLFNBQVMsRWI0RE0sSUFBSSxFYTNEbkIsV0FBVyxFYjRETSxHQUFHLEVhM0RwQiwyQkFBMkIsRUFBRSxXQUFXLEdBQ3pDOztBRGNELEFBQUEsSUFBSSxDQ1pDLEVBQ0gsVUFBVSxFYkNFLElBQUksRWFBaEIsS0FBSyxFYm9CVyxPQUF3QixFYW5CeEMsV0FBVyxFYjBCTSxhQUFhLEVBQUUsU0FBUyxFQUFFLGtCQUFrQixFQUFFLFVBQVUsRUFBRSxNQUFNLEVBRTVELGdCQUFnQixFQUFFLFVBQVUsRWEzQmpELFNBQVMsRWJxREMsTUFBSyxFYXBEZixVQUFVLEVBQUUsTUFBTSxFQUNsQixjQUFjLEVBQUUsa0JBQWtCLEdBQ25DOztBRDBFRCxBQUFBLENBQUMsQ0N4RUMsRUFDQSxLQUFLLEViakJTLE9BQU8sRWFrQnJCLE9BQU8sRUFBRSxJQUFJLEVBQ2IsZUFBZSxFQUFFLElBQUksR0FpQnRCOztBQXBCRCxBQUtFLENBTEQsQUFLRSxNQUFNLENBQUMsRUwxQlIsVUFBVSxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLE1BQUssQ1JLVCxzQkFBTyxHYXVCcEI7O0FBUEgsQUFTRSxDQVRELEFBU0UsTUFBTSxFQVRULENBQUMsQUFVRSxNQUFNLEVBVlQsQ0FBQyxBQVdFLE9BQU8sRUFYVixDQUFDLEFBWUUsT0FBTyxDQUFDLEVBQ1AsS0FBSyxFYkVTLE9BQXdCLEVhRHRDLGVBQWUsRUFBRSxTQUFTLEdBQzNCOztBQWZILEFBaUJFLENBakJELEFBaUJFLFFBQVEsQ0FBQyxFQUNSLEtBQUssRWJGVSxPQUF5QixHYUd6Qzs7QUN4Q0gsQUFBQSxFQUFFLEVBQ0YsRUFBRSxFQUNGLEVBQUUsRUFDRixFQUFFLEVBQ0YsRUFBRSxFQUNGLEVBQUUsQ0FBQyxFQUNELEtBQUssRUFBRSxPQUFPLEVBQ2QsV0FBVyxFQUFFLEdBQUcsRUFDaEIsV0FBVyxFQUFFLEdBQUcsRUFDaEIsYUFBYSxFQUFFLElBQUksRUFDbkIsVUFBVSxFQUFFLENBQUMsR0FDZDs7QUFDRCxBQUFBLEdBQUcsRUFDSCxHQUFHLEVBQ0gsR0FBRyxFQUNILEdBQUcsRUFDSCxHQUFHLEVBQ0gsR0FBRyxDQUFDLEVBQ0YsV0FBVyxFQUFFLEdBQUcsR0FDakI7O0FBQ0QsQUFBQSxFQUFFLEVBQ0YsR0FBRyxDQUFDLEVBQ0YsU0FBUyxFQUFFLElBQUksR0FDaEI7O0FBQ0QsQUFBQSxFQUFFLEVBQ0YsR0FBRyxDQUFDLEVBQ0YsU0FBUyxFQUFFLE1BQU0sR0FDbEI7O0FBQ0QsQUFBQSxFQUFFLEVBQ0YsR0FBRyxDQUFDLEVBQ0YsU0FBUyxFQUFFLE1BQU0sR0FDbEI7O0FBQ0QsQUFBQSxFQUFFLEVBQ0YsR0FBRyxDQUFDLEVBQ0YsU0FBUyxFQUFFLE1BQU0sR0FDbEI7O0FBQ0QsQUFBQSxFQUFFLEVBQ0YsR0FBRyxDQUFDLEVBQ0YsU0FBUyxFQUFFLElBQUksR0FDaEI7O0FBQ0QsQUFBQSxFQUFFLEVBQ0YsR0FBRyxDQUFDLEVBQ0YsU0FBUyxFQUFFLEtBQUssR0FDakI7O0FBR0QsQUFBQSxDQUFDLENBQUMsRUFDQSxNQUFNLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ2R5QkMsTUFBTSxHY3hCbkI7O0FBR0QsQUFBQSxDQUFDLEVBQ0QsR0FBRyxFQUNILENBQUMsQ0FBQyxFQUNBLG9CQUFvQixFQUFFLFNBQVMsR0FDaEM7O0FBRUQsQUFBQSxJQUFJLENBQUEsQUFBQSxLQUFDLEFBQUEsRUFBTyxFQUNWLGFBQWEsRWRQTixPQUFNLENjT2dCLE1BQU0sRUFDbkMsTUFBTSxFQUFFLElBQUksRUFDWixlQUFlLEVBQUUsSUFBSSxHQUN0Qjs7QUFFRCxBQUFBLEdBQUcsQ0FBQyxFUi9ERixhQUFhLEVOb0ROLE1BQUssRU1uRFosV0FBVyxFQUFFLEdBQUcsRUFDaEIsT0FBTyxFQUFFLFdBQVcsRUFJcEIsVUFBVSxFTk9DLE9BQU8sRU1ObEIsS0FBSyxFTk9PLElBQUksRWNvRGhCLFNBQVMsRWRJSSxNQUFLLEdjSG5COztBQUVELEFBQUEsSUFBSSxDQUFDLEVSL0RILFVBQVUsRU4wQk0sT0FBTyxFTXpCdkIsS0FBSyxFTjJCVyxPQUF3QixFY3FDeEMsYUFBYSxFZG5CTixNQUFLLEVjb0JaLE9BQU8sRUFBRSxNQUFNLEdBQ2hCOztBQUdELEFBQUEsVUFBVSxDQUFDLEVBQ1QsV0FBVyxFZHpCSixNQUFLLENjeUJrQixLQUFLLENkMUR0QixPQUF5QixFYzJEdEMsV0FBVyxFQUFFLENBQUMsRUFDZCxPQUFPLEVkekJBLE1BQUssQ0FFTCxNQUFLLEdjNEJiOztBQVJELEFBS0UsVUFMUSxDQUtSLENBQUMsQUFBQSxXQUFXLENBQUMsRUFDWCxhQUFhLEVBQUUsQ0FBQyxHQUNqQjs7QUFJSCxBQUFBLEVBQUUsRUFDRixFQUFFLENBQUMsRUFDRCxNQUFNLEVkakNDLE1BQUssQ2NpQ0ksQ0FBQyxDZGpDVixNQUFLLENBQUwsTUFBSyxFY2tDWixPQUFPLEVBQUUsQ0FBQyxHQVVYOztBQWJELEFBS0UsRUFMQSxDQUtBLEVBQUUsRUFMSixFQUFFLENBTUEsRUFBRSxFQUxKLEVBQUUsQ0FJQSxFQUFFLEVBSkosRUFBRSxDQUtBLEVBQUUsQ0FBQyxFQUNELE1BQU0sRWR0Q0QsTUFBSyxDY3NDTSxDQUFDLENkdENaLE1BQUssQ0FBTCxNQUFLLEdjdUNYOztBQVJILEFBVUUsRUFWQSxDQVVBLEVBQUUsRUFUSixFQUFFLENBU0EsRUFBRSxDQUFDLEVBQ0QsVUFBVSxFZDVDTCxNQUFLLEdjNkNYOztBQUdILEFBQUEsRUFBRSxDQUFDLEVBQ0QsVUFBVSxFQUFFLFdBQVcsR0FLeEI7O0FBTkQsQUFHRSxFQUhBLENBR0EsRUFBRSxDQUFDLEVBQ0QsZUFBZSxFQUFFLE1BQU0sR0FDeEI7O0FBR0gsQUFBQSxFQUFFLENBQUMsRUFDRCxVQUFVLEVBQUUsY0FBYyxHQUszQjs7QUFORCxBQUdFLEVBSEEsQ0FHQSxFQUFFLENBQUMsRUFDRCxlQUFlLEVBQUUsV0FBVyxHQUM3Qjs7QUFHSCxBQUNFLEVBREEsQ0FDQSxFQUFFLENBQUMsRUFDRCxXQUFXLEVBQUUsSUFBSSxHQUNsQjs7QUFISCxBQUlFLEVBSkEsQ0FJQSxFQUFFLENBQUMsRUFDRCxNQUFNLEVkckVELE1BQUssQ2NxRU0sQ0FBQyxDZG5FWixNQUFLLENjbUVnQixDQUFDLEdBQzVCOztBQzdISCxBQUFBLEtBQU0sQ0FBQSxFQUFFLEdBQ1IsS0FBTSxDQUFBLE9BQU8sRUFBRSxFQUNiLFdBQVcsRWZ3Q00sYUFBYSxFQUFFLFNBQVMsRUFBRSxrQkFBa0IsRUFBRSxVQUFVLEVBQUUsTUFBTSxFQUd0QyxhQUFhLEVBQUUsa0JBQWtCLEVBQUUsaUJBQWlCLEVBRDFFLGdCQUFnQixFQUFFLFVBQVUsR2V6Q2xEOztBQUVELEFBQUEsS0FBTSxDQUFBLE9BQU8sRUFBRSxFQUNiLFdBQVcsRWZvQ00sYUFBYSxFQUFFLFNBQVMsRUFBRSxrQkFBa0IsRUFBRSxVQUFVLEVBQUUsTUFBTSxFQUl0QyxhQUFhLEVBQUUsbUJBQW1CLEVBQUUsb0JBQW9CLEVBRjlFLGdCQUFnQixFQUFFLFVBQVUsR2VyQ2xEOztBQUVELEFBQUEsS0FBTSxDQUFBLEVBQUUsRUFBRSxFQUNSLFdBQVcsRWZnQ00sYUFBYSxFQUFFLFNBQVMsRUFBRSxrQkFBa0IsRUFBRSxVQUFVLEVBQUUsTUFBTSxFQUszQyxlQUFlLEVBQUUsMEJBQTBCLEVBQUUsV0FBVyxFQUFFLFFBQVEsRUFBRSxNQUFNLEVBSDNGLGdCQUFnQixFQUFFLFVBQVUsR2VqQ2xEOztBQUVELEFBQUEsS0FBTSxDQUFBLEVBQUUsRUFBRSxFQUNSLFdBQVcsRWY0Qk0sYUFBYSxFQUFFLFNBQVMsRUFBRSxrQkFBa0IsRUFBRSxVQUFVLEVBQUUsTUFBTSxFQU0zQyxlQUFlLEVBSmhDLGdCQUFnQixFQUFFLFVBQVUsR2U3QmxEOztBQUVELEFBR0UsS0FISSxDQWpCQSxFQUFFLEVBb0JOLEdBQUcsRUFITCxLQUFNLENBakJBLEVBQUUsRUFxQk4sQ0FBQyxFQUhILEtBQU0sQ0FUQSxFQUFFLEVBV04sR0FBRyxFQUZMLEtBQU0sQ0FUQSxFQUFFLEVBWU4sQ0FBQyxFQUZILElBQUksQ0FDRixHQUFHLEVBREwsSUFBSSxDQUVGLENBQUMsQ0FBQyxFQUNBLGFBQWEsRWY4QlIsT0FBTSxDZTlCa0IsS0FBSyxFQUNsQyxlQUFlLEVBQUUsSUFBSSxHQUN0Qjs7QUFQSCxBQVNFLEtBVEksQ0FqQkEsRUFBRSxFQTBCTixHQUFHLEdBQUcsR0FBRyxFQVRYLEtBQU0sQ0FqQkEsRUFBRSxFQTJCTixHQUFHLEdBQUcsQ0FBQyxFQVZULEtBQU0sQ0FqQkEsRUFBRSxFQTRCTixHQUFHLEdBQUcsR0FBRyxFQVhYLEtBQU0sQ0FqQkEsRUFBRSxFQTZCTixHQUFHLEdBQUcsQ0FBQyxFQVpULEtBQU0sQ0FqQkEsRUFBRSxFQThCTixDQUFDLEdBQUcsR0FBRyxFQWJULEtBQU0sQ0FqQkEsRUFBRSxFQStCTixDQUFDLEdBQUcsQ0FBQyxFQWRQLEtBQU0sQ0FqQkEsRUFBRSxFQWdDTixDQUFDLEdBQUcsR0FBRyxFQWZULEtBQU0sQ0FqQkEsRUFBRSxFQWlDTixDQUFDLEdBQUcsQ0FBQyxFQWZQLEtBQU0sQ0FUQSxFQUFFLEVBaUJOLEdBQUcsR0FBRyxHQUFHLEVBUlgsS0FBTSxDQVRBLEVBQUUsRUFrQk4sR0FBRyxHQUFHLENBQUMsRUFUVCxLQUFNLENBVEEsRUFBRSxFQW1CTixHQUFHLEdBQUcsR0FBRyxFQVZYLEtBQU0sQ0FUQSxFQUFFLEVBb0JOLEdBQUcsR0FBRyxDQUFDLEVBWFQsS0FBTSxDQVRBLEVBQUUsRUFxQk4sQ0FBQyxHQUFHLEdBQUcsRUFaVCxLQUFNLENBVEEsRUFBRSxFQXNCTixDQUFDLEdBQUcsQ0FBQyxFQWJQLEtBQU0sQ0FUQSxFQUFFLEVBdUJOLENBQUMsR0FBRyxHQUFHLEVBZFQsS0FBTSxDQVRBLEVBQUUsRUF3Qk4sQ0FBQyxHQUFHLENBQUMsRUFkUCxJQUFJLENBT0YsR0FBRyxHQUFHLEdBQUcsRUFQWCxJQUFJLENBUUYsR0FBRyxHQUFHLENBQUMsRUFSVCxJQUFJLENBU0YsR0FBRyxHQUFHLEdBQUcsRUFUWCxJQUFJLENBVUYsR0FBRyxHQUFHLENBQUMsRUFWVCxJQUFJLENBV0YsQ0FBQyxHQUFHLEdBQUcsRUFYVCxJQUFJLENBWUYsQ0FBQyxHQUFHLENBQUMsRUFaUCxJQUFJLENBYUYsQ0FBQyxHQUFHLEdBQUcsRUFiVCxJQUFJLENBY0YsQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUNKLFdBQVcsRUFBRSxNQUFNLEdBQ3BCOztBQ25DSCxBQUFBLE1BQU0sQ0FBQyxFQUNMLGVBQWUsRUFBRSxRQUFRLEVBQ3pCLGNBQWMsRUFBRSxDQUFDLEVBQ2pCLEtBQUssRUFBRSxJQUFJLEVBSVQsVUFBVSxFQUFFLElBQUksR0FnRG5COztBQXZERCxBQVlNLE1BWkEsQUFVSCxjQUFjLENBQ2IsS0FBSyxDQUNILEVBQUUsQUFBQSxZQUFhLENBQUEsR0FBRyxFQUFFLEVBQ2xCLFVBQVUsRWhCU1AsT0FBeUIsR2dCUjdCOztBQWRQLEFBc0JRLE1BdEJGLENBb0JGLEtBQUssQ0FDSCxFQUFFLEFBQ0MsT0FBTyxFQXRCaEIsTUFBTSxBQW1CSCxjQUFjLENBQ2IsS0FBSyxDQUNILEVBQUUsQUFDQyxPQUFPLENBQUMsRUFDUCxVQUFVLEVoQkFKLE9BQXFCLEdnQkM1Qjs7QUF4QlQsQUFnQ1EsTUFoQ0YsQUE2QkgsWUFBWSxDQUNYLEtBQUssQ0FDSCxFQUFFLEFBQ0MsTUFBTSxDQUFDLEVBQ04sVUFBVSxFaEJWSixPQUFxQixHZ0JXNUI7O0FBbENULEFBd0NFLE1BeENJLEFBd0NILGFBQWEsQ0FBQyxFQUNiLE9BQU8sRUFBRSxLQUFLLEVBQ2QsVUFBVSxFQUFFLElBQUksRUFDaEIsY0FBYyxFQUFFLE1BQU0sRUFDdEIsV0FBVyxFQUFFLE1BQU0sR0FDcEI7O0FBN0NILEFBK0NFLE1BL0NJLENBK0NKLEVBQUUsRUEvQ0osTUFBTSxDQWdESixFQUFFLENBQUMsRUFDRCxhQUFhLEVoQkdSLE9BQU0sQ2dCSGtCLEtBQUssQ2hCN0J2QixPQUF5QixFZ0I4QnBDLE9BQU8sRWhCTUYsTUFBSyxDQURMLE1BQUssR2dCSlg7O0FBbkRILEFBb0RFLE1BcERJLENBb0RKLEVBQUUsQ0FBQyxFQUNELG1CQUFtQixFaEJBZCxNQUFLLEdnQkNYOztBQ3RESCxBQUFBLElBQUksQ0FBQyxFTkNILFVBQVUsRUFBRSxZQUFZLEVNQ3hCLFVBQVUsRUFBRSxJQUFJLEVBQ2hCLFVBQVUsRWpCWUUsSUFBSSxFaUJYaEIsTUFBTSxFakJnREMsT0FBTSxDaUJoRFMsS0FBSyxDakJFYixPQUFPLEVpQkRyQixhQUFhLEVqQmdETixNQUFLLEVpQi9DWixLQUFLLEVqQkFTLE9BQU8sRWlCQ3JCLE1BQU0sRUFBRSxPQUFPLEVBQ2YsT0FBTyxFQUFFLFlBQVksRUFDckIsU0FBUyxFakI2REMsTUFBSyxFaUI1RGYsTUFBTSxFakJvREMsTUFBTSxFaUJuRGIsV0FBVyxFakI4REMsTUFBTSxFaUI3RGxCLE9BQU8sRUFBRSxJQUFJLEVBQ2IsT0FBTyxFakIyRVcsT0FBa0QsQ0FqQzdELE1BQUssRWlCekNaLFVBQVUsRUFBRSxNQUFNLEVBQ2xCLGVBQWUsRUFBRSxJQUFJLEVBQ3JCLFdBQVcsRUFBRSxJQUFJLEVBQ2pCLGNBQWMsRUFBRSxNQUFNLEVBQ3RCLFdBQVcsRUFBRSxNQUFNLEdBMElwQjs7QUE1SkQsQUFtQkUsSUFuQkUsQUFtQkQsTUFBTSxDQUFDLEVUbEJSLFVBQVUsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxNQUFLLENSS1Qsc0JBQU8sR2lCZXBCOztBQXJCSCxBQXNCRSxJQXRCRSxBQXNCRCxNQUFNLEVBdEJULElBQUksQUF1QkQsTUFBTSxDQUFDLEVBQ04sVUFBVSxFakJmSSxPQUE4QixFaUJnQjVDLFlBQVksRWpCbEJLLE9BQTBCLEVpQm1CM0MsZUFBZSxFQUFFLElBQUksR0FDdEI7O0FBM0JILEFBNEJFLElBNUJFLEFBNEJELE9BQU8sRUE1QlYsSUFBSSxBQTZCRCxPQUFPLENBQUMsRUFDUCxVQUFVLEVqQnZCTyxPQUEwQixFaUJ3QjNDLFlBQVksRUFBRSxPQUErQixFQUM3QyxLQUFLLEVqQmpCSyxJQUFJLEVpQmtCZCxlQUFlLEVBQUUsSUFBSSxHQU90Qjs7QUF4Q0gsQUFtQ00sSUFuQ0YsQUE0QkQsT0FBTyxBQU1MLFFBQVEsQUFDTixPQUFPLEVBbkNkLElBQUksQUE2QkQsT0FBTyxBQUtMLFFBQVEsQUFDTixPQUFPLENBQUMsRUFDUCxtQkFBbUIsRWpCckJiLElBQUksRWlCc0JWLGlCQUFpQixFakJ0QlgsSUFBSSxHaUJ1Qlg7O0FBdENQLEFBeUNFLElBekNFLENBeUNELEFBQUEsUUFBQyxBQUFBLEdBekNKLElBQUksQUEwQ0QsU0FBUyxFQTFDWixJQUFJLEFBMkNELFNBQVMsQ0FBQyxFQUNULE1BQU0sRUFBRSxPQUFPLEVBQ2YsT0FBTyxFQUFFLEVBQUUsRUFDWCxjQUFjLEVBQUUsSUFBSSxHQUNyQjs7QUEvQ0gsQUFrREUsSUFsREUsQUFrREQsWUFBWSxDQUFDLEVBQ1osVUFBVSxFakI3Q0UsT0FBTyxFaUI4Q25CLFlBQVksRWpCN0NLLE9BQTBCLEVpQjhDM0MsS0FBSyxFakJ0Q0ssSUFBSSxHaUJ5RGY7O0FBeEVILEFBc0RJLElBdERBLEFBa0RELFlBQVksQUFJVixNQUFNLEVBdERYLElBQUksQUFrREQsWUFBWSxBQUtWLE1BQU0sQ0FBQyxFQUNOLFVBQVUsRUFBRSxPQUErQixFQUMzQyxZQUFZLEVBQUUsT0FBK0IsRUFDN0MsS0FBSyxFakIzQ0csSUFBSSxHaUI0Q2I7O0FBM0RMLEFBNERJLElBNURBLEFBa0RELFlBQVksQUFVVixPQUFPLEVBNURaLElBQUksQUFrREQsWUFBWSxBQVdWLE9BQU8sQ0FBQyxFQUNQLFVBQVUsRUFBRSxPQUErQixFQUMzQyxZQUFZLEVBQUUsT0FBK0IsRUFDN0MsS0FBSyxFakJqREcsSUFBSSxHaUJrRGI7O0FBakVMLEFBbUVNLElBbkVGLEFBa0RELFlBQVksQUFnQlYsUUFBUSxBQUNOLE9BQU8sQ0FBQyxFQUNQLG1CQUFtQixFakJyRGIsSUFBSSxFaUJzRFYsaUJBQWlCLEVqQnREWCxJQUFJLEdpQnVEWDs7QUF0RVAsQUEyRUUsSUEzRUUsQUEyRUQsWUFBWSxDQUFDLEVkMUVkLFVBQVUsRUgwQkksT0FBTyxFR3pCckIsWUFBWSxFQUFFLE9BQWtCLEVBQ2hDLEtBQUssRUhZTyxJQUFJLEdpQjhEZjs7QUE3RUgsQWRJRSxJY0pFLEFBMkVELFlBQVksQWR2RVosTUFBTSxDQUFDLEVLSFIsVUFBVSxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLE1BQUssQ1IwQlQsc0JBQU8sR0dyQnBCOztBY05ILEFkT0UsSWNQRSxBQTJFRCxZQUFZLEFkcEVaLE1BQU0sRWNQVCxJQUFJLEFBMkVELFlBQVksQWRuRVosTUFBTSxDQUFDLEVBQ04sVUFBVSxFQUFFLE9BQWtCLEVBQzlCLFlBQVksRUFBRSxPQUFrQixFQUNoQyxLQUFLLEVISUssSUFBSSxHR0hmOztBY1pILEFkYUUsSWNiRSxBQTJFRCxZQUFZLEFkOURaLE9BQU8sRWNiVixJQUFJLEFBMkVELFlBQVksQWQ3RFosT0FBTyxDQUFDLEVBQ1AsVUFBVSxFQUFFLE9BQWtCLEVBQzlCLFlBQVksRUFBRSxPQUFtQixFQUNqQyxLQUFLLEVIRkssSUFBSSxHR0dmOztBY2xCSCxBZG9CSSxJY3BCQSxBQTJFRCxZQUFZLEFkeERaLFFBQVEsQUFDTixPQUFPLENBQUMsRUFDUCxtQkFBbUIsRUhOWCxJQUFJLEVHT1osaUJBQWlCLEVIUFQsSUFBSSxHR1FiOztBY3ZCTCxBQStFRSxJQS9FRSxBQStFRCxVQUFVLENBQUMsRWQ5RVosVUFBVSxFSDRCRSxPQUFPLEVHM0JuQixZQUFZLEVBQUUsT0FBa0IsRUFDaEMsS0FBSyxFSFlPLElBQUksR2lCa0VmOztBQWpGSCxBZElFLEljSkUsQUErRUQsVUFBVSxBZDNFVixNQUFNLENBQUMsRUtIUixVQUFVLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBSyxDUjRCWCxzQkFBTyxHR3ZCbEI7O0FjTkgsQWRPRSxJY1BFLEFBK0VELFVBQVUsQWR4RVYsTUFBTSxFY1BULElBQUksQUErRUQsVUFBVSxBZHZFVixNQUFNLENBQUMsRUFDTixVQUFVLEVBQUUsT0FBa0IsRUFDOUIsWUFBWSxFQUFFLE9BQWtCLEVBQ2hDLEtBQUssRUhJSyxJQUFJLEdHSGY7O0FjWkgsQWRhRSxJY2JFLEFBK0VELFVBQVUsQWRsRVYsT0FBTyxFY2JWLElBQUksQUErRUQsVUFBVSxBZGpFVixPQUFPLENBQUMsRUFDUCxVQUFVLEVBQUUsT0FBa0IsRUFDOUIsWUFBWSxFQUFFLE9BQW1CLEVBQ2pDLEtBQUssRUhGSyxJQUFJLEdHR2Y7O0FjbEJILEFkb0JJLEljcEJBLEFBK0VELFVBQVUsQWQ1RFYsUUFBUSxBQUNOLE9BQU8sQ0FBQyxFQUNQLG1CQUFtQixFSE5YLElBQUksRUdPWixpQkFBaUIsRUhQVCxJQUFJLEdHUWI7O0FjdkJMLEFBbUZFLElBbkZFLEFBbUZELFlBQVksQ0FBQyxFZGxGZCxVQUFVLEVIMkJJLE9BQU8sRUcxQnJCLFlBQVksRUFBRSxPQUFrQixFQUNoQyxLQUFLLEVIWU8sSUFBSSxHaUJzRWY7O0FBckZILEFkSUUsSWNKRSxBQW1GRCxZQUFZLEFkL0VaLE1BQU0sQ0FBQyxFS0hSLFVBQVUsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxNQUFLLENSMkJULHVCQUFPLEdHdEJwQjs7QWNOSCxBZE9FLEljUEUsQUFtRkQsWUFBWSxBZDVFWixNQUFNLEVjUFQsSUFBSSxBQW1GRCxZQUFZLEFkM0VaLE1BQU0sQ0FBQyxFQUNOLFVBQVUsRUFBRSxPQUFrQixFQUM5QixZQUFZLEVBQUUsT0FBa0IsRUFDaEMsS0FBSyxFSElLLElBQUksR0dIZjs7QWNaSCxBZGFFLEljYkUsQUFtRkQsWUFBWSxBZHRFWixPQUFPLEVjYlYsSUFBSSxBQW1GRCxZQUFZLEFkckVaLE9BQU8sQ0FBQyxFQUNQLFVBQVUsRUFBRSxPQUFrQixFQUM5QixZQUFZLEVBQUUsT0FBbUIsRUFDakMsS0FBSyxFSEZLLElBQUksR0dHZjs7QWNsQkgsQWRvQkksSWNwQkEsQUFtRkQsWUFBWSxBZGhFWixRQUFRLEFBQ04sT0FBTyxDQUFDLEVBQ1AsbUJBQW1CLEVITlgsSUFBSSxFR09aLGlCQUFpQixFSFBULElBQUksR0dRYjs7QWN2QkwsQUF3RkUsSUF4RkUsQUF3RkQsU0FBUyxDQUFDLEVBQ1QsVUFBVSxFQUFFLFdBQVcsRUFDdkIsWUFBWSxFQUFFLFdBQVcsRUFDekIsS0FBSyxFakJyRk8sT0FBTyxHaUI0RnBCOztBQWxHSCxBQTRGSSxJQTVGQSxBQXdGRCxTQUFTLEFBSVAsTUFBTSxFQTVGWCxJQUFJLEFBd0ZELFNBQVMsQUFLUCxNQUFNLEVBN0ZYLElBQUksQUF3RkQsU0FBUyxBQU1QLE9BQU8sRUE5RlosSUFBSSxBQXdGRCxTQUFTLEFBT1AsT0FBTyxDQUFDLEVBQ1AsS0FBSyxFakIzRE8sT0FBd0IsR2lCNERyQzs7QUFqR0wsQUFxR0UsSUFyR0UsQUFxR0QsT0FBTyxDQUFDLEVBQ1AsU0FBUyxFakIvQkUsTUFBSyxFaUJnQ2hCLE1BQU0sRWpCM0NELE1BQU0sRWlCNENYLE9BQU8sRWpCZlksT0FBcUQsQ0FIckQsTUFBYSxHaUJtQmpDOztBQXpHSCxBQTJHRSxJQTNHRSxBQTJHRCxPQUFPLENBQUMsRUFDUCxTQUFTLEVqQnBDRSxNQUFLLEVpQnFDaEIsTUFBTSxFakI5Q0EsSUFBSSxFaUIrQ1YsT0FBTyxFakJwQlksT0FBcUQsQ0FIckQsTUFBYSxHaUJ3QmpDOztBQS9HSCxBQWtIRSxJQWxIRSxBQWtIRCxVQUFVLENBQUMsRUFDVixPQUFPLEVBQUUsS0FBSyxFQUNkLEtBQUssRUFBRSxJQUFJLEdBQ1o7O0FBckhILEFBd0hFLElBeEhFLEFBd0hELFdBQVcsQ0FBQyxFQUNYLEtBQUssRWpCM0RBLE1BQU0sRWlCNERYLFlBQVksRUFBRSxDQUFDLEVBQ2YsYUFBYSxFQUFFLENBQUMsR0FTakI7O0FBcElILEFBNkhJLElBN0hBLEFBd0hELFdBQVcsQUFLVCxPQUFPLENBQUMsRUFDUCxLQUFLLEVqQmxFRixNQUFNLEdpQm1FVjs7QUEvSEwsQUFpSUksSUFqSUEsQUF3SEQsV0FBVyxBQVNULE9BQU8sQ0FBQyxFQUNQLEtBQUssRWpCbkVELElBQUksR2lCb0VUOztBQW5JTCxBQXVJRSxJQXZJRSxBQXVJRCxVQUFVLENBQUMsRUFDVixVQUFVLEVBQUUsV0FBVyxFQUN2QixNQUFNLEVBQUUsQ0FBQyxFQUNULEtBQUssRUFBRSxZQUFZLEVBQ25CLE1BQU0sRWpCbEZELE1BQUssRWlCbUZWLFdBQVcsRWpCbkZOLE1BQUssRWlCb0ZWLFdBQVcsRWpCdkZOLE1BQUssRWlCd0ZWLFlBQVksRUFBRSxJQUFJLEVBQ2xCLE9BQU8sRUFBRSxDQUFDLEVBQ1YsT0FBTyxFQUFFLENBQUMsRUFDVixlQUFlLEVBQUUsSUFBSSxFQUNyQixLQUFLLEVqQnpGQSxNQUFLLEdpQmtHWDs7QUEzSkgsQUFvSkksSUFwSkEsQUF1SUQsVUFBVSxBQWFSLE1BQU0sQ0FBQyxFQUNOLE9BQU8sRUFBRSxHQUFHLEdBQ2I7O0FBdEpMLEFBd0pJLElBeEpBLEFBdUlELFVBQVUsQUFpQlIsUUFBUSxDQUFDLEVBQ1IsT0FBTyxFQUFFLE9BQU8sR0FDakI7O0FBS0wsQUFBQSxVQUFVLENBQUMsRUFDVCxPQUFPLEVBQUUsV0FBVyxFQUNwQixTQUFTLEVBQUUsSUFBSSxHQWdDaEI7O0FBbENELEFBSUUsVUFKUSxDQUlSLElBQUksQ0FBQyxFQUNILElBQUksRUFBRSxRQUFRLEdBb0JmOztBQXpCSCxBQU1JLFVBTk0sQ0FJUixJQUFJLEFBRUQsWUFBWSxBQUFBLElBQUssQ0FBQSxXQUFXLEVBQUUsRUFDN0IsMEJBQTBCLEVBQUUsQ0FBQyxFQUM3Qix1QkFBdUIsRUFBRSxDQUFDLEdBQzNCOztBQVRMLEFBVUksVUFWTSxDQUlSLElBQUksQUFNRCxJQUFLLENBQUEsWUFBWSxDQUFDLElBQUssQ0FKTixXQUFXLEVBSVEsRUFDbkMsYUFBYSxFQUFFLENBQUMsRUFDaEIsV0FBVyxFakJ2SFIsUUFBTSxHaUJ3SFY7O0FBYkwsQUFjSSxVQWRNLENBSVIsSUFBSSxBQVVELFdBQVcsQUFBQSxJQUFLLENBSlgsWUFBWSxFQUlhLEVBQzdCLHlCQUF5QixFQUFFLENBQUMsRUFDNUIsc0JBQXNCLEVBQUUsQ0FBQyxFQUN6QixXQUFXLEVqQjVIUixRQUFNLEdpQjZIVjs7QUFsQkwsQUFtQkksVUFuQk0sQ0FJUixJQUFJLEFBZUQsTUFBTSxFQW5CWCxVQUFVLENBSVIsSUFBSSxBQWdCRCxNQUFNLEVBcEJYLFVBQVUsQ0FJUixJQUFJLEFBaUJELE9BQU8sRUFyQlosVUFBVSxDQUlSLElBQUksQUFrQkQsT0FBTyxDQUFDLEVBQ1AsT0FBTyxFakJ4RUYsQ0FBQyxHaUJ5RVA7O0FBeEJMLEFBMkJFLFVBM0JRLEFBMkJQLGdCQUFnQixDQUFDLEVBQ2hCLE9BQU8sRUFBRSxJQUFJLEdBS2Q7O0FBakNILEFBOEJJLFVBOUJNLEFBMkJQLGdCQUFnQixDQUdmLElBQUksQ0FBQyxFQUNILElBQUksRUFBRSxLQUFLLEdBQ1o7O0FDL0xMLEFBQ0UsV0FEUyxBQUNSLElBQUssQ0RvS2MsV0FBVyxFQ3BLWixFQUNqQixhQUFhLEVsQnFEUixNQUFLLEdrQnBEWDs7QU44U0gsQUFBQSxRQUFRLENNM1NDLEVBQ1AsYUFBYSxFbEJrRE4sTUFBSyxHa0JqRGI7O0FOc1RELEFBQUEsTUFBTSxDTXBUQyxFQUNMLFNBQVMsRWxCNkRJLE1BQUssRWtCNURsQixXQUFXLEVBQUUsR0FBRyxFQUNoQixhQUFhLEVsQjRDTixNQUFLLEdrQjNDYjs7QUFHRCxBQUFBLFdBQVcsQ0FBQyxFQUNWLE9BQU8sRUFBRSxLQUFLLEVBQ2QsV0FBVyxFbEJzREMsTUFBTSxFa0JyRGxCLE9BQU8sRUFBRSxNQUFrQyxDQUFDLENBQUMsR0FXOUM7O0FBZEQsQUFLRSxXQUxTLEFBS1IsU0FBUyxDQUFDLEVBQ1QsU0FBUyxFbEJnREUsTUFBSyxFa0IvQ2hCLE9BQU8sRUFBRSxNQUFxQyxDQUFDLENBQUMsR0FDakQ7O0FBUkgsQUFVRSxXQVZTLEFBVVIsU0FBUyxDQUFDLEVBQ1QsU0FBUyxFbEI0Q0UsTUFBSyxFa0IzQ2hCLE9BQU8sRUFBRSxNQUFxQyxDQUFDLENBQUMsR0FDakQ7O0FBSUgsQUFBQSxXQUFXLENBQUMsRVBqQ1YsVUFBVSxFQUFFLFlBQVksRU9tQ3hCLFVBQVUsRUFBRSxJQUFJLEVBQ2hCLFVBQVUsRWxCdEJFLElBQUksRWtCdUJoQixnQkFBZ0IsRUFBRSxJQUFJLEVBQ3RCLE1BQU0sRWxCYUMsT0FBTSxDa0JiUyxLQUFLLENsQmxCVCxPQUEwQixFa0JtQjVDLGFBQWEsRWxCYU4sTUFBSyxFa0JaWixLQUFLLEVsQk5XLE9BQXdCLEVrQk94QyxPQUFPLEVBQUUsS0FBSyxFQUNkLFNBQVMsRWxCMkJDLE1BQUssRWtCMUJmLE1BQU0sRWxCa0JDLE1BQU0sRWtCakJiLFdBQVcsRWxCNEJDLE1BQU0sRWtCM0JsQixTQUFTLEVBQUUsSUFBSSxFQUNmLE9BQU8sRUFBRSxJQUFJLEVBQ2IsT0FBTyxFbEJ3Q1csT0FBa0QsQ0FqQzdELE1BQUssRWtCTlosUUFBUSxFQUFFLFFBQVEsRUFDbEIsS0FBSyxFQUFFLElBQUksR0FnQ1o7O0FBaERELEFBaUJFLFdBakJTLEFBaUJSLE1BQU0sQ0FBQyxFVmxEUixVQUFVLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBSyxDUktULHNCQUFPLEVrQitDbkIsWUFBWSxFbEIvQ0EsT0FBTyxHa0JnRHBCOztBQXBCSCxBQXFCRSxXQXJCUyxBQXFCUixhQUFhLENBQUMsRUFDYixLQUFLLEVsQnhDSSxPQUF5QixHa0J5Q25DOztBQXZCSCxBQTBCRSxXQTFCUyxBQTBCUixTQUFTLENBQUMsRUFDVCxTQUFTLEVsQlVFLE1BQUssRWtCVGhCLE1BQU0sRWxCRkQsTUFBTSxFa0JHWCxPQUFPLEVsQjBCWSxPQUFxRCxDQUhyRCxNQUFhLEdrQnRCakM7O0FBOUJILEFBZ0NFLFdBaENTLEFBZ0NSLFNBQVMsQ0FBQyxFQUNULFNBQVMsRWxCS0UsTUFBSyxFa0JKaEIsTUFBTSxFbEJMQSxJQUFJLEVrQk1WLE9BQU8sRWxCcUJZLE9BQXFELENBSHJELE1BQWEsR2tCakJqQzs7QUFwQ0gsQUFzQ0UsV0F0Q1MsQUFzQ1IsYUFBYSxDQUFDLEVBQ2IsT0FBTyxFQUFFLFlBQVksRUFDckIsY0FBYyxFQUFFLE1BQU0sRUFDdEIsS0FBSyxFQUFFLElBQUksR0FDWjs7QUExQ0gsQUE2Q0UsV0E3Q1MsQ0E2Q1IsQUFBQSxJQUFDLENBQUssTUFBTSxBQUFYLEVBQWEsRUFDYixNQUFNLEVBQUUsSUFBSSxHQUNiOztBQUlILEFBQUEsUUFBUSxBQUFBLFdBQVcsQ0FBQyxFQUNsQixNQUFNLEVBQUUsSUFBSSxHQUNiOztBQUdELEFBQUEsZ0JBQWdCLENBQUMsRUFDZixLQUFLLEVsQjNFTSxPQUF5QixFa0I0RXBDLFNBQVMsRWxCckJJLE1BQUssRWtCc0JsQixVQUFVLEVsQnZDSCxNQUFLLEdrQmtEYjs7QUFUQyxBQUFBLFlBQVksQ0FMZCxnQkFBZ0IsRUFNZCxXQUFXLEdBTmIsZ0JBQWdCLENBTUUsRUFDZCxLQUFLLEVsQnRFTyxPQUFPLEdrQnVFcEI7O0FBRUQsQUFBQSxVQUFVLENBVlosZ0JBQWdCLEVBV2QsU0FBUyxHQVhYLGdCQUFnQixDQVdBLEVBQ1osS0FBSyxFbEJ6RUssT0FBTyxHa0IwRWxCOztBQUlILEFBQUEsWUFBWSxDQUFDLEVBQ1gsVUFBVSxFQUFFLElBQUksRUFDaEIsTUFBTSxFbEJ6REMsT0FBTSxDa0J5RFMsS0FBSyxDbEJ4RlQsT0FBMEIsRWtCeUY1QyxhQUFhLEVsQnpETixNQUFLLEVrQjBEWixLQUFLLEVBQUUsT0FBTyxFQUNkLFNBQVMsRWxCMUNDLE1BQUssRWtCMkNmLE1BQU0sRWxCbkRDLE1BQU0sRWtCb0RiLFdBQVcsRWxCekNDLE1BQU0sRWtCMENsQixPQUFPLEVBQUUsSUFBSSxFQUNiLE9BQU8sRWxCNUJXLE9BQWtELENBakM3RCxNQUFLLEVrQjhEWixjQUFjLEVBQUUsTUFBTSxFQUN0QixLQUFLLEVBQUUsSUFBSSxHQWtDWjs7QUE3Q0QsQUFhRSxZQWJVLENBYVQsQUFBQSxJQUFDLEFBQUEsR0FiSixZQUFZLENBY1QsQUFBQSxRQUFDLEFBQUEsRUFBVSxFQUNWLE1BQU0sRUFBRSxJQUFJLEdBS2I7O0FBcEJILEFBaUJJLFlBakJRLENBYVQsQUFBQSxJQUFDLEFBQUEsRUFJQSxNQUFNLEVBakJWLFlBQVksQ0FjVCxBQUFBLFFBQUMsQUFBQSxFQUdBLE1BQU0sQ0FBQyxFQUNMLE9BQU8sRWxCeEVKLE1BQUssQ0FDTCxNQUFLLEdrQndFVDs7QUFuQkwsQUFxQkUsWUFyQlUsQUFxQlQsSUFBSyxFQUFBLEFBQUEsUUFBQyxBQUFBLEVBQVUsSUFBSyxFQUFBLEFBQUEsSUFBQyxBQUFBLEdBQU8sRUFDNUIsVUFBVSxFQUFFLElBQUksQ0FBQyw0TEFBNEwsQ0FBQyxTQUFTLENBQUMsS0FBSyxDQUFDLE9BQU0sQ0FBQyxhQUFZLENBQUMsTUFBSyxFQUN2UCxhQUFhLEVBQUUsTUFBdUMsR0FDdkQ7O0FBeEJILEFBeUJFLFlBekJVLEFBeUJULE1BQU0sQ0FBQyxFVm5JUixVQUFVLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBSyxDUktULHNCQUFPLEVrQmdJbkIsWUFBWSxFbEJoSUEsT0FBTyxHa0JpSXBCOztBQTVCSCxBQTZCRSxZQTdCVSxBQTZCVCxZQUFZLENBQUMsRUFDWixPQUFPLEVBQUUsSUFBSSxHQUNkOztBQS9CSCxBQWtDRSxZQWxDVSxBQWtDVCxVQUFVLENBQUMsRUFDVixTQUFTLEVsQnZFRSxNQUFLLEVrQndFaEIsTUFBTSxFbEJuRkQsTUFBTSxFa0JvRlgsT0FBTyxFbEJ2RFksT0FBcUQsQ2tCdUR6QyxNQUE0QyxDbEJ2RHhELE9BQXFELENBSHJELE1BQWEsR2tCMkRqQzs7QUF0Q0gsQUF3Q0UsWUF4Q1UsQUF3Q1QsVUFBVSxDQUFDLEVBQ1YsU0FBUyxFbEI1RUUsTUFBSyxFa0I2RWhCLE1BQU0sRWxCdEZBLElBQUksRWtCdUZWLE9BQU8sRWxCNURZLE9BQXFELENrQjREekMsTUFBNEMsQ2xCNUR4RCxPQUFxRCxDQUhyRCxNQUFhLEdrQmdFakM7O0FBSUgsQUFBQSxjQUFjLEVBQ2QsZUFBZSxDQUFDLEVBQ2QsUUFBUSxFQUFFLFFBQVEsR0FXbkI7O0FBYkQsQUFJRSxjQUpZLENBSVosVUFBVSxFQUhaLGVBQWUsQ0FHYixVQUFVLENBQUMsRUFDVCxNQUFNLEVsQnJFVSxNQUFLLEVrQnNFckIsTUFBTSxFQUFFLENBQUMsQ2xCekVPLE9BQWtELEVrQjBFbEUsUUFBUSxFQUFFLFFBQVEsRUFDbEIsR0FBRyxFQUFFLEdBQUcsRUFDUixTQUFTLEVBQUUsZ0JBQWdCLEVBQzNCLEtBQUssRWxCMUVXLE1BQUssRWtCMkVyQixPQUFPLEVsQnhEQSxDQUFDLEdrQnlEVDs7QUFHSCxBQUNFLGNBRFksQ0FDWixVQUFVLENBQUMsRUFDVCxJQUFJLEVsQnhIQyxPQUFNLEdrQnlIWjs7QUFISCxBQUtFLGNBTFksQ0FLWixXQUFXLENBQUMsRUFDVixZQUFZLEVBQUUsTUFBMkMsR0FDMUQ7O0FBR0gsQUFDRSxlQURhLENBQ2IsVUFBVSxDQUFDLEVBQ1QsS0FBSyxFbEJsSUEsT0FBTSxHa0JtSVo7O0FBSEgsQUFLRSxlQUxhLENBS2IsV0FBVyxDQUFDLEVBQ1YsYUFBYSxFQUFFLE1BQTJDLEdBQzNEOztBQUlILEFBQUEsY0FBYyxFQUNkLFdBQVcsRUFDWCxZQUFZLENBQUMsRUFDWCxPQUFPLEVBQUUsS0FBSyxFQUNkLFdBQVcsRWxCMUhDLE1BQU0sRWtCMkhsQixNQUFNLEVBQUUsTUFBc0MsQ0FBQyxDQUFDLEVBQ2hELFVBQVUsRUFBRSxNQUFNLEVBQ2xCLE9BQU8sRUFBRSxNQUF1QyxDbEIvSXpDLE1BQUssQ2tCK0l3RCxNQUF1QyxDQUFDLE1BQXlDLEVBQ3JKLFFBQVEsRUFBRSxRQUFRLEdBcUNuQjs7QUE3Q0QsQUFVRSxjQVZZLENBVVosS0FBSyxFQVRQLFdBQVcsQ0FTVCxLQUFLLEVBUlAsWUFBWSxDQVFWLEtBQUssQ0FBQyxFQUNKLElBQUksRUFBRSxnQkFBZ0IsRUFDdEIsTUFBTSxFQUFFLEdBQUcsRUFDWCxNQUFNLEVBQUUsSUFBSSxFQUNaLFFBQVEsRUFBRSxNQUFNLEVBQ2hCLFFBQVEsRUFBRSxRQUFRLEVBQ2xCLEtBQUssRUFBRSxHQUFHLEdBU1g7O0FBekJILEFBaUJJLGNBakJVLENBVVosS0FBSyxBQU9GLE1BQU0sR0FBRyxVQUFVLEVBaEJ4QixXQUFXLENBU1QsS0FBSyxBQU9GLE1BQU0sR0FBRyxVQUFVLEVBZnhCLFlBQVksQ0FRVixLQUFLLEFBT0YsTUFBTSxHQUFHLFVBQVUsQ0FBQyxFVi9NdkIsVUFBVSxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLE1BQUssQ1JLVCxzQkFBTyxFa0I0TWpCLFlBQVksRWxCNU1GLE9BQU8sR2tCNk1sQjs7QUFwQkwsQUFxQkksY0FyQlUsQ0FVWixLQUFLLEFBV0YsUUFBUSxHQUFHLFVBQVUsRUFwQjFCLFdBQVcsQ0FTVCxLQUFLLEFBV0YsUUFBUSxHQUFHLFVBQVUsRUFuQjFCLFlBQVksQ0FRVixLQUFLLEFBV0YsUUFBUSxHQUFHLFVBQVUsQ0FBQyxFQUNyQixVQUFVLEVsQi9NQSxPQUFPLEVrQmdOakIsWUFBWSxFbEJoTkYsT0FBTyxHa0JpTmxCOztBQXhCTCxBQTJCRSxjQTNCWSxDQTJCWixVQUFVLEVBMUJaLFdBQVcsQ0EwQlQsVUFBVSxFQXpCWixZQUFZLENBeUJWLFVBQVUsQ0FBQyxFUHpOWCxVQUFVLEVBQUUsWUFBWSxFTzJOdEIsTUFBTSxFbEJ4S0QsT0FBTSxDa0J3S1csS0FBSyxDbEJ2TVgsT0FBMEIsRWtCd00xQyxNQUFNLEVBQUUsT0FBTyxFQUNmLE9BQU8sRUFBRSxZQUFZLEVBQ3JCLFFBQVEsRUFBRSxRQUFRLEdBQ25COztBQWpDSCxBQW9DRSxjQXBDWSxBQW9DWCxTQUFTLEVBbkNaLFdBQVcsQUFtQ1IsU0FBUyxFQWxDWixZQUFZLEFBa0NULFNBQVMsQ0FBQyxFQUNULFNBQVMsRWxCN0pFLE1BQUssRWtCOEpoQixNQUFNLEVBQUUsQ0FBQyxHQUNWOztBQXZDSCxBQXlDRSxjQXpDWSxBQXlDWCxTQUFTLEVBeENaLFdBQVcsQUF3Q1IsU0FBUyxFQXZDWixZQUFZLEFBdUNULFNBQVMsQ0FBQyxFQUNULFNBQVMsRWxCaktFLE1BQUssRWtCa0toQixNQUFNLEVBQUUsTUFBeUMsQ0FBQyxDQUFDLEdBQ3BEOztBQUdILEFBRUUsY0FGWSxDQUVaLFVBQVUsRUFEWixXQUFXLENBQ1QsVUFBVSxDQUFDLEVBQ1QsVUFBVSxFbEJsT0EsSUFBSSxFa0JtT2QsTUFBTSxFbEJ2SlUsTUFBSyxFa0J3SnJCLElBQUksRUFBRSxDQUFDLEVBQ1AsR0FBRyxFQUFFLE1BQTJDLEVBQ2hELEtBQUssRWxCMUpXLE1BQUssR2tCMkp0Qjs7QUFSSCxBQVdJLGNBWFUsQ0FVWixLQUFLLEFBQ0YsT0FBTyxHQUFHLFVBQVUsRUFWekIsV0FBVyxDQVNULEtBQUssQUFDRixPQUFPLEdBQUcsVUFBVSxDQUFDLEVBQ3BCLFVBQVUsRWxCbk9BLE9BQXFCLEdrQm9PaEM7O0FBR0wsQUFDRSxjQURZLENBQ1osVUFBVSxDQUFDLEVBQ1QsYUFBYSxFbEIzTVIsTUFBSyxHa0I0TVg7O0FBSEgsQUFPTSxjQVBRLENBS1osS0FBSyxBQUNGLFFBQVEsR0FBRyxVQUFVLEFBQ25CLFFBQVEsQ0FBQyxFQUNSLGVBQWUsRUFBRSxXQUFXLEVBQzVCLE1BQU0sRWxCbE5MLE1BQUssQ2tCa05tQixLQUFLLENsQnhQeEIsSUFBSSxFa0J5UFYsaUJBQWlCLEVBQUUsQ0FBQyxFQUNwQixnQkFBZ0IsRUFBRSxDQUFDLEVBQ25CLE9BQU8sRUFBRSxFQUFFLEVBQ1gsTUFBTSxFQUFFLElBQUksRUFDWixJQUFJLEVBQUUsR0FBRyxFQUNULFdBQVcsRUFBRSxJQUFJLEVBQ2pCLFVBQVUsRUFBRSxJQUFJLEVBQ2hCLFFBQVEsRUFBRSxRQUFRLEVBQ2xCLEdBQUcsRUFBRSxHQUFHLEVBQ1IsU0FBUyxFQUFFLGFBQWEsRUFDeEIsS0FBSyxFQUFFLEdBQUcsR0FDWDs7QUFyQlAsQUF1QkksY0F2QlUsQ0FLWixLQUFLLEFBa0JGLGNBQWMsR0FBRyxVQUFVLENBQUMsRUFDM0IsVUFBVSxFbEJoUkEsT0FBTyxFa0JpUmpCLFlBQVksRWxCalJGLE9BQU8sR2tCNlJsQjs7QUFyQ0wsQUEwQk0sY0ExQlEsQ0FLWixLQUFLLEFBa0JGLGNBQWMsR0FBRyxVQUFVLEFBR3pCLFFBQVEsQ0FBQyxFQUNSLFVBQVUsRWxCMVFKLElBQUksRWtCMlFWLE9BQU8sRUFBRSxFQUFFLEVBQ1gsTUFBTSxFQUFFLEdBQUcsRUFDWCxJQUFJLEVBQUUsR0FBRyxFQUNULFdBQVcsRUFBRSxJQUFJLEVBQ2pCLFVBQVUsRUFBRSxJQUFJLEVBQ2hCLFFBQVEsRUFBRSxRQUFRLEVBQ2xCLEdBQUcsRUFBRSxHQUFHLEVBQ1IsS0FBSyxFQUFFLElBQUksR0FDWjs7QUFJUCxBQUNFLFdBRFMsQ0FDVCxVQUFVLENBQUMsRUFDVCxhQUFhLEVBQUUsR0FBRyxHQUNuQjs7QUFISCxBQU9NLFdBUEssQ0FLVCxLQUFLLEFBQ0YsUUFBUSxHQUFHLFVBQVUsQUFDbkIsUUFBUSxDQUFDLEVBQ1IsVUFBVSxFbEIvUkosSUFBSSxFa0JnU1YsYUFBYSxFQUFFLEdBQUcsRUFDbEIsT0FBTyxFQUFFLEVBQUUsRUFDWCxNQUFNLEVBQUUsR0FBRyxFQUNYLElBQUksRUFBRSxHQUFHLEVBQ1QsUUFBUSxFQUFFLFFBQVEsRUFDbEIsR0FBRyxFQUFFLEdBQUcsRUFDUixTQUFTLEVBQUUscUJBQXFCLEVBQ2hDLEtBQUssRUFBRSxHQUFHLEdBQ1g7O0FBTVAsQUFBQSxZQUFZLENBQUMsRUFDWCxZQUFZLEVBQUUsSUFBOEIsR0FvQzdDOztBQXJDRCxBQUdFLFlBSFUsQ0FHVixVQUFVLENBQUMsRUFDVCxVQUFVLEVsQi9TSyxPQUF5QixFa0JnVHhDLGVBQWUsRUFBRSxXQUFXLEVBQzVCLGFBQWEsRUFBRSxPQUF1QixFQUN0QyxNQUFNLEVBQUUsTUFBMkIsRUFDbkMsSUFBSSxFQUFFLENBQUMsRUFDUCxHQUFHLEVBQUUsT0FBZ0QsRUFDckQsS0FBSyxFbEIxUUEsTUFBTSxHa0J1Ulo7O0FBdkJILEFBV0ksWUFYUSxDQUdWLFVBQVUsQUFRUCxRQUFRLENBQUMsRVB2VVosVUFBVSxFQUFFLFlBQVksRU95VXBCLFVBQVUsRWxCM1RGLElBQUksRWtCNFRaLGFBQWEsRUFBRSxHQUFHLEVBQ2xCLE9BQU8sRUFBRSxFQUFFLEVBQ1gsT0FBTyxFQUFFLEtBQUssRUFDZCxNQUFNLEVsQnJSSCxNQUFLLEVrQnNSUixJQUFJLEVBQUUsQ0FBQyxFQUNQLFFBQVEsRUFBRSxRQUFRLEVBQ2xCLEdBQUcsRUFBRSxDQUFDLEVBQ04sS0FBSyxFbEJ6UkYsTUFBSyxHa0IwUlQ7O0FBdEJMLEFBMkJNLFlBM0JNLENBeUJWLEtBQUssQUFDRixRQUFRLEdBQUcsVUFBVSxBQUNuQixRQUFRLENBQUMsRUFDUixJQUFJLEVBQUUsSUFBSSxHQUNYOztBQTdCUCxBQWdDTSxZQWhDTSxDQXlCVixLQUFLLEFBTUYsT0FBTyxHQUFHLFVBQVUsQUFDbEIsUUFBUSxDQUFDLEVBQ1IsVUFBVSxFbEJ4VVAsT0FBeUIsR2tCeVU3Qjs7QUFNUCxBQUFBLFlBQVksQ0FBQyxFQUNYLE9BQU8sRUFBRSxJQUFJLEdBNERkOztBQTdERCxBQUdFLFlBSFUsQ0FHVixrQkFBa0IsQ0FBQyxFQUNqQixVQUFVLEVsQm5WSCxPQUF5QixFa0JvVmhDLE1BQU0sRWxCdFRELE9BQU0sQ2tCc1RXLEtBQUssQ2xCclZYLE9BQTBCLEVrQnNWMUMsYUFBYSxFbEJ0VFIsTUFBSyxFa0J1VFYsV0FBVyxFbEJuU0QsTUFBTSxFa0JvU2hCLE9BQU8sRWxCclJTLE9BQWtELENBakM3RCxNQUFLLEVrQnVUVixXQUFXLEVBQUUsTUFBTSxHQVdwQjs7QUFwQkgsQUFXSSxZQVhRLENBR1Ysa0JBQWtCLEFBUWYsU0FBUyxDQUFDLEVBQ1QsU0FBUyxFbEIxU0EsTUFBSyxFa0IyU2QsT0FBTyxFbEJ6UlUsT0FBcUQsQ0FIckQsTUFBYSxHa0I2Ui9COztBQWRMLEFBZ0JJLFlBaEJRLENBR1Ysa0JBQWtCLEFBYWYsU0FBUyxDQUFDLEVBQ1QsU0FBUyxFbEI5U0EsTUFBSyxFa0IrU2QsT0FBTyxFbEI3UlUsT0FBcUQsQ0FIckQsTUFBYSxHa0JpUy9COztBQW5CTCxBQXNCRSxZQXRCVSxDQXNCVixXQUFXLEVBdEJiLFlBQVksQ0F1QlYsWUFBWSxDQUFDLEVBQ1gsSUFBSSxFQUFFLFFBQVEsRUFDZCxLQUFLLEVBQUUsRUFBRSxHQUNWOztBQTFCSCxBQTRCRSxZQTVCVSxDQTRCVixnQkFBZ0IsQ0FBQyxFQUNmLE9BQU8sRWxCcFJBLENBQUMsR2tCcVJUOztBQTlCSCxBQW9DSSxZQXBDUSxDQWdDVixXQUFXLEFBSVIsWUFBWSxBQUFBLElBQUssQ0RwT0EsV0FBVyxHQ2dNakMsWUFBWSxDQWlDVixZQUFZLEFBR1QsWUFBWSxBQUFBLElBQUssQ0RwT0EsV0FBVyxHQ2dNakMsWUFBWSxDQWtDVixrQkFBa0IsQUFFZixZQUFZLEFBQUEsSUFBSyxDRHBPQSxXQUFXLEdDZ01qQyxZQUFZLENBbUNWLGdCQUFnQixBQUNiLFlBQVksQUFBQSxJQUFLLENEcE9BLFdBQVcsRUNvT0UsRUFDN0IsMEJBQTBCLEVBQUUsQ0FBQyxFQUM3Qix1QkFBdUIsRUFBRSxDQUFDLEdBQzNCOztBQXZDTCxBQXdDSSxZQXhDUSxDQWdDVixXQUFXLEFBUVIsSUFBSyxDRHBPQSxZQUFZLENDb09DLElBQUssQ0R4T04sV0FBVyxHQ2dNakMsWUFBWSxDQWlDVixZQUFZLEFBT1QsSUFBSyxDRHBPQSxZQUFZLENDb09DLElBQUssQ0R4T04sV0FBVyxHQ2dNakMsWUFBWSxDQWtDVixrQkFBa0IsQUFNZixJQUFLLENEcE9BLFlBQVksQ0NvT0MsSUFBSyxDRHhPTixXQUFXLEdDZ01qQyxZQUFZLENBbUNWLGdCQUFnQixBQUtiLElBQUssQ0RwT0EsWUFBWSxDQ29PQyxJQUFLLENEeE9OLFdBQVcsRUN3T1EsRUFDbkMsYUFBYSxFQUFFLENBQUMsRUFDaEIsV0FBVyxFbEIzVlIsUUFBTSxHa0I0VlY7O0FBM0NMLEFBNENJLFlBNUNRLENBZ0NWLFdBQVcsQUFZUixXQUFXLEFBQUEsSUFBSyxDRHhPWCxZQUFZLEdDNEx0QixZQUFZLENBaUNWLFlBQVksQUFXVCxXQUFXLEFBQUEsSUFBSyxDRHhPWCxZQUFZLEdDNEx0QixZQUFZLENBa0NWLGtCQUFrQixBQVVmLFdBQVcsQUFBQSxJQUFLLENEeE9YLFlBQVksR0M0THRCLFlBQVksQ0FtQ1YsZ0JBQWdCLEFBU2IsV0FBVyxBQUFBLElBQUssQ0R4T1gsWUFBWSxFQ3dPYSxFQUM3Qix5QkFBeUIsRUFBRSxDQUFDLEVBQzVCLHNCQUFzQixFQUFFLENBQUMsRUFDekIsV0FBVyxFbEJoV1IsUUFBTSxHa0JpV1Y7O0FBaERMLEFBaURJLFlBakRRLENBZ0NWLFdBQVcsQUFpQlIsTUFBTSxFQWpEWCxZQUFZLENBaUNWLFlBQVksQUFnQlQsTUFBTSxFQWpEWCxZQUFZLENBa0NWLGtCQUFrQixBQWVmLE1BQU0sRUFqRFgsWUFBWSxDQW1DVixnQkFBZ0IsQUFjYixNQUFNLENBQUMsRUFDTixPQUFPLEVsQnpTRixDQUFDLEdrQjBTUDs7QUFuREwsQUFzREUsWUF0RFUsQ0FzRFYsWUFBWSxDQUFDLEVBQ1gsS0FBSyxFQUFFLElBQUksR0FDWjs7QUF4REgsQUEwREUsWUExRFUsQUEwRFQsYUFBYSxDQUFDLEVBQ2IsT0FBTyxFQUFFLFdBQVcsR0FDckI7O0FBTUQsQUFBQSxZQUFZLENBRmQsV0FBVyxFQUFYLFdBQVcsQUFHUixXQUFXLEVBRFosWUFBWSxDQURkLFlBQVksRUFBWixZQUFZLEFBRVQsV0FBVyxDQUFDLEVBQ1gsWUFBWSxFbEI5WUEsT0FBTyxHa0JrWnBCOztBQU5ELEFBR0UsWUFIVSxDQUZkLFdBQVcsQUFLTixNQUFNLEVBTFgsV0FBVyxBQUdSLFdBQVcsQUFFVCxNQUFNLEVBSFQsWUFBWSxDQURkLFlBQVksQUFJUCxNQUFNLEVBSlgsWUFBWSxBQUVULFdBQVcsQUFFVCxNQUFNLENBQUMsRVZ6YVYsVUFBVSxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLE1BQUssQ1IwQlQsc0JBQU8sR2tCaVpsQjs7QUFHSCxBQUFBLFVBQVUsQ0FWWixXQUFXLEVBQVgsV0FBVyxBQVdSLFNBQVMsRUFEVixVQUFVLENBVFosWUFBWSxFQUFaLFlBQVksQUFVVCxTQUFTLENBQUMsRUFDVCxZQUFZLEVsQnBaRixPQUFPLEdrQndabEI7O0FBTkQsQUFHRSxVQUhRLENBVlosV0FBVyxBQWFOLE1BQU0sRUFiWCxXQUFXLEFBV1IsU0FBUyxBQUVQLE1BQU0sRUFIVCxVQUFVLENBVFosWUFBWSxBQVlQLE1BQU0sRUFaWCxZQUFZLEFBVVQsU0FBUyxBQUVQLE1BQU0sQ0FBQyxFVmpiVixVQUFVLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBSyxDUjRCWCxzQkFBTyxHa0J1WmhCOztBQU9ILEFBRUUsVUFGUSxDQUhaLGNBQWMsQ0FLVixVQUFVLEVBTGQsY0FBYyxBQUlYLFNBQVMsQ0FDUixVQUFVLEVBRlosVUFBVSxDQUZaLFdBQVcsQ0FJUCxVQUFVLEVBSmQsV0FBVyxBQUdSLFNBQVMsQ0FDUixVQUFVLEVBRlosVUFBVSxDQURaLFlBQVksQ0FHUixVQUFVLEVBSGQsWUFBWSxBQUVULFNBQVMsQ0FDUixVQUFVLENBQUMsRUFDVCxZQUFZLEVsQmphSixPQUFPLEdrQmthaEI7O0FBSkgsQUFPSSxVQVBNLENBSFosY0FBYyxDQVNWLEtBQUssQUFDRixRQUFRLEdBQUcsVUFBVSxFQVY1QixjQUFjLEFBSVgsU0FBUyxDQUtSLEtBQUssQUFDRixRQUFRLEdBQUcsVUFBVSxFQVAxQixVQUFVLENBRlosV0FBVyxDQVFQLEtBQUssQUFDRixRQUFRLEdBQUcsVUFBVSxFQVQ1QixXQUFXLEFBR1IsU0FBUyxDQUtSLEtBQUssQUFDRixRQUFRLEdBQUcsVUFBVSxFQVAxQixVQUFVLENBRFosWUFBWSxDQU9SLEtBQUssQUFDRixRQUFRLEdBQUcsVUFBVSxFQVI1QixZQUFZLEFBRVQsU0FBUyxDQUtSLEtBQUssQUFDRixRQUFRLEdBQUcsVUFBVSxDQUFDLEVBQ3JCLFVBQVUsRWxCdGFKLE9BQU8sRWtCdWFiLFlBQVksRWxCdmFOLE9BQU8sR2tCd2FkOztBQVZMLEFBWUksVUFaTSxDQUhaLGNBQWMsQ0FTVixLQUFLLEFBTUYsTUFBTSxHQUFHLFVBQVUsRUFmMUIsY0FBYyxBQUlYLFNBQVMsQ0FLUixLQUFLLEFBTUYsTUFBTSxHQUFHLFVBQVUsRUFaeEIsVUFBVSxDQUZaLFdBQVcsQ0FRUCxLQUFLLEFBTUYsTUFBTSxHQUFHLFVBQVUsRUFkMUIsV0FBVyxBQUdSLFNBQVMsQ0FLUixLQUFLLEFBTUYsTUFBTSxHQUFHLFVBQVUsRUFaeEIsVUFBVSxDQURaLFlBQVksQ0FPUixLQUFLLEFBTUYsTUFBTSxHQUFHLFVBQVUsRUFiMUIsWUFBWSxBQUVULFNBQVMsQ0FLUixLQUFLLEFBTUYsTUFBTSxHQUFHLFVBQVUsQ0FBQyxFVnRjekIsVUFBVSxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLE1BQUssQ1I0Qlgsc0JBQU8sRWtCNGFiLFlBQVksRWxCNWFOLE9BQU8sR2tCNmFkOztBQU1MLEFBR0ksVUFITSxDQURaLGNBQWMsQ0FHVixLQUFLLEFBQ0YsY0FBYyxHQUFHLFVBQVUsRUFKbEMsY0FBYyxBQUVYLFNBQVMsQ0FDUixLQUFLLEFBQ0YsY0FBYyxHQUFHLFVBQVUsQ0FBQyxFQUMzQixVQUFVLEVsQnZiSixPQUFPLEVrQndiYixZQUFZLEVsQnhiTixPQUFPLEdrQnliZDs7QUFNUCxBQUVJLFdBRk8sQUFDUixJQUFLLENBQUEsa0JBQWtCLENBQ3JCLFFBQVEsQ0FBQyxFQUNSLFlBQVksRWxCbGNKLE9BQU8sR2tCMGNoQjs7QUFYTCxBQUlNLFdBSkssQUFDUixJQUFLLENBQUEsa0JBQWtCLENBQ3JCLFFBQVEsQUFFTixNQUFNLENBQUMsRVYvZFosVUFBVSxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLE1BQUssQ1I0Qlgsc0JBQU8sR2tCcWNkOztBQU5QLEFBUU0sV0FSSyxBQUNSLElBQUssQ0FBQSxrQkFBa0IsQ0FDckIsUUFBUSxHQU1ILGdCQUFnQixDQUFDLEVBQ25CLEtBQUssRWxCeGNDLE9BQU8sR2tCeWNkOztBQU1QLEFBRUUsV0FGUyxBQUVSLFNBQVMsRUFGWixXQUFXLEFBR1IsU0FBUyxFQUZaLFlBQVksQUFDVCxTQUFTLEVBRFosWUFBWSxBQUVULFNBQVMsQ0FBQyxFQUNULGdCQUFnQixFbEJ6ZEosT0FBcUIsRWtCMGRqQyxNQUFNLEVBQUUsV0FBVyxFQUNuQixPQUFPLEVBQUUsRUFBRSxHQUNaOztBQUdILEFBQ0UsV0FEUyxDQUNSLEFBQUEsUUFBQyxBQUFBLEVBQVUsRUFDVixnQkFBZ0IsRWxCbGVULE9BQXlCLEdrQm1lakM7O0FBR0gsQUFHSSxLQUhDLEFBQ0YsU0FBUyxHQUVKLFVBQVUsRUFIbEIsS0FBSyxBQUVGLFNBQVMsR0FDSixVQUFVLENBQUMsRUFDYixVQUFVLEVsQnplQSxPQUFxQixFa0IwZS9CLE1BQU0sRUFBRSxXQUFXLEVBQ25CLE9BQU8sRUFBRSxFQUFFLEdBQ1o7O0FBSUwsQUFJTSxZQUpNLENBQ1YsS0FBSyxBQUNGLFNBQVMsR0FFSixVQUFVLEFBQUEsUUFBUSxFQUo1QixZQUFZLENBQ1YsS0FBSyxBQUVGLFNBQVMsR0FDSixVQUFVLEFBQUEsUUFBUSxDQUFDLEVBQ3JCLFVBQVUsRWxCN2ZKLElBQUksR2tCOGZYOztBQU1QLEFBQUEsZ0JBQWdCLENBQUMsRUFDZixPQUFPLEVsQjdkQSxNQUFLLENrQjZkYSxDQUFDLEdBTTNCOztBQVBELEFBR0UsZ0JBSGMsQ0FHZCxXQUFXLENBQUMsRUFDVixPQUFPLEVBQUUsSUFBSSxFQUNiLFNBQVMsRUFBRSxJQUFJLEdBQ2hCOztBQUlILEFBQUEsWUFBWSxDQUFDLEVBQ1gsT0FBTyxFQUFFLFlBQVksR0FDdEI7O0FDL2hCRCxBQUFBLE1BQU0sQ0FBQyxFYkNMLGFBQWEsRU5vRE4sTUFBSyxFTW5EWixXQUFXLEVBQUUsR0FBRyxFQUNoQixPQUFPLEVBQUUsV0FBVyxFQUlwQixVQUFVLEVOZ0JJLE9BQXFCLEVNZm5DLEtBQUssRWFOa0IsT0FBNkIsRUFDcEQsT0FBTyxFQUFFLFlBQVksR0E2QnRCOztBQWhDRCxBQU1FLE1BTkksQUFNSCxjQUFjLENBQUMsRUFDZCxhQUFhLEVBQUUsSUFBSSxFQUNuQixZQUFZLEVBQUUsS0FBSyxFQUNuQixhQUFhLEVBQUUsS0FBSyxHQUNyQjs7QUFWSCxBQWFFLE1BYkksQUFhSCxjQUFjLENBQUMsRWJOaEIsVUFBVSxFTkRJLE9BQU8sRU1FckIsS0FBSyxFTk9PLElBQUksR21CQWY7O0FBZkgsQUFpQkUsTUFqQkksQUFpQkgsZ0JBQWdCLENBQUMsRWJWbEIsVUFBVSxFTkVNLE9BQThCLEVNRDlDLEtBQUssRU5GUyxPQUFPLEdtQmFwQjs7QUFuQkgsQUFxQkUsTUFyQkksQUFxQkgsY0FBYyxDQUFDLEViZGhCLFVBQVUsRU5vQkksT0FBTyxFTW5CckIsS0FBSyxFTk9PLElBQUksR21CUWY7O0FBdkJILEFBeUJFLE1BekJJLEFBeUJILGNBQWMsQ0FBQyxFYmxCaEIsVUFBVSxFTnFCSSxPQUFPLEVNcEJyQixLQUFLLEVOT08sSUFBSSxHbUJZZjs7QUEzQkgsQUE2QkUsTUE3QkksQUE2QkgsWUFBWSxDQUFDLEVidEJkLFVBQVUsRU5zQkUsT0FBTyxFTXJCbkIsS0FBSyxFTk9PLElBQUksR21CZ0JmOztBQy9CSCxBQUFBLElBQUksQ0FBQyxFZENILGFBQWEsRU5vRE4sTUFBSyxFTW5EWixXQUFXLEVBQUUsR0FBRyxFQUNoQixPQUFPLEVBQUUsV0FBVyxFQUlwQixVQUFVLEVjTDBCLE9BQTJCLEVkTS9ELEtBQUssRU53Qk0sT0FBTyxFb0I3QmxCLFNBQVMsRUFBRSxHQUFHLEdBQ2Y7O0FBRUQsQUFBQSxLQUFLLENBQUMsRUFDSixhQUFhLEVwQjhDTixNQUFLLEVvQjdDWixLQUFLLEVwQjJCVyxPQUF3QixFb0IxQnhDLFFBQVEsRUFBRSxRQUFRLEdBb0JuQjs7QUF2QkQsQUFLRSxLQUxHLEFBS0YsUUFBUSxDQUFDLEVBQ1IsS0FBSyxFcEJJSSxPQUF5QixFb0JIbEMsT0FBTyxFQUFFLGVBQWUsRUFDeEIsU0FBUyxFcEJ5REUsTUFBSyxFb0J4RGhCLFFBQVEsRUFBRSxRQUFRLEVBQ2xCLEtBQUssRXBCdUNBLE1BQUssRW9CdENWLEdBQUcsRXBCb0NFLE1BQUssR29CbkNYOztBQVpILEFBY0UsS0FkRyxDQWNILElBQUksQ0FBQyxFQUNILFVBQVUsRXBCQ0gsT0FBeUIsRW9CQWhDLEtBQUssRUFBRSxPQUFPLEVBQ2QsT0FBTyxFQUFFLEtBQUssRUFDZCxXQUFXLEVBQUUsR0FBRyxFQUNoQixVQUFVLEVBQUUsSUFBSSxFQUNoQixPQUFPLEVBQUUsSUFBSSxFQUNiLEtBQUssRUFBRSxJQUFJLEdBQ1o7O0FDM0JILEFBQUEsZUFBZSxDQUFDLEVBQ2QsT0FBTyxFQUFFLEtBQUssRUFDZCxNQUFNLEVBQUUsSUFBSSxFQUNaLFNBQVMsRUFBRSxJQUFJLEdBQ2hCOztBQUlELEFBQUEsY0FBYyxDQUFDLEVBQ2IsVUFBVSxFQUFFLEtBQUssR0FDbEI7O0FBRUQsQUFBQSxnQkFBZ0IsQ0FBQyxFQUNmLFVBQVUsRUFBRSxPQUFPLEdBQ3BCOztBQUdELEFBQUEsaUJBQWlCLENBQUMsRUFDaEIsT0FBTyxFQUFFLEtBQUssRUFDZCxRQUFRLEVBQUUsTUFBTSxFQUNoQixPQUFPLEVBQUUsQ0FBQyxFQUNWLFFBQVEsRUFBRSxRQUFRLEVBQ2xCLEtBQUssRUFBRSxJQUFJLEdBbUJaOztBQXhCRCxBQU1FLGlCQU5lLEFBTWQsUUFBUSxDQUFDLEVBQ1IsT0FBTyxFQUFFLEVBQUUsRUFDWCxPQUFPLEVBQUUsS0FBSyxFQUNkLGNBQWMsRUFBRSxNQUFNLEdBQ3ZCOztBQVZILEFBWUUsaUJBWmUsQ0FZZixNQUFNLEVBWlIsaUJBQWlCLENBYWYsTUFBTSxFQWJSLGlCQUFpQixDQWNmLEtBQUssQ0FBQyxFQUNKLE1BQU0sRUFBRSxDQUFDLEVBQ1QsTUFBTSxFQUFFLENBQUMsRUFDVCxNQUFNLEVBQUUsSUFBSSxFQUNaLElBQUksRUFBRSxDQUFDLEVBQ1AsUUFBUSxFQUFFLFFBQVEsRUFDbEIsS0FBSyxFQUFFLENBQUMsRUFDUixHQUFHLEVBQUUsQ0FBQyxFQUNOLEtBQUssRUFBRSxJQUFJLEdBQ1o7O0FBR0gsQUFBQSxLQUFLLEFBQUEsaUJBQWlCLENBQUMsRUFDckIsTUFBTSxFQUFFLElBQUksRUFDWixTQUFTLEVBQUUsSUFBSSxHQUtoQjs7QUFQRCxBQUlFLEtBSkcsQUFBQSxpQkFBaUIsQUFJbkIsUUFBUSxDQUFDLEVBQ1IsT0FBTyxFQUFFLElBQUksR0FDZDs7QUFHSCxBQUNFLHFCQURtQixBQUNsQixRQUFRLENBQUMsRUFDUixjQUFjLEVBQUUsR0FBRyxHQUNwQjs7QUFHSCxBQUNFLHFCQURtQixBQUNsQixRQUFRLENBQUMsRUFDUixjQUFjLEVBQUUsSUFBSSxHQUNyQjs7QUFJSCxBQUFBLE9BQU8sQ0FBQyxFQUNOLE1BQU0sRUFBRSxDQUFDLENBQUMsQ0FBQyxDckJaSixNQUFLLENxQllnQixDQUFDLEdBTTlCOztBQVBELEFBR0UsT0FISyxDQUdMLGVBQWUsQ0FBQyxFQUNkLEtBQUssRXJCckRTLE9BQXdCLEVxQnNEdEMsVUFBVSxFckJoQkwsTUFBSyxHcUJpQlg7O0FDeEVILEFBQUEsVUFBVSxDQUFDLEVBQ1QsV0FBVyxFQUFFLElBQUksRUFDakIsWUFBWSxFQUFFLElBQUksRUFDbEIsWUFBWSxFdEJvREwsTUFBSyxFc0JuRFosYUFBYSxFdEJtRE4sTUFBSyxFc0JsRFosS0FBSyxFQUFFLElBQUksR0F3Qlo7O0FBN0JELEFBVUUsVUFWUSxBQVVQLFFBQVEsQ0FBQyxFQUNSLFNBQVMsRUFBRSxNQUE0QixHQUN4Qzs7QUFaSCxBQWNFLFVBZFEsQUFjUCxRQUFRLENBQUMsRUFDUixTQUFTLEVBQUUsS0FBNEIsR0FDeEM7O0FBaEJILEFBa0JFLFVBbEJRLEFBa0JQLFFBQVEsQ0FBQyxFQUNSLFNBQVMsRUFBRSxLQUE0QixHQUN4Qzs7QUFwQkgsQUFzQkUsVUF0QlEsQUFzQlAsUUFBUSxDQUFDLEVBQ1IsU0FBUyxFQUFFLEtBQTRCLEdBQ3hDOztBQXhCSCxBQTBCRSxVQTFCUSxBQTBCUCxRQUFRLENBQUMsRUFDUixTQUFTLEVBQUUsS0FBNEIsR0FDeEM7O0FBSUgsQUFBQSxRQUFRLEVBQ1IsUUFBUSxFQUNSLFFBQVEsRUFDUixRQUFRLEVBQ1IsUUFBUSxDQUFDLEVBQ1AsT0FBTyxFQUFFLGVBQWUsR0FDekI7O0FBR0QsQUFBQSxRQUFRLENBQUMsRUFDUCxPQUFPLEVBQUUsSUFBSSxFQUNiLFNBQVMsRUFBRSxJQUFJLEVBQ2YsV0FBVyxFdEJXSixPQUFLLEVzQlZaLFlBQVksRXRCVUwsT0FBSyxHc0JLYjs7QUFuQkQsQUFNRSxRQU5NLEFBTUwsWUFBWSxDQUFDLEVBQ1osV0FBVyxFQUFFLENBQUMsRUFDZCxZQUFZLEVBQUUsQ0FBQyxHQU1oQjs7QUFkSCxBQVVJLFFBVkksQUFNTCxZQUFZLEdBSVAsT0FBTyxDQUFDLEVBQ1YsWUFBWSxFQUFFLENBQUMsRUFDZixhQUFhLEVBQUUsQ0FBQyxHQUNqQjs7QUFiTCxBQWVFLFFBZk0sQUFlTCxZQUFZLENBQUMsRUFDWixTQUFTLEVBQUUsTUFBTSxFQUNqQixVQUFVLEVBQUUsSUFBSSxHQUNqQjs7QUFFSCxBQUFBLE9BQU8sQ0FBQyxFQUNOLElBQUksRUFBRSxDQUFDLEVBQ1AsU0FBUyxFQUFFLElBQUksRUFDZixZQUFZLEV0QlRMLE1BQUssRXNCVVosYUFBYSxFdEJWTixNQUFLLEdzQjBCYjs7QUFwQkQsQUFNRSxPQU5LLEFBTUosT0FBTyxFQU5WLE9BQU8sQUFPSixPQUFPLEVBUFYsT0FBTyxBQVFKLE9BQU8sRUFSVixPQUFPLEFBU0osTUFBTSxFQVRULE9BQU8sQUFVSixNQUFNLEVBVlQsT0FBTyxBQVdKLE1BQU0sRUFYVCxPQUFPLEFBWUosTUFBTSxFQVpULE9BQU8sQUFhSixNQUFNLEVBYlQsT0FBTyxBQWNKLE1BQU0sRUFkVCxPQUFPLEFBZUosTUFBTSxFQWZULE9BQU8sQUFnQkosTUFBTSxFQWhCVCxPQUFPLEFBaUJKLE1BQU0sQ0FBQyxFQUNOLElBQUksRUFBRSxJQUFJLEdBQ1g7O0FBRUgsQUFBQSxPQUFPLENBQUMsRUFDTixLQUFLLEVBQUUsSUFBSSxHQUNaOztBQUNELEFBQUEsT0FBTyxDQUFDLEVBQ04sS0FBSyxFQUFFLFlBQVksR0FDcEI7O0FBQ0QsQUFBQSxPQUFPLENBQUMsRUFDTixLQUFLLEVBQUUsWUFBWSxHQUNwQjs7QUFDRCxBQUFBLE1BQU0sQ0FBQyxFQUNMLEtBQUssRUFBRSxHQUFHLEdBQ1g7O0FBQ0QsQUFBQSxNQUFNLENBQUMsRUFDTCxLQUFLLEVBQUUsWUFBWSxHQUNwQjs7QUFDRCxBQUFBLE1BQU0sQ0FBQyxFQUNMLEtBQUssRUFBRSxZQUFZLEdBQ3BCOztBQUNELEFBQUEsTUFBTSxDQUFDLEVBQ0wsS0FBSyxFQUFFLEdBQUcsR0FDWDs7QUFDRCxBQUFBLE1BQU0sQ0FBQyxFQUNMLEtBQUssRUFBRSxZQUFZLEdBQ3BCOztBQUNELEFBQUEsTUFBTSxDQUFDLEVBQ0wsS0FBSyxFQUFFLFlBQVksR0FDcEI7O0FBQ0QsQUFBQSxNQUFNLENBQUMsRUFDTCxLQUFLLEVBQUUsR0FBRyxHQUNYOztBQUNELEFBQUEsTUFBTSxDQUFDLEVBQ0wsS0FBSyxFQUFFLFlBQVksR0FDcEI7O0FBQ0QsQUFBQSxNQUFNLENBQUMsRUFDTCxLQUFLLEVBQUUsV0FBVyxHQUNuQjs7QUFDRCxBQUFBLFNBQVMsQ0FBQyxFQUNSLElBQUksRUFBRSxRQUFRLEVBQ2QsU0FBUyxFQUFFLElBQUksRUFDZixLQUFLLEVBQUUsSUFBSSxHQUNaOztBQUNELEFBQUEsWUFBWSxDQUFDLEVBQ1gsV0FBVyxFQUFFLElBQUksRUFDakIsWUFBWSxFQUFFLElBQUksR0FDbkI7O0FBQ0QsQUFBQSxZQUFZLENBQUMsRUFDWCxXQUFXLEVBQUUsSUFBSSxHQUNsQjs7QUFDRCxBQUFBLFlBQVksQ0FBQyxFQUNYLFlBQVksRUFBRSxJQUFJLEdBQ25COztBQUNELE1BQU0sRUFBRSxTQUFTLEVBQUUsTUFBTSxJQUN2QixBQUFBLFVBQVUsRUFDVixVQUFVLEVBQ1YsVUFBVSxFQUNWLFNBQVMsRUFDVCxTQUFTLEVBQ1QsU0FBUyxFQUNULFNBQVMsRUFDVCxTQUFTLEVBQ1QsU0FBUyxFQUNULFNBQVMsRUFDVCxTQUFTLEVBQ1QsU0FBUyxDQUFDLEVBQ1IsSUFBSSxFQUFFLElBQUksR0FDWDtFQUNELEFBQUEsVUFBVSxDQUFDLEVBQ1QsS0FBSyxFQUFFLElBQUksR0FDWjtFQUNELEFBQUEsVUFBVSxDQUFDLEVBQ1QsS0FBSyxFQUFFLFlBQVksR0FDcEI7RUFDRCxBQUFBLFVBQVUsQ0FBQyxFQUNULEtBQUssRUFBRSxZQUFZLEdBQ3BCO0VBQ0QsQUFBQSxTQUFTLENBQUMsRUFDUixLQUFLLEVBQUUsR0FBRyxHQUNYO0VBQ0QsQUFBQSxTQUFTLENBQUMsRUFDUixLQUFLLEVBQUUsWUFBWSxHQUNwQjtFQUNELEFBQUEsU0FBUyxDQUFDLEVBQ1IsS0FBSyxFQUFFLFlBQVksR0FDcEI7RUFDRCxBQUFBLFNBQVMsQ0FBQyxFQUNSLEtBQUssRUFBRSxHQUFHLEdBQ1g7RUFDRCxBQUFBLFNBQVMsQ0FBQyxFQUNSLEtBQUssRUFBRSxZQUFZLEdBQ3BCO0VBQ0QsQUFBQSxTQUFTLENBQUMsRUFDUixLQUFLLEVBQUUsWUFBWSxHQUNwQjtFQUNELEFBQUEsU0FBUyxDQUFDLEVBQ1IsS0FBSyxFQUFFLEdBQUcsR0FDWDtFQUNELEFBQUEsU0FBUyxDQUFDLEVBQ1IsS0FBSyxFQUFFLFlBQVksR0FDcEI7RUFDRCxBQUFBLFNBQVMsQ0FBQyxFQUNSLEtBQUssRUFBRSxXQUFXLEdBQ25CO0VBQ0QsQUFBQSxRQUFRLENBQUMsRUFDUCxPQUFPLEVBQUUsZUFBZSxHQUN6QjtFQUNELEFBQUEsUUFBUSxDQUFDLEVBQ1AsT0FBTyxFQUFFLGdCQUFnQixHQUMxQjs7QUFFSCxNQUFNLEVBQUUsU0FBUyxFQUFFLEtBQUssSUFDdEIsQUFBQSxVQUFVLEVBQ1YsVUFBVSxFQUNWLFVBQVUsRUFDVixTQUFTLEVBQ1QsU0FBUyxFQUNULFNBQVMsRUFDVCxTQUFTLEVBQ1QsU0FBUyxFQUNULFNBQVMsRUFDVCxTQUFTLEVBQ1QsU0FBUyxFQUNULFNBQVMsQ0FBQyxFQUNSLElBQUksRUFBRSxJQUFJLEdBQ1g7RUFDRCxBQUFBLFVBQVUsQ0FBQyxFQUNULEtBQUssRUFBRSxJQUFJLEdBQ1o7RUFDRCxBQUFBLFVBQVUsQ0FBQyxFQUNULEtBQUssRUFBRSxZQUFZLEdBQ3BCO0VBQ0QsQUFBQSxVQUFVLENBQUMsRUFDVCxLQUFLLEVBQUUsWUFBWSxHQUNwQjtFQUNELEFBQUEsU0FBUyxDQUFDLEVBQ1IsS0FBSyxFQUFFLEdBQUcsR0FDWDtFQUNELEFBQUEsU0FBUyxDQUFDLEVBQ1IsS0FBSyxFQUFFLFlBQVksR0FDcEI7RUFDRCxBQUFBLFNBQVMsQ0FBQyxFQUNSLEtBQUssRUFBRSxZQUFZLEdBQ3BCO0VBQ0QsQUFBQSxTQUFTLENBQUMsRUFDUixLQUFLLEVBQUUsR0FBRyxHQUNYO0VBQ0QsQUFBQSxTQUFTLENBQUMsRUFDUixLQUFLLEVBQUUsWUFBWSxHQUNwQjtFQUNELEFBQUEsU0FBUyxDQUFDLEVBQ1IsS0FBSyxFQUFFLFlBQVksR0FDcEI7RUFDRCxBQUFBLFNBQVMsQ0FBQyxFQUNSLEtBQUssRUFBRSxHQUFHLEdBQ1g7RUFDRCxBQUFBLFNBQVMsQ0FBQyxFQUNSLEtBQUssRUFBRSxZQUFZLEdBQ3BCO0VBQ0QsQUFBQSxTQUFTLENBQUMsRUFDUixLQUFLLEVBQUUsV0FBVyxHQUNuQjtFQUNELEFBQUEsUUFBUSxDQUFDLEVBQ1AsT0FBTyxFQUFFLGVBQWUsR0FDekI7RUFDRCxBQUFBLFFBQVEsQ0FBQyxFQUNQLE9BQU8sRUFBRSxnQkFBZ0IsR0FDMUI7O0FBRUgsTUFBTSxFQUFFLFNBQVMsRUFBRSxLQUFLLElBQ3RCLEFBQUEsVUFBVSxFQUNWLFVBQVUsRUFDVixVQUFVLEVBQ1YsU0FBUyxFQUNULFNBQVMsRUFDVCxTQUFTLEVBQ1QsU0FBUyxFQUNULFNBQVMsRUFDVCxTQUFTLEVBQ1QsU0FBUyxFQUNULFNBQVMsRUFDVCxTQUFTLENBQUMsRUFDUixJQUFJLEVBQUUsSUFBSSxHQUNYO0VBQ0QsQUFBQSxVQUFVLENBQUMsRUFDVCxLQUFLLEVBQUUsSUFBSSxHQUNaO0VBQ0QsQUFBQSxVQUFVLENBQUMsRUFDVCxLQUFLLEVBQUUsWUFBWSxHQUNwQjtFQUNELEFBQUEsVUFBVSxDQUFDLEVBQ1QsS0FBSyxFQUFFLFlBQVksR0FDcEI7RUFDRCxBQUFBLFNBQVMsQ0FBQyxFQUNSLEtBQUssRUFBRSxHQUFHLEdBQ1g7RUFDRCxBQUFBLFNBQVMsQ0FBQyxFQUNSLEtBQUssRUFBRSxZQUFZLEdBQ3BCO0VBQ0QsQUFBQSxTQUFTLENBQUMsRUFDUixLQUFLLEVBQUUsWUFBWSxHQUNwQjtFQUNELEFBQUEsU0FBUyxDQUFDLEVBQ1IsS0FBSyxFQUFFLEdBQUcsR0FDWDtFQUNELEFBQUEsU0FBUyxDQUFDLEVBQ1IsS0FBSyxFQUFFLFlBQVksR0FDcEI7RUFDRCxBQUFBLFNBQVMsQ0FBQyxFQUNSLEtBQUssRUFBRSxZQUFZLEdBQ3BCO0VBQ0QsQUFBQSxTQUFTLENBQUMsRUFDUixLQUFLLEVBQUUsR0FBRyxHQUNYO0VBQ0QsQUFBQSxTQUFTLENBQUMsRUFDUixLQUFLLEVBQUUsWUFBWSxHQUNwQjtFQUNELEFBQUEsU0FBUyxDQUFDLEVBQ1IsS0FBSyxFQUFFLFdBQVcsR0FDbkI7RUFDRCxBQUFBLFFBQVEsQ0FBQyxFQUNQLE9BQU8sRUFBRSxlQUFlLEdBQ3pCO0VBQ0QsQUFBQSxRQUFRLENBQUMsRUFDUCxPQUFPLEVBQUUsZ0JBQWdCLEdBQzFCOztBQUVILE1BQU0sRUFBRSxTQUFTLEVBQUUsS0FBSyxJQUN0QixBQUFBLFVBQVUsRUFDVixVQUFVLEVBQ1YsVUFBVSxFQUNWLFNBQVMsRUFDVCxTQUFTLEVBQ1QsU0FBUyxFQUNULFNBQVMsRUFDVCxTQUFTLEVBQ1QsU0FBUyxFQUNULFNBQVMsRUFDVCxTQUFTLEVBQ1QsU0FBUyxDQUFDLEVBQ1IsSUFBSSxFQUFFLElBQUksR0FDWDtFQUNELEFBQUEsVUFBVSxDQUFDLEVBQ1QsS0FBSyxFQUFFLElBQUksR0FDWjtFQUNELEFBQUEsVUFBVSxDQUFDLEVBQ1QsS0FBSyxFQUFFLFlBQVksR0FDcEI7RUFDRCxBQUFBLFVBQVUsQ0FBQyxFQUNULEtBQUssRUFBRSxZQUFZLEdBQ3BCO0VBQ0QsQUFBQSxTQUFTLENBQUMsRUFDUixLQUFLLEVBQUUsR0FBRyxHQUNYO0VBQ0QsQUFBQSxTQUFTLENBQUMsRUFDUixLQUFLLEVBQUUsWUFBWSxHQUNwQjtFQUNELEFBQUEsU0FBUyxDQUFDLEVBQ1IsS0FBSyxFQUFFLFlBQVksR0FDcEI7RUFDRCxBQUFBLFNBQVMsQ0FBQyxFQUNSLEtBQUssRUFBRSxHQUFHLEdBQ1g7RUFDRCxBQUFBLFNBQVMsQ0FBQyxFQUNSLEtBQUssRUFBRSxZQUFZLEdBQ3BCO0VBQ0QsQUFBQSxTQUFTLENBQUMsRUFDUixLQUFLLEVBQUUsWUFBWSxHQUNwQjtFQUNELEFBQUEsU0FBUyxDQUFDLEVBQ1IsS0FBSyxFQUFFLEdBQUcsR0FDWDtFQUNELEFBQUEsU0FBUyxDQUFDLEVBQ1IsS0FBSyxFQUFFLFlBQVksR0FDcEI7RUFDRCxBQUFBLFNBQVMsQ0FBQyxFQUNSLEtBQUssRUFBRSxXQUFXLEdBQ25CO0VBQ0QsQUFBQSxRQUFRLENBQUMsRUFDUCxPQUFPLEVBQUUsZUFBZSxHQUN6QjtFQUNELEFBQUEsUUFBUSxDQUFDLEVBQ1AsT0FBTyxFQUFFLGdCQUFnQixHQUMxQjs7QUFFSCxNQUFNLEVBQUUsU0FBUyxFQUFFLEtBQUssSUFDdEIsQUFBQSxVQUFVLEVBQ1YsVUFBVSxFQUNWLFVBQVUsRUFDVixTQUFTLEVBQ1QsU0FBUyxFQUNULFNBQVMsRUFDVCxTQUFTLEVBQ1QsU0FBUyxFQUNULFNBQVMsRUFDVCxTQUFTLEVBQ1QsU0FBUyxFQUNULFNBQVMsQ0FBQyxFQUNSLElBQUksRUFBRSxJQUFJLEdBQ1g7RUFDRCxBQUFBLFVBQVUsQ0FBQyxFQUNULEtBQUssRUFBRSxJQUFJLEdBQ1o7RUFDRCxBQUFBLFVBQVUsQ0FBQyxFQUNULEtBQUssRUFBRSxZQUFZLEdBQ3BCO0VBQ0QsQUFBQSxVQUFVLENBQUMsRUFDVCxLQUFLLEVBQUUsWUFBWSxHQUNwQjtFQUNELEFBQUEsU0FBUyxDQUFDLEVBQ1IsS0FBSyxFQUFFLEdBQUcsR0FDWDtFQUNELEFBQUEsU0FBUyxDQUFDLEVBQ1IsS0FBSyxFQUFFLFlBQVksR0FDcEI7RUFDRCxBQUFBLFNBQVMsQ0FBQyxFQUNSLEtBQUssRUFBRSxZQUFZLEdBQ3BCO0VBQ0QsQUFBQSxTQUFTLENBQUMsRUFDUixLQUFLLEVBQUUsR0FBRyxHQUNYO0VBQ0QsQUFBQSxTQUFTLENBQUMsRUFDUixLQUFLLEVBQUUsWUFBWSxHQUNwQjtFQUNELEFBQUEsU0FBUyxDQUFDLEVBQ1IsS0FBSyxFQUFFLFlBQVksR0FDcEI7RUFDRCxBQUFBLFNBQVMsQ0FBQyxFQUNSLEtBQUssRUFBRSxHQUFHLEdBQ1g7RUFDRCxBQUFBLFNBQVMsQ0FBQyxFQUNSLEtBQUssRUFBRSxZQUFZLEdBQ3BCO0VBQ0QsQUFBQSxTQUFTLENBQUMsRUFDUixLQUFLLEVBQUUsV0FBVyxHQUNuQjtFQUNELEFBQUEsUUFBUSxDQUFDLEVBQ1AsT0FBTyxFQUFFLGVBQWUsR0FDekI7RUFDRCxBQUFBLFFBQVEsQ0FBQyxFQUNQLE9BQU8sRUFBRSxnQkFBZ0IsR0FDMUI7O0FDcmFILEFBQUEsT0FBTyxDQUFDLEVBQ04sV0FBVyxFQUFFLE9BQU8sRUFDcEIsT0FBTyxFQUFFLElBQUksRUFDYixTQUFTLEVBQUUsSUFBSSxFQUNmLGVBQWUsRUFBRSxhQUFhLEdBdUIvQjs7QUEzQkQsQUFNRSxPQU5LLENBTUwsZUFBZSxDQUFDLEVBQ2QsV0FBVyxFQUFFLE1BQU0sRUFDbkIsT0FBTyxFQUFFLElBQUksRUFDYixJQUFJLEVBQUUsS0FBSyxHQUtaOztBQWRILEFBV0ksT0FYRyxDQU1MLGVBQWUsQUFLWixJQUFLLENOOEpBLFlBQVksQ005SkMsV0FBVyxDQUFDLEVBQzdCLGVBQWUsRUFBRSxRQUFRLEdBQzFCOztBQWJMLEFBZ0JFLE9BaEJLLENBZ0JMLGNBQWMsQ0FBQyxFQUNiLFdBQVcsRUFBRSxNQUFNLEVBQ25CLE9BQU8sRUFBRSxJQUFJLEVBQ2IsSUFBSSxFQUFFLFFBQVEsR0FDZjs7QUFwQkgsQUFzQkUsT0F0QkssQ0FzQkwsYUFBYSxDQUFDLEVBQ1osU0FBUyxFdkJpREUsTUFBSyxFdUJoRGhCLFdBQVcsRUFBRSxHQUFHLEVBQ2hCLGVBQWUsRUFBRSxJQUFJLEdBQ3RCOztBQzFCSCxBQUlNLFVBSkksQ0FDUixLQUFLLEFBQUEsUUFBUSxHQUVULGlCQUFpQixDQUNqQixLQUFLLEVBSlgsVUFBVSxDQUVQLEFBQUEsSUFBQyxBQUFBLEVBQ0UsaUJBQWlCLENBQ2pCLEtBQUssQ0FBQyxFQUNKLFNBQVMsRUFBRSxhQUFhLEdBQ3pCOztBQU5QLEFBU0ksVUFUTSxDQUNSLEtBQUssQUFBQSxRQUFRLEdBUVQsZUFBZSxFQVRyQixVQUFVLENBRVAsQUFBQSxJQUFDLEFBQUEsRUFPRSxlQUFlLENBQUMsRUFDaEIsVUFBVSxFQUFFLEtBQUssR0FDbEI7O0FBWEwsQUFjRSxVQWRRLENBY1IsaUJBQWlCLENBQUMsRUFDaEIsT0FBTyxFQUFFLEtBQUssRUFDZCxPQUFPLEV4QnNDRixNQUFLLENBQ0wsTUFBSyxHd0JsQ1g7O0FBckJILEFBa0JJLFVBbEJNLENBY1IsaUJBQWlCLENBSWYsS0FBSyxDQUFDLEVBQ0osVUFBVSxFQUFFLFlBQVksR0FDekI7O0FBcEJMLEFBdUJFLFVBdkJRLENBdUJSLGVBQWUsQ0FBQyxFQUNkLGFBQWEsRXhCK0JSLE1BQUssRXdCOUJWLFVBQVUsRUFBRSxDQUFDLEVBQ2IsUUFBUSxFQUFFLE1BQU0sRUFDaEIsVUFBVSxFQUFFLG1CQUFtQixHQUNoQzs7QUFJSCxBQUNFLE9BREssQUFBQSxpQkFBaUIsQUFDckIsd0JBQXdCLENBQUMsRUFDeEIsT0FBTyxFQUFFLElBQUksR0FDZDs7QUNuQ0gsQUFBQSxPQUFPLENBQUMsRXZCQ04sU0FBUyxFQUFFLE1BQVMsRUFDcEIsTUFBTSxFRjJEQyxNQUFNLEVFMURiLEtBQUssRUYwREUsTUFBTSxFeUIzRGIsVUFBVSxFekJJSSxPQUFPLEV5QkhyQixhQUFhLEVBQUUsR0FBRyxFQUNsQixLQUFLLEV6QldPLHlCQUFJLEV5QlZoQixPQUFPLEVBQUUsWUFBWSxFQUNyQixXQUFXLEVBQUUsR0FBRyxFQUNoQixXQUFXLEVBQUUsSUFBSSxFQUNqQixNQUFNLEVBQUUsQ0FBQyxFQUNULFFBQVEsRUFBRSxRQUFRLEVBQ2xCLGNBQWMsRUFBRSxNQUFNLEdBaUV2Qjs7QUEzRUQsQUFZRSxPQVpLLEFBWUosVUFBVSxDQUFDLEV2QlhaLFNBQVMsRUFBRSxNQUFTLEVBQ3BCLE1BQU0sRUZ1REMsTUFBSyxFRXREWixLQUFLLEVGc0RFLE1BQUssR3lCM0NYOztBQWRILEFBZUUsT0FmSyxBQWVKLFVBQVUsQ0FBQyxFdkJkWixTQUFTLEVBQUUsTUFBUyxFQUNwQixNQUFNLEVGeURDLE1BQU0sRUV4RGIsS0FBSyxFRndERSxNQUFNLEd5QjFDWjs7QUFqQkgsQUFrQkUsT0FsQkssQUFrQkosVUFBVSxDQUFDLEV2QmpCWixTQUFTLEVBQUUsTUFBUyxFQUNwQixNQUFNLEVGOERFLE1BQU0sRUU3RGQsS0FBSyxFRjZERyxNQUFNLEd5QjVDYjs7QUFwQkgsQUFxQkUsT0FyQkssQUFxQkosVUFBVSxDQUFDLEV2QnBCWixTQUFTLEVBQUUsTUFBUyxFQUNwQixNQUFNLEVGK0RFLE1BQU0sRUU5RGQsS0FBSyxFRjhERyxNQUFNLEd5QjFDYjs7QUF2QkgsQUF5QkUsT0F6QkssQ0F5QkwsR0FBRyxDQUFDLEVBQ0YsYUFBYSxFQUFFLEdBQUcsRUFDbEIsTUFBTSxFQUFFLElBQUksRUFDWixRQUFRLEVBQUUsUUFBUSxFQUNsQixLQUFLLEVBQUUsSUFBSSxFQUNYLE9BQU8sRXpCZ0ZBLENBQUMsR3lCL0VUOztBQS9CSCxBQWlDRSxPQWpDSyxDQWlDTCxZQUFZLEVBakNkLE9BQU8sQ0FrQ0wsZ0JBQWdCLENBQUMsRUFDZixVQUFVLEV6QnBCQSxJQUFJLEV5QnFCZCxNQUFNLEVBQUUsTUFBTSxFQUNkLE1BQU0sRUFBRSxHQUFHLEVBQ1gsT0FBTyxFekJlRixNQUFLLEV5QmRWLFFBQVEsRUFBRSxRQUFRLEVBQ2xCLEtBQUssRUFBRSxNQUFNLEVBQ2IsU0FBUyxFQUFFLG1CQUFtQixFQUM5QixLQUFLLEVBQUUsR0FBRyxFQUNWLE9BQU8sRXpCbUVBLENBQUMsR3lCbEVUOztBQTVDSCxBQThDRSxPQTlDSyxDQThDTCxnQkFBZ0IsQ0FBQyxFQUNmLFVBQVUsRXpCL0JELE9BQXlCLEV5QmdDbEMsVUFBVSxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDekJLWixNQUFLLENBdENBLElBQUksRXlCa0NkLGFBQWEsRUFBRSxHQUFHLEVBQ2xCLE1BQU0sRUFBRSxJQUFJLEVBQ1osS0FBSyxFQUFFLElBQUksR0FhWjs7QUFoRUgsQUFxREksT0FyREcsQ0E4Q0wsZ0JBQWdCLEFBT2IsT0FBTyxDQUFDLEVBQ1AsVUFBVSxFekIzQkEsT0FBTyxHeUI0QmxCOztBQXZETCxBQXlESSxPQXpERyxDQThDTCxnQkFBZ0IsQUFXYixLQUFLLENBQUMsRUFDTCxVQUFVLEV6QjdCRixPQUFPLEd5QjhCaEI7O0FBM0RMLEFBNkRJLE9BN0RHLENBOENMLGdCQUFnQixBQWViLEtBQUssQ0FBQyxFQUNMLFVBQVUsRXpCbENBLE9BQU8sR3lCbUNsQjs7QUEvREwsQUFrRUUsT0FsRUssQ0FrRUosQUFBQSxZQUFDLEFBQUEsQ0FBYSxRQUFRLENBQUMsRUFDdEIsS0FBSyxFQUFFLFlBQVksRUFDbkIsT0FBTyxFQUFFLGtCQUFrQixFQUMzQixJQUFJLEVBQUUsR0FBRyxFQUNULFFBQVEsRUFBRSxRQUFRLEVBQ2xCLEdBQUcsRUFBRSxHQUFHLEVBQ1IsU0FBUyxFQUFFLHFCQUFxQixFQUNoQyxPQUFPLEV6QnFDQSxDQUFDLEd5QnBDVDs7QUMxRUgsQUFBQSxNQUFNLENBQUMsRUFDTCxRQUFRLEVBQUUsUUFBUSxFQUNsQixXQUFXLEVBQUUsTUFBTSxHQXdEcEI7O0FBMURELEFBTUksTUFORSxDQUlILEFBQUEsVUFBQyxBQUFBLENBRUMsT0FBTyxFQU5aLE1BQU0sQUFLSCxJQUFLLEVBQUEsQUFBQSxVQUFDLEFBQUEsRUFDSixPQUFPLENBQUMsRUFDUCxVQUFVLEUxQkRBLE9BQU8sRTBCRWpCLGVBQWUsRUFBRSxXQUFXLEVBQzVCLGFBQWEsRUFBRSxLQUFLLEVBQ3BCLFVBQVUsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxNQUFLLEMxQktmLElBQUksRTBCSlosS0FBSyxFMUJJRyxJQUFJLEUwQkhaLE9BQU8sRUFBRSxnQkFBZ0IsRUFDekIsT0FBTyxFQUFFLFlBQVksRUFDckIsU0FBUyxFQUFFLDRCQUEwQixHQUN0Qzs7QUFmTCxBQWtCSSxNQWxCRSxDQWlCSCxBQUFBLFVBQUMsQUFBQSxDQUNDLE9BQU8sQ0FBQyxFQUNQLFNBQVMsRTFCb0RBLE1BQUssRTBCbkRkLE1BQU0sRUFBRSxLQUFLLEVBQ2IsV0FBVyxFQUFFLENBQUMsRUFDZCxTQUFTLEVBQUUsS0FBSyxFQUNoQixPQUFPLEVBQUUsV0FBVyxFQUNwQixVQUFVLEVBQUUsTUFBTSxFQUNsQixXQUFXLEVBQUUsTUFBTSxHQUNwQjs7QUExQkwsQUE4QkksTUE5QkUsQUE0QkgsSUFBSyxFQXZCQSxBQUFBLFVBQUMsQUFBQSxFQXlCSixPQUFPLEVBOUJaLE1BQU0sQ0E2QkgsQUFBQSxVQUFDLENBQVcsRUFBRSxBQUFiLENBQ0MsT0FBTyxDQUFDLEVBQ1AsTUFBTSxFQUFFLEdBQUcsRUFDWCxTQUFTLEVBQUUsR0FBRyxFQUNkLE9BQU8sRUFBRSxDQUFDLEVBQ1YsS0FBSyxFQUFFLEdBQUcsR0FDWDs7QUFuQ0wsQUF3Q0ksTUF4Q0UsQUF1Q0gsSUFBSSxBQUNGLE9BQU8sQ0FBQyxFQUNQLFFBQVEsRUFBRSxRQUFRLEVBQ2xCLEdBQUcsRUFBRSxDQUFDLEVBQ04sS0FBSyxFQUFFLENBQUMsRUFDUixTQUFTLEVBQUUsb0JBQW9CLEdBQ2hDOztBQTdDTCxBQWtESSxNQWxERSxBQWlESCxPQUFPLEFBQ0wsT0FBTyxDQUFDLEVBQ1AsUUFBUSxFQUFFLFFBQVEsRUFDbEIsR0FBRyxFQUFFLE1BQU0sRUFDWCxLQUFLLEVBQUUsTUFBTSxFQUNiLFNBQVMsRUFBRSxvQkFBb0IsRUFDL0IsT0FBTyxFMUJ3REYsR0FBRyxHMEJ2RFQ7O0FDeERMLEFBQUEsV0FBVyxDQUFDLEVBQ1YsVUFBVSxFQUFFLElBQUksRUFDaEIsTUFBTSxFM0JvREMsTUFBSyxDMkJwREksQ0FBQyxFQUNqQixPQUFPLEUzQm1EQSxNQUFLLEMyQm5ESyxDQUFDLEdBd0JuQjs7QUEzQkQsQUFLRSxXQUxTLENBS1QsZ0JBQWdCLENBQUMsRUFDZixLQUFLLEUzQldTLE9BQXdCLEUyQlZ0QyxPQUFPLEVBQUUsWUFBWSxFQUNyQixNQUFNLEVBQUUsQ0FBQyxFQUNULE9BQU8sRTNCNkNGLE1BQUssQzJCN0NPLENBQUMsR0FpQm5COztBQTFCSCxBQVdJLFdBWE8sQ0FLVCxnQkFBZ0IsQUFNYixJQUFLLENWMEpZLFdBQVcsRVUxSlYsRUFDakIsWUFBWSxFM0IwQ1QsTUFBSyxHMkJyQ1Q7O0FBakJMLEFBY00sV0FkSyxDQUtULGdCQUFnQixBQU1iLElBQUssQ1YwSlksV0FBVyxFVXZKM0IsQ0FBQyxDQUFDLEVBQ0EsS0FBSyxFM0JFSyxPQUF3QixHMkJEbkM7O0FBaEJQLEFBb0JNLFdBcEJLLENBS1QsZ0JBQWdCLEFBY2IsSUFBSyxDVnNKQSxZQUFZLENVckpmLFFBQVEsQ0FBQyxFQUNSLEtBQUssRTNCSE0sT0FBeUIsRTJCSXBDLE9BQU8sRUFBRSxHQUFHLEVBQ1osYUFBYSxFM0JnQ1osTUFBSyxHMkIvQlA7O0FDeEJQLEFBQUEsSUFBSSxDQUFDLEVBQ0gsVUFBVSxFNUJzQkksT0FBcUIsRTRCckJuQyxhQUFhLEU1Qm1ETixNQUFLLEU0QmxEWixPQUFPLEVBQUUsSUFBSSxFQUNiLFNBQVMsRUFBRSxNQUFNLEVBQ2pCLE1BQU0sRTVCb0RDLE1BQUssRTRCbkRaLEtBQUssRUFBRSxJQUFJLEdBNkJaOztBQW5DRCxBQVFFLElBUkUsQUFRRCxPQUFPLENBQUMsRUFDUCxNQUFNLEU1QjZDRCxNQUFLLEc0QjVDWDs7QUFWSCxBQWFFLElBYkUsQ0FhRixTQUFTLENBQUMsRUFDUixVQUFVLEU1QlJFLE9BQU8sRTRCU25CLEtBQUssRTVCQUssSUFBSSxFNEJDZCxPQUFPLEVBQUUsS0FBSyxFQUNkLFNBQVMsRTVCc0RFLE1BQUssRTRCckRoQixXQUFXLEVBQUUsQ0FBQyxFQUNkLFdBQVcsRTVCc0NOLE1BQUssRTRCckNWLE1BQU0sRUFBRSxJQUFJLEVBQ1osUUFBUSxFQUFFLFFBQVEsRUFDbEIsVUFBVSxFQUFFLE1BQU0sRUFDbEIsS0FBSyxFQUFFLENBQUMsR0FXVDs7QUFsQ0gsQUF5QkksSUF6QkEsQ0FhRixTQUFTLEFBWU4sWUFBWSxDQUFDLEVBQ1oseUJBQXlCLEU1QjJCdEIsTUFBSyxFNEIxQlIsc0JBQXNCLEU1QjBCbkIsTUFBSyxHNEJ6QlQ7O0FBNUJMLEFBNkJJLElBN0JBLENBYUYsU0FBUyxBQWdCTixXQUFXLENBQUMsRUFDWCwwQkFBMEIsRTVCdUJ2QixNQUFLLEU0QnRCUix1QkFBdUIsRTVCc0JwQixNQUFLLEU0QnJCUixXQUFXLEVBQUUsQ0FBQyxHQUNmOztBQUtMLEFBQUEsV0FBVyxDQUFDLEVBQ1YsTUFBTSxFNUJjQyxNQUFLLEU0QmJaLE1BQU0sRTVCZUMsTUFBSyxDNEJmWSxDQUFDLEVBQ3pCLFFBQVEsRUFBRSxRQUFRLEdBNEJuQjs7QUEvQkQsQUFLRSxXQUxTLENBS1QsU0FBUyxDQUFDLEVBQ1IsSUFBSSxFQUFFLENBQUMsRUFDUCxPQUFPLEVBQUUsQ0FBQyxFQUNWLFFBQVEsRUFBRSxRQUFRLEdBS25COztBQWJILEFBU0ksV0FUTyxDQUtULFNBQVMsQUFJTixJQUFLLENYc0hZLFdBQVcsQ1d0SFgsWUFBWSxDQUFDLEVBQzdCLFVBQVUsRTVCekJBLE9BQXFCLEU0QjBCL0IsT0FBTyxFNUI2REYsQ0FBQyxHNEI1RFA7O0FBWkwsQUFlRSxXQWZTLENBZVQsZUFBZSxDQUFDLEVBQ2QsVUFBVSxFNUJoREUsT0FBTyxFNEJpRG5CLE1BQU0sRUFBRSxDQUFDLEVBQ1QsYUFBYSxFQUFFLEdBQUcsRUFDbEIsTUFBTSxFNUJERCxNQUFLLEU0QkVWLE9BQU8sRUFBRSxDQUFDLEVBQ1YsUUFBUSxFQUFFLFFBQVEsRUFDbEIsS0FBSyxFQUFFLENBQUMsRUFDUixHQUFHLEVBQUUsR0FBRyxFQUNSLFNBQVMsRUFBRSxvQkFBb0IsRUFDL0IsS0FBSyxFNUJQQSxNQUFLLEc0QllYOztBQTlCSCxBQTJCSSxXQTNCTyxDQWVULGVBQWUsQUFZWixPQUFPLENBQUMsRUFDUCxVQUFVLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBSyxDNUI1RGIsT0FBTyxHNEI2RGxCOztBQ25FTCxBQUFBLEtBQUssQ0FBQyxFQUNKLFVBQVUsRTdCY0UsSUFBSSxFNkJiaEIsTUFBTSxFN0JrREMsT0FBTSxDNkJsRFMsS0FBSyxDN0JrQmQsT0FBeUIsRTZCakJ0QyxhQUFhLEU3QmtETixNQUFLLEU2QmpEWixPQUFPLEVBQUUsSUFBSSxFQUNiLGNBQWMsRUFBRSxNQUFNLEdBb0N2Qjs7QUF6Q0QsQUFPRSxLQVBHLENBT0gsWUFBWSxFQVBkLEtBQUssQ0FRSCxVQUFVLEVBUlosS0FBSyxDQVNILFlBQVksQ0FBQyxFQUNYLE9BQU8sRTdCK0NGLE1BQUssRTZCOUNWLGNBQWMsRUFBRSxDQUFDLEdBS2xCOztBQWhCSCxBQWFJLEtBYkMsQ0FPSCxZQUFZLEFBTVQsV0FBVyxFQWJoQixLQUFLLENBUUgsVUFBVSxBQUtQLFdBQVcsRUFiaEIsS0FBSyxDQVNILFlBQVksQUFJVCxXQUFXLENBQUMsRUFDWCxjQUFjLEU3QjJDWCxNQUFLLEc2QjFDVDs7QUFmTCxBQWtCRSxLQWxCRyxDQWtCSCxVQUFVLENBQUMsRUFDVCxJQUFJLEVBQUUsUUFBUSxHQUNmOztBQXBCSCxBQXNCRSxLQXRCRyxDQXNCSCxXQUFXLENBQUMsRUFDVixXQUFXLEU3QmtDTixNQUFLLEc2QmpCWDs7QUF4Q0gsQUF5QkksS0F6QkMsQ0FzQkgsV0FBVyxBQUdSLFlBQVksQ0FBQyxFQUNaLFdBQVcsRUFBRSxDQUFDLEdBTWY7O0FBaENMLEFBNEJNLEtBNUJELENBc0JILFdBQVcsQUFHUixZQUFZLENBR1gsR0FBRyxDQUFDLEVBQ0Ysc0JBQXNCLEU3QndCckIsTUFBSyxFNkJ2Qk4sdUJBQXVCLEU3QnVCdEIsTUFBSyxHNkJ0QlA7O0FBL0JQLEFBbUNNLEtBbkNELENBc0JILFdBQVcsQUFZUixXQUFXLENBQ1YsR0FBRyxDQUFDLEVBQ0YseUJBQXlCLEU3QmlCeEIsTUFBSyxFNkJoQk4sMEJBQTBCLEU3QmdCekIsTUFBSyxHNkJmUDs7QUN0Q1AsQUFBQSxLQUFLLENBQUMsRUFDSixXQUFXLEVBQUUsTUFBTSxFQUNuQixVQUFVLEU5QnFCSSxPQUFxQixFOEJwQm5DLGFBQWEsRUFBRSxJQUFJLEVBQ25CLEtBQUssRTlCYVcsT0FBd0IsRThCWnhDLE9BQU8sRUFBRSxXQUFXLEVBQ3BCLFNBQVMsRUFBRSxHQUFHLEVBQ2QsTUFBTSxFOUJvREMsTUFBTSxFOEJuRGIsV0FBVyxFOUJpREosTUFBSyxFOEJoRFosTUFBTSxFOUI0Q0MsTUFBSyxFOEIzQ1osU0FBUyxFQUFFLElBQUksRUFDZixPQUFPLEU5QjJDQSxNQUFLLENBQ0wsTUFBSyxFOEIzQ1osZUFBZSxFQUFFLElBQUksRUFDckIsY0FBYyxFQUFFLE1BQU0sR0FldkI7O0FBNUJELEFBZUUsS0FmRyxBQWVGLE9BQU8sQ0FBQyxFQUNQLFVBQVUsRTlCVkUsT0FBTyxFOEJXbkIsS0FBSyxFOUJGSyxJQUFJLEc4QkdmOztBQWxCSCxBQW9CRSxLQXBCRyxDQW9CSCxPQUFPLENBQUMsRUFDTixXQUFXLEU5QmtDTixPQUFLLEU4QmpDVixZQUFZLEU5QmdDUCxNQUFLLEc4Qi9CWDs7QUF2QkgsQUF5QkUsS0F6QkcsQ0F5QkgsVUFBVSxDQUFDLEVBQ1QsU0FBUyxFQUFFLFdBQVUsR0FDdEI7O0FDM0JILEFBQUEsU0FBUyxDQUFDLEVBQ1IsT0FBTyxFQUFFLFlBQVksRUFDckIsUUFBUSxFQUFFLFFBQVEsR0FnQ25COztBQWxDRCxBQUlFLFNBSk8sQ0FJUCxLQUFLLENBQUMsRUFDSixTQUFTLEVBQUUsc0JBQXNCLEVBQ2pDLE9BQU8sRUFBRSxJQUFJLEVBQ2IsSUFBSSxFQUFFLENBQUMsRUFDUCxVQUFVLEVBQUUsSUFBSSxFQUNoQixVQUFVLEVBQUUsSUFBSSxFQUNoQixRQUFRLEVBQUUsUUFBUSxFQUNsQixHQUFHLEVBQUUsSUFBSSxHQUNWOztBQVpILEFBZUksU0FmSyxBQWNOLGVBQWUsQ0FDZCxLQUFLLENBQUMsRUFDSixJQUFJLEVBQUUsSUFBSSxFQUNWLEtBQUssRUFBRSxDQUFDLEdBQ1Q7O0FBbEJMLEFBcUJFLFNBckJPLEFBcUJOLE9BQU8sQ0FBQyxLQUFLLEVBckJoQixTQUFTLENBc0JQLGdCQUFnQixBQUFBLE1BQU0sR0FBRyxLQUFLLEVBdEJoQyxTQUFTLENBdUJQLEtBQUssQUFBQSxNQUFNLENBQUMsRUFDVixPQUFPLEVBQUUsS0FBSyxHQUNmOztBQXpCSCxBQTZCSSxTQTdCSyxDQTRCUCxVQUFVLENBQ1IsZ0JBQWdCLEFBQUEsZUFBZ0IsQ0FBQSxDQUFDLEVBQUUsRUFDakMsMEJBQTBCLEUvQnVCdkIsTUFBSyxFK0J0QlIsdUJBQXVCLEUvQnNCcEIsTUFBSyxHK0JyQlQ7O0FDaENMLEFBQUEsTUFBTSxDQUFDLEVBQ0wsVUFBVSxFaENxQkQsT0FBeUIsRWdDcEJsQyxhQUFhLEVoQ21ETixNQUFLLEVnQ2xEWixLQUFLLEVoQ2NXLE9BQXdCLEVnQ2J4QyxVQUFVLEVBQUUsTUFBTSxFQUNsQixPQUFPLEVoQzREQyxNQUFNLENBSlAsTUFBTSxHZ0MxQ2Q7O0FBbkJELEFBT0UsTUFQSSxDQU9KLFdBQVcsQ0FBQyxFQUNWLGFBQWEsRWhDaURSLE1BQUssR2dDaERYOztBQVRILEFBV0UsTUFYSSxDQVdKLFlBQVksRUFYZCxNQUFNLENBWUosZUFBZSxDQUFDLEVBQ2QsTUFBTSxFaEMwQ0QsTUFBSyxDZ0MxQ2MsSUFBSSxHQUM3Qjs7QUFkSCxBQWdCRSxNQWhCSSxDQWdCSixhQUFhLENBQUMsRUFDWixVQUFVLEVoQ3dDTCxNQUFLLEdnQ3ZDWDs7QUNsQkgsQUFBQSxLQUFLLENBQUMsRXpCTUosVUFBVSxFQUFFLENBQUMsQ3lCTFcsT0FBTSxDekJLUixNQUFzQixDUlFqQyxxQkFBTyxFaUNabEIsVUFBVSxFakNhRSxJQUFJLEVpQ1poQixhQUFhLEVqQ2tETixNQUFLLEVpQ2pEWixVQUFVLEVBQUUsSUFBSSxFQUNoQixNQUFNLEVBQUUsQ0FBQyxFQUNULFNBQVMsRWpDdUZRLEtBQUssRWlDdEZ0QixPQUFPLEVqQ2dEQSxNQUFLLEVpQy9DWixTQUFTLEVBQUUsa0JBQThCLEVBQ3pDLE9BQU8sRWpDd0dFLEdBQUcsR2lDckRiOztBQTVERCxBQVdFLEtBWEcsQUFXRixTQUFTLENBQUMsRUFDVCxVQUFVLEVBQUUsV0FBVyxFQUN2QixVQUFVLEVBQUUsSUFBSSxHQUNqQjs7QUFkSCxBQWdCRSxLQWhCRyxDQWdCSCxVQUFVLENBQUMsRUFDVCxVQUFVLEVBQUUsQ0FBQyxFQUNiLE9BQU8sRUFBRSxDQUFDLENqQ3FDTCxNQUFLLEVpQ3BDVixlQUFlLEVBQUUsSUFBSSxFQUNyQixXQUFXLEVBQUUsSUFBSSxHQThCbEI7O0FBbERILEFBc0JJLEtBdEJDLENBZ0JILFVBQVUsR0FNSixDQUFDLENBQUMsRUFDSixhQUFhLEVqQzhCVixNQUFLLEVpQzdCUixLQUFLLEVBQUUsT0FBTyxFQUNkLE9BQU8sRUFBRSxLQUFLLEVBQ2QsTUFBTSxFQUFFLENBQUMsQ2pDNkJOLE9BQUssRWlDNUJSLE9BQU8sRWpDMkJKLE1BQUssQ0FDTCxNQUFLLEVpQzNCUixlQUFlLEVBQUUsSUFBSSxHQVd0Qjs7QUF2Q0wsQUE2Qk0sS0E3QkQsQ0FnQkgsVUFBVSxHQU1KLENBQUMsQUFPRixNQUFNLEVBN0JiLEtBQUssQ0FnQkgsVUFBVSxHQU1KLENBQUMsQUFRRixNQUFNLENBQUMsRUFDTixVQUFVLEVqQ3RCQSxPQUE4QixFaUN1QnhDLEtBQUssRWpDMUJHLE9BQU8sR2lDMkJoQjs7QUFqQ1AsQUFrQ00sS0FsQ0QsQ0FnQkgsVUFBVSxHQU1KLENBQUMsQUFZRixPQUFPLEVBbENkLEtBQUssQ0FnQkgsVUFBVSxHQU1KLENBQUMsQUFhRixPQUFPLENBQUMsRUFDUCxVQUFVLEVqQzNCQSxPQUE4QixFaUM0QnhDLEtBQUssRWpDL0JHLE9BQU8sR2lDZ0NoQjs7QUF0Q1AsQUF5Q0ksS0F6Q0MsQ0FnQkgsVUFBVSxDQXlCUixjQUFjLEVBekNsQixLQUFLLENBZ0JILFVBQVUsQ0EwQlIsV0FBVyxFQTFDZixLQUFLLENBZ0JILFVBQVUsQ0EyQlIsWUFBWSxDQUFDLEVBQ1gsTUFBTSxFakNTSCxNQUFLLENpQ1RRLENBQUMsR0FDbEI7O0FBN0NMLEFBK0NJLEtBL0NDLENBZ0JILFVBQVUsR0ErQkosVUFBVSxDQUFDLEVBQ2IsVUFBVSxFakNNUCxNQUFLLEdpQ0xUOztBQWpETCxBQW9ERSxLQXBERyxDQW9ESCxXQUFXLENBQUMsRUFDVixLQUFLLEVBQUUsS0FBSyxFQUNaLE9BQU8sRWpDQUYsTUFBSyxDaUNBTyxDQUFDLEdBS25COztBQTNESCxBQXdESSxLQXhEQyxDQW9ESCxXQUFXLENBSVQsSUFBSSxDQUFDLEVBQ0gsVUFBVSxFakNKUCxPQUFLLEdpQ0tUOztBQzFETCxBQUFBLE1BQU0sQ0FBQyxFQUNMLFdBQVcsRUFBRSxNQUFNLEVBQ25CLE1BQU0sRUFBRSxDQUFDLEVBQ1QsT0FBTyxFQUFFLElBQUksRUFDYixlQUFlLEVBQUUsTUFBTSxFQUN2QixJQUFJLEVBQUUsQ0FBQyxFQUNQLE9BQU8sRUFBRSxDQUFDLEVBQ1YsUUFBUSxFQUFFLE1BQU0sRUFDaEIsT0FBTyxFbEMrQ0EsTUFBSyxFa0M5Q1osUUFBUSxFQUFFLEtBQUssRUFDZixLQUFLLEVBQUUsQ0FBQyxFQUNSLEdBQUcsRUFBRSxDQUFDLEdBMENQOztBQXJERCxBQWFFLE1BYkksQUFhSCxPQUFPLEVBYlYsTUFBTSxBQWNILE9BQU8sQ0FBQyxFQUNQLE9BQU8sRUFBRSxJQUFJLEVBQ2IsT0FBTyxFQUFFLENBQUMsRUFDVixPQUFPLEVsQ2lHQSxHQUFHLEdrQ2hGWDs7QUFsQ0gsQUFtQkksTUFuQkUsQUFhSCxPQUFPLENBTU4sY0FBYyxFQW5CbEIsTUFBTSxBQWNILE9BQU8sQ0FLTixjQUFjLENBQUMsRUFDYixVQUFVLEVsQ0VMLHlCQUF5QixFa0NEOUIsTUFBTSxFQUFFLENBQUMsRUFDVCxNQUFNLEVBQUUsT0FBTyxFQUNmLE9BQU8sRUFBRSxLQUFLLEVBQ2QsSUFBSSxFQUFFLENBQUMsRUFDUCxRQUFRLEVBQUUsUUFBUSxFQUNsQixLQUFLLEVBQUUsQ0FBQyxFQUNSLEdBQUcsRUFBRSxDQUFDLEdBQ1A7O0FBNUJMLEFBOEJJLE1BOUJFLEFBYUgsT0FBTyxDQWlCTixnQkFBZ0IsRUE5QnBCLE1BQU0sQUFjSCxPQUFPLENBZ0JOLGdCQUFnQixDQUFDLEVBQ2YsU0FBUyxFQUFFLHFCQUFxQixFQUNoQyxPQUFPLEVsQzhFRixDQUFDLEdrQzdFUDs7QUFqQ0wsQUFxQ0ksTUFyQ0UsQUFvQ0gsU0FBUyxDQUNSLGdCQUFnQixDQUFDLEVBQ2YsU0FBUyxFbEN3REksS0FBSyxFa0N2RGxCLE9BQU8sRUFBRSxDQUFDLENsQ2dCUCxNQUFLLEdrQ2ZUOztBQXhDTCxBQTRDSSxNQTVDRSxBQTJDSCxTQUFTLENBQ1IsY0FBYyxDQUFDLEVBQ2IsVUFBVSxFbEM5QkYsSUFBSSxHa0MrQmI7O0FBOUNMLEFBZ0RJLE1BaERFLEFBMkNILFNBQVMsQ0FLUixnQkFBZ0IsQ0FBQyxFQUNmLFVBQVUsRUFBRSxJQUFJLEVBQ2hCLFNBQVMsRWxDOENJLEtBQUssR2tDN0NuQjs7QUFJTCxBQUFBLGdCQUFnQixDQUFDLEUxQmpEZixVQUFVLEVBQUUsQ0FBQyxDMEJrRFcsTUFBSyxDMUJsRFAsTUFBc0IsQ1JRakMscUJBQU8sRWtDMkNsQixVQUFVLEVsQzFDRSxJQUFJLEVrQzJDaEIsYUFBYSxFbENMTixNQUFLLEVrQ01aLE9BQU8sRUFBRSxJQUFJLEVBQ2IsY0FBYyxFQUFFLE1BQU0sRUFDdEIsVUFBVSxFQUFFLElBQUksRUFDaEIsU0FBUyxFbENpQ1EsS0FBSyxFa0NoQ3RCLE9BQU8sRUFBRSxDQUFDLENsQ05ILE1BQUssRWtDT1osS0FBSyxFQUFFLElBQUksR0FxQlo7O0FBOUJELEFBV0UsZ0JBWGMsQUFXYixpQkFBaUIsQ0FBQyxFQUNqQixVQUFVLEVBQUUsS0FBSyxHQUNsQjs7QUFiSCxBQWVFLGdCQWZjLENBZWQsYUFBYSxDQUFDLEVBQ1osS0FBSyxFbEN6REksT0FBTyxFa0MwRGhCLE9BQU8sRWxDZkYsTUFBSyxHa0NnQlg7O0FBbEJILEFBb0JFLGdCQXBCYyxDQW9CZCxXQUFXLENBQUMsRUFDVixVQUFVLEVBQUUsSUFBSSxFQUNoQixPQUFPLEVsQ3BCRixNQUFLLEVrQ3FCVixRQUFRLEVBQUUsUUFBUSxHQUNuQjs7QUF4QkgsQUEwQkUsZ0JBMUJjLENBMEJkLGFBQWEsQ0FBQyxFQUNaLE9BQU8sRWxDekJGLE1BQUssRWtDMEJWLFVBQVUsRUFBRSxLQUFLLEdBQ2xCOztBQ3BGSCxBQUFBLElBQUksQ0FBQyxFQUNILE9BQU8sRUFBRSxJQUFJLEVBQ2IsY0FBYyxFQUFFLE1BQU0sRUFDdEIsVUFBVSxFQUFFLElBQUksRUFDaEIsTUFBTSxFbkNrREMsTUFBSyxDbUNsREksQ0FBQyxHQTRCbEI7O0FBaENELEFBT0ksSUFQQSxDQU1GLFNBQVMsQ0FDUCxDQUFDLENBQUMsRUFDQSxLQUFLLEVuQ1NPLE9BQXdCLEVtQ1JwQyxPQUFPLEVuQzZDSixNQUFLLENBQ0wsTUFBSyxFbUM3Q1IsZUFBZSxFQUFFLElBQUksR0FLdEI7O0FBZkwsQUFXTSxJQVhGLENBTUYsU0FBUyxDQUNQLENBQUMsQUFJRSxNQUFNLEVBWGIsSUFBSSxDQU1GLFNBQVMsQ0FDUCxDQUFDLEFBS0UsTUFBTSxDQUFDLEVBQ04sS0FBSyxFbkNQRyxPQUFPLEdtQ1FoQjs7QUFkUCxBQWlCTSxJQWpCRixDQU1GLFNBQVMsQUFVTixPQUFPLEdBQ0YsQ0FBQyxDQUFDLEVBQ0osS0FBSyxFQUFFLE9BQTZCLEVBQ3BDLFdBQVcsRUFBRSxJQUFJLEdBS2xCOztBQXhCUCxBQW9CUSxJQXBCSixDQU1GLFNBQVMsQUFVTixPQUFPLEdBQ0YsQ0FBQyxBQUdGLE1BQU0sRUFwQmYsSUFBSSxDQU1GLFNBQVMsQUFVTixPQUFPLEdBQ0YsQ0FBQyxBQUlGLE1BQU0sQ0FBQyxFQUNOLEtBQUssRW5DaEJDLE9BQU8sR21DaUJkOztBQXZCVCxBQTRCRSxJQTVCRSxDQTRCQSxJQUFJLENBQUMsRUFDTCxhQUFhLEVuQzBCUixNQUFLLEVtQ3pCVixXQUFXLEVuQzJCTixNQUFLLEdtQzFCWDs7QUMvQkgsQUFBQSxXQUFXLENBQUMsRUFDVixPQUFPLEVBQUUsSUFBSSxFQUNiLFVBQVUsRUFBRSxJQUFJLEVBQ2hCLE1BQU0sRXBDbURDLE1BQUssQ29DbkRJLENBQUMsRUFDakIsT0FBTyxFcENrREEsTUFBSyxDb0NsREssQ0FBQyxHQXVEbkI7O0FBM0RELEFBTUUsV0FOUyxDQU1ULFVBQVUsQ0FBQyxFQUNULE1BQU0sRXBDK0NELE1BQUssQ0FGTCxPQUFNLEdvQ01aOztBQTFESCxBQVNJLFdBVE8sQ0FNVCxVQUFVLENBR1IsSUFBSSxDQUFDLEVBQ0gsT0FBTyxFQUFFLFlBQVksRUFDckIsT0FBTyxFcEMyQ0osTUFBSyxDQUFMLE1BQUssR29DMUNUOztBQVpMLEFBY0ksV0FkTyxDQU1ULFVBQVUsQ0FRUixDQUFDLENBQUMsRUFDQSxhQUFhLEVwQ3NDVixNQUFLLEVvQ3JDUixLQUFLLEVwQ0NPLE9BQXdCLEVvQ0FwQyxPQUFPLEVBQUUsWUFBWSxFQUNyQixPQUFPLEVwQ29DSixNQUFLLENBQ0wsTUFBSyxFb0NwQ1IsZUFBZSxFQUFFLElBQUksR0FLdEI7O0FBeEJMLEFBb0JNLFdBcEJLLENBTVQsVUFBVSxDQVFSLENBQUMsQUFNRSxNQUFNLEVBcEJiLFdBQVcsQ0FNVCxVQUFVLENBUVIsQ0FBQyxBQU9FLE1BQU0sQ0FBQyxFQUNOLEtBQUssRXBDaEJHLE9BQU8sR29DaUJoQjs7QUF2QlAsQUEyQk0sV0EzQkssQ0FNVCxVQUFVLEFBb0JQLFNBQVMsQ0FDUixDQUFDLENBQUMsRUFDQSxNQUFNLEVBQUUsT0FBTyxFQUNmLE9BQU8sRUFBRSxFQUFFLEVBQ1gsY0FBYyxFQUFFLElBQUksR0FDckI7O0FBL0JQLEFBbUNNLFdBbkNLLENBTVQsVUFBVSxBQTRCUCxPQUFPLENBQ04sQ0FBQyxDQUFDLEVBQ0EsVUFBVSxFcEM5QkYsT0FBTyxFb0MrQmYsS0FBSyxFcEN0QkMsSUFBSSxHb0N1Qlg7O0FBdENQLEFBeUNJLFdBekNPLENBTVQsVUFBVSxBQW1DUCxVQUFVLEVBekNmLFdBQVcsQ0FNVCxVQUFVLEFBb0NQLFVBQVUsQ0FBQyxFQUNWLElBQUksRUFBRSxPQUFPLEdBQ2Q7O0FBNUNMLEFBOENJLFdBOUNPLENBTVQsVUFBVSxBQXdDUCxVQUFVLENBQUMsRUFDVixVQUFVLEVBQUUsS0FBSyxHQUNsQjs7QUFoREwsQUFrREksV0FsRE8sQ0FNVCxVQUFVLENBNENSLGdCQUFnQixDQUFDLEVBQ2YsTUFBTSxFQUFFLENBQUMsR0FDVjs7QUFwREwsQUFzREksV0F0RE8sQ0FNVCxVQUFVLENBZ0RSLG1CQUFtQixDQUFDLEVBQ2xCLE1BQU0sRUFBRSxDQUFDLEVBQ1QsT0FBTyxFQUFFLEVBQUUsR0FDWjs7QUN6REwsQUFBQSxNQUFNLENBQUMsRUFDTCxNQUFNLEVyQ21EQyxPQUFNLENxQ25EUyxLQUFLLENyQ21CZCxPQUF5QixFcUNsQnRDLGFBQWEsRXJDbUROLE1BQUssRXFDbERaLE9BQU8sRUFBRSxJQUFJLEVBQ2IsY0FBYyxFQUFFLE1BQU0sR0FpQnZCOztBQXJCRCxBQU1FLE1BTkksQ0FNSixhQUFhLEVBTmYsTUFBTSxDQU9KLGFBQWEsQ0FBQyxFQUNaLElBQUksRUFBRSxRQUFRLEVBQ2QsT0FBTyxFckNnREYsTUFBSyxHcUMvQ1g7O0FBVkgsQUFZRSxNQVpJLENBWUosVUFBVSxDQUFDLEVBQ1QsSUFBSSxFQUFFLFFBQVEsR0FDZjs7QUFkSCxBQWdCRSxNQWhCSSxDQWdCSixXQUFXLENBQUMsRUFDVixJQUFJLEVBQUUsUUFBUSxFQUNkLFVBQVUsRUFBRSxJQUFJLEVBQ2hCLE9BQU8sRUFBRSxDQUFDLENyQ3NDTCxNQUFLLEdxQ3JDWDs7QUNwQkgsQUFBQSxRQUFRLENBQUMsRUFDUCxPQUFPLEVBQUUsWUFBWSxFQUNyQixRQUFRLEVBQUUsUUFBUSxHQTZEbkI7O0FBL0RELEFBSUUsUUFKTSxDQUlOLGtCQUFrQixDQUFDLEVBQ2pCLElBQUksRUFBRSxHQUFHLEVBQ1QsT0FBTyxFQUFFLENBQUMsRUFDVixPQUFPLEV0Q2dERixNQUFLLEVzQy9DVixRQUFRLEVBQUUsUUFBUSxFQUNsQixHQUFHLEVBQUUsQ0FBQyxFQUNOLFNBQVMsRUFBRSxxQkFBcUIsQ0FBQyxRQUFRLEVBQ3pDLFVBQVUsRUFBRSxrQkFBa0IsRUFDOUIsS0FBSyxFdENrRlUsS0FBSyxFc0NqRnBCLE9BQU8sRXRDb0dBLEdBQUcsR3NDbkdYOztBQWRILEFBZ0JFLFFBaEJNLENBZ0JOLENBQUMsQUFBQSxNQUFNLEdBQUcsa0JBQWtCLEVBaEI5QixRQUFRLEFBaUJMLE1BQU0sQ0FBQyxrQkFBa0IsQ0FBQyxFQUN6QixPQUFPLEVBQUUsS0FBSyxFQUNkLE9BQU8sRUFBRSxDQUFDLEVBQ1YsU0FBUyxFQUFFLHNCQUFzQixHQUNsQzs7QUFyQkgsQUF3QkksUUF4QkksQUF1QkwsY0FBYyxDQUNiLGtCQUFrQixDQUFDLEVBQ2pCLElBQUksRUFBRSxJQUFJLEVBQ1YsR0FBRyxFQUFFLEdBQUcsR0FDVDs7QUEzQkwsQUE2QkksUUE3QkksQUF1QkwsY0FBYyxDQU1iLENBQUMsQUFBQSxNQUFNLEdBQUcsa0JBQWtCLEVBN0JoQyxRQUFRLEFBdUJMLGNBQWMsQUFPWixNQUFNLENBQUMsa0JBQWtCLENBQUMsRUFDekIsU0FBUyxFQUFFLGtCQUFrQixHQUM5Qjs7QUFoQ0wsQUFvQ0ksUUFwQ0ksQUFtQ0wsZUFBZSxDQUNkLGtCQUFrQixDQUFDLEVBQ2pCLElBQUksRUFBRSxHQUFHLEVBQ1QsR0FBRyxFQUFFLElBQUksR0FDVjs7QUF2Q0wsQUF5Q0ksUUF6Q0ksQUFtQ0wsZUFBZSxDQU1kLENBQUMsQUFBQSxNQUFNLEdBQUcsa0JBQWtCLEVBekNoQyxRQUFRLEFBbUNMLGVBQWUsQUFPYixNQUFNLENBQUMsa0JBQWtCLENBQUMsRUFDekIsU0FBUyxFQUFFLGtCQUFrQixHQUM5Qjs7QUE1Q0wsQUFnREksUUFoREksQUErQ0wsYUFBYSxDQUNaLGtCQUFrQixDQUFDLEVBQ2pCLElBQUksRUFBRSxDQUFDLEVBQ1AsR0FBRyxFQUFFLEdBQUcsR0FDVDs7QUFuREwsQUFxREksUUFyREksQUErQ0wsYUFBYSxDQU1aLENBQUMsQUFBQSxNQUFNLEdBQUcsa0JBQWtCLEVBckRoQyxRQUFRLEFBK0NMLGFBQWEsQUFPWCxNQUFNLENBQUMsa0JBQWtCLENBQUMsRUFDekIsU0FBUyxFQUFFLHNCQUFzQixHQUNsQzs7QUF4REwsQUEyREUsUUEzRE0sQ0EyRE4sS0FBSyxDQUFDLEU5QnJETixVQUFVLEVBQUUsQ0FBQyxDOEJzRGEsTUFBSyxDOUJ0RFQsTUFBc0IsQ1JRakMscUJBQU8sRXNDK0NoQixNQUFNLEVBQUUsQ0FBQyxHQUNWOztBQzlESCxBQUFBLEtBQUssQ0FBQyxFQUNKLE9BQU8sRUFBRSxJQUFJLEVBQ2IsU0FBUyxFQUFFLE1BQU0sRUFDakIsVUFBVSxFQUFFLElBQUksRUFDaEIsTUFBTSxFdkNrREMsTUFBSyxDdUNsREksQ0FBQyxFQUNqQixLQUFLLEVBQUUsSUFBSSxHQStEWjs7QUFwRUQsQUFPRSxLQVBHLENBT0gsVUFBVSxDQUFDLEVBQ1QsSUFBSSxFQUFFLEtBQUssRUFDWCxVQUFVLEVBQUUsQ0FBQyxFQUNiLFVBQVUsRUFBRSxJQUFJLEVBQ2hCLFVBQVUsRUFBRSxNQUFNLEVBQ2xCLFFBQVEsRUFBRSxRQUFRLEdBdURuQjs7QUFuRUgsQUFjSSxLQWRDLENBT0gsVUFBVSxBQU9QLElBQUssQ3RCMkpBLFlBQVksQ3NCM0pDLFFBQVEsQ0FBQyxFQUMxQixVQUFVLEV2Q1RBLE9BQU8sRXVDVWpCLE9BQU8sRUFBRSxFQUFFLEVBQ1gsTUFBTSxFQUFFLEdBQUcsRUFDWCxJQUFJLEVBQUUsSUFBSSxFQUNWLFFBQVEsRUFBRSxRQUFRLEVBQ2xCLEdBQUcsRUFBRSxHQUFHLEVBQ1IsS0FBSyxFQUFFLElBQUksR0FDWjs7QUF0QkwsQUF3QkksS0F4QkMsQ0FPSCxVQUFVLENBaUJSLENBQUMsQ0FBQyxFQUNBLEtBQUssRXZDVEUsT0FBeUIsRXVDVWhDLE9BQU8sRUFBRSxZQUFZLEVBQ3JCLE9BQU8sRUFBRSxXQUFXLEVBQ3BCLGVBQWUsRUFBRSxJQUFJLEdBZ0J0Qjs7QUE1Q0wsQUE4Qk0sS0E5QkQsQ0FPSCxVQUFVLENBaUJSLENBQUMsQUFNRSxRQUFRLENBQUMsRUFDUixVQUFVLEV2Q3pCRixPQUFPLEV1QzBCZixNQUFNLEV2Q3FCTCxNQUFLLEN1Q3JCbUIsS0FBSyxDdkNqQnhCLElBQUksRXVDa0JWLGFBQWEsRUFBRSxHQUFHLEVBQ2xCLE9BQU8sRUFBRSxFQUFFLEVBQ1gsT0FBTyxFQUFFLEtBQUssRUFDZCxNQUFNLEV2Q29CTCxNQUFLLEV1Q25CTixJQUFJLEVBQUUsR0FBRyxFQUNULFFBQVEsRUFBRSxRQUFRLEVBQ2xCLEdBQUcsRXZDZUYsTUFBSyxFdUNkTixTQUFTLEVBQUUsZ0JBQWdCLEVBQzNCLEtBQUssRXZDZUosTUFBSyxFdUNkTixPQUFPLEV2Q29FSixDQUFDLEd1Q25FTDs7QUEzQ1AsQUFnRFEsS0FoREgsQ0FPSCxVQUFVLEFBdUNQLE9BQU8sQ0FDTixDQUFDLEFBQ0UsUUFBUSxDQUFDLEVBQ1IsVUFBVSxFdkNsQ04sSUFBSSxFdUNtQ1IsTUFBTSxFdkNHUCxNQUFLLEN1Q0hxQixLQUFLLEN2QzVDeEIsT0FBTyxHdUM2Q2Q7O0FBbkRULEFBdURRLEtBdkRILENBT0gsVUFBVSxBQXVDUCxPQUFPLEdBUUYsVUFBVSxBQUNYLFFBQVEsQ0FBQyxFQUNSLFVBQVUsRXZDcENMLE9BQXlCLEd1Q3FDL0I7O0FBekRULEFBNkRVLEtBN0RMLENBT0gsVUFBVSxBQXVDUCxPQUFPLEdBUUYsVUFBVSxDQUtaLENBQUMsQUFFRSxRQUFRLENBQUMsRUFDUixVQUFVLEV2QzVDSCxPQUF5QixHdUM2Q2pDOztBQy9EWCxBQUFBLElBQUksQ0FBQyxFQUNILFdBQVcsRUFBRSxNQUFNLEVBQ25CLGFBQWEsRXhDa0ROLE9BQU0sQ3dDbERnQixLQUFLLEN4Q2tCckIsT0FBeUIsRXdDakJ0QyxPQUFPLEVBQUUsSUFBSSxFQUNiLFNBQVMsRUFBRSxJQUFJLEVBQ2YsVUFBVSxFQUFFLElBQUksRUFDaEIsTUFBTSxFeENnREMsTUFBSyxDd0NoREksQ0FBQyxDQUFDLE9BQXlCLENBQUMsQ0FBQyxHQTBEOUM7O0FBaEVELEFBUUUsSUFSRSxDQVFGLFNBQVMsQ0FBQyxFQUNSLFVBQVUsRUFBRSxDQUFDLEdBNEJkOztBQXJDSCxBQVdJLElBWEEsQ0FRRixTQUFTLENBR1AsQ0FBQyxDQUFDLEVBQ0EsYUFBYSxFeEN5Q1YsTUFBSyxDd0N6Q3dCLEtBQUssQ0FBQyxXQUFXLEVBQ2pELEtBQUssRUFBRSxPQUFPLEVBQ2QsT0FBTyxFQUFFLEtBQUssRUFDZCxNQUFNLEVBQUUsQ0FBQyxDeEN3Q04sTUFBSyxDd0N4Q1UsQ0FBQyxDQUFDLENBQUMsRUFDckIsT0FBTyxFeEN1Q0osTUFBSyxDQURMLE1BQUssQ3dDdENpQixNQUEwQixDeENzQ2hELE1BQUssRXdDckNSLGVBQWUsRUFBRSxJQUFJLEdBS3RCOztBQXRCTCxBQWtCTSxJQWxCRixDQVFGLFNBQVMsQ0FHUCxDQUFDLEFBT0UsTUFBTSxFQWxCYixJQUFJLENBUUYsU0FBUyxDQUdQLENBQUMsQUFRRSxNQUFNLENBQUMsRUFDTixLQUFLLEV4Q2RHLE9BQU8sR3dDZWhCOztBQXJCUCxBQXVCSSxJQXZCQSxDQVFGLFNBQVMsQUFlTixPQUFPLENBQUMsQ0FBQyxFQXZCZCxJQUFJLENBUUYsU0FBUyxDQWdCUCxDQUFDLEFBQUEsT0FBTyxDQUFDLEVBQ1AsbUJBQW1CLEV4Q25CVCxPQUFPLEV3Q29CakIsS0FBSyxFeENwQkssT0FBTyxHd0NxQmxCOztBQTNCTCxBQTZCSSxJQTdCQSxDQVFGLFNBQVMsQUFxQk4sV0FBVyxDQUFDLEVBQ1gsSUFBSSxFQUFFLFFBQVEsRUFDZCxVQUFVLEVBQUUsS0FBSyxHQUNsQjs7QUFoQ0wsQUFrQ0ksSUFsQ0EsQ0FRRixTQUFTLENBMEJQLFVBQVUsQ0FBQyxFQUNULFVBQVUsRXhDbUJQLE9BQUssR3dDbEJUOztBQXBDTCxBQXdDSSxJQXhDQSxBQXVDRCxVQUFVLENBQ1QsU0FBUyxDQUFDLEVBQ1IsSUFBSSxFQUFFLEtBQUssRUFDWCxVQUFVLEVBQUUsTUFBTSxHQWNuQjs7QUF4REwsQUE0Q00sSUE1Q0YsQUF1Q0QsVUFBVSxDQUNULFNBQVMsQ0FJUCxDQUFDLENBQUMsRUFDQSxNQUFNLEVBQUUsQ0FBQyxHQUNWOztBQTlDUCxBQWlEUSxJQWpESixBQXVDRCxVQUFVLENBQ1QsU0FBUyxDQVFQLE1BQU0sQ0FDSCxBQUFBLFVBQUMsQUFBQSxDQUFXLE9BQU8sQ0FBQyxFQUNuQixRQUFRLEVBQUUsUUFBUSxFQUNsQixLQUFLLEV4Q0VOLE1BQUssRXdDREosR0FBRyxFeENDSixNQUFLLEV3Q0FKLFNBQVMsRUFBRSxlQUFlLEdBQzNCOztBQXREVCxBQTRESSxJQTVEQSxBQTJERCxJQUFLLENBQUEsVUFBVSxFQUNkLE1BQU0sQ0FBQyxFQUNMLGFBQWEsRUFBRSxDQUFDLEdBQ2pCOztBQzlETCxBQUFBLEtBQUssQ0FBQyxFQUNKLGFBQWEsRUFBRSxhQUFhLEVBQzVCLFdBQVcsRUFBRSxVQUFVLEVBQ3ZCLE9BQU8sRUFBRSxJQUFJLEdBaUNkOztBQXBDRCxBQUtFLEtBTEcsQ0FLSCxVQUFVLEVBTFosS0FBSyxDQU1ILFlBQVksQ0FBQyxFQUNYLElBQUksRUFBRSxRQUFRLEdBQ2Y7O0FBUkgsQUFTRSxLQVRHLENBU0gsYUFBYSxDQUFDLEVBQ1osSUFBSSxFQUFFLFFBQVEsR0FPZjs7QUFqQkgsQUFXSSxLQVhDLENBU0gsYUFBYSxBQUVWLElBQUssQ3hCOEpBLFlBQVksRXdCOUpFLEVBQ2xCLFlBQVksRXpDMkNULE1BQUssR3lDMUNUOztBQWJMLEFBY0ksS0FkQyxDQVNILGFBQWEsQUFLVixJQUFLLEN4QnVKWSxXQUFXLEV3QnZKVixFQUNqQixhQUFhLEV6Q3dDVixNQUFLLEd5Q3ZDVDs7QUFoQkwsQUFrQkUsS0FsQkcsQ0FrQkgsV0FBVyxFQWxCYixLQUFLLENBbUJILGNBQWMsQ0FBQyxFQUNiLFdBQVcsRXpDcURELE1BQU0sR3lDcERqQjs7QUFyQkgsQUF1QkUsS0F2QkcsQUF1QkYsY0FBYyxDQUFDLEVBQ2QsV0FBVyxFQUFFLE1BQU0sR0FXcEI7O0FBbkNILEFBMEJJLEtBMUJDLEFBdUJGLGNBQWMsQ0FHYixhQUFhLENBQUMsRUFDWixRQUFRLEVBQUUsTUFBTSxHQUNqQjs7QUE1QkwsQUE4QkksS0E5QkMsQUF1QkYsY0FBYyxDQU9iLFdBQVcsRUE5QmYsS0FBSyxBQXVCRixjQUFjLENBUWIsY0FBYyxDQUFDLEVoQzlCakIsUUFBUSxFQUFFLE1BQU0sRUFDaEIsYUFBYSxFQUFFLFFBQVEsRUFDdkIsV0FBVyxFQUFFLE1BQU0sRWdDOEJmLGFBQWEsRUFBRSxDQUFDLEdBQ2pCOztBQ2xDTCxBQUFBLE1BQU0sQ0FBQyxFaENDTCxVQUFVLEVWYUMscUJBQU8sRVVabEIsWUFBWSxFVllELE9BQU8sRTBDWmxCLE1BQU0sRTFDa0RDLE9BQU0sQzBDbERTLEtBQUssQzFDWWhCLE9BQU8sRTBDWGxCLGFBQWEsRTFDa0ROLE1BQUssRTBDakRaLEtBQUssRTFDV08sSUFBSSxFMENWaEIsT0FBTyxFQUFFLEtBQUssRUFDZCxPQUFPLEUxQ2lEQSxNQUFLLEUwQ2hEWixLQUFLLEVBQUUsSUFBSSxHQWlDWjs7QUF4Q0QsQUFTRSxNQVRJLEFBU0gsY0FBYyxDQUFDLEVoQ1JoQixVQUFVLEVWS0ksc0JBQU8sRVVKckIsWUFBWSxFVklFLE9BQU8sRzBDS3BCOztBQVhILEFBYUUsTUFiSSxBQWFILGNBQWMsQ0FBQyxFaENaaEIsVUFBVSxFVjBCSSxzQkFBTyxFVXpCckIsWUFBWSxFVnlCRSxPQUFPLEcwQ1pwQjs7QUFmSCxBQWlCRSxNQWpCSSxBQWlCSCxjQUFjLENBQUMsRWhDaEJoQixVQUFVLEVWMkJJLHVCQUFPLEVVMUJyQixZQUFZLEVWMEJFLE9BQU8sRzBDVHBCOztBQW5CSCxBQXFCRSxNQXJCSSxBQXFCSCxZQUFZLENBQUMsRWhDcEJkLFVBQVUsRVY0QkUsc0JBQU8sRVUzQm5CLFlBQVksRVYyQkEsT0FBTyxHMENObEI7O0FBdkJILEFBeUJFLE1BekJJLENBeUJKLENBQUMsQ0FBQyxFQUNBLEtBQUssRTFDWEssSUFBSSxFMENZZCxlQUFlLEVBQUUsU0FBUyxHQVEzQjs7QUFuQ0gsQUE2QkksTUE3QkUsQ0F5QkosQ0FBQyxBQUlFLE1BQU0sRUE3QlgsTUFBTSxDQXlCSixDQUFDLEFBS0UsTUFBTSxFQTlCWCxNQUFNLENBeUJKLENBQUMsQUFNRSxPQUFPLEVBL0JaLE1BQU0sQ0F5QkosQ0FBQyxBQU9FLE9BQU8sQ0FBQyxFQUNQLE9BQU8sRUFBRSxHQUFHLEdBQ2I7O0FBbENMLEFBcUNFLE1BckNJLENBcUNKLFVBQVUsQ0FBQyxFQUNULE1BQU0sRUFBRSxnQkFBZ0IsR0FDekI7O0FDdkNILEFBQUEsUUFBUSxDQUFDLEVBQ1AsUUFBUSxFQUFFLFFBQVEsR0E0RW5COztBQTdFRCxBQUVFLFFBRk0sQUFFTCxPQUFPLENBQUMsRUFDUCxVQUFVLEUzQ1dELHFCQUFPLEUyQ1ZoQixhQUFhLEUzQ2lEUixNQUFLLEUyQ2hEVixNQUFNLEVBQUUsSUFBSSxFQUNaLEtBQUssRTNDU0ssSUFBSSxFMkNSZCxPQUFPLEVBQUUsa0JBQWtCLEVBQzNCLE9BQU8sRUFBRSxLQUFLLEVBQ2QsU0FBUyxFM0M4REUsTUFBSyxFMkM3RGhCLElBQUksRUFBRSxHQUFHLEVBQ1QsU0FBUyxFM0NtRk0sS0FBSyxFMkNsRnBCLE9BQU8sRUFBRSxDQUFDLEVBQ1YsUUFBUSxFQUFFLE1BQU0sRUFDaEIsT0FBTyxFM0N3Q0YsTUFBSyxDQUNMLE1BQUssRTJDeENWLGNBQWMsRUFBRSxJQUFJLEVBQ3BCLFFBQVEsRUFBRSxRQUFRLEVBQ2xCLGFBQWEsRUFBRSxRQUFRLEVBQ3ZCLFNBQVMsRUFBRSx1QkFBd0IsRUFDbkMsVUFBVSxFQUFFLFlBQVksRUFDeEIsV0FBVyxFQUFFLEdBQUcsRUFDaEIsT0FBTyxFM0M0RkEsR0FBRyxHMkMzRlg7O0FBdEJILEFBeUJJLFFBekJJLEFBdUJMLE1BQU0sQUFFSixPQUFPLEVBekJaLFFBQVEsQUF3QkwsTUFBTSxBQUNKLE9BQU8sQ0FBQyxFQUNQLE9BQU8sRUFBRSxDQUFDLEVBQ1YsU0FBUyxFQUFFLHdCQUF5QixHQUNyQzs7QUE1QkwsQUE4QkUsUUE5Qk0sQ0E4QkwsQUFBQSxRQUFDLEFBQUEsR0E5QkosUUFBUSxBQStCTCxTQUFTLENBQUMsRUFDVCxjQUFjLEVBQUUsSUFBSSxHQUNyQjs7QUFqQ0gsQUFvQ0ksUUFwQ0ksQUFtQ0wsY0FBYyxBQUNaLE9BQU8sQ0FBQyxFQUNQLE1BQU0sRUFBRSxHQUFHLEVBQ1gsSUFBSSxFQUFFLElBQUksRUFDVixTQUFTLEVBQUUsdUJBQXdCLEdBQ3BDOztBQXhDTCxBQTJDTSxRQTNDRSxBQW1DTCxjQUFjLEFBTVosTUFBTSxBQUVKLE9BQU8sRUEzQ2QsUUFBUSxBQW1DTCxjQUFjLEFBT1osTUFBTSxBQUNKLE9BQU8sQ0FBQyxFQUNQLFNBQVMsRUFBRSxzQkFBdUIsR0FDbkM7O0FBN0NQLEFBa0RJLFFBbERJLEFBaURMLGVBQWUsQUFDYixPQUFPLENBQUMsRUFDUCxNQUFNLEVBQUUsSUFBSSxFQUNaLEdBQUcsRUFBRSxJQUFJLEVBQ1QsU0FBUyxFQUFFLHdCQUF5QixHQUNyQzs7QUF0REwsQUF5RE0sUUF6REUsQUFpREwsZUFBZSxBQU1iLE1BQU0sQUFFSixPQUFPLEVBekRkLFFBQVEsQUFpREwsZUFBZSxBQU9iLE1BQU0sQUFDSixPQUFPLENBQUMsRUFDUCxTQUFTLEVBQUUsdUJBQXdCLEdBQ3BDOztBQTNEUCxBQWdFSSxRQWhFSSxBQStETCxhQUFhLEFBQ1gsT0FBTyxDQUFDLEVBQ1AsTUFBTSxFQUFFLEdBQUcsRUFDWCxJQUFJLEVBQUUsSUFBSSxFQUNWLEtBQUssRUFBRSxJQUFJLEVBQ1gsU0FBUyxFQUFFLHNCQUF1QixHQUNuQzs7QUFyRUwsQUF3RU0sUUF4RUUsQUErREwsYUFBYSxBQU9YLE1BQU0sQUFFSixPQUFPLEVBeEVkLFFBQVEsQUErREwsYUFBYSxBQVFYLE1BQU0sQUFDSixPQUFPLENBQUMsRUFDUCxTQUFTLEVBQUUsdUJBQXdCLEdBQ3BDOztBL0JqRFAsQUFBQSxJQUFJLENnQzFCQyxFQUNILE9BQU8sRUFBRSxNQUFNLEdBQ2hCOztBQUVELEFBQUEsR0FBRyxBQUFBLEtBQUssQ0FBQyxFQUNQLEtBQUssRUFBRSxLQUFLLEVBQ1osYUFBYSxFQUFFLElBQUksR0FDcEI7O0FBRUQsQUFBQSxFQUFFLEVBQUUsRUFBRSxDQUFDLEVBQ0wsV0FBVyxFQUFFLEdBQUcsR0FDakI7O0FBRUQsQUFBQSxPQUFPLENBQUMsRUFDTixLQUFLLEU1Q0dNLE9BQXlCLEU0Q0ZwQyxVQUFVLEVBQUUsSUFBSSxHQU9qQjs7QUFURCxBQUlFLE9BSkssQ0FJTCxHQUFHLENBQUMsRUFDRixNQUFNLEVBQUUsSUFBSSxFQUNaLGNBQWMsRUFBRSxNQUFNLEVBQ3RCLE1BQU0sRUFBRSxRQUFRLEdBQ2pCOztBQUdILEFBQ0UsTUFESSxDQUNKLElBQUksQ0FBQyxFQUNILFdBQVcsRUFBRSxJQUFJLEVBQ2pCLGVBQWUsRUFBRSxlQUFlLEdBSWpDOztBQVBILEFBSUksTUFKRSxDQUNKLElBQUksQ0FHRixDQUFDLENBQUMsRUFDQSxZQUFZLEVBQUUsTUFBTSxHQUNyQjs7QUFJTCxBQUFBLEVBQUUsQUFBQSxTQUFTLENBQUMsRUFDVixNQUFNLEVBQUUsTUFBTSxHQWdCZjs7QUFqQkQsQUFHRSxFQUhBLEFBQUEsU0FBUyxDQUdULEVBQUUsQ0FBQyxFQUNELE1BQU0sRUFBRSxDQUFDLEdBQ1Y7O0FBTEgsQUFPRSxFQVBBLEFBQUEsU0FBUyxDQU9ULEVBQUUsQUFBQSxLQUFLLENBQUMsRUFDTixhQUFhLEVBQUUsSUFBSSxHQVFwQjs7QUFoQkgsQUFXTSxFQVhKLEFBQUEsU0FBUyxDQU9ULEVBQUUsQUFBQSxLQUFLLENBR0wsTUFBTSxDQUNKLElBQUksQ0FBQyxFQUNILEtBQUssRUFBRSxLQUFLLEVBQ1osVUFBVSxFQUFFLElBQUksR0FDakI7O0FBS1AsQUFBQSxFQUFFLEFBQUEsUUFBUSxDQUFDLEVBQ1QsTUFBTSxFQUFFLE1BQU0sRUFDZCxVQUFVLEVBQUUsSUFBSSxFQUNoQixTQUFTLEVBQUUsR0FBRyxHQWVmOztBQWxCRCxBQUtFLEVBTEEsQUFBQSxRQUFRLENBS1IsVUFBVSxDQUFDLEVBQ1QsVUFBVSxFQUFFLGdCQUFnQixFQUM1QixVQUFVLEVBQUUsR0FBRyxDQUFDLEtBQUssQzVDdkNWLE9BQXlCLEU0Q3dDcEMsV0FBVyxFQUFFLE1BQU0sR0FLcEI7O0FBYkgsQUFVSSxFQVZGLEFBQUEsUUFBUSxDQUtSLFVBQVUsQUFLUCxZQUFZLENBQUMsRUFDWixNQUFNLEVBQUUsSUFBSSxHQUNiOztBQVpMLEFBZUUsRUFmQSxBQUFBLFFBQVEsQ0FlUixXQUFXLENBQUMsRUFDVixPQUFPLEVBQUUsQ0FBQyxHQUNYOztBQ3JFSCxVQUFVLENBQVYsT0FBVSxHQUNSLEVBQUUsR0FDQSxTQUFTLEVBQUUsWUFBWTtFQUV6QixJQUFJLEdBQ0YsU0FBUyxFQUFFLGNBQWM7O0FBSTdCLFVBQVUsQ0FBVixVQUFVLEdBQ1IsRUFBRSxHQUNBLE9BQU8sRUFBRSxDQUFDO0lBQ1YsU0FBUyxFQUFFLG1CQUFvQjtFQUVqQyxJQUFJLEdBQ0YsT0FBTyxFQUFFLENBQUM7SUFDVixTQUFTLEVBQUUsYUFBYTs7QXhDSjFCLEFBQUEsYUFBYSxDQUFKLEVBQ1AsS0FBSyxFTFBPLE9BQU8sR0tRcEI7O0FBRUQsQUFDRSxDQURELEFBQUEsYUFBYSxBQUNYLE1BQU0sRUFEVCxDQUFDLEFBQUEsYUFBYSxBQUVYLE1BQU0sQ0FBQyxFQUNOLEtBQUssRUFBRSxPQUFrQixHQUMxQjs7QUFKSCxBQUtFLENBTEQsQUFBQSxhQUFhLEFBS1gsUUFBUSxDQUFDLEVBQ1IsS0FBSyxFQUFFLE9BQW1CLEdBQzNCOztBQVhILEFBQUEsZUFBZSxDQUFOLEVBQ1AsS0FBSyxFTEhjLE9BQTRCLEdLSWhEOztBQUVELEFBQ0UsQ0FERCxBQUFBLGVBQWUsQUFDYixNQUFNLEVBRFQsQ0FBQyxBQUFBLGVBQWUsQUFFYixNQUFNLENBQUMsRUFDTixLQUFLLEVBQUUsT0FBa0IsR0FDMUI7O0FBSkgsQUFLRSxDQUxELEFBQUEsZUFBZSxBQUtiLFFBQVEsQ0FBQyxFQUNSLEtBQUssRUFBRSxPQUFtQixHQUMzQjs7QUFYSCxBQUFBLFVBQVUsQ0FBRCxFQUNQLEtBQUssRUxHSSxPQUF5QixHS0ZuQzs7QUFFRCxBQUNFLENBREQsQUFBQSxVQUFVLEFBQ1IsTUFBTSxFQURULENBQUMsQUFBQSxVQUFVLEFBRVIsTUFBTSxDQUFDLEVBQ04sS0FBSyxFQUFFLE9BQWtCLEdBQzFCOztBQUpILEFBS0UsQ0FMRCxBQUFBLFVBQVUsQUFLUixRQUFRLENBQUMsRUFDUixLQUFLLEVBQUUsT0FBbUIsR0FDM0I7O0FBWEgsQUFBQSxXQUFXLENBQUYsRUFDUCxLQUFLLEVMRUssSUFBSSxHS0RmOztBQUVELEFBQ0UsQ0FERCxBQUFBLFdBQVcsQUFDVCxNQUFNLEVBRFQsQ0FBQyxBQUFBLFdBQVcsQUFFVCxNQUFNLENBQUMsRUFDTixLQUFLLEVBQUUsT0FBa0IsR0FDMUI7O0FBSkgsQUFLRSxDQUxELEFBQUEsV0FBVyxBQUtULFFBQVEsQ0FBQyxFQUNSLEtBQUssRUFBRSxLQUFtQixHQUMzQjs7QUFYSCxBQUFBLFVBQVUsQ0FBRCxFQUNQLEtBQUssRUxzQlMsT0FBd0IsR0tyQnZDOztBQUVELEFBQ0UsQ0FERCxBQUFBLFVBQVUsQUFDUixNQUFNLEVBRFQsQ0FBQyxBQUFBLFVBQVUsQUFFUixNQUFNLENBQUMsRUFDTixLQUFLLEVBQUUsT0FBa0IsR0FDMUI7O0FBSkgsQUFLRSxDQUxELEFBQUEsVUFBVSxBQUtSLFFBQVEsQ0FBQyxFQUNSLEtBQUssRUFBRSxPQUFtQixHQUMzQjs7QUFYSCxBQUFBLGFBQWEsQ0FBSixFQUNQLEtBQUssRUxjTyxPQUFPLEdLYnBCOztBQUVELEFBQ0UsQ0FERCxBQUFBLGFBQWEsQUFDWCxNQUFNLEVBRFQsQ0FBQyxBQUFBLGFBQWEsQUFFWCxNQUFNLENBQUMsRUFDTixLQUFLLEVBQUUsT0FBa0IsR0FDMUI7O0FBSkgsQUFLRSxDQUxELEFBQUEsYUFBYSxBQUtYLFFBQVEsQ0FBQyxFQUNSLEtBQUssRUFBRSxPQUFtQixHQUMzQjs7QUFYSCxBQUFBLGFBQWEsQ0FBSixFQUNQLEtBQUssRUxlTyxPQUFPLEdLZHBCOztBQUVELEFBQ0UsQ0FERCxBQUFBLGFBQWEsQUFDWCxNQUFNLEVBRFQsQ0FBQyxBQUFBLGFBQWEsQUFFWCxNQUFNLENBQUMsRUFDTixLQUFLLEVBQUUsT0FBa0IsR0FDMUI7O0FBSkgsQUFLRSxDQUxELEFBQUEsYUFBYSxBQUtYLFFBQVEsQ0FBQyxFQUNSLEtBQUssRUFBRSxPQUFtQixHQUMzQjs7QUFYSCxBQUFBLFdBQVcsQ0FBRixFQUNQLEtBQUssRUxnQkssT0FBTyxHS2ZsQjs7QUFFRCxBQUNFLENBREQsQUFBQSxXQUFXLEFBQ1QsTUFBTSxFQURULENBQUMsQUFBQSxXQUFXLEFBRVQsTUFBTSxDQUFDLEVBQ04sS0FBSyxFQUFFLE9BQWtCLEdBQzFCOztBQUpILEFBS0UsQ0FMRCxBQUFBLFdBQVcsQUFLVCxRQUFRLENBQUMsRUFDUixLQUFLLEVBQUUsT0FBbUIsR0FDM0I7O0FBdEJILEFBQUEsV0FBVyxDQUFGLEVBQ1AsVUFBVSxFTElFLE9BQU8sRUtEakIsS0FBSyxFTFVHLElBQUksR0tSZjs7QUFORCxBQUFBLGFBQWEsQ0FBSixFQUNQLFVBQVUsRUxPSSxPQUE4QixHS0Y3Qzs7QUFORCxBQUFBLFFBQVEsQ0FBQyxFQUNQLFVBQVUsRUxZRCxPQUFPLEVLVGQsS0FBSyxFTFVHLElBQUksR0tSZjs7QUFORCxBQUFBLFFBQVEsQ0FBQyxFQUNQLFVBQVUsRUxvQkgsT0FBeUIsR0tmakM7O0FBTkQsQUFBQSxXQUFXLENBQUYsRUFDUCxVQUFVLEVMeUJFLE9BQU8sRUt0QmpCLEtBQUssRUxVRyxJQUFJLEdLUmY7O0FBTkQsQUFBQSxXQUFXLENBQUYsRUFDUCxVQUFVLEVMMEJFLE9BQU8sRUt2QmpCLEtBQUssRUxVRyxJQUFJLEdLUmY7O0FBTkQsQUFBQSxTQUFTLENBQUEsRUFDUCxVQUFVLEVMMkJBLE9BQU8sR0t0QmxCOztBMkNQSCxBQUFBLE9BQU8sQ0FBQyxFQUNOLE1BQU0sRUFBRSxPQUFPLEdBQ2hCOztBQUVELEFBQUEsT0FBTyxDQUFDLEVBQ04sTUFBTSxFQUFFLElBQUksR0FDYjs7QUFFRCxBQUFBLFVBQVUsQ0FBQyxFQUNULE1BQU0sRUFBRSxPQUFPLEdBQ2hCOztBQUVELEFBQUEsV0FBVyxDQUFDLEVBQ1YsTUFBTSxFQUFFLFFBQVEsR0FDakI7O0FBRUQsQUFBQSxjQUFjLENBQUMsRUFDYixNQUFNLEVBQUUsV0FBVyxHQUNwQjs7QUFFRCxBQUFBLE9BQU8sQ0FBQyxFQUNOLE1BQU0sRUFBRSxJQUFJLEdBQ2I7O0FDdEJELEFBQUEsUUFBUSxDQUFDLEVBQ1AsT0FBTyxFQUFFLEtBQUssR0FDZjs7QUFDRCxBQUFBLFNBQVMsQ0FBQyxFQUNSLE9BQU8sRUFBRSxNQUFNLEdBQ2hCOztBQUNELEFBQUEsZUFBZSxDQUFDLEVBQ2QsT0FBTyxFQUFFLFlBQVksR0FDdEI7O0FBQ0QsQUFBQSxPQUFPLENBQUMsRUFDTixPQUFPLEVBQUUsSUFBSSxHQUNkOztBQUNELEFBQUEsY0FBYyxDQUFDLEVBQ2IsT0FBTyxFQUFFLFdBQVcsR0FDckI7O0FBQ0QsQUFBQSxPQUFPLEVBQ1AsT0FBTyxDQUFDLEVBQ04sT0FBTyxFQUFFLGVBQWUsR0FDekI7O0FBQ0QsQUFBQSxVQUFVLENBQUMsRUFDVCxVQUFVLEVBQUUsT0FBTyxHQUNwQjs7QUFDRCxBQUFBLFlBQVksQ0FBQyxFQUNYLFVBQVUsRUFBRSxNQUFNLEdBQ25COztBQUNELEFBQUEsVUFBVSxDQUFDLEVBQ1QsVUFBVSxFQUFFLFdBQVcsRUFDdkIsTUFBTSxFQUFFLENBQUMsRUFDVCxLQUFLLEVBQUUsV0FBVyxFQUNsQixTQUFTLEVBQUUsQ0FBQyxFQUNaLFdBQVcsRUFBRSxDQUFDLEVBQ2QsV0FBVyxFQUFFLElBQUksR0FDbEI7O0FBQ0QsQUFBQSxlQUFlLENBQUMsRUFDZCxNQUFNLEVBQUUsQ0FBQyxFQUNULElBQUksRUFBRSxnQkFBYSxFQUNuQixNQUFNLEVBQUUsR0FBRyxFQUNYLE1BQU0sRUFBRSxJQUFJLEVBQ1osUUFBUSxFQUFFLE1BQU0sRUFDaEIsT0FBTyxFQUFFLENBQUMsRUFDVixRQUFRLEVBQUUsUUFBUSxFQUNsQixLQUFLLEVBQUUsR0FBRyxHQUNYOztBQzFDRCxBQUFBLFFBQVEsRUFDUixhQUFhLENBQUMsRUFDWixPQUFPLEVBQUUsS0FBSyxFQUNkLFFBQVEsRUFBRSxRQUFRLEdBV25COztBQWRELEFBS0UsUUFMTSxDQUtMLEFBQUEsWUFBQyxBQUFBLENBQWEsT0FBTyxFQUp4QixhQUFhLENBSVYsQUFBQSxZQUFDLEFBQUEsQ0FBYSxPQUFPLENBQUMsRUFDckIsVUFBVSxFbERTQSxJQUFJLEVrRFJkLEtBQUssRWxEU0ksT0FBeUIsRWtEUmxDLE9BQU8sRUFBRSxrQkFBa0IsRUFDM0IsT0FBTyxFQUFFLFlBQVksRUFDckIsU0FBUyxFbEQ2REUsTUFBSyxFa0Q1RGhCLE9BQU8sRUFBRSxDQUFDLENsRDRDTCxNQUFLLEVrRDNDVixTQUFTLEVBQUUsb0JBQTBDLEdBQ3REOztBQUdILEFBQUEsUUFBUSxDQUFDLEVBQ1AsVUFBVSxFbERtQ0gsT0FBTSxDa0RuQ2EsS0FBSyxDbERHbEIsT0FBeUIsRWtERnRDLE1BQU0sRWxEa0NDLE9BQU0sRWtEakNiLE1BQU0sRWxEb0NDLE1BQUssQ2tEcENJLENBQUMsR0FLbEI7O0FBUkQsQUFLRSxRQUxNLENBS0wsQUFBQSxZQUFDLEFBQUEsRUFBYyxFQUNkLE1BQU0sRWxEbUNELE1BQUssQ2tEbkNNLENBQUMsR0FDbEI7O0FBR0gsQUFBQSxhQUFhLENBQUMsRUFDWixPQUFPLEVBQUUsS0FBSyxFQUNkLE9BQU8sRWxENkJBLE1BQUssR2tEVGI7O0FBdEJELEFBSUUsYUFKVyxBQUlWLFFBQVEsQ0FBQyxFQUNSLFdBQVcsRWxEcUJOLE9BQU0sQ2tEckJnQixLQUFLLENsRFhyQixPQUF5QixFa0RZcEMsTUFBTSxFbER1QkQsTUFBSyxFa0R0QlYsT0FBTyxFQUFFLEVBQUUsRUFDWCxPQUFPLEVBQUUsS0FBSyxFQUNkLElBQUksRUFBRSxHQUFHLEVBQ1QsUUFBUSxFQUFFLFFBQVEsRUFDbEIsR0FBRyxFbERrQkUsTUFBSyxFa0RqQlYsU0FBUyxFQUFFLGdCQUFnQixHQUM1Qjs7QUFiSCxBQWVFLGFBZlcsQ0FlVixBQUFBLFlBQUMsQUFBQSxDQUFhLE9BQU8sQ0FBQyxFQUNyQixJQUFJLEVBQUUsR0FBRyxFQUNULE9BQU8sRWxEV0YsTUFBSyxDa0RYTyxDQUFDLEVBQ2xCLFFBQVEsRUFBRSxRQUFRLEVBQ2xCLEdBQUcsRUFBRSxHQUFHLEVBQ1IsU0FBUyxFQUFFLHFCQUFxQixHQUNqQzs7QUMvQ0gsQUFBQSxRQUFRLENBQUMsRUFDUCxLQUFLLEVBQUUsc0JBQXNCLEVBQzdCLFVBQVUsRW5EdURILE1BQUssRW1EdERaLGNBQWMsRUFBRSxJQUFJLEVBQ3BCLFFBQVEsRUFBRSxRQUFRLEdBNEJuQjs7QUFoQ0QsQUFLRSxRQUxNLEFBS0wsT0FBTyxDQUFDLEVBQ1AsU0FBUyxFQUFFLDZCQUE2QixFQUN4QyxNQUFNLEVuRDhDRCxNQUFLLENtRDlDZSxLQUFLLENuRERsQixPQUFPLEVtREVuQixhQUFhLEVBQUUsR0FBRyxFQUNsQixrQkFBa0IsRUFBRSxXQUFXLEVBQy9CLGdCQUFnQixFQUFFLFdBQVcsRUFDN0IsT0FBTyxFQUFFLEVBQUUsRUFDWCxPQUFPLEVBQUUsS0FBSyxFQUNkLE1BQU0sRW5ENENELE1BQUssRW1EM0NWLElBQUksRUFBRSxHQUFHLEVBQ1QsV0FBVyxFbkR3Q04sT0FBSyxFbUR2Q1YsVUFBVSxFbkR1Q0wsT0FBSyxFbUR0Q1YsUUFBUSxFQUFFLFFBQVEsRUFDbEIsR0FBRyxFQUFFLEdBQUcsRUFDUixLQUFLLEVuRHNDQSxNQUFLLEVtRHJDVixPQUFPLEVuRDBGQSxDQUFDLEdtRHpGVDs7QUFyQkgsQUF1QkUsUUF2Qk0sQUF1QkwsV0FBVyxDQUFDLEVBQ1gsVUFBVSxFbkR1Q0osSUFBSSxHbURoQ1g7O0FBL0JILEFBeUJJLFFBekJJLEFBdUJMLFdBQVcsQUFFVCxPQUFPLENBQUMsRUFDUCxNQUFNLEVuRG1DSCxNQUFNLEVtRGxDVCxXQUFXLEVuRDhCUixPQUFLLEVtRDdCUixVQUFVLEVuRDZCUCxPQUFLLEVtRDVCUixLQUFLLEVuRGdDRixNQUFNLEdtRC9CVjs7QUM5QkwsQWhEQ0UsU2dERE8sQWhEQ04sT0FBTyxFa0JEVixVQUFVLEFsQkNQLE9BQU8sQ0FBQyxFQUNQLEtBQUssRUFBRSxJQUFJLEVBQ1gsT0FBTyxFQUFFLEVBQUUsRUFDWCxPQUFPLEVBQUUsS0FBSyxHQUNmOztBZ0RESCxBQUFBLFdBQVcsQ0FBQyxFQUNWLEtBQUssRUFBRSxlQUFlLEdBQ3ZCOztBQUVELEFBQUEsWUFBWSxDQUFDLEVBQ1gsS0FBSyxFQUFFLGdCQUFnQixHQUN4Qjs7QUFFRCxBQUFBLFNBQVMsQ0FBQyxFQUNSLFFBQVEsRUFBRSxtQkFBbUIsR0FDOUI7O0FBRUQsQUFBQSxTQUFTLENBQUMsRUFDUixRQUFRLEVBQUUsbUJBQW1CLEdBQzlCOztBQUVELEFBQUEsTUFBTSxDQUFDLEVBQ0wsUUFBUSxFQUFFLGdCQUFnQixHQUMzQjs7QUFFRCxBQUFBLFNBQVMsQ0FBQyxFQUNSLE9BQU8sRUFBRSxLQUFLLEVBQ2QsS0FBSyxFQUFFLElBQUksRUFDWCxXQUFXLEVBQUUsSUFBSSxFQUNqQixZQUFZLEVBQUUsSUFBSSxHQUNuQjs7QUFFRCxBQUFBLGNBQWMsQ0FBQyxFQUNiLFdBQVcsRUFBRSxNQUFNLEVBQ25CLE9BQU8sRUFBRSxJQUFJLEVBQ2IsZUFBZSxFQUFFLE1BQU0sR0FDeEI7O0E3Q2xDQyxBQUFBLElBQUksQ0FBTSxFQUNSLE1BQU0sRTZDb0NpQixDQUFDLEM3Q3BDVixVQUFVLEdBQ3pCOztBQUVELEFBQUEsS0FBSyxDQUFNLEVBQ1QsYUFBYSxFNkNnQ1UsQ0FBQyxDN0NoQ0gsVUFBVSxHQUNoQzs7QUFFRCxBQUFBLEtBQUssQ0FBTSxFQUNULFdBQVcsRTZDNEJZLENBQUMsQzdDNUJMLFVBQVUsR0FDOUI7O0FBRUQsQUFBQSxLQUFLLENBQU0sRUFDVCxZQUFZLEU2Q3dCVyxDQUFDLEM3Q3hCSixVQUFVLEdBQy9COztBQUVELEFBQUEsS0FBSyxDQUFNLEVBQ1QsVUFBVSxFNkNvQmEsQ0FBQyxDN0NwQk4sVUFBVSxHQUM3Qjs7QUFFRCxBQUFBLEtBQUssQ0FBTSxFQUNULFdBQVcsRTZDZ0JZLENBQUMsQzdDaEJMLFVBQVUsRUFDN0IsWUFBWSxFNkNlVyxDQUFDLEM3Q2ZKLFVBQVUsR0FDL0I7O0FBRUQsQUFBQSxLQUFLLENBQU0sRUFDVCxhQUFhLEU2Q1dVLENBQUMsQzdDWEgsVUFBVSxFQUMvQixVQUFVLEU2Q1VhLENBQUMsQzdDVk4sVUFBVSxHQUM3Qjs7QUE1QkQsQUFBQSxJQUFJLENBQU0sRUFDUixNQUFNLEVQb0RELE1BQUssQ09wREksVUFBVSxHQUN6Qjs7QUFFRCxBQUFBLEtBQUssQ0FBTSxFQUNULGFBQWEsRVBnRFIsTUFBSyxDT2hEVyxVQUFVLEdBQ2hDOztBQUVELEFBQUEsS0FBSyxDQUFNLEVBQ1QsV0FBVyxFUDRDTixNQUFLLENPNUNTLFVBQVUsR0FDOUI7O0FBRUQsQUFBQSxLQUFLLENBQU0sRUFDVCxZQUFZLEVQd0NQLE1BQUssQ094Q1UsVUFBVSxHQUMvQjs7QUFFRCxBQUFBLEtBQUssQ0FBTSxFQUNULFVBQVUsRVBvQ0wsTUFBSyxDT3BDUSxVQUFVLEdBQzdCOztBQUVELEFBQUEsS0FBSyxDQUFNLEVBQ1QsV0FBVyxFUGdDTixNQUFLLENPaENTLFVBQVUsRUFDN0IsWUFBWSxFUCtCUCxNQUFLLENPL0JVLFVBQVUsR0FDL0I7O0FBRUQsQUFBQSxLQUFLLENBQU0sRUFDVCxhQUFhLEVQMkJSLE1BQUssQ08zQlcsVUFBVSxFQUMvQixVQUFVLEVQMEJMLE1BQUssQ08xQlEsVUFBVSxHQUM3Qjs7QUE1QkQsQUFBQSxJQUFJLENBQU0sRUFDUixNQUFNLEVQcURELE1BQUssQ09yREksVUFBVSxHQUN6Qjs7QUFFRCxBQUFBLEtBQUssQ0FBTSxFQUNULGFBQWEsRVBpRFIsTUFBSyxDT2pEVyxVQUFVLEdBQ2hDOztBQUVELEFBQUEsS0FBSyxDQUFNLEVBQ1QsV0FBVyxFUDZDTixNQUFLLENPN0NTLFVBQVUsR0FDOUI7O0FBRUQsQUFBQSxLQUFLLENBQU0sRUFDVCxZQUFZLEVQeUNQLE1BQUssQ096Q1UsVUFBVSxHQUMvQjs7QUFFRCxBQUFBLEtBQUssQ0FBTSxFQUNULFVBQVUsRVBxQ0wsTUFBSyxDT3JDUSxVQUFVLEdBQzdCOztBQUVELEFBQUEsS0FBSyxDQUFNLEVBQ1QsV0FBVyxFUGlDTixNQUFLLENPakNTLFVBQVUsRUFDN0IsWUFBWSxFUGdDUCxNQUFLLENPaENVLFVBQVUsR0FDL0I7O0FBRUQsQUFBQSxLQUFLLENBQU0sRUFDVCxhQUFhLEVQNEJSLE1BQUssQ081QlcsVUFBVSxFQUMvQixVQUFVLEVQMkJMLE1BQUssQ08zQlEsVUFBVSxHQUM3Qjs7QUFLRCxBQUFBLElBQUksQ0FBTSxFQUNSLE9BQU8sRTZDU2lCLENBQUMsQzdDVFYsVUFBVSxHQUMxQjs7QUFFRCxBQUFBLEtBQUssQ0FBTSxFQUNULGNBQWMsRTZDS1UsQ0FBQyxDN0NMSCxVQUFVLEdBQ2pDOztBQUVELEFBQUEsS0FBSyxDQUFNLEVBQ1QsWUFBWSxFNkNDWSxDQUFDLEM3Q0RMLFVBQVUsR0FDL0I7O0FBRUQsQUFBQSxLQUFLLENBQU0sRUFDVCxhQUFhLEU2Q0hXLENBQUMsQzdDR0osVUFBVSxHQUNoQzs7QUFFRCxBQUFBLEtBQUssQ0FBTSxFQUNULFdBQVcsRTZDUGEsQ0FBQyxDN0NPTixVQUFVLEdBQzlCOztBQUVELEFBQUEsS0FBSyxDQUFNLEVBQ1QsWUFBWSxFNkNYWSxDQUFDLEM3Q1dMLFVBQVUsRUFDOUIsYUFBYSxFNkNaVyxDQUFDLEM3Q1lKLFVBQVUsR0FDaEM7O0FBRUQsQUFBQSxLQUFLLENBQU0sRUFDVCxjQUFjLEU2Q2hCVSxDQUFDLEM3Q2dCSCxVQUFVLEVBQ2hDLFdBQVcsRTZDakJhLENBQUMsQzdDaUJOLFVBQVUsR0FDOUI7O0FBNUJELEFBQUEsSUFBSSxDQUFNLEVBQ1IsT0FBTyxFUG1CRixNQUFLLENPbkJLLFVBQVUsR0FDMUI7O0FBRUQsQUFBQSxLQUFLLENBQU0sRUFDVCxjQUFjLEVQZVQsTUFBSyxDT2ZZLFVBQVUsR0FDakM7O0FBRUQsQUFBQSxLQUFLLENBQU0sRUFDVCxZQUFZLEVQV1AsTUFBSyxDT1hVLFVBQVUsR0FDL0I7O0FBRUQsQUFBQSxLQUFLLENBQU0sRUFDVCxhQUFhLEVQT1IsTUFBSyxDT1BXLFVBQVUsR0FDaEM7O0FBRUQsQUFBQSxLQUFLLENBQU0sRUFDVCxXQUFXLEVQR04sTUFBSyxDT0hTLFVBQVUsR0FDOUI7O0FBRUQsQUFBQSxLQUFLLENBQU0sRUFDVCxZQUFZLEVQRFAsTUFBSyxDT0NVLFVBQVUsRUFDOUIsYUFBYSxFUEZSLE1BQUssQ09FVyxVQUFVLEdBQ2hDOztBQUVELEFBQUEsS0FBSyxDQUFNLEVBQ1QsY0FBYyxFUE5ULE1BQUssQ09NWSxVQUFVLEVBQ2hDLFdBQVcsRVBQTixNQUFLLENPT1MsVUFBVSxHQUM5Qjs7QUE1QkQsQUFBQSxJQUFJLENBQU0sRUFDUixPQUFPLEVQb0JGLE1BQUssQ09wQkssVUFBVSxHQUMxQjs7QUFFRCxBQUFBLEtBQUssQ0FBTSxFQUNULGNBQWMsRVBnQlQsTUFBSyxDT2hCWSxVQUFVLEdBQ2pDOztBQUVELEFBQUEsS0FBSyxDQUFNLEVBQ1QsWUFBWSxFUFlQLE1BQUssQ09aVSxVQUFVLEdBQy9COztBQUVELEFBQUEsS0FBSyxDQUFNLEVBQ1QsYUFBYSxFUFFSLE1BQUssQ09SVyxVQUFVLEdBQ2hDOztBQUVELEFBQUEsS0FBSyxDQUFNLEVBQ1QsV0FBVyxFUElOLE1BQUssQ09KUyxVQUFVLEdBQzlCOztBQUVELEFBQUEsS0FBSyxDQUFNLEVBQ1QsWUFBWSxFUEFQLE1BQUssQ09BVSxVQUFVLEVBQzlCLGFBQWEsRVBEUixNQUFLLENPQ1csVUFBVSxHQUNoQzs7QUFFRCxBQUFBLEtBQUssQ0FBTSxFQUNULGNBQWMsRVBMVCxNQUFLLENPS1ksVUFBVSxFQUNoQyxXQUFXLEVQTk4sTUFBSyxDT01TLFVBQVUsR0FDOUI7O0E4QzlESCxBQUFBLFVBQVUsQ0FBQyxFQUNULGFBQWEsRXJEb0ROLE1BQUssR3FEbkRiOztBQUVELEFBQUEsU0FBUyxDQUFDLEVBQ1IsYUFBYSxFQUFFLEdBQUcsR0FDbkI7O0FDTEQsQUFBQSxVQUFVLENBQUMsRUFDVCxVQUFVLEVBQUUsSUFBSSxHQUNqQjs7QUFFRCxBQUFBLFdBQVcsQ0FBQyxFQUNWLFVBQVUsRUFBRSxLQUFLLEdBQ2xCOztBQUVELEFBQUEsWUFBWSxDQUFDLEVBQ1gsVUFBVSxFQUFFLE1BQU0sR0FDbkI7O0FBRUQsQUFBQSxhQUFhLENBQUMsRUFDWixVQUFVLEVBQUUsT0FBTyxHQUNwQjs7QUFHRCxBQUFBLGVBQWUsQ0FBQyxFQUNkLGNBQWMsRUFBRSxTQUFTLEdBQzFCOztBQUVELEFBQUEsZUFBZSxDQUFDLEVBQ2QsY0FBYyxFQUFFLFNBQVMsR0FDMUI7O0FBRUQsQUFBQSxnQkFBZ0IsQ0FBQyxFQUNmLGNBQWMsRUFBRSxVQUFVLEdBQzNCOztBQUdELEFBQUEsWUFBWSxDQUFDLEVBQ1gsV0FBVyxFQUFFLE1BQU0sR0FDcEI7O0FBRUQsQUFBQSxVQUFVLENBQUMsRUFDVCxXQUFXLEVBQUUsSUFBSSxHQUNsQjs7QUFFRCxBQUFBLFlBQVksQ0FBQyxFQUNYLFVBQVUsRUFBRSxNQUFNLEdBQ25COztBQUVELEFBQUEsV0FBVyxDQUFDLEVBQ1YsU0FBUyxFQUFFLEtBQUssR0FDakI7O0FBR0QsQUFBQSxjQUFjLENBQUMsRTdDL0NiLFFBQVEsRUFBRSxNQUFNLEVBQ2hCLGFBQWEsRUFBRSxRQUFRLEVBQ3ZCLFdBQVcsRUFBRSxNQUFNLEc2QytDcEI7O0FBRUQsQUFBQSxVQUFVLENBQUMsRUFDVCxRQUFRLEVBQUUsTUFBTSxFQUNoQixhQUFhLEVBQUUsSUFBSSxFQUNuQixXQUFXLEVBQUUsTUFBTSxHQUNwQjs7QUFFRCxBQUFBLFdBQVcsQ0FBQyxFQUNWLE9BQU8sRUFBRSxJQUFJLEVBQ2IsVUFBVSxFQUFFLFVBQVUsRUFDdEIsU0FBUyxFQUFFLFVBQVUsR0FDdEIifQ== */ diff --git a/user/plugins/problems/css/spectre.min.css b/user/plugins/problems/css/spectre.min.css new file mode 100644 index 00000000..5616ab19 --- /dev/null +++ b/user/plugins/problems/css/spectre.min.css @@ -0,0 +1 @@ +/*! Spectre.css v0.5.3 | MIT License | github.com/picturepan2/spectre */html{font-family:sans-serif;-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}hr{overflow:visible;box-sizing:content-box;height:0}a{background-color:transparent;-webkit-text-decoration-skip:objects}a:active,a:hover{outline-width:0}address{font-style:normal}b,strong{font-weight:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:'SF Mono','Segoe UI Mono','Roboto Mono',Menlo,Courier,monospace;font-size:1em}dfn{font-style:italic}small{font-size:80%;font-weight:400}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:inherit;font-size:inherit;line-height:inherit;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{padding:0;border-style:none}fieldset{margin:0;padding:0;border:0}legend{display:table;box-sizing:border-box;max-width:100%;padding:0;white-space:normal;color:inherit}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]{outline-offset:-2px;-webkit-appearance:textfield}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}details,menu{display:block}summary{display:list-item;outline:0}canvas{display:inline-block}template{display:none}[hidden]{display:none}*,::after,::before{box-sizing:inherit}html{font-size:20px;line-height:1.5;box-sizing:border-box;-webkit-tap-highlight-color:transparent}body{font-family:-apple-system,system-ui,BlinkMacSystemFont,'Segoe UI',Roboto,'Helvetica Neue',sans-serif;font-size:.8rem;overflow-x:hidden;color:#50596c;background:#fff;text-rendering:optimizeLegibility}a{text-decoration:none;color:#0074d9;outline:0}a:focus{box-shadow:0 0 0 .1rem rgba(0,116,217,.2)}a.active,a:active,a:focus,a:hover{text-decoration:underline;color:#0059a6}a:visited{color:#0d8eff}h1,h2,h3,h4,h5,h6{font-weight:500;line-height:1.2;margin-top:0;margin-bottom:.5em;color:inherit}.h1,.h2,.h3,.h4,.h5,.h6{font-weight:500}.h1,h1{font-size:2rem}.h2,h2{font-size:1.6rem}.h3,h3{font-size:1.4rem}.h4,h4{font-size:1.2rem}.h5,h5{font-size:1rem}.h6,h6{font-size:.8rem}p{margin:0 0 1.2rem}a,ins,u{-webkit-text-decoration-skip:ink edges;text-decoration-skip:ink edges}abbr[title]{cursor:help;text-decoration:none;border-bottom:.05rem dotted}kbd{font-size:.7rem;line-height:1.2;padding:.1rem .2rem;color:#fff;border-radius:.1rem;background:#454d5d}mark{padding:.05rem;color:#50596c;border-radius:.1rem;background:#ffe9b3}blockquote{margin-left:0;padding:.4rem .8rem;border-left:.1rem solid #e7e9ed}blockquote p:last-child{margin-bottom:0}ol,ul{margin:.8rem 0 .8rem .8rem;padding:0}ol ol,ol ul,ul ol,ul ul{margin:.8rem 0 .8rem .8rem}ol li,ul li{margin-top:.4rem}ul{list-style:disc inside}ul ul{list-style-type:circle}ol{list-style:decimal inside}ol ol{list-style-type:lower-alpha}dl dt{font-weight:700}dl dd{margin:.4rem 0 .8rem 0}:lang(zh),:lang(zh-Hans){font-family:-apple-system,system-ui,BlinkMacSystemFont,'Segoe UI',Roboto,'PingFang SC','Hiragino Sans GB','Microsoft YaHei','Helvetica Neue',sans-serif}:lang(zh-Hant){font-family:-apple-system,system-ui,BlinkMacSystemFont,'Segoe UI',Roboto,'PingFang TC','Hiragino Sans CNS','Microsoft JhengHei','Helvetica Neue',sans-serif}:lang(ja){font-family:-apple-system,system-ui,BlinkMacSystemFont,'Segoe UI',Roboto,'Hiragino Sans','Hiragino Kaku Gothic Pro','Yu Gothic',YuGothic,Meiryo,'Helvetica Neue',sans-serif}:lang(ko){font-family:-apple-system,system-ui,BlinkMacSystemFont,'Segoe UI',Roboto,'Malgun Gothic','Helvetica Neue',sans-serif}.cjk ins,.cjk u,:lang(ja) ins,:lang(ja) u,:lang(zh) ins,:lang(zh) u{text-decoration:none;border-bottom:.05rem solid}.cjk del+del,.cjk del+s,.cjk ins+ins,.cjk ins+u,.cjk s+del,.cjk s+s,.cjk u+ins,.cjk u+u,:lang(ja) del+del,:lang(ja) del+s,:lang(ja) ins+ins,:lang(ja) ins+u,:lang(ja) s+del,:lang(ja) s+s,:lang(ja) u+ins,:lang(ja) u+u,:lang(zh) del+del,:lang(zh) del+s,:lang(zh) ins+ins,:lang(zh) ins+u,:lang(zh) s+del,:lang(zh) s+s,:lang(zh) u+ins,:lang(zh) u+u{margin-left:.125em}.table{width:100%;border-spacing:0;border-collapse:collapse;text-align:left}.table.table-striped tbody tr:nth-of-type(odd){background:#f8f9fa}.table tbody tr.active,.table.table-striped tbody tr.active{background:#f0f1f4}.table.table-hover tbody tr:hover{background:#f0f1f4}.table.table-scroll{display:block;overflow-x:auto;padding-bottom:.75rem;white-space:nowrap}.table td,.table th{padding:.6rem .4rem;border-bottom:.05rem solid #e7e9ed}.table th{border-bottom-width:.1rem}.btn{font-size:.8rem;line-height:1.2rem;display:inline-block;height:1.8rem;padding:.25rem .4rem;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;transition:all .2s ease;text-align:center;vertical-align:middle;white-space:nowrap;text-decoration:none;color:#0074d9;border:.05rem solid #0074d9;border-radius:.1rem;outline:0;background:#fff;-webkit-appearance:none;-moz-appearance:none;appearance:none}.btn:focus{box-shadow:0 0 0 .1rem rgba(0,116,217,.2)}.btn:focus,.btn:hover{text-decoration:none;border-color:#006cca;background:#99d0ff}.btn.active,.btn:active{text-decoration:none;color:#fff;border-color:#005eb0;background:#006cca}.btn.active.loading::after,.btn:active.loading::after{border-bottom-color:#fff;border-left-color:#fff}.btn.disabled,.btn:disabled,.btn[disabled]{cursor:default;pointer-events:none;opacity:.5}.btn.btn-primary{color:#fff;border-color:#006cca;background:#0074d9}.btn.btn-primary:focus,.btn.btn-primary:hover{color:#fff;border-color:#005eb0;background:#0066c0}.btn.btn-primary.active,.btn.btn-primary:active{color:#fff;border-color:#0059a6;background:#0061b5}.btn.btn-primary.loading::after{border-bottom-color:#fff;border-left-color:#fff}.btn.btn-success{color:#fff;border-color:#2bc03c;background:#2ecc40}.btn.btn-success:focus{box-shadow:0 0 0 .1rem rgba(46,204,64,.2)}.btn.btn-success:focus,.btn.btn-success:hover{color:#fff;border-color:#29b739;background:#2cc43d}.btn.btn-success.active,.btn.btn-success:active{color:#fff;border-color:#25a233;background:#27af37}.btn.btn-success.loading::after{border-bottom-color:#fff;border-left-color:#fff}.btn.btn-error{color:#fff;border-color:#ff3327;background:#ff4136}.btn.btn-error:focus{box-shadow:0 0 0 .1rem rgba(255,65,54,.2)}.btn.btn-error:focus,.btn.btn-error:hover{color:#fff;border-color:#ff291d;background:#ff372c}.btn.btn-error.active,.btn.btn-error:active{color:#fff;border-color:#ff1103;background:#ff1f12}.btn.btn-error.loading::after{border-bottom-color:#fff;border-left-color:#fff}.btn.btn-warning{color:#fff;border-color:#ff7d0c;background:#ff851b}.btn.btn-warning:focus{box-shadow:0 0 0 .1rem rgba(255,133,27,.2)}.btn.btn-warning:focus,.btn.btn-warning:hover{color:#fff;border-color:#ff7702;background:#ff8011}.btn.btn-warning.active,.btn.btn-warning:active{color:#fff;border-color:#e76b00;background:#f67300}.btn.btn-warning.loading::after{border-bottom-color:#fff;border-left-color:#fff}.btn.btn-link{color:#0074d9;border-color:transparent;background:0 0}.btn.btn-link.active,.btn.btn-link:active,.btn.btn-link:focus,.btn.btn-link:hover{color:#0059a6}.btn.btn-sm{font-size:.7rem;height:1.4rem;padding:.05rem .3rem}.btn.btn-lg{font-size:.9rem;height:2rem;padding:.35rem .6rem}.btn.btn-block{display:block;width:100%}.btn.btn-action{width:1.8rem;padding-right:0;padding-left:0}.btn.btn-action.btn-sm{width:1.4rem}.btn.btn-action.btn-lg{width:2rem}.btn.btn-clear{line-height:.8rem;width:.8rem;height:.8rem;margin-right:-2px;margin-left:.2rem;padding:0;text-decoration:none;opacity:1;color:currentColor;border:0;background:0 0}.btn.btn-clear:hover{opacity:.95}.btn.btn-clear::before{content:'\2715'}.btn-group{display:-ms-inline-flexbox;display:inline-flex;-ms-flex-wrap:wrap;flex-wrap:wrap}.btn-group .btn{-ms-flex:1 0 auto;flex:1 0 auto}.btn-group .btn:first-child:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group .btn:not(:first-child):not(:last-child){margin-left:-.05rem;border-radius:0}.btn-group .btn:last-child:not(:first-child){margin-left:-.05rem;border-top-left-radius:0;border-bottom-left-radius:0}.btn-group .btn.active,.btn-group .btn:active,.btn-group .btn:focus,.btn-group .btn:hover{z-index:1}.btn-group.btn-group-block{display:-ms-flexbox;display:flex}.btn-group.btn-group-block .btn{-ms-flex:1 0 0;flex:1 0 0}.form-group:not(:last-child){margin-bottom:.4rem}fieldset{margin-bottom:.8rem}legend{font-size:.9rem;font-weight:500;margin-bottom:.8rem}.form-label{line-height:1.2rem;display:block;padding:.3rem 0}.form-label.label-sm{font-size:.7rem;padding:.1rem 0}.form-label.label-lg{font-size:.9rem;padding:.4rem 0}.form-input{font-size:.8rem;line-height:1.2rem;position:relative;display:block;width:100%;max-width:100%;height:1.8rem;padding:.25rem .4rem;transition:all .2s ease;color:#50596c;border:.05rem solid #caced7;border-radius:.1rem;outline:0;background:#fff;background-image:none;-webkit-appearance:none;-moz-appearance:none;appearance:none}.form-input:focus{border-color:#0074d9;box-shadow:0 0 0 .1rem rgba(0,116,217,.2)}.form-input::-webkit-input-placeholder{color:#acb3c2}.form-input:-ms-input-placeholder{color:#acb3c2}.form-input::-ms-input-placeholder{color:#acb3c2}.form-input::placeholder{color:#acb3c2}.form-input.input-sm{font-size:.7rem;height:1.4rem;padding:.05rem .3rem}.form-input.input-lg{font-size:.9rem;height:2rem;padding:.35rem .6rem}.form-input.input-inline{display:inline-block;width:auto;vertical-align:middle}.form-input[type=file]{height:auto}textarea.form-input{height:auto}.form-input-hint{font-size:.7rem;margin-top:.2rem;color:#acb3c2}.has-success .form-input-hint,.is-success+.form-input-hint{color:#2ecc40}.has-error .form-input-hint,.is-error+.form-input-hint{color:#ff4136}.form-select{font-size:.8rem;line-height:1.2rem;width:100%;height:1.8rem;padding:.25rem .4rem;vertical-align:middle;color:inherit;border:.05rem solid #caced7;border-radius:.1rem;outline:0;-webkit-appearance:none;-moz-appearance:none;appearance:none}.form-select[multiple],.form-select[size]{height:auto}.form-select[multiple] option,.form-select[size] option{padding:.1rem .2rem}.form-select:not([multiple]):not([size]){padding-right:1.2rem;background:#fff url('data:image/svg+xml;charset=utf8,%3Csvg%20xmlns=\'http://www.w3.org/2000/svg\'%20viewBox=\'0%200%204%205\'%3E%3Cpath%20fill=\'%23667189\'%20d=\'M2%200L0%202h4zm0%205L0%203h4z\'/%3E%3C/svg%3E') no-repeat right .35rem center/.4rem .5rem}.form-select:focus{border-color:#0074d9;box-shadow:0 0 0 .1rem rgba(0,116,217,.2)}.form-select::-ms-expand{display:none}.form-select.select-sm{font-size:.7rem;height:1.4rem;padding:.05rem 1.1rem .05rem .3rem}.form-select.select-lg{font-size:.9rem;height:2rem;padding:.35rem 1.4rem .35rem .6rem}.has-icon-left,.has-icon-right{position:relative}.has-icon-left .form-icon,.has-icon-right .form-icon{position:absolute;z-index:2;top:50%;width:.8rem;height:.8rem;margin:0 .25rem;transform:translateY(-50%)}.has-icon-left .form-icon{left:.05rem}.has-icon-left .form-input{padding-left:1.3rem}.has-icon-right .form-icon{right:.05rem}.has-icon-right .form-input{padding-right:1.3rem}.form-checkbox,.form-radio,.form-switch{line-height:1.2rem;position:relative;display:block;min-height:1.2rem;margin:.2rem 0;padding:.1rem .4rem .1rem 1.2rem}.form-checkbox input,.form-radio input,.form-switch input{position:absolute;overflow:hidden;clip:rect(0,0,0,0);width:1px;height:1px;margin:-1px}.form-checkbox input:focus+.form-icon,.form-radio input:focus+.form-icon,.form-switch input:focus+.form-icon{border-color:#0074d9;box-shadow:0 0 0 .1rem rgba(0,116,217,.2)}.form-checkbox input:checked+.form-icon,.form-radio input:checked+.form-icon,.form-switch input:checked+.form-icon{border-color:#0074d9;background:#0074d9}.form-checkbox .form-icon,.form-radio .form-icon,.form-switch .form-icon{position:absolute;display:inline-block;cursor:pointer;transition:all .2s ease;border:.05rem solid #caced7}.form-checkbox.input-sm,.form-radio.input-sm,.form-switch.input-sm{font-size:.7rem;margin:0}.form-checkbox.input-lg,.form-radio.input-lg,.form-switch.input-lg{font-size:.9rem;margin:.3rem 0}.form-checkbox .form-icon,.form-radio .form-icon{top:.3rem;left:0;width:.8rem;height:.8rem;background:#fff}.form-checkbox input:active+.form-icon,.form-radio input:active+.form-icon{background:#f0f1f4}.form-checkbox .form-icon{border-radius:.1rem}.form-checkbox input:checked+.form-icon::before{position:absolute;top:50%;left:50%;width:8px;height:12px;margin-top:-8px;margin-left:-4px;content:'';transform:rotate(45deg);border:.1rem solid #fff;border-top-width:0;border-left-width:0;background-clip:padding-box}.form-checkbox input:indeterminate+.form-icon{border-color:#0074d9;background:#0074d9}.form-checkbox input:indeterminate+.form-icon::before{position:absolute;top:50%;left:50%;width:10px;height:2px;margin-top:-1px;margin-left:-5px;content:'';background:#fff}.form-radio .form-icon{border-radius:50%}.form-radio input:checked+.form-icon::before{position:absolute;top:50%;left:50%;width:4px;height:4px;content:'';transform:translate(-50%,-50%);border-radius:50%;background:#fff}.form-switch{padding-left:2rem}.form-switch .form-icon{top:.25rem;left:0;width:1.6rem;height:.9rem;border-radius:.45rem;background:#e7e9ed;background-clip:padding-box}.form-switch .form-icon::before{position:absolute;top:0;left:0;display:block;width:.8rem;height:.8rem;content:'';transition:all .2s ease;border-radius:50%;background:#fff}.form-switch input:checked+.form-icon::before{left:14px}.form-switch input:active+.form-icon::before{background:#f8f9fa}.input-group{display:-ms-flexbox;display:flex}.input-group .input-group-addon{line-height:1.2rem;padding:.25rem .4rem;white-space:nowrap;border:.05rem solid #caced7;border-radius:.1rem;background:#f8f9fa}.input-group .input-group-addon.addon-sm{font-size:.7rem;padding:.05rem .3rem}.input-group .input-group-addon.addon-lg{font-size:.9rem;padding:.35rem .6rem}.input-group .form-input,.input-group .form-select{width:1%;-ms-flex:1 1 auto;flex:1 1 auto}.input-group .input-group-btn{z-index:1}.input-group .form-input:first-child:not(:last-child),.input-group .form-select:first-child:not(:last-child),.input-group .input-group-addon:first-child:not(:last-child),.input-group .input-group-btn:first-child:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.input-group .form-input:not(:first-child):not(:last-child),.input-group .form-select:not(:first-child):not(:last-child),.input-group .input-group-addon:not(:first-child):not(:last-child),.input-group .input-group-btn:not(:first-child):not(:last-child){margin-left:-.05rem;border-radius:0}.input-group .form-input:last-child:not(:first-child),.input-group .form-select:last-child:not(:first-child),.input-group .input-group-addon:last-child:not(:first-child),.input-group .input-group-btn:last-child:not(:first-child){margin-left:-.05rem;border-top-left-radius:0;border-bottom-left-radius:0}.input-group .form-input:focus,.input-group .form-select:focus,.input-group .input-group-addon:focus,.input-group .input-group-btn:focus{z-index:2}.input-group .form-select{width:auto}.input-group.input-inline{display:-ms-inline-flexbox;display:inline-flex}.form-input.is-success,.form-select.is-success,.has-success .form-input,.has-success .form-select{border-color:#2ecc40}.form-input.is-success:focus,.form-select.is-success:focus,.has-success .form-input:focus,.has-success .form-select:focus{box-shadow:0 0 0 .1rem rgba(46,204,64,.2)}.form-input.is-error,.form-select.is-error,.has-error .form-input,.has-error .form-select{border-color:#ff4136}.form-input.is-error:focus,.form-select.is-error:focus,.has-error .form-input:focus,.has-error .form-select:focus{box-shadow:0 0 0 .1rem rgba(255,65,54,.2)}.form-checkbox.is-error .form-icon,.form-radio.is-error .form-icon,.form-switch.is-error .form-icon,.has-error .form-checkbox .form-icon,.has-error .form-radio .form-icon,.has-error .form-switch .form-icon{border-color:#ff4136}.form-checkbox.is-error input:checked+.form-icon,.form-radio.is-error input:checked+.form-icon,.form-switch.is-error input:checked+.form-icon,.has-error .form-checkbox input:checked+.form-icon,.has-error .form-radio input:checked+.form-icon,.has-error .form-switch input:checked+.form-icon{border-color:#ff4136;background:#ff4136}.form-checkbox.is-error input:focus+.form-icon,.form-radio.is-error input:focus+.form-icon,.form-switch.is-error input:focus+.form-icon,.has-error .form-checkbox input:focus+.form-icon,.has-error .form-radio input:focus+.form-icon,.has-error .form-switch input:focus+.form-icon{border-color:#ff4136;box-shadow:0 0 0 .1rem rgba(255,65,54,.2)}.form-checkbox.is-error input:indeterminate+.form-icon,.has-error .form-checkbox input:indeterminate+.form-icon{border-color:#ff4136;background:#ff4136}.form-input:not(:placeholder-shown):invalid{border-color:#ff4136}.form-input:not(:placeholder-shown):invalid:focus{box-shadow:0 0 0 .1rem rgba(255,65,54,.2)}.form-input:not(:placeholder-shown):invalid+.form-input-hint{color:#ff4136}.form-input.disabled,.form-input:disabled,.form-select.disabled,.form-select:disabled{cursor:not-allowed;opacity:.5;background-color:#f0f1f4}.form-input[readonly]{background-color:#f8f9fa}input.disabled+.form-icon,input:disabled+.form-icon{cursor:not-allowed;opacity:.5;background:#f0f1f4}.form-switch input.disabled+.form-icon::before,.form-switch input:disabled+.form-icon::before{background:#fff}.form-horizontal{padding:.4rem 0}.form-horizontal .form-group{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap}.form-inline{display:inline-block}.label{line-height:1.2;display:inline-block;padding:.1rem .2rem;color:#5b657a;border-radius:.1rem;background:#f0f1f4}.label.label-rounded{padding-right:.4rem;padding-left:.4rem;border-radius:5rem}.label.label-primary{color:#fff;background:#0074d9}.label.label-secondary{color:#0074d9;background:#99d0ff}.label.label-success{color:#fff;background:#2ecc40}.label.label-warning{color:#fff;background:#ff851b}.label.label-error{color:#fff;background:#ff4136}code{font-size:85%;line-height:1.2;padding:.1rem .2rem;color:#288fed;border-radius:.1rem;background:#f0f7fe}.code{position:relative;color:#50596c;border-radius:.1rem}.code::before{font-size:.7rem;position:absolute;top:.1rem;right:.4rem;content:attr(data-lang);color:#acb3c2}.code code{line-height:1.5;display:block;overflow-x:auto;width:100%;padding:1rem;color:inherit;background:#f8f9fa}.img-responsive{display:block;max-width:100%;height:auto}.img-fit-cover{object-fit:cover}.img-fit-contain{object-fit:contain}.video-responsive{position:relative;display:block;overflow:hidden;width:100%;padding:0}.video-responsive::before{display:block;padding-bottom:56.25%;content:''}.video-responsive embed,.video-responsive iframe,.video-responsive object{position:absolute;top:0;right:0;bottom:0;left:0;width:100%;height:100%;border:0}video.video-responsive{max-width:100%;height:auto}video.video-responsive::before{content:none}.video-responsive-4-3::before{padding-bottom:75%}.video-responsive-1-1::before{padding-bottom:100%}.figure{margin:0 0 .4rem 0}.figure .figure-caption{margin-top:.4rem;color:#667189}.container{width:100%;margin-right:auto;margin-left:auto;padding-right:.4rem;padding-left:.4rem}.container.grid-xl{max-width:1296px}.container.grid-lg{max-width:976px}.container.grid-md{max-width:856px}.container.grid-sm{max-width:616px}.container.grid-xs{max-width:496px}.show-lg,.show-md,.show-sm,.show-xl,.show-xs{display:none!important}.columns{display:-ms-flexbox;display:flex;margin-right:-.4rem;margin-left:-.4rem;-ms-flex-wrap:wrap;flex-wrap:wrap}.columns.col-gapless{margin-right:0;margin-left:0}.columns.col-gapless>.column{padding-right:0;padding-left:0}.columns.col-oneline{overflow-x:auto;-ms-flex-wrap:nowrap;flex-wrap:nowrap}.column{max-width:100%;padding-right:.4rem;padding-left:.4rem;-ms-flex:1;flex:1}.column.col-1,.column.col-10,.column.col-11,.column.col-12,.column.col-2,.column.col-3,.column.col-4,.column.col-5,.column.col-6,.column.col-7,.column.col-8,.column.col-9{-ms-flex:none;flex:none}.col-12{width:100%}.col-11{width:91.66666667%}.col-10{width:83.33333333%}.col-9{width:75%}.col-8{width:66.66666667%}.col-7{width:58.33333333%}.col-6{width:50%}.col-5{width:41.66666667%}.col-4{width:33.33333333%}.col-3{width:25%}.col-2{width:16.66666667%}.col-1{width:8.33333333%}.col-auto{width:auto;max-width:none;-ms-flex:0 0 auto;flex:0 0 auto}.col-mx-auto{margin-right:auto;margin-left:auto}.col-ml-auto{margin-left:auto}.col-mr-auto{margin-right:auto}@media (max-width:1280px){.col-xl-1,.col-xl-10,.col-xl-11,.col-xl-12,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9{-ms-flex:none;flex:none}.col-xl-12{width:100%}.col-xl-11{width:91.66666667%}.col-xl-10{width:83.33333333%}.col-xl-9{width:75%}.col-xl-8{width:66.66666667%}.col-xl-7{width:58.33333333%}.col-xl-6{width:50%}.col-xl-5{width:41.66666667%}.col-xl-4{width:33.33333333%}.col-xl-3{width:25%}.col-xl-2{width:16.66666667%}.col-xl-1{width:8.33333333%}.hide-xl{display:none!important}.show-xl{display:block!important}}@media (max-width:960px){.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{-ms-flex:none;flex:none}.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%}.hide-lg{display:none!important}.show-lg{display:block!important}}@media (max-width:840px){.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{-ms-flex:none;flex:none}.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%}.hide-md{display:none!important}.show-md{display:block!important}}@media (max-width:600px){.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{-ms-flex:none;flex:none}.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%}.hide-sm{display:none!important}.show-sm{display:block!important}}@media (max-width:480px){.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{-ms-flex:none;flex:none}.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%}.hide-xs{display:none!important}.show-xs{display:block!important}}.navbar{display:-ms-flexbox;display:flex;-ms-flex-align:stretch;align-items:stretch;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-pack:justify;justify-content:space-between}.navbar .navbar-section{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex:1 0 0;flex:1 0 0}.navbar .navbar-section:not(:first-child):last-child{-ms-flex-pack:end;justify-content:flex-end}.navbar .navbar-center{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex:0 0 auto;flex:0 0 auto}.navbar .navbar-brand{font-size:.9rem;font-weight:500;text-decoration:none}.accordion input:checked~.accordion-header .icon,.accordion[open] .accordion-header .icon{transform:rotate(90deg)}.accordion input:checked~.accordion-body,.accordion[open] .accordion-body{max-height:50rem}.accordion .accordion-header{display:block;padding:.2rem .4rem}.accordion .accordion-header .icon{transition:all .2s ease}.accordion .accordion-body{overflow:hidden;max-height:0;margin-bottom:.4rem;transition:max-height .2s ease}summary.accordion-header::-webkit-details-marker{display:none}.avatar{font-size:.8rem;font-weight:300;line-height:1.25;position:relative;display:inline-block;width:1.6rem;height:1.6rem;margin:0;vertical-align:middle;color:rgba(255,255,255,.85);border-radius:50%;background:#0074d9}.avatar.avatar-xs{font-size:.4rem;width:.8rem;height:.8rem}.avatar.avatar-sm{font-size:.6rem;width:1.2rem;height:1.2rem}.avatar.avatar-lg{font-size:1.2rem;width:2.4rem;height:2.4rem}.avatar.avatar-xl{font-size:1.6rem;width:3.2rem;height:3.2rem}.avatar img{position:relative;z-index:1;width:100%;height:100%;border-radius:50%}.avatar .avatar-icon,.avatar .avatar-presence{position:absolute;z-index:2;right:14.64%;bottom:14.64%;width:50%;height:50%;padding:.1rem;transform:translate(50%,50%);background:#fff}.avatar .avatar-presence{width:.5em;height:.5em;border-radius:50%;background:#acb3c2;box-shadow:0 0 0 .1rem #fff}.avatar .avatar-presence.online{background:#2ecc40}.avatar .avatar-presence.busy{background:#ff4136}.avatar .avatar-presence.away{background:#ff851b}.avatar[data-initial]::before{position:absolute;z-index:1;top:50%;left:50%;content:attr(data-initial);transform:translate(-50%,-50%);color:currentColor}.badge{position:relative;white-space:nowrap}.badge:not([data-badge])::after,.badge[data-badge]::after{display:inline-block;content:attr(data-badge);transform:translate(-.05rem,-.5rem);color:#fff;border-radius:.5rem;background:#0074d9;background-clip:padding-box;box-shadow:0 0 0 .1rem #fff}.badge[data-badge]::after{font-size:.7rem;line-height:1;min-width:.9rem;height:.9rem;padding:.1rem .2rem;text-align:center;white-space:nowrap}.badge:not([data-badge])::after,.badge[data-badge='']::after{width:6px;min-width:6px;height:6px;padding:0}.badge.btn::after{position:absolute;top:0;right:0;transform:translate(50%,-50%)}.badge.avatar::after{position:absolute;z-index:100;top:14.64%;right:14.64%;transform:translate(50%,-50%)}.breadcrumb{margin:.2rem 0;padding:.2rem 0;list-style:none}.breadcrumb .breadcrumb-item{display:inline-block;margin:0;padding:.2rem 0;color:#667189}.breadcrumb .breadcrumb-item:not(:last-child){margin-right:.2rem}.breadcrumb .breadcrumb-item:not(:last-child) a{color:#667189}.breadcrumb .breadcrumb-item:not(:first-child)::before{padding-right:.4rem;content:'/';color:#e7e9ed}.bar{display:-ms-flexbox;display:flex;width:100%;height:.8rem;border-radius:.1rem;background:#f0f1f4;-ms-flex-wrap:nowrap;flex-wrap:nowrap}.bar.bar-sm{height:.2rem}.bar .bar-item{font-size:.7rem;line-height:.8rem;position:relative;display:block;width:0;height:100%;text-align:center;color:#fff;background:#0074d9;-ms-flex-negative:0;flex-shrink:0}.bar .bar-item:first-child{border-top-left-radius:.1rem;border-bottom-left-radius:.1rem}.bar .bar-item:last-child{border-top-right-radius:.1rem;border-bottom-right-radius:.1rem;-ms-flex-negative:1;flex-shrink:1}.bar-slider{position:relative;height:.1rem;margin:.4rem 0}.bar-slider .bar-item{position:absolute;left:0;padding:0}.bar-slider .bar-item:not(:last-child):first-child{z-index:1;background:#f0f1f4}.bar-slider .bar-slider-btn{position:absolute;top:50%;right:0;width:.6rem;height:.6rem;padding:0;transform:translate(50%,-50%);border:0;border-radius:50%;background:#0074d9}.bar-slider .bar-slider-btn:active{box-shadow:0 0 0 .1rem #0074d9}.card{display:-ms-flexbox;display:flex;flex-direction:column;border:.05rem solid #e7e9ed;border-radius:.1rem;background:#fff;-ms-flex-direction:column}.card .card-body,.card .card-footer,.card .card-header{padding:.8rem;padding-bottom:0}.card .card-body:last-child,.card .card-footer:last-child,.card .card-header:last-child{padding-bottom:.8rem}.card .card-body{-ms-flex:1 1 auto;flex:1 1 auto}.card .card-image{padding-top:.8rem}.card .card-image:first-child{padding-top:0}.card .card-image:first-child img{border-top-left-radius:.1rem;border-top-right-radius:.1rem}.card .card-image:last-child img{border-bottom-right-radius:.1rem;border-bottom-left-radius:.1rem}.chip{font-size:90%;line-height:.8rem;display:-ms-inline-flexbox;display:inline-flex;max-width:100%;height:1.2rem;margin:.1rem;padding:.2rem .4rem;vertical-align:middle;text-decoration:none;color:#667189;border-radius:5rem;background:#f0f1f4;-ms-flex-align:center;align-items:center}.chip.active{color:#fff;background:#0074d9}.chip .avatar{margin-right:.2rem;margin-left:-.4rem}.chip .btn-clear{transform:scale(.75)}.dropdown{position:relative;display:inline-block}.dropdown .menu{position:absolute;top:100%;left:0;display:none;overflow-y:auto;max-height:50vh;animation:slide-down .15s ease 1}.dropdown.dropdown-right .menu{right:0;left:auto}.dropdown .dropdown-toggle:focus+.menu,.dropdown .menu:hover,.dropdown.active .menu{display:block}.dropdown .btn-group .dropdown-toggle:nth-last-child(2){border-top-right-radius:.1rem;border-bottom-right-radius:.1rem}.empty{padding:3.2rem 1.6rem;text-align:center;color:#667189;border-radius:.1rem;background:#f8f9fa}.empty .empty-icon{margin-bottom:.8rem}.empty .empty-subtitle,.empty .empty-title{margin:.4rem auto}.empty .empty-action{margin-top:.8rem}.menu{z-index:300;min-width:180px;margin:0;padding:.4rem;list-style:none;transform:translateY(.2rem);border-radius:.1rem;background:#fff;box-shadow:0 .05rem .2rem rgba(69,77,93,.3)}.menu.menu-nav{background:0 0;box-shadow:none}.menu .menu-item{margin-top:0;padding:0 .4rem;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;text-decoration:none}.menu .menu-item>a{display:block;margin:0 -.4rem;padding:.2rem .4rem;text-decoration:none;color:inherit;border-radius:.1rem}.menu .menu-item>a:focus,.menu .menu-item>a:hover{color:#0074d9;background:#99d0ff}.menu .menu-item>a.active,.menu .menu-item>a:active{color:#0074d9;background:#99d0ff}.menu .menu-item .form-checkbox,.menu .menu-item .form-radio,.menu .menu-item .form-switch{margin:.1rem 0}.menu .menu-item+.menu-item{margin-top:.2rem}.menu .menu-badge{float:right;padding:.2rem 0}.menu .menu-badge .btn{margin-top:-.1rem}.modal{position:fixed;top:0;right:0;bottom:0;left:0;display:none;overflow:hidden;padding:.4rem;opacity:0;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center}.modal.active,.modal:target{z-index:400;display:-ms-flexbox;display:flex;opacity:1}.modal.active .modal-overlay,.modal:target .modal-overlay{position:absolute;top:0;right:0;bottom:0;left:0;display:block;cursor:default;background:rgba(248,249,250,.75)}.modal.active .modal-container,.modal:target .modal-container{z-index:1;animation:slide-down .2s ease 1}.modal.modal-sm .modal-container{max-width:320px;padding:0 .4rem}.modal.modal-lg .modal-overlay{background:#fff}.modal.modal-lg .modal-container{max-width:960px;box-shadow:none}.modal-container{display:-ms-flexbox;display:flex;flex-direction:column;width:100%;max-width:640px;max-height:75vh;padding:0 .8rem;border-radius:.1rem;background:#fff;box-shadow:0 .2rem .5rem rgba(69,77,93,.3);-ms-flex-direction:column}.modal-container.modal-fullheight{max-height:100vh}.modal-container .modal-header{padding:.8rem;color:#454d5d}.modal-container .modal-body{position:relative;overflow-y:auto;padding:.8rem}.modal-container .modal-footer{padding:.8rem;text-align:right}.nav{display:-ms-flexbox;display:flex;flex-direction:column;margin:.2rem 0;list-style:none;-ms-flex-direction:column}.nav .nav-item a{padding:.2rem .4rem;text-decoration:none;color:#667189}.nav .nav-item a:focus,.nav .nav-item a:hover{color:#0074d9}.nav .nav-item.active>a{font-weight:700;color:#50596c}.nav .nav-item.active>a:focus,.nav .nav-item.active>a:hover{color:#0074d9}.nav .nav{margin-bottom:.4rem;margin-left:.8rem}.pagination{display:-ms-flexbox;display:flex;margin:.2rem 0;padding:.2rem 0;list-style:none}.pagination .page-item{margin:.2rem .05rem}.pagination .page-item span{display:inline-block;padding:.2rem .2rem}.pagination .page-item a{display:inline-block;padding:.2rem .4rem;text-decoration:none;color:#667189;border-radius:.1rem}.pagination .page-item a:focus,.pagination .page-item a:hover{color:#0074d9}.pagination .page-item.disabled a{cursor:default;pointer-events:none;opacity:.5}.pagination .page-item.active a{color:#fff;background:#0074d9}.pagination .page-item.page-next,.pagination .page-item.page-prev{-ms-flex:1 0 50%;flex:1 0 50%}.pagination .page-item.page-next{text-align:right}.pagination .page-item .page-item-title{margin:0}.pagination .page-item .page-item-subtitle{margin:0;opacity:.5}.panel{display:-ms-flexbox;display:flex;flex-direction:column;border:.05rem solid #e7e9ed;border-radius:.1rem;-ms-flex-direction:column}.panel .panel-footer,.panel .panel-header{padding:.8rem;-ms-flex:0 0 auto;flex:0 0 auto}.panel .panel-nav{-ms-flex:0 0 auto;flex:0 0 auto}.panel .panel-body{overflow-y:auto;padding:0 .8rem;-ms-flex:1 1 auto;flex:1 1 auto}.popover{position:relative;display:inline-block}.popover .popover-container{position:absolute;z-index:300;top:0;left:50%;width:320px;padding:.4rem;transition:transform .2s ease;transform:translate(-50%,-50%) scale(0);opacity:0}.popover :focus+.popover-container,.popover:hover .popover-container{display:block;transform:translate(-50%,-100%);opacity:1}.popover.popover-right .popover-container{top:50%;left:100%}.popover.popover-right :focus+.popover-container,.popover.popover-right:hover .popover-container{transform:translate(0,-50%)}.popover.popover-bottom .popover-container{top:100%;left:50%}.popover.popover-bottom :focus+.popover-container,.popover.popover-bottom:hover .popover-container{transform:translate(-50%,0)}.popover.popover-left .popover-container{top:50%;left:0}.popover.popover-left :focus+.popover-container,.popover.popover-left:hover .popover-container{transform:translate(-100%,-50%)}.popover .card{border:0;box-shadow:0 .2rem .5rem rgba(69,77,93,.3)}.step{display:-ms-flexbox;display:flex;width:100%;margin:.2rem 0;list-style:none;-ms-flex-wrap:nowrap;flex-wrap:nowrap}.step .step-item{position:relative;min-height:1rem;margin-top:0;text-align:center;-ms-flex:1 1 0;flex:1 1 0}.step .step-item:not(:first-child)::before{position:absolute;top:9px;left:-50%;width:100%;height:2px;content:'';background:#0074d9}.step .step-item a{display:inline-block;padding:20px 10px 0;text-decoration:none;color:#acb3c2}.step .step-item a::before{position:absolute;z-index:1;top:.2rem;left:50%;display:block;width:.6rem;height:.6rem;content:'';transform:translateX(-50%);border:.1rem solid #fff;border-radius:50%;background:#0074d9}.step .step-item.active a::before{border:.1rem solid #0074d9;background:#fff}.step .step-item.active~.step-item::before{background:#e7e9ed}.step .step-item.active~.step-item a::before{background:#e7e9ed}.tab{display:-ms-flexbox;display:flex;margin:.2rem 0 .15rem 0;list-style:none;border-bottom:.05rem solid #e7e9ed;-ms-flex-align:center;align-items:center;-ms-flex-wrap:wrap;flex-wrap:wrap}.tab .tab-item{margin-top:0}.tab .tab-item a{display:block;margin:0 .4rem 0 0;padding:.4rem .2rem .3rem .2rem;text-decoration:none;color:inherit;border-bottom:.1rem solid transparent}.tab .tab-item a:focus,.tab .tab-item a:hover{color:#0074d9}.tab .tab-item a.active,.tab .tab-item.active a{color:#0074d9;border-bottom-color:#0074d9}.tab .tab-item.tab-action{text-align:right;-ms-flex:1 0 auto;flex:1 0 auto}.tab .tab-item .btn-clear{margin-top:-.2rem}.tab.tab-block .tab-item{text-align:center;-ms-flex:1 0 0;flex:1 0 0}.tab.tab-block .tab-item a{margin:0}.tab.tab-block .tab-item .badge[data-badge]::after{position:absolute;top:.1rem;right:.1rem;transform:translate(0,0)}.tab:not(.tab-block) .badge{padding-right:0}.tile{display:-ms-flexbox;display:flex;-ms-flex-line-pack:justify;align-content:space-between;-ms-flex-align:start;align-items:flex-start}.tile .tile-action,.tile .tile-icon{-ms-flex:0 0 auto;flex:0 0 auto}.tile .tile-content{-ms-flex:1 1 auto;flex:1 1 auto}.tile .tile-content:not(:first-child){padding-left:.4rem}.tile .tile-content:not(:last-child){padding-right:.4rem}.tile .tile-subtitle,.tile .tile-title{line-height:1.2rem}.tile.tile-centered{-ms-flex-align:center;align-items:center}.tile.tile-centered .tile-content{overflow:hidden}.tile.tile-centered .tile-subtitle,.tile.tile-centered .tile-title{overflow:hidden;margin-bottom:0;white-space:nowrap;text-overflow:ellipsis}.toast{display:block;width:100%;padding:.4rem;color:#fff;border:.05rem solid #454d5d;border-color:#454d5d;border-radius:.1rem;background:rgba(69,77,93,.9)}.toast.toast-primary{border-color:#0074d9;background:rgba(0,116,217,.9)}.toast.toast-success{border-color:#2ecc40;background:rgba(46,204,64,.9)}.toast.toast-warning{border-color:#ff851b;background:rgba(255,133,27,.9)}.toast.toast-error{border-color:#ff4136;background:rgba(255,65,54,.9)}.toast a{text-decoration:underline;color:#fff}.toast a.active,.toast a:active,.toast a:focus,.toast a:hover{opacity:.75}.toast .btn-clear{margin:4px -2px 4px 4px}.tooltip{position:relative}.tooltip::after{font-size:.7rem;position:absolute;z-index:300;bottom:100%;left:50%;display:block;overflow:hidden;max-width:320px;padding:.2rem .4rem;content:attr(data-tooltip);transition:all .2s ease;transform:translate(-50%,.4rem);white-space:pre;text-overflow:ellipsis;pointer-events:none;opacity:0;color:#fff;border-radius:.1rem;background:rgba(69,77,93,.9)}.tooltip:focus::after,.tooltip:hover::after{transform:translate(-50%,-.2rem);opacity:1}.tooltip.disabled,.tooltip[disabled]{pointer-events:auto}.tooltip.tooltip-right::after{bottom:50%;left:100%;transform:translate(-.2rem,50%)}.tooltip.tooltip-right:focus::after,.tooltip.tooltip-right:hover::after{transform:translate(.2rem,50%)}.tooltip.tooltip-bottom::after{top:100%;bottom:auto;transform:translate(-50%,-.4rem)}.tooltip.tooltip-bottom:focus::after,.tooltip.tooltip-bottom:hover::after{transform:translate(-50%,.2rem)}.tooltip.tooltip-left::after{right:100%;bottom:50%;left:auto;transform:translate(.4rem,50%)}.tooltip.tooltip-left:focus::after,.tooltip.tooltip-left:hover::after{transform:translate(-.2rem,50%)}body{padding:2rem 0}img.logo{width:200px;margin-bottom:1rem}h1,h2{font-weight:700}.footer{margin-top:2rem;color:#acb3c2}.footer img{height:18px;margin:0 .2rem;vertical-align:middle}.toast .btn{margin-left:1rem;text-decoration:none!important}.toast .btn i{margin-right:.3rem}ul.problems{margin:1rem 0}ul.problems h5{margin:0}ul.problems li.menu{margin-bottom:1rem}ul.problems li.menu .toast .btn{float:right;margin-top:-2px}ul.details{font-size:90%;margin:.5rem;list-style:none}ul.details .menu-item{margin-top:.5rem!important;padding-top:.5rem;border-top:1px solid #e7e9ed}ul.details .menu-item:first-child{border:none}ul.details .menu-badge{padding:0}@keyframes loading{0%{transform:rotate(0)}100%{transform:rotate(360deg)}}@keyframes slide-down{0%{transform:translateY(-1.6rem);opacity:0}100%{transform:translateY(0);opacity:1}}.text-primary{color:#0074d9}a.text-primary:focus,a.text-primary:hover{color:#0066c0}a.text-primary:visited{color:#0082f3}.text-secondary{color:#8ac9ff}a.text-secondary:focus,a.text-secondary:hover{color:#70bdff}a.text-secondary:visited{color:#a3d4ff}.text-gray{color:#acb3c2}a.text-gray:focus,a.text-gray:hover{color:#9ea6b7}a.text-gray:visited{color:#bbc1cd}.text-light{color:#fff}a.text-light:focus,a.text-light:hover{color:#f2f2f2}a.text-light:visited{color:#fff}.text-dark{color:#50596c}a.text-dark:focus,a.text-dark:hover{color:#454d5d}a.text-dark:visited{color:#5b657a}.text-success{color:#2ecc40}a.text-success:focus,a.text-success:hover{color:#29b739}a.text-success:visited{color:#40d451}.text-warning{color:#ff851b}a.text-warning:focus,a.text-warning:hover{color:#ff7702}a.text-warning:visited{color:#ff9335}.text-error{color:#ff4136}a.text-error:focus,a.text-error:hover{color:#ff291d}a.text-error:visited{color:#ff5950}.bg-primary{color:#fff;background:#0074d9}.bg-secondary{background:#99d0ff}.bg-dark{color:#fff;background:#454d5d}.bg-gray{background:#f8f9fa}.bg-success{color:#fff;background:#2ecc40}.bg-warning{color:#fff;background:#ff851b}.bg-error{background:#ff4136}.c-hand{cursor:pointer}.c-move{cursor:move}.c-zoom-in{cursor:zoom-in}.c-zoom-out{cursor:zoom-out}.c-not-allowed{cursor:not-allowed}.c-auto{cursor:auto}.d-block{display:block}.d-inline{display:inline}.d-inline-block{display:inline-block}.d-flex{display:-ms-flexbox;display:flex}.d-inline-flex{display:-ms-inline-flexbox;display:inline-flex}.d-hide,.d-none{display:none!important}.d-visible{visibility:visible}.d-invisible{visibility:hidden}.text-hide{font-size:0;line-height:0;color:transparent;border:0;background:0 0;text-shadow:none}.text-assistive{position:absolute;overflow:hidden;clip:rect(0,0,0,0);width:1px;height:1px;margin:-1px;padding:0;border:0}.divider,.divider-vert{position:relative;display:block}.divider-vert[data-content]::after,.divider[data-content]::after{font-size:.7rem;display:inline-block;padding:0 .4rem;content:attr(data-content);transform:translateY(-.65rem);color:#acb3c2;background:#fff}.divider{height:.05rem;margin:.4rem 0;border-top:.05rem solid #e7e9ed}.divider[data-content]{margin:.8rem 0}.divider-vert{display:block;padding:.8rem}.divider-vert::before{position:absolute;top:.4rem;bottom:.4rem;left:50%;display:block;content:'';transform:translateX(-50%);border-left:.05rem solid #e7e9ed}.divider-vert[data-content]::after{position:absolute;top:50%;left:50%;padding:.2rem 0;transform:translate(-50%,-50%)}.loading{position:relative;min-height:.8rem;pointer-events:none;color:transparent!important}.loading::after{position:absolute;z-index:1;top:50%;left:50%;display:block;width:.8rem;height:.8rem;margin-top:-.4rem;margin-left:-.4rem;content:'';animation:loading .5s infinite linear;border:.1rem solid #0074d9;border-top-color:transparent;border-right-color:transparent;border-radius:50%}.loading.loading-lg{min-height:2rem}.loading.loading-lg::after{width:1.6rem;height:1.6rem;margin-top:-.8rem;margin-left:-.8rem}.clearfix::after,.container::after{display:table;clear:both;content:''}.float-left{float:left!important}.float-right{float:right!important}.relative{position:relative!important}.absolute{position:absolute!important}.fixed{position:fixed!important}.centered{display:block;float:none;margin-right:auto;margin-left:auto}.flex-centered{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center}.m-0{margin:0!important}.mb-0{margin-bottom:0!important}.ml-0{margin-left:0!important}.mr-0{margin-right:0!important}.mt-0{margin-top:0!important}.mx-0{margin-right:0!important;margin-left:0!important}.my-0{margin-top:0!important;margin-bottom:0!important}.m-1{margin:.2rem!important}.mb-1{margin-bottom:.2rem!important}.ml-1{margin-left:.2rem!important}.mr-1{margin-right:.2rem!important}.mt-1{margin-top:.2rem!important}.mx-1{margin-right:.2rem!important;margin-left:.2rem!important}.my-1{margin-top:.2rem!important;margin-bottom:.2rem!important}.m-2{margin:.4rem!important}.mb-2{margin-bottom:.4rem!important}.ml-2{margin-left:.4rem!important}.mr-2{margin-right:.4rem!important}.mt-2{margin-top:.4rem!important}.mx-2{margin-right:.4rem!important;margin-left:.4rem!important}.my-2{margin-top:.4rem!important;margin-bottom:.4rem!important}.p-0{padding:0!important}.pb-0{padding-bottom:0!important}.pl-0{padding-left:0!important}.pr-0{padding-right:0!important}.pt-0{padding-top:0!important}.px-0{padding-right:0!important;padding-left:0!important}.py-0{padding-top:0!important;padding-bottom:0!important}.p-1{padding:.2rem!important}.pb-1{padding-bottom:.2rem!important}.pl-1{padding-left:.2rem!important}.pr-1{padding-right:.2rem!important}.pt-1{padding-top:.2rem!important}.px-1{padding-right:.2rem!important;padding-left:.2rem!important}.py-1{padding-top:.2rem!important;padding-bottom:.2rem!important}.p-2{padding:.4rem!important}.pb-2{padding-bottom:.4rem!important}.pl-2{padding-left:.4rem!important}.pr-2{padding-right:.4rem!important}.pt-2{padding-top:.4rem!important}.px-2{padding-right:.4rem!important;padding-left:.4rem!important}.py-2{padding-top:.4rem!important;padding-bottom:.4rem!important}.s-rounded{border-radius:.1rem}.s-circle{border-radius:50%}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.text-justify{text-align:justify}.text-lowercase{text-transform:lowercase}.text-uppercase{text-transform:uppercase}.text-capitalize{text-transform:capitalize}.text-normal{font-weight:400}.text-bold{font-weight:700}.text-italic{font-style:italic}.text-large{font-size:1.2em}.text-ellipsis{overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.text-clip{overflow:hidden;white-space:nowrap;text-overflow:clip}.text-break{word-wrap:break-word;word-break:break-word;-webkit-hyphens:auto;hyphens:auto;-ms-hyphens:auto} \ No newline at end of file diff --git a/user/plugins/problems/gulpfile.js b/user/plugins/problems/gulpfile.js new file mode 100644 index 00000000..a4acb84d --- /dev/null +++ b/user/plugins/problems/gulpfile.js @@ -0,0 +1,39 @@ +var gulp = require('gulp'); +var sass = require('gulp-sass'); +var cleancss = require('gulp-clean-css'); +var csscomb = require('gulp-csscomb'); +var rename = require('gulp-rename'); +var autoprefixer = require('gulp-autoprefixer'); +var sourcemaps = require('gulp-sourcemaps'); + +// configure the paths +var watch_dir = './scss/*.scss'; +var src_dir = './scss/*.scss'; +var dest_dir = './css'; + +var paths = { + source: src_dir +}; + +gulp.task('watch', function() { + gulp.watch(watch_dir, ['build']); +}); + +gulp.task('build', function() { + gulp.src(paths.source) + .pipe(sourcemaps.init()) + .pipe(sass({outputStyle: 'compact', precision: 10}) + .on('error', sass.logError) + ) + .pipe(sourcemaps.write()) + .pipe(autoprefixer()) + .pipe(gulp.dest(dest_dir)) + .pipe(csscomb()) + .pipe(cleancss()) + .pipe(rename({ + suffix: '.min' + })) + .pipe(gulp.dest(dest_dir)); +}); + +gulp.task('default', ['build']); diff --git a/user/plugins/problems/languages.yaml b/user/plugins/problems/languages.yaml new file mode 100644 index 00000000..e0306ab7 --- /dev/null +++ b/user/plugins/problems/languages.yaml @@ -0,0 +1,14 @@ +en: + PLUGIN_PROBLEMS: + BUILTIN_CSS: 'Use built in CSS' + BUILTIN_CSS_HELP: 'Include the CSS provided by the Problems plugin' + +ru: + PLUGIN_PROBLEMS: + BUILTIN_CSS: 'Использовать встроенный CSS' + BUILTIN_CSS_HELP: 'Использовать CSS, предоставленный плагином Problems' + +uk: + PLUGIN_PROBLEMS: + BUILTIN_CSS: 'Використовувати вбудований CSS' + BUILTIN_CSS_HELP: 'Використовувати CSS, наданий плагіном Problems' diff --git a/user/plugins/problems/package.json b/user/plugins/problems/package.json new file mode 100644 index 00000000..bc7aacba --- /dev/null +++ b/user/plugins/problems/package.json @@ -0,0 +1,45 @@ +{ + "name": "spectre.css", + "version": "0.5.1", + "homepage": "http://picturepan2.github.io/spectre", + "author": "Yan Zhu ", + "description": "Spectre.css: a lightweight, responsive and modern CSS framework", + "main": "docs/dist/spectre.css", + "repository": { + "type": "git", + "url": "https://github.com/picturepan2/spectre.git" + }, + "license": "MIT", + "keywords": [ + "css", + "framework", + "flexbox", + "responsive", + "mobile-friendly", + "front-end", + "sass", + "modern" + ], + "bugs": { + "url": "https://github.com/picturepan2/spectre/issues" + }, + "devDependencies": { + "gulp": "^3.9.1", + "gulp-autoprefixer": "latest", + "gulp-clean-css": "^3.9.4", + "gulp-csscomb": "^3.0.8", + "gulp-rename": "^1.2.2", + "gulp-sass": "^4.0.1" + }, + "browserslist": [ + "last 4 Chrome versions", + "Edge >= 12", + "Firefox ESR", + "last 4 Safari versions", + "last 4 Opera versions", + "Explorer >= 10" + ], + "dependencies": { + "gulp-sourcemaps": "^2.6.4" + } +} diff --git a/user/plugins/problems/problems.php b/user/plugins/problems/problems.php new file mode 100644 index 00000000..18facaff --- /dev/null +++ b/user/plugins/problems/problems.php @@ -0,0 +1,142 @@ + [ + ['autoload', 100002], + ['onPluginsInitialized', 100001] + ], + 'onFatalException' => ['onFatalException', 0], + 'onAdminGenerateReports' => ['onAdminGenerateReports', 0], + ]; + } + + /** + * [onPluginsInitialized:100000] Composer autoload. + * + * @return ClassLoader + */ + public function autoload() + { + return require __DIR__ . '/vendor/autoload.php'; + } + + public function onFatalException() + { + if (\defined('GRAV_CLI') || $this->isAdmin()) { + return; + } + + // Run through potential issues + if ($this->problemsFound()) { + $this->renderProblems(); + } + } + + public function onPluginsInitialized() + { + if (\defined('GRAV_CLI') || $this->isAdmin()) { + return; + } + + $this->checker = new ProblemChecker(); + + if (!$this->checker->statusFileExists()) { + // If no issues remain, save a state file in the cache + if (!$this->problemsFound()) { + // delete any existing validated files + /** @var \SplFileInfo $fileInfo */ + foreach (new \GlobIterator(CACHE_DIR . ProblemChecker::PROBLEMS_PREFIX . '*') as $fileInfo) { + @unlink($fileInfo->getPathname()); + } + // create a file in the cache dir so it only runs on cache changes + $this->checker->storeStatusFile(); + } else { + $this->renderProblems(); + } + } + } + + private function renderProblems() + { + /** @var Uri $uri */ + $uri = $this->grav['uri']; + + /** @var \Twig_Environment $twig */ + $twig = $this->getTwig(); + + $data = [ + 'problems' => $this->problems, + 'base_url' => $baseUrlRelative = $uri->rootUrl(false), + 'problems_url' => $baseUrlRelative . '/user/plugins/problems', + ]; + + echo $twig->render('problems.html.twig', $data); + http_response_code(500); + exit(); + } + + public function onAdminGenerateReports(Event $e) + { + $reports = $e['reports']; + + $this->checker = new ProblemChecker(); + + // Check for problems + $this->problemsFound(); + + /** @var Uri $uri */ + $uri = $this->grav['uri']; + + /** @var \Twig_Environment $twig */ + $twig = $this->getTwig(); + + $data = [ + 'problems' => $this->problems, + 'base_url' => $baseUrlRelative = $uri->rootUrl(false), + 'problems_url' => $baseUrlRelative . '/user/plugins/problems', + ]; + + $reports['Grav Potential Problems'] = $twig->render('reports/problems-report.html.twig', $data); + + $this->grav['assets']->addCss('plugins://problems/css/admin.css'); + $this->grav['assets']->addCss('plugins://problems/css/spectre-icons.css'); + } + + private function problemsFound() + { + if (null === $this->checker) { + $this->checker = new ProblemChecker(); + } + + $status = $this->checker->check(__DIR__ . '/classes/Problems'); + $this->problems = $this->checker->getProblems(); + + return $status; + } + + private function getTwig() + { + $loader = new \Twig_Loader_Filesystem(__DIR__ . '/templates'); + $twig = new \Twig_Environment($loader, ['debug' => true]); + $twig->addExtension(New \Twig_Extension_Debug()); + + return $twig; + } +} diff --git a/user/plugins/problems/problems.yaml b/user/plugins/problems/problems.yaml new file mode 100644 index 00000000..1ab22e74 --- /dev/null +++ b/user/plugins/problems/problems.yaml @@ -0,0 +1,2 @@ +enabled: true +built_in_css: true diff --git a/user/plugins/problems/scss/_accordions.scss b/user/plugins/problems/scss/_accordions.scss new file mode 100644 index 00000000..4c696860 --- /dev/null +++ b/user/plugins/problems/scss/_accordions.scss @@ -0,0 +1,38 @@ +// Accordions +.accordion { + input:checked ~, + &[open] { + & .accordion-header { + .icon { + transform: rotate(90deg); + } + } + + & .accordion-body { + max-height: 50rem; + } + } + + .accordion-header { + display: block; + padding: $unit-1 $unit-2; + + .icon { + transition: all .2s ease; + } + } + + .accordion-body { + margin-bottom: $layout-spacing; + max-height: 0; + overflow: hidden; + transition: max-height .2s ease; + } +} + +// Remove default details marker in Webkit +summary.accordion-header { + &::-webkit-details-marker { + display: none; + } +} diff --git a/user/plugins/problems/scss/_animations.scss b/user/plugins/problems/scss/_animations.scss new file mode 100644 index 00000000..e7fde1ac --- /dev/null +++ b/user/plugins/problems/scss/_animations.scss @@ -0,0 +1,20 @@ +// Animations +@keyframes loading { + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(360deg); + } +} + +@keyframes slide-down { + 0% { + opacity: 0; + transform: translateY(-$unit-8); + } + 100% { + opacity: 1; + transform: translateY(0); + } +} diff --git a/user/plugins/problems/scss/_asian.scss b/user/plugins/problems/scss/_asian.scss new file mode 100644 index 00000000..38dc77ed --- /dev/null +++ b/user/plugins/problems/scss/_asian.scss @@ -0,0 +1,38 @@ +// Optimized for East Asian CJK +:lang(zh), +:lang(zh-Hans) { + font-family: $cjk-zh-hans-font-family; +} + +:lang(zh-Hant) { + font-family: $cjk-zh-hant-font-family; +} + +:lang(ja) { + font-family: $cjk-jp-font-family; +} + +:lang(ko) { + font-family: $cjk-ko-font-family; +} + +:lang(zh), +:lang(ja), +.cjk { + ins, + u { + border-bottom: $border-width solid; + text-decoration: none; + } + + del + del, + del + s, + ins + ins, + ins + u, + s + del, + s + s, + u + ins, + u + u { + margin-left: .125em; + } +} diff --git a/user/plugins/problems/scss/_autocomplete.scss b/user/plugins/problems/scss/_autocomplete.scss new file mode 100644 index 00000000..279fa036 --- /dev/null +++ b/user/plugins/problems/scss/_autocomplete.scss @@ -0,0 +1,47 @@ +// Autocomplete +.form-autocomplete { + position: relative; + + .form-autocomplete-input { + align-content: flex-start; + display: flex; + flex-wrap: wrap; + height: auto; + min-height: $unit-8; + padding: $unit-h; + + &.is-focused { + @include control-shadow(); + border-color: $primary-color; + } + + .form-input { + border-color: transparent; + box-shadow: none; + display: inline-block; + flex: 1 0 auto; + height: $unit-6; + line-height: $unit-4; + margin: $unit-h; + width: auto; + } + } + + .menu { + left: 0; + position: absolute; + top: 100%; + width: 100%; + } + + &.autocomplete-oneline { + .form-autocomplete-input { + flex-wrap: nowrap; + overflow-x: auto; + } + + .chip { + flex: 1 0 auto; + } + } +} diff --git a/user/plugins/problems/scss/_avatars.scss b/user/plugins/problems/scss/_avatars.scss new file mode 100644 index 00000000..b203aa25 --- /dev/null +++ b/user/plugins/problems/scss/_avatars.scss @@ -0,0 +1,77 @@ +// Avatars +.avatar { + @include avatar-base(); + background: $primary-color; + border-radius: 50%; + color: rgba($light-color, .85); + display: inline-block; + font-weight: 300; + line-height: 1.25; + margin: 0; + position: relative; + vertical-align: middle; + + &.avatar-xs { + @include avatar-base($unit-4); + } + &.avatar-sm { + @include avatar-base($unit-6); + } + &.avatar-lg { + @include avatar-base($unit-12); + } + &.avatar-xl { + @include avatar-base($unit-16); + } + + img { + border-radius: 50%; + height: 100%; + position: relative; + width: 100%; + z-index: $zindex-0; + } + + .avatar-icon, + .avatar-presence { + background: $bg-color-light; + bottom: 14.64%; + height: 50%; + padding: $border-width-lg; + position: absolute; + right: 14.64%; + transform: translate(50%, 50%); + width: 50%; + z-index: $zindex-0 + 1; + } + + .avatar-presence { + background: $gray-color; + box-shadow: 0 0 0 $border-width-lg $light-color; + border-radius: 50%; + height: .5em; + width: .5em; + + &.online { + background: $success-color; + } + + &.busy { + background: $error-color; + } + + &.away { + background: $warning-color; + } + } + + &[data-initial]::before { + color: currentColor; + content: attr(data-initial); + left: 50%; + position: absolute; + top: 50%; + transform: translate(-50%, -50%); + z-index: $zindex-0; + } +} \ No newline at end of file diff --git a/user/plugins/problems/scss/_badges.scss b/user/plugins/problems/scss/_badges.scss new file mode 100644 index 00000000..d67f6d19 --- /dev/null +++ b/user/plugins/problems/scss/_badges.scss @@ -0,0 +1,60 @@ +// Badges +.badge { + position: relative; + white-space: nowrap; + + &[data-badge], + &:not([data-badge]) { + &::after { + background: $primary-color; + background-clip: padding-box; + border-radius: .5rem; + box-shadow: 0 0 0 .1rem $bg-color-light; + color: $light-color; + content: attr(data-badge); + display: inline-block; + transform: translate(-.05rem, -.5rem); + } + } + &[data-badge] { + &::after { + font-size: $font-size-sm; + height: .9rem; + line-height: 1; + min-width: .9rem; + padding: .1rem .2rem; + text-align: center; + white-space: nowrap; + } + } + &:not([data-badge]), + &[data-badge=""] { + &::after { + height: 6px; + min-width: 6px; + padding: 0; + width: 6px; + } + } + + // Badges for Buttons + &.btn { + &::after { + position: absolute; + top: 0; + right: 0; + transform: translate(50%, -50%); + } + } + + // Badges for Avatars + &.avatar { + &::after { + position: absolute; + top: 14.64%; + right: 14.64%; + transform: translate(50%, -50%); + z-index: $zindex-1; + } + } +} diff --git a/user/plugins/problems/scss/_bars.scss b/user/plugins/problems/scss/_bars.scss new file mode 100644 index 00000000..47e21c9a --- /dev/null +++ b/user/plugins/problems/scss/_bars.scss @@ -0,0 +1,71 @@ +// Bars +.bar { + background: $bg-color-dark; + border-radius: $border-radius; + display: flex; + flex-wrap: nowrap; + height: $unit-4; + width: 100%; + + &.bar-sm { + height: $unit-1; + } + + // TODO: attr() support + .bar-item { + background: $primary-color; + color: $light-color; + display: block; + font-size: $font-size-sm; + flex-shrink: 0; + line-height: $unit-4; + height: 100%; + position: relative; + text-align: center; + width: 0; + + &:first-child { + border-bottom-left-radius: $border-radius; + border-top-left-radius: $border-radius; + } + &:last-child { + border-bottom-right-radius: $border-radius; + border-top-right-radius: $border-radius; + flex-shrink: 1; + } + } +} + +// Slider bar +.bar-slider { + height: $border-width-lg; + margin: $layout-spacing 0; + position: relative; + + .bar-item { + left: 0; + padding: 0; + position: absolute; + &:not(:last-child):first-child { + background: $bg-color-dark; + z-index: $zindex-0; + } + } + + .bar-slider-btn { + background: $primary-color; + border: 0; + border-radius: 50%; + height: $unit-3; + padding: 0; + position: absolute; + right: 0; + top: 50%; + transform: translate(50%, -50%); + width: $unit-3; + + &:active { + box-shadow: 0 0 0 .1rem $primary-color; + } + } +} diff --git a/user/plugins/problems/scss/_base.scss b/user/plugins/problems/scss/_base.scss new file mode 100644 index 00000000..4e01b202 --- /dev/null +++ b/user/plugins/problems/scss/_base.scss @@ -0,0 +1,44 @@ +// Base +*, +*::before, +*::after { + box-sizing: inherit; +} + +html { + box-sizing: border-box; + font-size: $html-font-size; + line-height: $html-line-height; + -webkit-tap-highlight-color: transparent; +} + +body { + background: $body-bg; + color: $body-font-color; + font-family: $body-font-family; + font-size: $font-size; + overflow-x: hidden; + text-rendering: optimizeLegibility; +} + +a { + color: $link-color; + outline: none; + text-decoration: none; + + &:focus { + @include control-shadow(); + } + + &:focus, + &:hover, + &:active, + &.active { + color: $link-color-dark; + text-decoration: underline; + } + + &:visited { + color: $link-color-light; + } +} diff --git a/user/plugins/problems/scss/_breadcrumbs.scss b/user/plugins/problems/scss/_breadcrumbs.scss new file mode 100644 index 00000000..f2c9185a --- /dev/null +++ b/user/plugins/problems/scss/_breadcrumbs.scss @@ -0,0 +1,29 @@ +// Breadcrumbs +.breadcrumb { + list-style: none; + margin: $unit-1 0; + padding: $unit-1 0; + + .breadcrumb-item { + color: $gray-color-dark; + display: inline-block; + margin: 0; + padding: $unit-1 0; + + &:not(:last-child) { + margin-right: $unit-1; + + a { + color: $gray-color-dark; + } + } + + &:not(:first-child) { + &::before { + color: $gray-color-light; + content: "/"; + padding-right: $unit-2; + } + } + } +} diff --git a/user/plugins/problems/scss/_buttons.scss b/user/plugins/problems/scss/_buttons.scss new file mode 100644 index 00000000..2ae8463a --- /dev/null +++ b/user/plugins/problems/scss/_buttons.scss @@ -0,0 +1,195 @@ +// Buttons +.btn { + @include control-transition(); + appearance: none; + background: $bg-color-light; + border: $border-width solid $primary-color; + border-radius: $border-radius; + color: $primary-color; + cursor: pointer; + display: inline-block; + font-size: $font-size; + height: $control-size; + line-height: $line-height; + outline: none; + padding: $control-padding-y $control-padding-x; + text-align: center; + text-decoration: none; + user-select: none; + vertical-align: middle; + white-space: nowrap; + &:focus { + @include control-shadow(); + } + &:focus, + &:hover { + background: $secondary-color; + border-color: $primary-color-dark; + text-decoration: none; + } + &:active, + &.active { + background: $primary-color-dark; + border-color: darken($primary-color-dark, 5%); + color: $light-color; + text-decoration: none; + &.loading { + &::after { + border-bottom-color: $light-color; + border-left-color: $light-color; + } + } + } + &[disabled], + &:disabled, + &.disabled { + cursor: default; + opacity: .5; + pointer-events: none; + } + + // Button Primary + &.btn-primary { + background: $primary-color; + border-color: $primary-color-dark; + color: $light-color; + &:focus, + &:hover { + background: darken($primary-color-dark, 2%); + border-color: darken($primary-color-dark, 5%); + color: $light-color; + } + &:active, + &.active { + background: darken($primary-color-dark, 4%); + border-color: darken($primary-color-dark, 7%); + color: $light-color; + } + &.loading { + &::after { + border-bottom-color: $light-color; + border-left-color: $light-color; + } + } + } + + // Button Colors + &.btn-success { + @include button-variant($success-color); + } + + &.btn-error { + @include button-variant($error-color); + } + + &.btn-warning { + @include button-variant($warning-color); + } + + // Button Link + &.btn-link { + background: transparent; + border-color: transparent; + color: $link-color; + &:focus, + &:hover, + &:active, + &.active { + color: $link-color-dark; + } + } + + // Button Sizes + &.btn-sm { + font-size: $font-size-sm; + height: $control-size-sm; + padding: $control-padding-y-sm $control-padding-x-sm; + } + + &.btn-lg { + font-size: $font-size-lg; + height: $control-size-lg; + padding: $control-padding-y-lg $control-padding-x-lg; + } + + // Button Block + &.btn-block { + display: block; + width: 100%; + } + + // Button Action + &.btn-action { + width: $control-size; + padding-left: 0; + padding-right: 0; + + &.btn-sm { + width: $control-size-sm; + } + + &.btn-lg { + width: $control-size-lg; + } + } + + // Button Clear + &.btn-clear { + background: transparent; + border: 0; + color: currentColor; + height: $unit-4; + line-height: $unit-4; + margin-left: $unit-1; + margin-right: -2px; + opacity: 1; + padding: 0; + text-decoration: none; + width: $unit-4; + + &:hover { + opacity: .95; + } + + &::before { + content: "\2715"; + } + } +} + +// Button groups +.btn-group { + display: inline-flex; + flex-wrap: wrap; + + .btn { + flex: 1 0 auto; + &:first-child:not(:last-child) { + border-bottom-right-radius: 0; + border-top-right-radius: 0; + } + &:not(:first-child):not(:last-child) { + border-radius: 0; + margin-left: -$border-width; + } + &:last-child:not(:first-child) { + border-bottom-left-radius: 0; + border-top-left-radius: 0; + margin-left: -$border-width; + } + &:focus, + &:hover, + &:active, + &.active { + z-index: $zindex-0; + } + } + + &.btn-group-block { + display: flex; + + .btn { + flex: 1 0 0; + } + } +} diff --git a/user/plugins/problems/scss/_calendars.scss b/user/plugins/problems/scss/_calendars.scss new file mode 100644 index 00000000..ff001451 --- /dev/null +++ b/user/plugins/problems/scss/_calendars.scss @@ -0,0 +1,222 @@ +// Calendars +.calendar { + border: $border-width solid $border-color; + border-radius: $border-radius; + display: block; + min-width: 280px; + + .calendar-nav { + align-items: center; + background: $bg-color; + border-top-left-radius: $border-radius; + border-top-right-radius: $border-radius; + display: flex; + font-size: $font-size-lg; + padding: $layout-spacing; + } + + .calendar-header, + .calendar-body { + display: flex; + flex-wrap: wrap; + justify-content: center; + padding: $layout-spacing 0; + + .calendar-date { + flex: 0 0 14.28%; // 7 calendar-items each row + max-width: 14.28%; + } + } + + .calendar-header { + background: $bg-color; + border-bottom: $border-width solid $border-color; + color: $gray-color; + font-size: $font-size-sm; + text-align: center; + } + + .calendar-body { + color: $gray-color-dark; + } + + .calendar-date { + border: 0; + padding: $unit-1; + + .date-item { + @include control-transition(); + appearance: none; + background: transparent; + border: $border-width solid transparent; + border-radius: 50%; + color: $gray-color-dark; + cursor: pointer; + font-size: $font-size-sm; + height: $unit-7; + line-height: $unit-5; + outline: none; + padding: $unit-h; + position: relative; + text-align: center; + text-decoration: none; + vertical-align: middle; + white-space: nowrap; + width: $unit-7; + + &.date-today { + border-color: $secondary-color-dark; + color: $primary-color; + } + + &:focus { + @include control-shadow(); + } + + &:focus, + &:hover { + background: $secondary-color-light; + border-color: $secondary-color-dark; + color: $primary-color; + text-decoration: none; + } + &:active, + &.active { + background: $primary-color-dark; + border-color: darken($primary-color-dark, 5%); + color: $light-color; + } + + // Calendar badge support + &.badge { + &::after { + position: absolute; + top: 3px; + right: 3px; + transform: translate(50%, -50%); + } + } + } + + .date-item, + .calendar-event { + &:disabled, + &.disabled { + cursor: default; + opacity: .25; + pointer-events: none; + } + } + + &.prev-month, + &.next-month { + .date-item, + .calendar-event { + opacity: .25; + } + } + } + + .calendar-range { + position: relative; + + &::before { + background: $secondary-color; + content: ""; + height: $unit-7; + left: 0; + position: absolute; + right: 0; + top: 50%; + transform: translateY(-50%); + } + &.range-start { + &::before { + left: 50%; + } + } + &.range-end { + &::before { + right: 50%; + } + } + + &.range-start, + &.range-end { + .date-item { + background: $primary-color-dark; + border-color: darken($primary-color-dark, 5%); + color: $light-color; + } + } + + .date-item { + color: $primary-color; + } + } + + // Calendars size + &.calendar-lg { + .calendar-body { + padding: 0; + + .calendar-date { + border-bottom: $border-width solid $border-color; + border-right: $border-width solid $border-color; + display: flex; + flex-direction: column; + height: 5.5rem; + padding: 0; + + &:nth-child(7n) { + border-right: 0; + } + &:nth-last-child(-n+7) { + border-bottom: 0; + } + } + } + + .date-item { + align-self: flex-end; + height: $unit-7; + margin-right: $layout-spacing-sm; + margin-top: $layout-spacing-sm; + } + + .calendar-range { + &::before { + top: 19px; + } + &.range-start { + &::before { + left: auto; + width: 19px; + } + } + &.range-end { + &::before { + right: 19px; + } + } + } + + .calendar-events { + flex-grow: 1; + line-height: 1; + overflow-y: auto; + padding: $layout-spacing-sm; + } + + .calendar-event { + border-radius: $border-radius; + font-size: $font-size-sm; + display: block; + margin: $unit-h auto; + overflow: hidden; + padding: 3px 4px; + text-overflow: ellipsis; + white-space: nowrap; + } + } +} diff --git a/user/plugins/problems/scss/_cards.scss b/user/plugins/problems/scss/_cards.scss new file mode 100644 index 00000000..6b712e15 --- /dev/null +++ b/user/plugins/problems/scss/_cards.scss @@ -0,0 +1,43 @@ +// Cards +.card { + background: $bg-color-light; + border: $border-width solid $border-color; + border-radius: $border-radius; + display: flex; + flex-direction: column; + + .card-header, + .card-body, + .card-footer { + padding: $layout-spacing-lg; + padding-bottom: 0; + + &:last-child { + padding-bottom: $layout-spacing-lg; + } + } + + .card-body { + flex: 1 1 auto; + } + + .card-image { + padding-top: $layout-spacing-lg; + + &:first-child { + padding-top: 0; + + img { + border-top-left-radius: $border-radius; + border-top-right-radius: $border-radius; + } + } + + &:last-child { + img { + border-bottom-left-radius: $border-radius; + border-bottom-right-radius: $border-radius; + } + } + } +} diff --git a/user/plugins/problems/scss/_carousels.scss b/user/plugins/problems/scss/_carousels.scss new file mode 100644 index 00000000..55dc31ce --- /dev/null +++ b/user/plugins/problems/scss/_carousels.scss @@ -0,0 +1,126 @@ +// Carousels +.carousel { + background: $bg-color; + display: block; + overflow: hidden; + position: relative; + width: 100%; + -webkit-overflow-scrolling: touch; + z-index: $zindex-0; + + .carousel-container { + height: 100%; + left: 0; + position: relative; + &::before { + content: ""; + display: block; + padding-bottom: 56.25%; + } + + .carousel-item { + animation: carousel-slideout 1s ease-in-out 1; + height: 100%; + left: 0; + margin: 0; + opacity: 0; + position: absolute; + top: 0; + width: 100%; + + &:hover { + .item-prev, + .item-next { + opacity: 1; + } + } + } + + .item-prev, + .item-next { + background: rgba($gray-color-light, .25); + border-color: rgba($gray-color-light, .5); + color: $gray-color-light; + opacity: 0; + position: absolute; + top: 50%; + transition: all .4s ease; + transform: translateY(-50%); + z-index: $zindex-1; + } + .item-prev { + left: 1rem; + } + .item-next { + right: 1rem; + } + } + + .carousel-locator { + &:nth-of-type(1):checked ~ .carousel-container .carousel-item:nth-of-type(1), + &:nth-of-type(2):checked ~ .carousel-container .carousel-item:nth-of-type(2), + &:nth-of-type(3):checked ~ .carousel-container .carousel-item:nth-of-type(3), + &:nth-of-type(4):checked ~ .carousel-container .carousel-item:nth-of-type(4) { + animation: carousel-slidein .75s ease-in-out 1; + opacity: 1; + z-index: $zindex-1; + } + &:nth-of-type(1):checked ~ .carousel-nav .nav-item:nth-of-type(1), + &:nth-of-type(2):checked ~ .carousel-nav .nav-item:nth-of-type(2), + &:nth-of-type(3):checked ~ .carousel-nav .nav-item:nth-of-type(3), + &:nth-of-type(4):checked ~ .carousel-nav .nav-item:nth-of-type(4) { + color: $gray-color-light; + } + } + + .carousel-nav { + bottom: $layout-spacing; + display: flex; + justify-content: center; + left: 50%; + position: absolute; + transform: translateX(-50%); + width: 10rem; + z-index: $zindex-1; + + .nav-item { + color: rgba($gray-color-light, .5); + display: block; + flex: 1 0 auto; + height: $unit-8; + margin: $unit-1; + max-width: 2.5rem; + position: relative; + + &::before { + background: currentColor; + content: ""; + display: block; + height: $unit-h; + position: absolute; + top: .5rem; + width: 100%; + } + } + } +} + +@keyframes carousel-slidein { + 0% { + transform: translateX(100%); + } + 100% { + transform: translateX(0); + } +} + +@keyframes carousel-slideout { + 0% { + opacity: 1; + transform: translateX(0); + } + 100% { + opacity: 1; + transform: translateX(-50%); + } +} diff --git a/user/plugins/problems/scss/_chips.scss b/user/plugins/problems/scss/_chips.scss new file mode 100644 index 00000000..1763567c --- /dev/null +++ b/user/plugins/problems/scss/_chips.scss @@ -0,0 +1,30 @@ +// Chips +.chip { + align-items: center; + background: $bg-color-dark; + border-radius: 5rem; + color: $gray-color-dark; + display: inline-flex; + font-size: 90%; + height: $unit-6; + line-height: $unit-4; + margin: $unit-h; + max-width: 100%; + padding: $unit-1 $unit-2; + text-decoration: none; + vertical-align: middle; + + &.active { + background: $primary-color; + color: $light-color; + } + + .avatar { + margin-left: -$unit-2; + margin-right: $unit-1; + } + + .btn-clear { + transform: scale(.75); + } +} diff --git a/user/plugins/problems/scss/_codes.scss b/user/plugins/problems/scss/_codes.scss new file mode 100644 index 00000000..817452bd --- /dev/null +++ b/user/plugins/problems/scss/_codes.scss @@ -0,0 +1,31 @@ +// Codes +code { + @include label-base(); + @include label-variant($code-color, lighten($code-color, 42.5%)); + font-size: 85%; +} + +.code { + border-radius: $border-radius; + color: $body-font-color; + position: relative; + + &::before { + color: $gray-color; + content: attr(data-lang); + font-size: $font-size-sm; + position: absolute; + right: $layout-spacing; + top: $unit-h; + } + + code { + background: $bg-color; + color: inherit; + display: block; + line-height: 1.5; + overflow-x: auto; + padding: 1rem; + width: 100%; + } +} diff --git a/user/plugins/problems/scss/_comparison-sliders.scss b/user/plugins/problems/scss/_comparison-sliders.scss new file mode 100644 index 00000000..72bb25f8 --- /dev/null +++ b/user/plugins/problems/scss/_comparison-sliders.scss @@ -0,0 +1,115 @@ +// Image comparison slider +// Credit: http://codepen.io/solipsistacp/pen/Gpmaq +.comparison-slider { + height: 50vh; + overflow: hidden; + position: relative; + width: 100%; + -webkit-overflow-scrolling: touch; + + .comparison-before, + .comparison-after { + height: 100%; + left: 0; + margin: 0; + overflow: hidden; + position: absolute; + top: 0; + + img { + height: 100%; + object-fit: cover; + object-position: left center; + position: absolute; + width: 100%; + } + } + + .comparison-before { + width: 100%; + z-index: 1; + + .comparison-label { + right: $unit-4; + } + } + + .comparison-after { + max-width: 100%; + min-width: 0; + z-index: 2; + + &::before { + background: transparent; + content: ""; + cursor: default; + height: 100%; + left: 0; + position: absolute; + right: $unit-4; + top: 0; + z-index: $zindex-0; + } + + &::after { + background: currentColor; + border-radius: 50%; + box-shadow: 0 -5px, 0 5px; + color: $light-color; + content: ""; + height: 3px; + position: absolute; + right: $unit-2; + top: 50%; + transform: translate(50%, -50%); + width: 3px; + } + + .comparison-label { + left: $unit-4; + } + } + + .comparison-resizer { + animation: first-run 1.5s 1 ease-in-out; + cursor: ew-resize; + height: $unit-4; + left: 0; + max-width: 100%; + min-width: $unit-4; + opacity: 0; + outline: none; + position: relative; + resize: horizontal; + top: 50%; + transform: translateY(-50%) scaleY(30); + width: 0; + } + + .comparison-label { + background: rgba($dark-color, .5); + bottom: $unit-4; + color: $light-color; + padding: $unit-1 $unit-2; + position: absolute; + user-select: none; + } +} + +@keyframes first-run { + 0% { + width: 0; + } + 25% { + width: $unit-12; + } + 50% { + width: $unit-4; + } + 75% { + width: $unit-6; + } + 100% { + width: 0; + } +} diff --git a/user/plugins/problems/scss/_dropdowns.scss b/user/plugins/problems/scss/_dropdowns.scss new file mode 100644 index 00000000..324440ba --- /dev/null +++ b/user/plugins/problems/scss/_dropdowns.scss @@ -0,0 +1,36 @@ +// Dropdown +.dropdown { + display: inline-block; + position: relative; + + .menu { + animation: slide-down .15s ease 1; + display: none; + left: 0; + max-height: 50vh; + overflow-y: auto; + position: absolute; + top: 100%; + } + + &.dropdown-right { + .menu { + left: auto; + right: 0; + } + } + + &.active .menu, + .dropdown-toggle:focus + .menu, + .menu:hover { + display: block; + } + + // Fix dropdown-toggle border radius in button groups + .btn-group { + .dropdown-toggle:nth-last-child(2) { + border-bottom-right-radius: $border-radius; + border-top-right-radius: $border-radius; + } + } +} diff --git a/user/plugins/problems/scss/_empty.scss b/user/plugins/problems/scss/_empty.scss new file mode 100644 index 00000000..accba9ca --- /dev/null +++ b/user/plugins/problems/scss/_empty.scss @@ -0,0 +1,21 @@ +// Empty states (or Blank slates) +.empty { + background: $bg-color; + border-radius: $border-radius; + color: $gray-color-dark; + text-align: center; + padding: $unit-16 $unit-8; + + .empty-icon { + margin-bottom: $layout-spacing-lg; + } + + .empty-title, + .empty-subtitle { + margin: $layout-spacing auto; + } + + .empty-action { + margin-top: $layout-spacing-lg; + } +} diff --git a/user/plugins/problems/scss/_filters.scss b/user/plugins/problems/scss/_filters.scss new file mode 100644 index 00000000..37ccc89e --- /dev/null +++ b/user/plugins/problems/scss/_filters.scss @@ -0,0 +1,37 @@ +// Filters +// The number of filter options +$filter-number: 8 !default; + +%filter-checked-nav { + background: $primary-color; + color: $light-color; +} + +%filter-checked-body { + display: none; +} + +.filter { + .filter-nav { + margin: $layout-spacing 0; + } + + .filter-body { + display: flex; + flex-wrap: wrap; + } + + .filter-tag { + @for $i from 0 through ($filter-number) { + &#tag-#{$i}:checked ~ .filter-nav .chip[for="tag-#{$i}"] { + @extend %filter-checked-nav; + } + } + + @for $i from 1 through ($filter-number) { + &#tag-#{$i}:checked ~ .filter-body .filter-item:not([data-tag~="tag-#{$i}"]) { + @extend %filter-checked-body; + } + } + } +} diff --git a/user/plugins/problems/scss/_forms.scss b/user/plugins/problems/scss/_forms.scss new file mode 100644 index 00000000..8b53df9f --- /dev/null +++ b/user/plugins/problems/scss/_forms.scss @@ -0,0 +1,545 @@ +// Forms +.form-group { + &:not(:last-child) { + margin-bottom: $layout-spacing; + } +} + +fieldset { + margin-bottom: $layout-spacing-lg; +} + +legend { + font-size: $font-size-lg; + font-weight: 500; + margin-bottom: $layout-spacing-lg; +} + +// Form element: Label +.form-label { + display: block; + line-height: $line-height; + padding: $control-padding-y + $border-width 0; + + &.label-sm { + font-size: $font-size-sm; + padding: $control-padding-y-sm + $border-width 0; + } + + &.label-lg { + font-size: $font-size-lg; + padding: $control-padding-y-lg + $border-width 0; + } +} + +// Form element: Input +.form-input { + @include control-transition(); + appearance: none; + background: $bg-color-light; + background-image: none; + border: $border-width solid $border-color-dark; + border-radius: $border-radius; + color: $body-font-color; + display: block; + font-size: $font-size; + height: $control-size; + line-height: $line-height; + max-width: 100%; + outline: none; + padding: $control-padding-y $control-padding-x; + position: relative; + width: 100%; + &:focus { + @include control-shadow(); + border-color: $primary-color; + } + &::placeholder { + color: $gray-color; + } + + // Input sizes + &.input-sm { + font-size: $font-size-sm; + height: $control-size-sm; + padding: $control-padding-y-sm $control-padding-x-sm; + } + + &.input-lg { + font-size: $font-size-lg; + height: $control-size-lg; + padding: $control-padding-y-lg $control-padding-x-lg; + } + + &.input-inline { + display: inline-block; + vertical-align: middle; + width: auto; + } + + // Input types + &[type="file"] { + height: auto; + } +} + +// Form element: Textarea +textarea.form-input { + height: auto; +} + +// Form element: Input hint +.form-input-hint { + color: $gray-color; + font-size: $font-size-sm; + margin-top: $unit-1; + + .has-success &, + .is-success + & { + color: $success-color; + } + + .has-error &, + .is-error + & { + color: $error-color; + } +} + +// Form element: Select +.form-select { + appearance: none; + border: $border-width solid $border-color-dark; + border-radius: $border-radius; + color: inherit; + font-size: $font-size; + height: $control-size; + line-height: $line-height; + outline: none; + padding: $control-padding-y $control-padding-x; + vertical-align: middle; + width: 100%; + + &[size], + &[multiple] { + height: auto; + + option { + padding: $unit-h $unit-1; + } + } + &:not([multiple]):not([size]) { + background: #fff url("data:image/svg+xml;charset=utf8,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%204%205'%3E%3Cpath%20fill='%23667189'%20d='M2%200L0%202h4zm0%205L0%203h4z'/%3E%3C/svg%3E") no-repeat right .35rem center/.4rem .5rem; + padding-right: $control-icon-size + $control-padding-x; + } + &:focus { + @include control-shadow(); + border-color: $primary-color; + } + &::-ms-expand { + display: none; + } + + // Select sizes + &.select-sm { + font-size: $font-size-sm; + height: $control-size-sm; + padding: $control-padding-y-sm ($control-icon-size + $control-padding-x-sm) $control-padding-y-sm $control-padding-x-sm; + } + + &.select-lg { + font-size: $font-size-lg; + height: $control-size-lg; + padding: $control-padding-y-lg ($control-icon-size + $control-padding-x-lg) $control-padding-y-lg $control-padding-x-lg; + } +} + +// Form Icons +.has-icon-left, +.has-icon-right { + position: relative; + + .form-icon { + height: $control-icon-size; + margin: 0 $control-padding-y; + position: absolute; + top: 50%; + transform: translateY(-50%); + width: $control-icon-size; + z-index: $zindex-0 + 1; + } +} + +.has-icon-left { + .form-icon { + left: $border-width; + } + + .form-input { + padding-left: $control-icon-size + $control-padding-y * 2; + } +} + +.has-icon-right { + .form-icon { + right: $border-width; + } + + .form-input { + padding-right: $control-icon-size + $control-padding-y * 2; + } +} + +// Form element: Checkbox and Radio +.form-checkbox, +.form-radio, +.form-switch { + display: block; + line-height: $line-height; + margin: ($control-size - $control-size-sm) / 2 0; + min-height: 1.2rem; + padding: (($control-size-sm - $line-height) / 2) $control-padding-x (($control-size-sm - $line-height) / 2) ($control-icon-size + $control-padding-x); + position: relative; + + input { + clip: rect(0, 0, 0, 0); + height: 1px; + margin: -1px; + overflow: hidden; + position: absolute; + width: 1px; + &:focus + .form-icon { + @include control-shadow(); + border-color: $primary-color; + } + &:checked + .form-icon { + background: $primary-color; + border-color: $primary-color; + } + } + + .form-icon { + @include control-transition(); + border: $border-width solid $border-color-dark; + cursor: pointer; + display: inline-block; + position: absolute; + } + + // Input checkbox, radio and switch sizes + &.input-sm { + font-size: $font-size-sm; + margin: 0; + } + + &.input-lg { + font-size: $font-size-lg; + margin: ($control-size-lg - $control-size-sm) / 2 0; + } +} + +.form-checkbox, +.form-radio { + .form-icon { + background: $bg-color-light; + height: $control-icon-size; + left: 0; + top: ($control-size-sm - $control-icon-size) / 2; + width: $control-icon-size; + } + + input { + &:active + .form-icon { + background: $bg-color-dark; + } + } +} +.form-checkbox { + .form-icon { + border-radius: $border-radius; + } + + input { + &:checked + .form-icon { + &::before { + background-clip: padding-box; + border: $border-width-lg solid $light-color; + border-left-width: 0; + border-top-width: 0; + content: ""; + height: 12px; + left: 50%; + margin-left: -4px; + margin-top: -8px; + position: absolute; + top: 50%; + transform: rotate(45deg); + width: 8px; + } + } + &:indeterminate + .form-icon { + background: $primary-color; + border-color: $primary-color; + &::before { + background: $bg-color-light; + content: ""; + height: 2px; + left: 50%; + margin-left: -5px; + margin-top: -1px; + position: absolute; + top: 50%; + width: 10px; + } + } + } +} +.form-radio { + .form-icon { + border-radius: 50%; + } + + input { + &:checked + .form-icon { + &::before { + background: $bg-color-light; + border-radius: 50%; + content: ""; + height: 4px; + left: 50%; + position: absolute; + top: 50%; + transform: translate(-50%, -50%); + width: 4px; + } + } + } +} + +// Form element: Switch +.form-switch { + padding-left: ($unit-8 + $control-padding-x); + + .form-icon { + background: $gray-color-light; + background-clip: padding-box; + border-radius: $unit-2 + $border-width; + height: $unit-4 + $border-width * 2; + left: 0; + top: ($control-size-sm - $unit-4) / 2 - $border-width; + width: $unit-8; + &::before { + @include control-transition(); + background: $bg-color-light; + border-radius: 50%; + content: ""; + display: block; + height: $unit-4; + left: 0; + position: absolute; + top: 0; + width: $unit-4; + } + } + + input { + &:checked + .form-icon { + &::before { + left: 14px; + } + } + &:active + .form-icon { + &::before { + background: $bg-color; + } + } + } +} + +// Form element: Input groups +.input-group { + display: flex; + + .input-group-addon { + background: $bg-color; + border: $border-width solid $border-color-dark; + border-radius: $border-radius; + line-height: $line-height; + padding: $control-padding-y $control-padding-x; + white-space: nowrap; + + &.addon-sm { + font-size: $font-size-sm; + padding: $control-padding-y-sm $control-padding-x-sm; + } + + &.addon-lg { + font-size: $font-size-lg; + padding: $control-padding-y-lg $control-padding-x-lg; + } + } + + .form-input, + .form-select { + flex: 1 1 auto; + width: 1%; + } + + .input-group-btn { + z-index: $zindex-0; + } + + .form-input, + .form-select, + .input-group-addon, + .input-group-btn { + &:first-child:not(:last-child) { + border-bottom-right-radius: 0; + border-top-right-radius: 0; + } + &:not(:first-child):not(:last-child) { + border-radius: 0; + margin-left: -$border-width; + } + &:last-child:not(:first-child) { + border-bottom-left-radius: 0; + border-top-left-radius: 0; + margin-left: -$border-width; + } + &:focus { + z-index: $zindex-0 + 1; + } + } + + .form-select { + width: auto; + } + + &.input-inline { + display: inline-flex; + } +} + +// Form validation states +.form-input, +.form-select { + .has-success &, + &.is-success { + border-color: $success-color; + &:focus { + @include control-shadow($success-color); + } + } + + .has-error &, + &.is-error { + border-color: $error-color; + &:focus { + @include control-shadow($error-color); + } + } +} + +.form-checkbox, +.form-radio, +.form-switch { + .has-error &, + &.is-error { + .form-icon { + border-color: $error-color; + } + + input { + &:checked + .form-icon { + background: $error-color; + border-color: $error-color; + } + + &:focus + .form-icon { + @include control-shadow($error-color); + border-color: $error-color; + } + } + } +} + +.form-checkbox { + .has-error &, + &.is-error { + input { + &:indeterminate + .form-icon { + background: $error-color; + border-color: $error-color; + } + } + } +} + +// validation based on :placeholder-shown (Edge doesn't support it yet) +.form-input { + &:not(:placeholder-shown) { + &:invalid { + border-color: $error-color; + &:focus { + @include control-shadow($error-color); + } + + & + .form-input-hint { + color: $error-color; + } + } + } +} + +// Form disabled and readonly +.form-input, +.form-select { + &:disabled, + &.disabled { + background-color: $bg-color-dark; + cursor: not-allowed; + opacity: .5; + } +} + +.form-input { + &[readonly] { + background-color: $bg-color; + } +} + +input { + &:disabled, + &.disabled { + & + .form-icon { + background: $bg-color-dark; + cursor: not-allowed; + opacity: .5; + } + } +} + +.form-switch { + input { + &:disabled, + &.disabled { + & + .form-icon::before { + background: $bg-color-light; + } + } + } +} + +// Form horizontal +.form-horizontal { + padding: $layout-spacing 0; + + .form-group { + display: flex; + flex-wrap: wrap; + } +} + +// Form inline +.form-inline { + display: inline-block; +} \ No newline at end of file diff --git a/user/plugins/problems/scss/_icons.scss b/user/plugins/problems/scss/_icons.scss new file mode 100644 index 00000000..4f3c5ce6 --- /dev/null +++ b/user/plugins/problems/scss/_icons.scss @@ -0,0 +1,5 @@ +// CSS Icons +@import "icons/icons-core"; +@import "icons/icons-navigation"; +@import "icons/icons-action"; +@import "icons/icons-object"; \ No newline at end of file diff --git a/user/plugins/problems/scss/_labels.scss b/user/plugins/problems/scss/_labels.scss new file mode 100644 index 00000000..ca693cd2 --- /dev/null +++ b/user/plugins/problems/scss/_labels.scss @@ -0,0 +1,34 @@ +// Labels +.label { + @include label-base(); + @include label-variant(lighten($body-font-color, 5%), $bg-color-dark); + display: inline-block; + + // Label rounded + &.label-rounded { + border-radius: 5rem; + padding-left: .4rem; + padding-right: .4rem; + } + + // Label colors + &.label-primary { + @include label-variant($light-color, $primary-color); + } + + &.label-secondary { + @include label-variant($primary-color, $secondary-color); + } + + &.label-success { + @include label-variant($light-color, $success-color); + } + + &.label-warning { + @include label-variant($light-color, $warning-color); + } + + &.label-error { + @include label-variant($light-color, $error-color); + } +} diff --git a/user/plugins/problems/scss/_layout.scss b/user/plugins/problems/scss/_layout.scss new file mode 100644 index 00000000..83e2c18b --- /dev/null +++ b/user/plugins/problems/scss/_layout.scss @@ -0,0 +1,424 @@ +// Layout +.container { + margin-left: auto; + margin-right: auto; + padding-left: $layout-spacing; + padding-right: $layout-spacing; + width: 100%; + @extend .clearfix; + + $grid-spacing: ($layout-spacing / ($layout-spacing * 0 + 1)) * $html-font-size; + + &.grid-xl { + max-width: $grid-spacing * 2 + $size-xl; + } + + &.grid-lg { + max-width: $grid-spacing * 2 + $size-lg; + } + + &.grid-md { + max-width: $grid-spacing * 2 + $size-md; + } + + &.grid-sm { + max-width: $grid-spacing * 2 + $size-sm; + } + + &.grid-xs { + max-width: $grid-spacing * 2 + $size-xs; + } +} + +// Responsive breakpoint system +.show-xs, +.show-sm, +.show-md, +.show-lg, +.show-xl { + display: none !important; +} + +// Responsive grid system +.columns { + display: flex; + flex-wrap: wrap; + margin-left: -$layout-spacing; + margin-right: -$layout-spacing; + + &.col-gapless { + margin-left: 0; + margin-right: 0; + + & > .column { + padding-left: 0; + padding-right: 0; + } + } + &.col-oneline { + flex-wrap: nowrap; + overflow-x: auto; + } +} +.column { + flex: 1; + max-width: 100%; + padding-left: $layout-spacing; + padding-right: $layout-spacing; + + &.col-12, + &.col-11, + &.col-10, + &.col-9, + &.col-8, + &.col-7, + &.col-6, + &.col-5, + &.col-4, + &.col-3, + &.col-2, + &.col-1 { + flex: none; + } +} +.col-12 { + width: 100%; +} +.col-11 { + width: 91.66666667%; +} +.col-10 { + width: 83.33333333%; +} +.col-9 { + width: 75%; +} +.col-8 { + width: 66.66666667%; +} +.col-7 { + width: 58.33333333%; +} +.col-6 { + width: 50%; +} +.col-5 { + width: 41.66666667%; +} +.col-4 { + width: 33.33333333%; +} +.col-3 { + width: 25%; +} +.col-2 { + width: 16.66666667%; +} +.col-1 { + width: 8.33333333%; +} +.col-auto { + flex: 0 0 auto; + max-width: none; + width: auto; +} +.col-mx-auto { + margin-left: auto; + margin-right: auto; +} +.col-ml-auto { + margin-left: auto; +} +.col-mr-auto { + margin-right: auto; +} +@media (max-width: $size-xl) { + .col-xl-12, + .col-xl-11, + .col-xl-10, + .col-xl-9, + .col-xl-8, + .col-xl-7, + .col-xl-6, + .col-xl-5, + .col-xl-4, + .col-xl-3, + .col-xl-2, + .col-xl-1 { + flex: none; + } + .col-xl-12 { + width: 100%; + } + .col-xl-11 { + width: 91.66666667%; + } + .col-xl-10 { + width: 83.33333333%; + } + .col-xl-9 { + width: 75%; + } + .col-xl-8 { + width: 66.66666667%; + } + .col-xl-7 { + width: 58.33333333%; + } + .col-xl-6 { + width: 50%; + } + .col-xl-5 { + width: 41.66666667%; + } + .col-xl-4 { + width: 33.33333333%; + } + .col-xl-3 { + width: 25%; + } + .col-xl-2 { + width: 16.66666667%; + } + .col-xl-1 { + width: 8.33333333%; + } + .hide-xl { + display: none !important; + } + .show-xl { + display: block !important; + } +} +@media (max-width: $size-lg) { + .col-lg-12, + .col-lg-11, + .col-lg-10, + .col-lg-9, + .col-lg-8, + .col-lg-7, + .col-lg-6, + .col-lg-5, + .col-lg-4, + .col-lg-3, + .col-lg-2, + .col-lg-1 { + flex: none; + } + .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%; + } + .hide-lg { + display: none !important; + } + .show-lg { + display: block !important; + } +} +@media (max-width: $size-md) { + .col-md-12, + .col-md-11, + .col-md-10, + .col-md-9, + .col-md-8, + .col-md-7, + .col-md-6, + .col-md-5, + .col-md-4, + .col-md-3, + .col-md-2, + .col-md-1 { + flex: none; + } + .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%; + } + .hide-md { + display: none !important; + } + .show-md { + display: block !important; + } +} +@media (max-width: $size-sm) { + .col-sm-12, + .col-sm-11, + .col-sm-10, + .col-sm-9, + .col-sm-8, + .col-sm-7, + .col-sm-6, + .col-sm-5, + .col-sm-4, + .col-sm-3, + .col-sm-2, + .col-sm-1 { + flex: none; + } + .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%; + } + .hide-sm { + display: none !important; + } + .show-sm { + display: block !important; + } +} +@media (max-width: $size-xs) { + .col-xs-12, + .col-xs-11, + .col-xs-10, + .col-xs-9, + .col-xs-8, + .col-xs-7, + .col-xs-6, + .col-xs-5, + .col-xs-4, + .col-xs-3, + .col-xs-2, + .col-xs-1 { + flex: none; + } + .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%; + } + .hide-xs { + display: none !important; + } + .show-xs { + display: block !important; + } +} diff --git a/user/plugins/problems/scss/_media.scss b/user/plugins/problems/scss/_media.scss new file mode 100644 index 00000000..4029e4cd --- /dev/null +++ b/user/plugins/problems/scss/_media.scss @@ -0,0 +1,75 @@ +// Media +// Image responsive +.img-responsive { + display: block; + height: auto; + max-width: 100%; +} + +// object-fit support is coming to Microsoft Edge +// https://developer.microsoft.com/en-us/microsoft-edge/platform/status/objectfitandobjectposition/ +.img-fit-cover { + object-fit: cover; +} + +.img-fit-contain { + object-fit: contain; +} + +// Video responsive +.video-responsive { + display: block; + overflow: hidden; + padding: 0; + position: relative; + width: 100%; + &::before { + content: ""; + display: block; + padding-bottom: 56.25%; // Default ratio 16:9, you can calculate this value by dividing 9 by 16 + } + + iframe, + object, + embed { + border: 0; + bottom: 0; + height: 100%; + left: 0; + position: absolute; + right: 0; + top: 0; + width: 100%; + } +} + +video.video-responsive { + height: auto; + max-width: 100%; + + &::before { + content: none; + } +} + +.video-responsive-4-3 { + &::before { + padding-bottom: 75%; // Ratio 4:3 + } +} + +.video-responsive-1-1 { + &::before { + padding-bottom: 100%; // Ratio 1:1 + } +} + +// Figure +.figure { + margin: 0 0 $layout-spacing 0; + + .figure-caption { + color: $gray-color-dark; + margin-top: $layout-spacing; + } +} diff --git a/user/plugins/problems/scss/_menus.scss b/user/plugins/problems/scss/_menus.scss new file mode 100644 index 00000000..5bc5ef82 --- /dev/null +++ b/user/plugins/problems/scss/_menus.scss @@ -0,0 +1,62 @@ +// Menus +.menu { + @include shadow-variant(.05rem); + background: $bg-color-light; + border-radius: $border-radius; + list-style: none; + margin: 0; + min-width: $control-width-xs; + padding: $unit-2; + transform: translateY($layout-spacing-sm); + z-index: $zindex-3; + + &.menu-nav { + background: transparent; + box-shadow: none; + } + + .menu-item { + margin-top: 0; + padding: 0 $unit-2; + text-decoration: none; + user-select: none; + + & > a { + border-radius: $border-radius; + color: inherit; + display: block; + margin: 0 (-$unit-2); + padding: $unit-1 $unit-2; + text-decoration: none; + &:focus, + &:hover { + background: $secondary-color; + color: $primary-color; + } + &:active, + &.active { + background: $secondary-color; + color: $primary-color; + } + } + + .form-checkbox, + .form-radio, + .form-switch { + margin: $unit-h 0; + } + + & + .menu-item { + margin-top: $unit-1; + } + } + + .menu-badge { + float: right; + padding: $unit-1 0; + + .btn { + margin-top: -$unit-h; + } + } +} diff --git a/user/plugins/problems/scss/_meters.scss b/user/plugins/problems/scss/_meters.scss new file mode 100644 index 00000000..9fd98b0e --- /dev/null +++ b/user/plugins/problems/scss/_meters.scss @@ -0,0 +1,57 @@ +// Meters +// Credit: https://css-tricks.com/html5-meter-element/ +.meter { + appearance: none; + background: $bg-color; + border: 0; + border-radius: $border-radius; + display: block; + width: 100%; + height: $unit-4; + + &::-webkit-meter-inner-element { + display: block; + } + + &::-webkit-meter-bar, + &::-webkit-meter-optimum-value, + &::-webkit-meter-suboptimum-value, + &::-webkit-meter-even-less-good-value { + border-radius: $border-radius; + } + + &::-webkit-meter-bar { + background: $bg-color; + } + + &::-webkit-meter-optimum-value { + background: $success-color; + } + + &::-webkit-meter-suboptimum-value { + background: $warning-color; + } + + &::-webkit-meter-even-less-good-value { + background: $error-color; + } + + &::-moz-meter-bar, + &:-moz-meter-optimum, + &:-moz-meter-sub-optimum, + &:-moz-meter-sub-sub-optimum { + border-radius: $border-radius; + } + + &:-moz-meter-optimum::-moz-meter-bar { + background: $success-color; + } + + &:-moz-meter-sub-optimum::-moz-meter-bar { + background: $warning-color; + } + + &:-moz-meter-sub-sub-optimum::-moz-meter-bar { + background: $error-color; + } +} diff --git a/user/plugins/problems/scss/_mixins.scss b/user/plugins/problems/scss/_mixins.scss new file mode 100644 index 00000000..54bed34e --- /dev/null +++ b/user/plugins/problems/scss/_mixins.scss @@ -0,0 +1,11 @@ +// Mixins +@import "mixins/avatar"; +@import "mixins/button"; +@import "mixins/clearfix"; +@import "mixins/color"; +@import "mixins/label"; +@import "mixins/position"; +@import "mixins/shadow"; +@import "mixins/text"; +@import "mixins/toast"; +@import "mixins/transition"; diff --git a/user/plugins/problems/scss/_modals.scss b/user/plugins/problems/scss/_modals.scss new file mode 100644 index 00000000..a7b3f10e --- /dev/null +++ b/user/plugins/problems/scss/_modals.scss @@ -0,0 +1,87 @@ +// Modals +.modal { + align-items: center; + bottom: 0; + display: none; + justify-content: center; + left: 0; + opacity: 0; + overflow: hidden; + padding: $layout-spacing; + position: fixed; + right: 0; + top: 0; + + &:target, + &.active { + display: flex; + opacity: 1; + z-index: $zindex-4; + + .modal-overlay { + background: rgba($bg-color, .75); + bottom: 0; + cursor: default; + display: block; + left: 0; + position: absolute; + right: 0; + top: 0; + } + + .modal-container { + animation: slide-down .2s ease 1; + z-index: $zindex-0; + } + } + + &.modal-sm { + .modal-container { + max-width: $control-width-sm; + padding: 0 $unit-2; + } + } + + &.modal-lg { + .modal-overlay { + background: $bg-color-light; + } + + .modal-container { + box-shadow: none; + max-width: $control-width-lg; + } + } +} + +.modal-container { + @include shadow-variant(.2rem); + background: $bg-color-light; + border-radius: $border-radius; + display: flex; + flex-direction: column; + max-height: 75vh; + max-width: $control-width-md; + padding: 0 $unit-4; + width: 100%; + + &.modal-fullheight { + max-height: 100vh; + } + + .modal-header { + color: $dark-color; + padding: $unit-4; + } + + .modal-body { + overflow-y: auto; + padding: $unit-4; + position: relative; + } + + .modal-footer { + padding: $unit-4; + text-align: right; + } +} diff --git a/user/plugins/problems/scss/_navbar.scss b/user/plugins/problems/scss/_navbar.scss new file mode 100644 index 00000000..57585ab0 --- /dev/null +++ b/user/plugins/problems/scss/_navbar.scss @@ -0,0 +1,29 @@ +// Navbar +.navbar { + align-items: stretch; + display: flex; + flex-wrap: wrap; + justify-content: space-between; + + .navbar-section { + align-items: center; + display: flex; + flex: 1 0 0; + + &:not(:first-child):last-child { + justify-content: flex-end; + } + } + + .navbar-center { + align-items: center; + display: flex; + flex: 0 0 auto; + } + + .navbar-brand { + font-size: $font-size-lg; + font-weight: 500; + text-decoration: none; + } +} diff --git a/user/plugins/problems/scss/_navs.scss b/user/plugins/problems/scss/_navs.scss new file mode 100644 index 00000000..4bedc27b --- /dev/null +++ b/user/plugins/problems/scss/_navs.scss @@ -0,0 +1,34 @@ +// Navs +.nav { + display: flex; + flex-direction: column; + list-style: none; + margin: $unit-1 0; + + .nav-item { + a { + color: $gray-color-dark; + padding: $unit-1 $unit-2; + text-decoration: none; + &:focus, + &:hover { + color: $primary-color; + } + } + &.active { + & > a { + color: darken($gray-color-dark, 10%); + font-weight: bold; + &:focus, + &:hover { + color: $primary-color; + } + } + } + } + + & .nav { + margin-bottom: $unit-2; + margin-left: $unit-4; + } +} diff --git a/user/plugins/problems/scss/_normalize.scss b/user/plugins/problems/scss/_normalize.scss new file mode 100644 index 00000000..a098a84d --- /dev/null +++ b/user/plugins/problems/scss/_normalize.scss @@ -0,0 +1,446 @@ +/* Manually forked from Normalize.css */ +/* normalize.css v5.0.0 | MIT License | github.com/necolas/normalize.css */ + +/** + * 1. Change the default font family in all browsers (opinionated). + * 2. Correct the line height in all browsers. + * 3. Prevent adjustments of font size after orientation changes in + * IE on Windows Phone and in iOS. + */ + +/* Document + ========================================================================== */ + +html { + font-family: sans-serif; /* 1 */ + -ms-text-size-adjust: 100%; /* 3 */ + -webkit-text-size-adjust: 100%; /* 3 */ +} + +/* Sections + ========================================================================== */ + +/** + * Remove the margin in all browsers (opinionated). + */ + +body { + margin: 0; +} + +/** + * Add the correct display in IE 9-. + */ + +article, +aside, +footer, +header, +nav, +section { + display: block; +} + +/** + * Correct the font size and margin on `h1` elements within `section` and + * `article` contexts in Chrome, Firefox, and Safari. + */ + +h1 { + font-size: 2em; + margin: 0.67em 0; +} + +/* Grouping content + ========================================================================== */ + +/** + * Add the correct display in IE 9-. + * 1. Add the correct display in IE. + */ + +figcaption, +figure, +main { /* 1 */ + display: block; +} + +/** + * Add the correct margin in IE 8 (removed). + */ + +/** + * 1. Add the correct box sizing in Firefox. + * 2. Show the overflow in Edge and IE. + */ + +hr { + box-sizing: content-box; /* 1 */ + height: 0; /* 1 */ + overflow: visible; /* 2 */ +} + +/** + * 1. Correct the inheritance and scaling of font size in all browsers. (removed) + * 2. Correct the odd `em` font sizing in all browsers. + */ + +/* Text-level semantics + ========================================================================== */ + +/** + * 1. Remove the gray background on active links in IE 10. + * 2. Remove gaps in links underline in iOS 8+ and Safari 8+. + */ + +a { + background-color: transparent; /* 1 */ + -webkit-text-decoration-skip: objects; /* 2 */ +} + +/** + * Remove the outline on focused links when they are also active or hovered + * in all browsers (opinionated). + */ + +a:active, +a:hover { + outline-width: 0; +} + +/** + * Modify default styling of address. + */ + +address { + font-style: normal; +} + +/** + * 1. Remove the bottom border in Firefox 39-. + * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari. (removed) + */ + +/** + * Prevent the duplicate application of `bolder` by the next rule in Safari 6. + */ + +b, +strong { + font-weight: inherit; +} + +/** + * Add the correct font weight in Chrome, Edge, and Safari. + */ + +b, +strong { + font-weight: bolder; +} + +/** + * 1. Correct the inheritance and scaling of font size in all browsers. + * 2. Correct the odd `em` font sizing in all browsers. + */ + +code, +kbd, +pre, +samp { + font-family: $mono-font-family; /* 1 (changed) */ + font-size: 1em; /* 2 */ +} + +/** + * Add the correct font style in Android 4.3-. + */ + +dfn { + font-style: italic; +} + +/** + * Add the correct background and color in IE 9-. (Removed) + */ + +/** + * Add the correct font size in all browsers. + */ + +small { + font-size: 80%; + font-weight: 400; /* (added) */ +} + +/** + * Prevent `sub` and `sup` elements from affecting the line height in + * all browsers. + */ + +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +sub { + bottom: -0.25em; +} + +sup { + top: -0.5em; +} + +/* Embedded content + ========================================================================== */ + +/** + * Add the correct display in IE 9-. + */ + +audio, +video { + display: inline-block; +} + +/** + * Add the correct display in iOS 4-7. + */ + +audio:not([controls]) { + display: none; + height: 0; +} + +/** + * Remove the border on images inside links in IE 10-. + */ + +img { + border-style: none; +} + +/** + * Hide the overflow in IE. + */ + +svg:not(:root) { + overflow: hidden; +} + +/* Forms + ========================================================================== */ + +/** + * 1. Change the font styles in all browsers (opinionated). + * 2. Remove the margin in Firefox and Safari. + */ + +button, +input, +optgroup, +select, +textarea { + font-family: inherit; /* 1 (changed) */ + font-size: inherit; /* 1 (changed) */ + line-height: inherit; /* 1 (changed) */ + margin: 0; /* 2 */ +} + +/** + * Show the overflow in IE. + * 1. Show the overflow in Edge. + */ + +button, +input { /* 1 */ + overflow: visible; +} + +/** + * Remove the inheritance of text transform in Edge, Firefox, and IE. + * 1. Remove the inheritance of text transform in Firefox. + */ + +button, +select { /* 1 */ + text-transform: none; +} + +/** + * 1. Prevent a WebKit bug where (2) destroys native `audio` and `video` + * controls in Android 4. + * 2. Correct the inability to style clickable types in iOS and Safari. + */ + +button, +html [type="button"], /* 1 */ +[type="reset"], +[type="submit"] { + -webkit-appearance: button; /* 2 */ +} + +/** + * Remove the inner border and padding in Firefox. + */ + +button::-moz-focus-inner, +[type="button"]::-moz-focus-inner, +[type="reset"]::-moz-focus-inner, +[type="submit"]::-moz-focus-inner { + border-style: none; + padding: 0; +} + +/** + * Restore the focus styles unset by the previous rule (removed). + */ + + +/** + * Change the border, margin, and padding in all browsers (opinionated) (changed). + */ + +fieldset { + border: 0; + margin: 0; + padding: 0; +} + +/** + * 1. Correct the text wrapping in Edge and IE. + * 2. Correct the color inheritance from `fieldset` elements in IE. + * 3. Remove the padding so developers are not caught out when they zero out + * `fieldset` elements in all browsers. + */ + +legend { + box-sizing: border-box; /* 1 */ + color: inherit; /* 2 */ + display: table; /* 1 */ + max-width: 100%; /* 1 */ + padding: 0; /* 3 */ + white-space: normal; /* 1 */ +} + +/** + * 1. Add the correct display in IE 9-. + * 2. Add the correct vertical alignment in Chrome, Firefox, and Opera. + */ + +progress { + display: inline-block; /* 1 */ + vertical-align: baseline; /* 2 */ +} + +/** + * Remove the default vertical scrollbar in IE. + */ + +textarea { + overflow: auto; +} + +/** + * 1. Add the correct box sizing in IE 10-. + * 2. Remove the padding in IE 10-. + */ + +[type="checkbox"], +[type="radio"] { + box-sizing: border-box; /* 1 */ + padding: 0; /* 2 */ +} + +/** + * Correct the cursor style of increment and decrement buttons in Chrome. + */ + +[type="number"]::-webkit-inner-spin-button, +[type="number"]::-webkit-outer-spin-button { + height: auto; +} + +/** + * 1. Correct the odd appearance in Chrome and Safari. + * 2. Correct the outline style in Safari. + */ + +[type="search"] { + -webkit-appearance: textfield; /* 1 */ + outline-offset: -2px; /* 2 */ +} + +/** + * Remove the inner padding and cancel buttons in Chrome and Safari on macOS. + */ + +[type="search"]::-webkit-search-cancel-button, +[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; +} + +/** + * 1. Correct the inability to style clickable types in iOS and Safari. + * 2. Change font properties to `inherit` in Safari. + */ + +::-webkit-file-upload-button { + -webkit-appearance: button; /* 1 */ + font: inherit; /* 2 */ +} + +/* Interactive + ========================================================================== */ + +/* + * Add the correct display in IE 9-. + * 1. Add the correct display in Edge, IE, and Firefox. + */ + +details, /* 1 */ +menu { + display: block; +} + +/* + * Add the correct display in all browsers. + */ + +summary { + display: list-item; + outline: none; +} + +/* Scripting + ========================================================================== */ + +/** + * Add the correct display in IE 9-. + */ + +canvas { + display: inline-block; +} + +/** + * Add the correct display in IE. + */ + +template { + display: none; +} + +/* Hidden + ========================================================================== */ + +/** + * Add the correct display in IE 10-. + */ + +[hidden] { + display: none; +} diff --git a/user/plugins/problems/scss/_off-canvas.scss b/user/plugins/problems/scss/_off-canvas.scss new file mode 100644 index 00000000..32cefb62 --- /dev/null +++ b/user/plugins/problems/scss/_off-canvas.scss @@ -0,0 +1,95 @@ +// Off canvas menus +$off-canvas-breakpoint: $size-lg !default; + +.off-canvas { + display: flex; + flex-flow: nowrap; + height: 100%; + position: relative; + width: 100%; + + .off-canvas-toggle { + display: block; + position: absolute; + top: $layout-spacing; + transition: none; + z-index: $zindex-0; + @if $rtl == true { + right: $layout-spacing; + } @else { + left: $layout-spacing; + } + } + + .off-canvas-sidebar { + background: $bg-color; + bottom: 0; + min-width: 10rem; + overflow-y: auto; + position: fixed; + top: 0; + transition: transform .25s ease; + z-index: $zindex-2; + @if $rtl == true { + right: 0; + transform: translateX(100%); + } @else { + left: 0; + transform: translateX(-100%); + } + } + + .off-canvas-content { + flex: 1 1 auto; + height: 100%; + padding: $layout-spacing $layout-spacing $layout-spacing 4rem; + } + + .off-canvas-overlay { + background: rgba($dark-color, .1); + border-color: transparent; + border-radius: 0; + bottom: 0; + display: none; + height: 100%; + left: 0; + position: fixed; + right: 0; + top: 0; + width: 100%; + } + + .off-canvas-sidebar { + &:target, + &.active { + transform: translateX(0); + } + + &:target ~ .off-canvas-overlay, + &.active ~ .off-canvas-overlay { + display: block; + z-index: $zindex-1; + } + } +} + +// Responsive layout +@media (min-width: $off-canvas-breakpoint) { + .off-canvas { + &.off-canvas-sidebar-show { + .off-canvas-toggle { + display: none; + } + + .off-canvas-sidebar { + flex: 0 0 auto; + position: relative; + transform: none; + } + + .off-canvas-overlay { + display: none !important; + } + } + } +} diff --git a/user/plugins/problems/scss/_pagination.scss b/user/plugins/problems/scss/_pagination.scss new file mode 100644 index 00000000..6efc7bae --- /dev/null +++ b/user/plugins/problems/scss/_pagination.scss @@ -0,0 +1,61 @@ +// Pagination +.pagination { + display: flex; + list-style: none; + margin: $unit-1 0; + padding: $unit-1 0; + + .page-item { + margin: $unit-1 $unit-o; + + span { + display: inline-block; + padding: $unit-1 $unit-1; + } + + a { + border-radius: $border-radius; + color: $gray-color-dark; + display: inline-block; + padding: $unit-1 $unit-2; + text-decoration: none; + &:focus, + &:hover { + color: $primary-color; + } + } + + &.disabled { + a { + cursor: default; + opacity: .5; + pointer-events: none; + } + } + + &.active { + a { + background: $primary-color; + color: $light-color; + } + } + + &.page-prev, + &.page-next { + flex: 1 0 50%; + } + + &.page-next { + text-align: right; + } + + .page-item-title { + margin: 0; + } + + .page-item-subtitle { + margin: 0; + opacity: .5; + } + } +} diff --git a/user/plugins/problems/scss/_panels.scss b/user/plugins/problems/scss/_panels.scss new file mode 100644 index 00000000..386f96ec --- /dev/null +++ b/user/plugins/problems/scss/_panels.scss @@ -0,0 +1,23 @@ +// Panels +.panel { + border: $border-width solid $border-color; + border-radius: $border-radius; + display: flex; + flex-direction: column; + + .panel-header, + .panel-footer { + flex: 0 0 auto; + padding: $layout-spacing-lg; + } + + .panel-nav { + flex: 0 0 auto; + } + + .panel-body { + flex: 1 1 auto; + overflow-y: auto; + padding: 0 $layout-spacing-lg; + } +} diff --git a/user/plugins/problems/scss/_parallax.scss b/user/plugins/problems/scss/_parallax.scss new file mode 100644 index 00000000..acc05be6 --- /dev/null +++ b/user/plugins/problems/scss/_parallax.scss @@ -0,0 +1,135 @@ +// Parallax +$parallax-deg: 3deg !default; +$parallax-offset: 4.5px !default; +$parallax-offset-z: 50px !default; +$parallax-perspective: 1000px !default; +$parallax-scale: .95 !default; +$parallax-fade-color: rgba(255, 255, 255, .35) !default; + +// Mixin: Parallax direction +@mixin parallax-dir() { + height: 50%; + outline: none; + position: absolute; + width: 50%; + z-index: $zindex-1; +} + +.parallax { + display: block; + height: auto; + position: relative; + width: auto; + + .parallax-content { + @include shadow-variant(1rem); + height: auto; + transform: perspective($parallax-perspective); + transform-style: preserve-3d; + transition: all .4s ease; + width: 100%; + + &::before { + content: ""; + display: block; + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; + } + } + + .parallax-front { + align-items: center; + color: $light-color; + display: flex; + height: 100%; + justify-content: center; + left: 0; + position: absolute; + text-align: center; + text-shadow: 0 0 20px rgba($dark-color, .75); + top: 0; + transform: translateZ($parallax-offset-z) scale($parallax-scale); + transition: all .4s ease; + width: 100%; + z-index: $zindex-0; + } + + .parallax-top-left { + @include parallax-dir(); + left: 0; + top: 0; + + &:focus ~ .parallax-content, + &:hover ~ .parallax-content { + transform: perspective($parallax-perspective) rotateX($parallax-deg) rotateY(-$parallax-deg); + + &::before { + background: linear-gradient(135deg, $parallax-fade-color 0%, transparent 50%); + } + + .parallax-front { + transform: translate3d($parallax-offset, $parallax-offset, $parallax-offset-z) scale($parallax-scale); + } + } + } + + .parallax-top-right { + @include parallax-dir(); + right: 0; + top: 0; + + &:focus ~ .parallax-content, + &:hover ~ .parallax-content { + transform: perspective($parallax-perspective) rotateX($parallax-deg) rotateY($parallax-deg); + + &::before { + background: linear-gradient(-135deg, $parallax-fade-color 0%, transparent 50%); + } + + .parallax-front { + transform: translate3d(-$parallax-offset, $parallax-offset, $parallax-offset-z) scale($parallax-scale); + } + } + } + + .parallax-bottom-left { + @include parallax-dir(); + bottom: 0; + left: 0; + + &:focus ~ .parallax-content, + &:hover ~ .parallax-content { + transform: perspective($parallax-perspective) rotateX(-$parallax-deg) rotateY(-$parallax-deg); + + &::before { + background: linear-gradient(45deg, $parallax-fade-color 0%, transparent 50%); + } + + .parallax-front { + transform: translate3d($parallax-offset, -$parallax-offset, $parallax-offset-z) scale($parallax-scale); + } + } + } + + .parallax-bottom-right { + @include parallax-dir(); + bottom: 0; + right: 0; + + &:focus ~ .parallax-content, + &:hover ~ .parallax-content { + transform: perspective($parallax-perspective) rotateX(-$parallax-deg) rotateY($parallax-deg); + + &::before { + background: linear-gradient(-45deg, $parallax-fade-color 0%, transparent 50%); + } + + .parallax-front { + transform: translate3d(-$parallax-offset, -$parallax-offset, $parallax-offset-z) scale($parallax-scale); + } + } + } +} diff --git a/user/plugins/problems/scss/_popovers.scss b/user/plugins/problems/scss/_popovers.scss new file mode 100644 index 00000000..c43a6d13 --- /dev/null +++ b/user/plugins/problems/scss/_popovers.scss @@ -0,0 +1,65 @@ +// Popovers +.popover { + display: inline-block; + position: relative; + + .popover-container { + left: 50%; + opacity: 0; + padding: $layout-spacing; + position: absolute; + top: 0; + transform: translate(-50%, -50%) scale(0); + transition: transform .2s ease; + width: $control-width-sm; + z-index: $zindex-3; + } + + *:focus + .popover-container, + &:hover .popover-container { + display: block; + opacity: 1; + transform: translate(-50%, -100%); + } + + &.popover-right { + .popover-container { + left: 100%; + top: 50%; + } + + *:focus + .popover-container, + &:hover .popover-container { + transform: translate(0, -50%); + } + } + + &.popover-bottom { + .popover-container { + left: 50%; + top: 100%; + } + + *:focus + .popover-container, + &:hover .popover-container { + transform: translate(-50%, 0); + } + } + + &.popover-left { + .popover-container { + left: 0; + top: 50%; + } + + *:focus + .popover-container, + &:hover .popover-container { + transform: translate(-100%, -50%); + } + } + + .card { + @include shadow-variant(.2rem); + border: 0; + } +} diff --git a/user/plugins/problems/scss/_problems.scss b/user/plugins/problems/scss/_problems.scss new file mode 100644 index 00000000..0ac9ddae --- /dev/null +++ b/user/plugins/problems/scss/_problems.scss @@ -0,0 +1,72 @@ +body { + padding: 2rem 0; +} + +img.logo { + width: 200px; + margin-bottom: 1rem; +} + +h1, h2 { + font-weight: 700; +} + +.footer { + color: $gray-color; + margin-top: 2rem; + + img { + height: 18px; + vertical-align: middle; + margin: 0 0.2rem; + } +} + +.toast { + .btn { + margin-left: 1rem; + text-decoration: none !important; + i { + margin-right: 0.3rem; + } + } +} + +ul.problems { + margin: 1rem 0; + + h5 { + margin: 0; + } + + li.menu { + margin-bottom: 1rem; + + .toast { + .btn { + float: right; + margin-top: -2px; + } + } + } +} + +ul.details { + margin: 0.5rem; + list-style: none; + font-size: 90%; + + .menu-item { + margin-top: .5rem !important; + border-top: 1px solid $border-color; + padding-top: 0.5rem; + + &:first-child { + border: none; + } + } + + .menu-badge { + padding: 0; + } +} diff --git a/user/plugins/problems/scss/_progress.scss b/user/plugins/problems/scss/_progress.scss new file mode 100644 index 00000000..f173772b --- /dev/null +++ b/user/plugins/problems/scss/_progress.scss @@ -0,0 +1,45 @@ +// Progress +// Credit: https://css-tricks.com/html5-progress-element/ +.progress { + appearance: none; + background: $bg-color-dark; + border: 0; + border-radius: $border-radius; + color: $primary-color; + height: $unit-1; + position: relative; + width: 100%; + + &::-webkit-progress-bar { + background: transparent; + border-radius: $border-radius; + } + + &::-webkit-progress-value { + background: $primary-color; + border-radius: $border-radius; + } + + &::-moz-progress-bar { + background: $primary-color; + border-radius: $border-radius; + } + + &:indeterminate { + animation: progress-indeterminate 1.5s linear infinite; + background: $bg-color-dark linear-gradient(to right, $primary-color 30%, $bg-color-dark 30%) top left / 150% 150% no-repeat; + + &::-moz-progress-bar { + background: transparent; + } + } +} + +@keyframes progress-indeterminate { + 0% { + background-position: 200% 0; + } + 100% { + background-position: -200% 0; + } +} diff --git a/user/plugins/problems/scss/_sliders.scss b/user/plugins/problems/scss/_sliders.scss new file mode 100644 index 00000000..01576b92 --- /dev/null +++ b/user/plugins/problems/scss/_sliders.scss @@ -0,0 +1,99 @@ +// Sliders +// Credit: https://css-tricks.com/styling-cross-browser-compatible-range-inputs-css/ +.slider { + appearance: none; + background: transparent; + display: block; + width: 100%; + height: $unit-6; + + &:focus { + @include control-shadow(); + outline: none; + } + + &.tooltip:not([data-tooltip]) { + &::after { + content: attr(value); + } + } + + // Slider Thumb + &::-webkit-slider-thumb { + -webkit-appearance: none; + background: $primary-color; + border: 0; + border-radius: 50%; + height: $unit-3; + margin-top: -($unit-3 - $unit-h) / 2; + transition: transform .2s ease; + width: $unit-3; + } + &::-moz-range-thumb { + background: $primary-color; + border: 0; + border-radius: 50%; + height: $unit-3; + transition: transform .2s ease; + width: $unit-3; + } + &::-ms-thumb { + background: $primary-color; + border: 0; + border-radius: 50%; + height: $unit-3; + transition: transform .2s ease; + width: $unit-3; + } + + &:active { + &::-webkit-slider-thumb { + transform: scale(1.25); + } + &::-moz-range-thumb { + transform: scale(1.25); + } + &::-ms-thumb { + transform: scale(1.25); + } + } + + &:disabled, + &.disabled { + &::-webkit-slider-thumb { + background: $gray-color-light; + transform: scale(1); + } + &::-moz-range-thumb { + background: $gray-color-light; + transform: scale(1); + } + &::-ms-thumb { + background: $gray-color-light; + transform: scale(1); + } + } + + // Slider Track + &::-webkit-slider-runnable-track { + background: $bg-color-dark; + border-radius: $border-radius; + height: $unit-h; + width: 100%; + } + &::-moz-range-track { + background: $bg-color-dark; + border-radius: $border-radius; + height: $unit-h; + width: 100%; + } + &::-ms-track { + background: $bg-color-dark; + border-radius: $border-radius; + height: $unit-h; + width: 100%; + } + &::-ms-fill-lower { + background: $primary-color; + } +} diff --git a/user/plugins/problems/scss/_steps.scss b/user/plugins/problems/scss/_steps.scss new file mode 100644 index 00000000..d5ddc6e4 --- /dev/null +++ b/user/plugins/problems/scss/_steps.scss @@ -0,0 +1,70 @@ +// Steps +.step { + display: flex; + flex-wrap: nowrap; + list-style: none; + margin: $unit-1 0; + width: 100%; + + .step-item { + flex: 1 1 0; + margin-top: 0; + min-height: 1rem; + text-align: center; + position: relative; + + &:not(:first-child)::before { + background: $primary-color; + content: ""; + height: 2px; + left: -50%; + position: absolute; + top: 9px; + width: 100%; + } + + a { + color: $gray-color; + display: inline-block; + padding: 20px 10px 0; + text-decoration: none; + + &::before { + background: $primary-color; + border: $border-width-lg solid $light-color; + border-radius: 50%; + content: ""; + display: block; + height: $unit-3; + left: 50%; + position: absolute; + top: $unit-1; + transform: translateX(-50%); + width: $unit-3; + z-index: $zindex-0; + } + } + + &.active { + a { + &::before { + background: $light-color; + border: $border-width-lg solid $primary-color; + } + } + + & ~ .step-item { + &::before { + background: $border-color; + } + + a { + + &::before { + background: $gray-color-light; + } + } + } + } + } +} diff --git a/user/plugins/problems/scss/_tables.scss b/user/plugins/problems/scss/_tables.scss new file mode 100644 index 00000000..732718c3 --- /dev/null +++ b/user/plugins/problems/scss/_tables.scss @@ -0,0 +1,57 @@ +// Tables +.table { + border-collapse: collapse; + border-spacing: 0; + width: 100%; + @if $rtl == true { + text-align: right; + } @else { + text-align: left; + } + + &.table-striped { + tbody { + tr:nth-of-type(odd) { + background: $bg-color; + } + } + } + + &, + &.table-striped { + tbody { + tr { + &.active { + background: $bg-color-dark; + } + } + } + } + + &.table-hover { + tbody { + tr { + &:hover { + background: $bg-color-dark; + } + } + } + } + + // Tables with horizontal scrollbar + &.table-scroll { + display: block; + overflow-x: auto; + padding-bottom: .75rem; + white-space: nowrap; + } + + td, + th { + border-bottom: $border-width solid $border-color; + padding: $unit-3 $unit-2; + } + th { + border-bottom-width: $border-width-lg; + } +} diff --git a/user/plugins/problems/scss/_tabs.scss b/user/plugins/problems/scss/_tabs.scss new file mode 100644 index 00000000..0dcbaf37 --- /dev/null +++ b/user/plugins/problems/scss/_tabs.scss @@ -0,0 +1,66 @@ +// Tabs +.tab { + align-items: center; + border-bottom: $border-width solid $border-color; + display: flex; + flex-wrap: wrap; + list-style: none; + margin: $unit-1 0 ($unit-1 - $border-width) 0; + + .tab-item { + margin-top: 0; + + a { + border-bottom: $border-width-lg solid transparent; + color: inherit; + display: block; + margin: 0 $unit-2 0 0; + padding: $unit-2 $unit-1 $unit-2 - $border-width-lg $unit-1; + text-decoration: none; + &:focus, + &:hover { + color: $link-color; + } + } + &.active a, + a.active { + border-bottom-color: $primary-color; + color: $link-color; + } + + &.tab-action { + flex: 1 0 auto; + text-align: right; + } + + .btn-clear { + margin-top: -$unit-1; + } + } + + &.tab-block { + .tab-item { + flex: 1 0 0; + text-align: center; + + a { + margin: 0; + } + + .badge { + &[data-badge]::after { + position: absolute; + right: $unit-h; + top: $unit-h; + transform: translate(0, 0); + } + } + } + } + + &:not(.tab-block) { + .badge { + padding-right: 0; + } + } +} diff --git a/user/plugins/problems/scss/_tiles.scss b/user/plugins/problems/scss/_tiles.scss new file mode 100644 index 00000000..742bbaeb --- /dev/null +++ b/user/plugins/problems/scss/_tiles.scss @@ -0,0 +1,38 @@ +// Tiles +.tile { + align-content: space-between; + align-items: flex-start; + display: flex; + + .tile-icon, + .tile-action { + flex: 0 0 auto; + } + .tile-content { + flex: 1 1 auto; + &:not(:first-child) { + padding-left: $unit-2; + } + &:not(:last-child) { + padding-right: $unit-2; + } + } + .tile-title, + .tile-subtitle { + line-height: $line-height; + } + + &.tile-centered { + align-items: center; + + .tile-content { + overflow: hidden; + } + + .tile-title, + .tile-subtitle { + @include text-ellipsis(); + margin-bottom: 0; + } + } +} diff --git a/user/plugins/problems/scss/_timelines.scss b/user/plugins/problems/scss/_timelines.scss new file mode 100644 index 00000000..67041a85 --- /dev/null +++ b/user/plugins/problems/scss/_timelines.scss @@ -0,0 +1,54 @@ +// Timelines +.timeline { + .timeline-item { + display: flex; + margin-bottom: $unit-6; + position: relative; + &::before { + background: $border-color; + content: ""; + height: 100%; + left: 11px; + position: absolute; + top: $unit-6; + width: 2px; + } + + .timeline-left { + flex: 0 0 auto; + } + + .timeline-content { + flex: 1 1 auto; + padding: 2px 0 2px $layout-spacing-lg; + } + + .timeline-icon { + border-radius: 50%; + color: $light-color; + display: block; + height: $unit-6; + text-align: center; + width: $unit-6; + &::before { + border: $border-width-lg solid $primary-color; + border-radius: 50%; + content: ""; + display: block; + height: $unit-2; + left: $unit-2; + position: absolute; + top: $unit-2; + width: $unit-2; + } + + &.icon-lg { + background: $primary-color; + line-height: $line-height; + &::before { + content: none; + } + } + } + } +} diff --git a/user/plugins/problems/scss/_toasts.scss b/user/plugins/problems/scss/_toasts.scss new file mode 100644 index 00000000..61e7c5f5 --- /dev/null +++ b/user/plugins/problems/scss/_toasts.scss @@ -0,0 +1,42 @@ +// Toasts +.toast { + @include toast-variant($dark-color); + border: $border-width solid $dark-color; + border-radius: $border-radius; + color: $light-color; + display: block; + padding: $layout-spacing; + width: 100%; + + &.toast-primary { + @include toast-variant($primary-color); + } + + &.toast-success { + @include toast-variant($success-color); + } + + &.toast-warning { + @include toast-variant($warning-color); + } + + &.toast-error { + @include toast-variant($error-color); + } + + a { + color: $light-color; + text-decoration: underline; + + &:focus, + &:hover, + &:active, + &.active { + opacity: .75; + } + } + + .btn-clear { + margin: 4px -2px 4px 4px; + } +} diff --git a/user/plugins/problems/scss/_tooltips.scss b/user/plugins/problems/scss/_tooltips.scss new file mode 100644 index 00000000..061f9d33 --- /dev/null +++ b/user/plugins/problems/scss/_tooltips.scss @@ -0,0 +1,79 @@ +// Tooltips +.tooltip { + position: relative; + &::after { + background: rgba($dark-color, .9); + border-radius: $border-radius; + bottom: 100%; + color: $light-color; + content: attr(data-tooltip); + display: block; + font-size: $font-size-sm; + left: 50%; + max-width: $control-width-sm; + opacity: 0; + overflow: hidden; + padding: $unit-1 $unit-2; + pointer-events: none; + position: absolute; + text-overflow: ellipsis; + transform: translate(-50%, $unit-2); + transition: all .2s ease; + white-space: pre; + z-index: $zindex-3; + } + &:focus, + &:hover { + &::after { + opacity: 1; + transform: translate(-50%, -$unit-1); + } + } + &[disabled], + &.disabled { + pointer-events: auto; + } + + &.tooltip-right { + &::after { + bottom: 50%; + left: 100%; + transform: translate(-$unit-1, 50%); + } + &:focus, + &:hover { + &::after { + transform: translate($unit-1, 50%); + } + } + } + + &.tooltip-bottom { + &::after { + bottom: auto; + top: 100%; + transform: translate(-50%, -$unit-2); + } + &:focus, + &:hover { + &::after { + transform: translate(-50%, $unit-1); + } + } + } + + &.tooltip-left { + &::after { + bottom: 50%; + left: auto; + right: 100%; + transform: translate($unit-2, 50%); + } + &:focus, + &:hover { + &::after { + transform: translate(-$unit-1, 50%); + } + } + } +} diff --git a/user/plugins/problems/scss/_typography.scss b/user/plugins/problems/scss/_typography.scss new file mode 100644 index 00000000..d15d39e8 --- /dev/null +++ b/user/plugins/problems/scss/_typography.scss @@ -0,0 +1,128 @@ +// Typography +// Headings +h1, +h2, +h3, +h4, +h5, +h6 { + color: inherit; + font-weight: 500; + line-height: 1.2; + margin-bottom: .5em; + margin-top: 0; +} +.h1, +.h2, +.h3, +.h4, +.h5, +.h6 { + font-weight: 500; +} +h1, +.h1 { + font-size: 2rem; +} +h2, +.h2 { + font-size: 1.6rem; +} +h3, +.h3 { + font-size: 1.4rem; +} +h4, +.h4 { + font-size: 1.2rem; +} +h5, +.h5 { + font-size: 1rem; +} +h6, +.h6 { + font-size: .8rem; +} + +// Paragraphs +p { + margin: 0 0 $line-height; +} + +// Semantic text elements +a, +ins, +u { + text-decoration-skip: ink edges; +} + +abbr[title] { + border-bottom: $border-width dotted; + cursor: help; + text-decoration: none; +} + +kbd { + @include label-base(); + @include label-variant($light-color, $dark-color); + font-size: $font-size-sm; +} + +mark { + @include label-variant($body-font-color, $highlight-color); + border-radius: $border-radius; + padding: .05rem; +} + +// Blockquote +blockquote { + border-left: $border-width-lg solid $border-color; + margin-left: 0; + padding: $unit-2 $unit-4; + + p:last-child { + margin-bottom: 0; + } +} + +// Lists +ul, +ol { + margin: $unit-4 0 $unit-4 $unit-4; + padding: 0; + + ul, + ol { + margin: $unit-4 0 $unit-4 $unit-4; + } + + li { + margin-top: $unit-2; + } +} + +ul { + list-style: disc inside; + + ul { + list-style-type: circle; + } +} + +ol { + list-style: decimal inside; + + ol { + list-style-type: lower-alpha; + } +} + +dl { + dt { + font-weight: bold; + } + dd { + margin: $unit-2 0 $unit-4 0; + } +} diff --git a/user/plugins/problems/scss/_utilities.scss b/user/plugins/problems/scss/_utilities.scss new file mode 100644 index 00000000..80f1e0b5 --- /dev/null +++ b/user/plugins/problems/scss/_utilities.scss @@ -0,0 +1,8 @@ +@import "utilities/colors"; +@import "utilities/cursors"; +@import "utilities/display"; +@import "utilities/divider"; +@import "utilities/loading"; +@import "utilities/position"; +@import "utilities/shapes"; +@import "utilities/text"; diff --git a/user/plugins/problems/scss/_variables.scss b/user/plugins/problems/scss/_variables.scss new file mode 100644 index 00000000..86f512cf --- /dev/null +++ b/user/plugins/problems/scss/_variables.scss @@ -0,0 +1,116 @@ +// Core variables +$version: "0.5.3"; + +// Core features +$rtl: false !default; + +// Core colors +$primary-color: #0074D9 !default; +$primary-color-dark: darken($primary-color, 3%) !default; +$primary-color-light: lighten($primary-color, 3%) !default; +$secondary-color: lighten($primary-color, 37.5%) !default; +$secondary-color-dark: darken($secondary-color, 3%) !default; +$secondary-color-light: lighten($secondary-color, 3%) !default; + +// Gray colors +$dark-color: #454d5d !default; +$light-color: #fff !default; +$gray-color: lighten($dark-color, 40%) !default; +$gray-color-dark: darken($gray-color, 25%) !default; +$gray-color-light: lighten($gray-color, 20%) !default; + +$border-color: lighten($dark-color, 60%) !default; +$border-color-dark: darken($border-color, 10%) !default; +$bg-color: lighten($dark-color, 66%) !default; +$bg-color-dark: darken($bg-color, 3%) !default; +$bg-color-light: $light-color !default; + +// Control colors +$success-color: #2ECC40 !default; +$warning-color: #FF851B !default; +$error-color: #FF4136 !default; + +// Other colors +$code-color: #288FED !default; +$highlight-color: #ffe9b3 !default; +$body-bg: $bg-color-light !default; +$body-font-color: lighten($dark-color, 5%) !default; +$link-color: $primary-color !default; +$link-color-dark: darken($link-color, 10%) !default; +$link-color-light: lighten($link-color, 10%) !default; + +// Fonts +// Credit: https://www.smashingmagazine.com/2015/11/using-system-ui-fonts-practical-guide/ +$base-font-family: -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", Roboto !default; +$mono-font-family: "SF Mono", "Segoe UI Mono", "Roboto Mono", Menlo, Courier, monospace !default; +$fallback-font-family: "Helvetica Neue", sans-serif !default; +$cjk-zh-hans-font-family: $base-font-family, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", $fallback-font-family !default; +$cjk-zh-hant-font-family: $base-font-family, "PingFang TC", "Hiragino Sans CNS", "Microsoft JhengHei", $fallback-font-family !default; +$cjk-jp-font-family: $base-font-family, "Hiragino Sans", "Hiragino Kaku Gothic Pro", "Yu Gothic", YuGothic, Meiryo, $fallback-font-family !default; +$cjk-ko-font-family: $base-font-family, "Malgun Gothic", $fallback-font-family !default; +$body-font-family: $base-font-family, $fallback-font-family !default; + +// Unit sizes +$unit-o: .05rem !default; +$unit-h: .1rem !default; +$unit-1: .2rem !default; +$unit-2: .4rem !default; +$unit-3: .6rem !default; +$unit-4: .8rem !default; +$unit-5: 1rem !default; +$unit-6: 1.2rem !default; +$unit-7: 1.4rem !default; +$unit-8: 1.6rem !default; +$unit-9: 1.8rem !default; +$unit-10: 2rem !default; +$unit-12: 2.4rem !default; +$unit-16: 3.2rem !default; + +// Font sizes +$html-font-size: 20px !default; +$html-line-height: 1.5 !default; +$font-size: .8rem !default; +$font-size-sm: .7rem !default; +$font-size-lg: .9rem !default; +$line-height: 1.2rem !default; + +// Sizes +$layout-spacing: $unit-2 !default; +$layout-spacing-sm: $unit-1 !default; +$layout-spacing-lg: $unit-4 !default; +$border-radius: $unit-h !default; +$border-width: $unit-o !default; +$border-width-lg: $unit-h !default; +$control-size: $unit-9 !default; +$control-size-sm: $unit-7 !default; +$control-size-lg: $unit-10 !default; +$control-padding-x: $unit-2 !default; +$control-padding-x-sm: $unit-2 * .75 !default; +$control-padding-x-lg: $unit-2 * 1.5 !default; +$control-padding-y: ($control-size - $line-height) / 2 - $border-width !default; +$control-padding-y-sm: ($control-size-sm - $line-height) / 2 - $border-width !default; +$control-padding-y-lg: ($control-size-lg - $line-height) / 2 - $border-width !default; +$control-icon-size: .8rem !default; + +$control-width-xs: 180px !default; +$control-width-sm: 320px !default; +$control-width-md: 640px !default; +$control-width-lg: 960px !default; +$control-width-xl: 1280px !default; + +// Responsive breakpoints +$size-xs: 480px !default; +$size-sm: 600px !default; +$size-md: 840px !default; +$size-lg: 960px !default; +$size-xl: 1280px !default; +$size-2x: 1440px !default; + +$responsive-breakpoint: $size-xs !default; + +// Z-index +$zindex-0: 1 !default; +$zindex-1: 100 !default; +$zindex-2: 200 !default; +$zindex-3: 300 !default; +$zindex-4: 400 !default; diff --git a/user/plugins/problems/scss/admin.scss b/user/plugins/problems/scss/admin.scss new file mode 100644 index 00000000..81ea8f48 --- /dev/null +++ b/user/plugins/problems/scss/admin.scss @@ -0,0 +1,151 @@ +@import "variables"; + +$error-color: #F45857; + +.report-output { + + #admin-main .admin-block & { + h1 { + margin-top: 2rem; + } + + .toast { + .btn { + float: right; + margin-top: -2px; + margin-right: 0.5rem; + + + color: $light-color; + font-size: 90%; + padding: 2px 7px; + border-radius: 3px; + + border: 1px solid darken($success-color, 5%); + background-color: darken($success-color, 3%); + + &:hover { + border-color: darken($success-color, 7%); + background-color: darken($success-color, 5%); + } + + &.btn-error { + border: 1px solid darken($error-color, 5%); + background-color: darken($error-color, 3%); + + &:hover { + border-color: darken($error-color, 7%); + background-color: darken($error-color, 5%); + } + } + + &.btn-warning { + border: 1px solid darken($warning-color, 5%); + background-color: darken($warning-color, 3%); + + &:hover { + border-color: darken($warning-color, 7%); + background-color: darken($warning-color, 5%); + } + } + } + } + } + + ul.problems { + + margin: 1rem 0; + list-style: none; + padding: 0; + background-color: #f7f7f7; + + h5 { + margin: 0; + } + + li.menu { + margin-bottom: 1rem; + box-shadow: 0 10px 20px -10px rgba(0,0,0,0.2); + } + + .toast { + font-size: 1rem; + padding: 0.5rem 1.5rem; + color: $light-color; + + &.toast-success { + background-color: $success-color; + } + + &.toast-error { + background-color: $error-color; + } + + &.toast-warning { + background-color: $warning-color; + } + + .btn { + margin-left: 1rem; + text-decoration: none !important; + i { + margin-right: 0.3rem; + } + } + } + + ul.details { + list-style: none; + padding-left: 0; + padding-bottom: 1rem; + background-color: #fff; + + li { + padding-left: 1.5rem; + padding-right: 1.5rem; + } + + code { + font-size: 90%; + line-height: 1.2; + padding: .1rem .2rem; + color: #288fed; + border-radius: .1rem; + background: #f0f7fe; + vertical-align: middle; + } + + .menu-item { + margin-top: .5rem !important; + border-top: 1px solid #f7f7f7; + padding-top: 0.5rem; + + &:first-child { + border: none; + } + } + + .menu-badge { + padding: 0; + display: inline; + float: right; + + .label { + font-size: 1rem; + height: 1.5rem; + width: 1.5rem; + line-height: 1.5rem; + border-radius: 3px; + + &.label-success { + background: $success-color; + } + + &.label-error { + background: $error-color; + } + } + } + } + } +} \ No newline at end of file diff --git a/user/plugins/problems/scss/icons/_icons-action.scss b/user/plugins/problems/scss/icons/_icons-action.scss new file mode 100644 index 00000000..807f05e4 --- /dev/null +++ b/user/plugins/problems/scss/icons/_icons-action.scss @@ -0,0 +1,316 @@ + +// Icon resize +.icon-resize-horiz, +.icon-resize-vert { + &::before, + &::after { + border: $icon-border-width solid currentColor; + border-bottom: 0; + border-right: 0; + content: ""; + height: .45em; + width: .45em; + } + &::before { + transform: translate(-50%, -90%) rotate(45deg); + } + &::after { + transform: translate(-50%, -10%) rotate(225deg); + } +} + +.icon-resize-horiz { + &::before { + transform: translate(-90%, -50%) rotate(-45deg); + } + &::after { + transform: translate(-10%, -50%) rotate(135deg); + } +} + +// Icon more +.icon-more-horiz, +.icon-more-vert { + &::before { + background: currentColor; + box-shadow: -.4em 0, .4em 0; + border-radius: 50%; + content: ""; + height: 3px; + width: 3px; + } +} + +.icon-more-vert { + &::before { + box-shadow: 0 -.4em, 0 .4em; + } +} + +// Icon plus, minus, cross +.icon-plus, +.icon-minus, +.icon-cross { + &::before { + background: currentColor; + content: ""; + height: $icon-border-width; + width: 100%; + } +} + +.icon-plus, +.icon-cross { + &::after { + background: currentColor; + content: ""; + height: 100%; + width: $icon-border-width; + } +} + +.icon-cross { + &::before { + width: 100%; + } + &::after { + height: 100%; + } + &::before, + &::after { + transform: translate(-50%, -50%) rotate(45deg); + } +} + +// Icon check +.icon-check { + &::before { + border: $icon-border-width solid currentColor; + border-right: 0; + border-top: 0; + content: ""; + height: .5em; + width: .9em; + transform: translate(-50%, -75%) rotate(-45deg); + } +} + +// Icon stop +.icon-stop { + border: $icon-border-width solid currentColor; + border-radius: 50%; + &::before { + background: currentColor; + content: ""; + height: $icon-border-width; + transform: translate(-50%, -50%) rotate(45deg); + width: 1em; + } +} + +// Icon shutdown +.icon-shutdown { + border: $icon-border-width solid currentColor; + border-radius: 50%; + border-top-color: transparent; + &::before { + background: currentColor; + content: ""; + height: .5em; + top: .1em; + width: $icon-border-width; + } +} + +// Icon refresh +.icon-refresh { + &::before { + border: $icon-border-width solid currentColor; + border-radius: 50%; + border-right-color: transparent; + content: ""; + height: 1em; + width: 1em; + } + &::after { + border: .2em solid currentColor; + border-top-color: transparent; + border-left-color: transparent; + content: ""; + height: 0; + left: 80%; + top: 20%; + width: 0; + } +} + +// Icon search +.icon-search { + &::before { + border: $icon-border-width solid currentColor; + border-radius: 50%; + content: ""; + height: .75em; + left: 5%; + top: 5%; + transform: translate(0, 0) rotate(45deg); + width: .75em; + } + &::after { + background: currentColor; + content: ""; + height: $icon-border-width; + left: 80%; + top: 80%; + transform: translate(-50%, -50%) rotate(45deg); + width: .4em; + } +} + +// Icon edit +.icon-edit { + &::before { + border: $icon-border-width solid currentColor; + content: ""; + height: .4em; + transform: translate(-40%, -60%) rotate(-45deg); + width: .85em; + } + &::after { + border: .15em solid currentColor; + border-top-color: transparent; + border-right-color: transparent; + content: ""; + height: 0; + left: 5%; + top: 95%; + transform: translate(0, -100%); + width: 0; + } +} + +// Icon delete +.icon-delete { + &::before { + border: $icon-border-width solid currentColor; + border-bottom-left-radius: $border-radius; + border-bottom-right-radius: $border-radius; + border-top: 0; + content: ""; + height: .75em; + top: 60%; + width: .75em; + } + &::after { + background: currentColor; + box-shadow: -.25em .2em, .25em .2em; + content: ""; + height: $icon-border-width; + top: $icon-border-width/2; + width: .5em; + } +} + +// Icon share +.icon-share { + border: $icon-border-width solid currentColor; + border-radius: $border-radius; + border-right: 0; + border-top: 0; + &::before { + border: $icon-border-width solid currentColor; + border-left: 0; + border-top: 0; + content: ""; + height: .4em; + left: 100%; + top: .25em; + transform: translate(-125%, -50%) rotate(-45deg); + width: .4em; + } + &::after { + border: $icon-border-width solid currentColor; + border-bottom: 0; + border-right: 0; + border-radius: 75% 0; + content: ""; + height: .5em; + width: .6em; + } +} + +// Icon flag +.icon-flag { + &::before { + background: currentColor; + content: ""; + height: 1em; + left: 15%; + width: $icon-border-width; + } + &::after { + border: $icon-border-width solid currentColor; + border-bottom-right-radius: $border-radius; + border-left: 0; + border-top-right-radius: $border-radius; + content: ""; + height: .65em; + top: 35%; + left: 60%; + width: .8em; + } +} + +// Icon bookmark +.icon-bookmark { + &::before { + border: $icon-border-width solid currentColor; + border-bottom: 0; + border-top-left-radius: $border-radius; + border-top-right-radius: $border-radius; + content: ""; + height: .9em; + width: .8em; + } + &::after { + border: $icon-border-width solid currentColor; + border-bottom: 0; + border-left: 0; + border-radius: $border-radius; + content: ""; + height: .5em; + transform: translate(-50%, 35%) rotate(-45deg) skew(15deg, 15deg); + width: .5em; + } +} + +// Icon download & upload +.icon-download, +.icon-upload { + border-bottom: $icon-border-width solid currentColor; + &::before { + border: $icon-border-width solid currentColor; + border-bottom: 0; + border-right: 0; + content: ""; + height: .5em; + width: .5em; + transform: translate(-50%, -60%) rotate(-135deg); + } + &::after { + background: currentColor; + content: ""; + height: .6em; + top: 40%; + width: $icon-border-width; + } +} + +.icon-upload { + &::before { + transform: translate(-50%, -60%) rotate(45deg); + } + &::after { + top: 50%; + } +} diff --git a/user/plugins/problems/scss/icons/_icons-core.scss b/user/plugins/problems/scss/icons/_icons-core.scss new file mode 100644 index 00000000..577024d6 --- /dev/null +++ b/user/plugins/problems/scss/icons/_icons-core.scss @@ -0,0 +1,53 @@ +// Icon variables +$icon-border-width: $border-width-lg; +$icon-prefix: "icon"; + +// Icon base style +.#{$icon-prefix} { + box-sizing: border-box; + display: inline-block; + font-size: inherit; + font-style: normal; + height: 1em; + position: relative; + text-indent: -9999px; + vertical-align: middle; + width: 1em; + &::before, + &::after { + display: block; + left: 50%; + position: absolute; + top: 50%; + transform: translate(-50%, -50%); + } + + // Icon sizes + &.icon-2x { + font-size: 1.6rem; + } + + &.icon-3x { + font-size: 2.4rem; + } + + &.icon-4x { + font-size: 3.2rem; + } +} + +// Component icon support +.accordion, +.btn, +.toast, +.menu { + .#{$icon-prefix} { + vertical-align: -10%; + } +} + +.btn-lg { + .#{$icon-prefix} { + vertical-align: -15%; + } +} diff --git a/user/plugins/problems/scss/icons/_icons-navigation.scss b/user/plugins/problems/scss/icons/_icons-navigation.scss new file mode 100644 index 00000000..7d7fcd31 --- /dev/null +++ b/user/plugins/problems/scss/icons/_icons-navigation.scss @@ -0,0 +1,133 @@ +// Icon arrows +.icon-arrow-down, +.icon-arrow-left, +.icon-arrow-right, +.icon-arrow-up, +.icon-downward, +.icon-back, +.icon-forward, +.icon-upward { + &::before { + border: $icon-border-width solid currentColor; + border-bottom: 0; + border-right: 0; + content: ""; + height: .65em; + width: .65em; + } +} + +.icon-arrow-down { + &::before { + transform: translate(-50%, -75%) rotate(225deg); + } +} + +.icon-arrow-left { + &::before { + transform: translate(-25%, -50%) rotate(-45deg); + } +} + +.icon-arrow-right { + &::before { + transform: translate(-75%, -50%) rotate(135deg); + } +} + +.icon-arrow-up { + &::before { + transform: translate(-50%, -25%) rotate(45deg); + } +} + +.icon-back, +.icon-forward { + &::after { + background: currentColor; + content: ""; + height: $icon-border-width; + width: .8em; + } +} + +.icon-downward, +.icon-upward { + &::after { + background: currentColor; + content: ""; + height: .8em; + width: $icon-border-width; + } +} + +.icon-back { + &::after { + left: 55%; + } + &::before { + transform: translate(-50%, -50%) rotate(-45deg); + } +} + +.icon-downward { + &::after { + top: 45%; + } + &::before { + transform: translate(-50%, -50%) rotate(-135deg); + } +} + +.icon-forward { + &::after { + left: 45%; + } + &::before { + transform: translate(-50%, -50%) rotate(135deg); + } +} + +.icon-upward { + &::after { + top: 55%; + } + &::before { + transform: translate(-50%, -50%) rotate(45deg); + } +} + +// Icon caret +.icon-caret { + &::before { + border-top: .3em solid currentColor; + border-right: .3em solid transparent; + border-left: .3em solid transparent; + content: ""; + height: 0; + transform: translate(-50%, -25%); + width: 0; + } +} + +// Icon menu +.icon-menu { + &::before { + background: currentColor; + box-shadow: 0 -.35em, 0 .35em; + content: ""; + height: $icon-border-width; + width: 100%; + } +} + +// Icon apps +.icon-apps { + &::before { + background: currentColor; + box-shadow: -.35em -.35em, -.35em 0, -.35em .35em, 0 -.35em, 0 .35em, .35em -.35em, .35em 0, .35em .35em; + content: ""; + height: 3px; + width: 3px; + } +} diff --git a/user/plugins/problems/scss/icons/_icons-object.scss b/user/plugins/problems/scss/icons/_icons-object.scss new file mode 100644 index 00000000..746d25b0 --- /dev/null +++ b/user/plugins/problems/scss/icons/_icons-object.scss @@ -0,0 +1,176 @@ +// Icon time +.icon-time { + border: $icon-border-width solid currentColor; + border-radius: 50%; + &::before { + background: currentColor; + content: ""; + height: .4em; + transform: translate(-50%, -75%); + width: $icon-border-width; + } + &::after { + background: currentColor; + content: ""; + height: .3em; + transform: translate(-50%, -75%) rotate(90deg); + transform-origin: 50% 90%; + width: $icon-border-width; + } +} + +// Icon mail +.icon-mail { + &::before { + border: $icon-border-width solid currentColor; + border-radius: $border-radius; + content: ""; + height: .8em; + width: 1em; + } + &::after { + border: $icon-border-width solid currentColor; + border-right: 0; + border-top: 0; + content: ""; + height: .5em; + transform: translate(-50%, -90%) rotate(-45deg) skew(10deg, 10deg); + width: .5em; + } +} + +// Icon people +.icon-people { + &::before { + border: $icon-border-width solid currentColor; + border-radius: 50%; + content: ""; + height: .45em; + top: 25%; + width: .45em; + } + &::after { + border: $icon-border-width solid currentColor; + border-radius: 50% 50% 0 0; + content: ""; + height: .4em; + top: 75%; + width: .9em; + } +} + +// Icon message +.icon-message { + border: $icon-border-width solid currentColor; + border-bottom: 0; + border-radius: $border-radius; + border-right: 0; + &::before { + border: $icon-border-width solid currentColor; + border-bottom-right-radius: $border-radius; + border-left: 0; + border-top: 0; + content: ""; + height: .8em; + left: 65%; + top: 40%; + width: .7em; + } + &::after { + background: currentColor; + border-radius: $border-radius; + content: ""; + height: .3em; + left: 10%; + top: 100%; + transform: translate(0, -90%) rotate(45deg); + width: $icon-border-width; + } +} + +// Icon photo +.icon-photo { + border: $icon-border-width solid currentColor; + border-radius: $border-radius; + &::before { + border: $icon-border-width solid currentColor; + border-radius: 50%; + content: ""; + height: .25em; + left: 35%; + top: 35%; + width: .25em; + } + &::after { + border: $icon-border-width solid currentColor; + border-bottom: 0; + border-left: 0; + content: ""; + height: .5em; + left: 60%; + transform: translate(-50%, 25%) rotate(-45deg); + width: .5em; + } +} + +// Icon link +.icon-link { + &::before, + &::after { + border: $icon-border-width solid currentColor; + border-radius: 5em 0 0 5em; + border-right: 0; + content: ""; + height: .5em; + width: .75em; + } + &::before { + transform: translate(-70%, -45%) rotate(-45deg); + } + &::after { + transform: translate(-30%, -55%) rotate(135deg); + } +} + +// Icon location +.icon-location { + &::before { + border: $icon-border-width solid currentColor; + border-radius: 50% 50% 50% 0; + content: ""; + height: .8em; + transform: translate(-50%, -60%) rotate(-45deg); + width: .8em; + } + &::after { + border: $icon-border-width solid currentColor; + border-radius: 50%; + content: ""; + height: .2em; + transform: translate(-50%, -80%); + width: .2em; + } +} + +// Icon emoji +.icon-emoji { + border: $icon-border-width solid currentColor; + border-radius: 50%; + &::before { + border-radius: 50%; + box-shadow: -.17em -.15em, .17em -.15em; + content: ""; + height: .1em; + width: .1em; + } + &::after { + border: $icon-border-width solid currentColor; + border-bottom-color: transparent; + border-radius: 50%; + border-right-color: transparent; + content: ""; + height: .5em; + transform: translate(-50%, -40%) rotate(-135deg); + width: .5em; + } +} diff --git a/user/plugins/problems/scss/mixins/_avatar.scss b/user/plugins/problems/scss/mixins/_avatar.scss new file mode 100644 index 00000000..14617adb --- /dev/null +++ b/user/plugins/problems/scss/mixins/_avatar.scss @@ -0,0 +1,6 @@ +// Avatar mixin +@mixin avatar-base($size: $unit-8) { + font-size: $size / 2; + height: $size; + width: $size; +} diff --git a/user/plugins/problems/scss/mixins/_button.scss b/user/plugins/problems/scss/mixins/_button.scss new file mode 100644 index 00000000..c90a94bd --- /dev/null +++ b/user/plugins/problems/scss/mixins/_button.scss @@ -0,0 +1,54 @@ +// Button variant mixin +@mixin button-variant($color: $primary-color) { + background: $color; + border-color: darken($color, 3%); + color: $light-color; + &:focus { + @include control-shadow($color); + } + &:focus, + &:hover { + background: darken($color, 2%); + border-color: darken($color, 5%); + color: $light-color; + } + &:active, + &.active { + background: darken($color, 7%); + border-color: darken($color, 10%); + color: $light-color; + } + &.loading { + &::after { + border-bottom-color: $light-color; + border-left-color: $light-color; + } + } +} + +@mixin button-outline-variant($color: $primary-color) { + background: $light-color; + border-color: $color; + color: $color; + &:focus { + @include control-shadow($color); + } + &:focus, + &:hover { + background: lighten($color, 50%); + border-color: darken($color, 2%); + color: $color; + } + &:active, + &.active { + background: $color; + border-color: darken($color, 5%); + color: $light-color; + } + &.loading { + &::after { + border-bottom-color: $color; + border-left-color: $color; + } + } +} diff --git a/user/plugins/problems/scss/mixins/_clearfix.scss b/user/plugins/problems/scss/mixins/_clearfix.scss new file mode 100644 index 00000000..db6895f9 --- /dev/null +++ b/user/plugins/problems/scss/mixins/_clearfix.scss @@ -0,0 +1,8 @@ +// Clearfix mixin +@mixin clearfix() { + &::after { + clear: both; + content: ""; + display: table; + } +} diff --git a/user/plugins/problems/scss/mixins/_color.scss b/user/plugins/problems/scss/mixins/_color.scss new file mode 100644 index 00000000..3ac90414 --- /dev/null +++ b/user/plugins/problems/scss/mixins/_color.scss @@ -0,0 +1,27 @@ +// Background color utility mixin +@mixin bg-color-variant($name: ".bg-primary", $color: $primary-color) { + #{$name} { + background: $color; + + @if (lightness($color) < 60) { + color: $light-color; + } + } +} + +// Text color utility mixin +@mixin text-color-variant($name: ".text-primary", $color: $primary-color) { + #{$name} { + color: $color; + } + + a#{$name} { + &:focus, + &:hover { + color: darken($color, 5%); + } + &:visited { + color: lighten($color, 5%); + } + } +} diff --git a/user/plugins/problems/scss/mixins/_label.scss b/user/plugins/problems/scss/mixins/_label.scss new file mode 100644 index 00000000..70dcac33 --- /dev/null +++ b/user/plugins/problems/scss/mixins/_label.scss @@ -0,0 +1,11 @@ +// Label base style +@mixin label-base() { + border-radius: $border-radius; + line-height: 1.2; + padding: .1rem .2rem; +} + +@mixin label-variant($color: $light-color, $bg-color: $primary-color) { + background: $bg-color; + color: $color; +} diff --git a/user/plugins/problems/scss/mixins/_position.scss b/user/plugins/problems/scss/mixins/_position.scss new file mode 100644 index 00000000..98b5cfc0 --- /dev/null +++ b/user/plugins/problems/scss/mixins/_position.scss @@ -0,0 +1,65 @@ +// Margin utility mixin +@mixin margin-variant($id: 1, $size: $unit-1) { + .m-#{$id} { + margin: $size !important; + } + + .mb-#{$id} { + margin-bottom: $size !important; + } + + .ml-#{$id} { + margin-left: $size !important; + } + + .mr-#{$id} { + margin-right: $size !important; + } + + .mt-#{$id} { + margin-top: $size !important; + } + + .mx-#{$id} { + margin-left: $size !important; + margin-right: $size !important; + } + + .my-#{$id} { + margin-bottom: $size !important; + margin-top: $size !important; + } +} + +// Padding utility mixin +@mixin padding-variant($id: 1, $size: $unit-1) { + .p-#{$id} { + padding: $size !important; + } + + .pb-#{$id} { + padding-bottom: $size !important; + } + + .pl-#{$id} { + padding-left: $size !important; + } + + .pr-#{$id} { + padding-right: $size !important; + } + + .pt-#{$id} { + padding-top: $size !important; + } + + .px-#{$id} { + padding-left: $size !important; + padding-right: $size !important; + } + + .py-#{$id} { + padding-bottom: $size !important; + padding-top: $size !important; + } +} diff --git a/user/plugins/problems/scss/mixins/_shadow.scss b/user/plugins/problems/scss/mixins/_shadow.scss new file mode 100644 index 00000000..79844491 --- /dev/null +++ b/user/plugins/problems/scss/mixins/_shadow.scss @@ -0,0 +1,9 @@ +// Component focus shadow +@mixin control-shadow($color: $primary-color) { + box-shadow: 0 0 0 .1rem rgba($color, .2); +} + +// Shadow mixin +@mixin shadow-variant($offset) { + box-shadow: 0 $offset ($offset + .05rem) * 2 rgba($dark-color, .3); +} diff --git a/user/plugins/problems/scss/mixins/_text.scss b/user/plugins/problems/scss/mixins/_text.scss new file mode 100644 index 00000000..97dc99d0 --- /dev/null +++ b/user/plugins/problems/scss/mixins/_text.scss @@ -0,0 +1,6 @@ +// Text Ellipsis +@mixin text-ellipsis() { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} diff --git a/user/plugins/problems/scss/mixins/_toast.scss b/user/plugins/problems/scss/mixins/_toast.scss new file mode 100644 index 00000000..a7d3bbf2 --- /dev/null +++ b/user/plugins/problems/scss/mixins/_toast.scss @@ -0,0 +1,5 @@ +// Toast variant mixin +@mixin toast-variant($color: $dark-color) { + background: rgba($color, .9); + border-color: $color; +} diff --git a/user/plugins/problems/scss/mixins/_transition.scss b/user/plugins/problems/scss/mixins/_transition.scss new file mode 100644 index 00000000..0b7497b8 --- /dev/null +++ b/user/plugins/problems/scss/mixins/_transition.scss @@ -0,0 +1,4 @@ +// Component transition +@mixin control-transition() { + transition: all .2s ease; +} diff --git a/user/plugins/problems/scss/spectre-icons.scss b/user/plugins/problems/scss/spectre-icons.scss new file mode 100644 index 00000000..383624e8 --- /dev/null +++ b/user/plugins/problems/scss/spectre-icons.scss @@ -0,0 +1,10 @@ +// Variables and mixins +@import "variables"; +@import "mixins"; + +/*! Spectre.css Icons v#{$version} | MIT License | github.com/picturepan2/spectre */ +// Icons +@import "icons/icons-core"; +@import "icons/icons-navigation"; +@import "icons/icons-action"; +@import "icons/icons-object"; diff --git a/user/plugins/problems/scss/spectre.scss b/user/plugins/problems/scss/spectre.scss new file mode 100644 index 00000000..5345b4b3 --- /dev/null +++ b/user/plugins/problems/scss/spectre.scss @@ -0,0 +1,51 @@ +// Variables and mixins +@import "variables"; +@import "mixins"; + +/*! Spectre.css v#{$version} | MIT License | github.com/picturepan2/spectre */ +// Reset and dependencies +@import "normalize"; +@import "base"; + +// Elements +@import "typography"; +@import "asian"; +@import "tables"; +@import "buttons"; +@import "forms"; +@import "labels"; +@import "codes"; +@import "media"; + +// Layout +@import "layout"; +@import "navbar"; + +// Components +@import "accordions"; +@import "avatars"; +@import "badges"; +@import "breadcrumbs"; +@import "bars"; +@import "cards"; +@import "chips"; +@import "dropdowns"; +@import "empty"; +@import "menus"; +@import "modals"; +@import "navs"; +@import "pagination"; +@import "panels"; +@import "popovers"; +@import "steps"; +@import "tabs"; +@import "tiles"; +@import "toasts"; +@import "tooltips"; + +// Custom +@import "problems"; + +// Utility classes +@import "animations"; +@import "utilities"; diff --git a/user/plugins/problems/scss/utilities/_colors.scss b/user/plugins/problems/scss/utilities/_colors.scss new file mode 100644 index 00000000..28dd2218 --- /dev/null +++ b/user/plugins/problems/scss/utilities/_colors.scss @@ -0,0 +1,31 @@ +// Text colors +@include text-color-variant(".text-primary", $primary-color); + +@include text-color-variant(".text-secondary", $secondary-color-dark); + +@include text-color-variant(".text-gray", $gray-color); + +@include text-color-variant(".text-light", $light-color); + +@include text-color-variant(".text-dark", $body-font-color); + +@include text-color-variant(".text-success", $success-color); + +@include text-color-variant(".text-warning", $warning-color); + +@include text-color-variant(".text-error", $error-color); + +// Background colors +@include bg-color-variant(".bg-primary", $primary-color); + +@include bg-color-variant(".bg-secondary", $secondary-color); + +@include bg-color-variant(".bg-dark", $dark-color); + +@include bg-color-variant(".bg-gray", $bg-color); + +@include bg-color-variant(".bg-success", $success-color); + +@include bg-color-variant(".bg-warning", $warning-color); + +@include bg-color-variant(".bg-error", $error-color); diff --git a/user/plugins/problems/scss/utilities/_cursors.scss b/user/plugins/problems/scss/utilities/_cursors.scss new file mode 100644 index 00000000..bfc4c6b1 --- /dev/null +++ b/user/plugins/problems/scss/utilities/_cursors.scss @@ -0,0 +1,24 @@ +// Cursors +.c-hand { + cursor: pointer; +} + +.c-move { + cursor: move; +} + +.c-zoom-in { + cursor: zoom-in; +} + +.c-zoom-out { + cursor: zoom-out; +} + +.c-not-allowed { + cursor: not-allowed; +} + +.c-auto { + cursor: auto; +} diff --git a/user/plugins/problems/scss/utilities/_display.scss b/user/plugins/problems/scss/utilities/_display.scss new file mode 100644 index 00000000..c6248e07 --- /dev/null +++ b/user/plugins/problems/scss/utilities/_display.scss @@ -0,0 +1,44 @@ +// Display +.d-block { + display: block; +} +.d-inline { + display: inline; +} +.d-inline-block { + display: inline-block; +} +.d-flex { + display: flex; +} +.d-inline-flex { + display: inline-flex; +} +.d-none, +.d-hide { + display: none !important; +} +.d-visible { + visibility: visible; +} +.d-invisible { + visibility: hidden; +} +.text-hide { + background: transparent; + border: 0; + color: transparent; + font-size: 0; + line-height: 0; + text-shadow: none; +} +.text-assistive { + border: 0; + clip: rect(0,0,0,0); + height: 1px; + margin: -1px; + overflow: hidden; + padding: 0; + position: absolute; + width: 1px; +} diff --git a/user/plugins/problems/scss/utilities/_divider.scss b/user/plugins/problems/scss/utilities/_divider.scss new file mode 100644 index 00000000..5d0feb24 --- /dev/null +++ b/user/plugins/problems/scss/utilities/_divider.scss @@ -0,0 +1,50 @@ +// Divider +.divider, +.divider-vert { + display: block; + position: relative; + + &[data-content]::after { + background: $bg-color-light; + color: $gray-color; + content: attr(data-content); + display: inline-block; + font-size: $font-size-sm; + padding: 0 $unit-2; + transform: translateY(-$font-size-sm + $border-width); + } +} + +.divider { + border-top: $border-width solid $border-color; + height: $border-width; + margin: $unit-2 0; + + &[data-content] { + margin: $unit-4 0; + } +} + +.divider-vert { + display: block; + padding: $unit-4; + + &::before { + border-left: $border-width solid $border-color; + bottom: $unit-2; + content: ""; + display: block; + left: 50%; + position: absolute; + top: $unit-2; + transform: translateX(-50%); + } + + &[data-content]::after { + left: 50%; + padding: $unit-1 0; + position: absolute; + top: 50%; + transform: translate(-50%, -50%); + } +} diff --git a/user/plugins/problems/scss/utilities/_loading.scss b/user/plugins/problems/scss/utilities/_loading.scss new file mode 100644 index 00000000..1b4ea609 --- /dev/null +++ b/user/plugins/problems/scss/utilities/_loading.scss @@ -0,0 +1,34 @@ +// Loading +.loading { + color: transparent !important; + min-height: $unit-4; + pointer-events: none; + position: relative; + &::after { + animation: loading 500ms infinite linear; + border: $border-width-lg solid $primary-color; + border-radius: 50%; + border-right-color: transparent; + border-top-color: transparent; + content: ""; + display: block; + height: $unit-4; + left: 50%; + margin-left: -$unit-2; + margin-top: -$unit-2; + position: absolute; + top: 50%; + width: $unit-4; + z-index: $zindex-0; + } + + &.loading-lg { + min-height: $unit-10; + &::after { + height: $unit-8; + margin-left: -$unit-4; + margin-top: -$unit-4; + width: $unit-8; + } + } +} diff --git a/user/plugins/problems/scss/utilities/_position.scss b/user/plugins/problems/scss/utilities/_position.scss new file mode 100644 index 00000000..229bd34b --- /dev/null +++ b/user/plugins/problems/scss/utilities/_position.scss @@ -0,0 +1,50 @@ +// Position +.clearfix { + @include clearfix(); +} + +.float-left { + float: left !important; +} + +.float-right { + float: right !important; +} + +.relative { + position: relative !important; +} + +.absolute { + position: absolute !important; +} + +.fixed { + position: fixed !important; +} + +.centered { + display: block; + float: none; + margin-left: auto; + margin-right: auto; +} + +.flex-centered { + align-items: center; + display: flex; + justify-content: center; +} + +// Spacing +@include margin-variant(0, 0); + +@include margin-variant(1, $unit-1); + +@include margin-variant(2, $unit-2); + +@include padding-variant(0, 0); + +@include padding-variant(1, $unit-1); + +@include padding-variant(2, $unit-2); diff --git a/user/plugins/problems/scss/utilities/_shapes.scss b/user/plugins/problems/scss/utilities/_shapes.scss new file mode 100644 index 00000000..23e131e9 --- /dev/null +++ b/user/plugins/problems/scss/utilities/_shapes.scss @@ -0,0 +1,8 @@ +// Shapes +.s-rounded { + border-radius: $border-radius; +} + +.s-circle { + border-radius: 50%; +} \ No newline at end of file diff --git a/user/plugins/problems/scss/utilities/_text.scss b/user/plugins/problems/scss/utilities/_text.scss new file mode 100644 index 00000000..67793ac2 --- /dev/null +++ b/user/plugins/problems/scss/utilities/_text.scss @@ -0,0 +1,64 @@ +// Text +// Text alignment utilities +.text-left { + text-align: left; +} + +.text-right { + text-align: right; +} + +.text-center { + text-align: center; +} + +.text-justify { + text-align: justify; +} + +// Text transform utilities +.text-lowercase { + text-transform: lowercase; +} + +.text-uppercase { + text-transform: uppercase; +} + +.text-capitalize { + text-transform: capitalize; +} + +// Text style utilities +.text-normal { + font-weight: normal; +} + +.text-bold { + font-weight: bold; +} + +.text-italic { + font-style: italic; +} + +.text-large { + font-size: 1.2em; +} + +// Text overflow utilities +.text-ellipsis { + @include text-ellipsis(); +} + +.text-clip { + overflow: hidden; + text-overflow: clip; + white-space: nowrap; +} + +.text-break { + hyphens: auto; + word-break: break-word; + word-wrap: break-word; +} diff --git a/user/plugins/problems/templates/problems.html.twig b/user/plugins/problems/templates/problems.html.twig new file mode 100644 index 00000000..b6f0e826 --- /dev/null +++ b/user/plugins/problems/templates/problems.html.twig @@ -0,0 +1,34 @@ + + + + + Grav Problems + + + + + + +
                                                            +
                                                            +
                                                            + +
                                                            + + +

                                                            + Please Review and Resolve before continuing Reload Page +

                                                            +
                                                            + + {% include 'reports/problems-report.html.twig' %} + + +
                                                            + +
                                                            +
                                                            + + diff --git a/user/plugins/problems/templates/reports/problems-report.html.twig b/user/plugins/problems/templates/reports/problems-report.html.twig new file mode 100644 index 00000000..19d212a2 --- /dev/null +++ b/user/plugins/problems/templates/reports/problems-report.html.twig @@ -0,0 +1,33 @@ +
                                                              + {% for problem in problems %} + {% set status = problem.status ? 'success' : problem.level == 'critical' ? 'error' : 'warning' %} + + {% endfor %} +
                                                            \ No newline at end of file diff --git a/user/plugins/problems/vendor/autoload.php b/user/plugins/problems/vendor/autoload.php new file mode 100644 index 00000000..c4e41ebb --- /dev/null +++ b/user/plugins/problems/vendor/autoload.php @@ -0,0 +1,7 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer\Autoload; + +/** + * ClassLoader implements a PSR-0, PSR-4 and classmap class loader. + * + * $loader = new \Composer\Autoload\ClassLoader(); + * + * // register classes with namespaces + * $loader->add('Symfony\Component', __DIR__.'/component'); + * $loader->add('Symfony', __DIR__.'/framework'); + * + * // activate the autoloader + * $loader->register(); + * + * // to enable searching the include path (eg. for PEAR packages) + * $loader->setUseIncludePath(true); + * + * In this example, if you try to use a class in the Symfony\Component + * namespace or one of its children (Symfony\Component\Console for instance), + * the autoloader will first look for the class under the component/ + * directory, and it will then fallback to the framework/ directory if not + * found before giving up. + * + * This class is loosely based on the Symfony UniversalClassLoader. + * + * @author Fabien Potencier + * @author Jordi Boggiano + * @see http://www.php-fig.org/psr/psr-0/ + * @see http://www.php-fig.org/psr/psr-4/ + */ +class ClassLoader +{ + // PSR-4 + private $prefixLengthsPsr4 = array(); + private $prefixDirsPsr4 = array(); + private $fallbackDirsPsr4 = array(); + + // PSR-0 + private $prefixesPsr0 = array(); + private $fallbackDirsPsr0 = array(); + + private $useIncludePath = false; + private $classMap = array(); + private $classMapAuthoritative = false; + private $missingClasses = array(); + private $apcuPrefix; + + public function getPrefixes() + { + if (!empty($this->prefixesPsr0)) { + return call_user_func_array('array_merge', $this->prefixesPsr0); + } + + return array(); + } + + public function getPrefixesPsr4() + { + return $this->prefixDirsPsr4; + } + + public function getFallbackDirs() + { + return $this->fallbackDirsPsr0; + } + + public function getFallbackDirsPsr4() + { + return $this->fallbackDirsPsr4; + } + + public function getClassMap() + { + return $this->classMap; + } + + /** + * @param array $classMap Class to filename map + */ + public function addClassMap(array $classMap) + { + if ($this->classMap) { + $this->classMap = array_merge($this->classMap, $classMap); + } else { + $this->classMap = $classMap; + } + } + + /** + * Registers a set of PSR-0 directories for a given prefix, either + * appending or prepending to the ones previously set for this prefix. + * + * @param string $prefix The prefix + * @param array|string $paths The PSR-0 root directories + * @param bool $prepend Whether to prepend the directories + */ + public function add($prefix, $paths, $prepend = false) + { + if (!$prefix) { + if ($prepend) { + $this->fallbackDirsPsr0 = array_merge( + (array) $paths, + $this->fallbackDirsPsr0 + ); + } else { + $this->fallbackDirsPsr0 = array_merge( + $this->fallbackDirsPsr0, + (array) $paths + ); + } + + return; + } + + $first = $prefix[0]; + if (!isset($this->prefixesPsr0[$first][$prefix])) { + $this->prefixesPsr0[$first][$prefix] = (array) $paths; + + return; + } + if ($prepend) { + $this->prefixesPsr0[$first][$prefix] = array_merge( + (array) $paths, + $this->prefixesPsr0[$first][$prefix] + ); + } else { + $this->prefixesPsr0[$first][$prefix] = array_merge( + $this->prefixesPsr0[$first][$prefix], + (array) $paths + ); + } + } + + /** + * Registers a set of PSR-4 directories for a given namespace, either + * appending or prepending to the ones previously set for this namespace. + * + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param array|string $paths The PSR-4 base directories + * @param bool $prepend Whether to prepend the directories + * + * @throws \InvalidArgumentException + */ + public function addPsr4($prefix, $paths, $prepend = false) + { + if (!$prefix) { + // Register directories for the root namespace. + if ($prepend) { + $this->fallbackDirsPsr4 = array_merge( + (array) $paths, + $this->fallbackDirsPsr4 + ); + } else { + $this->fallbackDirsPsr4 = array_merge( + $this->fallbackDirsPsr4, + (array) $paths + ); + } + } elseif (!isset($this->prefixDirsPsr4[$prefix])) { + // Register directories for a new namespace. + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = (array) $paths; + } elseif ($prepend) { + // Prepend directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + (array) $paths, + $this->prefixDirsPsr4[$prefix] + ); + } else { + // Append directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + $this->prefixDirsPsr4[$prefix], + (array) $paths + ); + } + } + + /** + * Registers a set of PSR-0 directories for a given prefix, + * replacing any others previously set for this prefix. + * + * @param string $prefix The prefix + * @param array|string $paths The PSR-0 base directories + */ + public function set($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr0 = (array) $paths; + } else { + $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths; + } + } + + /** + * Registers a set of PSR-4 directories for a given namespace, + * replacing any others previously set for this namespace. + * + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param array|string $paths The PSR-4 base directories + * + * @throws \InvalidArgumentException + */ + public function setPsr4($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr4 = (array) $paths; + } else { + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = (array) $paths; + } + } + + /** + * Turns on searching the include path for class files. + * + * @param bool $useIncludePath + */ + public function setUseIncludePath($useIncludePath) + { + $this->useIncludePath = $useIncludePath; + } + + /** + * Can be used to check if the autoloader uses the include path to check + * for classes. + * + * @return bool + */ + public function getUseIncludePath() + { + return $this->useIncludePath; + } + + /** + * Turns off searching the prefix and fallback directories for classes + * that have not been registered with the class map. + * + * @param bool $classMapAuthoritative + */ + public function setClassMapAuthoritative($classMapAuthoritative) + { + $this->classMapAuthoritative = $classMapAuthoritative; + } + + /** + * Should class lookup fail if not found in the current class map? + * + * @return bool + */ + public function isClassMapAuthoritative() + { + return $this->classMapAuthoritative; + } + + /** + * APCu prefix to use to cache found/not-found classes, if the extension is enabled. + * + * @param string|null $apcuPrefix + */ + public function setApcuPrefix($apcuPrefix) + { + $this->apcuPrefix = function_exists('apcu_fetch') && ini_get('apc.enabled') ? $apcuPrefix : null; + } + + /** + * The APCu prefix in use, or null if APCu caching is not enabled. + * + * @return string|null + */ + public function getApcuPrefix() + { + return $this->apcuPrefix; + } + + /** + * Registers this instance as an autoloader. + * + * @param bool $prepend Whether to prepend the autoloader or not + */ + public function register($prepend = false) + { + spl_autoload_register(array($this, 'loadClass'), true, $prepend); + } + + /** + * Unregisters this instance as an autoloader. + */ + public function unregister() + { + spl_autoload_unregister(array($this, 'loadClass')); + } + + /** + * Loads the given class or interface. + * + * @param string $class The name of the class + * @return bool|null True if loaded, null otherwise + */ + public function loadClass($class) + { + if ($file = $this->findFile($class)) { + includeFile($file); + + return true; + } + } + + /** + * Finds the path to the file where the class is defined. + * + * @param string $class The name of the class + * + * @return string|false The path if found, false otherwise + */ + public function findFile($class) + { + // class map lookup + if (isset($this->classMap[$class])) { + return $this->classMap[$class]; + } + if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) { + return false; + } + if (null !== $this->apcuPrefix) { + $file = apcu_fetch($this->apcuPrefix.$class, $hit); + if ($hit) { + return $file; + } + } + + $file = $this->findFileWithExtension($class, '.php'); + + // Search for Hack files if we are running on HHVM + if (false === $file && defined('HHVM_VERSION')) { + $file = $this->findFileWithExtension($class, '.hh'); + } + + if (null !== $this->apcuPrefix) { + apcu_add($this->apcuPrefix.$class, $file); + } + + if (false === $file) { + // Remember that this class does not exist. + $this->missingClasses[$class] = true; + } + + return $file; + } + + private function findFileWithExtension($class, $ext) + { + // PSR-4 lookup + $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext; + + $first = $class[0]; + if (isset($this->prefixLengthsPsr4[$first])) { + $subPath = $class; + while (false !== $lastPos = strrpos($subPath, '\\')) { + $subPath = substr($subPath, 0, $lastPos); + $search = $subPath.'\\'; + if (isset($this->prefixDirsPsr4[$search])) { + $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1); + foreach ($this->prefixDirsPsr4[$search] as $dir) { + if (file_exists($file = $dir . $pathEnd)) { + return $file; + } + } + } + } + } + + // PSR-4 fallback dirs + foreach ($this->fallbackDirsPsr4 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) { + return $file; + } + } + + // PSR-0 lookup + if (false !== $pos = strrpos($class, '\\')) { + // namespaced class name + $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1) + . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR); + } else { + // PEAR-like class name + $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext; + } + + if (isset($this->prefixesPsr0[$first])) { + foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) { + if (0 === strpos($class, $prefix)) { + foreach ($dirs as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + } + } + } + + // PSR-0 fallback dirs + foreach ($this->fallbackDirsPsr0 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + + // PSR-0 include paths. + if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { + return $file; + } + + return false; + } +} + +/** + * Scope isolated include. + * + * Prevents access to $this/self from included files. + */ +function includeFile($file) +{ + include $file; +} diff --git a/user/plugins/problems/vendor/composer/LICENSE b/user/plugins/problems/vendor/composer/LICENSE new file mode 100644 index 00000000..f27399a0 --- /dev/null +++ b/user/plugins/problems/vendor/composer/LICENSE @@ -0,0 +1,21 @@ + +Copyright (c) Nils Adermann, Jordi Boggiano + +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. + diff --git a/user/plugins/problems/vendor/composer/autoload_classmap.php b/user/plugins/problems/vendor/composer/autoload_classmap.php new file mode 100644 index 00000000..2308dcf2 --- /dev/null +++ b/user/plugins/problems/vendor/composer/autoload_classmap.php @@ -0,0 +1,10 @@ + $baseDir . '/problems.php', +); diff --git a/user/plugins/problems/vendor/composer/autoload_namespaces.php b/user/plugins/problems/vendor/composer/autoload_namespaces.php new file mode 100644 index 00000000..b7fc0125 --- /dev/null +++ b/user/plugins/problems/vendor/composer/autoload_namespaces.php @@ -0,0 +1,9 @@ + array($baseDir . '/cli'), + 'Grav\\Plugin\\' => array($baseDir . '/classes'), +); diff --git a/user/plugins/problems/vendor/composer/autoload_real.php b/user/plugins/problems/vendor/composer/autoload_real.php new file mode 100644 index 00000000..54f15719 --- /dev/null +++ b/user/plugins/problems/vendor/composer/autoload_real.php @@ -0,0 +1,52 @@ += 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded()); + if ($useStaticLoader) { + require_once __DIR__ . '/autoload_static.php'; + + call_user_func(\Composer\Autoload\ComposerStaticInit36088575ecf50ba483833f50fe25b743::getInitializer($loader)); + } else { + $map = require __DIR__ . '/autoload_namespaces.php'; + foreach ($map as $namespace => $path) { + $loader->set($namespace, $path); + } + + $map = require __DIR__ . '/autoload_psr4.php'; + foreach ($map as $namespace => $path) { + $loader->setPsr4($namespace, $path); + } + + $classMap = require __DIR__ . '/autoload_classmap.php'; + if ($classMap) { + $loader->addClassMap($classMap); + } + } + + $loader->register(true); + + return $loader; + } +} diff --git a/user/plugins/problems/vendor/composer/autoload_static.php b/user/plugins/problems/vendor/composer/autoload_static.php new file mode 100644 index 00000000..00b700ab --- /dev/null +++ b/user/plugins/problems/vendor/composer/autoload_static.php @@ -0,0 +1,41 @@ + + array ( + 'Grav\\Plugin\\Console\\' => 20, + 'Grav\\Plugin\\' => 12, + ), + ); + + public static $prefixDirsPsr4 = array ( + 'Grav\\Plugin\\Console\\' => + array ( + 0 => __DIR__ . '/../..' . '/cli', + ), + 'Grav\\Plugin\\' => + array ( + 0 => __DIR__ . '/../..' . '/classes', + ), + ); + + public static $classMap = array ( + 'Grav\\Plugin\\ProblemsPlugin' => __DIR__ . '/../..' . '/problems.php', + ); + + public static function getInitializer(ClassLoader $loader) + { + return \Closure::bind(function () use ($loader) { + $loader->prefixLengthsPsr4 = ComposerStaticInit36088575ecf50ba483833f50fe25b743::$prefixLengthsPsr4; + $loader->prefixDirsPsr4 = ComposerStaticInit36088575ecf50ba483833f50fe25b743::$prefixDirsPsr4; + $loader->classMap = ComposerStaticInit36088575ecf50ba483833f50fe25b743::$classMap; + + }, null, ClassLoader::class); + } +} diff --git a/user/plugins/problems/vendor/composer/installed.json b/user/plugins/problems/vendor/composer/installed.json new file mode 100644 index 00000000..fe51488c --- /dev/null +++ b/user/plugins/problems/vendor/composer/installed.json @@ -0,0 +1 @@ +[] diff --git a/user/themes/.gitkeep b/user/themes/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/user/themes/bulma-portfolio/CHANGELOG.md b/user/themes/bulma-portfolio/CHANGELOG.md new file mode 100644 index 00000000..e988ae62 --- /dev/null +++ b/user/themes/bulma-portfolio/CHANGELOG.md @@ -0,0 +1,27 @@ +# v0.1.7 +## 30/03/2018 +1. [](#improved) + - logo upload and modification + - favicon upload and modification + - new release to upadte the GPM hopefully with latest changes + +# v0.1.6 +## 26/03/2018 +1. [](#improved) + - logo upload and modification + - favicon upload and modification + +# v0.1.5 +## 22/03/2018 +1. [](#new) + - updated GitHub Links + - created the demo pages + + +1. [](#improved) + - added possibility to select a Logo (only SVG ) and a favicon (usually a png/jpg) from the theme settings. Before a logo / favicon can be added, at least a page must be created and saved and media added to that page. (next iteration could see improvements in this) +# v0.1.0 +## 18/03/2018 + +- initial release + diff --git a/user/themes/bulma-portfolio/LICENSE b/user/themes/bulma-portfolio/LICENSE new file mode 100644 index 00000000..e42c093e --- /dev/null +++ b/user/themes/bulma-portfolio/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2017 John Mica + +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. diff --git a/user/themes/bulma-portfolio/README.md b/user/themes/bulma-portfolio/README.md new file mode 100644 index 00000000..3af59b48 --- /dev/null +++ b/user/themes/bulma-portfolio/README.md @@ -0,0 +1,31 @@ +# Bulma Portfolio Theme + +The **Bulma Portfolio** Theme is for [Grav CMS](http://github.com/getgrav/grav). + + +![Theme Preview](./assets/normal-view.png) + +## Description + +Bulma Portfolio Theme includes + +- Bulma forms +- Carousel +- Testimonials +- Product Modals + +Almost all have beenn done to be changed and updated from the Admin UI (tabs and options to select items) + +For any bugs / features dont hesitate to open an issue and suggest them + +## Usage + +Most components have been built using Blueprints and thus simplifying the end-user experience and magically appear in the front-end :) + +Carousels => end user can select images, add text, buttons, etc ... + +Features => end user can add as many as needed, select Font-Awesome icons, add text, links, etc ... + +Products / Portfolio items => end user ads images, descriptions, categories, etc ... + +Forms => most Bulma fields have been ported to the theme, but more are welcomed \ No newline at end of file diff --git a/user/themes/bulma-portfolio/_demo/pages/01.home/_clients/alert-circle.svg b/user/themes/bulma-portfolio/_demo/pages/01.home/_clients/alert-circle.svg new file mode 100644 index 00000000..6b41c0b9 --- /dev/null +++ b/user/themes/bulma-portfolio/_demo/pages/01.home/_clients/alert-circle.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/_demo/pages/01.home/_clients/alert-triangle.svg b/user/themes/bulma-portfolio/_demo/pages/01.home/_clients/alert-triangle.svg new file mode 100644 index 00000000..59e65b15 --- /dev/null +++ b/user/themes/bulma-portfolio/_demo/pages/01.home/_clients/alert-triangle.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/_demo/pages/01.home/_clients/arrow-down-circle.svg b/user/themes/bulma-portfolio/_demo/pages/01.home/_clients/arrow-down-circle.svg new file mode 100644 index 00000000..3238091b --- /dev/null +++ b/user/themes/bulma-portfolio/_demo/pages/01.home/_clients/arrow-down-circle.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/_demo/pages/01.home/_clients/arrow-right.svg b/user/themes/bulma-portfolio/_demo/pages/01.home/_clients/arrow-right.svg new file mode 100644 index 00000000..939b57c5 --- /dev/null +++ b/user/themes/bulma-portfolio/_demo/pages/01.home/_clients/arrow-right.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/_demo/pages/01.home/_clients/clients.md b/user/themes/bulma-portfolio/_demo/pages/01.home/_clients/clients.md new file mode 100644 index 00000000..cc21254a --- /dev/null +++ b/user/themes/bulma-portfolio/_demo/pages/01.home/_clients/clients.md @@ -0,0 +1,51 @@ +--- +title: 'Our Clients' +media_order: 'alert-circle.svg,arrow-right.svg,arrow-down-circle.svg,alert-triangle.svg' +slider: + - + feature_img: alert-circle.svg + feature_title: 'The Fore-front of Design & Technology' + feature_subtitle: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed a lorem quis neque interdum consequat ut sed sem. Duis quis tempor nunc. Interdum et malesuada fames ac ante ipsum primis in faucibus.' + feature_link: '#features' + feature_link_text: 'Find out why this freebie rocks!' + - + feature_img: arrow-down-circle.svg + feature_title: 'Multi-Purpose User Centric Design' + feature_subtitle: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed a lorem quis neque interdum consequat ut sed sem. Duis quis tempor nunc. Interdum et malesuada fames ac ante ipsum primis in faucibus.' + feature_link: 'http://google.com' + feature_link_text: 'Find out why this freebie rocks!' + - + feature_img: arrow-right.svg + feature_title: 'Made with Love, Released for Free' + feature_subtitle: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed a lorem quis neque interdum consequat ut sed sem. Duis quis tempor nunc. Interdum et malesuada fames ac ante ipsum primis in faucibus.' + feature_link: 'http://google.com' + feature_link_text: 'Find out why this freebie rocks!' +--- + +### These are out clients + +Bona campus? Alto adsumpserat spatiosum vaticinata poplitibus hydrae. Rauco +Iris, **bifores non quondam** fecit; pedes haec natus hoc est. Pennae *novos +aliud*; illum lustra et ad certi: mea sua arbor est criminis neci. Variari habe +suas femineis ede pressaeque turbida. + +Iugo vultus sua est tum dubitabat primis Larisaea semine: quam habent; hoc orbem +voco longi: cuius **multo**. Lelegeia mandata *Cybeleius sceptrum conprensus* +plura concorditer alebat et ius virtutem plurima. Gloria est utraque cervicis, +arte non, fata **ripa est**, mox fonte cacumen stetit! *Equos in* sacro timentem +quam quantus noscit modo quamlibet genus aut virides erat. Contenta Meropisque +praedam quaerit tollens, dextra est cedit occidit Thetis, ore fornace **mensis +concubitus**. + +> Tuorum aries annis subiecta manum urbesque Hennaeis; in erat habenas languore +> voces Oebalio sollerti patebant olim visamque. Troezena multo volucresque +> erat, est hospitis tetigit, detur. Male tinxerat in cineres sceleri *quid +> sacris*, quam potest hostem. Procnes Regi **virgo** fronti; plausis pro mors +> fine reddat rapinae [fortisque](http://reieci.net/qui) metallis multaque +> patrem. + +Circum in omnia coepitque facinus scire litoris mollis animum at paratis aliter +pedes promittet. Cupiunt me fervens foedera; quoque e genitor quibus cognoscenda +hiems tulisse: aliud quae, post, concordia. Et fuge aggere? Nitente locus +precibusque oculos, per leonem gratam intendensque reddidit? Eumque tempus fecit +adverso, sidere quassasque fuit vates, illa in ubi. \ No newline at end of file diff --git a/user/themes/bulma-portfolio/_demo/pages/01.home/_contact/form.md b/user/themes/bulma-portfolio/_demo/pages/01.home/_contact/form.md new file mode 100644 index 00000000..5ca63802 --- /dev/null +++ b/user/themes/bulma-portfolio/_demo/pages/01.home/_contact/form.md @@ -0,0 +1,75 @@ +--- +title: Contact +cache_enable: false +hidemenu: false +form: + name: contact-form + action: /home + fields: + - name: name + id: name + label: Name + classes: input + outerclasses: field + placeholder: Enter your name + autocomplete: on + help: "Your name should consist of only letter. No numbers or other characters are accepted" + attributes: + autocomplete: name + type: text + validate: + required: true + - name: honeypot + type: honeypot + - name: email + id: email + classes: input + outerclasses: field + label: Email + autocomplete: on + help: 'The email address should appear as john@domain.something' + placeholder: Enter your email address + type: email + validate: + rule: email + required: true + + - name: message + label: Message + classes: textarea + outerclasses: field + autocomplete: off + help: "Your message should not consists of any scripts or other web elements" + size: long + placeholder: Enter your message + type: textarea + validate: + required: true + + buttons: + - type: submit + value: Submit + classes: is-medium is-info is-outlined + outerclasses: control + + + process: + - email: + from: "{{ config.plugins.email.from }}" + to: + - "{{ config.plugins.email.from }}" + - "{{ form.value.email }}" + subject: "[Feedback] {{ form.value.name|e }}" + body: "{% include 'forms/data.html.twig' %}" + - save: + fileprefix: feedback- + dateformat: Ymd-His-u + extension: txt + body: "{% include 'forms/data.txt.twig' %}" + - message: Thank you for your feedback! + - display: thanks + + +--- + +## Send me a message \ No newline at end of file diff --git a/user/themes/bulma-portfolio/_demo/pages/01.home/_featureslist/features.md b/user/themes/bulma-portfolio/_demo/pages/01.home/_featureslist/features.md new file mode 100644 index 00000000..737771aa --- /dev/null +++ b/user/themes/bulma-portfolio/_demo/pages/01.home/_featureslist/features.md @@ -0,0 +1,42 @@ +--- +title: 'Features List' +features: + - + icons: 'fa fa-repeat' + title: Responsive + text: 'Built using HTML5/CSS3 and javascript, and built using one of the world''''s most flexible CSS frameworks available, Bulma.' + link: 'http://google.com' + link_text: 'Read More' + - + icons: 'fa fa-bold' + title: Multi-Purpose + text: 'Perfect if you run your own start-up, product or service. Boxify can showcase your business converting your visits to income.' + link: 'http://google.com' + link_text: 'Read More' + - + icons: 'fa fa-pencil-square-o' + title: 'Absolutely Free' + text: 'As aways, download Boxify for free exclusively from Codrops. If you love Boxify and want to thank me, simply buy me a beer.' + link: 'http://google.com' + link_text: 'Read More' + - + icons: 'fa fa-search-plus' + title: 'Absolutely Free' + text: 'As aways, download Boxify for free exclusively from Codrops. If you love Boxify and want to thank me, simply buy me a beer.' + link: 'http://google.com' + link_text: 'Read More' + - + icons: 'fa fa-home' + title: 'Absolutely Free' + text: 'As aways, download Boxify for free exclusively from Codrops. If you love Boxify and want to thank me, simply buy me a beer.' + link: 'http://google.com' + link_text: 'Read More' +hidemenu: false +--- + +**Lorem markdownum circumdata** male. Herosmaxime Sigeia auxiliaribus vocem Et +[habetur meruistis paulum](http://manuque.io/), prole solacia, mulcet, parte. +Illi celebres perspicit valle novis perluit non utque capiat pennis ignibus +pater caesarumque sumpto aspera qualiacumque quamvis perque, in. Olim summo +inquit coniuge dumque docta illinc potiorque nodis Thebas, facies vetitus +posita. \ No newline at end of file diff --git a/user/themes/bulma-portfolio/_demo/pages/01.home/_landing/beautiful-sunset-images-196063.jpg b/user/themes/bulma-portfolio/_demo/pages/01.home/_landing/beautiful-sunset-images-196063.jpg new file mode 100644 index 00000000..07c52afb Binary files /dev/null and b/user/themes/bulma-portfolio/_demo/pages/01.home/_landing/beautiful-sunset-images-196063.jpg differ diff --git a/user/themes/bulma-portfolio/_demo/pages/01.home/_landing/landing.md b/user/themes/bulma-portfolio/_demo/pages/01.home/_landing/landing.md new file mode 100644 index 00000000..10bc967f --- /dev/null +++ b/user/themes/bulma-portfolio/_demo/pages/01.home/_landing/landing.md @@ -0,0 +1,14 @@ +--- +title: Welcome +media_order: beautiful-sunset-images-196063.jpg +banner_img: beautiful-sunset-images-196063.jpg +--- + +## Littera matertera accenseor in tibi sed aquis + +Spolieris ut flammis confusa ipse, caesa doluere vix dixit mirabile. Et animam +veniret nec capere triumphos cupidine necis mortis, vaccam erat fertis, tam +parvi. Velociter munere; abolere latratibus **matrem naides** consensistis ignes +**nec umbrae medio** fulvis Tirynthia. Mecum in dabunt sidera, post novo angues, +exit quem ensis: quoque, cornua et cycnorum. Ad non, aevo currus magno tremens, +at ima inritamen. \ No newline at end of file diff --git a/user/themes/bulma-portfolio/_demo/pages/01.home/_portfolio/201017031244-17033.jpg b/user/themes/bulma-portfolio/_demo/pages/01.home/_portfolio/201017031244-17033.jpg new file mode 100644 index 00000000..7eb88eea Binary files /dev/null and b/user/themes/bulma-portfolio/_demo/pages/01.home/_portfolio/201017031244-17033.jpg differ diff --git a/user/themes/bulma-portfolio/_demo/pages/01.home/_portfolio/6968796-desktop-wallpaper-backgrounds-1080p.jpg b/user/themes/bulma-portfolio/_demo/pages/01.home/_portfolio/6968796-desktop-wallpaper-backgrounds-1080p.jpg new file mode 100644 index 00000000..824787fc Binary files /dev/null and b/user/themes/bulma-portfolio/_demo/pages/01.home/_portfolio/6968796-desktop-wallpaper-backgrounds-1080p.jpg differ diff --git a/user/themes/bulma-portfolio/_demo/pages/01.home/_portfolio/beautiful-sunset-images-196063.jpg b/user/themes/bulma-portfolio/_demo/pages/01.home/_portfolio/beautiful-sunset-images-196063.jpg new file mode 100644 index 00000000..07c52afb Binary files /dev/null and b/user/themes/bulma-portfolio/_demo/pages/01.home/_portfolio/beautiful-sunset-images-196063.jpg differ diff --git a/user/themes/bulma-portfolio/_demo/pages/01.home/_portfolio/image322.png b/user/themes/bulma-portfolio/_demo/pages/01.home/_portfolio/image322.png new file mode 100644 index 00000000..75fc4311 Binary files /dev/null and b/user/themes/bulma-portfolio/_demo/pages/01.home/_portfolio/image322.png differ diff --git a/user/themes/bulma-portfolio/_demo/pages/01.home/_portfolio/nature_backgrounds_amazing_background_cover_7052.jpg b/user/themes/bulma-portfolio/_demo/pages/01.home/_portfolio/nature_backgrounds_amazing_background_cover_7052.jpg new file mode 100644 index 00000000..f75abca4 Binary files /dev/null and b/user/themes/bulma-portfolio/_demo/pages/01.home/_portfolio/nature_backgrounds_amazing_background_cover_7052.jpg differ diff --git a/user/themes/bulma-portfolio/_demo/pages/01.home/_portfolio/nature_backgrounds_best_version_pictures_7014.jpg b/user/themes/bulma-portfolio/_demo/pages/01.home/_portfolio/nature_backgrounds_best_version_pictures_7014.jpg new file mode 100644 index 00000000..92244d4a Binary files /dev/null and b/user/themes/bulma-portfolio/_demo/pages/01.home/_portfolio/nature_backgrounds_best_version_pictures_7014.jpg differ diff --git a/user/themes/bulma-portfolio/_demo/pages/01.home/_portfolio/nature_backgrounds_elegant_background_pictures_7072.jpg b/user/themes/bulma-portfolio/_demo/pages/01.home/_portfolio/nature_backgrounds_elegant_background_pictures_7072.jpg new file mode 100644 index 00000000..1004ef44 Binary files /dev/null and b/user/themes/bulma-portfolio/_demo/pages/01.home/_portfolio/nature_backgrounds_elegant_background_pictures_7072.jpg differ diff --git a/user/themes/bulma-portfolio/_demo/pages/01.home/_portfolio/nature_backgrounds_good_version_high_definition_photos_7084.jpg b/user/themes/bulma-portfolio/_demo/pages/01.home/_portfolio/nature_backgrounds_good_version_high_definition_photos_7084.jpg new file mode 100644 index 00000000..9ed0a0a2 Binary files /dev/null and b/user/themes/bulma-portfolio/_demo/pages/01.home/_portfolio/nature_backgrounds_good_version_high_definition_photos_7084.jpg differ diff --git a/user/themes/bulma-portfolio/_demo/pages/01.home/_portfolio/portfolio.md b/user/themes/bulma-portfolio/_demo/pages/01.home/_portfolio/portfolio.md new file mode 100644 index 00000000..6d97c8b0 --- /dev/null +++ b/user/themes/bulma-portfolio/_demo/pages/01.home/_portfolio/portfolio.md @@ -0,0 +1,70 @@ +--- +title: 'My Projects' +media_order: 'beautiful-sunset-images-196063.jpg,nature_backgrounds_amazing_background_cover_7052.jpg,nature_backgrounds_best_version_pictures_7014.jpg,nature_backgrounds_elegant_background_pictures_7072.jpg,nature_backgrounds_good_version_high_definition_photos_7084.jpg,6968796-desktop-wallpaper-backgrounds-1080p.jpg,201017031244-17033.jpg,image322.png' +portfolio: + - + project_img: 6968796-desktop-wallpaper-backgrounds-1080p.jpg + project_title: 'First Title' + project_description: "What is Lorem Ipsum?\r\nLorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum." + project_link: 'https://google.com' + project_date: '2018-02-01' + project_work: + - desing + - 'work and stuff' + - 'more dev' + project_client: 'Somewhere searching' + - + project_img: 201017031244-17033.jpg + project_title: 'Second Title' + project_description: "What is Lorem Ipsum?\r\nLorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum." + project_date: '2018-07-12' + project_work: + - 'more stuff' + - stuff + project_client: 'Rebranding images' + - + project_img: nature_backgrounds_best_version_pictures_7014.jpg + project_title: 'Third Title' + project_description: "What is Lorem Ipsum?\r\nLorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum." + project_date: '2016-11-02' + project_work: + - project_work + - stuff + project_client: 'More To the point' + - + project_img: beautiful-sunset-images-196063.jpg + project_title: 'Fourth Title' + project_description: "What is Lorem Ipsum?\r\nLorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum." + project_date: '2018-02-12' + project_work: + - project_work + - stuff + - photographs + project_client: 'Sunset Agency' + - + project_img: nature_backgrounds_amazing_background_cover_7052.jpg + project_title: 'Fifth Title' + project_description: "What is Lorem Ipsum?\r\nLorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum." + project_date: '2018-02-08' + project_work: + - 'project_work stuff' + - 'web development' + - rebranding + project_client: 'Nature Agency' + - + project_img: nature_backgrounds_elegant_background_pictures_7072.jpg + project_title: 'Sixth Title' + project_description: "What is Lorem Ipsum?\r\nLorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum." + project_date: '2017-10-06' + project_work: + - 'web design' + - development + - redrawing + - SEO + project_client: 'Example Agency' +--- + +### This is mu little portfolio + + +#### i have played long with it to make it with Bulma \ No newline at end of file diff --git a/user/themes/bulma-portfolio/_demo/pages/01.home/_screenshots/01-screenshot.jpg b/user/themes/bulma-portfolio/_demo/pages/01.home/_screenshots/01-screenshot.jpg new file mode 100644 index 00000000..87ebdd35 Binary files /dev/null and b/user/themes/bulma-portfolio/_demo/pages/01.home/_screenshots/01-screenshot.jpg differ diff --git a/user/themes/bulma-portfolio/_demo/pages/01.home/_screenshots/01.jpg b/user/themes/bulma-portfolio/_demo/pages/01.home/_screenshots/01.jpg new file mode 100644 index 00000000..be43d639 Binary files /dev/null and b/user/themes/bulma-portfolio/_demo/pages/01.home/_screenshots/01.jpg differ diff --git a/user/themes/bulma-portfolio/_demo/pages/01.home/_screenshots/02-screenshot.jpg b/user/themes/bulma-portfolio/_demo/pages/01.home/_screenshots/02-screenshot.jpg new file mode 100644 index 00000000..6509eaab Binary files /dev/null and b/user/themes/bulma-portfolio/_demo/pages/01.home/_screenshots/02-screenshot.jpg differ diff --git a/user/themes/bulma-portfolio/_demo/pages/01.home/_screenshots/02.jpg b/user/themes/bulma-portfolio/_demo/pages/01.home/_screenshots/02.jpg new file mode 100644 index 00000000..797eb014 Binary files /dev/null and b/user/themes/bulma-portfolio/_demo/pages/01.home/_screenshots/02.jpg differ diff --git a/user/themes/bulma-portfolio/_demo/pages/01.home/_screenshots/03-screenshot.jpg b/user/themes/bulma-portfolio/_demo/pages/01.home/_screenshots/03-screenshot.jpg new file mode 100644 index 00000000..887faf28 Binary files /dev/null and b/user/themes/bulma-portfolio/_demo/pages/01.home/_screenshots/03-screenshot.jpg differ diff --git a/user/themes/bulma-portfolio/_demo/pages/01.home/_screenshots/03.jpg b/user/themes/bulma-portfolio/_demo/pages/01.home/_screenshots/03.jpg new file mode 100644 index 00000000..1856b0df Binary files /dev/null and b/user/themes/bulma-portfolio/_demo/pages/01.home/_screenshots/03.jpg differ diff --git a/user/themes/bulma-portfolio/_demo/pages/01.home/_screenshots/04-screenshot.jpg b/user/themes/bulma-portfolio/_demo/pages/01.home/_screenshots/04-screenshot.jpg new file mode 100644 index 00000000..e2624c84 Binary files /dev/null and b/user/themes/bulma-portfolio/_demo/pages/01.home/_screenshots/04-screenshot.jpg differ diff --git a/user/themes/bulma-portfolio/_demo/pages/01.home/_screenshots/04.jpg b/user/themes/bulma-portfolio/_demo/pages/01.home/_screenshots/04.jpg new file mode 100644 index 00000000..f2a7b1d8 Binary files /dev/null and b/user/themes/bulma-portfolio/_demo/pages/01.home/_screenshots/04.jpg differ diff --git a/user/themes/bulma-portfolio/_demo/pages/01.home/_screenshots/05-screenshot.jpg b/user/themes/bulma-portfolio/_demo/pages/01.home/_screenshots/05-screenshot.jpg new file mode 100644 index 00000000..1d7e659e Binary files /dev/null and b/user/themes/bulma-portfolio/_demo/pages/01.home/_screenshots/05-screenshot.jpg differ diff --git a/user/themes/bulma-portfolio/_demo/pages/01.home/_screenshots/05.jpg b/user/themes/bulma-portfolio/_demo/pages/01.home/_screenshots/05.jpg new file mode 100644 index 00000000..33669ab1 Binary files /dev/null and b/user/themes/bulma-portfolio/_demo/pages/01.home/_screenshots/05.jpg differ diff --git a/user/themes/bulma-portfolio/_demo/pages/01.home/_screenshots/06-screenshot.jpg b/user/themes/bulma-portfolio/_demo/pages/01.home/_screenshots/06-screenshot.jpg new file mode 100644 index 00000000..6c2e9fd4 Binary files /dev/null and b/user/themes/bulma-portfolio/_demo/pages/01.home/_screenshots/06-screenshot.jpg differ diff --git a/user/themes/bulma-portfolio/_demo/pages/01.home/_screenshots/06.jpg b/user/themes/bulma-portfolio/_demo/pages/01.home/_screenshots/06.jpg new file mode 100644 index 00000000..799cee76 Binary files /dev/null and b/user/themes/bulma-portfolio/_demo/pages/01.home/_screenshots/06.jpg differ diff --git a/user/themes/bulma-portfolio/_demo/pages/01.home/_screenshots/07-screenshot.jpg b/user/themes/bulma-portfolio/_demo/pages/01.home/_screenshots/07-screenshot.jpg new file mode 100644 index 00000000..b17beb01 Binary files /dev/null and b/user/themes/bulma-portfolio/_demo/pages/01.home/_screenshots/07-screenshot.jpg differ diff --git a/user/themes/bulma-portfolio/_demo/pages/01.home/_screenshots/07.jpg b/user/themes/bulma-portfolio/_demo/pages/01.home/_screenshots/07.jpg new file mode 100644 index 00000000..20a68e3f Binary files /dev/null and b/user/themes/bulma-portfolio/_demo/pages/01.home/_screenshots/07.jpg differ diff --git a/user/themes/bulma-portfolio/_demo/pages/01.home/_screenshots/08-screenshot.jpg b/user/themes/bulma-portfolio/_demo/pages/01.home/_screenshots/08-screenshot.jpg new file mode 100644 index 00000000..ef889736 Binary files /dev/null and b/user/themes/bulma-portfolio/_demo/pages/01.home/_screenshots/08-screenshot.jpg differ diff --git a/user/themes/bulma-portfolio/_demo/pages/01.home/_screenshots/08.jpg b/user/themes/bulma-portfolio/_demo/pages/01.home/_screenshots/08.jpg new file mode 100644 index 00000000..9fa7ee88 Binary files /dev/null and b/user/themes/bulma-portfolio/_demo/pages/01.home/_screenshots/08.jpg differ diff --git a/user/themes/bulma-portfolio/_demo/pages/01.home/_screenshots/screenshots.md b/user/themes/bulma-portfolio/_demo/pages/01.home/_screenshots/screenshots.md new file mode 100644 index 00000000..bd4f3c36 --- /dev/null +++ b/user/themes/bulma-portfolio/_demo/pages/01.home/_screenshots/screenshots.md @@ -0,0 +1,44 @@ +--- +title: Screenshots +hidemenu: false +menu: Screenshots +screenshots: + - image: 01-screenshot.jpg + large_image: 01.jpg + description: Optimised For Design + icon: search + - image: 02-screenshot.jpg + large_image: 02.jpg + description: User Centric Design + icon: search + - image: 03-screenshot.jpg + large_image: 03.jpg + description: Responsive and Adaptive + icon: search + - image: 04-screenshot.jpg + large_image: 04.jpg + description: Absolutely Free + icon: search + - image: 05-screenshot.jpg + large_image: 05.jpg + description: Multi-Purpose Design + icon: search + - image: 06-screenshot.jpg + large_image: 06.jpg + description: Exclusive to Codrops + icon: search + - image: 07-screenshot.jpg + large_image: 07.jpg + description: Made with Love + icon: search + - image: 08-screenshot.jpg + large_image: 08.jpg + description: In Sydney, Australia + icon: search +--- + +# Packed Full of Powerful Features + +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed a lorem quis neque interdum consequat ut sed sem. Duis quis tempor nunc. Interdum et malesuada fames ac ante ipsum primis in faucibus. + +See the screenshots! \ No newline at end of file diff --git a/user/themes/bulma-portfolio/_demo/pages/01.home/_showcase/Spring-Desktop-Backgrounds-HD-2.jpg b/user/themes/bulma-portfolio/_demo/pages/01.home/_showcase/Spring-Desktop-Backgrounds-HD-2.jpg new file mode 100644 index 00000000..46f0293a Binary files /dev/null and b/user/themes/bulma-portfolio/_demo/pages/01.home/_showcase/Spring-Desktop-Backgrounds-HD-2.jpg differ diff --git a/user/themes/bulma-portfolio/_demo/pages/01.home/_showcase/pexels-photo-248797.jpeg b/user/themes/bulma-portfolio/_demo/pages/01.home/_showcase/pexels-photo-248797.jpeg new file mode 100644 index 00000000..5cee9f6a Binary files /dev/null and b/user/themes/bulma-portfolio/_demo/pages/01.home/_showcase/pexels-photo-248797.jpeg differ diff --git a/user/themes/bulma-portfolio/_demo/pages/01.home/_showcase/showcase.md b/user/themes/bulma-portfolio/_demo/pages/01.home/_showcase/showcase.md new file mode 100644 index 00000000..1d3eab57 --- /dev/null +++ b/user/themes/bulma-portfolio/_demo/pages/01.home/_showcase/showcase.md @@ -0,0 +1,27 @@ +--- +title: Showcase +media_order: 'Spring-Desktop-Backgrounds-HD-2.jpg,violet-vector-leaves-circles-backgrounds-for-powerpoint_PdfkI4q.jpg,trolltunga.jpg,pexels-photo-248797.jpeg' +showcase: + - + carousel_item: pexels-photo-248797.jpeg + carousel_title: 'First Image' + carousel_description: 'Lorem, ipsum dolor sit amet consectetur adipisicing elit. Veniam, ab voluptatibus. Iure voluptates nisi excepturi dolores! Quibusdam veritatis expedita, in eos fugiat reprehenderit adipisci, laboriosam, obcaecati dolore nisi soluta iste.' + carousel_link: /contact + - + carousel_item: Spring-Desktop-Backgrounds-HD-2.jpg + carousel_title: 'Second Image' + carousel_description: "Lorem, ipsum dolor sit amet consectetur adipisicing elit. Veniam, ab voluptatibus. Iure voluptates nisi excepturi dolores! Quibusdam veritatis expedita, in eos fugiat reprehenderit adipisci, laboriosam, obcaecati dolore nisi soluta iste." + - + carousel_item: trolltunga.jpg + carousel_title: 'Third Image' + carousel_description: "Lorem, ipsum dolor sit amet consectetur adipisicing elit. Veniam, ab voluptatibus. Iure voluptates nisi excepturi dolores! Quibusdam veritatis expedita, in eos fugiat reprehenderit adipisci, laboriosam, obcaecati dolore nisi soluta iste." + - + carousel_item: violet-vector-leaves-circles-backgrounds-for-powerpoint_PdfkI4q.jpg + carousel_title: 'Fourth Image' + carousel_description: "Lorem, ipsum dolor sit amet consectetur adipisicing elit. Veniam, ab voluptatibus. Iure voluptates nisi excepturi dolores! Quibusdam veritatis expedita, in eos fugiat reprehenderit adipisci, laboriosam, obcaecati dolore nisi soluta iste." + carousel_link: 'https://google.com' +--- + +# Showcase your Product or Service + +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed a lorem quis neque interdum consequat ut sed sem. Duis quis tempor nunc. Interdum et malesuada fames ac ante ipsum primis in faucibus. \ No newline at end of file diff --git a/user/themes/bulma-portfolio/_demo/pages/01.home/_showcase/trolltunga.jpg b/user/themes/bulma-portfolio/_demo/pages/01.home/_showcase/trolltunga.jpg new file mode 100644 index 00000000..39b48c96 Binary files /dev/null and b/user/themes/bulma-portfolio/_demo/pages/01.home/_showcase/trolltunga.jpg differ diff --git a/user/themes/bulma-portfolio/_demo/pages/01.home/_showcase/violet-vector-leaves-circles-backgrounds-for-powerpoint_PdfkI4q.jpg b/user/themes/bulma-portfolio/_demo/pages/01.home/_showcase/violet-vector-leaves-circles-backgrounds-for-powerpoint_PdfkI4q.jpg new file mode 100644 index 00000000..0f9d088c Binary files /dev/null and b/user/themes/bulma-portfolio/_demo/pages/01.home/_showcase/violet-vector-leaves-circles-backgrounds-for-powerpoint_PdfkI4q.jpg differ diff --git a/user/themes/bulma-portfolio/_demo/pages/01.home/_video/493663023.mp4 b/user/themes/bulma-portfolio/_demo/pages/01.home/_video/493663023.mp4 new file mode 100644 index 00000000..cbc12f01 Binary files /dev/null and b/user/themes/bulma-portfolio/_demo/pages/01.home/_video/493663023.mp4 differ diff --git a/user/themes/bulma-portfolio/_demo/pages/01.home/_video/nature_backgrounds_amazing_background_cover_7052.jpg b/user/themes/bulma-portfolio/_demo/pages/01.home/_video/nature_backgrounds_amazing_background_cover_7052.jpg new file mode 100644 index 00000000..f75abca4 Binary files /dev/null and b/user/themes/bulma-portfolio/_demo/pages/01.home/_video/nature_backgrounds_amazing_background_cover_7052.jpg differ diff --git a/user/themes/bulma-portfolio/_demo/pages/01.home/_video/video.md b/user/themes/bulma-portfolio/_demo/pages/01.home/_video/video.md new file mode 100644 index 00000000..16b8d728 --- /dev/null +++ b/user/themes/bulma-portfolio/_demo/pages/01.home/_video/video.md @@ -0,0 +1,21 @@ +--- +title: Video +media_order: '493663023.mp4,nature_backgrounds_amazing_background_cover_7052.jpg' +video_url: 493663023.mp4 +video_thumb: nature_backgrounds_amazing_background_cover_7052.jpg +--- + +# Pennis Cretaei admissa si vimine stipite + +## Iam imago studio obsessos me ferro si + +Lorem markdownum madefacta tamen, inquit barbam accepisse quamquam tantis +mortalia haec. Repugnat Ditis ambiguum tulerunt premunt moti **ullis Lapithae**, +est. Esset Aestas nunc nec vires, gestare fuit animus ad frenis crinitas. + +- Magnorum corpora +- Novitate vivusque +- Tyrannidis frontem cumque nigris aevo +- Claris Siculo posita genetrix enixa manebo +- Percussere equidem tamquam +- Audeat suos \ No newline at end of file diff --git a/user/themes/bulma-portfolio/_demo/pages/01.home/logo-johnmica.svg b/user/themes/bulma-portfolio/_demo/pages/01.home/logo-johnmica.svg new file mode 100644 index 00000000..9c73a43f --- /dev/null +++ b/user/themes/bulma-portfolio/_demo/pages/01.home/logo-johnmica.svg @@ -0,0 +1,127 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/_demo/pages/01.home/modular.md b/user/themes/bulma-portfolio/_demo/pages/01.home/modular.md new file mode 100644 index 00000000..3729d84e --- /dev/null +++ b/user/themes/bulma-portfolio/_demo/pages/01.home/modular.md @@ -0,0 +1,23 @@ +--- +title: Welcome +media_order: logo-johnmica.svg +content: + items: '@self.modular' + order: + by: default + dir: asc + custom: + - _landing + - _portfolio + - _video + - _clients + - _featureslist + - _showcase + - _screenshots + - _contact +menu: Home +--- + +### This is my little playground + +Anytime you play, you win some happines \ No newline at end of file diff --git a/user/themes/bulma-portfolio/_demo/pages/01.home/thanks/default.md b/user/themes/bulma-portfolio/_demo/pages/01.home/thanks/default.md new file mode 100644 index 00000000..aafddff8 --- /dev/null +++ b/user/themes/bulma-portfolio/_demo/pages/01.home/thanks/default.md @@ -0,0 +1,7 @@ +--- +title: 'Thank you !' +--- + +Your email was sent. Thank you ! + +click [here](/?classes=button,is-info,is-outlined,is-inline,home-link) to go back home \ No newline at end of file diff --git a/user/themes/bulma-portfolio/assets/normal-view.png b/user/themes/bulma-portfolio/assets/normal-view.png new file mode 100644 index 00000000..56fecc05 Binary files /dev/null and b/user/themes/bulma-portfolio/assets/normal-view.png differ diff --git a/user/themes/bulma-portfolio/blueprints.yaml b/user/themes/bulma-portfolio/blueprints.yaml new file mode 100644 index 00000000..f0df80fb --- /dev/null +++ b/user/themes/bulma-portfolio/blueprints.yaml @@ -0,0 +1,71 @@ +name: Bulma Portfolio +version: 0.1.7 +description: Bulma Portfolio Theme +icon: rebel +author: + name: John Mica + email: john@johnmica.me +homepage: https://github.com/JohnMica/grav-theme-bulma-portfolio +# demo: http://demo.yoursite.com +keywords: grav, theme, etc +bugs: https://github.com/JohnMica/grav-theme-bulma-portfolio/issues +readme: https://github.com/JohnMica/grav-theme-bulma-portfolio/blob/develop/README.md +license: MIT + +form: + validation: loose + fields: + fixed.navigation: + type: toggle + label: Fixed Navigation + highlight: 1 + default: 0 + options: + 1: PLUGIN_ADMIN.ENABLED + 0: PLUGIN_ADMIN.DISABLED + validate: + type: bool + + theme.upload_image: + type: file + label: Upload Images + destination: 'theme@:/assets' + autofocus: false + multiple: true + random_name: false + avoid_overwriting: false + limit: 5 + accept: + - image/* + theme.logo: + type: filepicker + folder: 'theme@:/assets' + label: Chose Theme Logo + preview_images: true + accept: + - .svg + - .png + - .jpg + - .jpeg + theme.favicon: + type: filepicker + folder: 'theme@:/assets' + label: Theme Favicon + preview_images: true + accept: + - .jpg + - .png + - .jpeg + footer.copyright: + type: text + label: Footer Copyright + footer.icon: + type: list + label: Footer Icons + fields: + .name: + type: iconpicker + label: pick icon + .link: + type: text + label: link diff --git a/user/themes/bulma-portfolio/blueprints/modular/clients.yaml b/user/themes/bulma-portfolio/blueprints/modular/clients.yaml new file mode 100644 index 00000000..3f7bc95f --- /dev/null +++ b/user/themes/bulma-portfolio/blueprints/modular/clients.yaml @@ -0,0 +1,30 @@ +title: Clients Slider +'@extends': default + +form: + fields: + tabs: + fields: + content: + fields: + header.slider: + type: list + label: Create Slider by adding items + fields: + .feature_img: + type: filepicker + label: feature image + preview_images: true + .feature_title: + type: text + label: The header of the slider + .feature_subtitle: + type: text + label: subtitle of slider + .feature_link: + type: text + label: where does this slide link to + .feature_link_text: + type: text + label: the button text + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/blueprints/modular/features.yaml b/user/themes/bulma-portfolio/blueprints/modular/features.yaml new file mode 100644 index 00000000..55676d5e --- /dev/null +++ b/user/themes/bulma-portfolio/blueprints/modular/features.yaml @@ -0,0 +1,28 @@ +title: Feature Icons +'@extends': default + +form: + fields: + tabs: + fields: + content: + fields: + header.features: + type: list + label: Features + fields: + .icons: + type: iconpicker + label: Feature Icon + .title: + type: text + label: Feature title + .text: + type: textarea + label: Feature Text + .link: + type: text + label: Feature link + .link_text: + type: text + label: Button Text diff --git a/user/themes/bulma-portfolio/blueprints/modular/landing.yaml b/user/themes/bulma-portfolio/blueprints/modular/landing.yaml new file mode 100644 index 00000000..1b0d3d60 --- /dev/null +++ b/user/themes/bulma-portfolio/blueprints/modular/landing.yaml @@ -0,0 +1,14 @@ +title: Landing Image +'@extends': default + +form: + fields: + tabs: + fields: + content: + fields: + header.banner_img: + type: filepicker + preview_images: true + label: Landing Image + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/blueprints/modular/portfolio.yaml b/user/themes/bulma-portfolio/blueprints/modular/portfolio.yaml new file mode 100644 index 00000000..ee48edb4 --- /dev/null +++ b/user/themes/bulma-portfolio/blueprints/modular/portfolio.yaml @@ -0,0 +1,39 @@ +title: Portfolio +'@extends': default + +form: + fields: + tabs: + fields: + content: + fields: + header.portfolio: + type: list + label: Portfolio + fields: + .project_img: + type: filepicker + label: Project image + preview_images: true + .project_title: + type: text + label: Project title + .project_description: + type: textarea + label: Project Description + .project_link: + type: text + label: Project Link + .project_date: + type: date + label: When project was launched + .project_work: + type: selectize + class: fancy + label: What type of work was done + size: large + validate: + type: commalist + .project_client: + type: text + label: Client's name \ No newline at end of file diff --git a/user/themes/bulma-portfolio/blueprints/modular/showcase.yaml b/user/themes/bulma-portfolio/blueprints/modular/showcase.yaml new file mode 100644 index 00000000..3ad17649 --- /dev/null +++ b/user/themes/bulma-portfolio/blueprints/modular/showcase.yaml @@ -0,0 +1,26 @@ +title: Showcase +'@extends': default + +form: + fields: + tabs: + fields: + content: + fields: + header.showcase: + type: list + label: Showcase Carousel + fields: + .carousel_item: + type: filepicker + label: Carousel image + preview_images: true + .carousel_title: + type: text + label: Carousel title + .carousel_description: + type: textarea + label: Carousel Description + .carousel_link: + type: text + label: Carousel Link \ No newline at end of file diff --git a/user/themes/bulma-portfolio/blueprints/modular/spotlight.yaml b/user/themes/bulma-portfolio/blueprints/modular/spotlight.yaml new file mode 100644 index 00000000..effb8e56 --- /dev/null +++ b/user/themes/bulma-portfolio/blueprints/modular/spotlight.yaml @@ -0,0 +1,14 @@ +title: Banner Image +'@extends': default + +form: + fields: + tabs: + fields: + content: + fields: + header.bannerimg: + type: filepicker + preview_images: true + label: Banner Image + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/blueprints/modular/video.yaml b/user/themes/bulma-portfolio/blueprints/modular/video.yaml new file mode 100644 index 00000000..8749597c --- /dev/null +++ b/user/themes/bulma-portfolio/blueprints/modular/video.yaml @@ -0,0 +1,18 @@ +title: Video +'@extends': default + +form: + fields: + tabs: + fields: + content: + fields: + header.video_url: + type: filepicker + preview_images: false + label: Video + header.video_thumb: + type: filepicker + preview_images: true + label: Video Background Image + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/bulma-portfolio.php b/user/themes/bulma-portfolio/bulma-portfolio.php new file mode 100644 index 00000000..3de0bf51 --- /dev/null +++ b/user/themes/bulma-portfolio/bulma-portfolio.php @@ -0,0 +1,9 @@ +.control { + -ms-flex-negative: 0; + flex-shrink: 0; +} + +.field.is-grouped>.control:not(:last-child) { + margin-bottom: 0; + margin-right: 0.75rem; +} + +.field.is-grouped>.control.is-expanded { + -webkit-box-flex: 1; + -ms-flex-positive: 1; + flex-grow: 1; + -ms-flex-negative: 1; + flex-shrink: 1; +} + +.field.is-grouped.is-grouped-centered { + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; +} + +.field.is-grouped.is-grouped-right { + -webkit-box-pack: end; + -ms-flex-pack: end; + justify-content: flex-end; +} + +.field.is-grouped.is-grouped-multiline { + -ms-flex-wrap: wrap; + flex-wrap: wrap; +} + +.field.is-grouped.is-grouped-multiline>.control:last-child, +.field.is-grouped.is-grouped-multiline>.control:not(:last-child) { + margin-bottom: 0.75rem; +} + +.field.is-grouped.is-grouped-multiline:last-child { + margin-bottom: -0.75rem; +} + +.field.is-grouped.is-grouped-multiline:not(:last-child) { + margin-bottom: 0; +} + +@media screen and (min-width: 769px), +print { + .field.is-horizontal { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + } +} + +.field-label .label { + font-size: inherit; +} + +@media screen and (max-width: 768px) { + .field-label { + margin-bottom: 0.5rem; + } +} + +@media screen and (min-width: 769px), +print { + .field-label { + -ms-flex-preferred-size: 0; + flex-basis: 0; + -webkit-box-flex: 1; + -ms-flex-positive: 1; + flex-grow: 1; + -ms-flex-negative: 0; + flex-shrink: 0; + margin-right: 1.5rem; + text-align: right; + } + .field-label.is-small { + font-size: 0.75rem; + padding-top: 0.375em; + } + .field-label.is-normal { + padding-top: 0.375em; + } + .field-label.is-medium { + font-size: 1.25rem; + padding-top: 0.375em; + } + .field-label.is-large { + font-size: 1.5rem; + padding-top: 0.375em; + } +} + +.field-body .field .field { + margin-bottom: 0; +} + +@media screen and (min-width: 769px), +print { + .field-body { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -ms-flex-preferred-size: 0; + flex-basis: 0; + -webkit-box-flex: 5; + -ms-flex-positive: 5; + flex-grow: 5; + -ms-flex-negative: 1; + flex-shrink: 1; + } + .field-body .field { + margin-bottom: 0; + } + .field-body>.field { + -ms-flex-negative: 1; + flex-shrink: 1; + } + .field-body>.field:not(.is-narrow) { + -webkit-box-flex: 1; + -ms-flex-positive: 1; + flex-grow: 1; + } + .field-body>.field:not(:last-child) { + margin-right: 0.75rem; + } +} + +.control { + font-size: 1rem; + position: relative; + text-align: left; +} + +.control.has-icon .icon { + color: #dbdbdb; + height: 2.25em; + pointer-events: none; + position: absolute; + top: 0; + width: 2.25em; + z-index: 4; +} + +.control.has-icon .input:focus+.icon { + color: #7a7a7a; +} + +.control.has-icon .input.is-small+.icon { + font-size: 0.75rem; +} + +.control.has-icon .input.is-medium+.icon { + font-size: 1.25rem; +} + +.control.has-icon .input.is-large+.icon { + font-size: 1.5rem; +} + +.control.has-icon:not(.has-icon-right) .icon { + left: 0; +} + +.control.has-icon:not(.has-icon-right) .input { + padding-left: 2.25em; +} + +.control.has-icon.has-icon-right .icon { + right: 0; +} + +.control.has-icon.has-icon-right .input { + padding-right: 2.25em; +} + +.control.has-icons-left .input:focus~.icon, +.control.has-icons-left .select:focus~.icon, +.control.has-icons-right .input:focus~.icon, +.control.has-icons-right .select:focus~.icon { + color: #7a7a7a; +} + +.control.has-icons-left .input.is-small~.icon, +.control.has-icons-left .select.is-small~.icon, +.control.has-icons-right .input.is-small~.icon, +.control.has-icons-right .select.is-small~.icon { + font-size: 0.75rem; +} + +.control.has-icons-left .input.is-medium~.icon, +.control.has-icons-left .select.is-medium~.icon, +.control.has-icons-right .input.is-medium~.icon, +.control.has-icons-right .select.is-medium~.icon { + font-size: 1.25rem; +} + +.control.has-icons-left .input.is-large~.icon, +.control.has-icons-left .select.is-large~.icon, +.control.has-icons-right .input.is-large~.icon, +.control.has-icons-right .select.is-large~.icon { + font-size: 1.5rem; +} + +.control.has-icons-left .icon, +.control.has-icons-right .icon { + color: #dbdbdb; + height: 2.25em; + pointer-events: none; + position: absolute; + top: 0; + width: 2.25em; + z-index: 4; +} + +.control.has-icons-left .input, +.control.has-icons-left .select select { + padding-left: 2.25em; +} + +.control.has-icons-left .icon.is-left { + left: 0; +} + +.control.has-icons-right .input, +.control.has-icons-right .select select { + padding-right: 2.25em; +} + +.control.has-icons-right .icon.is-right { + right: 0; +} + +.control.is-loading::after { + -webkit-animation: spinAround 500ms infinite linear; + animation: spinAround 500ms infinite linear; + border: 2px solid #dbdbdb; + border-radius: 290486px; + border-right-color: transparent; + border-top-color: transparent; + content: ""; + display: block; + height: 1em; + position: relative; + width: 1em; + position: absolute !important; + right: 0.625em; + top: 0.625em; + z-index: 4; +} + +.control.is-loading.is-small:after { + font-size: 0.75rem; +} + +.control.is-loading.is-medium:after { + font-size: 1.25rem; +} + +.control.is-loading.is-large:after { + font-size: 1.5rem; +} + +.icon { + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + display: -webkit-inline-box; + display: -ms-inline-flexbox; + display: inline-flex; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + height: 1.5rem; + width: 1.5rem; +} + +.icon.is-small { + height: 1rem; + width: 1rem; +} + +.icon.is-medium { + height: 2rem; + width: 2rem; +} + +.icon.is-large { + height: 3rem; + width: 3rem; +} + +.image { + display: block; + position: relative; +} + +.image img { + display: block; + height: auto; + width: 100%; +} + +.image img.is-rounded { + border-radius: 290486px; +} + +.image.is-square img, +.image.is-1by1 img, +.image.is-4by3 img, +.image.is-3by2 img, +.image.is-16by9 img, +.image.is-2by1 img { + bottom: 0; + left: 0; + position: absolute; + right: 0; + top: 0; + height: 100%; + width: 100%; +} + +.image.is-square, +.image.is-1by1 { + padding-top: 100%; +} + +.image.is-4by3 { + padding-top: 75%; +} + +.image.is-3by2 { + padding-top: 66.6666%; +} + +.image.is-16by9 { + padding-top: 56.25%; +} + +.image.is-2by1 { + padding-top: 50%; +} + +.image.is-16x16 { + height: 16px; + width: 16px; +} + +.image.is-24x24 { + height: 24px; + width: 24px; +} + +.image.is-32x32 { + height: 32px; + width: 32px; +} + +.image.is-48x48 { + height: 48px; + width: 48px; +} + +.image.is-64x64 { + height: 64px; + width: 64px; +} + +.image.is-96x96 { + height: 96px; + width: 96px; +} + +.image.is-128x128 { + height: 128px; + width: 128px; +} + +.notification { + background-color: whitesmoke; + border-radius: 3px; + padding: 1.25rem 2.5rem 1.25rem 1.5rem; + position: relative; +} + +.notification:not(:last-child) { + margin-bottom: 1.5rem; +} + +.notification a:not(.button) { + color: currentColor; + text-decoration: underline; +} + +.notification strong { + color: currentColor; +} + +.notification code, +.notification pre { + background: white; +} + +.notification pre code { + background: transparent; +} + +.notification>.delete { + position: absolute; + right: 0.5rem; + top: 0.5rem; +} + +.notification .title, +.notification .subtitle, +.notification .content { + color: currentColor; +} + +.notification.is-white { + background-color: white; + color: #0a0a0a; +} + +.notification.is-black { + background-color: #0a0a0a; + color: white; +} + +.notification.is-light { + background-color: whitesmoke; + color: #363636; +} + +.notification.is-dark { + background-color: #363636; + color: whitesmoke; +} + +.notification.is-primary { + background-color: #00d1b2; + color: #fff; +} + +.notification.is-link { + background-color: #3273dc; + color: #fff; +} + +.notification.is-info { + background-color: #209cee; + color: #fff; +} + +.notification.is-success { + background-color: #23d160; + color: #fff; +} + +.notification.is-warning { + background-color: #ffdd57; + color: rgba(0, 0, 0, 0.7); +} + +.notification.is-danger { + background-color: #ff3860; + color: #fff; +} + +.progress { + -moz-appearance: none; + -webkit-appearance: none; + border: none; + border-radius: 290486px; + display: block; + height: 1rem; + overflow: hidden; + padding: 0; + width: 100%; +} + +.progress:not(:last-child) { + margin-bottom: 1.5rem; +} + +.progress::-webkit-progress-bar { + background-color: #dbdbdb; +} + +.progress::-webkit-progress-value { + background-color: #4a4a4a; +} + +.progress::-moz-progress-bar { + background-color: #4a4a4a; +} + +.progress::-ms-fill { + background-color: #4a4a4a; + border: none; +} + +.progress.is-white::-webkit-progress-value { + background-color: white; +} + +.progress.is-white::-moz-progress-bar { + background-color: white; +} + +.progress.is-white::-ms-fill { + background-color: white; +} + +.progress.is-black::-webkit-progress-value { + background-color: #0a0a0a; +} + +.progress.is-black::-moz-progress-bar { + background-color: #0a0a0a; +} + +.progress.is-black::-ms-fill { + background-color: #0a0a0a; +} + +.progress.is-light::-webkit-progress-value { + background-color: whitesmoke; +} + +.progress.is-light::-moz-progress-bar { + background-color: whitesmoke; +} + +.progress.is-light::-ms-fill { + background-color: whitesmoke; +} + +.progress.is-dark::-webkit-progress-value { + background-color: #363636; +} + +.progress.is-dark::-moz-progress-bar { + background-color: #363636; +} + +.progress.is-dark::-ms-fill { + background-color: #363636; +} + +.progress.is-primary::-webkit-progress-value { + background-color: #00d1b2; +} + +.progress.is-primary::-moz-progress-bar { + background-color: #00d1b2; +} + +.progress.is-primary::-ms-fill { + background-color: #00d1b2; +} + +.progress.is-link::-webkit-progress-value { + background-color: #3273dc; +} + +.progress.is-link::-moz-progress-bar { + background-color: #3273dc; +} + +.progress.is-link::-ms-fill { + background-color: #3273dc; +} + +.progress.is-info::-webkit-progress-value { + background-color: #209cee; +} + +.progress.is-info::-moz-progress-bar { + background-color: #209cee; +} + +.progress.is-info::-ms-fill { + background-color: #209cee; +} + +.progress.is-success::-webkit-progress-value { + background-color: #23d160; +} + +.progress.is-success::-moz-progress-bar { + background-color: #23d160; +} + +.progress.is-success::-ms-fill { + background-color: #23d160; +} + +.progress.is-warning::-webkit-progress-value { + background-color: #ffdd57; +} + +.progress.is-warning::-moz-progress-bar { + background-color: #ffdd57; +} + +.progress.is-warning::-ms-fill { + background-color: #ffdd57; +} + +.progress.is-danger::-webkit-progress-value { + background-color: #ff3860; +} + +.progress.is-danger::-moz-progress-bar { + background-color: #ff3860; +} + +.progress.is-danger::-ms-fill { + background-color: #ff3860; +} + +.progress.is-small { + height: 0.75rem; +} + +.progress.is-medium { + height: 1.25rem; +} + +.progress.is-large { + height: 1.5rem; +} + +.table { + background-color: white; + color: #363636; + margin-bottom: 1.5rem; +} + +.table td, +.table th { + border: 1px solid #dbdbdb; + border-width: 0 0 1px; + padding: 0.5em 0.75em; + vertical-align: top; +} + +.table td.is-white, +.table th.is-white { + background-color: white; + border-color: white; + color: #0a0a0a; +} + +.table td.is-black, +.table th.is-black { + background-color: #0a0a0a; + border-color: #0a0a0a; + color: white; +} + +.table td.is-light, +.table th.is-light { + background-color: whitesmoke; + border-color: whitesmoke; + color: #363636; +} + +.table td.is-dark, +.table th.is-dark { + background-color: #363636; + border-color: #363636; + color: whitesmoke; +} + +.table td.is-primary, +.table th.is-primary { + background-color: #00d1b2; + border-color: #00d1b2; + color: #fff; +} + +.table td.is-link, +.table th.is-link { + background-color: #3273dc; + border-color: #3273dc; + color: #fff; +} + +.table td.is-info, +.table th.is-info { + background-color: #209cee; + border-color: #209cee; + color: #fff; +} + +.table td.is-success, +.table th.is-success { + background-color: #23d160; + border-color: #23d160; + color: #fff; +} + +.table td.is-warning, +.table th.is-warning { + background-color: #ffdd57; + border-color: #ffdd57; + color: rgba(0, 0, 0, 0.7); +} + +.table td.is-danger, +.table th.is-danger { + background-color: #ff3860; + border-color: #ff3860; + color: #fff; +} + +.table td.is-narrow, +.table th.is-narrow { + white-space: nowrap; + width: 1%; +} + +.table td.is-selected, +.table th.is-selected { + background-color: #00d1b2; + color: #fff; +} + +.table td.is-selected a, +.table td.is-selected strong, +.table th.is-selected a, +.table th.is-selected strong { + color: currentColor; +} + +.table th { + color: #363636; + text-align: left; +} + +.table tr.is-selected { + background-color: #00d1b2; + color: #fff; +} + +.table tr.is-selected a, +.table tr.is-selected strong { + color: currentColor; +} + +.table tr.is-selected td, +.table tr.is-selected th { + border-color: #fff; + color: currentColor; +} + +.table thead td, +.table thead th { + border-width: 0 0 2px; + color: #363636; +} + +.table tfoot td, +.table tfoot th { + border-width: 2px 0 0; + color: #363636; +} + +.table tbody tr:last-child td, +.table tbody tr:last-child th { + border-bottom-width: 0; +} + +.table.is-bordered td, +.table.is-bordered th { + border-width: 1px; +} + +.table.is-bordered tr:last-child td, +.table.is-bordered tr:last-child th { + border-bottom-width: 1px; +} + +.table.is-fullwidth { + width: 100%; +} + +.table.is-hoverable tbody tr:not(.is-selected):hover { + background-color: #fafafa; +} + +.table.is-hoverable.is-striped tbody tr:not(.is-selected):hover { + background-color: whitesmoke; +} + +.table.is-narrow td, +.table.is-narrow th { + padding: 0.25em 0.5em; +} + +.table.is-striped tbody tr:not(.is-selected):nth-child(even) { + background-color: #fafafa; +} + +.tags { + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -ms-flex-wrap: wrap; + flex-wrap: wrap; + -webkit-box-pack: start; + -ms-flex-pack: start; + justify-content: flex-start; +} + +.tags .tag { + margin-bottom: 0.5rem; +} + +.tags .tag:not(:last-child) { + margin-right: 0.5rem; +} + +.tags:last-child { + margin-bottom: -0.5rem; +} + +.tags:not(:last-child) { + margin-bottom: 1rem; +} + +.tags.has-addons .tag { + margin-right: 0; +} + +.tags.has-addons .tag:not(:first-child) { + border-bottom-left-radius: 0; + border-top-left-radius: 0; +} + +.tags.has-addons .tag:not(:last-child) { + border-bottom-right-radius: 0; + border-top-right-radius: 0; +} + +.tags.is-centered { + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; +} + +.tags.is-centered .tag { + margin-right: 0.25rem; + margin-left: 0.25rem; +} + +.tags.is-right { + -webkit-box-pack: end; + -ms-flex-pack: end; + justify-content: flex-end; +} + +.tags.is-right .tag:not(:first-child) { + margin-left: 0.5rem; +} + +.tags.is-right .tag:not(:last-child) { + margin-right: 0; +} + +.tag:not(body) { + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + background-color: whitesmoke; + border-radius: 3px; + color: #4a4a4a; + display: -webkit-inline-box; + display: -ms-inline-flexbox; + display: inline-flex; + font-size: 0.75rem; + height: 2em; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + line-height: 1.5; + padding-left: 0.75em; + padding-right: 0.75em; + white-space: nowrap; +} + +.tag:not(body) .delete { + margin-left: 0.25em; + margin-right: -0.375em; +} + +.tag:not(body).is-white { + background-color: white; + color: #0a0a0a; +} + +.tag:not(body).is-black { + background-color: #0a0a0a; + color: white; +} + +.tag:not(body).is-light { + background-color: whitesmoke; + color: #363636; +} + +.tag:not(body).is-dark { + background-color: #363636; + color: whitesmoke; +} + +.tag:not(body).is-primary { + background-color: #00d1b2; + color: #fff; +} + +.tag:not(body).is-link { + background-color: #3273dc; + color: #fff; +} + +.tag:not(body).is-info { + background-color: #209cee; + color: #fff; +} + +.tag:not(body).is-success { + background-color: #23d160; + color: #fff; +} + +.tag:not(body).is-warning { + background-color: #ffdd57; + color: rgba(0, 0, 0, 0.7); +} + +.tag:not(body).is-danger { + background-color: #ff3860; + color: #fff; +} + +.tag:not(body).is-medium { + font-size: 1rem; +} + +.tag:not(body).is-large { + font-size: 1.25rem; +} + +.tag:not(body) .icon:first-child:not(:last-child) { + margin-left: -0.375em; + margin-right: 0.1875em; +} + +.tag:not(body) .icon:last-child:not(:first-child) { + margin-left: 0.1875em; + margin-right: -0.375em; +} + +.tag:not(body) .icon:first-child:last-child { + margin-left: -0.375em; + margin-right: -0.375em; +} + +.tag:not(body).is-delete { + margin-left: 1px; + padding: 0; + position: relative; + width: 2em; +} + +.tag:not(body).is-delete:before, +.tag:not(body).is-delete:after { + background-color: currentColor; + content: ""; + display: block; + left: 50%; + position: absolute; + top: 50%; + -webkit-transform: translateX(-50%) translateY(-50%) rotate(45deg); + transform: translateX(-50%) translateY(-50%) rotate(45deg); + -webkit-transform-origin: center center; + transform-origin: center center; +} + +.tag:not(body).is-delete:before { + height: 1px; + width: 50%; +} + +.tag:not(body).is-delete:after { + height: 50%; + width: 1px; +} + +.tag:not(body).is-delete:hover, +.tag:not(body).is-delete:focus { + background-color: #e8e8e8; +} + +.tag:not(body).is-delete:active { + background-color: #dbdbdb; +} + +.tag:not(body).is-rounded { + border-radius: 290486px; +} + +a.tag:hover { + text-decoration: underline; +} + +.title, +.subtitle { + word-break: break-word; +} + +.title:not(:last-child), +.subtitle:not(:last-child) { + margin-bottom: 1.5rem; +} + +.title em, +.title span, +.subtitle em, +.subtitle span { + font-weight: inherit; +} + +.title sub, +.subtitle sub { + font-size: 0.75em; +} + +.title sup, +.subtitle sup { + font-size: 0.75em; +} + +.title .tag, +.subtitle .tag { + vertical-align: middle; +} + +.title { + color: #363636; + font-size: 2rem; + font-weight: 600; + line-height: 1.125; +} + +.title strong { + color: inherit; + font-weight: inherit; +} + +.title+.highlight { + margin-top: -0.75rem; +} + +.title:not(.is-spaced)+.subtitle { + margin-top: -1.5rem; +} + +.title.is-1 { + font-size: 3rem; +} + +.title.is-2 { + font-size: 2.5rem; +} + +.title.is-3 { + font-size: 2rem; +} + +.title.is-4 { + font-size: 1.5rem; +} + +.title.is-5 { + font-size: 1.25rem; +} + +.title.is-6 { + font-size: 1rem; +} + +.title.is-7 { + font-size: 0.75rem; +} + +.subtitle { + color: #4a4a4a; + font-size: 1.25rem; + font-weight: 400; + line-height: 1.25; +} + +.subtitle strong { + color: #363636; + font-weight: 600; +} + +.subtitle:not(.is-spaced)+.title { + margin-top: -1.5rem; +} + +.subtitle.is-1 { + font-size: 3rem; +} + +.subtitle.is-2 { + font-size: 2.5rem; +} + +.subtitle.is-3 { + font-size: 2rem; +} + +.subtitle.is-4 { + font-size: 1.5rem; +} + +.subtitle.is-5 { + font-size: 1.25rem; +} + +.subtitle.is-6 { + font-size: 1rem; +} + +.subtitle.is-7 { + font-size: 0.75rem; +} + +.block:not(:last-child) { + margin-bottom: 1.5rem; +} + +.delete { + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + -moz-appearance: none; + -webkit-appearance: none; + background-color: rgba(10, 10, 10, 0.2); + border: none; + border-radius: 290486px; + cursor: pointer; + display: inline-block; + -webkit-box-flex: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + font-size: 0; + height: 20px; + max-height: 20px; + max-width: 20px; + min-height: 20px; + min-width: 20px; + outline: none; + position: relative; + vertical-align: top; + width: 20px; +} + +.delete:before, +.delete:after { + background-color: white; + content: ""; + display: block; + left: 50%; + position: absolute; + top: 50%; + -webkit-transform: translateX(-50%) translateY(-50%) rotate(45deg); + transform: translateX(-50%) translateY(-50%) rotate(45deg); + -webkit-transform-origin: center center; + transform-origin: center center; +} + +.delete:before { + height: 2px; + width: 50%; +} + +.delete:after { + height: 50%; + width: 2px; +} + +.delete:hover, +.delete:focus { + background-color: rgba(10, 10, 10, 0.3); +} + +.delete:active { + background-color: rgba(10, 10, 10, 0.4); +} + +.delete.is-small { + height: 16px; + max-height: 16px; + max-width: 16px; + min-height: 16px; + min-width: 16px; + width: 16px; +} + +.delete.is-medium { + height: 24px; + max-height: 24px; + max-width: 24px; + min-height: 24px; + min-width: 24px; + width: 24px; +} + +.delete.is-large { + height: 32px; + max-height: 32px; + max-width: 32px; + min-height: 32px; + min-width: 32px; + width: 32px; +} + +.heading { + display: block; + font-size: 11px; + letter-spacing: 1px; + margin-bottom: 5px; + text-transform: uppercase; +} + +.highlight { + font-weight: 400; + max-width: 100%; + overflow: hidden; + padding: 0; +} + +.highlight:not(:last-child) { + margin-bottom: 1.5rem; +} + +.highlight pre { + overflow: auto; + max-width: 100%; +} + +.loader { + -webkit-animation: spinAround 500ms infinite linear; + animation: spinAround 500ms infinite linear; + border: 2px solid #dbdbdb; + border-radius: 290486px; + border-right-color: transparent; + border-top-color: transparent; + content: ""; + display: block; + height: 1em; + position: relative; + width: 1em; +} + +.number { + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + background-color: whitesmoke; + border-radius: 290486px; + display: -webkit-inline-box; + display: -ms-inline-flexbox; + display: inline-flex; + font-size: 1.25rem; + height: 2em; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + margin-right: 1.5rem; + min-width: 2.5em; + padding: 0.25rem 0.5rem; + text-align: center; + vertical-align: top; +} + +.breadcrumb { + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + -webkit-box-align: stretch; + -ms-flex-align: stretch; + align-items: stretch; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + font-size: 1rem; + overflow: hidden; + overflow-x: auto; + white-space: nowrap; +} + +.breadcrumb:not(:last-child) { + margin-bottom: 1.5rem; +} + +.breadcrumb a { + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + color: #3273dc; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + padding: 0.5em 0.75em; +} + +.breadcrumb a:hover { + color: #363636; +} + +.breadcrumb li { + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + display: -webkit-box; + display: -ms-flexbox; + display: flex; +} + +.breadcrumb li:first-child a { + padding-left: 0; +} + +.breadcrumb li.is-active a { + color: #363636; + cursor: default; + pointer-events: none; +} + +.breadcrumb li+li::before { + color: #4a4a4a; + content: "\0002f"; +} + +.breadcrumb ul, +.breadcrumb ol { + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-flex: 1; + -ms-flex-positive: 1; + flex-grow: 1; + -ms-flex-negative: 0; + flex-shrink: 0; + -webkit-box-pack: start; + -ms-flex-pack: start; + justify-content: flex-start; +} + +.breadcrumb .icon:first-child { + margin-right: 0.5em; +} + +.breadcrumb .icon:last-child { + margin-left: 0.5em; +} + +.breadcrumb.is-centered ol, +.breadcrumb.is-centered ul { + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; +} + +.breadcrumb.is-right ol, +.breadcrumb.is-right ul { + -webkit-box-pack: end; + -ms-flex-pack: end; + justify-content: flex-end; +} + +.breadcrumb.is-small { + font-size: 0.75rem; +} + +.breadcrumb.is-medium { + font-size: 1.25rem; +} + +.breadcrumb.is-large { + font-size: 1.5rem; +} + +.breadcrumb.has-arrow-separator li+li::before { + content: "\02192"; +} + +.breadcrumb.has-bullet-separator li+li::before { + content: "\02022"; +} + +.breadcrumb.has-dot-separator li+li::before { + content: "\000b7"; +} + +.breadcrumb.has-succeeds-separator li+li::before { + content: "\0227B"; +} + +.card { + background-color: white; + -webkit-box-shadow: 0 2px 3px rgba(10, 10, 10, 0.1), 0 0 0 1px rgba(10, 10, 10, 0.1); + box-shadow: 0 2px 3px rgba(10, 10, 10, 0.1), 0 0 0 1px rgba(10, 10, 10, 0.1); + color: #4a4a4a; + max-width: 100%; + position: relative; +} + +.card-header { + -webkit-box-align: stretch; + -ms-flex-align: stretch; + align-items: stretch; + -webkit-box-shadow: 0 1px 2px rgba(10, 10, 10, 0.1); + box-shadow: 0 1px 2px rgba(10, 10, 10, 0.1); + display: -webkit-box; + display: -ms-flexbox; + display: flex; +} + +.card-header-title { + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + color: #363636; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-flex: 1; + -ms-flex-positive: 1; + flex-grow: 1; + font-weight: 700; + padding: 0.75rem; +} + +.card-header-title.is-centered { + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; +} + +.card-header-icon { + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + cursor: pointer; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + padding: 0.75rem; +} + +.card-image { + display: block; + position: relative; +} + +.card-content { + padding: 1.5rem; +} + +.card-footer { + border-top: 1px solid #dbdbdb; + -webkit-box-align: stretch; + -ms-flex-align: stretch; + align-items: stretch; + display: -webkit-box; + display: -ms-flexbox; + display: flex; +} + +.card-footer-item { + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -ms-flex-preferred-size: 0; + flex-basis: 0; + -webkit-box-flex: 1; + -ms-flex-positive: 1; + flex-grow: 1; + -ms-flex-negative: 0; + flex-shrink: 0; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + padding: 0.75rem; +} + +.card-footer-item:not(:last-child) { + border-right: 1px solid #dbdbdb; +} + +.card .media:not(:last-child) { + margin-bottom: 0.75rem; +} + +.dropdown { + display: -webkit-inline-box; + display: -ms-inline-flexbox; + display: inline-flex; + position: relative; + vertical-align: top; +} + +.dropdown.is-active .dropdown-menu, +.dropdown.is-hoverable:hover .dropdown-menu { + display: block; +} + +.dropdown.is-right .dropdown-menu { + left: auto; + right: 0; +} + +.dropdown.is-up .dropdown-menu { + bottom: 100%; + padding-bottom: 4px; + padding-top: unset; + top: auto; +} + +.dropdown-menu { + display: none; + left: 0; + min-width: 12rem; + padding-top: 4px; + position: absolute; + top: 100%; + z-index: 20; +} + +.dropdown-content { + background-color: white; + border-radius: 3px; + -webkit-box-shadow: 0 2px 3px rgba(10, 10, 10, 0.1), 0 0 0 1px rgba(10, 10, 10, 0.1); + box-shadow: 0 2px 3px rgba(10, 10, 10, 0.1), 0 0 0 1px rgba(10, 10, 10, 0.1); + padding-bottom: 0.5rem; + padding-top: 0.5rem; +} + +.dropdown-item { + color: #4a4a4a; + display: block; + font-size: 0.875rem; + line-height: 1.5; + padding: 0.375rem 1rem; + position: relative; +} + +a.dropdown-item { + padding-right: 3rem; + white-space: nowrap; +} + +a.dropdown-item:hover { + background-color: whitesmoke; + color: #0a0a0a; +} + +a.dropdown-item.is-active { + background-color: #3273dc; + color: #fff; +} + +.dropdown-divider { + background-color: #dbdbdb; + border: none; + display: block; + height: 1px; + margin: 0.5rem 0; +} + +.level { + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: justify; + -ms-flex-pack: justify; + justify-content: space-between; +} + +.level:not(:last-child) { + margin-bottom: 1.5rem; +} + +.level code { + border-radius: 3px; +} + +.level img { + display: inline-block; + vertical-align: top; +} + +.level.is-mobile { + display: -webkit-box; + display: -ms-flexbox; + display: flex; +} + +.level.is-mobile .level-left, +.level.is-mobile .level-right { + display: -webkit-box; + display: -ms-flexbox; + display: flex; +} + +.level.is-mobile .level-left+.level-right { + margin-top: 0; +} + +.level.is-mobile .level-item { + margin-right: 0.75rem; +} + +.level.is-mobile .level-item:not(:last-child) { + margin-bottom: 0; +} + +.level.is-mobile .level-item:not(.is-narrow) { + -webkit-box-flex: 1; + -ms-flex-positive: 1; + flex-grow: 1; +} + +@media screen and (min-width: 769px), +print { + .level { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + } + .level>.level-item:not(.is-narrow) { + -webkit-box-flex: 1; + -ms-flex-positive: 1; + flex-grow: 1; + } +} + +.level-item { + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -ms-flex-preferred-size: auto; + flex-basis: auto; + -webkit-box-flex: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; +} + +.level-item .title, +.level-item .subtitle { + margin-bottom: 0; +} + +@media screen and (max-width: 768px) { + .level-item:not(:last-child) { + margin-bottom: 0.75rem; + } +} + +.level-left, +.level-right { + -ms-flex-preferred-size: auto; + flex-basis: auto; + -webkit-box-flex: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; +} + +.level-left .level-item.is-flexible, +.level-right .level-item.is-flexible { + -webkit-box-flex: 1; + -ms-flex-positive: 1; + flex-grow: 1; +} + +@media screen and (min-width: 769px), +print { + .level-left .level-item:not(:last-child), + .level-right .level-item:not(:last-child) { + margin-right: 0.75rem; + } +} + +.level-left { + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: start; + -ms-flex-pack: start; + justify-content: flex-start; +} + +@media screen and (max-width: 768px) { + .level-left+.level-right { + margin-top: 1.5rem; + } +} + +@media screen and (min-width: 769px), +print { + .level-left { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + } +} + +.level-right { + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: end; + -ms-flex-pack: end; + justify-content: flex-end; +} + +@media screen and (min-width: 769px), +print { + .level-right { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + } +} + +.media { + -webkit-box-align: start; + -ms-flex-align: start; + align-items: flex-start; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + text-align: left; +} + +.media .content:not(:last-child) { + margin-bottom: 0.75rem; +} + +.media .media { + border-top: 1px solid rgba(219, 219, 219, 0.5); + display: -webkit-box; + display: -ms-flexbox; + display: flex; + padding-top: 0.75rem; +} + +.media .media .content:not(:last-child), +.media .media .control:not(:last-child) { + margin-bottom: 0.5rem; +} + +.media .media .media { + padding-top: 0.5rem; +} + +.media .media .media+.media { + margin-top: 0.5rem; +} + +.media+.media { + border-top: 1px solid rgba(219, 219, 219, 0.5); + margin-top: 1rem; + padding-top: 1rem; +} + +.media.is-large+.media { + margin-top: 1.5rem; + padding-top: 1.5rem; +} + +.media-left, +.media-right { + -ms-flex-preferred-size: auto; + flex-basis: auto; + -webkit-box-flex: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; +} + +.media-left { + margin-right: 1rem; +} + +.media-right { + margin-left: 1rem; +} + +.media-content { + -ms-flex-preferred-size: auto; + flex-basis: auto; + -webkit-box-flex: 1; + -ms-flex-positive: 1; + flex-grow: 1; + -ms-flex-negative: 1; + flex-shrink: 1; + overflow: auto; + text-align: left; +} + +.menu { + font-size: 1rem; +} + +.menu.is-small { + font-size: 0.75rem; +} + +.menu.is-medium { + font-size: 1.25rem; +} + +.menu.is-large { + font-size: 1.5rem; +} + +.menu-list { + line-height: 1.25; +} + +.menu-list a { + border-radius: 2px; + color: #4a4a4a; + display: block; + padding: 0.5em 0.75em; +} + +.menu-list a:hover { + background-color: whitesmoke; + color: #363636; +} + +.menu-list a.is-active { + background-color: #3273dc; + color: #fff; +} + +.menu-list li ul { + border-left: 1px solid #dbdbdb; + margin: 0.75em; + padding-left: 0.75em; +} + +.menu-label { + color: #7a7a7a; + font-size: 0.75em; + letter-spacing: 0.1em; + text-transform: uppercase; +} + +.menu-label:not(:first-child) { + margin-top: 1em; +} + +.menu-label:not(:last-child) { + margin-bottom: 1em; +} + +.message { + background-color: whitesmoke; + border-radius: 3px; + font-size: 1rem; +} + +.message:not(:last-child) { + margin-bottom: 1.5rem; +} + +.message strong { + color: currentColor; +} + +.message a:not(.button):not(.tag) { + color: currentColor; + text-decoration: underline; +} + +.message.is-small { + font-size: 0.75rem; +} + +.message.is-medium { + font-size: 1.25rem; +} + +.message.is-large { + font-size: 1.5rem; +} + +.message.is-white { + background-color: white; +} + +.message.is-white .message-header { + background-color: white; + color: #0a0a0a; +} + +.message.is-white .message-body { + border-color: white; + color: #4d4d4d; +} + +.message.is-black { + background-color: #fafafa; +} + +.message.is-black .message-header { + background-color: #0a0a0a; + color: white; +} + +.message.is-black .message-body { + border-color: #0a0a0a; + color: #090909; +} + +.message.is-light { + background-color: #fafafa; +} + +.message.is-light .message-header { + background-color: whitesmoke; + color: #363636; +} + +.message.is-light .message-body { + border-color: whitesmoke; + color: #505050; +} + +.message.is-dark { + background-color: #fafafa; +} + +.message.is-dark .message-header { + background-color: #363636; + color: whitesmoke; +} + +.message.is-dark .message-body { + border-color: #363636; + color: #2a2a2a; +} + +.message.is-primary { + background-color: #f5fffd; +} + +.message.is-primary .message-header { + background-color: #00d1b2; + color: #fff; +} + +.message.is-primary .message-body { + border-color: #00d1b2; + color: #021310; +} + +.message.is-link { + background-color: #f6f9fe; +} + +.message.is-link .message-header { + background-color: #3273dc; + color: #fff; +} + +.message.is-link .message-body { + border-color: #3273dc; + color: #22509a; +} + +.message.is-info { + background-color: #f6fbfe; +} + +.message.is-info .message-header { + background-color: #209cee; + color: #fff; +} + +.message.is-info .message-body { + border-color: #209cee; + color: #12537e; +} + +.message.is-success { + background-color: #f6fef9; +} + +.message.is-success .message-header { + background-color: #23d160; + color: #fff; +} + +.message.is-success .message-body { + border-color: #23d160; + color: #0e301a; +} + +.message.is-warning { + background-color: #fffdf5; +} + +.message.is-warning .message-header { + background-color: #ffdd57; + color: rgba(0, 0, 0, 0.7); +} + +.message.is-warning .message-body { + border-color: #ffdd57; + color: #3b3108; +} + +.message.is-danger { + background-color: #fff5f7; +} + +.message.is-danger .message-header { + background-color: #ff3860; + color: #fff; +} + +.message.is-danger .message-body { + border-color: #ff3860; + color: #cd0930; +} + +.message-header { + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + background-color: #4a4a4a; + border-radius: 3px 3px 0 0; + color: #fff; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: justify; + -ms-flex-pack: justify; + justify-content: space-between; + line-height: 1.25; + padding: 0.5em 0.75em; + position: relative; +} + +.message-header .delete { + -webkit-box-flex: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + margin-left: 0.75em; +} + +.message-header+.message-body { + border-top-left-radius: 0; + border-top-right-radius: 0; + border-top: none; +} + +.message-body { + border: 1px solid #dbdbdb; + border-radius: 3px; + color: #4a4a4a; + padding: 1em 1.25em; +} + +.message-body code, +.message-body pre { + background-color: white; +} + +.message-body pre code { + background-color: transparent; +} + +.modal { + bottom: 0; + left: 0; + position: absolute; + right: 0; + top: 0; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + display: none; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + overflow: hidden; + position: fixed; + z-index: 40; +} + +.modal.is-active { + display: -webkit-box; + display: -ms-flexbox; + display: flex; +} + +.modal-background { + bottom: 0; + left: 0; + position: absolute; + right: 0; + top: 0; + background-color: rgba(10, 10, 10, 0.86); +} + +.modal-content, +.modal-card { + margin: 0 20px; + max-height: calc(100vh - 160px); + overflow: auto; + position: relative; + width: 100%; +} + +@media screen and (min-width: 769px), +print { + .modal-content, + .modal-card { + margin: 0 auto; + max-height: calc(100vh - 40px); + width: 640px; + } +} + +.modal-close { + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + -moz-appearance: none; + -webkit-appearance: none; + background-color: rgba(10, 10, 10, 0.2); + border: none; + border-radius: 290486px; + cursor: pointer; + display: inline-block; + -webkit-box-flex: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + font-size: 0; + height: 20px; + max-height: 20px; + max-width: 20px; + min-height: 20px; + min-width: 20px; + outline: none; + position: relative; + vertical-align: top; + width: 20px; + background: none; + height: 40px; + position: fixed; + right: 20px; + top: 20px; + width: 40px; +} + +.modal-close:before, +.modal-close:after { + background-color: white; + content: ""; + display: block; + left: 50%; + position: absolute; + top: 50%; + -webkit-transform: translateX(-50%) translateY(-50%) rotate(45deg); + transform: translateX(-50%) translateY(-50%) rotate(45deg); + -webkit-transform-origin: center center; + transform-origin: center center; +} + +.modal-close:before { + height: 2px; + width: 50%; +} + +.modal-close:after { + height: 50%; + width: 2px; +} + +.modal-close:hover, +.modal-close:focus { + background-color: rgba(10, 10, 10, 0.3); +} + +.modal-close:active { + background-color: rgba(10, 10, 10, 0.4); +} + +.modal-close.is-small { + height: 16px; + max-height: 16px; + max-width: 16px; + min-height: 16px; + min-width: 16px; + width: 16px; +} + +.modal-close.is-medium { + height: 24px; + max-height: 24px; + max-width: 24px; + min-height: 24px; + min-width: 24px; + width: 24px; +} + +.modal-close.is-large { + height: 32px; + max-height: 32px; + max-width: 32px; + min-height: 32px; + min-width: 32px; + width: 32px; +} + +.modal-card { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; + max-height: calc(100vh - 40px); + overflow: hidden; +} + +.modal-card-head, +.modal-card-foot { + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + background-color: whitesmoke; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -ms-flex-negative: 0; + flex-shrink: 0; + -webkit-box-pack: start; + -ms-flex-pack: start; + justify-content: flex-start; + padding: 20px; + position: relative; +} + +.modal-card-head { + border-bottom: 1px solid #dbdbdb; + border-top-left-radius: 5px; + border-top-right-radius: 5px; +} + +.modal-card-title { + color: #363636; + -webkit-box-flex: 1; + -ms-flex-positive: 1; + flex-grow: 1; + -ms-flex-negative: 0; + flex-shrink: 0; + font-size: 1.5rem; + line-height: 1; +} + +.modal-card-foot { + border-bottom-left-radius: 5px; + border-bottom-right-radius: 5px; + border-top: 1px solid #dbdbdb; +} + +.modal-card-foot .button:not(:last-child) { + margin-right: 10px; +} + +.modal-card-body { + -webkit-overflow-scrolling: touch; + background-color: white; + -webkit-box-flex: 1; + -ms-flex-positive: 1; + flex-grow: 1; + -ms-flex-negative: 1; + flex-shrink: 1; + overflow: auto; + padding: 20px; +} + +.navbar { + background-color: white; + min-height: 3.25rem; + position: relative; +} + +.navbar.is-white { + background-color: white; + color: #0a0a0a; +} + +.navbar.is-white .navbar-brand>.navbar-item, +.navbar.is-white .navbar-brand .navbar-link { + color: #0a0a0a; +} + +.navbar.is-white .navbar-brand>a.navbar-item:hover, +.navbar.is-white .navbar-brand>a.navbar-item.is-active, +.navbar.is-white .navbar-brand .navbar-link:hover, +.navbar.is-white .navbar-brand .navbar-link.is-active { + background-color: #f2f2f2; + color: #0a0a0a; +} + +.navbar.is-white .navbar-brand .navbar-link::after { + border-color: #0a0a0a; +} + +@media screen and (min-width: 1024px) { + .navbar.is-white .navbar-start>.navbar-item, + .navbar.is-white .navbar-start .navbar-link, + .navbar.is-white .navbar-end>.navbar-item, + .navbar.is-white .navbar-end .navbar-link { + color: #0a0a0a; + } + .navbar.is-white .navbar-start>a.navbar-item:hover, + .navbar.is-white .navbar-start>a.navbar-item.is-active, + .navbar.is-white .navbar-start .navbar-link:hover, + .navbar.is-white .navbar-start .navbar-link.is-active, + .navbar.is-white .navbar-end>a.navbar-item:hover, + .navbar.is-white .navbar-end>a.navbar-item.is-active, + .navbar.is-white .navbar-end .navbar-link:hover, + .navbar.is-white .navbar-end .navbar-link.is-active { + background-color: #f2f2f2; + color: #0a0a0a; + } + .navbar.is-white .navbar-start .navbar-link::after, + .navbar.is-white .navbar-end .navbar-link::after { + border-color: #0a0a0a; + } + .navbar.is-white .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-white .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #f2f2f2; + color: #0a0a0a; + } + .navbar.is-white .navbar-dropdown a.navbar-item.is-active { + background-color: white; + color: #0a0a0a; + } +} + +.navbar.is-black { + background-color: #0a0a0a; + color: white; +} + +.navbar.is-black .navbar-brand>.navbar-item, +.navbar.is-black .navbar-brand .navbar-link { + color: white; +} + +.navbar.is-black .navbar-brand>a.navbar-item:hover, +.navbar.is-black .navbar-brand>a.navbar-item.is-active, +.navbar.is-black .navbar-brand .navbar-link:hover, +.navbar.is-black .navbar-brand .navbar-link.is-active { + background-color: black; + color: white; +} + +.navbar.is-black .navbar-brand .navbar-link::after { + border-color: white; +} + +@media screen and (min-width: 1024px) { + .navbar.is-black .navbar-start>.navbar-item, + .navbar.is-black .navbar-start .navbar-link, + .navbar.is-black .navbar-end>.navbar-item, + .navbar.is-black .navbar-end .navbar-link { + color: white; + } + .navbar.is-black .navbar-start>a.navbar-item:hover, + .navbar.is-black .navbar-start>a.navbar-item.is-active, + .navbar.is-black .navbar-start .navbar-link:hover, + .navbar.is-black .navbar-start .navbar-link.is-active, + .navbar.is-black .navbar-end>a.navbar-item:hover, + .navbar.is-black .navbar-end>a.navbar-item.is-active, + .navbar.is-black .navbar-end .navbar-link:hover, + .navbar.is-black .navbar-end .navbar-link.is-active { + background-color: black; + color: white; + } + .navbar.is-black .navbar-start .navbar-link::after, + .navbar.is-black .navbar-end .navbar-link::after { + border-color: white; + } + .navbar.is-black .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-black .navbar-item.has-dropdown.is-active .navbar-link { + background-color: black; + color: white; + } + .navbar.is-black .navbar-dropdown a.navbar-item.is-active { + background-color: #0a0a0a; + color: white; + } +} + +.navbar.is-light { + background-color: whitesmoke; + color: #363636; +} + +.navbar.is-light .navbar-brand>.navbar-item, +.navbar.is-light .navbar-brand .navbar-link { + color: #363636; +} + +.navbar.is-light .navbar-brand>a.navbar-item:hover, +.navbar.is-light .navbar-brand>a.navbar-item.is-active, +.navbar.is-light .navbar-brand .navbar-link:hover, +.navbar.is-light .navbar-brand .navbar-link.is-active { + background-color: #e8e8e8; + color: #363636; +} + +.navbar.is-light .navbar-brand .navbar-link::after { + border-color: #363636; +} + +@media screen and (min-width: 1024px) { + .navbar.is-light .navbar-start>.navbar-item, + .navbar.is-light .navbar-start .navbar-link, + .navbar.is-light .navbar-end>.navbar-item, + .navbar.is-light .navbar-end .navbar-link { + color: #363636; + } + .navbar.is-light .navbar-start>a.navbar-item:hover, + .navbar.is-light .navbar-start>a.navbar-item.is-active, + .navbar.is-light .navbar-start .navbar-link:hover, + .navbar.is-light .navbar-start .navbar-link.is-active, + .navbar.is-light .navbar-end>a.navbar-item:hover, + .navbar.is-light .navbar-end>a.navbar-item.is-active, + .navbar.is-light .navbar-end .navbar-link:hover, + .navbar.is-light .navbar-end .navbar-link.is-active { + background-color: #e8e8e8; + color: #363636; + } + .navbar.is-light .navbar-start .navbar-link::after, + .navbar.is-light .navbar-end .navbar-link::after { + border-color: #363636; + } + .navbar.is-light .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-light .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #e8e8e8; + color: #363636; + } + .navbar.is-light .navbar-dropdown a.navbar-item.is-active { + background-color: whitesmoke; + color: #363636; + } +} + +.navbar.is-dark { + background-color: #363636; + color: whitesmoke; +} + +.navbar.is-dark .navbar-brand>.navbar-item, +.navbar.is-dark .navbar-brand .navbar-link { + color: whitesmoke; +} + +.navbar.is-dark .navbar-brand>a.navbar-item:hover, +.navbar.is-dark .navbar-brand>a.navbar-item.is-active, +.navbar.is-dark .navbar-brand .navbar-link:hover, +.navbar.is-dark .navbar-brand .navbar-link.is-active { + background-color: #292929; + color: whitesmoke; +} + +.navbar.is-dark .navbar-brand .navbar-link::after { + border-color: whitesmoke; +} + +@media screen and (min-width: 1024px) { + .navbar.is-dark .navbar-start>.navbar-item, + .navbar.is-dark .navbar-start .navbar-link, + .navbar.is-dark .navbar-end>.navbar-item, + .navbar.is-dark .navbar-end .navbar-link { + color: whitesmoke; + } + .navbar.is-dark .navbar-start>a.navbar-item:hover, + .navbar.is-dark .navbar-start>a.navbar-item.is-active, + .navbar.is-dark .navbar-start .navbar-link:hover, + .navbar.is-dark .navbar-start .navbar-link.is-active, + .navbar.is-dark .navbar-end>a.navbar-item:hover, + .navbar.is-dark .navbar-end>a.navbar-item.is-active, + .navbar.is-dark .navbar-end .navbar-link:hover, + .navbar.is-dark .navbar-end .navbar-link.is-active { + background-color: #292929; + color: whitesmoke; + } + .navbar.is-dark .navbar-start .navbar-link::after, + .navbar.is-dark .navbar-end .navbar-link::after { + border-color: whitesmoke; + } + .navbar.is-dark .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-dark .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #292929; + color: whitesmoke; + } + .navbar.is-dark .navbar-dropdown a.navbar-item.is-active { + background-color: #363636; + color: whitesmoke; + } +} + +.navbar.is-primary { + background-color: #00d1b2; + color: #fff; +} + +.navbar.is-primary .navbar-brand>.navbar-item, +.navbar.is-primary .navbar-brand .navbar-link { + color: #fff; +} + +.navbar.is-primary .navbar-brand>a.navbar-item:hover, +.navbar.is-primary .navbar-brand>a.navbar-item.is-active, +.navbar.is-primary .navbar-brand .navbar-link:hover, +.navbar.is-primary .navbar-brand .navbar-link.is-active { + background-color: #00b89c; + color: #fff; +} + +.navbar.is-primary .navbar-brand .navbar-link::after { + border-color: #fff; +} + +@media screen and (min-width: 1024px) { + .navbar.is-primary .navbar-start>.navbar-item, + .navbar.is-primary .navbar-start .navbar-link, + .navbar.is-primary .navbar-end>.navbar-item, + .navbar.is-primary .navbar-end .navbar-link { + color: #fff; + } + .navbar.is-primary .navbar-start>a.navbar-item:hover, + .navbar.is-primary .navbar-start>a.navbar-item.is-active, + .navbar.is-primary .navbar-start .navbar-link:hover, + .navbar.is-primary .navbar-start .navbar-link.is-active, + .navbar.is-primary .navbar-end>a.navbar-item:hover, + .navbar.is-primary .navbar-end>a.navbar-item.is-active, + .navbar.is-primary .navbar-end .navbar-link:hover, + .navbar.is-primary .navbar-end .navbar-link.is-active { + background-color: #00b89c; + color: #fff; + } + .navbar.is-primary .navbar-start .navbar-link::after, + .navbar.is-primary .navbar-end .navbar-link::after { + border-color: #fff; + } + .navbar.is-primary .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-primary .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #00b89c; + color: #fff; + } + .navbar.is-primary .navbar-dropdown a.navbar-item.is-active { + background-color: #00d1b2; + color: #fff; + } +} + +.navbar.is-link { + background-color: #3273dc; + color: #fff; +} + +.navbar.is-link .navbar-brand>.navbar-item, +.navbar.is-link .navbar-brand .navbar-link { + color: #fff; +} + +.navbar.is-link .navbar-brand>a.navbar-item:hover, +.navbar.is-link .navbar-brand>a.navbar-item.is-active, +.navbar.is-link .navbar-brand .navbar-link:hover, +.navbar.is-link .navbar-brand .navbar-link.is-active { + background-color: #2366d1; + color: #fff; +} + +.navbar.is-link .navbar-brand .navbar-link::after { + border-color: #fff; +} + +@media screen and (min-width: 1024px) { + .navbar.is-link .navbar-start>.navbar-item, + .navbar.is-link .navbar-start .navbar-link, + .navbar.is-link .navbar-end>.navbar-item, + .navbar.is-link .navbar-end .navbar-link { + color: #fff; + } + .navbar.is-link .navbar-start>a.navbar-item:hover, + .navbar.is-link .navbar-start>a.navbar-item.is-active, + .navbar.is-link .navbar-start .navbar-link:hover, + .navbar.is-link .navbar-start .navbar-link.is-active, + .navbar.is-link .navbar-end>a.navbar-item:hover, + .navbar.is-link .navbar-end>a.navbar-item.is-active, + .navbar.is-link .navbar-end .navbar-link:hover, + .navbar.is-link .navbar-end .navbar-link.is-active { + background-color: #2366d1; + color: #fff; + } + .navbar.is-link .navbar-start .navbar-link::after, + .navbar.is-link .navbar-end .navbar-link::after { + border-color: #fff; + } + .navbar.is-link .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-link .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #2366d1; + color: #fff; + } + .navbar.is-link .navbar-dropdown a.navbar-item.is-active { + background-color: #3273dc; + color: #fff; + } +} + +.navbar.is-info { + background-color: #209cee; + color: #fff; +} + +.navbar.is-info .navbar-brand>.navbar-item, +.navbar.is-info .navbar-brand .navbar-link { + color: #fff; +} + +.navbar.is-info .navbar-brand>a.navbar-item:hover, +.navbar.is-info .navbar-brand>a.navbar-item.is-active, +.navbar.is-info .navbar-brand .navbar-link:hover, +.navbar.is-info .navbar-brand .navbar-link.is-active { + background-color: #118fe4; + color: #fff; +} + +.navbar.is-info .navbar-brand .navbar-link::after { + border-color: #fff; +} + +@media screen and (min-width: 1024px) { + .navbar.is-info .navbar-start>.navbar-item, + .navbar.is-info .navbar-start .navbar-link, + .navbar.is-info .navbar-end>.navbar-item, + .navbar.is-info .navbar-end .navbar-link { + color: #fff; + } + .navbar.is-info .navbar-start>a.navbar-item:hover, + .navbar.is-info .navbar-start>a.navbar-item.is-active, + .navbar.is-info .navbar-start .navbar-link:hover, + .navbar.is-info .navbar-start .navbar-link.is-active, + .navbar.is-info .navbar-end>a.navbar-item:hover, + .navbar.is-info .navbar-end>a.navbar-item.is-active, + .navbar.is-info .navbar-end .navbar-link:hover, + .navbar.is-info .navbar-end .navbar-link.is-active { + background-color: #118fe4; + color: #fff; + } + .navbar.is-info .navbar-start .navbar-link::after, + .navbar.is-info .navbar-end .navbar-link::after { + border-color: #fff; + } + .navbar.is-info .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-info .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #118fe4; + color: #fff; + } + .navbar.is-info .navbar-dropdown a.navbar-item.is-active { + background-color: #209cee; + color: #fff; + } +} + +.navbar.is-success { + background-color: #23d160; + color: #fff; +} + +.navbar.is-success .navbar-brand>.navbar-item, +.navbar.is-success .navbar-brand .navbar-link { + color: #fff; +} + +.navbar.is-success .navbar-brand>a.navbar-item:hover, +.navbar.is-success .navbar-brand>a.navbar-item.is-active, +.navbar.is-success .navbar-brand .navbar-link:hover, +.navbar.is-success .navbar-brand .navbar-link.is-active { + background-color: #20bc56; + color: #fff; +} + +.navbar.is-success .navbar-brand .navbar-link::after { + border-color: #fff; +} + +@media screen and (min-width: 1024px) { + .navbar.is-success .navbar-start>.navbar-item, + .navbar.is-success .navbar-start .navbar-link, + .navbar.is-success .navbar-end>.navbar-item, + .navbar.is-success .navbar-end .navbar-link { + color: #fff; + } + .navbar.is-success .navbar-start>a.navbar-item:hover, + .navbar.is-success .navbar-start>a.navbar-item.is-active, + .navbar.is-success .navbar-start .navbar-link:hover, + .navbar.is-success .navbar-start .navbar-link.is-active, + .navbar.is-success .navbar-end>a.navbar-item:hover, + .navbar.is-success .navbar-end>a.navbar-item.is-active, + .navbar.is-success .navbar-end .navbar-link:hover, + .navbar.is-success .navbar-end .navbar-link.is-active { + background-color: #20bc56; + color: #fff; + } + .navbar.is-success .navbar-start .navbar-link::after, + .navbar.is-success .navbar-end .navbar-link::after { + border-color: #fff; + } + .navbar.is-success .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-success .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #20bc56; + color: #fff; + } + .navbar.is-success .navbar-dropdown a.navbar-item.is-active { + background-color: #23d160; + color: #fff; + } +} + +.navbar.is-warning { + background-color: #ffdd57; + color: rgba(0, 0, 0, 0.7); +} + +.navbar.is-warning .navbar-brand>.navbar-item, +.navbar.is-warning .navbar-brand .navbar-link { + color: rgba(0, 0, 0, 0.7); +} + +.navbar.is-warning .navbar-brand>a.navbar-item:hover, +.navbar.is-warning .navbar-brand>a.navbar-item.is-active, +.navbar.is-warning .navbar-brand .navbar-link:hover, +.navbar.is-warning .navbar-brand .navbar-link.is-active { + background-color: #ffd83d; + color: rgba(0, 0, 0, 0.7); +} + +.navbar.is-warning .navbar-brand .navbar-link::after { + border-color: rgba(0, 0, 0, 0.7); +} + +@media screen and (min-width: 1024px) { + .navbar.is-warning .navbar-start>.navbar-item, + .navbar.is-warning .navbar-start .navbar-link, + .navbar.is-warning .navbar-end>.navbar-item, + .navbar.is-warning .navbar-end .navbar-link { + color: rgba(0, 0, 0, 0.7); + } + .navbar.is-warning .navbar-start>a.navbar-item:hover, + .navbar.is-warning .navbar-start>a.navbar-item.is-active, + .navbar.is-warning .navbar-start .navbar-link:hover, + .navbar.is-warning .navbar-start .navbar-link.is-active, + .navbar.is-warning .navbar-end>a.navbar-item:hover, + .navbar.is-warning .navbar-end>a.navbar-item.is-active, + .navbar.is-warning .navbar-end .navbar-link:hover, + .navbar.is-warning .navbar-end .navbar-link.is-active { + background-color: #ffd83d; + color: rgba(0, 0, 0, 0.7); + } + .navbar.is-warning .navbar-start .navbar-link::after, + .navbar.is-warning .navbar-end .navbar-link::after { + border-color: rgba(0, 0, 0, 0.7); + } + .navbar.is-warning .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-warning .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #ffd83d; + color: rgba(0, 0, 0, 0.7); + } + .navbar.is-warning .navbar-dropdown a.navbar-item.is-active { + background-color: #ffdd57; + color: rgba(0, 0, 0, 0.7); + } +} + +.navbar.is-danger { + background-color: #ff3860; + color: #fff; +} + +.navbar.is-danger .navbar-brand>.navbar-item, +.navbar.is-danger .navbar-brand .navbar-link { + color: #fff; +} + +.navbar.is-danger .navbar-brand>a.navbar-item:hover, +.navbar.is-danger .navbar-brand>a.navbar-item.is-active, +.navbar.is-danger .navbar-brand .navbar-link:hover, +.navbar.is-danger .navbar-brand .navbar-link.is-active { + background-color: #ff1f4b; + color: #fff; +} + +.navbar.is-danger .navbar-brand .navbar-link::after { + border-color: #fff; +} + +@media screen and (min-width: 1024px) { + .navbar.is-danger .navbar-start>.navbar-item, + .navbar.is-danger .navbar-start .navbar-link, + .navbar.is-danger .navbar-end>.navbar-item, + .navbar.is-danger .navbar-end .navbar-link { + color: #fff; + } + .navbar.is-danger .navbar-start>a.navbar-item:hover, + .navbar.is-danger .navbar-start>a.navbar-item.is-active, + .navbar.is-danger .navbar-start .navbar-link:hover, + .navbar.is-danger .navbar-start .navbar-link.is-active, + .navbar.is-danger .navbar-end>a.navbar-item:hover, + .navbar.is-danger .navbar-end>a.navbar-item.is-active, + .navbar.is-danger .navbar-end .navbar-link:hover, + .navbar.is-danger .navbar-end .navbar-link.is-active { + background-color: #ff1f4b; + color: #fff; + } + .navbar.is-danger .navbar-start .navbar-link::after, + .navbar.is-danger .navbar-end .navbar-link::after { + border-color: #fff; + } + .navbar.is-danger .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-danger .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #ff1f4b; + color: #fff; + } + .navbar.is-danger .navbar-dropdown a.navbar-item.is-active { + background-color: #ff3860; + color: #fff; + } +} + +.navbar>.container { + -webkit-box-align: stretch; + -ms-flex-align: stretch; + align-items: stretch; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + min-height: 3.25rem; + width: 100%; +} + +.navbar.has-shadow { + -webkit-box-shadow: 0 2px 3px rgba(10, 10, 10, 0.1); + box-shadow: 0 2px 3px rgba(10, 10, 10, 0.1); +} + +.navbar.is-fixed-bottom, +.navbar.is-fixed-top { + left: 0; + position: fixed; + right: 0; + z-index: 30; +} + +.navbar.is-fixed-bottom { + bottom: 0; +} + +.navbar.is-fixed-bottom.has-shadow { + -webkit-box-shadow: 0 -2px 3px rgba(10, 10, 10, 0.1); + box-shadow: 0 -2px 3px rgba(10, 10, 10, 0.1); +} + +.navbar.is-fixed-top { + top: 0; +} + +html.has-navbar-fixed-top { + padding-top: 3.25rem; +} + +html.has-navbar-fixed-bottom { + padding-bottom: 3.25rem; +} + +.navbar-brand, +.navbar-tabs { + -webkit-box-align: stretch; + -ms-flex-align: stretch; + align-items: stretch; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -ms-flex-negative: 0; + flex-shrink: 0; + min-height: 3.25rem; +} + +.navbar-tabs { + -webkit-overflow-scrolling: touch; + max-width: 100vw; + overflow-x: auto; + overflow-y: hidden; +} + +.navbar-burger { + cursor: pointer; + display: block; + height: 3.25rem; + position: relative; + width: 3.25rem; + margin-left: auto; +} + +.navbar-burger span { + background-color: currentColor; + display: block; + height: 1px; + left: calc(50% - 8px); + position: absolute; + -webkit-transform-origin: center; + transform-origin: center; + -webkit-transition-duration: 86ms; + transition-duration: 86ms; + -webkit-transition-property: background-color, opacity, -webkit-transform; + transition-property: background-color, opacity, -webkit-transform; + transition-property: background-color, opacity, transform; + transition-property: background-color, opacity, transform, -webkit-transform; + -webkit-transition-timing-function: ease-out; + transition-timing-function: ease-out; + width: 16px; +} + +.navbar-burger span:nth-child(1) { + top: calc(50% - 6px); +} + +.navbar-burger span:nth-child(2) { + top: calc(50% - 1px); +} + +.navbar-burger span:nth-child(3) { + top: calc(50% + 4px); +} + +.navbar-burger:hover { + background-color: rgba(0, 0, 0, 0.05); +} + +.navbar-burger.is-active span:nth-child(1) { + -webkit-transform: translateY(5px) rotate(45deg); + transform: translateY(5px) rotate(45deg); +} + +.navbar-burger.is-active span:nth-child(2) { + opacity: 0; +} + +.navbar-burger.is-active span:nth-child(3) { + -webkit-transform: translateY(-5px) rotate(-45deg); + transform: translateY(-5px) rotate(-45deg); +} + +.navbar-menu { + display: none; +} + +.navbar-item, +.navbar-link { + color: #4a4a4a; + display: block; + line-height: 1.5; + padding: 0.5rem 1rem; + position: relative; +} + +a.navbar-item:hover, +a.navbar-item.is-active, +a.navbar-link:hover, +a.navbar-link.is-active { + background-color: whitesmoke; + color: #3273dc; +} + +.navbar-item { + -webkit-box-flex: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; +} + +.navbar-item img { + max-height: 1.75rem; +} + +.navbar-item.has-dropdown { + padding: 0; +} + +.navbar-item.is-expanded { + -webkit-box-flex: 1; + -ms-flex-positive: 1; + flex-grow: 1; + -ms-flex-negative: 1; + flex-shrink: 1; +} + +.navbar-item.is-tab { + border-bottom: 1px solid transparent; + min-height: 3.25rem; + padding-bottom: calc(0.5rem - 1px); +} + +.navbar-item.is-tab:hover { + background-color: transparent; + border-bottom-color: #3273dc; +} + +.navbar-item.is-tab.is-active { + background-color: transparent; + border-bottom-color: #3273dc; + border-bottom-style: solid; + border-bottom-width: 3px; + color: #3273dc; + padding-bottom: calc(0.5rem - 3px); +} + +.navbar-content { + -webkit-box-flex: 1; + -ms-flex-positive: 1; + flex-grow: 1; + -ms-flex-negative: 1; + flex-shrink: 1; +} + +.navbar-link { + padding-right: 2.5em; +} + +.navbar-dropdown { + font-size: 0.875rem; + padding-bottom: 0.5rem; + padding-top: 0.5rem; +} + +.navbar-dropdown .navbar-item { + padding-left: 1.5rem; + padding-right: 1.5rem; +} + +.navbar-divider { + background-color: #dbdbdb; + border: none; + display: none; + height: 1px; + margin: 0.5rem 0; +} + +@media screen and (max-width: 1023px) { + .navbar>.container { + display: block; + } + .navbar-brand .navbar-item, + .navbar-tabs .navbar-item { + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + } + .navbar-menu { + background-color: white; + -webkit-box-shadow: 0 8px 16px rgba(10, 10, 10, 0.1); + box-shadow: 0 8px 16px rgba(10, 10, 10, 0.1); + padding: 0.5rem 0; + } + .navbar-menu.is-active { + display: block; + } + .navbar.is-fixed-bottom-touch, + .navbar.is-fixed-top-touch { + left: 0; + position: fixed; + right: 0; + z-index: 30; + } + .navbar.is-fixed-bottom-touch { + bottom: 0; + } + .navbar.is-fixed-bottom-touch.has-shadow { + -webkit-box-shadow: 0 -2px 3px rgba(10, 10, 10, 0.1); + box-shadow: 0 -2px 3px rgba(10, 10, 10, 0.1); + } + .navbar.is-fixed-top-touch { + top: 0; + } + .navbar.is-fixed-top .navbar-menu, + .navbar.is-fixed-top-touch .navbar-menu { + -webkit-overflow-scrolling: touch; + max-height: calc(100vh - 3.25rem); + overflow: auto; + } + html.has-navbar-fixed-top-touch { + padding-top: 3.25rem; + } + html.has-navbar-fixed-bottom-touch { + padding-bottom: 3.25rem; + } +} + +@media screen and (min-width: 1024px) { + .navbar, + .navbar-menu, + .navbar-start, + .navbar-end { + -webkit-box-align: stretch; + -ms-flex-align: stretch; + align-items: stretch; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + } + .navbar { + min-height: 3.25rem; + } + .navbar.is-transparent a.navbar-item:hover, + .navbar.is-transparent a.navbar-item.is-active, + .navbar.is-transparent a.navbar-link:hover, + .navbar.is-transparent a.navbar-link.is-active { + background-color: transparent !important; + } + .navbar.is-transparent .navbar-item.has-dropdown.is-active .navbar-link, + .navbar.is-transparent .navbar-item.has-dropdown.is-hoverable:hover .navbar-link { + background-color: transparent !important; + } + .navbar.is-transparent .navbar-dropdown a.navbar-item:hover { + background-color: whitesmoke; + color: #0a0a0a; + } + .navbar.is-transparent .navbar-dropdown a.navbar-item.is-active { + background-color: whitesmoke; + color: #3273dc; + } + .navbar-burger { + display: none; + } + .navbar-item, + .navbar-link { + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + } + .navbar-item.has-dropdown { + -webkit-box-align: stretch; + -ms-flex-align: stretch; + align-items: stretch; + } + .navbar-item.has-dropdown-up .navbar-link::after { + -webkit-transform: rotate(135deg) translate(0.25em, -0.25em); + transform: rotate(135deg) translate(0.25em, -0.25em); + } + .navbar-item.has-dropdown-up .navbar-dropdown { + border-bottom: 1px solid #dbdbdb; + border-radius: 5px 5px 0 0; + border-top: none; + bottom: 100%; + -webkit-box-shadow: 0 -8px 8px rgba(10, 10, 10, 0.1); + box-shadow: 0 -8px 8px rgba(10, 10, 10, 0.1); + top: auto; + } + .navbar-item.is-active .navbar-dropdown, + .navbar-item.is-hoverable:hover .navbar-dropdown { + display: block; + } + .navbar-item.is-active .navbar-dropdown.is-boxed, + .navbar-item.is-hoverable:hover .navbar-dropdown.is-boxed { + opacity: 1; + pointer-events: auto; + -webkit-transform: translateY(0); + transform: translateY(0); + } + .navbar-link::after { + border: 1px solid #3273dc; + border-right: 0; + border-top: 0; + content: " "; + display: block; + height: 0.5em; + pointer-events: none; + position: absolute; + -webkit-transform: rotate(-45deg); + transform: rotate(-45deg); + -webkit-transform-origin: center; + transform-origin: center; + width: 0.5em; + margin-top: -0.375em; + right: 1.125em; + top: 50%; + } + .navbar-menu { + -webkit-box-flex: 1; + -ms-flex-positive: 1; + flex-grow: 1; + -ms-flex-negative: 0; + flex-shrink: 0; + } + .navbar-start { + -webkit-box-pack: start; + -ms-flex-pack: start; + justify-content: flex-start; + margin-right: auto; + } + .navbar-end { + -webkit-box-pack: end; + -ms-flex-pack: end; + justify-content: flex-end; + margin-left: auto; + } + .navbar-dropdown { + background-color: white; + border-bottom-left-radius: 5px; + border-bottom-right-radius: 5px; + border-top: 1px solid #dbdbdb; + -webkit-box-shadow: 0 8px 8px rgba(10, 10, 10, 0.1); + box-shadow: 0 8px 8px rgba(10, 10, 10, 0.1); + display: none; + font-size: 0.875rem; + left: 0; + min-width: 100%; + position: absolute; + top: 100%; + z-index: 20; + } + .navbar-dropdown .navbar-item { + padding: 0.375rem 1rem; + white-space: nowrap; + } + .navbar-dropdown a.navbar-item { + padding-right: 3rem; + } + .navbar-dropdown a.navbar-item:hover { + background-color: whitesmoke; + color: #0a0a0a; + } + .navbar-dropdown a.navbar-item.is-active { + background-color: whitesmoke; + color: #3273dc; + } + .navbar-dropdown.is-boxed { + border-radius: 5px; + border-top: none; + -webkit-box-shadow: 0 8px 8px rgba(10, 10, 10, 0.1), 0 0 0 1px rgba(10, 10, 10, 0.1); + box-shadow: 0 8px 8px rgba(10, 10, 10, 0.1), 0 0 0 1px rgba(10, 10, 10, 0.1); + display: block; + opacity: 0; + pointer-events: none; + top: calc(100% + (-4px)); + -webkit-transform: translateY(-5px); + transform: translateY(-5px); + -webkit-transition-duration: 86ms; + transition-duration: 86ms; + -webkit-transition-property: opacity, -webkit-transform; + transition-property: opacity, -webkit-transform; + transition-property: opacity, transform; + transition-property: opacity, transform, -webkit-transform; + } + .navbar-dropdown.is-right { + left: auto; + right: 0; + } + .navbar-divider { + display: block; + } + .navbar>.container .navbar-brand, + .container>.navbar .navbar-brand { + margin-left: -1rem; + } + .navbar>.container .navbar-menu, + .container>.navbar .navbar-menu { + margin-right: -1rem; + } + .navbar.is-fixed-bottom-desktop, + .navbar.is-fixed-top-desktop { + left: 0; + position: fixed; + right: 0; + z-index: 30; + } + .navbar.is-fixed-bottom-desktop { + bottom: 0; + } + .navbar.is-fixed-bottom-desktop.has-shadow { + -webkit-box-shadow: 0 -2px 3px rgba(10, 10, 10, 0.1); + box-shadow: 0 -2px 3px rgba(10, 10, 10, 0.1); + } + .navbar.is-fixed-top-desktop { + top: 0; + } + html.has-navbar-fixed-top-desktop { + padding-top: 3.25rem; + } + html.has-navbar-fixed-bottom-desktop { + padding-bottom: 3.25rem; + } + a.navbar-item.is-active, + a.navbar-link.is-active { + color: #0a0a0a; + } + a.navbar-item.is-active:not(:hover), + a.navbar-link.is-active:not(:hover) { + background-color: transparent; + } + .navbar-item.has-dropdown:hover .navbar-link, + .navbar-item.has-dropdown.is-active .navbar-link { + background-color: whitesmoke; + } +} + +.pagination { + font-size: 1rem; + margin: -0.25rem; +} + +.pagination.is-small { + font-size: 0.75rem; +} + +.pagination.is-medium { + font-size: 1.25rem; +} + +.pagination.is-large { + font-size: 1.5rem; +} + +.pagination.is-rounded .pagination-previous, +.pagination.is-rounded .pagination-next { + padding-left: 1em; + padding-right: 1em; + border-radius: 290486px; +} + +.pagination.is-rounded .pagination-link { + border-radius: 290486px; +} + +.pagination, +.pagination-list { + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + text-align: center; +} + +.pagination-previous, +.pagination-next, +.pagination-link, +.pagination-ellipsis { + -moz-appearance: none; + -webkit-appearance: none; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + border: 1px solid transparent; + border-radius: 3px; + -webkit-box-shadow: none; + box-shadow: none; + display: -webkit-inline-box; + display: -ms-inline-flexbox; + display: inline-flex; + font-size: 1rem; + height: 2.25em; + -webkit-box-pack: start; + -ms-flex-pack: start; + justify-content: flex-start; + line-height: 1.5; + padding-bottom: calc(0.375em - 1px); + padding-left: calc(0.625em - 1px); + padding-right: calc(0.625em - 1px); + padding-top: calc(0.375em - 1px); + position: relative; + vertical-align: top; + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + font-size: 1em; + padding-left: 0.5em; + padding-right: 0.5em; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + margin: 0.25rem; + text-align: center; +} + +.pagination-previous:focus, +.pagination-previous.is-focused, +.pagination-previous:active, +.pagination-previous.is-active, +.pagination-next:focus, +.pagination-next.is-focused, +.pagination-next:active, +.pagination-next.is-active, +.pagination-link:focus, +.pagination-link.is-focused, +.pagination-link:active, +.pagination-link.is-active, +.pagination-ellipsis:focus, +.pagination-ellipsis.is-focused, +.pagination-ellipsis:active, +.pagination-ellipsis.is-active { + outline: none; +} + +.pagination-previous[disabled], +.pagination-next[disabled], +.pagination-link[disabled], +.pagination-ellipsis[disabled] { + cursor: not-allowed; +} + +.pagination-previous, +.pagination-next, +.pagination-link { + border-color: #dbdbdb; + color: #363636; + min-width: 2.25em; +} + +.pagination-previous:hover, +.pagination-next:hover, +.pagination-link:hover { + border-color: #b5b5b5; + color: #363636; +} + +.pagination-previous:focus, +.pagination-next:focus, +.pagination-link:focus { + border-color: #3273dc; +} + +.pagination-previous:active, +.pagination-next:active, +.pagination-link:active { + -webkit-box-shadow: inset 0 1px 2px rgba(10, 10, 10, 0.2); + box-shadow: inset 0 1px 2px rgba(10, 10, 10, 0.2); +} + +.pagination-previous[disabled], +.pagination-next[disabled], +.pagination-link[disabled] { + background-color: #dbdbdb; + border-color: #dbdbdb; + -webkit-box-shadow: none; + box-shadow: none; + color: #7a7a7a; + opacity: 0.5; +} + +.pagination-previous, +.pagination-next { + padding-left: 0.75em; + padding-right: 0.75em; + white-space: nowrap; +} + +.pagination-link.is-current { + background-color: #3273dc; + border-color: #3273dc; + color: #fff; +} + +.pagination-ellipsis { + color: #b5b5b5; + pointer-events: none; +} + +.pagination-list { + -ms-flex-wrap: wrap; + flex-wrap: wrap; +} + +@media screen and (max-width: 768px) { + .pagination { + -ms-flex-wrap: wrap; + flex-wrap: wrap; + } + .pagination-previous, + .pagination-next { + -webkit-box-flex: 1; + -ms-flex-positive: 1; + flex-grow: 1; + -ms-flex-negative: 1; + flex-shrink: 1; + } + .pagination-list li { + -webkit-box-flex: 1; + -ms-flex-positive: 1; + flex-grow: 1; + -ms-flex-negative: 1; + flex-shrink: 1; + } +} + +@media screen and (min-width: 769px), +print { + .pagination-list { + -webkit-box-flex: 1; + -ms-flex-positive: 1; + flex-grow: 1; + -ms-flex-negative: 1; + flex-shrink: 1; + -webkit-box-pack: start; + -ms-flex-pack: start; + justify-content: flex-start; + -webkit-box-ordinal-group: 2; + -ms-flex-order: 1; + order: 1; + } + .pagination-previous { + -webkit-box-ordinal-group: 3; + -ms-flex-order: 2; + order: 2; + } + .pagination-next { + -webkit-box-ordinal-group: 4; + -ms-flex-order: 3; + order: 3; + } + .pagination { + -webkit-box-pack: justify; + -ms-flex-pack: justify; + justify-content: space-between; + } + .pagination.is-centered .pagination-previous { + -webkit-box-ordinal-group: 2; + -ms-flex-order: 1; + order: 1; + } + .pagination.is-centered .pagination-list { + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + -webkit-box-ordinal-group: 3; + -ms-flex-order: 2; + order: 2; + } + .pagination.is-centered .pagination-next { + -webkit-box-ordinal-group: 4; + -ms-flex-order: 3; + order: 3; + } + .pagination.is-right .pagination-previous { + -webkit-box-ordinal-group: 2; + -ms-flex-order: 1; + order: 1; + } + .pagination.is-right .pagination-next { + -webkit-box-ordinal-group: 3; + -ms-flex-order: 2; + order: 2; + } + .pagination.is-right .pagination-list { + -webkit-box-pack: end; + -ms-flex-pack: end; + justify-content: flex-end; + -webkit-box-ordinal-group: 4; + -ms-flex-order: 3; + order: 3; + } +} + +.panel { + font-size: 1rem; +} + +.panel:not(:last-child) { + margin-bottom: 1.5rem; +} + +.panel-heading, +.panel-tabs, +.panel-block { + border-bottom: 1px solid #dbdbdb; + border-left: 1px solid #dbdbdb; + border-right: 1px solid #dbdbdb; +} + +.panel-heading:first-child, +.panel-tabs:first-child, +.panel-block:first-child { + border-top: 1px solid #dbdbdb; +} + +.panel-heading { + background-color: whitesmoke; + border-radius: 3px 3px 0 0; + color: #363636; + font-size: 1.25em; + font-weight: 300; + line-height: 1.25; + padding: 0.5em 0.75em; +} + +.panel-tabs { + -webkit-box-align: end; + -ms-flex-align: end; + align-items: flex-end; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + font-size: 0.875em; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; +} + +.panel-tabs a { + border-bottom: 1px solid #dbdbdb; + margin-bottom: -1px; + padding: 0.5em; +} + +.panel-tabs a.is-active { + border-bottom-color: #4a4a4a; + color: #363636; +} + +.panel-list a { + color: #4a4a4a; +} + +.panel-list a:hover { + color: #3273dc; +} + +.panel-block { + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + color: #363636; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: start; + -ms-flex-pack: start; + justify-content: flex-start; + padding: 0.5em 0.75em; +} + +.panel-block input[type="checkbox"] { + margin-right: 0.75em; +} + +.panel-block>.control { + -webkit-box-flex: 1; + -ms-flex-positive: 1; + flex-grow: 1; + -ms-flex-negative: 1; + flex-shrink: 1; + width: 100%; +} + +.panel-block.is-wrapped { + -ms-flex-wrap: wrap; + flex-wrap: wrap; +} + +.panel-block.is-active { + border-left-color: #3273dc; + color: #363636; +} + +.panel-block.is-active .panel-icon { + color: #3273dc; +} + +a.panel-block, +label.panel-block { + cursor: pointer; +} + +a.panel-block:hover, +label.panel-block:hover { + background-color: whitesmoke; +} + +.panel-icon { + display: inline-block; + font-size: 14px; + height: 1em; + line-height: 1em; + text-align: center; + vertical-align: top; + width: 1em; + color: #7a7a7a; + margin-right: 0.75em; +} + +.panel-icon .fa { + font-size: inherit; + line-height: inherit; +} + +.tabs { + -webkit-overflow-scrolling: touch; + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + -webkit-box-align: stretch; + -ms-flex-align: stretch; + align-items: stretch; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + font-size: 1rem; + -webkit-box-pack: justify; + -ms-flex-pack: justify; + justify-content: space-between; + overflow: hidden; + overflow-x: auto; + white-space: nowrap; +} + +.tabs:not(:last-child) { + margin-bottom: 1.5rem; +} + +.tabs a { + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + border-bottom-color: #dbdbdb; + border-bottom-style: solid; + border-bottom-width: 1px; + color: #4a4a4a; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + margin-bottom: -1px; + padding: 0.5em 1em; + vertical-align: top; +} + +.tabs a:hover { + border-bottom-color: #363636; + color: #363636; +} + +.tabs li { + display: block; +} + +.tabs li.is-active a { + border-bottom-color: #3273dc; + color: #3273dc; +} + +.tabs ul { + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + border-bottom-color: #dbdbdb; + border-bottom-style: solid; + border-bottom-width: 1px; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-flex: 1; + -ms-flex-positive: 1; + flex-grow: 1; + -ms-flex-negative: 0; + flex-shrink: 0; + -webkit-box-pack: start; + -ms-flex-pack: start; + justify-content: flex-start; +} + +.tabs ul.is-left { + padding-right: 0.75em; +} + +.tabs ul.is-center { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + padding-left: 0.75em; + padding-right: 0.75em; +} + +.tabs ul.is-right { + -webkit-box-pack: end; + -ms-flex-pack: end; + justify-content: flex-end; + padding-left: 0.75em; +} + +.tabs .icon:first-child { + margin-right: 0.5em; +} + +.tabs .icon:last-child { + margin-left: 0.5em; +} + +.tabs.is-centered ul { + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; +} + +.tabs.is-right ul { + -webkit-box-pack: end; + -ms-flex-pack: end; + justify-content: flex-end; +} + +.tabs.is-boxed a { + border: 1px solid transparent; + border-radius: 3px 3px 0 0; +} + +.tabs.is-boxed a:hover { + background-color: whitesmoke; + border-bottom-color: #dbdbdb; +} + +.tabs.is-boxed li.is-active a { + background-color: white; + border-color: #dbdbdb; + border-bottom-color: transparent !important; +} + +.tabs.is-fullwidth li { + -webkit-box-flex: 1; + -ms-flex-positive: 1; + flex-grow: 1; + -ms-flex-negative: 0; + flex-shrink: 0; +} + +.tabs.is-toggle a { + border-color: #dbdbdb; + border-style: solid; + border-width: 1px; + margin-bottom: 0; + position: relative; +} + +.tabs.is-toggle a:hover { + background-color: whitesmoke; + border-color: #b5b5b5; + z-index: 2; +} + +.tabs.is-toggle li+li { + margin-left: -1px; +} + +.tabs.is-toggle li:first-child a { + border-radius: 3px 0 0 3px; +} + +.tabs.is-toggle li:last-child a { + border-radius: 0 3px 3px 0; +} + +.tabs.is-toggle li.is-active a { + background-color: #3273dc; + border-color: #3273dc; + color: #fff; + z-index: 1; +} + +.tabs.is-toggle ul { + border-bottom: none; +} + +.tabs.is-toggle.is-toggle-rounded li:first-child a { + border-bottom-left-radius: 290486px; + border-top-left-radius: 290486px; + padding-left: 1.25em; +} + +.tabs.is-toggle.is-toggle-rounded li:last-child a { + border-bottom-right-radius: 290486px; + border-top-right-radius: 290486px; + padding-right: 1.25em; +} + +.tabs.is-small { + font-size: 0.75rem; +} + +.tabs.is-medium { + font-size: 1.25rem; +} + +.tabs.is-large { + font-size: 1.5rem; +} + +.column { + display: block; + -ms-flex-preferred-size: 0; + flex-basis: 0; + -webkit-box-flex: 1; + -ms-flex-positive: 1; + flex-grow: 1; + -ms-flex-negative: 1; + flex-shrink: 1; + padding: 0.75rem; +} + +.columns.is-mobile>.column.is-narrow { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; +} + +.columns.is-mobile>.column.is-full { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 100%; +} + +.columns.is-mobile>.column.is-three-quarters { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 75%; +} + +.columns.is-mobile>.column.is-two-thirds { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 66.6666%; +} + +.columns.is-mobile>.column.is-half { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 50%; +} + +.columns.is-mobile>.column.is-one-third { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 33.3333%; +} + +.columns.is-mobile>.column.is-one-quarter { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 25%; +} + +.columns.is-mobile>.column.is-one-fifth { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 20%; +} + +.columns.is-mobile>.column.is-two-fifths { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 40%; +} + +.columns.is-mobile>.column.is-three-fifths { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 60%; +} + +.columns.is-mobile>.column.is-four-fifths { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 80%; +} + +.columns.is-mobile>.column.is-offset-three-quarters { + margin-left: 75%; +} + +.columns.is-mobile>.column.is-offset-two-thirds { + margin-left: 66.6666%; +} + +.columns.is-mobile>.column.is-offset-half { + margin-left: 50%; +} + +.columns.is-mobile>.column.is-offset-one-third { + margin-left: 33.3333%; +} + +.columns.is-mobile>.column.is-offset-one-quarter { + margin-left: 25%; +} + +.columns.is-mobile>.column.is-offset-one-fifth { + margin-left: 20%; +} + +.columns.is-mobile>.column.is-offset-two-fifths { + margin-left: 40%; +} + +.columns.is-mobile>.column.is-offset-three-fifths { + margin-left: 60%; +} + +.columns.is-mobile>.column.is-offset-four-fifths { + margin-left: 80%; +} + +.columns.is-mobile>.column.is-1 { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 8.33333%; +} + +.columns.is-mobile>.column.is-offset-1 { + margin-left: 8.33333%; +} + +.columns.is-mobile>.column.is-2 { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 16.66667%; +} + +.columns.is-mobile>.column.is-offset-2 { + margin-left: 16.66667%; +} + +.columns.is-mobile>.column.is-3 { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 25%; +} + +.columns.is-mobile>.column.is-offset-3 { + margin-left: 25%; +} + +.columns.is-mobile>.column.is-4 { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 33.33333%; +} + +.columns.is-mobile>.column.is-offset-4 { + margin-left: 33.33333%; +} + +.columns.is-mobile>.column.is-5 { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 41.66667%; +} + +.columns.is-mobile>.column.is-offset-5 { + margin-left: 41.66667%; +} + +.columns.is-mobile>.column.is-6 { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 50%; +} + +.columns.is-mobile>.column.is-offset-6 { + margin-left: 50%; +} + +.columns.is-mobile>.column.is-7 { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 58.33333%; +} + +.columns.is-mobile>.column.is-offset-7 { + margin-left: 58.33333%; +} + +.columns.is-mobile>.column.is-8 { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 66.66667%; +} + +.columns.is-mobile>.column.is-offset-8 { + margin-left: 66.66667%; +} + +.columns.is-mobile>.column.is-9 { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 75%; +} + +.columns.is-mobile>.column.is-offset-9 { + margin-left: 75%; +} + +.columns.is-mobile>.column.is-10 { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 83.33333%; +} + +.columns.is-mobile>.column.is-offset-10 { + margin-left: 83.33333%; +} + +.columns.is-mobile>.column.is-11 { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 91.66667%; +} + +.columns.is-mobile>.column.is-offset-11 { + margin-left: 91.66667%; +} + +.columns.is-mobile>.column.is-12 { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 100%; +} + +.columns.is-mobile>.column.is-offset-12 { + margin-left: 100%; +} + +@media screen and (max-width: 768px) { + .column.is-narrow-mobile { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + } + .column.is-full-mobile { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 100%; + } + .column.is-three-quarters-mobile { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 75%; + } + .column.is-two-thirds-mobile { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 66.6666%; + } + .column.is-half-mobile { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 50%; + } + .column.is-one-third-mobile { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 33.3333%; + } + .column.is-one-quarter-mobile { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 25%; + } + .column.is-one-fifth-mobile { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 20%; + } + .column.is-two-fifths-mobile { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 40%; + } + .column.is-three-fifths-mobile { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 60%; + } + .column.is-four-fifths-mobile { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 80%; + } + .column.is-offset-three-quarters-mobile { + margin-left: 75%; + } + .column.is-offset-two-thirds-mobile { + margin-left: 66.6666%; + } + .column.is-offset-half-mobile { + margin-left: 50%; + } + .column.is-offset-one-third-mobile { + margin-left: 33.3333%; + } + .column.is-offset-one-quarter-mobile { + margin-left: 25%; + } + .column.is-offset-one-fifth-mobile { + margin-left: 20%; + } + .column.is-offset-two-fifths-mobile { + margin-left: 40%; + } + .column.is-offset-three-fifths-mobile { + margin-left: 60%; + } + .column.is-offset-four-fifths-mobile { + margin-left: 80%; + } + .column.is-1-mobile { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 8.33333%; + } + .column.is-offset-1-mobile { + margin-left: 8.33333%; + } + .column.is-2-mobile { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 16.66667%; + } + .column.is-offset-2-mobile { + margin-left: 16.66667%; + } + .column.is-3-mobile { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 25%; + } + .column.is-offset-3-mobile { + margin-left: 25%; + } + .column.is-4-mobile { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 33.33333%; + } + .column.is-offset-4-mobile { + margin-left: 33.33333%; + } + .column.is-5-mobile { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 41.66667%; + } + .column.is-offset-5-mobile { + margin-left: 41.66667%; + } + .column.is-6-mobile { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 50%; + } + .column.is-offset-6-mobile { + margin-left: 50%; + } + .column.is-7-mobile { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 58.33333%; + } + .column.is-offset-7-mobile { + margin-left: 58.33333%; + } + .column.is-8-mobile { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 66.66667%; + } + .column.is-offset-8-mobile { + margin-left: 66.66667%; + } + .column.is-9-mobile { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 75%; + } + .column.is-offset-9-mobile { + margin-left: 75%; + } + .column.is-10-mobile { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 83.33333%; + } + .column.is-offset-10-mobile { + margin-left: 83.33333%; + } + .column.is-11-mobile { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 91.66667%; + } + .column.is-offset-11-mobile { + margin-left: 91.66667%; + } + .column.is-12-mobile { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 100%; + } + .column.is-offset-12-mobile { + margin-left: 100%; + } +} + +@media screen and (min-width: 769px), +print { + .column.is-narrow, + .column.is-narrow-tablet { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + } + .column.is-full, + .column.is-full-tablet { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 100%; + } + .column.is-three-quarters, + .column.is-three-quarters-tablet { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 75%; + } + .column.is-two-thirds, + .column.is-two-thirds-tablet { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 66.6666%; + } + .column.is-half, + .column.is-half-tablet { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 50%; + } + .column.is-one-third, + .column.is-one-third-tablet { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 33.3333%; + } + .column.is-one-quarter, + .column.is-one-quarter-tablet { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 25%; + } + .column.is-one-fifth, + .column.is-one-fifth-tablet { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 20%; + } + .column.is-two-fifths, + .column.is-two-fifths-tablet { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 40%; + } + .column.is-three-fifths, + .column.is-three-fifths-tablet { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 60%; + } + .column.is-four-fifths, + .column.is-four-fifths-tablet { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 80%; + } + .column.is-offset-three-quarters, + .column.is-offset-three-quarters-tablet { + margin-left: 75%; + } + .column.is-offset-two-thirds, + .column.is-offset-two-thirds-tablet { + margin-left: 66.6666%; + } + .column.is-offset-half, + .column.is-offset-half-tablet { + margin-left: 50%; + } + .column.is-offset-one-third, + .column.is-offset-one-third-tablet { + margin-left: 33.3333%; + } + .column.is-offset-one-quarter, + .column.is-offset-one-quarter-tablet { + margin-left: 25%; + } + .column.is-offset-one-fifth, + .column.is-offset-one-fifth-tablet { + margin-left: 20%; + } + .column.is-offset-two-fifths, + .column.is-offset-two-fifths-tablet { + margin-left: 40%; + } + .column.is-offset-three-fifths, + .column.is-offset-three-fifths-tablet { + margin-left: 60%; + } + .column.is-offset-four-fifths, + .column.is-offset-four-fifths-tablet { + margin-left: 80%; + } + .column.is-1, + .column.is-1-tablet { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 8.33333%; + } + .column.is-offset-1, + .column.is-offset-1-tablet { + margin-left: 8.33333%; + } + .column.is-2, + .column.is-2-tablet { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 16.66667%; + } + .column.is-offset-2, + .column.is-offset-2-tablet { + margin-left: 16.66667%; + } + .column.is-3, + .column.is-3-tablet { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 25%; + } + .column.is-offset-3, + .column.is-offset-3-tablet { + margin-left: 25%; + } + .column.is-4, + .column.is-4-tablet { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 33.33333%; + } + .column.is-offset-4, + .column.is-offset-4-tablet { + margin-left: 33.33333%; + } + .column.is-5, + .column.is-5-tablet { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 41.66667%; + } + .column.is-offset-5, + .column.is-offset-5-tablet { + margin-left: 41.66667%; + } + .column.is-6, + .column.is-6-tablet { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 50%; + } + .column.is-offset-6, + .column.is-offset-6-tablet { + margin-left: 50%; + } + .column.is-7, + .column.is-7-tablet { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 58.33333%; + } + .column.is-offset-7, + .column.is-offset-7-tablet { + margin-left: 58.33333%; + } + .column.is-8, + .column.is-8-tablet { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 66.66667%; + } + .column.is-offset-8, + .column.is-offset-8-tablet { + margin-left: 66.66667%; + } + .column.is-9, + .column.is-9-tablet { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 75%; + } + .column.is-offset-9, + .column.is-offset-9-tablet { + margin-left: 75%; + } + .column.is-10, + .column.is-10-tablet { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 83.33333%; + } + .column.is-offset-10, + .column.is-offset-10-tablet { + margin-left: 83.33333%; + } + .column.is-11, + .column.is-11-tablet { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 91.66667%; + } + .column.is-offset-11, + .column.is-offset-11-tablet { + margin-left: 91.66667%; + } + .column.is-12, + .column.is-12-tablet { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 100%; + } + .column.is-offset-12, + .column.is-offset-12-tablet { + margin-left: 100%; + } +} + +@media screen and (max-width: 1023px) { + .column.is-narrow-touch { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + } + .column.is-full-touch { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 100%; + } + .column.is-three-quarters-touch { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 75%; + } + .column.is-two-thirds-touch { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 66.6666%; + } + .column.is-half-touch { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 50%; + } + .column.is-one-third-touch { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 33.3333%; + } + .column.is-one-quarter-touch { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 25%; + } + .column.is-one-fifth-touch { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 20%; + } + .column.is-two-fifths-touch { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 40%; + } + .column.is-three-fifths-touch { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 60%; + } + .column.is-four-fifths-touch { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 80%; + } + .column.is-offset-three-quarters-touch { + margin-left: 75%; + } + .column.is-offset-two-thirds-touch { + margin-left: 66.6666%; + } + .column.is-offset-half-touch { + margin-left: 50%; + } + .column.is-offset-one-third-touch { + margin-left: 33.3333%; + } + .column.is-offset-one-quarter-touch { + margin-left: 25%; + } + .column.is-offset-one-fifth-touch { + margin-left: 20%; + } + .column.is-offset-two-fifths-touch { + margin-left: 40%; + } + .column.is-offset-three-fifths-touch { + margin-left: 60%; + } + .column.is-offset-four-fifths-touch { + margin-left: 80%; + } + .column.is-1-touch { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 8.33333%; + } + .column.is-offset-1-touch { + margin-left: 8.33333%; + } + .column.is-2-touch { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 16.66667%; + } + .column.is-offset-2-touch { + margin-left: 16.66667%; + } + .column.is-3-touch { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 25%; + } + .column.is-offset-3-touch { + margin-left: 25%; + } + .column.is-4-touch { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 33.33333%; + } + .column.is-offset-4-touch { + margin-left: 33.33333%; + } + .column.is-5-touch { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 41.66667%; + } + .column.is-offset-5-touch { + margin-left: 41.66667%; + } + .column.is-6-touch { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 50%; + } + .column.is-offset-6-touch { + margin-left: 50%; + } + .column.is-7-touch { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 58.33333%; + } + .column.is-offset-7-touch { + margin-left: 58.33333%; + } + .column.is-8-touch { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 66.66667%; + } + .column.is-offset-8-touch { + margin-left: 66.66667%; + } + .column.is-9-touch { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 75%; + } + .column.is-offset-9-touch { + margin-left: 75%; + } + .column.is-10-touch { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 83.33333%; + } + .column.is-offset-10-touch { + margin-left: 83.33333%; + } + .column.is-11-touch { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 91.66667%; + } + .column.is-offset-11-touch { + margin-left: 91.66667%; + } + .column.is-12-touch { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 100%; + } + .column.is-offset-12-touch { + margin-left: 100%; + } +} + +@media screen and (min-width: 1024px) { + .column.is-narrow-desktop { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + } + .column.is-full-desktop { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 100%; + } + .column.is-three-quarters-desktop { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 75%; + } + .column.is-two-thirds-desktop { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 66.6666%; + } + .column.is-half-desktop { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 50%; + } + .column.is-one-third-desktop { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 33.3333%; + } + .column.is-one-quarter-desktop { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 25%; + } + .column.is-one-fifth-desktop { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 20%; + } + .column.is-two-fifths-desktop { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 40%; + } + .column.is-three-fifths-desktop { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 60%; + } + .column.is-four-fifths-desktop { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 80%; + } + .column.is-offset-three-quarters-desktop { + margin-left: 75%; + } + .column.is-offset-two-thirds-desktop { + margin-left: 66.6666%; + } + .column.is-offset-half-desktop { + margin-left: 50%; + } + .column.is-offset-one-third-desktop { + margin-left: 33.3333%; + } + .column.is-offset-one-quarter-desktop { + margin-left: 25%; + } + .column.is-offset-one-fifth-desktop { + margin-left: 20%; + } + .column.is-offset-two-fifths-desktop { + margin-left: 40%; + } + .column.is-offset-three-fifths-desktop { + margin-left: 60%; + } + .column.is-offset-four-fifths-desktop { + margin-left: 80%; + } + .column.is-1-desktop { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 8.33333%; + } + .column.is-offset-1-desktop { + margin-left: 8.33333%; + } + .column.is-2-desktop { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 16.66667%; + } + .column.is-offset-2-desktop { + margin-left: 16.66667%; + } + .column.is-3-desktop { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 25%; + } + .column.is-offset-3-desktop { + margin-left: 25%; + } + .column.is-4-desktop { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 33.33333%; + } + .column.is-offset-4-desktop { + margin-left: 33.33333%; + } + .column.is-5-desktop { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 41.66667%; + } + .column.is-offset-5-desktop { + margin-left: 41.66667%; + } + .column.is-6-desktop { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 50%; + } + .column.is-offset-6-desktop { + margin-left: 50%; + } + .column.is-7-desktop { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 58.33333%; + } + .column.is-offset-7-desktop { + margin-left: 58.33333%; + } + .column.is-8-desktop { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 66.66667%; + } + .column.is-offset-8-desktop { + margin-left: 66.66667%; + } + .column.is-9-desktop { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 75%; + } + .column.is-offset-9-desktop { + margin-left: 75%; + } + .column.is-10-desktop { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 83.33333%; + } + .column.is-offset-10-desktop { + margin-left: 83.33333%; + } + .column.is-11-desktop { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 91.66667%; + } + .column.is-offset-11-desktop { + margin-left: 91.66667%; + } + .column.is-12-desktop { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 100%; + } + .column.is-offset-12-desktop { + margin-left: 100%; + } +} + +@media screen and (min-width: 1216px) { + .column.is-narrow-widescreen { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + } + .column.is-full-widescreen { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 100%; + } + .column.is-three-quarters-widescreen { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 75%; + } + .column.is-two-thirds-widescreen { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 66.6666%; + } + .column.is-half-widescreen { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 50%; + } + .column.is-one-third-widescreen { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 33.3333%; + } + .column.is-one-quarter-widescreen { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 25%; + } + .column.is-one-fifth-widescreen { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 20%; + } + .column.is-two-fifths-widescreen { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 40%; + } + .column.is-three-fifths-widescreen { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 60%; + } + .column.is-four-fifths-widescreen { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 80%; + } + .column.is-offset-three-quarters-widescreen { + margin-left: 75%; + } + .column.is-offset-two-thirds-widescreen { + margin-left: 66.6666%; + } + .column.is-offset-half-widescreen { + margin-left: 50%; + } + .column.is-offset-one-third-widescreen { + margin-left: 33.3333%; + } + .column.is-offset-one-quarter-widescreen { + margin-left: 25%; + } + .column.is-offset-one-fifth-widescreen { + margin-left: 20%; + } + .column.is-offset-two-fifths-widescreen { + margin-left: 40%; + } + .column.is-offset-three-fifths-widescreen { + margin-left: 60%; + } + .column.is-offset-four-fifths-widescreen { + margin-left: 80%; + } + .column.is-1-widescreen { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 8.33333%; + } + .column.is-offset-1-widescreen { + margin-left: 8.33333%; + } + .column.is-2-widescreen { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 16.66667%; + } + .column.is-offset-2-widescreen { + margin-left: 16.66667%; + } + .column.is-3-widescreen { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 25%; + } + .column.is-offset-3-widescreen { + margin-left: 25%; + } + .column.is-4-widescreen { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 33.33333%; + } + .column.is-offset-4-widescreen { + margin-left: 33.33333%; + } + .column.is-5-widescreen { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 41.66667%; + } + .column.is-offset-5-widescreen { + margin-left: 41.66667%; + } + .column.is-6-widescreen { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 50%; + } + .column.is-offset-6-widescreen { + margin-left: 50%; + } + .column.is-7-widescreen { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 58.33333%; + } + .column.is-offset-7-widescreen { + margin-left: 58.33333%; + } + .column.is-8-widescreen { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 66.66667%; + } + .column.is-offset-8-widescreen { + margin-left: 66.66667%; + } + .column.is-9-widescreen { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 75%; + } + .column.is-offset-9-widescreen { + margin-left: 75%; + } + .column.is-10-widescreen { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 83.33333%; + } + .column.is-offset-10-widescreen { + margin-left: 83.33333%; + } + .column.is-11-widescreen { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 91.66667%; + } + .column.is-offset-11-widescreen { + margin-left: 91.66667%; + } + .column.is-12-widescreen { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 100%; + } + .column.is-offset-12-widescreen { + margin-left: 100%; + } +} + +@media screen and (min-width: 1408px) { + .column.is-narrow-fullhd { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + } + .column.is-full-fullhd { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 100%; + } + .column.is-three-quarters-fullhd { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 75%; + } + .column.is-two-thirds-fullhd { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 66.6666%; + } + .column.is-half-fullhd { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 50%; + } + .column.is-one-third-fullhd { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 33.3333%; + } + .column.is-one-quarter-fullhd { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 25%; + } + .column.is-one-fifth-fullhd { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 20%; + } + .column.is-two-fifths-fullhd { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 40%; + } + .column.is-three-fifths-fullhd { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 60%; + } + .column.is-four-fifths-fullhd { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 80%; + } + .column.is-offset-three-quarters-fullhd { + margin-left: 75%; + } + .column.is-offset-two-thirds-fullhd { + margin-left: 66.6666%; + } + .column.is-offset-half-fullhd { + margin-left: 50%; + } + .column.is-offset-one-third-fullhd { + margin-left: 33.3333%; + } + .column.is-offset-one-quarter-fullhd { + margin-left: 25%; + } + .column.is-offset-one-fifth-fullhd { + margin-left: 20%; + } + .column.is-offset-two-fifths-fullhd { + margin-left: 40%; + } + .column.is-offset-three-fifths-fullhd { + margin-left: 60%; + } + .column.is-offset-four-fifths-fullhd { + margin-left: 80%; + } + .column.is-1-fullhd { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 8.33333%; + } + .column.is-offset-1-fullhd { + margin-left: 8.33333%; + } + .column.is-2-fullhd { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 16.66667%; + } + .column.is-offset-2-fullhd { + margin-left: 16.66667%; + } + .column.is-3-fullhd { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 25%; + } + .column.is-offset-3-fullhd { + margin-left: 25%; + } + .column.is-4-fullhd { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 33.33333%; + } + .column.is-offset-4-fullhd { + margin-left: 33.33333%; + } + .column.is-5-fullhd { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 41.66667%; + } + .column.is-offset-5-fullhd { + margin-left: 41.66667%; + } + .column.is-6-fullhd { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 50%; + } + .column.is-offset-6-fullhd { + margin-left: 50%; + } + .column.is-7-fullhd { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 58.33333%; + } + .column.is-offset-7-fullhd { + margin-left: 58.33333%; + } + .column.is-8-fullhd { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 66.66667%; + } + .column.is-offset-8-fullhd { + margin-left: 66.66667%; + } + .column.is-9-fullhd { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 75%; + } + .column.is-offset-9-fullhd { + margin-left: 75%; + } + .column.is-10-fullhd { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 83.33333%; + } + .column.is-offset-10-fullhd { + margin-left: 83.33333%; + } + .column.is-11-fullhd { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 91.66667%; + } + .column.is-offset-11-fullhd { + margin-left: 91.66667%; + } + .column.is-12-fullhd { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 100%; + } + .column.is-offset-12-fullhd { + margin-left: 100%; + } +} + +.columns { + margin-left: -0.75rem; + margin-right: -0.75rem; + margin-top: -0.75rem; +} + +.columns:last-child { + margin-bottom: -0.75rem; +} + +.columns:not(:last-child) { + margin-bottom: calc(1.5rem - 0.75rem); +} + +.columns.is-centered { + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; +} + +.columns.is-gapless { + margin-left: 0; + margin-right: 0; + margin-top: 0; +} + +.columns.is-gapless>.column { + margin: 0; + padding: 0 !important; +} + +.columns.is-gapless:not(:last-child) { + margin-bottom: 1.5rem; +} + +.columns.is-gapless:last-child { + margin-bottom: 0; +} + +.columns.is-mobile { + display: -webkit-box; + display: -ms-flexbox; + display: flex; +} + +.columns.is-multiline { + -ms-flex-wrap: wrap; + flex-wrap: wrap; +} + +.columns.is-vcentered { + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; +} + +@media screen and (min-width: 769px), +print { + .columns:not(.is-desktop) { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + } +} + +@media screen and (min-width: 1024px) { + .columns.is-desktop { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + } +} + +.columns.is-variable { + --columnGap: 0.75rem; + margin-left: calc(-1 * var(--columnGap)); + margin-right: calc(-1 * var(--columnGap)); +} + +.columns.is-variable .column { + padding-left: var(--columnGap); + padding-right: var(--columnGap); +} + +.columns.is-variable.is-0 { + --columnGap: 0rem; +} + +.columns.is-variable.is-1 { + --columnGap: 0.25rem; +} + +.columns.is-variable.is-2 { + --columnGap: 0.5rem; +} + +.columns.is-variable.is-3 { + --columnGap: 0.75rem; +} + +.columns.is-variable.is-4 { + --columnGap: 1rem; +} + +.columns.is-variable.is-5 { + --columnGap: 1.25rem; +} + +.columns.is-variable.is-6 { + --columnGap: 1.5rem; +} + +.columns.is-variable.is-7 { + --columnGap: 1.75rem; +} + +.columns.is-variable.is-8 { + --columnGap: 2rem; +} + +.tile { + -webkit-box-align: stretch; + -ms-flex-align: stretch; + align-items: stretch; + display: block; + -ms-flex-preferred-size: 0; + flex-basis: 0; + -webkit-box-flex: 1; + -ms-flex-positive: 1; + flex-grow: 1; + -ms-flex-negative: 1; + flex-shrink: 1; + min-height: -webkit-min-content; + min-height: -moz-min-content; + min-height: min-content; +} + +.tile.is-ancestor { + margin-left: -0.75rem; + margin-right: -0.75rem; + margin-top: -0.75rem; +} + +.tile.is-ancestor:last-child { + margin-bottom: -0.75rem; +} + +.tile.is-ancestor:not(:last-child) { + margin-bottom: 0.75rem; +} + +.tile.is-child { + margin: 0 !important; +} + +.tile.is-parent { + padding: 0.75rem; +} + +.tile.is-vertical { + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; +} + +.tile.is-vertical>.tile.is-child:not(:last-child) { + margin-bottom: 1.5rem !important; +} + +@media screen and (min-width: 769px), +print { + .tile:not(.is-child) { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + } + .tile.is-1 { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 8.33333%; + } + .tile.is-2 { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 16.66667%; + } + .tile.is-3 { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 25%; + } + .tile.is-4 { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 33.33333%; + } + .tile.is-5 { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 41.66667%; + } + .tile.is-6 { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 50%; + } + .tile.is-7 { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 58.33333%; + } + .tile.is-8 { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 66.66667%; + } + .tile.is-9 { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 75%; + } + .tile.is-10 { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 83.33333%; + } + .tile.is-11 { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 91.66667%; + } + .tile.is-12 { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + width: 100%; + } +} + +.hero { + -webkit-box-align: stretch; + -ms-flex-align: stretch; + align-items: stretch; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; + -webkit-box-pack: justify; + -ms-flex-pack: justify; + justify-content: space-between; +} + +.hero .navbar { + background: none; +} + +.hero .tabs ul { + border-bottom: none; +} + +.hero.is-white { + background-color: white; + color: #0a0a0a; +} + +.hero.is-white a:not(.button):not(.dropdown-item):not(.tag), +.hero.is-white strong { + color: inherit; +} + +.hero.is-white .title { + color: #0a0a0a; +} + +.hero.is-white .subtitle { + color: rgba(10, 10, 10, 0.9); +} + +.hero.is-white .subtitle a:not(.button), +.hero.is-white .subtitle strong { + color: #0a0a0a; +} + +@media screen and (max-width: 1023px) { + .hero.is-white .navbar-menu { + background-color: white; + } +} + +.hero.is-white .navbar-item, +.hero.is-white .navbar-link { + color: rgba(10, 10, 10, 0.7); +} + +.hero.is-white a.navbar-item:hover, +.hero.is-white a.navbar-item.is-active, +.hero.is-white .navbar-link:hover, +.hero.is-white .navbar-link.is-active { + background-color: #f2f2f2; + color: #0a0a0a; +} + +.hero.is-white .tabs a { + color: #0a0a0a; + opacity: 0.9; +} + +.hero.is-white .tabs a:hover { + opacity: 1; +} + +.hero.is-white .tabs li.is-active a { + opacity: 1; +} + +.hero.is-white .tabs.is-boxed a, +.hero.is-white .tabs.is-toggle a { + color: #0a0a0a; +} + +.hero.is-white .tabs.is-boxed a:hover, +.hero.is-white .tabs.is-toggle a:hover { + background-color: rgba(10, 10, 10, 0.1); +} + +.hero.is-white .tabs.is-boxed li.is-active a, +.hero.is-white .tabs.is-boxed li.is-active a:hover, +.hero.is-white .tabs.is-toggle li.is-active a, +.hero.is-white .tabs.is-toggle li.is-active a:hover { + background-color: #0a0a0a; + border-color: #0a0a0a; + color: white; +} + +.hero.is-white.is-bold { + background-image: linear-gradient(141deg, #e6e6e6 0%, white 71%, white 100%); +} + +@media screen and (max-width: 768px) { + .hero.is-white.is-bold .navbar-menu { + background-image: linear-gradient(141deg, #e6e6e6 0%, white 71%, white 100%); + } +} + +.hero.is-black { + background-color: #0a0a0a; + color: white; +} + +.hero.is-black a:not(.button):not(.dropdown-item):not(.tag), +.hero.is-black strong { + color: inherit; +} + +.hero.is-black .title { + color: white; +} + +.hero.is-black .subtitle { + color: rgba(255, 255, 255, 0.9); +} + +.hero.is-black .subtitle a:not(.button), +.hero.is-black .subtitle strong { + color: white; +} + +@media screen and (max-width: 1023px) { + .hero.is-black .navbar-menu { + background-color: #0a0a0a; + } +} + +.hero.is-black .navbar-item, +.hero.is-black .navbar-link { + color: rgba(255, 255, 255, 0.7); +} + +.hero.is-black a.navbar-item:hover, +.hero.is-black a.navbar-item.is-active, +.hero.is-black .navbar-link:hover, +.hero.is-black .navbar-link.is-active { + background-color: black; + color: white; +} + +.hero.is-black .tabs a { + color: white; + opacity: 0.9; +} + +.hero.is-black .tabs a:hover { + opacity: 1; +} + +.hero.is-black .tabs li.is-active a { + opacity: 1; +} + +.hero.is-black .tabs.is-boxed a, +.hero.is-black .tabs.is-toggle a { + color: white; +} + +.hero.is-black .tabs.is-boxed a:hover, +.hero.is-black .tabs.is-toggle a:hover { + background-color: rgba(10, 10, 10, 0.1); +} + +.hero.is-black .tabs.is-boxed li.is-active a, +.hero.is-black .tabs.is-boxed li.is-active a:hover, +.hero.is-black .tabs.is-toggle li.is-active a, +.hero.is-black .tabs.is-toggle li.is-active a:hover { + background-color: white; + border-color: white; + color: #0a0a0a; +} + +.hero.is-black.is-bold { + background-image: linear-gradient(141deg, black 0%, #0a0a0a 71%, #181616 100%); +} + +@media screen and (max-width: 768px) { + .hero.is-black.is-bold .navbar-menu { + background-image: linear-gradient(141deg, black 0%, #0a0a0a 71%, #181616 100%); + } +} + +.hero.is-light { + background-color: whitesmoke; + color: #363636; +} + +.hero.is-light a:not(.button):not(.dropdown-item):not(.tag), +.hero.is-light strong { + color: inherit; +} + +.hero.is-light .title { + color: #363636; +} + +.hero.is-light .subtitle { + color: rgba(54, 54, 54, 0.9); +} + +.hero.is-light .subtitle a:not(.button), +.hero.is-light .subtitle strong { + color: #363636; +} + +@media screen and (max-width: 1023px) { + .hero.is-light .navbar-menu { + background-color: whitesmoke; + } +} + +.hero.is-light .navbar-item, +.hero.is-light .navbar-link { + color: rgba(54, 54, 54, 0.7); +} + +.hero.is-light a.navbar-item:hover, +.hero.is-light a.navbar-item.is-active, +.hero.is-light .navbar-link:hover, +.hero.is-light .navbar-link.is-active { + background-color: #e8e8e8; + color: #363636; +} + +.hero.is-light .tabs a { + color: #363636; + opacity: 0.9; +} + +.hero.is-light .tabs a:hover { + opacity: 1; +} + +.hero.is-light .tabs li.is-active a { + opacity: 1; +} + +.hero.is-light .tabs.is-boxed a, +.hero.is-light .tabs.is-toggle a { + color: #363636; +} + +.hero.is-light .tabs.is-boxed a:hover, +.hero.is-light .tabs.is-toggle a:hover { + background-color: rgba(10, 10, 10, 0.1); +} + +.hero.is-light .tabs.is-boxed li.is-active a, +.hero.is-light .tabs.is-boxed li.is-active a:hover, +.hero.is-light .tabs.is-toggle li.is-active a, +.hero.is-light .tabs.is-toggle li.is-active a:hover { + background-color: #363636; + border-color: #363636; + color: whitesmoke; +} + +.hero.is-light.is-bold { + background-image: linear-gradient(141deg, #dfd8d9 0%, whitesmoke 71%, white 100%); +} + +@media screen and (max-width: 768px) { + .hero.is-light.is-bold .navbar-menu { + background-image: linear-gradient(141deg, #dfd8d9 0%, whitesmoke 71%, white 100%); + } +} + +.hero.is-dark { + background-color: #363636; + color: whitesmoke; +} + +.hero.is-dark a:not(.button):not(.dropdown-item):not(.tag), +.hero.is-dark strong { + color: inherit; +} + +.hero.is-dark .title { + color: whitesmoke; +} + +.hero.is-dark .subtitle { + color: rgba(245, 245, 245, 0.9); +} + +.hero.is-dark .subtitle a:not(.button), +.hero.is-dark .subtitle strong { + color: whitesmoke; +} + +@media screen and (max-width: 1023px) { + .hero.is-dark .navbar-menu { + background-color: #363636; + } +} + +.hero.is-dark .navbar-item, +.hero.is-dark .navbar-link { + color: rgba(245, 245, 245, 0.7); +} + +.hero.is-dark a.navbar-item:hover, +.hero.is-dark a.navbar-item.is-active, +.hero.is-dark .navbar-link:hover, +.hero.is-dark .navbar-link.is-active { + background-color: #292929; + color: whitesmoke; +} + +.hero.is-dark .tabs a { + color: whitesmoke; + opacity: 0.9; +} + +.hero.is-dark .tabs a:hover { + opacity: 1; +} + +.hero.is-dark .tabs li.is-active a { + opacity: 1; +} + +.hero.is-dark .tabs.is-boxed a, +.hero.is-dark .tabs.is-toggle a { + color: whitesmoke; +} + +.hero.is-dark .tabs.is-boxed a:hover, +.hero.is-dark .tabs.is-toggle a:hover { + background-color: rgba(10, 10, 10, 0.1); +} + +.hero.is-dark .tabs.is-boxed li.is-active a, +.hero.is-dark .tabs.is-boxed li.is-active a:hover, +.hero.is-dark .tabs.is-toggle li.is-active a, +.hero.is-dark .tabs.is-toggle li.is-active a:hover { + background-color: whitesmoke; + border-color: whitesmoke; + color: #363636; +} + +.hero.is-dark.is-bold { + background-image: linear-gradient(141deg, #1f191a 0%, #363636 71%, #46403f 100%); +} + +@media screen and (max-width: 768px) { + .hero.is-dark.is-bold .navbar-menu { + background-image: linear-gradient(141deg, #1f191a 0%, #363636 71%, #46403f 100%); + } +} + +.hero.is-primary { + background-color: #00d1b2; + color: #fff; +} + +.hero.is-primary a:not(.button):not(.dropdown-item):not(.tag), +.hero.is-primary strong { + color: inherit; +} + +.hero.is-primary .title { + color: #fff; +} + +.hero.is-primary .subtitle { + color: rgba(255, 255, 255, 0.9); +} + +.hero.is-primary .subtitle a:not(.button), +.hero.is-primary .subtitle strong { + color: #fff; +} + +@media screen and (max-width: 1023px) { + .hero.is-primary .navbar-menu { + background-color: #00d1b2; + } +} + +.hero.is-primary .navbar-item, +.hero.is-primary .navbar-link { + color: rgba(255, 255, 255, 0.7); +} + +.hero.is-primary a.navbar-item:hover, +.hero.is-primary a.navbar-item.is-active, +.hero.is-primary .navbar-link:hover, +.hero.is-primary .navbar-link.is-active { + background-color: #00b89c; + color: #fff; +} + +.hero.is-primary .tabs a { + color: #fff; + opacity: 0.9; +} + +.hero.is-primary .tabs a:hover { + opacity: 1; +} + +.hero.is-primary .tabs li.is-active a { + opacity: 1; +} + +.hero.is-primary .tabs.is-boxed a, +.hero.is-primary .tabs.is-toggle a { + color: #fff; +} + +.hero.is-primary .tabs.is-boxed a:hover, +.hero.is-primary .tabs.is-toggle a:hover { + background-color: rgba(10, 10, 10, 0.1); +} + +.hero.is-primary .tabs.is-boxed li.is-active a, +.hero.is-primary .tabs.is-boxed li.is-active a:hover, +.hero.is-primary .tabs.is-toggle li.is-active a, +.hero.is-primary .tabs.is-toggle li.is-active a:hover { + background-color: #fff; + border-color: #fff; + color: #00d1b2; +} + +.hero.is-primary.is-bold { + background-image: linear-gradient(141deg, #009e6c 0%, #00d1b2 71%, #00e7eb 100%); +} + +@media screen and (max-width: 768px) { + .hero.is-primary.is-bold .navbar-menu { + background-image: linear-gradient(141deg, #009e6c 0%, #00d1b2 71%, #00e7eb 100%); + } +} + +.hero.is-link { + background-color: #3273dc; + color: #fff; +} + +.hero.is-link a:not(.button):not(.dropdown-item):not(.tag), +.hero.is-link strong { + color: inherit; +} + +.hero.is-link .title { + color: #fff; +} + +.hero.is-link .subtitle { + color: rgba(255, 255, 255, 0.9); +} + +.hero.is-link .subtitle a:not(.button), +.hero.is-link .subtitle strong { + color: #fff; +} + +@media screen and (max-width: 1023px) { + .hero.is-link .navbar-menu { + background-color: #3273dc; + } +} + +.hero.is-link .navbar-item, +.hero.is-link .navbar-link { + color: rgba(255, 255, 255, 0.7); +} + +.hero.is-link a.navbar-item:hover, +.hero.is-link a.navbar-item.is-active, +.hero.is-link .navbar-link:hover, +.hero.is-link .navbar-link.is-active { + background-color: #2366d1; + color: #fff; +} + +.hero.is-link .tabs a { + color: #fff; + opacity: 0.9; +} + +.hero.is-link .tabs a:hover { + opacity: 1; +} + +.hero.is-link .tabs li.is-active a { + opacity: 1; +} + +.hero.is-link .tabs.is-boxed a, +.hero.is-link .tabs.is-toggle a { + color: #fff; +} + +.hero.is-link .tabs.is-boxed a:hover, +.hero.is-link .tabs.is-toggle a:hover { + background-color: rgba(10, 10, 10, 0.1); +} + +.hero.is-link .tabs.is-boxed li.is-active a, +.hero.is-link .tabs.is-boxed li.is-active a:hover, +.hero.is-link .tabs.is-toggle li.is-active a, +.hero.is-link .tabs.is-toggle li.is-active a:hover { + background-color: #fff; + border-color: #fff; + color: #3273dc; +} + +.hero.is-link.is-bold { + background-image: linear-gradient(141deg, #1577c6 0%, #3273dc 71%, #4366e5 100%); +} + +@media screen and (max-width: 768px) { + .hero.is-link.is-bold .navbar-menu { + background-image: linear-gradient(141deg, #1577c6 0%, #3273dc 71%, #4366e5 100%); + } +} + +.hero.is-info { + background-color: #209cee; + color: #fff; +} + +.hero.is-info a:not(.button):not(.dropdown-item):not(.tag), +.hero.is-info strong { + color: inherit; +} + +.hero.is-info .title { + color: #fff; +} + +.hero.is-info .subtitle { + color: rgba(255, 255, 255, 0.9); +} + +.hero.is-info .subtitle a:not(.button), +.hero.is-info .subtitle strong { + color: #fff; +} + +@media screen and (max-width: 1023px) { + .hero.is-info .navbar-menu { + background-color: #209cee; + } +} + +.hero.is-info .navbar-item, +.hero.is-info .navbar-link { + color: rgba(255, 255, 255, 0.7); +} + +.hero.is-info a.navbar-item:hover, +.hero.is-info a.navbar-item.is-active, +.hero.is-info .navbar-link:hover, +.hero.is-info .navbar-link.is-active { + background-color: #118fe4; + color: #fff; +} + +.hero.is-info .tabs a { + color: #fff; + opacity: 0.9; +} + +.hero.is-info .tabs a:hover { + opacity: 1; +} + +.hero.is-info .tabs li.is-active a { + opacity: 1; +} + +.hero.is-info .tabs.is-boxed a, +.hero.is-info .tabs.is-toggle a { + color: #fff; +} + +.hero.is-info .tabs.is-boxed a:hover, +.hero.is-info .tabs.is-toggle a:hover { + background-color: rgba(10, 10, 10, 0.1); +} + +.hero.is-info .tabs.is-boxed li.is-active a, +.hero.is-info .tabs.is-boxed li.is-active a:hover, +.hero.is-info .tabs.is-toggle li.is-active a, +.hero.is-info .tabs.is-toggle li.is-active a:hover { + background-color: #fff; + border-color: #fff; + color: #209cee; +} + +.hero.is-info.is-bold { + background-image: linear-gradient(141deg, #04a6d7 0%, #209cee 71%, #3287f5 100%); +} + +@media screen and (max-width: 768px) { + .hero.is-info.is-bold .navbar-menu { + background-image: linear-gradient(141deg, #04a6d7 0%, #209cee 71%, #3287f5 100%); + } +} + +.hero.is-success { + background-color: #23d160; + color: #fff; +} + +.hero.is-success a:not(.button):not(.dropdown-item):not(.tag), +.hero.is-success strong { + color: inherit; +} + +.hero.is-success .title { + color: #fff; +} + +.hero.is-success .subtitle { + color: rgba(255, 255, 255, 0.9); +} + +.hero.is-success .subtitle a:not(.button), +.hero.is-success .subtitle strong { + color: #fff; +} + +@media screen and (max-width: 1023px) { + .hero.is-success .navbar-menu { + background-color: #23d160; + } +} + +.hero.is-success .navbar-item, +.hero.is-success .navbar-link { + color: rgba(255, 255, 255, 0.7); +} + +.hero.is-success a.navbar-item:hover, +.hero.is-success a.navbar-item.is-active, +.hero.is-success .navbar-link:hover, +.hero.is-success .navbar-link.is-active { + background-color: #20bc56; + color: #fff; +} + +.hero.is-success .tabs a { + color: #fff; + opacity: 0.9; +} + +.hero.is-success .tabs a:hover { + opacity: 1; +} + +.hero.is-success .tabs li.is-active a { + opacity: 1; +} + +.hero.is-success .tabs.is-boxed a, +.hero.is-success .tabs.is-toggle a { + color: #fff; +} + +.hero.is-success .tabs.is-boxed a:hover, +.hero.is-success .tabs.is-toggle a:hover { + background-color: rgba(10, 10, 10, 0.1); +} + +.hero.is-success .tabs.is-boxed li.is-active a, +.hero.is-success .tabs.is-boxed li.is-active a:hover, +.hero.is-success .tabs.is-toggle li.is-active a, +.hero.is-success .tabs.is-toggle li.is-active a:hover { + background-color: #fff; + border-color: #fff; + color: #23d160; +} + +.hero.is-success.is-bold { + background-image: linear-gradient(141deg, #12af2f 0%, #23d160 71%, #2ce28a 100%); +} + +@media screen and (max-width: 768px) { + .hero.is-success.is-bold .navbar-menu { + background-image: linear-gradient(141deg, #12af2f 0%, #23d160 71%, #2ce28a 100%); + } +} + +.hero.is-warning { + background-color: #ffdd57; + color: rgba(0, 0, 0, 0.7); +} + +.hero.is-warning a:not(.button):not(.dropdown-item):not(.tag), +.hero.is-warning strong { + color: inherit; +} + +.hero.is-warning .title { + color: rgba(0, 0, 0, 0.7); +} + +.hero.is-warning .subtitle { + color: rgba(0, 0, 0, 0.9); +} + +.hero.is-warning .subtitle a:not(.button), +.hero.is-warning .subtitle strong { + color: rgba(0, 0, 0, 0.7); +} + +@media screen and (max-width: 1023px) { + .hero.is-warning .navbar-menu { + background-color: #ffdd57; + } +} + +.hero.is-warning .navbar-item, +.hero.is-warning .navbar-link { + color: rgba(0, 0, 0, 0.7); +} + +.hero.is-warning a.navbar-item:hover, +.hero.is-warning a.navbar-item.is-active, +.hero.is-warning .navbar-link:hover, +.hero.is-warning .navbar-link.is-active { + background-color: #ffd83d; + color: rgba(0, 0, 0, 0.7); +} + +.hero.is-warning .tabs a { + color: rgba(0, 0, 0, 0.7); + opacity: 0.9; +} + +.hero.is-warning .tabs a:hover { + opacity: 1; +} + +.hero.is-warning .tabs li.is-active a { + opacity: 1; +} + +.hero.is-warning .tabs.is-boxed a, +.hero.is-warning .tabs.is-toggle a { + color: rgba(0, 0, 0, 0.7); +} + +.hero.is-warning .tabs.is-boxed a:hover, +.hero.is-warning .tabs.is-toggle a:hover { + background-color: rgba(10, 10, 10, 0.1); +} + +.hero.is-warning .tabs.is-boxed li.is-active a, +.hero.is-warning .tabs.is-boxed li.is-active a:hover, +.hero.is-warning .tabs.is-toggle li.is-active a, +.hero.is-warning .tabs.is-toggle li.is-active a:hover { + background-color: rgba(0, 0, 0, 0.7); + border-color: rgba(0, 0, 0, 0.7); + color: #ffdd57; +} + +.hero.is-warning.is-bold { + background-image: linear-gradient(141deg, #ffaf24 0%, #ffdd57 71%, #fffa70 100%); +} + +@media screen and (max-width: 768px) { + .hero.is-warning.is-bold .navbar-menu { + background-image: linear-gradient(141deg, #ffaf24 0%, #ffdd57 71%, #fffa70 100%); + } +} + +.hero.is-danger { + background-color: #ff3860; + color: #fff; +} + +.hero.is-danger a:not(.button):not(.dropdown-item):not(.tag), +.hero.is-danger strong { + color: inherit; +} + +.hero.is-danger .title { + color: #fff; +} + +.hero.is-danger .subtitle { + color: rgba(255, 255, 255, 0.9); +} + +.hero.is-danger .subtitle a:not(.button), +.hero.is-danger .subtitle strong { + color: #fff; +} + +@media screen and (max-width: 1023px) { + .hero.is-danger .navbar-menu { + background-color: #ff3860; + } +} + +.hero.is-danger .navbar-item, +.hero.is-danger .navbar-link { + color: rgba(255, 255, 255, 0.7); +} + +.hero.is-danger a.navbar-item:hover, +.hero.is-danger a.navbar-item.is-active, +.hero.is-danger .navbar-link:hover, +.hero.is-danger .navbar-link.is-active { + background-color: #ff1f4b; + color: #fff; +} + +.hero.is-danger .tabs a { + color: #fff; + opacity: 0.9; +} + +.hero.is-danger .tabs a:hover { + opacity: 1; +} + +.hero.is-danger .tabs li.is-active a { + opacity: 1; +} + +.hero.is-danger .tabs.is-boxed a, +.hero.is-danger .tabs.is-toggle a { + color: #fff; +} + +.hero.is-danger .tabs.is-boxed a:hover, +.hero.is-danger .tabs.is-toggle a:hover { + background-color: rgba(10, 10, 10, 0.1); +} + +.hero.is-danger .tabs.is-boxed li.is-active a, +.hero.is-danger .tabs.is-boxed li.is-active a:hover, +.hero.is-danger .tabs.is-toggle li.is-active a, +.hero.is-danger .tabs.is-toggle li.is-active a:hover { + background-color: #fff; + border-color: #fff; + color: #ff3860; +} + +.hero.is-danger.is-bold { + background-image: linear-gradient(141deg, #ff0561 0%, #ff3860 71%, #ff5257 100%); +} + +@media screen and (max-width: 768px) { + .hero.is-danger.is-bold .navbar-menu { + background-image: linear-gradient(141deg, #ff0561 0%, #ff3860 71%, #ff5257 100%); + } +} + +.hero.is-small .hero-body { + padding-bottom: 1.5rem; + padding-top: 1.5rem; +} + +@media screen and (min-width: 769px), +print { + .hero.is-medium .hero-body { + padding-bottom: 9rem; + padding-top: 9rem; + } +} + +@media screen and (min-width: 769px), +print { + .hero.is-large .hero-body { + padding-bottom: 18rem; + padding-top: 18rem; + } +} + +.hero.is-halfheight .hero-body, +.hero.is-fullheight .hero-body { + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + display: -webkit-box; + display: -ms-flexbox; + display: flex; +} + +.hero.is-halfheight .hero-body>.container, +.hero.is-fullheight .hero-body>.container { + -webkit-box-flex: 1; + -ms-flex-positive: 1; + flex-grow: 1; + -ms-flex-negative: 1; + flex-shrink: 1; +} + +.hero.is-halfheight { + min-height: 50vh; +} + +.hero.is-fullheight { + min-height: 100vh; +} + +.hero-video { + bottom: 0; + left: 0; + position: absolute; + right: 0; + top: 0; + overflow: hidden; +} + +.hero-video video { + left: 50%; + min-height: 100%; + min-width: 100%; + position: absolute; + top: 50%; + -webkit-transform: translate3d(-50%, -50%, 0); + transform: translate3d(-50%, -50%, 0); +} + +.hero-video.is-transparent { + opacity: 0.3; +} + +@media screen and (max-width: 768px) { + .hero-video { + display: none; + } +} + +.hero-buttons { + margin-top: 1.5rem; +} + +@media screen and (max-width: 768px) { + .hero-buttons .button { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + } + .hero-buttons .button:not(:last-child) { + margin-bottom: 0.75rem; + } +} + +@media screen and (min-width: 769px), +print { + .hero-buttons { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + } + .hero-buttons .button:not(:last-child) { + margin-right: 1.5rem; + } +} + +.hero-head, +.hero-foot { + -webkit-box-flex: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; +} + +.hero-body { + -webkit-box-flex: 1; + -ms-flex-positive: 1; + flex-grow: 1; + -ms-flex-negative: 0; + flex-shrink: 0; + padding: 3rem 1.5rem; +} + +.section { + padding: 3rem 1.5rem; +} + +@media screen and (min-width: 1024px) { + .section.is-medium { + padding: 9rem 1.5rem; + } + .section.is-large { + padding: 18rem 1.5rem; + } +} + +.footer { + background-color: whitesmoke; + padding: 3rem 1.5rem 6rem; +} + + +/*# sourceMappingURL=bulma.css.map */ \ No newline at end of file diff --git a/user/themes/bulma-portfolio/css/svg.css b/user/themes/bulma-portfolio/css/svg.css new file mode 100644 index 00000000..4d73a87d --- /dev/null +++ b/user/themes/bulma-portfolio/css/svg.css @@ -0,0 +1,3 @@ +svg { + fill: none; + stroke: deepskyblue; } diff --git a/user/themes/bulma-portfolio/images/feather/activity.svg b/user/themes/bulma-portfolio/images/feather/activity.svg new file mode 100644 index 00000000..669a57a7 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/activity.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/airplay.svg b/user/themes/bulma-portfolio/images/feather/airplay.svg new file mode 100644 index 00000000..7ce73022 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/airplay.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/alert-circle.svg b/user/themes/bulma-portfolio/images/feather/alert-circle.svg new file mode 100644 index 00000000..6b41c0b9 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/alert-circle.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/alert-octagon.svg b/user/themes/bulma-portfolio/images/feather/alert-octagon.svg new file mode 100644 index 00000000..6943b6d0 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/alert-octagon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/alert-triangle.svg b/user/themes/bulma-portfolio/images/feather/alert-triangle.svg new file mode 100644 index 00000000..59e65b15 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/alert-triangle.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/align-center.svg b/user/themes/bulma-portfolio/images/feather/align-center.svg new file mode 100644 index 00000000..5b8842ea --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/align-center.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/align-justify.svg b/user/themes/bulma-portfolio/images/feather/align-justify.svg new file mode 100644 index 00000000..0539876f --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/align-justify.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/align-left.svg b/user/themes/bulma-portfolio/images/feather/align-left.svg new file mode 100644 index 00000000..9ac852a5 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/align-left.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/align-right.svg b/user/themes/bulma-portfolio/images/feather/align-right.svg new file mode 100644 index 00000000..ef139ffa --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/align-right.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/anchor.svg b/user/themes/bulma-portfolio/images/feather/anchor.svg new file mode 100644 index 00000000..e01627a3 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/anchor.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/aperture.svg b/user/themes/bulma-portfolio/images/feather/aperture.svg new file mode 100644 index 00000000..9936e868 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/aperture.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/arrow-down-circle.svg b/user/themes/bulma-portfolio/images/feather/arrow-down-circle.svg new file mode 100644 index 00000000..3238091b --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/arrow-down-circle.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/arrow-down-left.svg b/user/themes/bulma-portfolio/images/feather/arrow-down-left.svg new file mode 100644 index 00000000..72483584 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/arrow-down-left.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/arrow-down-right.svg b/user/themes/bulma-portfolio/images/feather/arrow-down-right.svg new file mode 100644 index 00000000..81d9822b --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/arrow-down-right.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/arrow-down.svg b/user/themes/bulma-portfolio/images/feather/arrow-down.svg new file mode 100644 index 00000000..4f84f627 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/arrow-down.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/arrow-left-circle.svg b/user/themes/bulma-portfolio/images/feather/arrow-left-circle.svg new file mode 100644 index 00000000..3b19ff8a --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/arrow-left-circle.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/arrow-left.svg b/user/themes/bulma-portfolio/images/feather/arrow-left.svg new file mode 100644 index 00000000..a5058fc7 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/arrow-left.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/arrow-right-circle.svg b/user/themes/bulma-portfolio/images/feather/arrow-right-circle.svg new file mode 100644 index 00000000..ff01dd58 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/arrow-right-circle.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/arrow-right.svg b/user/themes/bulma-portfolio/images/feather/arrow-right.svg new file mode 100644 index 00000000..939b57c5 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/arrow-right.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/arrow-up-circle.svg b/user/themes/bulma-portfolio/images/feather/arrow-up-circle.svg new file mode 100644 index 00000000..044a75d3 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/arrow-up-circle.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/arrow-up-left.svg b/user/themes/bulma-portfolio/images/feather/arrow-up-left.svg new file mode 100644 index 00000000..cea55e87 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/arrow-up-left.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/arrow-up-right.svg b/user/themes/bulma-portfolio/images/feather/arrow-up-right.svg new file mode 100644 index 00000000..95678e00 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/arrow-up-right.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/arrow-up.svg b/user/themes/bulma-portfolio/images/feather/arrow-up.svg new file mode 100644 index 00000000..16b13aba --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/arrow-up.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/at-sign.svg b/user/themes/bulma-portfolio/images/feather/at-sign.svg new file mode 100644 index 00000000..5a5e5d0d --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/at-sign.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/award.svg b/user/themes/bulma-portfolio/images/feather/award.svg new file mode 100644 index 00000000..be70d5a1 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/award.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/bar-chart-2.svg b/user/themes/bulma-portfolio/images/feather/bar-chart-2.svg new file mode 100644 index 00000000..864167a6 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/bar-chart-2.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/bar-chart.svg b/user/themes/bulma-portfolio/images/feather/bar-chart.svg new file mode 100644 index 00000000..074d7c1a --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/bar-chart.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/battery-charging.svg b/user/themes/bulma-portfolio/images/feather/battery-charging.svg new file mode 100644 index 00000000..644cb59c --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/battery-charging.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/battery.svg b/user/themes/bulma-portfolio/images/feather/battery.svg new file mode 100644 index 00000000..7fe87710 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/battery.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/bell-off.svg b/user/themes/bulma-portfolio/images/feather/bell-off.svg new file mode 100644 index 00000000..b73bcb2d --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/bell-off.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/bell.svg b/user/themes/bulma-portfolio/images/feather/bell.svg new file mode 100644 index 00000000..94c5d207 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/bell.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/bluetooth.svg b/user/themes/bulma-portfolio/images/feather/bluetooth.svg new file mode 100644 index 00000000..cebed7b1 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/bluetooth.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/bold.svg b/user/themes/bulma-portfolio/images/feather/bold.svg new file mode 100644 index 00000000..d1a4efd3 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/bold.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/book-open.svg b/user/themes/bulma-portfolio/images/feather/book-open.svg new file mode 100644 index 00000000..5e0ca0ab --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/book-open.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/book.svg b/user/themes/bulma-portfolio/images/feather/book.svg new file mode 100644 index 00000000..12ffcbc4 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/book.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/bookmark.svg b/user/themes/bulma-portfolio/images/feather/bookmark.svg new file mode 100644 index 00000000..2239cc58 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/bookmark.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/box.svg b/user/themes/bulma-portfolio/images/feather/box.svg new file mode 100644 index 00000000..6711535b --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/box.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/briefcase.svg b/user/themes/bulma-portfolio/images/feather/briefcase.svg new file mode 100644 index 00000000..e3af0506 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/briefcase.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/calendar.svg b/user/themes/bulma-portfolio/images/feather/calendar.svg new file mode 100644 index 00000000..6c7fd870 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/calendar.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/camera-off.svg b/user/themes/bulma-portfolio/images/feather/camera-off.svg new file mode 100644 index 00000000..daa3e25f --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/camera-off.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/camera.svg b/user/themes/bulma-portfolio/images/feather/camera.svg new file mode 100644 index 00000000..0e7f0603 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/camera.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/cast.svg b/user/themes/bulma-portfolio/images/feather/cast.svg new file mode 100644 index 00000000..9e27cb48 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/cast.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/check-circle.svg b/user/themes/bulma-portfolio/images/feather/check-circle.svg new file mode 100644 index 00000000..f2f4fd1a --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/check-circle.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/check-square.svg b/user/themes/bulma-portfolio/images/feather/check-square.svg new file mode 100644 index 00000000..72ab7a80 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/check-square.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/check.svg b/user/themes/bulma-portfolio/images/feather/check.svg new file mode 100644 index 00000000..1c209899 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/check.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/chevron-down.svg b/user/themes/bulma-portfolio/images/feather/chevron-down.svg new file mode 100644 index 00000000..278c6a31 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/chevron-down.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/chevron-left.svg b/user/themes/bulma-portfolio/images/feather/chevron-left.svg new file mode 100644 index 00000000..747d46d9 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/chevron-left.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/chevron-right.svg b/user/themes/bulma-portfolio/images/feather/chevron-right.svg new file mode 100644 index 00000000..258de414 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/chevron-right.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/chevron-up.svg b/user/themes/bulma-portfolio/images/feather/chevron-up.svg new file mode 100644 index 00000000..4eb5ecc3 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/chevron-up.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/chevrons-down.svg b/user/themes/bulma-portfolio/images/feather/chevrons-down.svg new file mode 100644 index 00000000..e67ef2fb --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/chevrons-down.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/chevrons-left.svg b/user/themes/bulma-portfolio/images/feather/chevrons-left.svg new file mode 100644 index 00000000..c32e3983 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/chevrons-left.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/chevrons-right.svg b/user/themes/bulma-portfolio/images/feather/chevrons-right.svg new file mode 100644 index 00000000..f5068145 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/chevrons-right.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/chevrons-up.svg b/user/themes/bulma-portfolio/images/feather/chevrons-up.svg new file mode 100644 index 00000000..0eaf5183 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/chevrons-up.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/chrome.svg b/user/themes/bulma-portfolio/images/feather/chrome.svg new file mode 100644 index 00000000..9189815e --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/chrome.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/circle.svg b/user/themes/bulma-portfolio/images/feather/circle.svg new file mode 100644 index 00000000..b0090882 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/circle.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/clipboard.svg b/user/themes/bulma-portfolio/images/feather/clipboard.svg new file mode 100644 index 00000000..ccee454d --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/clipboard.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/clock.svg b/user/themes/bulma-portfolio/images/feather/clock.svg new file mode 100644 index 00000000..ea3f5e50 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/clock.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/cloud-drizzle.svg b/user/themes/bulma-portfolio/images/feather/cloud-drizzle.svg new file mode 100644 index 00000000..13af6bb5 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/cloud-drizzle.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/cloud-lightning.svg b/user/themes/bulma-portfolio/images/feather/cloud-lightning.svg new file mode 100644 index 00000000..32d154cc --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/cloud-lightning.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/cloud-off.svg b/user/themes/bulma-portfolio/images/feather/cloud-off.svg new file mode 100644 index 00000000..1e1e7d60 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/cloud-off.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/cloud-rain.svg b/user/themes/bulma-portfolio/images/feather/cloud-rain.svg new file mode 100644 index 00000000..3e0b85b0 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/cloud-rain.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/cloud-snow.svg b/user/themes/bulma-portfolio/images/feather/cloud-snow.svg new file mode 100644 index 00000000..78e0008b --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/cloud-snow.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/cloud.svg b/user/themes/bulma-portfolio/images/feather/cloud.svg new file mode 100644 index 00000000..0ee0c632 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/cloud.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/code.svg b/user/themes/bulma-portfolio/images/feather/code.svg new file mode 100644 index 00000000..c4954b55 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/code.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/codepen.svg b/user/themes/bulma-portfolio/images/feather/codepen.svg new file mode 100644 index 00000000..ab2a815a --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/codepen.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/command.svg b/user/themes/bulma-portfolio/images/feather/command.svg new file mode 100644 index 00000000..93f554c3 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/command.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/compass.svg b/user/themes/bulma-portfolio/images/feather/compass.svg new file mode 100644 index 00000000..32962608 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/compass.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/copy.svg b/user/themes/bulma-portfolio/images/feather/copy.svg new file mode 100644 index 00000000..4e0b09f1 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/copy.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/corner-down-left.svg b/user/themes/bulma-portfolio/images/feather/corner-down-left.svg new file mode 100644 index 00000000..9fffb3e9 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/corner-down-left.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/corner-down-right.svg b/user/themes/bulma-portfolio/images/feather/corner-down-right.svg new file mode 100644 index 00000000..b27d408d --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/corner-down-right.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/corner-left-down.svg b/user/themes/bulma-portfolio/images/feather/corner-left-down.svg new file mode 100644 index 00000000..24b8375c --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/corner-left-down.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/corner-left-up.svg b/user/themes/bulma-portfolio/images/feather/corner-left-up.svg new file mode 100644 index 00000000..e54527cd --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/corner-left-up.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/corner-right-down.svg b/user/themes/bulma-portfolio/images/feather/corner-right-down.svg new file mode 100644 index 00000000..a49e6d6c --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/corner-right-down.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/corner-right-up.svg b/user/themes/bulma-portfolio/images/feather/corner-right-up.svg new file mode 100644 index 00000000..a5c5dce5 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/corner-right-up.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/corner-up-left.svg b/user/themes/bulma-portfolio/images/feather/corner-up-left.svg new file mode 100644 index 00000000..0a1ffd61 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/corner-up-left.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/corner-up-right.svg b/user/themes/bulma-portfolio/images/feather/corner-up-right.svg new file mode 100644 index 00000000..0b8f961b --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/corner-up-right.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/cpu.svg b/user/themes/bulma-portfolio/images/feather/cpu.svg new file mode 100644 index 00000000..2ed16ef7 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/cpu.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/credit-card.svg b/user/themes/bulma-portfolio/images/feather/credit-card.svg new file mode 100644 index 00000000..1b7fd029 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/credit-card.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/crop.svg b/user/themes/bulma-portfolio/images/feather/crop.svg new file mode 100644 index 00000000..ffbfd045 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/crop.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/crosshair.svg b/user/themes/bulma-portfolio/images/feather/crosshair.svg new file mode 100644 index 00000000..ba394015 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/crosshair.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/database.svg b/user/themes/bulma-portfolio/images/feather/database.svg new file mode 100644 index 00000000..c296fbcf --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/database.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/delete.svg b/user/themes/bulma-portfolio/images/feather/delete.svg new file mode 100644 index 00000000..8c6074b9 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/delete.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/disc.svg b/user/themes/bulma-portfolio/images/feather/disc.svg new file mode 100644 index 00000000..2595b444 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/disc.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/dollar-sign.svg b/user/themes/bulma-portfolio/images/feather/dollar-sign.svg new file mode 100644 index 00000000..1a124d26 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/dollar-sign.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/download-cloud.svg b/user/themes/bulma-portfolio/images/feather/download-cloud.svg new file mode 100644 index 00000000..f3126fc3 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/download-cloud.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/download.svg b/user/themes/bulma-portfolio/images/feather/download.svg new file mode 100644 index 00000000..76767a92 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/download.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/droplet.svg b/user/themes/bulma-portfolio/images/feather/droplet.svg new file mode 100644 index 00000000..ca093014 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/droplet.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/edit-2.svg b/user/themes/bulma-portfolio/images/feather/edit-2.svg new file mode 100644 index 00000000..867fde42 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/edit-2.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/edit-3.svg b/user/themes/bulma-portfolio/images/feather/edit-3.svg new file mode 100644 index 00000000..310732cc --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/edit-3.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/edit.svg b/user/themes/bulma-portfolio/images/feather/edit.svg new file mode 100644 index 00000000..ed7fdfdd --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/edit.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/external-link.svg b/user/themes/bulma-portfolio/images/feather/external-link.svg new file mode 100644 index 00000000..6236df3e --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/external-link.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/eye-off.svg b/user/themes/bulma-portfolio/images/feather/eye-off.svg new file mode 100644 index 00000000..77c54cb4 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/eye-off.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/eye.svg b/user/themes/bulma-portfolio/images/feather/eye.svg new file mode 100644 index 00000000..9cde2437 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/eye.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/facebook.svg b/user/themes/bulma-portfolio/images/feather/facebook.svg new file mode 100644 index 00000000..2570f56a --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/facebook.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/fast-forward.svg b/user/themes/bulma-portfolio/images/feather/fast-forward.svg new file mode 100644 index 00000000..fa39877a --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/fast-forward.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/feather.svg b/user/themes/bulma-portfolio/images/feather/feather.svg new file mode 100644 index 00000000..3ce3d84c --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/feather.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/file-minus.svg b/user/themes/bulma-portfolio/images/feather/file-minus.svg new file mode 100644 index 00000000..345756ef --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/file-minus.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/file-plus.svg b/user/themes/bulma-portfolio/images/feather/file-plus.svg new file mode 100644 index 00000000..eed12004 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/file-plus.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/file-text.svg b/user/themes/bulma-portfolio/images/feather/file-text.svg new file mode 100644 index 00000000..4197ddd4 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/file-text.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/file.svg b/user/themes/bulma-portfolio/images/feather/file.svg new file mode 100644 index 00000000..378519ab --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/file.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/film.svg b/user/themes/bulma-portfolio/images/feather/film.svg new file mode 100644 index 00000000..ac46360d --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/film.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/filter.svg b/user/themes/bulma-portfolio/images/feather/filter.svg new file mode 100644 index 00000000..38a47e04 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/filter.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/flag.svg b/user/themes/bulma-portfolio/images/feather/flag.svg new file mode 100644 index 00000000..037737cb --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/flag.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/folder-minus.svg b/user/themes/bulma-portfolio/images/feather/folder-minus.svg new file mode 100644 index 00000000..d5b7af65 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/folder-minus.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/folder-plus.svg b/user/themes/bulma-portfolio/images/feather/folder-plus.svg new file mode 100644 index 00000000..898f2fc9 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/folder-plus.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/folder.svg b/user/themes/bulma-portfolio/images/feather/folder.svg new file mode 100644 index 00000000..134458b9 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/folder.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/git-branch.svg b/user/themes/bulma-portfolio/images/feather/git-branch.svg new file mode 100644 index 00000000..44003726 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/git-branch.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/git-commit.svg b/user/themes/bulma-portfolio/images/feather/git-commit.svg new file mode 100644 index 00000000..e959d725 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/git-commit.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/git-merge.svg b/user/themes/bulma-portfolio/images/feather/git-merge.svg new file mode 100644 index 00000000..c65fffdd --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/git-merge.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/git-pull-request.svg b/user/themes/bulma-portfolio/images/feather/git-pull-request.svg new file mode 100644 index 00000000..fc80bdfd --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/git-pull-request.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/github.svg b/user/themes/bulma-portfolio/images/feather/github.svg new file mode 100644 index 00000000..ff0af481 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/github.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/gitlab.svg b/user/themes/bulma-portfolio/images/feather/gitlab.svg new file mode 100644 index 00000000..85d54a1e --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/gitlab.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/globe.svg b/user/themes/bulma-portfolio/images/feather/globe.svg new file mode 100644 index 00000000..0a0586d3 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/globe.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/grid.svg b/user/themes/bulma-portfolio/images/feather/grid.svg new file mode 100644 index 00000000..8ef2e9d8 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/grid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/hard-drive.svg b/user/themes/bulma-portfolio/images/feather/hard-drive.svg new file mode 100644 index 00000000..c08131d6 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/hard-drive.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/hash.svg b/user/themes/bulma-portfolio/images/feather/hash.svg new file mode 100644 index 00000000..c9c8d41f --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/hash.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/headphones.svg b/user/themes/bulma-portfolio/images/feather/headphones.svg new file mode 100644 index 00000000..fd8915b4 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/headphones.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/heart.svg b/user/themes/bulma-portfolio/images/feather/heart.svg new file mode 100644 index 00000000..a083b7e2 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/heart.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/help-circle.svg b/user/themes/bulma-portfolio/images/feather/help-circle.svg new file mode 100644 index 00000000..9173eb0f --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/help-circle.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/home.svg b/user/themes/bulma-portfolio/images/feather/home.svg new file mode 100644 index 00000000..7bb31b23 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/home.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/image.svg b/user/themes/bulma-portfolio/images/feather/image.svg new file mode 100644 index 00000000..a7d84b98 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/image.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/inbox.svg b/user/themes/bulma-portfolio/images/feather/inbox.svg new file mode 100644 index 00000000..03a13b4e --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/inbox.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/info.svg b/user/themes/bulma-portfolio/images/feather/info.svg new file mode 100644 index 00000000..332616d8 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/info.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/instagram.svg b/user/themes/bulma-portfolio/images/feather/instagram.svg new file mode 100644 index 00000000..c0a95628 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/instagram.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/italic.svg b/user/themes/bulma-portfolio/images/feather/italic.svg new file mode 100644 index 00000000..a123d371 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/italic.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/layers.svg b/user/themes/bulma-portfolio/images/feather/layers.svg new file mode 100644 index 00000000..ea788c22 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/layers.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/layout.svg b/user/themes/bulma-portfolio/images/feather/layout.svg new file mode 100644 index 00000000..28743d92 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/layout.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/life-buoy.svg b/user/themes/bulma-portfolio/images/feather/life-buoy.svg new file mode 100644 index 00000000..54c2bd7d --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/life-buoy.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/link-2.svg b/user/themes/bulma-portfolio/images/feather/link-2.svg new file mode 100644 index 00000000..8cc7f6dd --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/link-2.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/link.svg b/user/themes/bulma-portfolio/images/feather/link.svg new file mode 100644 index 00000000..c89dd41c --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/link.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/linkedin.svg b/user/themes/bulma-portfolio/images/feather/linkedin.svg new file mode 100644 index 00000000..39531094 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/linkedin.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/list.svg b/user/themes/bulma-portfolio/images/feather/list.svg new file mode 100644 index 00000000..e7344989 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/list.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/loader.svg b/user/themes/bulma-portfolio/images/feather/loader.svg new file mode 100644 index 00000000..e1a70c12 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/loader.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/lock.svg b/user/themes/bulma-portfolio/images/feather/lock.svg new file mode 100644 index 00000000..de09d9db --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/lock.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/log-in.svg b/user/themes/bulma-portfolio/images/feather/log-in.svg new file mode 100644 index 00000000..ba0da59a --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/log-in.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/log-out.svg b/user/themes/bulma-portfolio/images/feather/log-out.svg new file mode 100644 index 00000000..c9002c90 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/log-out.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/mail.svg b/user/themes/bulma-portfolio/images/feather/mail.svg new file mode 100644 index 00000000..2af169e8 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/mail.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/map-pin.svg b/user/themes/bulma-portfolio/images/feather/map-pin.svg new file mode 100644 index 00000000..d5548e92 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/map-pin.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/map.svg b/user/themes/bulma-portfolio/images/feather/map.svg new file mode 100644 index 00000000..ecebd7bf --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/map.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/maximize-2.svg b/user/themes/bulma-portfolio/images/feather/maximize-2.svg new file mode 100644 index 00000000..e41fc0b7 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/maximize-2.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/maximize.svg b/user/themes/bulma-portfolio/images/feather/maximize.svg new file mode 100644 index 00000000..fc305189 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/maximize.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/menu.svg b/user/themes/bulma-portfolio/images/feather/menu.svg new file mode 100644 index 00000000..e8a84a95 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/menu.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/message-circle.svg b/user/themes/bulma-portfolio/images/feather/message-circle.svg new file mode 100644 index 00000000..4b21b32b --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/message-circle.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/message-square.svg b/user/themes/bulma-portfolio/images/feather/message-square.svg new file mode 100644 index 00000000..6a2e4e59 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/message-square.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/mic-off.svg b/user/themes/bulma-portfolio/images/feather/mic-off.svg new file mode 100644 index 00000000..0786219c --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/mic-off.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/mic.svg b/user/themes/bulma-portfolio/images/feather/mic.svg new file mode 100644 index 00000000..dc5f780c --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/mic.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/minimize-2.svg b/user/themes/bulma-portfolio/images/feather/minimize-2.svg new file mode 100644 index 00000000..a720fa6c --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/minimize-2.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/minimize.svg b/user/themes/bulma-portfolio/images/feather/minimize.svg new file mode 100644 index 00000000..46d61196 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/minimize.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/minus-circle.svg b/user/themes/bulma-portfolio/images/feather/minus-circle.svg new file mode 100644 index 00000000..80c0de1e --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/minus-circle.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/minus-square.svg b/user/themes/bulma-portfolio/images/feather/minus-square.svg new file mode 100644 index 00000000..4862832a --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/minus-square.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/minus.svg b/user/themes/bulma-portfolio/images/feather/minus.svg new file mode 100644 index 00000000..93cc7340 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/minus.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/monitor.svg b/user/themes/bulma-portfolio/images/feather/monitor.svg new file mode 100644 index 00000000..6c3556db --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/monitor.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/moon.svg b/user/themes/bulma-portfolio/images/feather/moon.svg new file mode 100644 index 00000000..dbf7c6cf --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/moon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/more-horizontal.svg b/user/themes/bulma-portfolio/images/feather/more-horizontal.svg new file mode 100644 index 00000000..dc6a8556 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/more-horizontal.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/more-vertical.svg b/user/themes/bulma-portfolio/images/feather/more-vertical.svg new file mode 100644 index 00000000..cba6958f --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/more-vertical.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/move.svg b/user/themes/bulma-portfolio/images/feather/move.svg new file mode 100644 index 00000000..4e251b56 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/move.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/music.svg b/user/themes/bulma-portfolio/images/feather/music.svg new file mode 100644 index 00000000..2f804f96 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/music.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/navigation-2.svg b/user/themes/bulma-portfolio/images/feather/navigation-2.svg new file mode 100644 index 00000000..ae31db96 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/navigation-2.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/navigation.svg b/user/themes/bulma-portfolio/images/feather/navigation.svg new file mode 100644 index 00000000..f600a414 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/navigation.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/octagon.svg b/user/themes/bulma-portfolio/images/feather/octagon.svg new file mode 100644 index 00000000..124c5483 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/octagon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/package.svg b/user/themes/bulma-portfolio/images/feather/package.svg new file mode 100644 index 00000000..0c9c823e --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/package.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/paperclip.svg b/user/themes/bulma-portfolio/images/feather/paperclip.svg new file mode 100644 index 00000000..b1f69b7a --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/paperclip.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/pause-circle.svg b/user/themes/bulma-portfolio/images/feather/pause-circle.svg new file mode 100644 index 00000000..f6b1a8df --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/pause-circle.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/pause.svg b/user/themes/bulma-portfolio/images/feather/pause.svg new file mode 100644 index 00000000..4e78038d --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/pause.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/percent.svg b/user/themes/bulma-portfolio/images/feather/percent.svg new file mode 100644 index 00000000..2cb9719d --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/percent.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/phone-call.svg b/user/themes/bulma-portfolio/images/feather/phone-call.svg new file mode 100644 index 00000000..8b866602 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/phone-call.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/phone-forwarded.svg b/user/themes/bulma-portfolio/images/feather/phone-forwarded.svg new file mode 100644 index 00000000..aa21befc --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/phone-forwarded.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/phone-incoming.svg b/user/themes/bulma-portfolio/images/feather/phone-incoming.svg new file mode 100644 index 00000000..b2d523a8 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/phone-incoming.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/phone-missed.svg b/user/themes/bulma-portfolio/images/feather/phone-missed.svg new file mode 100644 index 00000000..4950f09f --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/phone-missed.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/phone-off.svg b/user/themes/bulma-portfolio/images/feather/phone-off.svg new file mode 100644 index 00000000..4d00fb3d --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/phone-off.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/phone-outgoing.svg b/user/themes/bulma-portfolio/images/feather/phone-outgoing.svg new file mode 100644 index 00000000..fea27a37 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/phone-outgoing.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/phone.svg b/user/themes/bulma-portfolio/images/feather/phone.svg new file mode 100644 index 00000000..2a35154a --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/phone.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/pie-chart.svg b/user/themes/bulma-portfolio/images/feather/pie-chart.svg new file mode 100644 index 00000000..b5bbe67c --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/pie-chart.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/play-circle.svg b/user/themes/bulma-portfolio/images/feather/play-circle.svg new file mode 100644 index 00000000..8766dc7b --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/play-circle.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/play.svg b/user/themes/bulma-portfolio/images/feather/play.svg new file mode 100644 index 00000000..fd76e30d --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/play.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/plus-circle.svg b/user/themes/bulma-portfolio/images/feather/plus-circle.svg new file mode 100644 index 00000000..4291ff05 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/plus-circle.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/plus-square.svg b/user/themes/bulma-portfolio/images/feather/plus-square.svg new file mode 100644 index 00000000..c380e24b --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/plus-square.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/plus.svg b/user/themes/bulma-portfolio/images/feather/plus.svg new file mode 100644 index 00000000..703c5b7b --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/plus.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/pocket.svg b/user/themes/bulma-portfolio/images/feather/pocket.svg new file mode 100644 index 00000000..a3b25619 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/pocket.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/power.svg b/user/themes/bulma-portfolio/images/feather/power.svg new file mode 100644 index 00000000..598308fc --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/power.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/printer.svg b/user/themes/bulma-portfolio/images/feather/printer.svg new file mode 100644 index 00000000..8a9a7ace --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/printer.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/radio.svg b/user/themes/bulma-portfolio/images/feather/radio.svg new file mode 100644 index 00000000..5abfcd13 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/radio.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/refresh-ccw.svg b/user/themes/bulma-portfolio/images/feather/refresh-ccw.svg new file mode 100644 index 00000000..10cff0ec --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/refresh-ccw.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/refresh-cw.svg b/user/themes/bulma-portfolio/images/feather/refresh-cw.svg new file mode 100644 index 00000000..06c358dd --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/refresh-cw.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/repeat.svg b/user/themes/bulma-portfolio/images/feather/repeat.svg new file mode 100644 index 00000000..c7657b08 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/repeat.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/rewind.svg b/user/themes/bulma-portfolio/images/feather/rewind.svg new file mode 100644 index 00000000..7b0fa3d5 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/rewind.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/rotate-ccw.svg b/user/themes/bulma-portfolio/images/feather/rotate-ccw.svg new file mode 100644 index 00000000..ade5dc42 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/rotate-ccw.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/rotate-cw.svg b/user/themes/bulma-portfolio/images/feather/rotate-cw.svg new file mode 100644 index 00000000..83dca351 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/rotate-cw.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/rss.svg b/user/themes/bulma-portfolio/images/feather/rss.svg new file mode 100644 index 00000000..c9a13684 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/rss.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/save.svg b/user/themes/bulma-portfolio/images/feather/save.svg new file mode 100644 index 00000000..46c72990 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/save.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/scissors.svg b/user/themes/bulma-portfolio/images/feather/scissors.svg new file mode 100644 index 00000000..fd0647ff --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/scissors.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/search.svg b/user/themes/bulma-portfolio/images/feather/search.svg new file mode 100644 index 00000000..8710306d --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/search.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/send.svg b/user/themes/bulma-portfolio/images/feather/send.svg new file mode 100644 index 00000000..42ef2a24 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/send.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/server.svg b/user/themes/bulma-portfolio/images/feather/server.svg new file mode 100644 index 00000000..d1f6d487 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/server.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/settings.svg b/user/themes/bulma-portfolio/images/feather/settings.svg new file mode 100644 index 00000000..19c27265 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/settings.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/share-2.svg b/user/themes/bulma-portfolio/images/feather/share-2.svg new file mode 100644 index 00000000..09b1c7bc --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/share-2.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/share.svg b/user/themes/bulma-portfolio/images/feather/share.svg new file mode 100644 index 00000000..df38c14d --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/share.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/shield-off.svg b/user/themes/bulma-portfolio/images/feather/shield-off.svg new file mode 100644 index 00000000..18692ddd --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/shield-off.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/shield.svg b/user/themes/bulma-portfolio/images/feather/shield.svg new file mode 100644 index 00000000..c7c48413 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/shield.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/shopping-bag.svg b/user/themes/bulma-portfolio/images/feather/shopping-bag.svg new file mode 100644 index 00000000..eaa39e81 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/shopping-bag.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/shopping-cart.svg b/user/themes/bulma-portfolio/images/feather/shopping-cart.svg new file mode 100644 index 00000000..17a40bf4 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/shopping-cart.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/shuffle.svg b/user/themes/bulma-portfolio/images/feather/shuffle.svg new file mode 100644 index 00000000..8cfb5db5 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/shuffle.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/sidebar.svg b/user/themes/bulma-portfolio/images/feather/sidebar.svg new file mode 100644 index 00000000..8ba817e6 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/sidebar.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/skip-back.svg b/user/themes/bulma-portfolio/images/feather/skip-back.svg new file mode 100644 index 00000000..88d024e2 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/skip-back.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/skip-forward.svg b/user/themes/bulma-portfolio/images/feather/skip-forward.svg new file mode 100644 index 00000000..f3fdac3a --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/skip-forward.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/slack.svg b/user/themes/bulma-portfolio/images/feather/slack.svg new file mode 100644 index 00000000..0136cb41 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/slack.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/slash.svg b/user/themes/bulma-portfolio/images/feather/slash.svg new file mode 100644 index 00000000..f4131b85 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/slash.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/sliders.svg b/user/themes/bulma-portfolio/images/feather/sliders.svg new file mode 100644 index 00000000..19c93852 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/sliders.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/smartphone.svg b/user/themes/bulma-portfolio/images/feather/smartphone.svg new file mode 100644 index 00000000..f7d5ba8e --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/smartphone.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/speaker.svg b/user/themes/bulma-portfolio/images/feather/speaker.svg new file mode 100644 index 00000000..8e7ffdaf --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/speaker.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/square.svg b/user/themes/bulma-portfolio/images/feather/square.svg new file mode 100644 index 00000000..6eabc77d --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/square.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/star.svg b/user/themes/bulma-portfolio/images/feather/star.svg new file mode 100644 index 00000000..bcdc31aa --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/star.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/stop-circle.svg b/user/themes/bulma-portfolio/images/feather/stop-circle.svg new file mode 100644 index 00000000..c10d9d47 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/stop-circle.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/sun.svg b/user/themes/bulma-portfolio/images/feather/sun.svg new file mode 100644 index 00000000..7f51b94d --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/sun.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/sunrise.svg b/user/themes/bulma-portfolio/images/feather/sunrise.svg new file mode 100644 index 00000000..eff4b1e4 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/sunrise.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/sunset.svg b/user/themes/bulma-portfolio/images/feather/sunset.svg new file mode 100644 index 00000000..a5a22215 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/sunset.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/tablet.svg b/user/themes/bulma-portfolio/images/feather/tablet.svg new file mode 100644 index 00000000..76f58494 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/tablet.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/tag.svg b/user/themes/bulma-portfolio/images/feather/tag.svg new file mode 100644 index 00000000..b5e495cb --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/tag.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/target.svg b/user/themes/bulma-portfolio/images/feather/target.svg new file mode 100644 index 00000000..be84b17c --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/target.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/terminal.svg b/user/themes/bulma-portfolio/images/feather/terminal.svg new file mode 100644 index 00000000..af459c04 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/terminal.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/thermometer.svg b/user/themes/bulma-portfolio/images/feather/thermometer.svg new file mode 100644 index 00000000..33142ccc --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/thermometer.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/thumbs-down.svg b/user/themes/bulma-portfolio/images/feather/thumbs-down.svg new file mode 100644 index 00000000..3e7bcd6d --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/thumbs-down.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/thumbs-up.svg b/user/themes/bulma-portfolio/images/feather/thumbs-up.svg new file mode 100644 index 00000000..226c44d8 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/thumbs-up.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/toggle-left.svg b/user/themes/bulma-portfolio/images/feather/toggle-left.svg new file mode 100644 index 00000000..240be290 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/toggle-left.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/toggle-right.svg b/user/themes/bulma-portfolio/images/feather/toggle-right.svg new file mode 100644 index 00000000..fc6e81c1 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/toggle-right.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/trash-2.svg b/user/themes/bulma-portfolio/images/feather/trash-2.svg new file mode 100644 index 00000000..f24d55bf --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/trash-2.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/trash.svg b/user/themes/bulma-portfolio/images/feather/trash.svg new file mode 100644 index 00000000..55650bd4 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/trash.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/trending-down.svg b/user/themes/bulma-portfolio/images/feather/trending-down.svg new file mode 100644 index 00000000..a9d4cfa5 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/trending-down.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/trending-up.svg b/user/themes/bulma-portfolio/images/feather/trending-up.svg new file mode 100644 index 00000000..52026a4d --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/trending-up.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/triangle.svg b/user/themes/bulma-portfolio/images/feather/triangle.svg new file mode 100644 index 00000000..274b6528 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/triangle.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/truck.svg b/user/themes/bulma-portfolio/images/feather/truck.svg new file mode 100644 index 00000000..33898373 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/truck.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/tv.svg b/user/themes/bulma-portfolio/images/feather/tv.svg new file mode 100644 index 00000000..955bbfff --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/tv.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/twitter.svg b/user/themes/bulma-portfolio/images/feather/twitter.svg new file mode 100644 index 00000000..f8886eca --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/twitter.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/type.svg b/user/themes/bulma-portfolio/images/feather/type.svg new file mode 100644 index 00000000..c6b2de33 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/type.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/umbrella.svg b/user/themes/bulma-portfolio/images/feather/umbrella.svg new file mode 100644 index 00000000..dc77c0cb --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/umbrella.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/underline.svg b/user/themes/bulma-portfolio/images/feather/underline.svg new file mode 100644 index 00000000..044945d4 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/underline.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/unlock.svg b/user/themes/bulma-portfolio/images/feather/unlock.svg new file mode 100644 index 00000000..01dc3597 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/unlock.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/upload-cloud.svg b/user/themes/bulma-portfolio/images/feather/upload-cloud.svg new file mode 100644 index 00000000..a1db297c --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/upload-cloud.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/upload.svg b/user/themes/bulma-portfolio/images/feather/upload.svg new file mode 100644 index 00000000..91eaff75 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/upload.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/user-check.svg b/user/themes/bulma-portfolio/images/feather/user-check.svg new file mode 100644 index 00000000..42f91b29 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/user-check.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/user-minus.svg b/user/themes/bulma-portfolio/images/feather/user-minus.svg new file mode 100644 index 00000000..44b75f5a --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/user-minus.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/user-plus.svg b/user/themes/bulma-portfolio/images/feather/user-plus.svg new file mode 100644 index 00000000..21460f6e --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/user-plus.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/user-x.svg b/user/themes/bulma-portfolio/images/feather/user-x.svg new file mode 100644 index 00000000..0c41a481 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/user-x.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/user.svg b/user/themes/bulma-portfolio/images/feather/user.svg new file mode 100644 index 00000000..7bb5f291 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/user.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/users.svg b/user/themes/bulma-portfolio/images/feather/users.svg new file mode 100644 index 00000000..aacf6b08 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/users.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/video-off.svg b/user/themes/bulma-portfolio/images/feather/video-off.svg new file mode 100644 index 00000000..08ec6973 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/video-off.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/video.svg b/user/themes/bulma-portfolio/images/feather/video.svg new file mode 100644 index 00000000..8ff156aa --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/video.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/voicemail.svg b/user/themes/bulma-portfolio/images/feather/voicemail.svg new file mode 100644 index 00000000..5d78a8e7 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/voicemail.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/volume-1.svg b/user/themes/bulma-portfolio/images/feather/volume-1.svg new file mode 100644 index 00000000..150e875f --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/volume-1.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/volume-2.svg b/user/themes/bulma-portfolio/images/feather/volume-2.svg new file mode 100644 index 00000000..03d521c7 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/volume-2.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/volume-x.svg b/user/themes/bulma-portfolio/images/feather/volume-x.svg new file mode 100644 index 00000000..be442406 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/volume-x.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/volume.svg b/user/themes/bulma-portfolio/images/feather/volume.svg new file mode 100644 index 00000000..53bfe15e --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/volume.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/watch.svg b/user/themes/bulma-portfolio/images/feather/watch.svg new file mode 100644 index 00000000..a1099da3 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/watch.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/wifi-off.svg b/user/themes/bulma-portfolio/images/feather/wifi-off.svg new file mode 100644 index 00000000..79430c3c --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/wifi-off.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/wifi.svg b/user/themes/bulma-portfolio/images/feather/wifi.svg new file mode 100644 index 00000000..2e1a7fda --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/wifi.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/wind.svg b/user/themes/bulma-portfolio/images/feather/wind.svg new file mode 100644 index 00000000..82b36468 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/wind.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/x-circle.svg b/user/themes/bulma-portfolio/images/feather/x-circle.svg new file mode 100644 index 00000000..94aad5e5 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/x-circle.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/x-square.svg b/user/themes/bulma-portfolio/images/feather/x-square.svg new file mode 100644 index 00000000..7677c387 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/x-square.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/x.svg b/user/themes/bulma-portfolio/images/feather/x.svg new file mode 100644 index 00000000..7d5875ca --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/x.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/zap-off.svg b/user/themes/bulma-portfolio/images/feather/zap-off.svg new file mode 100644 index 00000000..c636f8bb --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/zap-off.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/zap.svg b/user/themes/bulma-portfolio/images/feather/zap.svg new file mode 100644 index 00000000..8fdafa93 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/zap.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/zoom-in.svg b/user/themes/bulma-portfolio/images/feather/zoom-in.svg new file mode 100644 index 00000000..da4572d2 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/zoom-in.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/feather/zoom-out.svg b/user/themes/bulma-portfolio/images/feather/zoom-out.svg new file mode 100644 index 00000000..fd678d72 --- /dev/null +++ b/user/themes/bulma-portfolio/images/feather/zoom-out.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/images/logo.png b/user/themes/bulma-portfolio/images/logo.png new file mode 100644 index 00000000..eb5dbedd Binary files /dev/null and b/user/themes/bulma-portfolio/images/logo.png differ diff --git a/user/themes/bulma-portfolio/images/logo.svg b/user/themes/bulma-portfolio/images/logo.svg new file mode 100644 index 00000000..33a67fac --- /dev/null +++ b/user/themes/bulma-portfolio/images/logo.svg @@ -0,0 +1,625 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/js/bulma-carousel.js b/user/themes/bulma-portfolio/js/bulma-carousel.js new file mode 100644 index 00000000..28296237 --- /dev/null +++ b/user/themes/bulma-portfolio/js/bulma-carousel.js @@ -0,0 +1,290 @@ +'use strict'; + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +var bulmaCarousel = function () { + 'use strict'; + + var Carousel = function () { + function Carousel(selector) { + _classCallCheck(this, Carousel); + + // Determine click event depending on if we are on Touch device or not + this._clickEvent = 'ontouchstart' in window ? 'touchstart' : 'click'; + + this.element = typeof selector === 'string' ? document.querySelector(selector) : selector; + // An invalid selector or non-DOM node has been provided. + if (!this.element) { + throw new Error('An invalid selector or non-DOM node has been provided.'); + } + + this.init(); + } + + /** + * Initiate plugin + * @method init + * @return {void} + */ + + + _createClass(Carousel, [{ + key: 'init', + value: function init() { + this.items = Array.from(this.element.querySelectorAll('.carousel-item')); + this.items.forEach(function (item) { + var img = item.querySelector('img'); + img.setAttribute('draggable', false); + }); + this.computedStyle = window.getComputedStyle(this.element); + + this.previousControl = this.element.querySelector('.carousel-nav-left'); + this.nextControl = this.element.querySelector('.carousel-nav-right'); + + this._bindEvents(); + this._initOrder(); + + if (this.element.dataset.autoplay && this.element.dataset.autoplay == 'true') { + this._autoPlay(this.element.dataset.delay || 5000); + } + } + + /** + * Bind all events + * @method _bindEvents + * @return {void} + */ + + }, { + key: '_bindEvents', + value: function _bindEvents() { + var _this = this; + + if (this.previousControl) { + this.previousControl.addEventListener(this._clickEvent, function (e) { + e.preventDefault(); + _this._slide('previous'); + if (_this._autoPlayInterval) { + clearInterval(_this._autoPlayInterval); + _this._autoPlay(_this.element.dataset.delay || 5000); + } + }, false); + } + if (this.nextControl) { + this.nextControl.addEventListener(this._clickEvent, function (e) { + e.preventDefault(); + _this._slide('next'); + if (_this._autoPlayInterval) { + clearInterval(_this._autoPlayInterval); + _this._autoPlay(_this.element.dataset.delay || 5000); + } + }, false); + } + + // Bind swipe events + this.element.addEventListener('touchstart', function (e) { + _this._swipeStart(e); + }); + this.element.addEventListener('mousedown', function (e) { + _this._swipeStart(e); + }); + + this.element.addEventListener('touchend', function (e) { + _this._swipeEnd(e); + }); + this.element.addEventListener('mouseup', function (e) { + _this._swipeEnd(e); + }); + } + + /** + * Initiate slides order + * @method _initOrder + * @return {void} + */ + + }, { + key: '_initOrder', + value: function _initOrder() { + var currentActiveItem = this.element.querySelector('.carousel-item.is-active'); + var currentActiveItemPos = this.items.indexOf(currentActiveItem); + if (currentActiveItemPos) { + this.items.push(this.items.splice(0, currentActiveItemPos)); + } else { + this.items.unshift(this.items.pop()); + } + this._setOrder(); + } + + /** + * Update each slide order + * @method _setOrder + */ + + }, { + key: '_setOrder', + value: function _setOrder() { + this.items.forEach(function (item, index) { + if (index !== 1) { + item.style['z-index'] = '0'; + } else { + item.style['z-index'] = '1'; + } + item.style.order = index; + }); + } + + /** + * Save current position on start swiping + * @method _swipeStart + * @param {Event} e Swipe event + * @return {void} + */ + + }, { + key: '_swipeStart', + value: function _swipeStart(e) { + this._touch = { + start: { + x: e.clientX, + y: e.clientY + }, + end: { + x: e.clientX, + y: e.clientY + } + }; + } + + /** + * Save current position on end swiping + * @method _swipeEnd + * @param {Event} e swipe event + * @return {void} + */ + + }, { + key: '_swipeEnd', + value: function _swipeEnd(e) { + this._touch.end = { + x: e.clientX, + y: e.clientY + }; + + this._handleGesture(); + } + + /** + * Identify the gestureand slide if necessary + * @method _handleGesture + * @return {void} + */ + + }, { + key: '_handleGesture', + value: function _handleGesture() { + var ratio = { + horizontal: (this._touch.end.x - this._touch.start.x) / parseInt(this.computedStyle.getPropertyValue('width')), + vertical: (this._touch.end.y - this._touch.start.y) / parseInt(this.computedStyle.getPropertyValue('height')) + }; + + if (ratio.horizontal > ratio.vertical && ratio.horizontal > 0.25) { + this._slide('previous'); + } + + if (ratio.horizontal < ratio.vertical && ratio.horizontal < -0.25) { + this._slide('next'); + } + } + + /** + * Update slides to display the wanted one + * @method _slide + * @param {String} [direction='next'] Direction in which slide needs to move + * @return {void} + */ + + }, { + key: '_slide', + value: function _slide() { + var _this2 = this; + + var direction = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'next'; + + if (this.items.length) { + var currentActiveItem = this.element.querySelector('.carousel-item.is-active'); + var newActiveItem = void 0; + + currentActiveItem.classList.remove('is-active'); + + // initialize direction to change order + if (direction === 'previous') { + // Reorder items + this.items.unshift(this.items.pop()); + // add reverse class + this.element.classList.add('is-reversing'); + } else { + // Reorder items + this.items.push(this.items.shift()); + // re_slide reverse class + this.element.classList.remove('is-reversing'); + } + + if (this.items.length >= 1) { + newActiveItem = this.items[1]; + } else { + newActiveItem = this.items[0]; + } + newActiveItem.classList.add('is-active'); + this._setOrder(); + + // Disable transition to instant change order + this.element.classList.toggle('carousel-animated'); + // Enable transition to animate order 1 to order 2 + setTimeout(function () { + _this2.element.classList.toggle('carousel-animated'); + }, 50); + } + } + + /** + * Initiate autoplay system + * @method _autoPlay + * @param {Number} [delay=5000] Delay between slides in milliseconds + * @return {void} + */ + + }, { + key: '_autoPlay', + value: function _autoPlay() { + var _this3 = this; + + var delay = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 5000; + + this._autoPlayInterval = setInterval(function () { + _this3._slide('next'); + }, delay); + } + }]); + + return Carousel; + }(); + + /** + * Initiate all DOM element containing carousel class + * @method + * @return {[type]} [description] + */ + + + document.addEventListener('DOMContentLoaded', function () { + var carousels = document.querySelectorAll('.carousel, .hero-carousel'); + [].forEach.call(carousels, function (carousel) { + new Carousel(carousel); + }); + }); + + return Carousel; +}(); diff --git a/user/themes/bulma-portfolio/js/feather.js b/user/themes/bulma-portfolio/js/feather.js new file mode 100644 index 00000000..89b77c98 --- /dev/null +++ b/user/themes/bulma-portfolio/js/feather.js @@ -0,0 +1,2876 @@ +"use strict"; + +var _typeof2 = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + +var _typeof = typeof Symbol === "function" && _typeof2(Symbol.iterator) === "symbol" ? function (obj) { + return typeof obj === "undefined" ? "undefined" : _typeof2(obj); +} : function (obj) { + return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj === "undefined" ? "undefined" : _typeof2(obj); +}; + +(function webpackUniversalModuleDefinition(root, factory) { + if ((typeof exports === "undefined" ? "undefined" : _typeof(exports)) === "object" && (typeof module === "undefined" ? "undefined" : _typeof(module)) === "object") module.exports = factory();else if (typeof define === "function" && define.amd) define([], factory);else if ((typeof exports === "undefined" ? "undefined" : _typeof(exports)) === "object") exports["feather"] = factory();else root["feather"] = factory(); +})(typeof self !== "undefined" ? self : undefined, function () { + return (/******/function (modules) { + // webpackBootstrap + /******/ // The module cache + /******/ + var installedModules = {}; // The require function + /******/ + /******/ + /******/ + function __webpack_require__(moduleId) { + /******/ + /******/ // Check if module is in cache + /******/ + if (installedModules[moduleId]) { + /******/ + return installedModules[moduleId].exports; + /******/ + } // Create a new module (and put it into the cache) + /******/ + /******/ + var module = installedModules[moduleId] = { + /******/ + i: moduleId, + /******/ + l: false, + /******/ + exports: {} + /******/ + }; // Execute the module function + /******/ + /******/ + /******/ + modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); // Flag the module as loaded + /******/ + /******/ + /******/ + module.l = true; // Return the exports of the module + /******/ + /******/ + /******/ + return module.exports; + /******/ + } // expose the modules object (__webpack_modules__) + /******/ + /******/ + /******/ + /******/ + __webpack_require__.m = modules; // expose the module cache + /******/ + /******/ + /******/ + __webpack_require__.c = installedModules; // define getter function for harmony exports + /******/ + /******/ + /******/ + __webpack_require__.d = function (exports, name, getter) { + /******/ + if (!__webpack_require__.o(exports, name)) { + /******/ + Object.defineProperty(exports, name, { + /******/ + configurable: false, + /******/ + enumerable: true, + /******/ + get: getter + /******/ + }); + /******/ + } + /******/ + }; // getDefaultExport function for compatibility with non-harmony modules + /******/ + /******/ + /******/ + __webpack_require__.n = function (module) { + /******/ + var getter = module && module.__esModule ? + /******/function getDefault() { + return module["default"]; + } : + /******/function getModuleExports() { + return module; + }; + /******/ + __webpack_require__.d(getter, "a", getter); + /******/ + return getter; + /******/ + }; // Object.prototype.hasOwnProperty.call + /******/ + /******/ + /******/ + __webpack_require__.o = function (object, property) { + return Object.prototype.hasOwnProperty.call(object, property); + }; // __webpack_public_path__ + /******/ + /******/ + /******/ + __webpack_require__.p = ""; // Load entry module and return exports + /******/ + /******/ + /******/ + return __webpack_require__(__webpack_require__.s = 49); + /******/ + }( + /************************************************************************/ + /******/ + [ + /* 0 */ + /***/ + function (module, exports, __webpack_require__) { + var store = __webpack_require__(36)("wks"); + var uid = __webpack_require__(15); + var _Symbol = __webpack_require__(1).Symbol; + var USE_SYMBOL = typeof _Symbol == "function"; + + var $exports = module.exports = function (name) { + return store[name] || (store[name] = USE_SYMBOL && _Symbol[name] || (USE_SYMBOL ? _Symbol : uid)("Symbol." + name)); + }; + + $exports.store = store; + + /***/ + }, + /* 1 */ + /***/ + function (module, exports) { + // https://github.com/zloirock/core-js/issues/86#issuecomment-115759028 + var global = module.exports = typeof window != "undefined" && window.Math == Math ? window : typeof self != "undefined" && self.Math == Math ? self : // eslint-disable-next-line no-new-func + Function("return this")(); + if (typeof __g == "number") __g = global; // eslint-disable-line no-undef + + /***/ + }, + /* 2 */ + /***/ + function (module, exports) { + module.exports = function (it) { + return (typeof it === "undefined" ? "undefined" : _typeof(it)) === "object" ? it !== null : typeof it === "function"; + }; + + /***/ + }, + /* 3 */ + /***/ + function (module, exports, __webpack_require__) { + var global = __webpack_require__(1); + var core = __webpack_require__(7); + var hide = __webpack_require__(8); + var redefine = __webpack_require__(10); + var ctx = __webpack_require__(11); + var PROTOTYPE = "prototype"; + + var $export = function $export(type, name, source) { + var IS_FORCED = type & $export.F; + var IS_GLOBAL = type & $export.G; + var IS_STATIC = type & $export.S; + var IS_PROTO = type & $export.P; + var IS_BIND = type & $export.B; + var target = IS_GLOBAL ? global : IS_STATIC ? global[name] || (global[name] = {}) : (global[name] || {})[PROTOTYPE]; + var exports = IS_GLOBAL ? core : core[name] || (core[name] = {}); + var expProto = exports[PROTOTYPE] || (exports[PROTOTYPE] = {}); + var key, own, out, exp; + if (IS_GLOBAL) source = name; + for (key in source) { + // contains in native + own = !IS_FORCED && target && target[key] !== undefined; + // export native or passed + out = (own ? target : source)[key]; + // bind timers to global for call from export context + exp = IS_BIND && own ? ctx(out, global) : IS_PROTO && typeof out == "function" ? ctx(Function.call, out) : out; + // extend global + if (target) redefine(target, key, out, type & $export.U); + // export + if (exports[key] != out) hide(exports, key, exp); + if (IS_PROTO && expProto[key] != out) expProto[key] = out; + } + }; + global.core = core; + // type bitmap + $export.F = 1; // forced + $export.G = 2; // global + $export.S = 4; // static + $export.P = 8; // proto + $export.B = 16; // bind + $export.W = 32; // wrap + $export.U = 64; // safe + $export.R = 128; // real proto method for `library` + module.exports = $export; + + /***/ + }, + /* 4 */ + /***/ + function (module, exports, __webpack_require__) { + var anObject = __webpack_require__(9); + var IE8_DOM_DEFINE = __webpack_require__(29); + var toPrimitive = __webpack_require__(31); + var dP = Object.defineProperty; + + exports.f = __webpack_require__(5) ? Object.defineProperty : function defineProperty(O, P, Attributes) { + anObject(O); + P = toPrimitive(P, true); + anObject(Attributes); + if (IE8_DOM_DEFINE) try { + return dP(O, P, Attributes); + } catch (e) { + /* empty */ + } + if ("get" in Attributes || "set" in Attributes) throw TypeError("Accessors not supported!"); + if ("value" in Attributes) O[P] = Attributes.value; + return O; + }; + + /***/ + }, + /* 5 */ + /***/ + function (module, exports, __webpack_require__) { + // Thank's IE8 for his funny defineProperty + module.exports = !__webpack_require__(12)(function () { + return Object.defineProperty({}, "a", { + get: function get() { + return 7; + } + }).a != 7; + }); + + /***/ + }, + /* 6 */ + /***/ + function (module, exports) { + var hasOwnProperty = {}.hasOwnProperty; + module.exports = function (it, key) { + return hasOwnProperty.call(it, key); + }; + + /***/ + }, + /* 7 */ + /***/ + function (module, exports) { + var core = module.exports = { version: "2.5.3" }; + if (typeof __e == "number") __e = core; // eslint-disable-line no-undef + + /***/ + }, + /* 8 */ + /***/ + function (module, exports, __webpack_require__) { + var dP = __webpack_require__(4); + var createDesc = __webpack_require__(14); + module.exports = __webpack_require__(5) ? function (object, key, value) { + return dP.f(object, key, createDesc(1, value)); + } : function (object, key, value) { + object[key] = value; + return object; + }; + + /***/ + }, + /* 9 */ + /***/ + function (module, exports, __webpack_require__) { + var isObject = __webpack_require__(2); + module.exports = function (it) { + if (!isObject(it)) throw TypeError(it + " is not an object!"); + return it; + }; + + /***/ + }, + /* 10 */ + /***/ + function (module, exports, __webpack_require__) { + var global = __webpack_require__(1); + var hide = __webpack_require__(8); + var has = __webpack_require__(6); + var SRC = __webpack_require__(15)("src"); + var TO_STRING = "toString"; + var $toString = Function[TO_STRING]; + var TPL = ("" + $toString).split(TO_STRING); + + __webpack_require__(7).inspectSource = function (it) { + return $toString.call(it); + }; + + (module.exports = function (O, key, val, safe) { + var isFunction = typeof val == "function"; + if (isFunction) has(val, "name") || hide(val, "name", key); + if (O[key] === val) return; + if (isFunction) has(val, SRC) || hide(val, SRC, O[key] ? "" + O[key] : TPL.join(String(key))); + if (O === global) { + O[key] = val; + } else if (!safe) { + delete O[key]; + hide(O, key, val); + } else if (O[key]) { + O[key] = val; + } else { + hide(O, key, val); + } + // add fake Function#toString for correct work wrapped methods / constructors with methods like LoDash isNative + })(Function.prototype, TO_STRING, function toString() { + return typeof this == "function" && this[SRC] || $toString.call(this); + }); + + /***/ + }, + /* 11 */ + /***/ + function (module, exports, __webpack_require__) { + // optional / simple context binding + var aFunction = __webpack_require__(32); + module.exports = function (fn, that, length) { + aFunction(fn); + if (that === undefined) return fn; + switch (length) { + case 1: + return function (a) { + return fn.call(that, a); + }; + case 2: + return function (a, b) { + return fn.call(that, a, b); + }; + case 3: + return function (a, b, c) { + return fn.call(that, a, b, c); + }; + } + return function () /* ...args */{ + return fn.apply(that, arguments); + }; + }; + + /***/ + }, + /* 12 */ + /***/ + function (module, exports) { + module.exports = function (exec) { + try { + return !!exec(); + } catch (e) { + return true; + } + }; + + /***/ + }, + /* 13 */ + /***/ + function (module, exports) { + module.exports = {}; + + /***/ + }, + /* 14 */ + /***/ + function (module, exports) { + module.exports = function (bitmap, value) { + return { + enumerable: !(bitmap & 1), + configurable: !(bitmap & 2), + writable: !(bitmap & 4), + value: value + }; + }; + + /***/ + }, + /* 15 */ + /***/ + function (module, exports) { + var id = 0; + var px = Math.random(); + module.exports = function (key) { + return "Symbol(".concat(key === undefined ? "" : key, ")_", (++id + px).toString(36)); + }; + + /***/ + }, + /* 16 */ + /***/ + function (module, exports, __webpack_require__) { + // to indexed object, toObject with fallback for non-array-like ES3 strings + var IObject = __webpack_require__(34); + var defined = __webpack_require__(19); + module.exports = function (it) { + return IObject(defined(it)); + }; + + /***/ + }, + /* 17 */ + /***/ + function (module, exports, __webpack_require__) { + var ctx = __webpack_require__(11); + var call = __webpack_require__(38); + var isArrayIter = __webpack_require__(39); + var anObject = __webpack_require__(9); + var toLength = __webpack_require__(22); + var getIterFn = __webpack_require__(40); + var BREAK = {}; + var RETURN = {}; + var exports = module.exports = function (iterable, entries, fn, that, ITERATOR) { + var iterFn = ITERATOR ? function () { + return iterable; + } : getIterFn(iterable); + var f = ctx(fn, that, entries ? 2 : 1); + var index = 0; + var length, step, iterator, result; + if (typeof iterFn != "function") throw TypeError(iterable + " is not iterable!"); + // fast case for arrays with default iterator + if (isArrayIter(iterFn)) for (length = toLength(iterable.length); length > index; index++) { + result = entries ? f(anObject(step = iterable[index])[0], step[1]) : f(iterable[index]); + if (result === BREAK || result === RETURN) return result; + } else for (iterator = iterFn.call(iterable); !(step = iterator.next()).done;) { + result = call(iterator, f, step.value, entries); + if (result === BREAK || result === RETURN) return result; + } + }; + exports.BREAK = BREAK; + exports.RETURN = RETURN; + + /***/ + }, + /* 18 */ + /***/ + function (module, exports) { + // 7.1.4 ToInteger + var ceil = Math.ceil; + var floor = Math.floor; + module.exports = function (it) { + return isNaN(it = +it) ? 0 : (it > 0 ? floor : ceil)(it); + }; + + /***/ + }, + /* 19 */ + /***/ + function (module, exports) { + // 7.2.1 RequireObjectCoercible(argument) + module.exports = function (it) { + if (it == undefined) throw TypeError("Can't call method on " + it); + return it; + }; + + /***/ + }, + /* 20 */ + /***/ + function (module, exports, __webpack_require__) { + "use strict"; + + var LIBRARY = __webpack_require__(52); + var $export = __webpack_require__(3); + var redefine = __webpack_require__(10); + var hide = __webpack_require__(8); + var has = __webpack_require__(6); + var Iterators = __webpack_require__(13); + var $iterCreate = __webpack_require__(53); + var setToStringTag = __webpack_require__(24); + var getPrototypeOf = __webpack_require__(59); + var ITERATOR = __webpack_require__(0)("iterator"); + var BUGGY = !([].keys && "next" in [].keys()); // Safari has buggy iterators w/o `next` + var FF_ITERATOR = "@@iterator"; + var KEYS = "keys"; + var VALUES = "values"; + + var returnThis = function returnThis() { + return this; + }; + + module.exports = function (Base, NAME, Constructor, next, DEFAULT, IS_SET, FORCED) { + $iterCreate(Constructor, NAME, next); + var getMethod = function getMethod(kind) { + if (!BUGGY && kind in proto) return proto[kind]; + switch (kind) { + case KEYS: + return function keys() { + return new Constructor(this, kind); + }; + case VALUES: + return function values() { + return new Constructor(this, kind); + }; + } + return function entries() { + return new Constructor(this, kind); + }; + }; + var TAG = NAME + " Iterator"; + var DEF_VALUES = DEFAULT == VALUES; + var VALUES_BUG = false; + var proto = Base.prototype; + var $native = proto[ITERATOR] || proto[FF_ITERATOR] || DEFAULT && proto[DEFAULT]; + var $default = !BUGGY && $native || getMethod(DEFAULT); + var $entries = DEFAULT ? !DEF_VALUES ? $default : getMethod("entries") : undefined; + var $anyNative = NAME == "Array" ? proto.entries || $native : $native; + var methods, key, IteratorPrototype; + // Fix native + if ($anyNative) { + IteratorPrototype = getPrototypeOf($anyNative.call(new Base())); + if (IteratorPrototype !== Object.prototype && IteratorPrototype.next) { + // Set @@toStringTag to native iterators + setToStringTag(IteratorPrototype, TAG, true); + // fix for some old engines + if (!LIBRARY && !has(IteratorPrototype, ITERATOR)) hide(IteratorPrototype, ITERATOR, returnThis); + } + } + // fix Array#{values, @@iterator}.name in V8 / FF + if (DEF_VALUES && $native && $native.name !== VALUES) { + VALUES_BUG = true; + $default = function values() { + return $native.call(this); + }; + } + // Define iterator + if ((!LIBRARY || FORCED) && (BUGGY || VALUES_BUG || !proto[ITERATOR])) { + hide(proto, ITERATOR, $default); + } + // Plug for library + Iterators[NAME] = $default; + Iterators[TAG] = returnThis; + if (DEFAULT) { + methods = { + values: DEF_VALUES ? $default : getMethod(VALUES), + keys: IS_SET ? $default : getMethod(KEYS), + entries: $entries + }; + if (FORCED) for (key in methods) { + if (!(key in proto)) redefine(proto, key, methods[key]); + } else $export($export.P + $export.F * (BUGGY || VALUES_BUG), NAME, methods); + } + return methods; + }; + + /***/ + }, + /* 21 */ + /***/ + function (module, exports, __webpack_require__) { + // 19.1.2.14 / 15.2.3.14 Object.keys(O) + var $keys = __webpack_require__(55); + var enumBugKeys = __webpack_require__(37); + + module.exports = Object.keys || function keys(O) { + return $keys(O, enumBugKeys); + }; + + /***/ + }, + /* 22 */ + /***/ + function (module, exports, __webpack_require__) { + // 7.1.15 ToLength + var toInteger = __webpack_require__(18); + var min = Math.min; + module.exports = function (it) { + return it > 0 ? min(toInteger(it), 0x1fffffffffffff) : 0; // pow(2, 53) - 1 == 9007199254740991 + }; + + /***/ + }, + /* 23 */ + /***/ + function (module, exports, __webpack_require__) { + var shared = __webpack_require__(36)("keys"); + var uid = __webpack_require__(15); + module.exports = function (key) { + return shared[key] || (shared[key] = uid(key)); + }; + + /***/ + }, + /* 24 */ + /***/ + function (module, exports, __webpack_require__) { + var def = __webpack_require__(4).f; + var has = __webpack_require__(6); + var TAG = __webpack_require__(0)("toStringTag"); + + module.exports = function (it, tag, stat) { + if (it && !has(it = stat ? it : it.prototype, TAG)) def(it, TAG, { configurable: true, value: tag }); + }; + + /***/ + }, + /* 25 */ + /***/ + function (module, exports, __webpack_require__) { + // 7.1.13 ToObject(argument) + var defined = __webpack_require__(19); + module.exports = function (it) { + return Object(defined(it)); + }; + + /***/ + }, + /* 26 */ + /***/ + function (module, exports, __webpack_require__) { + // getting tag from 19.1.3.6 Object.prototype.toString() + var cof = __webpack_require__(35); + var TAG = __webpack_require__(0)("toStringTag"); + // ES3 wrong here + var ARG = cof(function () { + return arguments; + }()) == "Arguments"; + + // fallback for IE11 Script Access Denied error + var tryGet = function tryGet(it, key) { + try { + return it[key]; + } catch (e) { + /* empty */ + } + }; + + module.exports = function (it) { + var O, T, B; + return it === undefined ? "Undefined" : it === null ? "Null" : // @@toStringTag case + typeof (T = tryGet(O = Object(it), TAG)) == "string" ? T : // builtinTag case + ARG ? cof(O) : // ES3 arguments fallback + (B = cof(O)) == "Object" && typeof O.callee == "function" ? "Arguments" : B; + }; + + /***/ + }, + /* 27 */ + /***/ + function (module, exports, __webpack_require__) { + "use strict"; + + Object.defineProperty(exports, "__esModule", { + value: true + }); + + var _icon = __webpack_require__(86); + + var _icon2 = _interopRequireDefault(_icon); + + var _icons = __webpack_require__(88); + + var _icons2 = _interopRequireDefault(_icons); + + var _tags = __webpack_require__(89); + + var _tags2 = _interopRequireDefault(_tags); + + function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; + } + + exports.default = Object.keys(_icons2.default).map(function (key) { + return new _icon2.default(key, _icons2.default[key], _tags2.default[key]); + }).reduce(function (object, icon) { + object[icon.name] = icon; + return object; + }, {}); + + /***/ + }, + /* 28 */ + /***/ + function (module, exports, __webpack_require__) { + "use strict"; + + var $at = __webpack_require__(51)(true); + + // 21.1.3.27 String.prototype[@@iterator]() + __webpack_require__(20)(String, "String", function (iterated) { + this._t = String(iterated); // target + this._i = 0; // next index + // 21.1.5.2.1 %StringIteratorPrototype%.next() + }, function () { + var O = this._t; + var index = this._i; + var point; + if (index >= O.length) return { value: undefined, done: true }; + point = $at(O, index); + this._i += point.length; + return { value: point, done: false }; + }); + + /***/ + }, + /* 29 */ + /***/ + function (module, exports, __webpack_require__) { + module.exports = !__webpack_require__(5) && !__webpack_require__(12)(function () { + return Object.defineProperty(__webpack_require__(30)("div"), "a", { + get: function get() { + return 7; + } + }).a != 7; + }); + + /***/ + }, + /* 30 */ + /***/ + function (module, exports, __webpack_require__) { + var isObject = __webpack_require__(2); + var document = __webpack_require__(1).document; + // typeof document.createElement is 'object' in old IE + var is = isObject(document) && isObject(document.createElement); + module.exports = function (it) { + return is ? document.createElement(it) : {}; + }; + + /***/ + }, + /* 31 */ + /***/ + function (module, exports, __webpack_require__) { + // 7.1.1 ToPrimitive(input [, PreferredType]) + var isObject = __webpack_require__(2); + // instead of the ES6 spec version, we didn't implement @@toPrimitive case + // and the second argument - flag - preferred type is a string + module.exports = function (it, S) { + if (!isObject(it)) return it; + var fn, val; + if (S && typeof (fn = it.toString) == "function" && !isObject(val = fn.call(it))) return val; + if (typeof (fn = it.valueOf) == "function" && !isObject(val = fn.call(it))) return val; + if (!S && typeof (fn = it.toString) == "function" && !isObject(val = fn.call(it))) return val; + throw TypeError("Can't convert object to primitive value"); + }; + + /***/ + }, + /* 32 */ + /***/ + function (module, exports) { + module.exports = function (it) { + if (typeof it != "function") throw TypeError(it + " is not a function!"); + return it; + }; + + /***/ + }, + /* 33 */ + /***/ + function (module, exports, __webpack_require__) { + // 19.1.2.2 / 15.2.3.5 Object.create(O [, Properties]) + var anObject = __webpack_require__(9); + var dPs = __webpack_require__(54); + var enumBugKeys = __webpack_require__(37); + var IE_PROTO = __webpack_require__(23)("IE_PROTO"); + var Empty = function Empty() { + /* empty */ + }; + var PROTOTYPE = "prototype"; + + // Create object with fake `null` prototype: use iframe Object with cleared prototype + var _createDict = function createDict() { + // Thrash, waste and sodomy: IE GC bug + var iframe = __webpack_require__(30)("iframe"); + var i = enumBugKeys.length; + var lt = "<"; + var gt = ">"; + var iframeDocument; + iframe.style.display = "none"; + __webpack_require__(58).appendChild(iframe); + iframe.src = "javascript:"; // eslint-disable-line no-script-url + // createDict = iframe.contentWindow.Object; + // html.removeChild(iframe); + iframeDocument = iframe.contentWindow.document; + iframeDocument.open(); + iframeDocument.write(lt + "script" + gt + "document.F=Object" + lt + "/script" + gt); + iframeDocument.close(); + _createDict = iframeDocument.F; + while (i--) { + delete _createDict[PROTOTYPE][enumBugKeys[i]]; + } + return _createDict(); + }; + + module.exports = Object.create || function create(O, Properties) { + var result; + if (O !== null) { + Empty[PROTOTYPE] = anObject(O); + result = new Empty(); + Empty[PROTOTYPE] = null; + // add "__proto__" for Object.getPrototypeOf polyfill + result[IE_PROTO] = O; + } else result = _createDict(); + return Properties === undefined ? result : dPs(result, Properties); + }; + + /***/ + }, + /* 34 */ + /***/ + function (module, exports, __webpack_require__) { + // fallback for non-array-like ES3 and non-enumerable old V8 strings + var cof = __webpack_require__(35); + // eslint-disable-next-line no-prototype-builtins + module.exports = Object("z").propertyIsEnumerable(0) ? Object : function (it) { + return cof(it) == "String" ? it.split("") : Object(it); + }; + + /***/ + }, + /* 35 */ + /***/ + function (module, exports) { + var toString = {}.toString; + + module.exports = function (it) { + return toString.call(it).slice(8, -1); + }; + + /***/ + }, + /* 36 */ + /***/ + function (module, exports, __webpack_require__) { + var global = __webpack_require__(1); + var SHARED = "__core-js_shared__"; + var store = global[SHARED] || (global[SHARED] = {}); + module.exports = function (key) { + return store[key] || (store[key] = {}); + }; + + /***/ + }, + /* 37 */ + /***/ + function (module, exports) { + // IE 8- don't enum bug keys + module.exports = "constructor,hasOwnProperty,isPrototypeOf,propertyIsEnumerable,toLocaleString,toString,valueOf".split(","); + + /***/ + }, + /* 38 */ + /***/ + function (module, exports, __webpack_require__) { + // call something on iterator step with safe closing on error + var anObject = __webpack_require__(9); + module.exports = function (iterator, fn, value, entries) { + try { + return entries ? fn(anObject(value)[0], value[1]) : fn(value); + // 7.4.6 IteratorClose(iterator, completion) + } catch (e) { + var ret = iterator["return"]; + if (ret !== undefined) anObject(ret.call(iterator)); + throw e; + } + }; + + /***/ + }, + /* 39 */ + /***/ + function (module, exports, __webpack_require__) { + // check on default Array iterator + var Iterators = __webpack_require__(13); + var ITERATOR = __webpack_require__(0)("iterator"); + var ArrayProto = Array.prototype; + + module.exports = function (it) { + return it !== undefined && (Iterators.Array === it || ArrayProto[ITERATOR] === it); + }; + + /***/ + }, + /* 40 */ + /***/ + function (module, exports, __webpack_require__) { + var classof = __webpack_require__(26); + var ITERATOR = __webpack_require__(0)("iterator"); + var Iterators = __webpack_require__(13); + module.exports = __webpack_require__(7).getIteratorMethod = function (it) { + if (it != undefined) return it[ITERATOR] || it["@@iterator"] || Iterators[classof(it)]; + }; + + /***/ + }, + /* 41 */ + /***/ + function (module, exports, __webpack_require__) { + var ITERATOR = __webpack_require__(0)("iterator"); + var SAFE_CLOSING = false; + + try { + var riter = [7][ITERATOR](); + riter["return"] = function () { + SAFE_CLOSING = true; + }; + // eslint-disable-next-line no-throw-literal + Array.from(riter, function () { + throw 2; + }); + } catch (e) { + /* empty */ + } + + module.exports = function (exec, skipClosing) { + if (!skipClosing && !SAFE_CLOSING) return false; + var safe = false; + try { + var arr = [7]; + var iter = arr[ITERATOR](); + iter.next = function () { + return { done: safe = true }; + }; + arr[ITERATOR] = function () { + return iter; + }; + exec(arr); + } catch (e) { + /* empty */ + } + return safe; + }; + + /***/ + }, + /* 42 */ + /***/ + function (module, exports) { + exports.f = {}.propertyIsEnumerable; + + /***/ + }, + /* 43 */ + /***/ + function (module, exports) { + module.exports = function (done, value) { + return { value: value, done: !!done }; + }; + + /***/ + }, + /* 44 */ + /***/ + function (module, exports, __webpack_require__) { + var redefine = __webpack_require__(10); + module.exports = function (target, src, safe) { + for (var key in src) { + redefine(target, key, src[key], safe); + } + return target; + }; + + /***/ + }, + /* 45 */ + /***/ + function (module, exports) { + module.exports = function (it, Constructor, name, forbiddenField) { + if (!(it instanceof Constructor) || forbiddenField !== undefined && forbiddenField in it) { + throw TypeError(name + ": incorrect invocation!"); + } + return it; + }; + + /***/ + }, + /* 46 */ + /***/ + function (module, exports, __webpack_require__) { + var META = __webpack_require__(15)("meta"); + var isObject = __webpack_require__(2); + var has = __webpack_require__(6); + var setDesc = __webpack_require__(4).f; + var id = 0; + var isExtensible = Object.isExtensible || function () { + return true; + }; + var FREEZE = !__webpack_require__(12)(function () { + return isExtensible(Object.preventExtensions({})); + }); + var setMeta = function setMeta(it) { + setDesc(it, META, { + value: { + i: "O" + ++id, // object ID + w: {} // weak collections IDs + } + }); + }; + var fastKey = function fastKey(it, create) { + // return primitive with prefix + if (!isObject(it)) return (typeof it === "undefined" ? "undefined" : _typeof(it)) == "symbol" ? it : (typeof it == "string" ? "S" : "P") + it; + if (!has(it, META)) { + // can't set metadata to uncaught frozen object + if (!isExtensible(it)) return "F"; + // not necessary to add metadata + if (!create) return "E"; + // add missing metadata + setMeta(it); + // return object ID + } + return it[META].i; + }; + var getWeak = function getWeak(it, create) { + if (!has(it, META)) { + // can't set metadata to uncaught frozen object + if (!isExtensible(it)) return true; + // not necessary to add metadata + if (!create) return false; + // add missing metadata + setMeta(it); + // return hash weak collections IDs + } + return it[META].w; + }; + // add metadata on freeze-family methods calling + var onFreeze = function onFreeze(it) { + if (FREEZE && meta.NEED && isExtensible(it) && !has(it, META)) setMeta(it); + return it; + }; + var meta = module.exports = { + KEY: META, + NEED: false, + fastKey: fastKey, + getWeak: getWeak, + onFreeze: onFreeze + }; + + /***/ + }, + /* 47 */ + /***/ + function (module, exports, __webpack_require__) { + var isObject = __webpack_require__(2); + module.exports = function (it, TYPE) { + if (!isObject(it) || it._t !== TYPE) throw TypeError("Incompatible receiver, " + TYPE + " required!"); + return it; + }; + + /***/ + }, + /* 48 */ + /***/ + function (module, exports, __webpack_require__) { + var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__; + /*! + Copyright (c) 2016 Jed Watson. + Licensed under the MIT License (MIT), see + http://jedwatson.github.io/classnames + */ + /* global define */ + + (function () { + "use strict"; + + var classNames = function () { + // don't inherit from Object so we can skip hasOwnProperty check later + // http://stackoverflow.com/questions/15518328/creating-js-object-with-object-createnull#answer-21079232 + function StorageObject() {} + StorageObject.prototype = Object.create(null); + + function _parseArray(resultSet, array) { + var length = array.length; + + for (var i = 0; i < length; ++i) { + _parse(resultSet, array[i]); + } + } + + var hasOwn = {}.hasOwnProperty; + + function _parseNumber(resultSet, num) { + resultSet[num] = true; + } + + function _parseObject(resultSet, object) { + for (var k in object) { + if (hasOwn.call(object, k)) { + // set value to false instead of deleting it to avoid changing object structure + // https://www.smashingmagazine.com/2012/11/writing-fast-memory-efficient-javascript/#de-referencing-misconceptions + resultSet[k] = !!object[k]; + } + } + } + + var SPACE = /\s+/; + + function _parseString(resultSet, str) { + var array = str.split(SPACE); + var length = array.length; + + for (var i = 0; i < length; ++i) { + resultSet[array[i]] = true; + } + } + + function _parse(resultSet, arg) { + if (!arg) return; + var argType = typeof arg === "undefined" ? "undefined" : _typeof(arg); + + // 'foo bar' + if (argType === "string") { + _parseString(resultSet, arg); + + // ['foo', 'bar', ...] + } else if (Array.isArray(arg)) { + _parseArray(resultSet, arg); + + // { 'foo': true, ... } + } else if (argType === "object") { + _parseObject(resultSet, arg); + + // '130' + } else if (argType === "number") { + _parseNumber(resultSet, arg); + } + } + + function _classNames() { + // don't leak arguments + // https://github.com/petkaantonov/bluebird/wiki/Optimization-killers#32-leaking-arguments + var len = arguments.length; + var args = Array(len); + for (var i = 0; i < len; i++) { + args[i] = arguments[i]; + } + + var classSet = new StorageObject(); + _parseArray(classSet, args); + + var list = []; + + for (var k in classSet) { + if (classSet[k]) { + list.push(k); + } + } + + return list.join(" "); + } + + return _classNames; + }(); + + if (typeof module !== "undefined" && module.exports) { + module.exports = classNames; + } else if (true) { + // register as 'classnames', consistent with npm package name + !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function () { + return classNames; + }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); + } else { + window.classNames = classNames; + } + })(); + + /***/ + }, + /* 49 */ + /***/ + function (module, exports, __webpack_require__) { + __webpack_require__(50); + __webpack_require__(62); + __webpack_require__(66); + module.exports = __webpack_require__(85); + + /***/ + }, + /* 50 */ + /***/ + function (module, exports, __webpack_require__) { + __webpack_require__(28); + __webpack_require__(60); + module.exports = __webpack_require__(7).Array.from; + + /***/ + }, + /* 51 */ + /***/ + function (module, exports, __webpack_require__) { + var toInteger = __webpack_require__(18); + var defined = __webpack_require__(19); + // true -> String#at + // false -> String#codePointAt + module.exports = function (TO_STRING) { + return function (that, pos) { + var s = String(defined(that)); + var i = toInteger(pos); + var l = s.length; + var a, b; + if (i < 0 || i >= l) return TO_STRING ? "" : undefined; + a = s.charCodeAt(i); + return a < 0xd800 || a > 0xdbff || i + 1 === l || (b = s.charCodeAt(i + 1)) < 0xdc00 || b > 0xdfff ? TO_STRING ? s.charAt(i) : a : TO_STRING ? s.slice(i, i + 2) : (a - 0xd800 << 10) + (b - 0xdc00) + 0x10000; + }; + }; + + /***/ + }, + /* 52 */ + /***/ + function (module, exports) { + module.exports = false; + + /***/ + }, + /* 53 */ + /***/ + function (module, exports, __webpack_require__) { + "use strict"; + + var create = __webpack_require__(33); + var descriptor = __webpack_require__(14); + var setToStringTag = __webpack_require__(24); + var IteratorPrototype = {}; + + // 25.1.2.1.1 %IteratorPrototype%[@@iterator]() + __webpack_require__(8)(IteratorPrototype, __webpack_require__(0)("iterator"), function () { + return this; + }); + + module.exports = function (Constructor, NAME, next) { + Constructor.prototype = create(IteratorPrototype, { + next: descriptor(1, next) + }); + setToStringTag(Constructor, NAME + " Iterator"); + }; + + /***/ + }, + /* 54 */ + /***/ + function (module, exports, __webpack_require__) { + var dP = __webpack_require__(4); + var anObject = __webpack_require__(9); + var getKeys = __webpack_require__(21); + + module.exports = __webpack_require__(5) ? Object.defineProperties : function defineProperties(O, Properties) { + anObject(O); + var keys = getKeys(Properties); + var length = keys.length; + var i = 0; + var P; + while (length > i) { + dP.f(O, P = keys[i++], Properties[P]); + } + return O; + }; + + /***/ + }, + /* 55 */ + /***/ + function (module, exports, __webpack_require__) { + var has = __webpack_require__(6); + var toIObject = __webpack_require__(16); + var arrayIndexOf = __webpack_require__(56)(false); + var IE_PROTO = __webpack_require__(23)("IE_PROTO"); + + module.exports = function (object, names) { + var O = toIObject(object); + var i = 0; + var result = []; + var key; + for (key in O) { + if (key != IE_PROTO) has(O, key) && result.push(key); + } // Don't enum bug & hidden keys + while (names.length > i) { + if (has(O, key = names[i++])) { + ~arrayIndexOf(result, key) || result.push(key); + } + } + return result; + }; + + /***/ + }, + /* 56 */ + /***/ + function (module, exports, __webpack_require__) { + // false -> Array#indexOf + // true -> Array#includes + var toIObject = __webpack_require__(16); + var toLength = __webpack_require__(22); + var toAbsoluteIndex = __webpack_require__(57); + module.exports = function (IS_INCLUDES) { + return function ($this, el, fromIndex) { + var O = toIObject($this); + var length = toLength(O.length); + var index = toAbsoluteIndex(fromIndex, length); + var value; + // Array#includes uses SameValueZero equality algorithm + // eslint-disable-next-line no-self-compare + if (IS_INCLUDES && el != el) while (length > index) { + value = O[index++]; + // eslint-disable-next-line no-self-compare + if (value != value) return true; + // Array#indexOf ignores holes, Array#includes - not + } else for (; length > index; index++) { + if (IS_INCLUDES || index in O) { + if (O[index] === el) return IS_INCLUDES || index || 0; + } + } + return !IS_INCLUDES && -1; + }; + }; + + /***/ + }, + /* 57 */ + /***/ + function (module, exports, __webpack_require__) { + var toInteger = __webpack_require__(18); + var max = Math.max; + var min = Math.min; + module.exports = function (index, length) { + index = toInteger(index); + return index < 0 ? max(index + length, 0) : min(index, length); + }; + + /***/ + }, + /* 58 */ + /***/ + function (module, exports, __webpack_require__) { + var document = __webpack_require__(1).document; + module.exports = document && document.documentElement; + + /***/ + }, + /* 59 */ + /***/ + function (module, exports, __webpack_require__) { + // 19.1.2.9 / 15.2.3.2 Object.getPrototypeOf(O) + var has = __webpack_require__(6); + var toObject = __webpack_require__(25); + var IE_PROTO = __webpack_require__(23)("IE_PROTO"); + var ObjectProto = Object.prototype; + + module.exports = Object.getPrototypeOf || function (O) { + O = toObject(O); + if (has(O, IE_PROTO)) return O[IE_PROTO]; + if (typeof O.constructor == "function" && O instanceof O.constructor) { + return O.constructor.prototype; + } + return O instanceof Object ? ObjectProto : null; + }; + + /***/ + }, + /* 60 */ + /***/ + function (module, exports, __webpack_require__) { + "use strict"; + + var ctx = __webpack_require__(11); + var $export = __webpack_require__(3); + var toObject = __webpack_require__(25); + var call = __webpack_require__(38); + var isArrayIter = __webpack_require__(39); + var toLength = __webpack_require__(22); + var createProperty = __webpack_require__(61); + var getIterFn = __webpack_require__(40); + + $export($export.S + $export.F * !__webpack_require__(41)(function (iter) { + Array.from(iter); + }), "Array", { + // 22.1.2.1 Array.from(arrayLike, mapfn = undefined, thisArg = undefined) + from: function from(arrayLike /* , mapfn = undefined, thisArg = undefined */ + ) { + var O = toObject(arrayLike); + var C = typeof this == "function" ? this : Array; + var aLen = arguments.length; + var mapfn = aLen > 1 ? arguments[1] : undefined; + var mapping = mapfn !== undefined; + var index = 0; + var iterFn = getIterFn(O); + var length, result, step, iterator; + if (mapping) mapfn = ctx(mapfn, aLen > 2 ? arguments[2] : undefined, 2); + // if object isn't iterable or it's array with default iterator - use simple case + if (iterFn != undefined && !(C == Array && isArrayIter(iterFn))) { + for (iterator = iterFn.call(O), result = new C(); !(step = iterator.next()).done; index++) { + createProperty(result, index, mapping ? call(iterator, mapfn, [step.value, index], true) : step.value); + } + } else { + length = toLength(O.length); + for (result = new C(length); length > index; index++) { + createProperty(result, index, mapping ? mapfn(O[index], index) : O[index]); + } + } + result.length = index; + return result; + } + }); + + /***/ + }, + /* 61 */ + /***/ + function (module, exports, __webpack_require__) { + "use strict"; + + var $defineProperty = __webpack_require__(4); + var createDesc = __webpack_require__(14); + + module.exports = function (object, index, value) { + if (index in object) $defineProperty.f(object, index, createDesc(0, value));else object[index] = value; + }; + + /***/ + }, + /* 62 */ + /***/ + function (module, exports, __webpack_require__) { + __webpack_require__(63); + module.exports = __webpack_require__(7).Object.assign; + + /***/ + }, + /* 63 */ + /***/ + function (module, exports, __webpack_require__) { + // 19.1.3.1 Object.assign(target, source) + var $export = __webpack_require__(3); + + $export($export.S + $export.F, "Object", { + assign: __webpack_require__(64) + }); + + /***/ + }, + /* 64 */ + /***/ + function (module, exports, __webpack_require__) { + "use strict"; + + // 19.1.2.1 Object.assign(target, source, ...) + + var getKeys = __webpack_require__(21); + var gOPS = __webpack_require__(65); + var pIE = __webpack_require__(42); + var toObject = __webpack_require__(25); + var IObject = __webpack_require__(34); + var $assign = Object.assign; + + // should work with symbols and should have deterministic property order (V8 bug) + module.exports = !$assign || __webpack_require__(12)(function () { + var A = {}; + var B = {}; + // eslint-disable-next-line no-undef + var S = Symbol(); + var K = "abcdefghijklmnopqrst"; + A[S] = 7; + K.split("").forEach(function (k) { + B[k] = k; + }); + return $assign({}, A)[S] != 7 || Object.keys($assign({}, B)).join("") != K; + }) ? function assign(target, source) { + // eslint-disable-line no-unused-vars + var T = toObject(target); + var aLen = arguments.length; + var index = 1; + var getSymbols = gOPS.f; + var isEnum = pIE.f; + while (aLen > index) { + var S = IObject(arguments[index++]); + var keys = getSymbols ? getKeys(S).concat(getSymbols(S)) : getKeys(S); + var length = keys.length; + var j = 0; + var key; + while (length > j) { + if (isEnum.call(S, key = keys[j++])) T[key] = S[key]; + } + } + return T; + } : $assign; + + /***/ + }, + /* 65 */ + /***/ + function (module, exports) { + exports.f = Object.getOwnPropertySymbols; + + /***/ + }, + /* 66 */ + /***/ + function (module, exports, __webpack_require__) { + __webpack_require__(67); + __webpack_require__(28); + __webpack_require__(68); + __webpack_require__(71); + __webpack_require__(78); + __webpack_require__(81); + __webpack_require__(83); + module.exports = __webpack_require__(7).Set; + + /***/ + }, + /* 67 */ + /***/ + function (module, exports, __webpack_require__) { + "use strict"; + + // 19.1.3.6 Object.prototype.toString() + + var classof = __webpack_require__(26); + var test = {}; + test[__webpack_require__(0)("toStringTag")] = "z"; + if (test + "" != "[object z]") { + __webpack_require__(10)(Object.prototype, "toString", function toString() { + return "[object " + classof(this) + "]"; + }, true); + } + + /***/ + }, + /* 68 */ + /***/ + function (module, exports, __webpack_require__) { + var $iterators = __webpack_require__(69); + var getKeys = __webpack_require__(21); + var redefine = __webpack_require__(10); + var global = __webpack_require__(1); + var hide = __webpack_require__(8); + var Iterators = __webpack_require__(13); + var wks = __webpack_require__(0); + var ITERATOR = wks("iterator"); + var TO_STRING_TAG = wks("toStringTag"); + var ArrayValues = Iterators.Array; + + var DOMIterables = { + CSSRuleList: true, // TODO: Not spec compliant, should be false. + CSSStyleDeclaration: false, + CSSValueList: false, + ClientRectList: false, + DOMRectList: false, + DOMStringList: false, + DOMTokenList: true, + DataTransferItemList: false, + FileList: false, + HTMLAllCollection: false, + HTMLCollection: false, + HTMLFormElement: false, + HTMLSelectElement: false, + MediaList: true, // TODO: Not spec compliant, should be false. + MimeTypeArray: false, + NamedNodeMap: false, + NodeList: true, + PaintRequestList: false, + Plugin: false, + PluginArray: false, + SVGLengthList: false, + SVGNumberList: false, + SVGPathSegList: false, + SVGPointList: false, + SVGStringList: false, + SVGTransformList: false, + SourceBufferList: false, + StyleSheetList: true, // TODO: Not spec compliant, should be false. + TextTrackCueList: false, + TextTrackList: false, + TouchList: false + }; + + for (var collections = getKeys(DOMIterables), i = 0; i < collections.length; i++) { + var NAME = collections[i]; + var explicit = DOMIterables[NAME]; + var Collection = global[NAME]; + var proto = Collection && Collection.prototype; + var key; + if (proto) { + if (!proto[ITERATOR]) hide(proto, ITERATOR, ArrayValues); + if (!proto[TO_STRING_TAG]) hide(proto, TO_STRING_TAG, NAME); + Iterators[NAME] = ArrayValues; + if (explicit) for (key in $iterators) { + if (!proto[key]) redefine(proto, key, $iterators[key], true); + } + } + } + + /***/ + }, + /* 69 */ + /***/ + function (module, exports, __webpack_require__) { + "use strict"; + + var addToUnscopables = __webpack_require__(70); + var step = __webpack_require__(43); + var Iterators = __webpack_require__(13); + var toIObject = __webpack_require__(16); + + // 22.1.3.4 Array.prototype.entries() + // 22.1.3.13 Array.prototype.keys() + // 22.1.3.29 Array.prototype.values() + // 22.1.3.30 Array.prototype[@@iterator]() + module.exports = __webpack_require__(20)(Array, "Array", function (iterated, kind) { + this._t = toIObject(iterated); // target + this._i = 0; // next index + this._k = kind; // kind + // 22.1.5.2.1 %ArrayIteratorPrototype%.next() + }, function () { + var O = this._t; + var kind = this._k; + var index = this._i++; + if (!O || index >= O.length) { + this._t = undefined; + return step(1); + } + if (kind == "keys") return step(0, index); + if (kind == "values") return step(0, O[index]); + return step(0, [index, O[index]]); + }, "values"); + + // argumentsList[@@iterator] is %ArrayProto_values% (9.4.4.6, 9.4.4.7) + Iterators.Arguments = Iterators.Array; + + addToUnscopables("keys"); + addToUnscopables("values"); + addToUnscopables("entries"); + + /***/ + }, + /* 70 */ + /***/ + function (module, exports, __webpack_require__) { + // 22.1.3.31 Array.prototype[@@unscopables] + var UNSCOPABLES = __webpack_require__(0)("unscopables"); + var ArrayProto = Array.prototype; + if (ArrayProto[UNSCOPABLES] == undefined) __webpack_require__(8)(ArrayProto, UNSCOPABLES, {}); + module.exports = function (key) { + ArrayProto[UNSCOPABLES][key] = true; + }; + + /***/ + }, + /* 71 */ + /***/ + function (module, exports, __webpack_require__) { + "use strict"; + + var strong = __webpack_require__(72); + var validate = __webpack_require__(47); + var SET = "Set"; + + // 23.2 Set Objects + module.exports = __webpack_require__(74)(SET, function (get) { + return function Set() { + return get(this, arguments.length > 0 ? arguments[0] : undefined); + }; + }, { + // 23.2.3.1 Set.prototype.add(value) + add: function add(value) { + return strong.def(validate(this, SET), value = value === 0 ? 0 : value, value); + } + }, strong); + + /***/ + }, + /* 72 */ + /***/ + function (module, exports, __webpack_require__) { + "use strict"; + + var dP = __webpack_require__(4).f; + var create = __webpack_require__(33); + var redefineAll = __webpack_require__(44); + var ctx = __webpack_require__(11); + var anInstance = __webpack_require__(45); + var forOf = __webpack_require__(17); + var $iterDefine = __webpack_require__(20); + var step = __webpack_require__(43); + var setSpecies = __webpack_require__(73); + var DESCRIPTORS = __webpack_require__(5); + var fastKey = __webpack_require__(46).fastKey; + var validate = __webpack_require__(47); + var SIZE = DESCRIPTORS ? "_s" : "size"; + + var getEntry = function getEntry(that, key) { + // fast case + var index = fastKey(key); + var entry; + if (index !== "F") return that._i[index]; + // frozen object case + for (entry = that._f; entry; entry = entry.n) { + if (entry.k == key) return entry; + } + }; + + module.exports = { + getConstructor: function getConstructor(wrapper, NAME, IS_MAP, ADDER) { + var C = wrapper(function (that, iterable) { + anInstance(that, C, NAME, "_i"); + that._t = NAME; // collection type + that._i = create(null); // index + that._f = undefined; // first entry + that._l = undefined; // last entry + that[SIZE] = 0; // size + if (iterable != undefined) forOf(iterable, IS_MAP, that[ADDER], that); + }); + redefineAll(C.prototype, { + // 23.1.3.1 Map.prototype.clear() + // 23.2.3.2 Set.prototype.clear() + clear: function clear() { + for (var that = validate(this, NAME), data = that._i, entry = that._f; entry; entry = entry.n) { + entry.r = true; + if (entry.p) entry.p = entry.p.n = undefined; + delete data[entry.i]; + } + that._f = that._l = undefined; + that[SIZE] = 0; + }, + // 23.1.3.3 Map.prototype.delete(key) + // 23.2.3.4 Set.prototype.delete(value) + delete: function _delete(key) { + var that = validate(this, NAME); + var entry = getEntry(that, key); + if (entry) { + var next = entry.n; + var prev = entry.p; + delete that._i[entry.i]; + entry.r = true; + if (prev) prev.n = next; + if (next) next.p = prev; + if (that._f == entry) that._f = next; + if (that._l == entry) that._l = prev; + that[SIZE]--; + } + return !!entry; + }, + // 23.2.3.6 Set.prototype.forEach(callbackfn, thisArg = undefined) + // 23.1.3.5 Map.prototype.forEach(callbackfn, thisArg = undefined) + forEach: function forEach(callbackfn /* , that = undefined */) { + validate(this, NAME); + var f = ctx(callbackfn, arguments.length > 1 ? arguments[1] : undefined, 3); + var entry; + while (entry = entry ? entry.n : this._f) { + f(entry.v, entry.k, this); + // revert to the last existing entry + while (entry && entry.r) { + entry = entry.p; + } + } + }, + // 23.1.3.7 Map.prototype.has(key) + // 23.2.3.7 Set.prototype.has(value) + has: function has(key) { + return !!getEntry(validate(this, NAME), key); + } + }); + if (DESCRIPTORS) dP(C.prototype, "size", { + get: function get() { + return validate(this, NAME)[SIZE]; + } + }); + return C; + }, + def: function def(that, key, value) { + var entry = getEntry(that, key); + var prev, index; + // change existing entry + if (entry) { + entry.v = value; + // create new entry + } else { + that._l = entry = { + i: index = fastKey(key, true), // <- index + k: key, // <- key + v: value, // <- value + p: prev = that._l, // <- previous entry + n: undefined, // <- next entry + r: false // <- removed + }; + if (!that._f) that._f = entry; + if (prev) prev.n = entry; + that[SIZE]++; + // add to index + if (index !== "F") that._i[index] = entry; + } + return that; + }, + getEntry: getEntry, + setStrong: function setStrong(C, NAME, IS_MAP) { + // add .keys, .values, .entries, [@@iterator] + // 23.1.3.4, 23.1.3.8, 23.1.3.11, 23.1.3.12, 23.2.3.5, 23.2.3.8, 23.2.3.10, 23.2.3.11 + $iterDefine(C, NAME, function (iterated, kind) { + this._t = validate(iterated, NAME); // target + this._k = kind; // kind + this._l = undefined; // previous + }, function () { + var that = this; + var kind = that._k; + var entry = that._l; + // revert to the last existing entry + while (entry && entry.r) { + entry = entry.p; + } // get next entry + if (!that._t || !(that._l = entry = entry ? entry.n : that._t._f)) { + // or finish the iteration + that._t = undefined; + return step(1); + } + // return step by kind + if (kind == "keys") return step(0, entry.k); + if (kind == "values") return step(0, entry.v); + return step(0, [entry.k, entry.v]); + }, IS_MAP ? "entries" : "values", !IS_MAP, true); + + // add [@@species], 23.1.2.2, 23.2.2.2 + setSpecies(NAME); + } + }; + + /***/ + }, + /* 73 */ + /***/ + function (module, exports, __webpack_require__) { + "use strict"; + + var global = __webpack_require__(1); + var dP = __webpack_require__(4); + var DESCRIPTORS = __webpack_require__(5); + var SPECIES = __webpack_require__(0)("species"); + + module.exports = function (KEY) { + var C = global[KEY]; + if (DESCRIPTORS && C && !C[SPECIES]) dP.f(C, SPECIES, { + configurable: true, + get: function get() { + return this; + } + }); + }; + + /***/ + }, + /* 74 */ + /***/ + function (module, exports, __webpack_require__) { + "use strict"; + + var global = __webpack_require__(1); + var $export = __webpack_require__(3); + var redefine = __webpack_require__(10); + var redefineAll = __webpack_require__(44); + var meta = __webpack_require__(46); + var forOf = __webpack_require__(17); + var anInstance = __webpack_require__(45); + var isObject = __webpack_require__(2); + var fails = __webpack_require__(12); + var $iterDetect = __webpack_require__(41); + var setToStringTag = __webpack_require__(24); + var inheritIfRequired = __webpack_require__(75); + + module.exports = function (NAME, wrapper, methods, common, IS_MAP, IS_WEAK) { + var Base = global[NAME]; + var C = Base; + var ADDER = IS_MAP ? "set" : "add"; + var proto = C && C.prototype; + var O = {}; + var fixMethod = function fixMethod(KEY) { + var fn = proto[KEY]; + redefine(proto, KEY, KEY == "delete" ? function (a) { + return IS_WEAK && !isObject(a) ? false : fn.call(this, a === 0 ? 0 : a); + } : KEY == "has" ? function has(a) { + return IS_WEAK && !isObject(a) ? false : fn.call(this, a === 0 ? 0 : a); + } : KEY == "get" ? function get(a) { + return IS_WEAK && !isObject(a) ? undefined : fn.call(this, a === 0 ? 0 : a); + } : KEY == "add" ? function add(a) { + fn.call(this, a === 0 ? 0 : a); + return this; + } : function set(a, b) { + fn.call(this, a === 0 ? 0 : a, b); + return this; + }); + }; + if (typeof C != "function" || !(IS_WEAK || proto.forEach && !fails(function () { + new C().entries().next(); + }))) { + // create collection constructor + C = common.getConstructor(wrapper, NAME, IS_MAP, ADDER); + redefineAll(C.prototype, methods); + meta.NEED = true; + } else { + var instance = new C(); + // early implementations not supports chaining + var HASNT_CHAINING = instance[ADDER](IS_WEAK ? {} : -0, 1) != instance; + // V8 ~ Chromium 40- weak-collections throws on primitives, but should return false + var THROWS_ON_PRIMITIVES = fails(function () { + instance.has(1); + }); + // most early implementations doesn't supports iterables, most modern - not close it correctly + var ACCEPT_ITERABLES = $iterDetect(function (iter) { + new C(iter); + }); // eslint-disable-line no-new + // for early implementations -0 and +0 not the same + var BUGGY_ZERO = !IS_WEAK && fails(function () { + // V8 ~ Chromium 42- fails only with 5+ elements + var $instance = new C(); + var index = 5; + while (index--) { + $instance[ADDER](index, index); + } + return !$instance.has(-0); + }); + if (!ACCEPT_ITERABLES) { + C = wrapper(function (target, iterable) { + anInstance(target, C, NAME); + var that = inheritIfRequired(new Base(), target, C); + if (iterable != undefined) forOf(iterable, IS_MAP, that[ADDER], that); + return that; + }); + C.prototype = proto; + proto.constructor = C; + } + if (THROWS_ON_PRIMITIVES || BUGGY_ZERO) { + fixMethod("delete"); + fixMethod("has"); + IS_MAP && fixMethod("get"); + } + if (BUGGY_ZERO || HASNT_CHAINING) fixMethod(ADDER); + // weak collections should not contains .clear method + if (IS_WEAK && proto.clear) delete proto.clear; + } + + setToStringTag(C, NAME); + + O[NAME] = C; + $export($export.G + $export.W + $export.F * (C != Base), O); + + if (!IS_WEAK) common.setStrong(C, NAME, IS_MAP); + + return C; + }; + + /***/ + }, + /* 75 */ + /***/ + function (module, exports, __webpack_require__) { + var isObject = __webpack_require__(2); + var setPrototypeOf = __webpack_require__(76).set; + module.exports = function (that, target, C) { + var S = target.constructor; + var P; + if (S !== C && typeof S == "function" && (P = S.prototype) !== C.prototype && isObject(P) && setPrototypeOf) { + setPrototypeOf(that, P); + } + return that; + }; + + /***/ + }, + /* 76 */ + /***/ + function (module, exports, __webpack_require__) { + // Works with __proto__ only. Old v8 can't work with null proto objects. + /* eslint-disable no-proto */ + var isObject = __webpack_require__(2); + var anObject = __webpack_require__(9); + var check = function check(O, proto) { + anObject(O); + if (!isObject(proto) && proto !== null) throw TypeError(proto + ": can't set as prototype!"); + }; + module.exports = { + set: Object.setPrototypeOf || ("__proto__" in {} // eslint-disable-line + ? function (test, buggy, set) { + try { + set = __webpack_require__(11)(Function.call, __webpack_require__(77).f(Object.prototype, "__proto__").set, 2); + set(test, []); + buggy = !(test instanceof Array); + } catch (e) { + buggy = true; + } + return function setPrototypeOf(O, proto) { + check(O, proto); + if (buggy) O.__proto__ = proto;else set(O, proto); + return O; + }; + }({}, false) : undefined), + check: check + }; + + /***/ + }, + /* 77 */ + /***/ + function (module, exports, __webpack_require__) { + var pIE = __webpack_require__(42); + var createDesc = __webpack_require__(14); + var toIObject = __webpack_require__(16); + var toPrimitive = __webpack_require__(31); + var has = __webpack_require__(6); + var IE8_DOM_DEFINE = __webpack_require__(29); + var gOPD = Object.getOwnPropertyDescriptor; + + exports.f = __webpack_require__(5) ? gOPD : function getOwnPropertyDescriptor(O, P) { + O = toIObject(O); + P = toPrimitive(P, true); + if (IE8_DOM_DEFINE) try { + return gOPD(O, P); + } catch (e) { + /* empty */ + } + if (has(O, P)) return createDesc(!pIE.f.call(O, P), O[P]); + }; + + /***/ + }, + /* 78 */ + /***/ + function (module, exports, __webpack_require__) { + // https://github.com/DavidBruant/Map-Set.prototype.toJSON + var $export = __webpack_require__(3); + + $export($export.P + $export.R, "Set", { + toJSON: __webpack_require__(79)("Set") + }); + + /***/ + }, + /* 79 */ + /***/ + function (module, exports, __webpack_require__) { + // https://github.com/DavidBruant/Map-Set.prototype.toJSON + var classof = __webpack_require__(26); + var from = __webpack_require__(80); + module.exports = function (NAME) { + return function toJSON() { + if (classof(this) != NAME) throw TypeError(NAME + "#toJSON isn't generic"); + return from(this); + }; + }; + + /***/ + }, + /* 80 */ + /***/ + function (module, exports, __webpack_require__) { + var forOf = __webpack_require__(17); + + module.exports = function (iter, ITERATOR) { + var result = []; + forOf(iter, false, result.push, result, ITERATOR); + return result; + }; + + /***/ + }, + /* 81 */ + /***/ + function (module, exports, __webpack_require__) { + // https://tc39.github.io/proposal-setmap-offrom/#sec-set.of + __webpack_require__(82)("Set"); + + /***/ + }, + /* 82 */ + /***/ + function (module, exports, __webpack_require__) { + "use strict"; + + // https://tc39.github.io/proposal-setmap-offrom/ + + var $export = __webpack_require__(3); + + module.exports = function (COLLECTION) { + $export($export.S, COLLECTION, { + of: function of() { + var length = arguments.length; + var A = new Array(length); + while (length--) { + A[length] = arguments[length]; + } + return new this(A); + } + }); + }; + + /***/ + }, + /* 83 */ + /***/ + function (module, exports, __webpack_require__) { + // https://tc39.github.io/proposal-setmap-offrom/#sec-set.from + __webpack_require__(84)("Set"); + + /***/ + }, + /* 84 */ + /***/ + function (module, exports, __webpack_require__) { + "use strict"; + + // https://tc39.github.io/proposal-setmap-offrom/ + + var $export = __webpack_require__(3); + var aFunction = __webpack_require__(32); + var ctx = __webpack_require__(11); + var forOf = __webpack_require__(17); + + module.exports = function (COLLECTION) { + $export($export.S, COLLECTION, { + from: function from(source /* , mapFn, thisArg */) { + var mapFn = arguments[1]; + var mapping, A, n, cb; + aFunction(this); + mapping = mapFn !== undefined; + if (mapping) aFunction(mapFn); + if (source == undefined) return new this(); + A = []; + if (mapping) { + n = 0; + cb = ctx(mapFn, arguments[2], 2); + forOf(source, false, function (nextItem) { + A.push(cb(nextItem, n++)); + }); + } else { + forOf(source, false, A.push, A); + } + return new this(A); + } + }); + }; + + /***/ + }, + /* 85 */ + /***/ + function (module, exports, __webpack_require__) { + "use strict"; + + var _icons = __webpack_require__(27); + + var _icons2 = _interopRequireDefault(_icons); + + var _toSvg = __webpack_require__(90); + + var _toSvg2 = _interopRequireDefault(_toSvg); + + var _replace = __webpack_require__(91); + + var _replace2 = _interopRequireDefault(_replace); + + function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; + } + + module.exports = { + icons: _icons2.default, + toSvg: _toSvg2.default, + replace: _replace2.default + }; + + /***/ + }, + /* 86 */ + /***/ + function (module, exports, __webpack_require__) { + "use strict"; + + Object.defineProperty(exports, "__esModule", { + value: true + }); + + var _extends = Object.assign || function (target) { + for (var i = 1; i < arguments.length; i++) { + var source = arguments[i]; + for (var key in source) { + if (Object.prototype.hasOwnProperty.call(source, key)) { + target[key] = source[key]; + } + } + } + return target; + }; + + var _createClass = function () { + function defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, descriptor.key, descriptor); + } + } + return function (Constructor, protoProps, staticProps) { + if (protoProps) defineProperties(Constructor.prototype, protoProps); + if (staticProps) defineProperties(Constructor, staticProps); + return Constructor; + }; + }(); + + var _dedupe = __webpack_require__(48); + + var _dedupe2 = _interopRequireDefault(_dedupe); + + var _defaultAttrs = __webpack_require__(87); + + var _defaultAttrs2 = _interopRequireDefault(_defaultAttrs); + + function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; + } + + function _classCallCheck(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } + } + + var Icon = function () { + function Icon(name, contents) { + var tags = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : []; + + _classCallCheck(this, Icon); + + this.name = name; + this.contents = contents; + this.tags = tags; + this.attrs = _extends({}, _defaultAttrs2.default, { + class: "feather feather-" + name + }); + } + + /** + * Create an SVG string. + * @param {Object} attrs + * @returns {string} + */ + + _createClass(Icon, [{ + key: "toSvg", + value: function toSvg() { + var attrs = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + + var combinedAttrs = _extends({}, this.attrs, attrs, { + class: (0, _dedupe2.default)(this.attrs.class, attrs.class) + }); + + return "" + this.contents + ""; + } + + /** + * Return string representation of an `Icon`. + * + * Added for backward compatibility. If old code expects `feather.icons.` + * to be a string, `toString()` will get implicitly called. + * + * @returns {string} + */ + }, { + key: "toString", + value: function toString() { + return this.contents; + } + }]); + + return Icon; + }(); + + /** + * Convert attributes object to string of HTML attributes. + * @param {Object} attrs + * @returns {string} + */ + + function attrsToString(attrs) { + return Object.keys(attrs).map(function (key) { + return key + '="' + attrs[key] + '"'; + }).join(" "); + } + + exports.default = Icon; + + /***/ + }, + /* 87 */ + /***/ + function (module, exports) { + module.exports = { + xmlns: "http://www.w3.org/2000/svg", + width: 24, + height: 24, + viewBox: "0 0 24 24", + fill: "none", + stroke: "currentColor", + "stroke-width": 2, + "stroke-linecap": "round", + "stroke-linejoin": "round" + + /***/ + }; + }, + /* 88 */ + /***/ + function (module, exports) { + module.exports = { + activity: '', + airplay: '', + "alert-circle": '', + "alert-octagon": '', + "alert-triangle": '', + "align-center": '', + "align-justify": '', + "align-left": '', + "align-right": '', + anchor: '', + aperture: '', + "arrow-down-circle": '', + "arrow-down-left": '', + "arrow-down-right": '', + "arrow-down": '', + "arrow-left-circle": '', + "arrow-left": '', + "arrow-right-circle": '', + "arrow-right": '', + "arrow-up-circle": '', + "arrow-up-left": '', + "arrow-up-right": '', + "arrow-up": '', + "at-sign": '', + award: '', + "bar-chart-2": '', + "bar-chart": '', + "battery-charging": '', + battery: '', + "bell-off": '', + bell: '', + bluetooth: '', + bold: '', + "book-open": '', + book: '', + bookmark: '', + box: '', + briefcase: '', + calendar: '', + "camera-off": '', + camera: '', + cast: '', + "check-circle": '', + "check-square": '', + check: '', + "chevron-down": '', + "chevron-left": '', + "chevron-right": '', + "chevron-up": '', + "chevrons-down": '', + "chevrons-left": '', + "chevrons-right": '', + "chevrons-up": '', + chrome: '', + circle: '', + clipboard: '', + clock: '', + "cloud-drizzle": '', + "cloud-lightning": '', + "cloud-off": '', + "cloud-rain": '', + "cloud-snow": '', + cloud: '', + code: '', + codepen: '', + command: '', + compass: '', + copy: '', + "corner-down-left": '', + "corner-down-right": '', + "corner-left-down": '', + "corner-left-up": '', + "corner-right-down": '', + "corner-right-up": '', + "corner-up-left": '', + "corner-up-right": '', + cpu: '', + "credit-card": '', + crop: '', + crosshair: '', + database: '', + delete: '', + disc: '', + "dollar-sign": '', + "download-cloud": '', + download: '', + droplet: '', + "edit-2": '', + "edit-3": '', + edit: '', + "external-link": '', + "eye-off": '', + eye: '', + facebook: '', + "fast-forward": '', + feather: '', + "file-minus": '', + "file-plus": '', + "file-text": '', + file: '', + film: '', + filter: '', + flag: '', + "folder-minus": '', + "folder-plus": '', + folder: '', + "git-branch": '', + "git-commit": '', + "git-merge": '', + "git-pull-request": '', + github: '', + gitlab: '', + globe: '', + grid: '', + "hard-drive": '', + hash: '', + headphones: '', + heart: '', + "help-circle": '', + home: '', + image: '', + inbox: '', + info: '', + instagram: '', + italic: '', + layers: '', + layout: '', + "life-buoy": '', + "link-2": '', + link: '', + linkedin: '', + list: '', + loader: '', + lock: '', + "log-in": '', + "log-out": '', + mail: '', + "map-pin": '', + map: '', + "maximize-2": '', + maximize: '', + menu: '', + "message-circle": '', + "message-square": '', + "mic-off": '', + mic: '', + "minimize-2": '', + minimize: '', + "minus-circle": '', + "minus-square": '', + minus: '', + monitor: '', + moon: '', + "more-horizontal": '', + "more-vertical": '', + move: '', + music: '', + "navigation-2": '', + navigation: '', + octagon: '', + package: '', + paperclip: '', + "pause-circle": '', + pause: '', + percent: '', + "phone-call": '', + "phone-forwarded": '', + "phone-incoming": '', + "phone-missed": '', + "phone-off": '', + "phone-outgoing": '', + phone: '', + "pie-chart": '', + "play-circle": '', + play: '', + "plus-circle": '', + "plus-square": '', + plus: '', + pocket: '', + power: '', + printer: '', + radio: '', + "refresh-ccw": '', + "refresh-cw": '', + repeat: '', + rewind: '', + "rotate-ccw": '', + "rotate-cw": '', + rss: '', + save: '', + scissors: '', + search: '', + send: '', + server: '', + settings: '', + "share-2": '', + share: '', + "shield-off": '', + shield: '', + "shopping-bag": '', + "shopping-cart": '', + shuffle: '', + sidebar: '', + "skip-back": '', + "skip-forward": '', + slack: '', + slash: '', + sliders: '', + smartphone: '', + speaker: '', + square: '', + star: '', + "stop-circle": '', + sun: '', + sunrise: '', + sunset: '', + tablet: '', + tag: '', + target: '', + terminal: '', + thermometer: '', + "thumbs-down": '', + "thumbs-up": '', + "toggle-left": '', + "toggle-right": '', + "trash-2": '', + trash: '', + "trending-down": '', + "trending-up": '', + triangle: '', + truck: '', + tv: '', + twitter: '', + type: '', + umbrella: '', + underline: '', + unlock: '', + "upload-cloud": '', + upload: '', + "user-check": '', + "user-minus": '', + "user-plus": '', + "user-x": '', + user: '', + users: '', + "video-off": '', + video: '', + voicemail: '', + "volume-1": '', + "volume-2": '', + "volume-x": '', + volume: '', + watch: '', + "wifi-off": '', + wifi: '', + wind: '', + "x-circle": '', + "x-square": '', + x: '', + "zap-off": '', + zap: '', + "zoom-in": '', + "zoom-out": '' + + /***/ + }; + }, + /* 89 */ + /***/ + function (module, exports) { + module.exports = { + activity: ["pulse", "health", "action", "motion"], + airplay: ["stream", "cast", "mirroring"], + "alert-circle": ["warning"], + "alert-octagon": ["warning"], + "alert-triangle": ["warning"], + "at-sign": ["mention"], + award: ["achievement", "badge"], + aperture: ["camera", "photo"], + bell: ["alarm", "notification"], + "bell-off": ["alarm", "notification", "silent"], + bluetooth: ["wireless"], + "book-open": ["read"], + book: ["read", "dictionary", "booklet", "magazine"], + bookmark: ["read", "clip", "marker", "tag"], + briefcase: ["work", "bag", "baggage", "folder"], + clipboard: ["copy"], + clock: ["time", "watch", "alarm"], + "cloud-drizzle": ["weather", "shower"], + "cloud-lightning": ["weather", "bolt"], + "cloud-rain": ["weather"], + "cloud-snow": ["weather", "blizzard"], + cloud: ["weather"], + codepen: ["logo"], + command: ["keyboard", "cmd"], + compass: ["navigation", "safari", "travel"], + copy: ["clone", "duplicate"], + "corner-down-left": ["arrow"], + "corner-down-right": ["arrow"], + "corner-left-down": ["arrow"], + "corner-left-up": ["arrow"], + "corner-right-down": ["arrow"], + "corner-right-up": ["arrow"], + "corner-up-left": ["arrow"], + "corner-up-right": ["arrow"], + "credit-card": ["purchase", "payment", "cc"], + crop: ["photo", "image"], + crosshair: ["aim", "target"], + database: ["storage"], + delete: ["remove"], + disc: ["album", "cd", "dvd", "music"], + "dollar-sign": ["currency", "money", "payment"], + droplet: ["water"], + edit: ["pencil", "change"], + "edit-2": ["pencil", "change"], + "edit-3": ["pencil", "change"], + eye: ["view", "watch"], + "eye-off": ["view", "watch"], + "external-link": ["outbound"], + facebook: ["logo"], + "fast-forward": ["music"], + film: ["movie", "video"], + "folder-minus": ["directory"], + "folder-plus": ["directory"], + folder: ["directory"], + "git-branch": ["code", "version control"], + "git-commit": ["code", "version control"], + "git-merge": ["code", "version control"], + "git-pull-request": ["code", "version control"], + github: ["logo", "version control"], + gitlab: ["logo", "version control"], + global: ["world", "browser", "language", "translate"], + "hard-drive": ["computer", "server"], + hash: ["hashtag", "number", "pound"], + headphones: ["music", "audio"], + heart: ["like", "love"], + "help-circle": ["question mark"], + home: ["house"], + image: ["picture"], + inbox: ["email"], + instagram: ["logo", "camera"], + "life-bouy": ["help", "life ring", "support"], + linkedin: ["logo"], + lock: ["security", "password"], + "log-in": ["sign in", "arrow"], + "log-out": ["sign out", "arrow"], + mail: ["email"], + "map-pin": ["location", "navigation", "travel", "marker"], + map: ["location", "navigation", "travel"], + maximize: ["fullscreen"], + "maximize-2": ["fullscreen", "arrows"], + menu: ["bars", "navigation", "hamburger"], + "message-circle": ["comment", "chat"], + "message-square": ["comment", "chat"], + "mic-off": ["record"], + mic: ["record"], + minimize: ["exit fullscreen"], + "minimize-2": ["exit fullscreen", "arrows"], + monitor: ["tv"], + moon: ["dark", "night"], + "more-horizontal": ["ellipsis"], + "more-vertical": ["ellipsis"], + move: ["arrows"], + navigation: ["location", "travel"], + "navigation-2": ["location", "travel"], + octagon: ["stop"], + package: ["box"], + paperclip: ["attachment"], + pause: ["music", "stop"], + "pause-circle": ["music", "stop"], + play: ["music", "start"], + "play-circle": ["music", "start"], + plus: ["add", "new"], + "plus-circle": ["add", "new"], + "plus-square": ["add", "new"], + pocket: ["logo", "save"], + power: ["on", "off"], + radio: ["signal"], + rewind: ["music"], + rss: ["feed", "subscribe"], + save: ["floppy disk"], + send: ["message", "mail", "paper airplane"], + settings: ["cog", "edit", "gear", "preferences"], + shield: ["security"], + "shield-off": ["security"], + "shopping-bag": ["ecommerce", "cart", "purchase", "store"], + "shopping-cart": ["ecommerce", "cart", "purchase", "store"], + shuffle: ["music"], + "skip-back": ["music"], + "skip-forward": ["music"], + slash: ["ban", "no"], + sliders: ["settings", "controls"], + speaker: ["music"], + star: ["bookmark", "favorite", "like"], + sun: ["brightness", "weather", "light"], + sunrise: ["weather"], + sunset: ["weather"], + tag: ["label"], + target: ["bullseye"], + terminal: ["code", "command line"], + "thumbs-down": ["dislike", "bad"], + "thumbs-up": ["like", "good"], + "toggle-left": ["on", "off", "switch"], + "toggle-right": ["on", "off", "switch"], + trash: ["garbage", "delete", "remove"], + "trash-2": ["garbage", "delete", "remove"], + triangle: ["delta"], + truck: ["delivery", "van", "shipping"], + twitter: ["logo"], + umbrella: ["rain", "weather"], + "video-off": ["camera", "movie", "film"], + video: ["camera", "movie", "film"], + voicemail: ["phone"], + volume: ["music", "sound", "mute"], + "volume-1": ["music", "sound"], + "volume-2": ["music", "sound"], + "volume-x": ["music", "sound", "mute"], + watch: ["clock", "time"], + wind: ["weather", "air"], + "x-circle": ["cancel", "close", "delete", "remove", "times"], + "x-square": ["cancel", "close", "delete", "remove", "times"], + x: ["cancel", "close", "delete", "remove", "times"], + "zap-off": ["flash", "camera", "lightning"], + zap: ["flash", "camera", "lightning"] + + /***/ + }; + }, + /* 90 */ + /***/ + function (module, exports, __webpack_require__) { + "use strict"; + + Object.defineProperty(exports, "__esModule", { + value: true + }); + + var _icons = __webpack_require__(27); + + var _icons2 = _interopRequireDefault(_icons); + + function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; + } + + /** + * Create an SVG string. + * @deprecated + * @param {string} name + * @param {Object} attrs + * @returns {string} + */ + function toSvg(name) { + var attrs = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + + console.warn("feather.toSvg() is deprecated. Please use feather.icons[name].toSvg() instead."); + + if (!name) { + throw new Error("The required `key` (icon name) parameter is missing."); + } + + if (!_icons2.default[name]) { + throw new Error("No icon matching '" + name + "'. See the complete list of icons at https://feathericons.com"); + } + + return _icons2.default[name].toSvg(attrs); + } + + exports.default = toSvg; + + /***/ + }, + /* 91 */ + /***/ + function (module, exports, __webpack_require__) { + "use strict"; + + Object.defineProperty(exports, "__esModule", { + value: true + }); + + var _extends = Object.assign || function (target) { + for (var i = 1; i < arguments.length; i++) { + var source = arguments[i]; + for (var key in source) { + if (Object.prototype.hasOwnProperty.call(source, key)) { + target[key] = source[key]; + } + } + } + return target; + }; /* eslint-env browser */ + + var _dedupe = __webpack_require__(48); + + var _dedupe2 = _interopRequireDefault(_dedupe); + + var _icons = __webpack_require__(27); + + var _icons2 = _interopRequireDefault(_icons); + + function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; + } + + /** + * Replace all HTML elements that have a `data-feather` attribute with SVG markup + * corresponding to the element's `data-feather` attribute value. + * @param {Object} attrs + */ + function replace() { + var attrs = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + + if (typeof document === "undefined") { + throw new Error("`feather.replace()` only works in a browser environment."); + } + + var elementsToReplace = document.querySelectorAll("[data-feather]"); + + Array.from(elementsToReplace).forEach(function (element) { + return replaceElement(element, attrs); + }); + } + + /** + * Replace a single HTML element with SVG markup + * corresponding to the element's `data-feather` attribute value. + * @param {HTMLElement} element + * @param {Object} attrs + */ + function replaceElement(element) { + var attrs = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + + var elementAttrs = getAttrs(element); + var name = elementAttrs["data-feather"]; + delete elementAttrs["data-feather"]; + + var svgString = _icons2.default[name].toSvg(_extends({}, attrs, elementAttrs, { + class: (0, _dedupe2.default)(attrs.class, elementAttrs.class) + })); + var svgDocument = new DOMParser().parseFromString(svgString, "image/svg+xml"); + var svgElement = svgDocument.querySelector("svg"); + + element.parentNode.replaceChild(svgElement, element); + } + + /** + * Get the attributes of an HTML element. + * @param {HTMLElement} element + * @returns {Object} + */ + function getAttrs(element) { + return Array.from(element.attributes).reduce(function (attrs, attr) { + attrs[attr.name] = attr.value; + return attrs; + }, {}); + } + + exports.default = replace; + + /***/ + }] + /******/ + ) + ); +}); diff --git a/user/themes/bulma-portfolio/js/portfolio.js b/user/themes/bulma-portfolio/js/portfolio.js new file mode 100644 index 00000000..53d7069a --- /dev/null +++ b/user/themes/bulma-portfolio/js/portfolio.js @@ -0,0 +1,76 @@ +"use strict"; + +document.addEventListener('DOMContentLoaded', function () { + + // Get all "navbar-burger" elements + var $navbarBurgers = Array.prototype.slice.call(document.querySelectorAll('.navbar-burger'), 0); + + // Check if there are any navbar burgers + if ($navbarBurgers.length > 0) { + // Add a click event on each of them + $navbarBurgers.forEach(function ($el) { + $el.addEventListener('click', function () { + // Get the target from the "data-target" attribute + var target = $el.dataset.target; + var $target = document.getElementById(target); + // Toggle the class on both the "navbar-burger" and the "navbar-menu" + $el.classList.toggle('is-active'); + $target.classList.toggle('is-active'); + }); + }); + } + var $modalBtns = Array.from(document.querySelectorAll('.modal-button')); + if ($modalBtns.length > 0) { + // Add a click event on each of them + $modalBtns.forEach(function ($btn) { + $btn.addEventListener('click', function () { + // Get the target from the "data-target" attribute + var target = $btn.dataset.target; + var $target = document.getElementById(target); + // Toggle the class on both the "navbar-burger" and the "navbar-menu" + $target.classList.add('is-active'); + var html = document.documentElement; + html.classList.add('is-clipped'); + var modalBg = Array.from(document.querySelectorAll('.modal-background')); + var closeBtn = Array.from(document.querySelectorAll('[data-dismiss]')); + closeBtn.forEach(function (button) { + return button.addEventListener('click', function () { + $target.classList.remove('is-active'); + html.classList.remove('is-clipped'); + }); + }); + + modalBg.forEach(function (modBg) { + return modBg.addEventListener('click', function () { + $target.classList.remove('is-active'); + html.classList.remove('is-clipped'); + }); + }); + }); + }); + } + var scroll = new SmoothScroll('a[href*="#"]', { + // Selectors + ignore: '[data-scroll-ignore]', // Selector for links to ignore (must be a valid CSS selector) + header: null, // Selector for fixed headers (must be a valid CSS selector) + + // Speed & Easing + speed: 500, // Integer. How fast to complete the scroll in milliseconds + offset: 0, // Integer or Function returning an integer. How far to offset the scrolling anchor location in pixels + easing: 'easeInOutCubic', // Easing pattern to use + customEasing: function customEasing(time) { + + // Function. Custom easing pattern + // If this is set to anything other than null, will override the easing option above + + // return + + // Example: easeInOut Quad + return time < 0.5 ? 2 * time * time : -1 + (4 - 2 * time) * time; + } + + // Callback API + // before: function(anchor, toggle) {}, // Callback to run before scroll + // after: function(anchor, toggle) {} // Callback to run after scroll + }); +}); diff --git a/user/themes/bulma-portfolio/js/smooth-scroll.js b/user/themes/bulma-portfolio/js/smooth-scroll.js new file mode 100644 index 00000000..6e6709c3 --- /dev/null +++ b/user/themes/bulma-portfolio/js/smooth-scroll.js @@ -0,0 +1,576 @@ +/*! + * smooth-scroll v12.1.5: Animate scrolling to anchor links + * (c) 2017 Chris Ferdinandi + * MIT License + * http://github.com/cferdinandi/smooth-scroll + */ + +(function(root, factory) { + if (typeof define === 'function' && define.amd) { + define([], (function() { + return factory(root); + })); + } else if (typeof exports === 'object') { + module.exports = factory(root); + } else { + root.SmoothScroll = factory(root); + } +})(typeof global !== 'undefined' ? global : typeof window !== 'undefined' ? window : this, (function(window) { + + 'use strict'; + + // + // Feature Test + // + + var supports = + 'querySelector' in document && + 'addEventListener' in window && + 'requestAnimationFrame' in window && + 'closest' in window.Element.prototype; + + + // + // Default settings + // + + var defaults = { + // Selectors + ignore: '[data-scroll-ignore]', + header: null, + + // Speed & Easing + speed: 500, + offset: 0, + easing: 'easeInOutCubic', + customEasing: null, + + // Callback API + before: function() {}, + after: function() {} + }; + + + // + // Utility Methods + // + + /** + * Merge two or more objects. Returns a new object. + * @param {Object} objects The objects to merge together + * @returns {Object} Merged values of defaults and options + */ + var extend = function() { + + // Variables + var extended = {}; + var deep = false; + var i = 0; + var length = arguments.length; + + // Merge the object into the extended object + var merge = function(obj) { + for (var prop in obj) { + if (obj.hasOwnProperty(prop)) { + extended[prop] = obj[prop]; + } + } + }; + + // Loop through each object and conduct a merge + for (; i < length; i++) { + var obj = arguments[i]; + merge(obj); + } + + return extended; + + }; + + /** + * Get the height of an element. + * @param {Node} elem The element to get the height of + * @return {Number} The element's height in pixels + */ + var getHeight = function(elem) { + return parseInt(window.getComputedStyle(elem).height, 10); + }; + + /** + * Escape special characters for use with querySelector + * @param {String} id The anchor ID to escape + * @author Mathias Bynens + * @link https://github.com/mathiasbynens/CSS.escape + */ + var escapeCharacters = function(id) { + + // Remove leading hash + if (id.charAt(0) === '#') { + id = id.substr(1); + } + + var string = String(id); + var length = string.length; + var index = -1; + var codeUnit; + var result = ''; + var firstCodeUnit = string.charCodeAt(0); + while (++index < length) { + codeUnit = string.charCodeAt(index); + // Note: there’s no need to special-case astral symbols, surrogate + // pairs, or lone surrogates. + + // If the character is NULL (U+0000), then throw an + // `InvalidCharacterError` exception and terminate these steps. + if (codeUnit === 0x0000) { + throw new InvalidCharacterError( + 'Invalid character: the input contains U+0000.' + ); + } + + if ( + // If the character is in the range [\1-\1F] (U+0001 to U+001F) or is + // U+007F, […] + (codeUnit >= 0x0001 && codeUnit <= 0x001F) || codeUnit == 0x007F || + // If the character is the first character and is in the range [0-9] + // (U+0030 to U+0039), […] + (index === 0 && codeUnit >= 0x0030 && codeUnit <= 0x0039) || + // If the character is the second character and is in the range [0-9] + // (U+0030 to U+0039) and the first character is a `-` (U+002D), […] + ( + index === 1 && + codeUnit >= 0x0030 && codeUnit <= 0x0039 && + firstCodeUnit === 0x002D + ) + ) { + // http://dev.w3.org/csswg/cssom/#escape-a-character-as-code-point + result += '\\' + codeUnit.toString(16) + ' '; + continue; + } + + // If the character is not handled by one of the above rules and is + // greater than or equal to U+0080, is `-` (U+002D) or `_` (U+005F), or + // is in one of the ranges [0-9] (U+0030 to U+0039), [A-Z] (U+0041 to + // U+005A), or [a-z] (U+0061 to U+007A), […] + if ( + codeUnit >= 0x0080 || + codeUnit === 0x002D || + codeUnit === 0x005F || + codeUnit >= 0x0030 && codeUnit <= 0x0039 || + codeUnit >= 0x0041 && codeUnit <= 0x005A || + codeUnit >= 0x0061 && codeUnit <= 0x007A + ) { + // the character itself + result += string.charAt(index); + continue; + } + + // Otherwise, the escaped character. + // http://dev.w3.org/csswg/cssom/#escape-a-character + result += '\\' + string.charAt(index); + + } + + return '#' + result; + + }; + + /** + * Calculate the easing pattern + * @link https://gist.github.com/gre/1650294 + * @param {String} type Easing pattern + * @param {Number} time Time animation should take to complete + * @returns {Number} + */ + var easingPattern = function(settings, time) { + var pattern; + + // Default Easing Patterns + if (settings.easing === 'easeInQuad') pattern = time * time; // accelerating from zero velocity + if (settings.easing === 'easeOutQuad') pattern = time * (2 - time); // decelerating to zero velocity + if (settings.easing === 'easeInOutQuad') pattern = time < 0.5 ? 2 * time * time : -1 + (4 - 2 * time) * time; // acceleration until halfway, then deceleration + if (settings.easing === 'easeInCubic') pattern = time * time * time; // accelerating from zero velocity + if (settings.easing === 'easeOutCubic') pattern = (--time) * time * time + 1; // decelerating to zero velocity + if (settings.easing === 'easeInOutCubic') pattern = time < 0.5 ? 4 * time * time * time : (time - 1) * (2 * time - 2) * (2 * time - 2) + 1; // acceleration until halfway, then deceleration + if (settings.easing === 'easeInQuart') pattern = time * time * time * time; // accelerating from zero velocity + if (settings.easing === 'easeOutQuart') pattern = 1 - (--time) * time * time * time; // decelerating to zero velocity + if (settings.easing === 'easeInOutQuart') pattern = time < 0.5 ? 8 * time * time * time * time : 1 - 8 * (--time) * time * time * time; // acceleration until halfway, then deceleration + if (settings.easing === 'easeInQuint') pattern = time * time * time * time * time; // accelerating from zero velocity + if (settings.easing === 'easeOutQuint') pattern = 1 + (--time) * time * time * time * time; // decelerating to zero velocity + if (settings.easing === 'easeInOutQuint') pattern = time < 0.5 ? 16 * time * time * time * time * time : 1 + 16 * (--time) * time * time * time * time; // acceleration until halfway, then deceleration + + // Custom Easing Patterns + if (!!settings.customEasing) pattern = settings.customEasing(time); + + return pattern || time; // no easing, no acceleration + }; + + /** + * Determine the document's height + * @returns {Number} + */ + var getDocumentHeight = function() { + return Math.max( + document.body.scrollHeight, document.documentElement.scrollHeight, + document.body.offsetHeight, document.documentElement.offsetHeight, + document.body.clientHeight, document.documentElement.clientHeight + ); + }; + + /** + * Calculate how far to scroll + * @param {Element} anchor The anchor element to scroll to + * @param {Number} headerHeight Height of a fixed header, if any + * @param {Number} offset Number of pixels by which to offset scroll + * @returns {Number} + */ + var getEndLocation = function(anchor, headerHeight, offset) { + var location = 0; + if (anchor.offsetParent) { + do { + location += anchor.offsetTop; + anchor = anchor.offsetParent; + } while (anchor); + } + location = Math.max(location - headerHeight - offset, 0); + return location; + }; + + /** + * Get the height of the fixed header + * @param {Node} header The header + * @return {Number} The height of the header + */ + var getHeaderHeight = function(header) { + return !header ? 0 : (getHeight(header) + header.offsetTop); + }; + + /** + * Bring the anchored element into focus + * @param {Node} anchor The anchor element + * @param {Number} endLocation The end location to scroll to + * @param {Boolean} isNum If true, scroll is to a position rather than an element + */ + var adjustFocus = function(anchor, endLocation, isNum) { + + // Don't run if scrolling to a number on the page + if (isNum) return; + + // Otherwise, bring anchor element into focus + anchor.focus(); + if (document.activeElement.id !== anchor.id) { + anchor.setAttribute('tabindex', '-1'); + anchor.focus(); + anchor.style.outline = 'none'; + } + window.scrollTo(0, endLocation); + + }; + + /** + * Check to see if user prefers reduced motion + * @param {Object} settings Script settings + */ + var reduceMotion = function(settings) { + if ('matchMedia' in window && window.matchMedia('(prefers-reduced-motion)').matches) { + return true; + } + return false; + }; + + + // + // SmoothScroll Constructor + // + + var SmoothScroll = function(selector, options) { + + // + // Variables + // + + var smoothScroll = {}; // Object for public APIs + var settings, anchor, toggle, fixedHeader, headerHeight, eventTimeout, animationInterval; + + + // + // Methods + // + + /** + * Cancel a scroll-in-progress + */ + smoothScroll.cancelScroll = function() { + // clearInterval(animationInterval); + cancelAnimationFrame(animationInterval); + }; + + /** + * Start/stop the scrolling animation + * @param {Node|Number} anchor The element or position to scroll to + * @param {Element} toggle The element that toggled the scroll event + * @param {Object} options + */ + smoothScroll.animateScroll = function(anchor, toggle, options) { + + // Local settings + var animateSettings = extend(settings || defaults, options || {}); // Merge user options with defaults + + // Selectors and variables + var isNum = Object.prototype.toString.call(anchor) === '[object Number]' ? true : false; + var anchorElem = isNum || !anchor.tagName ? null : anchor; + if (!isNum && !anchorElem) return; + var startLocation = window.pageYOffset; // Current location on the page + if (animateSettings.header && !fixedHeader) { + // Get the fixed header if not already set + fixedHeader = document.querySelector(animateSettings.header); + } + if (!headerHeight) { + // Get the height of a fixed header if one exists and not already set + headerHeight = getHeaderHeight(fixedHeader); + } + var endLocation = isNum ? anchor : getEndLocation(anchorElem, headerHeight, parseInt((typeof animateSettings.offset === 'function' ? animateSettings.offset() : animateSettings.offset), 10)); // Location to scroll to + var distance = endLocation - startLocation; // distance to travel + var documentHeight = getDocumentHeight(); + var timeLapsed = 0; + var start, percentage, position; + + /** + * Stop the scroll animation when it reaches its target (or the bottom/top of page) + * @param {Number} position Current position on the page + * @param {Number} endLocation Scroll to location + * @param {Number} animationInterval How much to scroll on this loop + */ + var stopAnimateScroll = function(position, endLocation) { + + // Get the current location + var currentLocation = window.pageYOffset; + + // Check if the end location has been reached yet (or we've hit the end of the document) + if (position == endLocation || currentLocation == endLocation || ((startLocation < endLocation && window.innerHeight + currentLocation) >= documentHeight)) { + + // Clear the animation timer + smoothScroll.cancelScroll(); + + // Bring the anchored element into focus + adjustFocus(anchor, endLocation, isNum); + + // Run callback after animation complete + animateSettings.after(anchor, toggle); + + // Reset start + start = null; + + return true; + + } + }; + + /** + * Loop scrolling animation + */ + var loopAnimateScroll = function(timestamp) { + if (!start) { start = timestamp; } + timeLapsed += timestamp - start; + percentage = (timeLapsed / parseInt(animateSettings.speed, 10)); + percentage = (percentage > 1) ? 1 : percentage; + position = startLocation + (distance * easingPattern(animateSettings, percentage)); + window.scrollTo(0, Math.floor(position)); + if (!stopAnimateScroll(position, endLocation)) { + window.requestAnimationFrame(loopAnimateScroll); + start = timestamp; + } + }; + + /** + * Reset position to fix weird iOS bug + * @link https://github.com/cferdinandi/smooth-scroll/issues/45 + */ + if (window.pageYOffset === 0) { + window.scrollTo(0, 0); + } + + // Run callback before animation starts + animateSettings.before(anchor, toggle); + + // Start scrolling animation + smoothScroll.cancelScroll(); + window.requestAnimationFrame(loopAnimateScroll); + + + }; + + /** + * Handle has change event + */ + var hashChangeHandler = function(event) { + + // Only run if there's an anchor element to scroll to + if (!anchor) return; + + // Reset the anchor element's ID + anchor.id = anchor.getAttribute('data-scroll-id'); + + // Scroll to the anchored content + smoothScroll.animateScroll(anchor, toggle); + + // Reset anchor and toggle + anchor = null; + toggle = null; + + }; + + /** + * If smooth scroll element clicked, animate scroll + */ + var clickHandler = function(event) { + + // Don't run if the user prefers reduced motion + if (reduceMotion(settings)) return; + + // Don't run if right-click or command/control + click + if (event.button !== 0 || event.metaKey || event.ctrlKey) return; + + // Check if a smooth scroll link was clicked + toggle = event.target.closest(selector); + if (!toggle || toggle.tagName.toLowerCase() !== 'a' || event.target.closest(settings.ignore)) return; + + // Only run if link is an anchor and points to the current page + if (toggle.hostname !== window.location.hostname || toggle.pathname !== window.location.pathname || !/#/.test(toggle.href)) return; + + // Get the sanitized hash + var hash; + try { + hash = escapeCharacters(decodeURIComponent(toggle.hash)); + } catch (e) { + hash = escapeCharacters(toggle.hash); + } + + // If the hash is empty, scroll to the top of the page + if (hash === '#') { + + // Prevent default link behavior + event.preventDefault(); + + // Set the anchored element + anchor = document.body; + + // Save or create the ID as a data attribute and remove it (prevents scroll jump) + var id = anchor.id ? anchor.id : 'smooth-scroll-top'; + anchor.setAttribute('data-scroll-id', id); + anchor.id = ''; + + // If no hash change event will happen, fire manually + // Otherwise, update the hash + if (window.location.hash.substring(1) === id) { + hashChangeHandler(); + } else { + window.location.hash = id; + } + + return; + + } + + // Get the anchored element + anchor = document.querySelector(hash); + + // If anchored element exists, save the ID as a data attribute and remove it (prevents scroll jump) + if (!anchor) return; + anchor.setAttribute('data-scroll-id', anchor.id); + anchor.id = ''; + + // If no hash change event will happen, fire manually + if (toggle.hash === window.location.hash) { + event.preventDefault(); + hashChangeHandler(); + } + + }; + + /** + * On window scroll and resize, only run events at a rate of 15fps for better performance + */ + var resizeThrottler = function(event) { + if (!eventTimeout) { + eventTimeout = setTimeout((function() { + eventTimeout = null; // Reset timeout + headerHeight = getHeaderHeight(fixedHeader); // Get the height of a fixed header if one exists + }), 66); + } + }; + + /** + * Destroy the current initialization. + */ + smoothScroll.destroy = function() { + + // If plugin isn't already initialized, stop + if (!settings) return; + + // Remove event listeners + document.removeEventListener('click', clickHandler, false); + window.removeEventListener('resize', resizeThrottler, false); + + // Cancel any scrolls-in-progress + smoothScroll.cancelScroll(); + + // Reset variables + settings = null; + anchor = null; + toggle = null; + fixedHeader = null; + headerHeight = null; + eventTimeout = null; + animationInterval = null; + }; + + /** + * Initialize Smooth Scroll + * @param {Object} options User settings + */ + smoothScroll.init = function(options) { + + // feature test + if (!supports) return; + + // Destroy any existing initializations + smoothScroll.destroy(); + + // Selectors and variables + settings = extend(defaults, options || {}); // Merge user options with defaults + fixedHeader = settings.header ? document.querySelector(settings.header) : null; // Get the fixed header + headerHeight = getHeaderHeight(fixedHeader); + + // When a toggle is clicked, run the click handler + document.addEventListener('click', clickHandler, false); + + // Listen for hash changes + window.addEventListener('hashchange', hashChangeHandler, false); + + // If window is resized and there's a fixed header, recalculate its size + if (fixedHeader) { + window.addEventListener('resize', resizeThrottler, false); + } + + }; + + + // + // Initialize plugin + // + + smoothScroll.init(options); + + + // + // Public APIs + // + + return smoothScroll; + + }; + + return SmoothScroll; + +})); \ No newline at end of file diff --git a/user/themes/bulma-portfolio/js/smooth-scrolls-polifylls.js b/user/themes/bulma-portfolio/js/smooth-scrolls-polifylls.js new file mode 100644 index 00000000..e8d7e928 --- /dev/null +++ b/user/themes/bulma-portfolio/js/smooth-scrolls-polifylls.js @@ -0,0 +1,627 @@ +/*! + * smooth-scroll v12.1.5: Animate scrolling to anchor links + * (c) 2017 Chris Ferdinandi + * MIT License + * http://github.com/cferdinandi/smooth-scroll + */ + +/** + * closest() polyfill + * @link https://developer.mozilla.org/en-US/docs/Web/API/Element/closest#Polyfill + */ +if (window.Element && !Element.prototype.closest) { + Element.prototype.closest = function(s) { + var matches = (this.document || this.ownerDocument).querySelectorAll(s), + i, + el = this; + do { + i = matches.length; + while (--i >= 0 && matches.item(i) !== el) {} + } while ((i < 0) && (el = el.parentElement)); + return el; + }; +} + +/** + * requestAnimationFrame() polyfill + * By Erik Möller. Fixes from Paul Irish and Tino Zijdel. + * @link http://paulirish.com/2011/requestanimationframe-for-smart-animating/ + * @link http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating + * @license MIT + */ +(function() { + var lastTime = 0; + var vendors = ['ms', 'moz', 'webkit', 'o']; + for (var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) { + window.requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame']; + window.cancelAnimationFrame = window[vendors[x] + 'CancelAnimationFrame'] || + window[vendors[x] + 'CancelRequestAnimationFrame']; + } + + if (!window.requestAnimationFrame) { + window.requestAnimationFrame = function(callback, element) { + var currTime = new Date().getTime(); + var timeToCall = Math.max(0, 16 - (currTime - lastTime)); + var id = window.setTimeout((function() { callback(currTime + timeToCall); }), + timeToCall); + lastTime = currTime + timeToCall; + return id; + }; + } + + if (!window.cancelAnimationFrame) { + window.cancelAnimationFrame = function(id) { + clearTimeout(id); + }; + } +}()); + +(function(root, factory) { + if (typeof define === 'function' && define.amd) { + define([], (function() { + return factory(root); + })); + } else if (typeof exports === 'object') { + module.exports = factory(root); + } else { + root.SmoothScroll = factory(root); + } +})(typeof global !== 'undefined' ? global : typeof window !== 'undefined' ? window : this, (function(window) { + + 'use strict'; + + // + // Feature Test + // + + var supports = + 'querySelector' in document && + 'addEventListener' in window && + 'requestAnimationFrame' in window && + 'closest' in window.Element.prototype; + + + // + // Default settings + // + + var defaults = { + // Selectors + ignore: '[data-scroll-ignore]', + header: null, + + // Speed & Easing + speed: 500, + offset: 0, + easing: 'easeInOutCubic', + customEasing: null, + + // Callback API + before: function() {}, + after: function() {} + }; + + + // + // Utility Methods + // + + /** + * Merge two or more objects. Returns a new object. + * @param {Object} objects The objects to merge together + * @returns {Object} Merged values of defaults and options + */ + var extend = function() { + + // Variables + var extended = {}; + var deep = false; + var i = 0; + var length = arguments.length; + + // Merge the object into the extended object + var merge = function(obj) { + for (var prop in obj) { + if (obj.hasOwnProperty(prop)) { + extended[prop] = obj[prop]; + } + } + }; + + // Loop through each object and conduct a merge + for (; i < length; i++) { + var obj = arguments[i]; + merge(obj); + } + + return extended; + + }; + + /** + * Get the height of an element. + * @param {Node} elem The element to get the height of + * @return {Number} The element's height in pixels + */ + var getHeight = function(elem) { + return parseInt(window.getComputedStyle(elem).height, 10); + }; + + /** + * Escape special characters for use with querySelector + * @param {String} id The anchor ID to escape + * @author Mathias Bynens + * @link https://github.com/mathiasbynens/CSS.escape + */ + var escapeCharacters = function(id) { + + // Remove leading hash + if (id.charAt(0) === '#') { + id = id.substr(1); + } + + var string = String(id); + var length = string.length; + var index = -1; + var codeUnit; + var result = ''; + var firstCodeUnit = string.charCodeAt(0); + while (++index < length) { + codeUnit = string.charCodeAt(index); + // Note: there’s no need to special-case astral symbols, surrogate + // pairs, or lone surrogates. + + // If the character is NULL (U+0000), then throw an + // `InvalidCharacterError` exception and terminate these steps. + if (codeUnit === 0x0000) { + throw new InvalidCharacterError( + 'Invalid character: the input contains U+0000.' + ); + } + + if ( + // If the character is in the range [\1-\1F] (U+0001 to U+001F) or is + // U+007F, […] + (codeUnit >= 0x0001 && codeUnit <= 0x001F) || codeUnit == 0x007F || + // If the character is the first character and is in the range [0-9] + // (U+0030 to U+0039), […] + (index === 0 && codeUnit >= 0x0030 && codeUnit <= 0x0039) || + // If the character is the second character and is in the range [0-9] + // (U+0030 to U+0039) and the first character is a `-` (U+002D), […] + ( + index === 1 && + codeUnit >= 0x0030 && codeUnit <= 0x0039 && + firstCodeUnit === 0x002D + ) + ) { + // http://dev.w3.org/csswg/cssom/#escape-a-character-as-code-point + result += '\\' + codeUnit.toString(16) + ' '; + continue; + } + + // If the character is not handled by one of the above rules and is + // greater than or equal to U+0080, is `-` (U+002D) or `_` (U+005F), or + // is in one of the ranges [0-9] (U+0030 to U+0039), [A-Z] (U+0041 to + // U+005A), or [a-z] (U+0061 to U+007A), […] + if ( + codeUnit >= 0x0080 || + codeUnit === 0x002D || + codeUnit === 0x005F || + codeUnit >= 0x0030 && codeUnit <= 0x0039 || + codeUnit >= 0x0041 && codeUnit <= 0x005A || + codeUnit >= 0x0061 && codeUnit <= 0x007A + ) { + // the character itself + result += string.charAt(index); + continue; + } + + // Otherwise, the escaped character. + // http://dev.w3.org/csswg/cssom/#escape-a-character + result += '\\' + string.charAt(index); + + } + + return '#' + result; + + }; + + /** + * Calculate the easing pattern + * @link https://gist.github.com/gre/1650294 + * @param {String} type Easing pattern + * @param {Number} time Time animation should take to complete + * @returns {Number} + */ + var easingPattern = function(settings, time) { + var pattern; + + // Default Easing Patterns + if (settings.easing === 'easeInQuad') pattern = time * time; // accelerating from zero velocity + if (settings.easing === 'easeOutQuad') pattern = time * (2 - time); // decelerating to zero velocity + if (settings.easing === 'easeInOutQuad') pattern = time < 0.5 ? 2 * time * time : -1 + (4 - 2 * time) * time; // acceleration until halfway, then deceleration + if (settings.easing === 'easeInCubic') pattern = time * time * time; // accelerating from zero velocity + if (settings.easing === 'easeOutCubic') pattern = (--time) * time * time + 1; // decelerating to zero velocity + if (settings.easing === 'easeInOutCubic') pattern = time < 0.5 ? 4 * time * time * time : (time - 1) * (2 * time - 2) * (2 * time - 2) + 1; // acceleration until halfway, then deceleration + if (settings.easing === 'easeInQuart') pattern = time * time * time * time; // accelerating from zero velocity + if (settings.easing === 'easeOutQuart') pattern = 1 - (--time) * time * time * time; // decelerating to zero velocity + if (settings.easing === 'easeInOutQuart') pattern = time < 0.5 ? 8 * time * time * time * time : 1 - 8 * (--time) * time * time * time; // acceleration until halfway, then deceleration + if (settings.easing === 'easeInQuint') pattern = time * time * time * time * time; // accelerating from zero velocity + if (settings.easing === 'easeOutQuint') pattern = 1 + (--time) * time * time * time * time; // decelerating to zero velocity + if (settings.easing === 'easeInOutQuint') pattern = time < 0.5 ? 16 * time * time * time * time * time : 1 + 16 * (--time) * time * time * time * time; // acceleration until halfway, then deceleration + + // Custom Easing Patterns + if (!!settings.customEasing) pattern = settings.customEasing(time); + + return pattern || time; // no easing, no acceleration + }; + + /** + * Determine the document's height + * @returns {Number} + */ + var getDocumentHeight = function() { + return Math.max( + document.body.scrollHeight, document.documentElement.scrollHeight, + document.body.offsetHeight, document.documentElement.offsetHeight, + document.body.clientHeight, document.documentElement.clientHeight + ); + }; + + /** + * Calculate how far to scroll + * @param {Element} anchor The anchor element to scroll to + * @param {Number} headerHeight Height of a fixed header, if any + * @param {Number} offset Number of pixels by which to offset scroll + * @returns {Number} + */ + var getEndLocation = function(anchor, headerHeight, offset) { + var location = 0; + if (anchor.offsetParent) { + do { + location += anchor.offsetTop; + anchor = anchor.offsetParent; + } while (anchor); + } + location = Math.max(location - headerHeight - offset, 0); + return location; + }; + + /** + * Get the height of the fixed header + * @param {Node} header The header + * @return {Number} The height of the header + */ + var getHeaderHeight = function(header) { + return !header ? 0 : (getHeight(header) + header.offsetTop); + }; + + /** + * Bring the anchored element into focus + * @param {Node} anchor The anchor element + * @param {Number} endLocation The end location to scroll to + * @param {Boolean} isNum If true, scroll is to a position rather than an element + */ + var adjustFocus = function(anchor, endLocation, isNum) { + + // Don't run if scrolling to a number on the page + if (isNum) return; + + // Otherwise, bring anchor element into focus + anchor.focus(); + if (document.activeElement.id !== anchor.id) { + anchor.setAttribute('tabindex', '-1'); + anchor.focus(); + anchor.style.outline = 'none'; + } + window.scrollTo(0, endLocation); + + }; + + /** + * Check to see if user prefers reduced motion + * @param {Object} settings Script settings + */ + var reduceMotion = function(settings) { + if ('matchMedia' in window && window.matchMedia('(prefers-reduced-motion)').matches) { + return true; + } + return false; + }; + + + // + // SmoothScroll Constructor + // + + var SmoothScroll = function(selector, options) { + + // + // Variables + // + + var smoothScroll = {}; // Object for public APIs + var settings, anchor, toggle, fixedHeader, headerHeight, eventTimeout, animationInterval; + + + // + // Methods + // + + /** + * Cancel a scroll-in-progress + */ + smoothScroll.cancelScroll = function() { + // clearInterval(animationInterval); + cancelAnimationFrame(animationInterval); + }; + + /** + * Start/stop the scrolling animation + * @param {Node|Number} anchor The element or position to scroll to + * @param {Element} toggle The element that toggled the scroll event + * @param {Object} options + */ + smoothScroll.animateScroll = function(anchor, toggle, options) { + + // Local settings + var animateSettings = extend(settings || defaults, options || {}); // Merge user options with defaults + + // Selectors and variables + var isNum = Object.prototype.toString.call(anchor) === '[object Number]' ? true : false; + var anchorElem = isNum || !anchor.tagName ? null : anchor; + if (!isNum && !anchorElem) return; + var startLocation = window.pageYOffset; // Current location on the page + if (animateSettings.header && !fixedHeader) { + // Get the fixed header if not already set + fixedHeader = document.querySelector(animateSettings.header); + } + if (!headerHeight) { + // Get the height of a fixed header if one exists and not already set + headerHeight = getHeaderHeight(fixedHeader); + } + var endLocation = isNum ? anchor : getEndLocation(anchorElem, headerHeight, parseInt((typeof animateSettings.offset === 'function' ? animateSettings.offset() : animateSettings.offset), 10)); // Location to scroll to + var distance = endLocation - startLocation; // distance to travel + var documentHeight = getDocumentHeight(); + var timeLapsed = 0; + var start, percentage, position; + + /** + * Stop the scroll animation when it reaches its target (or the bottom/top of page) + * @param {Number} position Current position on the page + * @param {Number} endLocation Scroll to location + * @param {Number} animationInterval How much to scroll on this loop + */ + var stopAnimateScroll = function(position, endLocation) { + + // Get the current location + var currentLocation = window.pageYOffset; + + // Check if the end location has been reached yet (or we've hit the end of the document) + if (position == endLocation || currentLocation == endLocation || ((startLocation < endLocation && window.innerHeight + currentLocation) >= documentHeight)) { + + // Clear the animation timer + smoothScroll.cancelScroll(); + + // Bring the anchored element into focus + adjustFocus(anchor, endLocation, isNum); + + // Run callback after animation complete + animateSettings.after(anchor, toggle); + + // Reset start + start = null; + + return true; + + } + }; + + /** + * Loop scrolling animation + */ + var loopAnimateScroll = function(timestamp) { + if (!start) { start = timestamp; } + timeLapsed += timestamp - start; + percentage = (timeLapsed / parseInt(animateSettings.speed, 10)); + percentage = (percentage > 1) ? 1 : percentage; + position = startLocation + (distance * easingPattern(animateSettings, percentage)); + window.scrollTo(0, Math.floor(position)); + if (!stopAnimateScroll(position, endLocation)) { + window.requestAnimationFrame(loopAnimateScroll); + start = timestamp; + } + }; + + /** + * Reset position to fix weird iOS bug + * @link https://github.com/cferdinandi/smooth-scroll/issues/45 + */ + if (window.pageYOffset === 0) { + window.scrollTo(0, 0); + } + + // Run callback before animation starts + animateSettings.before(anchor, toggle); + + // Start scrolling animation + smoothScroll.cancelScroll(); + window.requestAnimationFrame(loopAnimateScroll); + + + }; + + /** + * Handle has change event + */ + var hashChangeHandler = function(event) { + + // Only run if there's an anchor element to scroll to + if (!anchor) return; + + // Reset the anchor element's ID + anchor.id = anchor.getAttribute('data-scroll-id'); + + // Scroll to the anchored content + smoothScroll.animateScroll(anchor, toggle); + + // Reset anchor and toggle + anchor = null; + toggle = null; + + }; + + /** + * If smooth scroll element clicked, animate scroll + */ + var clickHandler = function(event) { + + // Don't run if the user prefers reduced motion + if (reduceMotion(settings)) return; + + // Don't run if right-click or command/control + click + if (event.button !== 0 || event.metaKey || event.ctrlKey) return; + + // Check if a smooth scroll link was clicked + toggle = event.target.closest(selector); + if (!toggle || toggle.tagName.toLowerCase() !== 'a' || event.target.closest(settings.ignore)) return; + + // Only run if link is an anchor and points to the current page + if (toggle.hostname !== window.location.hostname || toggle.pathname !== window.location.pathname || !/#/.test(toggle.href)) return; + + // Get the sanitized hash + var hash; + try { + hash = escapeCharacters(decodeURIComponent(toggle.hash)); + } catch (e) { + hash = escapeCharacters(toggle.hash); + } + + // If the hash is empty, scroll to the top of the page + if (hash === '#') { + + // Prevent default link behavior + event.preventDefault(); + + // Set the anchored element + anchor = document.body; + + // Save or create the ID as a data attribute and remove it (prevents scroll jump) + var id = anchor.id ? anchor.id : 'smooth-scroll-top'; + anchor.setAttribute('data-scroll-id', id); + anchor.id = ''; + + // If no hash change event will happen, fire manually + // Otherwise, update the hash + if (window.location.hash.substring(1) === id) { + hashChangeHandler(); + } else { + window.location.hash = id; + } + + return; + + } + + // Get the anchored element + anchor = document.querySelector(hash); + + // If anchored element exists, save the ID as a data attribute and remove it (prevents scroll jump) + if (!anchor) return; + anchor.setAttribute('data-scroll-id', anchor.id); + anchor.id = ''; + + // If no hash change event will happen, fire manually + if (toggle.hash === window.location.hash) { + event.preventDefault(); + hashChangeHandler(); + } + + }; + + /** + * On window scroll and resize, only run events at a rate of 15fps for better performance + */ + var resizeThrottler = function(event) { + if (!eventTimeout) { + eventTimeout = setTimeout((function() { + eventTimeout = null; // Reset timeout + headerHeight = getHeaderHeight(fixedHeader); // Get the height of a fixed header if one exists + }), 66); + } + }; + + /** + * Destroy the current initialization. + */ + smoothScroll.destroy = function() { + + // If plugin isn't already initialized, stop + if (!settings) return; + + // Remove event listeners + document.removeEventListener('click', clickHandler, false); + window.removeEventListener('resize', resizeThrottler, false); + + // Cancel any scrolls-in-progress + smoothScroll.cancelScroll(); + + // Reset variables + settings = null; + anchor = null; + toggle = null; + fixedHeader = null; + headerHeight = null; + eventTimeout = null; + animationInterval = null; + }; + + /** + * Initialize Smooth Scroll + * @param {Object} options User settings + */ + smoothScroll.init = function(options) { + + // feature test + if (!supports) return; + + // Destroy any existing initializations + smoothScroll.destroy(); + + // Selectors and variables + settings = extend(defaults, options || {}); // Merge user options with defaults + fixedHeader = settings.header ? document.querySelector(settings.header) : null; // Get the fixed header + headerHeight = getHeaderHeight(fixedHeader); + + // When a toggle is clicked, run the click handler + document.addEventListener('click', clickHandler, false); + + // Listen for hash changes + window.addEventListener('hashchange', hashChangeHandler, false); + + // If window is resized and there's a fixed header, recalculate its size + if (fixedHeader) { + window.addEventListener('resize', resizeThrottler, false); + } + + }; + + + // + // Initialize plugin + // + + smoothScroll.init(options); + + + // + // Public APIs + // + + return smoothScroll; + + }; + + return SmoothScroll; + +})); \ No newline at end of file diff --git a/user/themes/bulma-portfolio/screenshot.jpg b/user/themes/bulma-portfolio/screenshot.jpg new file mode 100644 index 00000000..9e43133e Binary files /dev/null and b/user/themes/bulma-portfolio/screenshot.jpg differ diff --git a/user/themes/bulma-portfolio/scss/_body.scss b/user/themes/bulma-portfolio/scss/_body.scss new file mode 100644 index 00000000..dd9d23d7 --- /dev/null +++ b/user/themes/bulma-portfolio/scss/_body.scss @@ -0,0 +1,70 @@ +* { + box-sizing: border-box; +} + +html { + height: 100%; +} + +img { + max-width: 100%; +} + +.nopadding { + padding: 0; +} + +object { + pointer-events: none; +} + +.screenshot-wrapper { + margin-bottom: 2rem; + margin-top: 1rem; + transition: all .2s ease; + &:hover { + opacity: .7; + transform: scale(1.1) + } +} + +.screenshot-image { + text-align: center; +} + +.pt { + padding-top: 2rem; +} + +.clients-slider { + .is-centered { + margin: 1rem auto; + } +} + +body { + display: flex; + flex-flow: column nowrap; + min-height: 100vh; +} + +.content-wrapper { + flex: 1 0 auto; +} + +footer { + flex-shrink: 0; +} + +.footer { + padding: 3rem 1.5rem; + .icons { + display: inline-flex; + padding-bottom: 1rem; + li { + width: fit-content; + margin-left: 1rem; + margin-right: 1rem; + } + } +} \ No newline at end of file diff --git a/user/themes/bulma-portfolio/scss/_features.scss b/user/themes/bulma-portfolio/scss/_features.scss new file mode 100644 index 00000000..eb721af2 --- /dev/null +++ b/user/themes/bulma-portfolio/scss/_features.scss @@ -0,0 +1,11 @@ +//main: portfolio.scss +.feature-list-icon { + .svg-inline--fa { + // height: 50px; + } +} + +.feature-list-content { + justify-content: center; + align-items: center; +} \ No newline at end of file diff --git a/user/themes/bulma-portfolio/scss/_modal.scss b/user/themes/bulma-portfolio/scss/_modal.scss new file mode 100644 index 00000000..f74740ac --- /dev/null +++ b/user/themes/bulma-portfolio/scss/_modal.scss @@ -0,0 +1,13 @@ +//main: portfolio.scss +.space-between { + justify-content: space-between; +} + +.flex-end { + justify-content: flex-end; +} + +.padding { + padding-top: 2rem; + padding-bottom: 2rem; +} \ No newline at end of file diff --git a/user/themes/bulma-portfolio/scss/_tooltip.scss b/user/themes/bulma-portfolio/scss/_tooltip.scss new file mode 100644 index 00000000..cdb0d669 --- /dev/null +++ b/user/themes/bulma-portfolio/scss/_tooltip.scss @@ -0,0 +1,381 @@ +@-webkit-keyframes spinAround { + from { + -webkit-transform: rotate(0); + transform: rotate(0) + } + to { + -webkit-transform: rotate(359deg); + transform: rotate(359deg) + } +} + +@keyframes spinAround { + from { + -webkit-transform: rotate(0); + transform: rotate(0) + } + to { + -webkit-transform: rotate(359deg); + transform: rotate(359deg) + } +} + +.tooltip { + position: relative +} + +.tooltip.is-tooltip-active:not(.is-loading)::after, +.tooltip:hover:not(.is-loading)::after { + z-index: 99999; + position: absolute; + display: inline-block; + pointer-events: none +} + +.tooltip.is-tooltip-active::before, +.tooltip:hover::before { + z-index: 99999; + position: absolute; + display: inline-block; + pointer-events: none +} + +.tooltip.is-tooltip-active:not(.is-loading)::after, +.tooltip:hover:not(.is-loading)::after { + content: ""; + border-style: solid; + border-width: .5rem +} + +.tooltip.is-tooltip-active::before, +.tooltip:hover::before { + opacity: 0; + content: attr(data-tooltip); + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + font-size: .75rem; + padding: .4rem .8rem; + -webkit-transform: translate(-50%, 1rem); + transform: translate(-50%, 1rem); + background: rgba(74, 74, 74, .9); + border-radius: 3px; + color: #fff; + max-width: 24rem +} + +.tooltip.is-tooltip-active:not(.is-loading)::after, +.tooltip:focus:not(.is-loading)::after, +.tooltip:hover:not(.is-loading)::after { + top: 0; + bottom: auto; + left: 50%; + opacity: 1; + margin-left: -.5rem; + margin-top: -.5rem; + border-color: rgba(74, 74, 74, .9) transparent transparent transparent +} + +.tooltip.is-tooltip-active::before, +.tooltip:focus::before, +.tooltip:hover::before { + top: auto; + bottom: 100%; + left: 50%; + opacity: 1; + -webkit-transform: translate(-50%, -.5rem); + transform: translate(-50%, -.5rem) +} + +.tooltip.is-tooltip-right::before { + top: auto; + bottom: 50%; + left: 100%; + right: auto; + -webkit-transform: translate(-1rem, 50%); + transform: translate(-1rem, 50%) +} + +.tooltip.is-tooltip-right.is-tooltip-active:not(.is-loading)::after, +.tooltip.is-tooltip-right:focus:not(.is-loading)::after, +.tooltip.is-tooltip-right:hover:not(.is-loading)::after { + top: 50%; + left: 100%; + right: auto; + border-color: transparent rgba(74, 74, 74, .9) transparent transparent +} + +.tooltip.is-tooltip-right.is-tooltip-active::before, +.tooltip.is-tooltip-right:focus::before, +.tooltip.is-tooltip-right:hover::before { + -webkit-transform: translate(.5rem, 50%); + transform: translate(.5rem, 50%) +} + +.tooltip.is-tooltip-bottom::before { + top: 100%; + bottom: auto; + left: 50%; + right: auto; + -webkit-transform: translate(-50%, -1rem); + transform: translate(-50%, -1rem) +} + +.tooltip.is-tooltip-bottom.is-tooltip-active:not(.is-loading)::after, +.tooltip.is-tooltip-bottom:focus:not(.is-loading)::after, +.tooltip.is-tooltip-bottom:hover:not(.is-loading)::after { + top: 100%; + bottom: auto; + left: 50%; + right: auto; + border-color: transparent transparent rgba(74, 74, 74, .9) transparent +} + +.tooltip.is-tooltip-bottom.is-tooltip-active::before, +.tooltip.is-tooltip-bottom:focus::before, +.tooltip.is-tooltip-bottom:hover::before { + -webkit-transform: translate(-50%, .5rem); + transform: translate(-50%, .5rem) +} + +.tooltip.is-tooltip-left::before { + top: auto; + bottom: 50%; + left: auto; + right: 100%; + -webkit-transform: translate(1rem, 50%); + transform: translate(1rem, 50%) +} + +.tooltip.is-tooltip-left.is-tooltip-active:not(.is-loading)::after, +.tooltip.is-tooltip-left:focus:not(.is-loading)::after, +.tooltip.is-tooltip-left:hover:not(.is-loading)::after { + top: 50%; + left: auto; + right: calc(100% - .5rem); + border-color: transparent transparent transparent rgba(74, 74, 74, .9) +} + +.tooltip.is-tooltip-left.is-tooltip-active::before, +.tooltip.is-tooltip-left:focus::before, +.tooltip.is-tooltip-left:hover::before { + -webkit-transform: translate(-.5rem, 50%); + transform: translate(-.5rem, 50%) +} + +.tooltip.is-tooltip-multiline::before { + min-width: 24rem; + text-overflow: clip; + white-space: normal; + word-break: break-word +} + +.tooltip.is-tooltip-white:not(.is-loading)::after { + border-color: rgba(255, 255, 255, .9) transparent transparent transparent +} + +.tooltip.is-tooltip-white.is-tooltip-right:not(.is-loading)::after { + border-color: transparent rgba(255, 255, 255, .9) transparent transparent +} + +.tooltip.is-tooltip-white.is-tooltip-bottom:not(.is-loading)::after { + border-color: transparent transparent rgba(255, 255, 255, .9) transparent +} + +.tooltip.is-tooltip-white.is-tooltip-left:not(.is-loading)::after { + border-color: transparent transparent transparent rgba(255, 255, 255, .9) +} + +.tooltip.is-tooltip-white::before { + background: rgba(255, 255, 255, .9); + color: #0a0a0a +} + +.tooltip.is-tooltip-black:not(.is-loading)::after { + border-color: rgba(10, 10, 10, .9) transparent transparent transparent +} + +.tooltip.is-tooltip-black.is-tooltip-right:not(.is-loading)::after { + border-color: transparent rgba(10, 10, 10, .9) transparent transparent +} + +.tooltip.is-tooltip-black.is-tooltip-bottom:not(.is-loading)::after { + border-color: transparent transparent rgba(10, 10, 10, .9) transparent +} + +.tooltip.is-tooltip-black.is-tooltip-left:not(.is-loading)::after { + border-color: transparent transparent transparent rgba(10, 10, 10, .9) +} + +.tooltip.is-tooltip-black::before { + background: rgba(10, 10, 10, .9); + color: #fff +} + +.tooltip.is-tooltip-light:not(.is-loading)::after { + border-color: rgba(245, 245, 245, .9) transparent transparent transparent +} + +.tooltip.is-tooltip-light.is-tooltip-right:not(.is-loading)::after { + border-color: transparent rgba(245, 245, 245, .9) transparent transparent +} + +.tooltip.is-tooltip-light.is-tooltip-bottom:not(.is-loading)::after { + border-color: transparent transparent rgba(245, 245, 245, .9) transparent +} + +.tooltip.is-tooltip-light.is-tooltip-left:not(.is-loading)::after { + border-color: transparent transparent transparent rgba(245, 245, 245, .9) +} + +.tooltip.is-tooltip-light::before { + background: rgba(245, 245, 245, .9); + color: #363636 +} + +.tooltip.is-tooltip-dark:not(.is-loading)::after { + border-color: rgba(54, 54, 54, .9) transparent transparent transparent +} + +.tooltip.is-tooltip-dark.is-tooltip-right:not(.is-loading)::after { + border-color: transparent rgba(54, 54, 54, .9) transparent transparent +} + +.tooltip.is-tooltip-dark.is-tooltip-bottom:not(.is-loading)::after { + border-color: transparent transparent rgba(54, 54, 54, .9) transparent +} + +.tooltip.is-tooltip-dark.is-tooltip-left:not(.is-loading)::after { + border-color: transparent transparent transparent rgba(54, 54, 54, .9) +} + +.tooltip.is-tooltip-dark::before { + background: rgba(54, 54, 54, .9); + color: #f5f5f5 +} + +.tooltip.is-tooltip-primary:not(.is-loading)::after { + border-color: rgba(0, 209, 178, .9) transparent transparent transparent +} + +.tooltip.is-tooltip-primary.is-tooltip-right:not(.is-loading)::after { + border-color: transparent rgba(0, 209, 178, .9) transparent transparent +} + +.tooltip.is-tooltip-primary.is-tooltip-bottom:not(.is-loading)::after { + border-color: transparent transparent rgba(0, 209, 178, .9) transparent +} + +.tooltip.is-tooltip-primary.is-tooltip-left:not(.is-loading)::after { + border-color: transparent transparent transparent rgba(0, 209, 178, .9) +} + +.tooltip.is-tooltip-primary::before { + background: rgba(0, 209, 178, .9); + color: #fff +} + +.tooltip.is-tooltip-link:not(.is-loading)::after { + border-color: rgba(50, 115, 220, .9) transparent transparent transparent +} + +.tooltip.is-tooltip-link.is-tooltip-right:not(.is-loading)::after { + border-color: transparent rgba(50, 115, 220, .9) transparent transparent +} + +.tooltip.is-tooltip-link.is-tooltip-bottom:not(.is-loading)::after { + border-color: transparent transparent rgba(50, 115, 220, .9) transparent +} + +.tooltip.is-tooltip-link.is-tooltip-left:not(.is-loading)::after { + border-color: transparent transparent transparent rgba(50, 115, 220, .9) +} + +.tooltip.is-tooltip-link::before { + background: rgba(50, 115, 220, .9); + color: #fff +} + +.tooltip.is-tooltip-info:not(.is-loading)::after { + border-color: rgba(32, 156, 238, .9) transparent transparent transparent +} + +.tooltip.is-tooltip-info.is-tooltip-right:not(.is-loading)::after { + border-color: transparent rgba(32, 156, 238, .9) transparent transparent +} + +.tooltip.is-tooltip-info.is-tooltip-bottom:not(.is-loading)::after { + border-color: transparent transparent rgba(32, 156, 238, .9) transparent +} + +.tooltip.is-tooltip-info.is-tooltip-left:not(.is-loading)::after { + border-color: transparent transparent transparent rgba(32, 156, 238, .9) +} + +.tooltip.is-tooltip-info::before { + background: rgba(32, 156, 238, .9); + color: #fff +} + +.tooltip.is-tooltip-success:not(.is-loading)::after { + border-color: rgba(35, 209, 96, .9) transparent transparent transparent +} + +.tooltip.is-tooltip-success.is-tooltip-right:not(.is-loading)::after { + border-color: transparent rgba(35, 209, 96, .9) transparent transparent +} + +.tooltip.is-tooltip-success.is-tooltip-bottom:not(.is-loading)::after { + border-color: transparent transparent rgba(35, 209, 96, .9) transparent +} + +.tooltip.is-tooltip-success.is-tooltip-left:not(.is-loading)::after { + border-color: transparent transparent transparent rgba(35, 209, 96, .9) +} + +.tooltip.is-tooltip-success::before { + background: rgba(35, 209, 96, .9); + color: #fff +} + +.tooltip.is-tooltip-warning:not(.is-loading)::after { + border-color: rgba(255, 221, 87, .9) transparent transparent transparent +} + +.tooltip.is-tooltip-warning.is-tooltip-right:not(.is-loading)::after { + border-color: transparent rgba(255, 221, 87, .9) transparent transparent +} + +.tooltip.is-tooltip-warning.is-tooltip-bottom:not(.is-loading)::after { + border-color: transparent transparent rgba(255, 221, 87, .9) transparent +} + +.tooltip.is-tooltip-warning.is-tooltip-left:not(.is-loading)::after { + border-color: transparent transparent transparent rgba(255, 221, 87, .9) +} + +.tooltip.is-tooltip-warning::before { + background: rgba(255, 221, 87, .9); + color: rgba(0, 0, 0, .7) +} + +.tooltip.is-tooltip-danger:not(.is-loading)::after { + border-color: rgba(255, 56, 96, .9) transparent transparent transparent +} + +.tooltip.is-tooltip-danger.is-tooltip-right:not(.is-loading)::after { + border-color: transparent rgba(255, 56, 96, .9) transparent transparent +} + +.tooltip.is-tooltip-danger.is-tooltip-bottom:not(.is-loading)::after { + border-color: transparent transparent rgba(255, 56, 96, .9) transparent +} + +.tooltip.is-tooltip-danger.is-tooltip-left:not(.is-loading)::after { + border-color: transparent transparent transparent rgba(255, 56, 96, .9) +} + +.tooltip.is-tooltip-danger::before { + background: rgba(255, 56, 96, .9); + color: #fff +} \ No newline at end of file diff --git a/user/themes/bulma-portfolio/scss/portfolio.scss b/user/themes/bulma-portfolio/scss/portfolio.scss new file mode 100644 index 00000000..67d212b7 --- /dev/null +++ b/user/themes/bulma-portfolio/scss/portfolio.scss @@ -0,0 +1,23 @@ +.help { + visibility: hidden; + opacity: 0; + transition: all .2s ease-in; +} + +//to be added to the validation of the form - next itteration +.help-shown { + visibility: visible; + opacity: 1; + transition: all .2s ease-out; +} + +@media screen and (max-width: 576px) { + .column.is-12-phone { + width: 100%; + } +} + +@import 'body'; +@import 'features'; +@import 'modal'; +@import 'tooltip'; \ No newline at end of file diff --git a/user/themes/bulma-portfolio/templates/blog.html.twig b/user/themes/bulma-portfolio/templates/blog.html.twig new file mode 100644 index 00000000..195d474f --- /dev/null +++ b/user/themes/bulma-portfolio/templates/blog.html.twig @@ -0,0 +1,38 @@ +{% embed 'partials/base.html.twig' %} + +{% set collection = page.collection() %} + +{% block content %} + {% set blog_image = page.media.images|first.grayscale().contrast(20).brightness(-100).colorize(-35,81,122) %} + + {% if blog_image %} +
                                                            + {% else %} +
                                                            + {% endif %} + {{ page.content }} +
                                                            + + {% if config.plugins.breadcrumbs.enabled %} + {% include 'partials/breadcrumbs.html.twig' %} + {% endif %} + +
                                                            +
                                                            + {% for child in collection %} + {% include 'partials/blog_item.html.twig' with {'blog':page, 'page':child, 'truncate':true} %} + {% endfor %} + + {% if config.plugins.pagination.enabled and collection.params.pagination %} + {% include 'partials/pagination.html.twig' with {'base_url':page.url, 'pagination':collection.params.pagination} %} + {% endif %} +
                                                            + +
                                                            +{% endblock %} + +{% endembed %} + + diff --git a/user/themes/bulma-portfolio/templates/default.html.twig b/user/themes/bulma-portfolio/templates/default.html.twig new file mode 100644 index 00000000..ed9e64f5 --- /dev/null +++ b/user/themes/bulma-portfolio/templates/default.html.twig @@ -0,0 +1,12 @@ +{% extends 'partials/base.html.twig' %} + +{% block content %} +
                                                            +
                                                            + + {{ page.content }} + {% include 'forms/data.html.twig' %} +
                                                            + +
                                                            +{% endblock %} diff --git a/user/themes/bulma-portfolio/templates/error.html.twig b/user/themes/bulma-portfolio/templates/error.html.twig new file mode 100644 index 00000000..f23aa786 --- /dev/null +++ b/user/themes/bulma-portfolio/templates/error.html.twig @@ -0,0 +1,8 @@ +{% extends 'partials/base.html.twig' %} + +{% block content %} +
                                                            +

                                                            Error!

                                                            + {{ page.content }} +
                                                            +{% endblock %} diff --git a/user/themes/bulma-portfolio/templates/forms/data.html.twig b/user/themes/bulma-portfolio/templates/forms/data.html.twig new file mode 100644 index 00000000..9cb16c23 --- /dev/null +++ b/user/themes/bulma-portfolio/templates/forms/data.html.twig @@ -0,0 +1 @@ +{% extends "forms/default/data.html.twig" %} diff --git a/user/themes/bulma-portfolio/templates/forms/data.txt.twig b/user/themes/bulma-portfolio/templates/forms/data.txt.twig new file mode 100644 index 00000000..c647832f --- /dev/null +++ b/user/themes/bulma-portfolio/templates/forms/data.txt.twig @@ -0,0 +1 @@ +{% extends "forms/default/data.txt.twig" %} diff --git a/user/themes/bulma-portfolio/templates/forms/fields/checkbox/checkbox.html.twig b/user/themes/bulma-portfolio/templates/forms/fields/checkbox/checkbox.html.twig new file mode 100644 index 00000000..5a6f3d19 --- /dev/null +++ b/user/themes/bulma-portfolio/templates/forms/fields/checkbox/checkbox.html.twig @@ -0,0 +1,16 @@ +{% set value = (value is null ? field.default : value) %} + +
                                                            +
                                                            + +
                                                            +
                                                            \ No newline at end of file diff --git a/user/themes/bulma-portfolio/templates/forms/fields/checkboxes/checkboxes.html.twig b/user/themes/bulma-portfolio/templates/forms/fields/checkboxes/checkboxes.html.twig new file mode 100644 index 00000000..ca9a50c9 --- /dev/null +++ b/user/themes/bulma-portfolio/templates/forms/fields/checkboxes/checkboxes.html.twig @@ -0,0 +1,27 @@ +{% set value = (value is null ? field.default : value) %} + +
                                                            + +
                                                            + {% for key, text in field.options %} + {% set checked = (field.use == 'keys' ? value[key] : key in value) %} + {% set name = field.name|fieldName ~ '[' ~ (field.use == 'keys' ? key : '') ~ ']' %} + {% set key = (field.use == 'keys' ? '1' : key) %} + + + + {% if field.help %} +

                                                            {{ field.help|e }}

                                                            + {% endif %} + {% endfor %} +
                                                            + +
                                                            \ No newline at end of file diff --git a/user/themes/bulma-portfolio/templates/forms/fields/email/email.html.twig b/user/themes/bulma-portfolio/templates/forms/fields/email/email.html.twig new file mode 100644 index 00000000..05251ddf --- /dev/null +++ b/user/themes/bulma-portfolio/templates/forms/fields/email/email.html.twig @@ -0,0 +1,32 @@ +{% set value = (value is null ? field.default : value) %} + +
                                                            + + +
                                                            + +
                                                            + {% if field.help %} +

                                                            + {{ field.help|default(field.name|capitalize)|t }} +

                                                            + {% endif %} + +
                                                            \ No newline at end of file diff --git a/user/themes/bulma-portfolio/templates/forms/fields/hidden/hidden.html.twig b/user/themes/bulma-portfolio/templates/forms/fields/hidden/hidden.html.twig new file mode 100644 index 00000000..1e70bff1 --- /dev/null +++ b/user/themes/bulma-portfolio/templates/forms/fields/hidden/hidden.html.twig @@ -0,0 +1,5 @@ +{% set value = (value is null ? field.default : value) %} + +
                                                            + +
                                                            \ No newline at end of file diff --git a/user/themes/bulma-portfolio/templates/forms/fields/honneypot/honeypot.html.twig b/user/themes/bulma-portfolio/templates/forms/fields/honneypot/honeypot.html.twig new file mode 100644 index 00000000..1e70bff1 --- /dev/null +++ b/user/themes/bulma-portfolio/templates/forms/fields/honneypot/honeypot.html.twig @@ -0,0 +1,5 @@ +{% set value = (value is null ? field.default : value) %} + +
                                                            + +
                                                            \ No newline at end of file diff --git a/user/themes/bulma-portfolio/templates/forms/fields/password/password.html.twig b/user/themes/bulma-portfolio/templates/forms/fields/password/password.html.twig new file mode 100644 index 00000000..888242ec --- /dev/null +++ b/user/themes/bulma-portfolio/templates/forms/fields/password/password.html.twig @@ -0,0 +1,27 @@ +{% set value = (value is null ? field.default : value) %} + +
                                                            +
                                                            + + + +
                                                            + {% if field.help %} +

                                                            {{ field.help|default(field.name|capitalize)|t }}

                                                            + {% endif %} +
                                                            \ No newline at end of file diff --git a/user/themes/bulma-portfolio/templates/forms/fields/radio/radio.html.twig b/user/themes/bulma-portfolio/templates/forms/fields/radio/radio.html.twig new file mode 100644 index 00000000..bcd653e5 --- /dev/null +++ b/user/themes/bulma-portfolio/templates/forms/fields/radio/radio.html.twig @@ -0,0 +1,26 @@ +{% set value = (value is null ? field.default : value) %} + +
                                                            +
                                                            + {% for key, text in field.options %} + {% set id = "radio_" ~ field.name ~ key %} + + {% if field.help %} + {{ field.help|default(field.name|capitalize)|t }} + {% endif %} + {% endfor %} +
                                                            +
                                                            \ No newline at end of file diff --git a/user/themes/bulma-portfolio/templates/forms/fields/select/select.html.twig b/user/themes/bulma-portfolio/templates/forms/fields/select/select.html.twig new file mode 100644 index 00000000..b2553997 --- /dev/null +++ b/user/themes/bulma-portfolio/templates/forms/fields/select/select.html.twig @@ -0,0 +1,27 @@ +{% set value = (value is null ? field.default : value) %} + +
                                                            + +
                                                            diff --git a/user/themes/bulma-portfolio/templates/forms/fields/text/text.html.twig b/user/themes/bulma-portfolio/templates/forms/fields/text/text.html.twig new file mode 100644 index 00000000..98ee5b9d --- /dev/null +++ b/user/themes/bulma-portfolio/templates/forms/fields/text/text.html.twig @@ -0,0 +1,28 @@ +{% set value = (value is null ? field.default : value) %} + +
                                                            + +
                                                            + + +
                                                            + {% if field.help %} +

                                                            {{ field.help|default(field.name|capitalize)|t }}

                                                            + {% endif %} +
                                                            \ No newline at end of file diff --git a/user/themes/bulma-portfolio/templates/forms/fields/textarea/textarea.html.twig b/user/themes/bulma-portfolio/templates/forms/fields/textarea/textarea.html.twig new file mode 100644 index 00000000..13050516 --- /dev/null +++ b/user/themes/bulma-portfolio/templates/forms/fields/textarea/textarea.html.twig @@ -0,0 +1,16 @@ +{% set value = (value is null ? field.default : value) %} + +
                                                            + +
                                                            + +
                                                            + {% if field.help %} +

                                                            {{ field.help|default(field.name|capitalize)|t }}

                                                            + {% endif %} +
                                                            \ No newline at end of file diff --git a/user/themes/bulma-portfolio/templates/forms/form.html.twig b/user/themes/bulma-portfolio/templates/forms/form.html.twig new file mode 100644 index 00000000..8f1d4670 --- /dev/null +++ b/user/themes/bulma-portfolio/templates/forms/form.html.twig @@ -0,0 +1 @@ +{% extends "forms/default/form.html.twig" %} diff --git a/user/themes/bulma-portfolio/templates/item.html.twig b/user/themes/bulma-portfolio/templates/item.html.twig new file mode 100644 index 00000000..6139cd45 --- /dev/null +++ b/user/themes/bulma-portfolio/templates/item.html.twig @@ -0,0 +1,7 @@ +{% extends 'partials/base.html.twig' %} + +{% block content %} + {{ page.content }} + + {% endblock %} + \ No newline at end of file diff --git a/user/themes/bulma-portfolio/templates/modular.html.twig b/user/themes/bulma-portfolio/templates/modular.html.twig new file mode 100644 index 00000000..fc324e57 --- /dev/null +++ b/user/themes/bulma-portfolio/templates/modular.html.twig @@ -0,0 +1,12 @@ +{% extends 'partials/base.html.twig' %} + +{% set show_onpage_menu = header.onpage_menu == true or header.onpage_menu is null %} +{% macro pageLinkName(text) %}{{ text|lower|replace({' ':'_'}) }}{% endmacro %} + +{% block content %} + + {% for module in page.collection() %} + {{ module.content }} + {% endfor %} + +{% endblock %} diff --git a/user/themes/bulma-portfolio/templates/modular/clients.html.twig b/user/themes/bulma-portfolio/templates/modular/clients.html.twig new file mode 100644 index 00000000..c9b541c9 --- /dev/null +++ b/user/themes/bulma-portfolio/templates/modular/clients.html.twig @@ -0,0 +1,38 @@ + +
                                                            + +
                                                            + {{page.content}} +
                                                            + + + +
                                                            + diff --git a/user/themes/bulma-portfolio/templates/modular/downloads.html.twig b/user/themes/bulma-portfolio/templates/modular/downloads.html.twig new file mode 100644 index 00000000..b1d787f7 --- /dev/null +++ b/user/themes/bulma-portfolio/templates/modular/downloads.html.twig @@ -0,0 +1,9 @@ +
                                                            +
                                                            + +
                                                            + {{ page.content }} + +
                                                            +
                                                            +
                                                            \ No newline at end of file diff --git a/user/themes/bulma-portfolio/templates/modular/features.html.twig b/user/themes/bulma-portfolio/templates/modular/features.html.twig new file mode 100644 index 00000000..0347d570 --- /dev/null +++ b/user/themes/bulma-portfolio/templates/modular/features.html.twig @@ -0,0 +1,23 @@ + + +
                                                            +
                                                            + {{ page.content }} +
                                                            +
                                                            +
                                                            + {% for item in page.header.features %} +
                                                            +
                                                            + +
                                                            +
                                                            +

                                                            {{ item.title }}

                                                            +

                                                            {{ item.text }}

                                                            + {{ item.link_text }} +
                                                            +
                                                            + {% endfor %} +
                                                            +
                                                            +
                                                            \ No newline at end of file diff --git a/user/themes/bulma-portfolio/templates/modular/form.html.twig b/user/themes/bulma-portfolio/templates/modular/form.html.twig new file mode 100644 index 00000000..38affdb3 --- /dev/null +++ b/user/themes/bulma-portfolio/templates/modular/form.html.twig @@ -0,0 +1,14 @@ + + +
                                                            +
                                                            + +
                                                            + {{ page.content }} +
                                                            +
                                                            + {% include "forms/form.html.twig" %} +
                                                            +
                                                            + +
                                                            diff --git a/user/themes/bulma-portfolio/templates/modular/landing.html.twig b/user/themes/bulma-portfolio/templates/modular/landing.html.twig new file mode 100644 index 00000000..557d046a --- /dev/null +++ b/user/themes/bulma-portfolio/templates/modular/landing.html.twig @@ -0,0 +1,32 @@ + + +
                                                            +
                                                            +
                                                            +
                                                            +
                                                            +

                                                            {{ page.title }}

                                                            +
                                                            + {{ page.content }} + Get Started +
                                                            +
                                                            +
                                                            +
                                                            + 	{{ page.header.title }} image +
                                                            +
                                                            + +
                                                            +
                                                            +
                                                            +
                                                            +
                                                            +
                                                            + + Contact Form + +
                                                            +
                                                            +
                                                            +
                                                            diff --git a/user/themes/bulma-portfolio/templates/modular/portfolio.html.twig b/user/themes/bulma-portfolio/templates/modular/portfolio.html.twig new file mode 100644 index 00000000..c0808f2d --- /dev/null +++ b/user/themes/bulma-portfolio/templates/modular/portfolio.html.twig @@ -0,0 +1,80 @@ + +
                                                            +
                                                            +

                                                            {{page.title}}

                                                            +
                                                            + {{page.content}} +
                                                            +
                                                            + + + +
                                                            + +{% for item in page.header.portfolio %} + +{% endfor %} \ No newline at end of file diff --git a/user/themes/bulma-portfolio/templates/modular/screenshots.html.twig b/user/themes/bulma-portfolio/templates/modular/screenshots.html.twig new file mode 100644 index 00000000..948da69e --- /dev/null +++ b/user/themes/bulma-portfolio/templates/modular/screenshots.html.twig @@ -0,0 +1,33 @@ + +
                                                            +
                                                            +
                                                            + {{ page.content }} +
                                                            +
                                                            + +
                                                            +
                                                            +
                                                            + {% for row in page.header.screenshots|batch(4) %} +
                                                            + {% for item in row %} +
                                                            +
                                                            + {{ page.media[item.image].lightbox(1024,768).cropResize(300,300).html('{{item.description}}')}} +
                                                            + +
                                                            +
                                                            +
                                                            + {% endfor %} +
                                                            + + {% endfor %} +
                                                            +
                                                            \ No newline at end of file diff --git a/user/themes/bulma-portfolio/templates/modular/showcase.html.twig b/user/themes/bulma-portfolio/templates/modular/showcase.html.twig new file mode 100644 index 00000000..ebe76b56 --- /dev/null +++ b/user/themes/bulma-portfolio/templates/modular/showcase.html.twig @@ -0,0 +1,34 @@ + + +
                                                            +
                                                            + {{ page.content }} + +
                                                            + +
                                                            diff --git a/user/themes/bulma-portfolio/templates/modular/spotlight.html.twig b/user/themes/bulma-portfolio/templates/modular/spotlight.html.twig new file mode 100644 index 00000000..b74ea656 --- /dev/null +++ b/user/themes/bulma-portfolio/templates/modular/spotlight.html.twig @@ -0,0 +1,13 @@ + +
                                                            +
                                                            +

                                                            {{ page.title }}

                                                            + {{ page.content }} + +
                                                            +
                                                            + {{ page.media[header.spotlight_img].cropZoom(1440,900) }} +
                                                            +
                                                            diff --git a/user/themes/bulma-portfolio/templates/modular/video.html.twig b/user/themes/bulma-portfolio/templates/modular/video.html.twig new file mode 100644 index 00000000..9e57665e --- /dev/null +++ b/user/themes/bulma-portfolio/templates/modular/video.html.twig @@ -0,0 +1,24 @@ + +
                                                            +
                                                            +
                                                            +
                                                            + {{ page.content }} +
                                                            +
                                                            + {% if page.header.video_url %} + + {% endif %} +
                                                            + +
                                                            +
                                                            +
                                                            \ No newline at end of file diff --git a/user/themes/bulma-portfolio/templates/partials/base.html.twig b/user/themes/bulma-portfolio/templates/partials/base.html.twig new file mode 100644 index 00000000..f4a80961 --- /dev/null +++ b/user/themes/bulma-portfolio/templates/partials/base.html.twig @@ -0,0 +1,58 @@ +{% set theme_config = attribute(config.themes, config.system.pages.theme) %} + + + + {% block head %} + + + {% if header.title %}{{ header.title|e('html') }} + | + {% endif %}{{ site.title|e('html') }} + + + + {% include 'partials/metadata.html.twig' %} + {% set image_parts = pathinfo(grav.theme.config.theme.favicon) %} + + + + + + {% block stylesheets %} + {% do assets.addCss('theme://css/bulma.min.css', 100) %} + {% do assets.addCss('theme://css/bulma-carousel.min.css', 100) %} + {% do assets.addCss('theme://css/svg.css', 98) %} + {% do assets.addCss('theme://css-compiled/portfolio.css', 98) %} + {% endblock %} + {{ assets.css() }} + + {% endblock head%} + + +
                                                            + {% include 'partials/header.html.twig' %} + {% block content %}{% endblock %} +
                                                            + + {% block footer %} + {% include 'partials/footer.html.twig' %} + {% endblock %} + + {% block javascripts %} + {% do assets.addJs('theme://js/bulma-carousel.js', 100) %} + {% do assets.addJs('https://use.fontawesome.com/releases/v5.0.0/js/all.js', 120) %} + {% do assets.addJs('https://use.fontawesome.com/releases/v5.0.0/js/v4-shims.js', 120) %} + {% do assets.addJs('theme://js/smooth-scroll.js', 120) %} + {% do assets.addJs('theme://js/smooth-scroll-polifylls.js', 120) %} + {% do assets.addJs('theme://js/portfolio.js', 98) %} + {% endblock %} + + {{ assets.js() }} + + {% block bottom %} + {{ assets.js('bottom') }} + + {% endblock %} + + + diff --git a/user/themes/bulma-portfolio/templates/partials/blog_item.html.twig b/user/themes/bulma-portfolio/templates/partials/blog_item.html.twig new file mode 100644 index 00000000..3e653099 --- /dev/null +++ b/user/themes/bulma-portfolio/templates/partials/blog_item.html.twig @@ -0,0 +1,90 @@ + + +
                                                            + + {% set header_image = page.header.header_image|defined(true) %} + {% set header_image_width = page.header.header_image_width|defined(900) %} + {% set header_image_height = page.header.header_image_height|defined(300) %} + {% set header_image_file = page.header.header_image_file %} + +
                                                            + + + + {% if page.header.link %} +

                                                            + {% if page.header.continue_link is not sameas(false) %} + + {% endif %} + {{ page.title }} +

                                                            + {% else %} +

                                                            {{ page.title }}

                                                            + {% endif %} + + {% if page.taxonomy.tag %} + + {% for tag in page.taxonomy.tag %} + {{ tag }} + {% endfor %} + + {% endif %} + {% if header_image %} + {% if header_image_file %} + {% set header_image_media = page.media.images[header_image_file] %} + {% else %} + {% set header_image_media = page.media.images|first %} + {% endif %} + {{ header_image_media.cropZoom(header_image_width, header_image_height).html }} + {% endif %} + +
                                                            + +
                                                            + + {% if page.header.continue_link is sameas(false) %} +
                                                            + {{ page.content }} +
                                                            + {% if not truncate %} + {% set show_prev_next = true %} + {% endif %} + {% elseif truncate and page.summary != page.content %} +
                                                            + {{ page.summary }} +

                                                            {{ 'BLOG.ITEM.CONTINUE_READING'|t }}

                                                            +
                                                            + {% elseif truncate %} +
                                                            + {{ page.content }} +

                                                            {{ 'BLOG.ITEM.CONTINUE_READING'|t }}

                                                            +
                                                            + {% else %} +
                                                            + {{ page.content }} +
                                                            + + {% if config.plugins.comments.enabled %} + {% include 'partials/comments.html.twig' %} + {% endif %} + + {% set show_prev_next = true %} + {% endif %} + + {% if show_prev_next %} + +

                                                            + {% if not page.isFirst %} + {{ 'BLOG.ITEM.NEXT_POST'|t }} + {% endif %} + + {% if not page.isLast %} + {{ 'BLOG.ITEM.PREV_POST'|t }} + {% endif %} +

                                                            + {% endif %} + +
                                                            +
                                                            diff --git a/user/themes/bulma-portfolio/templates/partials/footer.html.twig b/user/themes/bulma-portfolio/templates/partials/footer.html.twig new file mode 100644 index 00000000..41f2e4be --- /dev/null +++ b/user/themes/bulma-portfolio/templates/partials/footer.html.twig @@ -0,0 +1,21 @@ +
                                                            +
                                                            +
                                                              + {% for icons in theme_config.footer.icon %} +
                                                            • + + + +
                                                            • + {% endfor %} +
                                                            +

                                                            {{ theme_config.footer.copyright }}

                                                            +
                                                            + +
                                                            +

                                                            + This site was + + by Jonh's Design with the help of the awesome Bulma.io and Bulma Components .

                                                            +
                                                            +
                                                            \ No newline at end of file diff --git a/user/themes/bulma-portfolio/templates/partials/header.html.twig b/user/themes/bulma-portfolio/templates/partials/header.html.twig new file mode 100644 index 00000000..4540e4f4 --- /dev/null +++ b/user/themes/bulma-portfolio/templates/partials/header.html.twig @@ -0,0 +1,28 @@ + + +{% block header %} + +
                                                            + + +
                                                            + +{% endblock %} \ No newline at end of file diff --git a/user/themes/bulma-portfolio/templates/partials/hero.html.twig b/user/themes/bulma-portfolio/templates/partials/hero.html.twig new file mode 100644 index 00000000..e38c1bc2 --- /dev/null +++ b/user/themes/bulma-portfolio/templates/partials/hero.html.twig @@ -0,0 +1,32 @@ + + +
                                                            +
                                                            + {% include 'partials/header.html.twig' %} +
                                                            +
                                                            +
                                                            +
                                                            +
                                                            +

                                                            {{ page.title }}

                                                            +
                                                            + {{ page.content }} + Get Started +
                                                            +
                                                            +
                                                            +
                                                            + 	{{ page.header.title }} image +
                                                            +
                                                            +
                                                            +
                                                            +
                                                            +
                                                            +
                                                            +
                                                            + Contact +
                                                            +
                                                            +
                                                            +
                                                            diff --git a/user/themes/bulma-portfolio/templates/partials/metadata.html.twig b/user/themes/bulma-portfolio/templates/partials/metadata.html.twig new file mode 100644 index 00000000..2f08a0e5 --- /dev/null +++ b/user/themes/bulma-portfolio/templates/partials/metadata.html.twig @@ -0,0 +1,3 @@ +{% for meta in page.metadata %} + +{% endfor %} diff --git a/user/themes/bulma-portfolio/templates/partials/navigation.html.twig b/user/themes/bulma-portfolio/templates/partials/navigation.html.twig new file mode 100644 index 00000000..a244eb84 --- /dev/null +++ b/user/themes/bulma-portfolio/templates/partials/navigation.html.twig @@ -0,0 +1,25 @@ + + {% for page in pages.children.visible %} + {% set current_page = (page.active or page.activeChild) + ? 'is-active' + : '' %} + + + {% if page.header.icon %} + + {% endif %} + {{ page.menu }} + + + {% endfor %} + + {% for mitem in site.menu %} + + + {% if mitem.icon %} + + {% endif %} + {{ mitem.text }} + + + {% endfor %} diff --git a/user/themes/bulma-portfolio/templates/partials/projects.html.twig b/user/themes/bulma-portfolio/templates/partials/projects.html.twig new file mode 100644 index 00000000..dc14ee4b --- /dev/null +++ b/user/themes/bulma-portfolio/templates/partials/projects.html.twig @@ -0,0 +1,10 @@ +{% for module in page.collection() %} + {% if module.header.footermenu %} + {% set current_page = (module.active or module.activeChild) + ? 'active' + : '' %} + + {% endif %} +{% endfor %} \ No newline at end of file diff --git a/user/themes/bulma-portfolio/templates/partials/sidebar.html.twig b/user/themes/bulma-portfolio/templates/partials/sidebar.html.twig new file mode 100644 index 00000000..9a85b77d --- /dev/null +++ b/user/themes/bulma-portfolio/templates/partials/sidebar.html.twig @@ -0,0 +1,35 @@ +{% set feed_url = blog.url == '/' or blog.url == base_url_relative ? (base_url_relative~'/'~blog.slug) : blog.url %} +{% set new_base_url = blog.url == '/' ? '' : blog.url %} + +{% if config.plugins.simplesearch.enabled %} + +{% endif %} +{% if config.plugins.relatedpages.enabled and related_pages|length > 0 %} +

                                                            {{ 'SIDEBAR.RELATED_POSTS.HEADLINE'|t }}

                                                            + {% include 'partials/relatedpages.html.twig' %} +{% endif %} +{% if config.plugins.random.enabled %} + +{% endif %} + +{% if config.plugins.taxonomylist.enabled %} + +{% endif %} +{% if config.plugins.archives.enabled %} + +{% endif %} diff --git a/user/themes/bulma-portfolio/thumbnail.jpg b/user/themes/bulma-portfolio/thumbnail.jpg new file mode 100644 index 00000000..bbf5506c Binary files /dev/null and b/user/themes/bulma-portfolio/thumbnail.jpg differ diff --git a/user/themes/goku/CHANGELOG.md b/user/themes/goku/CHANGELOG.md new file mode 100644 index 00000000..b4c7c5ba --- /dev/null +++ b/user/themes/goku/CHANGELOG.md @@ -0,0 +1,5 @@ +# v0.1.0 +## 11/28/2019 + +1. [](#new) + * ChangeLog started... diff --git a/user/themes/goku/LICENSE b/user/themes/goku/LICENSE new file mode 100644 index 00000000..da30586d --- /dev/null +++ b/user/themes/goku/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2019 Keith Malcolm + +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. diff --git a/user/themes/goku/README.md b/user/themes/goku/README.md new file mode 100644 index 00000000..f4fe7e16 --- /dev/null +++ b/user/themes/goku/README.md @@ -0,0 +1,7 @@ +# Goku Theme + +The **Goku** Theme is for [Grav CMS](http://github.com/getgrav/grav). This README.md file should be modified to describe the features, installation, configuration, and general usage of this theme. + +## Description + +Grav with Bulma diff --git a/user/themes/goku/blueprints.yaml b/user/themes/goku/blueprints.yaml new file mode 100644 index 00000000..929c2f69 --- /dev/null +++ b/user/themes/goku/blueprints.yaml @@ -0,0 +1,27 @@ +name: Goku +version: 0.1.0 +description: Grav with Bulma +icon: rebel +author: + name: Keith Malcolm + email: keith@kthmlclm.uk +homepage: https://github.com/kthmlclm/grav-theme-goku +demo: http://demo.yoursite.com +keywords: grav, theme, etc +bugs: https://github.com/kthmlclm/grav-theme-goku/issues +readme: https://github.com/kthmlclm/grav-theme-goku/blob/develop/README.md +license: MIT + +form: + validation: loose + fields: + dropdown.enabled: + type: toggle + label: Dropdown in Menu + highlight: 1 + default: 1 + options: + 1: PLUGIN_ADMIN.ENABLED + 0: PLUGIN_ADMIN.DISABLED + validate: + type: bool diff --git a/user/themes/goku/css-compiled/goku.css b/user/themes/goku/css-compiled/goku.css new file mode 100644 index 00000000..d75b4bf1 --- /dev/null +++ b/user/themes/goku/css-compiled/goku.css @@ -0,0 +1,7102 @@ +/*! bulma.io v0.8.0 | MIT License | github.com/jgthms/bulma */ +@keyframes spinAround { + from { + transform: rotate(0deg); } + to { + transform: rotate(359deg); } } + +.delete, .modal-close, .is-unselectable, .button, .file, .breadcrumb, .pagination-previous, +.pagination-next, +.pagination-link, +.pagination-ellipsis, .tabs { + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; } + +.select:not(.is-multiple):not(.is-loading)::after, .navbar-link:not(.is-arrowless)::after { + border: 3px solid transparent; + border-radius: 2px; + border-right: 0; + border-top: 0; + content: " "; + display: block; + height: 0.625em; + margin-top: -0.4375em; + pointer-events: none; + position: absolute; + top: 50%; + transform: rotate(-45deg); + transform-origin: center; + width: 0.625em; } + +.box:not(:last-child), .content:not(:last-child), .notification:not(:last-child), .progress:not(:last-child), .table:not(:last-child), .table-container:not(:last-child), .title:not(:last-child), +.subtitle:not(:last-child), .block:not(:last-child), .highlight:not(:last-child), .breadcrumb:not(:last-child), .level:not(:last-child), .list:not(:last-child), .message:not(:last-child), .pagination:not(:last-child), .tabs:not(:last-child) { + margin-bottom: 1.5rem; } + +.delete, .modal-close { + -moz-appearance: none; + -webkit-appearance: none; + background-color: rgba(10, 10, 10, 0.2); + border: none; + border-radius: 290486px; + cursor: pointer; + pointer-events: auto; + display: inline-block; + flex-grow: 0; + flex-shrink: 0; + font-size: 0; + height: 20px; + max-height: 20px; + max-width: 20px; + min-height: 20px; + min-width: 20px; + outline: none; + position: relative; + vertical-align: top; + width: 20px; } + .delete::before, .modal-close::before, .delete::after, .modal-close::after { + background-color: white; + content: ""; + display: block; + left: 50%; + position: absolute; + top: 50%; + transform: translateX(-50%) translateY(-50%) rotate(45deg); + transform-origin: center center; } + .delete::before, .modal-close::before { + height: 2px; + width: 50%; } + .delete::after, .modal-close::after { + height: 50%; + width: 2px; } + .delete:hover, .modal-close:hover, .delete:focus, .modal-close:focus { + background-color: rgba(10, 10, 10, 0.3); } + .delete:active, .modal-close:active { + background-color: rgba(10, 10, 10, 0.4); } + .is-small.delete, .is-small.modal-close { + height: 16px; + max-height: 16px; + max-width: 16px; + min-height: 16px; + min-width: 16px; + width: 16px; } + .is-medium.delete, .is-medium.modal-close { + height: 24px; + max-height: 24px; + max-width: 24px; + min-height: 24px; + min-width: 24px; + width: 24px; } + .is-large.delete, .is-large.modal-close { + height: 32px; + max-height: 32px; + max-width: 32px; + min-height: 32px; + min-width: 32px; + width: 32px; } + +.button.is-loading::after, .loader, .select.is-loading::after, .control.is-loading::after { + animation: spinAround 500ms infinite linear; + border: 2px solid #dbdbdb; + border-radius: 290486px; + border-right-color: transparent; + border-top-color: transparent; + content: ""; + display: block; + height: 1em; + position: relative; + width: 1em; } + +.is-overlay, .image.is-square img, +.image.is-square .has-ratio, .image.is-1by1 img, +.image.is-1by1 .has-ratio, .image.is-5by4 img, +.image.is-5by4 .has-ratio, .image.is-4by3 img, +.image.is-4by3 .has-ratio, .image.is-3by2 img, +.image.is-3by2 .has-ratio, .image.is-5by3 img, +.image.is-5by3 .has-ratio, .image.is-16by9 img, +.image.is-16by9 .has-ratio, .image.is-2by1 img, +.image.is-2by1 .has-ratio, .image.is-3by1 img, +.image.is-3by1 .has-ratio, .image.is-4by5 img, +.image.is-4by5 .has-ratio, .image.is-3by4 img, +.image.is-3by4 .has-ratio, .image.is-2by3 img, +.image.is-2by3 .has-ratio, .image.is-3by5 img, +.image.is-3by5 .has-ratio, .image.is-9by16 img, +.image.is-9by16 .has-ratio, .image.is-1by2 img, +.image.is-1by2 .has-ratio, .image.is-1by3 img, +.image.is-1by3 .has-ratio, .modal, .modal-background, .hero-video { + bottom: 0; + left: 0; + position: absolute; + right: 0; + top: 0; } + +.button, .input, .textarea, .select select, .file-cta, +.file-name, .pagination-previous, +.pagination-next, +.pagination-link, +.pagination-ellipsis { + -moz-appearance: none; + -webkit-appearance: none; + align-items: center; + border: 1px solid transparent; + border-radius: 4px; + box-shadow: none; + display: inline-flex; + font-size: 1rem; + height: 2.5em; + justify-content: flex-start; + line-height: 1.5; + padding-bottom: calc(0.5em - 1px); + padding-left: calc(0.75em - 1px); + padding-right: calc(0.75em - 1px); + padding-top: calc(0.5em - 1px); + position: relative; + vertical-align: top; } + .button:focus, .input:focus, .textarea:focus, .select select:focus, .file-cta:focus, + .file-name:focus, .pagination-previous:focus, + .pagination-next:focus, + .pagination-link:focus, + .pagination-ellipsis:focus, .is-focused.button, .is-focused.input, .is-focused.textarea, .select select.is-focused, .is-focused.file-cta, + .is-focused.file-name, .is-focused.pagination-previous, + .is-focused.pagination-next, + .is-focused.pagination-link, + .is-focused.pagination-ellipsis, .button:active, .input:active, .textarea:active, .select select:active, .file-cta:active, + .file-name:active, .pagination-previous:active, + .pagination-next:active, + .pagination-link:active, + .pagination-ellipsis:active, .is-active.button, .is-active.input, .is-active.textarea, .select select.is-active, .is-active.file-cta, + .is-active.file-name, .is-active.pagination-previous, + .is-active.pagination-next, + .is-active.pagination-link, + .is-active.pagination-ellipsis { + outline: none; } + .button[disabled], .input[disabled], .textarea[disabled], .select select[disabled], .file-cta[disabled], + .file-name[disabled], .pagination-previous[disabled], + .pagination-next[disabled], + .pagination-link[disabled], + .pagination-ellipsis[disabled], + fieldset[disabled] .button, + fieldset[disabled] .input, + fieldset[disabled] .textarea, + fieldset[disabled] .select select, + .select fieldset[disabled] select, + fieldset[disabled] .file-cta, + fieldset[disabled] .file-name, + fieldset[disabled] .pagination-previous, + fieldset[disabled] .pagination-next, + fieldset[disabled] .pagination-link, + fieldset[disabled] .pagination-ellipsis { + cursor: not-allowed; } + +/*! minireset.css v0.0.6 | MIT License | github.com/jgthms/minireset.css */ +html, +body, +p, +ol, +ul, +li, +dl, +dt, +dd, +blockquote, +figure, +fieldset, +legend, +textarea, +pre, +iframe, +hr, +h1, +h2, +h3, +h4, +h5, +h6 { + margin: 0; + padding: 0; } + +h1, +h2, +h3, +h4, +h5, +h6 { + font-size: 100%; + font-weight: normal; } + +ul { + list-style: none; } + +button, +input, +select, +textarea { + margin: 0; } + +html { + box-sizing: border-box; } + +*, *::before, *::after { + box-sizing: inherit; } + +img, +video { + height: auto; + max-width: 100%; } + +iframe { + border: 0; } + +table { + border-collapse: collapse; + border-spacing: 0; } + +td, +th { + padding: 0; } + td:not([align]), + th:not([align]) { + text-align: left; } + +html { + background-color: white; + font-size: 16px; + -moz-osx-font-smoothing: grayscale; + -webkit-font-smoothing: antialiased; + min-width: 300px; + overflow-x: hidden; + overflow-y: scroll; + text-rendering: optimizeLegibility; + text-size-adjust: 100%; } + +article, +aside, +figure, +footer, +header, +hgroup, +section { + display: block; } + +body, +button, +input, +select, +textarea { + font-family: BlinkMacSystemFont, -apple-system, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", "Helvetica", "Arial", sans-serif; } + +code, +pre { + -moz-osx-font-smoothing: auto; + -webkit-font-smoothing: auto; + font-family: monospace; } + +body { + color: #4a4a4a; + font-size: 1em; + font-weight: 400; + line-height: 1.5; } + +a { + color: #3273dc; + cursor: pointer; + text-decoration: none; } + a strong { + color: currentColor; } + a:hover { + color: #363636; } + +code { + background-color: whitesmoke; + color: #f14668; + font-size: 0.875em; + font-weight: normal; + padding: 0.25em 0.5em 0.25em; } + +hr { + background-color: whitesmoke; + border: none; + display: block; + height: 2px; + margin: 1.5rem 0; } + +img { + height: auto; + max-width: 100%; } + +input[type="checkbox"], +input[type="radio"] { + vertical-align: baseline; } + +small { + font-size: 0.875em; } + +span { + font-style: inherit; + font-weight: inherit; } + +strong { + color: #363636; + font-weight: 700; } + +fieldset { + border: none; } + +pre { + -webkit-overflow-scrolling: touch; + background-color: whitesmoke; + color: #4a4a4a; + font-size: 0.875em; + overflow-x: auto; + padding: 1.25rem 1.5rem; + white-space: pre; + word-wrap: normal; } + pre code { + background-color: transparent; + color: currentColor; + font-size: 1em; + padding: 0; } + +table td, +table th { + vertical-align: top; } + table td:not([align]), + table th:not([align]) { + text-align: left; } + +table th { + color: #363636; } + +.is-clearfix::after { + clear: both; + content: " "; + display: table; } + +.is-pulled-left { + float: left !important; } + +.is-pulled-right { + float: right !important; } + +.is-clipped { + overflow: hidden !important; } + +.is-size-1 { + font-size: 3rem !important; } + +.is-size-2 { + font-size: 2.5rem !important; } + +.is-size-3 { + font-size: 2rem !important; } + +.is-size-4 { + font-size: 1.5rem !important; } + +.is-size-5 { + font-size: 1.25rem !important; } + +.is-size-6 { + font-size: 1rem !important; } + +.is-size-7 { + font-size: 0.75rem !important; } + +@media screen and (max-width: 768px) { + .is-size-1-mobile { + font-size: 3rem !important; } + .is-size-2-mobile { + font-size: 2.5rem !important; } + .is-size-3-mobile { + font-size: 2rem !important; } + .is-size-4-mobile { + font-size: 1.5rem !important; } + .is-size-5-mobile { + font-size: 1.25rem !important; } + .is-size-6-mobile { + font-size: 1rem !important; } + .is-size-7-mobile { + font-size: 0.75rem !important; } } + +@media screen and (min-width: 769px), print { + .is-size-1-tablet { + font-size: 3rem !important; } + .is-size-2-tablet { + font-size: 2.5rem !important; } + .is-size-3-tablet { + font-size: 2rem !important; } + .is-size-4-tablet { + font-size: 1.5rem !important; } + .is-size-5-tablet { + font-size: 1.25rem !important; } + .is-size-6-tablet { + font-size: 1rem !important; } + .is-size-7-tablet { + font-size: 0.75rem !important; } } + +@media screen and (max-width: 1023px) { + .is-size-1-touch { + font-size: 3rem !important; } + .is-size-2-touch { + font-size: 2.5rem !important; } + .is-size-3-touch { + font-size: 2rem !important; } + .is-size-4-touch { + font-size: 1.5rem !important; } + .is-size-5-touch { + font-size: 1.25rem !important; } + .is-size-6-touch { + font-size: 1rem !important; } + .is-size-7-touch { + font-size: 0.75rem !important; } } + +@media screen and (min-width: 1024px) { + .is-size-1-desktop { + font-size: 3rem !important; } + .is-size-2-desktop { + font-size: 2.5rem !important; } + .is-size-3-desktop { + font-size: 2rem !important; } + .is-size-4-desktop { + font-size: 1.5rem !important; } + .is-size-5-desktop { + font-size: 1.25rem !important; } + .is-size-6-desktop { + font-size: 1rem !important; } + .is-size-7-desktop { + font-size: 0.75rem !important; } } + +@media screen and (min-width: 1216px) { + .is-size-1-widescreen { + font-size: 3rem !important; } + .is-size-2-widescreen { + font-size: 2.5rem !important; } + .is-size-3-widescreen { + font-size: 2rem !important; } + .is-size-4-widescreen { + font-size: 1.5rem !important; } + .is-size-5-widescreen { + font-size: 1.25rem !important; } + .is-size-6-widescreen { + font-size: 1rem !important; } + .is-size-7-widescreen { + font-size: 0.75rem !important; } } + +@media screen and (min-width: 1408px) { + .is-size-1-fullhd { + font-size: 3rem !important; } + .is-size-2-fullhd { + font-size: 2.5rem !important; } + .is-size-3-fullhd { + font-size: 2rem !important; } + .is-size-4-fullhd { + font-size: 1.5rem !important; } + .is-size-5-fullhd { + font-size: 1.25rem !important; } + .is-size-6-fullhd { + font-size: 1rem !important; } + .is-size-7-fullhd { + font-size: 0.75rem !important; } } + +.has-text-centered { + text-align: center !important; } + +.has-text-justified { + text-align: justify !important; } + +.has-text-left { + text-align: left !important; } + +.has-text-right { + text-align: right !important; } + +@media screen and (max-width: 768px) { + .has-text-centered-mobile { + text-align: center !important; } } + +@media screen and (min-width: 769px), print { + .has-text-centered-tablet { + text-align: center !important; } } + +@media screen and (min-width: 769px) and (max-width: 1023px) { + .has-text-centered-tablet-only { + text-align: center !important; } } + +@media screen and (max-width: 1023px) { + .has-text-centered-touch { + text-align: center !important; } } + +@media screen and (min-width: 1024px) { + .has-text-centered-desktop { + text-align: center !important; } } + +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .has-text-centered-desktop-only { + text-align: center !important; } } + +@media screen and (min-width: 1216px) { + .has-text-centered-widescreen { + text-align: center !important; } } + +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .has-text-centered-widescreen-only { + text-align: center !important; } } + +@media screen and (min-width: 1408px) { + .has-text-centered-fullhd { + text-align: center !important; } } + +@media screen and (max-width: 768px) { + .has-text-justified-mobile { + text-align: justify !important; } } + +@media screen and (min-width: 769px), print { + .has-text-justified-tablet { + text-align: justify !important; } } + +@media screen and (min-width: 769px) and (max-width: 1023px) { + .has-text-justified-tablet-only { + text-align: justify !important; } } + +@media screen and (max-width: 1023px) { + .has-text-justified-touch { + text-align: justify !important; } } + +@media screen and (min-width: 1024px) { + .has-text-justified-desktop { + text-align: justify !important; } } + +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .has-text-justified-desktop-only { + text-align: justify !important; } } + +@media screen and (min-width: 1216px) { + .has-text-justified-widescreen { + text-align: justify !important; } } + +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .has-text-justified-widescreen-only { + text-align: justify !important; } } + +@media screen and (min-width: 1408px) { + .has-text-justified-fullhd { + text-align: justify !important; } } + +@media screen and (max-width: 768px) { + .has-text-left-mobile { + text-align: left !important; } } + +@media screen and (min-width: 769px), print { + .has-text-left-tablet { + text-align: left !important; } } + +@media screen and (min-width: 769px) and (max-width: 1023px) { + .has-text-left-tablet-only { + text-align: left !important; } } + +@media screen and (max-width: 1023px) { + .has-text-left-touch { + text-align: left !important; } } + +@media screen and (min-width: 1024px) { + .has-text-left-desktop { + text-align: left !important; } } + +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .has-text-left-desktop-only { + text-align: left !important; } } + +@media screen and (min-width: 1216px) { + .has-text-left-widescreen { + text-align: left !important; } } + +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .has-text-left-widescreen-only { + text-align: left !important; } } + +@media screen and (min-width: 1408px) { + .has-text-left-fullhd { + text-align: left !important; } } + +@media screen and (max-width: 768px) { + .has-text-right-mobile { + text-align: right !important; } } + +@media screen and (min-width: 769px), print { + .has-text-right-tablet { + text-align: right !important; } } + +@media screen and (min-width: 769px) and (max-width: 1023px) { + .has-text-right-tablet-only { + text-align: right !important; } } + +@media screen and (max-width: 1023px) { + .has-text-right-touch { + text-align: right !important; } } + +@media screen and (min-width: 1024px) { + .has-text-right-desktop { + text-align: right !important; } } + +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .has-text-right-desktop-only { + text-align: right !important; } } + +@media screen and (min-width: 1216px) { + .has-text-right-widescreen { + text-align: right !important; } } + +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .has-text-right-widescreen-only { + text-align: right !important; } } + +@media screen and (min-width: 1408px) { + .has-text-right-fullhd { + text-align: right !important; } } + +.is-capitalized { + text-transform: capitalize !important; } + +.is-lowercase { + text-transform: lowercase !important; } + +.is-uppercase { + text-transform: uppercase !important; } + +.is-italic { + font-style: italic !important; } + +.has-text-white { + color: white !important; } + +a.has-text-white:hover, a.has-text-white:focus { + color: #e6e6e6 !important; } + +.has-background-white { + background-color: white !important; } + +.has-text-black { + color: #0a0a0a !important; } + +a.has-text-black:hover, a.has-text-black:focus { + color: black !important; } + +.has-background-black { + background-color: #0a0a0a !important; } + +.has-text-light { + color: whitesmoke !important; } + +a.has-text-light:hover, a.has-text-light:focus { + color: #dbdbdb !important; } + +.has-background-light { + background-color: whitesmoke !important; } + +.has-text-dark { + color: #363636 !important; } + +a.has-text-dark:hover, a.has-text-dark:focus { + color: #1c1c1c !important; } + +.has-background-dark { + background-color: #363636 !important; } + +.has-text-primary { + color: #00d1b2 !important; } + +a.has-text-primary:hover, a.has-text-primary:focus { + color: #009e86 !important; } + +.has-background-primary { + background-color: #00d1b2 !important; } + +.has-text-link { + color: #3273dc !important; } + +a.has-text-link:hover, a.has-text-link:focus { + color: #205bbc !important; } + +.has-background-link { + background-color: #3273dc !important; } + +.has-text-info { + color: #3298dc !important; } + +a.has-text-info:hover, a.has-text-info:focus { + color: #207dbc !important; } + +.has-background-info { + background-color: #3298dc !important; } + +.has-text-success { + color: #48c774 !important; } + +a.has-text-success:hover, a.has-text-success:focus { + color: #34a85c !important; } + +.has-background-success { + background-color: #48c774 !important; } + +.has-text-warning { + color: #ffdd57 !important; } + +a.has-text-warning:hover, a.has-text-warning:focus { + color: #ffd324 !important; } + +.has-background-warning { + background-color: #ffdd57 !important; } + +.has-text-danger { + color: #f14668 !important; } + +a.has-text-danger:hover, a.has-text-danger:focus { + color: #ee1742 !important; } + +.has-background-danger { + background-color: #f14668 !important; } + +.has-text-black-bis { + color: #121212 !important; } + +.has-background-black-bis { + background-color: #121212 !important; } + +.has-text-black-ter { + color: #242424 !important; } + +.has-background-black-ter { + background-color: #242424 !important; } + +.has-text-grey-darker { + color: #363636 !important; } + +.has-background-grey-darker { + background-color: #363636 !important; } + +.has-text-grey-dark { + color: #4a4a4a !important; } + +.has-background-grey-dark { + background-color: #4a4a4a !important; } + +.has-text-grey { + color: #7a7a7a !important; } + +.has-background-grey { + background-color: #7a7a7a !important; } + +.has-text-grey-light { + color: #b5b5b5 !important; } + +.has-background-grey-light { + background-color: #b5b5b5 !important; } + +.has-text-grey-lighter { + color: #dbdbdb !important; } + +.has-background-grey-lighter { + background-color: #dbdbdb !important; } + +.has-text-white-ter { + color: whitesmoke !important; } + +.has-background-white-ter { + background-color: whitesmoke !important; } + +.has-text-white-bis { + color: #fafafa !important; } + +.has-background-white-bis { + background-color: #fafafa !important; } + +.has-text-weight-light { + font-weight: 300 !important; } + +.has-text-weight-normal { + font-weight: 400 !important; } + +.has-text-weight-medium { + font-weight: 500 !important; } + +.has-text-weight-semibold { + font-weight: 600 !important; } + +.has-text-weight-bold { + font-weight: 700 !important; } + +.is-family-primary { + font-family: BlinkMacSystemFont, -apple-system, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", "Helvetica", "Arial", sans-serif !important; } + +.is-family-secondary { + font-family: BlinkMacSystemFont, -apple-system, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", "Helvetica", "Arial", sans-serif !important; } + +.is-family-sans-serif { + font-family: BlinkMacSystemFont, -apple-system, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", "Helvetica", "Arial", sans-serif !important; } + +.is-family-monospace { + font-family: monospace !important; } + +.is-family-code { + font-family: monospace !important; } + +.is-block { + display: block !important; } + +@media screen and (max-width: 768px) { + .is-block-mobile { + display: block !important; } } + +@media screen and (min-width: 769px), print { + .is-block-tablet { + display: block !important; } } + +@media screen and (min-width: 769px) and (max-width: 1023px) { + .is-block-tablet-only { + display: block !important; } } + +@media screen and (max-width: 1023px) { + .is-block-touch { + display: block !important; } } + +@media screen and (min-width: 1024px) { + .is-block-desktop { + display: block !important; } } + +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .is-block-desktop-only { + display: block !important; } } + +@media screen and (min-width: 1216px) { + .is-block-widescreen { + display: block !important; } } + +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .is-block-widescreen-only { + display: block !important; } } + +@media screen and (min-width: 1408px) { + .is-block-fullhd { + display: block !important; } } + +.is-flex { + display: flex !important; } + +@media screen and (max-width: 768px) { + .is-flex-mobile { + display: flex !important; } } + +@media screen and (min-width: 769px), print { + .is-flex-tablet { + display: flex !important; } } + +@media screen and (min-width: 769px) and (max-width: 1023px) { + .is-flex-tablet-only { + display: flex !important; } } + +@media screen and (max-width: 1023px) { + .is-flex-touch { + display: flex !important; } } + +@media screen and (min-width: 1024px) { + .is-flex-desktop { + display: flex !important; } } + +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .is-flex-desktop-only { + display: flex !important; } } + +@media screen and (min-width: 1216px) { + .is-flex-widescreen { + display: flex !important; } } + +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .is-flex-widescreen-only { + display: flex !important; } } + +@media screen and (min-width: 1408px) { + .is-flex-fullhd { + display: flex !important; } } + +.is-inline { + display: inline !important; } + +@media screen and (max-width: 768px) { + .is-inline-mobile { + display: inline !important; } } + +@media screen and (min-width: 769px), print { + .is-inline-tablet { + display: inline !important; } } + +@media screen and (min-width: 769px) and (max-width: 1023px) { + .is-inline-tablet-only { + display: inline !important; } } + +@media screen and (max-width: 1023px) { + .is-inline-touch { + display: inline !important; } } + +@media screen and (min-width: 1024px) { + .is-inline-desktop { + display: inline !important; } } + +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .is-inline-desktop-only { + display: inline !important; } } + +@media screen and (min-width: 1216px) { + .is-inline-widescreen { + display: inline !important; } } + +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .is-inline-widescreen-only { + display: inline !important; } } + +@media screen and (min-width: 1408px) { + .is-inline-fullhd { + display: inline !important; } } + +.is-inline-block { + display: inline-block !important; } + +@media screen and (max-width: 768px) { + .is-inline-block-mobile { + display: inline-block !important; } } + +@media screen and (min-width: 769px), print { + .is-inline-block-tablet { + display: inline-block !important; } } + +@media screen and (min-width: 769px) and (max-width: 1023px) { + .is-inline-block-tablet-only { + display: inline-block !important; } } + +@media screen and (max-width: 1023px) { + .is-inline-block-touch { + display: inline-block !important; } } + +@media screen and (min-width: 1024px) { + .is-inline-block-desktop { + display: inline-block !important; } } + +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .is-inline-block-desktop-only { + display: inline-block !important; } } + +@media screen and (min-width: 1216px) { + .is-inline-block-widescreen { + display: inline-block !important; } } + +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .is-inline-block-widescreen-only { + display: inline-block !important; } } + +@media screen and (min-width: 1408px) { + .is-inline-block-fullhd { + display: inline-block !important; } } + +.is-inline-flex { + display: inline-flex !important; } + +@media screen and (max-width: 768px) { + .is-inline-flex-mobile { + display: inline-flex !important; } } + +@media screen and (min-width: 769px), print { + .is-inline-flex-tablet { + display: inline-flex !important; } } + +@media screen and (min-width: 769px) and (max-width: 1023px) { + .is-inline-flex-tablet-only { + display: inline-flex !important; } } + +@media screen and (max-width: 1023px) { + .is-inline-flex-touch { + display: inline-flex !important; } } + +@media screen and (min-width: 1024px) { + .is-inline-flex-desktop { + display: inline-flex !important; } } + +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .is-inline-flex-desktop-only { + display: inline-flex !important; } } + +@media screen and (min-width: 1216px) { + .is-inline-flex-widescreen { + display: inline-flex !important; } } + +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .is-inline-flex-widescreen-only { + display: inline-flex !important; } } + +@media screen and (min-width: 1408px) { + .is-inline-flex-fullhd { + display: inline-flex !important; } } + +.is-hidden { + display: none !important; } + +.is-sr-only { + border: none !important; + clip: rect(0, 0, 0, 0) !important; + height: 0.01em !important; + overflow: hidden !important; + padding: 0 !important; + position: absolute !important; + white-space: nowrap !important; + width: 0.01em !important; } + +@media screen and (max-width: 768px) { + .is-hidden-mobile { + display: none !important; } } + +@media screen and (min-width: 769px), print { + .is-hidden-tablet { + display: none !important; } } + +@media screen and (min-width: 769px) and (max-width: 1023px) { + .is-hidden-tablet-only { + display: none !important; } } + +@media screen and (max-width: 1023px) { + .is-hidden-touch { + display: none !important; } } + +@media screen and (min-width: 1024px) { + .is-hidden-desktop { + display: none !important; } } + +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .is-hidden-desktop-only { + display: none !important; } } + +@media screen and (min-width: 1216px) { + .is-hidden-widescreen { + display: none !important; } } + +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .is-hidden-widescreen-only { + display: none !important; } } + +@media screen and (min-width: 1408px) { + .is-hidden-fullhd { + display: none !important; } } + +.is-invisible { + visibility: hidden !important; } + +@media screen and (max-width: 768px) { + .is-invisible-mobile { + visibility: hidden !important; } } + +@media screen and (min-width: 769px), print { + .is-invisible-tablet { + visibility: hidden !important; } } + +@media screen and (min-width: 769px) and (max-width: 1023px) { + .is-invisible-tablet-only { + visibility: hidden !important; } } + +@media screen and (max-width: 1023px) { + .is-invisible-touch { + visibility: hidden !important; } } + +@media screen and (min-width: 1024px) { + .is-invisible-desktop { + visibility: hidden !important; } } + +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .is-invisible-desktop-only { + visibility: hidden !important; } } + +@media screen and (min-width: 1216px) { + .is-invisible-widescreen { + visibility: hidden !important; } } + +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .is-invisible-widescreen-only { + visibility: hidden !important; } } + +@media screen and (min-width: 1408px) { + .is-invisible-fullhd { + visibility: hidden !important; } } + +.is-marginless { + margin: 0 !important; } + +.is-paddingless { + padding: 0 !important; } + +.is-radiusless { + border-radius: 0 !important; } + +.is-shadowless { + box-shadow: none !important; } + +.is-relative { + position: relative !important; } + +.box { + background-color: white; + border-radius: 6px; + box-shadow: 0 0.5em 1em -0.125em rgba(10, 10, 10, 0.1), 0 0px 0 1px rgba(10, 10, 10, 0.02); + color: #4a4a4a; + display: block; + padding: 1.25rem; } + +a.box:hover, a.box:focus { + box-shadow: 0 0.5em 1em -0.125em rgba(10, 10, 10, 0.1), 0 0 0 1px #3273dc; } + +a.box:active { + box-shadow: inset 0 1px 2px rgba(10, 10, 10, 0.2), 0 0 0 1px #3273dc; } + +.button { + background-color: white; + border-color: #dbdbdb; + border-width: 1px; + color: #363636; + cursor: pointer; + justify-content: center; + padding-bottom: calc(0.5em - 1px); + padding-left: 1em; + padding-right: 1em; + padding-top: calc(0.5em - 1px); + text-align: center; + white-space: nowrap; } + .button strong { + color: inherit; } + .button .icon, .button .icon.is-small, .button .icon.is-medium, .button .icon.is-large { + height: 1.5em; + width: 1.5em; } + .button .icon:first-child:not(:last-child) { + margin-left: calc(-0.5em - 1px); + margin-right: 0.25em; } + .button .icon:last-child:not(:first-child) { + margin-left: 0.25em; + margin-right: calc(-0.5em - 1px); } + .button .icon:first-child:last-child { + margin-left: calc(-0.5em - 1px); + margin-right: calc(-0.5em - 1px); } + .button:hover, .button.is-hovered { + border-color: #b5b5b5; + color: #363636; } + .button:focus, .button.is-focused { + border-color: #3273dc; + color: #363636; } + .button:focus:not(:active), .button.is-focused:not(:active) { + box-shadow: 0 0 0 0.125em rgba(50, 115, 220, 0.25); } + .button:active, .button.is-active { + border-color: #4a4a4a; + color: #363636; } + .button.is-text { + background-color: transparent; + border-color: transparent; + color: #4a4a4a; + text-decoration: underline; } + .button.is-text:hover, .button.is-text.is-hovered, .button.is-text:focus, .button.is-text.is-focused { + background-color: whitesmoke; + color: #363636; } + .button.is-text:active, .button.is-text.is-active { + background-color: #e8e8e8; + color: #363636; } + .button.is-text[disabled], + fieldset[disabled] .button.is-text { + background-color: transparent; + border-color: transparent; + box-shadow: none; } + .button.is-white { + background-color: white; + border-color: transparent; + color: #0a0a0a; } + .button.is-white:hover, .button.is-white.is-hovered { + background-color: #f9f9f9; + border-color: transparent; + color: #0a0a0a; } + .button.is-white:focus, .button.is-white.is-focused { + border-color: transparent; + color: #0a0a0a; } + .button.is-white:focus:not(:active), .button.is-white.is-focused:not(:active) { + box-shadow: 0 0 0 0.125em rgba(255, 255, 255, 0.25); } + .button.is-white:active, .button.is-white.is-active { + background-color: #f2f2f2; + border-color: transparent; + color: #0a0a0a; } + .button.is-white[disabled], + fieldset[disabled] .button.is-white { + background-color: white; + border-color: transparent; + box-shadow: none; } + .button.is-white.is-inverted { + background-color: #0a0a0a; + color: white; } + .button.is-white.is-inverted:hover, .button.is-white.is-inverted.is-hovered { + background-color: black; } + .button.is-white.is-inverted[disabled], + fieldset[disabled] .button.is-white.is-inverted { + background-color: #0a0a0a; + border-color: transparent; + box-shadow: none; + color: white; } + .button.is-white.is-loading::after { + border-color: transparent transparent #0a0a0a #0a0a0a !important; } + .button.is-white.is-outlined { + background-color: transparent; + border-color: white; + color: white; } + .button.is-white.is-outlined:hover, .button.is-white.is-outlined.is-hovered, .button.is-white.is-outlined:focus, .button.is-white.is-outlined.is-focused { + background-color: white; + border-color: white; + color: #0a0a0a; } + .button.is-white.is-outlined.is-loading::after { + border-color: transparent transparent white white !important; } + .button.is-white.is-outlined.is-loading:hover::after, .button.is-white.is-outlined.is-loading.is-hovered::after, .button.is-white.is-outlined.is-loading:focus::after, .button.is-white.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #0a0a0a #0a0a0a !important; } + .button.is-white.is-outlined[disabled], + fieldset[disabled] .button.is-white.is-outlined { + background-color: transparent; + border-color: white; + box-shadow: none; + color: white; } + .button.is-white.is-inverted.is-outlined { + background-color: transparent; + border-color: #0a0a0a; + color: #0a0a0a; } + .button.is-white.is-inverted.is-outlined:hover, .button.is-white.is-inverted.is-outlined.is-hovered, .button.is-white.is-inverted.is-outlined:focus, .button.is-white.is-inverted.is-outlined.is-focused { + background-color: #0a0a0a; + color: white; } + .button.is-white.is-inverted.is-outlined.is-loading:hover::after, .button.is-white.is-inverted.is-outlined.is-loading.is-hovered::after, .button.is-white.is-inverted.is-outlined.is-loading:focus::after, .button.is-white.is-inverted.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent white white !important; } + .button.is-white.is-inverted.is-outlined[disabled], + fieldset[disabled] .button.is-white.is-inverted.is-outlined { + background-color: transparent; + border-color: #0a0a0a; + box-shadow: none; + color: #0a0a0a; } + .button.is-black { + background-color: #0a0a0a; + border-color: transparent; + color: white; } + .button.is-black:hover, .button.is-black.is-hovered { + background-color: #040404; + border-color: transparent; + color: white; } + .button.is-black:focus, .button.is-black.is-focused { + border-color: transparent; + color: white; } + .button.is-black:focus:not(:active), .button.is-black.is-focused:not(:active) { + box-shadow: 0 0 0 0.125em rgba(10, 10, 10, 0.25); } + .button.is-black:active, .button.is-black.is-active { + background-color: black; + border-color: transparent; + color: white; } + .button.is-black[disabled], + fieldset[disabled] .button.is-black { + background-color: #0a0a0a; + border-color: transparent; + box-shadow: none; } + .button.is-black.is-inverted { + background-color: white; + color: #0a0a0a; } + .button.is-black.is-inverted:hover, .button.is-black.is-inverted.is-hovered { + background-color: #f2f2f2; } + .button.is-black.is-inverted[disabled], + fieldset[disabled] .button.is-black.is-inverted { + background-color: white; + border-color: transparent; + box-shadow: none; + color: #0a0a0a; } + .button.is-black.is-loading::after { + border-color: transparent transparent white white !important; } + .button.is-black.is-outlined { + background-color: transparent; + border-color: #0a0a0a; + color: #0a0a0a; } + .button.is-black.is-outlined:hover, .button.is-black.is-outlined.is-hovered, .button.is-black.is-outlined:focus, .button.is-black.is-outlined.is-focused { + background-color: #0a0a0a; + border-color: #0a0a0a; + color: white; } + .button.is-black.is-outlined.is-loading::after { + border-color: transparent transparent #0a0a0a #0a0a0a !important; } + .button.is-black.is-outlined.is-loading:hover::after, .button.is-black.is-outlined.is-loading.is-hovered::after, .button.is-black.is-outlined.is-loading:focus::after, .button.is-black.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent white white !important; } + .button.is-black.is-outlined[disabled], + fieldset[disabled] .button.is-black.is-outlined { + background-color: transparent; + border-color: #0a0a0a; + box-shadow: none; + color: #0a0a0a; } + .button.is-black.is-inverted.is-outlined { + background-color: transparent; + border-color: white; + color: white; } + .button.is-black.is-inverted.is-outlined:hover, .button.is-black.is-inverted.is-outlined.is-hovered, .button.is-black.is-inverted.is-outlined:focus, .button.is-black.is-inverted.is-outlined.is-focused { + background-color: white; + color: #0a0a0a; } + .button.is-black.is-inverted.is-outlined.is-loading:hover::after, .button.is-black.is-inverted.is-outlined.is-loading.is-hovered::after, .button.is-black.is-inverted.is-outlined.is-loading:focus::after, .button.is-black.is-inverted.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #0a0a0a #0a0a0a !important; } + .button.is-black.is-inverted.is-outlined[disabled], + fieldset[disabled] .button.is-black.is-inverted.is-outlined { + background-color: transparent; + border-color: white; + box-shadow: none; + color: white; } + .button.is-light { + background-color: whitesmoke; + border-color: transparent; + color: rgba(0, 0, 0, 0.7); } + .button.is-light:hover, .button.is-light.is-hovered { + background-color: #eeeeee; + border-color: transparent; + color: rgba(0, 0, 0, 0.7); } + .button.is-light:focus, .button.is-light.is-focused { + border-color: transparent; + color: rgba(0, 0, 0, 0.7); } + .button.is-light:focus:not(:active), .button.is-light.is-focused:not(:active) { + box-shadow: 0 0 0 0.125em rgba(245, 245, 245, 0.25); } + .button.is-light:active, .button.is-light.is-active { + background-color: #e8e8e8; + border-color: transparent; + color: rgba(0, 0, 0, 0.7); } + .button.is-light[disabled], + fieldset[disabled] .button.is-light { + background-color: whitesmoke; + border-color: transparent; + box-shadow: none; } + .button.is-light.is-inverted { + background-color: rgba(0, 0, 0, 0.7); + color: whitesmoke; } + .button.is-light.is-inverted:hover, .button.is-light.is-inverted.is-hovered { + background-color: rgba(0, 0, 0, 0.7); } + .button.is-light.is-inverted[disabled], + fieldset[disabled] .button.is-light.is-inverted { + background-color: rgba(0, 0, 0, 0.7); + border-color: transparent; + box-shadow: none; + color: whitesmoke; } + .button.is-light.is-loading::after { + border-color: transparent transparent rgba(0, 0, 0, 0.7) rgba(0, 0, 0, 0.7) !important; } + .button.is-light.is-outlined { + background-color: transparent; + border-color: whitesmoke; + color: whitesmoke; } + .button.is-light.is-outlined:hover, .button.is-light.is-outlined.is-hovered, .button.is-light.is-outlined:focus, .button.is-light.is-outlined.is-focused { + background-color: whitesmoke; + border-color: whitesmoke; + color: rgba(0, 0, 0, 0.7); } + .button.is-light.is-outlined.is-loading::after { + border-color: transparent transparent whitesmoke whitesmoke !important; } + .button.is-light.is-outlined.is-loading:hover::after, .button.is-light.is-outlined.is-loading.is-hovered::after, .button.is-light.is-outlined.is-loading:focus::after, .button.is-light.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent rgba(0, 0, 0, 0.7) rgba(0, 0, 0, 0.7) !important; } + .button.is-light.is-outlined[disabled], + fieldset[disabled] .button.is-light.is-outlined { + background-color: transparent; + border-color: whitesmoke; + box-shadow: none; + color: whitesmoke; } + .button.is-light.is-inverted.is-outlined { + background-color: transparent; + border-color: rgba(0, 0, 0, 0.7); + color: rgba(0, 0, 0, 0.7); } + .button.is-light.is-inverted.is-outlined:hover, .button.is-light.is-inverted.is-outlined.is-hovered, .button.is-light.is-inverted.is-outlined:focus, .button.is-light.is-inverted.is-outlined.is-focused { + background-color: rgba(0, 0, 0, 0.7); + color: whitesmoke; } + .button.is-light.is-inverted.is-outlined.is-loading:hover::after, .button.is-light.is-inverted.is-outlined.is-loading.is-hovered::after, .button.is-light.is-inverted.is-outlined.is-loading:focus::after, .button.is-light.is-inverted.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent whitesmoke whitesmoke !important; } + .button.is-light.is-inverted.is-outlined[disabled], + fieldset[disabled] .button.is-light.is-inverted.is-outlined { + background-color: transparent; + border-color: rgba(0, 0, 0, 0.7); + box-shadow: none; + color: rgba(0, 0, 0, 0.7); } + .button.is-dark { + background-color: #363636; + border-color: transparent; + color: #fff; } + .button.is-dark:hover, .button.is-dark.is-hovered { + background-color: #2f2f2f; + border-color: transparent; + color: #fff; } + .button.is-dark:focus, .button.is-dark.is-focused { + border-color: transparent; + color: #fff; } + .button.is-dark:focus:not(:active), .button.is-dark.is-focused:not(:active) { + box-shadow: 0 0 0 0.125em rgba(54, 54, 54, 0.25); } + .button.is-dark:active, .button.is-dark.is-active { + background-color: #292929; + border-color: transparent; + color: #fff; } + .button.is-dark[disabled], + fieldset[disabled] .button.is-dark { + background-color: #363636; + border-color: transparent; + box-shadow: none; } + .button.is-dark.is-inverted { + background-color: #fff; + color: #363636; } + .button.is-dark.is-inverted:hover, .button.is-dark.is-inverted.is-hovered { + background-color: #f2f2f2; } + .button.is-dark.is-inverted[disabled], + fieldset[disabled] .button.is-dark.is-inverted { + background-color: #fff; + border-color: transparent; + box-shadow: none; + color: #363636; } + .button.is-dark.is-loading::after { + border-color: transparent transparent #fff #fff !important; } + .button.is-dark.is-outlined { + background-color: transparent; + border-color: #363636; + color: #363636; } + .button.is-dark.is-outlined:hover, .button.is-dark.is-outlined.is-hovered, .button.is-dark.is-outlined:focus, .button.is-dark.is-outlined.is-focused { + background-color: #363636; + border-color: #363636; + color: #fff; } + .button.is-dark.is-outlined.is-loading::after { + border-color: transparent transparent #363636 #363636 !important; } + .button.is-dark.is-outlined.is-loading:hover::after, .button.is-dark.is-outlined.is-loading.is-hovered::after, .button.is-dark.is-outlined.is-loading:focus::after, .button.is-dark.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #fff #fff !important; } + .button.is-dark.is-outlined[disabled], + fieldset[disabled] .button.is-dark.is-outlined { + background-color: transparent; + border-color: #363636; + box-shadow: none; + color: #363636; } + .button.is-dark.is-inverted.is-outlined { + background-color: transparent; + border-color: #fff; + color: #fff; } + .button.is-dark.is-inverted.is-outlined:hover, .button.is-dark.is-inverted.is-outlined.is-hovered, .button.is-dark.is-inverted.is-outlined:focus, .button.is-dark.is-inverted.is-outlined.is-focused { + background-color: #fff; + color: #363636; } + .button.is-dark.is-inverted.is-outlined.is-loading:hover::after, .button.is-dark.is-inverted.is-outlined.is-loading.is-hovered::after, .button.is-dark.is-inverted.is-outlined.is-loading:focus::after, .button.is-dark.is-inverted.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #363636 #363636 !important; } + .button.is-dark.is-inverted.is-outlined[disabled], + fieldset[disabled] .button.is-dark.is-inverted.is-outlined { + background-color: transparent; + border-color: #fff; + box-shadow: none; + color: #fff; } + .button.is-primary { + background-color: #00d1b2; + border-color: transparent; + color: #fff; } + .button.is-primary:hover, .button.is-primary.is-hovered { + background-color: #00c4a7; + border-color: transparent; + color: #fff; } + .button.is-primary:focus, .button.is-primary.is-focused { + border-color: transparent; + color: #fff; } + .button.is-primary:focus:not(:active), .button.is-primary.is-focused:not(:active) { + box-shadow: 0 0 0 0.125em rgba(0, 209, 178, 0.25); } + .button.is-primary:active, .button.is-primary.is-active { + background-color: #00b89c; + border-color: transparent; + color: #fff; } + .button.is-primary[disabled], + fieldset[disabled] .button.is-primary { + background-color: #00d1b2; + border-color: transparent; + box-shadow: none; } + .button.is-primary.is-inverted { + background-color: #fff; + color: #00d1b2; } + .button.is-primary.is-inverted:hover, .button.is-primary.is-inverted.is-hovered { + background-color: #f2f2f2; } + .button.is-primary.is-inverted[disabled], + fieldset[disabled] .button.is-primary.is-inverted { + background-color: #fff; + border-color: transparent; + box-shadow: none; + color: #00d1b2; } + .button.is-primary.is-loading::after { + border-color: transparent transparent #fff #fff !important; } + .button.is-primary.is-outlined { + background-color: transparent; + border-color: #00d1b2; + color: #00d1b2; } + .button.is-primary.is-outlined:hover, .button.is-primary.is-outlined.is-hovered, .button.is-primary.is-outlined:focus, .button.is-primary.is-outlined.is-focused { + background-color: #00d1b2; + border-color: #00d1b2; + color: #fff; } + .button.is-primary.is-outlined.is-loading::after { + border-color: transparent transparent #00d1b2 #00d1b2 !important; } + .button.is-primary.is-outlined.is-loading:hover::after, .button.is-primary.is-outlined.is-loading.is-hovered::after, .button.is-primary.is-outlined.is-loading:focus::after, .button.is-primary.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #fff #fff !important; } + .button.is-primary.is-outlined[disabled], + fieldset[disabled] .button.is-primary.is-outlined { + background-color: transparent; + border-color: #00d1b2; + box-shadow: none; + color: #00d1b2; } + .button.is-primary.is-inverted.is-outlined { + background-color: transparent; + border-color: #fff; + color: #fff; } + .button.is-primary.is-inverted.is-outlined:hover, .button.is-primary.is-inverted.is-outlined.is-hovered, .button.is-primary.is-inverted.is-outlined:focus, .button.is-primary.is-inverted.is-outlined.is-focused { + background-color: #fff; + color: #00d1b2; } + .button.is-primary.is-inverted.is-outlined.is-loading:hover::after, .button.is-primary.is-inverted.is-outlined.is-loading.is-hovered::after, .button.is-primary.is-inverted.is-outlined.is-loading:focus::after, .button.is-primary.is-inverted.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #00d1b2 #00d1b2 !important; } + .button.is-primary.is-inverted.is-outlined[disabled], + fieldset[disabled] .button.is-primary.is-inverted.is-outlined { + background-color: transparent; + border-color: #fff; + box-shadow: none; + color: #fff; } + .button.is-primary.is-light { + background-color: #ebfffc; + color: #00947e; } + .button.is-primary.is-light:hover, .button.is-primary.is-light.is-hovered { + background-color: #defffa; + border-color: transparent; + color: #00947e; } + .button.is-primary.is-light:active, .button.is-primary.is-light.is-active { + background-color: #d1fff8; + border-color: transparent; + color: #00947e; } + .button.is-link { + background-color: #3273dc; + border-color: transparent; + color: #fff; } + .button.is-link:hover, .button.is-link.is-hovered { + background-color: #276cda; + border-color: transparent; + color: #fff; } + .button.is-link:focus, .button.is-link.is-focused { + border-color: transparent; + color: #fff; } + .button.is-link:focus:not(:active), .button.is-link.is-focused:not(:active) { + box-shadow: 0 0 0 0.125em rgba(50, 115, 220, 0.25); } + .button.is-link:active, .button.is-link.is-active { + background-color: #2366d1; + border-color: transparent; + color: #fff; } + .button.is-link[disabled], + fieldset[disabled] .button.is-link { + background-color: #3273dc; + border-color: transparent; + box-shadow: none; } + .button.is-link.is-inverted { + background-color: #fff; + color: #3273dc; } + .button.is-link.is-inverted:hover, .button.is-link.is-inverted.is-hovered { + background-color: #f2f2f2; } + .button.is-link.is-inverted[disabled], + fieldset[disabled] .button.is-link.is-inverted { + background-color: #fff; + border-color: transparent; + box-shadow: none; + color: #3273dc; } + .button.is-link.is-loading::after { + border-color: transparent transparent #fff #fff !important; } + .button.is-link.is-outlined { + background-color: transparent; + border-color: #3273dc; + color: #3273dc; } + .button.is-link.is-outlined:hover, .button.is-link.is-outlined.is-hovered, .button.is-link.is-outlined:focus, .button.is-link.is-outlined.is-focused { + background-color: #3273dc; + border-color: #3273dc; + color: #fff; } + .button.is-link.is-outlined.is-loading::after { + border-color: transparent transparent #3273dc #3273dc !important; } + .button.is-link.is-outlined.is-loading:hover::after, .button.is-link.is-outlined.is-loading.is-hovered::after, .button.is-link.is-outlined.is-loading:focus::after, .button.is-link.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #fff #fff !important; } + .button.is-link.is-outlined[disabled], + fieldset[disabled] .button.is-link.is-outlined { + background-color: transparent; + border-color: #3273dc; + box-shadow: none; + color: #3273dc; } + .button.is-link.is-inverted.is-outlined { + background-color: transparent; + border-color: #fff; + color: #fff; } + .button.is-link.is-inverted.is-outlined:hover, .button.is-link.is-inverted.is-outlined.is-hovered, .button.is-link.is-inverted.is-outlined:focus, .button.is-link.is-inverted.is-outlined.is-focused { + background-color: #fff; + color: #3273dc; } + .button.is-link.is-inverted.is-outlined.is-loading:hover::after, .button.is-link.is-inverted.is-outlined.is-loading.is-hovered::after, .button.is-link.is-inverted.is-outlined.is-loading:focus::after, .button.is-link.is-inverted.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #3273dc #3273dc !important; } + .button.is-link.is-inverted.is-outlined[disabled], + fieldset[disabled] .button.is-link.is-inverted.is-outlined { + background-color: transparent; + border-color: #fff; + box-shadow: none; + color: #fff; } + .button.is-link.is-light { + background-color: #eef3fc; + color: #2160c4; } + .button.is-link.is-light:hover, .button.is-link.is-light.is-hovered { + background-color: #e3ecfa; + border-color: transparent; + color: #2160c4; } + .button.is-link.is-light:active, .button.is-link.is-light.is-active { + background-color: #d8e4f8; + border-color: transparent; + color: #2160c4; } + .button.is-info { + background-color: #3298dc; + border-color: transparent; + color: #fff; } + .button.is-info:hover, .button.is-info.is-hovered { + background-color: #2793da; + border-color: transparent; + color: #fff; } + .button.is-info:focus, .button.is-info.is-focused { + border-color: transparent; + color: #fff; } + .button.is-info:focus:not(:active), .button.is-info.is-focused:not(:active) { + box-shadow: 0 0 0 0.125em rgba(50, 152, 220, 0.25); } + .button.is-info:active, .button.is-info.is-active { + background-color: #238cd1; + border-color: transparent; + color: #fff; } + .button.is-info[disabled], + fieldset[disabled] .button.is-info { + background-color: #3298dc; + border-color: transparent; + box-shadow: none; } + .button.is-info.is-inverted { + background-color: #fff; + color: #3298dc; } + .button.is-info.is-inverted:hover, .button.is-info.is-inverted.is-hovered { + background-color: #f2f2f2; } + .button.is-info.is-inverted[disabled], + fieldset[disabled] .button.is-info.is-inverted { + background-color: #fff; + border-color: transparent; + box-shadow: none; + color: #3298dc; } + .button.is-info.is-loading::after { + border-color: transparent transparent #fff #fff !important; } + .button.is-info.is-outlined { + background-color: transparent; + border-color: #3298dc; + color: #3298dc; } + .button.is-info.is-outlined:hover, .button.is-info.is-outlined.is-hovered, .button.is-info.is-outlined:focus, .button.is-info.is-outlined.is-focused { + background-color: #3298dc; + border-color: #3298dc; + color: #fff; } + .button.is-info.is-outlined.is-loading::after { + border-color: transparent transparent #3298dc #3298dc !important; } + .button.is-info.is-outlined.is-loading:hover::after, .button.is-info.is-outlined.is-loading.is-hovered::after, .button.is-info.is-outlined.is-loading:focus::after, .button.is-info.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #fff #fff !important; } + .button.is-info.is-outlined[disabled], + fieldset[disabled] .button.is-info.is-outlined { + background-color: transparent; + border-color: #3298dc; + box-shadow: none; + color: #3298dc; } + .button.is-info.is-inverted.is-outlined { + background-color: transparent; + border-color: #fff; + color: #fff; } + .button.is-info.is-inverted.is-outlined:hover, .button.is-info.is-inverted.is-outlined.is-hovered, .button.is-info.is-inverted.is-outlined:focus, .button.is-info.is-inverted.is-outlined.is-focused { + background-color: #fff; + color: #3298dc; } + .button.is-info.is-inverted.is-outlined.is-loading:hover::after, .button.is-info.is-inverted.is-outlined.is-loading.is-hovered::after, .button.is-info.is-inverted.is-outlined.is-loading:focus::after, .button.is-info.is-inverted.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #3298dc #3298dc !important; } + .button.is-info.is-inverted.is-outlined[disabled], + fieldset[disabled] .button.is-info.is-inverted.is-outlined { + background-color: transparent; + border-color: #fff; + box-shadow: none; + color: #fff; } + .button.is-info.is-light { + background-color: #eef6fc; + color: #1d72aa; } + .button.is-info.is-light:hover, .button.is-info.is-light.is-hovered { + background-color: #e3f1fa; + border-color: transparent; + color: #1d72aa; } + .button.is-info.is-light:active, .button.is-info.is-light.is-active { + background-color: #d8ebf8; + border-color: transparent; + color: #1d72aa; } + .button.is-success { + background-color: #48c774; + border-color: transparent; + color: #fff; } + .button.is-success:hover, .button.is-success.is-hovered { + background-color: #3ec46d; + border-color: transparent; + color: #fff; } + .button.is-success:focus, .button.is-success.is-focused { + border-color: transparent; + color: #fff; } + .button.is-success:focus:not(:active), .button.is-success.is-focused:not(:active) { + box-shadow: 0 0 0 0.125em rgba(72, 199, 116, 0.25); } + .button.is-success:active, .button.is-success.is-active { + background-color: #3abb67; + border-color: transparent; + color: #fff; } + .button.is-success[disabled], + fieldset[disabled] .button.is-success { + background-color: #48c774; + border-color: transparent; + box-shadow: none; } + .button.is-success.is-inverted { + background-color: #fff; + color: #48c774; } + .button.is-success.is-inverted:hover, .button.is-success.is-inverted.is-hovered { + background-color: #f2f2f2; } + .button.is-success.is-inverted[disabled], + fieldset[disabled] .button.is-success.is-inverted { + background-color: #fff; + border-color: transparent; + box-shadow: none; + color: #48c774; } + .button.is-success.is-loading::after { + border-color: transparent transparent #fff #fff !important; } + .button.is-success.is-outlined { + background-color: transparent; + border-color: #48c774; + color: #48c774; } + .button.is-success.is-outlined:hover, .button.is-success.is-outlined.is-hovered, .button.is-success.is-outlined:focus, .button.is-success.is-outlined.is-focused { + background-color: #48c774; + border-color: #48c774; + color: #fff; } + .button.is-success.is-outlined.is-loading::after { + border-color: transparent transparent #48c774 #48c774 !important; } + .button.is-success.is-outlined.is-loading:hover::after, .button.is-success.is-outlined.is-loading.is-hovered::after, .button.is-success.is-outlined.is-loading:focus::after, .button.is-success.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #fff #fff !important; } + .button.is-success.is-outlined[disabled], + fieldset[disabled] .button.is-success.is-outlined { + background-color: transparent; + border-color: #48c774; + box-shadow: none; + color: #48c774; } + .button.is-success.is-inverted.is-outlined { + background-color: transparent; + border-color: #fff; + color: #fff; } + .button.is-success.is-inverted.is-outlined:hover, .button.is-success.is-inverted.is-outlined.is-hovered, .button.is-success.is-inverted.is-outlined:focus, .button.is-success.is-inverted.is-outlined.is-focused { + background-color: #fff; + color: #48c774; } + .button.is-success.is-inverted.is-outlined.is-loading:hover::after, .button.is-success.is-inverted.is-outlined.is-loading.is-hovered::after, .button.is-success.is-inverted.is-outlined.is-loading:focus::after, .button.is-success.is-inverted.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #48c774 #48c774 !important; } + .button.is-success.is-inverted.is-outlined[disabled], + fieldset[disabled] .button.is-success.is-inverted.is-outlined { + background-color: transparent; + border-color: #fff; + box-shadow: none; + color: #fff; } + .button.is-success.is-light { + background-color: #effaf3; + color: #257942; } + .button.is-success.is-light:hover, .button.is-success.is-light.is-hovered { + background-color: #e6f7ec; + border-color: transparent; + color: #257942; } + .button.is-success.is-light:active, .button.is-success.is-light.is-active { + background-color: #dcf4e4; + border-color: transparent; + color: #257942; } + .button.is-warning { + background-color: #ffdd57; + border-color: transparent; + color: rgba(0, 0, 0, 0.7); } + .button.is-warning:hover, .button.is-warning.is-hovered { + background-color: #ffdb4a; + border-color: transparent; + color: rgba(0, 0, 0, 0.7); } + .button.is-warning:focus, .button.is-warning.is-focused { + border-color: transparent; + color: rgba(0, 0, 0, 0.7); } + .button.is-warning:focus:not(:active), .button.is-warning.is-focused:not(:active) { + box-shadow: 0 0 0 0.125em rgba(255, 221, 87, 0.25); } + .button.is-warning:active, .button.is-warning.is-active { + background-color: #ffd83d; + border-color: transparent; + color: rgba(0, 0, 0, 0.7); } + .button.is-warning[disabled], + fieldset[disabled] .button.is-warning { + background-color: #ffdd57; + border-color: transparent; + box-shadow: none; } + .button.is-warning.is-inverted { + background-color: rgba(0, 0, 0, 0.7); + color: #ffdd57; } + .button.is-warning.is-inverted:hover, .button.is-warning.is-inverted.is-hovered { + background-color: rgba(0, 0, 0, 0.7); } + .button.is-warning.is-inverted[disabled], + fieldset[disabled] .button.is-warning.is-inverted { + background-color: rgba(0, 0, 0, 0.7); + border-color: transparent; + box-shadow: none; + color: #ffdd57; } + .button.is-warning.is-loading::after { + border-color: transparent transparent rgba(0, 0, 0, 0.7) rgba(0, 0, 0, 0.7) !important; } + .button.is-warning.is-outlined { + background-color: transparent; + border-color: #ffdd57; + color: #ffdd57; } + .button.is-warning.is-outlined:hover, .button.is-warning.is-outlined.is-hovered, .button.is-warning.is-outlined:focus, .button.is-warning.is-outlined.is-focused { + background-color: #ffdd57; + border-color: #ffdd57; + color: rgba(0, 0, 0, 0.7); } + .button.is-warning.is-outlined.is-loading::after { + border-color: transparent transparent #ffdd57 #ffdd57 !important; } + .button.is-warning.is-outlined.is-loading:hover::after, .button.is-warning.is-outlined.is-loading.is-hovered::after, .button.is-warning.is-outlined.is-loading:focus::after, .button.is-warning.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent rgba(0, 0, 0, 0.7) rgba(0, 0, 0, 0.7) !important; } + .button.is-warning.is-outlined[disabled], + fieldset[disabled] .button.is-warning.is-outlined { + background-color: transparent; + border-color: #ffdd57; + box-shadow: none; + color: #ffdd57; } + .button.is-warning.is-inverted.is-outlined { + background-color: transparent; + border-color: rgba(0, 0, 0, 0.7); + color: rgba(0, 0, 0, 0.7); } + .button.is-warning.is-inverted.is-outlined:hover, .button.is-warning.is-inverted.is-outlined.is-hovered, .button.is-warning.is-inverted.is-outlined:focus, .button.is-warning.is-inverted.is-outlined.is-focused { + background-color: rgba(0, 0, 0, 0.7); + color: #ffdd57; } + .button.is-warning.is-inverted.is-outlined.is-loading:hover::after, .button.is-warning.is-inverted.is-outlined.is-loading.is-hovered::after, .button.is-warning.is-inverted.is-outlined.is-loading:focus::after, .button.is-warning.is-inverted.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #ffdd57 #ffdd57 !important; } + .button.is-warning.is-inverted.is-outlined[disabled], + fieldset[disabled] .button.is-warning.is-inverted.is-outlined { + background-color: transparent; + border-color: rgba(0, 0, 0, 0.7); + box-shadow: none; + color: rgba(0, 0, 0, 0.7); } + .button.is-warning.is-light { + background-color: #fffbeb; + color: #947600; } + .button.is-warning.is-light:hover, .button.is-warning.is-light.is-hovered { + background-color: #fff8de; + border-color: transparent; + color: #947600; } + .button.is-warning.is-light:active, .button.is-warning.is-light.is-active { + background-color: #fff6d1; + border-color: transparent; + color: #947600; } + .button.is-danger { + background-color: #f14668; + border-color: transparent; + color: #fff; } + .button.is-danger:hover, .button.is-danger.is-hovered { + background-color: #f03a5f; + border-color: transparent; + color: #fff; } + .button.is-danger:focus, .button.is-danger.is-focused { + border-color: transparent; + color: #fff; } + .button.is-danger:focus:not(:active), .button.is-danger.is-focused:not(:active) { + box-shadow: 0 0 0 0.125em rgba(241, 70, 104, 0.25); } + .button.is-danger:active, .button.is-danger.is-active { + background-color: #ef2e55; + border-color: transparent; + color: #fff; } + .button.is-danger[disabled], + fieldset[disabled] .button.is-danger { + background-color: #f14668; + border-color: transparent; + box-shadow: none; } + .button.is-danger.is-inverted { + background-color: #fff; + color: #f14668; } + .button.is-danger.is-inverted:hover, .button.is-danger.is-inverted.is-hovered { + background-color: #f2f2f2; } + .button.is-danger.is-inverted[disabled], + fieldset[disabled] .button.is-danger.is-inverted { + background-color: #fff; + border-color: transparent; + box-shadow: none; + color: #f14668; } + .button.is-danger.is-loading::after { + border-color: transparent transparent #fff #fff !important; } + .button.is-danger.is-outlined { + background-color: transparent; + border-color: #f14668; + color: #f14668; } + .button.is-danger.is-outlined:hover, .button.is-danger.is-outlined.is-hovered, .button.is-danger.is-outlined:focus, .button.is-danger.is-outlined.is-focused { + background-color: #f14668; + border-color: #f14668; + color: #fff; } + .button.is-danger.is-outlined.is-loading::after { + border-color: transparent transparent #f14668 #f14668 !important; } + .button.is-danger.is-outlined.is-loading:hover::after, .button.is-danger.is-outlined.is-loading.is-hovered::after, .button.is-danger.is-outlined.is-loading:focus::after, .button.is-danger.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #fff #fff !important; } + .button.is-danger.is-outlined[disabled], + fieldset[disabled] .button.is-danger.is-outlined { + background-color: transparent; + border-color: #f14668; + box-shadow: none; + color: #f14668; } + .button.is-danger.is-inverted.is-outlined { + background-color: transparent; + border-color: #fff; + color: #fff; } + .button.is-danger.is-inverted.is-outlined:hover, .button.is-danger.is-inverted.is-outlined.is-hovered, .button.is-danger.is-inverted.is-outlined:focus, .button.is-danger.is-inverted.is-outlined.is-focused { + background-color: #fff; + color: #f14668; } + .button.is-danger.is-inverted.is-outlined.is-loading:hover::after, .button.is-danger.is-inverted.is-outlined.is-loading.is-hovered::after, .button.is-danger.is-inverted.is-outlined.is-loading:focus::after, .button.is-danger.is-inverted.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #f14668 #f14668 !important; } + .button.is-danger.is-inverted.is-outlined[disabled], + fieldset[disabled] .button.is-danger.is-inverted.is-outlined { + background-color: transparent; + border-color: #fff; + box-shadow: none; + color: #fff; } + .button.is-danger.is-light { + background-color: #feecf0; + color: #cc0f35; } + .button.is-danger.is-light:hover, .button.is-danger.is-light.is-hovered { + background-color: #fde0e6; + border-color: transparent; + color: #cc0f35; } + .button.is-danger.is-light:active, .button.is-danger.is-light.is-active { + background-color: #fcd4dc; + border-color: transparent; + color: #cc0f35; } + .button.is-small { + border-radius: 2px; + font-size: 0.75rem; } + .button.is-normal { + font-size: 1rem; } + .button.is-medium { + font-size: 1.25rem; } + .button.is-large { + font-size: 1.5rem; } + .button[disabled], + fieldset[disabled] .button { + background-color: white; + border-color: #dbdbdb; + box-shadow: none; + opacity: 0.5; } + .button.is-fullwidth { + display: flex; + width: 100%; } + .button.is-loading { + color: transparent !important; + pointer-events: none; } + .button.is-loading::after { + position: absolute; + left: calc(50% - (1em / 2)); + top: calc(50% - (1em / 2)); + position: absolute !important; } + .button.is-static { + background-color: whitesmoke; + border-color: #dbdbdb; + color: #7a7a7a; + box-shadow: none; + pointer-events: none; } + .button.is-rounded { + border-radius: 290486px; + padding-left: calc(1em + 0.25em); + padding-right: calc(1em + 0.25em); } + +.buttons { + align-items: center; + display: flex; + flex-wrap: wrap; + justify-content: flex-start; } + .buttons .button { + margin-bottom: 0.5rem; } + .buttons .button:not(:last-child):not(.is-fullwidth) { + margin-right: 0.5rem; } + .buttons:last-child { + margin-bottom: -0.5rem; } + .buttons:not(:last-child) { + margin-bottom: 1rem; } + .buttons.are-small .button:not(.is-normal):not(.is-medium):not(.is-large) { + border-radius: 2px; + font-size: 0.75rem; } + .buttons.are-medium .button:not(.is-small):not(.is-normal):not(.is-large) { + font-size: 1.25rem; } + .buttons.are-large .button:not(.is-small):not(.is-normal):not(.is-medium) { + font-size: 1.5rem; } + .buttons.has-addons .button:not(:first-child) { + border-bottom-left-radius: 0; + border-top-left-radius: 0; } + .buttons.has-addons .button:not(:last-child) { + border-bottom-right-radius: 0; + border-top-right-radius: 0; + margin-right: -1px; } + .buttons.has-addons .button:last-child { + margin-right: 0; } + .buttons.has-addons .button:hover, .buttons.has-addons .button.is-hovered { + z-index: 2; } + .buttons.has-addons .button:focus, .buttons.has-addons .button.is-focused, .buttons.has-addons .button:active, .buttons.has-addons .button.is-active, .buttons.has-addons .button.is-selected { + z-index: 3; } + .buttons.has-addons .button:focus:hover, .buttons.has-addons .button.is-focused:hover, .buttons.has-addons .button:active:hover, .buttons.has-addons .button.is-active:hover, .buttons.has-addons .button.is-selected:hover { + z-index: 4; } + .buttons.has-addons .button.is-expanded { + flex-grow: 1; + flex-shrink: 1; } + .buttons.is-centered { + justify-content: center; } + .buttons.is-centered:not(.has-addons) .button:not(.is-fullwidth) { + margin-left: 0.25rem; + margin-right: 0.25rem; } + .buttons.is-right { + justify-content: flex-end; } + .buttons.is-right:not(.has-addons) .button:not(.is-fullwidth) { + margin-left: 0.25rem; + margin-right: 0.25rem; } + +.container { + flex-grow: 1; + margin: 0 auto; + position: relative; + width: auto; } + .container.is-fluid { + max-width: none; + padding-left: 32px; + padding-right: 32px; + width: 100%; } + @media screen and (min-width: 1024px) { + .container { + max-width: 960px; } } + @media screen and (max-width: 1215px) { + .container.is-widescreen { + max-width: 1152px; } } + @media screen and (max-width: 1407px) { + .container.is-fullhd { + max-width: 1344px; } } + @media screen and (min-width: 1216px) { + .container { + max-width: 1152px; } } + @media screen and (min-width: 1408px) { + .container { + max-width: 1344px; } } + +.content li + li { + margin-top: 0.25em; } + +.content p:not(:last-child), +.content dl:not(:last-child), +.content ol:not(:last-child), +.content ul:not(:last-child), +.content blockquote:not(:last-child), +.content pre:not(:last-child), +.content table:not(:last-child) { + margin-bottom: 1em; } + +.content h1, +.content h2, +.content h3, +.content h4, +.content h5, +.content h6 { + color: #363636; + font-weight: 600; + line-height: 1.125; } + +.content h1 { + font-size: 2em; + margin-bottom: 0.5em; } + .content h1:not(:first-child) { + margin-top: 1em; } + +.content h2 { + font-size: 1.75em; + margin-bottom: 0.5714em; } + .content h2:not(:first-child) { + margin-top: 1.1428em; } + +.content h3 { + font-size: 1.5em; + margin-bottom: 0.6666em; } + .content h3:not(:first-child) { + margin-top: 1.3333em; } + +.content h4 { + font-size: 1.25em; + margin-bottom: 0.8em; } + +.content h5 { + font-size: 1.125em; + margin-bottom: 0.8888em; } + +.content h6 { + font-size: 1em; + margin-bottom: 1em; } + +.content blockquote { + background-color: whitesmoke; + border-left: 5px solid #dbdbdb; + padding: 1.25em 1.5em; } + +.content ol { + list-style-position: outside; + margin-left: 2em; + margin-top: 1em; } + .content ol:not([type]) { + list-style-type: decimal; } + .content ol:not([type]).is-lower-alpha { + list-style-type: lower-alpha; } + .content ol:not([type]).is-lower-roman { + list-style-type: lower-roman; } + .content ol:not([type]).is-upper-alpha { + list-style-type: upper-alpha; } + .content ol:not([type]).is-upper-roman { + list-style-type: upper-roman; } + +.content ul { + list-style: disc outside; + margin-left: 2em; + margin-top: 1em; } + .content ul ul { + list-style-type: circle; + margin-top: 0.5em; } + .content ul ul ul { + list-style-type: square; } + +.content dd { + margin-left: 2em; } + +.content figure { + margin-left: 2em; + margin-right: 2em; + text-align: center; } + .content figure:not(:first-child) { + margin-top: 2em; } + .content figure:not(:last-child) { + margin-bottom: 2em; } + .content figure img { + display: inline-block; } + .content figure figcaption { + font-style: italic; } + +.content pre { + -webkit-overflow-scrolling: touch; + overflow-x: auto; + padding: 1.25em 1.5em; + white-space: pre; + word-wrap: normal; } + +.content sup, +.content sub { + font-size: 75%; } + +.content table { + width: 100%; } + .content table td, + .content table th { + border: 1px solid #dbdbdb; + border-width: 0 0 1px; + padding: 0.5em 0.75em; + vertical-align: top; } + .content table th { + color: #363636; } + .content table th:not([align]) { + text-align: left; } + .content table thead td, + .content table thead th { + border-width: 0 0 2px; + color: #363636; } + .content table tfoot td, + .content table tfoot th { + border-width: 2px 0 0; + color: #363636; } + .content table tbody tr:last-child td, + .content table tbody tr:last-child th { + border-bottom-width: 0; } + +.content .tabs li + li { + margin-top: 0; } + +.content.is-small { + font-size: 0.75rem; } + +.content.is-medium { + font-size: 1.25rem; } + +.content.is-large { + font-size: 1.5rem; } + +.icon { + align-items: center; + display: inline-flex; + justify-content: center; + height: 1.5rem; + width: 1.5rem; } + .icon.is-small { + height: 1rem; + width: 1rem; } + .icon.is-medium { + height: 2rem; + width: 2rem; } + .icon.is-large { + height: 3rem; + width: 3rem; } + +.image { + display: block; + position: relative; } + .image img { + display: block; + height: auto; + width: 100%; } + .image img.is-rounded { + border-radius: 290486px; } + .image.is-fullwidth { + width: 100%; } + .image.is-square img, + .image.is-square .has-ratio, .image.is-1by1 img, + .image.is-1by1 .has-ratio, .image.is-5by4 img, + .image.is-5by4 .has-ratio, .image.is-4by3 img, + .image.is-4by3 .has-ratio, .image.is-3by2 img, + .image.is-3by2 .has-ratio, .image.is-5by3 img, + .image.is-5by3 .has-ratio, .image.is-16by9 img, + .image.is-16by9 .has-ratio, .image.is-2by1 img, + .image.is-2by1 .has-ratio, .image.is-3by1 img, + .image.is-3by1 .has-ratio, .image.is-4by5 img, + .image.is-4by5 .has-ratio, .image.is-3by4 img, + .image.is-3by4 .has-ratio, .image.is-2by3 img, + .image.is-2by3 .has-ratio, .image.is-3by5 img, + .image.is-3by5 .has-ratio, .image.is-9by16 img, + .image.is-9by16 .has-ratio, .image.is-1by2 img, + .image.is-1by2 .has-ratio, .image.is-1by3 img, + .image.is-1by3 .has-ratio { + height: 100%; + width: 100%; } + .image.is-square, .image.is-1by1 { + padding-top: 100%; } + .image.is-5by4 { + padding-top: 80%; } + .image.is-4by3 { + padding-top: 75%; } + .image.is-3by2 { + padding-top: 66.6666%; } + .image.is-5by3 { + padding-top: 60%; } + .image.is-16by9 { + padding-top: 56.25%; } + .image.is-2by1 { + padding-top: 50%; } + .image.is-3by1 { + padding-top: 33.3333%; } + .image.is-4by5 { + padding-top: 125%; } + .image.is-3by4 { + padding-top: 133.3333%; } + .image.is-2by3 { + padding-top: 150%; } + .image.is-3by5 { + padding-top: 166.6666%; } + .image.is-9by16 { + padding-top: 177.7777%; } + .image.is-1by2 { + padding-top: 200%; } + .image.is-1by3 { + padding-top: 300%; } + .image.is-16x16 { + height: 16px; + width: 16px; } + .image.is-24x24 { + height: 24px; + width: 24px; } + .image.is-32x32 { + height: 32px; + width: 32px; } + .image.is-48x48 { + height: 48px; + width: 48px; } + .image.is-64x64 { + height: 64px; + width: 64px; } + .image.is-96x96 { + height: 96px; + width: 96px; } + .image.is-128x128 { + height: 128px; + width: 128px; } + +.notification { + background-color: whitesmoke; + border-radius: 4px; + padding: 1.25rem 2.5rem 1.25rem 1.5rem; + position: relative; } + .notification a:not(.button):not(.dropdown-item) { + color: currentColor; + text-decoration: underline; } + .notification strong { + color: currentColor; } + .notification code, + .notification pre { + background: white; } + .notification pre code { + background: transparent; } + .notification > .delete { + position: absolute; + right: 0.5rem; + top: 0.5rem; } + .notification .title, + .notification .subtitle, + .notification .content { + color: currentColor; } + .notification.is-white { + background-color: white; + color: #0a0a0a; } + .notification.is-black { + background-color: #0a0a0a; + color: white; } + .notification.is-light { + background-color: whitesmoke; + color: rgba(0, 0, 0, 0.7); } + .notification.is-dark { + background-color: #363636; + color: #fff; } + .notification.is-primary { + background-color: #00d1b2; + color: #fff; } + .notification.is-link { + background-color: #3273dc; + color: #fff; } + .notification.is-info { + background-color: #3298dc; + color: #fff; } + .notification.is-success { + background-color: #48c774; + color: #fff; } + .notification.is-warning { + background-color: #ffdd57; + color: rgba(0, 0, 0, 0.7); } + .notification.is-danger { + background-color: #f14668; + color: #fff; } + +.progress { + -moz-appearance: none; + -webkit-appearance: none; + border: none; + border-radius: 290486px; + display: block; + height: 1rem; + overflow: hidden; + padding: 0; + width: 100%; } + .progress::-webkit-progress-bar { + background-color: #ededed; } + .progress::-webkit-progress-value { + background-color: #4a4a4a; } + .progress::-moz-progress-bar { + background-color: #4a4a4a; } + .progress::-ms-fill { + background-color: #4a4a4a; + border: none; } + .progress.is-white::-webkit-progress-value { + background-color: white; } + .progress.is-white::-moz-progress-bar { + background-color: white; } + .progress.is-white::-ms-fill { + background-color: white; } + .progress.is-white:indeterminate { + background-image: linear-gradient(to right, white 30%, #ededed 30%); } + .progress.is-black::-webkit-progress-value { + background-color: #0a0a0a; } + .progress.is-black::-moz-progress-bar { + background-color: #0a0a0a; } + .progress.is-black::-ms-fill { + background-color: #0a0a0a; } + .progress.is-black:indeterminate { + background-image: linear-gradient(to right, #0a0a0a 30%, #ededed 30%); } + .progress.is-light::-webkit-progress-value { + background-color: whitesmoke; } + .progress.is-light::-moz-progress-bar { + background-color: whitesmoke; } + .progress.is-light::-ms-fill { + background-color: whitesmoke; } + .progress.is-light:indeterminate { + background-image: linear-gradient(to right, whitesmoke 30%, #ededed 30%); } + .progress.is-dark::-webkit-progress-value { + background-color: #363636; } + .progress.is-dark::-moz-progress-bar { + background-color: #363636; } + .progress.is-dark::-ms-fill { + background-color: #363636; } + .progress.is-dark:indeterminate { + background-image: linear-gradient(to right, #363636 30%, #ededed 30%); } + .progress.is-primary::-webkit-progress-value { + background-color: #00d1b2; } + .progress.is-primary::-moz-progress-bar { + background-color: #00d1b2; } + .progress.is-primary::-ms-fill { + background-color: #00d1b2; } + .progress.is-primary:indeterminate { + background-image: linear-gradient(to right, #00d1b2 30%, #ededed 30%); } + .progress.is-link::-webkit-progress-value { + background-color: #3273dc; } + .progress.is-link::-moz-progress-bar { + background-color: #3273dc; } + .progress.is-link::-ms-fill { + background-color: #3273dc; } + .progress.is-link:indeterminate { + background-image: linear-gradient(to right, #3273dc 30%, #ededed 30%); } + .progress.is-info::-webkit-progress-value { + background-color: #3298dc; } + .progress.is-info::-moz-progress-bar { + background-color: #3298dc; } + .progress.is-info::-ms-fill { + background-color: #3298dc; } + .progress.is-info:indeterminate { + background-image: linear-gradient(to right, #3298dc 30%, #ededed 30%); } + .progress.is-success::-webkit-progress-value { + background-color: #48c774; } + .progress.is-success::-moz-progress-bar { + background-color: #48c774; } + .progress.is-success::-ms-fill { + background-color: #48c774; } + .progress.is-success:indeterminate { + background-image: linear-gradient(to right, #48c774 30%, #ededed 30%); } + .progress.is-warning::-webkit-progress-value { + background-color: #ffdd57; } + .progress.is-warning::-moz-progress-bar { + background-color: #ffdd57; } + .progress.is-warning::-ms-fill { + background-color: #ffdd57; } + .progress.is-warning:indeterminate { + background-image: linear-gradient(to right, #ffdd57 30%, #ededed 30%); } + .progress.is-danger::-webkit-progress-value { + background-color: #f14668; } + .progress.is-danger::-moz-progress-bar { + background-color: #f14668; } + .progress.is-danger::-ms-fill { + background-color: #f14668; } + .progress.is-danger:indeterminate { + background-image: linear-gradient(to right, #f14668 30%, #ededed 30%); } + .progress:indeterminate { + animation-duration: 1.5s; + animation-iteration-count: infinite; + animation-name: moveIndeterminate; + animation-timing-function: linear; + background-color: #ededed; + background-image: linear-gradient(to right, #4a4a4a 30%, #ededed 30%); + background-position: top left; + background-repeat: no-repeat; + background-size: 150% 150%; } + .progress:indeterminate::-webkit-progress-bar { + background-color: transparent; } + .progress:indeterminate::-moz-progress-bar { + background-color: transparent; } + .progress.is-small { + height: 0.75rem; } + .progress.is-medium { + height: 1.25rem; } + .progress.is-large { + height: 1.5rem; } + +@keyframes moveIndeterminate { + from { + background-position: 200% 0; } + to { + background-position: -200% 0; } } + +.table { + background-color: white; + color: #363636; } + .table td, + .table th { + border: 1px solid #dbdbdb; + border-width: 0 0 1px; + padding: 0.5em 0.75em; + vertical-align: top; } + .table td.is-white, + .table th.is-white { + background-color: white; + border-color: white; + color: #0a0a0a; } + .table td.is-black, + .table th.is-black { + background-color: #0a0a0a; + border-color: #0a0a0a; + color: white; } + .table td.is-light, + .table th.is-light { + background-color: whitesmoke; + border-color: whitesmoke; + color: rgba(0, 0, 0, 0.7); } + .table td.is-dark, + .table th.is-dark { + background-color: #363636; + border-color: #363636; + color: #fff; } + .table td.is-primary, + .table th.is-primary { + background-color: #00d1b2; + border-color: #00d1b2; + color: #fff; } + .table td.is-link, + .table th.is-link { + background-color: #3273dc; + border-color: #3273dc; + color: #fff; } + .table td.is-info, + .table th.is-info { + background-color: #3298dc; + border-color: #3298dc; + color: #fff; } + .table td.is-success, + .table th.is-success { + background-color: #48c774; + border-color: #48c774; + color: #fff; } + .table td.is-warning, + .table th.is-warning { + background-color: #ffdd57; + border-color: #ffdd57; + color: rgba(0, 0, 0, 0.7); } + .table td.is-danger, + .table th.is-danger { + background-color: #f14668; + border-color: #f14668; + color: #fff; } + .table td.is-narrow, + .table th.is-narrow { + white-space: nowrap; + width: 1%; } + .table td.is-selected, + .table th.is-selected { + background-color: #00d1b2; + color: #fff; } + .table td.is-selected a, + .table td.is-selected strong, + .table th.is-selected a, + .table th.is-selected strong { + color: currentColor; } + .table th { + color: #363636; } + .table th:not([align]) { + text-align: left; } + .table tr.is-selected { + background-color: #00d1b2; + color: #fff; } + .table tr.is-selected a, + .table tr.is-selected strong { + color: currentColor; } + .table tr.is-selected td, + .table tr.is-selected th { + border-color: #fff; + color: currentColor; } + .table thead { + background-color: transparent; } + .table thead td, + .table thead th { + border-width: 0 0 2px; + color: #363636; } + .table tfoot { + background-color: transparent; } + .table tfoot td, + .table tfoot th { + border-width: 2px 0 0; + color: #363636; } + .table tbody { + background-color: transparent; } + .table tbody tr:last-child td, + .table tbody tr:last-child th { + border-bottom-width: 0; } + .table.is-bordered td, + .table.is-bordered th { + border-width: 1px; } + .table.is-bordered tr:last-child td, + .table.is-bordered tr:last-child th { + border-bottom-width: 1px; } + .table.is-fullwidth { + width: 100%; } + .table.is-hoverable tbody tr:not(.is-selected):hover { + background-color: #fafafa; } + .table.is-hoverable.is-striped tbody tr:not(.is-selected):hover { + background-color: #fafafa; } + .table.is-hoverable.is-striped tbody tr:not(.is-selected):hover:nth-child(even) { + background-color: whitesmoke; } + .table.is-narrow td, + .table.is-narrow th { + padding: 0.25em 0.5em; } + .table.is-striped tbody tr:not(.is-selected):nth-child(even) { + background-color: #fafafa; } + +.table-container { + -webkit-overflow-scrolling: touch; + overflow: auto; + overflow-y: hidden; + max-width: 100%; } + +.tags { + align-items: center; + display: flex; + flex-wrap: wrap; + justify-content: flex-start; } + .tags .tag { + margin-bottom: 0.5rem; } + .tags .tag:not(:last-child) { + margin-right: 0.5rem; } + .tags:last-child { + margin-bottom: -0.5rem; } + .tags:not(:last-child) { + margin-bottom: 1rem; } + .tags.are-medium .tag:not(.is-normal):not(.is-large) { + font-size: 1rem; } + .tags.are-large .tag:not(.is-normal):not(.is-medium) { + font-size: 1.25rem; } + .tags.is-centered { + justify-content: center; } + .tags.is-centered .tag { + margin-right: 0.25rem; + margin-left: 0.25rem; } + .tags.is-right { + justify-content: flex-end; } + .tags.is-right .tag:not(:first-child) { + margin-left: 0.5rem; } + .tags.is-right .tag:not(:last-child) { + margin-right: 0; } + .tags.has-addons .tag { + margin-right: 0; } + .tags.has-addons .tag:not(:first-child) { + margin-left: 0; + border-bottom-left-radius: 0; + border-top-left-radius: 0; } + .tags.has-addons .tag:not(:last-child) { + border-bottom-right-radius: 0; + border-top-right-radius: 0; } + +.tag:not(body) { + align-items: center; + background-color: whitesmoke; + border-radius: 4px; + color: #4a4a4a; + display: inline-flex; + font-size: 0.75rem; + height: 2em; + justify-content: center; + line-height: 1.5; + padding-left: 0.75em; + padding-right: 0.75em; + white-space: nowrap; } + .tag:not(body) .delete { + margin-left: 0.25rem; + margin-right: -0.375rem; } + .tag:not(body).is-white { + background-color: white; + color: #0a0a0a; } + .tag:not(body).is-black { + background-color: #0a0a0a; + color: white; } + .tag:not(body).is-light { + background-color: whitesmoke; + color: rgba(0, 0, 0, 0.7); } + .tag:not(body).is-dark { + background-color: #363636; + color: #fff; } + .tag:not(body).is-primary { + background-color: #00d1b2; + color: #fff; } + .tag:not(body).is-primary.is-light { + background-color: #ebfffc; + color: #00947e; } + .tag:not(body).is-link { + background-color: #3273dc; + color: #fff; } + .tag:not(body).is-link.is-light { + background-color: #eef3fc; + color: #2160c4; } + .tag:not(body).is-info { + background-color: #3298dc; + color: #fff; } + .tag:not(body).is-info.is-light { + background-color: #eef6fc; + color: #1d72aa; } + .tag:not(body).is-success { + background-color: #48c774; + color: #fff; } + .tag:not(body).is-success.is-light { + background-color: #effaf3; + color: #257942; } + .tag:not(body).is-warning { + background-color: #ffdd57; + color: rgba(0, 0, 0, 0.7); } + .tag:not(body).is-warning.is-light { + background-color: #fffbeb; + color: #947600; } + .tag:not(body).is-danger { + background-color: #f14668; + color: #fff; } + .tag:not(body).is-danger.is-light { + background-color: #feecf0; + color: #cc0f35; } + .tag:not(body).is-normal { + font-size: 0.75rem; } + .tag:not(body).is-medium { + font-size: 1rem; } + .tag:not(body).is-large { + font-size: 1.25rem; } + .tag:not(body) .icon:first-child:not(:last-child) { + margin-left: -0.375em; + margin-right: 0.1875em; } + .tag:not(body) .icon:last-child:not(:first-child) { + margin-left: 0.1875em; + margin-right: -0.375em; } + .tag:not(body) .icon:first-child:last-child { + margin-left: -0.375em; + margin-right: -0.375em; } + .tag:not(body).is-delete { + margin-left: 1px; + padding: 0; + position: relative; + width: 2em; } + .tag:not(body).is-delete::before, .tag:not(body).is-delete::after { + background-color: currentColor; + content: ""; + display: block; + left: 50%; + position: absolute; + top: 50%; + transform: translateX(-50%) translateY(-50%) rotate(45deg); + transform-origin: center center; } + .tag:not(body).is-delete::before { + height: 1px; + width: 50%; } + .tag:not(body).is-delete::after { + height: 50%; + width: 1px; } + .tag:not(body).is-delete:hover, .tag:not(body).is-delete:focus { + background-color: #e8e8e8; } + .tag:not(body).is-delete:active { + background-color: #dbdbdb; } + .tag:not(body).is-rounded { + border-radius: 290486px; } + +a.tag:hover { + text-decoration: underline; } + +.title, +.subtitle { + word-break: break-word; } + .title em, + .title span, + .subtitle em, + .subtitle span { + font-weight: inherit; } + .title sub, + .subtitle sub { + font-size: 0.75em; } + .title sup, + .subtitle sup { + font-size: 0.75em; } + .title .tag, + .subtitle .tag { + vertical-align: middle; } + +.title { + color: #363636; + font-size: 2rem; + font-weight: 600; + line-height: 1.125; } + .title strong { + color: inherit; + font-weight: inherit; } + .title + .highlight { + margin-top: -0.75rem; } + .title:not(.is-spaced) + .subtitle { + margin-top: -1.25rem; } + .title.is-1 { + font-size: 3rem; } + .title.is-2 { + font-size: 2.5rem; } + .title.is-3 { + font-size: 2rem; } + .title.is-4 { + font-size: 1.5rem; } + .title.is-5 { + font-size: 1.25rem; } + .title.is-6 { + font-size: 1rem; } + .title.is-7 { + font-size: 0.75rem; } + +.subtitle { + color: #4a4a4a; + font-size: 1.25rem; + font-weight: 400; + line-height: 1.25; } + .subtitle strong { + color: #363636; + font-weight: 600; } + .subtitle:not(.is-spaced) + .title { + margin-top: -1.25rem; } + .subtitle.is-1 { + font-size: 3rem; } + .subtitle.is-2 { + font-size: 2.5rem; } + .subtitle.is-3 { + font-size: 2rem; } + .subtitle.is-4 { + font-size: 1.5rem; } + .subtitle.is-5 { + font-size: 1.25rem; } + .subtitle.is-6 { + font-size: 1rem; } + .subtitle.is-7 { + font-size: 0.75rem; } + +.heading { + display: block; + font-size: 11px; + letter-spacing: 1px; + margin-bottom: 5px; + text-transform: uppercase; } + +.highlight { + font-weight: 400; + max-width: 100%; + overflow: hidden; + padding: 0; } + .highlight pre { + overflow: auto; + max-width: 100%; } + +.number { + align-items: center; + background-color: whitesmoke; + border-radius: 290486px; + display: inline-flex; + font-size: 1.25rem; + height: 2em; + justify-content: center; + margin-right: 1.5rem; + min-width: 2.5em; + padding: 0.25rem 0.5rem; + text-align: center; + vertical-align: top; } + +.input, .textarea, .select select { + background-color: white; + border-color: #dbdbdb; + border-radius: 4px; + color: #363636; } + .input::-moz-placeholder, .textarea::-moz-placeholder, .select select::-moz-placeholder { + color: rgba(54, 54, 54, 0.3); } + .input::-webkit-input-placeholder, .textarea::-webkit-input-placeholder, .select select::-webkit-input-placeholder { + color: rgba(54, 54, 54, 0.3); } + .input:-moz-placeholder, .textarea:-moz-placeholder, .select select:-moz-placeholder { + color: rgba(54, 54, 54, 0.3); } + .input:-ms-input-placeholder, .textarea:-ms-input-placeholder, .select select:-ms-input-placeholder { + color: rgba(54, 54, 54, 0.3); } + .input:hover, .textarea:hover, .select select:hover, .is-hovered.input, .is-hovered.textarea, .select select.is-hovered { + border-color: #b5b5b5; } + .input:focus, .textarea:focus, .select select:focus, .is-focused.input, .is-focused.textarea, .select select.is-focused, .input:active, .textarea:active, .select select:active, .is-active.input, .is-active.textarea, .select select.is-active { + border-color: #3273dc; + box-shadow: 0 0 0 0.125em rgba(50, 115, 220, 0.25); } + .input[disabled], .textarea[disabled], .select select[disabled], + fieldset[disabled] .input, + fieldset[disabled] .textarea, + fieldset[disabled] .select select, + .select fieldset[disabled] select { + background-color: whitesmoke; + border-color: whitesmoke; + box-shadow: none; + color: #7a7a7a; } + .input[disabled]::-moz-placeholder, .textarea[disabled]::-moz-placeholder, .select select[disabled]::-moz-placeholder, + fieldset[disabled] .input::-moz-placeholder, + fieldset[disabled] .textarea::-moz-placeholder, + fieldset[disabled] .select select::-moz-placeholder, + .select fieldset[disabled] select::-moz-placeholder { + color: rgba(122, 122, 122, 0.3); } + .input[disabled]::-webkit-input-placeholder, .textarea[disabled]::-webkit-input-placeholder, .select select[disabled]::-webkit-input-placeholder, + fieldset[disabled] .input::-webkit-input-placeholder, + fieldset[disabled] .textarea::-webkit-input-placeholder, + fieldset[disabled] .select select::-webkit-input-placeholder, + .select fieldset[disabled] select::-webkit-input-placeholder { + color: rgba(122, 122, 122, 0.3); } + .input[disabled]:-moz-placeholder, .textarea[disabled]:-moz-placeholder, .select select[disabled]:-moz-placeholder, + fieldset[disabled] .input:-moz-placeholder, + fieldset[disabled] .textarea:-moz-placeholder, + fieldset[disabled] .select select:-moz-placeholder, + .select fieldset[disabled] select:-moz-placeholder { + color: rgba(122, 122, 122, 0.3); } + .input[disabled]:-ms-input-placeholder, .textarea[disabled]:-ms-input-placeholder, .select select[disabled]:-ms-input-placeholder, + fieldset[disabled] .input:-ms-input-placeholder, + fieldset[disabled] .textarea:-ms-input-placeholder, + fieldset[disabled] .select select:-ms-input-placeholder, + .select fieldset[disabled] select:-ms-input-placeholder { + color: rgba(122, 122, 122, 0.3); } + +.input, .textarea { + box-shadow: inset 0 0.0625em 0.125em rgba(10, 10, 10, 0.05); + max-width: 100%; + width: 100%; } + .input[readonly], .textarea[readonly] { + box-shadow: none; } + .is-white.input, .is-white.textarea { + border-color: white; } + .is-white.input:focus, .is-white.textarea:focus, .is-white.is-focused.input, .is-white.is-focused.textarea, .is-white.input:active, .is-white.textarea:active, .is-white.is-active.input, .is-white.is-active.textarea { + box-shadow: 0 0 0 0.125em rgba(255, 255, 255, 0.25); } + .is-black.input, .is-black.textarea { + border-color: #0a0a0a; } + .is-black.input:focus, .is-black.textarea:focus, .is-black.is-focused.input, .is-black.is-focused.textarea, .is-black.input:active, .is-black.textarea:active, .is-black.is-active.input, .is-black.is-active.textarea { + box-shadow: 0 0 0 0.125em rgba(10, 10, 10, 0.25); } + .is-light.input, .is-light.textarea { + border-color: whitesmoke; } + .is-light.input:focus, .is-light.textarea:focus, .is-light.is-focused.input, .is-light.is-focused.textarea, .is-light.input:active, .is-light.textarea:active, .is-light.is-active.input, .is-light.is-active.textarea { + box-shadow: 0 0 0 0.125em rgba(245, 245, 245, 0.25); } + .is-dark.input, .is-dark.textarea { + border-color: #363636; } + .is-dark.input:focus, .is-dark.textarea:focus, .is-dark.is-focused.input, .is-dark.is-focused.textarea, .is-dark.input:active, .is-dark.textarea:active, .is-dark.is-active.input, .is-dark.is-active.textarea { + box-shadow: 0 0 0 0.125em rgba(54, 54, 54, 0.25); } + .is-primary.input, .is-primary.textarea { + border-color: #00d1b2; } + .is-primary.input:focus, .is-primary.textarea:focus, .is-primary.is-focused.input, .is-primary.is-focused.textarea, .is-primary.input:active, .is-primary.textarea:active, .is-primary.is-active.input, .is-primary.is-active.textarea { + box-shadow: 0 0 0 0.125em rgba(0, 209, 178, 0.25); } + .is-link.input, .is-link.textarea { + border-color: #3273dc; } + .is-link.input:focus, .is-link.textarea:focus, .is-link.is-focused.input, .is-link.is-focused.textarea, .is-link.input:active, .is-link.textarea:active, .is-link.is-active.input, .is-link.is-active.textarea { + box-shadow: 0 0 0 0.125em rgba(50, 115, 220, 0.25); } + .is-info.input, .is-info.textarea { + border-color: #3298dc; } + .is-info.input:focus, .is-info.textarea:focus, .is-info.is-focused.input, .is-info.is-focused.textarea, .is-info.input:active, .is-info.textarea:active, .is-info.is-active.input, .is-info.is-active.textarea { + box-shadow: 0 0 0 0.125em rgba(50, 152, 220, 0.25); } + .is-success.input, .is-success.textarea { + border-color: #48c774; } + .is-success.input:focus, .is-success.textarea:focus, .is-success.is-focused.input, .is-success.is-focused.textarea, .is-success.input:active, .is-success.textarea:active, .is-success.is-active.input, .is-success.is-active.textarea { + box-shadow: 0 0 0 0.125em rgba(72, 199, 116, 0.25); } + .is-warning.input, .is-warning.textarea { + border-color: #ffdd57; } + .is-warning.input:focus, .is-warning.textarea:focus, .is-warning.is-focused.input, .is-warning.is-focused.textarea, .is-warning.input:active, .is-warning.textarea:active, .is-warning.is-active.input, .is-warning.is-active.textarea { + box-shadow: 0 0 0 0.125em rgba(255, 221, 87, 0.25); } + .is-danger.input, .is-danger.textarea { + border-color: #f14668; } + .is-danger.input:focus, .is-danger.textarea:focus, .is-danger.is-focused.input, .is-danger.is-focused.textarea, .is-danger.input:active, .is-danger.textarea:active, .is-danger.is-active.input, .is-danger.is-active.textarea { + box-shadow: 0 0 0 0.125em rgba(241, 70, 104, 0.25); } + .is-small.input, .is-small.textarea { + border-radius: 2px; + font-size: 0.75rem; } + .is-medium.input, .is-medium.textarea { + font-size: 1.25rem; } + .is-large.input, .is-large.textarea { + font-size: 1.5rem; } + .is-fullwidth.input, .is-fullwidth.textarea { + display: block; + width: 100%; } + .is-inline.input, .is-inline.textarea { + display: inline; + width: auto; } + +.input.is-rounded { + border-radius: 290486px; + padding-left: calc(calc(0.75em - 1px) + 0.375em); + padding-right: calc(calc(0.75em - 1px) + 0.375em); } + +.input.is-static { + background-color: transparent; + border-color: transparent; + box-shadow: none; + padding-left: 0; + padding-right: 0; } + +.textarea { + display: block; + max-width: 100%; + min-width: 100%; + padding: calc(0.75em - 1px); + resize: vertical; } + .textarea:not([rows]) { + max-height: 40em; + min-height: 8em; } + .textarea[rows] { + height: initial; } + .textarea.has-fixed-size { + resize: none; } + +.checkbox, .radio { + cursor: pointer; + display: inline-block; + line-height: 1.25; + position: relative; } + .checkbox input, .radio input { + cursor: pointer; } + .checkbox:hover, .radio:hover { + color: #363636; } + .checkbox[disabled], .radio[disabled], + fieldset[disabled] .checkbox, + fieldset[disabled] .radio { + color: #7a7a7a; + cursor: not-allowed; } + +.radio + .radio { + margin-left: 0.5em; } + +.select { + display: inline-block; + max-width: 100%; + position: relative; + vertical-align: top; } + .select:not(.is-multiple) { + height: 2.5em; } + .select:not(.is-multiple):not(.is-loading)::after { + border-color: #3273dc; + right: 1.125em; + z-index: 4; } + .select.is-rounded select { + border-radius: 290486px; + padding-left: 1em; } + .select select { + cursor: pointer; + display: block; + font-size: 1em; + max-width: 100%; + outline: none; } + .select select::-ms-expand { + display: none; } + .select select[disabled]:hover, + fieldset[disabled] .select select:hover { + border-color: whitesmoke; } + .select select:not([multiple]) { + padding-right: 2.5em; } + .select select[multiple] { + height: auto; + padding: 0; } + .select select[multiple] option { + padding: 0.5em 1em; } + .select:not(.is-multiple):not(.is-loading):hover::after { + border-color: #363636; } + .select.is-white:not(:hover)::after { + border-color: white; } + .select.is-white select { + border-color: white; } + .select.is-white select:hover, .select.is-white select.is-hovered { + border-color: #f2f2f2; } + .select.is-white select:focus, .select.is-white select.is-focused, .select.is-white select:active, .select.is-white select.is-active { + box-shadow: 0 0 0 0.125em rgba(255, 255, 255, 0.25); } + .select.is-black:not(:hover)::after { + border-color: #0a0a0a; } + .select.is-black select { + border-color: #0a0a0a; } + .select.is-black select:hover, .select.is-black select.is-hovered { + border-color: black; } + .select.is-black select:focus, .select.is-black select.is-focused, .select.is-black select:active, .select.is-black select.is-active { + box-shadow: 0 0 0 0.125em rgba(10, 10, 10, 0.25); } + .select.is-light:not(:hover)::after { + border-color: whitesmoke; } + .select.is-light select { + border-color: whitesmoke; } + .select.is-light select:hover, .select.is-light select.is-hovered { + border-color: #e8e8e8; } + .select.is-light select:focus, .select.is-light select.is-focused, .select.is-light select:active, .select.is-light select.is-active { + box-shadow: 0 0 0 0.125em rgba(245, 245, 245, 0.25); } + .select.is-dark:not(:hover)::after { + border-color: #363636; } + .select.is-dark select { + border-color: #363636; } + .select.is-dark select:hover, .select.is-dark select.is-hovered { + border-color: #292929; } + .select.is-dark select:focus, .select.is-dark select.is-focused, .select.is-dark select:active, .select.is-dark select.is-active { + box-shadow: 0 0 0 0.125em rgba(54, 54, 54, 0.25); } + .select.is-primary:not(:hover)::after { + border-color: #00d1b2; } + .select.is-primary select { + border-color: #00d1b2; } + .select.is-primary select:hover, .select.is-primary select.is-hovered { + border-color: #00b89c; } + .select.is-primary select:focus, .select.is-primary select.is-focused, .select.is-primary select:active, .select.is-primary select.is-active { + box-shadow: 0 0 0 0.125em rgba(0, 209, 178, 0.25); } + .select.is-link:not(:hover)::after { + border-color: #3273dc; } + .select.is-link select { + border-color: #3273dc; } + .select.is-link select:hover, .select.is-link select.is-hovered { + border-color: #2366d1; } + .select.is-link select:focus, .select.is-link select.is-focused, .select.is-link select:active, .select.is-link select.is-active { + box-shadow: 0 0 0 0.125em rgba(50, 115, 220, 0.25); } + .select.is-info:not(:hover)::after { + border-color: #3298dc; } + .select.is-info select { + border-color: #3298dc; } + .select.is-info select:hover, .select.is-info select.is-hovered { + border-color: #238cd1; } + .select.is-info select:focus, .select.is-info select.is-focused, .select.is-info select:active, .select.is-info select.is-active { + box-shadow: 0 0 0 0.125em rgba(50, 152, 220, 0.25); } + .select.is-success:not(:hover)::after { + border-color: #48c774; } + .select.is-success select { + border-color: #48c774; } + .select.is-success select:hover, .select.is-success select.is-hovered { + border-color: #3abb67; } + .select.is-success select:focus, .select.is-success select.is-focused, .select.is-success select:active, .select.is-success select.is-active { + box-shadow: 0 0 0 0.125em rgba(72, 199, 116, 0.25); } + .select.is-warning:not(:hover)::after { + border-color: #ffdd57; } + .select.is-warning select { + border-color: #ffdd57; } + .select.is-warning select:hover, .select.is-warning select.is-hovered { + border-color: #ffd83d; } + .select.is-warning select:focus, .select.is-warning select.is-focused, .select.is-warning select:active, .select.is-warning select.is-active { + box-shadow: 0 0 0 0.125em rgba(255, 221, 87, 0.25); } + .select.is-danger:not(:hover)::after { + border-color: #f14668; } + .select.is-danger select { + border-color: #f14668; } + .select.is-danger select:hover, .select.is-danger select.is-hovered { + border-color: #ef2e55; } + .select.is-danger select:focus, .select.is-danger select.is-focused, .select.is-danger select:active, .select.is-danger select.is-active { + box-shadow: 0 0 0 0.125em rgba(241, 70, 104, 0.25); } + .select.is-small { + border-radius: 2px; + font-size: 0.75rem; } + .select.is-medium { + font-size: 1.25rem; } + .select.is-large { + font-size: 1.5rem; } + .select.is-disabled::after { + border-color: #7a7a7a; } + .select.is-fullwidth { + width: 100%; } + .select.is-fullwidth select { + width: 100%; } + .select.is-loading::after { + margin-top: 0; + position: absolute; + right: 0.625em; + top: 0.625em; + transform: none; } + .select.is-loading.is-small:after { + font-size: 0.75rem; } + .select.is-loading.is-medium:after { + font-size: 1.25rem; } + .select.is-loading.is-large:after { + font-size: 1.5rem; } + +.file { + align-items: stretch; + display: flex; + justify-content: flex-start; + position: relative; } + .file.is-white .file-cta { + background-color: white; + border-color: transparent; + color: #0a0a0a; } + .file.is-white:hover .file-cta, .file.is-white.is-hovered .file-cta { + background-color: #f9f9f9; + border-color: transparent; + color: #0a0a0a; } + .file.is-white:focus .file-cta, .file.is-white.is-focused .file-cta { + border-color: transparent; + box-shadow: 0 0 0.5em rgba(255, 255, 255, 0.25); + color: #0a0a0a; } + .file.is-white:active .file-cta, .file.is-white.is-active .file-cta { + background-color: #f2f2f2; + border-color: transparent; + color: #0a0a0a; } + .file.is-black .file-cta { + background-color: #0a0a0a; + border-color: transparent; + color: white; } + .file.is-black:hover .file-cta, .file.is-black.is-hovered .file-cta { + background-color: #040404; + border-color: transparent; + color: white; } + .file.is-black:focus .file-cta, .file.is-black.is-focused .file-cta { + border-color: transparent; + box-shadow: 0 0 0.5em rgba(10, 10, 10, 0.25); + color: white; } + .file.is-black:active .file-cta, .file.is-black.is-active .file-cta { + background-color: black; + border-color: transparent; + color: white; } + .file.is-light .file-cta { + background-color: whitesmoke; + border-color: transparent; + color: rgba(0, 0, 0, 0.7); } + .file.is-light:hover .file-cta, .file.is-light.is-hovered .file-cta { + background-color: #eeeeee; + border-color: transparent; + color: rgba(0, 0, 0, 0.7); } + .file.is-light:focus .file-cta, .file.is-light.is-focused .file-cta { + border-color: transparent; + box-shadow: 0 0 0.5em rgba(245, 245, 245, 0.25); + color: rgba(0, 0, 0, 0.7); } + .file.is-light:active .file-cta, .file.is-light.is-active .file-cta { + background-color: #e8e8e8; + border-color: transparent; + color: rgba(0, 0, 0, 0.7); } + .file.is-dark .file-cta { + background-color: #363636; + border-color: transparent; + color: #fff; } + .file.is-dark:hover .file-cta, .file.is-dark.is-hovered .file-cta { + background-color: #2f2f2f; + border-color: transparent; + color: #fff; } + .file.is-dark:focus .file-cta, .file.is-dark.is-focused .file-cta { + border-color: transparent; + box-shadow: 0 0 0.5em rgba(54, 54, 54, 0.25); + color: #fff; } + .file.is-dark:active .file-cta, .file.is-dark.is-active .file-cta { + background-color: #292929; + border-color: transparent; + color: #fff; } + .file.is-primary .file-cta { + background-color: #00d1b2; + border-color: transparent; + color: #fff; } + .file.is-primary:hover .file-cta, .file.is-primary.is-hovered .file-cta { + background-color: #00c4a7; + border-color: transparent; + color: #fff; } + .file.is-primary:focus .file-cta, .file.is-primary.is-focused .file-cta { + border-color: transparent; + box-shadow: 0 0 0.5em rgba(0, 209, 178, 0.25); + color: #fff; } + .file.is-primary:active .file-cta, .file.is-primary.is-active .file-cta { + background-color: #00b89c; + border-color: transparent; + color: #fff; } + .file.is-link .file-cta { + background-color: #3273dc; + border-color: transparent; + color: #fff; } + .file.is-link:hover .file-cta, .file.is-link.is-hovered .file-cta { + background-color: #276cda; + border-color: transparent; + color: #fff; } + .file.is-link:focus .file-cta, .file.is-link.is-focused .file-cta { + border-color: transparent; + box-shadow: 0 0 0.5em rgba(50, 115, 220, 0.25); + color: #fff; } + .file.is-link:active .file-cta, .file.is-link.is-active .file-cta { + background-color: #2366d1; + border-color: transparent; + color: #fff; } + .file.is-info .file-cta { + background-color: #3298dc; + border-color: transparent; + color: #fff; } + .file.is-info:hover .file-cta, .file.is-info.is-hovered .file-cta { + background-color: #2793da; + border-color: transparent; + color: #fff; } + .file.is-info:focus .file-cta, .file.is-info.is-focused .file-cta { + border-color: transparent; + box-shadow: 0 0 0.5em rgba(50, 152, 220, 0.25); + color: #fff; } + .file.is-info:active .file-cta, .file.is-info.is-active .file-cta { + background-color: #238cd1; + border-color: transparent; + color: #fff; } + .file.is-success .file-cta { + background-color: #48c774; + border-color: transparent; + color: #fff; } + .file.is-success:hover .file-cta, .file.is-success.is-hovered .file-cta { + background-color: #3ec46d; + border-color: transparent; + color: #fff; } + .file.is-success:focus .file-cta, .file.is-success.is-focused .file-cta { + border-color: transparent; + box-shadow: 0 0 0.5em rgba(72, 199, 116, 0.25); + color: #fff; } + .file.is-success:active .file-cta, .file.is-success.is-active .file-cta { + background-color: #3abb67; + border-color: transparent; + color: #fff; } + .file.is-warning .file-cta { + background-color: #ffdd57; + border-color: transparent; + color: rgba(0, 0, 0, 0.7); } + .file.is-warning:hover .file-cta, .file.is-warning.is-hovered .file-cta { + background-color: #ffdb4a; + border-color: transparent; + color: rgba(0, 0, 0, 0.7); } + .file.is-warning:focus .file-cta, .file.is-warning.is-focused .file-cta { + border-color: transparent; + box-shadow: 0 0 0.5em rgba(255, 221, 87, 0.25); + color: rgba(0, 0, 0, 0.7); } + .file.is-warning:active .file-cta, .file.is-warning.is-active .file-cta { + background-color: #ffd83d; + border-color: transparent; + color: rgba(0, 0, 0, 0.7); } + .file.is-danger .file-cta { + background-color: #f14668; + border-color: transparent; + color: #fff; } + .file.is-danger:hover .file-cta, .file.is-danger.is-hovered .file-cta { + background-color: #f03a5f; + border-color: transparent; + color: #fff; } + .file.is-danger:focus .file-cta, .file.is-danger.is-focused .file-cta { + border-color: transparent; + box-shadow: 0 0 0.5em rgba(241, 70, 104, 0.25); + color: #fff; } + .file.is-danger:active .file-cta, .file.is-danger.is-active .file-cta { + background-color: #ef2e55; + border-color: transparent; + color: #fff; } + .file.is-small { + font-size: 0.75rem; } + .file.is-medium { + font-size: 1.25rem; } + .file.is-medium .file-icon .fa { + font-size: 21px; } + .file.is-large { + font-size: 1.5rem; } + .file.is-large .file-icon .fa { + font-size: 28px; } + .file.has-name .file-cta { + border-bottom-right-radius: 0; + border-top-right-radius: 0; } + .file.has-name .file-name { + border-bottom-left-radius: 0; + border-top-left-radius: 0; } + .file.has-name.is-empty .file-cta { + border-radius: 4px; } + .file.has-name.is-empty .file-name { + display: none; } + .file.is-boxed .file-label { + flex-direction: column; } + .file.is-boxed .file-cta { + flex-direction: column; + height: auto; + padding: 1em 3em; } + .file.is-boxed .file-name { + border-width: 0 1px 1px; } + .file.is-boxed .file-icon { + height: 1.5em; + width: 1.5em; } + .file.is-boxed .file-icon .fa { + font-size: 21px; } + .file.is-boxed.is-small .file-icon .fa { + font-size: 14px; } + .file.is-boxed.is-medium .file-icon .fa { + font-size: 28px; } + .file.is-boxed.is-large .file-icon .fa { + font-size: 35px; } + .file.is-boxed.has-name .file-cta { + border-radius: 4px 4px 0 0; } + .file.is-boxed.has-name .file-name { + border-radius: 0 0 4px 4px; + border-width: 0 1px 1px; } + .file.is-centered { + justify-content: center; } + .file.is-fullwidth .file-label { + width: 100%; } + .file.is-fullwidth .file-name { + flex-grow: 1; + max-width: none; } + .file.is-right { + justify-content: flex-end; } + .file.is-right .file-cta { + border-radius: 0 4px 4px 0; } + .file.is-right .file-name { + border-radius: 4px 0 0 4px; + border-width: 1px 0 1px 1px; + order: -1; } + +.file-label { + align-items: stretch; + display: flex; + cursor: pointer; + justify-content: flex-start; + overflow: hidden; + position: relative; } + .file-label:hover .file-cta { + background-color: #eeeeee; + color: #363636; } + .file-label:hover .file-name { + border-color: #d5d5d5; } + .file-label:active .file-cta { + background-color: #e8e8e8; + color: #363636; } + .file-label:active .file-name { + border-color: #cfcfcf; } + +.file-input { + height: 100%; + left: 0; + opacity: 0; + outline: none; + position: absolute; + top: 0; + width: 100%; } + +.file-cta, +.file-name { + border-color: #dbdbdb; + border-radius: 4px; + font-size: 1em; + padding-left: 1em; + padding-right: 1em; + white-space: nowrap; } + +.file-cta { + background-color: whitesmoke; + color: #4a4a4a; } + +.file-name { + border-color: #dbdbdb; + border-style: solid; + border-width: 1px 1px 1px 0; + display: block; + max-width: 16em; + overflow: hidden; + text-align: left; + text-overflow: ellipsis; } + +.file-icon { + align-items: center; + display: flex; + height: 1em; + justify-content: center; + margin-right: 0.5em; + width: 1em; } + .file-icon .fa { + font-size: 14px; } + +.label { + color: #363636; + display: block; + font-size: 1rem; + font-weight: 700; } + .label:not(:last-child) { + margin-bottom: 0.5em; } + .label.is-small { + font-size: 0.75rem; } + .label.is-medium { + font-size: 1.25rem; } + .label.is-large { + font-size: 1.5rem; } + +.help { + display: block; + font-size: 0.75rem; + margin-top: 0.25rem; } + .help.is-white { + color: white; } + .help.is-black { + color: #0a0a0a; } + .help.is-light { + color: whitesmoke; } + .help.is-dark { + color: #363636; } + .help.is-primary { + color: #00d1b2; } + .help.is-link { + color: #3273dc; } + .help.is-info { + color: #3298dc; } + .help.is-success { + color: #48c774; } + .help.is-warning { + color: #ffdd57; } + .help.is-danger { + color: #f14668; } + +.field:not(:last-child) { + margin-bottom: 0.75rem; } + +.field.has-addons { + display: flex; + justify-content: flex-start; } + .field.has-addons .control:not(:last-child) { + margin-right: -1px; } + .field.has-addons .control:not(:first-child):not(:last-child) .button, + .field.has-addons .control:not(:first-child):not(:last-child) .input, + .field.has-addons .control:not(:first-child):not(:last-child) .select select { + border-radius: 0; } + .field.has-addons .control:first-child:not(:only-child) .button, + .field.has-addons .control:first-child:not(:only-child) .input, + .field.has-addons .control:first-child:not(:only-child) .select select { + border-bottom-right-radius: 0; + border-top-right-radius: 0; } + .field.has-addons .control:last-child:not(:only-child) .button, + .field.has-addons .control:last-child:not(:only-child) .input, + .field.has-addons .control:last-child:not(:only-child) .select select { + border-bottom-left-radius: 0; + border-top-left-radius: 0; } + .field.has-addons .control .button:not([disabled]):hover, .field.has-addons .control .button:not([disabled]).is-hovered, + .field.has-addons .control .input:not([disabled]):hover, + .field.has-addons .control .input:not([disabled]).is-hovered, + .field.has-addons .control .select select:not([disabled]):hover, + .field.has-addons .control .select select:not([disabled]).is-hovered { + z-index: 2; } + .field.has-addons .control .button:not([disabled]):focus, .field.has-addons .control .button:not([disabled]).is-focused, .field.has-addons .control .button:not([disabled]):active, .field.has-addons .control .button:not([disabled]).is-active, + .field.has-addons .control .input:not([disabled]):focus, + .field.has-addons .control .input:not([disabled]).is-focused, + .field.has-addons .control .input:not([disabled]):active, + .field.has-addons .control .input:not([disabled]).is-active, + .field.has-addons .control .select select:not([disabled]):focus, + .field.has-addons .control .select select:not([disabled]).is-focused, + .field.has-addons .control .select select:not([disabled]):active, + .field.has-addons .control .select select:not([disabled]).is-active { + z-index: 3; } + .field.has-addons .control .button:not([disabled]):focus:hover, .field.has-addons .control .button:not([disabled]).is-focused:hover, .field.has-addons .control .button:not([disabled]):active:hover, .field.has-addons .control .button:not([disabled]).is-active:hover, + .field.has-addons .control .input:not([disabled]):focus:hover, + .field.has-addons .control .input:not([disabled]).is-focused:hover, + .field.has-addons .control .input:not([disabled]):active:hover, + .field.has-addons .control .input:not([disabled]).is-active:hover, + .field.has-addons .control .select select:not([disabled]):focus:hover, + .field.has-addons .control .select select:not([disabled]).is-focused:hover, + .field.has-addons .control .select select:not([disabled]):active:hover, + .field.has-addons .control .select select:not([disabled]).is-active:hover { + z-index: 4; } + .field.has-addons .control.is-expanded { + flex-grow: 1; + flex-shrink: 1; } + .field.has-addons.has-addons-centered { + justify-content: center; } + .field.has-addons.has-addons-right { + justify-content: flex-end; } + .field.has-addons.has-addons-fullwidth .control { + flex-grow: 1; + flex-shrink: 0; } + +.field.is-grouped { + display: flex; + justify-content: flex-start; } + .field.is-grouped > .control { + flex-shrink: 0; } + .field.is-grouped > .control:not(:last-child) { + margin-bottom: 0; + margin-right: 0.75rem; } + .field.is-grouped > .control.is-expanded { + flex-grow: 1; + flex-shrink: 1; } + .field.is-grouped.is-grouped-centered { + justify-content: center; } + .field.is-grouped.is-grouped-right { + justify-content: flex-end; } + .field.is-grouped.is-grouped-multiline { + flex-wrap: wrap; } + .field.is-grouped.is-grouped-multiline > .control:last-child, .field.is-grouped.is-grouped-multiline > .control:not(:last-child) { + margin-bottom: 0.75rem; } + .field.is-grouped.is-grouped-multiline:last-child { + margin-bottom: -0.75rem; } + .field.is-grouped.is-grouped-multiline:not(:last-child) { + margin-bottom: 0; } + +@media screen and (min-width: 769px), print { + .field.is-horizontal { + display: flex; } } + +.field-label .label { + font-size: inherit; } + +@media screen and (max-width: 768px) { + .field-label { + margin-bottom: 0.5rem; } } + +@media screen and (min-width: 769px), print { + .field-label { + flex-basis: 0; + flex-grow: 1; + flex-shrink: 0; + margin-right: 1.5rem; + text-align: right; } + .field-label.is-small { + font-size: 0.75rem; + padding-top: 0.375em; } + .field-label.is-normal { + padding-top: 0.375em; } + .field-label.is-medium { + font-size: 1.25rem; + padding-top: 0.375em; } + .field-label.is-large { + font-size: 1.5rem; + padding-top: 0.375em; } } + +.field-body .field .field { + margin-bottom: 0; } + +@media screen and (min-width: 769px), print { + .field-body { + display: flex; + flex-basis: 0; + flex-grow: 5; + flex-shrink: 1; } + .field-body .field { + margin-bottom: 0; } + .field-body > .field { + flex-shrink: 1; } + .field-body > .field:not(.is-narrow) { + flex-grow: 1; } + .field-body > .field:not(:last-child) { + margin-right: 0.75rem; } } + +.control { + box-sizing: border-box; + clear: both; + font-size: 1rem; + position: relative; + text-align: left; } + .control.has-icons-left .input:focus ~ .icon, + .control.has-icons-left .select:focus ~ .icon, .control.has-icons-right .input:focus ~ .icon, + .control.has-icons-right .select:focus ~ .icon { + color: #4a4a4a; } + .control.has-icons-left .input.is-small ~ .icon, + .control.has-icons-left .select.is-small ~ .icon, .control.has-icons-right .input.is-small ~ .icon, + .control.has-icons-right .select.is-small ~ .icon { + font-size: 0.75rem; } + .control.has-icons-left .input.is-medium ~ .icon, + .control.has-icons-left .select.is-medium ~ .icon, .control.has-icons-right .input.is-medium ~ .icon, + .control.has-icons-right .select.is-medium ~ .icon { + font-size: 1.25rem; } + .control.has-icons-left .input.is-large ~ .icon, + .control.has-icons-left .select.is-large ~ .icon, .control.has-icons-right .input.is-large ~ .icon, + .control.has-icons-right .select.is-large ~ .icon { + font-size: 1.5rem; } + .control.has-icons-left .icon, .control.has-icons-right .icon { + color: #dbdbdb; + height: 2.5em; + pointer-events: none; + position: absolute; + top: 0; + width: 2.5em; + z-index: 4; } + .control.has-icons-left .input, + .control.has-icons-left .select select { + padding-left: 2.5em; } + .control.has-icons-left .icon.is-left { + left: 0; } + .control.has-icons-right .input, + .control.has-icons-right .select select { + padding-right: 2.5em; } + .control.has-icons-right .icon.is-right { + right: 0; } + .control.is-loading::after { + position: absolute !important; + right: 0.625em; + top: 0.625em; + z-index: 4; } + .control.is-loading.is-small:after { + font-size: 0.75rem; } + .control.is-loading.is-medium:after { + font-size: 1.25rem; } + .control.is-loading.is-large:after { + font-size: 1.5rem; } + +.breadcrumb { + font-size: 1rem; + white-space: nowrap; } + .breadcrumb a { + align-items: center; + color: #3273dc; + display: flex; + justify-content: center; + padding: 0 0.75em; } + .breadcrumb a:hover { + color: #363636; } + .breadcrumb li { + align-items: center; + display: flex; } + .breadcrumb li:first-child a { + padding-left: 0; } + .breadcrumb li.is-active a { + color: #363636; + cursor: default; + pointer-events: none; } + .breadcrumb li + li::before { + color: #b5b5b5; + content: "\0002f"; } + .breadcrumb ul, + .breadcrumb ol { + align-items: flex-start; + display: flex; + flex-wrap: wrap; + justify-content: flex-start; } + .breadcrumb .icon:first-child { + margin-right: 0.5em; } + .breadcrumb .icon:last-child { + margin-left: 0.5em; } + .breadcrumb.is-centered ol, + .breadcrumb.is-centered ul { + justify-content: center; } + .breadcrumb.is-right ol, + .breadcrumb.is-right ul { + justify-content: flex-end; } + .breadcrumb.is-small { + font-size: 0.75rem; } + .breadcrumb.is-medium { + font-size: 1.25rem; } + .breadcrumb.is-large { + font-size: 1.5rem; } + .breadcrumb.has-arrow-separator li + li::before { + content: "\02192"; } + .breadcrumb.has-bullet-separator li + li::before { + content: "\02022"; } + .breadcrumb.has-dot-separator li + li::before { + content: "\000b7"; } + .breadcrumb.has-succeeds-separator li + li::before { + content: "\0227B"; } + +.card { + background-color: white; + box-shadow: 0 0.5em 1em -0.125em rgba(10, 10, 10, 0.1), 0 0px 0 1px rgba(10, 10, 10, 0.02); + color: #4a4a4a; + max-width: 100%; + position: relative; } + +.card-header { + background-color: transparent; + align-items: stretch; + box-shadow: 0 0.125em 0.25em rgba(10, 10, 10, 0.1); + display: flex; } + +.card-header-title { + align-items: center; + color: #363636; + display: flex; + flex-grow: 1; + font-weight: 700; + padding: 0.75rem 1rem; } + .card-header-title.is-centered { + justify-content: center; } + +.card-header-icon { + align-items: center; + cursor: pointer; + display: flex; + justify-content: center; + padding: 0.75rem 1rem; } + +.card-image { + display: block; + position: relative; } + +.card-content { + background-color: transparent; + padding: 1.5rem; } + +.card-footer { + background-color: transparent; + border-top: 1px solid #ededed; + align-items: stretch; + display: flex; } + +.card-footer-item { + align-items: center; + display: flex; + flex-basis: 0; + flex-grow: 1; + flex-shrink: 0; + justify-content: center; + padding: 0.75rem; } + .card-footer-item:not(:last-child) { + border-right: 1px solid #ededed; } + +.card .media:not(:last-child) { + margin-bottom: 1.5rem; } + +.dropdown { + display: inline-flex; + position: relative; + vertical-align: top; } + .dropdown.is-active .dropdown-menu, .dropdown.is-hoverable:hover .dropdown-menu { + display: block; } + .dropdown.is-right .dropdown-menu { + left: auto; + right: 0; } + .dropdown.is-up .dropdown-menu { + bottom: 100%; + padding-bottom: 4px; + padding-top: initial; + top: auto; } + +.dropdown-menu { + display: none; + left: 0; + min-width: 12rem; + padding-top: 4px; + position: absolute; + top: 100%; + z-index: 20; } + +.dropdown-content { + background-color: white; + border-radius: 4px; + box-shadow: 0 0.5em 1em -0.125em rgba(10, 10, 10, 0.1), 0 0px 0 1px rgba(10, 10, 10, 0.02); + padding-bottom: 0.5rem; + padding-top: 0.5rem; } + +.dropdown-item { + color: #4a4a4a; + display: block; + font-size: 0.875rem; + line-height: 1.5; + padding: 0.375rem 1rem; + position: relative; } + +a.dropdown-item, +button.dropdown-item { + padding-right: 3rem; + text-align: left; + white-space: nowrap; + width: 100%; } + a.dropdown-item:hover, + button.dropdown-item:hover { + background-color: whitesmoke; + color: #0a0a0a; } + a.dropdown-item.is-active, + button.dropdown-item.is-active { + background-color: #3273dc; + color: #fff; } + +.dropdown-divider { + background-color: #ededed; + border: none; + display: block; + height: 1px; + margin: 0.5rem 0; } + +.level { + align-items: center; + justify-content: space-between; } + .level code { + border-radius: 4px; } + .level img { + display: inline-block; + vertical-align: top; } + .level.is-mobile { + display: flex; } + .level.is-mobile .level-left, + .level.is-mobile .level-right { + display: flex; } + .level.is-mobile .level-left + .level-right { + margin-top: 0; } + .level.is-mobile .level-item:not(:last-child) { + margin-bottom: 0; + margin-right: 0.75rem; } + .level.is-mobile .level-item:not(.is-narrow) { + flex-grow: 1; } + @media screen and (min-width: 769px), print { + .level { + display: flex; } + .level > .level-item:not(.is-narrow) { + flex-grow: 1; } } + +.level-item { + align-items: center; + display: flex; + flex-basis: auto; + flex-grow: 0; + flex-shrink: 0; + justify-content: center; } + .level-item .title, + .level-item .subtitle { + margin-bottom: 0; } + @media screen and (max-width: 768px) { + .level-item:not(:last-child) { + margin-bottom: 0.75rem; } } + +.level-left, +.level-right { + flex-basis: auto; + flex-grow: 0; + flex-shrink: 0; } + .level-left .level-item.is-flexible, + .level-right .level-item.is-flexible { + flex-grow: 1; } + @media screen and (min-width: 769px), print { + .level-left .level-item:not(:last-child), + .level-right .level-item:not(:last-child) { + margin-right: 0.75rem; } } + +.level-left { + align-items: center; + justify-content: flex-start; } + @media screen and (max-width: 768px) { + .level-left + .level-right { + margin-top: 1.5rem; } } + @media screen and (min-width: 769px), print { + .level-left { + display: flex; } } + +.level-right { + align-items: center; + justify-content: flex-end; } + @media screen and (min-width: 769px), print { + .level-right { + display: flex; } } + +.list { + background-color: white; + border-radius: 4px; + box-shadow: 0 2px 3px rgba(10, 10, 10, 0.1), 0 0 0 1px rgba(10, 10, 10, 0.1); } + +.list-item { + display: block; + padding: 0.5em 1em; } + .list-item:not(a) { + color: #4a4a4a; } + .list-item:first-child { + border-top-left-radius: 4px; + border-top-right-radius: 4px; } + .list-item:last-child { + border-bottom-left-radius: 4px; + border-bottom-right-radius: 4px; } + .list-item:not(:last-child) { + border-bottom: 1px solid #dbdbdb; } + .list-item.is-active { + background-color: #3273dc; + color: #fff; } + +a.list-item { + background-color: whitesmoke; + cursor: pointer; } + +.media { + align-items: flex-start; + display: flex; + text-align: left; } + .media .content:not(:last-child) { + margin-bottom: 0.75rem; } + .media .media { + border-top: 1px solid rgba(219, 219, 219, 0.5); + display: flex; + padding-top: 0.75rem; } + .media .media .content:not(:last-child), + .media .media .control:not(:last-child) { + margin-bottom: 0.5rem; } + .media .media .media { + padding-top: 0.5rem; } + .media .media .media + .media { + margin-top: 0.5rem; } + .media + .media { + border-top: 1px solid rgba(219, 219, 219, 0.5); + margin-top: 1rem; + padding-top: 1rem; } + .media.is-large + .media { + margin-top: 1.5rem; + padding-top: 1.5rem; } + +.media-left, +.media-right { + flex-basis: auto; + flex-grow: 0; + flex-shrink: 0; } + +.media-left { + margin-right: 1rem; } + +.media-right { + margin-left: 1rem; } + +.media-content { + flex-basis: auto; + flex-grow: 1; + flex-shrink: 1; + text-align: left; } + +@media screen and (max-width: 768px) { + .media-content { + overflow-x: auto; } } + +.menu { + font-size: 1rem; } + .menu.is-small { + font-size: 0.75rem; } + .menu.is-medium { + font-size: 1.25rem; } + .menu.is-large { + font-size: 1.5rem; } + +.menu-list { + line-height: 1.25; } + .menu-list a { + border-radius: 2px; + color: #4a4a4a; + display: block; + padding: 0.5em 0.75em; } + .menu-list a:hover { + background-color: whitesmoke; + color: #363636; } + .menu-list a.is-active { + background-color: #3273dc; + color: #fff; } + .menu-list li ul { + border-left: 1px solid #dbdbdb; + margin: 0.75em; + padding-left: 0.75em; } + +.menu-label { + color: #7a7a7a; + font-size: 0.75em; + letter-spacing: 0.1em; + text-transform: uppercase; } + .menu-label:not(:first-child) { + margin-top: 1em; } + .menu-label:not(:last-child) { + margin-bottom: 1em; } + +.message { + background-color: whitesmoke; + border-radius: 4px; + font-size: 1rem; } + .message strong { + color: currentColor; } + .message a:not(.button):not(.tag):not(.dropdown-item) { + color: currentColor; + text-decoration: underline; } + .message.is-small { + font-size: 0.75rem; } + .message.is-medium { + font-size: 1.25rem; } + .message.is-large { + font-size: 1.5rem; } + .message.is-white { + background-color: white; } + .message.is-white .message-header { + background-color: white; + color: #0a0a0a; } + .message.is-white .message-body { + border-color: white; } + .message.is-black { + background-color: #fafafa; } + .message.is-black .message-header { + background-color: #0a0a0a; + color: white; } + .message.is-black .message-body { + border-color: #0a0a0a; } + .message.is-light { + background-color: #fafafa; } + .message.is-light .message-header { + background-color: whitesmoke; + color: rgba(0, 0, 0, 0.7); } + .message.is-light .message-body { + border-color: whitesmoke; } + .message.is-dark { + background-color: #fafafa; } + .message.is-dark .message-header { + background-color: #363636; + color: #fff; } + .message.is-dark .message-body { + border-color: #363636; } + .message.is-primary { + background-color: #ebfffc; } + .message.is-primary .message-header { + background-color: #00d1b2; + color: #fff; } + .message.is-primary .message-body { + border-color: #00d1b2; + color: #00947e; } + .message.is-link { + background-color: #eef3fc; } + .message.is-link .message-header { + background-color: #3273dc; + color: #fff; } + .message.is-link .message-body { + border-color: #3273dc; + color: #2160c4; } + .message.is-info { + background-color: #eef6fc; } + .message.is-info .message-header { + background-color: #3298dc; + color: #fff; } + .message.is-info .message-body { + border-color: #3298dc; + color: #1d72aa; } + .message.is-success { + background-color: #effaf3; } + .message.is-success .message-header { + background-color: #48c774; + color: #fff; } + .message.is-success .message-body { + border-color: #48c774; + color: #257942; } + .message.is-warning { + background-color: #fffbeb; } + .message.is-warning .message-header { + background-color: #ffdd57; + color: rgba(0, 0, 0, 0.7); } + .message.is-warning .message-body { + border-color: #ffdd57; + color: #947600; } + .message.is-danger { + background-color: #feecf0; } + .message.is-danger .message-header { + background-color: #f14668; + color: #fff; } + .message.is-danger .message-body { + border-color: #f14668; + color: #cc0f35; } + +.message-header { + align-items: center; + background-color: #4a4a4a; + border-radius: 4px 4px 0 0; + color: #fff; + display: flex; + font-weight: 700; + justify-content: space-between; + line-height: 1.25; + padding: 0.75em 1em; + position: relative; } + .message-header .delete { + flex-grow: 0; + flex-shrink: 0; + margin-left: 0.75em; } + .message-header + .message-body { + border-width: 0; + border-top-left-radius: 0; + border-top-right-radius: 0; } + +.message-body { + border-color: #dbdbdb; + border-radius: 4px; + border-style: solid; + border-width: 0 0 0 4px; + color: #4a4a4a; + padding: 1.25em 1.5em; } + .message-body code, + .message-body pre { + background-color: white; } + .message-body pre code { + background-color: transparent; } + +.modal { + align-items: center; + display: none; + flex-direction: column; + justify-content: center; + overflow: hidden; + position: fixed; + z-index: 40; } + .modal.is-active { + display: flex; } + +.modal-background { + background-color: rgba(10, 10, 10, 0.86); } + +.modal-content, +.modal-card { + margin: 0 20px; + max-height: calc(100vh - 160px); + overflow: auto; + position: relative; + width: 100%; } + @media screen and (min-width: 769px), print { + .modal-content, + .modal-card { + margin: 0 auto; + max-height: calc(100vh - 40px); + width: 640px; } } + +.modal-close { + background: none; + height: 40px; + position: fixed; + right: 20px; + top: 20px; + width: 40px; } + +.modal-card { + display: flex; + flex-direction: column; + max-height: calc(100vh - 40px); + overflow: hidden; + -ms-overflow-y: visible; } + +.modal-card-head, +.modal-card-foot { + align-items: center; + background-color: whitesmoke; + display: flex; + flex-shrink: 0; + justify-content: flex-start; + padding: 20px; + position: relative; } + +.modal-card-head { + border-bottom: 1px solid #dbdbdb; + border-top-left-radius: 6px; + border-top-right-radius: 6px; } + +.modal-card-title { + color: #363636; + flex-grow: 1; + flex-shrink: 0; + font-size: 1.5rem; + line-height: 1; } + +.modal-card-foot { + border-bottom-left-radius: 6px; + border-bottom-right-radius: 6px; + border-top: 1px solid #dbdbdb; } + .modal-card-foot .button:not(:last-child) { + margin-right: 0.5em; } + +.modal-card-body { + -webkit-overflow-scrolling: touch; + background-color: white; + flex-grow: 1; + flex-shrink: 1; + overflow: auto; + padding: 20px; } + +.navbar { + background-color: white; + min-height: 3.25rem; + position: relative; + z-index: 30; } + .navbar.is-white { + background-color: white; + color: #0a0a0a; } + .navbar.is-white .navbar-brand > .navbar-item, + .navbar.is-white .navbar-brand .navbar-link { + color: #0a0a0a; } + .navbar.is-white .navbar-brand > a.navbar-item:focus, .navbar.is-white .navbar-brand > a.navbar-item:hover, .navbar.is-white .navbar-brand > a.navbar-item.is-active, + .navbar.is-white .navbar-brand .navbar-link:focus, + .navbar.is-white .navbar-brand .navbar-link:hover, + .navbar.is-white .navbar-brand .navbar-link.is-active { + background-color: #f2f2f2; + color: #0a0a0a; } + .navbar.is-white .navbar-brand .navbar-link::after { + border-color: #0a0a0a; } + .navbar.is-white .navbar-burger { + color: #0a0a0a; } + @media screen and (min-width: 1024px) { + .navbar.is-white .navbar-start > .navbar-item, + .navbar.is-white .navbar-start .navbar-link, + .navbar.is-white .navbar-end > .navbar-item, + .navbar.is-white .navbar-end .navbar-link { + color: #0a0a0a; } + .navbar.is-white .navbar-start > a.navbar-item:focus, .navbar.is-white .navbar-start > a.navbar-item:hover, .navbar.is-white .navbar-start > a.navbar-item.is-active, + .navbar.is-white .navbar-start .navbar-link:focus, + .navbar.is-white .navbar-start .navbar-link:hover, + .navbar.is-white .navbar-start .navbar-link.is-active, + .navbar.is-white .navbar-end > a.navbar-item:focus, + .navbar.is-white .navbar-end > a.navbar-item:hover, + .navbar.is-white .navbar-end > a.navbar-item.is-active, + .navbar.is-white .navbar-end .navbar-link:focus, + .navbar.is-white .navbar-end .navbar-link:hover, + .navbar.is-white .navbar-end .navbar-link.is-active { + background-color: #f2f2f2; + color: #0a0a0a; } + .navbar.is-white .navbar-start .navbar-link::after, + .navbar.is-white .navbar-end .navbar-link::after { + border-color: #0a0a0a; } + .navbar.is-white .navbar-item.has-dropdown:focus .navbar-link, + .navbar.is-white .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-white .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #f2f2f2; + color: #0a0a0a; } + .navbar.is-white .navbar-dropdown a.navbar-item.is-active { + background-color: white; + color: #0a0a0a; } } + .navbar.is-black { + background-color: #0a0a0a; + color: white; } + .navbar.is-black .navbar-brand > .navbar-item, + .navbar.is-black .navbar-brand .navbar-link { + color: white; } + .navbar.is-black .navbar-brand > a.navbar-item:focus, .navbar.is-black .navbar-brand > a.navbar-item:hover, .navbar.is-black .navbar-brand > a.navbar-item.is-active, + .navbar.is-black .navbar-brand .navbar-link:focus, + .navbar.is-black .navbar-brand .navbar-link:hover, + .navbar.is-black .navbar-brand .navbar-link.is-active { + background-color: black; + color: white; } + .navbar.is-black .navbar-brand .navbar-link::after { + border-color: white; } + .navbar.is-black .navbar-burger { + color: white; } + @media screen and (min-width: 1024px) { + .navbar.is-black .navbar-start > .navbar-item, + .navbar.is-black .navbar-start .navbar-link, + .navbar.is-black .navbar-end > .navbar-item, + .navbar.is-black .navbar-end .navbar-link { + color: white; } + .navbar.is-black .navbar-start > a.navbar-item:focus, .navbar.is-black .navbar-start > a.navbar-item:hover, .navbar.is-black .navbar-start > a.navbar-item.is-active, + .navbar.is-black .navbar-start .navbar-link:focus, + .navbar.is-black .navbar-start .navbar-link:hover, + .navbar.is-black .navbar-start .navbar-link.is-active, + .navbar.is-black .navbar-end > a.navbar-item:focus, + .navbar.is-black .navbar-end > a.navbar-item:hover, + .navbar.is-black .navbar-end > a.navbar-item.is-active, + .navbar.is-black .navbar-end .navbar-link:focus, + .navbar.is-black .navbar-end .navbar-link:hover, + .navbar.is-black .navbar-end .navbar-link.is-active { + background-color: black; + color: white; } + .navbar.is-black .navbar-start .navbar-link::after, + .navbar.is-black .navbar-end .navbar-link::after { + border-color: white; } + .navbar.is-black .navbar-item.has-dropdown:focus .navbar-link, + .navbar.is-black .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-black .navbar-item.has-dropdown.is-active .navbar-link { + background-color: black; + color: white; } + .navbar.is-black .navbar-dropdown a.navbar-item.is-active { + background-color: #0a0a0a; + color: white; } } + .navbar.is-light { + background-color: whitesmoke; + color: rgba(0, 0, 0, 0.7); } + .navbar.is-light .navbar-brand > .navbar-item, + .navbar.is-light .navbar-brand .navbar-link { + color: rgba(0, 0, 0, 0.7); } + .navbar.is-light .navbar-brand > a.navbar-item:focus, .navbar.is-light .navbar-brand > a.navbar-item:hover, .navbar.is-light .navbar-brand > a.navbar-item.is-active, + .navbar.is-light .navbar-brand .navbar-link:focus, + .navbar.is-light .navbar-brand .navbar-link:hover, + .navbar.is-light .navbar-brand .navbar-link.is-active { + background-color: #e8e8e8; + color: rgba(0, 0, 0, 0.7); } + .navbar.is-light .navbar-brand .navbar-link::after { + border-color: rgba(0, 0, 0, 0.7); } + .navbar.is-light .navbar-burger { + color: rgba(0, 0, 0, 0.7); } + @media screen and (min-width: 1024px) { + .navbar.is-light .navbar-start > .navbar-item, + .navbar.is-light .navbar-start .navbar-link, + .navbar.is-light .navbar-end > .navbar-item, + .navbar.is-light .navbar-end .navbar-link { + color: rgba(0, 0, 0, 0.7); } + .navbar.is-light .navbar-start > a.navbar-item:focus, .navbar.is-light .navbar-start > a.navbar-item:hover, .navbar.is-light .navbar-start > a.navbar-item.is-active, + .navbar.is-light .navbar-start .navbar-link:focus, + .navbar.is-light .navbar-start .navbar-link:hover, + .navbar.is-light .navbar-start .navbar-link.is-active, + .navbar.is-light .navbar-end > a.navbar-item:focus, + .navbar.is-light .navbar-end > a.navbar-item:hover, + .navbar.is-light .navbar-end > a.navbar-item.is-active, + .navbar.is-light .navbar-end .navbar-link:focus, + .navbar.is-light .navbar-end .navbar-link:hover, + .navbar.is-light .navbar-end .navbar-link.is-active { + background-color: #e8e8e8; + color: rgba(0, 0, 0, 0.7); } + .navbar.is-light .navbar-start .navbar-link::after, + .navbar.is-light .navbar-end .navbar-link::after { + border-color: rgba(0, 0, 0, 0.7); } + .navbar.is-light .navbar-item.has-dropdown:focus .navbar-link, + .navbar.is-light .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-light .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #e8e8e8; + color: rgba(0, 0, 0, 0.7); } + .navbar.is-light .navbar-dropdown a.navbar-item.is-active { + background-color: whitesmoke; + color: rgba(0, 0, 0, 0.7); } } + .navbar.is-dark { + background-color: #363636; + color: #fff; } + .navbar.is-dark .navbar-brand > .navbar-item, + .navbar.is-dark .navbar-brand .navbar-link { + color: #fff; } + .navbar.is-dark .navbar-brand > a.navbar-item:focus, .navbar.is-dark .navbar-brand > a.navbar-item:hover, .navbar.is-dark .navbar-brand > a.navbar-item.is-active, + .navbar.is-dark .navbar-brand .navbar-link:focus, + .navbar.is-dark .navbar-brand .navbar-link:hover, + .navbar.is-dark .navbar-brand .navbar-link.is-active { + background-color: #292929; + color: #fff; } + .navbar.is-dark .navbar-brand .navbar-link::after { + border-color: #fff; } + .navbar.is-dark .navbar-burger { + color: #fff; } + @media screen and (min-width: 1024px) { + .navbar.is-dark .navbar-start > .navbar-item, + .navbar.is-dark .navbar-start .navbar-link, + .navbar.is-dark .navbar-end > .navbar-item, + .navbar.is-dark .navbar-end .navbar-link { + color: #fff; } + .navbar.is-dark .navbar-start > a.navbar-item:focus, .navbar.is-dark .navbar-start > a.navbar-item:hover, .navbar.is-dark .navbar-start > a.navbar-item.is-active, + .navbar.is-dark .navbar-start .navbar-link:focus, + .navbar.is-dark .navbar-start .navbar-link:hover, + .navbar.is-dark .navbar-start .navbar-link.is-active, + .navbar.is-dark .navbar-end > a.navbar-item:focus, + .navbar.is-dark .navbar-end > a.navbar-item:hover, + .navbar.is-dark .navbar-end > a.navbar-item.is-active, + .navbar.is-dark .navbar-end .navbar-link:focus, + .navbar.is-dark .navbar-end .navbar-link:hover, + .navbar.is-dark .navbar-end .navbar-link.is-active { + background-color: #292929; + color: #fff; } + .navbar.is-dark .navbar-start .navbar-link::after, + .navbar.is-dark .navbar-end .navbar-link::after { + border-color: #fff; } + .navbar.is-dark .navbar-item.has-dropdown:focus .navbar-link, + .navbar.is-dark .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-dark .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #292929; + color: #fff; } + .navbar.is-dark .navbar-dropdown a.navbar-item.is-active { + background-color: #363636; + color: #fff; } } + .navbar.is-primary { + background-color: #00d1b2; + color: #fff; } + .navbar.is-primary .navbar-brand > .navbar-item, + .navbar.is-primary .navbar-brand .navbar-link { + color: #fff; } + .navbar.is-primary .navbar-brand > a.navbar-item:focus, .navbar.is-primary .navbar-brand > a.navbar-item:hover, .navbar.is-primary .navbar-brand > a.navbar-item.is-active, + .navbar.is-primary .navbar-brand .navbar-link:focus, + .navbar.is-primary .navbar-brand .navbar-link:hover, + .navbar.is-primary .navbar-brand .navbar-link.is-active { + background-color: #00b89c; + color: #fff; } + .navbar.is-primary .navbar-brand .navbar-link::after { + border-color: #fff; } + .navbar.is-primary .navbar-burger { + color: #fff; } + @media screen and (min-width: 1024px) { + .navbar.is-primary .navbar-start > .navbar-item, + .navbar.is-primary .navbar-start .navbar-link, + .navbar.is-primary .navbar-end > .navbar-item, + .navbar.is-primary .navbar-end .navbar-link { + color: #fff; } + .navbar.is-primary .navbar-start > a.navbar-item:focus, .navbar.is-primary .navbar-start > a.navbar-item:hover, .navbar.is-primary .navbar-start > a.navbar-item.is-active, + .navbar.is-primary .navbar-start .navbar-link:focus, + .navbar.is-primary .navbar-start .navbar-link:hover, + .navbar.is-primary .navbar-start .navbar-link.is-active, + .navbar.is-primary .navbar-end > a.navbar-item:focus, + .navbar.is-primary .navbar-end > a.navbar-item:hover, + .navbar.is-primary .navbar-end > a.navbar-item.is-active, + .navbar.is-primary .navbar-end .navbar-link:focus, + .navbar.is-primary .navbar-end .navbar-link:hover, + .navbar.is-primary .navbar-end .navbar-link.is-active { + background-color: #00b89c; + color: #fff; } + .navbar.is-primary .navbar-start .navbar-link::after, + .navbar.is-primary .navbar-end .navbar-link::after { + border-color: #fff; } + .navbar.is-primary .navbar-item.has-dropdown:focus .navbar-link, + .navbar.is-primary .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-primary .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #00b89c; + color: #fff; } + .navbar.is-primary .navbar-dropdown a.navbar-item.is-active { + background-color: #00d1b2; + color: #fff; } } + .navbar.is-link { + background-color: #3273dc; + color: #fff; } + .navbar.is-link .navbar-brand > .navbar-item, + .navbar.is-link .navbar-brand .navbar-link { + color: #fff; } + .navbar.is-link .navbar-brand > a.navbar-item:focus, .navbar.is-link .navbar-brand > a.navbar-item:hover, .navbar.is-link .navbar-brand > a.navbar-item.is-active, + .navbar.is-link .navbar-brand .navbar-link:focus, + .navbar.is-link .navbar-brand .navbar-link:hover, + .navbar.is-link .navbar-brand .navbar-link.is-active { + background-color: #2366d1; + color: #fff; } + .navbar.is-link .navbar-brand .navbar-link::after { + border-color: #fff; } + .navbar.is-link .navbar-burger { + color: #fff; } + @media screen and (min-width: 1024px) { + .navbar.is-link .navbar-start > .navbar-item, + .navbar.is-link .navbar-start .navbar-link, + .navbar.is-link .navbar-end > .navbar-item, + .navbar.is-link .navbar-end .navbar-link { + color: #fff; } + .navbar.is-link .navbar-start > a.navbar-item:focus, .navbar.is-link .navbar-start > a.navbar-item:hover, .navbar.is-link .navbar-start > a.navbar-item.is-active, + .navbar.is-link .navbar-start .navbar-link:focus, + .navbar.is-link .navbar-start .navbar-link:hover, + .navbar.is-link .navbar-start .navbar-link.is-active, + .navbar.is-link .navbar-end > a.navbar-item:focus, + .navbar.is-link .navbar-end > a.navbar-item:hover, + .navbar.is-link .navbar-end > a.navbar-item.is-active, + .navbar.is-link .navbar-end .navbar-link:focus, + .navbar.is-link .navbar-end .navbar-link:hover, + .navbar.is-link .navbar-end .navbar-link.is-active { + background-color: #2366d1; + color: #fff; } + .navbar.is-link .navbar-start .navbar-link::after, + .navbar.is-link .navbar-end .navbar-link::after { + border-color: #fff; } + .navbar.is-link .navbar-item.has-dropdown:focus .navbar-link, + .navbar.is-link .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-link .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #2366d1; + color: #fff; } + .navbar.is-link .navbar-dropdown a.navbar-item.is-active { + background-color: #3273dc; + color: #fff; } } + .navbar.is-info { + background-color: #3298dc; + color: #fff; } + .navbar.is-info .navbar-brand > .navbar-item, + .navbar.is-info .navbar-brand .navbar-link { + color: #fff; } + .navbar.is-info .navbar-brand > a.navbar-item:focus, .navbar.is-info .navbar-brand > a.navbar-item:hover, .navbar.is-info .navbar-brand > a.navbar-item.is-active, + .navbar.is-info .navbar-brand .navbar-link:focus, + .navbar.is-info .navbar-brand .navbar-link:hover, + .navbar.is-info .navbar-brand .navbar-link.is-active { + background-color: #238cd1; + color: #fff; } + .navbar.is-info .navbar-brand .navbar-link::after { + border-color: #fff; } + .navbar.is-info .navbar-burger { + color: #fff; } + @media screen and (min-width: 1024px) { + .navbar.is-info .navbar-start > .navbar-item, + .navbar.is-info .navbar-start .navbar-link, + .navbar.is-info .navbar-end > .navbar-item, + .navbar.is-info .navbar-end .navbar-link { + color: #fff; } + .navbar.is-info .navbar-start > a.navbar-item:focus, .navbar.is-info .navbar-start > a.navbar-item:hover, .navbar.is-info .navbar-start > a.navbar-item.is-active, + .navbar.is-info .navbar-start .navbar-link:focus, + .navbar.is-info .navbar-start .navbar-link:hover, + .navbar.is-info .navbar-start .navbar-link.is-active, + .navbar.is-info .navbar-end > a.navbar-item:focus, + .navbar.is-info .navbar-end > a.navbar-item:hover, + .navbar.is-info .navbar-end > a.navbar-item.is-active, + .navbar.is-info .navbar-end .navbar-link:focus, + .navbar.is-info .navbar-end .navbar-link:hover, + .navbar.is-info .navbar-end .navbar-link.is-active { + background-color: #238cd1; + color: #fff; } + .navbar.is-info .navbar-start .navbar-link::after, + .navbar.is-info .navbar-end .navbar-link::after { + border-color: #fff; } + .navbar.is-info .navbar-item.has-dropdown:focus .navbar-link, + .navbar.is-info .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-info .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #238cd1; + color: #fff; } + .navbar.is-info .navbar-dropdown a.navbar-item.is-active { + background-color: #3298dc; + color: #fff; } } + .navbar.is-success { + background-color: #48c774; + color: #fff; } + .navbar.is-success .navbar-brand > .navbar-item, + .navbar.is-success .navbar-brand .navbar-link { + color: #fff; } + .navbar.is-success .navbar-brand > a.navbar-item:focus, .navbar.is-success .navbar-brand > a.navbar-item:hover, .navbar.is-success .navbar-brand > a.navbar-item.is-active, + .navbar.is-success .navbar-brand .navbar-link:focus, + .navbar.is-success .navbar-brand .navbar-link:hover, + .navbar.is-success .navbar-brand .navbar-link.is-active { + background-color: #3abb67; + color: #fff; } + .navbar.is-success .navbar-brand .navbar-link::after { + border-color: #fff; } + .navbar.is-success .navbar-burger { + color: #fff; } + @media screen and (min-width: 1024px) { + .navbar.is-success .navbar-start > .navbar-item, + .navbar.is-success .navbar-start .navbar-link, + .navbar.is-success .navbar-end > .navbar-item, + .navbar.is-success .navbar-end .navbar-link { + color: #fff; } + .navbar.is-success .navbar-start > a.navbar-item:focus, .navbar.is-success .navbar-start > a.navbar-item:hover, .navbar.is-success .navbar-start > a.navbar-item.is-active, + .navbar.is-success .navbar-start .navbar-link:focus, + .navbar.is-success .navbar-start .navbar-link:hover, + .navbar.is-success .navbar-start .navbar-link.is-active, + .navbar.is-success .navbar-end > a.navbar-item:focus, + .navbar.is-success .navbar-end > a.navbar-item:hover, + .navbar.is-success .navbar-end > a.navbar-item.is-active, + .navbar.is-success .navbar-end .navbar-link:focus, + .navbar.is-success .navbar-end .navbar-link:hover, + .navbar.is-success .navbar-end .navbar-link.is-active { + background-color: #3abb67; + color: #fff; } + .navbar.is-success .navbar-start .navbar-link::after, + .navbar.is-success .navbar-end .navbar-link::after { + border-color: #fff; } + .navbar.is-success .navbar-item.has-dropdown:focus .navbar-link, + .navbar.is-success .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-success .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #3abb67; + color: #fff; } + .navbar.is-success .navbar-dropdown a.navbar-item.is-active { + background-color: #48c774; + color: #fff; } } + .navbar.is-warning { + background-color: #ffdd57; + color: rgba(0, 0, 0, 0.7); } + .navbar.is-warning .navbar-brand > .navbar-item, + .navbar.is-warning .navbar-brand .navbar-link { + color: rgba(0, 0, 0, 0.7); } + .navbar.is-warning .navbar-brand > a.navbar-item:focus, .navbar.is-warning .navbar-brand > a.navbar-item:hover, .navbar.is-warning .navbar-brand > a.navbar-item.is-active, + .navbar.is-warning .navbar-brand .navbar-link:focus, + .navbar.is-warning .navbar-brand .navbar-link:hover, + .navbar.is-warning .navbar-brand .navbar-link.is-active { + background-color: #ffd83d; + color: rgba(0, 0, 0, 0.7); } + .navbar.is-warning .navbar-brand .navbar-link::after { + border-color: rgba(0, 0, 0, 0.7); } + .navbar.is-warning .navbar-burger { + color: rgba(0, 0, 0, 0.7); } + @media screen and (min-width: 1024px) { + .navbar.is-warning .navbar-start > .navbar-item, + .navbar.is-warning .navbar-start .navbar-link, + .navbar.is-warning .navbar-end > .navbar-item, + .navbar.is-warning .navbar-end .navbar-link { + color: rgba(0, 0, 0, 0.7); } + .navbar.is-warning .navbar-start > a.navbar-item:focus, .navbar.is-warning .navbar-start > a.navbar-item:hover, .navbar.is-warning .navbar-start > a.navbar-item.is-active, + .navbar.is-warning .navbar-start .navbar-link:focus, + .navbar.is-warning .navbar-start .navbar-link:hover, + .navbar.is-warning .navbar-start .navbar-link.is-active, + .navbar.is-warning .navbar-end > a.navbar-item:focus, + .navbar.is-warning .navbar-end > a.navbar-item:hover, + .navbar.is-warning .navbar-end > a.navbar-item.is-active, + .navbar.is-warning .navbar-end .navbar-link:focus, + .navbar.is-warning .navbar-end .navbar-link:hover, + .navbar.is-warning .navbar-end .navbar-link.is-active { + background-color: #ffd83d; + color: rgba(0, 0, 0, 0.7); } + .navbar.is-warning .navbar-start .navbar-link::after, + .navbar.is-warning .navbar-end .navbar-link::after { + border-color: rgba(0, 0, 0, 0.7); } + .navbar.is-warning .navbar-item.has-dropdown:focus .navbar-link, + .navbar.is-warning .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-warning .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #ffd83d; + color: rgba(0, 0, 0, 0.7); } + .navbar.is-warning .navbar-dropdown a.navbar-item.is-active { + background-color: #ffdd57; + color: rgba(0, 0, 0, 0.7); } } + .navbar.is-danger { + background-color: #f14668; + color: #fff; } + .navbar.is-danger .navbar-brand > .navbar-item, + .navbar.is-danger .navbar-brand .navbar-link { + color: #fff; } + .navbar.is-danger .navbar-brand > a.navbar-item:focus, .navbar.is-danger .navbar-brand > a.navbar-item:hover, .navbar.is-danger .navbar-brand > a.navbar-item.is-active, + .navbar.is-danger .navbar-brand .navbar-link:focus, + .navbar.is-danger .navbar-brand .navbar-link:hover, + .navbar.is-danger .navbar-brand .navbar-link.is-active { + background-color: #ef2e55; + color: #fff; } + .navbar.is-danger .navbar-brand .navbar-link::after { + border-color: #fff; } + .navbar.is-danger .navbar-burger { + color: #fff; } + @media screen and (min-width: 1024px) { + .navbar.is-danger .navbar-start > .navbar-item, + .navbar.is-danger .navbar-start .navbar-link, + .navbar.is-danger .navbar-end > .navbar-item, + .navbar.is-danger .navbar-end .navbar-link { + color: #fff; } + .navbar.is-danger .navbar-start > a.navbar-item:focus, .navbar.is-danger .navbar-start > a.navbar-item:hover, .navbar.is-danger .navbar-start > a.navbar-item.is-active, + .navbar.is-danger .navbar-start .navbar-link:focus, + .navbar.is-danger .navbar-start .navbar-link:hover, + .navbar.is-danger .navbar-start .navbar-link.is-active, + .navbar.is-danger .navbar-end > a.navbar-item:focus, + .navbar.is-danger .navbar-end > a.navbar-item:hover, + .navbar.is-danger .navbar-end > a.navbar-item.is-active, + .navbar.is-danger .navbar-end .navbar-link:focus, + .navbar.is-danger .navbar-end .navbar-link:hover, + .navbar.is-danger .navbar-end .navbar-link.is-active { + background-color: #ef2e55; + color: #fff; } + .navbar.is-danger .navbar-start .navbar-link::after, + .navbar.is-danger .navbar-end .navbar-link::after { + border-color: #fff; } + .navbar.is-danger .navbar-item.has-dropdown:focus .navbar-link, + .navbar.is-danger .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-danger .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #ef2e55; + color: #fff; } + .navbar.is-danger .navbar-dropdown a.navbar-item.is-active { + background-color: #f14668; + color: #fff; } } + .navbar > .container { + align-items: stretch; + display: flex; + min-height: 3.25rem; + width: 100%; } + .navbar.has-shadow { + box-shadow: 0 2px 0 0 whitesmoke; } + .navbar.is-fixed-bottom, .navbar.is-fixed-top { + left: 0; + position: fixed; + right: 0; + z-index: 30; } + .navbar.is-fixed-bottom { + bottom: 0; } + .navbar.is-fixed-bottom.has-shadow { + box-shadow: 0 -2px 0 0 whitesmoke; } + .navbar.is-fixed-top { + top: 0; } + +html.has-navbar-fixed-top, +body.has-navbar-fixed-top { + padding-top: 3.25rem; } + +html.has-navbar-fixed-bottom, +body.has-navbar-fixed-bottom { + padding-bottom: 3.25rem; } + +.navbar-brand, +.navbar-tabs { + align-items: stretch; + display: flex; + flex-shrink: 0; + min-height: 3.25rem; } + +.navbar-brand a.navbar-item:focus, .navbar-brand a.navbar-item:hover { + background-color: transparent; } + +.navbar-tabs { + -webkit-overflow-scrolling: touch; + max-width: 100vw; + overflow-x: auto; + overflow-y: hidden; } + +.navbar-burger { + color: #4a4a4a; + cursor: pointer; + display: block; + height: 3.25rem; + position: relative; + width: 3.25rem; + margin-left: auto; } + .navbar-burger span { + background-color: currentColor; + display: block; + height: 1px; + left: calc(50% - 8px); + position: absolute; + transform-origin: center; + transition-duration: 86ms; + transition-property: background-color, opacity, transform; + transition-timing-function: ease-out; + width: 16px; } + .navbar-burger span:nth-child(1) { + top: calc(50% - 6px); } + .navbar-burger span:nth-child(2) { + top: calc(50% - 1px); } + .navbar-burger span:nth-child(3) { + top: calc(50% + 4px); } + .navbar-burger:hover { + background-color: rgba(0, 0, 0, 0.05); } + .navbar-burger.is-active span:nth-child(1) { + transform: translateY(5px) rotate(45deg); } + .navbar-burger.is-active span:nth-child(2) { + opacity: 0; } + .navbar-burger.is-active span:nth-child(3) { + transform: translateY(-5px) rotate(-45deg); } + +.navbar-menu { + display: none; } + +.navbar-item, +.navbar-link { + color: #4a4a4a; + display: block; + line-height: 1.5; + padding: 0.5rem 0.75rem; + position: relative; } + .navbar-item .icon:only-child, + .navbar-link .icon:only-child { + margin-left: -0.25rem; + margin-right: -0.25rem; } + +a.navbar-item, +.navbar-link { + cursor: pointer; } + a.navbar-item:focus, a.navbar-item:focus-within, a.navbar-item:hover, a.navbar-item.is-active, + .navbar-link:focus, + .navbar-link:focus-within, + .navbar-link:hover, + .navbar-link.is-active { + background-color: #fafafa; + color: #3273dc; } + +.navbar-item { + display: block; + flex-grow: 0; + flex-shrink: 0; } + .navbar-item img { + max-height: 1.75rem; } + .navbar-item.has-dropdown { + padding: 0; } + .navbar-item.is-expanded { + flex-grow: 1; + flex-shrink: 1; } + .navbar-item.is-tab { + border-bottom: 1px solid transparent; + min-height: 3.25rem; + padding-bottom: calc(0.5rem - 1px); } + .navbar-item.is-tab:focus, .navbar-item.is-tab:hover { + background-color: transparent; + border-bottom-color: #3273dc; } + .navbar-item.is-tab.is-active { + background-color: transparent; + border-bottom-color: #3273dc; + border-bottom-style: solid; + border-bottom-width: 3px; + color: #3273dc; + padding-bottom: calc(0.5rem - 3px); } + +.navbar-content { + flex-grow: 1; + flex-shrink: 1; } + +.navbar-link:not(.is-arrowless) { + padding-right: 2.5em; } + .navbar-link:not(.is-arrowless)::after { + border-color: #3273dc; + margin-top: -0.375em; + right: 1.125em; } + +.navbar-dropdown { + font-size: 0.875rem; + padding-bottom: 0.5rem; + padding-top: 0.5rem; } + .navbar-dropdown .navbar-item { + padding-left: 1.5rem; + padding-right: 1.5rem; } + +.navbar-divider { + background-color: whitesmoke; + border: none; + display: none; + height: 2px; + margin: 0.5rem 0; } + +@media screen and (max-width: 1023px) { + .navbar > .container { + display: block; } + .navbar-brand .navbar-item, + .navbar-tabs .navbar-item { + align-items: center; + display: flex; } + .navbar-link::after { + display: none; } + .navbar-menu { + background-color: white; + box-shadow: 0 8px 16px rgba(10, 10, 10, 0.1); + padding: 0.5rem 0; } + .navbar-menu.is-active { + display: block; } + .navbar.is-fixed-bottom-touch, .navbar.is-fixed-top-touch { + left: 0; + position: fixed; + right: 0; + z-index: 30; } + .navbar.is-fixed-bottom-touch { + bottom: 0; } + .navbar.is-fixed-bottom-touch.has-shadow { + box-shadow: 0 -2px 3px rgba(10, 10, 10, 0.1); } + .navbar.is-fixed-top-touch { + top: 0; } + .navbar.is-fixed-top .navbar-menu, .navbar.is-fixed-top-touch .navbar-menu { + -webkit-overflow-scrolling: touch; + max-height: calc(100vh - 3.25rem); + overflow: auto; } + html.has-navbar-fixed-top-touch, + body.has-navbar-fixed-top-touch { + padding-top: 3.25rem; } + html.has-navbar-fixed-bottom-touch, + body.has-navbar-fixed-bottom-touch { + padding-bottom: 3.25rem; } } + +@media screen and (min-width: 1024px) { + .navbar, + .navbar-menu, + .navbar-start, + .navbar-end { + align-items: stretch; + display: flex; } + .navbar { + min-height: 3.25rem; } + .navbar.is-spaced { + padding: 1rem 2rem; } + .navbar.is-spaced .navbar-start, + .navbar.is-spaced .navbar-end { + align-items: center; } + .navbar.is-spaced a.navbar-item, + .navbar.is-spaced .navbar-link { + border-radius: 4px; } + .navbar.is-transparent a.navbar-item:focus, .navbar.is-transparent a.navbar-item:hover, .navbar.is-transparent a.navbar-item.is-active, + .navbar.is-transparent .navbar-link:focus, + .navbar.is-transparent .navbar-link:hover, + .navbar.is-transparent .navbar-link.is-active { + background-color: transparent !important; } + .navbar.is-transparent .navbar-item.has-dropdown.is-active .navbar-link, .navbar.is-transparent .navbar-item.has-dropdown.is-hoverable:focus .navbar-link, .navbar.is-transparent .navbar-item.has-dropdown.is-hoverable:focus-within .navbar-link, .navbar.is-transparent .navbar-item.has-dropdown.is-hoverable:hover .navbar-link { + background-color: transparent !important; } + .navbar.is-transparent .navbar-dropdown a.navbar-item:focus, .navbar.is-transparent .navbar-dropdown a.navbar-item:hover { + background-color: whitesmoke; + color: #0a0a0a; } + .navbar.is-transparent .navbar-dropdown a.navbar-item.is-active { + background-color: whitesmoke; + color: #3273dc; } + .navbar-burger { + display: none; } + .navbar-item, + .navbar-link { + align-items: center; + display: flex; } + .navbar-item { + display: flex; } + .navbar-item.has-dropdown { + align-items: stretch; } + .navbar-item.has-dropdown-up .navbar-link::after { + transform: rotate(135deg) translate(0.25em, -0.25em); } + .navbar-item.has-dropdown-up .navbar-dropdown { + border-bottom: 2px solid #dbdbdb; + border-radius: 6px 6px 0 0; + border-top: none; + bottom: 100%; + box-shadow: 0 -8px 8px rgba(10, 10, 10, 0.1); + top: auto; } + .navbar-item.is-active .navbar-dropdown, .navbar-item.is-hoverable:focus .navbar-dropdown, .navbar-item.is-hoverable:focus-within .navbar-dropdown, .navbar-item.is-hoverable:hover .navbar-dropdown { + display: block; } + .navbar.is-spaced .navbar-item.is-active .navbar-dropdown, .navbar-item.is-active .navbar-dropdown.is-boxed, .navbar.is-spaced .navbar-item.is-hoverable:focus .navbar-dropdown, .navbar-item.is-hoverable:focus .navbar-dropdown.is-boxed, .navbar.is-spaced .navbar-item.is-hoverable:focus-within .navbar-dropdown, .navbar-item.is-hoverable:focus-within .navbar-dropdown.is-boxed, .navbar.is-spaced .navbar-item.is-hoverable:hover .navbar-dropdown, .navbar-item.is-hoverable:hover .navbar-dropdown.is-boxed { + opacity: 1; + pointer-events: auto; + transform: translateY(0); } + .navbar-menu { + flex-grow: 1; + flex-shrink: 0; } + .navbar-start { + justify-content: flex-start; + margin-right: auto; } + .navbar-end { + justify-content: flex-end; + margin-left: auto; } + .navbar-dropdown { + background-color: white; + border-bottom-left-radius: 6px; + border-bottom-right-radius: 6px; + border-top: 2px solid #dbdbdb; + box-shadow: 0 8px 8px rgba(10, 10, 10, 0.1); + display: none; + font-size: 0.875rem; + left: 0; + min-width: 100%; + position: absolute; + top: 100%; + z-index: 20; } + .navbar-dropdown .navbar-item { + padding: 0.375rem 1rem; + white-space: nowrap; } + .navbar-dropdown a.navbar-item { + padding-right: 3rem; } + .navbar-dropdown a.navbar-item:focus, .navbar-dropdown a.navbar-item:hover { + background-color: whitesmoke; + color: #0a0a0a; } + .navbar-dropdown a.navbar-item.is-active { + background-color: whitesmoke; + color: #3273dc; } + .navbar.is-spaced .navbar-dropdown, .navbar-dropdown.is-boxed { + border-radius: 6px; + border-top: none; + box-shadow: 0 8px 8px rgba(10, 10, 10, 0.1), 0 0 0 1px rgba(10, 10, 10, 0.1); + display: block; + opacity: 0; + pointer-events: none; + top: calc(100% + (-4px)); + transform: translateY(-5px); + transition-duration: 86ms; + transition-property: opacity, transform; } + .navbar-dropdown.is-right { + left: auto; + right: 0; } + .navbar-divider { + display: block; } + .navbar > .container .navbar-brand, + .container > .navbar .navbar-brand { + margin-left: -.75rem; } + .navbar > .container .navbar-menu, + .container > .navbar .navbar-menu { + margin-right: -.75rem; } + .navbar.is-fixed-bottom-desktop, .navbar.is-fixed-top-desktop { + left: 0; + position: fixed; + right: 0; + z-index: 30; } + .navbar.is-fixed-bottom-desktop { + bottom: 0; } + .navbar.is-fixed-bottom-desktop.has-shadow { + box-shadow: 0 -2px 3px rgba(10, 10, 10, 0.1); } + .navbar.is-fixed-top-desktop { + top: 0; } + html.has-navbar-fixed-top-desktop, + body.has-navbar-fixed-top-desktop { + padding-top: 3.25rem; } + html.has-navbar-fixed-bottom-desktop, + body.has-navbar-fixed-bottom-desktop { + padding-bottom: 3.25rem; } + html.has-spaced-navbar-fixed-top, + body.has-spaced-navbar-fixed-top { + padding-top: 5.25rem; } + html.has-spaced-navbar-fixed-bottom, + body.has-spaced-navbar-fixed-bottom { + padding-bottom: 5.25rem; } + a.navbar-item.is-active, + .navbar-link.is-active { + color: #0a0a0a; } + a.navbar-item.is-active:not(:focus):not(:hover), + .navbar-link.is-active:not(:focus):not(:hover) { + background-color: transparent; } + .navbar-item.has-dropdown:focus .navbar-link, .navbar-item.has-dropdown:hover .navbar-link, .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #fafafa; } } + +.hero.is-fullheight-with-navbar { + min-height: calc(100vh - 3.25rem); } + +.pagination { + font-size: 1rem; + margin: -0.25rem; } + .pagination.is-small { + font-size: 0.75rem; } + .pagination.is-medium { + font-size: 1.25rem; } + .pagination.is-large { + font-size: 1.5rem; } + .pagination.is-rounded .pagination-previous, + .pagination.is-rounded .pagination-next { + padding-left: 1em; + padding-right: 1em; + border-radius: 290486px; } + .pagination.is-rounded .pagination-link { + border-radius: 290486px; } + +.pagination, +.pagination-list { + align-items: center; + display: flex; + justify-content: center; + text-align: center; } + +.pagination-previous, +.pagination-next, +.pagination-link, +.pagination-ellipsis { + font-size: 1em; + justify-content: center; + margin: 0.25rem; + padding-left: 0.5em; + padding-right: 0.5em; + text-align: center; } + +.pagination-previous, +.pagination-next, +.pagination-link { + border-color: #dbdbdb; + color: #363636; + min-width: 2.5em; } + .pagination-previous:hover, + .pagination-next:hover, + .pagination-link:hover { + border-color: #b5b5b5; + color: #363636; } + .pagination-previous:focus, + .pagination-next:focus, + .pagination-link:focus { + border-color: #3273dc; } + .pagination-previous:active, + .pagination-next:active, + .pagination-link:active { + box-shadow: inset 0 1px 2px rgba(10, 10, 10, 0.2); } + .pagination-previous[disabled], + .pagination-next[disabled], + .pagination-link[disabled] { + background-color: #dbdbdb; + border-color: #dbdbdb; + box-shadow: none; + color: #7a7a7a; + opacity: 0.5; } + +.pagination-previous, +.pagination-next { + padding-left: 0.75em; + padding-right: 0.75em; + white-space: nowrap; } + +.pagination-link.is-current { + background-color: #3273dc; + border-color: #3273dc; + color: #fff; } + +.pagination-ellipsis { + color: #b5b5b5; + pointer-events: none; } + +.pagination-list { + flex-wrap: wrap; } + +@media screen and (max-width: 768px) { + .pagination { + flex-wrap: wrap; } + .pagination-previous, + .pagination-next { + flex-grow: 1; + flex-shrink: 1; } + .pagination-list li { + flex-grow: 1; + flex-shrink: 1; } } + +@media screen and (min-width: 769px), print { + .pagination-list { + flex-grow: 1; + flex-shrink: 1; + justify-content: flex-start; + order: 1; } + .pagination-previous { + order: 2; } + .pagination-next { + order: 3; } + .pagination { + justify-content: space-between; } + .pagination.is-centered .pagination-previous { + order: 1; } + .pagination.is-centered .pagination-list { + justify-content: center; + order: 2; } + .pagination.is-centered .pagination-next { + order: 3; } + .pagination.is-right .pagination-previous { + order: 1; } + .pagination.is-right .pagination-next { + order: 2; } + .pagination.is-right .pagination-list { + justify-content: flex-end; + order: 3; } } + +.panel { + border-radius: 6px; + box-shadow: 0 0.5em 1em -0.125em rgba(10, 10, 10, 0.1), 0 0px 0 1px rgba(10, 10, 10, 0.02); + font-size: 1rem; } + .panel:not(:last-child) { + margin-bottom: 1.5rem; } + .panel.is-white .panel-heading { + background-color: white; + color: #0a0a0a; } + .panel.is-white .panel-tabs a.is-active { + border-bottom-color: white; } + .panel.is-white .panel-block.is-active .panel-icon { + color: white; } + .panel.is-black .panel-heading { + background-color: #0a0a0a; + color: white; } + .panel.is-black .panel-tabs a.is-active { + border-bottom-color: #0a0a0a; } + .panel.is-black .panel-block.is-active .panel-icon { + color: #0a0a0a; } + .panel.is-light .panel-heading { + background-color: whitesmoke; + color: rgba(0, 0, 0, 0.7); } + .panel.is-light .panel-tabs a.is-active { + border-bottom-color: whitesmoke; } + .panel.is-light .panel-block.is-active .panel-icon { + color: whitesmoke; } + .panel.is-dark .panel-heading { + background-color: #363636; + color: #fff; } + .panel.is-dark .panel-tabs a.is-active { + border-bottom-color: #363636; } + .panel.is-dark .panel-block.is-active .panel-icon { + color: #363636; } + .panel.is-primary .panel-heading { + background-color: #00d1b2; + color: #fff; } + .panel.is-primary .panel-tabs a.is-active { + border-bottom-color: #00d1b2; } + .panel.is-primary .panel-block.is-active .panel-icon { + color: #00d1b2; } + .panel.is-link .panel-heading { + background-color: #3273dc; + color: #fff; } + .panel.is-link .panel-tabs a.is-active { + border-bottom-color: #3273dc; } + .panel.is-link .panel-block.is-active .panel-icon { + color: #3273dc; } + .panel.is-info .panel-heading { + background-color: #3298dc; + color: #fff; } + .panel.is-info .panel-tabs a.is-active { + border-bottom-color: #3298dc; } + .panel.is-info .panel-block.is-active .panel-icon { + color: #3298dc; } + .panel.is-success .panel-heading { + background-color: #48c774; + color: #fff; } + .panel.is-success .panel-tabs a.is-active { + border-bottom-color: #48c774; } + .panel.is-success .panel-block.is-active .panel-icon { + color: #48c774; } + .panel.is-warning .panel-heading { + background-color: #ffdd57; + color: rgba(0, 0, 0, 0.7); } + .panel.is-warning .panel-tabs a.is-active { + border-bottom-color: #ffdd57; } + .panel.is-warning .panel-block.is-active .panel-icon { + color: #ffdd57; } + .panel.is-danger .panel-heading { + background-color: #f14668; + color: #fff; } + .panel.is-danger .panel-tabs a.is-active { + border-bottom-color: #f14668; } + .panel.is-danger .panel-block.is-active .panel-icon { + color: #f14668; } + +.panel-tabs:not(:last-child), +.panel-block:not(:last-child) { + border-bottom: 1px solid #ededed; } + +.panel-heading { + background-color: #ededed; + border-radius: 6px 6px 0 0; + color: #363636; + font-size: 1.25em; + font-weight: 700; + line-height: 1.25; + padding: 0.75em 1em; } + +.panel-tabs { + align-items: flex-end; + display: flex; + font-size: 0.875em; + justify-content: center; } + .panel-tabs a { + border-bottom: 1px solid #dbdbdb; + margin-bottom: -1px; + padding: 0.5em; } + .panel-tabs a.is-active { + border-bottom-color: #4a4a4a; + color: #363636; } + +.panel-list a { + color: #4a4a4a; } + .panel-list a:hover { + color: #3273dc; } + +.panel-block { + align-items: center; + color: #363636; + display: flex; + justify-content: flex-start; + padding: 0.5em 0.75em; } + .panel-block input[type="checkbox"] { + margin-right: 0.75em; } + .panel-block > .control { + flex-grow: 1; + flex-shrink: 1; + width: 100%; } + .panel-block.is-wrapped { + flex-wrap: wrap; } + .panel-block.is-active { + border-left-color: #3273dc; + color: #363636; } + .panel-block.is-active .panel-icon { + color: #3273dc; } + .panel-block:last-child { + border-bottom-left-radius: 6px; + border-bottom-right-radius: 6px; } + +a.panel-block, +label.panel-block { + cursor: pointer; } + a.panel-block:hover, + label.panel-block:hover { + background-color: whitesmoke; } + +.panel-icon { + display: inline-block; + font-size: 14px; + height: 1em; + line-height: 1em; + text-align: center; + vertical-align: top; + width: 1em; + color: #7a7a7a; + margin-right: 0.75em; } + .panel-icon .fa { + font-size: inherit; + line-height: inherit; } + +.tabs { + -webkit-overflow-scrolling: touch; + align-items: stretch; + display: flex; + font-size: 1rem; + justify-content: space-between; + overflow: hidden; + overflow-x: auto; + white-space: nowrap; } + .tabs a { + align-items: center; + border-bottom-color: #dbdbdb; + border-bottom-style: solid; + border-bottom-width: 1px; + color: #4a4a4a; + display: flex; + justify-content: center; + margin-bottom: -1px; + padding: 0.5em 1em; + vertical-align: top; } + .tabs a:hover { + border-bottom-color: #363636; + color: #363636; } + .tabs li { + display: block; } + .tabs li.is-active a { + border-bottom-color: #3273dc; + color: #3273dc; } + .tabs ul { + align-items: center; + border-bottom-color: #dbdbdb; + border-bottom-style: solid; + border-bottom-width: 1px; + display: flex; + flex-grow: 1; + flex-shrink: 0; + justify-content: flex-start; } + .tabs ul.is-left { + padding-right: 0.75em; } + .tabs ul.is-center { + flex: none; + justify-content: center; + padding-left: 0.75em; + padding-right: 0.75em; } + .tabs ul.is-right { + justify-content: flex-end; + padding-left: 0.75em; } + .tabs .icon:first-child { + margin-right: 0.5em; } + .tabs .icon:last-child { + margin-left: 0.5em; } + .tabs.is-centered ul { + justify-content: center; } + .tabs.is-right ul { + justify-content: flex-end; } + .tabs.is-boxed a { + border: 1px solid transparent; + border-radius: 4px 4px 0 0; } + .tabs.is-boxed a:hover { + background-color: whitesmoke; + border-bottom-color: #dbdbdb; } + .tabs.is-boxed li.is-active a { + background-color: white; + border-color: #dbdbdb; + border-bottom-color: transparent !important; } + .tabs.is-fullwidth li { + flex-grow: 1; + flex-shrink: 0; } + .tabs.is-toggle a { + border-color: #dbdbdb; + border-style: solid; + border-width: 1px; + margin-bottom: 0; + position: relative; } + .tabs.is-toggle a:hover { + background-color: whitesmoke; + border-color: #b5b5b5; + z-index: 2; } + .tabs.is-toggle li + li { + margin-left: -1px; } + .tabs.is-toggle li:first-child a { + border-radius: 4px 0 0 4px; } + .tabs.is-toggle li:last-child a { + border-radius: 0 4px 4px 0; } + .tabs.is-toggle li.is-active a { + background-color: #3273dc; + border-color: #3273dc; + color: #fff; + z-index: 1; } + .tabs.is-toggle ul { + border-bottom: none; } + .tabs.is-toggle.is-toggle-rounded li:first-child a { + border-bottom-left-radius: 290486px; + border-top-left-radius: 290486px; + padding-left: 1.25em; } + .tabs.is-toggle.is-toggle-rounded li:last-child a { + border-bottom-right-radius: 290486px; + border-top-right-radius: 290486px; + padding-right: 1.25em; } + .tabs.is-small { + font-size: 0.75rem; } + .tabs.is-medium { + font-size: 1.25rem; } + .tabs.is-large { + font-size: 1.5rem; } + +.column { + display: block; + flex-basis: 0; + flex-grow: 1; + flex-shrink: 1; + padding: 0.75rem; } + .columns.is-mobile > .column.is-narrow { + flex: none; } + .columns.is-mobile > .column.is-full { + flex: none; + width: 100%; } + .columns.is-mobile > .column.is-three-quarters { + flex: none; + width: 75%; } + .columns.is-mobile > .column.is-two-thirds { + flex: none; + width: 66.6666%; } + .columns.is-mobile > .column.is-half { + flex: none; + width: 50%; } + .columns.is-mobile > .column.is-one-third { + flex: none; + width: 33.3333%; } + .columns.is-mobile > .column.is-one-quarter { + flex: none; + width: 25%; } + .columns.is-mobile > .column.is-one-fifth { + flex: none; + width: 20%; } + .columns.is-mobile > .column.is-two-fifths { + flex: none; + width: 40%; } + .columns.is-mobile > .column.is-three-fifths { + flex: none; + width: 60%; } + .columns.is-mobile > .column.is-four-fifths { + flex: none; + width: 80%; } + .columns.is-mobile > .column.is-offset-three-quarters { + margin-left: 75%; } + .columns.is-mobile > .column.is-offset-two-thirds { + margin-left: 66.6666%; } + .columns.is-mobile > .column.is-offset-half { + margin-left: 50%; } + .columns.is-mobile > .column.is-offset-one-third { + margin-left: 33.3333%; } + .columns.is-mobile > .column.is-offset-one-quarter { + margin-left: 25%; } + .columns.is-mobile > .column.is-offset-one-fifth { + margin-left: 20%; } + .columns.is-mobile > .column.is-offset-two-fifths { + margin-left: 40%; } + .columns.is-mobile > .column.is-offset-three-fifths { + margin-left: 60%; } + .columns.is-mobile > .column.is-offset-four-fifths { + margin-left: 80%; } + .columns.is-mobile > .column.is-0 { + flex: none; + width: 0%; } + .columns.is-mobile > .column.is-offset-0 { + margin-left: 0%; } + .columns.is-mobile > .column.is-1 { + flex: none; + width: 8.33333%; } + .columns.is-mobile > .column.is-offset-1 { + margin-left: 8.33333%; } + .columns.is-mobile > .column.is-2 { + flex: none; + width: 16.66667%; } + .columns.is-mobile > .column.is-offset-2 { + margin-left: 16.66667%; } + .columns.is-mobile > .column.is-3 { + flex: none; + width: 25%; } + .columns.is-mobile > .column.is-offset-3 { + margin-left: 25%; } + .columns.is-mobile > .column.is-4 { + flex: none; + width: 33.33333%; } + .columns.is-mobile > .column.is-offset-4 { + margin-left: 33.33333%; } + .columns.is-mobile > .column.is-5 { + flex: none; + width: 41.66667%; } + .columns.is-mobile > .column.is-offset-5 { + margin-left: 41.66667%; } + .columns.is-mobile > .column.is-6 { + flex: none; + width: 50%; } + .columns.is-mobile > .column.is-offset-6 { + margin-left: 50%; } + .columns.is-mobile > .column.is-7 { + flex: none; + width: 58.33333%; } + .columns.is-mobile > .column.is-offset-7 { + margin-left: 58.33333%; } + .columns.is-mobile > .column.is-8 { + flex: none; + width: 66.66667%; } + .columns.is-mobile > .column.is-offset-8 { + margin-left: 66.66667%; } + .columns.is-mobile > .column.is-9 { + flex: none; + width: 75%; } + .columns.is-mobile > .column.is-offset-9 { + margin-left: 75%; } + .columns.is-mobile > .column.is-10 { + flex: none; + width: 83.33333%; } + .columns.is-mobile > .column.is-offset-10 { + margin-left: 83.33333%; } + .columns.is-mobile > .column.is-11 { + flex: none; + width: 91.66667%; } + .columns.is-mobile > .column.is-offset-11 { + margin-left: 91.66667%; } + .columns.is-mobile > .column.is-12 { + flex: none; + width: 100%; } + .columns.is-mobile > .column.is-offset-12 { + margin-left: 100%; } + @media screen and (max-width: 768px) { + .column.is-narrow-mobile { + flex: none; } + .column.is-full-mobile { + flex: none; + width: 100%; } + .column.is-three-quarters-mobile { + flex: none; + width: 75%; } + .column.is-two-thirds-mobile { + flex: none; + width: 66.6666%; } + .column.is-half-mobile { + flex: none; + width: 50%; } + .column.is-one-third-mobile { + flex: none; + width: 33.3333%; } + .column.is-one-quarter-mobile { + flex: none; + width: 25%; } + .column.is-one-fifth-mobile { + flex: none; + width: 20%; } + .column.is-two-fifths-mobile { + flex: none; + width: 40%; } + .column.is-three-fifths-mobile { + flex: none; + width: 60%; } + .column.is-four-fifths-mobile { + flex: none; + width: 80%; } + .column.is-offset-three-quarters-mobile { + margin-left: 75%; } + .column.is-offset-two-thirds-mobile { + margin-left: 66.6666%; } + .column.is-offset-half-mobile { + margin-left: 50%; } + .column.is-offset-one-third-mobile { + margin-left: 33.3333%; } + .column.is-offset-one-quarter-mobile { + margin-left: 25%; } + .column.is-offset-one-fifth-mobile { + margin-left: 20%; } + .column.is-offset-two-fifths-mobile { + margin-left: 40%; } + .column.is-offset-three-fifths-mobile { + margin-left: 60%; } + .column.is-offset-four-fifths-mobile { + margin-left: 80%; } + .column.is-0-mobile { + flex: none; + width: 0%; } + .column.is-offset-0-mobile { + margin-left: 0%; } + .column.is-1-mobile { + flex: none; + width: 8.33333%; } + .column.is-offset-1-mobile { + margin-left: 8.33333%; } + .column.is-2-mobile { + flex: none; + width: 16.66667%; } + .column.is-offset-2-mobile { + margin-left: 16.66667%; } + .column.is-3-mobile { + flex: none; + width: 25%; } + .column.is-offset-3-mobile { + margin-left: 25%; } + .column.is-4-mobile { + flex: none; + width: 33.33333%; } + .column.is-offset-4-mobile { + margin-left: 33.33333%; } + .column.is-5-mobile { + flex: none; + width: 41.66667%; } + .column.is-offset-5-mobile { + margin-left: 41.66667%; } + .column.is-6-mobile { + flex: none; + width: 50%; } + .column.is-offset-6-mobile { + margin-left: 50%; } + .column.is-7-mobile { + flex: none; + width: 58.33333%; } + .column.is-offset-7-mobile { + margin-left: 58.33333%; } + .column.is-8-mobile { + flex: none; + width: 66.66667%; } + .column.is-offset-8-mobile { + margin-left: 66.66667%; } + .column.is-9-mobile { + flex: none; + width: 75%; } + .column.is-offset-9-mobile { + margin-left: 75%; } + .column.is-10-mobile { + flex: none; + width: 83.33333%; } + .column.is-offset-10-mobile { + margin-left: 83.33333%; } + .column.is-11-mobile { + flex: none; + width: 91.66667%; } + .column.is-offset-11-mobile { + margin-left: 91.66667%; } + .column.is-12-mobile { + flex: none; + width: 100%; } + .column.is-offset-12-mobile { + margin-left: 100%; } } + @media screen and (min-width: 769px), print { + .column.is-narrow, .column.is-narrow-tablet { + flex: none; } + .column.is-full, .column.is-full-tablet { + flex: none; + width: 100%; } + .column.is-three-quarters, .column.is-three-quarters-tablet { + flex: none; + width: 75%; } + .column.is-two-thirds, .column.is-two-thirds-tablet { + flex: none; + width: 66.6666%; } + .column.is-half, .column.is-half-tablet { + flex: none; + width: 50%; } + .column.is-one-third, .column.is-one-third-tablet { + flex: none; + width: 33.3333%; } + .column.is-one-quarter, .column.is-one-quarter-tablet { + flex: none; + width: 25%; } + .column.is-one-fifth, .column.is-one-fifth-tablet { + flex: none; + width: 20%; } + .column.is-two-fifths, .column.is-two-fifths-tablet { + flex: none; + width: 40%; } + .column.is-three-fifths, .column.is-three-fifths-tablet { + flex: none; + width: 60%; } + .column.is-four-fifths, .column.is-four-fifths-tablet { + flex: none; + width: 80%; } + .column.is-offset-three-quarters, .column.is-offset-three-quarters-tablet { + margin-left: 75%; } + .column.is-offset-two-thirds, .column.is-offset-two-thirds-tablet { + margin-left: 66.6666%; } + .column.is-offset-half, .column.is-offset-half-tablet { + margin-left: 50%; } + .column.is-offset-one-third, .column.is-offset-one-third-tablet { + margin-left: 33.3333%; } + .column.is-offset-one-quarter, .column.is-offset-one-quarter-tablet { + margin-left: 25%; } + .column.is-offset-one-fifth, .column.is-offset-one-fifth-tablet { + margin-left: 20%; } + .column.is-offset-two-fifths, .column.is-offset-two-fifths-tablet { + margin-left: 40%; } + .column.is-offset-three-fifths, .column.is-offset-three-fifths-tablet { + margin-left: 60%; } + .column.is-offset-four-fifths, .column.is-offset-four-fifths-tablet { + margin-left: 80%; } + .column.is-0, .column.is-0-tablet { + flex: none; + width: 0%; } + .column.is-offset-0, .column.is-offset-0-tablet { + margin-left: 0%; } + .column.is-1, .column.is-1-tablet { + flex: none; + width: 8.33333%; } + .column.is-offset-1, .column.is-offset-1-tablet { + margin-left: 8.33333%; } + .column.is-2, .column.is-2-tablet { + flex: none; + width: 16.66667%; } + .column.is-offset-2, .column.is-offset-2-tablet { + margin-left: 16.66667%; } + .column.is-3, .column.is-3-tablet { + flex: none; + width: 25%; } + .column.is-offset-3, .column.is-offset-3-tablet { + margin-left: 25%; } + .column.is-4, .column.is-4-tablet { + flex: none; + width: 33.33333%; } + .column.is-offset-4, .column.is-offset-4-tablet { + margin-left: 33.33333%; } + .column.is-5, .column.is-5-tablet { + flex: none; + width: 41.66667%; } + .column.is-offset-5, .column.is-offset-5-tablet { + margin-left: 41.66667%; } + .column.is-6, .column.is-6-tablet { + flex: none; + width: 50%; } + .column.is-offset-6, .column.is-offset-6-tablet { + margin-left: 50%; } + .column.is-7, .column.is-7-tablet { + flex: none; + width: 58.33333%; } + .column.is-offset-7, .column.is-offset-7-tablet { + margin-left: 58.33333%; } + .column.is-8, .column.is-8-tablet { + flex: none; + width: 66.66667%; } + .column.is-offset-8, .column.is-offset-8-tablet { + margin-left: 66.66667%; } + .column.is-9, .column.is-9-tablet { + flex: none; + width: 75%; } + .column.is-offset-9, .column.is-offset-9-tablet { + margin-left: 75%; } + .column.is-10, .column.is-10-tablet { + flex: none; + width: 83.33333%; } + .column.is-offset-10, .column.is-offset-10-tablet { + margin-left: 83.33333%; } + .column.is-11, .column.is-11-tablet { + flex: none; + width: 91.66667%; } + .column.is-offset-11, .column.is-offset-11-tablet { + margin-left: 91.66667%; } + .column.is-12, .column.is-12-tablet { + flex: none; + width: 100%; } + .column.is-offset-12, .column.is-offset-12-tablet { + margin-left: 100%; } } + @media screen and (max-width: 1023px) { + .column.is-narrow-touch { + flex: none; } + .column.is-full-touch { + flex: none; + width: 100%; } + .column.is-three-quarters-touch { + flex: none; + width: 75%; } + .column.is-two-thirds-touch { + flex: none; + width: 66.6666%; } + .column.is-half-touch { + flex: none; + width: 50%; } + .column.is-one-third-touch { + flex: none; + width: 33.3333%; } + .column.is-one-quarter-touch { + flex: none; + width: 25%; } + .column.is-one-fifth-touch { + flex: none; + width: 20%; } + .column.is-two-fifths-touch { + flex: none; + width: 40%; } + .column.is-three-fifths-touch { + flex: none; + width: 60%; } + .column.is-four-fifths-touch { + flex: none; + width: 80%; } + .column.is-offset-three-quarters-touch { + margin-left: 75%; } + .column.is-offset-two-thirds-touch { + margin-left: 66.6666%; } + .column.is-offset-half-touch { + margin-left: 50%; } + .column.is-offset-one-third-touch { + margin-left: 33.3333%; } + .column.is-offset-one-quarter-touch { + margin-left: 25%; } + .column.is-offset-one-fifth-touch { + margin-left: 20%; } + .column.is-offset-two-fifths-touch { + margin-left: 40%; } + .column.is-offset-three-fifths-touch { + margin-left: 60%; } + .column.is-offset-four-fifths-touch { + margin-left: 80%; } + .column.is-0-touch { + flex: none; + width: 0%; } + .column.is-offset-0-touch { + margin-left: 0%; } + .column.is-1-touch { + flex: none; + width: 8.33333%; } + .column.is-offset-1-touch { + margin-left: 8.33333%; } + .column.is-2-touch { + flex: none; + width: 16.66667%; } + .column.is-offset-2-touch { + margin-left: 16.66667%; } + .column.is-3-touch { + flex: none; + width: 25%; } + .column.is-offset-3-touch { + margin-left: 25%; } + .column.is-4-touch { + flex: none; + width: 33.33333%; } + .column.is-offset-4-touch { + margin-left: 33.33333%; } + .column.is-5-touch { + flex: none; + width: 41.66667%; } + .column.is-offset-5-touch { + margin-left: 41.66667%; } + .column.is-6-touch { + flex: none; + width: 50%; } + .column.is-offset-6-touch { + margin-left: 50%; } + .column.is-7-touch { + flex: none; + width: 58.33333%; } + .column.is-offset-7-touch { + margin-left: 58.33333%; } + .column.is-8-touch { + flex: none; + width: 66.66667%; } + .column.is-offset-8-touch { + margin-left: 66.66667%; } + .column.is-9-touch { + flex: none; + width: 75%; } + .column.is-offset-9-touch { + margin-left: 75%; } + .column.is-10-touch { + flex: none; + width: 83.33333%; } + .column.is-offset-10-touch { + margin-left: 83.33333%; } + .column.is-11-touch { + flex: none; + width: 91.66667%; } + .column.is-offset-11-touch { + margin-left: 91.66667%; } + .column.is-12-touch { + flex: none; + width: 100%; } + .column.is-offset-12-touch { + margin-left: 100%; } } + @media screen and (min-width: 1024px) { + .column.is-narrow-desktop { + flex: none; } + .column.is-full-desktop { + flex: none; + width: 100%; } + .column.is-three-quarters-desktop { + flex: none; + width: 75%; } + .column.is-two-thirds-desktop { + flex: none; + width: 66.6666%; } + .column.is-half-desktop { + flex: none; + width: 50%; } + .column.is-one-third-desktop { + flex: none; + width: 33.3333%; } + .column.is-one-quarter-desktop { + flex: none; + width: 25%; } + .column.is-one-fifth-desktop { + flex: none; + width: 20%; } + .column.is-two-fifths-desktop { + flex: none; + width: 40%; } + .column.is-three-fifths-desktop { + flex: none; + width: 60%; } + .column.is-four-fifths-desktop { + flex: none; + width: 80%; } + .column.is-offset-three-quarters-desktop { + margin-left: 75%; } + .column.is-offset-two-thirds-desktop { + margin-left: 66.6666%; } + .column.is-offset-half-desktop { + margin-left: 50%; } + .column.is-offset-one-third-desktop { + margin-left: 33.3333%; } + .column.is-offset-one-quarter-desktop { + margin-left: 25%; } + .column.is-offset-one-fifth-desktop { + margin-left: 20%; } + .column.is-offset-two-fifths-desktop { + margin-left: 40%; } + .column.is-offset-three-fifths-desktop { + margin-left: 60%; } + .column.is-offset-four-fifths-desktop { + margin-left: 80%; } + .column.is-0-desktop { + flex: none; + width: 0%; } + .column.is-offset-0-desktop { + margin-left: 0%; } + .column.is-1-desktop { + flex: none; + width: 8.33333%; } + .column.is-offset-1-desktop { + margin-left: 8.33333%; } + .column.is-2-desktop { + flex: none; + width: 16.66667%; } + .column.is-offset-2-desktop { + margin-left: 16.66667%; } + .column.is-3-desktop { + flex: none; + width: 25%; } + .column.is-offset-3-desktop { + margin-left: 25%; } + .column.is-4-desktop { + flex: none; + width: 33.33333%; } + .column.is-offset-4-desktop { + margin-left: 33.33333%; } + .column.is-5-desktop { + flex: none; + width: 41.66667%; } + .column.is-offset-5-desktop { + margin-left: 41.66667%; } + .column.is-6-desktop { + flex: none; + width: 50%; } + .column.is-offset-6-desktop { + margin-left: 50%; } + .column.is-7-desktop { + flex: none; + width: 58.33333%; } + .column.is-offset-7-desktop { + margin-left: 58.33333%; } + .column.is-8-desktop { + flex: none; + width: 66.66667%; } + .column.is-offset-8-desktop { + margin-left: 66.66667%; } + .column.is-9-desktop { + flex: none; + width: 75%; } + .column.is-offset-9-desktop { + margin-left: 75%; } + .column.is-10-desktop { + flex: none; + width: 83.33333%; } + .column.is-offset-10-desktop { + margin-left: 83.33333%; } + .column.is-11-desktop { + flex: none; + width: 91.66667%; } + .column.is-offset-11-desktop { + margin-left: 91.66667%; } + .column.is-12-desktop { + flex: none; + width: 100%; } + .column.is-offset-12-desktop { + margin-left: 100%; } } + @media screen and (min-width: 1216px) { + .column.is-narrow-widescreen { + flex: none; } + .column.is-full-widescreen { + flex: none; + width: 100%; } + .column.is-three-quarters-widescreen { + flex: none; + width: 75%; } + .column.is-two-thirds-widescreen { + flex: none; + width: 66.6666%; } + .column.is-half-widescreen { + flex: none; + width: 50%; } + .column.is-one-third-widescreen { + flex: none; + width: 33.3333%; } + .column.is-one-quarter-widescreen { + flex: none; + width: 25%; } + .column.is-one-fifth-widescreen { + flex: none; + width: 20%; } + .column.is-two-fifths-widescreen { + flex: none; + width: 40%; } + .column.is-three-fifths-widescreen { + flex: none; + width: 60%; } + .column.is-four-fifths-widescreen { + flex: none; + width: 80%; } + .column.is-offset-three-quarters-widescreen { + margin-left: 75%; } + .column.is-offset-two-thirds-widescreen { + margin-left: 66.6666%; } + .column.is-offset-half-widescreen { + margin-left: 50%; } + .column.is-offset-one-third-widescreen { + margin-left: 33.3333%; } + .column.is-offset-one-quarter-widescreen { + margin-left: 25%; } + .column.is-offset-one-fifth-widescreen { + margin-left: 20%; } + .column.is-offset-two-fifths-widescreen { + margin-left: 40%; } + .column.is-offset-three-fifths-widescreen { + margin-left: 60%; } + .column.is-offset-four-fifths-widescreen { + margin-left: 80%; } + .column.is-0-widescreen { + flex: none; + width: 0%; } + .column.is-offset-0-widescreen { + margin-left: 0%; } + .column.is-1-widescreen { + flex: none; + width: 8.33333%; } + .column.is-offset-1-widescreen { + margin-left: 8.33333%; } + .column.is-2-widescreen { + flex: none; + width: 16.66667%; } + .column.is-offset-2-widescreen { + margin-left: 16.66667%; } + .column.is-3-widescreen { + flex: none; + width: 25%; } + .column.is-offset-3-widescreen { + margin-left: 25%; } + .column.is-4-widescreen { + flex: none; + width: 33.33333%; } + .column.is-offset-4-widescreen { + margin-left: 33.33333%; } + .column.is-5-widescreen { + flex: none; + width: 41.66667%; } + .column.is-offset-5-widescreen { + margin-left: 41.66667%; } + .column.is-6-widescreen { + flex: none; + width: 50%; } + .column.is-offset-6-widescreen { + margin-left: 50%; } + .column.is-7-widescreen { + flex: none; + width: 58.33333%; } + .column.is-offset-7-widescreen { + margin-left: 58.33333%; } + .column.is-8-widescreen { + flex: none; + width: 66.66667%; } + .column.is-offset-8-widescreen { + margin-left: 66.66667%; } + .column.is-9-widescreen { + flex: none; + width: 75%; } + .column.is-offset-9-widescreen { + margin-left: 75%; } + .column.is-10-widescreen { + flex: none; + width: 83.33333%; } + .column.is-offset-10-widescreen { + margin-left: 83.33333%; } + .column.is-11-widescreen { + flex: none; + width: 91.66667%; } + .column.is-offset-11-widescreen { + margin-left: 91.66667%; } + .column.is-12-widescreen { + flex: none; + width: 100%; } + .column.is-offset-12-widescreen { + margin-left: 100%; } } + @media screen and (min-width: 1408px) { + .column.is-narrow-fullhd { + flex: none; } + .column.is-full-fullhd { + flex: none; + width: 100%; } + .column.is-three-quarters-fullhd { + flex: none; + width: 75%; } + .column.is-two-thirds-fullhd { + flex: none; + width: 66.6666%; } + .column.is-half-fullhd { + flex: none; + width: 50%; } + .column.is-one-third-fullhd { + flex: none; + width: 33.3333%; } + .column.is-one-quarter-fullhd { + flex: none; + width: 25%; } + .column.is-one-fifth-fullhd { + flex: none; + width: 20%; } + .column.is-two-fifths-fullhd { + flex: none; + width: 40%; } + .column.is-three-fifths-fullhd { + flex: none; + width: 60%; } + .column.is-four-fifths-fullhd { + flex: none; + width: 80%; } + .column.is-offset-three-quarters-fullhd { + margin-left: 75%; } + .column.is-offset-two-thirds-fullhd { + margin-left: 66.6666%; } + .column.is-offset-half-fullhd { + margin-left: 50%; } + .column.is-offset-one-third-fullhd { + margin-left: 33.3333%; } + .column.is-offset-one-quarter-fullhd { + margin-left: 25%; } + .column.is-offset-one-fifth-fullhd { + margin-left: 20%; } + .column.is-offset-two-fifths-fullhd { + margin-left: 40%; } + .column.is-offset-three-fifths-fullhd { + margin-left: 60%; } + .column.is-offset-four-fifths-fullhd { + margin-left: 80%; } + .column.is-0-fullhd { + flex: none; + width: 0%; } + .column.is-offset-0-fullhd { + margin-left: 0%; } + .column.is-1-fullhd { + flex: none; + width: 8.33333%; } + .column.is-offset-1-fullhd { + margin-left: 8.33333%; } + .column.is-2-fullhd { + flex: none; + width: 16.66667%; } + .column.is-offset-2-fullhd { + margin-left: 16.66667%; } + .column.is-3-fullhd { + flex: none; + width: 25%; } + .column.is-offset-3-fullhd { + margin-left: 25%; } + .column.is-4-fullhd { + flex: none; + width: 33.33333%; } + .column.is-offset-4-fullhd { + margin-left: 33.33333%; } + .column.is-5-fullhd { + flex: none; + width: 41.66667%; } + .column.is-offset-5-fullhd { + margin-left: 41.66667%; } + .column.is-6-fullhd { + flex: none; + width: 50%; } + .column.is-offset-6-fullhd { + margin-left: 50%; } + .column.is-7-fullhd { + flex: none; + width: 58.33333%; } + .column.is-offset-7-fullhd { + margin-left: 58.33333%; } + .column.is-8-fullhd { + flex: none; + width: 66.66667%; } + .column.is-offset-8-fullhd { + margin-left: 66.66667%; } + .column.is-9-fullhd { + flex: none; + width: 75%; } + .column.is-offset-9-fullhd { + margin-left: 75%; } + .column.is-10-fullhd { + flex: none; + width: 83.33333%; } + .column.is-offset-10-fullhd { + margin-left: 83.33333%; } + .column.is-11-fullhd { + flex: none; + width: 91.66667%; } + .column.is-offset-11-fullhd { + margin-left: 91.66667%; } + .column.is-12-fullhd { + flex: none; + width: 100%; } + .column.is-offset-12-fullhd { + margin-left: 100%; } } + +.columns { + margin-left: -0.75rem; + margin-right: -0.75rem; + margin-top: -0.75rem; } + .columns:last-child { + margin-bottom: -0.75rem; } + .columns:not(:last-child) { + margin-bottom: calc(1.5rem - 0.75rem); } + .columns.is-centered { + justify-content: center; } + .columns.is-gapless { + margin-left: 0; + margin-right: 0; + margin-top: 0; } + .columns.is-gapless > .column { + margin: 0; + padding: 0 !important; } + .columns.is-gapless:not(:last-child) { + margin-bottom: 1.5rem; } + .columns.is-gapless:last-child { + margin-bottom: 0; } + .columns.is-mobile { + display: flex; } + .columns.is-multiline { + flex-wrap: wrap; } + .columns.is-vcentered { + align-items: center; } + @media screen and (min-width: 769px), print { + .columns:not(.is-desktop) { + display: flex; } } + @media screen and (min-width: 1024px) { + .columns.is-desktop { + display: flex; } } + +.columns.is-variable { + --columnGap: 0.75rem; + margin-left: calc(-1 * var(--columnGap)); + margin-right: calc(-1 * var(--columnGap)); } + .columns.is-variable .column { + padding-left: var(--columnGap); + padding-right: var(--columnGap); } + .columns.is-variable.is-0 { + --columnGap: 0rem; } + @media screen and (max-width: 768px) { + .columns.is-variable.is-0-mobile { + --columnGap: 0rem; } } + @media screen and (min-width: 769px), print { + .columns.is-variable.is-0-tablet { + --columnGap: 0rem; } } + @media screen and (min-width: 769px) and (max-width: 1023px) { + .columns.is-variable.is-0-tablet-only { + --columnGap: 0rem; } } + @media screen and (max-width: 1023px) { + .columns.is-variable.is-0-touch { + --columnGap: 0rem; } } + @media screen and (min-width: 1024px) { + .columns.is-variable.is-0-desktop { + --columnGap: 0rem; } } + @media screen and (min-width: 1024px) and (max-width: 1215px) { + .columns.is-variable.is-0-desktop-only { + --columnGap: 0rem; } } + @media screen and (min-width: 1216px) { + .columns.is-variable.is-0-widescreen { + --columnGap: 0rem; } } + @media screen and (min-width: 1216px) and (max-width: 1407px) { + .columns.is-variable.is-0-widescreen-only { + --columnGap: 0rem; } } + @media screen and (min-width: 1408px) { + .columns.is-variable.is-0-fullhd { + --columnGap: 0rem; } } + .columns.is-variable.is-1 { + --columnGap: 0.25rem; } + @media screen and (max-width: 768px) { + .columns.is-variable.is-1-mobile { + --columnGap: 0.25rem; } } + @media screen and (min-width: 769px), print { + .columns.is-variable.is-1-tablet { + --columnGap: 0.25rem; } } + @media screen and (min-width: 769px) and (max-width: 1023px) { + .columns.is-variable.is-1-tablet-only { + --columnGap: 0.25rem; } } + @media screen and (max-width: 1023px) { + .columns.is-variable.is-1-touch { + --columnGap: 0.25rem; } } + @media screen and (min-width: 1024px) { + .columns.is-variable.is-1-desktop { + --columnGap: 0.25rem; } } + @media screen and (min-width: 1024px) and (max-width: 1215px) { + .columns.is-variable.is-1-desktop-only { + --columnGap: 0.25rem; } } + @media screen and (min-width: 1216px) { + .columns.is-variable.is-1-widescreen { + --columnGap: 0.25rem; } } + @media screen and (min-width: 1216px) and (max-width: 1407px) { + .columns.is-variable.is-1-widescreen-only { + --columnGap: 0.25rem; } } + @media screen and (min-width: 1408px) { + .columns.is-variable.is-1-fullhd { + --columnGap: 0.25rem; } } + .columns.is-variable.is-2 { + --columnGap: 0.5rem; } + @media screen and (max-width: 768px) { + .columns.is-variable.is-2-mobile { + --columnGap: 0.5rem; } } + @media screen and (min-width: 769px), print { + .columns.is-variable.is-2-tablet { + --columnGap: 0.5rem; } } + @media screen and (min-width: 769px) and (max-width: 1023px) { + .columns.is-variable.is-2-tablet-only { + --columnGap: 0.5rem; } } + @media screen and (max-width: 1023px) { + .columns.is-variable.is-2-touch { + --columnGap: 0.5rem; } } + @media screen and (min-width: 1024px) { + .columns.is-variable.is-2-desktop { + --columnGap: 0.5rem; } } + @media screen and (min-width: 1024px) and (max-width: 1215px) { + .columns.is-variable.is-2-desktop-only { + --columnGap: 0.5rem; } } + @media screen and (min-width: 1216px) { + .columns.is-variable.is-2-widescreen { + --columnGap: 0.5rem; } } + @media screen and (min-width: 1216px) and (max-width: 1407px) { + .columns.is-variable.is-2-widescreen-only { + --columnGap: 0.5rem; } } + @media screen and (min-width: 1408px) { + .columns.is-variable.is-2-fullhd { + --columnGap: 0.5rem; } } + .columns.is-variable.is-3 { + --columnGap: 0.75rem; } + @media screen and (max-width: 768px) { + .columns.is-variable.is-3-mobile { + --columnGap: 0.75rem; } } + @media screen and (min-width: 769px), print { + .columns.is-variable.is-3-tablet { + --columnGap: 0.75rem; } } + @media screen and (min-width: 769px) and (max-width: 1023px) { + .columns.is-variable.is-3-tablet-only { + --columnGap: 0.75rem; } } + @media screen and (max-width: 1023px) { + .columns.is-variable.is-3-touch { + --columnGap: 0.75rem; } } + @media screen and (min-width: 1024px) { + .columns.is-variable.is-3-desktop { + --columnGap: 0.75rem; } } + @media screen and (min-width: 1024px) and (max-width: 1215px) { + .columns.is-variable.is-3-desktop-only { + --columnGap: 0.75rem; } } + @media screen and (min-width: 1216px) { + .columns.is-variable.is-3-widescreen { + --columnGap: 0.75rem; } } + @media screen and (min-width: 1216px) and (max-width: 1407px) { + .columns.is-variable.is-3-widescreen-only { + --columnGap: 0.75rem; } } + @media screen and (min-width: 1408px) { + .columns.is-variable.is-3-fullhd { + --columnGap: 0.75rem; } } + .columns.is-variable.is-4 { + --columnGap: 1rem; } + @media screen and (max-width: 768px) { + .columns.is-variable.is-4-mobile { + --columnGap: 1rem; } } + @media screen and (min-width: 769px), print { + .columns.is-variable.is-4-tablet { + --columnGap: 1rem; } } + @media screen and (min-width: 769px) and (max-width: 1023px) { + .columns.is-variable.is-4-tablet-only { + --columnGap: 1rem; } } + @media screen and (max-width: 1023px) { + .columns.is-variable.is-4-touch { + --columnGap: 1rem; } } + @media screen and (min-width: 1024px) { + .columns.is-variable.is-4-desktop { + --columnGap: 1rem; } } + @media screen and (min-width: 1024px) and (max-width: 1215px) { + .columns.is-variable.is-4-desktop-only { + --columnGap: 1rem; } } + @media screen and (min-width: 1216px) { + .columns.is-variable.is-4-widescreen { + --columnGap: 1rem; } } + @media screen and (min-width: 1216px) and (max-width: 1407px) { + .columns.is-variable.is-4-widescreen-only { + --columnGap: 1rem; } } + @media screen and (min-width: 1408px) { + .columns.is-variable.is-4-fullhd { + --columnGap: 1rem; } } + .columns.is-variable.is-5 { + --columnGap: 1.25rem; } + @media screen and (max-width: 768px) { + .columns.is-variable.is-5-mobile { + --columnGap: 1.25rem; } } + @media screen and (min-width: 769px), print { + .columns.is-variable.is-5-tablet { + --columnGap: 1.25rem; } } + @media screen and (min-width: 769px) and (max-width: 1023px) { + .columns.is-variable.is-5-tablet-only { + --columnGap: 1.25rem; } } + @media screen and (max-width: 1023px) { + .columns.is-variable.is-5-touch { + --columnGap: 1.25rem; } } + @media screen and (min-width: 1024px) { + .columns.is-variable.is-5-desktop { + --columnGap: 1.25rem; } } + @media screen and (min-width: 1024px) and (max-width: 1215px) { + .columns.is-variable.is-5-desktop-only { + --columnGap: 1.25rem; } } + @media screen and (min-width: 1216px) { + .columns.is-variable.is-5-widescreen { + --columnGap: 1.25rem; } } + @media screen and (min-width: 1216px) and (max-width: 1407px) { + .columns.is-variable.is-5-widescreen-only { + --columnGap: 1.25rem; } } + @media screen and (min-width: 1408px) { + .columns.is-variable.is-5-fullhd { + --columnGap: 1.25rem; } } + .columns.is-variable.is-6 { + --columnGap: 1.5rem; } + @media screen and (max-width: 768px) { + .columns.is-variable.is-6-mobile { + --columnGap: 1.5rem; } } + @media screen and (min-width: 769px), print { + .columns.is-variable.is-6-tablet { + --columnGap: 1.5rem; } } + @media screen and (min-width: 769px) and (max-width: 1023px) { + .columns.is-variable.is-6-tablet-only { + --columnGap: 1.5rem; } } + @media screen and (max-width: 1023px) { + .columns.is-variable.is-6-touch { + --columnGap: 1.5rem; } } + @media screen and (min-width: 1024px) { + .columns.is-variable.is-6-desktop { + --columnGap: 1.5rem; } } + @media screen and (min-width: 1024px) and (max-width: 1215px) { + .columns.is-variable.is-6-desktop-only { + --columnGap: 1.5rem; } } + @media screen and (min-width: 1216px) { + .columns.is-variable.is-6-widescreen { + --columnGap: 1.5rem; } } + @media screen and (min-width: 1216px) and (max-width: 1407px) { + .columns.is-variable.is-6-widescreen-only { + --columnGap: 1.5rem; } } + @media screen and (min-width: 1408px) { + .columns.is-variable.is-6-fullhd { + --columnGap: 1.5rem; } } + .columns.is-variable.is-7 { + --columnGap: 1.75rem; } + @media screen and (max-width: 768px) { + .columns.is-variable.is-7-mobile { + --columnGap: 1.75rem; } } + @media screen and (min-width: 769px), print { + .columns.is-variable.is-7-tablet { + --columnGap: 1.75rem; } } + @media screen and (min-width: 769px) and (max-width: 1023px) { + .columns.is-variable.is-7-tablet-only { + --columnGap: 1.75rem; } } + @media screen and (max-width: 1023px) { + .columns.is-variable.is-7-touch { + --columnGap: 1.75rem; } } + @media screen and (min-width: 1024px) { + .columns.is-variable.is-7-desktop { + --columnGap: 1.75rem; } } + @media screen and (min-width: 1024px) and (max-width: 1215px) { + .columns.is-variable.is-7-desktop-only { + --columnGap: 1.75rem; } } + @media screen and (min-width: 1216px) { + .columns.is-variable.is-7-widescreen { + --columnGap: 1.75rem; } } + @media screen and (min-width: 1216px) and (max-width: 1407px) { + .columns.is-variable.is-7-widescreen-only { + --columnGap: 1.75rem; } } + @media screen and (min-width: 1408px) { + .columns.is-variable.is-7-fullhd { + --columnGap: 1.75rem; } } + .columns.is-variable.is-8 { + --columnGap: 2rem; } + @media screen and (max-width: 768px) { + .columns.is-variable.is-8-mobile { + --columnGap: 2rem; } } + @media screen and (min-width: 769px), print { + .columns.is-variable.is-8-tablet { + --columnGap: 2rem; } } + @media screen and (min-width: 769px) and (max-width: 1023px) { + .columns.is-variable.is-8-tablet-only { + --columnGap: 2rem; } } + @media screen and (max-width: 1023px) { + .columns.is-variable.is-8-touch { + --columnGap: 2rem; } } + @media screen and (min-width: 1024px) { + .columns.is-variable.is-8-desktop { + --columnGap: 2rem; } } + @media screen and (min-width: 1024px) and (max-width: 1215px) { + .columns.is-variable.is-8-desktop-only { + --columnGap: 2rem; } } + @media screen and (min-width: 1216px) { + .columns.is-variable.is-8-widescreen { + --columnGap: 2rem; } } + @media screen and (min-width: 1216px) and (max-width: 1407px) { + .columns.is-variable.is-8-widescreen-only { + --columnGap: 2rem; } } + @media screen and (min-width: 1408px) { + .columns.is-variable.is-8-fullhd { + --columnGap: 2rem; } } + +.tile { + align-items: stretch; + display: block; + flex-basis: 0; + flex-grow: 1; + flex-shrink: 1; + min-height: min-content; } + .tile.is-ancestor { + margin-left: -0.75rem; + margin-right: -0.75rem; + margin-top: -0.75rem; } + .tile.is-ancestor:last-child { + margin-bottom: -0.75rem; } + .tile.is-ancestor:not(:last-child) { + margin-bottom: 0.75rem; } + .tile.is-child { + margin: 0 !important; } + .tile.is-parent { + padding: 0.75rem; } + .tile.is-vertical { + flex-direction: column; } + .tile.is-vertical > .tile.is-child:not(:last-child) { + margin-bottom: 1.5rem !important; } + @media screen and (min-width: 769px), print { + .tile:not(.is-child) { + display: flex; } + .tile.is-1 { + flex: none; + width: 8.33333%; } + .tile.is-2 { + flex: none; + width: 16.66667%; } + .tile.is-3 { + flex: none; + width: 25%; } + .tile.is-4 { + flex: none; + width: 33.33333%; } + .tile.is-5 { + flex: none; + width: 41.66667%; } + .tile.is-6 { + flex: none; + width: 50%; } + .tile.is-7 { + flex: none; + width: 58.33333%; } + .tile.is-8 { + flex: none; + width: 66.66667%; } + .tile.is-9 { + flex: none; + width: 75%; } + .tile.is-10 { + flex: none; + width: 83.33333%; } + .tile.is-11 { + flex: none; + width: 91.66667%; } + .tile.is-12 { + flex: none; + width: 100%; } } + +.hero { + align-items: stretch; + display: flex; + flex-direction: column; + justify-content: space-between; } + .hero .navbar { + background: none; } + .hero .tabs ul { + border-bottom: none; } + .hero.is-white { + background-color: white; + color: #0a0a0a; } + .hero.is-white a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current), + .hero.is-white strong { + color: inherit; } + .hero.is-white .title { + color: #0a0a0a; } + .hero.is-white .subtitle { + color: rgba(10, 10, 10, 0.9); } + .hero.is-white .subtitle a:not(.button), + .hero.is-white .subtitle strong { + color: #0a0a0a; } + @media screen and (max-width: 1023px) { + .hero.is-white .navbar-menu { + background-color: white; } } + .hero.is-white .navbar-item, + .hero.is-white .navbar-link { + color: rgba(10, 10, 10, 0.7); } + .hero.is-white a.navbar-item:hover, .hero.is-white a.navbar-item.is-active, + .hero.is-white .navbar-link:hover, + .hero.is-white .navbar-link.is-active { + background-color: #f2f2f2; + color: #0a0a0a; } + .hero.is-white .tabs a { + color: #0a0a0a; + opacity: 0.9; } + .hero.is-white .tabs a:hover { + opacity: 1; } + .hero.is-white .tabs li.is-active a { + opacity: 1; } + .hero.is-white .tabs.is-boxed a, .hero.is-white .tabs.is-toggle a { + color: #0a0a0a; } + .hero.is-white .tabs.is-boxed a:hover, .hero.is-white .tabs.is-toggle a:hover { + background-color: rgba(10, 10, 10, 0.1); } + .hero.is-white .tabs.is-boxed li.is-active a, .hero.is-white .tabs.is-boxed li.is-active a:hover, .hero.is-white .tabs.is-toggle li.is-active a, .hero.is-white .tabs.is-toggle li.is-active a:hover { + background-color: #0a0a0a; + border-color: #0a0a0a; + color: white; } + .hero.is-white.is-bold { + background-image: linear-gradient(141deg, #e6e6e6 0%, white 71%, white 100%); } + @media screen and (max-width: 768px) { + .hero.is-white.is-bold .navbar-menu { + background-image: linear-gradient(141deg, #e6e6e6 0%, white 71%, white 100%); } } + .hero.is-black { + background-color: #0a0a0a; + color: white; } + .hero.is-black a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current), + .hero.is-black strong { + color: inherit; } + .hero.is-black .title { + color: white; } + .hero.is-black .subtitle { + color: rgba(255, 255, 255, 0.9); } + .hero.is-black .subtitle a:not(.button), + .hero.is-black .subtitle strong { + color: white; } + @media screen and (max-width: 1023px) { + .hero.is-black .navbar-menu { + background-color: #0a0a0a; } } + .hero.is-black .navbar-item, + .hero.is-black .navbar-link { + color: rgba(255, 255, 255, 0.7); } + .hero.is-black a.navbar-item:hover, .hero.is-black a.navbar-item.is-active, + .hero.is-black .navbar-link:hover, + .hero.is-black .navbar-link.is-active { + background-color: black; + color: white; } + .hero.is-black .tabs a { + color: white; + opacity: 0.9; } + .hero.is-black .tabs a:hover { + opacity: 1; } + .hero.is-black .tabs li.is-active a { + opacity: 1; } + .hero.is-black .tabs.is-boxed a, .hero.is-black .tabs.is-toggle a { + color: white; } + .hero.is-black .tabs.is-boxed a:hover, .hero.is-black .tabs.is-toggle a:hover { + background-color: rgba(10, 10, 10, 0.1); } + .hero.is-black .tabs.is-boxed li.is-active a, .hero.is-black .tabs.is-boxed li.is-active a:hover, .hero.is-black .tabs.is-toggle li.is-active a, .hero.is-black .tabs.is-toggle li.is-active a:hover { + background-color: white; + border-color: white; + color: #0a0a0a; } + .hero.is-black.is-bold { + background-image: linear-gradient(141deg, black 0%, #0a0a0a 71%, #181616 100%); } + @media screen and (max-width: 768px) { + .hero.is-black.is-bold .navbar-menu { + background-image: linear-gradient(141deg, black 0%, #0a0a0a 71%, #181616 100%); } } + .hero.is-light { + background-color: whitesmoke; + color: rgba(0, 0, 0, 0.7); } + .hero.is-light a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current), + .hero.is-light strong { + color: inherit; } + .hero.is-light .title { + color: rgba(0, 0, 0, 0.7); } + .hero.is-light .subtitle { + color: rgba(0, 0, 0, 0.9); } + .hero.is-light .subtitle a:not(.button), + .hero.is-light .subtitle strong { + color: rgba(0, 0, 0, 0.7); } + @media screen and (max-width: 1023px) { + .hero.is-light .navbar-menu { + background-color: whitesmoke; } } + .hero.is-light .navbar-item, + .hero.is-light .navbar-link { + color: rgba(0, 0, 0, 0.7); } + .hero.is-light a.navbar-item:hover, .hero.is-light a.navbar-item.is-active, + .hero.is-light .navbar-link:hover, + .hero.is-light .navbar-link.is-active { + background-color: #e8e8e8; + color: rgba(0, 0, 0, 0.7); } + .hero.is-light .tabs a { + color: rgba(0, 0, 0, 0.7); + opacity: 0.9; } + .hero.is-light .tabs a:hover { + opacity: 1; } + .hero.is-light .tabs li.is-active a { + opacity: 1; } + .hero.is-light .tabs.is-boxed a, .hero.is-light .tabs.is-toggle a { + color: rgba(0, 0, 0, 0.7); } + .hero.is-light .tabs.is-boxed a:hover, .hero.is-light .tabs.is-toggle a:hover { + background-color: rgba(10, 10, 10, 0.1); } + .hero.is-light .tabs.is-boxed li.is-active a, .hero.is-light .tabs.is-boxed li.is-active a:hover, .hero.is-light .tabs.is-toggle li.is-active a, .hero.is-light .tabs.is-toggle li.is-active a:hover { + background-color: rgba(0, 0, 0, 0.7); + border-color: rgba(0, 0, 0, 0.7); + color: whitesmoke; } + .hero.is-light.is-bold { + background-image: linear-gradient(141deg, #dfd8d9 0%, whitesmoke 71%, white 100%); } + @media screen and (max-width: 768px) { + .hero.is-light.is-bold .navbar-menu { + background-image: linear-gradient(141deg, #dfd8d9 0%, whitesmoke 71%, white 100%); } } + .hero.is-dark { + background-color: #363636; + color: #fff; } + .hero.is-dark a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current), + .hero.is-dark strong { + color: inherit; } + .hero.is-dark .title { + color: #fff; } + .hero.is-dark .subtitle { + color: rgba(255, 255, 255, 0.9); } + .hero.is-dark .subtitle a:not(.button), + .hero.is-dark .subtitle strong { + color: #fff; } + @media screen and (max-width: 1023px) { + .hero.is-dark .navbar-menu { + background-color: #363636; } } + .hero.is-dark .navbar-item, + .hero.is-dark .navbar-link { + color: rgba(255, 255, 255, 0.7); } + .hero.is-dark a.navbar-item:hover, .hero.is-dark a.navbar-item.is-active, + .hero.is-dark .navbar-link:hover, + .hero.is-dark .navbar-link.is-active { + background-color: #292929; + color: #fff; } + .hero.is-dark .tabs a { + color: #fff; + opacity: 0.9; } + .hero.is-dark .tabs a:hover { + opacity: 1; } + .hero.is-dark .tabs li.is-active a { + opacity: 1; } + .hero.is-dark .tabs.is-boxed a, .hero.is-dark .tabs.is-toggle a { + color: #fff; } + .hero.is-dark .tabs.is-boxed a:hover, .hero.is-dark .tabs.is-toggle a:hover { + background-color: rgba(10, 10, 10, 0.1); } + .hero.is-dark .tabs.is-boxed li.is-active a, .hero.is-dark .tabs.is-boxed li.is-active a:hover, .hero.is-dark .tabs.is-toggle li.is-active a, .hero.is-dark .tabs.is-toggle li.is-active a:hover { + background-color: #fff; + border-color: #fff; + color: #363636; } + .hero.is-dark.is-bold { + background-image: linear-gradient(141deg, #1f191a 0%, #363636 71%, #46403f 100%); } + @media screen and (max-width: 768px) { + .hero.is-dark.is-bold .navbar-menu { + background-image: linear-gradient(141deg, #1f191a 0%, #363636 71%, #46403f 100%); } } + .hero.is-primary { + background-color: #00d1b2; + color: #fff; } + .hero.is-primary a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current), + .hero.is-primary strong { + color: inherit; } + .hero.is-primary .title { + color: #fff; } + .hero.is-primary .subtitle { + color: rgba(255, 255, 255, 0.9); } + .hero.is-primary .subtitle a:not(.button), + .hero.is-primary .subtitle strong { + color: #fff; } + @media screen and (max-width: 1023px) { + .hero.is-primary .navbar-menu { + background-color: #00d1b2; } } + .hero.is-primary .navbar-item, + .hero.is-primary .navbar-link { + color: rgba(255, 255, 255, 0.7); } + .hero.is-primary a.navbar-item:hover, .hero.is-primary a.navbar-item.is-active, + .hero.is-primary .navbar-link:hover, + .hero.is-primary .navbar-link.is-active { + background-color: #00b89c; + color: #fff; } + .hero.is-primary .tabs a { + color: #fff; + opacity: 0.9; } + .hero.is-primary .tabs a:hover { + opacity: 1; } + .hero.is-primary .tabs li.is-active a { + opacity: 1; } + .hero.is-primary .tabs.is-boxed a, .hero.is-primary .tabs.is-toggle a { + color: #fff; } + .hero.is-primary .tabs.is-boxed a:hover, .hero.is-primary .tabs.is-toggle a:hover { + background-color: rgba(10, 10, 10, 0.1); } + .hero.is-primary .tabs.is-boxed li.is-active a, .hero.is-primary .tabs.is-boxed li.is-active a:hover, .hero.is-primary .tabs.is-toggle li.is-active a, .hero.is-primary .tabs.is-toggle li.is-active a:hover { + background-color: #fff; + border-color: #fff; + color: #00d1b2; } + .hero.is-primary.is-bold { + background-image: linear-gradient(141deg, #009e6c 0%, #00d1b2 71%, #00e7eb 100%); } + @media screen and (max-width: 768px) { + .hero.is-primary.is-bold .navbar-menu { + background-image: linear-gradient(141deg, #009e6c 0%, #00d1b2 71%, #00e7eb 100%); } } + .hero.is-link { + background-color: #3273dc; + color: #fff; } + .hero.is-link a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current), + .hero.is-link strong { + color: inherit; } + .hero.is-link .title { + color: #fff; } + .hero.is-link .subtitle { + color: rgba(255, 255, 255, 0.9); } + .hero.is-link .subtitle a:not(.button), + .hero.is-link .subtitle strong { + color: #fff; } + @media screen and (max-width: 1023px) { + .hero.is-link .navbar-menu { + background-color: #3273dc; } } + .hero.is-link .navbar-item, + .hero.is-link .navbar-link { + color: rgba(255, 255, 255, 0.7); } + .hero.is-link a.navbar-item:hover, .hero.is-link a.navbar-item.is-active, + .hero.is-link .navbar-link:hover, + .hero.is-link .navbar-link.is-active { + background-color: #2366d1; + color: #fff; } + .hero.is-link .tabs a { + color: #fff; + opacity: 0.9; } + .hero.is-link .tabs a:hover { + opacity: 1; } + .hero.is-link .tabs li.is-active a { + opacity: 1; } + .hero.is-link .tabs.is-boxed a, .hero.is-link .tabs.is-toggle a { + color: #fff; } + .hero.is-link .tabs.is-boxed a:hover, .hero.is-link .tabs.is-toggle a:hover { + background-color: rgba(10, 10, 10, 0.1); } + .hero.is-link .tabs.is-boxed li.is-active a, .hero.is-link .tabs.is-boxed li.is-active a:hover, .hero.is-link .tabs.is-toggle li.is-active a, .hero.is-link .tabs.is-toggle li.is-active a:hover { + background-color: #fff; + border-color: #fff; + color: #3273dc; } + .hero.is-link.is-bold { + background-image: linear-gradient(141deg, #1577c6 0%, #3273dc 71%, #4366e5 100%); } + @media screen and (max-width: 768px) { + .hero.is-link.is-bold .navbar-menu { + background-image: linear-gradient(141deg, #1577c6 0%, #3273dc 71%, #4366e5 100%); } } + .hero.is-info { + background-color: #3298dc; + color: #fff; } + .hero.is-info a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current), + .hero.is-info strong { + color: inherit; } + .hero.is-info .title { + color: #fff; } + .hero.is-info .subtitle { + color: rgba(255, 255, 255, 0.9); } + .hero.is-info .subtitle a:not(.button), + .hero.is-info .subtitle strong { + color: #fff; } + @media screen and (max-width: 1023px) { + .hero.is-info .navbar-menu { + background-color: #3298dc; } } + .hero.is-info .navbar-item, + .hero.is-info .navbar-link { + color: rgba(255, 255, 255, 0.7); } + .hero.is-info a.navbar-item:hover, .hero.is-info a.navbar-item.is-active, + .hero.is-info .navbar-link:hover, + .hero.is-info .navbar-link.is-active { + background-color: #238cd1; + color: #fff; } + .hero.is-info .tabs a { + color: #fff; + opacity: 0.9; } + .hero.is-info .tabs a:hover { + opacity: 1; } + .hero.is-info .tabs li.is-active a { + opacity: 1; } + .hero.is-info .tabs.is-boxed a, .hero.is-info .tabs.is-toggle a { + color: #fff; } + .hero.is-info .tabs.is-boxed a:hover, .hero.is-info .tabs.is-toggle a:hover { + background-color: rgba(10, 10, 10, 0.1); } + .hero.is-info .tabs.is-boxed li.is-active a, .hero.is-info .tabs.is-boxed li.is-active a:hover, .hero.is-info .tabs.is-toggle li.is-active a, .hero.is-info .tabs.is-toggle li.is-active a:hover { + background-color: #fff; + border-color: #fff; + color: #3298dc; } + .hero.is-info.is-bold { + background-image: linear-gradient(141deg, #159dc6 0%, #3298dc 71%, #4389e5 100%); } + @media screen and (max-width: 768px) { + .hero.is-info.is-bold .navbar-menu { + background-image: linear-gradient(141deg, #159dc6 0%, #3298dc 71%, #4389e5 100%); } } + .hero.is-success { + background-color: #48c774; + color: #fff; } + .hero.is-success a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current), + .hero.is-success strong { + color: inherit; } + .hero.is-success .title { + color: #fff; } + .hero.is-success .subtitle { + color: rgba(255, 255, 255, 0.9); } + .hero.is-success .subtitle a:not(.button), + .hero.is-success .subtitle strong { + color: #fff; } + @media screen and (max-width: 1023px) { + .hero.is-success .navbar-menu { + background-color: #48c774; } } + .hero.is-success .navbar-item, + .hero.is-success .navbar-link { + color: rgba(255, 255, 255, 0.7); } + .hero.is-success a.navbar-item:hover, .hero.is-success a.navbar-item.is-active, + .hero.is-success .navbar-link:hover, + .hero.is-success .navbar-link.is-active { + background-color: #3abb67; + color: #fff; } + .hero.is-success .tabs a { + color: #fff; + opacity: 0.9; } + .hero.is-success .tabs a:hover { + opacity: 1; } + .hero.is-success .tabs li.is-active a { + opacity: 1; } + .hero.is-success .tabs.is-boxed a, .hero.is-success .tabs.is-toggle a { + color: #fff; } + .hero.is-success .tabs.is-boxed a:hover, .hero.is-success .tabs.is-toggle a:hover { + background-color: rgba(10, 10, 10, 0.1); } + .hero.is-success .tabs.is-boxed li.is-active a, .hero.is-success .tabs.is-boxed li.is-active a:hover, .hero.is-success .tabs.is-toggle li.is-active a, .hero.is-success .tabs.is-toggle li.is-active a:hover { + background-color: #fff; + border-color: #fff; + color: #48c774; } + .hero.is-success.is-bold { + background-image: linear-gradient(141deg, #29b342 0%, #48c774 71%, #56d296 100%); } + @media screen and (max-width: 768px) { + .hero.is-success.is-bold .navbar-menu { + background-image: linear-gradient(141deg, #29b342 0%, #48c774 71%, #56d296 100%); } } + .hero.is-warning { + background-color: #ffdd57; + color: rgba(0, 0, 0, 0.7); } + .hero.is-warning a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current), + .hero.is-warning strong { + color: inherit; } + .hero.is-warning .title { + color: rgba(0, 0, 0, 0.7); } + .hero.is-warning .subtitle { + color: rgba(0, 0, 0, 0.9); } + .hero.is-warning .subtitle a:not(.button), + .hero.is-warning .subtitle strong { + color: rgba(0, 0, 0, 0.7); } + @media screen and (max-width: 1023px) { + .hero.is-warning .navbar-menu { + background-color: #ffdd57; } } + .hero.is-warning .navbar-item, + .hero.is-warning .navbar-link { + color: rgba(0, 0, 0, 0.7); } + .hero.is-warning a.navbar-item:hover, .hero.is-warning a.navbar-item.is-active, + .hero.is-warning .navbar-link:hover, + .hero.is-warning .navbar-link.is-active { + background-color: #ffd83d; + color: rgba(0, 0, 0, 0.7); } + .hero.is-warning .tabs a { + color: rgba(0, 0, 0, 0.7); + opacity: 0.9; } + .hero.is-warning .tabs a:hover { + opacity: 1; } + .hero.is-warning .tabs li.is-active a { + opacity: 1; } + .hero.is-warning .tabs.is-boxed a, .hero.is-warning .tabs.is-toggle a { + color: rgba(0, 0, 0, 0.7); } + .hero.is-warning .tabs.is-boxed a:hover, .hero.is-warning .tabs.is-toggle a:hover { + background-color: rgba(10, 10, 10, 0.1); } + .hero.is-warning .tabs.is-boxed li.is-active a, .hero.is-warning .tabs.is-boxed li.is-active a:hover, .hero.is-warning .tabs.is-toggle li.is-active a, .hero.is-warning .tabs.is-toggle li.is-active a:hover { + background-color: rgba(0, 0, 0, 0.7); + border-color: rgba(0, 0, 0, 0.7); + color: #ffdd57; } + .hero.is-warning.is-bold { + background-image: linear-gradient(141deg, #ffaf24 0%, #ffdd57 71%, #fffa70 100%); } + @media screen and (max-width: 768px) { + .hero.is-warning.is-bold .navbar-menu { + background-image: linear-gradient(141deg, #ffaf24 0%, #ffdd57 71%, #fffa70 100%); } } + .hero.is-danger { + background-color: #f14668; + color: #fff; } + .hero.is-danger a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current), + .hero.is-danger strong { + color: inherit; } + .hero.is-danger .title { + color: #fff; } + .hero.is-danger .subtitle { + color: rgba(255, 255, 255, 0.9); } + .hero.is-danger .subtitle a:not(.button), + .hero.is-danger .subtitle strong { + color: #fff; } + @media screen and (max-width: 1023px) { + .hero.is-danger .navbar-menu { + background-color: #f14668; } } + .hero.is-danger .navbar-item, + .hero.is-danger .navbar-link { + color: rgba(255, 255, 255, 0.7); } + .hero.is-danger a.navbar-item:hover, .hero.is-danger a.navbar-item.is-active, + .hero.is-danger .navbar-link:hover, + .hero.is-danger .navbar-link.is-active { + background-color: #ef2e55; + color: #fff; } + .hero.is-danger .tabs a { + color: #fff; + opacity: 0.9; } + .hero.is-danger .tabs a:hover { + opacity: 1; } + .hero.is-danger .tabs li.is-active a { + opacity: 1; } + .hero.is-danger .tabs.is-boxed a, .hero.is-danger .tabs.is-toggle a { + color: #fff; } + .hero.is-danger .tabs.is-boxed a:hover, .hero.is-danger .tabs.is-toggle a:hover { + background-color: rgba(10, 10, 10, 0.1); } + .hero.is-danger .tabs.is-boxed li.is-active a, .hero.is-danger .tabs.is-boxed li.is-active a:hover, .hero.is-danger .tabs.is-toggle li.is-active a, .hero.is-danger .tabs.is-toggle li.is-active a:hover { + background-color: #fff; + border-color: #fff; + color: #f14668; } + .hero.is-danger.is-bold { + background-image: linear-gradient(141deg, #fa0a62 0%, #f14668 71%, #f7595f 100%); } + @media screen and (max-width: 768px) { + .hero.is-danger.is-bold .navbar-menu { + background-image: linear-gradient(141deg, #fa0a62 0%, #f14668 71%, #f7595f 100%); } } + .hero.is-small .hero-body { + padding-bottom: 1.5rem; + padding-top: 1.5rem; } + @media screen and (min-width: 769px), print { + .hero.is-medium .hero-body { + padding-bottom: 9rem; + padding-top: 9rem; } } + @media screen and (min-width: 769px), print { + .hero.is-large .hero-body { + padding-bottom: 18rem; + padding-top: 18rem; } } + .hero.is-halfheight .hero-body, .hero.is-fullheight .hero-body, .hero.is-fullheight-with-navbar .hero-body { + align-items: center; + display: flex; } + .hero.is-halfheight .hero-body > .container, .hero.is-fullheight .hero-body > .container, .hero.is-fullheight-with-navbar .hero-body > .container { + flex-grow: 1; + flex-shrink: 1; } + .hero.is-halfheight { + min-height: 50vh; } + .hero.is-fullheight { + min-height: 100vh; } + +.hero-video { + overflow: hidden; } + .hero-video video { + left: 50%; + min-height: 100%; + min-width: 100%; + position: absolute; + top: 50%; + transform: translate3d(-50%, -50%, 0); } + .hero-video.is-transparent { + opacity: 0.3; } + @media screen and (max-width: 768px) { + .hero-video { + display: none; } } + +.hero-buttons { + margin-top: 1.5rem; } + @media screen and (max-width: 768px) { + .hero-buttons .button { + display: flex; } + .hero-buttons .button:not(:last-child) { + margin-bottom: 0.75rem; } } + @media screen and (min-width: 769px), print { + .hero-buttons { + display: flex; + justify-content: center; } + .hero-buttons .button:not(:last-child) { + margin-right: 1.5rem; } } + +.hero-head, +.hero-foot { + flex-grow: 0; + flex-shrink: 0; } + +.hero-body { + flex-grow: 1; + flex-shrink: 0; + padding: 3rem 1.5rem; } + +.section { + padding: 3rem 1.5rem; } + @media screen and (min-width: 1024px) { + .section.is-medium { + padding: 9rem 1.5rem; } + .section.is-large { + padding: 18rem 1.5rem; } } + +.footer { + background-color: #fafafa; + padding: 3rem 1.5rem 6rem; } diff --git a/user/themes/goku/css/custom.css b/user/themes/goku/css/custom.css new file mode 100644 index 00000000..e7963287 --- /dev/null +++ b/user/themes/goku/css/custom.css @@ -0,0 +1,175 @@ +/* Core Stuff */ +* { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +body { + font-size: 1rem; + line-height: 1.7; + color: #606d6e; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + color: #454B4D; +} + +a { + color: #1F8CD6; + text-decoration: none; +} + +a:hover { + color: #175E91; +} + +pre { + background: #F0F0F0; + margin: 1rem 0; + border-radius: 2px; +} + +blockquote { + border-left: 10px solid #eee; + margin: 0; + padding: 0 2rem; +} + +/* Utility Classes */ +.wrapper { + margin: 0 3rem; +} + +.padding { + padding: 3rem 1rem; +} + +.left { + float: left; +} + +.right { + float: right +} + +.text-center { + text-align: center; +} + +.text-right { + text-align: right; +} + +.text-left { + text-align: left; +} + +/* Content Styling */ +.header .padding { + padding: 1rem 0; +} + +.header { + background-color: #1F8DD6; + color: #eee; +} + +.header a { + color: #fff; +} + +.header .logo { + font-size: 1.7rem; + text-transform: uppercase; +} + +.footer { + background-color: #eee; +} + +/* Menu Settings */ +.main-nav ul { + text-align: center; + letter-spacing: -1em; + margin: 0; + padding: 0; +} + +.main-nav ul li { + display: inline-block; + letter-spacing: normal; +} + +.main-nav ul li a { + position: relative; + display: block; + line-height: 45px; + color: #fff; + padding: 0 20px; + white-space: nowrap; +} + +.main-nav > ul > li > a { + border-radius: 2px; +} + +/*Active dropdown nav item */ +.main-nav ul li:hover > a { + background-color: #175E91; +} + +/* Selected Dropdown nav item */ +.main-nav ul li.selected > a { + background-color: #fff; + color: #175E91; +} + +/* Dropdown CSS */ +.main-nav ul li {position: relative;} + +.main-nav ul li ul { + position: absolute; + background-color: #1F8DD6; + min-width: 100%; + text-align: left; + z-index: 999; + + display: none; +} +.main-nav ul li ul li { + display: block; +} + +/* Dropdown CSS */ +.main-nav ul li ul ul { + left: 100%; + top: 0; +} + +/* Active on Hover */ +.main-nav li:hover > ul { + display: block; +} + +/* Child Indicator */ +.main-nav .has-children > a { + padding-right: 30px; +} +.main-nav .has-children > a:after { + font-family: FontAwesome; + content: '\f107'; + position: absolute; + display: inline-block; + right: 8px; + top: 0; +} + +.main-nav .has-children .has-children > a:after { + content: '\f105'; +} diff --git a/user/themes/goku/goku.php b/user/themes/goku/goku.php new file mode 100644 index 00000000..e1ab5a2a --- /dev/null +++ b/user/themes/goku/goku.php @@ -0,0 +1,9 @@ + b ? 1 : -1 +} diff --git a/user/themes/goku/node_modules/abbrev/package.json b/user/themes/goku/node_modules/abbrev/package.json new file mode 100644 index 00000000..a4124042 --- /dev/null +++ b/user/themes/goku/node_modules/abbrev/package.json @@ -0,0 +1,56 @@ +{ + "_from": "abbrev@1", + "_id": "abbrev@1.1.1", + "_inBundle": false, + "_integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "_location": "/abbrev", + "_phantomChildren": {}, + "_requested": { + "type": "range", + "registry": true, + "raw": "abbrev@1", + "name": "abbrev", + "escapedName": "abbrev", + "rawSpec": "1", + "saveSpec": null, + "fetchSpec": "1" + }, + "_requiredBy": [ + "/nopt" + ], + "_resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "_shasum": "f8f2c887ad10bf67f634f005b6987fed3179aac8", + "_spec": "abbrev@1", + "_where": "/srv/http/berryfarmprojects.org.uk/stay-grav/user/themes/goku/node_modules/nopt", + "author": { + "name": "Isaac Z. Schlueter", + "email": "i@izs.me" + }, + "bugs": { + "url": "https://github.com/isaacs/abbrev-js/issues" + }, + "bundleDependencies": false, + "deprecated": false, + "description": "Like ruby's abbrev module, but in js", + "devDependencies": { + "tap": "^10.1" + }, + "files": [ + "abbrev.js" + ], + "homepage": "https://github.com/isaacs/abbrev-js#readme", + "license": "ISC", + "main": "abbrev.js", + "name": "abbrev", + "repository": { + "type": "git", + "url": "git+ssh://git@github.com/isaacs/abbrev-js.git" + }, + "scripts": { + "postpublish": "git push origin --all; git push origin --tags", + "postversion": "npm publish", + "preversion": "npm test", + "test": "tap test.js --100" + }, + "version": "1.1.1" +} diff --git a/user/themes/goku/node_modules/ajv/.tonic_example.js b/user/themes/goku/node_modules/ajv/.tonic_example.js new file mode 100644 index 00000000..aa11812d --- /dev/null +++ b/user/themes/goku/node_modules/ajv/.tonic_example.js @@ -0,0 +1,20 @@ +var Ajv = require('ajv'); +var ajv = new Ajv({allErrors: true}); + +var schema = { + "properties": { + "foo": { "type": "string" }, + "bar": { "type": "number", "maximum": 3 } + } +}; + +var validate = ajv.compile(schema); + +test({"foo": "abc", "bar": 2}); +test({"foo": 2, "bar": 4}); + +function test(data) { + var valid = validate(data); + if (valid) console.log('Valid!'); + else console.log('Invalid: ' + ajv.errorsText(validate.errors)); +} \ No newline at end of file diff --git a/user/themes/goku/node_modules/ajv/LICENSE b/user/themes/goku/node_modules/ajv/LICENSE new file mode 100644 index 00000000..96ee7199 --- /dev/null +++ b/user/themes/goku/node_modules/ajv/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2015-2017 Evgeny Poberezkin + +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. + diff --git a/user/themes/goku/node_modules/ajv/README.md b/user/themes/goku/node_modules/ajv/README.md new file mode 100644 index 00000000..cafbd71c --- /dev/null +++ b/user/themes/goku/node_modules/ajv/README.md @@ -0,0 +1,1359 @@ +Ajv logo + +# Ajv: Another JSON Schema Validator + +The fastest JSON Schema validator for Node.js and browser. Supports draft-04/06/07. + +[![Build Status](https://travis-ci.org/epoberezkin/ajv.svg?branch=master)](https://travis-ci.org/epoberezkin/ajv) +[![npm](https://img.shields.io/npm/v/ajv.svg)](https://www.npmjs.com/package/ajv) +[![npm downloads](https://img.shields.io/npm/dm/ajv.svg)](https://www.npmjs.com/package/ajv) +[![Coverage Status](https://coveralls.io/repos/epoberezkin/ajv/badge.svg?branch=master&service=github)](https://coveralls.io/github/epoberezkin/ajv?branch=master) +[![Greenkeeper badge](https://badges.greenkeeper.io/epoberezkin/ajv.svg)](https://greenkeeper.io/) +[![Gitter](https://img.shields.io/gitter/room/ajv-validator/ajv.svg)](https://gitter.im/ajv-validator/ajv) + + +## Using version 6 + +[JSON Schema draft-07](http://json-schema.org/latest/json-schema-validation.html) is published. + +[Ajv version 6.0.0](https://github.com/epoberezkin/ajv/releases/tag/v6.0.0) that supports draft-07 is released. It may require either migrating your schemas or updating your code (to continue using draft-04 and v5 schemas, draft-06 schemas will be supported without changes). + +__Please note__: To use Ajv with draft-06 schemas you need to explicitly add the meta-schema to the validator instance: + +```javascript +ajv.addMetaSchema(require('ajv/lib/refs/json-schema-draft-06.json')); +``` + +To use Ajv with draft-04 schemas in addition to explicitly adding meta-schema you also need to use option schemaId: + +```javascript +var ajv = new Ajv({schemaId: 'id'}); +// If you want to use both draft-04 and draft-06/07 schemas: +// var ajv = new Ajv({schemaId: 'auto'}); +ajv.addMetaSchema(require('ajv/lib/refs/json-schema-draft-04.json')); +``` + + +## Contents + +- [Performance](#performance) +- [Features](#features) +- [Getting started](#getting-started) +- [Frequently Asked Questions](https://github.com/epoberezkin/ajv/blob/master/FAQ.md) +- [Using in browser](#using-in-browser) +- [Command line interface](#command-line-interface) +- Validation + - [Keywords](#validation-keywords) + - [Annotation keywords](#annotation-keywords) + - [Formats](#formats) + - [Combining schemas with $ref](#ref) + - [$data reference](#data-reference) + - NEW: [$merge and $patch keywords](#merge-and-patch-keywords) + - [Defining custom keywords](#defining-custom-keywords) + - [Asynchronous schema compilation](#asynchronous-schema-compilation) + - [Asynchronous validation](#asynchronous-validation) +- [Security considerations](#security-considerations) + - [Security contact](#security-contact) + - [Untrusted schemas](#untrusted-schemas) + - [Circular references in objects](#circular-references-in-javascript-objects) + - [Trusted schemas](#security-risks-of-trusted-schemas) +- Modifying data during validation + - [Filtering data](#filtering-data) + - [Assigning defaults](#assigning-defaults) + - [Coercing data types](#coercing-data-types) +- API + - [Methods](#api) + - [Options](#options) + - [Validation errors](#validation-errors) +- [Plugins](#plugins) +- [Related packages](#related-packages) +- [Some packages using Ajv](#some-packages-using-ajv) +- [Tests, Contributing, History, Support, License](#tests) + + +## Performance + +Ajv generates code using [doT templates](https://github.com/olado/doT) to turn JSON Schemas into super-fast validation functions that are efficient for v8 optimization. + +Currently Ajv is the fastest and the most standard compliant validator according to these benchmarks: + +- [json-schema-benchmark](https://github.com/ebdrup/json-schema-benchmark) - 50% faster than the second place +- [jsck benchmark](https://github.com/pandastrike/jsck#benchmarks) - 20-190% faster +- [z-schema benchmark](https://rawgit.com/zaggino/z-schema/master/benchmark/results.html) +- [themis benchmark](https://cdn.rawgit.com/playlyfe/themis/master/benchmark/results.html) + + +Performance of different validators by [json-schema-benchmark](https://github.com/ebdrup/json-schema-benchmark): + +[![performance](https://chart.googleapis.com/chart?chxt=x,y&cht=bhs&chco=76A4FB&chls=2.0&chbh=32,4,1&chs=600x416&chxl=-1:|djv|ajv|json-schema-validator-generator|jsen|is-my-json-valid|themis|z-schema|jsck|skeemas|json-schema-library|tv4&chd=t:100,98,72.1,66.8,50.1,15.1,6.1,3.8,1.2,0.7,0.2)](https://github.com/ebdrup/json-schema-benchmark/blob/master/README.md#performance) + + +## Features + +- Ajv implements full JSON Schema [draft-06/07](http://json-schema.org/) and draft-04 standards: + - all validation keywords (see [JSON Schema validation keywords](https://github.com/epoberezkin/ajv/blob/master/KEYWORDS.md)) + - full support of remote refs (remote schemas have to be added with `addSchema` or compiled to be available) + - support of circular references between schemas + - correct string lengths for strings with unicode pairs (can be turned off) + - [formats](#formats) defined by JSON Schema draft-07 standard and custom formats (can be turned off) + - [validates schemas against meta-schema](#api-validateschema) +- supports [browsers](#using-in-browser) and Node.js 0.10-8.x +- [asynchronous loading](#asynchronous-schema-compilation) of referenced schemas during compilation +- "All errors" validation mode with [option allErrors](#options) +- [error messages with parameters](#validation-errors) describing error reasons to allow creating custom error messages +- i18n error messages support with [ajv-i18n](https://github.com/epoberezkin/ajv-i18n) package +- [filtering data](#filtering-data) from additional properties +- [assigning defaults](#assigning-defaults) to missing properties and items +- [coercing data](#coercing-data-types) to the types specified in `type` keywords +- [custom keywords](#defining-custom-keywords) +- draft-06/07 keywords `const`, `contains`, `propertyNames` and `if/then/else` +- draft-06 boolean schemas (`true`/`false` as a schema to always pass/fail). +- keywords `switch`, `patternRequired`, `formatMaximum` / `formatMinimum` and `formatExclusiveMaximum` / `formatExclusiveMinimum` from [JSON Schema extension proposals](https://github.com/json-schema/json-schema/wiki/v5-Proposals) with [ajv-keywords](https://github.com/epoberezkin/ajv-keywords) package +- [$data reference](#data-reference) to use values from the validated data as values for the schema keywords +- [asynchronous validation](#asynchronous-validation) of custom formats and keywords + +Currently Ajv is the only validator that passes all the tests from [JSON Schema Test Suite](https://github.com/json-schema/JSON-Schema-Test-Suite) (according to [json-schema-benchmark](https://github.com/ebdrup/json-schema-benchmark), apart from the test that requires that `1.0` is not an integer that is impossible to satisfy in JavaScript). + + +## Install + +``` +npm install ajv +``` + + +## Getting started + +Try it in the Node.js REPL: https://tonicdev.com/npm/ajv + + +The fastest validation call: + +```javascript +var Ajv = require('ajv'); +var ajv = new Ajv(); // options can be passed, e.g. {allErrors: true} +var validate = ajv.compile(schema); +var valid = validate(data); +if (!valid) console.log(validate.errors); +``` + +or with less code + +```javascript +// ... +var valid = ajv.validate(schema, data); +if (!valid) console.log(ajv.errors); +// ... +``` + +or + +```javascript +// ... +var valid = ajv.addSchema(schema, 'mySchema') + .validate('mySchema', data); +if (!valid) console.log(ajv.errorsText()); +// ... +``` + +See [API](#api) and [Options](#options) for more details. + +Ajv compiles schemas to functions and caches them in all cases (using schema serialized with [fast-json-stable-stringify](https://github.com/epoberezkin/fast-json-stable-stringify) or a custom function as a key), so that the next time the same schema is used (not necessarily the same object instance) it won't be compiled again. + +The best performance is achieved when using compiled functions returned by `compile` or `getSchema` methods (there is no additional function call). + +__Please note__: every time a validation function or `ajv.validate` are called `errors` property is overwritten. You need to copy `errors` array reference to another variable if you want to use it later (e.g., in the callback). See [Validation errors](#validation-errors) + + +## Using in browser + +You can require Ajv directly from the code you browserify - in this case Ajv will be a part of your bundle. + +If you need to use Ajv in several bundles you can create a separate UMD bundle using `npm run bundle` script (thanks to [siddo420](https://github.com/siddo420)). + +Then you need to load Ajv in the browser: +```html + +``` + +This bundle can be used with different module systems; it creates global `Ajv` if no module system is found. + +The browser bundle is available on [cdnjs](https://cdnjs.com/libraries/ajv). + +Ajv is tested with these browsers: + +[![Sauce Test Status](https://saucelabs.com/browser-matrix/epoberezkin.svg)](https://saucelabs.com/u/epoberezkin) + +__Please note__: some frameworks, e.g. Dojo, may redefine global require in such way that is not compatible with CommonJS module format. In such case Ajv bundle has to be loaded before the framework and then you can use global Ajv (see issue [#234](https://github.com/epoberezkin/ajv/issues/234)). + + +## Command line interface + +CLI is available as a separate npm package [ajv-cli](https://github.com/jessedc/ajv-cli). It supports: + +- compiling JSON Schemas to test their validity +- BETA: generating standalone module exporting a validation function to be used without Ajv (using [ajv-pack](https://github.com/epoberezkin/ajv-pack)) +- migrate schemas to draft-07 (using [json-schema-migrate](https://github.com/epoberezkin/json-schema-migrate)) +- validating data file(s) against JSON Schema +- testing expected validity of data against JSON Schema +- referenced schemas +- custom meta-schemas +- files in JSON and JavaScript format +- all Ajv options +- reporting changes in data after validation in [JSON-patch](https://tools.ietf.org/html/rfc6902) format + + +## Validation keywords + +Ajv supports all validation keywords from draft-07 of JSON Schema standard: + +- [type](https://github.com/epoberezkin/ajv/blob/master/KEYWORDS.md#type) +- [for numbers](https://github.com/epoberezkin/ajv/blob/master/KEYWORDS.md#keywords-for-numbers) - maximum, minimum, exclusiveMaximum, exclusiveMinimum, multipleOf +- [for strings](https://github.com/epoberezkin/ajv/blob/master/KEYWORDS.md#keywords-for-strings) - maxLength, minLength, pattern, format +- [for arrays](https://github.com/epoberezkin/ajv/blob/master/KEYWORDS.md#keywords-for-arrays) - maxItems, minItems, uniqueItems, items, additionalItems, [contains](https://github.com/epoberezkin/ajv/blob/master/KEYWORDS.md#contains) +- [for objects](https://github.com/epoberezkin/ajv/blob/master/KEYWORDS.md#keywords-for-objects) - maxProperties, minProperties, required, properties, patternProperties, additionalProperties, dependencies, [propertyNames](https://github.com/epoberezkin/ajv/blob/master/KEYWORDS.md#propertynames) +- [for all types](https://github.com/epoberezkin/ajv/blob/master/KEYWORDS.md#keywords-for-all-types) - enum, [const](https://github.com/epoberezkin/ajv/blob/master/KEYWORDS.md#const) +- [compound keywords](https://github.com/epoberezkin/ajv/blob/master/KEYWORDS.md#compound-keywords) - not, oneOf, anyOf, allOf, [if/then/else](https://github.com/epoberezkin/ajv/blob/master/KEYWORDS.md#ifthenelse) + +With [ajv-keywords](https://github.com/epoberezkin/ajv-keywords) package Ajv also supports validation keywords from [JSON Schema extension proposals](https://github.com/json-schema/json-schema/wiki/v5-Proposals) for JSON Schema standard: + +- [patternRequired](https://github.com/epoberezkin/ajv/blob/master/KEYWORDS.md#patternrequired-proposed) - like `required` but with patterns that some property should match. +- [formatMaximum, formatMinimum, formatExclusiveMaximum, formatExclusiveMinimum](https://github.com/epoberezkin/ajv/blob/master/KEYWORDS.md#formatmaximum--formatminimum-and-exclusiveformatmaximum--exclusiveformatminimum-proposed) - setting limits for date, time, etc. + +See [JSON Schema validation keywords](https://github.com/epoberezkin/ajv/blob/master/KEYWORDS.md) for more details. + + +## Annotation keywords + +JSON Schema specification defines several annotation keywords that describe schema itself but do not perform any validation. + +- `title` and `description`: information about the data represented by that schema +- `$comment` (NEW in draft-07): information for developers. With option `$comment` Ajv logs or passes the comment string to the user-supplied function. See [Options](#options). +- `default`: a default value of the data instance, see [Assigning defaults](#assigning-defaults). +- `examples` (NEW in draft-06): an array of data instances. Ajv does not check the validity of these instances against the schema. +- `readOnly` and `writeOnly` (NEW in draft-07): marks data-instance as read-only or write-only in relation to the source of the data (database, api, etc.). +- `contentEncoding`: [RFC 2045](https://tools.ietf.org/html/rfc2045#section-6.1 ), e.g., "base64". +- `contentMediaType`: [RFC 2046](https://tools.ietf.org/html/rfc2046), e.g., "image/png". + +__Please note__: Ajv does not implement validation of the keywords `examples`, `contentEncoding` and `contentMediaType` but it reserves them. If you want to create a plugin that implements some of them, it should remove these keywords from the instance. + + +## Formats + +The following formats are supported for string validation with "format" keyword: + +- _date_: full-date according to [RFC3339](http://tools.ietf.org/html/rfc3339#section-5.6). +- _time_: time with optional time-zone. +- _date-time_: date-time from the same source (time-zone is mandatory). `date`, `time` and `date-time` validate ranges in `full` mode and only regexp in `fast` mode (see [options](#options)). +- _uri_: full URI. +- _uri-reference_: URI reference, including full and relative URIs. +- _uri-template_: URI template according to [RFC6570](https://tools.ietf.org/html/rfc6570) +- _url_ (deprecated): [URL record](https://url.spec.whatwg.org/#concept-url). +- _email_: email address. +- _hostname_: host name according to [RFC1034](http://tools.ietf.org/html/rfc1034#section-3.5). +- _ipv4_: IP address v4. +- _ipv6_: IP address v6. +- _regex_: tests whether a string is a valid regular expression by passing it to RegExp constructor. +- _uuid_: Universally Unique IDentifier according to [RFC4122](http://tools.ietf.org/html/rfc4122). +- _json-pointer_: JSON-pointer according to [RFC6901](https://tools.ietf.org/html/rfc6901). +- _relative-json-pointer_: relative JSON-pointer according to [this draft](http://tools.ietf.org/html/draft-luff-relative-json-pointer-00). + +__Please note__: JSON Schema draft-07 also defines formats `iri`, `iri-reference`, `idn-hostname` and `idn-email` for URLs, hostnames and emails with international characters. Ajv does not implement these formats. If you create Ajv plugin that implements them please make a PR to mention this plugin here. + +There are two modes of format validation: `fast` and `full`. This mode affects formats `date`, `time`, `date-time`, `uri`, `uri-reference`, `email`, and `hostname`. See [Options](#options) for details. + +You can add additional formats and replace any of the formats above using [addFormat](#api-addformat) method. + +The option `unknownFormats` allows changing the default behaviour when an unknown format is encountered. In this case Ajv can either fail schema compilation (default) or ignore it (default in versions before 5.0.0). You also can whitelist specific format(s) to be ignored. See [Options](#options) for details. + +You can find regular expressions used for format validation and the sources that were used in [formats.js](https://github.com/epoberezkin/ajv/blob/master/lib/compile/formats.js). + + +## Combining schemas with $ref + +You can structure your validation logic across multiple schema files and have schemas reference each other using `$ref` keyword. + +Example: + +```javascript +var schema = { + "$id": "http://example.com/schemas/schema.json", + "type": "object", + "properties": { + "foo": { "$ref": "defs.json#/definitions/int" }, + "bar": { "$ref": "defs.json#/definitions/str" } + } +}; + +var defsSchema = { + "$id": "http://example.com/schemas/defs.json", + "definitions": { + "int": { "type": "integer" }, + "str": { "type": "string" } + } +}; +``` + +Now to compile your schema you can either pass all schemas to Ajv instance: + +```javascript +var ajv = new Ajv({schemas: [schema, defsSchema]}); +var validate = ajv.getSchema('http://example.com/schemas/schema.json'); +``` + +or use `addSchema` method: + +```javascript +var ajv = new Ajv; +var validate = ajv.addSchema(defsSchema) + .compile(schema); +``` + +See [Options](#options) and [addSchema](#api) method. + +__Please note__: +- `$ref` is resolved as the uri-reference using schema $id as the base URI (see the example). +- References can be recursive (and mutually recursive) to implement the schemas for different data structures (such as linked lists, trees, graphs, etc.). +- You don't have to host your schema files at the URIs that you use as schema $id. These URIs are only used to identify the schemas, and according to JSON Schema specification validators should not expect to be able to download the schemas from these URIs. +- The actual location of the schema file in the file system is not used. +- You can pass the identifier of the schema as the second parameter of `addSchema` method or as a property name in `schemas` option. This identifier can be used instead of (or in addition to) schema $id. +- You cannot have the same $id (or the schema identifier) used for more than one schema - the exception will be thrown. +- You can implement dynamic resolution of the referenced schemas using `compileAsync` method. In this way you can store schemas in any system (files, web, database, etc.) and reference them without explicitly adding to Ajv instance. See [Asynchronous schema compilation](#asynchronous-schema-compilation). + + +## $data reference + +With `$data` option you can use values from the validated data as the values for the schema keywords. See [proposal](https://github.com/json-schema/json-schema/wiki/$data-(v5-proposal)) for more information about how it works. + +`$data` reference is supported in the keywords: const, enum, format, maximum/minimum, exclusiveMaximum / exclusiveMinimum, maxLength / minLength, maxItems / minItems, maxProperties / minProperties, formatMaximum / formatMinimum, formatExclusiveMaximum / formatExclusiveMinimum, multipleOf, pattern, required, uniqueItems. + +The value of "$data" should be a [JSON-pointer](https://tools.ietf.org/html/rfc6901) to the data (the root is always the top level data object, even if the $data reference is inside a referenced subschema) or a [relative JSON-pointer](http://tools.ietf.org/html/draft-luff-relative-json-pointer-00) (it is relative to the current point in data; if the $data reference is inside a referenced subschema it cannot point to the data outside of the root level for this subschema). + +Examples. + +This schema requires that the value in property `smaller` is less or equal than the value in the property larger: + +```javascript +var ajv = new Ajv({$data: true}); + +var schema = { + "properties": { + "smaller": { + "type": "number", + "maximum": { "$data": "1/larger" } + }, + "larger": { "type": "number" } + } +}; + +var validData = { + smaller: 5, + larger: 7 +}; + +ajv.validate(schema, validData); // true +``` + +This schema requires that the properties have the same format as their field names: + +```javascript +var schema = { + "additionalProperties": { + "type": "string", + "format": { "$data": "0#" } + } +}; + +var validData = { + 'date-time': '1963-06-19T08:30:06.283185Z', + email: 'joe.bloggs@example.com' +} +``` + +`$data` reference is resolved safely - it won't throw even if some property is undefined. If `$data` resolves to `undefined` the validation succeeds (with the exclusion of `const` keyword). If `$data` resolves to incorrect type (e.g. not "number" for maximum keyword) the validation fails. + + +## $merge and $patch keywords + +With the package [ajv-merge-patch](https://github.com/epoberezkin/ajv-merge-patch) you can use the keywords `$merge` and `$patch` that allow extending JSON Schemas with patches using formats [JSON Merge Patch (RFC 7396)](https://tools.ietf.org/html/rfc7396) and [JSON Patch (RFC 6902)](https://tools.ietf.org/html/rfc6902). + +To add keywords `$merge` and `$patch` to Ajv instance use this code: + +```javascript +require('ajv-merge-patch')(ajv); +``` + +Examples. + +Using `$merge`: + +```json +{ + "$merge": { + "source": { + "type": "object", + "properties": { "p": { "type": "string" } }, + "additionalProperties": false + }, + "with": { + "properties": { "q": { "type": "number" } } + } + } +} +``` + +Using `$patch`: + +```json +{ + "$patch": { + "source": { + "type": "object", + "properties": { "p": { "type": "string" } }, + "additionalProperties": false + }, + "with": [ + { "op": "add", "path": "/properties/q", "value": { "type": "number" } } + ] + } +} +``` + +The schemas above are equivalent to this schema: + +```json +{ + "type": "object", + "properties": { + "p": { "type": "string" }, + "q": { "type": "number" } + }, + "additionalProperties": false +} +``` + +The properties `source` and `with` in the keywords `$merge` and `$patch` can use absolute or relative `$ref` to point to other schemas previously added to the Ajv instance or to the fragments of the current schema. + +See the package [ajv-merge-patch](https://github.com/epoberezkin/ajv-merge-patch) for more information. + + +## Defining custom keywords + +The advantages of using custom keywords are: + +- allow creating validation scenarios that cannot be expressed using JSON Schema +- simplify your schemas +- help bringing a bigger part of the validation logic to your schemas +- make your schemas more expressive, less verbose and closer to your application domain +- implement custom data processors that modify your data (`modifying` option MUST be used in keyword definition) and/or create side effects while the data is being validated + +If a keyword is used only for side-effects and its validation result is pre-defined, use option `valid: true/false` in keyword definition to simplify both generated code (no error handling in case of `valid: true`) and your keyword functions (no need to return any validation result). + +The concerns you have to be aware of when extending JSON Schema standard with custom keywords are the portability and understanding of your schemas. You will have to support these custom keywords on other platforms and to properly document these keywords so that everybody can understand them in your schemas. + +You can define custom keywords with [addKeyword](#api-addkeyword) method. Keywords are defined on the `ajv` instance level - new instances will not have previously defined keywords. + +Ajv allows defining keywords with: +- validation function +- compilation function +- macro function +- inline compilation function that should return code (as string) that will be inlined in the currently compiled schema. + +Example. `range` and `exclusiveRange` keywords using compiled schema: + +```javascript +ajv.addKeyword('range', { + type: 'number', + compile: function (sch, parentSchema) { + var min = sch[0]; + var max = sch[1]; + + return parentSchema.exclusiveRange === true + ? function (data) { return data > min && data < max; } + : function (data) { return data >= min && data <= max; } + } +}); + +var schema = { "range": [2, 4], "exclusiveRange": true }; +var validate = ajv.compile(schema); +console.log(validate(2.01)); // true +console.log(validate(3.99)); // true +console.log(validate(2)); // false +console.log(validate(4)); // false +``` + +Several custom keywords (typeof, instanceof, range and propertyNames) are defined in [ajv-keywords](https://github.com/epoberezkin/ajv-keywords) package - they can be used for your schemas and as a starting point for your own custom keywords. + +See [Defining custom keywords](https://github.com/epoberezkin/ajv/blob/master/CUSTOM.md) for more details. + + +## Asynchronous schema compilation + +During asynchronous compilation remote references are loaded using supplied function. See `compileAsync` [method](#api-compileAsync) and `loadSchema` [option](#options). + +Example: + +```javascript +var ajv = new Ajv({ loadSchema: loadSchema }); + +ajv.compileAsync(schema).then(function (validate) { + var valid = validate(data); + // ... +}); + +function loadSchema(uri) { + return request.json(uri).then(function (res) { + if (res.statusCode >= 400) + throw new Error('Loading error: ' + res.statusCode); + return res.body; + }); +} +``` + +__Please note__: [Option](#options) `missingRefs` should NOT be set to `"ignore"` or `"fail"` for asynchronous compilation to work. + + +## Asynchronous validation + +Example in Node.js REPL: https://tonicdev.com/esp/ajv-asynchronous-validation + +You can define custom formats and keywords that perform validation asynchronously by accessing database or some other service. You should add `async: true` in the keyword or format definition (see [addFormat](#api-addformat), [addKeyword](#api-addkeyword) and [Defining custom keywords](#defining-custom-keywords)). + +If your schema uses asynchronous formats/keywords or refers to some schema that contains them it should have `"$async": true` keyword so that Ajv can compile it correctly. If asynchronous format/keyword or reference to asynchronous schema is used in the schema without `$async` keyword Ajv will throw an exception during schema compilation. + +__Please note__: all asynchronous subschemas that are referenced from the current or other schemas should have `"$async": true` keyword as well, otherwise the schema compilation will fail. + +Validation function for an asynchronous custom format/keyword should return a promise that resolves with `true` or `false` (or rejects with `new Ajv.ValidationError(errors)` if you want to return custom errors from the keyword function). + +Ajv compiles asynchronous schemas to [es7 async functions](http://tc39.github.io/ecmascript-asyncawait/) that can optionally be transpiled with [nodent](https://github.com/MatAtBread/nodent). Async functions are supported in Node.js 7+ and all modern browsers. You can also supply any other transpiler as a function via `processCode` option. See [Options](#options). + +The compiled validation function has `$async: true` property (if the schema is asynchronous), so you can differentiate these functions if you are using both synchronous and asynchronous schemas. + +Validation result will be a promise that resolves with validated data or rejects with an exception `Ajv.ValidationError` that contains the array of validation errors in `errors` property. + + +Example: + +```javascript +var ajv = new Ajv; +// require('ajv-async')(ajv); + +ajv.addKeyword('idExists', { + async: true, + type: 'number', + validate: checkIdExists +}); + + +function checkIdExists(schema, data) { + return knex(schema.table) + .select('id') + .where('id', data) + .then(function (rows) { + return !!rows.length; // true if record is found + }); +} + +var schema = { + "$async": true, + "properties": { + "userId": { + "type": "integer", + "idExists": { "table": "users" } + }, + "postId": { + "type": "integer", + "idExists": { "table": "posts" } + } + } +}; + +var validate = ajv.compile(schema); + +validate({ userId: 1, postId: 19 }) +.then(function (data) { + console.log('Data is valid', data); // { userId: 1, postId: 19 } +}) +.catch(function (err) { + if (!(err instanceof Ajv.ValidationError)) throw err; + // data is invalid + console.log('Validation errors:', err.errors); +}); +``` + +### Using transpilers with asynchronous validation functions. + +[ajv-async](https://github.com/epoberezkin/ajv-async) uses [nodent](https://github.com/MatAtBread/nodent) to transpile async functions. To use another transpiler you should separately install it (or load its bundle in the browser). + + +#### Using nodent + +```javascript +var ajv = new Ajv; +require('ajv-async')(ajv); +// in the browser if you want to load ajv-async bundle separately you can: +// window.ajvAsync(ajv); +var validate = ajv.compile(schema); // transpiled es7 async function +validate(data).then(successFunc).catch(errorFunc); +``` + + +#### Using other transpilers + +```javascript +var ajv = new Ajv({ processCode: transpileFunc }); +var validate = ajv.compile(schema); // transpiled es7 async function +validate(data).then(successFunc).catch(errorFunc); +``` + +See [Options](#options). + + +## Security considerations + +JSON Schema, if properly used, can replace data sanitisation. It doesn't replace other API security considerations. It also introduces additional security aspects to consider. + + +##### Security contact + +To report a security vulnerability, please use the +[Tidelift security contact](https://tidelift.com/security). +Tidelift will coordinate the fix and disclosure. Please do NOT report security vulnerabilities via GitHub issues. + + +##### Untrusted schemas + +Ajv treats JSON schemas as trusted as your application code. This security model is based on the most common use case, when the schemas are static and bundled together with the application. + +If your schemas are received from untrusted sources (or generated from untrusted data) there are several scenarios you need to prevent: +- compiling schemas can cause stack overflow (if they are too deep) +- compiling schemas can be slow (e.g. [#557](https://github.com/epoberezkin/ajv/issues/557)) +- validating certain data can be slow + +It is difficult to predict all the scenarios, but at the very least it may help to limit the size of untrusted schemas (e.g. limit JSON string length) and also the maximum schema object depth (that can be high for relatively small JSON strings). You also may want to mitigate slow regular expressions in `pattern` and `patternProperties` keywords. + +Regardless the measures you take, using untrusted schemas increases security risks. + + +##### Circular references in JavaScript objects + +Ajv does not support schemas and validated data that have circular references in objects. See [issue #802](https://github.com/epoberezkin/ajv/issues/802). + +An attempt to compile such schemas or validate such data would cause stack overflow (or will not complete in case of asynchronous validation). Depending on the parser you use, untrusted data can lead to circular references. + + +##### Security risks of trusted schemas + +Some keywords in JSON Schemas can lead to very slow validation for certain data. These keywords include (but may be not limited to): + +- `pattern` and `format` for large strings - use `maxLength` to mitigate +- `uniqueItems` for large non-scalar arrays - use `maxItems` to mitigate +- `patternProperties` for large property names - use `propertyNames` to mitigate + +__Please note__: The suggestions above to prevent slow validation would only work if you do NOT use `allErrors: true` in production code (using it would continue validation after validation errors). + +You can validate your JSON schemas against [this meta-schema](https://github.com/epoberezkin/ajv/blob/master/lib/refs/json-schema-secure.json) to check that these recommendations are followed: + +```javascript +const isSchemaSecure = ajv.compile(require('ajv/lib/refs/json-schema-secure.json')); + +const schema1 = {format: 'email'}; +isSchemaSecure(schema1); // false + +const schema2 = {format: 'email', maxLength: 256}; +isSchemaSecure(schema2); // true +``` + +__Please note__: following all these recommendation is not a guarantee that validation of untrusted data is safe - it can still lead to some undesirable results. + + +## Filtering data + +With [option `removeAdditional`](#options) (added by [andyscott](https://github.com/andyscott)) you can filter data during the validation. + +This option modifies original data. + +Example: + +```javascript +var ajv = new Ajv({ removeAdditional: true }); +var schema = { + "additionalProperties": false, + "properties": { + "foo": { "type": "number" }, + "bar": { + "additionalProperties": { "type": "number" }, + "properties": { + "baz": { "type": "string" } + } + } + } +} + +var data = { + "foo": 0, + "additional1": 1, // will be removed; `additionalProperties` == false + "bar": { + "baz": "abc", + "additional2": 2 // will NOT be removed; `additionalProperties` != false + }, +} + +var validate = ajv.compile(schema); + +console.log(validate(data)); // true +console.log(data); // { "foo": 0, "bar": { "baz": "abc", "additional2": 2 } +``` + +If `removeAdditional` option in the example above were `"all"` then both `additional1` and `additional2` properties would have been removed. + +If the option were `"failing"` then property `additional1` would have been removed regardless of its value and property `additional2` would have been removed only if its value were failing the schema in the inner `additionalProperties` (so in the example above it would have stayed because it passes the schema, but any non-number would have been removed). + +__Please note__: If you use `removeAdditional` option with `additionalProperties` keyword inside `anyOf`/`oneOf` keywords your validation can fail with this schema, for example: + +```json +{ + "type": "object", + "oneOf": [ + { + "properties": { + "foo": { "type": "string" } + }, + "required": [ "foo" ], + "additionalProperties": false + }, + { + "properties": { + "bar": { "type": "integer" } + }, + "required": [ "bar" ], + "additionalProperties": false + } + ] +} +``` + +The intention of the schema above is to allow objects with either the string property "foo" or the integer property "bar", but not with both and not with any other properties. + +With the option `removeAdditional: true` the validation will pass for the object `{ "foo": "abc"}` but will fail for the object `{"bar": 1}`. It happens because while the first subschema in `oneOf` is validated, the property `bar` is removed because it is an additional property according to the standard (because it is not included in `properties` keyword in the same schema). + +While this behaviour is unexpected (issues [#129](https://github.com/epoberezkin/ajv/issues/129), [#134](https://github.com/epoberezkin/ajv/issues/134)), it is correct. To have the expected behaviour (both objects are allowed and additional properties are removed) the schema has to be refactored in this way: + +```json +{ + "type": "object", + "properties": { + "foo": { "type": "string" }, + "bar": { "type": "integer" } + }, + "additionalProperties": false, + "oneOf": [ + { "required": [ "foo" ] }, + { "required": [ "bar" ] } + ] +} +``` + +The schema above is also more efficient - it will compile into a faster function. + + +## Assigning defaults + +With [option `useDefaults`](#options) Ajv will assign values from `default` keyword in the schemas of `properties` and `items` (when it is the array of schemas) to the missing properties and items. + +With the option value `"empty"` properties and items equal to `null` or `""` (empty string) will be considered missing and assigned defaults. + +This option modifies original data. + +__Please note__: the default value is inserted in the generated validation code as a literal, so the value inserted in the data will be the deep clone of the default in the schema. + + +Example 1 (`default` in `properties`): + +```javascript +var ajv = new Ajv({ useDefaults: true }); +var schema = { + "type": "object", + "properties": { + "foo": { "type": "number" }, + "bar": { "type": "string", "default": "baz" } + }, + "required": [ "foo", "bar" ] +}; + +var data = { "foo": 1 }; + +var validate = ajv.compile(schema); + +console.log(validate(data)); // true +console.log(data); // { "foo": 1, "bar": "baz" } +``` + +Example 2 (`default` in `items`): + +```javascript +var schema = { + "type": "array", + "items": [ + { "type": "number" }, + { "type": "string", "default": "foo" } + ] +} + +var data = [ 1 ]; + +var validate = ajv.compile(schema); + +console.log(validate(data)); // true +console.log(data); // [ 1, "foo" ] +``` + +`default` keywords in other cases are ignored: + +- not in `properties` or `items` subschemas +- in schemas inside `anyOf`, `oneOf` and `not` (see [#42](https://github.com/epoberezkin/ajv/issues/42)) +- in `if` subschema of `switch` keyword +- in schemas generated by custom macro keywords + +The [`strictDefaults` option](#options) customizes Ajv's behavior for the defaults that Ajv ignores (`true` raises an error, and `"log"` outputs a warning). + + +## Coercing data types + +When you are validating user inputs all your data properties are usually strings. The option `coerceTypes` allows you to have your data types coerced to the types specified in your schema `type` keywords, both to pass the validation and to use the correctly typed data afterwards. + +This option modifies original data. + +__Please note__: if you pass a scalar value to the validating function its type will be coerced and it will pass the validation, but the value of the variable you pass won't be updated because scalars are passed by value. + + +Example 1: + +```javascript +var ajv = new Ajv({ coerceTypes: true }); +var schema = { + "type": "object", + "properties": { + "foo": { "type": "number" }, + "bar": { "type": "boolean" } + }, + "required": [ "foo", "bar" ] +}; + +var data = { "foo": "1", "bar": "false" }; + +var validate = ajv.compile(schema); + +console.log(validate(data)); // true +console.log(data); // { "foo": 1, "bar": false } +``` + +Example 2 (array coercions): + +```javascript +var ajv = new Ajv({ coerceTypes: 'array' }); +var schema = { + "properties": { + "foo": { "type": "array", "items": { "type": "number" } }, + "bar": { "type": "boolean" } + } +}; + +var data = { "foo": "1", "bar": ["false"] }; + +var validate = ajv.compile(schema); + +console.log(validate(data)); // true +console.log(data); // { "foo": [1], "bar": false } +``` + +The coercion rules, as you can see from the example, are different from JavaScript both to validate user input as expected and to have the coercion reversible (to correctly validate cases where different types are defined in subschemas of "anyOf" and other compound keywords). + +See [Coercion rules](https://github.com/epoberezkin/ajv/blob/master/COERCION.md) for details. + + +## API + +##### new Ajv(Object options) -> Object + +Create Ajv instance. + + +##### .compile(Object schema) -> Function<Object data> + +Generate validating function and cache the compiled schema for future use. + +Validating function returns a boolean value. This function has properties `errors` and `schema`. Errors encountered during the last validation are assigned to `errors` property (it is assigned `null` if there was no errors). `schema` property contains the reference to the original schema. + +The schema passed to this method will be validated against meta-schema unless `validateSchema` option is false. If schema is invalid, an error will be thrown. See [options](#options). + + +##### .compileAsync(Object schema [, Boolean meta] [, Function callback]) -> Promise + +Asynchronous version of `compile` method that loads missing remote schemas using asynchronous function in `options.loadSchema`. This function returns a Promise that resolves to a validation function. An optional callback passed to `compileAsync` will be called with 2 parameters: error (or null) and validating function. The returned promise will reject (and the callback will be called with an error) when: + +- missing schema can't be loaded (`loadSchema` returns a Promise that rejects). +- a schema containing a missing reference is loaded, but the reference cannot be resolved. +- schema (or some loaded/referenced schema) is invalid. + +The function compiles schema and loads the first missing schema (or meta-schema) until all missing schemas are loaded. + +You can asynchronously compile meta-schema by passing `true` as the second parameter. + +See example in [Asynchronous compilation](#asynchronous-schema-compilation). + + +##### .validate(Object schema|String key|String ref, data) -> Boolean + +Validate data using passed schema (it will be compiled and cached). + +Instead of the schema you can use the key that was previously passed to `addSchema`, the schema id if it was present in the schema or any previously resolved reference. + +Validation errors will be available in the `errors` property of Ajv instance (`null` if there were no errors). + +__Please note__: every time this method is called the errors are overwritten so you need to copy them to another variable if you want to use them later. + +If the schema is asynchronous (has `$async` keyword on the top level) this method returns a Promise. See [Asynchronous validation](#asynchronous-validation). + + +##### .addSchema(Array<Object>|Object schema [, String key]) -> Ajv + +Add schema(s) to validator instance. This method does not compile schemas (but it still validates them). Because of that dependencies can be added in any order and circular dependencies are supported. It also prevents unnecessary compilation of schemas that are containers for other schemas but not used as a whole. + +Array of schemas can be passed (schemas should have ids), the second parameter will be ignored. + +Key can be passed that can be used to reference the schema and will be used as the schema id if there is no id inside the schema. If the key is not passed, the schema id will be used as the key. + + +Once the schema is added, it (and all the references inside it) can be referenced in other schemas and used to validate data. + +Although `addSchema` does not compile schemas, explicit compilation is not required - the schema will be compiled when it is used first time. + +By default the schema is validated against meta-schema before it is added, and if the schema does not pass validation the exception is thrown. This behaviour is controlled by `validateSchema` option. + +__Please note__: Ajv uses the [method chaining syntax](https://en.wikipedia.org/wiki/Method_chaining) for all methods with the prefix `add*` and `remove*`. +This allows you to do nice things like the following. + +```javascript +var validate = new Ajv().addSchema(schema).addFormat(name, regex).getSchema(uri); +``` + +##### .addMetaSchema(Array<Object>|Object schema [, String key]) -> Ajv + +Adds meta schema(s) that can be used to validate other schemas. That function should be used instead of `addSchema` because there may be instance options that would compile a meta schema incorrectly (at the moment it is `removeAdditional` option). + +There is no need to explicitly add draft-07 meta schema (http://json-schema.org/draft-07/schema) - it is added by default, unless option `meta` is set to `false`. You only need to use it if you have a changed meta-schema that you want to use to validate your schemas. See `validateSchema`. + + +##### .validateSchema(Object schema) -> Boolean + +Validates schema. This method should be used to validate schemas rather than `validate` due to the inconsistency of `uri` format in JSON Schema standard. + +By default this method is called automatically when the schema is added, so you rarely need to use it directly. + +If schema doesn't have `$schema` property, it is validated against draft 6 meta-schema (option `meta` should not be false). + +If schema has `$schema` property, then the schema with this id (that should be previously added) is used to validate passed schema. + +Errors will be available at `ajv.errors`. + + +##### .getSchema(String key) -> Function<Object data> + +Retrieve compiled schema previously added with `addSchema` by the key passed to `addSchema` or by its full reference (id). The returned validating function has `schema` property with the reference to the original schema. + + +##### .removeSchema([Object schema|String key|String ref|RegExp pattern]) -> Ajv + +Remove added/cached schema. Even if schema is referenced by other schemas it can be safely removed as dependent schemas have local references. + +Schema can be removed using: +- key passed to `addSchema` +- it's full reference (id) +- RegExp that should match schema id or key (meta-schemas won't be removed) +- actual schema object that will be stable-stringified to remove schema from cache + +If no parameter is passed all schemas but meta-schemas will be removed and the cache will be cleared. + + +##### .addFormat(String name, String|RegExp|Function|Object format) -> Ajv + +Add custom format to validate strings or numbers. It can also be used to replace pre-defined formats for Ajv instance. + +Strings are converted to RegExp. + +Function should return validation result as `true` or `false`. + +If object is passed it should have properties `validate`, `compare` and `async`: + +- _validate_: a string, RegExp or a function as described above. +- _compare_: an optional comparison function that accepts two strings and compares them according to the format meaning. This function is used with keywords `formatMaximum`/`formatMinimum` (defined in [ajv-keywords](https://github.com/epoberezkin/ajv-keywords) package). It should return `1` if the first value is bigger than the second value, `-1` if it is smaller and `0` if it is equal. +- _async_: an optional `true` value if `validate` is an asynchronous function; in this case it should return a promise that resolves with a value `true` or `false`. +- _type_: an optional type of data that the format applies to. It can be `"string"` (default) or `"number"` (see https://github.com/epoberezkin/ajv/issues/291#issuecomment-259923858). If the type of data is different, the validation will pass. + +Custom formats can be also added via `formats` option. + + +##### .addKeyword(String keyword, Object definition) -> Ajv + +Add custom validation keyword to Ajv instance. + +Keyword should be different from all standard JSON Schema keywords and different from previously defined keywords. There is no way to redefine keywords or to remove keyword definition from the instance. + +Keyword must start with a letter, `_` or `$`, and may continue with letters, numbers, `_`, `$`, or `-`. +It is recommended to use an application-specific prefix for keywords to avoid current and future name collisions. + +Example Keywords: +- `"xyz-example"`: valid, and uses prefix for the xyz project to avoid name collisions. +- `"example"`: valid, but not recommended as it could collide with future versions of JSON Schema etc. +- `"3-example"`: invalid as numbers are not allowed to be the first character in a keyword + +Keyword definition is an object with the following properties: + +- _type_: optional string or array of strings with data type(s) that the keyword applies to. If not present, the keyword will apply to all types. +- _validate_: validating function +- _compile_: compiling function +- _macro_: macro function +- _inline_: compiling function that returns code (as string) +- _schema_: an optional `false` value used with "validate" keyword to not pass schema +- _metaSchema_: an optional meta-schema for keyword schema +- _dependencies_: an optional list of properties that must be present in the parent schema - it will be checked during schema compilation +- _modifying_: `true` MUST be passed if keyword modifies data +- _statements_: `true` can be passed in case inline keyword generates statements (as opposed to expression) +- _valid_: pass `true`/`false` to pre-define validation result, the result returned from validation function will be ignored. This option cannot be used with macro keywords. +- _$data_: an optional `true` value to support [$data reference](#data-reference) as the value of custom keyword. The reference will be resolved at validation time. If the keyword has meta-schema it would be extended to allow $data and it will be used to validate the resolved value. Supporting $data reference requires that keyword has validating function (as the only option or in addition to compile, macro or inline function). +- _async_: an optional `true` value if the validation function is asynchronous (whether it is compiled or passed in _validate_ property); in this case it should return a promise that resolves with a value `true` or `false`. This option is ignored in case of "macro" and "inline" keywords. +- _errors_: an optional boolean or string `"full"` indicating whether keyword returns errors. If this property is not set Ajv will determine if the errors were set in case of failed validation. + +_compile_, _macro_ and _inline_ are mutually exclusive, only one should be used at a time. _validate_ can be used separately or in addition to them to support $data reference. + +__Please note__: If the keyword is validating data type that is different from the type(s) in its definition, the validation function will not be called (and expanded macro will not be used), so there is no need to check for data type inside validation function or inside schema returned by macro function (unless you want to enforce a specific type and for some reason do not want to use a separate `type` keyword for that). In the same way as standard keywords work, if the keyword does not apply to the data type being validated, the validation of this keyword will succeed. + +See [Defining custom keywords](#defining-custom-keywords) for more details. + + +##### .getKeyword(String keyword) -> Object|Boolean + +Returns custom keyword definition, `true` for pre-defined keywords and `false` if the keyword is unknown. + + +##### .removeKeyword(String keyword) -> Ajv + +Removes custom or pre-defined keyword so you can redefine them. + +While this method can be used to extend pre-defined keywords, it can also be used to completely change their meaning - it may lead to unexpected results. + +__Please note__: schemas compiled before the keyword is removed will continue to work without changes. To recompile schemas use `removeSchema` method and compile them again. + + +##### .errorsText([Array<Object> errors [, Object options]]) -> String + +Returns the text with all errors in a String. + +Options can have properties `separator` (string used to separate errors, ", " by default) and `dataVar` (the variable name that dataPaths are prefixed with, "data" by default). + + +## Options + +Defaults: + +```javascript +{ + // validation and reporting options: + $data: false, + allErrors: false, + verbose: false, + $comment: false, // NEW in Ajv version 6.0 + jsonPointers: false, + uniqueItems: true, + unicode: true, + nullable: false, + format: 'fast', + formats: {}, + unknownFormats: true, + schemas: {}, + logger: undefined, + // referenced schema options: + schemaId: '$id', + missingRefs: true, + extendRefs: 'ignore', // recommended 'fail' + loadSchema: undefined, // function(uri: string): Promise {} + // options to modify validated data: + removeAdditional: false, + useDefaults: false, + coerceTypes: false, + // strict mode options + strictDefaults: false, + strictKeywords: false, + // asynchronous validation options: + transpile: undefined, // requires ajv-async package + // advanced options: + meta: true, + validateSchema: true, + addUsedSchema: true, + inlineRefs: true, + passContext: false, + loopRequired: Infinity, + ownProperties: false, + multipleOfPrecision: false, + errorDataPath: 'object', // deprecated + messages: true, + sourceCode: false, + processCode: undefined, // function (str: string): string {} + cache: new Cache, + serialize: undefined +} +``` + +##### Validation and reporting options + +- _$data_: support [$data references](#data-reference). Draft 6 meta-schema that is added by default will be extended to allow them. If you want to use another meta-schema you need to use $dataMetaSchema method to add support for $data reference. See [API](#api). +- _allErrors_: check all rules collecting all errors. Default is to return after the first error. +- _verbose_: include the reference to the part of the schema (`schema` and `parentSchema`) and validated data in errors (false by default). +- _$comment_ (NEW in Ajv version 6.0): log or pass the value of `$comment` keyword to a function. Option values: + - `false` (default): ignore $comment keyword. + - `true`: log the keyword value to console. + - function: pass the keyword value, its schema path and root schema to the specified function +- _jsonPointers_: set `dataPath` property of errors using [JSON Pointers](https://tools.ietf.org/html/rfc6901) instead of JavaScript property access notation. +- _uniqueItems_: validate `uniqueItems` keyword (true by default). +- _unicode_: calculate correct length of strings with unicode pairs (true by default). Pass `false` to use `.length` of strings that is faster, but gives "incorrect" lengths of strings with unicode pairs - each unicode pair is counted as two characters. +- _nullable_: support keyword "nullable" from [Open API 3 specification](https://swagger.io/docs/specification/data-models/data-types/). +- _format_: formats validation mode. Option values: + - `"fast"` (default) - simplified and fast validation (see [Formats](#formats) for details of which formats are available and affected by this option). + - `"full"` - more restrictive and slow validation. E.g., 25:00:00 and 2015/14/33 will be invalid time and date in 'full' mode but it will be valid in 'fast' mode. + - `false` - ignore all format keywords. +- _formats_: an object with custom formats. Keys and values will be passed to `addFormat` method. +- _unknownFormats_: handling of unknown formats. Option values: + - `true` (default) - if an unknown format is encountered the exception is thrown during schema compilation. If `format` keyword value is [$data reference](#data-reference) and it is unknown the validation will fail. + - `[String]` - an array of unknown format names that will be ignored. This option can be used to allow usage of third party schemas with format(s) for which you don't have definitions, but still fail if another unknown format is used. If `format` keyword value is [$data reference](#data-reference) and it is not in this array the validation will fail. + - `"ignore"` - to log warning during schema compilation and always pass validation (the default behaviour in versions before 5.0.0). This option is not recommended, as it allows to mistype format name and it won't be validated without any error message. This behaviour is required by JSON Schema specification. +- _schemas_: an array or object of schemas that will be added to the instance. In case you pass the array the schemas must have IDs in them. When the object is passed the method `addSchema(value, key)` will be called for each schema in this object. +- _logger_: sets the logging method. Default is the global `console` object that should have methods `log`, `warn` and `error`. Option values: + - custom logger - it should have methods `log`, `warn` and `error`. If any of these methods is missing an exception will be thrown. + - `false` - logging is disabled. + + +##### Referenced schema options + +- _schemaId_: this option defines which keywords are used as schema URI. Option value: + - `"$id"` (default) - only use `$id` keyword as schema URI (as specified in JSON Schema draft-06/07), ignore `id` keyword (if it is present a warning will be logged). + - `"id"` - only use `id` keyword as schema URI (as specified in JSON Schema draft-04), ignore `$id` keyword (if it is present a warning will be logged). + - `"auto"` - use both `$id` and `id` keywords as schema URI. If both are present (in the same schema object) and different the exception will be thrown during schema compilation. +- _missingRefs_: handling of missing referenced schemas. Option values: + - `true` (default) - if the reference cannot be resolved during compilation the exception is thrown. The thrown error has properties `missingRef` (with hash fragment) and `missingSchema` (without it). Both properties are resolved relative to the current base id (usually schema id, unless it was substituted). + - `"ignore"` - to log error during compilation and always pass validation. + - `"fail"` - to log error and successfully compile schema but fail validation if this rule is checked. +- _extendRefs_: validation of other keywords when `$ref` is present in the schema. Option values: + - `"ignore"` (default) - when `$ref` is used other keywords are ignored (as per [JSON Reference](https://tools.ietf.org/html/draft-pbryan-zyp-json-ref-03#section-3) standard). A warning will be logged during the schema compilation. + - `"fail"` (recommended) - if other validation keywords are used together with `$ref` the exception will be thrown when the schema is compiled. This option is recommended to make sure schema has no keywords that are ignored, which can be confusing. + - `true` - validate all keywords in the schemas with `$ref` (the default behaviour in versions before 5.0.0). +- _loadSchema_: asynchronous function that will be used to load remote schemas when `compileAsync` [method](#api-compileAsync) is used and some reference is missing (option `missingRefs` should NOT be 'fail' or 'ignore'). This function should accept remote schema uri as a parameter and return a Promise that resolves to a schema. See example in [Asynchronous compilation](#asynchronous-schema-compilation). + + +##### Options to modify validated data + +- _removeAdditional_: remove additional properties - see example in [Filtering data](#filtering-data). This option is not used if schema is added with `addMetaSchema` method. Option values: + - `false` (default) - not to remove additional properties + - `"all"` - all additional properties are removed, regardless of `additionalProperties` keyword in schema (and no validation is made for them). + - `true` - only additional properties with `additionalProperties` keyword equal to `false` are removed. + - `"failing"` - additional properties that fail schema validation will be removed (where `additionalProperties` keyword is `false` or schema). +- _useDefaults_: replace missing or undefined properties and items with the values from corresponding `default` keywords. Default behaviour is to ignore `default` keywords. This option is not used if schema is added with `addMetaSchema` method. See examples in [Assigning defaults](#assigning-defaults). Option values: + - `false` (default) - do not use defaults + - `true` - insert defaults by value (object literal is used). + - `"empty"` - in addition to missing or undefined, use defaults for properties and items that are equal to `null` or `""` (an empty string). + - `"shared"` (deprecated) - insert defaults by reference. If the default is an object, it will be shared by all instances of validated data. If you modify the inserted default in the validated data, it will be modified in the schema as well. +- _coerceTypes_: change data type of data to match `type` keyword. See the example in [Coercing data types](#coercing-data-types) and [coercion rules](https://github.com/epoberezkin/ajv/blob/master/COERCION.md). Option values: + - `false` (default) - no type coercion. + - `true` - coerce scalar data types. + - `"array"` - in addition to coercions between scalar types, coerce scalar data to an array with one element and vice versa (as required by the schema). + + +##### Strict mode options + +- _strictDefaults_: report ignored `default` keywords in schemas. Option values: + - `false` (default) - ignored defaults are not reported + - `true` - if an ignored default is present, throw an error + - `"log"` - if an ignored default is present, log warning +- _strictKeywords_: report unknown keywords in schemas. Option values: + - `false` (default) - unknown keywords are not reported + - `true` - if an unknown keyword is present, throw an error + - `"log"` - if an unknown keyword is present, log warning + + +##### Asynchronous validation options + +- _transpile_: Requires [ajv-async](https://github.com/epoberezkin/ajv-async) package. It determines whether Ajv transpiles compiled asynchronous validation function. Option values: + - `undefined` (default) - transpile with [nodent](https://github.com/MatAtBread/nodent) if async functions are not supported. + - `true` - always transpile with nodent. + - `false` - do not transpile; if async functions are not supported an exception will be thrown. + + +##### Advanced options + +- _meta_: add [meta-schema](http://json-schema.org/documentation.html) so it can be used by other schemas (true by default). If an object is passed, it will be used as the default meta-schema for schemas that have no `$schema` keyword. This default meta-schema MUST have `$schema` keyword. +- _validateSchema_: validate added/compiled schemas against meta-schema (true by default). `$schema` property in the schema can be http://json-schema.org/draft-07/schema or absent (draft-07 meta-schema will be used) or can be a reference to the schema previously added with `addMetaSchema` method. Option values: + - `true` (default) - if the validation fails, throw the exception. + - `"log"` - if the validation fails, log error. + - `false` - skip schema validation. +- _addUsedSchema_: by default methods `compile` and `validate` add schemas to the instance if they have `$id` (or `id`) property that doesn't start with "#". If `$id` is present and it is not unique the exception will be thrown. Set this option to `false` to skip adding schemas to the instance and the `$id` uniqueness check when these methods are used. This option does not affect `addSchema` method. +- _inlineRefs_: Affects compilation of referenced schemas. Option values: + - `true` (default) - the referenced schemas that don't have refs in them are inlined, regardless of their size - that substantially improves performance at the cost of the bigger size of compiled schema functions. + - `false` - to not inline referenced schemas (they will be compiled as separate functions). + - integer number - to limit the maximum number of keywords of the schema that will be inlined. +- _passContext_: pass validation context to custom keyword functions. If this option is `true` and you pass some context to the compiled validation function with `validate.call(context, data)`, the `context` will be available as `this` in your custom keywords. By default `this` is Ajv instance. +- _loopRequired_: by default `required` keyword is compiled into a single expression (or a sequence of statements in `allErrors` mode). In case of a very large number of properties in this keyword it may result in a very big validation function. Pass integer to set the number of properties above which `required` keyword will be validated in a loop - smaller validation function size but also worse performance. +- _ownProperties_: by default Ajv iterates over all enumerable object properties; when this option is `true` only own enumerable object properties (i.e. found directly on the object rather than on its prototype) are iterated. Contributed by @mbroadst. +- _multipleOfPrecision_: by default `multipleOf` keyword is validated by comparing the result of division with parseInt() of that result. It works for dividers that are bigger than 1. For small dividers such as 0.01 the result of the division is usually not integer (even when it should be integer, see issue [#84](https://github.com/epoberezkin/ajv/issues/84)). If you need to use fractional dividers set this option to some positive integer N to have `multipleOf` validated using this formula: `Math.abs(Math.round(division) - division) < 1e-N` (it is slower but allows for float arithmetics deviations). +- _errorDataPath_ (deprecated): set `dataPath` to point to 'object' (default) or to 'property' when validating keywords `required`, `additionalProperties` and `dependencies`. +- _messages_: Include human-readable messages in errors. `true` by default. `false` can be passed when custom messages are used (e.g. with [ajv-i18n](https://github.com/epoberezkin/ajv-i18n)). +- _sourceCode_: add `sourceCode` property to validating function (for debugging; this code can be different from the result of toString call). +- _processCode_: an optional function to process generated code before it is passed to Function constructor. It can be used to either beautify (the validating function is generated without line-breaks) or to transpile code. Starting from version 5.0.0 this option replaced options: + - `beautify` that formatted the generated function using [js-beautify](https://github.com/beautify-web/js-beautify). If you want to beautify the generated code pass `require('js-beautify').js_beautify`. + - `transpile` that transpiled asynchronous validation function. You can still use `transpile` option with [ajv-async](https://github.com/epoberezkin/ajv-async) package. See [Asynchronous validation](#asynchronous-validation) for more information. +- _cache_: an optional instance of cache to store compiled schemas using stable-stringified schema as a key. For example, set-associative cache [sacjs](https://github.com/epoberezkin/sacjs) can be used. If not passed then a simple hash is used which is good enough for the common use case (a limited number of statically defined schemas). Cache should have methods `put(key, value)`, `get(key)`, `del(key)` and `clear()`. +- _serialize_: an optional function to serialize schema to cache key. Pass `false` to use schema itself as a key (e.g., if WeakMap used as a cache). By default [fast-json-stable-stringify](https://github.com/epoberezkin/fast-json-stable-stringify) is used. + + +## Validation errors + +In case of validation failure, Ajv assigns the array of errors to `errors` property of validation function (or to `errors` property of Ajv instance when `validate` or `validateSchema` methods were called). In case of [asynchronous validation](#asynchronous-validation), the returned promise is rejected with exception `Ajv.ValidationError` that has `errors` property. + + +### Error objects + +Each error is an object with the following properties: + +- _keyword_: validation keyword. +- _dataPath_: the path to the part of the data that was validated. By default `dataPath` uses JavaScript property access notation (e.g., `".prop[1].subProp"`). When the option `jsonPointers` is true (see [Options](#options)) `dataPath` will be set using JSON pointer standard (e.g., `"/prop/1/subProp"`). +- _schemaPath_: the path (JSON-pointer as a URI fragment) to the schema of the keyword that failed validation. +- _params_: the object with the additional information about error that can be used to create custom error messages (e.g., using [ajv-i18n](https://github.com/epoberezkin/ajv-i18n) package). See below for parameters set by all keywords. +- _message_: the standard error message (can be excluded with option `messages` set to false). +- _schema_: the schema of the keyword (added with `verbose` option). +- _parentSchema_: the schema containing the keyword (added with `verbose` option) +- _data_: the data validated by the keyword (added with `verbose` option). + +__Please note__: `propertyNames` keyword schema validation errors have an additional property `propertyName`, `dataPath` points to the object. After schema validation for each property name, if it is invalid an additional error is added with the property `keyword` equal to `"propertyNames"`. + + +### Error parameters + +Properties of `params` object in errors depend on the keyword that failed validation. + +- `maxItems`, `minItems`, `maxLength`, `minLength`, `maxProperties`, `minProperties` - property `limit` (number, the schema of the keyword). +- `additionalItems` - property `limit` (the maximum number of allowed items in case when `items` keyword is an array of schemas and `additionalItems` is false). +- `additionalProperties` - property `additionalProperty` (the property not used in `properties` and `patternProperties` keywords). +- `dependencies` - properties: + - `property` (dependent property), + - `missingProperty` (required missing dependency - only the first one is reported currently) + - `deps` (required dependencies, comma separated list as a string), + - `depsCount` (the number of required dependencies). +- `format` - property `format` (the schema of the keyword). +- `maximum`, `minimum` - properties: + - `limit` (number, the schema of the keyword), + - `exclusive` (boolean, the schema of `exclusiveMaximum` or `exclusiveMinimum`), + - `comparison` (string, comparison operation to compare the data to the limit, with the data on the left and the limit on the right; can be "<", "<=", ">", ">=") +- `multipleOf` - property `multipleOf` (the schema of the keyword) +- `pattern` - property `pattern` (the schema of the keyword) +- `required` - property `missingProperty` (required property that is missing). +- `propertyNames` - property `propertyName` (an invalid property name). +- `patternRequired` (in ajv-keywords) - property `missingPattern` (required pattern that did not match any property). +- `type` - property `type` (required type(s), a string, can be a comma-separated list) +- `uniqueItems` - properties `i` and `j` (indices of duplicate items). +- `const` - property `allowedValue` pointing to the value (the schema of the keyword). +- `enum` - property `allowedValues` pointing to the array of values (the schema of the keyword). +- `$ref` - property `ref` with the referenced schema URI. +- `oneOf` - property `passingSchemas` (array of indices of passing schemas, null if no schema passes). +- custom keywords (in case keyword definition doesn't create errors) - property `keyword` (the keyword name). + + +## Plugins + +Ajv can be extended with plugins that add custom keywords, formats or functions to process generated code. When such plugin is published as npm package it is recommended that it follows these conventions: + +- it exports a function +- this function accepts ajv instance as the first parameter and returns the same instance to allow chaining +- this function can accept an optional configuration as the second parameter + +If you have published a useful plugin please submit a PR to add it to the next section. + + +## Related packages + +- [ajv-async](https://github.com/epoberezkin/ajv-async) - plugin to configure async validation mode +- [ajv-bsontype](https://github.com/BoLaMN/ajv-bsontype) - plugin to validate mongodb's bsonType formats +- [ajv-cli](https://github.com/jessedc/ajv-cli) - command line interface +- [ajv-errors](https://github.com/epoberezkin/ajv-errors) - plugin for custom error messages +- [ajv-i18n](https://github.com/epoberezkin/ajv-i18n) - internationalised error messages +- [ajv-istanbul](https://github.com/epoberezkin/ajv-istanbul) - plugin to instrument generated validation code to measure test coverage of your schemas +- [ajv-keywords](https://github.com/epoberezkin/ajv-keywords) - plugin with custom validation keywords (select, typeof, etc.) +- [ajv-merge-patch](https://github.com/epoberezkin/ajv-merge-patch) - plugin with keywords $merge and $patch +- [ajv-pack](https://github.com/epoberezkin/ajv-pack) - produces a compact module exporting validation functions + + +## Some packages using Ajv + +- [webpack](https://github.com/webpack/webpack) - a module bundler. Its main purpose is to bundle JavaScript files for usage in a browser +- [jsonscript-js](https://github.com/JSONScript/jsonscript-js) - the interpreter for [JSONScript](http://www.jsonscript.org) - scripted processing of existing endpoints and services +- [osprey-method-handler](https://github.com/mulesoft-labs/osprey-method-handler) - Express middleware for validating requests and responses based on a RAML method object, used in [osprey](https://github.com/mulesoft/osprey) - validating API proxy generated from a RAML definition +- [har-validator](https://github.com/ahmadnassri/har-validator) - HTTP Archive (HAR) validator +- [jsoneditor](https://github.com/josdejong/jsoneditor) - a web-based tool to view, edit, format, and validate JSON http://jsoneditoronline.org +- [JSON Schema Lint](https://github.com/nickcmaynard/jsonschemalint) - a web tool to validate JSON/YAML document against a single JSON Schema http://jsonschemalint.com +- [objection](https://github.com/vincit/objection.js) - SQL-friendly ORM for Node.js +- [table](https://github.com/gajus/table) - formats data into a string table +- [ripple-lib](https://github.com/ripple/ripple-lib) - a JavaScript API for interacting with [Ripple](https://ripple.com) in Node.js and the browser +- [restbase](https://github.com/wikimedia/restbase) - distributed storage with REST API & dispatcher for backend services built to provide a low-latency & high-throughput API for Wikipedia / Wikimedia content +- [hippie-swagger](https://github.com/CacheControl/hippie-swagger) - [Hippie](https://github.com/vesln/hippie) wrapper that provides end to end API testing with swagger validation +- [react-form-controlled](https://github.com/seeden/react-form-controlled) - React controlled form components with validation +- [rabbitmq-schema](https://github.com/tjmehta/rabbitmq-schema) - a schema definition module for RabbitMQ graphs and messages +- [@query/schema](https://www.npmjs.com/package/@query/schema) - stream filtering with a URI-safe query syntax parsing to JSON Schema +- [chai-ajv-json-schema](https://github.com/peon374/chai-ajv-json-schema) - chai plugin to us JSON Schema with expect in mocha tests +- [grunt-jsonschema-ajv](https://github.com/SignpostMarv/grunt-jsonschema-ajv) - Grunt plugin for validating files against JSON Schema +- [extract-text-webpack-plugin](https://github.com/webpack-contrib/extract-text-webpack-plugin) - extract text from bundle into a file +- [electron-builder](https://github.com/electron-userland/electron-builder) - a solution to package and build a ready for distribution Electron app +- [addons-linter](https://github.com/mozilla/addons-linter) - Mozilla Add-ons Linter +- [gh-pages-generator](https://github.com/epoberezkin/gh-pages-generator) - multi-page site generator converting markdown files to GitHub pages +- [ESLint](https://github.com/eslint/eslint) - the pluggable linting utility for JavaScript and JSX + + +## Tests + +``` +npm install +git submodule update --init +npm test +``` + +## Contributing + +All validation functions are generated using doT templates in [dot](https://github.com/epoberezkin/ajv/tree/master/lib/dot) folder. Templates are precompiled so doT is not a run-time dependency. + +`npm run build` - compiles templates to [dotjs](https://github.com/epoberezkin/ajv/tree/master/lib/dotjs) folder. + +`npm run watch` - automatically compiles templates when files in dot folder change + +Please see [Contributing guidelines](https://github.com/epoberezkin/ajv/blob/master/CONTRIBUTING.md) + + +## Changes history + +See https://github.com/epoberezkin/ajv/releases + +__Please note__: [Changes in version 6.0.0](https://github.com/epoberezkin/ajv/releases/tag/v6.0.0). + +[Version 5.0.0](https://github.com/epoberezkin/ajv/releases/tag/5.0.0). + +[Version 4.0.0](https://github.com/epoberezkin/ajv/releases/tag/4.0.0). + +[Version 3.0.0](https://github.com/epoberezkin/ajv/releases/tag/3.0.0). + +[Version 2.0.0](https://github.com/epoberezkin/ajv/releases/tag/2.0.0). + + +## Open-source software support + +Ajv is a part of [Tidelift subscription](https://tidelift.com/subscription/pkg/npm-ajv?utm_source=npm-ajv&utm_medium=referral&utm_campaign=readme) - it provides a centralised support to open-source software users, in addition to the support provided by software maintainers. + + +## License + +[MIT](https://github.com/epoberezkin/ajv/blob/master/LICENSE) diff --git a/user/themes/goku/node_modules/ajv/dist/ajv.bundle.js b/user/themes/goku/node_modules/ajv/dist/ajv.bundle.js new file mode 100644 index 00000000..a6afe993 --- /dev/null +++ b/user/themes/goku/node_modules/ajv/dist/ajv.bundle.js @@ -0,0 +1,7172 @@ +(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.Ajv = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i%\\^`{|}]|%[0-9a-f]{2})|\{[+#./;?&=,!@|]?(?:[a-z0-9_]|%[0-9a-f]{2})+(?::[1-9][0-9]{0,3}|\*)?(?:,(?:[a-z0-9_]|%[0-9a-f]{2})+(?::[1-9][0-9]{0,3}|\*)?)*\})*$/i; +// For the source: https://gist.github.com/dperini/729294 +// For test cases: https://mathiasbynens.be/demo/url-regex +// @todo Delete current URL in favour of the commented out URL rule when this issue is fixed https://github.com/eslint/eslint/issues/7983. +// var URL = /^(?:(?:https?|ftp):\/\/)(?:\S+(?::\S*)?@)?(?:(?!10(?:\.\d{1,3}){3})(?!127(?:\.\d{1,3}){3})(?!169\.254(?:\.\d{1,3}){2})(?!192\.168(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u{00a1}-\u{ffff}0-9]+-?)*[a-z\u{00a1}-\u{ffff}0-9]+)(?:\.(?:[a-z\u{00a1}-\u{ffff}0-9]+-?)*[a-z\u{00a1}-\u{ffff}0-9]+)*(?:\.(?:[a-z\u{00a1}-\u{ffff}]{2,})))(?::\d{2,5})?(?:\/[^\s]*)?$/iu; +var URL = /^(?:(?:http[s\u017F]?|ftp):\/\/)(?:(?:[\0-\x08\x0E-\x1F!-\x9F\xA1-\u167F\u1681-\u1FFF\u200B-\u2027\u202A-\u202E\u2030-\u205E\u2060-\u2FFF\u3001-\uD7FF\uE000-\uFEFE\uFF00-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])+(?::(?:[\0-\x08\x0E-\x1F!-\x9F\xA1-\u167F\u1681-\u1FFF\u200B-\u2027\u202A-\u202E\u2030-\u205E\u2060-\u2FFF\u3001-\uD7FF\uE000-\uFEFE\uFF00-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])*)?@)?(?:(?!10(?:\.[0-9]{1,3}){3})(?!127(?:\.[0-9]{1,3}){3})(?!169\.254(?:\.[0-9]{1,3}){2})(?!192\.168(?:\.[0-9]{1,3}){2})(?!172\.(?:1[6-9]|2[0-9]|3[01])(?:\.[0-9]{1,3}){2})(?:[1-9][0-9]?|1[0-9][0-9]|2[01][0-9]|22[0-3])(?:\.(?:1?[0-9]{1,2}|2[0-4][0-9]|25[0-5])){2}(?:\.(?:[1-9][0-9]?|1[0-9][0-9]|2[0-4][0-9]|25[0-4]))|(?:(?:(?:[0-9KSa-z\xA1-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])+-?)*(?:[0-9KSa-z\xA1-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])+)(?:\.(?:(?:[0-9KSa-z\xA1-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])+-?)*(?:[0-9KSa-z\xA1-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])+)*(?:\.(?:(?:[KSa-z\xA1-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]){2,})))(?::[0-9]{2,5})?(?:\/(?:[\0-\x08\x0E-\x1F!-\x9F\xA1-\u167F\u1681-\u1FFF\u200B-\u2027\u202A-\u202E\u2030-\u205E\u2060-\u2FFF\u3001-\uD7FF\uE000-\uFEFE\uFF00-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])*)?$/i; +var UUID = /^(?:urn:uuid:)?[0-9a-f]{8}-(?:[0-9a-f]{4}-){3}[0-9a-f]{12}$/i; +var JSON_POINTER = /^(?:\/(?:[^~/]|~0|~1)*)*$/; +var JSON_POINTER_URI_FRAGMENT = /^#(?:\/(?:[a-z0-9_\-.!$&'()*+,;:=@]|%[0-9a-f]{2}|~0|~1)*)*$/i; +var RELATIVE_JSON_POINTER = /^(?:0|[1-9][0-9]*)(?:#|(?:\/(?:[^~/]|~0|~1)*)*)$/; + + +module.exports = formats; + +function formats(mode) { + mode = mode == 'full' ? 'full' : 'fast'; + return util.copy(formats[mode]); +} + + +formats.fast = { + // date: http://tools.ietf.org/html/rfc3339#section-5.6 + date: /^\d\d\d\d-[0-1]\d-[0-3]\d$/, + // date-time: http://tools.ietf.org/html/rfc3339#section-5.6 + time: /^(?:[0-2]\d:[0-5]\d:[0-5]\d|23:59:60)(?:\.\d+)?(?:z|[+-]\d\d:\d\d)?$/i, + 'date-time': /^\d\d\d\d-[0-1]\d-[0-3]\d[t\s](?:[0-2]\d:[0-5]\d:[0-5]\d|23:59:60)(?:\.\d+)?(?:z|[+-]\d\d:\d\d)$/i, + // uri: https://github.com/mafintosh/is-my-json-valid/blob/master/formats.js + uri: /^(?:[a-z][a-z0-9+-.]*:)(?:\/?\/)?[^\s]*$/i, + 'uri-reference': /^(?:(?:[a-z][a-z0-9+-.]*:)?\/?\/)?(?:[^\\\s#][^\s#]*)?(?:#[^\\\s]*)?$/i, + 'uri-template': URITEMPLATE, + url: URL, + // email (sources from jsen validator): + // http://stackoverflow.com/questions/201323/using-a-regular-expression-to-validate-an-email-address#answer-8829363 + // http://www.w3.org/TR/html5/forms.html#valid-e-mail-address (search for 'willful violation') + email: /^[a-z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)*$/i, + hostname: HOSTNAME, + // optimized https://www.safaribooksonline.com/library/view/regular-expressions-cookbook/9780596802837/ch07s16.html + ipv4: /^(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)$/, + // optimized http://stackoverflow.com/questions/53497/regular-expression-that-matches-valid-ipv6-addresses + ipv6: /^\s*(?:(?:(?:[0-9a-f]{1,4}:){7}(?:[0-9a-f]{1,4}|:))|(?:(?:[0-9a-f]{1,4}:){6}(?::[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(?:(?:[0-9a-f]{1,4}:){5}(?:(?:(?::[0-9a-f]{1,4}){1,2})|:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(?:(?:[0-9a-f]{1,4}:){4}(?:(?:(?::[0-9a-f]{1,4}){1,3})|(?:(?::[0-9a-f]{1,4})?:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[0-9a-f]{1,4}:){3}(?:(?:(?::[0-9a-f]{1,4}){1,4})|(?:(?::[0-9a-f]{1,4}){0,2}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[0-9a-f]{1,4}:){2}(?:(?:(?::[0-9a-f]{1,4}){1,5})|(?:(?::[0-9a-f]{1,4}){0,3}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[0-9a-f]{1,4}:){1}(?:(?:(?::[0-9a-f]{1,4}){1,6})|(?:(?::[0-9a-f]{1,4}){0,4}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?::(?:(?:(?::[0-9a-f]{1,4}){1,7})|(?:(?::[0-9a-f]{1,4}){0,5}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(?:%.+)?\s*$/i, + regex: regex, + // uuid: http://tools.ietf.org/html/rfc4122 + uuid: UUID, + // JSON-pointer: https://tools.ietf.org/html/rfc6901 + // uri fragment: https://tools.ietf.org/html/rfc3986#appendix-A + 'json-pointer': JSON_POINTER, + 'json-pointer-uri-fragment': JSON_POINTER_URI_FRAGMENT, + // relative JSON-pointer: http://tools.ietf.org/html/draft-luff-relative-json-pointer-00 + 'relative-json-pointer': RELATIVE_JSON_POINTER +}; + + +formats.full = { + date: date, + time: time, + 'date-time': date_time, + uri: uri, + 'uri-reference': URIREF, + 'uri-template': URITEMPLATE, + url: URL, + email: /^[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/i, + hostname: hostname, + ipv4: /^(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)$/, + ipv6: /^\s*(?:(?:(?:[0-9a-f]{1,4}:){7}(?:[0-9a-f]{1,4}|:))|(?:(?:[0-9a-f]{1,4}:){6}(?::[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(?:(?:[0-9a-f]{1,4}:){5}(?:(?:(?::[0-9a-f]{1,4}){1,2})|:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(?:(?:[0-9a-f]{1,4}:){4}(?:(?:(?::[0-9a-f]{1,4}){1,3})|(?:(?::[0-9a-f]{1,4})?:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[0-9a-f]{1,4}:){3}(?:(?:(?::[0-9a-f]{1,4}){1,4})|(?:(?::[0-9a-f]{1,4}){0,2}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[0-9a-f]{1,4}:){2}(?:(?:(?::[0-9a-f]{1,4}){1,5})|(?:(?::[0-9a-f]{1,4}){0,3}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[0-9a-f]{1,4}:){1}(?:(?:(?::[0-9a-f]{1,4}){1,6})|(?:(?::[0-9a-f]{1,4}){0,4}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?::(?:(?:(?::[0-9a-f]{1,4}){1,7})|(?:(?::[0-9a-f]{1,4}){0,5}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(?:%.+)?\s*$/i, + regex: regex, + uuid: UUID, + 'json-pointer': JSON_POINTER, + 'json-pointer-uri-fragment': JSON_POINTER_URI_FRAGMENT, + 'relative-json-pointer': RELATIVE_JSON_POINTER +}; + + +function isLeapYear(year) { + // https://tools.ietf.org/html/rfc3339#appendix-C + return year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0); +} + + +function date(str) { + // full-date from http://tools.ietf.org/html/rfc3339#section-5.6 + var matches = str.match(DATE); + if (!matches) return false; + + var year = +matches[1]; + var month = +matches[2]; + var day = +matches[3]; + + return month >= 1 && month <= 12 && day >= 1 && + day <= (month == 2 && isLeapYear(year) ? 29 : DAYS[month]); +} + + +function time(str, full) { + var matches = str.match(TIME); + if (!matches) return false; + + var hour = matches[1]; + var minute = matches[2]; + var second = matches[3]; + var timeZone = matches[5]; + return ((hour <= 23 && minute <= 59 && second <= 59) || + (hour == 23 && minute == 59 && second == 60)) && + (!full || timeZone); +} + + +var DATE_TIME_SEPARATOR = /t|\s/i; +function date_time(str) { + // http://tools.ietf.org/html/rfc3339#section-5.6 + var dateTime = str.split(DATE_TIME_SEPARATOR); + return dateTime.length == 2 && date(dateTime[0]) && time(dateTime[1], true); +} + + +function hostname(str) { + // https://tools.ietf.org/html/rfc1034#section-3.5 + // https://tools.ietf.org/html/rfc1123#section-2 + return str.length <= 255 && HOSTNAME.test(str); +} + + +var NOT_URI_FRAGMENT = /\/|:/; +function uri(str) { + // http://jmrware.com/articles/2009/uri_regexp/URI_regex.html + optional protocol + required "." + return NOT_URI_FRAGMENT.test(str) && URI.test(str); +} + + +var Z_ANCHOR = /[^\\]\\Z/; +function regex(str) { + if (Z_ANCHOR.test(str)) return false; + try { + new RegExp(str); + return true; + } catch(e) { + return false; + } +} + +},{"./util":10}],5:[function(require,module,exports){ +'use strict'; + +var resolve = require('./resolve') + , util = require('./util') + , errorClasses = require('./error_classes') + , stableStringify = require('fast-json-stable-stringify'); + +var validateGenerator = require('../dotjs/validate'); + +/** + * Functions below are used inside compiled validations function + */ + +var ucs2length = util.ucs2length; +var equal = require('fast-deep-equal'); + +// this error is thrown by async schemas to return validation errors via exception +var ValidationError = errorClasses.Validation; + +module.exports = compile; + + +/** + * Compiles schema to validation function + * @this Ajv + * @param {Object} schema schema object + * @param {Object} root object with information about the root schema for this schema + * @param {Object} localRefs the hash of local references inside the schema (created by resolve.id), used for inline resolution + * @param {String} baseId base ID for IDs in the schema + * @return {Function} validation function + */ +function compile(schema, root, localRefs, baseId) { + /* jshint validthis: true, evil: true */ + /* eslint no-shadow: 0 */ + var self = this + , opts = this._opts + , refVal = [ undefined ] + , refs = {} + , patterns = [] + , patternsHash = {} + , defaults = [] + , defaultsHash = {} + , customRules = []; + + root = root || { schema: schema, refVal: refVal, refs: refs }; + + var c = checkCompiling.call(this, schema, root, baseId); + var compilation = this._compilations[c.index]; + if (c.compiling) return (compilation.callValidate = callValidate); + + var formats = this._formats; + var RULES = this.RULES; + + try { + var v = localCompile(schema, root, localRefs, baseId); + compilation.validate = v; + var cv = compilation.callValidate; + if (cv) { + cv.schema = v.schema; + cv.errors = null; + cv.refs = v.refs; + cv.refVal = v.refVal; + cv.root = v.root; + cv.$async = v.$async; + if (opts.sourceCode) cv.source = v.source; + } + return v; + } finally { + endCompiling.call(this, schema, root, baseId); + } + + /* @this {*} - custom context, see passContext option */ + function callValidate() { + /* jshint validthis: true */ + var validate = compilation.validate; + var result = validate.apply(this, arguments); + callValidate.errors = validate.errors; + return result; + } + + function localCompile(_schema, _root, localRefs, baseId) { + var isRoot = !_root || (_root && _root.schema == _schema); + if (_root.schema != root.schema) + return compile.call(self, _schema, _root, localRefs, baseId); + + var $async = _schema.$async === true; + + var sourceCode = validateGenerator({ + isTop: true, + schema: _schema, + isRoot: isRoot, + baseId: baseId, + root: _root, + schemaPath: '', + errSchemaPath: '#', + errorPath: '""', + MissingRefError: errorClasses.MissingRef, + RULES: RULES, + validate: validateGenerator, + util: util, + resolve: resolve, + resolveRef: resolveRef, + usePattern: usePattern, + useDefault: useDefault, + useCustomRule: useCustomRule, + opts: opts, + formats: formats, + logger: self.logger, + self: self + }); + + sourceCode = vars(refVal, refValCode) + vars(patterns, patternCode) + + vars(defaults, defaultCode) + vars(customRules, customRuleCode) + + sourceCode; + + if (opts.processCode) sourceCode = opts.processCode(sourceCode); + // console.log('\n\n\n *** \n', JSON.stringify(sourceCode)); + var validate; + try { + var makeValidate = new Function( + 'self', + 'RULES', + 'formats', + 'root', + 'refVal', + 'defaults', + 'customRules', + 'equal', + 'ucs2length', + 'ValidationError', + sourceCode + ); + + validate = makeValidate( + self, + RULES, + formats, + root, + refVal, + defaults, + customRules, + equal, + ucs2length, + ValidationError + ); + + refVal[0] = validate; + } catch(e) { + self.logger.error('Error compiling schema, function code:', sourceCode); + throw e; + } + + validate.schema = _schema; + validate.errors = null; + validate.refs = refs; + validate.refVal = refVal; + validate.root = isRoot ? validate : _root; + if ($async) validate.$async = true; + if (opts.sourceCode === true) { + validate.source = { + code: sourceCode, + patterns: patterns, + defaults: defaults + }; + } + + return validate; + } + + function resolveRef(baseId, ref, isRoot) { + ref = resolve.url(baseId, ref); + var refIndex = refs[ref]; + var _refVal, refCode; + if (refIndex !== undefined) { + _refVal = refVal[refIndex]; + refCode = 'refVal[' + refIndex + ']'; + return resolvedRef(_refVal, refCode); + } + if (!isRoot && root.refs) { + var rootRefId = root.refs[ref]; + if (rootRefId !== undefined) { + _refVal = root.refVal[rootRefId]; + refCode = addLocalRef(ref, _refVal); + return resolvedRef(_refVal, refCode); + } + } + + refCode = addLocalRef(ref); + var v = resolve.call(self, localCompile, root, ref); + if (v === undefined) { + var localSchema = localRefs && localRefs[ref]; + if (localSchema) { + v = resolve.inlineRef(localSchema, opts.inlineRefs) + ? localSchema + : compile.call(self, localSchema, root, localRefs, baseId); + } + } + + if (v === undefined) { + removeLocalRef(ref); + } else { + replaceLocalRef(ref, v); + return resolvedRef(v, refCode); + } + } + + function addLocalRef(ref, v) { + var refId = refVal.length; + refVal[refId] = v; + refs[ref] = refId; + return 'refVal' + refId; + } + + function removeLocalRef(ref) { + delete refs[ref]; + } + + function replaceLocalRef(ref, v) { + var refId = refs[ref]; + refVal[refId] = v; + } + + function resolvedRef(refVal, code) { + return typeof refVal == 'object' || typeof refVal == 'boolean' + ? { code: code, schema: refVal, inline: true } + : { code: code, $async: refVal && !!refVal.$async }; + } + + function usePattern(regexStr) { + var index = patternsHash[regexStr]; + if (index === undefined) { + index = patternsHash[regexStr] = patterns.length; + patterns[index] = regexStr; + } + return 'pattern' + index; + } + + function useDefault(value) { + switch (typeof value) { + case 'boolean': + case 'number': + return '' + value; + case 'string': + return util.toQuotedString(value); + case 'object': + if (value === null) return 'null'; + var valueStr = stableStringify(value); + var index = defaultsHash[valueStr]; + if (index === undefined) { + index = defaultsHash[valueStr] = defaults.length; + defaults[index] = value; + } + return 'default' + index; + } + } + + function useCustomRule(rule, schema, parentSchema, it) { + if (self._opts.validateSchema !== false) { + var deps = rule.definition.dependencies; + if (deps && !deps.every(function(keyword) { + return Object.prototype.hasOwnProperty.call(parentSchema, keyword); + })) + throw new Error('parent schema must have all required keywords: ' + deps.join(',')); + + var validateSchema = rule.definition.validateSchema; + if (validateSchema) { + var valid = validateSchema(schema); + if (!valid) { + var message = 'keyword schema is invalid: ' + self.errorsText(validateSchema.errors); + if (self._opts.validateSchema == 'log') self.logger.error(message); + else throw new Error(message); + } + } + } + + var compile = rule.definition.compile + , inline = rule.definition.inline + , macro = rule.definition.macro; + + var validate; + if (compile) { + validate = compile.call(self, schema, parentSchema, it); + } else if (macro) { + validate = macro.call(self, schema, parentSchema, it); + if (opts.validateSchema !== false) self.validateSchema(validate, true); + } else if (inline) { + validate = inline.call(self, it, rule.keyword, schema, parentSchema); + } else { + validate = rule.definition.validate; + if (!validate) return; + } + + if (validate === undefined) + throw new Error('custom keyword "' + rule.keyword + '"failed to compile'); + + var index = customRules.length; + customRules[index] = validate; + + return { + code: 'customRule' + index, + validate: validate + }; + } +} + + +/** + * Checks if the schema is currently compiled + * @this Ajv + * @param {Object} schema schema to compile + * @param {Object} root root object + * @param {String} baseId base schema ID + * @return {Object} object with properties "index" (compilation index) and "compiling" (boolean) + */ +function checkCompiling(schema, root, baseId) { + /* jshint validthis: true */ + var index = compIndex.call(this, schema, root, baseId); + if (index >= 0) return { index: index, compiling: true }; + index = this._compilations.length; + this._compilations[index] = { + schema: schema, + root: root, + baseId: baseId + }; + return { index: index, compiling: false }; +} + + +/** + * Removes the schema from the currently compiled list + * @this Ajv + * @param {Object} schema schema to compile + * @param {Object} root root object + * @param {String} baseId base schema ID + */ +function endCompiling(schema, root, baseId) { + /* jshint validthis: true */ + var i = compIndex.call(this, schema, root, baseId); + if (i >= 0) this._compilations.splice(i, 1); +} + + +/** + * Index of schema compilation in the currently compiled list + * @this Ajv + * @param {Object} schema schema to compile + * @param {Object} root root object + * @param {String} baseId base schema ID + * @return {Integer} compilation index + */ +function compIndex(schema, root, baseId) { + /* jshint validthis: true */ + for (var i=0; i= 0xD800 && value <= 0xDBFF && pos < len) { + // high surrogate, and there is a next character + value = str.charCodeAt(pos); + if ((value & 0xFC00) == 0xDC00) pos++; // low surrogate + } + } + return length; +}; + +},{}],10:[function(require,module,exports){ +'use strict'; + + +module.exports = { + copy: copy, + checkDataType: checkDataType, + checkDataTypes: checkDataTypes, + coerceToTypes: coerceToTypes, + toHash: toHash, + getProperty: getProperty, + escapeQuotes: escapeQuotes, + equal: require('fast-deep-equal'), + ucs2length: require('./ucs2length'), + varOccurences: varOccurences, + varReplace: varReplace, + cleanUpCode: cleanUpCode, + finalCleanUpCode: finalCleanUpCode, + schemaHasRules: schemaHasRules, + schemaHasRulesExcept: schemaHasRulesExcept, + schemaUnknownRules: schemaUnknownRules, + toQuotedString: toQuotedString, + getPathExpr: getPathExpr, + getPath: getPath, + getData: getData, + unescapeFragment: unescapeFragment, + unescapeJsonPointer: unescapeJsonPointer, + escapeFragment: escapeFragment, + escapeJsonPointer: escapeJsonPointer +}; + + +function copy(o, to) { + to = to || {}; + for (var key in o) to[key] = o[key]; + return to; +} + + +function checkDataType(dataType, data, negate) { + var EQUAL = negate ? ' !== ' : ' === ' + , AND = negate ? ' || ' : ' && ' + , OK = negate ? '!' : '' + , NOT = negate ? '' : '!'; + switch (dataType) { + case 'null': return data + EQUAL + 'null'; + case 'array': return OK + 'Array.isArray(' + data + ')'; + case 'object': return '(' + OK + data + AND + + 'typeof ' + data + EQUAL + '"object"' + AND + + NOT + 'Array.isArray(' + data + '))'; + case 'integer': return '(typeof ' + data + EQUAL + '"number"' + AND + + NOT + '(' + data + ' % 1)' + + AND + data + EQUAL + data + ')'; + default: return 'typeof ' + data + EQUAL + '"' + dataType + '"'; + } +} + + +function checkDataTypes(dataTypes, data) { + switch (dataTypes.length) { + case 1: return checkDataType(dataTypes[0], data, true); + default: + var code = ''; + var types = toHash(dataTypes); + if (types.array && types.object) { + code = types.null ? '(': '(!' + data + ' || '; + code += 'typeof ' + data + ' !== "object")'; + delete types.null; + delete types.array; + delete types.object; + } + if (types.number) delete types.integer; + for (var t in types) + code += (code ? ' && ' : '' ) + checkDataType(t, data, true); + + return code; + } +} + + +var COERCE_TO_TYPES = toHash([ 'string', 'number', 'integer', 'boolean', 'null' ]); +function coerceToTypes(optionCoerceTypes, dataTypes) { + if (Array.isArray(dataTypes)) { + var types = []; + for (var i=0; i= lvl) throw new Error('Cannot access property/index ' + up + ' levels up, current level is ' + lvl); + return paths[lvl - up]; + } + + if (up > lvl) throw new Error('Cannot access data ' + up + ' levels up, current level is ' + lvl); + data = 'data' + ((lvl - up) || ''); + if (!jsonPointer) return data; + } + + var expr = data; + var segments = jsonPointer.split('/'); + for (var i=0; i', + $notOp = $isMax ? '>' : '<', + $errorKeyword = undefined; + if ($isDataExcl) { + var $schemaValueExcl = it.util.getData($schemaExcl.$data, $dataLvl, it.dataPathArr), + $exclusive = 'exclusive' + $lvl, + $exclType = 'exclType' + $lvl, + $exclIsNumber = 'exclIsNumber' + $lvl, + $opExpr = 'op' + $lvl, + $opStr = '\' + ' + $opExpr + ' + \''; + out += ' var schemaExcl' + ($lvl) + ' = ' + ($schemaValueExcl) + '; '; + $schemaValueExcl = 'schemaExcl' + $lvl; + out += ' var ' + ($exclusive) + '; var ' + ($exclType) + ' = typeof ' + ($schemaValueExcl) + '; if (' + ($exclType) + ' != \'boolean\' && ' + ($exclType) + ' != \'undefined\' && ' + ($exclType) + ' != \'number\') { '; + var $errorKeyword = $exclusiveKeyword; + var $$outStack = $$outStack || []; + $$outStack.push(out); + out = ''; /* istanbul ignore else */ + if (it.createErrors !== false) { + out += ' { keyword: \'' + ($errorKeyword || '_exclusiveLimit') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: {} '; + if (it.opts.messages !== false) { + out += ' , message: \'' + ($exclusiveKeyword) + ' should be boolean\' '; + } + if (it.opts.verbose) { + out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; + } + out += ' } '; + } else { + out += ' {} '; + } + var __err = out; + out = $$outStack.pop(); + if (!it.compositeRule && $breakOnError) { + /* istanbul ignore if */ + if (it.async) { + out += ' throw new ValidationError([' + (__err) + ']); '; + } else { + out += ' validate.errors = [' + (__err) + ']; return false; '; + } + } else { + out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; + } + out += ' } else if ( '; + if ($isData) { + out += ' (' + ($schemaValue) + ' !== undefined && typeof ' + ($schemaValue) + ' != \'number\') || '; + } + out += ' ' + ($exclType) + ' == \'number\' ? ( (' + ($exclusive) + ' = ' + ($schemaValue) + ' === undefined || ' + ($schemaValueExcl) + ' ' + ($op) + '= ' + ($schemaValue) + ') ? ' + ($data) + ' ' + ($notOp) + '= ' + ($schemaValueExcl) + ' : ' + ($data) + ' ' + ($notOp) + ' ' + ($schemaValue) + ' ) : ( (' + ($exclusive) + ' = ' + ($schemaValueExcl) + ' === true) ? ' + ($data) + ' ' + ($notOp) + '= ' + ($schemaValue) + ' : ' + ($data) + ' ' + ($notOp) + ' ' + ($schemaValue) + ' ) || ' + ($data) + ' !== ' + ($data) + ') { var op' + ($lvl) + ' = ' + ($exclusive) + ' ? \'' + ($op) + '\' : \'' + ($op) + '=\'; '; + if ($schema === undefined) { + $errorKeyword = $exclusiveKeyword; + $errSchemaPath = it.errSchemaPath + '/' + $exclusiveKeyword; + $schemaValue = $schemaValueExcl; + $isData = $isDataExcl; + } + } else { + var $exclIsNumber = typeof $schemaExcl == 'number', + $opStr = $op; + if ($exclIsNumber && $isData) { + var $opExpr = '\'' + $opStr + '\''; + out += ' if ( '; + if ($isData) { + out += ' (' + ($schemaValue) + ' !== undefined && typeof ' + ($schemaValue) + ' != \'number\') || '; + } + out += ' ( ' + ($schemaValue) + ' === undefined || ' + ($schemaExcl) + ' ' + ($op) + '= ' + ($schemaValue) + ' ? ' + ($data) + ' ' + ($notOp) + '= ' + ($schemaExcl) + ' : ' + ($data) + ' ' + ($notOp) + ' ' + ($schemaValue) + ' ) || ' + ($data) + ' !== ' + ($data) + ') { '; + } else { + if ($exclIsNumber && $schema === undefined) { + $exclusive = true; + $errorKeyword = $exclusiveKeyword; + $errSchemaPath = it.errSchemaPath + '/' + $exclusiveKeyword; + $schemaValue = $schemaExcl; + $notOp += '='; + } else { + if ($exclIsNumber) $schemaValue = Math[$isMax ? 'min' : 'max']($schemaExcl, $schema); + if ($schemaExcl === ($exclIsNumber ? $schemaValue : true)) { + $exclusive = true; + $errorKeyword = $exclusiveKeyword; + $errSchemaPath = it.errSchemaPath + '/' + $exclusiveKeyword; + $notOp += '='; + } else { + $exclusive = false; + $opStr += '='; + } + } + var $opExpr = '\'' + $opStr + '\''; + out += ' if ( '; + if ($isData) { + out += ' (' + ($schemaValue) + ' !== undefined && typeof ' + ($schemaValue) + ' != \'number\') || '; + } + out += ' ' + ($data) + ' ' + ($notOp) + ' ' + ($schemaValue) + ' || ' + ($data) + ' !== ' + ($data) + ') { '; + } + } + $errorKeyword = $errorKeyword || $keyword; + var $$outStack = $$outStack || []; + $$outStack.push(out); + out = ''; /* istanbul ignore else */ + if (it.createErrors !== false) { + out += ' { keyword: \'' + ($errorKeyword || '_limit') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { comparison: ' + ($opExpr) + ', limit: ' + ($schemaValue) + ', exclusive: ' + ($exclusive) + ' } '; + if (it.opts.messages !== false) { + out += ' , message: \'should be ' + ($opStr) + ' '; + if ($isData) { + out += '\' + ' + ($schemaValue); + } else { + out += '' + ($schemaValue) + '\''; + } + } + if (it.opts.verbose) { + out += ' , schema: '; + if ($isData) { + out += 'validate.schema' + ($schemaPath); + } else { + out += '' + ($schema); + } + out += ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; + } + out += ' } '; + } else { + out += ' {} '; + } + var __err = out; + out = $$outStack.pop(); + if (!it.compositeRule && $breakOnError) { + /* istanbul ignore if */ + if (it.async) { + out += ' throw new ValidationError([' + (__err) + ']); '; + } else { + out += ' validate.errors = [' + (__err) + ']; return false; '; + } + } else { + out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; + } + out += ' } '; + if ($breakOnError) { + out += ' else { '; + } + return out; +} + +},{}],14:[function(require,module,exports){ +'use strict'; +module.exports = function generate__limitItems(it, $keyword, $ruleType) { + var out = ' '; + var $lvl = it.level; + var $dataLvl = it.dataLevel; + var $schema = it.schema[$keyword]; + var $schemaPath = it.schemaPath + it.util.getProperty($keyword); + var $errSchemaPath = it.errSchemaPath + '/' + $keyword; + var $breakOnError = !it.opts.allErrors; + var $errorKeyword; + var $data = 'data' + ($dataLvl || ''); + var $isData = it.opts.$data && $schema && $schema.$data, + $schemaValue; + if ($isData) { + out += ' var schema' + ($lvl) + ' = ' + (it.util.getData($schema.$data, $dataLvl, it.dataPathArr)) + '; '; + $schemaValue = 'schema' + $lvl; + } else { + $schemaValue = $schema; + } + var $op = $keyword == 'maxItems' ? '>' : '<'; + out += 'if ( '; + if ($isData) { + out += ' (' + ($schemaValue) + ' !== undefined && typeof ' + ($schemaValue) + ' != \'number\') || '; + } + out += ' ' + ($data) + '.length ' + ($op) + ' ' + ($schemaValue) + ') { '; + var $errorKeyword = $keyword; + var $$outStack = $$outStack || []; + $$outStack.push(out); + out = ''; /* istanbul ignore else */ + if (it.createErrors !== false) { + out += ' { keyword: \'' + ($errorKeyword || '_limitItems') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { limit: ' + ($schemaValue) + ' } '; + if (it.opts.messages !== false) { + out += ' , message: \'should NOT have '; + if ($keyword == 'maxItems') { + out += 'more'; + } else { + out += 'fewer'; + } + out += ' than '; + if ($isData) { + out += '\' + ' + ($schemaValue) + ' + \''; + } else { + out += '' + ($schema); + } + out += ' items\' '; + } + if (it.opts.verbose) { + out += ' , schema: '; + if ($isData) { + out += 'validate.schema' + ($schemaPath); + } else { + out += '' + ($schema); + } + out += ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; + } + out += ' } '; + } else { + out += ' {} '; + } + var __err = out; + out = $$outStack.pop(); + if (!it.compositeRule && $breakOnError) { + /* istanbul ignore if */ + if (it.async) { + out += ' throw new ValidationError([' + (__err) + ']); '; + } else { + out += ' validate.errors = [' + (__err) + ']; return false; '; + } + } else { + out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; + } + out += '} '; + if ($breakOnError) { + out += ' else { '; + } + return out; +} + +},{}],15:[function(require,module,exports){ +'use strict'; +module.exports = function generate__limitLength(it, $keyword, $ruleType) { + var out = ' '; + var $lvl = it.level; + var $dataLvl = it.dataLevel; + var $schema = it.schema[$keyword]; + var $schemaPath = it.schemaPath + it.util.getProperty($keyword); + var $errSchemaPath = it.errSchemaPath + '/' + $keyword; + var $breakOnError = !it.opts.allErrors; + var $errorKeyword; + var $data = 'data' + ($dataLvl || ''); + var $isData = it.opts.$data && $schema && $schema.$data, + $schemaValue; + if ($isData) { + out += ' var schema' + ($lvl) + ' = ' + (it.util.getData($schema.$data, $dataLvl, it.dataPathArr)) + '; '; + $schemaValue = 'schema' + $lvl; + } else { + $schemaValue = $schema; + } + var $op = $keyword == 'maxLength' ? '>' : '<'; + out += 'if ( '; + if ($isData) { + out += ' (' + ($schemaValue) + ' !== undefined && typeof ' + ($schemaValue) + ' != \'number\') || '; + } + if (it.opts.unicode === false) { + out += ' ' + ($data) + '.length '; + } else { + out += ' ucs2length(' + ($data) + ') '; + } + out += ' ' + ($op) + ' ' + ($schemaValue) + ') { '; + var $errorKeyword = $keyword; + var $$outStack = $$outStack || []; + $$outStack.push(out); + out = ''; /* istanbul ignore else */ + if (it.createErrors !== false) { + out += ' { keyword: \'' + ($errorKeyword || '_limitLength') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { limit: ' + ($schemaValue) + ' } '; + if (it.opts.messages !== false) { + out += ' , message: \'should NOT be '; + if ($keyword == 'maxLength') { + out += 'longer'; + } else { + out += 'shorter'; + } + out += ' than '; + if ($isData) { + out += '\' + ' + ($schemaValue) + ' + \''; + } else { + out += '' + ($schema); + } + out += ' characters\' '; + } + if (it.opts.verbose) { + out += ' , schema: '; + if ($isData) { + out += 'validate.schema' + ($schemaPath); + } else { + out += '' + ($schema); + } + out += ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; + } + out += ' } '; + } else { + out += ' {} '; + } + var __err = out; + out = $$outStack.pop(); + if (!it.compositeRule && $breakOnError) { + /* istanbul ignore if */ + if (it.async) { + out += ' throw new ValidationError([' + (__err) + ']); '; + } else { + out += ' validate.errors = [' + (__err) + ']; return false; '; + } + } else { + out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; + } + out += '} '; + if ($breakOnError) { + out += ' else { '; + } + return out; +} + +},{}],16:[function(require,module,exports){ +'use strict'; +module.exports = function generate__limitProperties(it, $keyword, $ruleType) { + var out = ' '; + var $lvl = it.level; + var $dataLvl = it.dataLevel; + var $schema = it.schema[$keyword]; + var $schemaPath = it.schemaPath + it.util.getProperty($keyword); + var $errSchemaPath = it.errSchemaPath + '/' + $keyword; + var $breakOnError = !it.opts.allErrors; + var $errorKeyword; + var $data = 'data' + ($dataLvl || ''); + var $isData = it.opts.$data && $schema && $schema.$data, + $schemaValue; + if ($isData) { + out += ' var schema' + ($lvl) + ' = ' + (it.util.getData($schema.$data, $dataLvl, it.dataPathArr)) + '; '; + $schemaValue = 'schema' + $lvl; + } else { + $schemaValue = $schema; + } + var $op = $keyword == 'maxProperties' ? '>' : '<'; + out += 'if ( '; + if ($isData) { + out += ' (' + ($schemaValue) + ' !== undefined && typeof ' + ($schemaValue) + ' != \'number\') || '; + } + out += ' Object.keys(' + ($data) + ').length ' + ($op) + ' ' + ($schemaValue) + ') { '; + var $errorKeyword = $keyword; + var $$outStack = $$outStack || []; + $$outStack.push(out); + out = ''; /* istanbul ignore else */ + if (it.createErrors !== false) { + out += ' { keyword: \'' + ($errorKeyword || '_limitProperties') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { limit: ' + ($schemaValue) + ' } '; + if (it.opts.messages !== false) { + out += ' , message: \'should NOT have '; + if ($keyword == 'maxProperties') { + out += 'more'; + } else { + out += 'fewer'; + } + out += ' than '; + if ($isData) { + out += '\' + ' + ($schemaValue) + ' + \''; + } else { + out += '' + ($schema); + } + out += ' properties\' '; + } + if (it.opts.verbose) { + out += ' , schema: '; + if ($isData) { + out += 'validate.schema' + ($schemaPath); + } else { + out += '' + ($schema); + } + out += ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; + } + out += ' } '; + } else { + out += ' {} '; + } + var __err = out; + out = $$outStack.pop(); + if (!it.compositeRule && $breakOnError) { + /* istanbul ignore if */ + if (it.async) { + out += ' throw new ValidationError([' + (__err) + ']); '; + } else { + out += ' validate.errors = [' + (__err) + ']; return false; '; + } + } else { + out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; + } + out += '} '; + if ($breakOnError) { + out += ' else { '; + } + return out; +} + +},{}],17:[function(require,module,exports){ +'use strict'; +module.exports = function generate_allOf(it, $keyword, $ruleType) { + var out = ' '; + var $schema = it.schema[$keyword]; + var $schemaPath = it.schemaPath + it.util.getProperty($keyword); + var $errSchemaPath = it.errSchemaPath + '/' + $keyword; + var $breakOnError = !it.opts.allErrors; + var $it = it.util.copy(it); + var $closingBraces = ''; + $it.level++; + var $nextValid = 'valid' + $it.level; + var $currentBaseId = $it.baseId, + $allSchemasEmpty = true; + var arr1 = $schema; + if (arr1) { + var $sch, $i = -1, + l1 = arr1.length - 1; + while ($i < l1) { + $sch = arr1[$i += 1]; + if ((it.opts.strictKeywords ? typeof $sch == 'object' && Object.keys($sch).length > 0 : it.util.schemaHasRules($sch, it.RULES.all))) { + $allSchemasEmpty = false; + $it.schema = $sch; + $it.schemaPath = $schemaPath + '[' + $i + ']'; + $it.errSchemaPath = $errSchemaPath + '/' + $i; + out += ' ' + (it.validate($it)) + ' '; + $it.baseId = $currentBaseId; + if ($breakOnError) { + out += ' if (' + ($nextValid) + ') { '; + $closingBraces += '}'; + } + } + } + } + if ($breakOnError) { + if ($allSchemasEmpty) { + out += ' if (true) { '; + } else { + out += ' ' + ($closingBraces.slice(0, -1)) + ' '; + } + } + out = it.util.cleanUpCode(out); + return out; +} + +},{}],18:[function(require,module,exports){ +'use strict'; +module.exports = function generate_anyOf(it, $keyword, $ruleType) { + var out = ' '; + var $lvl = it.level; + var $dataLvl = it.dataLevel; + var $schema = it.schema[$keyword]; + var $schemaPath = it.schemaPath + it.util.getProperty($keyword); + var $errSchemaPath = it.errSchemaPath + '/' + $keyword; + var $breakOnError = !it.opts.allErrors; + var $data = 'data' + ($dataLvl || ''); + var $valid = 'valid' + $lvl; + var $errs = 'errs__' + $lvl; + var $it = it.util.copy(it); + var $closingBraces = ''; + $it.level++; + var $nextValid = 'valid' + $it.level; + var $noEmptySchema = $schema.every(function($sch) { + return (it.opts.strictKeywords ? typeof $sch == 'object' && Object.keys($sch).length > 0 : it.util.schemaHasRules($sch, it.RULES.all)); + }); + if ($noEmptySchema) { + var $currentBaseId = $it.baseId; + out += ' var ' + ($errs) + ' = errors; var ' + ($valid) + ' = false; '; + var $wasComposite = it.compositeRule; + it.compositeRule = $it.compositeRule = true; + var arr1 = $schema; + if (arr1) { + var $sch, $i = -1, + l1 = arr1.length - 1; + while ($i < l1) { + $sch = arr1[$i += 1]; + $it.schema = $sch; + $it.schemaPath = $schemaPath + '[' + $i + ']'; + $it.errSchemaPath = $errSchemaPath + '/' + $i; + out += ' ' + (it.validate($it)) + ' '; + $it.baseId = $currentBaseId; + out += ' ' + ($valid) + ' = ' + ($valid) + ' || ' + ($nextValid) + '; if (!' + ($valid) + ') { '; + $closingBraces += '}'; + } + } + it.compositeRule = $it.compositeRule = $wasComposite; + out += ' ' + ($closingBraces) + ' if (!' + ($valid) + ') { var err = '; /* istanbul ignore else */ + if (it.createErrors !== false) { + out += ' { keyword: \'' + ('anyOf') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: {} '; + if (it.opts.messages !== false) { + out += ' , message: \'should match some schema in anyOf\' '; + } + if (it.opts.verbose) { + out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; + } + out += ' } '; + } else { + out += ' {} '; + } + out += '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; + if (!it.compositeRule && $breakOnError) { + /* istanbul ignore if */ + if (it.async) { + out += ' throw new ValidationError(vErrors); '; + } else { + out += ' validate.errors = vErrors; return false; '; + } + } + out += ' } else { errors = ' + ($errs) + '; if (vErrors !== null) { if (' + ($errs) + ') vErrors.length = ' + ($errs) + '; else vErrors = null; } '; + if (it.opts.allErrors) { + out += ' } '; + } + out = it.util.cleanUpCode(out); + } else { + if ($breakOnError) { + out += ' if (true) { '; + } + } + return out; +} + +},{}],19:[function(require,module,exports){ +'use strict'; +module.exports = function generate_comment(it, $keyword, $ruleType) { + var out = ' '; + var $schema = it.schema[$keyword]; + var $errSchemaPath = it.errSchemaPath + '/' + $keyword; + var $breakOnError = !it.opts.allErrors; + var $comment = it.util.toQuotedString($schema); + if (it.opts.$comment === true) { + out += ' console.log(' + ($comment) + ');'; + } else if (typeof it.opts.$comment == 'function') { + out += ' self._opts.$comment(' + ($comment) + ', ' + (it.util.toQuotedString($errSchemaPath)) + ', validate.root.schema);'; + } + return out; +} + +},{}],20:[function(require,module,exports){ +'use strict'; +module.exports = function generate_const(it, $keyword, $ruleType) { + var out = ' '; + var $lvl = it.level; + var $dataLvl = it.dataLevel; + var $schema = it.schema[$keyword]; + var $schemaPath = it.schemaPath + it.util.getProperty($keyword); + var $errSchemaPath = it.errSchemaPath + '/' + $keyword; + var $breakOnError = !it.opts.allErrors; + var $data = 'data' + ($dataLvl || ''); + var $valid = 'valid' + $lvl; + var $isData = it.opts.$data && $schema && $schema.$data, + $schemaValue; + if ($isData) { + out += ' var schema' + ($lvl) + ' = ' + (it.util.getData($schema.$data, $dataLvl, it.dataPathArr)) + '; '; + $schemaValue = 'schema' + $lvl; + } else { + $schemaValue = $schema; + } + if (!$isData) { + out += ' var schema' + ($lvl) + ' = validate.schema' + ($schemaPath) + ';'; + } + out += 'var ' + ($valid) + ' = equal(' + ($data) + ', schema' + ($lvl) + '); if (!' + ($valid) + ') { '; + var $$outStack = $$outStack || []; + $$outStack.push(out); + out = ''; /* istanbul ignore else */ + if (it.createErrors !== false) { + out += ' { keyword: \'' + ('const') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { allowedValue: schema' + ($lvl) + ' } '; + if (it.opts.messages !== false) { + out += ' , message: \'should be equal to constant\' '; + } + if (it.opts.verbose) { + out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; + } + out += ' } '; + } else { + out += ' {} '; + } + var __err = out; + out = $$outStack.pop(); + if (!it.compositeRule && $breakOnError) { + /* istanbul ignore if */ + if (it.async) { + out += ' throw new ValidationError([' + (__err) + ']); '; + } else { + out += ' validate.errors = [' + (__err) + ']; return false; '; + } + } else { + out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; + } + out += ' }'; + if ($breakOnError) { + out += ' else { '; + } + return out; +} + +},{}],21:[function(require,module,exports){ +'use strict'; +module.exports = function generate_contains(it, $keyword, $ruleType) { + var out = ' '; + var $lvl = it.level; + var $dataLvl = it.dataLevel; + var $schema = it.schema[$keyword]; + var $schemaPath = it.schemaPath + it.util.getProperty($keyword); + var $errSchemaPath = it.errSchemaPath + '/' + $keyword; + var $breakOnError = !it.opts.allErrors; + var $data = 'data' + ($dataLvl || ''); + var $valid = 'valid' + $lvl; + var $errs = 'errs__' + $lvl; + var $it = it.util.copy(it); + var $closingBraces = ''; + $it.level++; + var $nextValid = 'valid' + $it.level; + var $idx = 'i' + $lvl, + $dataNxt = $it.dataLevel = it.dataLevel + 1, + $nextData = 'data' + $dataNxt, + $currentBaseId = it.baseId, + $nonEmptySchema = (it.opts.strictKeywords ? typeof $schema == 'object' && Object.keys($schema).length > 0 : it.util.schemaHasRules($schema, it.RULES.all)); + out += 'var ' + ($errs) + ' = errors;var ' + ($valid) + ';'; + if ($nonEmptySchema) { + var $wasComposite = it.compositeRule; + it.compositeRule = $it.compositeRule = true; + $it.schema = $schema; + $it.schemaPath = $schemaPath; + $it.errSchemaPath = $errSchemaPath; + out += ' var ' + ($nextValid) + ' = false; for (var ' + ($idx) + ' = 0; ' + ($idx) + ' < ' + ($data) + '.length; ' + ($idx) + '++) { '; + $it.errorPath = it.util.getPathExpr(it.errorPath, $idx, it.opts.jsonPointers, true); + var $passData = $data + '[' + $idx + ']'; + $it.dataPathArr[$dataNxt] = $idx; + var $code = it.validate($it); + $it.baseId = $currentBaseId; + if (it.util.varOccurences($code, $nextData) < 2) { + out += ' ' + (it.util.varReplace($code, $nextData, $passData)) + ' '; + } else { + out += ' var ' + ($nextData) + ' = ' + ($passData) + '; ' + ($code) + ' '; + } + out += ' if (' + ($nextValid) + ') break; } '; + it.compositeRule = $it.compositeRule = $wasComposite; + out += ' ' + ($closingBraces) + ' if (!' + ($nextValid) + ') {'; + } else { + out += ' if (' + ($data) + '.length == 0) {'; + } + var $$outStack = $$outStack || []; + $$outStack.push(out); + out = ''; /* istanbul ignore else */ + if (it.createErrors !== false) { + out += ' { keyword: \'' + ('contains') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: {} '; + if (it.opts.messages !== false) { + out += ' , message: \'should contain a valid item\' '; + } + if (it.opts.verbose) { + out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; + } + out += ' } '; + } else { + out += ' {} '; + } + var __err = out; + out = $$outStack.pop(); + if (!it.compositeRule && $breakOnError) { + /* istanbul ignore if */ + if (it.async) { + out += ' throw new ValidationError([' + (__err) + ']); '; + } else { + out += ' validate.errors = [' + (__err) + ']; return false; '; + } + } else { + out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; + } + out += ' } else { '; + if ($nonEmptySchema) { + out += ' errors = ' + ($errs) + '; if (vErrors !== null) { if (' + ($errs) + ') vErrors.length = ' + ($errs) + '; else vErrors = null; } '; + } + if (it.opts.allErrors) { + out += ' } '; + } + out = it.util.cleanUpCode(out); + return out; +} + +},{}],22:[function(require,module,exports){ +'use strict'; +module.exports = function generate_custom(it, $keyword, $ruleType) { + var out = ' '; + var $lvl = it.level; + var $dataLvl = it.dataLevel; + var $schema = it.schema[$keyword]; + var $schemaPath = it.schemaPath + it.util.getProperty($keyword); + var $errSchemaPath = it.errSchemaPath + '/' + $keyword; + var $breakOnError = !it.opts.allErrors; + var $errorKeyword; + var $data = 'data' + ($dataLvl || ''); + var $valid = 'valid' + $lvl; + var $errs = 'errs__' + $lvl; + var $isData = it.opts.$data && $schema && $schema.$data, + $schemaValue; + if ($isData) { + out += ' var schema' + ($lvl) + ' = ' + (it.util.getData($schema.$data, $dataLvl, it.dataPathArr)) + '; '; + $schemaValue = 'schema' + $lvl; + } else { + $schemaValue = $schema; + } + var $rule = this, + $definition = 'definition' + $lvl, + $rDef = $rule.definition, + $closingBraces = ''; + var $compile, $inline, $macro, $ruleValidate, $validateCode; + if ($isData && $rDef.$data) { + $validateCode = 'keywordValidate' + $lvl; + var $validateSchema = $rDef.validateSchema; + out += ' var ' + ($definition) + ' = RULES.custom[\'' + ($keyword) + '\'].definition; var ' + ($validateCode) + ' = ' + ($definition) + '.validate;'; + } else { + $ruleValidate = it.useCustomRule($rule, $schema, it.schema, it); + if (!$ruleValidate) return; + $schemaValue = 'validate.schema' + $schemaPath; + $validateCode = $ruleValidate.code; + $compile = $rDef.compile; + $inline = $rDef.inline; + $macro = $rDef.macro; + } + var $ruleErrs = $validateCode + '.errors', + $i = 'i' + $lvl, + $ruleErr = 'ruleErr' + $lvl, + $asyncKeyword = $rDef.async; + if ($asyncKeyword && !it.async) throw new Error('async keyword in sync schema'); + if (!($inline || $macro)) { + out += '' + ($ruleErrs) + ' = null;'; + } + out += 'var ' + ($errs) + ' = errors;var ' + ($valid) + ';'; + if ($isData && $rDef.$data) { + $closingBraces += '}'; + out += ' if (' + ($schemaValue) + ' === undefined) { ' + ($valid) + ' = true; } else { '; + if ($validateSchema) { + $closingBraces += '}'; + out += ' ' + ($valid) + ' = ' + ($definition) + '.validateSchema(' + ($schemaValue) + '); if (' + ($valid) + ') { '; + } + } + if ($inline) { + if ($rDef.statements) { + out += ' ' + ($ruleValidate.validate) + ' '; + } else { + out += ' ' + ($valid) + ' = ' + ($ruleValidate.validate) + '; '; + } + } else if ($macro) { + var $it = it.util.copy(it); + var $closingBraces = ''; + $it.level++; + var $nextValid = 'valid' + $it.level; + $it.schema = $ruleValidate.validate; + $it.schemaPath = ''; + var $wasComposite = it.compositeRule; + it.compositeRule = $it.compositeRule = true; + var $code = it.validate($it).replace(/validate\.schema/g, $validateCode); + it.compositeRule = $it.compositeRule = $wasComposite; + out += ' ' + ($code); + } else { + var $$outStack = $$outStack || []; + $$outStack.push(out); + out = ''; + out += ' ' + ($validateCode) + '.call( '; + if (it.opts.passContext) { + out += 'this'; + } else { + out += 'self'; + } + if ($compile || $rDef.schema === false) { + out += ' , ' + ($data) + ' '; + } else { + out += ' , ' + ($schemaValue) + ' , ' + ($data) + ' , validate.schema' + (it.schemaPath) + ' '; + } + out += ' , (dataPath || \'\')'; + if (it.errorPath != '""') { + out += ' + ' + (it.errorPath); + } + var $parentData = $dataLvl ? 'data' + (($dataLvl - 1) || '') : 'parentData', + $parentDataProperty = $dataLvl ? it.dataPathArr[$dataLvl] : 'parentDataProperty'; + out += ' , ' + ($parentData) + ' , ' + ($parentDataProperty) + ' , rootData ) '; + var def_callRuleValidate = out; + out = $$outStack.pop(); + if ($rDef.errors === false) { + out += ' ' + ($valid) + ' = '; + if ($asyncKeyword) { + out += 'await '; + } + out += '' + (def_callRuleValidate) + '; '; + } else { + if ($asyncKeyword) { + $ruleErrs = 'customErrors' + $lvl; + out += ' var ' + ($ruleErrs) + ' = null; try { ' + ($valid) + ' = await ' + (def_callRuleValidate) + '; } catch (e) { ' + ($valid) + ' = false; if (e instanceof ValidationError) ' + ($ruleErrs) + ' = e.errors; else throw e; } '; + } else { + out += ' ' + ($ruleErrs) + ' = null; ' + ($valid) + ' = ' + (def_callRuleValidate) + '; '; + } + } + } + if ($rDef.modifying) { + out += ' if (' + ($parentData) + ') ' + ($data) + ' = ' + ($parentData) + '[' + ($parentDataProperty) + '];'; + } + out += '' + ($closingBraces); + if ($rDef.valid) { + if ($breakOnError) { + out += ' if (true) { '; + } + } else { + out += ' if ( '; + if ($rDef.valid === undefined) { + out += ' !'; + if ($macro) { + out += '' + ($nextValid); + } else { + out += '' + ($valid); + } + } else { + out += ' ' + (!$rDef.valid) + ' '; + } + out += ') { '; + $errorKeyword = $rule.keyword; + var $$outStack = $$outStack || []; + $$outStack.push(out); + out = ''; + var $$outStack = $$outStack || []; + $$outStack.push(out); + out = ''; /* istanbul ignore else */ + if (it.createErrors !== false) { + out += ' { keyword: \'' + ($errorKeyword || 'custom') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { keyword: \'' + ($rule.keyword) + '\' } '; + if (it.opts.messages !== false) { + out += ' , message: \'should pass "' + ($rule.keyword) + '" keyword validation\' '; + } + if (it.opts.verbose) { + out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; + } + out += ' } '; + } else { + out += ' {} '; + } + var __err = out; + out = $$outStack.pop(); + if (!it.compositeRule && $breakOnError) { + /* istanbul ignore if */ + if (it.async) { + out += ' throw new ValidationError([' + (__err) + ']); '; + } else { + out += ' validate.errors = [' + (__err) + ']; return false; '; + } + } else { + out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; + } + var def_customError = out; + out = $$outStack.pop(); + if ($inline) { + if ($rDef.errors) { + if ($rDef.errors != 'full') { + out += ' for (var ' + ($i) + '=' + ($errs) + '; ' + ($i) + ' 0 : it.util.schemaHasRules($sch, it.RULES.all))) { + out += ' ' + ($nextValid) + ' = true; if ( ' + ($data) + (it.util.getProperty($property)) + ' !== undefined '; + if ($ownProperties) { + out += ' && Object.prototype.hasOwnProperty.call(' + ($data) + ', \'' + (it.util.escapeQuotes($property)) + '\') '; + } + out += ') { '; + $it.schema = $sch; + $it.schemaPath = $schemaPath + it.util.getProperty($property); + $it.errSchemaPath = $errSchemaPath + '/' + it.util.escapeFragment($property); + out += ' ' + (it.validate($it)) + ' '; + $it.baseId = $currentBaseId; + out += ' } '; + if ($breakOnError) { + out += ' if (' + ($nextValid) + ') { '; + $closingBraces += '}'; + } + } + } + if ($breakOnError) { + out += ' ' + ($closingBraces) + ' if (' + ($errs) + ' == errors) {'; + } + out = it.util.cleanUpCode(out); + return out; +} + +},{}],24:[function(require,module,exports){ +'use strict'; +module.exports = function generate_enum(it, $keyword, $ruleType) { + var out = ' '; + var $lvl = it.level; + var $dataLvl = it.dataLevel; + var $schema = it.schema[$keyword]; + var $schemaPath = it.schemaPath + it.util.getProperty($keyword); + var $errSchemaPath = it.errSchemaPath + '/' + $keyword; + var $breakOnError = !it.opts.allErrors; + var $data = 'data' + ($dataLvl || ''); + var $valid = 'valid' + $lvl; + var $isData = it.opts.$data && $schema && $schema.$data, + $schemaValue; + if ($isData) { + out += ' var schema' + ($lvl) + ' = ' + (it.util.getData($schema.$data, $dataLvl, it.dataPathArr)) + '; '; + $schemaValue = 'schema' + $lvl; + } else { + $schemaValue = $schema; + } + var $i = 'i' + $lvl, + $vSchema = 'schema' + $lvl; + if (!$isData) { + out += ' var ' + ($vSchema) + ' = validate.schema' + ($schemaPath) + ';'; + } + out += 'var ' + ($valid) + ';'; + if ($isData) { + out += ' if (schema' + ($lvl) + ' === undefined) ' + ($valid) + ' = true; else if (!Array.isArray(schema' + ($lvl) + ')) ' + ($valid) + ' = false; else {'; + } + out += '' + ($valid) + ' = false;for (var ' + ($i) + '=0; ' + ($i) + '<' + ($vSchema) + '.length; ' + ($i) + '++) if (equal(' + ($data) + ', ' + ($vSchema) + '[' + ($i) + '])) { ' + ($valid) + ' = true; break; }'; + if ($isData) { + out += ' } '; + } + out += ' if (!' + ($valid) + ') { '; + var $$outStack = $$outStack || []; + $$outStack.push(out); + out = ''; /* istanbul ignore else */ + if (it.createErrors !== false) { + out += ' { keyword: \'' + ('enum') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { allowedValues: schema' + ($lvl) + ' } '; + if (it.opts.messages !== false) { + out += ' , message: \'should be equal to one of the allowed values\' '; + } + if (it.opts.verbose) { + out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; + } + out += ' } '; + } else { + out += ' {} '; + } + var __err = out; + out = $$outStack.pop(); + if (!it.compositeRule && $breakOnError) { + /* istanbul ignore if */ + if (it.async) { + out += ' throw new ValidationError([' + (__err) + ']); '; + } else { + out += ' validate.errors = [' + (__err) + ']; return false; '; + } + } else { + out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; + } + out += ' }'; + if ($breakOnError) { + out += ' else { '; + } + return out; +} + +},{}],25:[function(require,module,exports){ +'use strict'; +module.exports = function generate_format(it, $keyword, $ruleType) { + var out = ' '; + var $lvl = it.level; + var $dataLvl = it.dataLevel; + var $schema = it.schema[$keyword]; + var $schemaPath = it.schemaPath + it.util.getProperty($keyword); + var $errSchemaPath = it.errSchemaPath + '/' + $keyword; + var $breakOnError = !it.opts.allErrors; + var $data = 'data' + ($dataLvl || ''); + if (it.opts.format === false) { + if ($breakOnError) { + out += ' if (true) { '; + } + return out; + } + var $isData = it.opts.$data && $schema && $schema.$data, + $schemaValue; + if ($isData) { + out += ' var schema' + ($lvl) + ' = ' + (it.util.getData($schema.$data, $dataLvl, it.dataPathArr)) + '; '; + $schemaValue = 'schema' + $lvl; + } else { + $schemaValue = $schema; + } + var $unknownFormats = it.opts.unknownFormats, + $allowUnknown = Array.isArray($unknownFormats); + if ($isData) { + var $format = 'format' + $lvl, + $isObject = 'isObject' + $lvl, + $formatType = 'formatType' + $lvl; + out += ' var ' + ($format) + ' = formats[' + ($schemaValue) + ']; var ' + ($isObject) + ' = typeof ' + ($format) + ' == \'object\' && !(' + ($format) + ' instanceof RegExp) && ' + ($format) + '.validate; var ' + ($formatType) + ' = ' + ($isObject) + ' && ' + ($format) + '.type || \'string\'; if (' + ($isObject) + ') { '; + if (it.async) { + out += ' var async' + ($lvl) + ' = ' + ($format) + '.async; '; + } + out += ' ' + ($format) + ' = ' + ($format) + '.validate; } if ( '; + if ($isData) { + out += ' (' + ($schemaValue) + ' !== undefined && typeof ' + ($schemaValue) + ' != \'string\') || '; + } + out += ' ('; + if ($unknownFormats != 'ignore') { + out += ' (' + ($schemaValue) + ' && !' + ($format) + ' '; + if ($allowUnknown) { + out += ' && self._opts.unknownFormats.indexOf(' + ($schemaValue) + ') == -1 '; + } + out += ') || '; + } + out += ' (' + ($format) + ' && ' + ($formatType) + ' == \'' + ($ruleType) + '\' && !(typeof ' + ($format) + ' == \'function\' ? '; + if (it.async) { + out += ' (async' + ($lvl) + ' ? await ' + ($format) + '(' + ($data) + ') : ' + ($format) + '(' + ($data) + ')) '; + } else { + out += ' ' + ($format) + '(' + ($data) + ') '; + } + out += ' : ' + ($format) + '.test(' + ($data) + '))))) {'; + } else { + var $format = it.formats[$schema]; + if (!$format) { + if ($unknownFormats == 'ignore') { + it.logger.warn('unknown format "' + $schema + '" ignored in schema at path "' + it.errSchemaPath + '"'); + if ($breakOnError) { + out += ' if (true) { '; + } + return out; + } else if ($allowUnknown && $unknownFormats.indexOf($schema) >= 0) { + if ($breakOnError) { + out += ' if (true) { '; + } + return out; + } else { + throw new Error('unknown format "' + $schema + '" is used in schema at path "' + it.errSchemaPath + '"'); + } + } + var $isObject = typeof $format == 'object' && !($format instanceof RegExp) && $format.validate; + var $formatType = $isObject && $format.type || 'string'; + if ($isObject) { + var $async = $format.async === true; + $format = $format.validate; + } + if ($formatType != $ruleType) { + if ($breakOnError) { + out += ' if (true) { '; + } + return out; + } + if ($async) { + if (!it.async) throw new Error('async format in sync schema'); + var $formatRef = 'formats' + it.util.getProperty($schema) + '.validate'; + out += ' if (!(await ' + ($formatRef) + '(' + ($data) + '))) { '; + } else { + out += ' if (! '; + var $formatRef = 'formats' + it.util.getProperty($schema); + if ($isObject) $formatRef += '.validate'; + if (typeof $format == 'function') { + out += ' ' + ($formatRef) + '(' + ($data) + ') '; + } else { + out += ' ' + ($formatRef) + '.test(' + ($data) + ') '; + } + out += ') { '; + } + } + var $$outStack = $$outStack || []; + $$outStack.push(out); + out = ''; /* istanbul ignore else */ + if (it.createErrors !== false) { + out += ' { keyword: \'' + ('format') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { format: '; + if ($isData) { + out += '' + ($schemaValue); + } else { + out += '' + (it.util.toQuotedString($schema)); + } + out += ' } '; + if (it.opts.messages !== false) { + out += ' , message: \'should match format "'; + if ($isData) { + out += '\' + ' + ($schemaValue) + ' + \''; + } else { + out += '' + (it.util.escapeQuotes($schema)); + } + out += '"\' '; + } + if (it.opts.verbose) { + out += ' , schema: '; + if ($isData) { + out += 'validate.schema' + ($schemaPath); + } else { + out += '' + (it.util.toQuotedString($schema)); + } + out += ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; + } + out += ' } '; + } else { + out += ' {} '; + } + var __err = out; + out = $$outStack.pop(); + if (!it.compositeRule && $breakOnError) { + /* istanbul ignore if */ + if (it.async) { + out += ' throw new ValidationError([' + (__err) + ']); '; + } else { + out += ' validate.errors = [' + (__err) + ']; return false; '; + } + } else { + out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; + } + out += ' } '; + if ($breakOnError) { + out += ' else { '; + } + return out; +} + +},{}],26:[function(require,module,exports){ +'use strict'; +module.exports = function generate_if(it, $keyword, $ruleType) { + var out = ' '; + var $lvl = it.level; + var $dataLvl = it.dataLevel; + var $schema = it.schema[$keyword]; + var $schemaPath = it.schemaPath + it.util.getProperty($keyword); + var $errSchemaPath = it.errSchemaPath + '/' + $keyword; + var $breakOnError = !it.opts.allErrors; + var $data = 'data' + ($dataLvl || ''); + var $valid = 'valid' + $lvl; + var $errs = 'errs__' + $lvl; + var $it = it.util.copy(it); + $it.level++; + var $nextValid = 'valid' + $it.level; + var $thenSch = it.schema['then'], + $elseSch = it.schema['else'], + $thenPresent = $thenSch !== undefined && (it.opts.strictKeywords ? typeof $thenSch == 'object' && Object.keys($thenSch).length > 0 : it.util.schemaHasRules($thenSch, it.RULES.all)), + $elsePresent = $elseSch !== undefined && (it.opts.strictKeywords ? typeof $elseSch == 'object' && Object.keys($elseSch).length > 0 : it.util.schemaHasRules($elseSch, it.RULES.all)), + $currentBaseId = $it.baseId; + if ($thenPresent || $elsePresent) { + var $ifClause; + $it.createErrors = false; + $it.schema = $schema; + $it.schemaPath = $schemaPath; + $it.errSchemaPath = $errSchemaPath; + out += ' var ' + ($errs) + ' = errors; var ' + ($valid) + ' = true; '; + var $wasComposite = it.compositeRule; + it.compositeRule = $it.compositeRule = true; + out += ' ' + (it.validate($it)) + ' '; + $it.baseId = $currentBaseId; + $it.createErrors = true; + out += ' errors = ' + ($errs) + '; if (vErrors !== null) { if (' + ($errs) + ') vErrors.length = ' + ($errs) + '; else vErrors = null; } '; + it.compositeRule = $it.compositeRule = $wasComposite; + if ($thenPresent) { + out += ' if (' + ($nextValid) + ') { '; + $it.schema = it.schema['then']; + $it.schemaPath = it.schemaPath + '.then'; + $it.errSchemaPath = it.errSchemaPath + '/then'; + out += ' ' + (it.validate($it)) + ' '; + $it.baseId = $currentBaseId; + out += ' ' + ($valid) + ' = ' + ($nextValid) + '; '; + if ($thenPresent && $elsePresent) { + $ifClause = 'ifClause' + $lvl; + out += ' var ' + ($ifClause) + ' = \'then\'; '; + } else { + $ifClause = '\'then\''; + } + out += ' } '; + if ($elsePresent) { + out += ' else { '; + } + } else { + out += ' if (!' + ($nextValid) + ') { '; + } + if ($elsePresent) { + $it.schema = it.schema['else']; + $it.schemaPath = it.schemaPath + '.else'; + $it.errSchemaPath = it.errSchemaPath + '/else'; + out += ' ' + (it.validate($it)) + ' '; + $it.baseId = $currentBaseId; + out += ' ' + ($valid) + ' = ' + ($nextValid) + '; '; + if ($thenPresent && $elsePresent) { + $ifClause = 'ifClause' + $lvl; + out += ' var ' + ($ifClause) + ' = \'else\'; '; + } else { + $ifClause = '\'else\''; + } + out += ' } '; + } + out += ' if (!' + ($valid) + ') { var err = '; /* istanbul ignore else */ + if (it.createErrors !== false) { + out += ' { keyword: \'' + ('if') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { failingKeyword: ' + ($ifClause) + ' } '; + if (it.opts.messages !== false) { + out += ' , message: \'should match "\' + ' + ($ifClause) + ' + \'" schema\' '; + } + if (it.opts.verbose) { + out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; + } + out += ' } '; + } else { + out += ' {} '; + } + out += '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; + if (!it.compositeRule && $breakOnError) { + /* istanbul ignore if */ + if (it.async) { + out += ' throw new ValidationError(vErrors); '; + } else { + out += ' validate.errors = vErrors; return false; '; + } + } + out += ' } '; + if ($breakOnError) { + out += ' else { '; + } + out = it.util.cleanUpCode(out); + } else { + if ($breakOnError) { + out += ' if (true) { '; + } + } + return out; +} + +},{}],27:[function(require,module,exports){ +'use strict'; + +//all requires must be explicit because browserify won't work with dynamic requires +module.exports = { + '$ref': require('./ref'), + allOf: require('./allOf'), + anyOf: require('./anyOf'), + '$comment': require('./comment'), + const: require('./const'), + contains: require('./contains'), + dependencies: require('./dependencies'), + 'enum': require('./enum'), + format: require('./format'), + 'if': require('./if'), + items: require('./items'), + maximum: require('./_limit'), + minimum: require('./_limit'), + maxItems: require('./_limitItems'), + minItems: require('./_limitItems'), + maxLength: require('./_limitLength'), + minLength: require('./_limitLength'), + maxProperties: require('./_limitProperties'), + minProperties: require('./_limitProperties'), + multipleOf: require('./multipleOf'), + not: require('./not'), + oneOf: require('./oneOf'), + pattern: require('./pattern'), + properties: require('./properties'), + propertyNames: require('./propertyNames'), + required: require('./required'), + uniqueItems: require('./uniqueItems'), + validate: require('./validate') +}; + +},{"./_limit":13,"./_limitItems":14,"./_limitLength":15,"./_limitProperties":16,"./allOf":17,"./anyOf":18,"./comment":19,"./const":20,"./contains":21,"./dependencies":23,"./enum":24,"./format":25,"./if":26,"./items":28,"./multipleOf":29,"./not":30,"./oneOf":31,"./pattern":32,"./properties":33,"./propertyNames":34,"./ref":35,"./required":36,"./uniqueItems":37,"./validate":38}],28:[function(require,module,exports){ +'use strict'; +module.exports = function generate_items(it, $keyword, $ruleType) { + var out = ' '; + var $lvl = it.level; + var $dataLvl = it.dataLevel; + var $schema = it.schema[$keyword]; + var $schemaPath = it.schemaPath + it.util.getProperty($keyword); + var $errSchemaPath = it.errSchemaPath + '/' + $keyword; + var $breakOnError = !it.opts.allErrors; + var $data = 'data' + ($dataLvl || ''); + var $valid = 'valid' + $lvl; + var $errs = 'errs__' + $lvl; + var $it = it.util.copy(it); + var $closingBraces = ''; + $it.level++; + var $nextValid = 'valid' + $it.level; + var $idx = 'i' + $lvl, + $dataNxt = $it.dataLevel = it.dataLevel + 1, + $nextData = 'data' + $dataNxt, + $currentBaseId = it.baseId; + out += 'var ' + ($errs) + ' = errors;var ' + ($valid) + ';'; + if (Array.isArray($schema)) { + var $additionalItems = it.schema.additionalItems; + if ($additionalItems === false) { + out += ' ' + ($valid) + ' = ' + ($data) + '.length <= ' + ($schema.length) + '; '; + var $currErrSchemaPath = $errSchemaPath; + $errSchemaPath = it.errSchemaPath + '/additionalItems'; + out += ' if (!' + ($valid) + ') { '; + var $$outStack = $$outStack || []; + $$outStack.push(out); + out = ''; /* istanbul ignore else */ + if (it.createErrors !== false) { + out += ' { keyword: \'' + ('additionalItems') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { limit: ' + ($schema.length) + ' } '; + if (it.opts.messages !== false) { + out += ' , message: \'should NOT have more than ' + ($schema.length) + ' items\' '; + } + if (it.opts.verbose) { + out += ' , schema: false , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; + } + out += ' } '; + } else { + out += ' {} '; + } + var __err = out; + out = $$outStack.pop(); + if (!it.compositeRule && $breakOnError) { + /* istanbul ignore if */ + if (it.async) { + out += ' throw new ValidationError([' + (__err) + ']); '; + } else { + out += ' validate.errors = [' + (__err) + ']; return false; '; + } + } else { + out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; + } + out += ' } '; + $errSchemaPath = $currErrSchemaPath; + if ($breakOnError) { + $closingBraces += '}'; + out += ' else { '; + } + } + var arr1 = $schema; + if (arr1) { + var $sch, $i = -1, + l1 = arr1.length - 1; + while ($i < l1) { + $sch = arr1[$i += 1]; + if ((it.opts.strictKeywords ? typeof $sch == 'object' && Object.keys($sch).length > 0 : it.util.schemaHasRules($sch, it.RULES.all))) { + out += ' ' + ($nextValid) + ' = true; if (' + ($data) + '.length > ' + ($i) + ') { '; + var $passData = $data + '[' + $i + ']'; + $it.schema = $sch; + $it.schemaPath = $schemaPath + '[' + $i + ']'; + $it.errSchemaPath = $errSchemaPath + '/' + $i; + $it.errorPath = it.util.getPathExpr(it.errorPath, $i, it.opts.jsonPointers, true); + $it.dataPathArr[$dataNxt] = $i; + var $code = it.validate($it); + $it.baseId = $currentBaseId; + if (it.util.varOccurences($code, $nextData) < 2) { + out += ' ' + (it.util.varReplace($code, $nextData, $passData)) + ' '; + } else { + out += ' var ' + ($nextData) + ' = ' + ($passData) + '; ' + ($code) + ' '; + } + out += ' } '; + if ($breakOnError) { + out += ' if (' + ($nextValid) + ') { '; + $closingBraces += '}'; + } + } + } + } + if (typeof $additionalItems == 'object' && (it.opts.strictKeywords ? typeof $additionalItems == 'object' && Object.keys($additionalItems).length > 0 : it.util.schemaHasRules($additionalItems, it.RULES.all))) { + $it.schema = $additionalItems; + $it.schemaPath = it.schemaPath + '.additionalItems'; + $it.errSchemaPath = it.errSchemaPath + '/additionalItems'; + out += ' ' + ($nextValid) + ' = true; if (' + ($data) + '.length > ' + ($schema.length) + ') { for (var ' + ($idx) + ' = ' + ($schema.length) + '; ' + ($idx) + ' < ' + ($data) + '.length; ' + ($idx) + '++) { '; + $it.errorPath = it.util.getPathExpr(it.errorPath, $idx, it.opts.jsonPointers, true); + var $passData = $data + '[' + $idx + ']'; + $it.dataPathArr[$dataNxt] = $idx; + var $code = it.validate($it); + $it.baseId = $currentBaseId; + if (it.util.varOccurences($code, $nextData) < 2) { + out += ' ' + (it.util.varReplace($code, $nextData, $passData)) + ' '; + } else { + out += ' var ' + ($nextData) + ' = ' + ($passData) + '; ' + ($code) + ' '; + } + if ($breakOnError) { + out += ' if (!' + ($nextValid) + ') break; '; + } + out += ' } } '; + if ($breakOnError) { + out += ' if (' + ($nextValid) + ') { '; + $closingBraces += '}'; + } + } + } else if ((it.opts.strictKeywords ? typeof $schema == 'object' && Object.keys($schema).length > 0 : it.util.schemaHasRules($schema, it.RULES.all))) { + $it.schema = $schema; + $it.schemaPath = $schemaPath; + $it.errSchemaPath = $errSchemaPath; + out += ' for (var ' + ($idx) + ' = ' + (0) + '; ' + ($idx) + ' < ' + ($data) + '.length; ' + ($idx) + '++) { '; + $it.errorPath = it.util.getPathExpr(it.errorPath, $idx, it.opts.jsonPointers, true); + var $passData = $data + '[' + $idx + ']'; + $it.dataPathArr[$dataNxt] = $idx; + var $code = it.validate($it); + $it.baseId = $currentBaseId; + if (it.util.varOccurences($code, $nextData) < 2) { + out += ' ' + (it.util.varReplace($code, $nextData, $passData)) + ' '; + } else { + out += ' var ' + ($nextData) + ' = ' + ($passData) + '; ' + ($code) + ' '; + } + if ($breakOnError) { + out += ' if (!' + ($nextValid) + ') break; '; + } + out += ' }'; + } + if ($breakOnError) { + out += ' ' + ($closingBraces) + ' if (' + ($errs) + ' == errors) {'; + } + out = it.util.cleanUpCode(out); + return out; +} + +},{}],29:[function(require,module,exports){ +'use strict'; +module.exports = function generate_multipleOf(it, $keyword, $ruleType) { + var out = ' '; + var $lvl = it.level; + var $dataLvl = it.dataLevel; + var $schema = it.schema[$keyword]; + var $schemaPath = it.schemaPath + it.util.getProperty($keyword); + var $errSchemaPath = it.errSchemaPath + '/' + $keyword; + var $breakOnError = !it.opts.allErrors; + var $data = 'data' + ($dataLvl || ''); + var $isData = it.opts.$data && $schema && $schema.$data, + $schemaValue; + if ($isData) { + out += ' var schema' + ($lvl) + ' = ' + (it.util.getData($schema.$data, $dataLvl, it.dataPathArr)) + '; '; + $schemaValue = 'schema' + $lvl; + } else { + $schemaValue = $schema; + } + out += 'var division' + ($lvl) + ';if ('; + if ($isData) { + out += ' ' + ($schemaValue) + ' !== undefined && ( typeof ' + ($schemaValue) + ' != \'number\' || '; + } + out += ' (division' + ($lvl) + ' = ' + ($data) + ' / ' + ($schemaValue) + ', '; + if (it.opts.multipleOfPrecision) { + out += ' Math.abs(Math.round(division' + ($lvl) + ') - division' + ($lvl) + ') > 1e-' + (it.opts.multipleOfPrecision) + ' '; + } else { + out += ' division' + ($lvl) + ' !== parseInt(division' + ($lvl) + ') '; + } + out += ' ) '; + if ($isData) { + out += ' ) '; + } + out += ' ) { '; + var $$outStack = $$outStack || []; + $$outStack.push(out); + out = ''; /* istanbul ignore else */ + if (it.createErrors !== false) { + out += ' { keyword: \'' + ('multipleOf') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { multipleOf: ' + ($schemaValue) + ' } '; + if (it.opts.messages !== false) { + out += ' , message: \'should be multiple of '; + if ($isData) { + out += '\' + ' + ($schemaValue); + } else { + out += '' + ($schemaValue) + '\''; + } + } + if (it.opts.verbose) { + out += ' , schema: '; + if ($isData) { + out += 'validate.schema' + ($schemaPath); + } else { + out += '' + ($schema); + } + out += ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; + } + out += ' } '; + } else { + out += ' {} '; + } + var __err = out; + out = $$outStack.pop(); + if (!it.compositeRule && $breakOnError) { + /* istanbul ignore if */ + if (it.async) { + out += ' throw new ValidationError([' + (__err) + ']); '; + } else { + out += ' validate.errors = [' + (__err) + ']; return false; '; + } + } else { + out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; + } + out += '} '; + if ($breakOnError) { + out += ' else { '; + } + return out; +} + +},{}],30:[function(require,module,exports){ +'use strict'; +module.exports = function generate_not(it, $keyword, $ruleType) { + var out = ' '; + var $lvl = it.level; + var $dataLvl = it.dataLevel; + var $schema = it.schema[$keyword]; + var $schemaPath = it.schemaPath + it.util.getProperty($keyword); + var $errSchemaPath = it.errSchemaPath + '/' + $keyword; + var $breakOnError = !it.opts.allErrors; + var $data = 'data' + ($dataLvl || ''); + var $errs = 'errs__' + $lvl; + var $it = it.util.copy(it); + $it.level++; + var $nextValid = 'valid' + $it.level; + if ((it.opts.strictKeywords ? typeof $schema == 'object' && Object.keys($schema).length > 0 : it.util.schemaHasRules($schema, it.RULES.all))) { + $it.schema = $schema; + $it.schemaPath = $schemaPath; + $it.errSchemaPath = $errSchemaPath; + out += ' var ' + ($errs) + ' = errors; '; + var $wasComposite = it.compositeRule; + it.compositeRule = $it.compositeRule = true; + $it.createErrors = false; + var $allErrorsOption; + if ($it.opts.allErrors) { + $allErrorsOption = $it.opts.allErrors; + $it.opts.allErrors = false; + } + out += ' ' + (it.validate($it)) + ' '; + $it.createErrors = true; + if ($allErrorsOption) $it.opts.allErrors = $allErrorsOption; + it.compositeRule = $it.compositeRule = $wasComposite; + out += ' if (' + ($nextValid) + ') { '; + var $$outStack = $$outStack || []; + $$outStack.push(out); + out = ''; /* istanbul ignore else */ + if (it.createErrors !== false) { + out += ' { keyword: \'' + ('not') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: {} '; + if (it.opts.messages !== false) { + out += ' , message: \'should NOT be valid\' '; + } + if (it.opts.verbose) { + out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; + } + out += ' } '; + } else { + out += ' {} '; + } + var __err = out; + out = $$outStack.pop(); + if (!it.compositeRule && $breakOnError) { + /* istanbul ignore if */ + if (it.async) { + out += ' throw new ValidationError([' + (__err) + ']); '; + } else { + out += ' validate.errors = [' + (__err) + ']; return false; '; + } + } else { + out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; + } + out += ' } else { errors = ' + ($errs) + '; if (vErrors !== null) { if (' + ($errs) + ') vErrors.length = ' + ($errs) + '; else vErrors = null; } '; + if (it.opts.allErrors) { + out += ' } '; + } + } else { + out += ' var err = '; /* istanbul ignore else */ + if (it.createErrors !== false) { + out += ' { keyword: \'' + ('not') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: {} '; + if (it.opts.messages !== false) { + out += ' , message: \'should NOT be valid\' '; + } + if (it.opts.verbose) { + out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; + } + out += ' } '; + } else { + out += ' {} '; + } + out += '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; + if ($breakOnError) { + out += ' if (false) { '; + } + } + return out; +} + +},{}],31:[function(require,module,exports){ +'use strict'; +module.exports = function generate_oneOf(it, $keyword, $ruleType) { + var out = ' '; + var $lvl = it.level; + var $dataLvl = it.dataLevel; + var $schema = it.schema[$keyword]; + var $schemaPath = it.schemaPath + it.util.getProperty($keyword); + var $errSchemaPath = it.errSchemaPath + '/' + $keyword; + var $breakOnError = !it.opts.allErrors; + var $data = 'data' + ($dataLvl || ''); + var $valid = 'valid' + $lvl; + var $errs = 'errs__' + $lvl; + var $it = it.util.copy(it); + var $closingBraces = ''; + $it.level++; + var $nextValid = 'valid' + $it.level; + var $currentBaseId = $it.baseId, + $prevValid = 'prevValid' + $lvl, + $passingSchemas = 'passingSchemas' + $lvl; + out += 'var ' + ($errs) + ' = errors , ' + ($prevValid) + ' = false , ' + ($valid) + ' = false , ' + ($passingSchemas) + ' = null; '; + var $wasComposite = it.compositeRule; + it.compositeRule = $it.compositeRule = true; + var arr1 = $schema; + if (arr1) { + var $sch, $i = -1, + l1 = arr1.length - 1; + while ($i < l1) { + $sch = arr1[$i += 1]; + if ((it.opts.strictKeywords ? typeof $sch == 'object' && Object.keys($sch).length > 0 : it.util.schemaHasRules($sch, it.RULES.all))) { + $it.schema = $sch; + $it.schemaPath = $schemaPath + '[' + $i + ']'; + $it.errSchemaPath = $errSchemaPath + '/' + $i; + out += ' ' + (it.validate($it)) + ' '; + $it.baseId = $currentBaseId; + } else { + out += ' var ' + ($nextValid) + ' = true; '; + } + if ($i) { + out += ' if (' + ($nextValid) + ' && ' + ($prevValid) + ') { ' + ($valid) + ' = false; ' + ($passingSchemas) + ' = [' + ($passingSchemas) + ', ' + ($i) + ']; } else { '; + $closingBraces += '}'; + } + out += ' if (' + ($nextValid) + ') { ' + ($valid) + ' = ' + ($prevValid) + ' = true; ' + ($passingSchemas) + ' = ' + ($i) + '; }'; + } + } + it.compositeRule = $it.compositeRule = $wasComposite; + out += '' + ($closingBraces) + 'if (!' + ($valid) + ') { var err = '; /* istanbul ignore else */ + if (it.createErrors !== false) { + out += ' { keyword: \'' + ('oneOf') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { passingSchemas: ' + ($passingSchemas) + ' } '; + if (it.opts.messages !== false) { + out += ' , message: \'should match exactly one schema in oneOf\' '; + } + if (it.opts.verbose) { + out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; + } + out += ' } '; + } else { + out += ' {} '; + } + out += '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; + if (!it.compositeRule && $breakOnError) { + /* istanbul ignore if */ + if (it.async) { + out += ' throw new ValidationError(vErrors); '; + } else { + out += ' validate.errors = vErrors; return false; '; + } + } + out += '} else { errors = ' + ($errs) + '; if (vErrors !== null) { if (' + ($errs) + ') vErrors.length = ' + ($errs) + '; else vErrors = null; }'; + if (it.opts.allErrors) { + out += ' } '; + } + return out; +} + +},{}],32:[function(require,module,exports){ +'use strict'; +module.exports = function generate_pattern(it, $keyword, $ruleType) { + var out = ' '; + var $lvl = it.level; + var $dataLvl = it.dataLevel; + var $schema = it.schema[$keyword]; + var $schemaPath = it.schemaPath + it.util.getProperty($keyword); + var $errSchemaPath = it.errSchemaPath + '/' + $keyword; + var $breakOnError = !it.opts.allErrors; + var $data = 'data' + ($dataLvl || ''); + var $isData = it.opts.$data && $schema && $schema.$data, + $schemaValue; + if ($isData) { + out += ' var schema' + ($lvl) + ' = ' + (it.util.getData($schema.$data, $dataLvl, it.dataPathArr)) + '; '; + $schemaValue = 'schema' + $lvl; + } else { + $schemaValue = $schema; + } + var $regexp = $isData ? '(new RegExp(' + $schemaValue + '))' : it.usePattern($schema); + out += 'if ( '; + if ($isData) { + out += ' (' + ($schemaValue) + ' !== undefined && typeof ' + ($schemaValue) + ' != \'string\') || '; + } + out += ' !' + ($regexp) + '.test(' + ($data) + ') ) { '; + var $$outStack = $$outStack || []; + $$outStack.push(out); + out = ''; /* istanbul ignore else */ + if (it.createErrors !== false) { + out += ' { keyword: \'' + ('pattern') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { pattern: '; + if ($isData) { + out += '' + ($schemaValue); + } else { + out += '' + (it.util.toQuotedString($schema)); + } + out += ' } '; + if (it.opts.messages !== false) { + out += ' , message: \'should match pattern "'; + if ($isData) { + out += '\' + ' + ($schemaValue) + ' + \''; + } else { + out += '' + (it.util.escapeQuotes($schema)); + } + out += '"\' '; + } + if (it.opts.verbose) { + out += ' , schema: '; + if ($isData) { + out += 'validate.schema' + ($schemaPath); + } else { + out += '' + (it.util.toQuotedString($schema)); + } + out += ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; + } + out += ' } '; + } else { + out += ' {} '; + } + var __err = out; + out = $$outStack.pop(); + if (!it.compositeRule && $breakOnError) { + /* istanbul ignore if */ + if (it.async) { + out += ' throw new ValidationError([' + (__err) + ']); '; + } else { + out += ' validate.errors = [' + (__err) + ']; return false; '; + } + } else { + out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; + } + out += '} '; + if ($breakOnError) { + out += ' else { '; + } + return out; +} + +},{}],33:[function(require,module,exports){ +'use strict'; +module.exports = function generate_properties(it, $keyword, $ruleType) { + var out = ' '; + var $lvl = it.level; + var $dataLvl = it.dataLevel; + var $schema = it.schema[$keyword]; + var $schemaPath = it.schemaPath + it.util.getProperty($keyword); + var $errSchemaPath = it.errSchemaPath + '/' + $keyword; + var $breakOnError = !it.opts.allErrors; + var $data = 'data' + ($dataLvl || ''); + var $errs = 'errs__' + $lvl; + var $it = it.util.copy(it); + var $closingBraces = ''; + $it.level++; + var $nextValid = 'valid' + $it.level; + var $key = 'key' + $lvl, + $idx = 'idx' + $lvl, + $dataNxt = $it.dataLevel = it.dataLevel + 1, + $nextData = 'data' + $dataNxt, + $dataProperties = 'dataProperties' + $lvl; + var $schemaKeys = Object.keys($schema || {}), + $pProperties = it.schema.patternProperties || {}, + $pPropertyKeys = Object.keys($pProperties), + $aProperties = it.schema.additionalProperties, + $someProperties = $schemaKeys.length || $pPropertyKeys.length, + $noAdditional = $aProperties === false, + $additionalIsSchema = typeof $aProperties == 'object' && Object.keys($aProperties).length, + $removeAdditional = it.opts.removeAdditional, + $checkAdditional = $noAdditional || $additionalIsSchema || $removeAdditional, + $ownProperties = it.opts.ownProperties, + $currentBaseId = it.baseId; + var $required = it.schema.required; + if ($required && !(it.opts.$data && $required.$data) && $required.length < it.opts.loopRequired) var $requiredHash = it.util.toHash($required); + out += 'var ' + ($errs) + ' = errors;var ' + ($nextValid) + ' = true;'; + if ($ownProperties) { + out += ' var ' + ($dataProperties) + ' = undefined;'; + } + if ($checkAdditional) { + if ($ownProperties) { + out += ' ' + ($dataProperties) + ' = ' + ($dataProperties) + ' || Object.keys(' + ($data) + '); for (var ' + ($idx) + '=0; ' + ($idx) + '<' + ($dataProperties) + '.length; ' + ($idx) + '++) { var ' + ($key) + ' = ' + ($dataProperties) + '[' + ($idx) + ']; '; + } else { + out += ' for (var ' + ($key) + ' in ' + ($data) + ') { '; + } + if ($someProperties) { + out += ' var isAdditional' + ($lvl) + ' = !(false '; + if ($schemaKeys.length) { + if ($schemaKeys.length > 8) { + out += ' || validate.schema' + ($schemaPath) + '.hasOwnProperty(' + ($key) + ') '; + } else { + var arr1 = $schemaKeys; + if (arr1) { + var $propertyKey, i1 = -1, + l1 = arr1.length - 1; + while (i1 < l1) { + $propertyKey = arr1[i1 += 1]; + out += ' || ' + ($key) + ' == ' + (it.util.toQuotedString($propertyKey)) + ' '; + } + } + } + } + if ($pPropertyKeys.length) { + var arr2 = $pPropertyKeys; + if (arr2) { + var $pProperty, $i = -1, + l2 = arr2.length - 1; + while ($i < l2) { + $pProperty = arr2[$i += 1]; + out += ' || ' + (it.usePattern($pProperty)) + '.test(' + ($key) + ') '; + } + } + } + out += ' ); if (isAdditional' + ($lvl) + ') { '; + } + if ($removeAdditional == 'all') { + out += ' delete ' + ($data) + '[' + ($key) + ']; '; + } else { + var $currentErrorPath = it.errorPath; + var $additionalProperty = '\' + ' + $key + ' + \''; + if (it.opts._errorDataPathProperty) { + it.errorPath = it.util.getPathExpr(it.errorPath, $key, it.opts.jsonPointers); + } + if ($noAdditional) { + if ($removeAdditional) { + out += ' delete ' + ($data) + '[' + ($key) + ']; '; + } else { + out += ' ' + ($nextValid) + ' = false; '; + var $currErrSchemaPath = $errSchemaPath; + $errSchemaPath = it.errSchemaPath + '/additionalProperties'; + var $$outStack = $$outStack || []; + $$outStack.push(out); + out = ''; /* istanbul ignore else */ + if (it.createErrors !== false) { + out += ' { keyword: \'' + ('additionalProperties') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { additionalProperty: \'' + ($additionalProperty) + '\' } '; + if (it.opts.messages !== false) { + out += ' , message: \''; + if (it.opts._errorDataPathProperty) { + out += 'is an invalid additional property'; + } else { + out += 'should NOT have additional properties'; + } + out += '\' '; + } + if (it.opts.verbose) { + out += ' , schema: false , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; + } + out += ' } '; + } else { + out += ' {} '; + } + var __err = out; + out = $$outStack.pop(); + if (!it.compositeRule && $breakOnError) { + /* istanbul ignore if */ + if (it.async) { + out += ' throw new ValidationError([' + (__err) + ']); '; + } else { + out += ' validate.errors = [' + (__err) + ']; return false; '; + } + } else { + out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; + } + $errSchemaPath = $currErrSchemaPath; + if ($breakOnError) { + out += ' break; '; + } + } + } else if ($additionalIsSchema) { + if ($removeAdditional == 'failing') { + out += ' var ' + ($errs) + ' = errors; '; + var $wasComposite = it.compositeRule; + it.compositeRule = $it.compositeRule = true; + $it.schema = $aProperties; + $it.schemaPath = it.schemaPath + '.additionalProperties'; + $it.errSchemaPath = it.errSchemaPath + '/additionalProperties'; + $it.errorPath = it.opts._errorDataPathProperty ? it.errorPath : it.util.getPathExpr(it.errorPath, $key, it.opts.jsonPointers); + var $passData = $data + '[' + $key + ']'; + $it.dataPathArr[$dataNxt] = $key; + var $code = it.validate($it); + $it.baseId = $currentBaseId; + if (it.util.varOccurences($code, $nextData) < 2) { + out += ' ' + (it.util.varReplace($code, $nextData, $passData)) + ' '; + } else { + out += ' var ' + ($nextData) + ' = ' + ($passData) + '; ' + ($code) + ' '; + } + out += ' if (!' + ($nextValid) + ') { errors = ' + ($errs) + '; if (validate.errors !== null) { if (errors) validate.errors.length = errors; else validate.errors = null; } delete ' + ($data) + '[' + ($key) + ']; } '; + it.compositeRule = $it.compositeRule = $wasComposite; + } else { + $it.schema = $aProperties; + $it.schemaPath = it.schemaPath + '.additionalProperties'; + $it.errSchemaPath = it.errSchemaPath + '/additionalProperties'; + $it.errorPath = it.opts._errorDataPathProperty ? it.errorPath : it.util.getPathExpr(it.errorPath, $key, it.opts.jsonPointers); + var $passData = $data + '[' + $key + ']'; + $it.dataPathArr[$dataNxt] = $key; + var $code = it.validate($it); + $it.baseId = $currentBaseId; + if (it.util.varOccurences($code, $nextData) < 2) { + out += ' ' + (it.util.varReplace($code, $nextData, $passData)) + ' '; + } else { + out += ' var ' + ($nextData) + ' = ' + ($passData) + '; ' + ($code) + ' '; + } + if ($breakOnError) { + out += ' if (!' + ($nextValid) + ') break; '; + } + } + } + it.errorPath = $currentErrorPath; + } + if ($someProperties) { + out += ' } '; + } + out += ' } '; + if ($breakOnError) { + out += ' if (' + ($nextValid) + ') { '; + $closingBraces += '}'; + } + } + var $useDefaults = it.opts.useDefaults && !it.compositeRule; + if ($schemaKeys.length) { + var arr3 = $schemaKeys; + if (arr3) { + var $propertyKey, i3 = -1, + l3 = arr3.length - 1; + while (i3 < l3) { + $propertyKey = arr3[i3 += 1]; + var $sch = $schema[$propertyKey]; + if ((it.opts.strictKeywords ? typeof $sch == 'object' && Object.keys($sch).length > 0 : it.util.schemaHasRules($sch, it.RULES.all))) { + var $prop = it.util.getProperty($propertyKey), + $passData = $data + $prop, + $hasDefault = $useDefaults && $sch.default !== undefined; + $it.schema = $sch; + $it.schemaPath = $schemaPath + $prop; + $it.errSchemaPath = $errSchemaPath + '/' + it.util.escapeFragment($propertyKey); + $it.errorPath = it.util.getPath(it.errorPath, $propertyKey, it.opts.jsonPointers); + $it.dataPathArr[$dataNxt] = it.util.toQuotedString($propertyKey); + var $code = it.validate($it); + $it.baseId = $currentBaseId; + if (it.util.varOccurences($code, $nextData) < 2) { + $code = it.util.varReplace($code, $nextData, $passData); + var $useData = $passData; + } else { + var $useData = $nextData; + out += ' var ' + ($nextData) + ' = ' + ($passData) + '; '; + } + if ($hasDefault) { + out += ' ' + ($code) + ' '; + } else { + if ($requiredHash && $requiredHash[$propertyKey]) { + out += ' if ( ' + ($useData) + ' === undefined '; + if ($ownProperties) { + out += ' || ! Object.prototype.hasOwnProperty.call(' + ($data) + ', \'' + (it.util.escapeQuotes($propertyKey)) + '\') '; + } + out += ') { ' + ($nextValid) + ' = false; '; + var $currentErrorPath = it.errorPath, + $currErrSchemaPath = $errSchemaPath, + $missingProperty = it.util.escapeQuotes($propertyKey); + if (it.opts._errorDataPathProperty) { + it.errorPath = it.util.getPath($currentErrorPath, $propertyKey, it.opts.jsonPointers); + } + $errSchemaPath = it.errSchemaPath + '/required'; + var $$outStack = $$outStack || []; + $$outStack.push(out); + out = ''; /* istanbul ignore else */ + if (it.createErrors !== false) { + out += ' { keyword: \'' + ('required') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { missingProperty: \'' + ($missingProperty) + '\' } '; + if (it.opts.messages !== false) { + out += ' , message: \''; + if (it.opts._errorDataPathProperty) { + out += 'is a required property'; + } else { + out += 'should have required property \\\'' + ($missingProperty) + '\\\''; + } + out += '\' '; + } + if (it.opts.verbose) { + out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; + } + out += ' } '; + } else { + out += ' {} '; + } + var __err = out; + out = $$outStack.pop(); + if (!it.compositeRule && $breakOnError) { + /* istanbul ignore if */ + if (it.async) { + out += ' throw new ValidationError([' + (__err) + ']); '; + } else { + out += ' validate.errors = [' + (__err) + ']; return false; '; + } + } else { + out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; + } + $errSchemaPath = $currErrSchemaPath; + it.errorPath = $currentErrorPath; + out += ' } else { '; + } else { + if ($breakOnError) { + out += ' if ( ' + ($useData) + ' === undefined '; + if ($ownProperties) { + out += ' || ! Object.prototype.hasOwnProperty.call(' + ($data) + ', \'' + (it.util.escapeQuotes($propertyKey)) + '\') '; + } + out += ') { ' + ($nextValid) + ' = true; } else { '; + } else { + out += ' if (' + ($useData) + ' !== undefined '; + if ($ownProperties) { + out += ' && Object.prototype.hasOwnProperty.call(' + ($data) + ', \'' + (it.util.escapeQuotes($propertyKey)) + '\') '; + } + out += ' ) { '; + } + } + out += ' ' + ($code) + ' } '; + } + } + if ($breakOnError) { + out += ' if (' + ($nextValid) + ') { '; + $closingBraces += '}'; + } + } + } + } + if ($pPropertyKeys.length) { + var arr4 = $pPropertyKeys; + if (arr4) { + var $pProperty, i4 = -1, + l4 = arr4.length - 1; + while (i4 < l4) { + $pProperty = arr4[i4 += 1]; + var $sch = $pProperties[$pProperty]; + if ((it.opts.strictKeywords ? typeof $sch == 'object' && Object.keys($sch).length > 0 : it.util.schemaHasRules($sch, it.RULES.all))) { + $it.schema = $sch; + $it.schemaPath = it.schemaPath + '.patternProperties' + it.util.getProperty($pProperty); + $it.errSchemaPath = it.errSchemaPath + '/patternProperties/' + it.util.escapeFragment($pProperty); + if ($ownProperties) { + out += ' ' + ($dataProperties) + ' = ' + ($dataProperties) + ' || Object.keys(' + ($data) + '); for (var ' + ($idx) + '=0; ' + ($idx) + '<' + ($dataProperties) + '.length; ' + ($idx) + '++) { var ' + ($key) + ' = ' + ($dataProperties) + '[' + ($idx) + ']; '; + } else { + out += ' for (var ' + ($key) + ' in ' + ($data) + ') { '; + } + out += ' if (' + (it.usePattern($pProperty)) + '.test(' + ($key) + ')) { '; + $it.errorPath = it.util.getPathExpr(it.errorPath, $key, it.opts.jsonPointers); + var $passData = $data + '[' + $key + ']'; + $it.dataPathArr[$dataNxt] = $key; + var $code = it.validate($it); + $it.baseId = $currentBaseId; + if (it.util.varOccurences($code, $nextData) < 2) { + out += ' ' + (it.util.varReplace($code, $nextData, $passData)) + ' '; + } else { + out += ' var ' + ($nextData) + ' = ' + ($passData) + '; ' + ($code) + ' '; + } + if ($breakOnError) { + out += ' if (!' + ($nextValid) + ') break; '; + } + out += ' } '; + if ($breakOnError) { + out += ' else ' + ($nextValid) + ' = true; '; + } + out += ' } '; + if ($breakOnError) { + out += ' if (' + ($nextValid) + ') { '; + $closingBraces += '}'; + } + } + } + } + } + if ($breakOnError) { + out += ' ' + ($closingBraces) + ' if (' + ($errs) + ' == errors) {'; + } + out = it.util.cleanUpCode(out); + return out; +} + +},{}],34:[function(require,module,exports){ +'use strict'; +module.exports = function generate_propertyNames(it, $keyword, $ruleType) { + var out = ' '; + var $lvl = it.level; + var $dataLvl = it.dataLevel; + var $schema = it.schema[$keyword]; + var $schemaPath = it.schemaPath + it.util.getProperty($keyword); + var $errSchemaPath = it.errSchemaPath + '/' + $keyword; + var $breakOnError = !it.opts.allErrors; + var $data = 'data' + ($dataLvl || ''); + var $errs = 'errs__' + $lvl; + var $it = it.util.copy(it); + var $closingBraces = ''; + $it.level++; + var $nextValid = 'valid' + $it.level; + out += 'var ' + ($errs) + ' = errors;'; + if ((it.opts.strictKeywords ? typeof $schema == 'object' && Object.keys($schema).length > 0 : it.util.schemaHasRules($schema, it.RULES.all))) { + $it.schema = $schema; + $it.schemaPath = $schemaPath; + $it.errSchemaPath = $errSchemaPath; + var $key = 'key' + $lvl, + $idx = 'idx' + $lvl, + $i = 'i' + $lvl, + $invalidName = '\' + ' + $key + ' + \'', + $dataNxt = $it.dataLevel = it.dataLevel + 1, + $nextData = 'data' + $dataNxt, + $dataProperties = 'dataProperties' + $lvl, + $ownProperties = it.opts.ownProperties, + $currentBaseId = it.baseId; + if ($ownProperties) { + out += ' var ' + ($dataProperties) + ' = undefined; '; + } + if ($ownProperties) { + out += ' ' + ($dataProperties) + ' = ' + ($dataProperties) + ' || Object.keys(' + ($data) + '); for (var ' + ($idx) + '=0; ' + ($idx) + '<' + ($dataProperties) + '.length; ' + ($idx) + '++) { var ' + ($key) + ' = ' + ($dataProperties) + '[' + ($idx) + ']; '; + } else { + out += ' for (var ' + ($key) + ' in ' + ($data) + ') { '; + } + out += ' var startErrs' + ($lvl) + ' = errors; '; + var $passData = $key; + var $wasComposite = it.compositeRule; + it.compositeRule = $it.compositeRule = true; + var $code = it.validate($it); + $it.baseId = $currentBaseId; + if (it.util.varOccurences($code, $nextData) < 2) { + out += ' ' + (it.util.varReplace($code, $nextData, $passData)) + ' '; + } else { + out += ' var ' + ($nextData) + ' = ' + ($passData) + '; ' + ($code) + ' '; + } + it.compositeRule = $it.compositeRule = $wasComposite; + out += ' if (!' + ($nextValid) + ') { for (var ' + ($i) + '=startErrs' + ($lvl) + '; ' + ($i) + ' 0 : it.util.schemaHasRules($propertySch, it.RULES.all)))) { + $required[$required.length] = $property; + } + } + } + } else { + var $required = $schema; + } + } + if ($isData || $required.length) { + var $currentErrorPath = it.errorPath, + $loopRequired = $isData || $required.length >= it.opts.loopRequired, + $ownProperties = it.opts.ownProperties; + if ($breakOnError) { + out += ' var missing' + ($lvl) + '; '; + if ($loopRequired) { + if (!$isData) { + out += ' var ' + ($vSchema) + ' = validate.schema' + ($schemaPath) + '; '; + } + var $i = 'i' + $lvl, + $propertyPath = 'schema' + $lvl + '[' + $i + ']', + $missingProperty = '\' + ' + $propertyPath + ' + \''; + if (it.opts._errorDataPathProperty) { + it.errorPath = it.util.getPathExpr($currentErrorPath, $propertyPath, it.opts.jsonPointers); + } + out += ' var ' + ($valid) + ' = true; '; + if ($isData) { + out += ' if (schema' + ($lvl) + ' === undefined) ' + ($valid) + ' = true; else if (!Array.isArray(schema' + ($lvl) + ')) ' + ($valid) + ' = false; else {'; + } + out += ' for (var ' + ($i) + ' = 0; ' + ($i) + ' < ' + ($vSchema) + '.length; ' + ($i) + '++) { ' + ($valid) + ' = ' + ($data) + '[' + ($vSchema) + '[' + ($i) + ']] !== undefined '; + if ($ownProperties) { + out += ' && Object.prototype.hasOwnProperty.call(' + ($data) + ', ' + ($vSchema) + '[' + ($i) + ']) '; + } + out += '; if (!' + ($valid) + ') break; } '; + if ($isData) { + out += ' } '; + } + out += ' if (!' + ($valid) + ') { '; + var $$outStack = $$outStack || []; + $$outStack.push(out); + out = ''; /* istanbul ignore else */ + if (it.createErrors !== false) { + out += ' { keyword: \'' + ('required') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { missingProperty: \'' + ($missingProperty) + '\' } '; + if (it.opts.messages !== false) { + out += ' , message: \''; + if (it.opts._errorDataPathProperty) { + out += 'is a required property'; + } else { + out += 'should have required property \\\'' + ($missingProperty) + '\\\''; + } + out += '\' '; + } + if (it.opts.verbose) { + out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; + } + out += ' } '; + } else { + out += ' {} '; + } + var __err = out; + out = $$outStack.pop(); + if (!it.compositeRule && $breakOnError) { + /* istanbul ignore if */ + if (it.async) { + out += ' throw new ValidationError([' + (__err) + ']); '; + } else { + out += ' validate.errors = [' + (__err) + ']; return false; '; + } + } else { + out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; + } + out += ' } else { '; + } else { + out += ' if ( '; + var arr2 = $required; + if (arr2) { + var $propertyKey, $i = -1, + l2 = arr2.length - 1; + while ($i < l2) { + $propertyKey = arr2[$i += 1]; + if ($i) { + out += ' || '; + } + var $prop = it.util.getProperty($propertyKey), + $useData = $data + $prop; + out += ' ( ( ' + ($useData) + ' === undefined '; + if ($ownProperties) { + out += ' || ! Object.prototype.hasOwnProperty.call(' + ($data) + ', \'' + (it.util.escapeQuotes($propertyKey)) + '\') '; + } + out += ') && (missing' + ($lvl) + ' = ' + (it.util.toQuotedString(it.opts.jsonPointers ? $propertyKey : $prop)) + ') ) '; + } + } + out += ') { '; + var $propertyPath = 'missing' + $lvl, + $missingProperty = '\' + ' + $propertyPath + ' + \''; + if (it.opts._errorDataPathProperty) { + it.errorPath = it.opts.jsonPointers ? it.util.getPathExpr($currentErrorPath, $propertyPath, true) : $currentErrorPath + ' + ' + $propertyPath; + } + var $$outStack = $$outStack || []; + $$outStack.push(out); + out = ''; /* istanbul ignore else */ + if (it.createErrors !== false) { + out += ' { keyword: \'' + ('required') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { missingProperty: \'' + ($missingProperty) + '\' } '; + if (it.opts.messages !== false) { + out += ' , message: \''; + if (it.opts._errorDataPathProperty) { + out += 'is a required property'; + } else { + out += 'should have required property \\\'' + ($missingProperty) + '\\\''; + } + out += '\' '; + } + if (it.opts.verbose) { + out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; + } + out += ' } '; + } else { + out += ' {} '; + } + var __err = out; + out = $$outStack.pop(); + if (!it.compositeRule && $breakOnError) { + /* istanbul ignore if */ + if (it.async) { + out += ' throw new ValidationError([' + (__err) + ']); '; + } else { + out += ' validate.errors = [' + (__err) + ']; return false; '; + } + } else { + out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; + } + out += ' } else { '; + } + } else { + if ($loopRequired) { + if (!$isData) { + out += ' var ' + ($vSchema) + ' = validate.schema' + ($schemaPath) + '; '; + } + var $i = 'i' + $lvl, + $propertyPath = 'schema' + $lvl + '[' + $i + ']', + $missingProperty = '\' + ' + $propertyPath + ' + \''; + if (it.opts._errorDataPathProperty) { + it.errorPath = it.util.getPathExpr($currentErrorPath, $propertyPath, it.opts.jsonPointers); + } + if ($isData) { + out += ' if (' + ($vSchema) + ' && !Array.isArray(' + ($vSchema) + ')) { var err = '; /* istanbul ignore else */ + if (it.createErrors !== false) { + out += ' { keyword: \'' + ('required') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { missingProperty: \'' + ($missingProperty) + '\' } '; + if (it.opts.messages !== false) { + out += ' , message: \''; + if (it.opts._errorDataPathProperty) { + out += 'is a required property'; + } else { + out += 'should have required property \\\'' + ($missingProperty) + '\\\''; + } + out += '\' '; + } + if (it.opts.verbose) { + out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; + } + out += ' } '; + } else { + out += ' {} '; + } + out += '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; } else if (' + ($vSchema) + ' !== undefined) { '; + } + out += ' for (var ' + ($i) + ' = 0; ' + ($i) + ' < ' + ($vSchema) + '.length; ' + ($i) + '++) { if (' + ($data) + '[' + ($vSchema) + '[' + ($i) + ']] === undefined '; + if ($ownProperties) { + out += ' || ! Object.prototype.hasOwnProperty.call(' + ($data) + ', ' + ($vSchema) + '[' + ($i) + ']) '; + } + out += ') { var err = '; /* istanbul ignore else */ + if (it.createErrors !== false) { + out += ' { keyword: \'' + ('required') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { missingProperty: \'' + ($missingProperty) + '\' } '; + if (it.opts.messages !== false) { + out += ' , message: \''; + if (it.opts._errorDataPathProperty) { + out += 'is a required property'; + } else { + out += 'should have required property \\\'' + ($missingProperty) + '\\\''; + } + out += '\' '; + } + if (it.opts.verbose) { + out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; + } + out += ' } '; + } else { + out += ' {} '; + } + out += '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; } } '; + if ($isData) { + out += ' } '; + } + } else { + var arr3 = $required; + if (arr3) { + var $propertyKey, i3 = -1, + l3 = arr3.length - 1; + while (i3 < l3) { + $propertyKey = arr3[i3 += 1]; + var $prop = it.util.getProperty($propertyKey), + $missingProperty = it.util.escapeQuotes($propertyKey), + $useData = $data + $prop; + if (it.opts._errorDataPathProperty) { + it.errorPath = it.util.getPath($currentErrorPath, $propertyKey, it.opts.jsonPointers); + } + out += ' if ( ' + ($useData) + ' === undefined '; + if ($ownProperties) { + out += ' || ! Object.prototype.hasOwnProperty.call(' + ($data) + ', \'' + (it.util.escapeQuotes($propertyKey)) + '\') '; + } + out += ') { var err = '; /* istanbul ignore else */ + if (it.createErrors !== false) { + out += ' { keyword: \'' + ('required') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { missingProperty: \'' + ($missingProperty) + '\' } '; + if (it.opts.messages !== false) { + out += ' , message: \''; + if (it.opts._errorDataPathProperty) { + out += 'is a required property'; + } else { + out += 'should have required property \\\'' + ($missingProperty) + '\\\''; + } + out += '\' '; + } + if (it.opts.verbose) { + out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; + } + out += ' } '; + } else { + out += ' {} '; + } + out += '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; } '; + } + } + } + } + it.errorPath = $currentErrorPath; + } else if ($breakOnError) { + out += ' if (true) {'; + } + return out; +} + +},{}],37:[function(require,module,exports){ +'use strict'; +module.exports = function generate_uniqueItems(it, $keyword, $ruleType) { + var out = ' '; + var $lvl = it.level; + var $dataLvl = it.dataLevel; + var $schema = it.schema[$keyword]; + var $schemaPath = it.schemaPath + it.util.getProperty($keyword); + var $errSchemaPath = it.errSchemaPath + '/' + $keyword; + var $breakOnError = !it.opts.allErrors; + var $data = 'data' + ($dataLvl || ''); + var $valid = 'valid' + $lvl; + var $isData = it.opts.$data && $schema && $schema.$data, + $schemaValue; + if ($isData) { + out += ' var schema' + ($lvl) + ' = ' + (it.util.getData($schema.$data, $dataLvl, it.dataPathArr)) + '; '; + $schemaValue = 'schema' + $lvl; + } else { + $schemaValue = $schema; + } + if (($schema || $isData) && it.opts.uniqueItems !== false) { + if ($isData) { + out += ' var ' + ($valid) + '; if (' + ($schemaValue) + ' === false || ' + ($schemaValue) + ' === undefined) ' + ($valid) + ' = true; else if (typeof ' + ($schemaValue) + ' != \'boolean\') ' + ($valid) + ' = false; else { '; + } + out += ' var i = ' + ($data) + '.length , ' + ($valid) + ' = true , j; if (i > 1) { '; + var $itemType = it.schema.items && it.schema.items.type, + $typeIsArray = Array.isArray($itemType); + if (!$itemType || $itemType == 'object' || $itemType == 'array' || ($typeIsArray && ($itemType.indexOf('object') >= 0 || $itemType.indexOf('array') >= 0))) { + out += ' outer: for (;i--;) { for (j = i; j--;) { if (equal(' + ($data) + '[i], ' + ($data) + '[j])) { ' + ($valid) + ' = false; break outer; } } } '; + } else { + out += ' var itemIndices = {}, item; for (;i--;) { var item = ' + ($data) + '[i]; '; + var $method = 'checkDataType' + ($typeIsArray ? 's' : ''); + out += ' if (' + (it.util[$method]($itemType, 'item', true)) + ') continue; '; + if ($typeIsArray) { + out += ' if (typeof item == \'string\') item = \'"\' + item; '; + } + out += ' if (typeof itemIndices[item] == \'number\') { ' + ($valid) + ' = false; j = itemIndices[item]; break; } itemIndices[item] = i; } '; + } + out += ' } '; + if ($isData) { + out += ' } '; + } + out += ' if (!' + ($valid) + ') { '; + var $$outStack = $$outStack || []; + $$outStack.push(out); + out = ''; /* istanbul ignore else */ + if (it.createErrors !== false) { + out += ' { keyword: \'' + ('uniqueItems') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { i: i, j: j } '; + if (it.opts.messages !== false) { + out += ' , message: \'should NOT have duplicate items (items ## \' + j + \' and \' + i + \' are identical)\' '; + } + if (it.opts.verbose) { + out += ' , schema: '; + if ($isData) { + out += 'validate.schema' + ($schemaPath); + } else { + out += '' + ($schema); + } + out += ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; + } + out += ' } '; + } else { + out += ' {} '; + } + var __err = out; + out = $$outStack.pop(); + if (!it.compositeRule && $breakOnError) { + /* istanbul ignore if */ + if (it.async) { + out += ' throw new ValidationError([' + (__err) + ']); '; + } else { + out += ' validate.errors = [' + (__err) + ']; return false; '; + } + } else { + out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; + } + out += ' } '; + if ($breakOnError) { + out += ' else { '; + } + } else { + if ($breakOnError) { + out += ' if (true) { '; + } + } + return out; +} + +},{}],38:[function(require,module,exports){ +'use strict'; +module.exports = function generate_validate(it, $keyword, $ruleType) { + var out = ''; + var $async = it.schema.$async === true, + $refKeywords = it.util.schemaHasRulesExcept(it.schema, it.RULES.all, '$ref'), + $id = it.self._getId(it.schema); + if (it.opts.strictKeywords) { + var $unknownKwd = it.util.schemaUnknownRules(it.schema, it.RULES.keywords); + if ($unknownKwd) { + var $keywordsMsg = 'unknown keyword: ' + $unknownKwd; + if (it.opts.strictKeywords === 'log') it.logger.warn($keywordsMsg); + else throw new Error($keywordsMsg); + } + } + if (it.isTop) { + out += ' var validate = '; + if ($async) { + it.async = true; + out += 'async '; + } + out += 'function(data, dataPath, parentData, parentDataProperty, rootData) { \'use strict\'; '; + if ($id && (it.opts.sourceCode || it.opts.processCode)) { + out += ' ' + ('/\*# sourceURL=' + $id + ' */') + ' '; + } + } + if (typeof it.schema == 'boolean' || !($refKeywords || it.schema.$ref)) { + var $keyword = 'false schema'; + var $lvl = it.level; + var $dataLvl = it.dataLevel; + var $schema = it.schema[$keyword]; + var $schemaPath = it.schemaPath + it.util.getProperty($keyword); + var $errSchemaPath = it.errSchemaPath + '/' + $keyword; + var $breakOnError = !it.opts.allErrors; + var $errorKeyword; + var $data = 'data' + ($dataLvl || ''); + var $valid = 'valid' + $lvl; + if (it.schema === false) { + if (it.isTop) { + $breakOnError = true; + } else { + out += ' var ' + ($valid) + ' = false; '; + } + var $$outStack = $$outStack || []; + $$outStack.push(out); + out = ''; /* istanbul ignore else */ + if (it.createErrors !== false) { + out += ' { keyword: \'' + ($errorKeyword || 'false schema') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: {} '; + if (it.opts.messages !== false) { + out += ' , message: \'boolean schema is false\' '; + } + if (it.opts.verbose) { + out += ' , schema: false , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; + } + out += ' } '; + } else { + out += ' {} '; + } + var __err = out; + out = $$outStack.pop(); + if (!it.compositeRule && $breakOnError) { + /* istanbul ignore if */ + if (it.async) { + out += ' throw new ValidationError([' + (__err) + ']); '; + } else { + out += ' validate.errors = [' + (__err) + ']; return false; '; + } + } else { + out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; + } + } else { + if (it.isTop) { + if ($async) { + out += ' return data; '; + } else { + out += ' validate.errors = null; return true; '; + } + } else { + out += ' var ' + ($valid) + ' = true; '; + } + } + if (it.isTop) { + out += ' }; return validate; '; + } + return out; + } + if (it.isTop) { + var $top = it.isTop, + $lvl = it.level = 0, + $dataLvl = it.dataLevel = 0, + $data = 'data'; + it.rootId = it.resolve.fullPath(it.self._getId(it.root.schema)); + it.baseId = it.baseId || it.rootId; + delete it.isTop; + it.dataPathArr = [undefined]; + if (it.schema.default !== undefined && it.opts.useDefaults && it.opts.strictDefaults) { + var $defaultMsg = 'default is ignored in the schema root'; + if (it.opts.strictDefaults === 'log') it.logger.warn($defaultMsg); + else throw new Error($defaultMsg); + } + out += ' var vErrors = null; '; + out += ' var errors = 0; '; + out += ' if (rootData === undefined) rootData = data; '; + } else { + var $lvl = it.level, + $dataLvl = it.dataLevel, + $data = 'data' + ($dataLvl || ''); + if ($id) it.baseId = it.resolve.url(it.baseId, $id); + if ($async && !it.async) throw new Error('async schema in sync schema'); + out += ' var errs_' + ($lvl) + ' = errors;'; + } + var $valid = 'valid' + $lvl, + $breakOnError = !it.opts.allErrors, + $closingBraces1 = '', + $closingBraces2 = ''; + var $errorKeyword; + var $typeSchema = it.schema.type, + $typeIsArray = Array.isArray($typeSchema); + if ($typeSchema && it.opts.nullable && it.schema.nullable === true) { + if ($typeIsArray) { + if ($typeSchema.indexOf('null') == -1) $typeSchema = $typeSchema.concat('null'); + } else if ($typeSchema != 'null') { + $typeSchema = [$typeSchema, 'null']; + $typeIsArray = true; + } + } + if ($typeIsArray && $typeSchema.length == 1) { + $typeSchema = $typeSchema[0]; + $typeIsArray = false; + } + if (it.schema.$ref && $refKeywords) { + if (it.opts.extendRefs == 'fail') { + throw new Error('$ref: validation keywords used in schema at path "' + it.errSchemaPath + '" (see option extendRefs)'); + } else if (it.opts.extendRefs !== true) { + $refKeywords = false; + it.logger.warn('$ref: keywords ignored in schema at path "' + it.errSchemaPath + '"'); + } + } + if (it.schema.$comment && it.opts.$comment) { + out += ' ' + (it.RULES.all.$comment.code(it, '$comment')); + } + if ($typeSchema) { + if (it.opts.coerceTypes) { + var $coerceToTypes = it.util.coerceToTypes(it.opts.coerceTypes, $typeSchema); + } + var $rulesGroup = it.RULES.types[$typeSchema]; + if ($coerceToTypes || $typeIsArray || $rulesGroup === true || ($rulesGroup && !$shouldUseGroup($rulesGroup))) { + var $schemaPath = it.schemaPath + '.type', + $errSchemaPath = it.errSchemaPath + '/type'; + var $schemaPath = it.schemaPath + '.type', + $errSchemaPath = it.errSchemaPath + '/type', + $method = $typeIsArray ? 'checkDataTypes' : 'checkDataType'; + out += ' if (' + (it.util[$method]($typeSchema, $data, true)) + ') { '; + if ($coerceToTypes) { + var $dataType = 'dataType' + $lvl, + $coerced = 'coerced' + $lvl; + out += ' var ' + ($dataType) + ' = typeof ' + ($data) + '; '; + if (it.opts.coerceTypes == 'array') { + out += ' if (' + ($dataType) + ' == \'object\' && Array.isArray(' + ($data) + ')) ' + ($dataType) + ' = \'array\'; '; + } + out += ' var ' + ($coerced) + ' = undefined; '; + var $bracesCoercion = ''; + var arr1 = $coerceToTypes; + if (arr1) { + var $type, $i = -1, + l1 = arr1.length - 1; + while ($i < l1) { + $type = arr1[$i += 1]; + if ($i) { + out += ' if (' + ($coerced) + ' === undefined) { '; + $bracesCoercion += '}'; + } + if (it.opts.coerceTypes == 'array' && $type != 'array') { + out += ' if (' + ($dataType) + ' == \'array\' && ' + ($data) + '.length == 1) { ' + ($coerced) + ' = ' + ($data) + ' = ' + ($data) + '[0]; ' + ($dataType) + ' = typeof ' + ($data) + '; } '; + } + if ($type == 'string') { + out += ' if (' + ($dataType) + ' == \'number\' || ' + ($dataType) + ' == \'boolean\') ' + ($coerced) + ' = \'\' + ' + ($data) + '; else if (' + ($data) + ' === null) ' + ($coerced) + ' = \'\'; '; + } else if ($type == 'number' || $type == 'integer') { + out += ' if (' + ($dataType) + ' == \'boolean\' || ' + ($data) + ' === null || (' + ($dataType) + ' == \'string\' && ' + ($data) + ' && ' + ($data) + ' == +' + ($data) + ' '; + if ($type == 'integer') { + out += ' && !(' + ($data) + ' % 1)'; + } + out += ')) ' + ($coerced) + ' = +' + ($data) + '; '; + } else if ($type == 'boolean') { + out += ' if (' + ($data) + ' === \'false\' || ' + ($data) + ' === 0 || ' + ($data) + ' === null) ' + ($coerced) + ' = false; else if (' + ($data) + ' === \'true\' || ' + ($data) + ' === 1) ' + ($coerced) + ' = true; '; + } else if ($type == 'null') { + out += ' if (' + ($data) + ' === \'\' || ' + ($data) + ' === 0 || ' + ($data) + ' === false) ' + ($coerced) + ' = null; '; + } else if (it.opts.coerceTypes == 'array' && $type == 'array') { + out += ' if (' + ($dataType) + ' == \'string\' || ' + ($dataType) + ' == \'number\' || ' + ($dataType) + ' == \'boolean\' || ' + ($data) + ' == null) ' + ($coerced) + ' = [' + ($data) + ']; '; + } + } + } + out += ' ' + ($bracesCoercion) + ' if (' + ($coerced) + ' === undefined) { '; + var $$outStack = $$outStack || []; + $$outStack.push(out); + out = ''; /* istanbul ignore else */ + if (it.createErrors !== false) { + out += ' { keyword: \'' + ($errorKeyword || 'type') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { type: \''; + if ($typeIsArray) { + out += '' + ($typeSchema.join(",")); + } else { + out += '' + ($typeSchema); + } + out += '\' } '; + if (it.opts.messages !== false) { + out += ' , message: \'should be '; + if ($typeIsArray) { + out += '' + ($typeSchema.join(",")); + } else { + out += '' + ($typeSchema); + } + out += '\' '; + } + if (it.opts.verbose) { + out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; + } + out += ' } '; + } else { + out += ' {} '; + } + var __err = out; + out = $$outStack.pop(); + if (!it.compositeRule && $breakOnError) { + /* istanbul ignore if */ + if (it.async) { + out += ' throw new ValidationError([' + (__err) + ']); '; + } else { + out += ' validate.errors = [' + (__err) + ']; return false; '; + } + } else { + out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; + } + out += ' } else { '; + var $parentData = $dataLvl ? 'data' + (($dataLvl - 1) || '') : 'parentData', + $parentDataProperty = $dataLvl ? it.dataPathArr[$dataLvl] : 'parentDataProperty'; + out += ' ' + ($data) + ' = ' + ($coerced) + '; '; + if (!$dataLvl) { + out += 'if (' + ($parentData) + ' !== undefined)'; + } + out += ' ' + ($parentData) + '[' + ($parentDataProperty) + '] = ' + ($coerced) + '; } '; + } else { + var $$outStack = $$outStack || []; + $$outStack.push(out); + out = ''; /* istanbul ignore else */ + if (it.createErrors !== false) { + out += ' { keyword: \'' + ($errorKeyword || 'type') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { type: \''; + if ($typeIsArray) { + out += '' + ($typeSchema.join(",")); + } else { + out += '' + ($typeSchema); + } + out += '\' } '; + if (it.opts.messages !== false) { + out += ' , message: \'should be '; + if ($typeIsArray) { + out += '' + ($typeSchema.join(",")); + } else { + out += '' + ($typeSchema); + } + out += '\' '; + } + if (it.opts.verbose) { + out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; + } + out += ' } '; + } else { + out += ' {} '; + } + var __err = out; + out = $$outStack.pop(); + if (!it.compositeRule && $breakOnError) { + /* istanbul ignore if */ + if (it.async) { + out += ' throw new ValidationError([' + (__err) + ']); '; + } else { + out += ' validate.errors = [' + (__err) + ']; return false; '; + } + } else { + out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; + } + } + out += ' } '; + } + } + if (it.schema.$ref && !$refKeywords) { + out += ' ' + (it.RULES.all.$ref.code(it, '$ref')) + ' '; + if ($breakOnError) { + out += ' } if (errors === '; + if ($top) { + out += '0'; + } else { + out += 'errs_' + ($lvl); + } + out += ') { '; + $closingBraces2 += '}'; + } + } else { + var arr2 = it.RULES; + if (arr2) { + var $rulesGroup, i2 = -1, + l2 = arr2.length - 1; + while (i2 < l2) { + $rulesGroup = arr2[i2 += 1]; + if ($shouldUseGroup($rulesGroup)) { + if ($rulesGroup.type) { + out += ' if (' + (it.util.checkDataType($rulesGroup.type, $data)) + ') { '; + } + if (it.opts.useDefaults) { + if ($rulesGroup.type == 'object' && it.schema.properties) { + var $schema = it.schema.properties, + $schemaKeys = Object.keys($schema); + var arr3 = $schemaKeys; + if (arr3) { + var $propertyKey, i3 = -1, + l3 = arr3.length - 1; + while (i3 < l3) { + $propertyKey = arr3[i3 += 1]; + var $sch = $schema[$propertyKey]; + if ($sch.default !== undefined) { + var $passData = $data + it.util.getProperty($propertyKey); + if (it.compositeRule) { + if (it.opts.strictDefaults) { + var $defaultMsg = 'default is ignored for: ' + $passData; + if (it.opts.strictDefaults === 'log') it.logger.warn($defaultMsg); + else throw new Error($defaultMsg); + } + } else { + out += ' if (' + ($passData) + ' === undefined '; + if (it.opts.useDefaults == 'empty') { + out += ' || ' + ($passData) + ' === null || ' + ($passData) + ' === \'\' '; + } + out += ' ) ' + ($passData) + ' = '; + if (it.opts.useDefaults == 'shared') { + out += ' ' + (it.useDefault($sch.default)) + ' '; + } else { + out += ' ' + (JSON.stringify($sch.default)) + ' '; + } + out += '; '; + } + } + } + } + } else if ($rulesGroup.type == 'array' && Array.isArray(it.schema.items)) { + var arr4 = it.schema.items; + if (arr4) { + var $sch, $i = -1, + l4 = arr4.length - 1; + while ($i < l4) { + $sch = arr4[$i += 1]; + if ($sch.default !== undefined) { + var $passData = $data + '[' + $i + ']'; + if (it.compositeRule) { + if (it.opts.strictDefaults) { + var $defaultMsg = 'default is ignored for: ' + $passData; + if (it.opts.strictDefaults === 'log') it.logger.warn($defaultMsg); + else throw new Error($defaultMsg); + } + } else { + out += ' if (' + ($passData) + ' === undefined '; + if (it.opts.useDefaults == 'empty') { + out += ' || ' + ($passData) + ' === null || ' + ($passData) + ' === \'\' '; + } + out += ' ) ' + ($passData) + ' = '; + if (it.opts.useDefaults == 'shared') { + out += ' ' + (it.useDefault($sch.default)) + ' '; + } else { + out += ' ' + (JSON.stringify($sch.default)) + ' '; + } + out += '; '; + } + } + } + } + } + } + var arr5 = $rulesGroup.rules; + if (arr5) { + var $rule, i5 = -1, + l5 = arr5.length - 1; + while (i5 < l5) { + $rule = arr5[i5 += 1]; + if ($shouldUseRule($rule)) { + var $code = $rule.code(it, $rule.keyword, $rulesGroup.type); + if ($code) { + out += ' ' + ($code) + ' '; + if ($breakOnError) { + $closingBraces1 += '}'; + } + } + } + } + } + if ($breakOnError) { + out += ' ' + ($closingBraces1) + ' '; + $closingBraces1 = ''; + } + if ($rulesGroup.type) { + out += ' } '; + if ($typeSchema && $typeSchema === $rulesGroup.type && !$coerceToTypes) { + out += ' else { '; + var $schemaPath = it.schemaPath + '.type', + $errSchemaPath = it.errSchemaPath + '/type'; + var $$outStack = $$outStack || []; + $$outStack.push(out); + out = ''; /* istanbul ignore else */ + if (it.createErrors !== false) { + out += ' { keyword: \'' + ($errorKeyword || 'type') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { type: \''; + if ($typeIsArray) { + out += '' + ($typeSchema.join(",")); + } else { + out += '' + ($typeSchema); + } + out += '\' } '; + if (it.opts.messages !== false) { + out += ' , message: \'should be '; + if ($typeIsArray) { + out += '' + ($typeSchema.join(",")); + } else { + out += '' + ($typeSchema); + } + out += '\' '; + } + if (it.opts.verbose) { + out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; + } + out += ' } '; + } else { + out += ' {} '; + } + var __err = out; + out = $$outStack.pop(); + if (!it.compositeRule && $breakOnError) { + /* istanbul ignore if */ + if (it.async) { + out += ' throw new ValidationError([' + (__err) + ']); '; + } else { + out += ' validate.errors = [' + (__err) + ']; return false; '; + } + } else { + out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; + } + out += ' } '; + } + } + if ($breakOnError) { + out += ' if (errors === '; + if ($top) { + out += '0'; + } else { + out += 'errs_' + ($lvl); + } + out += ') { '; + $closingBraces2 += '}'; + } + } + } + } + } + if ($breakOnError) { + out += ' ' + ($closingBraces2) + ' '; + } + if ($top) { + if ($async) { + out += ' if (errors === 0) return data; '; + out += ' else throw new ValidationError(vErrors); '; + } else { + out += ' validate.errors = vErrors; '; + out += ' return errors === 0; '; + } + out += ' }; return validate;'; + } else { + out += ' var ' + ($valid) + ' = errors === errs_' + ($lvl) + ';'; + } + out = it.util.cleanUpCode(out); + if ($top) { + out = it.util.finalCleanUpCode(out, $async); + } + + function $shouldUseGroup($rulesGroup) { + var rules = $rulesGroup.rules; + for (var i = 0; i < rules.length; i++) + if ($shouldUseRule(rules[i])) return true; + } + + function $shouldUseRule($rule) { + return it.schema[$rule.keyword] !== undefined || ($rule.implements && $ruleImplementsSomeKeyword($rule)); + } + + function $ruleImplementsSomeKeyword($rule) { + var impl = $rule.implements; + for (var i = 0; i < impl.length; i++) + if (it.schema[impl[i]] !== undefined) return true; + } + return out; +} + +},{}],39:[function(require,module,exports){ +'use strict'; + +var IDENTIFIER = /^[a-z_$][a-z0-9_$-]*$/i; +var customRuleCode = require('./dotjs/custom'); +var definitionSchema = require('./definition_schema'); + +module.exports = { + add: addKeyword, + get: getKeyword, + remove: removeKeyword, + validate: validateKeyword +}; + + +/** + * Define custom keyword + * @this Ajv + * @param {String} keyword custom keyword, should be unique (including different from all standard, custom and macro keywords). + * @param {Object} definition keyword definition object with properties `type` (type(s) which the keyword applies to), `validate` or `compile`. + * @return {Ajv} this for method chaining + */ +function addKeyword(keyword, definition) { + /* jshint validthis: true */ + /* eslint no-shadow: 0 */ + var RULES = this.RULES; + if (RULES.keywords[keyword]) + throw new Error('Keyword ' + keyword + ' is already defined'); + + if (!IDENTIFIER.test(keyword)) + throw new Error('Keyword ' + keyword + ' is not a valid identifier'); + + if (definition) { + this.validateKeyword(definition, true); + + var dataType = definition.type; + if (Array.isArray(dataType)) { + for (var i=0; i 1) { + sets[0] = sets[0].slice(0, -1); + var xl = sets.length - 1; + for (var x = 1; x < xl; ++x) { + sets[x] = sets[x].slice(1, -1); + } + sets[xl] = sets[xl].slice(1); + return sets.join(''); + } else { + return sets[0]; + } +} +function subexp(str) { + return "(?:" + str + ")"; +} +function typeOf(o) { + return o === undefined ? "undefined" : o === null ? "null" : Object.prototype.toString.call(o).split(" ").pop().split("]").shift().toLowerCase(); +} +function toUpperCase(str) { + return str.toUpperCase(); +} +function toArray(obj) { + return obj !== undefined && obj !== null ? obj instanceof Array ? obj : typeof obj.length !== "number" || obj.split || obj.setInterval || obj.call ? [obj] : Array.prototype.slice.call(obj) : []; +} +function assign(target, source) { + var obj = target; + if (source) { + for (var key in source) { + obj[key] = source[key]; + } + } + return obj; +} + +function buildExps(isIRI) { + var ALPHA$$ = "[A-Za-z]", + CR$ = "[\\x0D]", + DIGIT$$ = "[0-9]", + DQUOTE$$ = "[\\x22]", + HEXDIG$$ = merge(DIGIT$$, "[A-Fa-f]"), + //case-insensitive + LF$$ = "[\\x0A]", + SP$$ = "[\\x20]", + PCT_ENCODED$ = subexp(subexp("%[EFef]" + HEXDIG$$ + "%" + HEXDIG$$ + HEXDIG$$ + "%" + HEXDIG$$ + HEXDIG$$) + "|" + subexp("%[89A-Fa-f]" + HEXDIG$$ + "%" + HEXDIG$$ + HEXDIG$$) + "|" + subexp("%" + HEXDIG$$ + HEXDIG$$)), + //expanded + GEN_DELIMS$$ = "[\\:\\/\\?\\#\\[\\]\\@]", + SUB_DELIMS$$ = "[\\!\\$\\&\\'\\(\\)\\*\\+\\,\\;\\=]", + RESERVED$$ = merge(GEN_DELIMS$$, SUB_DELIMS$$), + UCSCHAR$$ = isIRI ? "[\\xA0-\\u200D\\u2010-\\u2029\\u202F-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF]" : "[]", + //subset, excludes bidi control characters + IPRIVATE$$ = isIRI ? "[\\uE000-\\uF8FF]" : "[]", + //subset + UNRESERVED$$ = merge(ALPHA$$, DIGIT$$, "[\\-\\.\\_\\~]", UCSCHAR$$), + SCHEME$ = subexp(ALPHA$$ + merge(ALPHA$$, DIGIT$$, "[\\+\\-\\.]") + "*"), + USERINFO$ = subexp(subexp(PCT_ENCODED$ + "|" + merge(UNRESERVED$$, SUB_DELIMS$$, "[\\:]")) + "*"), + DEC_OCTET$ = subexp(subexp("25[0-5]") + "|" + subexp("2[0-4]" + DIGIT$$) + "|" + subexp("1" + DIGIT$$ + DIGIT$$) + "|" + subexp("[1-9]" + DIGIT$$) + "|" + DIGIT$$), + DEC_OCTET_RELAXED$ = subexp(subexp("25[0-5]") + "|" + subexp("2[0-4]" + DIGIT$$) + "|" + subexp("1" + DIGIT$$ + DIGIT$$) + "|" + subexp("0?[1-9]" + DIGIT$$) + "|0?0?" + DIGIT$$), + //relaxed parsing rules + IPV4ADDRESS$ = subexp(DEC_OCTET_RELAXED$ + "\\." + DEC_OCTET_RELAXED$ + "\\." + DEC_OCTET_RELAXED$ + "\\." + DEC_OCTET_RELAXED$), + H16$ = subexp(HEXDIG$$ + "{1,4}"), + LS32$ = subexp(subexp(H16$ + "\\:" + H16$) + "|" + IPV4ADDRESS$), + IPV6ADDRESS1$ = subexp(subexp(H16$ + "\\:") + "{6}" + LS32$), + // 6( h16 ":" ) ls32 + IPV6ADDRESS2$ = subexp("\\:\\:" + subexp(H16$ + "\\:") + "{5}" + LS32$), + // "::" 5( h16 ":" ) ls32 + IPV6ADDRESS3$ = subexp(subexp(H16$) + "?\\:\\:" + subexp(H16$ + "\\:") + "{4}" + LS32$), + //[ h16 ] "::" 4( h16 ":" ) ls32 + IPV6ADDRESS4$ = subexp(subexp(subexp(H16$ + "\\:") + "{0,1}" + H16$) + "?\\:\\:" + subexp(H16$ + "\\:") + "{3}" + LS32$), + //[ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32 + IPV6ADDRESS5$ = subexp(subexp(subexp(H16$ + "\\:") + "{0,2}" + H16$) + "?\\:\\:" + subexp(H16$ + "\\:") + "{2}" + LS32$), + //[ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32 + IPV6ADDRESS6$ = subexp(subexp(subexp(H16$ + "\\:") + "{0,3}" + H16$) + "?\\:\\:" + H16$ + "\\:" + LS32$), + //[ *3( h16 ":" ) h16 ] "::" h16 ":" ls32 + IPV6ADDRESS7$ = subexp(subexp(subexp(H16$ + "\\:") + "{0,4}" + H16$) + "?\\:\\:" + LS32$), + //[ *4( h16 ":" ) h16 ] "::" ls32 + IPV6ADDRESS8$ = subexp(subexp(subexp(H16$ + "\\:") + "{0,5}" + H16$) + "?\\:\\:" + H16$), + //[ *5( h16 ":" ) h16 ] "::" h16 + IPV6ADDRESS9$ = subexp(subexp(subexp(H16$ + "\\:") + "{0,6}" + H16$) + "?\\:\\:"), + //[ *6( h16 ":" ) h16 ] "::" + IPV6ADDRESS$ = subexp([IPV6ADDRESS1$, IPV6ADDRESS2$, IPV6ADDRESS3$, IPV6ADDRESS4$, IPV6ADDRESS5$, IPV6ADDRESS6$, IPV6ADDRESS7$, IPV6ADDRESS8$, IPV6ADDRESS9$].join("|")), + ZONEID$ = subexp(subexp(UNRESERVED$$ + "|" + PCT_ENCODED$) + "+"), + //RFC 6874 + IPV6ADDRZ$ = subexp(IPV6ADDRESS$ + "\\%25" + ZONEID$), + //RFC 6874 + IPV6ADDRZ_RELAXED$ = subexp(IPV6ADDRESS$ + subexp("\\%25|\\%(?!" + HEXDIG$$ + "{2})") + ZONEID$), + //RFC 6874, with relaxed parsing rules + IPVFUTURE$ = subexp("[vV]" + HEXDIG$$ + "+\\." + merge(UNRESERVED$$, SUB_DELIMS$$, "[\\:]") + "+"), + IP_LITERAL$ = subexp("\\[" + subexp(IPV6ADDRZ_RELAXED$ + "|" + IPV6ADDRESS$ + "|" + IPVFUTURE$) + "\\]"), + //RFC 6874 + REG_NAME$ = subexp(subexp(PCT_ENCODED$ + "|" + merge(UNRESERVED$$, SUB_DELIMS$$)) + "*"), + HOST$ = subexp(IP_LITERAL$ + "|" + IPV4ADDRESS$ + "(?!" + REG_NAME$ + ")" + "|" + REG_NAME$), + PORT$ = subexp(DIGIT$$ + "*"), + AUTHORITY$ = subexp(subexp(USERINFO$ + "@") + "?" + HOST$ + subexp("\\:" + PORT$) + "?"), + PCHAR$ = subexp(PCT_ENCODED$ + "|" + merge(UNRESERVED$$, SUB_DELIMS$$, "[\\:\\@]")), + SEGMENT$ = subexp(PCHAR$ + "*"), + SEGMENT_NZ$ = subexp(PCHAR$ + "+"), + SEGMENT_NZ_NC$ = subexp(subexp(PCT_ENCODED$ + "|" + merge(UNRESERVED$$, SUB_DELIMS$$, "[\\@]")) + "+"), + PATH_ABEMPTY$ = subexp(subexp("\\/" + SEGMENT$) + "*"), + PATH_ABSOLUTE$ = subexp("\\/" + subexp(SEGMENT_NZ$ + PATH_ABEMPTY$) + "?"), + //simplified + PATH_NOSCHEME$ = subexp(SEGMENT_NZ_NC$ + PATH_ABEMPTY$), + //simplified + PATH_ROOTLESS$ = subexp(SEGMENT_NZ$ + PATH_ABEMPTY$), + //simplified + PATH_EMPTY$ = "(?!" + PCHAR$ + ")", + PATH$ = subexp(PATH_ABEMPTY$ + "|" + PATH_ABSOLUTE$ + "|" + PATH_NOSCHEME$ + "|" + PATH_ROOTLESS$ + "|" + PATH_EMPTY$), + QUERY$ = subexp(subexp(PCHAR$ + "|" + merge("[\\/\\?]", IPRIVATE$$)) + "*"), + FRAGMENT$ = subexp(subexp(PCHAR$ + "|[\\/\\?]") + "*"), + HIER_PART$ = subexp(subexp("\\/\\/" + AUTHORITY$ + PATH_ABEMPTY$) + "|" + PATH_ABSOLUTE$ + "|" + PATH_ROOTLESS$ + "|" + PATH_EMPTY$), + URI$ = subexp(SCHEME$ + "\\:" + HIER_PART$ + subexp("\\?" + QUERY$) + "?" + subexp("\\#" + FRAGMENT$) + "?"), + RELATIVE_PART$ = subexp(subexp("\\/\\/" + AUTHORITY$ + PATH_ABEMPTY$) + "|" + PATH_ABSOLUTE$ + "|" + PATH_NOSCHEME$ + "|" + PATH_EMPTY$), + RELATIVE$ = subexp(RELATIVE_PART$ + subexp("\\?" + QUERY$) + "?" + subexp("\\#" + FRAGMENT$) + "?"), + URI_REFERENCE$ = subexp(URI$ + "|" + RELATIVE$), + ABSOLUTE_URI$ = subexp(SCHEME$ + "\\:" + HIER_PART$ + subexp("\\?" + QUERY$) + "?"), + GENERIC_REF$ = "^(" + SCHEME$ + ")\\:" + subexp(subexp("\\/\\/(" + subexp("(" + USERINFO$ + ")@") + "?(" + HOST$ + ")" + subexp("\\:(" + PORT$ + ")") + "?)") + "?(" + PATH_ABEMPTY$ + "|" + PATH_ABSOLUTE$ + "|" + PATH_ROOTLESS$ + "|" + PATH_EMPTY$ + ")") + subexp("\\?(" + QUERY$ + ")") + "?" + subexp("\\#(" + FRAGMENT$ + ")") + "?$", + RELATIVE_REF$ = "^(){0}" + subexp(subexp("\\/\\/(" + subexp("(" + USERINFO$ + ")@") + "?(" + HOST$ + ")" + subexp("\\:(" + PORT$ + ")") + "?)") + "?(" + PATH_ABEMPTY$ + "|" + PATH_ABSOLUTE$ + "|" + PATH_NOSCHEME$ + "|" + PATH_EMPTY$ + ")") + subexp("\\?(" + QUERY$ + ")") + "?" + subexp("\\#(" + FRAGMENT$ + ")") + "?$", + ABSOLUTE_REF$ = "^(" + SCHEME$ + ")\\:" + subexp(subexp("\\/\\/(" + subexp("(" + USERINFO$ + ")@") + "?(" + HOST$ + ")" + subexp("\\:(" + PORT$ + ")") + "?)") + "?(" + PATH_ABEMPTY$ + "|" + PATH_ABSOLUTE$ + "|" + PATH_ROOTLESS$ + "|" + PATH_EMPTY$ + ")") + subexp("\\?(" + QUERY$ + ")") + "?$", + SAMEDOC_REF$ = "^" + subexp("\\#(" + FRAGMENT$ + ")") + "?$", + AUTHORITY_REF$ = "^" + subexp("(" + USERINFO$ + ")@") + "?(" + HOST$ + ")" + subexp("\\:(" + PORT$ + ")") + "?$"; + return { + NOT_SCHEME: new RegExp(merge("[^]", ALPHA$$, DIGIT$$, "[\\+\\-\\.]"), "g"), + NOT_USERINFO: new RegExp(merge("[^\\%\\:]", UNRESERVED$$, SUB_DELIMS$$), "g"), + NOT_HOST: new RegExp(merge("[^\\%\\[\\]\\:]", UNRESERVED$$, SUB_DELIMS$$), "g"), + NOT_PATH: new RegExp(merge("[^\\%\\/\\:\\@]", UNRESERVED$$, SUB_DELIMS$$), "g"), + NOT_PATH_NOSCHEME: new RegExp(merge("[^\\%\\/\\@]", UNRESERVED$$, SUB_DELIMS$$), "g"), + NOT_QUERY: new RegExp(merge("[^\\%]", UNRESERVED$$, SUB_DELIMS$$, "[\\:\\@\\/\\?]", IPRIVATE$$), "g"), + NOT_FRAGMENT: new RegExp(merge("[^\\%]", UNRESERVED$$, SUB_DELIMS$$, "[\\:\\@\\/\\?]"), "g"), + ESCAPE: new RegExp(merge("[^]", UNRESERVED$$, SUB_DELIMS$$), "g"), + UNRESERVED: new RegExp(UNRESERVED$$, "g"), + OTHER_CHARS: new RegExp(merge("[^\\%]", UNRESERVED$$, RESERVED$$), "g"), + PCT_ENCODED: new RegExp(PCT_ENCODED$, "g"), + IPV4ADDRESS: new RegExp("^(" + IPV4ADDRESS$ + ")$"), + IPV6ADDRESS: new RegExp("^\\[?(" + IPV6ADDRESS$ + ")" + subexp(subexp("\\%25|\\%(?!" + HEXDIG$$ + "{2})") + "(" + ZONEID$ + ")") + "?\\]?$") //RFC 6874, with relaxed parsing rules + }; +} +var URI_PROTOCOL = buildExps(false); + +var IRI_PROTOCOL = buildExps(true); + +var slicedToArray = function () { + function sliceIterator(arr, i) { + var _arr = []; + var _n = true; + var _d = false; + var _e = undefined; + + try { + for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { + _arr.push(_s.value); + + if (i && _arr.length === i) break; + } + } catch (err) { + _d = true; + _e = err; + } finally { + try { + if (!_n && _i["return"]) _i["return"](); + } finally { + if (_d) throw _e; + } + } + + return _arr; + } + + return function (arr, i) { + if (Array.isArray(arr)) { + return arr; + } else if (Symbol.iterator in Object(arr)) { + return sliceIterator(arr, i); + } else { + throw new TypeError("Invalid attempt to destructure non-iterable instance"); + } + }; +}(); + + + + + + + + + + + + + +var toConsumableArray = function (arr) { + if (Array.isArray(arr)) { + for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; + + return arr2; + } else { + return Array.from(arr); + } +}; + +/** Highest positive signed 32-bit float value */ + +var maxInt = 2147483647; // aka. 0x7FFFFFFF or 2^31-1 + +/** Bootstring parameters */ +var base = 36; +var tMin = 1; +var tMax = 26; +var skew = 38; +var damp = 700; +var initialBias = 72; +var initialN = 128; // 0x80 +var delimiter = '-'; // '\x2D' + +/** Regular expressions */ +var regexPunycode = /^xn--/; +var regexNonASCII = /[^\0-\x7E]/; // non-ASCII chars +var regexSeparators = /[\x2E\u3002\uFF0E\uFF61]/g; // RFC 3490 separators + +/** Error messages */ +var errors = { + 'overflow': 'Overflow: input needs wider integers to process', + 'not-basic': 'Illegal input >= 0x80 (not a basic code point)', + 'invalid-input': 'Invalid input' +}; + +/** Convenience shortcuts */ +var baseMinusTMin = base - tMin; +var floor = Math.floor; +var stringFromCharCode = String.fromCharCode; + +/*--------------------------------------------------------------------------*/ + +/** + * A generic error utility function. + * @private + * @param {String} type The error type. + * @returns {Error} Throws a `RangeError` with the applicable error message. + */ +function error$1(type) { + throw new RangeError(errors[type]); +} + +/** + * A generic `Array#map` utility function. + * @private + * @param {Array} array The array to iterate over. + * @param {Function} callback The function that gets called for every array + * item. + * @returns {Array} A new array of values returned by the callback function. + */ +function map(array, fn) { + var result = []; + var length = array.length; + while (length--) { + result[length] = fn(array[length]); + } + return result; +} + +/** + * A simple `Array#map`-like wrapper to work with domain name strings or email + * addresses. + * @private + * @param {String} domain The domain name or email address. + * @param {Function} callback The function that gets called for every + * character. + * @returns {Array} A new string of characters returned by the callback + * function. + */ +function mapDomain(string, fn) { + var parts = string.split('@'); + var result = ''; + if (parts.length > 1) { + // In email addresses, only the domain name should be punycoded. Leave + // the local part (i.e. everything up to `@`) intact. + result = parts[0] + '@'; + string = parts[1]; + } + // Avoid `split(regex)` for IE8 compatibility. See #17. + string = string.replace(regexSeparators, '\x2E'); + var labels = string.split('.'); + var encoded = map(labels, fn).join('.'); + return result + encoded; +} + +/** + * Creates an array containing the numeric code points of each Unicode + * character in the string. While JavaScript uses UCS-2 internally, + * this function will convert a pair of surrogate halves (each of which + * UCS-2 exposes as separate characters) into a single code point, + * matching UTF-16. + * @see `punycode.ucs2.encode` + * @see + * @memberOf punycode.ucs2 + * @name decode + * @param {String} string The Unicode input string (UCS-2). + * @returns {Array} The new array of code points. + */ +function ucs2decode(string) { + var output = []; + var counter = 0; + var length = string.length; + while (counter < length) { + var value = string.charCodeAt(counter++); + if (value >= 0xD800 && value <= 0xDBFF && counter < length) { + // It's a high surrogate, and there is a next character. + var extra = string.charCodeAt(counter++); + if ((extra & 0xFC00) == 0xDC00) { + // Low surrogate. + output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000); + } else { + // It's an unmatched surrogate; only append this code unit, in case the + // next code unit is the high surrogate of a surrogate pair. + output.push(value); + counter--; + } + } else { + output.push(value); + } + } + return output; +} + +/** + * Creates a string based on an array of numeric code points. + * @see `punycode.ucs2.decode` + * @memberOf punycode.ucs2 + * @name encode + * @param {Array} codePoints The array of numeric code points. + * @returns {String} The new Unicode string (UCS-2). + */ +var ucs2encode = function ucs2encode(array) { + return String.fromCodePoint.apply(String, toConsumableArray(array)); +}; + +/** + * Converts a basic code point into a digit/integer. + * @see `digitToBasic()` + * @private + * @param {Number} codePoint The basic numeric code point value. + * @returns {Number} The numeric value of a basic code point (for use in + * representing integers) in the range `0` to `base - 1`, or `base` if + * the code point does not represent a value. + */ +var basicToDigit = function basicToDigit(codePoint) { + if (codePoint - 0x30 < 0x0A) { + return codePoint - 0x16; + } + if (codePoint - 0x41 < 0x1A) { + return codePoint - 0x41; + } + if (codePoint - 0x61 < 0x1A) { + return codePoint - 0x61; + } + return base; +}; + +/** + * Converts a digit/integer into a basic code point. + * @see `basicToDigit()` + * @private + * @param {Number} digit The numeric value of a basic code point. + * @returns {Number} The basic code point whose value (when used for + * representing integers) is `digit`, which needs to be in the range + * `0` to `base - 1`. If `flag` is non-zero, the uppercase form is + * used; else, the lowercase form is used. The behavior is undefined + * if `flag` is non-zero and `digit` has no uppercase form. + */ +var digitToBasic = function digitToBasic(digit, flag) { + // 0..25 map to ASCII a..z or A..Z + // 26..35 map to ASCII 0..9 + return digit + 22 + 75 * (digit < 26) - ((flag != 0) << 5); +}; + +/** + * Bias adaptation function as per section 3.4 of RFC 3492. + * https://tools.ietf.org/html/rfc3492#section-3.4 + * @private + */ +var adapt = function adapt(delta, numPoints, firstTime) { + var k = 0; + delta = firstTime ? floor(delta / damp) : delta >> 1; + delta += floor(delta / numPoints); + for (; /* no initialization */delta > baseMinusTMin * tMax >> 1; k += base) { + delta = floor(delta / baseMinusTMin); + } + return floor(k + (baseMinusTMin + 1) * delta / (delta + skew)); +}; + +/** + * Converts a Punycode string of ASCII-only symbols to a string of Unicode + * symbols. + * @memberOf punycode + * @param {String} input The Punycode string of ASCII-only symbols. + * @returns {String} The resulting string of Unicode symbols. + */ +var decode = function decode(input) { + // Don't use UCS-2. + var output = []; + var inputLength = input.length; + var i = 0; + var n = initialN; + var bias = initialBias; + + // Handle the basic code points: let `basic` be the number of input code + // points before the last delimiter, or `0` if there is none, then copy + // the first basic code points to the output. + + var basic = input.lastIndexOf(delimiter); + if (basic < 0) { + basic = 0; + } + + for (var j = 0; j < basic; ++j) { + // if it's not a basic code point + if (input.charCodeAt(j) >= 0x80) { + error$1('not-basic'); + } + output.push(input.charCodeAt(j)); + } + + // Main decoding loop: start just after the last delimiter if any basic code + // points were copied; start at the beginning otherwise. + + for (var index = basic > 0 ? basic + 1 : 0; index < inputLength;) /* no final expression */{ + + // `index` is the index of the next character to be consumed. + // Decode a generalized variable-length integer into `delta`, + // which gets added to `i`. The overflow checking is easier + // if we increase `i` as we go, then subtract off its starting + // value at the end to obtain `delta`. + var oldi = i; + for (var w = 1, k = base;; /* no condition */k += base) { + + if (index >= inputLength) { + error$1('invalid-input'); + } + + var digit = basicToDigit(input.charCodeAt(index++)); + + if (digit >= base || digit > floor((maxInt - i) / w)) { + error$1('overflow'); + } + + i += digit * w; + var t = k <= bias ? tMin : k >= bias + tMax ? tMax : k - bias; + + if (digit < t) { + break; + } + + var baseMinusT = base - t; + if (w > floor(maxInt / baseMinusT)) { + error$1('overflow'); + } + + w *= baseMinusT; + } + + var out = output.length + 1; + bias = adapt(i - oldi, out, oldi == 0); + + // `i` was supposed to wrap around from `out` to `0`, + // incrementing `n` each time, so we'll fix that now: + if (floor(i / out) > maxInt - n) { + error$1('overflow'); + } + + n += floor(i / out); + i %= out; + + // Insert `n` at position `i` of the output. + output.splice(i++, 0, n); + } + + return String.fromCodePoint.apply(String, output); +}; + +/** + * Converts a string of Unicode symbols (e.g. a domain name label) to a + * Punycode string of ASCII-only symbols. + * @memberOf punycode + * @param {String} input The string of Unicode symbols. + * @returns {String} The resulting Punycode string of ASCII-only symbols. + */ +var encode = function encode(input) { + var output = []; + + // Convert the input in UCS-2 to an array of Unicode code points. + input = ucs2decode(input); + + // Cache the length. + var inputLength = input.length; + + // Initialize the state. + var n = initialN; + var delta = 0; + var bias = initialBias; + + // Handle the basic code points. + var _iteratorNormalCompletion = true; + var _didIteratorError = false; + var _iteratorError = undefined; + + try { + for (var _iterator = input[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { + var _currentValue2 = _step.value; + + if (_currentValue2 < 0x80) { + output.push(stringFromCharCode(_currentValue2)); + } + } + } catch (err) { + _didIteratorError = true; + _iteratorError = err; + } finally { + try { + if (!_iteratorNormalCompletion && _iterator.return) { + _iterator.return(); + } + } finally { + if (_didIteratorError) { + throw _iteratorError; + } + } + } + + var basicLength = output.length; + var handledCPCount = basicLength; + + // `handledCPCount` is the number of code points that have been handled; + // `basicLength` is the number of basic code points. + + // Finish the basic string with a delimiter unless it's empty. + if (basicLength) { + output.push(delimiter); + } + + // Main encoding loop: + while (handledCPCount < inputLength) { + + // All non-basic code points < n have been handled already. Find the next + // larger one: + var m = maxInt; + var _iteratorNormalCompletion2 = true; + var _didIteratorError2 = false; + var _iteratorError2 = undefined; + + try { + for (var _iterator2 = input[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { + var currentValue = _step2.value; + + if (currentValue >= n && currentValue < m) { + m = currentValue; + } + } + + // Increase `delta` enough to advance the decoder's state to , + // but guard against overflow. + } catch (err) { + _didIteratorError2 = true; + _iteratorError2 = err; + } finally { + try { + if (!_iteratorNormalCompletion2 && _iterator2.return) { + _iterator2.return(); + } + } finally { + if (_didIteratorError2) { + throw _iteratorError2; + } + } + } + + var handledCPCountPlusOne = handledCPCount + 1; + if (m - n > floor((maxInt - delta) / handledCPCountPlusOne)) { + error$1('overflow'); + } + + delta += (m - n) * handledCPCountPlusOne; + n = m; + + var _iteratorNormalCompletion3 = true; + var _didIteratorError3 = false; + var _iteratorError3 = undefined; + + try { + for (var _iterator3 = input[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) { + var _currentValue = _step3.value; + + if (_currentValue < n && ++delta > maxInt) { + error$1('overflow'); + } + if (_currentValue == n) { + // Represent delta as a generalized variable-length integer. + var q = delta; + for (var k = base;; /* no condition */k += base) { + var t = k <= bias ? tMin : k >= bias + tMax ? tMax : k - bias; + if (q < t) { + break; + } + var qMinusT = q - t; + var baseMinusT = base - t; + output.push(stringFromCharCode(digitToBasic(t + qMinusT % baseMinusT, 0))); + q = floor(qMinusT / baseMinusT); + } + + output.push(stringFromCharCode(digitToBasic(q, 0))); + bias = adapt(delta, handledCPCountPlusOne, handledCPCount == basicLength); + delta = 0; + ++handledCPCount; + } + } + } catch (err) { + _didIteratorError3 = true; + _iteratorError3 = err; + } finally { + try { + if (!_iteratorNormalCompletion3 && _iterator3.return) { + _iterator3.return(); + } + } finally { + if (_didIteratorError3) { + throw _iteratorError3; + } + } + } + + ++delta; + ++n; + } + return output.join(''); +}; + +/** + * Converts a Punycode string representing a domain name or an email address + * to Unicode. Only the Punycoded parts of the input will be converted, i.e. + * it doesn't matter if you call it on a string that has already been + * converted to Unicode. + * @memberOf punycode + * @param {String} input The Punycoded domain name or email address to + * convert to Unicode. + * @returns {String} The Unicode representation of the given Punycode + * string. + */ +var toUnicode = function toUnicode(input) { + return mapDomain(input, function (string) { + return regexPunycode.test(string) ? decode(string.slice(4).toLowerCase()) : string; + }); +}; + +/** + * Converts a Unicode string representing a domain name or an email address to + * Punycode. Only the non-ASCII parts of the domain name will be converted, + * i.e. it doesn't matter if you call it with a domain that's already in + * ASCII. + * @memberOf punycode + * @param {String} input The domain name or email address to convert, as a + * Unicode string. + * @returns {String} The Punycode representation of the given domain name or + * email address. + */ +var toASCII = function toASCII(input) { + return mapDomain(input, function (string) { + return regexNonASCII.test(string) ? 'xn--' + encode(string) : string; + }); +}; + +/*--------------------------------------------------------------------------*/ + +/** Define the public API */ +var punycode = { + /** + * A string representing the current Punycode.js version number. + * @memberOf punycode + * @type String + */ + 'version': '2.1.0', + /** + * An object of methods to convert from JavaScript's internal character + * representation (UCS-2) to Unicode code points, and back. + * @see + * @memberOf punycode + * @type Object + */ + 'ucs2': { + 'decode': ucs2decode, + 'encode': ucs2encode + }, + 'decode': decode, + 'encode': encode, + 'toASCII': toASCII, + 'toUnicode': toUnicode +}; + +/** + * URI.js + * + * @fileoverview An RFC 3986 compliant, scheme extendable URI parsing/validating/resolving library for JavaScript. + * @author Gary Court + * @see http://github.com/garycourt/uri-js + */ +/** + * Copyright 2011 Gary Court. 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 GARY COURT ``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 GARY COURT 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 Gary Court. + */ +var SCHEMES = {}; +function pctEncChar(chr) { + var c = chr.charCodeAt(0); + var e = void 0; + if (c < 16) e = "%0" + c.toString(16).toUpperCase();else if (c < 128) e = "%" + c.toString(16).toUpperCase();else if (c < 2048) e = "%" + (c >> 6 | 192).toString(16).toUpperCase() + "%" + (c & 63 | 128).toString(16).toUpperCase();else e = "%" + (c >> 12 | 224).toString(16).toUpperCase() + "%" + (c >> 6 & 63 | 128).toString(16).toUpperCase() + "%" + (c & 63 | 128).toString(16).toUpperCase(); + return e; +} +function pctDecChars(str) { + var newStr = ""; + var i = 0; + var il = str.length; + while (i < il) { + var c = parseInt(str.substr(i + 1, 2), 16); + if (c < 128) { + newStr += String.fromCharCode(c); + i += 3; + } else if (c >= 194 && c < 224) { + if (il - i >= 6) { + var c2 = parseInt(str.substr(i + 4, 2), 16); + newStr += String.fromCharCode((c & 31) << 6 | c2 & 63); + } else { + newStr += str.substr(i, 6); + } + i += 6; + } else if (c >= 224) { + if (il - i >= 9) { + var _c = parseInt(str.substr(i + 4, 2), 16); + var c3 = parseInt(str.substr(i + 7, 2), 16); + newStr += String.fromCharCode((c & 15) << 12 | (_c & 63) << 6 | c3 & 63); + } else { + newStr += str.substr(i, 9); + } + i += 9; + } else { + newStr += str.substr(i, 3); + i += 3; + } + } + return newStr; +} +function _normalizeComponentEncoding(components, protocol) { + function decodeUnreserved(str) { + var decStr = pctDecChars(str); + return !decStr.match(protocol.UNRESERVED) ? str : decStr; + } + if (components.scheme) components.scheme = String(components.scheme).replace(protocol.PCT_ENCODED, decodeUnreserved).toLowerCase().replace(protocol.NOT_SCHEME, ""); + if (components.userinfo !== undefined) components.userinfo = String(components.userinfo).replace(protocol.PCT_ENCODED, decodeUnreserved).replace(protocol.NOT_USERINFO, pctEncChar).replace(protocol.PCT_ENCODED, toUpperCase); + if (components.host !== undefined) components.host = String(components.host).replace(protocol.PCT_ENCODED, decodeUnreserved).toLowerCase().replace(protocol.NOT_HOST, pctEncChar).replace(protocol.PCT_ENCODED, toUpperCase); + if (components.path !== undefined) components.path = String(components.path).replace(protocol.PCT_ENCODED, decodeUnreserved).replace(components.scheme ? protocol.NOT_PATH : protocol.NOT_PATH_NOSCHEME, pctEncChar).replace(protocol.PCT_ENCODED, toUpperCase); + if (components.query !== undefined) components.query = String(components.query).replace(protocol.PCT_ENCODED, decodeUnreserved).replace(protocol.NOT_QUERY, pctEncChar).replace(protocol.PCT_ENCODED, toUpperCase); + if (components.fragment !== undefined) components.fragment = String(components.fragment).replace(protocol.PCT_ENCODED, decodeUnreserved).replace(protocol.NOT_FRAGMENT, pctEncChar).replace(protocol.PCT_ENCODED, toUpperCase); + return components; +} + +function _stripLeadingZeros(str) { + return str.replace(/^0*(.*)/, "$1") || "0"; +} +function _normalizeIPv4(host, protocol) { + var matches = host.match(protocol.IPV4ADDRESS) || []; + + var _matches = slicedToArray(matches, 2), + address = _matches[1]; + + if (address) { + return address.split(".").map(_stripLeadingZeros).join("."); + } else { + return host; + } +} +function _normalizeIPv6(host, protocol) { + var matches = host.match(protocol.IPV6ADDRESS) || []; + + var _matches2 = slicedToArray(matches, 3), + address = _matches2[1], + zone = _matches2[2]; + + if (address) { + var _address$toLowerCase$ = address.toLowerCase().split('::').reverse(), + _address$toLowerCase$2 = slicedToArray(_address$toLowerCase$, 2), + last = _address$toLowerCase$2[0], + first = _address$toLowerCase$2[1]; + + var firstFields = first ? first.split(":").map(_stripLeadingZeros) : []; + var lastFields = last.split(":").map(_stripLeadingZeros); + var isLastFieldIPv4Address = protocol.IPV4ADDRESS.test(lastFields[lastFields.length - 1]); + var fieldCount = isLastFieldIPv4Address ? 7 : 8; + var lastFieldsStart = lastFields.length - fieldCount; + var fields = Array(fieldCount); + for (var x = 0; x < fieldCount; ++x) { + fields[x] = firstFields[x] || lastFields[lastFieldsStart + x] || ''; + } + if (isLastFieldIPv4Address) { + fields[fieldCount - 1] = _normalizeIPv4(fields[fieldCount - 1], protocol); + } + var allZeroFields = fields.reduce(function (acc, field, index) { + if (!field || field === "0") { + var lastLongest = acc[acc.length - 1]; + if (lastLongest && lastLongest.index + lastLongest.length === index) { + lastLongest.length++; + } else { + acc.push({ index: index, length: 1 }); + } + } + return acc; + }, []); + var longestZeroFields = allZeroFields.sort(function (a, b) { + return b.length - a.length; + })[0]; + var newHost = void 0; + if (longestZeroFields && longestZeroFields.length > 1) { + var newFirst = fields.slice(0, longestZeroFields.index); + var newLast = fields.slice(longestZeroFields.index + longestZeroFields.length); + newHost = newFirst.join(":") + "::" + newLast.join(":"); + } else { + newHost = fields.join(":"); + } + if (zone) { + newHost += "%" + zone; + } + return newHost; + } else { + return host; + } +} +var URI_PARSE = /^(?:([^:\/?#]+):)?(?:\/\/((?:([^\/?#@]*)@)?(\[[^\/?#\]]+\]|[^\/?#:]*)(?:\:(\d*))?))?([^?#]*)(?:\?([^#]*))?(?:#((?:.|\n|\r)*))?/i; +var NO_MATCH_IS_UNDEFINED = "".match(/(){0}/)[1] === undefined; +function parse(uriString) { + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + + var components = {}; + var protocol = options.iri !== false ? IRI_PROTOCOL : URI_PROTOCOL; + if (options.reference === "suffix") uriString = (options.scheme ? options.scheme + ":" : "") + "//" + uriString; + var matches = uriString.match(URI_PARSE); + if (matches) { + if (NO_MATCH_IS_UNDEFINED) { + //store each component + components.scheme = matches[1]; + components.userinfo = matches[3]; + components.host = matches[4]; + components.port = parseInt(matches[5], 10); + components.path = matches[6] || ""; + components.query = matches[7]; + components.fragment = matches[8]; + //fix port number + if (isNaN(components.port)) { + components.port = matches[5]; + } + } else { + //IE FIX for improper RegExp matching + //store each component + components.scheme = matches[1] || undefined; + components.userinfo = uriString.indexOf("@") !== -1 ? matches[3] : undefined; + components.host = uriString.indexOf("//") !== -1 ? matches[4] : undefined; + components.port = parseInt(matches[5], 10); + components.path = matches[6] || ""; + components.query = uriString.indexOf("?") !== -1 ? matches[7] : undefined; + components.fragment = uriString.indexOf("#") !== -1 ? matches[8] : undefined; + //fix port number + if (isNaN(components.port)) { + components.port = uriString.match(/\/\/(?:.|\n)*\:(?:\/|\?|\#|$)/) ? matches[4] : undefined; + } + } + if (components.host) { + //normalize IP hosts + components.host = _normalizeIPv6(_normalizeIPv4(components.host, protocol), protocol); + } + //determine reference type + if (components.scheme === undefined && components.userinfo === undefined && components.host === undefined && components.port === undefined && !components.path && components.query === undefined) { + components.reference = "same-document"; + } else if (components.scheme === undefined) { + components.reference = "relative"; + } else if (components.fragment === undefined) { + components.reference = "absolute"; + } else { + components.reference = "uri"; + } + //check for reference errors + if (options.reference && options.reference !== "suffix" && options.reference !== components.reference) { + components.error = components.error || "URI is not a " + options.reference + " reference."; + } + //find scheme handler + var schemeHandler = SCHEMES[(options.scheme || components.scheme || "").toLowerCase()]; + //check if scheme can't handle IRIs + if (!options.unicodeSupport && (!schemeHandler || !schemeHandler.unicodeSupport)) { + //if host component is a domain name + if (components.host && (options.domainHost || schemeHandler && schemeHandler.domainHost)) { + //convert Unicode IDN -> ASCII IDN + try { + components.host = punycode.toASCII(components.host.replace(protocol.PCT_ENCODED, pctDecChars).toLowerCase()); + } catch (e) { + components.error = components.error || "Host's domain name can not be converted to ASCII via punycode: " + e; + } + } + //convert IRI -> URI + _normalizeComponentEncoding(components, URI_PROTOCOL); + } else { + //normalize encodings + _normalizeComponentEncoding(components, protocol); + } + //perform scheme specific parsing + if (schemeHandler && schemeHandler.parse) { + schemeHandler.parse(components, options); + } + } else { + components.error = components.error || "URI can not be parsed."; + } + return components; +} + +function _recomposeAuthority(components, options) { + var protocol = options.iri !== false ? IRI_PROTOCOL : URI_PROTOCOL; + var uriTokens = []; + if (components.userinfo !== undefined) { + uriTokens.push(components.userinfo); + uriTokens.push("@"); + } + if (components.host !== undefined) { + //normalize IP hosts, add brackets and escape zone separator for IPv6 + uriTokens.push(_normalizeIPv6(_normalizeIPv4(String(components.host), protocol), protocol).replace(protocol.IPV6ADDRESS, function (_, $1, $2) { + return "[" + $1 + ($2 ? "%25" + $2 : "") + "]"; + })); + } + if (typeof components.port === "number") { + uriTokens.push(":"); + uriTokens.push(components.port.toString(10)); + } + return uriTokens.length ? uriTokens.join("") : undefined; +} + +var RDS1 = /^\.\.?\//; +var RDS2 = /^\/\.(\/|$)/; +var RDS3 = /^\/\.\.(\/|$)/; +var RDS5 = /^\/?(?:.|\n)*?(?=\/|$)/; +function removeDotSegments(input) { + var output = []; + while (input.length) { + if (input.match(RDS1)) { + input = input.replace(RDS1, ""); + } else if (input.match(RDS2)) { + input = input.replace(RDS2, "/"); + } else if (input.match(RDS3)) { + input = input.replace(RDS3, "/"); + output.pop(); + } else if (input === "." || input === "..") { + input = ""; + } else { + var im = input.match(RDS5); + if (im) { + var s = im[0]; + input = input.slice(s.length); + output.push(s); + } else { + throw new Error("Unexpected dot segment condition"); + } + } + } + return output.join(""); +} + +function serialize(components) { + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + + var protocol = options.iri ? IRI_PROTOCOL : URI_PROTOCOL; + var uriTokens = []; + //find scheme handler + var schemeHandler = SCHEMES[(options.scheme || components.scheme || "").toLowerCase()]; + //perform scheme specific serialization + if (schemeHandler && schemeHandler.serialize) schemeHandler.serialize(components, options); + if (components.host) { + //if host component is an IPv6 address + if (protocol.IPV6ADDRESS.test(components.host)) {} + //TODO: normalize IPv6 address as per RFC 5952 + + //if host component is a domain name + else if (options.domainHost || schemeHandler && schemeHandler.domainHost) { + //convert IDN via punycode + try { + components.host = !options.iri ? punycode.toASCII(components.host.replace(protocol.PCT_ENCODED, pctDecChars).toLowerCase()) : punycode.toUnicode(components.host); + } catch (e) { + components.error = components.error || "Host's domain name can not be converted to " + (!options.iri ? "ASCII" : "Unicode") + " via punycode: " + e; + } + } + } + //normalize encoding + _normalizeComponentEncoding(components, protocol); + if (options.reference !== "suffix" && components.scheme) { + uriTokens.push(components.scheme); + uriTokens.push(":"); + } + var authority = _recomposeAuthority(components, options); + if (authority !== undefined) { + if (options.reference !== "suffix") { + uriTokens.push("//"); + } + uriTokens.push(authority); + if (components.path && components.path.charAt(0) !== "/") { + uriTokens.push("/"); + } + } + if (components.path !== undefined) { + var s = components.path; + if (!options.absolutePath && (!schemeHandler || !schemeHandler.absolutePath)) { + s = removeDotSegments(s); + } + if (authority === undefined) { + s = s.replace(/^\/\//, "/%2F"); //don't allow the path to start with "//" + } + uriTokens.push(s); + } + if (components.query !== undefined) { + uriTokens.push("?"); + uriTokens.push(components.query); + } + if (components.fragment !== undefined) { + uriTokens.push("#"); + uriTokens.push(components.fragment); + } + return uriTokens.join(""); //merge tokens into a string +} + +function resolveComponents(base, relative) { + var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; + var skipNormalization = arguments[3]; + + var target = {}; + if (!skipNormalization) { + base = parse(serialize(base, options), options); //normalize base components + relative = parse(serialize(relative, options), options); //normalize relative components + } + options = options || {}; + if (!options.tolerant && relative.scheme) { + target.scheme = relative.scheme; + //target.authority = relative.authority; + target.userinfo = relative.userinfo; + target.host = relative.host; + target.port = relative.port; + target.path = removeDotSegments(relative.path || ""); + target.query = relative.query; + } else { + if (relative.userinfo !== undefined || relative.host !== undefined || relative.port !== undefined) { + //target.authority = relative.authority; + target.userinfo = relative.userinfo; + target.host = relative.host; + target.port = relative.port; + target.path = removeDotSegments(relative.path || ""); + target.query = relative.query; + } else { + if (!relative.path) { + target.path = base.path; + if (relative.query !== undefined) { + target.query = relative.query; + } else { + target.query = base.query; + } + } else { + if (relative.path.charAt(0) === "/") { + target.path = removeDotSegments(relative.path); + } else { + if ((base.userinfo !== undefined || base.host !== undefined || base.port !== undefined) && !base.path) { + target.path = "/" + relative.path; + } else if (!base.path) { + target.path = relative.path; + } else { + target.path = base.path.slice(0, base.path.lastIndexOf("/") + 1) + relative.path; + } + target.path = removeDotSegments(target.path); + } + target.query = relative.query; + } + //target.authority = base.authority; + target.userinfo = base.userinfo; + target.host = base.host; + target.port = base.port; + } + target.scheme = base.scheme; + } + target.fragment = relative.fragment; + return target; +} + +function resolve(baseURI, relativeURI, options) { + var schemelessOptions = assign({ scheme: 'null' }, options); + return serialize(resolveComponents(parse(baseURI, schemelessOptions), parse(relativeURI, schemelessOptions), schemelessOptions, true), schemelessOptions); +} + +function normalize(uri, options) { + if (typeof uri === "string") { + uri = serialize(parse(uri, options), options); + } else if (typeOf(uri) === "object") { + uri = parse(serialize(uri, options), options); + } + return uri; +} + +function equal(uriA, uriB, options) { + if (typeof uriA === "string") { + uriA = serialize(parse(uriA, options), options); + } else if (typeOf(uriA) === "object") { + uriA = serialize(uriA, options); + } + if (typeof uriB === "string") { + uriB = serialize(parse(uriB, options), options); + } else if (typeOf(uriB) === "object") { + uriB = serialize(uriB, options); + } + return uriA === uriB; +} + +function escapeComponent(str, options) { + return str && str.toString().replace(!options || !options.iri ? URI_PROTOCOL.ESCAPE : IRI_PROTOCOL.ESCAPE, pctEncChar); +} + +function unescapeComponent(str, options) { + return str && str.toString().replace(!options || !options.iri ? URI_PROTOCOL.PCT_ENCODED : IRI_PROTOCOL.PCT_ENCODED, pctDecChars); +} + +var handler = { + scheme: "http", + domainHost: true, + parse: function parse(components, options) { + //report missing host + if (!components.host) { + components.error = components.error || "HTTP URIs must have a host."; + } + return components; + }, + serialize: function serialize(components, options) { + //normalize the default port + if (components.port === (String(components.scheme).toLowerCase() !== "https" ? 80 : 443) || components.port === "") { + components.port = undefined; + } + //normalize the empty path + if (!components.path) { + components.path = "/"; + } + //NOTE: We do not parse query strings for HTTP URIs + //as WWW Form Url Encoded query strings are part of the HTML4+ spec, + //and not the HTTP spec. + return components; + } +}; + +var handler$1 = { + scheme: "https", + domainHost: handler.domainHost, + parse: handler.parse, + serialize: handler.serialize +}; + +var O = {}; +var isIRI = true; +//RFC 3986 +var UNRESERVED$$ = "[A-Za-z0-9\\-\\.\\_\\~" + (isIRI ? "\\xA0-\\u200D\\u2010-\\u2029\\u202F-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF" : "") + "]"; +var HEXDIG$$ = "[0-9A-Fa-f]"; //case-insensitive +var PCT_ENCODED$ = subexp(subexp("%[EFef]" + HEXDIG$$ + "%" + HEXDIG$$ + HEXDIG$$ + "%" + HEXDIG$$ + HEXDIG$$) + "|" + subexp("%[89A-Fa-f]" + HEXDIG$$ + "%" + HEXDIG$$ + HEXDIG$$) + "|" + subexp("%" + HEXDIG$$ + HEXDIG$$)); //expanded +//RFC 5322, except these symbols as per RFC 6068: @ : / ? # [ ] & ; = +//const ATEXT$$ = "[A-Za-z0-9\\!\\#\\$\\%\\&\\'\\*\\+\\-\\/\\=\\?\\^\\_\\`\\{\\|\\}\\~]"; +//const WSP$$ = "[\\x20\\x09]"; +//const OBS_QTEXT$$ = "[\\x01-\\x08\\x0B\\x0C\\x0E-\\x1F\\x7F]"; //(%d1-8 / %d11-12 / %d14-31 / %d127) +//const QTEXT$$ = merge("[\\x21\\x23-\\x5B\\x5D-\\x7E]", OBS_QTEXT$$); //%d33 / %d35-91 / %d93-126 / obs-qtext +//const VCHAR$$ = "[\\x21-\\x7E]"; +//const WSP$$ = "[\\x20\\x09]"; +//const OBS_QP$ = subexp("\\\\" + merge("[\\x00\\x0D\\x0A]", OBS_QTEXT$$)); //%d0 / CR / LF / obs-qtext +//const FWS$ = subexp(subexp(WSP$$ + "*" + "\\x0D\\x0A") + "?" + WSP$$ + "+"); +//const QUOTED_PAIR$ = subexp(subexp("\\\\" + subexp(VCHAR$$ + "|" + WSP$$)) + "|" + OBS_QP$); +//const QUOTED_STRING$ = subexp('\\"' + subexp(FWS$ + "?" + QCONTENT$) + "*" + FWS$ + "?" + '\\"'); +var ATEXT$$ = "[A-Za-z0-9\\!\\$\\%\\'\\*\\+\\-\\^\\_\\`\\{\\|\\}\\~]"; +var QTEXT$$ = "[\\!\\$\\%\\'\\(\\)\\*\\+\\,\\-\\.0-9\\<\\>A-Z\\x5E-\\x7E]"; +var VCHAR$$ = merge(QTEXT$$, "[\\\"\\\\]"); +var SOME_DELIMS$$ = "[\\!\\$\\'\\(\\)\\*\\+\\,\\;\\:\\@]"; +var UNRESERVED = new RegExp(UNRESERVED$$, "g"); +var PCT_ENCODED = new RegExp(PCT_ENCODED$, "g"); +var NOT_LOCAL_PART = new RegExp(merge("[^]", ATEXT$$, "[\\.]", '[\\"]', VCHAR$$), "g"); +var NOT_HFNAME = new RegExp(merge("[^]", UNRESERVED$$, SOME_DELIMS$$), "g"); +var NOT_HFVALUE = NOT_HFNAME; +function decodeUnreserved(str) { + var decStr = pctDecChars(str); + return !decStr.match(UNRESERVED) ? str : decStr; +} +var handler$2 = { + scheme: "mailto", + parse: function parse$$1(components, options) { + var mailtoComponents = components; + var to = mailtoComponents.to = mailtoComponents.path ? mailtoComponents.path.split(",") : []; + mailtoComponents.path = undefined; + if (mailtoComponents.query) { + var unknownHeaders = false; + var headers = {}; + var hfields = mailtoComponents.query.split("&"); + for (var x = 0, xl = hfields.length; x < xl; ++x) { + var hfield = hfields[x].split("="); + switch (hfield[0]) { + case "to": + var toAddrs = hfield[1].split(","); + for (var _x = 0, _xl = toAddrs.length; _x < _xl; ++_x) { + to.push(toAddrs[_x]); + } + break; + case "subject": + mailtoComponents.subject = unescapeComponent(hfield[1], options); + break; + case "body": + mailtoComponents.body = unescapeComponent(hfield[1], options); + break; + default: + unknownHeaders = true; + headers[unescapeComponent(hfield[0], options)] = unescapeComponent(hfield[1], options); + break; + } + } + if (unknownHeaders) mailtoComponents.headers = headers; + } + mailtoComponents.query = undefined; + for (var _x2 = 0, _xl2 = to.length; _x2 < _xl2; ++_x2) { + var addr = to[_x2].split("@"); + addr[0] = unescapeComponent(addr[0]); + if (!options.unicodeSupport) { + //convert Unicode IDN -> ASCII IDN + try { + addr[1] = punycode.toASCII(unescapeComponent(addr[1], options).toLowerCase()); + } catch (e) { + mailtoComponents.error = mailtoComponents.error || "Email address's domain name can not be converted to ASCII via punycode: " + e; + } + } else { + addr[1] = unescapeComponent(addr[1], options).toLowerCase(); + } + to[_x2] = addr.join("@"); + } + return mailtoComponents; + }, + serialize: function serialize$$1(mailtoComponents, options) { + var components = mailtoComponents; + var to = toArray(mailtoComponents.to); + if (to) { + for (var x = 0, xl = to.length; x < xl; ++x) { + var toAddr = String(to[x]); + var atIdx = toAddr.lastIndexOf("@"); + var localPart = toAddr.slice(0, atIdx).replace(PCT_ENCODED, decodeUnreserved).replace(PCT_ENCODED, toUpperCase).replace(NOT_LOCAL_PART, pctEncChar); + var domain = toAddr.slice(atIdx + 1); + //convert IDN via punycode + try { + domain = !options.iri ? punycode.toASCII(unescapeComponent(domain, options).toLowerCase()) : punycode.toUnicode(domain); + } catch (e) { + components.error = components.error || "Email address's domain name can not be converted to " + (!options.iri ? "ASCII" : "Unicode") + " via punycode: " + e; + } + to[x] = localPart + "@" + domain; + } + components.path = to.join(","); + } + var headers = mailtoComponents.headers = mailtoComponents.headers || {}; + if (mailtoComponents.subject) headers["subject"] = mailtoComponents.subject; + if (mailtoComponents.body) headers["body"] = mailtoComponents.body; + var fields = []; + for (var name in headers) { + if (headers[name] !== O[name]) { + fields.push(name.replace(PCT_ENCODED, decodeUnreserved).replace(PCT_ENCODED, toUpperCase).replace(NOT_HFNAME, pctEncChar) + "=" + headers[name].replace(PCT_ENCODED, decodeUnreserved).replace(PCT_ENCODED, toUpperCase).replace(NOT_HFVALUE, pctEncChar)); + } + } + if (fields.length) { + components.query = fields.join("&"); + } + return components; + } +}; + +var URN_PARSE = /^([^\:]+)\:(.*)/; +//RFC 2141 +var handler$3 = { + scheme: "urn", + parse: function parse$$1(components, options) { + var matches = components.path && components.path.match(URN_PARSE); + var urnComponents = components; + if (matches) { + var scheme = options.scheme || urnComponents.scheme || "urn"; + var nid = matches[1].toLowerCase(); + var nss = matches[2]; + var urnScheme = scheme + ":" + (options.nid || nid); + var schemeHandler = SCHEMES[urnScheme]; + urnComponents.nid = nid; + urnComponents.nss = nss; + urnComponents.path = undefined; + if (schemeHandler) { + urnComponents = schemeHandler.parse(urnComponents, options); + } + } else { + urnComponents.error = urnComponents.error || "URN can not be parsed."; + } + return urnComponents; + }, + serialize: function serialize$$1(urnComponents, options) { + var scheme = options.scheme || urnComponents.scheme || "urn"; + var nid = urnComponents.nid; + var urnScheme = scheme + ":" + (options.nid || nid); + var schemeHandler = SCHEMES[urnScheme]; + if (schemeHandler) { + urnComponents = schemeHandler.serialize(urnComponents, options); + } + var uriComponents = urnComponents; + var nss = urnComponents.nss; + uriComponents.path = (nid || options.nid) + ":" + nss; + return uriComponents; + } +}; + +var UUID = /^[0-9A-Fa-f]{8}(?:\-[0-9A-Fa-f]{4}){3}\-[0-9A-Fa-f]{12}$/; +//RFC 4122 +var handler$4 = { + scheme: "urn:uuid", + parse: function parse(urnComponents, options) { + var uuidComponents = urnComponents; + uuidComponents.uuid = uuidComponents.nss; + uuidComponents.nss = undefined; + if (!options.tolerant && (!uuidComponents.uuid || !uuidComponents.uuid.match(UUID))) { + uuidComponents.error = uuidComponents.error || "UUID is not valid."; + } + return uuidComponents; + }, + serialize: function serialize(uuidComponents, options) { + var urnComponents = uuidComponents; + //normalize UUID + urnComponents.nss = (uuidComponents.uuid || "").toLowerCase(); + return urnComponents; + } +}; + +SCHEMES[handler.scheme] = handler; +SCHEMES[handler$1.scheme] = handler$1; +SCHEMES[handler$2.scheme] = handler$2; +SCHEMES[handler$3.scheme] = handler$3; +SCHEMES[handler$4.scheme] = handler$4; + +exports.SCHEMES = SCHEMES; +exports.pctEncChar = pctEncChar; +exports.pctDecChars = pctDecChars; +exports.parse = parse; +exports.removeDotSegments = removeDotSegments; +exports.serialize = serialize; +exports.resolveComponents = resolveComponents; +exports.resolve = resolve; +exports.normalize = normalize; +exports.equal = equal; +exports.escapeComponent = escapeComponent; +exports.unescapeComponent = unescapeComponent; + +Object.defineProperty(exports, '__esModule', { value: true }); + +}))); + + +},{}],"ajv":[function(require,module,exports){ +'use strict'; + +var compileSchema = require('./compile') + , resolve = require('./compile/resolve') + , Cache = require('./cache') + , SchemaObject = require('./compile/schema_obj') + , stableStringify = require('fast-json-stable-stringify') + , formats = require('./compile/formats') + , rules = require('./compile/rules') + , $dataMetaSchema = require('./data') + , util = require('./compile/util'); + +module.exports = Ajv; + +Ajv.prototype.validate = validate; +Ajv.prototype.compile = compile; +Ajv.prototype.addSchema = addSchema; +Ajv.prototype.addMetaSchema = addMetaSchema; +Ajv.prototype.validateSchema = validateSchema; +Ajv.prototype.getSchema = getSchema; +Ajv.prototype.removeSchema = removeSchema; +Ajv.prototype.addFormat = addFormat; +Ajv.prototype.errorsText = errorsText; + +Ajv.prototype._addSchema = _addSchema; +Ajv.prototype._compile = _compile; + +Ajv.prototype.compileAsync = require('./compile/async'); +var customKeyword = require('./keyword'); +Ajv.prototype.addKeyword = customKeyword.add; +Ajv.prototype.getKeyword = customKeyword.get; +Ajv.prototype.removeKeyword = customKeyword.remove; +Ajv.prototype.validateKeyword = customKeyword.validate; + +var errorClasses = require('./compile/error_classes'); +Ajv.ValidationError = errorClasses.Validation; +Ajv.MissingRefError = errorClasses.MissingRef; +Ajv.$dataMetaSchema = $dataMetaSchema; + +var META_SCHEMA_ID = 'http://json-schema.org/draft-07/schema'; + +var META_IGNORE_OPTIONS = [ 'removeAdditional', 'useDefaults', 'coerceTypes', 'strictDefaults' ]; +var META_SUPPORT_DATA = ['/properties']; + +/** + * Creates validator instance. + * Usage: `Ajv(opts)` + * @param {Object} opts optional options + * @return {Object} ajv instance + */ +function Ajv(opts) { + if (!(this instanceof Ajv)) return new Ajv(opts); + opts = this._opts = util.copy(opts) || {}; + setLogger(this); + this._schemas = {}; + this._refs = {}; + this._fragments = {}; + this._formats = formats(opts.format); + + this._cache = opts.cache || new Cache; + this._loadingSchemas = {}; + this._compilations = []; + this.RULES = rules(); + this._getId = chooseGetId(opts); + + opts.loopRequired = opts.loopRequired || Infinity; + if (opts.errorDataPath == 'property') opts._errorDataPathProperty = true; + if (opts.serialize === undefined) opts.serialize = stableStringify; + this._metaOpts = getMetaSchemaOptions(this); + + if (opts.formats) addInitialFormats(this); + addDefaultMetaSchema(this); + if (typeof opts.meta == 'object') this.addMetaSchema(opts.meta); + if (opts.nullable) this.addKeyword('nullable', {metaSchema: {type: 'boolean'}}); + addInitialSchemas(this); +} + + + +/** + * Validate data using schema + * Schema will be compiled and cached (using serialized JSON as key. [fast-json-stable-stringify](https://github.com/epoberezkin/fast-json-stable-stringify) is used to serialize. + * @this Ajv + * @param {String|Object} schemaKeyRef key, ref or schema object + * @param {Any} data to be validated + * @return {Boolean} validation result. Errors from the last validation will be available in `ajv.errors` (and also in compiled schema: `schema.errors`). + */ +function validate(schemaKeyRef, data) { + var v; + if (typeof schemaKeyRef == 'string') { + v = this.getSchema(schemaKeyRef); + if (!v) throw new Error('no schema with key or ref "' + schemaKeyRef + '"'); + } else { + var schemaObj = this._addSchema(schemaKeyRef); + v = schemaObj.validate || this._compile(schemaObj); + } + + var valid = v(data); + if (v.$async !== true) this.errors = v.errors; + return valid; +} + + +/** + * Create validating function for passed schema. + * @this Ajv + * @param {Object} schema schema object + * @param {Boolean} _meta true if schema is a meta-schema. Used internally to compile meta schemas of custom keywords. + * @return {Function} validating function + */ +function compile(schema, _meta) { + var schemaObj = this._addSchema(schema, undefined, _meta); + return schemaObj.validate || this._compile(schemaObj); +} + + +/** + * Adds schema to the instance. + * @this Ajv + * @param {Object|Array} schema schema or array of schemas. If array is passed, `key` and other parameters will be ignored. + * @param {String} key Optional schema key. Can be passed to `validate` method instead of schema object or id/ref. One schema per instance can have empty `id` and `key`. + * @param {Boolean} _skipValidation true to skip schema validation. Used internally, option validateSchema should be used instead. + * @param {Boolean} _meta true if schema is a meta-schema. Used internally, addMetaSchema should be used instead. + * @return {Ajv} this for method chaining + */ +function addSchema(schema, key, _skipValidation, _meta) { + if (Array.isArray(schema)){ + for (var i=0; i} errors optional array of validation errors, if not passed errors from the instance are used. + * @param {Object} options optional options with properties `separator` and `dataVar`. + * @return {String} human readable string with all errors descriptions + */ +function errorsText(errors, options) { + errors = errors || this.errors; + if (!errors) return 'No errors'; + options = options || {}; + var separator = options.separator === undefined ? ', ' : options.separator; + var dataVar = options.dataVar === undefined ? 'data' : options.dataVar; + + var text = ''; + for (var i=0; i%\\^`{|}]|%[0-9a-f]{2})|\{[+#./;?&=,!@|]?(?:[a-z0-9_]|%[0-9a-f]{2})+(?::[1-9][0-9]{0,3}|\*)?(?:,(?:[a-z0-9_]|%[0-9a-f]{2})+(?::[1-9][0-9]{0,3}|\*)?)*\})*$/i,u=/^(?:(?:http[s\u017F]?|ftp):\/\/)(?:(?:[\0-\x08\x0E-\x1F!-\x9F\xA1-\u167F\u1681-\u1FFF\u200B-\u2027\u202A-\u202E\u2030-\u205E\u2060-\u2FFF\u3001-\uD7FF\uE000-\uFEFE\uFF00-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])+(?::(?:[\0-\x08\x0E-\x1F!-\x9F\xA1-\u167F\u1681-\u1FFF\u200B-\u2027\u202A-\u202E\u2030-\u205E\u2060-\u2FFF\u3001-\uD7FF\uE000-\uFEFE\uFF00-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])*)?@)?(?:(?!10(?:\.[0-9]{1,3}){3})(?!127(?:\.[0-9]{1,3}){3})(?!169\.254(?:\.[0-9]{1,3}){2})(?!192\.168(?:\.[0-9]{1,3}){2})(?!172\.(?:1[6-9]|2[0-9]|3[01])(?:\.[0-9]{1,3}){2})(?:[1-9][0-9]?|1[0-9][0-9]|2[01][0-9]|22[0-3])(?:\.(?:1?[0-9]{1,2}|2[0-4][0-9]|25[0-5])){2}(?:\.(?:[1-9][0-9]?|1[0-9][0-9]|2[0-4][0-9]|25[0-4]))|(?:(?:(?:[0-9KSa-z\xA1-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])+-?)*(?:[0-9KSa-z\xA1-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])+)(?:\.(?:(?:[0-9KSa-z\xA1-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])+-?)*(?:[0-9KSa-z\xA1-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])+)*(?:\.(?:(?:[KSa-z\xA1-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]){2,})))(?::[0-9]{2,5})?(?:\/(?:[\0-\x08\x0E-\x1F!-\x9F\xA1-\u167F\u1681-\u1FFF\u200B-\u2027\u202A-\u202E\u2030-\u205E\u2060-\u2FFF\u3001-\uD7FF\uE000-\uFEFE\uFF00-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])*)?$/i,h=/^(?:urn:uuid:)?[0-9a-f]{8}-(?:[0-9a-f]{4}-){3}[0-9a-f]{12}$/i,d=/^(?:\/(?:[^~/]|~0|~1)*)*$/,f=/^#(?:\/(?:[a-z0-9_\-.!$&'()*+,;:=@]|%[0-9a-f]{2}|~0|~1)*)*$/i,p=/^(?:0|[1-9][0-9]*)(?:#|(?:\/(?:[^~/]|~0|~1)*)*)$/;function m(e){return a.copy(m[e="full"==e?"full":"fast"])}function v(e){var r=e.match(o);if(!r)return!1;var t,a=+r[2],s=+r[3];return 1<=a&&a<=12&&1<=s&&s<=(2!=a||((t=+r[1])%4!=0||t%100==0&&t%400!=0)?i[a]:29)}function y(e,r){var t=e.match(n);if(!t)return!1;var a=t[1],s=t[2],o=t[3];return(a<=23&&s<=59&&o<=59||23==a&&59==s&&60==o)&&(!r||t[5])}(r.exports=m).fast={date:/^\d\d\d\d-[0-1]\d-[0-3]\d$/,time:/^(?:[0-2]\d:[0-5]\d:[0-5]\d|23:59:60)(?:\.\d+)?(?:z|[+-]\d\d:\d\d)?$/i,"date-time":/^\d\d\d\d-[0-1]\d-[0-3]\d[t\s](?:[0-2]\d:[0-5]\d:[0-5]\d|23:59:60)(?:\.\d+)?(?:z|[+-]\d\d:\d\d)$/i,uri:/^(?:[a-z][a-z0-9+-.]*:)(?:\/?\/)?[^\s]*$/i,"uri-reference":/^(?:(?:[a-z][a-z0-9+-.]*:)?\/?\/)?(?:[^\\\s#][^\s#]*)?(?:#[^\\\s]*)?$/i,"uri-template":c,url:u,email:/^[a-z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)*$/i,hostname:s,ipv4:/^(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)$/,ipv6:/^\s*(?:(?:(?:[0-9a-f]{1,4}:){7}(?:[0-9a-f]{1,4}|:))|(?:(?:[0-9a-f]{1,4}:){6}(?::[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(?:(?:[0-9a-f]{1,4}:){5}(?:(?:(?::[0-9a-f]{1,4}){1,2})|:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(?:(?:[0-9a-f]{1,4}:){4}(?:(?:(?::[0-9a-f]{1,4}){1,3})|(?:(?::[0-9a-f]{1,4})?:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[0-9a-f]{1,4}:){3}(?:(?:(?::[0-9a-f]{1,4}){1,4})|(?:(?::[0-9a-f]{1,4}){0,2}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[0-9a-f]{1,4}:){2}(?:(?:(?::[0-9a-f]{1,4}){1,5})|(?:(?::[0-9a-f]{1,4}){0,3}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[0-9a-f]{1,4}:){1}(?:(?:(?::[0-9a-f]{1,4}){1,6})|(?:(?::[0-9a-f]{1,4}){0,4}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?::(?:(?:(?::[0-9a-f]{1,4}){1,7})|(?:(?::[0-9a-f]{1,4}){0,5}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(?:%.+)?\s*$/i,regex:w,uuid:h,"json-pointer":d,"json-pointer-uri-fragment":f,"relative-json-pointer":p},m.full={date:v,time:y,"date-time":function(e){var r=e.split(g);return 2==r.length&&v(r[0])&&y(r[1],!0)},uri:function(e){return P.test(e)&&l.test(e)},"uri-reference":/^(?:[a-z][a-z0-9+\-.]*:)?(?:\/?\/(?:(?:[a-z0-9\-._~!$&'()*+,;=:]|%[0-9a-f]{2})*@)?(?:\[(?:(?:(?:(?:[0-9a-f]{1,4}:){6}|::(?:[0-9a-f]{1,4}:){5}|(?:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){4}|(?:(?:[0-9a-f]{1,4}:){0,1}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){3}|(?:(?:[0-9a-f]{1,4}:){0,2}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){2}|(?:(?:[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?::[0-9a-f]{1,4}:|(?:(?:[0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?::)(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?))|(?:(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4})?::[0-9a-f]{1,4}|(?:(?:[0-9a-f]{1,4}:){0,6}[0-9a-f]{1,4})?::)|[Vv][0-9a-f]+\.[a-z0-9\-._~!$&'()*+,;=:]+)\]|(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)|(?:[a-z0-9\-._~!$&'"()*+,;=]|%[0-9a-f]{2})*)(?::\d*)?(?:\/(?:[a-z0-9\-._~!$&'"()*+,;=:@]|%[0-9a-f]{2})*)*|\/(?:(?:[a-z0-9\-._~!$&'"()*+,;=:@]|%[0-9a-f]{2})+(?:\/(?:[a-z0-9\-._~!$&'"()*+,;=:@]|%[0-9a-f]{2})*)*)?|(?:[a-z0-9\-._~!$&'"()*+,;=:@]|%[0-9a-f]{2})+(?:\/(?:[a-z0-9\-._~!$&'"()*+,;=:@]|%[0-9a-f]{2})*)*)?(?:\?(?:[a-z0-9\-._~!$&'"()*+,;=:@/?]|%[0-9a-f]{2})*)?(?:#(?:[a-z0-9\-._~!$&'"()*+,;=:@/?]|%[0-9a-f]{2})*)?$/i,"uri-template":c,url:u,email:/^[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/i,hostname:function(e){return e.length<=255&&s.test(e)},ipv4:/^(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)$/,ipv6:/^\s*(?:(?:(?:[0-9a-f]{1,4}:){7}(?:[0-9a-f]{1,4}|:))|(?:(?:[0-9a-f]{1,4}:){6}(?::[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(?:(?:[0-9a-f]{1,4}:){5}(?:(?:(?::[0-9a-f]{1,4}){1,2})|:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(?:(?:[0-9a-f]{1,4}:){4}(?:(?:(?::[0-9a-f]{1,4}){1,3})|(?:(?::[0-9a-f]{1,4})?:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[0-9a-f]{1,4}:){3}(?:(?:(?::[0-9a-f]{1,4}){1,4})|(?:(?::[0-9a-f]{1,4}){0,2}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[0-9a-f]{1,4}:){2}(?:(?:(?::[0-9a-f]{1,4}){1,5})|(?:(?::[0-9a-f]{1,4}){0,3}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[0-9a-f]{1,4}:){1}(?:(?:(?::[0-9a-f]{1,4}){1,6})|(?:(?::[0-9a-f]{1,4}){0,4}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?::(?:(?:(?::[0-9a-f]{1,4}){1,7})|(?:(?::[0-9a-f]{1,4}){0,5}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(?:%.+)?\s*$/i,regex:w,uuid:h,"json-pointer":d,"json-pointer-uri-fragment":f,"relative-json-pointer":p};var g=/t|\s/i;var P=/\/|:/;var E=/[^\\]\\Z/;function w(e){if(E.test(e))return!1;try{return new RegExp(e),!0}catch(e){return!1}}},{"./util":10}],5:[function(e,r,t){"use strict";var $=e("./resolve"),D=e("./util"),j=e("./error_classes"),O=e("fast-json-stable-stringify"),I=e("../dotjs/validate"),A=D.ucs2length,C=e("fast-deep-equal"),k=j.Validation;function L(e,r,t){var a=s.call(this,e,r,t);return 0<=a?{index:a,compiling:!0}:{index:a=this._compilations.length,compiling:!(this._compilations[a]={schema:e,root:r,baseId:t})}}function z(e,r,t){var a=s.call(this,e,r,t);0<=a&&this._compilations.splice(a,1)}function s(e,r,t){for(var a=0;a",g=f?">":"<",P=void 0;if(v){var E=e.util.getData(m.$data,i,e.dataPathArr),w="exclusive"+o,b="exclType"+o,S="exclIsNumber"+o,_="' + "+(R="op"+o)+" + '";s+=" var schemaExcl"+o+" = "+E+"; ";var F;P=p;(F=F||[]).push(s+=" var "+w+"; var "+b+" = typeof "+(E="schemaExcl"+o)+"; if ("+b+" != 'boolean' && "+b+" != 'undefined' && "+b+" != 'number') { "),s="",!1!==e.createErrors?(s+=" { keyword: '"+(P||"_exclusiveLimit")+"' , dataPath: (dataPath || '') + "+e.errorPath+" , schemaPath: "+e.util.toQuotedString(c)+" , params: {} ",!1!==e.opts.messages&&(s+=" , message: '"+p+" should be boolean' "),e.opts.verbose&&(s+=" , schema: validate.schema"+l+" , parentSchema: validate.schema"+e.schemaPath+" , data: "+h+" "),s+=" } "):s+=" {} ";var x=s;s=F.pop(),s+=!e.compositeRule&&u?e.async?" throw new ValidationError(["+x+"]); ":" validate.errors = ["+x+"]; return false; ":" var err = "+x+"; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ",s+=" } else if ( ",d&&(s+=" ("+a+" !== undefined && typeof "+a+" != 'number') || "),s+=" "+b+" == 'number' ? ( ("+w+" = "+a+" === undefined || "+E+" "+y+"= "+a+") ? "+h+" "+g+"= "+E+" : "+h+" "+g+" "+a+" ) : ( ("+w+" = "+E+" === true) ? "+h+" "+g+"= "+a+" : "+h+" "+g+" "+a+" ) || "+h+" !== "+h+") { var op"+o+" = "+w+" ? '"+y+"' : '"+y+"='; ",void 0===n&&(c=e.errSchemaPath+"/"+(P=p),a=E,d=v)}else{_=y;if((S="number"==typeof m)&&d){var R="'"+_+"'";s+=" if ( ",d&&(s+=" ("+a+" !== undefined && typeof "+a+" != 'number') || "),s+=" ( "+a+" === undefined || "+m+" "+y+"= "+a+" ? "+h+" "+g+"= "+m+" : "+h+" "+g+" "+a+" ) || "+h+" !== "+h+") { "}else{S&&void 0===n?(w=!0,c=e.errSchemaPath+"/"+(P=p),a=m,g+="="):(S&&(a=Math[f?"min":"max"](m,n)),m===(!S||a)?(w=!0,c=e.errSchemaPath+"/"+(P=p),g+="="):(w=!1,_+="="));R="'"+_+"'";s+=" if ( ",d&&(s+=" ("+a+" !== undefined && typeof "+a+" != 'number') || "),s+=" "+h+" "+g+" "+a+" || "+h+" !== "+h+") { "}}P=P||r,(F=F||[]).push(s),s="",!1!==e.createErrors?(s+=" { keyword: '"+(P||"_limit")+"' , dataPath: (dataPath || '') + "+e.errorPath+" , schemaPath: "+e.util.toQuotedString(c)+" , params: { comparison: "+R+", limit: "+a+", exclusive: "+w+" } ",!1!==e.opts.messages&&(s+=" , message: 'should be "+_+" ",s+=d?"' + "+a:a+"'"),e.opts.verbose&&(s+=" , schema: ",s+=d?"validate.schema"+l:""+n,s+=" , parentSchema: validate.schema"+e.schemaPath+" , data: "+h+" "),s+=" } "):s+=" {} ";x=s;return s=F.pop(),s+=!e.compositeRule&&u?e.async?" throw new ValidationError(["+x+"]); ":" validate.errors = ["+x+"]; return false; ":" var err = "+x+"; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ",s+=" } ",u&&(s+=" else { "),s}},{}],14:[function(e,r,t){"use strict";r.exports=function(e,r,t){var a,s=" ",o=e.level,i=e.dataLevel,n=e.schema[r],l=e.schemaPath+e.util.getProperty(r),c=e.errSchemaPath+"/"+r,u=!e.opts.allErrors,h="data"+(i||""),d=e.opts.$data&&n&&n.$data;a=d?(s+=" var schema"+o+" = "+e.util.getData(n.$data,i,e.dataPathArr)+"; ","schema"+o):n,s+="if ( ",d&&(s+=" ("+a+" !== undefined && typeof "+a+" != 'number') || ");var f=r,p=p||[];p.push(s+=" "+h+".length "+("maxItems"==r?">":"<")+" "+a+") { "),s="",!1!==e.createErrors?(s+=" { keyword: '"+(f||"_limitItems")+"' , dataPath: (dataPath || '') + "+e.errorPath+" , schemaPath: "+e.util.toQuotedString(c)+" , params: { limit: "+a+" } ",!1!==e.opts.messages&&(s+=" , message: 'should NOT have ",s+="maxItems"==r?"more":"fewer",s+=" than ",s+=d?"' + "+a+" + '":""+n,s+=" items' "),e.opts.verbose&&(s+=" , schema: ",s+=d?"validate.schema"+l:""+n,s+=" , parentSchema: validate.schema"+e.schemaPath+" , data: "+h+" "),s+=" } "):s+=" {} ";var m=s;return s=p.pop(),s+=!e.compositeRule&&u?e.async?" throw new ValidationError(["+m+"]); ":" validate.errors = ["+m+"]; return false; ":" var err = "+m+"; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ",s+="} ",u&&(s+=" else { "),s}},{}],15:[function(e,r,t){"use strict";r.exports=function(e,r,t){var a,s=" ",o=e.level,i=e.dataLevel,n=e.schema[r],l=e.schemaPath+e.util.getProperty(r),c=e.errSchemaPath+"/"+r,u=!e.opts.allErrors,h="data"+(i||""),d=e.opts.$data&&n&&n.$data;a=d?(s+=" var schema"+o+" = "+e.util.getData(n.$data,i,e.dataPathArr)+"; ","schema"+o):n,s+="if ( ",d&&(s+=" ("+a+" !== undefined && typeof "+a+" != 'number') || "),s+=!1===e.opts.unicode?" "+h+".length ":" ucs2length("+h+") ";var f=r,p=p||[];p.push(s+=" "+("maxLength"==r?">":"<")+" "+a+") { "),s="",!1!==e.createErrors?(s+=" { keyword: '"+(f||"_limitLength")+"' , dataPath: (dataPath || '') + "+e.errorPath+" , schemaPath: "+e.util.toQuotedString(c)+" , params: { limit: "+a+" } ",!1!==e.opts.messages&&(s+=" , message: 'should NOT be ",s+="maxLength"==r?"longer":"shorter",s+=" than ",s+=d?"' + "+a+" + '":""+n,s+=" characters' "),e.opts.verbose&&(s+=" , schema: ",s+=d?"validate.schema"+l:""+n,s+=" , parentSchema: validate.schema"+e.schemaPath+" , data: "+h+" "),s+=" } "):s+=" {} ";var m=s;return s=p.pop(),s+=!e.compositeRule&&u?e.async?" throw new ValidationError(["+m+"]); ":" validate.errors = ["+m+"]; return false; ":" var err = "+m+"; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ",s+="} ",u&&(s+=" else { "),s}},{}],16:[function(e,r,t){"use strict";r.exports=function(e,r,t){var a,s=" ",o=e.level,i=e.dataLevel,n=e.schema[r],l=e.schemaPath+e.util.getProperty(r),c=e.errSchemaPath+"/"+r,u=!e.opts.allErrors,h="data"+(i||""),d=e.opts.$data&&n&&n.$data;a=d?(s+=" var schema"+o+" = "+e.util.getData(n.$data,i,e.dataPathArr)+"; ","schema"+o):n,s+="if ( ",d&&(s+=" ("+a+" !== undefined && typeof "+a+" != 'number') || ");var f=r,p=p||[];p.push(s+=" Object.keys("+h+").length "+("maxProperties"==r?">":"<")+" "+a+") { "),s="",!1!==e.createErrors?(s+=" { keyword: '"+(f||"_limitProperties")+"' , dataPath: (dataPath || '') + "+e.errorPath+" , schemaPath: "+e.util.toQuotedString(c)+" , params: { limit: "+a+" } ",!1!==e.opts.messages&&(s+=" , message: 'should NOT have ",s+="maxProperties"==r?"more":"fewer",s+=" than ",s+=d?"' + "+a+" + '":""+n,s+=" properties' "),e.opts.verbose&&(s+=" , schema: ",s+=d?"validate.schema"+l:""+n,s+=" , parentSchema: validate.schema"+e.schemaPath+" , data: "+h+" "),s+=" } "):s+=" {} ";var m=s;return s=p.pop(),s+=!e.compositeRule&&u?e.async?" throw new ValidationError(["+m+"]); ":" validate.errors = ["+m+"]; return false; ":" var err = "+m+"; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ",s+="} ",u&&(s+=" else { "),s}},{}],17:[function(e,r,t){"use strict";r.exports=function(e,r,t){var a=" ",s=e.schema[r],o=e.schemaPath+e.util.getProperty(r),i=e.errSchemaPath+"/"+r,n=!e.opts.allErrors,l=e.util.copy(e),c="";l.level++;var u="valid"+l.level,h=l.baseId,d=!0,f=s;if(f)for(var p,m=-1,v=f.length-1;m "+x+") { ";var $=u+"["+x+"]";f.schema=F,f.schemaPath=n+"["+x+"]",f.errSchemaPath=l+"/"+x,f.errorPath=e.util.getPathExpr(e.errorPath,x,e.opts.jsonPointers,!0),f.dataPathArr[y]=x;var D=e.validate(f);f.baseId=P,e.util.varOccurences(D,g)<2?a+=" "+e.util.varReplace(D,g,$)+" ":a+=" var "+g+" = "+$+"; "+D+" ",a+=" } ",c&&(a+=" if ("+m+") { ",p+="}")}if("object"==typeof E&&(e.opts.strictKeywords?"object"==typeof E&&0 "+i.length+") { for (var "+v+" = "+i.length+"; "+v+" < "+u+".length; "+v+"++) { ",f.errorPath=e.util.getPathExpr(e.errorPath,v,e.opts.jsonPointers,!0);$=u+"["+v+"]";f.dataPathArr[y]=v;D=e.validate(f);f.baseId=P,e.util.varOccurences(D,g)<2?a+=" "+e.util.varReplace(D,g,$)+" ":a+=" var "+g+" = "+$+"; "+D+" ",c&&(a+=" if (!"+m+") break; "),a+=" } } ",c&&(a+=" if ("+m+") { ",p+="}")}}else if(e.opts.strictKeywords?"object"==typeof i&&0 1e-"+e.opts.multipleOfPrecision+" ":" division"+o+" !== parseInt(division"+o+") ",s+=" ) ",d&&(s+=" ) ");var f=f||[];f.push(s+=" ) { "),s="",!1!==e.createErrors?(s+=" { keyword: 'multipleOf' , dataPath: (dataPath || '') + "+e.errorPath+" , schemaPath: "+e.util.toQuotedString(c)+" , params: { multipleOf: "+a+" } ",!1!==e.opts.messages&&(s+=" , message: 'should be multiple of ",s+=d?"' + "+a:a+"'"),e.opts.verbose&&(s+=" , schema: ",s+=d?"validate.schema"+l:""+n,s+=" , parentSchema: validate.schema"+e.schemaPath+" , data: "+h+" "),s+=" } "):s+=" {} ";var p=s;return s=f.pop(),s+=!e.compositeRule&&u?e.async?" throw new ValidationError(["+p+"]); ":" validate.errors = ["+p+"]; return false; ":" var err = "+p+"; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ",s+="} ",u&&(s+=" else { "),s}},{}],30:[function(e,r,t){"use strict";r.exports=function(e,r,t){var a=" ",s=e.level,o=e.dataLevel,i=e.schema[r],n=e.schemaPath+e.util.getProperty(r),l=e.errSchemaPath+"/"+r,c=!e.opts.allErrors,u="data"+(o||""),h="errs__"+s,d=e.util.copy(e);d.level++;var f="valid"+d.level;if(e.opts.strictKeywords?"object"==typeof i&&0 1) { ";var p=e.schema.items&&e.schema.items.type,m=Array.isArray(p);if(!p||"object"==p||"array"==p||m&&(0<=p.indexOf("object")||0<=p.indexOf("array")))s+=" outer: for (;i--;) { for (j = i; j--;) { if (equal("+h+"[i], "+h+"[j])) { "+d+" = false; break outer; } } } ";else s+=" var itemIndices = {}, item; for (;i--;) { var item = "+h+"[i]; ",s+=" if ("+e.util["checkDataType"+(m?"s":"")](p,"item",!0)+") continue; ",m&&(s+=" if (typeof item == 'string') item = '\"' + item; "),s+=" if (typeof itemIndices[item] == 'number') { "+d+" = false; j = itemIndices[item]; break; } itemIndices[item] = i; } ";s+=" } ",f&&(s+=" } ");var v=v||[];v.push(s+=" if (!"+d+") { "),s="",!1!==e.createErrors?(s+=" { keyword: 'uniqueItems' , dataPath: (dataPath || '') + "+e.errorPath+" , schemaPath: "+e.util.toQuotedString(c)+" , params: { i: i, j: j } ",!1!==e.opts.messages&&(s+=" , message: 'should NOT have duplicate items (items ## ' + j + ' and ' + i + ' are identical)' "),e.opts.verbose&&(s+=" , schema: ",s+=f?"validate.schema"+l:""+n,s+=" , parentSchema: validate.schema"+e.schemaPath+" , data: "+h+" "),s+=" } "):s+=" {} ";var y=s;s=v.pop(),s+=!e.compositeRule&&u?e.async?" throw new ValidationError(["+y+"]); ":" validate.errors = ["+y+"]; return false; ":" var err = "+y+"; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ",s+=" } ",u&&(s+=" else { ")}else u&&(s+=" if (true) { ");return s}},{}],38:[function(e,r,t){"use strict";r.exports=function(a,e,r){var t="",s=!0===a.schema.$async,o=a.util.schemaHasRulesExcept(a.schema,a.RULES.all,"$ref"),i=a.self._getId(a.schema);if(a.opts.strictKeywords){var n=a.util.schemaUnknownRules(a.schema,a.RULES.keywords);if(n){var l="unknown keyword: "+n;if("log"!==a.opts.strictKeywords)throw new Error(l);a.logger.warn(l)}}if(a.isTop&&(t+=" var validate = ",s&&(a.async=!0,t+="async "),t+="function(data, dataPath, parentData, parentDataProperty, rootData) { 'use strict'; ",i&&(a.opts.sourceCode||a.opts.processCode)&&(t+=" /*# sourceURL="+i+" */ ")),"boolean"==typeof a.schema||!o&&!a.schema.$ref){var c=a.level,u=a.dataLevel,h=a.schema[e="false schema"],d=a.schemaPath+a.util.getProperty(e),f=a.errSchemaPath+"/"+e,p=!a.opts.allErrors,m="data"+(u||""),v="valid"+c;if(!1===a.schema){a.isTop?p=!0:t+=" var "+v+" = false; ",(G=G||[]).push(t),t="",!1!==a.createErrors?(t+=" { keyword: 'false schema' , dataPath: (dataPath || '') + "+a.errorPath+" , schemaPath: "+a.util.toQuotedString(f)+" , params: {} ",!1!==a.opts.messages&&(t+=" , message: 'boolean schema is false' "),a.opts.verbose&&(t+=" , schema: false , parentSchema: validate.schema"+a.schemaPath+" , data: "+m+" "),t+=" } "):t+=" {} ";var y=t;t=G.pop(),t+=!a.compositeRule&&p?a.async?" throw new ValidationError(["+y+"]); ":" validate.errors = ["+y+"]; return false; ":" var err = "+y+"; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; "}else t+=a.isTop?s?" return data; ":" validate.errors = null; return true; ":" var "+v+" = true; ";return a.isTop&&(t+=" }; return validate; "),t}if(a.isTop){var g=a.isTop;c=a.level=0,u=a.dataLevel=0,m="data";if(a.rootId=a.resolve.fullPath(a.self._getId(a.root.schema)),a.baseId=a.baseId||a.rootId,delete a.isTop,a.dataPathArr=[void 0],void 0!==a.schema.default&&a.opts.useDefaults&&a.opts.strictDefaults){var P="default is ignored in the schema root";if("log"!==a.opts.strictDefaults)throw new Error(P);a.logger.warn(P)}t+=" var vErrors = null; ",t+=" var errors = 0; ",t+=" if (rootData === undefined) rootData = data; "}else{c=a.level,m="data"+((u=a.dataLevel)||"");if(i&&(a.baseId=a.resolve.url(a.baseId,i)),s&&!a.async)throw new Error("async schema in sync schema");t+=" var errs_"+c+" = errors;"}v="valid"+c,p=!a.opts.allErrors;var E="",w="",b=a.schema.type,S=Array.isArray(b);if(b&&a.opts.nullable&&!0===a.schema.nullable&&(S?-1==b.indexOf("null")&&(b=b.concat("null")):"null"!=b&&(b=[b,"null"],S=!0)),S&&1==b.length&&(b=b[0],S=!1),a.schema.$ref&&o){if("fail"==a.opts.extendRefs)throw new Error('$ref: validation keywords used in schema at path "'+a.errSchemaPath+'" (see option extendRefs)');!0!==a.opts.extendRefs&&(o=!1,a.logger.warn('$ref: keywords ignored in schema at path "'+a.errSchemaPath+'"'))}if(a.schema.$comment&&a.opts.$comment&&(t+=" "+a.RULES.all.$comment.code(a,"$comment")),b){if(a.opts.coerceTypes)var _=a.util.coerceToTypes(a.opts.coerceTypes,b);var F=a.RULES.types[b];if(_||S||!0===F||F&&!Y(F)){d=a.schemaPath+".type",f=a.errSchemaPath+"/type",d=a.schemaPath+".type",f=a.errSchemaPath+"/type";if(t+=" if ("+a.util[S?"checkDataTypes":"checkDataType"](b,m,!0)+") { ",_){var x="dataType"+c,R="coerced"+c;t+=" var "+x+" = typeof "+m+"; ","array"==a.opts.coerceTypes&&(t+=" if ("+x+" == 'object' && Array.isArray("+m+")) "+x+" = 'array'; "),t+=" var "+R+" = undefined; ";var $="",D=_;if(D)for(var j,O=-1,I=D.length-1;O= 0x80 (not a basic code point)","invalid-input":"Invalid input"},L=Math.floor,z=String.fromCharCode;function T(e){throw new RangeError(i[e])}function n(e,r){var t=e.split("@"),a="";return 1>1,e+=L(e/r);455L((A-s)/h))&&T("overflow"),s+=f*h;var p=d<=i?1:i+26<=d?26:d-i;if(fL(A/m)&&T("overflow"),h*=m}var v=t.length+1;i=Q(s-u,v,0==u),L(s/v)>A-o&&T("overflow"),o+=L(s/v),s%=v,t.splice(s++,0,o)}return String.fromCodePoint.apply(String,t)},c=function(e){var r=[],t=(e=q(e)).length,a=128,s=0,o=72,i=!0,n=!1,l=void 0;try{for(var c,u=e[Symbol.iterator]();!(i=(c=u.next()).done);i=!0){var h=c.value;h<128&&r.push(z(h))}}catch(e){n=!0,l=e}finally{try{!i&&u.return&&u.return()}finally{if(n)throw l}}var d=r.length,f=d;for(d&&r.push("-");fL((A-s)/w)&&T("overflow"),s+=(p-a)*w,a=p;var b=!0,S=!1,_=void 0;try{for(var F,x=e[Symbol.iterator]();!(b=(F=x.next()).done);b=!0){var R=F.value;if(RA&&T("overflow"),R==a){for(var $=s,D=36;;D+=36){var j=D<=o?1:o+26<=D?26:D-o;if($>6|192).toString(16).toUpperCase()+"%"+(63&r|128).toString(16).toUpperCase():"%"+(r>>12|224).toString(16).toUpperCase()+"%"+(r>>6&63|128).toString(16).toUpperCase()+"%"+(63&r|128).toString(16).toUpperCase()}function f(e){for(var r="",t=0,a=e.length;tA-Z\\x5E-\\x7E]",'[\\"\\\\]'),Z=new RegExp(K,"g"),G=new RegExp(B,"g"),Y=new RegExp(C("[^]","[A-Za-z0-9\\!\\$\\%\\'\\*\\+\\-\\^\\_\\`\\{\\|\\}\\~]","[\\.]",'[\\"]',J),"g"),W=new RegExp(C("[^]",K,"[\\!\\$\\'\\(\\)\\*\\+\\,\\;\\:\\@]"),"g"),X=W;function ee(e){var r=f(e);return r.match(Z)?r:e}var re={scheme:"mailto",parse:function(e,r){var t=e,a=t.to=t.path?t.path.split(","):[];if(t.path=void 0,t.query){for(var s=!1,o={},i=t.query.split("&"),n=0,l=i.length;n); + + message: string; + errors: Array; + ajv: true; + validation: true; + } + + class MissingRefError extends Error { + constructor(baseId: string, ref: string, message?: string); + static message: (baseId: string, ref: string) => string; + + message: string; + missingRef: string; + missingSchema: string; + } +} + +declare namespace ajv { + type ValidationError = AjvErrors.ValidationError; + + type MissingRefError = AjvErrors.MissingRefError; + + interface Ajv { + /** + * Validate data using schema + * Schema will be compiled and cached (using serialized JSON as key, [fast-json-stable-stringify](https://github.com/epoberezkin/fast-json-stable-stringify) is used to serialize by default). + * @param {string|object|Boolean} schemaKeyRef key, ref or schema object + * @param {Any} data to be validated + * @return {Boolean} validation result. Errors from the last validation will be available in `ajv.errors` (and also in compiled schema: `schema.errors`). + */ + validate(schemaKeyRef: object | string | boolean, data: any): boolean | PromiseLike; + /** + * Create validating function for passed schema. + * @param {object|Boolean} schema schema object + * @return {Function} validating function + */ + compile(schema: object | boolean): ValidateFunction; + /** + * Creates validating function for passed schema with asynchronous loading of missing schemas. + * `loadSchema` option should be a function that accepts schema uri and node-style callback. + * @this Ajv + * @param {object|Boolean} schema schema object + * @param {Boolean} meta optional true to compile meta-schema; this parameter can be skipped + * @param {Function} callback optional node-style callback, it is always called with 2 parameters: error (or null) and validating function. + * @return {PromiseLike} validating function + */ + compileAsync(schema: object | boolean, meta?: Boolean, callback?: (err: Error, validate: ValidateFunction) => any): PromiseLike; + /** + * Adds schema to the instance. + * @param {object|Array} schema schema or array of schemas. If array is passed, `key` and other parameters will be ignored. + * @param {string} key Optional schema key. Can be passed to `validate` method instead of schema object or id/ref. One schema per instance can have empty `id` and `key`. + * @return {Ajv} this for method chaining + */ + addSchema(schema: Array | object, key?: string): Ajv; + /** + * Add schema that will be used to validate other schemas + * options in META_IGNORE_OPTIONS are alway set to false + * @param {object} schema schema object + * @param {string} key optional schema key + * @return {Ajv} this for method chaining + */ + addMetaSchema(schema: object, key?: string): Ajv; + /** + * Validate schema + * @param {object|Boolean} schema schema to validate + * @return {Boolean} true if schema is valid + */ + validateSchema(schema: object | boolean): boolean; + /** + * Get compiled schema from the instance by `key` or `ref`. + * @param {string} keyRef `key` that was passed to `addSchema` or full schema reference (`schema.id` or resolved id). + * @return {Function} schema validating function (with property `schema`). + */ + getSchema(keyRef: string): ValidateFunction; + /** + * Remove cached schema(s). + * If no parameter is passed all schemas but meta-schemas are removed. + * If RegExp is passed all schemas with key/id matching pattern but meta-schemas are removed. + * Even if schema is referenced by other schemas it still can be removed as other schemas have local references. + * @param {string|object|RegExp|Boolean} schemaKeyRef key, ref, pattern to match key/ref or schema object + * @return {Ajv} this for method chaining + */ + removeSchema(schemaKeyRef?: object | string | RegExp | boolean): Ajv; + /** + * Add custom format + * @param {string} name format name + * @param {string|RegExp|Function} format string is converted to RegExp; function should return boolean (true when valid) + * @return {Ajv} this for method chaining + */ + addFormat(name: string, format: FormatValidator | FormatDefinition): Ajv; + /** + * Define custom keyword + * @this Ajv + * @param {string} keyword custom keyword, should be a valid identifier, should be different from all standard, custom and macro keywords. + * @param {object} definition keyword definition object with properties `type` (type(s) which the keyword applies to), `validate` or `compile`. + * @return {Ajv} this for method chaining + */ + addKeyword(keyword: string, definition: KeywordDefinition): Ajv; + /** + * Get keyword definition + * @this Ajv + * @param {string} keyword pre-defined or custom keyword. + * @return {object|Boolean} custom keyword definition, `true` if it is a predefined keyword, `false` otherwise. + */ + getKeyword(keyword: string): object | boolean; + /** + * Remove keyword + * @this Ajv + * @param {string} keyword pre-defined or custom keyword. + * @return {Ajv} this for method chaining + */ + removeKeyword(keyword: string): Ajv; + /** + * Validate keyword + * @this Ajv + * @param {object} definition keyword definition object + * @param {boolean} throwError true to throw exception if definition is invalid + * @return {boolean} validation result + */ + validateKeyword(definition: KeywordDefinition, throwError: boolean): boolean; + /** + * Convert array of error message objects to string + * @param {Array} errors optional array of validation errors, if not passed errors from the instance are used. + * @param {object} options optional options with properties `separator` and `dataVar`. + * @return {string} human readable string with all errors descriptions + */ + errorsText(errors?: Array | null, options?: ErrorsTextOptions): string; + errors?: Array | null; + } + + interface CustomLogger { + log(...args: any[]): any; + warn(...args: any[]): any; + error(...args: any[]): any; + } + + interface ValidateFunction { + ( + data: any, + dataPath?: string, + parentData?: object | Array, + parentDataProperty?: string | number, + rootData?: object | Array + ): boolean | PromiseLike; + schema?: object | boolean; + errors?: null | Array; + refs?: object; + refVal?: Array; + root?: ValidateFunction | object; + $async?: true; + source?: object; + } + + interface Options { + $data?: boolean; + allErrors?: boolean; + verbose?: boolean; + jsonPointers?: boolean; + uniqueItems?: boolean; + unicode?: boolean; + format?: string; + formats?: object; + unknownFormats?: true | string[] | 'ignore'; + schemas?: Array | object; + schemaId?: '$id' | 'id' | 'auto'; + missingRefs?: true | 'ignore' | 'fail'; + extendRefs?: true | 'ignore' | 'fail'; + loadSchema?: (uri: string, cb?: (err: Error, schema: object) => void) => PromiseLike; + removeAdditional?: boolean | 'all' | 'failing'; + useDefaults?: boolean | 'empty' | 'shared'; + coerceTypes?: boolean | 'array'; + strictDefaults?: boolean | 'log'; + strictKeywords?: boolean | 'log'; + async?: boolean | string; + transpile?: string | ((code: string) => string); + meta?: boolean | object; + validateSchema?: boolean | 'log'; + addUsedSchema?: boolean; + inlineRefs?: boolean | number; + passContext?: boolean; + loopRequired?: number; + ownProperties?: boolean; + multipleOfPrecision?: boolean | number; + errorDataPath?: string, + messages?: boolean; + sourceCode?: boolean; + processCode?: (code: string) => string; + cache?: object; + logger?: CustomLogger | false; + nullable?: boolean; + serialize?: ((schema: object | boolean) => any) | false; + } + + type FormatValidator = string | RegExp | ((data: string) => boolean | PromiseLike); + type NumberFormatValidator = ((data: number) => boolean | PromiseLike); + + interface NumberFormatDefinition { + type: "number", + validate: NumberFormatValidator; + compare?: (data1: number, data2: number) => number; + async?: boolean; + } + + interface StringFormatDefinition { + type?: "string", + validate: FormatValidator; + compare?: (data1: string, data2: string) => number; + async?: boolean; + } + + type FormatDefinition = NumberFormatDefinition | StringFormatDefinition; + + interface KeywordDefinition { + type?: string | Array; + async?: boolean; + $data?: boolean; + errors?: boolean | string; + metaSchema?: object; + // schema: false makes validate not to expect schema (ValidateFunction) + schema?: boolean; + statements?: boolean; + dependencies?: Array; + modifying?: boolean; + valid?: boolean; + // one and only one of the following properties should be present + validate?: SchemaValidateFunction | ValidateFunction; + compile?: (schema: any, parentSchema: object, it: CompilationContext) => ValidateFunction; + macro?: (schema: any, parentSchema: object, it: CompilationContext) => object | boolean; + inline?: (it: CompilationContext, keyword: string, schema: any, parentSchema: object) => string; + } + + interface CompilationContext { + level: number; + dataLevel: number; + schema: any; + schemaPath: string; + baseId: string; + async: boolean; + opts: Options; + formats: { + [index: string]: FormatDefinition | undefined; + }; + compositeRule: boolean; + validate: (schema: object) => boolean; + util: { + copy(obj: any, target?: any): any; + toHash(source: string[]): { [index: string]: true | undefined }; + equal(obj: any, target: any): boolean; + getProperty(str: string): string; + schemaHasRules(schema: object, rules: any): string; + escapeQuotes(str: string): string; + toQuotedString(str: string): string; + getData(jsonPointer: string, dataLevel: number, paths: string[]): string; + escapeJsonPointer(str: string): string; + unescapeJsonPointer(str: string): string; + escapeFragment(str: string): string; + unescapeFragment(str: string): string; + }; + self: Ajv; + } + + interface SchemaValidateFunction { + ( + schema: any, + data: any, + parentSchema?: object, + dataPath?: string, + parentData?: object | Array, + parentDataProperty?: string | number, + rootData?: object | Array + ): boolean | PromiseLike; + errors?: Array; + } + + interface ErrorsTextOptions { + separator?: string; + dataVar?: string; + } + + interface ErrorObject { + keyword: string; + dataPath: string; + schemaPath: string; + params: ErrorParameters; + // Added to validation errors of propertyNames keyword schema + propertyName?: string; + // Excluded if messages set to false. + message?: string; + // These are added with the `verbose` option. + schema?: any; + parentSchema?: object; + data?: any; + } + + type ErrorParameters = RefParams | LimitParams | AdditionalPropertiesParams | + DependenciesParams | FormatParams | ComparisonParams | + MultipleOfParams | PatternParams | RequiredParams | + TypeParams | UniqueItemsParams | CustomParams | + PatternRequiredParams | PropertyNamesParams | + IfParams | SwitchParams | NoParams | EnumParams; + + interface RefParams { + ref: string; + } + + interface LimitParams { + limit: number; + } + + interface AdditionalPropertiesParams { + additionalProperty: string; + } + + interface DependenciesParams { + property: string; + missingProperty: string; + depsCount: number; + deps: string; + } + + interface FormatParams { + format: string + } + + interface ComparisonParams { + comparison: string; + limit: number | string; + exclusive: boolean; + } + + interface MultipleOfParams { + multipleOf: number; + } + + interface PatternParams { + pattern: string; + } + + interface RequiredParams { + missingProperty: string; + } + + interface TypeParams { + type: string; + } + + interface UniqueItemsParams { + i: number; + j: number; + } + + interface CustomParams { + keyword: string; + } + + interface PatternRequiredParams { + missingPattern: string; + } + + interface PropertyNamesParams { + propertyName: string; + } + + interface IfParams { + failingKeyword: string; + } + + interface SwitchParams { + caseIndex: number; + } + + interface NoParams { } + + interface EnumParams { + allowedValues: Array; + } +} + +export = ajv; diff --git a/user/themes/goku/node_modules/ajv/lib/ajv.js b/user/themes/goku/node_modules/ajv/lib/ajv.js new file mode 100644 index 00000000..611b9383 --- /dev/null +++ b/user/themes/goku/node_modules/ajv/lib/ajv.js @@ -0,0 +1,497 @@ +'use strict'; + +var compileSchema = require('./compile') + , resolve = require('./compile/resolve') + , Cache = require('./cache') + , SchemaObject = require('./compile/schema_obj') + , stableStringify = require('fast-json-stable-stringify') + , formats = require('./compile/formats') + , rules = require('./compile/rules') + , $dataMetaSchema = require('./data') + , util = require('./compile/util'); + +module.exports = Ajv; + +Ajv.prototype.validate = validate; +Ajv.prototype.compile = compile; +Ajv.prototype.addSchema = addSchema; +Ajv.prototype.addMetaSchema = addMetaSchema; +Ajv.prototype.validateSchema = validateSchema; +Ajv.prototype.getSchema = getSchema; +Ajv.prototype.removeSchema = removeSchema; +Ajv.prototype.addFormat = addFormat; +Ajv.prototype.errorsText = errorsText; + +Ajv.prototype._addSchema = _addSchema; +Ajv.prototype._compile = _compile; + +Ajv.prototype.compileAsync = require('./compile/async'); +var customKeyword = require('./keyword'); +Ajv.prototype.addKeyword = customKeyword.add; +Ajv.prototype.getKeyword = customKeyword.get; +Ajv.prototype.removeKeyword = customKeyword.remove; +Ajv.prototype.validateKeyword = customKeyword.validate; + +var errorClasses = require('./compile/error_classes'); +Ajv.ValidationError = errorClasses.Validation; +Ajv.MissingRefError = errorClasses.MissingRef; +Ajv.$dataMetaSchema = $dataMetaSchema; + +var META_SCHEMA_ID = 'http://json-schema.org/draft-07/schema'; + +var META_IGNORE_OPTIONS = [ 'removeAdditional', 'useDefaults', 'coerceTypes', 'strictDefaults' ]; +var META_SUPPORT_DATA = ['/properties']; + +/** + * Creates validator instance. + * Usage: `Ajv(opts)` + * @param {Object} opts optional options + * @return {Object} ajv instance + */ +function Ajv(opts) { + if (!(this instanceof Ajv)) return new Ajv(opts); + opts = this._opts = util.copy(opts) || {}; + setLogger(this); + this._schemas = {}; + this._refs = {}; + this._fragments = {}; + this._formats = formats(opts.format); + + this._cache = opts.cache || new Cache; + this._loadingSchemas = {}; + this._compilations = []; + this.RULES = rules(); + this._getId = chooseGetId(opts); + + opts.loopRequired = opts.loopRequired || Infinity; + if (opts.errorDataPath == 'property') opts._errorDataPathProperty = true; + if (opts.serialize === undefined) opts.serialize = stableStringify; + this._metaOpts = getMetaSchemaOptions(this); + + if (opts.formats) addInitialFormats(this); + addDefaultMetaSchema(this); + if (typeof opts.meta == 'object') this.addMetaSchema(opts.meta); + if (opts.nullable) this.addKeyword('nullable', {metaSchema: {type: 'boolean'}}); + addInitialSchemas(this); +} + + + +/** + * Validate data using schema + * Schema will be compiled and cached (using serialized JSON as key. [fast-json-stable-stringify](https://github.com/epoberezkin/fast-json-stable-stringify) is used to serialize. + * @this Ajv + * @param {String|Object} schemaKeyRef key, ref or schema object + * @param {Any} data to be validated + * @return {Boolean} validation result. Errors from the last validation will be available in `ajv.errors` (and also in compiled schema: `schema.errors`). + */ +function validate(schemaKeyRef, data) { + var v; + if (typeof schemaKeyRef == 'string') { + v = this.getSchema(schemaKeyRef); + if (!v) throw new Error('no schema with key or ref "' + schemaKeyRef + '"'); + } else { + var schemaObj = this._addSchema(schemaKeyRef); + v = schemaObj.validate || this._compile(schemaObj); + } + + var valid = v(data); + if (v.$async !== true) this.errors = v.errors; + return valid; +} + + +/** + * Create validating function for passed schema. + * @this Ajv + * @param {Object} schema schema object + * @param {Boolean} _meta true if schema is a meta-schema. Used internally to compile meta schemas of custom keywords. + * @return {Function} validating function + */ +function compile(schema, _meta) { + var schemaObj = this._addSchema(schema, undefined, _meta); + return schemaObj.validate || this._compile(schemaObj); +} + + +/** + * Adds schema to the instance. + * @this Ajv + * @param {Object|Array} schema schema or array of schemas. If array is passed, `key` and other parameters will be ignored. + * @param {String} key Optional schema key. Can be passed to `validate` method instead of schema object or id/ref. One schema per instance can have empty `id` and `key`. + * @param {Boolean} _skipValidation true to skip schema validation. Used internally, option validateSchema should be used instead. + * @param {Boolean} _meta true if schema is a meta-schema. Used internally, addMetaSchema should be used instead. + * @return {Ajv} this for method chaining + */ +function addSchema(schema, key, _skipValidation, _meta) { + if (Array.isArray(schema)){ + for (var i=0; i} errors optional array of validation errors, if not passed errors from the instance are used. + * @param {Object} options optional options with properties `separator` and `dataVar`. + * @return {String} human readable string with all errors descriptions + */ +function errorsText(errors, options) { + errors = errors || this.errors; + if (!errors) return 'No errors'; + options = options || {}; + var separator = options.separator === undefined ? ', ' : options.separator; + var dataVar = options.dataVar === undefined ? 'data' : options.dataVar; + + var text = ''; + for (var i=0; i%\\^`{|}]|%[0-9a-f]{2})|\{[+#./;?&=,!@|]?(?:[a-z0-9_]|%[0-9a-f]{2})+(?::[1-9][0-9]{0,3}|\*)?(?:,(?:[a-z0-9_]|%[0-9a-f]{2})+(?::[1-9][0-9]{0,3}|\*)?)*\})*$/i; +// For the source: https://gist.github.com/dperini/729294 +// For test cases: https://mathiasbynens.be/demo/url-regex +// @todo Delete current URL in favour of the commented out URL rule when this issue is fixed https://github.com/eslint/eslint/issues/7983. +// var URL = /^(?:(?:https?|ftp):\/\/)(?:\S+(?::\S*)?@)?(?:(?!10(?:\.\d{1,3}){3})(?!127(?:\.\d{1,3}){3})(?!169\.254(?:\.\d{1,3}){2})(?!192\.168(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u{00a1}-\u{ffff}0-9]+-?)*[a-z\u{00a1}-\u{ffff}0-9]+)(?:\.(?:[a-z\u{00a1}-\u{ffff}0-9]+-?)*[a-z\u{00a1}-\u{ffff}0-9]+)*(?:\.(?:[a-z\u{00a1}-\u{ffff}]{2,})))(?::\d{2,5})?(?:\/[^\s]*)?$/iu; +var URL = /^(?:(?:http[s\u017F]?|ftp):\/\/)(?:(?:[\0-\x08\x0E-\x1F!-\x9F\xA1-\u167F\u1681-\u1FFF\u200B-\u2027\u202A-\u202E\u2030-\u205E\u2060-\u2FFF\u3001-\uD7FF\uE000-\uFEFE\uFF00-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])+(?::(?:[\0-\x08\x0E-\x1F!-\x9F\xA1-\u167F\u1681-\u1FFF\u200B-\u2027\u202A-\u202E\u2030-\u205E\u2060-\u2FFF\u3001-\uD7FF\uE000-\uFEFE\uFF00-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])*)?@)?(?:(?!10(?:\.[0-9]{1,3}){3})(?!127(?:\.[0-9]{1,3}){3})(?!169\.254(?:\.[0-9]{1,3}){2})(?!192\.168(?:\.[0-9]{1,3}){2})(?!172\.(?:1[6-9]|2[0-9]|3[01])(?:\.[0-9]{1,3}){2})(?:[1-9][0-9]?|1[0-9][0-9]|2[01][0-9]|22[0-3])(?:\.(?:1?[0-9]{1,2}|2[0-4][0-9]|25[0-5])){2}(?:\.(?:[1-9][0-9]?|1[0-9][0-9]|2[0-4][0-9]|25[0-4]))|(?:(?:(?:[0-9KSa-z\xA1-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])+-?)*(?:[0-9KSa-z\xA1-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])+)(?:\.(?:(?:[0-9KSa-z\xA1-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])+-?)*(?:[0-9KSa-z\xA1-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])+)*(?:\.(?:(?:[KSa-z\xA1-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]){2,})))(?::[0-9]{2,5})?(?:\/(?:[\0-\x08\x0E-\x1F!-\x9F\xA1-\u167F\u1681-\u1FFF\u200B-\u2027\u202A-\u202E\u2030-\u205E\u2060-\u2FFF\u3001-\uD7FF\uE000-\uFEFE\uFF00-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])*)?$/i; +var UUID = /^(?:urn:uuid:)?[0-9a-f]{8}-(?:[0-9a-f]{4}-){3}[0-9a-f]{12}$/i; +var JSON_POINTER = /^(?:\/(?:[^~/]|~0|~1)*)*$/; +var JSON_POINTER_URI_FRAGMENT = /^#(?:\/(?:[a-z0-9_\-.!$&'()*+,;:=@]|%[0-9a-f]{2}|~0|~1)*)*$/i; +var RELATIVE_JSON_POINTER = /^(?:0|[1-9][0-9]*)(?:#|(?:\/(?:[^~/]|~0|~1)*)*)$/; + + +module.exports = formats; + +function formats(mode) { + mode = mode == 'full' ? 'full' : 'fast'; + return util.copy(formats[mode]); +} + + +formats.fast = { + // date: http://tools.ietf.org/html/rfc3339#section-5.6 + date: /^\d\d\d\d-[0-1]\d-[0-3]\d$/, + // date-time: http://tools.ietf.org/html/rfc3339#section-5.6 + time: /^(?:[0-2]\d:[0-5]\d:[0-5]\d|23:59:60)(?:\.\d+)?(?:z|[+-]\d\d:\d\d)?$/i, + 'date-time': /^\d\d\d\d-[0-1]\d-[0-3]\d[t\s](?:[0-2]\d:[0-5]\d:[0-5]\d|23:59:60)(?:\.\d+)?(?:z|[+-]\d\d:\d\d)$/i, + // uri: https://github.com/mafintosh/is-my-json-valid/blob/master/formats.js + uri: /^(?:[a-z][a-z0-9+-.]*:)(?:\/?\/)?[^\s]*$/i, + 'uri-reference': /^(?:(?:[a-z][a-z0-9+-.]*:)?\/?\/)?(?:[^\\\s#][^\s#]*)?(?:#[^\\\s]*)?$/i, + 'uri-template': URITEMPLATE, + url: URL, + // email (sources from jsen validator): + // http://stackoverflow.com/questions/201323/using-a-regular-expression-to-validate-an-email-address#answer-8829363 + // http://www.w3.org/TR/html5/forms.html#valid-e-mail-address (search for 'willful violation') + email: /^[a-z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)*$/i, + hostname: HOSTNAME, + // optimized https://www.safaribooksonline.com/library/view/regular-expressions-cookbook/9780596802837/ch07s16.html + ipv4: /^(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)$/, + // optimized http://stackoverflow.com/questions/53497/regular-expression-that-matches-valid-ipv6-addresses + ipv6: /^\s*(?:(?:(?:[0-9a-f]{1,4}:){7}(?:[0-9a-f]{1,4}|:))|(?:(?:[0-9a-f]{1,4}:){6}(?::[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(?:(?:[0-9a-f]{1,4}:){5}(?:(?:(?::[0-9a-f]{1,4}){1,2})|:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(?:(?:[0-9a-f]{1,4}:){4}(?:(?:(?::[0-9a-f]{1,4}){1,3})|(?:(?::[0-9a-f]{1,4})?:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[0-9a-f]{1,4}:){3}(?:(?:(?::[0-9a-f]{1,4}){1,4})|(?:(?::[0-9a-f]{1,4}){0,2}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[0-9a-f]{1,4}:){2}(?:(?:(?::[0-9a-f]{1,4}){1,5})|(?:(?::[0-9a-f]{1,4}){0,3}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[0-9a-f]{1,4}:){1}(?:(?:(?::[0-9a-f]{1,4}){1,6})|(?:(?::[0-9a-f]{1,4}){0,4}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?::(?:(?:(?::[0-9a-f]{1,4}){1,7})|(?:(?::[0-9a-f]{1,4}){0,5}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(?:%.+)?\s*$/i, + regex: regex, + // uuid: http://tools.ietf.org/html/rfc4122 + uuid: UUID, + // JSON-pointer: https://tools.ietf.org/html/rfc6901 + // uri fragment: https://tools.ietf.org/html/rfc3986#appendix-A + 'json-pointer': JSON_POINTER, + 'json-pointer-uri-fragment': JSON_POINTER_URI_FRAGMENT, + // relative JSON-pointer: http://tools.ietf.org/html/draft-luff-relative-json-pointer-00 + 'relative-json-pointer': RELATIVE_JSON_POINTER +}; + + +formats.full = { + date: date, + time: time, + 'date-time': date_time, + uri: uri, + 'uri-reference': URIREF, + 'uri-template': URITEMPLATE, + url: URL, + email: /^[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/i, + hostname: hostname, + ipv4: /^(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)$/, + ipv6: /^\s*(?:(?:(?:[0-9a-f]{1,4}:){7}(?:[0-9a-f]{1,4}|:))|(?:(?:[0-9a-f]{1,4}:){6}(?::[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(?:(?:[0-9a-f]{1,4}:){5}(?:(?:(?::[0-9a-f]{1,4}){1,2})|:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(?:(?:[0-9a-f]{1,4}:){4}(?:(?:(?::[0-9a-f]{1,4}){1,3})|(?:(?::[0-9a-f]{1,4})?:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[0-9a-f]{1,4}:){3}(?:(?:(?::[0-9a-f]{1,4}){1,4})|(?:(?::[0-9a-f]{1,4}){0,2}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[0-9a-f]{1,4}:){2}(?:(?:(?::[0-9a-f]{1,4}){1,5})|(?:(?::[0-9a-f]{1,4}){0,3}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[0-9a-f]{1,4}:){1}(?:(?:(?::[0-9a-f]{1,4}){1,6})|(?:(?::[0-9a-f]{1,4}){0,4}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?::(?:(?:(?::[0-9a-f]{1,4}){1,7})|(?:(?::[0-9a-f]{1,4}){0,5}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(?:%.+)?\s*$/i, + regex: regex, + uuid: UUID, + 'json-pointer': JSON_POINTER, + 'json-pointer-uri-fragment': JSON_POINTER_URI_FRAGMENT, + 'relative-json-pointer': RELATIVE_JSON_POINTER +}; + + +function isLeapYear(year) { + // https://tools.ietf.org/html/rfc3339#appendix-C + return year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0); +} + + +function date(str) { + // full-date from http://tools.ietf.org/html/rfc3339#section-5.6 + var matches = str.match(DATE); + if (!matches) return false; + + var year = +matches[1]; + var month = +matches[2]; + var day = +matches[3]; + + return month >= 1 && month <= 12 && day >= 1 && + day <= (month == 2 && isLeapYear(year) ? 29 : DAYS[month]); +} + + +function time(str, full) { + var matches = str.match(TIME); + if (!matches) return false; + + var hour = matches[1]; + var minute = matches[2]; + var second = matches[3]; + var timeZone = matches[5]; + return ((hour <= 23 && minute <= 59 && second <= 59) || + (hour == 23 && minute == 59 && second == 60)) && + (!full || timeZone); +} + + +var DATE_TIME_SEPARATOR = /t|\s/i; +function date_time(str) { + // http://tools.ietf.org/html/rfc3339#section-5.6 + var dateTime = str.split(DATE_TIME_SEPARATOR); + return dateTime.length == 2 && date(dateTime[0]) && time(dateTime[1], true); +} + + +function hostname(str) { + // https://tools.ietf.org/html/rfc1034#section-3.5 + // https://tools.ietf.org/html/rfc1123#section-2 + return str.length <= 255 && HOSTNAME.test(str); +} + + +var NOT_URI_FRAGMENT = /\/|:/; +function uri(str) { + // http://jmrware.com/articles/2009/uri_regexp/URI_regex.html + optional protocol + required "." + return NOT_URI_FRAGMENT.test(str) && URI.test(str); +} + + +var Z_ANCHOR = /[^\\]\\Z/; +function regex(str) { + if (Z_ANCHOR.test(str)) return false; + try { + new RegExp(str); + return true; + } catch(e) { + return false; + } +} diff --git a/user/themes/goku/node_modules/ajv/lib/compile/index.js b/user/themes/goku/node_modules/ajv/lib/compile/index.js new file mode 100644 index 00000000..f4d3f0d5 --- /dev/null +++ b/user/themes/goku/node_modules/ajv/lib/compile/index.js @@ -0,0 +1,387 @@ +'use strict'; + +var resolve = require('./resolve') + , util = require('./util') + , errorClasses = require('./error_classes') + , stableStringify = require('fast-json-stable-stringify'); + +var validateGenerator = require('../dotjs/validate'); + +/** + * Functions below are used inside compiled validations function + */ + +var ucs2length = util.ucs2length; +var equal = require('fast-deep-equal'); + +// this error is thrown by async schemas to return validation errors via exception +var ValidationError = errorClasses.Validation; + +module.exports = compile; + + +/** + * Compiles schema to validation function + * @this Ajv + * @param {Object} schema schema object + * @param {Object} root object with information about the root schema for this schema + * @param {Object} localRefs the hash of local references inside the schema (created by resolve.id), used for inline resolution + * @param {String} baseId base ID for IDs in the schema + * @return {Function} validation function + */ +function compile(schema, root, localRefs, baseId) { + /* jshint validthis: true, evil: true */ + /* eslint no-shadow: 0 */ + var self = this + , opts = this._opts + , refVal = [ undefined ] + , refs = {} + , patterns = [] + , patternsHash = {} + , defaults = [] + , defaultsHash = {} + , customRules = []; + + root = root || { schema: schema, refVal: refVal, refs: refs }; + + var c = checkCompiling.call(this, schema, root, baseId); + var compilation = this._compilations[c.index]; + if (c.compiling) return (compilation.callValidate = callValidate); + + var formats = this._formats; + var RULES = this.RULES; + + try { + var v = localCompile(schema, root, localRefs, baseId); + compilation.validate = v; + var cv = compilation.callValidate; + if (cv) { + cv.schema = v.schema; + cv.errors = null; + cv.refs = v.refs; + cv.refVal = v.refVal; + cv.root = v.root; + cv.$async = v.$async; + if (opts.sourceCode) cv.source = v.source; + } + return v; + } finally { + endCompiling.call(this, schema, root, baseId); + } + + /* @this {*} - custom context, see passContext option */ + function callValidate() { + /* jshint validthis: true */ + var validate = compilation.validate; + var result = validate.apply(this, arguments); + callValidate.errors = validate.errors; + return result; + } + + function localCompile(_schema, _root, localRefs, baseId) { + var isRoot = !_root || (_root && _root.schema == _schema); + if (_root.schema != root.schema) + return compile.call(self, _schema, _root, localRefs, baseId); + + var $async = _schema.$async === true; + + var sourceCode = validateGenerator({ + isTop: true, + schema: _schema, + isRoot: isRoot, + baseId: baseId, + root: _root, + schemaPath: '', + errSchemaPath: '#', + errorPath: '""', + MissingRefError: errorClasses.MissingRef, + RULES: RULES, + validate: validateGenerator, + util: util, + resolve: resolve, + resolveRef: resolveRef, + usePattern: usePattern, + useDefault: useDefault, + useCustomRule: useCustomRule, + opts: opts, + formats: formats, + logger: self.logger, + self: self + }); + + sourceCode = vars(refVal, refValCode) + vars(patterns, patternCode) + + vars(defaults, defaultCode) + vars(customRules, customRuleCode) + + sourceCode; + + if (opts.processCode) sourceCode = opts.processCode(sourceCode); + // console.log('\n\n\n *** \n', JSON.stringify(sourceCode)); + var validate; + try { + var makeValidate = new Function( + 'self', + 'RULES', + 'formats', + 'root', + 'refVal', + 'defaults', + 'customRules', + 'equal', + 'ucs2length', + 'ValidationError', + sourceCode + ); + + validate = makeValidate( + self, + RULES, + formats, + root, + refVal, + defaults, + customRules, + equal, + ucs2length, + ValidationError + ); + + refVal[0] = validate; + } catch(e) { + self.logger.error('Error compiling schema, function code:', sourceCode); + throw e; + } + + validate.schema = _schema; + validate.errors = null; + validate.refs = refs; + validate.refVal = refVal; + validate.root = isRoot ? validate : _root; + if ($async) validate.$async = true; + if (opts.sourceCode === true) { + validate.source = { + code: sourceCode, + patterns: patterns, + defaults: defaults + }; + } + + return validate; + } + + function resolveRef(baseId, ref, isRoot) { + ref = resolve.url(baseId, ref); + var refIndex = refs[ref]; + var _refVal, refCode; + if (refIndex !== undefined) { + _refVal = refVal[refIndex]; + refCode = 'refVal[' + refIndex + ']'; + return resolvedRef(_refVal, refCode); + } + if (!isRoot && root.refs) { + var rootRefId = root.refs[ref]; + if (rootRefId !== undefined) { + _refVal = root.refVal[rootRefId]; + refCode = addLocalRef(ref, _refVal); + return resolvedRef(_refVal, refCode); + } + } + + refCode = addLocalRef(ref); + var v = resolve.call(self, localCompile, root, ref); + if (v === undefined) { + var localSchema = localRefs && localRefs[ref]; + if (localSchema) { + v = resolve.inlineRef(localSchema, opts.inlineRefs) + ? localSchema + : compile.call(self, localSchema, root, localRefs, baseId); + } + } + + if (v === undefined) { + removeLocalRef(ref); + } else { + replaceLocalRef(ref, v); + return resolvedRef(v, refCode); + } + } + + function addLocalRef(ref, v) { + var refId = refVal.length; + refVal[refId] = v; + refs[ref] = refId; + return 'refVal' + refId; + } + + function removeLocalRef(ref) { + delete refs[ref]; + } + + function replaceLocalRef(ref, v) { + var refId = refs[ref]; + refVal[refId] = v; + } + + function resolvedRef(refVal, code) { + return typeof refVal == 'object' || typeof refVal == 'boolean' + ? { code: code, schema: refVal, inline: true } + : { code: code, $async: refVal && !!refVal.$async }; + } + + function usePattern(regexStr) { + var index = patternsHash[regexStr]; + if (index === undefined) { + index = patternsHash[regexStr] = patterns.length; + patterns[index] = regexStr; + } + return 'pattern' + index; + } + + function useDefault(value) { + switch (typeof value) { + case 'boolean': + case 'number': + return '' + value; + case 'string': + return util.toQuotedString(value); + case 'object': + if (value === null) return 'null'; + var valueStr = stableStringify(value); + var index = defaultsHash[valueStr]; + if (index === undefined) { + index = defaultsHash[valueStr] = defaults.length; + defaults[index] = value; + } + return 'default' + index; + } + } + + function useCustomRule(rule, schema, parentSchema, it) { + if (self._opts.validateSchema !== false) { + var deps = rule.definition.dependencies; + if (deps && !deps.every(function(keyword) { + return Object.prototype.hasOwnProperty.call(parentSchema, keyword); + })) + throw new Error('parent schema must have all required keywords: ' + deps.join(',')); + + var validateSchema = rule.definition.validateSchema; + if (validateSchema) { + var valid = validateSchema(schema); + if (!valid) { + var message = 'keyword schema is invalid: ' + self.errorsText(validateSchema.errors); + if (self._opts.validateSchema == 'log') self.logger.error(message); + else throw new Error(message); + } + } + } + + var compile = rule.definition.compile + , inline = rule.definition.inline + , macro = rule.definition.macro; + + var validate; + if (compile) { + validate = compile.call(self, schema, parentSchema, it); + } else if (macro) { + validate = macro.call(self, schema, parentSchema, it); + if (opts.validateSchema !== false) self.validateSchema(validate, true); + } else if (inline) { + validate = inline.call(self, it, rule.keyword, schema, parentSchema); + } else { + validate = rule.definition.validate; + if (!validate) return; + } + + if (validate === undefined) + throw new Error('custom keyword "' + rule.keyword + '"failed to compile'); + + var index = customRules.length; + customRules[index] = validate; + + return { + code: 'customRule' + index, + validate: validate + }; + } +} + + +/** + * Checks if the schema is currently compiled + * @this Ajv + * @param {Object} schema schema to compile + * @param {Object} root root object + * @param {String} baseId base schema ID + * @return {Object} object with properties "index" (compilation index) and "compiling" (boolean) + */ +function checkCompiling(schema, root, baseId) { + /* jshint validthis: true */ + var index = compIndex.call(this, schema, root, baseId); + if (index >= 0) return { index: index, compiling: true }; + index = this._compilations.length; + this._compilations[index] = { + schema: schema, + root: root, + baseId: baseId + }; + return { index: index, compiling: false }; +} + + +/** + * Removes the schema from the currently compiled list + * @this Ajv + * @param {Object} schema schema to compile + * @param {Object} root root object + * @param {String} baseId base schema ID + */ +function endCompiling(schema, root, baseId) { + /* jshint validthis: true */ + var i = compIndex.call(this, schema, root, baseId); + if (i >= 0) this._compilations.splice(i, 1); +} + + +/** + * Index of schema compilation in the currently compiled list + * @this Ajv + * @param {Object} schema schema to compile + * @param {Object} root root object + * @param {String} baseId base schema ID + * @return {Integer} compilation index + */ +function compIndex(schema, root, baseId) { + /* jshint validthis: true */ + for (var i=0; i= 0xD800 && value <= 0xDBFF && pos < len) { + // high surrogate, and there is a next character + value = str.charCodeAt(pos); + if ((value & 0xFC00) == 0xDC00) pos++; // low surrogate + } + } + return length; +}; diff --git a/user/themes/goku/node_modules/ajv/lib/compile/util.js b/user/themes/goku/node_modules/ajv/lib/compile/util.js new file mode 100644 index 00000000..0efa0011 --- /dev/null +++ b/user/themes/goku/node_modules/ajv/lib/compile/util.js @@ -0,0 +1,274 @@ +'use strict'; + + +module.exports = { + copy: copy, + checkDataType: checkDataType, + checkDataTypes: checkDataTypes, + coerceToTypes: coerceToTypes, + toHash: toHash, + getProperty: getProperty, + escapeQuotes: escapeQuotes, + equal: require('fast-deep-equal'), + ucs2length: require('./ucs2length'), + varOccurences: varOccurences, + varReplace: varReplace, + cleanUpCode: cleanUpCode, + finalCleanUpCode: finalCleanUpCode, + schemaHasRules: schemaHasRules, + schemaHasRulesExcept: schemaHasRulesExcept, + schemaUnknownRules: schemaUnknownRules, + toQuotedString: toQuotedString, + getPathExpr: getPathExpr, + getPath: getPath, + getData: getData, + unescapeFragment: unescapeFragment, + unescapeJsonPointer: unescapeJsonPointer, + escapeFragment: escapeFragment, + escapeJsonPointer: escapeJsonPointer +}; + + +function copy(o, to) { + to = to || {}; + for (var key in o) to[key] = o[key]; + return to; +} + + +function checkDataType(dataType, data, negate) { + var EQUAL = negate ? ' !== ' : ' === ' + , AND = negate ? ' || ' : ' && ' + , OK = negate ? '!' : '' + , NOT = negate ? '' : '!'; + switch (dataType) { + case 'null': return data + EQUAL + 'null'; + case 'array': return OK + 'Array.isArray(' + data + ')'; + case 'object': return '(' + OK + data + AND + + 'typeof ' + data + EQUAL + '"object"' + AND + + NOT + 'Array.isArray(' + data + '))'; + case 'integer': return '(typeof ' + data + EQUAL + '"number"' + AND + + NOT + '(' + data + ' % 1)' + + AND + data + EQUAL + data + ')'; + default: return 'typeof ' + data + EQUAL + '"' + dataType + '"'; + } +} + + +function checkDataTypes(dataTypes, data) { + switch (dataTypes.length) { + case 1: return checkDataType(dataTypes[0], data, true); + default: + var code = ''; + var types = toHash(dataTypes); + if (types.array && types.object) { + code = types.null ? '(': '(!' + data + ' || '; + code += 'typeof ' + data + ' !== "object")'; + delete types.null; + delete types.array; + delete types.object; + } + if (types.number) delete types.integer; + for (var t in types) + code += (code ? ' && ' : '' ) + checkDataType(t, data, true); + + return code; + } +} + + +var COERCE_TO_TYPES = toHash([ 'string', 'number', 'integer', 'boolean', 'null' ]); +function coerceToTypes(optionCoerceTypes, dataTypes) { + if (Array.isArray(dataTypes)) { + var types = []; + for (var i=0; i= lvl) throw new Error('Cannot access property/index ' + up + ' levels up, current level is ' + lvl); + return paths[lvl - up]; + } + + if (up > lvl) throw new Error('Cannot access data ' + up + ' levels up, current level is ' + lvl); + data = 'data' + ((lvl - up) || ''); + if (!jsonPointer) return data; + } + + var expr = data; + var segments = jsonPointer.split('/'); + for (var i=0; i' + , $notOp = $isMax ? '>' : '<' + , $errorKeyword = undefined; +}} + +{{? $isDataExcl }} + {{ + var $schemaValueExcl = it.util.getData($schemaExcl.$data, $dataLvl, it.dataPathArr) + , $exclusive = 'exclusive' + $lvl + , $exclType = 'exclType' + $lvl + , $exclIsNumber = 'exclIsNumber' + $lvl + , $opExpr = 'op' + $lvl + , $opStr = '\' + ' + $opExpr + ' + \''; + }} + var schemaExcl{{=$lvl}} = {{=$schemaValueExcl}}; + {{ $schemaValueExcl = 'schemaExcl' + $lvl; }} + + var {{=$exclusive}}; + var {{=$exclType}} = typeof {{=$schemaValueExcl}}; + if ({{=$exclType}} != 'boolean' && {{=$exclType}} != 'undefined' && {{=$exclType}} != 'number') { + {{ var $errorKeyword = $exclusiveKeyword; }} + {{# def.error:'_exclusiveLimit' }} + } else if ({{# def.$dataNotType:'number' }} + {{=$exclType}} == 'number' + ? ( + ({{=$exclusive}} = {{=$schemaValue}} === undefined || {{=$schemaValueExcl}} {{=$op}}= {{=$schemaValue}}) + ? {{=$data}} {{=$notOp}}= {{=$schemaValueExcl}} + : {{=$data}} {{=$notOp}} {{=$schemaValue}} + ) + : ( + ({{=$exclusive}} = {{=$schemaValueExcl}} === true) + ? {{=$data}} {{=$notOp}}= {{=$schemaValue}} + : {{=$data}} {{=$notOp}} {{=$schemaValue}} + ) + || {{=$data}} !== {{=$data}}) { + var op{{=$lvl}} = {{=$exclusive}} ? '{{=$op}}' : '{{=$op}}='; + {{ + if ($schema === undefined) { + $errorKeyword = $exclusiveKeyword; + $errSchemaPath = it.errSchemaPath + '/' + $exclusiveKeyword; + $schemaValue = $schemaValueExcl; + $isData = $isDataExcl; + } + }} +{{??}} + {{ + var $exclIsNumber = typeof $schemaExcl == 'number' + , $opStr = $op; /*used in error*/ + }} + + {{? $exclIsNumber && $isData }} + {{ var $opExpr = '\'' + $opStr + '\''; /*used in error*/ }} + if ({{# def.$dataNotType:'number' }} + ( {{=$schemaValue}} === undefined + || {{=$schemaExcl}} {{=$op}}= {{=$schemaValue}} + ? {{=$data}} {{=$notOp}}= {{=$schemaExcl}} + : {{=$data}} {{=$notOp}} {{=$schemaValue}} ) + || {{=$data}} !== {{=$data}}) { + {{??}} + {{ + if ($exclIsNumber && $schema === undefined) { + {{# def.setExclusiveLimit }} + $schemaValue = $schemaExcl; + $notOp += '='; + } else { + if ($exclIsNumber) + $schemaValue = Math[$isMax ? 'min' : 'max']($schemaExcl, $schema); + + if ($schemaExcl === ($exclIsNumber ? $schemaValue : true)) { + {{# def.setExclusiveLimit }} + $notOp += '='; + } else { + $exclusive = false; + $opStr += '='; + } + } + + var $opExpr = '\'' + $opStr + '\''; /*used in error*/ + }} + + if ({{# def.$dataNotType:'number' }} + {{=$data}} {{=$notOp}} {{=$schemaValue}} + || {{=$data}} !== {{=$data}}) { + {{?}} +{{?}} + {{ $errorKeyword = $errorKeyword || $keyword; }} + {{# def.error:'_limit' }} + } {{? $breakOnError }} else { {{?}} diff --git a/user/themes/goku/node_modules/ajv/lib/dot/_limitItems.jst b/user/themes/goku/node_modules/ajv/lib/dot/_limitItems.jst new file mode 100644 index 00000000..a3e078e5 --- /dev/null +++ b/user/themes/goku/node_modules/ajv/lib/dot/_limitItems.jst @@ -0,0 +1,10 @@ +{{# def.definitions }} +{{# def.errors }} +{{# def.setupKeyword }} +{{# def.$data }} + +{{ var $op = $keyword == 'maxItems' ? '>' : '<'; }} +if ({{# def.$dataNotType:'number' }} {{=$data}}.length {{=$op}} {{=$schemaValue}}) { + {{ var $errorKeyword = $keyword; }} + {{# def.error:'_limitItems' }} +} {{? $breakOnError }} else { {{?}} diff --git a/user/themes/goku/node_modules/ajv/lib/dot/_limitLength.jst b/user/themes/goku/node_modules/ajv/lib/dot/_limitLength.jst new file mode 100644 index 00000000..cfc8dbb0 --- /dev/null +++ b/user/themes/goku/node_modules/ajv/lib/dot/_limitLength.jst @@ -0,0 +1,10 @@ +{{# def.definitions }} +{{# def.errors }} +{{# def.setupKeyword }} +{{# def.$data }} + +{{ var $op = $keyword == 'maxLength' ? '>' : '<'; }} +if ({{# def.$dataNotType:'number' }} {{# def.strLength }} {{=$op}} {{=$schemaValue}}) { + {{ var $errorKeyword = $keyword; }} + {{# def.error:'_limitLength' }} +} {{? $breakOnError }} else { {{?}} diff --git a/user/themes/goku/node_modules/ajv/lib/dot/_limitProperties.jst b/user/themes/goku/node_modules/ajv/lib/dot/_limitProperties.jst new file mode 100644 index 00000000..da7ea776 --- /dev/null +++ b/user/themes/goku/node_modules/ajv/lib/dot/_limitProperties.jst @@ -0,0 +1,10 @@ +{{# def.definitions }} +{{# def.errors }} +{{# def.setupKeyword }} +{{# def.$data }} + +{{ var $op = $keyword == 'maxProperties' ? '>' : '<'; }} +if ({{# def.$dataNotType:'number' }} Object.keys({{=$data}}).length {{=$op}} {{=$schemaValue}}) { + {{ var $errorKeyword = $keyword; }} + {{# def.error:'_limitProperties' }} +} {{? $breakOnError }} else { {{?}} diff --git a/user/themes/goku/node_modules/ajv/lib/dot/allOf.jst b/user/themes/goku/node_modules/ajv/lib/dot/allOf.jst new file mode 100644 index 00000000..4c283631 --- /dev/null +++ b/user/themes/goku/node_modules/ajv/lib/dot/allOf.jst @@ -0,0 +1,34 @@ +{{# def.definitions }} +{{# def.errors }} +{{# def.setupKeyword }} +{{# def.setupNextLevel }} + +{{ + var $currentBaseId = $it.baseId + , $allSchemasEmpty = true; +}} + +{{~ $schema:$sch:$i }} + {{? {{# def.nonEmptySchema:$sch }} }} + {{ + $allSchemasEmpty = false; + $it.schema = $sch; + $it.schemaPath = $schemaPath + '[' + $i + ']'; + $it.errSchemaPath = $errSchemaPath + '/' + $i; + }} + + {{# def.insertSubschemaCode }} + + {{# def.ifResultValid }} + {{?}} +{{~}} + +{{? $breakOnError }} + {{? $allSchemasEmpty }} + if (true) { + {{??}} + {{= $closingBraces.slice(0,-1) }} + {{?}} +{{?}} + +{{# def.cleanUp }} diff --git a/user/themes/goku/node_modules/ajv/lib/dot/anyOf.jst b/user/themes/goku/node_modules/ajv/lib/dot/anyOf.jst new file mode 100644 index 00000000..086cf2b3 --- /dev/null +++ b/user/themes/goku/node_modules/ajv/lib/dot/anyOf.jst @@ -0,0 +1,48 @@ +{{# def.definitions }} +{{# def.errors }} +{{# def.setupKeyword }} +{{# def.setupNextLevel }} + +{{ + var $noEmptySchema = $schema.every(function($sch) { + return {{# def.nonEmptySchema:$sch }}; + }); +}} +{{? $noEmptySchema }} + {{ var $currentBaseId = $it.baseId; }} + var {{=$errs}} = errors; + var {{=$valid}} = false; + + {{# def.setCompositeRule }} + + {{~ $schema:$sch:$i }} + {{ + $it.schema = $sch; + $it.schemaPath = $schemaPath + '[' + $i + ']'; + $it.errSchemaPath = $errSchemaPath + '/' + $i; + }} + + {{# def.insertSubschemaCode }} + + {{=$valid}} = {{=$valid}} || {{=$nextValid}}; + + if (!{{=$valid}}) { + {{ $closingBraces += '}'; }} + {{~}} + + {{# def.resetCompositeRule }} + + {{= $closingBraces }} + + if (!{{=$valid}}) { + {{# def.extraError:'anyOf' }} + } else { + {{# def.resetErrors }} + {{? it.opts.allErrors }} } {{?}} + + {{# def.cleanUp }} +{{??}} + {{? $breakOnError }} + if (true) { + {{?}} +{{?}} diff --git a/user/themes/goku/node_modules/ajv/lib/dot/coerce.def b/user/themes/goku/node_modules/ajv/lib/dot/coerce.def new file mode 100644 index 00000000..86e0e18a --- /dev/null +++ b/user/themes/goku/node_modules/ajv/lib/dot/coerce.def @@ -0,0 +1,61 @@ +{{## def.coerceType: + {{ + var $dataType = 'dataType' + $lvl + , $coerced = 'coerced' + $lvl; + }} + var {{=$dataType}} = typeof {{=$data}}; + {{? it.opts.coerceTypes == 'array'}} + if ({{=$dataType}} == 'object' && Array.isArray({{=$data}})) {{=$dataType}} = 'array'; + {{?}} + + var {{=$coerced}} = undefined; + + {{ var $bracesCoercion = ''; }} + {{~ $coerceToTypes:$type:$i }} + {{? $i }} + if ({{=$coerced}} === undefined) { + {{ $bracesCoercion += '}'; }} + {{?}} + + {{? it.opts.coerceTypes == 'array' && $type != 'array' }} + if ({{=$dataType}} == 'array' && {{=$data}}.length == 1) { + {{=$coerced}} = {{=$data}} = {{=$data}}[0]; + {{=$dataType}} = typeof {{=$data}}; + /*if ({{=$dataType}} == 'object' && Array.isArray({{=$data}})) {{=$dataType}} = 'array';*/ + } + {{?}} + + {{? $type == 'string' }} + if ({{=$dataType}} == 'number' || {{=$dataType}} == 'boolean') + {{=$coerced}} = '' + {{=$data}}; + else if ({{=$data}} === null) {{=$coerced}} = ''; + {{?? $type == 'number' || $type == 'integer' }} + if ({{=$dataType}} == 'boolean' || {{=$data}} === null + || ({{=$dataType}} == 'string' && {{=$data}} && {{=$data}} == +{{=$data}} + {{? $type == 'integer' }} && !({{=$data}} % 1){{?}})) + {{=$coerced}} = +{{=$data}}; + {{?? $type == 'boolean' }} + if ({{=$data}} === 'false' || {{=$data}} === 0 || {{=$data}} === null) + {{=$coerced}} = false; + else if ({{=$data}} === 'true' || {{=$data}} === 1) + {{=$coerced}} = true; + {{?? $type == 'null' }} + if ({{=$data}} === '' || {{=$data}} === 0 || {{=$data}} === false) + {{=$coerced}} = null; + {{?? it.opts.coerceTypes == 'array' && $type == 'array' }} + if ({{=$dataType}} == 'string' || {{=$dataType}} == 'number' || {{=$dataType}} == 'boolean' || {{=$data}} == null) + {{=$coerced}} = [{{=$data}}]; + {{?}} + {{~}} + + {{= $bracesCoercion }} + + if ({{=$coerced}} === undefined) { + {{# def.error:'type' }} + } else { + {{# def.setParentData }} + {{=$data}} = {{=$coerced}}; + {{? !$dataLvl }}if ({{=$parentData}} !== undefined){{?}} + {{=$parentData}}[{{=$parentDataProperty}}] = {{=$coerced}}; + } +#}} diff --git a/user/themes/goku/node_modules/ajv/lib/dot/comment.jst b/user/themes/goku/node_modules/ajv/lib/dot/comment.jst new file mode 100644 index 00000000..f9591503 --- /dev/null +++ b/user/themes/goku/node_modules/ajv/lib/dot/comment.jst @@ -0,0 +1,9 @@ +{{# def.definitions }} +{{# def.setupKeyword }} + +{{ var $comment = it.util.toQuotedString($schema); }} +{{? it.opts.$comment === true }} + console.log({{=$comment}}); +{{?? typeof it.opts.$comment == 'function' }} + self._opts.$comment({{=$comment}}, {{=it.util.toQuotedString($errSchemaPath)}}, validate.root.schema); +{{?}} diff --git a/user/themes/goku/node_modules/ajv/lib/dot/const.jst b/user/themes/goku/node_modules/ajv/lib/dot/const.jst new file mode 100644 index 00000000..2aa22980 --- /dev/null +++ b/user/themes/goku/node_modules/ajv/lib/dot/const.jst @@ -0,0 +1,11 @@ +{{# def.definitions }} +{{# def.errors }} +{{# def.setupKeyword }} +{{# def.$data }} + +{{? !$isData }} + var schema{{=$lvl}} = validate.schema{{=$schemaPath}}; +{{?}} +var {{=$valid}} = equal({{=$data}}, schema{{=$lvl}}); +{{# def.checkError:'const' }} +{{? $breakOnError }} else { {{?}} diff --git a/user/themes/goku/node_modules/ajv/lib/dot/contains.jst b/user/themes/goku/node_modules/ajv/lib/dot/contains.jst new file mode 100644 index 00000000..925d2c84 --- /dev/null +++ b/user/themes/goku/node_modules/ajv/lib/dot/contains.jst @@ -0,0 +1,57 @@ +{{# def.definitions }} +{{# def.errors }} +{{# def.setupKeyword }} +{{# def.setupNextLevel }} + + +{{ + var $idx = 'i' + $lvl + , $dataNxt = $it.dataLevel = it.dataLevel + 1 + , $nextData = 'data' + $dataNxt + , $currentBaseId = it.baseId + , $nonEmptySchema = {{# def.nonEmptySchema:$schema }}; +}} + +var {{=$errs}} = errors; +var {{=$valid}}; + +{{? $nonEmptySchema }} + {{# def.setCompositeRule }} + + {{ + $it.schema = $schema; + $it.schemaPath = $schemaPath; + $it.errSchemaPath = $errSchemaPath; + }} + + var {{=$nextValid}} = false; + + for (var {{=$idx}} = 0; {{=$idx}} < {{=$data}}.length; {{=$idx}}++) { + {{ + $it.errorPath = it.util.getPathExpr(it.errorPath, $idx, it.opts.jsonPointers, true); + var $passData = $data + '[' + $idx + ']'; + $it.dataPathArr[$dataNxt] = $idx; + }} + + {{# def.generateSubschemaCode }} + {{# def.optimizeValidate }} + + if ({{=$nextValid}}) break; + } + + {{# def.resetCompositeRule }} + {{= $closingBraces }} + + if (!{{=$nextValid}}) { +{{??}} + if ({{=$data}}.length == 0) { +{{?}} + + {{# def.error:'contains' }} + } else { + {{? $nonEmptySchema }} + {{# def.resetErrors }} + {{?}} + {{? it.opts.allErrors }} } {{?}} + +{{# def.cleanUp }} diff --git a/user/themes/goku/node_modules/ajv/lib/dot/custom.jst b/user/themes/goku/node_modules/ajv/lib/dot/custom.jst new file mode 100644 index 00000000..d30588fb --- /dev/null +++ b/user/themes/goku/node_modules/ajv/lib/dot/custom.jst @@ -0,0 +1,191 @@ +{{# def.definitions }} +{{# def.errors }} +{{# def.setupKeyword }} +{{# def.$data }} + +{{ + var $rule = this + , $definition = 'definition' + $lvl + , $rDef = $rule.definition + , $closingBraces = ''; + var $validate = $rDef.validate; + var $compile, $inline, $macro, $ruleValidate, $validateCode; +}} + +{{? $isData && $rDef.$data }} + {{ + $validateCode = 'keywordValidate' + $lvl; + var $validateSchema = $rDef.validateSchema; + }} + var {{=$definition}} = RULES.custom['{{=$keyword}}'].definition; + var {{=$validateCode}} = {{=$definition}}.validate; +{{??}} + {{ + $ruleValidate = it.useCustomRule($rule, $schema, it.schema, it); + if (!$ruleValidate) return; + $schemaValue = 'validate.schema' + $schemaPath; + $validateCode = $ruleValidate.code; + $compile = $rDef.compile; + $inline = $rDef.inline; + $macro = $rDef.macro; + }} +{{?}} + +{{ + var $ruleErrs = $validateCode + '.errors' + , $i = 'i' + $lvl + , $ruleErr = 'ruleErr' + $lvl + , $asyncKeyword = $rDef.async; + + if ($asyncKeyword && !it.async) + throw new Error('async keyword in sync schema'); +}} + + +{{? !($inline || $macro) }}{{=$ruleErrs}} = null;{{?}} +var {{=$errs}} = errors; +var {{=$valid}}; + +{{## def.callRuleValidate: + {{=$validateCode}}.call( + {{? it.opts.passContext }}this{{??}}self{{?}} + {{? $compile || $rDef.schema === false }} + , {{=$data}} + {{??}} + , {{=$schemaValue}} + , {{=$data}} + , validate.schema{{=it.schemaPath}} + {{?}} + , {{# def.dataPath }} + {{# def.passParentData }} + , rootData + ) +#}} + +{{## def.extendErrors:_inline: + for (var {{=$i}}={{=$errs}}; {{=$i}} 0 + : it.util.schemaHasRules(_schema, it.RULES.all)) +#}} + + +{{## def.strLength: + {{? it.opts.unicode === false }} + {{=$data}}.length + {{??}} + ucs2length({{=$data}}) + {{?}} +#}} + + +{{## def.willOptimize: + it.util.varOccurences($code, $nextData) < 2 +#}} + + +{{## def.generateSubschemaCode: + {{ + var $code = it.validate($it); + $it.baseId = $currentBaseId; + }} +#}} + + +{{## def.insertSubschemaCode: + {{= it.validate($it) }} + {{ $it.baseId = $currentBaseId; }} +#}} + + +{{## def._optimizeValidate: + it.util.varReplace($code, $nextData, $passData) +#}} + + +{{## def.optimizeValidate: + {{? {{# def.willOptimize}} }} + {{= {{# def._optimizeValidate }} }} + {{??}} + var {{=$nextData}} = {{=$passData}}; + {{= $code }} + {{?}} +#}} + + +{{## def.cleanUp: {{ out = it.util.cleanUpCode(out); }} #}} + + +{{## def.finalCleanUp: {{ out = it.util.finalCleanUpCode(out, $async); }} #}} + + +{{## def.$data: + {{ + var $isData = it.opts.$data && $schema && $schema.$data + , $schemaValue; + }} + {{? $isData }} + var schema{{=$lvl}} = {{= it.util.getData($schema.$data, $dataLvl, it.dataPathArr) }}; + {{ $schemaValue = 'schema' + $lvl; }} + {{??}} + {{ $schemaValue = $schema; }} + {{?}} +#}} + + +{{## def.$dataNotType:_type: + {{?$isData}} ({{=$schemaValue}} !== undefined && typeof {{=$schemaValue}} != _type) || {{?}} +#}} + + +{{## def.check$dataIsArray: + if (schema{{=$lvl}} === undefined) {{=$valid}} = true; + else if (!Array.isArray(schema{{=$lvl}})) {{=$valid}} = false; + else { +#}} + + +{{## def.beginDefOut: + {{ + var $$outStack = $$outStack || []; + $$outStack.push(out); + out = ''; + }} +#}} + + +{{## def.storeDefOut:_variable: + {{ + var _variable = out; + out = $$outStack.pop(); + }} +#}} + + +{{## def.dataPath:(dataPath || ''){{? it.errorPath != '""'}} + {{= it.errorPath }}{{?}}#}} + +{{## def.setParentData: + {{ + var $parentData = $dataLvl ? 'data' + (($dataLvl-1)||'') : 'parentData' + , $parentDataProperty = $dataLvl ? it.dataPathArr[$dataLvl] : 'parentDataProperty'; + }} +#}} + +{{## def.passParentData: + {{# def.setParentData }} + , {{= $parentData }} + , {{= $parentDataProperty }} +#}} + + +{{## def.iterateProperties: + {{? $ownProperties }} + {{=$dataProperties}} = {{=$dataProperties}} || Object.keys({{=$data}}); + for (var {{=$idx}}=0; {{=$idx}}<{{=$dataProperties}}.length; {{=$idx}}++) { + var {{=$key}} = {{=$dataProperties}}[{{=$idx}}]; + {{??}} + for (var {{=$key}} in {{=$data}}) { + {{?}} +#}} + + +{{## def.noPropertyInData: + {{=$useData}} === undefined + {{? $ownProperties }} + || !{{# def.isOwnProperty }} + {{?}} +#}} + + +{{## def.isOwnProperty: + Object.prototype.hasOwnProperty.call({{=$data}}, '{{=it.util.escapeQuotes($propertyKey)}}') +#}} diff --git a/user/themes/goku/node_modules/ajv/lib/dot/dependencies.jst b/user/themes/goku/node_modules/ajv/lib/dot/dependencies.jst new file mode 100644 index 00000000..c41f3342 --- /dev/null +++ b/user/themes/goku/node_modules/ajv/lib/dot/dependencies.jst @@ -0,0 +1,80 @@ +{{# def.definitions }} +{{# def.errors }} +{{# def.missing }} +{{# def.setupKeyword }} +{{# def.setupNextLevel }} + + +{{## def.propertyInData: + {{=$data}}{{= it.util.getProperty($property) }} !== undefined + {{? $ownProperties }} + && Object.prototype.hasOwnProperty.call({{=$data}}, '{{=it.util.escapeQuotes($property)}}') + {{?}} +#}} + + +{{ + var $schemaDeps = {} + , $propertyDeps = {} + , $ownProperties = it.opts.ownProperties; + + for ($property in $schema) { + var $sch = $schema[$property]; + var $deps = Array.isArray($sch) ? $propertyDeps : $schemaDeps; + $deps[$property] = $sch; + } +}} + +var {{=$errs}} = errors; + +{{ var $currentErrorPath = it.errorPath; }} + +var missing{{=$lvl}}; +{{ for (var $property in $propertyDeps) { }} + {{ $deps = $propertyDeps[$property]; }} + {{? $deps.length }} + if ({{# def.propertyInData }} + {{? $breakOnError }} + && ({{# def.checkMissingProperty:$deps }})) { + {{# def.errorMissingProperty:'dependencies' }} + {{??}} + ) { + {{~ $deps:$propertyKey }} + {{# def.allErrorsMissingProperty:'dependencies' }} + {{~}} + {{?}} + } {{# def.elseIfValid }} + {{?}} +{{ } }} + +{{ + it.errorPath = $currentErrorPath; + var $currentBaseId = $it.baseId; +}} + + +{{ for (var $property in $schemaDeps) { }} + {{ var $sch = $schemaDeps[$property]; }} + {{? {{# def.nonEmptySchema:$sch }} }} + {{=$nextValid}} = true; + + if ({{# def.propertyInData }}) { + {{ + $it.schema = $sch; + $it.schemaPath = $schemaPath + it.util.getProperty($property); + $it.errSchemaPath = $errSchemaPath + '/' + it.util.escapeFragment($property); + }} + + {{# def.insertSubschemaCode }} + } + + {{# def.ifResultValid }} + {{?}} +{{ } }} + +{{? $breakOnError }} + {{= $closingBraces }} + if ({{=$errs}} == errors) { +{{?}} + +{{# def.cleanUp }} diff --git a/user/themes/goku/node_modules/ajv/lib/dot/enum.jst b/user/themes/goku/node_modules/ajv/lib/dot/enum.jst new file mode 100644 index 00000000..357c2e8c --- /dev/null +++ b/user/themes/goku/node_modules/ajv/lib/dot/enum.jst @@ -0,0 +1,30 @@ +{{# def.definitions }} +{{# def.errors }} +{{# def.setupKeyword }} +{{# def.$data }} + +{{ + var $i = 'i' + $lvl + , $vSchema = 'schema' + $lvl; +}} + +{{? !$isData }} + var {{=$vSchema}} = validate.schema{{=$schemaPath}}; +{{?}} +var {{=$valid}}; + +{{?$isData}}{{# def.check$dataIsArray }}{{?}} + +{{=$valid}} = false; + +for (var {{=$i}}=0; {{=$i}}<{{=$vSchema}}.length; {{=$i}}++) + if (equal({{=$data}}, {{=$vSchema}}[{{=$i}}])) { + {{=$valid}} = true; + break; + } + +{{? $isData }} } {{?}} + +{{# def.checkError:'enum' }} + +{{? $breakOnError }} else { {{?}} diff --git a/user/themes/goku/node_modules/ajv/lib/dot/errors.def b/user/themes/goku/node_modules/ajv/lib/dot/errors.def new file mode 100644 index 00000000..5c5752cb --- /dev/null +++ b/user/themes/goku/node_modules/ajv/lib/dot/errors.def @@ -0,0 +1,194 @@ +{{# def.definitions }} + +{{## def._error:_rule: + {{ 'istanbul ignore else'; }} + {{? it.createErrors !== false }} + { + keyword: '{{= $errorKeyword || _rule }}' + , dataPath: (dataPath || '') + {{= it.errorPath }} + , schemaPath: {{=it.util.toQuotedString($errSchemaPath)}} + , params: {{# def._errorParams[_rule] }} + {{? it.opts.messages !== false }} + , message: {{# def._errorMessages[_rule] }} + {{?}} + {{? it.opts.verbose }} + , schema: {{# def._errorSchemas[_rule] }} + , parentSchema: validate.schema{{=it.schemaPath}} + , data: {{=$data}} + {{?}} + } + {{??}} + {} + {{?}} +#}} + + +{{## def._addError:_rule: + if (vErrors === null) vErrors = [err]; + else vErrors.push(err); + errors++; +#}} + + +{{## def.addError:_rule: + var err = {{# def._error:_rule }}; + {{# def._addError:_rule }} +#}} + + +{{## def.error:_rule: + {{# def.beginDefOut}} + {{# def._error:_rule }} + {{# def.storeDefOut:__err }} + + {{? !it.compositeRule && $breakOnError }} + {{ 'istanbul ignore if'; }} + {{? it.async }} + throw new ValidationError([{{=__err}}]); + {{??}} + validate.errors = [{{=__err}}]; + return false; + {{?}} + {{??}} + var err = {{=__err}}; + {{# def._addError:_rule }} + {{?}} +#}} + + +{{## def.extraError:_rule: + {{# def.addError:_rule}} + {{? !it.compositeRule && $breakOnError }} + {{ 'istanbul ignore if'; }} + {{? it.async }} + throw new ValidationError(vErrors); + {{??}} + validate.errors = vErrors; + return false; + {{?}} + {{?}} +#}} + + +{{## def.checkError:_rule: + if (!{{=$valid}}) { + {{# def.error:_rule }} + } +#}} + + +{{## def.resetErrors: + errors = {{=$errs}}; + if (vErrors !== null) { + if ({{=$errs}}) vErrors.length = {{=$errs}}; + else vErrors = null; + } +#}} + + +{{## def.concatSchema:{{?$isData}}' + {{=$schemaValue}} + '{{??}}{{=$schema}}{{?}}#}} +{{## def.appendSchema:{{?$isData}}' + {{=$schemaValue}}{{??}}{{=$schemaValue}}'{{?}}#}} +{{## def.concatSchemaEQ:{{?$isData}}' + {{=$schemaValue}} + '{{??}}{{=it.util.escapeQuotes($schema)}}{{?}}#}} + +{{## def._errorMessages = { + 'false schema': "'boolean schema is false'", + $ref: "'can\\\'t resolve reference {{=it.util.escapeQuotes($schema)}}'", + additionalItems: "'should NOT have more than {{=$schema.length}} items'", + additionalProperties: "'{{? it.opts._errorDataPathProperty }}is an invalid additional property{{??}}should NOT have additional properties{{?}}'", + anyOf: "'should match some schema in anyOf'", + const: "'should be equal to constant'", + contains: "'should contain a valid item'", + dependencies: "'should have {{? $deps.length == 1 }}property {{= it.util.escapeQuotes($deps[0]) }}{{??}}properties {{= it.util.escapeQuotes($deps.join(\", \")) }}{{?}} when property {{= it.util.escapeQuotes($property) }} is present'", + 'enum': "'should be equal to one of the allowed values'", + format: "'should match format \"{{#def.concatSchemaEQ}}\"'", + 'if': "'should match \"' + {{=$ifClause}} + '\" schema'", + _limit: "'should be {{=$opStr}} {{#def.appendSchema}}", + _exclusiveLimit: "'{{=$exclusiveKeyword}} should be boolean'", + _limitItems: "'should NOT have {{?$keyword=='maxItems'}}more{{??}}fewer{{?}} than {{#def.concatSchema}} items'", + _limitLength: "'should NOT be {{?$keyword=='maxLength'}}longer{{??}}shorter{{?}} than {{#def.concatSchema}} characters'", + _limitProperties:"'should NOT have {{?$keyword=='maxProperties'}}more{{??}}fewer{{?}} than {{#def.concatSchema}} properties'", + multipleOf: "'should be multiple of {{#def.appendSchema}}", + not: "'should NOT be valid'", + oneOf: "'should match exactly one schema in oneOf'", + pattern: "'should match pattern \"{{#def.concatSchemaEQ}}\"'", + propertyNames: "'property name \\'{{=$invalidName}}\\' is invalid'", + required: "'{{? it.opts._errorDataPathProperty }}is a required property{{??}}should have required property \\'{{=$missingProperty}}\\'{{?}}'", + type: "'should be {{? $typeIsArray }}{{= $typeSchema.join(\",\") }}{{??}}{{=$typeSchema}}{{?}}'", + uniqueItems: "'should NOT have duplicate items (items ## ' + j + ' and ' + i + ' are identical)'", + custom: "'should pass \"{{=$rule.keyword}}\" keyword validation'", + patternRequired: "'should have property matching pattern \\'{{=$missingPattern}}\\''", + switch: "'should pass \"switch\" keyword validation'", + _formatLimit: "'should be {{=$opStr}} \"{{#def.concatSchemaEQ}}\"'", + _formatExclusiveLimit: "'{{=$exclusiveKeyword}} should be boolean'" +} #}} + + +{{## def.schemaRefOrVal: {{?$isData}}validate.schema{{=$schemaPath}}{{??}}{{=$schema}}{{?}} #}} +{{## def.schemaRefOrQS: {{?$isData}}validate.schema{{=$schemaPath}}{{??}}{{=it.util.toQuotedString($schema)}}{{?}} #}} + +{{## def._errorSchemas = { + 'false schema': "false", + $ref: "{{=it.util.toQuotedString($schema)}}", + additionalItems: "false", + additionalProperties: "false", + anyOf: "validate.schema{{=$schemaPath}}", + const: "validate.schema{{=$schemaPath}}", + contains: "validate.schema{{=$schemaPath}}", + dependencies: "validate.schema{{=$schemaPath}}", + 'enum': "validate.schema{{=$schemaPath}}", + format: "{{#def.schemaRefOrQS}}", + 'if': "validate.schema{{=$schemaPath}}", + _limit: "{{#def.schemaRefOrVal}}", + _exclusiveLimit: "validate.schema{{=$schemaPath}}", + _limitItems: "{{#def.schemaRefOrVal}}", + _limitLength: "{{#def.schemaRefOrVal}}", + _limitProperties:"{{#def.schemaRefOrVal}}", + multipleOf: "{{#def.schemaRefOrVal}}", + not: "validate.schema{{=$schemaPath}}", + oneOf: "validate.schema{{=$schemaPath}}", + pattern: "{{#def.schemaRefOrQS}}", + propertyNames: "validate.schema{{=$schemaPath}}", + required: "validate.schema{{=$schemaPath}}", + type: "validate.schema{{=$schemaPath}}", + uniqueItems: "{{#def.schemaRefOrVal}}", + custom: "validate.schema{{=$schemaPath}}", + patternRequired: "validate.schema{{=$schemaPath}}", + switch: "validate.schema{{=$schemaPath}}", + _formatLimit: "{{#def.schemaRefOrQS}}", + _formatExclusiveLimit: "validate.schema{{=$schemaPath}}" +} #}} + + +{{## def.schemaValueQS: {{?$isData}}{{=$schemaValue}}{{??}}{{=it.util.toQuotedString($schema)}}{{?}} #}} + +{{## def._errorParams = { + 'false schema': "{}", + $ref: "{ ref: '{{=it.util.escapeQuotes($schema)}}' }", + additionalItems: "{ limit: {{=$schema.length}} }", + additionalProperties: "{ additionalProperty: '{{=$additionalProperty}}' }", + anyOf: "{}", + const: "{ allowedValue: schema{{=$lvl}} }", + contains: "{}", + dependencies: "{ property: '{{= it.util.escapeQuotes($property) }}', missingProperty: '{{=$missingProperty}}', depsCount: {{=$deps.length}}, deps: '{{= it.util.escapeQuotes($deps.length==1 ? $deps[0] : $deps.join(\", \")) }}' }", + 'enum': "{ allowedValues: schema{{=$lvl}} }", + format: "{ format: {{#def.schemaValueQS}} }", + 'if': "{ failingKeyword: {{=$ifClause}} }", + _limit: "{ comparison: {{=$opExpr}}, limit: {{=$schemaValue}}, exclusive: {{=$exclusive}} }", + _exclusiveLimit: "{}", + _limitItems: "{ limit: {{=$schemaValue}} }", + _limitLength: "{ limit: {{=$schemaValue}} }", + _limitProperties:"{ limit: {{=$schemaValue}} }", + multipleOf: "{ multipleOf: {{=$schemaValue}} }", + not: "{}", + oneOf: "{ passingSchemas: {{=$passingSchemas}} }", + pattern: "{ pattern: {{#def.schemaValueQS}} }", + propertyNames: "{ propertyName: '{{=$invalidName}}' }", + required: "{ missingProperty: '{{=$missingProperty}}' }", + type: "{ type: '{{? $typeIsArray }}{{= $typeSchema.join(\",\") }}{{??}}{{=$typeSchema}}{{?}}' }", + uniqueItems: "{ i: i, j: j }", + custom: "{ keyword: '{{=$rule.keyword}}' }", + patternRequired: "{ missingPattern: '{{=$missingPattern}}' }", + switch: "{ caseIndex: {{=$caseIndex}} }", + _formatLimit: "{ comparison: {{=$opExpr}}, limit: {{#def.schemaValueQS}}, exclusive: {{=$exclusive}} }", + _formatExclusiveLimit: "{}" +} #}} diff --git a/user/themes/goku/node_modules/ajv/lib/dot/format.jst b/user/themes/goku/node_modules/ajv/lib/dot/format.jst new file mode 100644 index 00000000..37f14da8 --- /dev/null +++ b/user/themes/goku/node_modules/ajv/lib/dot/format.jst @@ -0,0 +1,106 @@ +{{# def.definitions }} +{{# def.errors }} +{{# def.setupKeyword }} + +{{## def.skipFormat: + {{? $breakOnError }} if (true) { {{?}} + {{ return out; }} +#}} + +{{? it.opts.format === false }}{{# def.skipFormat }}{{?}} + + +{{# def.$data }} + + +{{## def.$dataCheckFormat: + {{# def.$dataNotType:'string' }} + ({{? $unknownFormats != 'ignore' }} + ({{=$schemaValue}} && !{{=$format}} + {{? $allowUnknown }} + && self._opts.unknownFormats.indexOf({{=$schemaValue}}) == -1 + {{?}}) || + {{?}} + ({{=$format}} && {{=$formatType}} == '{{=$ruleType}}' + && !(typeof {{=$format}} == 'function' + ? {{? it.async}} + (async{{=$lvl}} ? await {{=$format}}({{=$data}}) : {{=$format}}({{=$data}})) + {{??}} + {{=$format}}({{=$data}}) + {{?}} + : {{=$format}}.test({{=$data}})))) +#}} + +{{## def.checkFormat: + {{ + var $formatRef = 'formats' + it.util.getProperty($schema); + if ($isObject) $formatRef += '.validate'; + }} + {{? typeof $format == 'function' }} + {{=$formatRef}}({{=$data}}) + {{??}} + {{=$formatRef}}.test({{=$data}}) + {{?}} +#}} + + +{{ + var $unknownFormats = it.opts.unknownFormats + , $allowUnknown = Array.isArray($unknownFormats); +}} + +{{? $isData }} + {{ + var $format = 'format' + $lvl + , $isObject = 'isObject' + $lvl + , $formatType = 'formatType' + $lvl; + }} + var {{=$format}} = formats[{{=$schemaValue}}]; + var {{=$isObject}} = typeof {{=$format}} == 'object' + && !({{=$format}} instanceof RegExp) + && {{=$format}}.validate; + var {{=$formatType}} = {{=$isObject}} && {{=$format}}.type || 'string'; + if ({{=$isObject}}) { + {{? it.async}} + var async{{=$lvl}} = {{=$format}}.async; + {{?}} + {{=$format}} = {{=$format}}.validate; + } + if ({{# def.$dataCheckFormat }}) { +{{??}} + {{ var $format = it.formats[$schema]; }} + {{? !$format }} + {{? $unknownFormats == 'ignore' }} + {{ it.logger.warn('unknown format "' + $schema + '" ignored in schema at path "' + it.errSchemaPath + '"'); }} + {{# def.skipFormat }} + {{?? $allowUnknown && $unknownFormats.indexOf($schema) >= 0 }} + {{# def.skipFormat }} + {{??}} + {{ throw new Error('unknown format "' + $schema + '" is used in schema at path "' + it.errSchemaPath + '"'); }} + {{?}} + {{?}} + {{ + var $isObject = typeof $format == 'object' + && !($format instanceof RegExp) + && $format.validate; + var $formatType = $isObject && $format.type || 'string'; + if ($isObject) { + var $async = $format.async === true; + $format = $format.validate; + } + }} + {{? $formatType != $ruleType }} + {{# def.skipFormat }} + {{?}} + {{? $async }} + {{ + if (!it.async) throw new Error('async format in sync schema'); + var $formatRef = 'formats' + it.util.getProperty($schema) + '.validate'; + }} + if (!(await {{=$formatRef}}({{=$data}}))) { + {{??}} + if (!{{# def.checkFormat }}) { + {{?}} +{{?}} + {{# def.error:'format' }} + } {{? $breakOnError }} else { {{?}} diff --git a/user/themes/goku/node_modules/ajv/lib/dot/if.jst b/user/themes/goku/node_modules/ajv/lib/dot/if.jst new file mode 100644 index 00000000..7ccc9b7f --- /dev/null +++ b/user/themes/goku/node_modules/ajv/lib/dot/if.jst @@ -0,0 +1,75 @@ +{{# def.definitions }} +{{# def.errors }} +{{# def.setupKeyword }} +{{# def.setupNextLevel }} + + +{{## def.validateIfClause:_clause: + {{ + $it.schema = it.schema['_clause']; + $it.schemaPath = it.schemaPath + '._clause'; + $it.errSchemaPath = it.errSchemaPath + '/_clause'; + }} + {{# def.insertSubschemaCode }} + {{=$valid}} = {{=$nextValid}}; + {{? $thenPresent && $elsePresent }} + {{ $ifClause = 'ifClause' + $lvl; }} + var {{=$ifClause}} = '_clause'; + {{??}} + {{ $ifClause = '\'_clause\''; }} + {{?}} +#}} + +{{ + var $thenSch = it.schema['then'] + , $elseSch = it.schema['else'] + , $thenPresent = $thenSch !== undefined && {{# def.nonEmptySchema:$thenSch }} + , $elsePresent = $elseSch !== undefined && {{# def.nonEmptySchema:$elseSch }} + , $currentBaseId = $it.baseId; +}} + +{{? $thenPresent || $elsePresent }} + {{ + var $ifClause; + $it.createErrors = false; + $it.schema = $schema; + $it.schemaPath = $schemaPath; + $it.errSchemaPath = $errSchemaPath; + }} + var {{=$errs}} = errors; + var {{=$valid}} = true; + + {{# def.setCompositeRule }} + {{# def.insertSubschemaCode }} + {{ $it.createErrors = true; }} + {{# def.resetErrors }} + {{# def.resetCompositeRule }} + + {{? $thenPresent }} + if ({{=$nextValid}}) { + {{# def.validateIfClause:then }} + } + {{? $elsePresent }} + else { + {{?}} + {{??}} + if (!{{=$nextValid}}) { + {{?}} + + {{? $elsePresent }} + {{# def.validateIfClause:else }} + } + {{?}} + + if (!{{=$valid}}) { + {{# def.extraError:'if' }} + } + {{? $breakOnError }} else { {{?}} + + {{# def.cleanUp }} +{{??}} + {{? $breakOnError }} + if (true) { + {{?}} +{{?}} + diff --git a/user/themes/goku/node_modules/ajv/lib/dot/items.jst b/user/themes/goku/node_modules/ajv/lib/dot/items.jst new file mode 100644 index 00000000..8c0f5acb --- /dev/null +++ b/user/themes/goku/node_modules/ajv/lib/dot/items.jst @@ -0,0 +1,100 @@ +{{# def.definitions }} +{{# def.errors }} +{{# def.setupKeyword }} +{{# def.setupNextLevel }} + + +{{## def.validateItems:startFrom: + for (var {{=$idx}} = {{=startFrom}}; {{=$idx}} < {{=$data}}.length; {{=$idx}}++) { + {{ + $it.errorPath = it.util.getPathExpr(it.errorPath, $idx, it.opts.jsonPointers, true); + var $passData = $data + '[' + $idx + ']'; + $it.dataPathArr[$dataNxt] = $idx; + }} + + {{# def.generateSubschemaCode }} + {{# def.optimizeValidate }} + + {{? $breakOnError }} + if (!{{=$nextValid}}) break; + {{?}} + } +#}} + +{{ + var $idx = 'i' + $lvl + , $dataNxt = $it.dataLevel = it.dataLevel + 1 + , $nextData = 'data' + $dataNxt + , $currentBaseId = it.baseId; +}} + +var {{=$errs}} = errors; +var {{=$valid}}; + +{{? Array.isArray($schema) }} + {{ /* 'items' is an array of schemas */}} + {{ var $additionalItems = it.schema.additionalItems; }} + {{? $additionalItems === false }} + {{=$valid}} = {{=$data}}.length <= {{= $schema.length }}; + {{ + var $currErrSchemaPath = $errSchemaPath; + $errSchemaPath = it.errSchemaPath + '/additionalItems'; + }} + {{# def.checkError:'additionalItems' }} + {{ $errSchemaPath = $currErrSchemaPath; }} + {{# def.elseIfValid}} + {{?}} + + {{~ $schema:$sch:$i }} + {{? {{# def.nonEmptySchema:$sch }} }} + {{=$nextValid}} = true; + + if ({{=$data}}.length > {{=$i}}) { + {{ + var $passData = $data + '[' + $i + ']'; + $it.schema = $sch; + $it.schemaPath = $schemaPath + '[' + $i + ']'; + $it.errSchemaPath = $errSchemaPath + '/' + $i; + $it.errorPath = it.util.getPathExpr(it.errorPath, $i, it.opts.jsonPointers, true); + $it.dataPathArr[$dataNxt] = $i; + }} + + {{# def.generateSubschemaCode }} + {{# def.optimizeValidate }} + } + + {{# def.ifResultValid }} + {{?}} + {{~}} + + {{? typeof $additionalItems == 'object' && {{# def.nonEmptySchema:$additionalItems }} }} + {{ + $it.schema = $additionalItems; + $it.schemaPath = it.schemaPath + '.additionalItems'; + $it.errSchemaPath = it.errSchemaPath + '/additionalItems'; + }} + {{=$nextValid}} = true; + + if ({{=$data}}.length > {{= $schema.length }}) { + {{# def.validateItems: $schema.length }} + } + + {{# def.ifResultValid }} + {{?}} + +{{?? {{# def.nonEmptySchema:$schema }} }} + {{ /* 'items' is a single schema */}} + {{ + $it.schema = $schema; + $it.schemaPath = $schemaPath; + $it.errSchemaPath = $errSchemaPath; + }} + {{# def.validateItems: 0 }} +{{?}} + +{{? $breakOnError }} + {{= $closingBraces }} + if ({{=$errs}} == errors) { +{{?}} + +{{# def.cleanUp }} diff --git a/user/themes/goku/node_modules/ajv/lib/dot/missing.def b/user/themes/goku/node_modules/ajv/lib/dot/missing.def new file mode 100644 index 00000000..a73b9f96 --- /dev/null +++ b/user/themes/goku/node_modules/ajv/lib/dot/missing.def @@ -0,0 +1,39 @@ +{{## def.checkMissingProperty:_properties: + {{~ _properties:$propertyKey:$i }} + {{?$i}} || {{?}} + {{ + var $prop = it.util.getProperty($propertyKey) + , $useData = $data + $prop; + }} + ( ({{# def.noPropertyInData }}) && (missing{{=$lvl}} = {{= it.util.toQuotedString(it.opts.jsonPointers ? $propertyKey : $prop) }}) ) + {{~}} +#}} + + +{{## def.errorMissingProperty:_error: + {{ + var $propertyPath = 'missing' + $lvl + , $missingProperty = '\' + ' + $propertyPath + ' + \''; + if (it.opts._errorDataPathProperty) { + it.errorPath = it.opts.jsonPointers + ? it.util.getPathExpr($currentErrorPath, $propertyPath, true) + : $currentErrorPath + ' + ' + $propertyPath; + } + }} + {{# def.error:_error }} +#}} + + +{{## def.allErrorsMissingProperty:_error: + {{ + var $prop = it.util.getProperty($propertyKey) + , $missingProperty = it.util.escapeQuotes($propertyKey) + , $useData = $data + $prop; + if (it.opts._errorDataPathProperty) { + it.errorPath = it.util.getPath($currentErrorPath, $propertyKey, it.opts.jsonPointers); + } + }} + if ({{# def.noPropertyInData }}) { + {{# def.addError:_error }} + } +#}} diff --git a/user/themes/goku/node_modules/ajv/lib/dot/multipleOf.jst b/user/themes/goku/node_modules/ajv/lib/dot/multipleOf.jst new file mode 100644 index 00000000..5f8dd33b --- /dev/null +++ b/user/themes/goku/node_modules/ajv/lib/dot/multipleOf.jst @@ -0,0 +1,20 @@ +{{# def.definitions }} +{{# def.errors }} +{{# def.setupKeyword }} +{{# def.$data }} + +var division{{=$lvl}}; +if ({{?$isData}} + {{=$schemaValue}} !== undefined && ( + typeof {{=$schemaValue}} != 'number' || + {{?}} + (division{{=$lvl}} = {{=$data}} / {{=$schemaValue}}, + {{? it.opts.multipleOfPrecision }} + Math.abs(Math.round(division{{=$lvl}}) - division{{=$lvl}}) > 1e-{{=it.opts.multipleOfPrecision}} + {{??}} + division{{=$lvl}} !== parseInt(division{{=$lvl}}) + {{?}} + ) + {{?$isData}} ) {{?}} ) { + {{# def.error:'multipleOf' }} +} {{? $breakOnError }} else { {{?}} diff --git a/user/themes/goku/node_modules/ajv/lib/dot/not.jst b/user/themes/goku/node_modules/ajv/lib/dot/not.jst new file mode 100644 index 00000000..e03185ae --- /dev/null +++ b/user/themes/goku/node_modules/ajv/lib/dot/not.jst @@ -0,0 +1,43 @@ +{{# def.definitions }} +{{# def.errors }} +{{# def.setupKeyword }} +{{# def.setupNextLevel }} + +{{? {{# def.nonEmptySchema:$schema }} }} + {{ + $it.schema = $schema; + $it.schemaPath = $schemaPath; + $it.errSchemaPath = $errSchemaPath; + }} + + var {{=$errs}} = errors; + + {{# def.setCompositeRule }} + + {{ + $it.createErrors = false; + var $allErrorsOption; + if ($it.opts.allErrors) { + $allErrorsOption = $it.opts.allErrors; + $it.opts.allErrors = false; + } + }} + {{= it.validate($it) }} + {{ + $it.createErrors = true; + if ($allErrorsOption) $it.opts.allErrors = $allErrorsOption; + }} + + {{# def.resetCompositeRule }} + + if ({{=$nextValid}}) { + {{# def.error:'not' }} + } else { + {{# def.resetErrors }} + {{? it.opts.allErrors }} } {{?}} +{{??}} + {{# def.addError:'not' }} + {{? $breakOnError}} + if (false) { + {{?}} +{{?}} diff --git a/user/themes/goku/node_modules/ajv/lib/dot/oneOf.jst b/user/themes/goku/node_modules/ajv/lib/dot/oneOf.jst new file mode 100644 index 00000000..bcce2c6e --- /dev/null +++ b/user/themes/goku/node_modules/ajv/lib/dot/oneOf.jst @@ -0,0 +1,54 @@ +{{# def.definitions }} +{{# def.errors }} +{{# def.setupKeyword }} +{{# def.setupNextLevel }} + +{{ + var $currentBaseId = $it.baseId + , $prevValid = 'prevValid' + $lvl + , $passingSchemas = 'passingSchemas' + $lvl; +}} + +var {{=$errs}} = errors + , {{=$prevValid}} = false + , {{=$valid}} = false + , {{=$passingSchemas}} = null; + +{{# def.setCompositeRule }} + +{{~ $schema:$sch:$i }} + {{? {{# def.nonEmptySchema:$sch }} }} + {{ + $it.schema = $sch; + $it.schemaPath = $schemaPath + '[' + $i + ']'; + $it.errSchemaPath = $errSchemaPath + '/' + $i; + }} + + {{# def.insertSubschemaCode }} + {{??}} + var {{=$nextValid}} = true; + {{?}} + + {{? $i }} + if ({{=$nextValid}} && {{=$prevValid}}) { + {{=$valid}} = false; + {{=$passingSchemas}} = [{{=$passingSchemas}}, {{=$i}}]; + } else { + {{ $closingBraces += '}'; }} + {{?}} + + if ({{=$nextValid}}) { + {{=$valid}} = {{=$prevValid}} = true; + {{=$passingSchemas}} = {{=$i}}; + } +{{~}} + +{{# def.resetCompositeRule }} + +{{= $closingBraces }} + +if (!{{=$valid}}) { + {{# def.extraError:'oneOf' }} +} else { + {{# def.resetErrors }} +{{? it.opts.allErrors }} } {{?}} diff --git a/user/themes/goku/node_modules/ajv/lib/dot/pattern.jst b/user/themes/goku/node_modules/ajv/lib/dot/pattern.jst new file mode 100644 index 00000000..3a37ef6c --- /dev/null +++ b/user/themes/goku/node_modules/ajv/lib/dot/pattern.jst @@ -0,0 +1,14 @@ +{{# def.definitions }} +{{# def.errors }} +{{# def.setupKeyword }} +{{# def.$data }} + +{{ + var $regexp = $isData + ? '(new RegExp(' + $schemaValue + '))' + : it.usePattern($schema); +}} + +if ({{# def.$dataNotType:'string' }} !{{=$regexp}}.test({{=$data}}) ) { + {{# def.error:'pattern' }} +} {{? $breakOnError }} else { {{?}} diff --git a/user/themes/goku/node_modules/ajv/lib/dot/properties.jst b/user/themes/goku/node_modules/ajv/lib/dot/properties.jst new file mode 100644 index 00000000..862067e7 --- /dev/null +++ b/user/themes/goku/node_modules/ajv/lib/dot/properties.jst @@ -0,0 +1,244 @@ +{{# def.definitions }} +{{# def.errors }} +{{# def.setupKeyword }} +{{# def.setupNextLevel }} + + +{{## def.validateAdditional: + {{ /* additionalProperties is schema */ + $it.schema = $aProperties; + $it.schemaPath = it.schemaPath + '.additionalProperties'; + $it.errSchemaPath = it.errSchemaPath + '/additionalProperties'; + $it.errorPath = it.opts._errorDataPathProperty + ? it.errorPath + : it.util.getPathExpr(it.errorPath, $key, it.opts.jsonPointers); + var $passData = $data + '[' + $key + ']'; + $it.dataPathArr[$dataNxt] = $key; + }} + + {{# def.generateSubschemaCode }} + {{# def.optimizeValidate }} +#}} + + +{{ + var $key = 'key' + $lvl + , $idx = 'idx' + $lvl + , $dataNxt = $it.dataLevel = it.dataLevel + 1 + , $nextData = 'data' + $dataNxt + , $dataProperties = 'dataProperties' + $lvl; + + var $schemaKeys = Object.keys($schema || {}) + , $pProperties = it.schema.patternProperties || {} + , $pPropertyKeys = Object.keys($pProperties) + , $aProperties = it.schema.additionalProperties + , $someProperties = $schemaKeys.length || $pPropertyKeys.length + , $noAdditional = $aProperties === false + , $additionalIsSchema = typeof $aProperties == 'object' + && Object.keys($aProperties).length + , $removeAdditional = it.opts.removeAdditional + , $checkAdditional = $noAdditional || $additionalIsSchema || $removeAdditional + , $ownProperties = it.opts.ownProperties + , $currentBaseId = it.baseId; + + var $required = it.schema.required; + if ($required && !(it.opts.$data && $required.$data) && $required.length < it.opts.loopRequired) + var $requiredHash = it.util.toHash($required); +}} + + +var {{=$errs}} = errors; +var {{=$nextValid}} = true; +{{? $ownProperties }} + var {{=$dataProperties}} = undefined; +{{?}} + +{{? $checkAdditional }} + {{# def.iterateProperties }} + {{? $someProperties }} + var isAdditional{{=$lvl}} = !(false + {{? $schemaKeys.length }} + {{? $schemaKeys.length > 8 }} + || validate.schema{{=$schemaPath}}.hasOwnProperty({{=$key}}) + {{??}} + {{~ $schemaKeys:$propertyKey }} + || {{=$key}} == {{= it.util.toQuotedString($propertyKey) }} + {{~}} + {{?}} + {{?}} + {{? $pPropertyKeys.length }} + {{~ $pPropertyKeys:$pProperty:$i }} + || {{= it.usePattern($pProperty) }}.test({{=$key}}) + {{~}} + {{?}} + ); + + if (isAdditional{{=$lvl}}) { + {{?}} + {{? $removeAdditional == 'all' }} + delete {{=$data}}[{{=$key}}]; + {{??}} + {{ + var $currentErrorPath = it.errorPath; + var $additionalProperty = '\' + ' + $key + ' + \''; + if (it.opts._errorDataPathProperty) { + it.errorPath = it.util.getPathExpr(it.errorPath, $key, it.opts.jsonPointers); + } + }} + {{? $noAdditional }} + {{? $removeAdditional }} + delete {{=$data}}[{{=$key}}]; + {{??}} + {{=$nextValid}} = false; + {{ + var $currErrSchemaPath = $errSchemaPath; + $errSchemaPath = it.errSchemaPath + '/additionalProperties'; + }} + {{# def.error:'additionalProperties' }} + {{ $errSchemaPath = $currErrSchemaPath; }} + {{? $breakOnError }} break; {{?}} + {{?}} + {{?? $additionalIsSchema }} + {{? $removeAdditional == 'failing' }} + var {{=$errs}} = errors; + {{# def.setCompositeRule }} + + {{# def.validateAdditional }} + + if (!{{=$nextValid}}) { + errors = {{=$errs}}; + if (validate.errors !== null) { + if (errors) validate.errors.length = errors; + else validate.errors = null; + } + delete {{=$data}}[{{=$key}}]; + } + + {{# def.resetCompositeRule }} + {{??}} + {{# def.validateAdditional }} + {{? $breakOnError }} if (!{{=$nextValid}}) break; {{?}} + {{?}} + {{?}} + {{ it.errorPath = $currentErrorPath; }} + {{?}} + {{? $someProperties }} + } + {{?}} + } + + {{# def.ifResultValid }} +{{?}} + +{{ var $useDefaults = it.opts.useDefaults && !it.compositeRule; }} + +{{? $schemaKeys.length }} + {{~ $schemaKeys:$propertyKey }} + {{ var $sch = $schema[$propertyKey]; }} + + {{? {{# def.nonEmptySchema:$sch}} }} + {{ + var $prop = it.util.getProperty($propertyKey) + , $passData = $data + $prop + , $hasDefault = $useDefaults && $sch.default !== undefined; + $it.schema = $sch; + $it.schemaPath = $schemaPath + $prop; + $it.errSchemaPath = $errSchemaPath + '/' + it.util.escapeFragment($propertyKey); + $it.errorPath = it.util.getPath(it.errorPath, $propertyKey, it.opts.jsonPointers); + $it.dataPathArr[$dataNxt] = it.util.toQuotedString($propertyKey); + }} + + {{# def.generateSubschemaCode }} + + {{? {{# def.willOptimize }} }} + {{ + $code = {{# def._optimizeValidate }}; + var $useData = $passData; + }} + {{??}} + {{ var $useData = $nextData; }} + var {{=$nextData}} = {{=$passData}}; + {{?}} + + {{? $hasDefault }} + {{= $code }} + {{??}} + {{? $requiredHash && $requiredHash[$propertyKey] }} + if ({{# def.noPropertyInData }}) { + {{=$nextValid}} = false; + {{ + var $currentErrorPath = it.errorPath + , $currErrSchemaPath = $errSchemaPath + , $missingProperty = it.util.escapeQuotes($propertyKey); + if (it.opts._errorDataPathProperty) { + it.errorPath = it.util.getPath($currentErrorPath, $propertyKey, it.opts.jsonPointers); + } + $errSchemaPath = it.errSchemaPath + '/required'; + }} + {{# def.error:'required' }} + {{ $errSchemaPath = $currErrSchemaPath; }} + {{ it.errorPath = $currentErrorPath; }} + } else { + {{??}} + {{? $breakOnError }} + if ({{# def.noPropertyInData }}) { + {{=$nextValid}} = true; + } else { + {{??}} + if ({{=$useData}} !== undefined + {{? $ownProperties }} + && {{# def.isOwnProperty }} + {{?}} + ) { + {{?}} + {{?}} + + {{= $code }} + } + {{?}} {{ /* $hasDefault */ }} + {{?}} {{ /* def.nonEmptySchema */ }} + + {{# def.ifResultValid }} + {{~}} +{{?}} + +{{? $pPropertyKeys.length }} + {{~ $pPropertyKeys:$pProperty }} + {{ var $sch = $pProperties[$pProperty]; }} + + {{? {{# def.nonEmptySchema:$sch}} }} + {{ + $it.schema = $sch; + $it.schemaPath = it.schemaPath + '.patternProperties' + it.util.getProperty($pProperty); + $it.errSchemaPath = it.errSchemaPath + '/patternProperties/' + + it.util.escapeFragment($pProperty); + }} + + {{# def.iterateProperties }} + if ({{= it.usePattern($pProperty) }}.test({{=$key}})) { + {{ + $it.errorPath = it.util.getPathExpr(it.errorPath, $key, it.opts.jsonPointers); + var $passData = $data + '[' + $key + ']'; + $it.dataPathArr[$dataNxt] = $key; + }} + + {{# def.generateSubschemaCode }} + {{# def.optimizeValidate }} + + {{? $breakOnError }} if (!{{=$nextValid}}) break; {{?}} + } + {{? $breakOnError }} else {{=$nextValid}} = true; {{?}} + } + + {{# def.ifResultValid }} + {{?}} {{ /* def.nonEmptySchema */ }} + {{~}} +{{?}} + + +{{? $breakOnError }} + {{= $closingBraces }} + if ({{=$errs}} == errors) { +{{?}} + +{{# def.cleanUp }} diff --git a/user/themes/goku/node_modules/ajv/lib/dot/propertyNames.jst b/user/themes/goku/node_modules/ajv/lib/dot/propertyNames.jst new file mode 100644 index 00000000..ee52b215 --- /dev/null +++ b/user/themes/goku/node_modules/ajv/lib/dot/propertyNames.jst @@ -0,0 +1,54 @@ +{{# def.definitions }} +{{# def.errors }} +{{# def.setupKeyword }} +{{# def.setupNextLevel }} + +var {{=$errs}} = errors; + +{{? {{# def.nonEmptySchema:$schema }} }} + {{ + $it.schema = $schema; + $it.schemaPath = $schemaPath; + $it.errSchemaPath = $errSchemaPath; + }} + + {{ + var $key = 'key' + $lvl + , $idx = 'idx' + $lvl + , $i = 'i' + $lvl + , $invalidName = '\' + ' + $key + ' + \'' + , $dataNxt = $it.dataLevel = it.dataLevel + 1 + , $nextData = 'data' + $dataNxt + , $dataProperties = 'dataProperties' + $lvl + , $ownProperties = it.opts.ownProperties + , $currentBaseId = it.baseId; + }} + + {{? $ownProperties }} + var {{=$dataProperties}} = undefined; + {{?}} + {{# def.iterateProperties }} + var startErrs{{=$lvl}} = errors; + + {{ var $passData = $key; }} + {{# def.setCompositeRule }} + {{# def.generateSubschemaCode }} + {{# def.optimizeValidate }} + {{# def.resetCompositeRule }} + + if (!{{=$nextValid}}) { + for (var {{=$i}}=startErrs{{=$lvl}}; {{=$i}}= it.opts.loopRequired + , $ownProperties = it.opts.ownProperties; + }} + + {{? $breakOnError }} + var missing{{=$lvl}}; + {{? $loopRequired }} + {{# def.setupLoop }} + var {{=$valid}} = true; + + {{?$isData}}{{# def.check$dataIsArray }}{{?}} + + for (var {{=$i}} = 0; {{=$i}} < {{=$vSchema}}.length; {{=$i}}++) { + {{=$valid}} = {{=$data}}[{{=$vSchema}}[{{=$i}}]] !== undefined + {{? $ownProperties }} + && {{# def.isRequiredOwnProperty }} + {{?}}; + if (!{{=$valid}}) break; + } + + {{? $isData }} } {{?}} + + {{# def.checkError:'required' }} + else { + {{??}} + if ({{# def.checkMissingProperty:$required }}) { + {{# def.errorMissingProperty:'required' }} + } else { + {{?}} + {{??}} + {{? $loopRequired }} + {{# def.setupLoop }} + {{? $isData }} + if ({{=$vSchema}} && !Array.isArray({{=$vSchema}})) { + {{# def.addError:'required' }} + } else if ({{=$vSchema}} !== undefined) { + {{?}} + + for (var {{=$i}} = 0; {{=$i}} < {{=$vSchema}}.length; {{=$i}}++) { + if ({{=$data}}[{{=$vSchema}}[{{=$i}}]] === undefined + {{? $ownProperties }} + || !{{# def.isRequiredOwnProperty }} + {{?}}) { + {{# def.addError:'required' }} + } + } + + {{? $isData }} } {{?}} + {{??}} + {{~ $required:$propertyKey }} + {{# def.allErrorsMissingProperty:'required' }} + {{~}} + {{?}} + {{?}} + + {{ it.errorPath = $currentErrorPath; }} + +{{?? $breakOnError }} + if (true) { +{{?}} diff --git a/user/themes/goku/node_modules/ajv/lib/dot/uniqueItems.jst b/user/themes/goku/node_modules/ajv/lib/dot/uniqueItems.jst new file mode 100644 index 00000000..22f82f99 --- /dev/null +++ b/user/themes/goku/node_modules/ajv/lib/dot/uniqueItems.jst @@ -0,0 +1,62 @@ +{{# def.definitions }} +{{# def.errors }} +{{# def.setupKeyword }} +{{# def.$data }} + + +{{? ($schema || $isData) && it.opts.uniqueItems !== false }} + {{? $isData }} + var {{=$valid}}; + if ({{=$schemaValue}} === false || {{=$schemaValue}} === undefined) + {{=$valid}} = true; + else if (typeof {{=$schemaValue}} != 'boolean') + {{=$valid}} = false; + else { + {{?}} + + var i = {{=$data}}.length + , {{=$valid}} = true + , j; + if (i > 1) { + {{ + var $itemType = it.schema.items && it.schema.items.type + , $typeIsArray = Array.isArray($itemType); + }} + {{? !$itemType || $itemType == 'object' || $itemType == 'array' || + ($typeIsArray && ($itemType.indexOf('object') >= 0 || $itemType.indexOf('array') >= 0)) }} + outer: + for (;i--;) { + for (j = i; j--;) { + if (equal({{=$data}}[i], {{=$data}}[j])) { + {{=$valid}} = false; + break outer; + } + } + } + {{??}} + var itemIndices = {}, item; + for (;i--;) { + var item = {{=$data}}[i]; + {{ var $method = 'checkDataType' + ($typeIsArray ? 's' : ''); }} + if ({{= it.util[$method]($itemType, 'item', true) }}) continue; + {{? $typeIsArray}} + if (typeof item == 'string') item = '"' + item; + {{?}} + if (typeof itemIndices[item] == 'number') { + {{=$valid}} = false; + j = itemIndices[item]; + break; + } + itemIndices[item] = i; + } + {{?}} + } + + {{? $isData }} } {{?}} + + if (!{{=$valid}}) { + {{# def.error:'uniqueItems' }} + } {{? $breakOnError }} else { {{?}} +{{??}} + {{? $breakOnError }} if (true) { {{?}} +{{?}} diff --git a/user/themes/goku/node_modules/ajv/lib/dot/validate.jst b/user/themes/goku/node_modules/ajv/lib/dot/validate.jst new file mode 100644 index 00000000..f8a1edfc --- /dev/null +++ b/user/themes/goku/node_modules/ajv/lib/dot/validate.jst @@ -0,0 +1,282 @@ +{{# def.definitions }} +{{# def.errors }} +{{# def.defaults }} +{{# def.coerce }} + +{{ /** + * schema compilation (render) time: + * it = { schema, RULES, _validate, opts } + * it.validate - this template function, + * it is used recursively to generate code for subschemas + * + * runtime: + * "validate" is a variable name to which this function will be assigned + * validateRef etc. are defined in the parent scope in index.js + */ }} + +{{ + var $async = it.schema.$async === true + , $refKeywords = it.util.schemaHasRulesExcept(it.schema, it.RULES.all, '$ref') + , $id = it.self._getId(it.schema); +}} + +{{ + if (it.opts.strictKeywords) { + var $unknownKwd = it.util.schemaUnknownRules(it.schema, it.RULES.keywords); + if ($unknownKwd) { + var $keywordsMsg = 'unknown keyword: ' + $unknownKwd; + if (it.opts.strictKeywords === 'log') it.logger.warn($keywordsMsg); + else throw new Error($keywordsMsg); + } + } +}} + +{{? it.isTop }} + var validate = {{?$async}}{{it.async = true;}}async {{?}}function(data, dataPath, parentData, parentDataProperty, rootData) { + 'use strict'; + {{? $id && (it.opts.sourceCode || it.opts.processCode) }} + {{= '/\*# sourceURL=' + $id + ' */' }} + {{?}} +{{?}} + +{{? typeof it.schema == 'boolean' || !($refKeywords || it.schema.$ref) }} + {{ var $keyword = 'false schema'; }} + {{# def.setupKeyword }} + {{? it.schema === false}} + {{? it.isTop}} + {{ $breakOnError = true; }} + {{??}} + var {{=$valid}} = false; + {{?}} + {{# def.error:'false schema' }} + {{??}} + {{? it.isTop}} + {{? $async }} + return data; + {{??}} + validate.errors = null; + return true; + {{?}} + {{??}} + var {{=$valid}} = true; + {{?}} + {{?}} + + {{? it.isTop}} + }; + return validate; + {{?}} + + {{ return out; }} +{{?}} + + +{{? it.isTop }} + {{ + var $top = it.isTop + , $lvl = it.level = 0 + , $dataLvl = it.dataLevel = 0 + , $data = 'data'; + it.rootId = it.resolve.fullPath(it.self._getId(it.root.schema)); + it.baseId = it.baseId || it.rootId; + delete it.isTop; + + it.dataPathArr = [undefined]; + + if (it.schema.default !== undefined && it.opts.useDefaults && it.opts.strictDefaults) { + var $defaultMsg = 'default is ignored in the schema root'; + if (it.opts.strictDefaults === 'log') it.logger.warn($defaultMsg); + else throw new Error($defaultMsg); + } + }} + + var vErrors = null; {{ /* don't edit, used in replace */ }} + var errors = 0; {{ /* don't edit, used in replace */ }} + if (rootData === undefined) rootData = data; {{ /* don't edit, used in replace */ }} +{{??}} + {{ + var $lvl = it.level + , $dataLvl = it.dataLevel + , $data = 'data' + ($dataLvl || ''); + + if ($id) it.baseId = it.resolve.url(it.baseId, $id); + + if ($async && !it.async) throw new Error('async schema in sync schema'); + }} + + var errs_{{=$lvl}} = errors; +{{?}} + +{{ + var $valid = 'valid' + $lvl + , $breakOnError = !it.opts.allErrors + , $closingBraces1 = '' + , $closingBraces2 = ''; + + var $errorKeyword; + var $typeSchema = it.schema.type + , $typeIsArray = Array.isArray($typeSchema); + + if ($typeSchema && it.opts.nullable && it.schema.nullable === true) { + if ($typeIsArray) { + if ($typeSchema.indexOf('null') == -1) + $typeSchema = $typeSchema.concat('null'); + } else if ($typeSchema != 'null') { + $typeSchema = [$typeSchema, 'null']; + $typeIsArray = true; + } + } + + if ($typeIsArray && $typeSchema.length == 1) { + $typeSchema = $typeSchema[0]; + $typeIsArray = false; + } +}} + +{{## def.checkType: + {{ + var $schemaPath = it.schemaPath + '.type' + , $errSchemaPath = it.errSchemaPath + '/type' + , $method = $typeIsArray ? 'checkDataTypes' : 'checkDataType'; + }} + + if ({{= it.util[$method]($typeSchema, $data, true) }}) { +#}} + +{{? it.schema.$ref && $refKeywords }} + {{? it.opts.extendRefs == 'fail' }} + {{ throw new Error('$ref: validation keywords used in schema at path "' + it.errSchemaPath + '" (see option extendRefs)'); }} + {{?? it.opts.extendRefs !== true }} + {{ + $refKeywords = false; + it.logger.warn('$ref: keywords ignored in schema at path "' + it.errSchemaPath + '"'); + }} + {{?}} +{{?}} + +{{? it.schema.$comment && it.opts.$comment }} + {{= it.RULES.all.$comment.code(it, '$comment') }} +{{?}} + +{{? $typeSchema }} + {{? it.opts.coerceTypes }} + {{ var $coerceToTypes = it.util.coerceToTypes(it.opts.coerceTypes, $typeSchema); }} + {{?}} + + {{ var $rulesGroup = it.RULES.types[$typeSchema]; }} + {{? $coerceToTypes || $typeIsArray || $rulesGroup === true || + ($rulesGroup && !$shouldUseGroup($rulesGroup)) }} + {{ + var $schemaPath = it.schemaPath + '.type' + , $errSchemaPath = it.errSchemaPath + '/type'; + }} + {{# def.checkType }} + {{? $coerceToTypes }} + {{# def.coerceType }} + {{??}} + {{# def.error:'type' }} + {{?}} + } + {{?}} +{{?}} + + +{{? it.schema.$ref && !$refKeywords }} + {{= it.RULES.all.$ref.code(it, '$ref') }} + {{? $breakOnError }} + } + if (errors === {{?$top}}0{{??}}errs_{{=$lvl}}{{?}}) { + {{ $closingBraces2 += '}'; }} + {{?}} +{{??}} + {{~ it.RULES:$rulesGroup }} + {{? $shouldUseGroup($rulesGroup) }} + {{? $rulesGroup.type }} + if ({{= it.util.checkDataType($rulesGroup.type, $data) }}) { + {{?}} + {{? it.opts.useDefaults }} + {{? $rulesGroup.type == 'object' && it.schema.properties }} + {{# def.defaultProperties }} + {{?? $rulesGroup.type == 'array' && Array.isArray(it.schema.items) }} + {{# def.defaultItems }} + {{?}} + {{?}} + {{~ $rulesGroup.rules:$rule }} + {{? $shouldUseRule($rule) }} + {{ var $code = $rule.code(it, $rule.keyword, $rulesGroup.type); }} + {{? $code }} + {{= $code }} + {{? $breakOnError }} + {{ $closingBraces1 += '}'; }} + {{?}} + {{?}} + {{?}} + {{~}} + {{? $breakOnError }} + {{= $closingBraces1 }} + {{ $closingBraces1 = ''; }} + {{?}} + {{? $rulesGroup.type }} + } + {{? $typeSchema && $typeSchema === $rulesGroup.type && !$coerceToTypes }} + else { + {{ + var $schemaPath = it.schemaPath + '.type' + , $errSchemaPath = it.errSchemaPath + '/type'; + }} + {{# def.error:'type' }} + } + {{?}} + {{?}} + + {{? $breakOnError }} + if (errors === {{?$top}}0{{??}}errs_{{=$lvl}}{{?}}) { + {{ $closingBraces2 += '}'; }} + {{?}} + {{?}} + {{~}} +{{?}} + +{{? $breakOnError }} {{= $closingBraces2 }} {{?}} + +{{? $top }} + {{? $async }} + if (errors === 0) return data; {{ /* don't edit, used in replace */ }} + else throw new ValidationError(vErrors); {{ /* don't edit, used in replace */ }} + {{??}} + validate.errors = vErrors; {{ /* don't edit, used in replace */ }} + return errors === 0; {{ /* don't edit, used in replace */ }} + {{?}} + }; + + return validate; +{{??}} + var {{=$valid}} = errors === errs_{{=$lvl}}; +{{?}} + +{{# def.cleanUp }} + +{{? $top }} + {{# def.finalCleanUp }} +{{?}} + +{{ + function $shouldUseGroup($rulesGroup) { + var rules = $rulesGroup.rules; + for (var i=0; i < rules.length; i++) + if ($shouldUseRule(rules[i])) + return true; + } + + function $shouldUseRule($rule) { + return it.schema[$rule.keyword] !== undefined || + ($rule.implements && $ruleImplementsSomeKeyword($rule)); + } + + function $ruleImplementsSomeKeyword($rule) { + var impl = $rule.implements; + for (var i=0; i < impl.length; i++) + if (it.schema[impl[i]] !== undefined) + return true; + } +}} diff --git a/user/themes/goku/node_modules/ajv/lib/dotjs/README.md b/user/themes/goku/node_modules/ajv/lib/dotjs/README.md new file mode 100644 index 00000000..4d994846 --- /dev/null +++ b/user/themes/goku/node_modules/ajv/lib/dotjs/README.md @@ -0,0 +1,3 @@ +These files are compiled dot templates from dot folder. + +Do NOT edit them directly, edit the templates and run `npm run build` from main ajv folder. diff --git a/user/themes/goku/node_modules/ajv/lib/dotjs/_limit.js b/user/themes/goku/node_modules/ajv/lib/dotjs/_limit.js new file mode 100644 index 00000000..f02a7601 --- /dev/null +++ b/user/themes/goku/node_modules/ajv/lib/dotjs/_limit.js @@ -0,0 +1,157 @@ +'use strict'; +module.exports = function generate__limit(it, $keyword, $ruleType) { + var out = ' '; + var $lvl = it.level; + var $dataLvl = it.dataLevel; + var $schema = it.schema[$keyword]; + var $schemaPath = it.schemaPath + it.util.getProperty($keyword); + var $errSchemaPath = it.errSchemaPath + '/' + $keyword; + var $breakOnError = !it.opts.allErrors; + var $errorKeyword; + var $data = 'data' + ($dataLvl || ''); + var $isData = it.opts.$data && $schema && $schema.$data, + $schemaValue; + if ($isData) { + out += ' var schema' + ($lvl) + ' = ' + (it.util.getData($schema.$data, $dataLvl, it.dataPathArr)) + '; '; + $schemaValue = 'schema' + $lvl; + } else { + $schemaValue = $schema; + } + var $isMax = $keyword == 'maximum', + $exclusiveKeyword = $isMax ? 'exclusiveMaximum' : 'exclusiveMinimum', + $schemaExcl = it.schema[$exclusiveKeyword], + $isDataExcl = it.opts.$data && $schemaExcl && $schemaExcl.$data, + $op = $isMax ? '<' : '>', + $notOp = $isMax ? '>' : '<', + $errorKeyword = undefined; + if ($isDataExcl) { + var $schemaValueExcl = it.util.getData($schemaExcl.$data, $dataLvl, it.dataPathArr), + $exclusive = 'exclusive' + $lvl, + $exclType = 'exclType' + $lvl, + $exclIsNumber = 'exclIsNumber' + $lvl, + $opExpr = 'op' + $lvl, + $opStr = '\' + ' + $opExpr + ' + \''; + out += ' var schemaExcl' + ($lvl) + ' = ' + ($schemaValueExcl) + '; '; + $schemaValueExcl = 'schemaExcl' + $lvl; + out += ' var ' + ($exclusive) + '; var ' + ($exclType) + ' = typeof ' + ($schemaValueExcl) + '; if (' + ($exclType) + ' != \'boolean\' && ' + ($exclType) + ' != \'undefined\' && ' + ($exclType) + ' != \'number\') { '; + var $errorKeyword = $exclusiveKeyword; + var $$outStack = $$outStack || []; + $$outStack.push(out); + out = ''; /* istanbul ignore else */ + if (it.createErrors !== false) { + out += ' { keyword: \'' + ($errorKeyword || '_exclusiveLimit') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: {} '; + if (it.opts.messages !== false) { + out += ' , message: \'' + ($exclusiveKeyword) + ' should be boolean\' '; + } + if (it.opts.verbose) { + out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; + } + out += ' } '; + } else { + out += ' {} '; + } + var __err = out; + out = $$outStack.pop(); + if (!it.compositeRule && $breakOnError) { + /* istanbul ignore if */ + if (it.async) { + out += ' throw new ValidationError([' + (__err) + ']); '; + } else { + out += ' validate.errors = [' + (__err) + ']; return false; '; + } + } else { + out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; + } + out += ' } else if ( '; + if ($isData) { + out += ' (' + ($schemaValue) + ' !== undefined && typeof ' + ($schemaValue) + ' != \'number\') || '; + } + out += ' ' + ($exclType) + ' == \'number\' ? ( (' + ($exclusive) + ' = ' + ($schemaValue) + ' === undefined || ' + ($schemaValueExcl) + ' ' + ($op) + '= ' + ($schemaValue) + ') ? ' + ($data) + ' ' + ($notOp) + '= ' + ($schemaValueExcl) + ' : ' + ($data) + ' ' + ($notOp) + ' ' + ($schemaValue) + ' ) : ( (' + ($exclusive) + ' = ' + ($schemaValueExcl) + ' === true) ? ' + ($data) + ' ' + ($notOp) + '= ' + ($schemaValue) + ' : ' + ($data) + ' ' + ($notOp) + ' ' + ($schemaValue) + ' ) || ' + ($data) + ' !== ' + ($data) + ') { var op' + ($lvl) + ' = ' + ($exclusive) + ' ? \'' + ($op) + '\' : \'' + ($op) + '=\'; '; + if ($schema === undefined) { + $errorKeyword = $exclusiveKeyword; + $errSchemaPath = it.errSchemaPath + '/' + $exclusiveKeyword; + $schemaValue = $schemaValueExcl; + $isData = $isDataExcl; + } + } else { + var $exclIsNumber = typeof $schemaExcl == 'number', + $opStr = $op; + if ($exclIsNumber && $isData) { + var $opExpr = '\'' + $opStr + '\''; + out += ' if ( '; + if ($isData) { + out += ' (' + ($schemaValue) + ' !== undefined && typeof ' + ($schemaValue) + ' != \'number\') || '; + } + out += ' ( ' + ($schemaValue) + ' === undefined || ' + ($schemaExcl) + ' ' + ($op) + '= ' + ($schemaValue) + ' ? ' + ($data) + ' ' + ($notOp) + '= ' + ($schemaExcl) + ' : ' + ($data) + ' ' + ($notOp) + ' ' + ($schemaValue) + ' ) || ' + ($data) + ' !== ' + ($data) + ') { '; + } else { + if ($exclIsNumber && $schema === undefined) { + $exclusive = true; + $errorKeyword = $exclusiveKeyword; + $errSchemaPath = it.errSchemaPath + '/' + $exclusiveKeyword; + $schemaValue = $schemaExcl; + $notOp += '='; + } else { + if ($exclIsNumber) $schemaValue = Math[$isMax ? 'min' : 'max']($schemaExcl, $schema); + if ($schemaExcl === ($exclIsNumber ? $schemaValue : true)) { + $exclusive = true; + $errorKeyword = $exclusiveKeyword; + $errSchemaPath = it.errSchemaPath + '/' + $exclusiveKeyword; + $notOp += '='; + } else { + $exclusive = false; + $opStr += '='; + } + } + var $opExpr = '\'' + $opStr + '\''; + out += ' if ( '; + if ($isData) { + out += ' (' + ($schemaValue) + ' !== undefined && typeof ' + ($schemaValue) + ' != \'number\') || '; + } + out += ' ' + ($data) + ' ' + ($notOp) + ' ' + ($schemaValue) + ' || ' + ($data) + ' !== ' + ($data) + ') { '; + } + } + $errorKeyword = $errorKeyword || $keyword; + var $$outStack = $$outStack || []; + $$outStack.push(out); + out = ''; /* istanbul ignore else */ + if (it.createErrors !== false) { + out += ' { keyword: \'' + ($errorKeyword || '_limit') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { comparison: ' + ($opExpr) + ', limit: ' + ($schemaValue) + ', exclusive: ' + ($exclusive) + ' } '; + if (it.opts.messages !== false) { + out += ' , message: \'should be ' + ($opStr) + ' '; + if ($isData) { + out += '\' + ' + ($schemaValue); + } else { + out += '' + ($schemaValue) + '\''; + } + } + if (it.opts.verbose) { + out += ' , schema: '; + if ($isData) { + out += 'validate.schema' + ($schemaPath); + } else { + out += '' + ($schema); + } + out += ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; + } + out += ' } '; + } else { + out += ' {} '; + } + var __err = out; + out = $$outStack.pop(); + if (!it.compositeRule && $breakOnError) { + /* istanbul ignore if */ + if (it.async) { + out += ' throw new ValidationError([' + (__err) + ']); '; + } else { + out += ' validate.errors = [' + (__err) + ']; return false; '; + } + } else { + out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; + } + out += ' } '; + if ($breakOnError) { + out += ' else { '; + } + return out; +} diff --git a/user/themes/goku/node_modules/ajv/lib/dotjs/_limitItems.js b/user/themes/goku/node_modules/ajv/lib/dotjs/_limitItems.js new file mode 100644 index 00000000..a27d1188 --- /dev/null +++ b/user/themes/goku/node_modules/ajv/lib/dotjs/_limitItems.js @@ -0,0 +1,77 @@ +'use strict'; +module.exports = function generate__limitItems(it, $keyword, $ruleType) { + var out = ' '; + var $lvl = it.level; + var $dataLvl = it.dataLevel; + var $schema = it.schema[$keyword]; + var $schemaPath = it.schemaPath + it.util.getProperty($keyword); + var $errSchemaPath = it.errSchemaPath + '/' + $keyword; + var $breakOnError = !it.opts.allErrors; + var $errorKeyword; + var $data = 'data' + ($dataLvl || ''); + var $isData = it.opts.$data && $schema && $schema.$data, + $schemaValue; + if ($isData) { + out += ' var schema' + ($lvl) + ' = ' + (it.util.getData($schema.$data, $dataLvl, it.dataPathArr)) + '; '; + $schemaValue = 'schema' + $lvl; + } else { + $schemaValue = $schema; + } + var $op = $keyword == 'maxItems' ? '>' : '<'; + out += 'if ( '; + if ($isData) { + out += ' (' + ($schemaValue) + ' !== undefined && typeof ' + ($schemaValue) + ' != \'number\') || '; + } + out += ' ' + ($data) + '.length ' + ($op) + ' ' + ($schemaValue) + ') { '; + var $errorKeyword = $keyword; + var $$outStack = $$outStack || []; + $$outStack.push(out); + out = ''; /* istanbul ignore else */ + if (it.createErrors !== false) { + out += ' { keyword: \'' + ($errorKeyword || '_limitItems') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { limit: ' + ($schemaValue) + ' } '; + if (it.opts.messages !== false) { + out += ' , message: \'should NOT have '; + if ($keyword == 'maxItems') { + out += 'more'; + } else { + out += 'fewer'; + } + out += ' than '; + if ($isData) { + out += '\' + ' + ($schemaValue) + ' + \''; + } else { + out += '' + ($schema); + } + out += ' items\' '; + } + if (it.opts.verbose) { + out += ' , schema: '; + if ($isData) { + out += 'validate.schema' + ($schemaPath); + } else { + out += '' + ($schema); + } + out += ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; + } + out += ' } '; + } else { + out += ' {} '; + } + var __err = out; + out = $$outStack.pop(); + if (!it.compositeRule && $breakOnError) { + /* istanbul ignore if */ + if (it.async) { + out += ' throw new ValidationError([' + (__err) + ']); '; + } else { + out += ' validate.errors = [' + (__err) + ']; return false; '; + } + } else { + out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; + } + out += '} '; + if ($breakOnError) { + out += ' else { '; + } + return out; +} diff --git a/user/themes/goku/node_modules/ajv/lib/dotjs/_limitLength.js b/user/themes/goku/node_modules/ajv/lib/dotjs/_limitLength.js new file mode 100644 index 00000000..789f3741 --- /dev/null +++ b/user/themes/goku/node_modules/ajv/lib/dotjs/_limitLength.js @@ -0,0 +1,82 @@ +'use strict'; +module.exports = function generate__limitLength(it, $keyword, $ruleType) { + var out = ' '; + var $lvl = it.level; + var $dataLvl = it.dataLevel; + var $schema = it.schema[$keyword]; + var $schemaPath = it.schemaPath + it.util.getProperty($keyword); + var $errSchemaPath = it.errSchemaPath + '/' + $keyword; + var $breakOnError = !it.opts.allErrors; + var $errorKeyword; + var $data = 'data' + ($dataLvl || ''); + var $isData = it.opts.$data && $schema && $schema.$data, + $schemaValue; + if ($isData) { + out += ' var schema' + ($lvl) + ' = ' + (it.util.getData($schema.$data, $dataLvl, it.dataPathArr)) + '; '; + $schemaValue = 'schema' + $lvl; + } else { + $schemaValue = $schema; + } + var $op = $keyword == 'maxLength' ? '>' : '<'; + out += 'if ( '; + if ($isData) { + out += ' (' + ($schemaValue) + ' !== undefined && typeof ' + ($schemaValue) + ' != \'number\') || '; + } + if (it.opts.unicode === false) { + out += ' ' + ($data) + '.length '; + } else { + out += ' ucs2length(' + ($data) + ') '; + } + out += ' ' + ($op) + ' ' + ($schemaValue) + ') { '; + var $errorKeyword = $keyword; + var $$outStack = $$outStack || []; + $$outStack.push(out); + out = ''; /* istanbul ignore else */ + if (it.createErrors !== false) { + out += ' { keyword: \'' + ($errorKeyword || '_limitLength') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { limit: ' + ($schemaValue) + ' } '; + if (it.opts.messages !== false) { + out += ' , message: \'should NOT be '; + if ($keyword == 'maxLength') { + out += 'longer'; + } else { + out += 'shorter'; + } + out += ' than '; + if ($isData) { + out += '\' + ' + ($schemaValue) + ' + \''; + } else { + out += '' + ($schema); + } + out += ' characters\' '; + } + if (it.opts.verbose) { + out += ' , schema: '; + if ($isData) { + out += 'validate.schema' + ($schemaPath); + } else { + out += '' + ($schema); + } + out += ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; + } + out += ' } '; + } else { + out += ' {} '; + } + var __err = out; + out = $$outStack.pop(); + if (!it.compositeRule && $breakOnError) { + /* istanbul ignore if */ + if (it.async) { + out += ' throw new ValidationError([' + (__err) + ']); '; + } else { + out += ' validate.errors = [' + (__err) + ']; return false; '; + } + } else { + out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; + } + out += '} '; + if ($breakOnError) { + out += ' else { '; + } + return out; +} diff --git a/user/themes/goku/node_modules/ajv/lib/dotjs/_limitProperties.js b/user/themes/goku/node_modules/ajv/lib/dotjs/_limitProperties.js new file mode 100644 index 00000000..11dc9393 --- /dev/null +++ b/user/themes/goku/node_modules/ajv/lib/dotjs/_limitProperties.js @@ -0,0 +1,77 @@ +'use strict'; +module.exports = function generate__limitProperties(it, $keyword, $ruleType) { + var out = ' '; + var $lvl = it.level; + var $dataLvl = it.dataLevel; + var $schema = it.schema[$keyword]; + var $schemaPath = it.schemaPath + it.util.getProperty($keyword); + var $errSchemaPath = it.errSchemaPath + '/' + $keyword; + var $breakOnError = !it.opts.allErrors; + var $errorKeyword; + var $data = 'data' + ($dataLvl || ''); + var $isData = it.opts.$data && $schema && $schema.$data, + $schemaValue; + if ($isData) { + out += ' var schema' + ($lvl) + ' = ' + (it.util.getData($schema.$data, $dataLvl, it.dataPathArr)) + '; '; + $schemaValue = 'schema' + $lvl; + } else { + $schemaValue = $schema; + } + var $op = $keyword == 'maxProperties' ? '>' : '<'; + out += 'if ( '; + if ($isData) { + out += ' (' + ($schemaValue) + ' !== undefined && typeof ' + ($schemaValue) + ' != \'number\') || '; + } + out += ' Object.keys(' + ($data) + ').length ' + ($op) + ' ' + ($schemaValue) + ') { '; + var $errorKeyword = $keyword; + var $$outStack = $$outStack || []; + $$outStack.push(out); + out = ''; /* istanbul ignore else */ + if (it.createErrors !== false) { + out += ' { keyword: \'' + ($errorKeyword || '_limitProperties') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { limit: ' + ($schemaValue) + ' } '; + if (it.opts.messages !== false) { + out += ' , message: \'should NOT have '; + if ($keyword == 'maxProperties') { + out += 'more'; + } else { + out += 'fewer'; + } + out += ' than '; + if ($isData) { + out += '\' + ' + ($schemaValue) + ' + \''; + } else { + out += '' + ($schema); + } + out += ' properties\' '; + } + if (it.opts.verbose) { + out += ' , schema: '; + if ($isData) { + out += 'validate.schema' + ($schemaPath); + } else { + out += '' + ($schema); + } + out += ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; + } + out += ' } '; + } else { + out += ' {} '; + } + var __err = out; + out = $$outStack.pop(); + if (!it.compositeRule && $breakOnError) { + /* istanbul ignore if */ + if (it.async) { + out += ' throw new ValidationError([' + (__err) + ']); '; + } else { + out += ' validate.errors = [' + (__err) + ']; return false; '; + } + } else { + out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; + } + out += '} '; + if ($breakOnError) { + out += ' else { '; + } + return out; +} diff --git a/user/themes/goku/node_modules/ajv/lib/dotjs/allOf.js b/user/themes/goku/node_modules/ajv/lib/dotjs/allOf.js new file mode 100644 index 00000000..4bad914d --- /dev/null +++ b/user/themes/goku/node_modules/ajv/lib/dotjs/allOf.js @@ -0,0 +1,43 @@ +'use strict'; +module.exports = function generate_allOf(it, $keyword, $ruleType) { + var out = ' '; + var $schema = it.schema[$keyword]; + var $schemaPath = it.schemaPath + it.util.getProperty($keyword); + var $errSchemaPath = it.errSchemaPath + '/' + $keyword; + var $breakOnError = !it.opts.allErrors; + var $it = it.util.copy(it); + var $closingBraces = ''; + $it.level++; + var $nextValid = 'valid' + $it.level; + var $currentBaseId = $it.baseId, + $allSchemasEmpty = true; + var arr1 = $schema; + if (arr1) { + var $sch, $i = -1, + l1 = arr1.length - 1; + while ($i < l1) { + $sch = arr1[$i += 1]; + if ((it.opts.strictKeywords ? typeof $sch == 'object' && Object.keys($sch).length > 0 : it.util.schemaHasRules($sch, it.RULES.all))) { + $allSchemasEmpty = false; + $it.schema = $sch; + $it.schemaPath = $schemaPath + '[' + $i + ']'; + $it.errSchemaPath = $errSchemaPath + '/' + $i; + out += ' ' + (it.validate($it)) + ' '; + $it.baseId = $currentBaseId; + if ($breakOnError) { + out += ' if (' + ($nextValid) + ') { '; + $closingBraces += '}'; + } + } + } + } + if ($breakOnError) { + if ($allSchemasEmpty) { + out += ' if (true) { '; + } else { + out += ' ' + ($closingBraces.slice(0, -1)) + ' '; + } + } + out = it.util.cleanUpCode(out); + return out; +} diff --git a/user/themes/goku/node_modules/ajv/lib/dotjs/anyOf.js b/user/themes/goku/node_modules/ajv/lib/dotjs/anyOf.js new file mode 100644 index 00000000..01551d54 --- /dev/null +++ b/user/themes/goku/node_modules/ajv/lib/dotjs/anyOf.js @@ -0,0 +1,74 @@ +'use strict'; +module.exports = function generate_anyOf(it, $keyword, $ruleType) { + var out = ' '; + var $lvl = it.level; + var $dataLvl = it.dataLevel; + var $schema = it.schema[$keyword]; + var $schemaPath = it.schemaPath + it.util.getProperty($keyword); + var $errSchemaPath = it.errSchemaPath + '/' + $keyword; + var $breakOnError = !it.opts.allErrors; + var $data = 'data' + ($dataLvl || ''); + var $valid = 'valid' + $lvl; + var $errs = 'errs__' + $lvl; + var $it = it.util.copy(it); + var $closingBraces = ''; + $it.level++; + var $nextValid = 'valid' + $it.level; + var $noEmptySchema = $schema.every(function($sch) { + return (it.opts.strictKeywords ? typeof $sch == 'object' && Object.keys($sch).length > 0 : it.util.schemaHasRules($sch, it.RULES.all)); + }); + if ($noEmptySchema) { + var $currentBaseId = $it.baseId; + out += ' var ' + ($errs) + ' = errors; var ' + ($valid) + ' = false; '; + var $wasComposite = it.compositeRule; + it.compositeRule = $it.compositeRule = true; + var arr1 = $schema; + if (arr1) { + var $sch, $i = -1, + l1 = arr1.length - 1; + while ($i < l1) { + $sch = arr1[$i += 1]; + $it.schema = $sch; + $it.schemaPath = $schemaPath + '[' + $i + ']'; + $it.errSchemaPath = $errSchemaPath + '/' + $i; + out += ' ' + (it.validate($it)) + ' '; + $it.baseId = $currentBaseId; + out += ' ' + ($valid) + ' = ' + ($valid) + ' || ' + ($nextValid) + '; if (!' + ($valid) + ') { '; + $closingBraces += '}'; + } + } + it.compositeRule = $it.compositeRule = $wasComposite; + out += ' ' + ($closingBraces) + ' if (!' + ($valid) + ') { var err = '; /* istanbul ignore else */ + if (it.createErrors !== false) { + out += ' { keyword: \'' + ('anyOf') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: {} '; + if (it.opts.messages !== false) { + out += ' , message: \'should match some schema in anyOf\' '; + } + if (it.opts.verbose) { + out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; + } + out += ' } '; + } else { + out += ' {} '; + } + out += '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; + if (!it.compositeRule && $breakOnError) { + /* istanbul ignore if */ + if (it.async) { + out += ' throw new ValidationError(vErrors); '; + } else { + out += ' validate.errors = vErrors; return false; '; + } + } + out += ' } else { errors = ' + ($errs) + '; if (vErrors !== null) { if (' + ($errs) + ') vErrors.length = ' + ($errs) + '; else vErrors = null; } '; + if (it.opts.allErrors) { + out += ' } '; + } + out = it.util.cleanUpCode(out); + } else { + if ($breakOnError) { + out += ' if (true) { '; + } + } + return out; +} diff --git a/user/themes/goku/node_modules/ajv/lib/dotjs/comment.js b/user/themes/goku/node_modules/ajv/lib/dotjs/comment.js new file mode 100644 index 00000000..dd66bb8f --- /dev/null +++ b/user/themes/goku/node_modules/ajv/lib/dotjs/comment.js @@ -0,0 +1,14 @@ +'use strict'; +module.exports = function generate_comment(it, $keyword, $ruleType) { + var out = ' '; + var $schema = it.schema[$keyword]; + var $errSchemaPath = it.errSchemaPath + '/' + $keyword; + var $breakOnError = !it.opts.allErrors; + var $comment = it.util.toQuotedString($schema); + if (it.opts.$comment === true) { + out += ' console.log(' + ($comment) + ');'; + } else if (typeof it.opts.$comment == 'function') { + out += ' self._opts.$comment(' + ($comment) + ', ' + (it.util.toQuotedString($errSchemaPath)) + ', validate.root.schema);'; + } + return out; +} diff --git a/user/themes/goku/node_modules/ajv/lib/dotjs/const.js b/user/themes/goku/node_modules/ajv/lib/dotjs/const.js new file mode 100644 index 00000000..15b7c619 --- /dev/null +++ b/user/themes/goku/node_modules/ajv/lib/dotjs/const.js @@ -0,0 +1,56 @@ +'use strict'; +module.exports = function generate_const(it, $keyword, $ruleType) { + var out = ' '; + var $lvl = it.level; + var $dataLvl = it.dataLevel; + var $schema = it.schema[$keyword]; + var $schemaPath = it.schemaPath + it.util.getProperty($keyword); + var $errSchemaPath = it.errSchemaPath + '/' + $keyword; + var $breakOnError = !it.opts.allErrors; + var $data = 'data' + ($dataLvl || ''); + var $valid = 'valid' + $lvl; + var $isData = it.opts.$data && $schema && $schema.$data, + $schemaValue; + if ($isData) { + out += ' var schema' + ($lvl) + ' = ' + (it.util.getData($schema.$data, $dataLvl, it.dataPathArr)) + '; '; + $schemaValue = 'schema' + $lvl; + } else { + $schemaValue = $schema; + } + if (!$isData) { + out += ' var schema' + ($lvl) + ' = validate.schema' + ($schemaPath) + ';'; + } + out += 'var ' + ($valid) + ' = equal(' + ($data) + ', schema' + ($lvl) + '); if (!' + ($valid) + ') { '; + var $$outStack = $$outStack || []; + $$outStack.push(out); + out = ''; /* istanbul ignore else */ + if (it.createErrors !== false) { + out += ' { keyword: \'' + ('const') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { allowedValue: schema' + ($lvl) + ' } '; + if (it.opts.messages !== false) { + out += ' , message: \'should be equal to constant\' '; + } + if (it.opts.verbose) { + out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; + } + out += ' } '; + } else { + out += ' {} '; + } + var __err = out; + out = $$outStack.pop(); + if (!it.compositeRule && $breakOnError) { + /* istanbul ignore if */ + if (it.async) { + out += ' throw new ValidationError([' + (__err) + ']); '; + } else { + out += ' validate.errors = [' + (__err) + ']; return false; '; + } + } else { + out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; + } + out += ' }'; + if ($breakOnError) { + out += ' else { '; + } + return out; +} diff --git a/user/themes/goku/node_modules/ajv/lib/dotjs/contains.js b/user/themes/goku/node_modules/ajv/lib/dotjs/contains.js new file mode 100644 index 00000000..cd4dfabe --- /dev/null +++ b/user/themes/goku/node_modules/ajv/lib/dotjs/contains.js @@ -0,0 +1,82 @@ +'use strict'; +module.exports = function generate_contains(it, $keyword, $ruleType) { + var out = ' '; + var $lvl = it.level; + var $dataLvl = it.dataLevel; + var $schema = it.schema[$keyword]; + var $schemaPath = it.schemaPath + it.util.getProperty($keyword); + var $errSchemaPath = it.errSchemaPath + '/' + $keyword; + var $breakOnError = !it.opts.allErrors; + var $data = 'data' + ($dataLvl || ''); + var $valid = 'valid' + $lvl; + var $errs = 'errs__' + $lvl; + var $it = it.util.copy(it); + var $closingBraces = ''; + $it.level++; + var $nextValid = 'valid' + $it.level; + var $idx = 'i' + $lvl, + $dataNxt = $it.dataLevel = it.dataLevel + 1, + $nextData = 'data' + $dataNxt, + $currentBaseId = it.baseId, + $nonEmptySchema = (it.opts.strictKeywords ? typeof $schema == 'object' && Object.keys($schema).length > 0 : it.util.schemaHasRules($schema, it.RULES.all)); + out += 'var ' + ($errs) + ' = errors;var ' + ($valid) + ';'; + if ($nonEmptySchema) { + var $wasComposite = it.compositeRule; + it.compositeRule = $it.compositeRule = true; + $it.schema = $schema; + $it.schemaPath = $schemaPath; + $it.errSchemaPath = $errSchemaPath; + out += ' var ' + ($nextValid) + ' = false; for (var ' + ($idx) + ' = 0; ' + ($idx) + ' < ' + ($data) + '.length; ' + ($idx) + '++) { '; + $it.errorPath = it.util.getPathExpr(it.errorPath, $idx, it.opts.jsonPointers, true); + var $passData = $data + '[' + $idx + ']'; + $it.dataPathArr[$dataNxt] = $idx; + var $code = it.validate($it); + $it.baseId = $currentBaseId; + if (it.util.varOccurences($code, $nextData) < 2) { + out += ' ' + (it.util.varReplace($code, $nextData, $passData)) + ' '; + } else { + out += ' var ' + ($nextData) + ' = ' + ($passData) + '; ' + ($code) + ' '; + } + out += ' if (' + ($nextValid) + ') break; } '; + it.compositeRule = $it.compositeRule = $wasComposite; + out += ' ' + ($closingBraces) + ' if (!' + ($nextValid) + ') {'; + } else { + out += ' if (' + ($data) + '.length == 0) {'; + } + var $$outStack = $$outStack || []; + $$outStack.push(out); + out = ''; /* istanbul ignore else */ + if (it.createErrors !== false) { + out += ' { keyword: \'' + ('contains') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: {} '; + if (it.opts.messages !== false) { + out += ' , message: \'should contain a valid item\' '; + } + if (it.opts.verbose) { + out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; + } + out += ' } '; + } else { + out += ' {} '; + } + var __err = out; + out = $$outStack.pop(); + if (!it.compositeRule && $breakOnError) { + /* istanbul ignore if */ + if (it.async) { + out += ' throw new ValidationError([' + (__err) + ']); '; + } else { + out += ' validate.errors = [' + (__err) + ']; return false; '; + } + } else { + out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; + } + out += ' } else { '; + if ($nonEmptySchema) { + out += ' errors = ' + ($errs) + '; if (vErrors !== null) { if (' + ($errs) + ') vErrors.length = ' + ($errs) + '; else vErrors = null; } '; + } + if (it.opts.allErrors) { + out += ' } '; + } + out = it.util.cleanUpCode(out); + return out; +} diff --git a/user/themes/goku/node_modules/ajv/lib/dotjs/custom.js b/user/themes/goku/node_modules/ajv/lib/dotjs/custom.js new file mode 100644 index 00000000..f3e641e7 --- /dev/null +++ b/user/themes/goku/node_modules/ajv/lib/dotjs/custom.js @@ -0,0 +1,228 @@ +'use strict'; +module.exports = function generate_custom(it, $keyword, $ruleType) { + var out = ' '; + var $lvl = it.level; + var $dataLvl = it.dataLevel; + var $schema = it.schema[$keyword]; + var $schemaPath = it.schemaPath + it.util.getProperty($keyword); + var $errSchemaPath = it.errSchemaPath + '/' + $keyword; + var $breakOnError = !it.opts.allErrors; + var $errorKeyword; + var $data = 'data' + ($dataLvl || ''); + var $valid = 'valid' + $lvl; + var $errs = 'errs__' + $lvl; + var $isData = it.opts.$data && $schema && $schema.$data, + $schemaValue; + if ($isData) { + out += ' var schema' + ($lvl) + ' = ' + (it.util.getData($schema.$data, $dataLvl, it.dataPathArr)) + '; '; + $schemaValue = 'schema' + $lvl; + } else { + $schemaValue = $schema; + } + var $rule = this, + $definition = 'definition' + $lvl, + $rDef = $rule.definition, + $closingBraces = ''; + var $compile, $inline, $macro, $ruleValidate, $validateCode; + if ($isData && $rDef.$data) { + $validateCode = 'keywordValidate' + $lvl; + var $validateSchema = $rDef.validateSchema; + out += ' var ' + ($definition) + ' = RULES.custom[\'' + ($keyword) + '\'].definition; var ' + ($validateCode) + ' = ' + ($definition) + '.validate;'; + } else { + $ruleValidate = it.useCustomRule($rule, $schema, it.schema, it); + if (!$ruleValidate) return; + $schemaValue = 'validate.schema' + $schemaPath; + $validateCode = $ruleValidate.code; + $compile = $rDef.compile; + $inline = $rDef.inline; + $macro = $rDef.macro; + } + var $ruleErrs = $validateCode + '.errors', + $i = 'i' + $lvl, + $ruleErr = 'ruleErr' + $lvl, + $asyncKeyword = $rDef.async; + if ($asyncKeyword && !it.async) throw new Error('async keyword in sync schema'); + if (!($inline || $macro)) { + out += '' + ($ruleErrs) + ' = null;'; + } + out += 'var ' + ($errs) + ' = errors;var ' + ($valid) + ';'; + if ($isData && $rDef.$data) { + $closingBraces += '}'; + out += ' if (' + ($schemaValue) + ' === undefined) { ' + ($valid) + ' = true; } else { '; + if ($validateSchema) { + $closingBraces += '}'; + out += ' ' + ($valid) + ' = ' + ($definition) + '.validateSchema(' + ($schemaValue) + '); if (' + ($valid) + ') { '; + } + } + if ($inline) { + if ($rDef.statements) { + out += ' ' + ($ruleValidate.validate) + ' '; + } else { + out += ' ' + ($valid) + ' = ' + ($ruleValidate.validate) + '; '; + } + } else if ($macro) { + var $it = it.util.copy(it); + var $closingBraces = ''; + $it.level++; + var $nextValid = 'valid' + $it.level; + $it.schema = $ruleValidate.validate; + $it.schemaPath = ''; + var $wasComposite = it.compositeRule; + it.compositeRule = $it.compositeRule = true; + var $code = it.validate($it).replace(/validate\.schema/g, $validateCode); + it.compositeRule = $it.compositeRule = $wasComposite; + out += ' ' + ($code); + } else { + var $$outStack = $$outStack || []; + $$outStack.push(out); + out = ''; + out += ' ' + ($validateCode) + '.call( '; + if (it.opts.passContext) { + out += 'this'; + } else { + out += 'self'; + } + if ($compile || $rDef.schema === false) { + out += ' , ' + ($data) + ' '; + } else { + out += ' , ' + ($schemaValue) + ' , ' + ($data) + ' , validate.schema' + (it.schemaPath) + ' '; + } + out += ' , (dataPath || \'\')'; + if (it.errorPath != '""') { + out += ' + ' + (it.errorPath); + } + var $parentData = $dataLvl ? 'data' + (($dataLvl - 1) || '') : 'parentData', + $parentDataProperty = $dataLvl ? it.dataPathArr[$dataLvl] : 'parentDataProperty'; + out += ' , ' + ($parentData) + ' , ' + ($parentDataProperty) + ' , rootData ) '; + var def_callRuleValidate = out; + out = $$outStack.pop(); + if ($rDef.errors === false) { + out += ' ' + ($valid) + ' = '; + if ($asyncKeyword) { + out += 'await '; + } + out += '' + (def_callRuleValidate) + '; '; + } else { + if ($asyncKeyword) { + $ruleErrs = 'customErrors' + $lvl; + out += ' var ' + ($ruleErrs) + ' = null; try { ' + ($valid) + ' = await ' + (def_callRuleValidate) + '; } catch (e) { ' + ($valid) + ' = false; if (e instanceof ValidationError) ' + ($ruleErrs) + ' = e.errors; else throw e; } '; + } else { + out += ' ' + ($ruleErrs) + ' = null; ' + ($valid) + ' = ' + (def_callRuleValidate) + '; '; + } + } + } + if ($rDef.modifying) { + out += ' if (' + ($parentData) + ') ' + ($data) + ' = ' + ($parentData) + '[' + ($parentDataProperty) + '];'; + } + out += '' + ($closingBraces); + if ($rDef.valid) { + if ($breakOnError) { + out += ' if (true) { '; + } + } else { + out += ' if ( '; + if ($rDef.valid === undefined) { + out += ' !'; + if ($macro) { + out += '' + ($nextValid); + } else { + out += '' + ($valid); + } + } else { + out += ' ' + (!$rDef.valid) + ' '; + } + out += ') { '; + $errorKeyword = $rule.keyword; + var $$outStack = $$outStack || []; + $$outStack.push(out); + out = ''; + var $$outStack = $$outStack || []; + $$outStack.push(out); + out = ''; /* istanbul ignore else */ + if (it.createErrors !== false) { + out += ' { keyword: \'' + ($errorKeyword || 'custom') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { keyword: \'' + ($rule.keyword) + '\' } '; + if (it.opts.messages !== false) { + out += ' , message: \'should pass "' + ($rule.keyword) + '" keyword validation\' '; + } + if (it.opts.verbose) { + out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; + } + out += ' } '; + } else { + out += ' {} '; + } + var __err = out; + out = $$outStack.pop(); + if (!it.compositeRule && $breakOnError) { + /* istanbul ignore if */ + if (it.async) { + out += ' throw new ValidationError([' + (__err) + ']); '; + } else { + out += ' validate.errors = [' + (__err) + ']; return false; '; + } + } else { + out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; + } + var def_customError = out; + out = $$outStack.pop(); + if ($inline) { + if ($rDef.errors) { + if ($rDef.errors != 'full') { + out += ' for (var ' + ($i) + '=' + ($errs) + '; ' + ($i) + ' 0 : it.util.schemaHasRules($sch, it.RULES.all))) { + out += ' ' + ($nextValid) + ' = true; if ( ' + ($data) + (it.util.getProperty($property)) + ' !== undefined '; + if ($ownProperties) { + out += ' && Object.prototype.hasOwnProperty.call(' + ($data) + ', \'' + (it.util.escapeQuotes($property)) + '\') '; + } + out += ') { '; + $it.schema = $sch; + $it.schemaPath = $schemaPath + it.util.getProperty($property); + $it.errSchemaPath = $errSchemaPath + '/' + it.util.escapeFragment($property); + out += ' ' + (it.validate($it)) + ' '; + $it.baseId = $currentBaseId; + out += ' } '; + if ($breakOnError) { + out += ' if (' + ($nextValid) + ') { '; + $closingBraces += '}'; + } + } + } + if ($breakOnError) { + out += ' ' + ($closingBraces) + ' if (' + ($errs) + ' == errors) {'; + } + out = it.util.cleanUpCode(out); + return out; +} diff --git a/user/themes/goku/node_modules/ajv/lib/dotjs/enum.js b/user/themes/goku/node_modules/ajv/lib/dotjs/enum.js new file mode 100644 index 00000000..90580b9f --- /dev/null +++ b/user/themes/goku/node_modules/ajv/lib/dotjs/enum.js @@ -0,0 +1,66 @@ +'use strict'; +module.exports = function generate_enum(it, $keyword, $ruleType) { + var out = ' '; + var $lvl = it.level; + var $dataLvl = it.dataLevel; + var $schema = it.schema[$keyword]; + var $schemaPath = it.schemaPath + it.util.getProperty($keyword); + var $errSchemaPath = it.errSchemaPath + '/' + $keyword; + var $breakOnError = !it.opts.allErrors; + var $data = 'data' + ($dataLvl || ''); + var $valid = 'valid' + $lvl; + var $isData = it.opts.$data && $schema && $schema.$data, + $schemaValue; + if ($isData) { + out += ' var schema' + ($lvl) + ' = ' + (it.util.getData($schema.$data, $dataLvl, it.dataPathArr)) + '; '; + $schemaValue = 'schema' + $lvl; + } else { + $schemaValue = $schema; + } + var $i = 'i' + $lvl, + $vSchema = 'schema' + $lvl; + if (!$isData) { + out += ' var ' + ($vSchema) + ' = validate.schema' + ($schemaPath) + ';'; + } + out += 'var ' + ($valid) + ';'; + if ($isData) { + out += ' if (schema' + ($lvl) + ' === undefined) ' + ($valid) + ' = true; else if (!Array.isArray(schema' + ($lvl) + ')) ' + ($valid) + ' = false; else {'; + } + out += '' + ($valid) + ' = false;for (var ' + ($i) + '=0; ' + ($i) + '<' + ($vSchema) + '.length; ' + ($i) + '++) if (equal(' + ($data) + ', ' + ($vSchema) + '[' + ($i) + '])) { ' + ($valid) + ' = true; break; }'; + if ($isData) { + out += ' } '; + } + out += ' if (!' + ($valid) + ') { '; + var $$outStack = $$outStack || []; + $$outStack.push(out); + out = ''; /* istanbul ignore else */ + if (it.createErrors !== false) { + out += ' { keyword: \'' + ('enum') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { allowedValues: schema' + ($lvl) + ' } '; + if (it.opts.messages !== false) { + out += ' , message: \'should be equal to one of the allowed values\' '; + } + if (it.opts.verbose) { + out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; + } + out += ' } '; + } else { + out += ' {} '; + } + var __err = out; + out = $$outStack.pop(); + if (!it.compositeRule && $breakOnError) { + /* istanbul ignore if */ + if (it.async) { + out += ' throw new ValidationError([' + (__err) + ']); '; + } else { + out += ' validate.errors = [' + (__err) + ']; return false; '; + } + } else { + out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; + } + out += ' }'; + if ($breakOnError) { + out += ' else { '; + } + return out; +} diff --git a/user/themes/goku/node_modules/ajv/lib/dotjs/format.js b/user/themes/goku/node_modules/ajv/lib/dotjs/format.js new file mode 100644 index 00000000..cd9a5693 --- /dev/null +++ b/user/themes/goku/node_modules/ajv/lib/dotjs/format.js @@ -0,0 +1,150 @@ +'use strict'; +module.exports = function generate_format(it, $keyword, $ruleType) { + var out = ' '; + var $lvl = it.level; + var $dataLvl = it.dataLevel; + var $schema = it.schema[$keyword]; + var $schemaPath = it.schemaPath + it.util.getProperty($keyword); + var $errSchemaPath = it.errSchemaPath + '/' + $keyword; + var $breakOnError = !it.opts.allErrors; + var $data = 'data' + ($dataLvl || ''); + if (it.opts.format === false) { + if ($breakOnError) { + out += ' if (true) { '; + } + return out; + } + var $isData = it.opts.$data && $schema && $schema.$data, + $schemaValue; + if ($isData) { + out += ' var schema' + ($lvl) + ' = ' + (it.util.getData($schema.$data, $dataLvl, it.dataPathArr)) + '; '; + $schemaValue = 'schema' + $lvl; + } else { + $schemaValue = $schema; + } + var $unknownFormats = it.opts.unknownFormats, + $allowUnknown = Array.isArray($unknownFormats); + if ($isData) { + var $format = 'format' + $lvl, + $isObject = 'isObject' + $lvl, + $formatType = 'formatType' + $lvl; + out += ' var ' + ($format) + ' = formats[' + ($schemaValue) + ']; var ' + ($isObject) + ' = typeof ' + ($format) + ' == \'object\' && !(' + ($format) + ' instanceof RegExp) && ' + ($format) + '.validate; var ' + ($formatType) + ' = ' + ($isObject) + ' && ' + ($format) + '.type || \'string\'; if (' + ($isObject) + ') { '; + if (it.async) { + out += ' var async' + ($lvl) + ' = ' + ($format) + '.async; '; + } + out += ' ' + ($format) + ' = ' + ($format) + '.validate; } if ( '; + if ($isData) { + out += ' (' + ($schemaValue) + ' !== undefined && typeof ' + ($schemaValue) + ' != \'string\') || '; + } + out += ' ('; + if ($unknownFormats != 'ignore') { + out += ' (' + ($schemaValue) + ' && !' + ($format) + ' '; + if ($allowUnknown) { + out += ' && self._opts.unknownFormats.indexOf(' + ($schemaValue) + ') == -1 '; + } + out += ') || '; + } + out += ' (' + ($format) + ' && ' + ($formatType) + ' == \'' + ($ruleType) + '\' && !(typeof ' + ($format) + ' == \'function\' ? '; + if (it.async) { + out += ' (async' + ($lvl) + ' ? await ' + ($format) + '(' + ($data) + ') : ' + ($format) + '(' + ($data) + ')) '; + } else { + out += ' ' + ($format) + '(' + ($data) + ') '; + } + out += ' : ' + ($format) + '.test(' + ($data) + '))))) {'; + } else { + var $format = it.formats[$schema]; + if (!$format) { + if ($unknownFormats == 'ignore') { + it.logger.warn('unknown format "' + $schema + '" ignored in schema at path "' + it.errSchemaPath + '"'); + if ($breakOnError) { + out += ' if (true) { '; + } + return out; + } else if ($allowUnknown && $unknownFormats.indexOf($schema) >= 0) { + if ($breakOnError) { + out += ' if (true) { '; + } + return out; + } else { + throw new Error('unknown format "' + $schema + '" is used in schema at path "' + it.errSchemaPath + '"'); + } + } + var $isObject = typeof $format == 'object' && !($format instanceof RegExp) && $format.validate; + var $formatType = $isObject && $format.type || 'string'; + if ($isObject) { + var $async = $format.async === true; + $format = $format.validate; + } + if ($formatType != $ruleType) { + if ($breakOnError) { + out += ' if (true) { '; + } + return out; + } + if ($async) { + if (!it.async) throw new Error('async format in sync schema'); + var $formatRef = 'formats' + it.util.getProperty($schema) + '.validate'; + out += ' if (!(await ' + ($formatRef) + '(' + ($data) + '))) { '; + } else { + out += ' if (! '; + var $formatRef = 'formats' + it.util.getProperty($schema); + if ($isObject) $formatRef += '.validate'; + if (typeof $format == 'function') { + out += ' ' + ($formatRef) + '(' + ($data) + ') '; + } else { + out += ' ' + ($formatRef) + '.test(' + ($data) + ') '; + } + out += ') { '; + } + } + var $$outStack = $$outStack || []; + $$outStack.push(out); + out = ''; /* istanbul ignore else */ + if (it.createErrors !== false) { + out += ' { keyword: \'' + ('format') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { format: '; + if ($isData) { + out += '' + ($schemaValue); + } else { + out += '' + (it.util.toQuotedString($schema)); + } + out += ' } '; + if (it.opts.messages !== false) { + out += ' , message: \'should match format "'; + if ($isData) { + out += '\' + ' + ($schemaValue) + ' + \''; + } else { + out += '' + (it.util.escapeQuotes($schema)); + } + out += '"\' '; + } + if (it.opts.verbose) { + out += ' , schema: '; + if ($isData) { + out += 'validate.schema' + ($schemaPath); + } else { + out += '' + (it.util.toQuotedString($schema)); + } + out += ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; + } + out += ' } '; + } else { + out += ' {} '; + } + var __err = out; + out = $$outStack.pop(); + if (!it.compositeRule && $breakOnError) { + /* istanbul ignore if */ + if (it.async) { + out += ' throw new ValidationError([' + (__err) + ']); '; + } else { + out += ' validate.errors = [' + (__err) + ']; return false; '; + } + } else { + out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; + } + out += ' } '; + if ($breakOnError) { + out += ' else { '; + } + return out; +} diff --git a/user/themes/goku/node_modules/ajv/lib/dotjs/if.js b/user/themes/goku/node_modules/ajv/lib/dotjs/if.js new file mode 100644 index 00000000..019f61ab --- /dev/null +++ b/user/themes/goku/node_modules/ajv/lib/dotjs/if.js @@ -0,0 +1,104 @@ +'use strict'; +module.exports = function generate_if(it, $keyword, $ruleType) { + var out = ' '; + var $lvl = it.level; + var $dataLvl = it.dataLevel; + var $schema = it.schema[$keyword]; + var $schemaPath = it.schemaPath + it.util.getProperty($keyword); + var $errSchemaPath = it.errSchemaPath + '/' + $keyword; + var $breakOnError = !it.opts.allErrors; + var $data = 'data' + ($dataLvl || ''); + var $valid = 'valid' + $lvl; + var $errs = 'errs__' + $lvl; + var $it = it.util.copy(it); + $it.level++; + var $nextValid = 'valid' + $it.level; + var $thenSch = it.schema['then'], + $elseSch = it.schema['else'], + $thenPresent = $thenSch !== undefined && (it.opts.strictKeywords ? typeof $thenSch == 'object' && Object.keys($thenSch).length > 0 : it.util.schemaHasRules($thenSch, it.RULES.all)), + $elsePresent = $elseSch !== undefined && (it.opts.strictKeywords ? typeof $elseSch == 'object' && Object.keys($elseSch).length > 0 : it.util.schemaHasRules($elseSch, it.RULES.all)), + $currentBaseId = $it.baseId; + if ($thenPresent || $elsePresent) { + var $ifClause; + $it.createErrors = false; + $it.schema = $schema; + $it.schemaPath = $schemaPath; + $it.errSchemaPath = $errSchemaPath; + out += ' var ' + ($errs) + ' = errors; var ' + ($valid) + ' = true; '; + var $wasComposite = it.compositeRule; + it.compositeRule = $it.compositeRule = true; + out += ' ' + (it.validate($it)) + ' '; + $it.baseId = $currentBaseId; + $it.createErrors = true; + out += ' errors = ' + ($errs) + '; if (vErrors !== null) { if (' + ($errs) + ') vErrors.length = ' + ($errs) + '; else vErrors = null; } '; + it.compositeRule = $it.compositeRule = $wasComposite; + if ($thenPresent) { + out += ' if (' + ($nextValid) + ') { '; + $it.schema = it.schema['then']; + $it.schemaPath = it.schemaPath + '.then'; + $it.errSchemaPath = it.errSchemaPath + '/then'; + out += ' ' + (it.validate($it)) + ' '; + $it.baseId = $currentBaseId; + out += ' ' + ($valid) + ' = ' + ($nextValid) + '; '; + if ($thenPresent && $elsePresent) { + $ifClause = 'ifClause' + $lvl; + out += ' var ' + ($ifClause) + ' = \'then\'; '; + } else { + $ifClause = '\'then\''; + } + out += ' } '; + if ($elsePresent) { + out += ' else { '; + } + } else { + out += ' if (!' + ($nextValid) + ') { '; + } + if ($elsePresent) { + $it.schema = it.schema['else']; + $it.schemaPath = it.schemaPath + '.else'; + $it.errSchemaPath = it.errSchemaPath + '/else'; + out += ' ' + (it.validate($it)) + ' '; + $it.baseId = $currentBaseId; + out += ' ' + ($valid) + ' = ' + ($nextValid) + '; '; + if ($thenPresent && $elsePresent) { + $ifClause = 'ifClause' + $lvl; + out += ' var ' + ($ifClause) + ' = \'else\'; '; + } else { + $ifClause = '\'else\''; + } + out += ' } '; + } + out += ' if (!' + ($valid) + ') { var err = '; /* istanbul ignore else */ + if (it.createErrors !== false) { + out += ' { keyword: \'' + ('if') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { failingKeyword: ' + ($ifClause) + ' } '; + if (it.opts.messages !== false) { + out += ' , message: \'should match "\' + ' + ($ifClause) + ' + \'" schema\' '; + } + if (it.opts.verbose) { + out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; + } + out += ' } '; + } else { + out += ' {} '; + } + out += '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; + if (!it.compositeRule && $breakOnError) { + /* istanbul ignore if */ + if (it.async) { + out += ' throw new ValidationError(vErrors); '; + } else { + out += ' validate.errors = vErrors; return false; '; + } + } + out += ' } '; + if ($breakOnError) { + out += ' else { '; + } + out = it.util.cleanUpCode(out); + } else { + if ($breakOnError) { + out += ' if (true) { '; + } + } + return out; +} diff --git a/user/themes/goku/node_modules/ajv/lib/dotjs/index.js b/user/themes/goku/node_modules/ajv/lib/dotjs/index.js new file mode 100644 index 00000000..2fb1b00e --- /dev/null +++ b/user/themes/goku/node_modules/ajv/lib/dotjs/index.js @@ -0,0 +1,33 @@ +'use strict'; + +//all requires must be explicit because browserify won't work with dynamic requires +module.exports = { + '$ref': require('./ref'), + allOf: require('./allOf'), + anyOf: require('./anyOf'), + '$comment': require('./comment'), + const: require('./const'), + contains: require('./contains'), + dependencies: require('./dependencies'), + 'enum': require('./enum'), + format: require('./format'), + 'if': require('./if'), + items: require('./items'), + maximum: require('./_limit'), + minimum: require('./_limit'), + maxItems: require('./_limitItems'), + minItems: require('./_limitItems'), + maxLength: require('./_limitLength'), + minLength: require('./_limitLength'), + maxProperties: require('./_limitProperties'), + minProperties: require('./_limitProperties'), + multipleOf: require('./multipleOf'), + not: require('./not'), + oneOf: require('./oneOf'), + pattern: require('./pattern'), + properties: require('./properties'), + propertyNames: require('./propertyNames'), + required: require('./required'), + uniqueItems: require('./uniqueItems'), + validate: require('./validate') +}; diff --git a/user/themes/goku/node_modules/ajv/lib/dotjs/items.js b/user/themes/goku/node_modules/ajv/lib/dotjs/items.js new file mode 100644 index 00000000..d5532f07 --- /dev/null +++ b/user/themes/goku/node_modules/ajv/lib/dotjs/items.js @@ -0,0 +1,141 @@ +'use strict'; +module.exports = function generate_items(it, $keyword, $ruleType) { + var out = ' '; + var $lvl = it.level; + var $dataLvl = it.dataLevel; + var $schema = it.schema[$keyword]; + var $schemaPath = it.schemaPath + it.util.getProperty($keyword); + var $errSchemaPath = it.errSchemaPath + '/' + $keyword; + var $breakOnError = !it.opts.allErrors; + var $data = 'data' + ($dataLvl || ''); + var $valid = 'valid' + $lvl; + var $errs = 'errs__' + $lvl; + var $it = it.util.copy(it); + var $closingBraces = ''; + $it.level++; + var $nextValid = 'valid' + $it.level; + var $idx = 'i' + $lvl, + $dataNxt = $it.dataLevel = it.dataLevel + 1, + $nextData = 'data' + $dataNxt, + $currentBaseId = it.baseId; + out += 'var ' + ($errs) + ' = errors;var ' + ($valid) + ';'; + if (Array.isArray($schema)) { + var $additionalItems = it.schema.additionalItems; + if ($additionalItems === false) { + out += ' ' + ($valid) + ' = ' + ($data) + '.length <= ' + ($schema.length) + '; '; + var $currErrSchemaPath = $errSchemaPath; + $errSchemaPath = it.errSchemaPath + '/additionalItems'; + out += ' if (!' + ($valid) + ') { '; + var $$outStack = $$outStack || []; + $$outStack.push(out); + out = ''; /* istanbul ignore else */ + if (it.createErrors !== false) { + out += ' { keyword: \'' + ('additionalItems') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { limit: ' + ($schema.length) + ' } '; + if (it.opts.messages !== false) { + out += ' , message: \'should NOT have more than ' + ($schema.length) + ' items\' '; + } + if (it.opts.verbose) { + out += ' , schema: false , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; + } + out += ' } '; + } else { + out += ' {} '; + } + var __err = out; + out = $$outStack.pop(); + if (!it.compositeRule && $breakOnError) { + /* istanbul ignore if */ + if (it.async) { + out += ' throw new ValidationError([' + (__err) + ']); '; + } else { + out += ' validate.errors = [' + (__err) + ']; return false; '; + } + } else { + out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; + } + out += ' } '; + $errSchemaPath = $currErrSchemaPath; + if ($breakOnError) { + $closingBraces += '}'; + out += ' else { '; + } + } + var arr1 = $schema; + if (arr1) { + var $sch, $i = -1, + l1 = arr1.length - 1; + while ($i < l1) { + $sch = arr1[$i += 1]; + if ((it.opts.strictKeywords ? typeof $sch == 'object' && Object.keys($sch).length > 0 : it.util.schemaHasRules($sch, it.RULES.all))) { + out += ' ' + ($nextValid) + ' = true; if (' + ($data) + '.length > ' + ($i) + ') { '; + var $passData = $data + '[' + $i + ']'; + $it.schema = $sch; + $it.schemaPath = $schemaPath + '[' + $i + ']'; + $it.errSchemaPath = $errSchemaPath + '/' + $i; + $it.errorPath = it.util.getPathExpr(it.errorPath, $i, it.opts.jsonPointers, true); + $it.dataPathArr[$dataNxt] = $i; + var $code = it.validate($it); + $it.baseId = $currentBaseId; + if (it.util.varOccurences($code, $nextData) < 2) { + out += ' ' + (it.util.varReplace($code, $nextData, $passData)) + ' '; + } else { + out += ' var ' + ($nextData) + ' = ' + ($passData) + '; ' + ($code) + ' '; + } + out += ' } '; + if ($breakOnError) { + out += ' if (' + ($nextValid) + ') { '; + $closingBraces += '}'; + } + } + } + } + if (typeof $additionalItems == 'object' && (it.opts.strictKeywords ? typeof $additionalItems == 'object' && Object.keys($additionalItems).length > 0 : it.util.schemaHasRules($additionalItems, it.RULES.all))) { + $it.schema = $additionalItems; + $it.schemaPath = it.schemaPath + '.additionalItems'; + $it.errSchemaPath = it.errSchemaPath + '/additionalItems'; + out += ' ' + ($nextValid) + ' = true; if (' + ($data) + '.length > ' + ($schema.length) + ') { for (var ' + ($idx) + ' = ' + ($schema.length) + '; ' + ($idx) + ' < ' + ($data) + '.length; ' + ($idx) + '++) { '; + $it.errorPath = it.util.getPathExpr(it.errorPath, $idx, it.opts.jsonPointers, true); + var $passData = $data + '[' + $idx + ']'; + $it.dataPathArr[$dataNxt] = $idx; + var $code = it.validate($it); + $it.baseId = $currentBaseId; + if (it.util.varOccurences($code, $nextData) < 2) { + out += ' ' + (it.util.varReplace($code, $nextData, $passData)) + ' '; + } else { + out += ' var ' + ($nextData) + ' = ' + ($passData) + '; ' + ($code) + ' '; + } + if ($breakOnError) { + out += ' if (!' + ($nextValid) + ') break; '; + } + out += ' } } '; + if ($breakOnError) { + out += ' if (' + ($nextValid) + ') { '; + $closingBraces += '}'; + } + } + } else if ((it.opts.strictKeywords ? typeof $schema == 'object' && Object.keys($schema).length > 0 : it.util.schemaHasRules($schema, it.RULES.all))) { + $it.schema = $schema; + $it.schemaPath = $schemaPath; + $it.errSchemaPath = $errSchemaPath; + out += ' for (var ' + ($idx) + ' = ' + (0) + '; ' + ($idx) + ' < ' + ($data) + '.length; ' + ($idx) + '++) { '; + $it.errorPath = it.util.getPathExpr(it.errorPath, $idx, it.opts.jsonPointers, true); + var $passData = $data + '[' + $idx + ']'; + $it.dataPathArr[$dataNxt] = $idx; + var $code = it.validate($it); + $it.baseId = $currentBaseId; + if (it.util.varOccurences($code, $nextData) < 2) { + out += ' ' + (it.util.varReplace($code, $nextData, $passData)) + ' '; + } else { + out += ' var ' + ($nextData) + ' = ' + ($passData) + '; ' + ($code) + ' '; + } + if ($breakOnError) { + out += ' if (!' + ($nextValid) + ') break; '; + } + out += ' }'; + } + if ($breakOnError) { + out += ' ' + ($closingBraces) + ' if (' + ($errs) + ' == errors) {'; + } + out = it.util.cleanUpCode(out); + return out; +} diff --git a/user/themes/goku/node_modules/ajv/lib/dotjs/multipleOf.js b/user/themes/goku/node_modules/ajv/lib/dotjs/multipleOf.js new file mode 100644 index 00000000..af087d2c --- /dev/null +++ b/user/themes/goku/node_modules/ajv/lib/dotjs/multipleOf.js @@ -0,0 +1,77 @@ +'use strict'; +module.exports = function generate_multipleOf(it, $keyword, $ruleType) { + var out = ' '; + var $lvl = it.level; + var $dataLvl = it.dataLevel; + var $schema = it.schema[$keyword]; + var $schemaPath = it.schemaPath + it.util.getProperty($keyword); + var $errSchemaPath = it.errSchemaPath + '/' + $keyword; + var $breakOnError = !it.opts.allErrors; + var $data = 'data' + ($dataLvl || ''); + var $isData = it.opts.$data && $schema && $schema.$data, + $schemaValue; + if ($isData) { + out += ' var schema' + ($lvl) + ' = ' + (it.util.getData($schema.$data, $dataLvl, it.dataPathArr)) + '; '; + $schemaValue = 'schema' + $lvl; + } else { + $schemaValue = $schema; + } + out += 'var division' + ($lvl) + ';if ('; + if ($isData) { + out += ' ' + ($schemaValue) + ' !== undefined && ( typeof ' + ($schemaValue) + ' != \'number\' || '; + } + out += ' (division' + ($lvl) + ' = ' + ($data) + ' / ' + ($schemaValue) + ', '; + if (it.opts.multipleOfPrecision) { + out += ' Math.abs(Math.round(division' + ($lvl) + ') - division' + ($lvl) + ') > 1e-' + (it.opts.multipleOfPrecision) + ' '; + } else { + out += ' division' + ($lvl) + ' !== parseInt(division' + ($lvl) + ') '; + } + out += ' ) '; + if ($isData) { + out += ' ) '; + } + out += ' ) { '; + var $$outStack = $$outStack || []; + $$outStack.push(out); + out = ''; /* istanbul ignore else */ + if (it.createErrors !== false) { + out += ' { keyword: \'' + ('multipleOf') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { multipleOf: ' + ($schemaValue) + ' } '; + if (it.opts.messages !== false) { + out += ' , message: \'should be multiple of '; + if ($isData) { + out += '\' + ' + ($schemaValue); + } else { + out += '' + ($schemaValue) + '\''; + } + } + if (it.opts.verbose) { + out += ' , schema: '; + if ($isData) { + out += 'validate.schema' + ($schemaPath); + } else { + out += '' + ($schema); + } + out += ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; + } + out += ' } '; + } else { + out += ' {} '; + } + var __err = out; + out = $$outStack.pop(); + if (!it.compositeRule && $breakOnError) { + /* istanbul ignore if */ + if (it.async) { + out += ' throw new ValidationError([' + (__err) + ']); '; + } else { + out += ' validate.errors = [' + (__err) + ']; return false; '; + } + } else { + out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; + } + out += '} '; + if ($breakOnError) { + out += ' else { '; + } + return out; +} diff --git a/user/themes/goku/node_modules/ajv/lib/dotjs/not.js b/user/themes/goku/node_modules/ajv/lib/dotjs/not.js new file mode 100644 index 00000000..6aea6599 --- /dev/null +++ b/user/themes/goku/node_modules/ajv/lib/dotjs/not.js @@ -0,0 +1,84 @@ +'use strict'; +module.exports = function generate_not(it, $keyword, $ruleType) { + var out = ' '; + var $lvl = it.level; + var $dataLvl = it.dataLevel; + var $schema = it.schema[$keyword]; + var $schemaPath = it.schemaPath + it.util.getProperty($keyword); + var $errSchemaPath = it.errSchemaPath + '/' + $keyword; + var $breakOnError = !it.opts.allErrors; + var $data = 'data' + ($dataLvl || ''); + var $errs = 'errs__' + $lvl; + var $it = it.util.copy(it); + $it.level++; + var $nextValid = 'valid' + $it.level; + if ((it.opts.strictKeywords ? typeof $schema == 'object' && Object.keys($schema).length > 0 : it.util.schemaHasRules($schema, it.RULES.all))) { + $it.schema = $schema; + $it.schemaPath = $schemaPath; + $it.errSchemaPath = $errSchemaPath; + out += ' var ' + ($errs) + ' = errors; '; + var $wasComposite = it.compositeRule; + it.compositeRule = $it.compositeRule = true; + $it.createErrors = false; + var $allErrorsOption; + if ($it.opts.allErrors) { + $allErrorsOption = $it.opts.allErrors; + $it.opts.allErrors = false; + } + out += ' ' + (it.validate($it)) + ' '; + $it.createErrors = true; + if ($allErrorsOption) $it.opts.allErrors = $allErrorsOption; + it.compositeRule = $it.compositeRule = $wasComposite; + out += ' if (' + ($nextValid) + ') { '; + var $$outStack = $$outStack || []; + $$outStack.push(out); + out = ''; /* istanbul ignore else */ + if (it.createErrors !== false) { + out += ' { keyword: \'' + ('not') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: {} '; + if (it.opts.messages !== false) { + out += ' , message: \'should NOT be valid\' '; + } + if (it.opts.verbose) { + out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; + } + out += ' } '; + } else { + out += ' {} '; + } + var __err = out; + out = $$outStack.pop(); + if (!it.compositeRule && $breakOnError) { + /* istanbul ignore if */ + if (it.async) { + out += ' throw new ValidationError([' + (__err) + ']); '; + } else { + out += ' validate.errors = [' + (__err) + ']; return false; '; + } + } else { + out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; + } + out += ' } else { errors = ' + ($errs) + '; if (vErrors !== null) { if (' + ($errs) + ') vErrors.length = ' + ($errs) + '; else vErrors = null; } '; + if (it.opts.allErrors) { + out += ' } '; + } + } else { + out += ' var err = '; /* istanbul ignore else */ + if (it.createErrors !== false) { + out += ' { keyword: \'' + ('not') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: {} '; + if (it.opts.messages !== false) { + out += ' , message: \'should NOT be valid\' '; + } + if (it.opts.verbose) { + out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; + } + out += ' } '; + } else { + out += ' {} '; + } + out += '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; + if ($breakOnError) { + out += ' if (false) { '; + } + } + return out; +} diff --git a/user/themes/goku/node_modules/ajv/lib/dotjs/oneOf.js b/user/themes/goku/node_modules/ajv/lib/dotjs/oneOf.js new file mode 100644 index 00000000..30988d5e --- /dev/null +++ b/user/themes/goku/node_modules/ajv/lib/dotjs/oneOf.js @@ -0,0 +1,73 @@ +'use strict'; +module.exports = function generate_oneOf(it, $keyword, $ruleType) { + var out = ' '; + var $lvl = it.level; + var $dataLvl = it.dataLevel; + var $schema = it.schema[$keyword]; + var $schemaPath = it.schemaPath + it.util.getProperty($keyword); + var $errSchemaPath = it.errSchemaPath + '/' + $keyword; + var $breakOnError = !it.opts.allErrors; + var $data = 'data' + ($dataLvl || ''); + var $valid = 'valid' + $lvl; + var $errs = 'errs__' + $lvl; + var $it = it.util.copy(it); + var $closingBraces = ''; + $it.level++; + var $nextValid = 'valid' + $it.level; + var $currentBaseId = $it.baseId, + $prevValid = 'prevValid' + $lvl, + $passingSchemas = 'passingSchemas' + $lvl; + out += 'var ' + ($errs) + ' = errors , ' + ($prevValid) + ' = false , ' + ($valid) + ' = false , ' + ($passingSchemas) + ' = null; '; + var $wasComposite = it.compositeRule; + it.compositeRule = $it.compositeRule = true; + var arr1 = $schema; + if (arr1) { + var $sch, $i = -1, + l1 = arr1.length - 1; + while ($i < l1) { + $sch = arr1[$i += 1]; + if ((it.opts.strictKeywords ? typeof $sch == 'object' && Object.keys($sch).length > 0 : it.util.schemaHasRules($sch, it.RULES.all))) { + $it.schema = $sch; + $it.schemaPath = $schemaPath + '[' + $i + ']'; + $it.errSchemaPath = $errSchemaPath + '/' + $i; + out += ' ' + (it.validate($it)) + ' '; + $it.baseId = $currentBaseId; + } else { + out += ' var ' + ($nextValid) + ' = true; '; + } + if ($i) { + out += ' if (' + ($nextValid) + ' && ' + ($prevValid) + ') { ' + ($valid) + ' = false; ' + ($passingSchemas) + ' = [' + ($passingSchemas) + ', ' + ($i) + ']; } else { '; + $closingBraces += '}'; + } + out += ' if (' + ($nextValid) + ') { ' + ($valid) + ' = ' + ($prevValid) + ' = true; ' + ($passingSchemas) + ' = ' + ($i) + '; }'; + } + } + it.compositeRule = $it.compositeRule = $wasComposite; + out += '' + ($closingBraces) + 'if (!' + ($valid) + ') { var err = '; /* istanbul ignore else */ + if (it.createErrors !== false) { + out += ' { keyword: \'' + ('oneOf') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { passingSchemas: ' + ($passingSchemas) + ' } '; + if (it.opts.messages !== false) { + out += ' , message: \'should match exactly one schema in oneOf\' '; + } + if (it.opts.verbose) { + out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; + } + out += ' } '; + } else { + out += ' {} '; + } + out += '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; + if (!it.compositeRule && $breakOnError) { + /* istanbul ignore if */ + if (it.async) { + out += ' throw new ValidationError(vErrors); '; + } else { + out += ' validate.errors = vErrors; return false; '; + } + } + out += '} else { errors = ' + ($errs) + '; if (vErrors !== null) { if (' + ($errs) + ') vErrors.length = ' + ($errs) + '; else vErrors = null; }'; + if (it.opts.allErrors) { + out += ' } '; + } + return out; +} diff --git a/user/themes/goku/node_modules/ajv/lib/dotjs/pattern.js b/user/themes/goku/node_modules/ajv/lib/dotjs/pattern.js new file mode 100644 index 00000000..1d74d6b0 --- /dev/null +++ b/user/themes/goku/node_modules/ajv/lib/dotjs/pattern.js @@ -0,0 +1,75 @@ +'use strict'; +module.exports = function generate_pattern(it, $keyword, $ruleType) { + var out = ' '; + var $lvl = it.level; + var $dataLvl = it.dataLevel; + var $schema = it.schema[$keyword]; + var $schemaPath = it.schemaPath + it.util.getProperty($keyword); + var $errSchemaPath = it.errSchemaPath + '/' + $keyword; + var $breakOnError = !it.opts.allErrors; + var $data = 'data' + ($dataLvl || ''); + var $isData = it.opts.$data && $schema && $schema.$data, + $schemaValue; + if ($isData) { + out += ' var schema' + ($lvl) + ' = ' + (it.util.getData($schema.$data, $dataLvl, it.dataPathArr)) + '; '; + $schemaValue = 'schema' + $lvl; + } else { + $schemaValue = $schema; + } + var $regexp = $isData ? '(new RegExp(' + $schemaValue + '))' : it.usePattern($schema); + out += 'if ( '; + if ($isData) { + out += ' (' + ($schemaValue) + ' !== undefined && typeof ' + ($schemaValue) + ' != \'string\') || '; + } + out += ' !' + ($regexp) + '.test(' + ($data) + ') ) { '; + var $$outStack = $$outStack || []; + $$outStack.push(out); + out = ''; /* istanbul ignore else */ + if (it.createErrors !== false) { + out += ' { keyword: \'' + ('pattern') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { pattern: '; + if ($isData) { + out += '' + ($schemaValue); + } else { + out += '' + (it.util.toQuotedString($schema)); + } + out += ' } '; + if (it.opts.messages !== false) { + out += ' , message: \'should match pattern "'; + if ($isData) { + out += '\' + ' + ($schemaValue) + ' + \''; + } else { + out += '' + (it.util.escapeQuotes($schema)); + } + out += '"\' '; + } + if (it.opts.verbose) { + out += ' , schema: '; + if ($isData) { + out += 'validate.schema' + ($schemaPath); + } else { + out += '' + (it.util.toQuotedString($schema)); + } + out += ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; + } + out += ' } '; + } else { + out += ' {} '; + } + var __err = out; + out = $$outStack.pop(); + if (!it.compositeRule && $breakOnError) { + /* istanbul ignore if */ + if (it.async) { + out += ' throw new ValidationError([' + (__err) + ']); '; + } else { + out += ' validate.errors = [' + (__err) + ']; return false; '; + } + } else { + out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; + } + out += '} '; + if ($breakOnError) { + out += ' else { '; + } + return out; +} diff --git a/user/themes/goku/node_modules/ajv/lib/dotjs/properties.js b/user/themes/goku/node_modules/ajv/lib/dotjs/properties.js new file mode 100644 index 00000000..34a82c62 --- /dev/null +++ b/user/themes/goku/node_modules/ajv/lib/dotjs/properties.js @@ -0,0 +1,330 @@ +'use strict'; +module.exports = function generate_properties(it, $keyword, $ruleType) { + var out = ' '; + var $lvl = it.level; + var $dataLvl = it.dataLevel; + var $schema = it.schema[$keyword]; + var $schemaPath = it.schemaPath + it.util.getProperty($keyword); + var $errSchemaPath = it.errSchemaPath + '/' + $keyword; + var $breakOnError = !it.opts.allErrors; + var $data = 'data' + ($dataLvl || ''); + var $errs = 'errs__' + $lvl; + var $it = it.util.copy(it); + var $closingBraces = ''; + $it.level++; + var $nextValid = 'valid' + $it.level; + var $key = 'key' + $lvl, + $idx = 'idx' + $lvl, + $dataNxt = $it.dataLevel = it.dataLevel + 1, + $nextData = 'data' + $dataNxt, + $dataProperties = 'dataProperties' + $lvl; + var $schemaKeys = Object.keys($schema || {}), + $pProperties = it.schema.patternProperties || {}, + $pPropertyKeys = Object.keys($pProperties), + $aProperties = it.schema.additionalProperties, + $someProperties = $schemaKeys.length || $pPropertyKeys.length, + $noAdditional = $aProperties === false, + $additionalIsSchema = typeof $aProperties == 'object' && Object.keys($aProperties).length, + $removeAdditional = it.opts.removeAdditional, + $checkAdditional = $noAdditional || $additionalIsSchema || $removeAdditional, + $ownProperties = it.opts.ownProperties, + $currentBaseId = it.baseId; + var $required = it.schema.required; + if ($required && !(it.opts.$data && $required.$data) && $required.length < it.opts.loopRequired) var $requiredHash = it.util.toHash($required); + out += 'var ' + ($errs) + ' = errors;var ' + ($nextValid) + ' = true;'; + if ($ownProperties) { + out += ' var ' + ($dataProperties) + ' = undefined;'; + } + if ($checkAdditional) { + if ($ownProperties) { + out += ' ' + ($dataProperties) + ' = ' + ($dataProperties) + ' || Object.keys(' + ($data) + '); for (var ' + ($idx) + '=0; ' + ($idx) + '<' + ($dataProperties) + '.length; ' + ($idx) + '++) { var ' + ($key) + ' = ' + ($dataProperties) + '[' + ($idx) + ']; '; + } else { + out += ' for (var ' + ($key) + ' in ' + ($data) + ') { '; + } + if ($someProperties) { + out += ' var isAdditional' + ($lvl) + ' = !(false '; + if ($schemaKeys.length) { + if ($schemaKeys.length > 8) { + out += ' || validate.schema' + ($schemaPath) + '.hasOwnProperty(' + ($key) + ') '; + } else { + var arr1 = $schemaKeys; + if (arr1) { + var $propertyKey, i1 = -1, + l1 = arr1.length - 1; + while (i1 < l1) { + $propertyKey = arr1[i1 += 1]; + out += ' || ' + ($key) + ' == ' + (it.util.toQuotedString($propertyKey)) + ' '; + } + } + } + } + if ($pPropertyKeys.length) { + var arr2 = $pPropertyKeys; + if (arr2) { + var $pProperty, $i = -1, + l2 = arr2.length - 1; + while ($i < l2) { + $pProperty = arr2[$i += 1]; + out += ' || ' + (it.usePattern($pProperty)) + '.test(' + ($key) + ') '; + } + } + } + out += ' ); if (isAdditional' + ($lvl) + ') { '; + } + if ($removeAdditional == 'all') { + out += ' delete ' + ($data) + '[' + ($key) + ']; '; + } else { + var $currentErrorPath = it.errorPath; + var $additionalProperty = '\' + ' + $key + ' + \''; + if (it.opts._errorDataPathProperty) { + it.errorPath = it.util.getPathExpr(it.errorPath, $key, it.opts.jsonPointers); + } + if ($noAdditional) { + if ($removeAdditional) { + out += ' delete ' + ($data) + '[' + ($key) + ']; '; + } else { + out += ' ' + ($nextValid) + ' = false; '; + var $currErrSchemaPath = $errSchemaPath; + $errSchemaPath = it.errSchemaPath + '/additionalProperties'; + var $$outStack = $$outStack || []; + $$outStack.push(out); + out = ''; /* istanbul ignore else */ + if (it.createErrors !== false) { + out += ' { keyword: \'' + ('additionalProperties') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { additionalProperty: \'' + ($additionalProperty) + '\' } '; + if (it.opts.messages !== false) { + out += ' , message: \''; + if (it.opts._errorDataPathProperty) { + out += 'is an invalid additional property'; + } else { + out += 'should NOT have additional properties'; + } + out += '\' '; + } + if (it.opts.verbose) { + out += ' , schema: false , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; + } + out += ' } '; + } else { + out += ' {} '; + } + var __err = out; + out = $$outStack.pop(); + if (!it.compositeRule && $breakOnError) { + /* istanbul ignore if */ + if (it.async) { + out += ' throw new ValidationError([' + (__err) + ']); '; + } else { + out += ' validate.errors = [' + (__err) + ']; return false; '; + } + } else { + out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; + } + $errSchemaPath = $currErrSchemaPath; + if ($breakOnError) { + out += ' break; '; + } + } + } else if ($additionalIsSchema) { + if ($removeAdditional == 'failing') { + out += ' var ' + ($errs) + ' = errors; '; + var $wasComposite = it.compositeRule; + it.compositeRule = $it.compositeRule = true; + $it.schema = $aProperties; + $it.schemaPath = it.schemaPath + '.additionalProperties'; + $it.errSchemaPath = it.errSchemaPath + '/additionalProperties'; + $it.errorPath = it.opts._errorDataPathProperty ? it.errorPath : it.util.getPathExpr(it.errorPath, $key, it.opts.jsonPointers); + var $passData = $data + '[' + $key + ']'; + $it.dataPathArr[$dataNxt] = $key; + var $code = it.validate($it); + $it.baseId = $currentBaseId; + if (it.util.varOccurences($code, $nextData) < 2) { + out += ' ' + (it.util.varReplace($code, $nextData, $passData)) + ' '; + } else { + out += ' var ' + ($nextData) + ' = ' + ($passData) + '; ' + ($code) + ' '; + } + out += ' if (!' + ($nextValid) + ') { errors = ' + ($errs) + '; if (validate.errors !== null) { if (errors) validate.errors.length = errors; else validate.errors = null; } delete ' + ($data) + '[' + ($key) + ']; } '; + it.compositeRule = $it.compositeRule = $wasComposite; + } else { + $it.schema = $aProperties; + $it.schemaPath = it.schemaPath + '.additionalProperties'; + $it.errSchemaPath = it.errSchemaPath + '/additionalProperties'; + $it.errorPath = it.opts._errorDataPathProperty ? it.errorPath : it.util.getPathExpr(it.errorPath, $key, it.opts.jsonPointers); + var $passData = $data + '[' + $key + ']'; + $it.dataPathArr[$dataNxt] = $key; + var $code = it.validate($it); + $it.baseId = $currentBaseId; + if (it.util.varOccurences($code, $nextData) < 2) { + out += ' ' + (it.util.varReplace($code, $nextData, $passData)) + ' '; + } else { + out += ' var ' + ($nextData) + ' = ' + ($passData) + '; ' + ($code) + ' '; + } + if ($breakOnError) { + out += ' if (!' + ($nextValid) + ') break; '; + } + } + } + it.errorPath = $currentErrorPath; + } + if ($someProperties) { + out += ' } '; + } + out += ' } '; + if ($breakOnError) { + out += ' if (' + ($nextValid) + ') { '; + $closingBraces += '}'; + } + } + var $useDefaults = it.opts.useDefaults && !it.compositeRule; + if ($schemaKeys.length) { + var arr3 = $schemaKeys; + if (arr3) { + var $propertyKey, i3 = -1, + l3 = arr3.length - 1; + while (i3 < l3) { + $propertyKey = arr3[i3 += 1]; + var $sch = $schema[$propertyKey]; + if ((it.opts.strictKeywords ? typeof $sch == 'object' && Object.keys($sch).length > 0 : it.util.schemaHasRules($sch, it.RULES.all))) { + var $prop = it.util.getProperty($propertyKey), + $passData = $data + $prop, + $hasDefault = $useDefaults && $sch.default !== undefined; + $it.schema = $sch; + $it.schemaPath = $schemaPath + $prop; + $it.errSchemaPath = $errSchemaPath + '/' + it.util.escapeFragment($propertyKey); + $it.errorPath = it.util.getPath(it.errorPath, $propertyKey, it.opts.jsonPointers); + $it.dataPathArr[$dataNxt] = it.util.toQuotedString($propertyKey); + var $code = it.validate($it); + $it.baseId = $currentBaseId; + if (it.util.varOccurences($code, $nextData) < 2) { + $code = it.util.varReplace($code, $nextData, $passData); + var $useData = $passData; + } else { + var $useData = $nextData; + out += ' var ' + ($nextData) + ' = ' + ($passData) + '; '; + } + if ($hasDefault) { + out += ' ' + ($code) + ' '; + } else { + if ($requiredHash && $requiredHash[$propertyKey]) { + out += ' if ( ' + ($useData) + ' === undefined '; + if ($ownProperties) { + out += ' || ! Object.prototype.hasOwnProperty.call(' + ($data) + ', \'' + (it.util.escapeQuotes($propertyKey)) + '\') '; + } + out += ') { ' + ($nextValid) + ' = false; '; + var $currentErrorPath = it.errorPath, + $currErrSchemaPath = $errSchemaPath, + $missingProperty = it.util.escapeQuotes($propertyKey); + if (it.opts._errorDataPathProperty) { + it.errorPath = it.util.getPath($currentErrorPath, $propertyKey, it.opts.jsonPointers); + } + $errSchemaPath = it.errSchemaPath + '/required'; + var $$outStack = $$outStack || []; + $$outStack.push(out); + out = ''; /* istanbul ignore else */ + if (it.createErrors !== false) { + out += ' { keyword: \'' + ('required') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { missingProperty: \'' + ($missingProperty) + '\' } '; + if (it.opts.messages !== false) { + out += ' , message: \''; + if (it.opts._errorDataPathProperty) { + out += 'is a required property'; + } else { + out += 'should have required property \\\'' + ($missingProperty) + '\\\''; + } + out += '\' '; + } + if (it.opts.verbose) { + out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; + } + out += ' } '; + } else { + out += ' {} '; + } + var __err = out; + out = $$outStack.pop(); + if (!it.compositeRule && $breakOnError) { + /* istanbul ignore if */ + if (it.async) { + out += ' throw new ValidationError([' + (__err) + ']); '; + } else { + out += ' validate.errors = [' + (__err) + ']; return false; '; + } + } else { + out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; + } + $errSchemaPath = $currErrSchemaPath; + it.errorPath = $currentErrorPath; + out += ' } else { '; + } else { + if ($breakOnError) { + out += ' if ( ' + ($useData) + ' === undefined '; + if ($ownProperties) { + out += ' || ! Object.prototype.hasOwnProperty.call(' + ($data) + ', \'' + (it.util.escapeQuotes($propertyKey)) + '\') '; + } + out += ') { ' + ($nextValid) + ' = true; } else { '; + } else { + out += ' if (' + ($useData) + ' !== undefined '; + if ($ownProperties) { + out += ' && Object.prototype.hasOwnProperty.call(' + ($data) + ', \'' + (it.util.escapeQuotes($propertyKey)) + '\') '; + } + out += ' ) { '; + } + } + out += ' ' + ($code) + ' } '; + } + } + if ($breakOnError) { + out += ' if (' + ($nextValid) + ') { '; + $closingBraces += '}'; + } + } + } + } + if ($pPropertyKeys.length) { + var arr4 = $pPropertyKeys; + if (arr4) { + var $pProperty, i4 = -1, + l4 = arr4.length - 1; + while (i4 < l4) { + $pProperty = arr4[i4 += 1]; + var $sch = $pProperties[$pProperty]; + if ((it.opts.strictKeywords ? typeof $sch == 'object' && Object.keys($sch).length > 0 : it.util.schemaHasRules($sch, it.RULES.all))) { + $it.schema = $sch; + $it.schemaPath = it.schemaPath + '.patternProperties' + it.util.getProperty($pProperty); + $it.errSchemaPath = it.errSchemaPath + '/patternProperties/' + it.util.escapeFragment($pProperty); + if ($ownProperties) { + out += ' ' + ($dataProperties) + ' = ' + ($dataProperties) + ' || Object.keys(' + ($data) + '); for (var ' + ($idx) + '=0; ' + ($idx) + '<' + ($dataProperties) + '.length; ' + ($idx) + '++) { var ' + ($key) + ' = ' + ($dataProperties) + '[' + ($idx) + ']; '; + } else { + out += ' for (var ' + ($key) + ' in ' + ($data) + ') { '; + } + out += ' if (' + (it.usePattern($pProperty)) + '.test(' + ($key) + ')) { '; + $it.errorPath = it.util.getPathExpr(it.errorPath, $key, it.opts.jsonPointers); + var $passData = $data + '[' + $key + ']'; + $it.dataPathArr[$dataNxt] = $key; + var $code = it.validate($it); + $it.baseId = $currentBaseId; + if (it.util.varOccurences($code, $nextData) < 2) { + out += ' ' + (it.util.varReplace($code, $nextData, $passData)) + ' '; + } else { + out += ' var ' + ($nextData) + ' = ' + ($passData) + '; ' + ($code) + ' '; + } + if ($breakOnError) { + out += ' if (!' + ($nextValid) + ') break; '; + } + out += ' } '; + if ($breakOnError) { + out += ' else ' + ($nextValid) + ' = true; '; + } + out += ' } '; + if ($breakOnError) { + out += ' if (' + ($nextValid) + ') { '; + $closingBraces += '}'; + } + } + } + } + } + if ($breakOnError) { + out += ' ' + ($closingBraces) + ' if (' + ($errs) + ' == errors) {'; + } + out = it.util.cleanUpCode(out); + return out; +} diff --git a/user/themes/goku/node_modules/ajv/lib/dotjs/propertyNames.js b/user/themes/goku/node_modules/ajv/lib/dotjs/propertyNames.js new file mode 100644 index 00000000..b2bf2954 --- /dev/null +++ b/user/themes/goku/node_modules/ajv/lib/dotjs/propertyNames.js @@ -0,0 +1,82 @@ +'use strict'; +module.exports = function generate_propertyNames(it, $keyword, $ruleType) { + var out = ' '; + var $lvl = it.level; + var $dataLvl = it.dataLevel; + var $schema = it.schema[$keyword]; + var $schemaPath = it.schemaPath + it.util.getProperty($keyword); + var $errSchemaPath = it.errSchemaPath + '/' + $keyword; + var $breakOnError = !it.opts.allErrors; + var $data = 'data' + ($dataLvl || ''); + var $errs = 'errs__' + $lvl; + var $it = it.util.copy(it); + var $closingBraces = ''; + $it.level++; + var $nextValid = 'valid' + $it.level; + out += 'var ' + ($errs) + ' = errors;'; + if ((it.opts.strictKeywords ? typeof $schema == 'object' && Object.keys($schema).length > 0 : it.util.schemaHasRules($schema, it.RULES.all))) { + $it.schema = $schema; + $it.schemaPath = $schemaPath; + $it.errSchemaPath = $errSchemaPath; + var $key = 'key' + $lvl, + $idx = 'idx' + $lvl, + $i = 'i' + $lvl, + $invalidName = '\' + ' + $key + ' + \'', + $dataNxt = $it.dataLevel = it.dataLevel + 1, + $nextData = 'data' + $dataNxt, + $dataProperties = 'dataProperties' + $lvl, + $ownProperties = it.opts.ownProperties, + $currentBaseId = it.baseId; + if ($ownProperties) { + out += ' var ' + ($dataProperties) + ' = undefined; '; + } + if ($ownProperties) { + out += ' ' + ($dataProperties) + ' = ' + ($dataProperties) + ' || Object.keys(' + ($data) + '); for (var ' + ($idx) + '=0; ' + ($idx) + '<' + ($dataProperties) + '.length; ' + ($idx) + '++) { var ' + ($key) + ' = ' + ($dataProperties) + '[' + ($idx) + ']; '; + } else { + out += ' for (var ' + ($key) + ' in ' + ($data) + ') { '; + } + out += ' var startErrs' + ($lvl) + ' = errors; '; + var $passData = $key; + var $wasComposite = it.compositeRule; + it.compositeRule = $it.compositeRule = true; + var $code = it.validate($it); + $it.baseId = $currentBaseId; + if (it.util.varOccurences($code, $nextData) < 2) { + out += ' ' + (it.util.varReplace($code, $nextData, $passData)) + ' '; + } else { + out += ' var ' + ($nextData) + ' = ' + ($passData) + '; ' + ($code) + ' '; + } + it.compositeRule = $it.compositeRule = $wasComposite; + out += ' if (!' + ($nextValid) + ') { for (var ' + ($i) + '=startErrs' + ($lvl) + '; ' + ($i) + ' 0 : it.util.schemaHasRules($propertySch, it.RULES.all)))) { + $required[$required.length] = $property; + } + } + } + } else { + var $required = $schema; + } + } + if ($isData || $required.length) { + var $currentErrorPath = it.errorPath, + $loopRequired = $isData || $required.length >= it.opts.loopRequired, + $ownProperties = it.opts.ownProperties; + if ($breakOnError) { + out += ' var missing' + ($lvl) + '; '; + if ($loopRequired) { + if (!$isData) { + out += ' var ' + ($vSchema) + ' = validate.schema' + ($schemaPath) + '; '; + } + var $i = 'i' + $lvl, + $propertyPath = 'schema' + $lvl + '[' + $i + ']', + $missingProperty = '\' + ' + $propertyPath + ' + \''; + if (it.opts._errorDataPathProperty) { + it.errorPath = it.util.getPathExpr($currentErrorPath, $propertyPath, it.opts.jsonPointers); + } + out += ' var ' + ($valid) + ' = true; '; + if ($isData) { + out += ' if (schema' + ($lvl) + ' === undefined) ' + ($valid) + ' = true; else if (!Array.isArray(schema' + ($lvl) + ')) ' + ($valid) + ' = false; else {'; + } + out += ' for (var ' + ($i) + ' = 0; ' + ($i) + ' < ' + ($vSchema) + '.length; ' + ($i) + '++) { ' + ($valid) + ' = ' + ($data) + '[' + ($vSchema) + '[' + ($i) + ']] !== undefined '; + if ($ownProperties) { + out += ' && Object.prototype.hasOwnProperty.call(' + ($data) + ', ' + ($vSchema) + '[' + ($i) + ']) '; + } + out += '; if (!' + ($valid) + ') break; } '; + if ($isData) { + out += ' } '; + } + out += ' if (!' + ($valid) + ') { '; + var $$outStack = $$outStack || []; + $$outStack.push(out); + out = ''; /* istanbul ignore else */ + if (it.createErrors !== false) { + out += ' { keyword: \'' + ('required') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { missingProperty: \'' + ($missingProperty) + '\' } '; + if (it.opts.messages !== false) { + out += ' , message: \''; + if (it.opts._errorDataPathProperty) { + out += 'is a required property'; + } else { + out += 'should have required property \\\'' + ($missingProperty) + '\\\''; + } + out += '\' '; + } + if (it.opts.verbose) { + out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; + } + out += ' } '; + } else { + out += ' {} '; + } + var __err = out; + out = $$outStack.pop(); + if (!it.compositeRule && $breakOnError) { + /* istanbul ignore if */ + if (it.async) { + out += ' throw new ValidationError([' + (__err) + ']); '; + } else { + out += ' validate.errors = [' + (__err) + ']; return false; '; + } + } else { + out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; + } + out += ' } else { '; + } else { + out += ' if ( '; + var arr2 = $required; + if (arr2) { + var $propertyKey, $i = -1, + l2 = arr2.length - 1; + while ($i < l2) { + $propertyKey = arr2[$i += 1]; + if ($i) { + out += ' || '; + } + var $prop = it.util.getProperty($propertyKey), + $useData = $data + $prop; + out += ' ( ( ' + ($useData) + ' === undefined '; + if ($ownProperties) { + out += ' || ! Object.prototype.hasOwnProperty.call(' + ($data) + ', \'' + (it.util.escapeQuotes($propertyKey)) + '\') '; + } + out += ') && (missing' + ($lvl) + ' = ' + (it.util.toQuotedString(it.opts.jsonPointers ? $propertyKey : $prop)) + ') ) '; + } + } + out += ') { '; + var $propertyPath = 'missing' + $lvl, + $missingProperty = '\' + ' + $propertyPath + ' + \''; + if (it.opts._errorDataPathProperty) { + it.errorPath = it.opts.jsonPointers ? it.util.getPathExpr($currentErrorPath, $propertyPath, true) : $currentErrorPath + ' + ' + $propertyPath; + } + var $$outStack = $$outStack || []; + $$outStack.push(out); + out = ''; /* istanbul ignore else */ + if (it.createErrors !== false) { + out += ' { keyword: \'' + ('required') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { missingProperty: \'' + ($missingProperty) + '\' } '; + if (it.opts.messages !== false) { + out += ' , message: \''; + if (it.opts._errorDataPathProperty) { + out += 'is a required property'; + } else { + out += 'should have required property \\\'' + ($missingProperty) + '\\\''; + } + out += '\' '; + } + if (it.opts.verbose) { + out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; + } + out += ' } '; + } else { + out += ' {} '; + } + var __err = out; + out = $$outStack.pop(); + if (!it.compositeRule && $breakOnError) { + /* istanbul ignore if */ + if (it.async) { + out += ' throw new ValidationError([' + (__err) + ']); '; + } else { + out += ' validate.errors = [' + (__err) + ']; return false; '; + } + } else { + out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; + } + out += ' } else { '; + } + } else { + if ($loopRequired) { + if (!$isData) { + out += ' var ' + ($vSchema) + ' = validate.schema' + ($schemaPath) + '; '; + } + var $i = 'i' + $lvl, + $propertyPath = 'schema' + $lvl + '[' + $i + ']', + $missingProperty = '\' + ' + $propertyPath + ' + \''; + if (it.opts._errorDataPathProperty) { + it.errorPath = it.util.getPathExpr($currentErrorPath, $propertyPath, it.opts.jsonPointers); + } + if ($isData) { + out += ' if (' + ($vSchema) + ' && !Array.isArray(' + ($vSchema) + ')) { var err = '; /* istanbul ignore else */ + if (it.createErrors !== false) { + out += ' { keyword: \'' + ('required') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { missingProperty: \'' + ($missingProperty) + '\' } '; + if (it.opts.messages !== false) { + out += ' , message: \''; + if (it.opts._errorDataPathProperty) { + out += 'is a required property'; + } else { + out += 'should have required property \\\'' + ($missingProperty) + '\\\''; + } + out += '\' '; + } + if (it.opts.verbose) { + out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; + } + out += ' } '; + } else { + out += ' {} '; + } + out += '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; } else if (' + ($vSchema) + ' !== undefined) { '; + } + out += ' for (var ' + ($i) + ' = 0; ' + ($i) + ' < ' + ($vSchema) + '.length; ' + ($i) + '++) { if (' + ($data) + '[' + ($vSchema) + '[' + ($i) + ']] === undefined '; + if ($ownProperties) { + out += ' || ! Object.prototype.hasOwnProperty.call(' + ($data) + ', ' + ($vSchema) + '[' + ($i) + ']) '; + } + out += ') { var err = '; /* istanbul ignore else */ + if (it.createErrors !== false) { + out += ' { keyword: \'' + ('required') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { missingProperty: \'' + ($missingProperty) + '\' } '; + if (it.opts.messages !== false) { + out += ' , message: \''; + if (it.opts._errorDataPathProperty) { + out += 'is a required property'; + } else { + out += 'should have required property \\\'' + ($missingProperty) + '\\\''; + } + out += '\' '; + } + if (it.opts.verbose) { + out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; + } + out += ' } '; + } else { + out += ' {} '; + } + out += '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; } } '; + if ($isData) { + out += ' } '; + } + } else { + var arr3 = $required; + if (arr3) { + var $propertyKey, i3 = -1, + l3 = arr3.length - 1; + while (i3 < l3) { + $propertyKey = arr3[i3 += 1]; + var $prop = it.util.getProperty($propertyKey), + $missingProperty = it.util.escapeQuotes($propertyKey), + $useData = $data + $prop; + if (it.opts._errorDataPathProperty) { + it.errorPath = it.util.getPath($currentErrorPath, $propertyKey, it.opts.jsonPointers); + } + out += ' if ( ' + ($useData) + ' === undefined '; + if ($ownProperties) { + out += ' || ! Object.prototype.hasOwnProperty.call(' + ($data) + ', \'' + (it.util.escapeQuotes($propertyKey)) + '\') '; + } + out += ') { var err = '; /* istanbul ignore else */ + if (it.createErrors !== false) { + out += ' { keyword: \'' + ('required') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { missingProperty: \'' + ($missingProperty) + '\' } '; + if (it.opts.messages !== false) { + out += ' , message: \''; + if (it.opts._errorDataPathProperty) { + out += 'is a required property'; + } else { + out += 'should have required property \\\'' + ($missingProperty) + '\\\''; + } + out += '\' '; + } + if (it.opts.verbose) { + out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; + } + out += ' } '; + } else { + out += ' {} '; + } + out += '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; } '; + } + } + } + } + it.errorPath = $currentErrorPath; + } else if ($breakOnError) { + out += ' if (true) {'; + } + return out; +} diff --git a/user/themes/goku/node_modules/ajv/lib/dotjs/uniqueItems.js b/user/themes/goku/node_modules/ajv/lib/dotjs/uniqueItems.js new file mode 100644 index 00000000..c4f6536b --- /dev/null +++ b/user/themes/goku/node_modules/ajv/lib/dotjs/uniqueItems.js @@ -0,0 +1,86 @@ +'use strict'; +module.exports = function generate_uniqueItems(it, $keyword, $ruleType) { + var out = ' '; + var $lvl = it.level; + var $dataLvl = it.dataLevel; + var $schema = it.schema[$keyword]; + var $schemaPath = it.schemaPath + it.util.getProperty($keyword); + var $errSchemaPath = it.errSchemaPath + '/' + $keyword; + var $breakOnError = !it.opts.allErrors; + var $data = 'data' + ($dataLvl || ''); + var $valid = 'valid' + $lvl; + var $isData = it.opts.$data && $schema && $schema.$data, + $schemaValue; + if ($isData) { + out += ' var schema' + ($lvl) + ' = ' + (it.util.getData($schema.$data, $dataLvl, it.dataPathArr)) + '; '; + $schemaValue = 'schema' + $lvl; + } else { + $schemaValue = $schema; + } + if (($schema || $isData) && it.opts.uniqueItems !== false) { + if ($isData) { + out += ' var ' + ($valid) + '; if (' + ($schemaValue) + ' === false || ' + ($schemaValue) + ' === undefined) ' + ($valid) + ' = true; else if (typeof ' + ($schemaValue) + ' != \'boolean\') ' + ($valid) + ' = false; else { '; + } + out += ' var i = ' + ($data) + '.length , ' + ($valid) + ' = true , j; if (i > 1) { '; + var $itemType = it.schema.items && it.schema.items.type, + $typeIsArray = Array.isArray($itemType); + if (!$itemType || $itemType == 'object' || $itemType == 'array' || ($typeIsArray && ($itemType.indexOf('object') >= 0 || $itemType.indexOf('array') >= 0))) { + out += ' outer: for (;i--;) { for (j = i; j--;) { if (equal(' + ($data) + '[i], ' + ($data) + '[j])) { ' + ($valid) + ' = false; break outer; } } } '; + } else { + out += ' var itemIndices = {}, item; for (;i--;) { var item = ' + ($data) + '[i]; '; + var $method = 'checkDataType' + ($typeIsArray ? 's' : ''); + out += ' if (' + (it.util[$method]($itemType, 'item', true)) + ') continue; '; + if ($typeIsArray) { + out += ' if (typeof item == \'string\') item = \'"\' + item; '; + } + out += ' if (typeof itemIndices[item] == \'number\') { ' + ($valid) + ' = false; j = itemIndices[item]; break; } itemIndices[item] = i; } '; + } + out += ' } '; + if ($isData) { + out += ' } '; + } + out += ' if (!' + ($valid) + ') { '; + var $$outStack = $$outStack || []; + $$outStack.push(out); + out = ''; /* istanbul ignore else */ + if (it.createErrors !== false) { + out += ' { keyword: \'' + ('uniqueItems') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { i: i, j: j } '; + if (it.opts.messages !== false) { + out += ' , message: \'should NOT have duplicate items (items ## \' + j + \' and \' + i + \' are identical)\' '; + } + if (it.opts.verbose) { + out += ' , schema: '; + if ($isData) { + out += 'validate.schema' + ($schemaPath); + } else { + out += '' + ($schema); + } + out += ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; + } + out += ' } '; + } else { + out += ' {} '; + } + var __err = out; + out = $$outStack.pop(); + if (!it.compositeRule && $breakOnError) { + /* istanbul ignore if */ + if (it.async) { + out += ' throw new ValidationError([' + (__err) + ']); '; + } else { + out += ' validate.errors = [' + (__err) + ']; return false; '; + } + } else { + out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; + } + out += ' } '; + if ($breakOnError) { + out += ' else { '; + } + } else { + if ($breakOnError) { + out += ' if (true) { '; + } + } + return out; +} diff --git a/user/themes/goku/node_modules/ajv/lib/dotjs/validate.js b/user/themes/goku/node_modules/ajv/lib/dotjs/validate.js new file mode 100644 index 00000000..cd0efc81 --- /dev/null +++ b/user/themes/goku/node_modules/ajv/lib/dotjs/validate.js @@ -0,0 +1,494 @@ +'use strict'; +module.exports = function generate_validate(it, $keyword, $ruleType) { + var out = ''; + var $async = it.schema.$async === true, + $refKeywords = it.util.schemaHasRulesExcept(it.schema, it.RULES.all, '$ref'), + $id = it.self._getId(it.schema); + if (it.opts.strictKeywords) { + var $unknownKwd = it.util.schemaUnknownRules(it.schema, it.RULES.keywords); + if ($unknownKwd) { + var $keywordsMsg = 'unknown keyword: ' + $unknownKwd; + if (it.opts.strictKeywords === 'log') it.logger.warn($keywordsMsg); + else throw new Error($keywordsMsg); + } + } + if (it.isTop) { + out += ' var validate = '; + if ($async) { + it.async = true; + out += 'async '; + } + out += 'function(data, dataPath, parentData, parentDataProperty, rootData) { \'use strict\'; '; + if ($id && (it.opts.sourceCode || it.opts.processCode)) { + out += ' ' + ('/\*# sourceURL=' + $id + ' */') + ' '; + } + } + if (typeof it.schema == 'boolean' || !($refKeywords || it.schema.$ref)) { + var $keyword = 'false schema'; + var $lvl = it.level; + var $dataLvl = it.dataLevel; + var $schema = it.schema[$keyword]; + var $schemaPath = it.schemaPath + it.util.getProperty($keyword); + var $errSchemaPath = it.errSchemaPath + '/' + $keyword; + var $breakOnError = !it.opts.allErrors; + var $errorKeyword; + var $data = 'data' + ($dataLvl || ''); + var $valid = 'valid' + $lvl; + if (it.schema === false) { + if (it.isTop) { + $breakOnError = true; + } else { + out += ' var ' + ($valid) + ' = false; '; + } + var $$outStack = $$outStack || []; + $$outStack.push(out); + out = ''; /* istanbul ignore else */ + if (it.createErrors !== false) { + out += ' { keyword: \'' + ($errorKeyword || 'false schema') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: {} '; + if (it.opts.messages !== false) { + out += ' , message: \'boolean schema is false\' '; + } + if (it.opts.verbose) { + out += ' , schema: false , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; + } + out += ' } '; + } else { + out += ' {} '; + } + var __err = out; + out = $$outStack.pop(); + if (!it.compositeRule && $breakOnError) { + /* istanbul ignore if */ + if (it.async) { + out += ' throw new ValidationError([' + (__err) + ']); '; + } else { + out += ' validate.errors = [' + (__err) + ']; return false; '; + } + } else { + out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; + } + } else { + if (it.isTop) { + if ($async) { + out += ' return data; '; + } else { + out += ' validate.errors = null; return true; '; + } + } else { + out += ' var ' + ($valid) + ' = true; '; + } + } + if (it.isTop) { + out += ' }; return validate; '; + } + return out; + } + if (it.isTop) { + var $top = it.isTop, + $lvl = it.level = 0, + $dataLvl = it.dataLevel = 0, + $data = 'data'; + it.rootId = it.resolve.fullPath(it.self._getId(it.root.schema)); + it.baseId = it.baseId || it.rootId; + delete it.isTop; + it.dataPathArr = [undefined]; + if (it.schema.default !== undefined && it.opts.useDefaults && it.opts.strictDefaults) { + var $defaultMsg = 'default is ignored in the schema root'; + if (it.opts.strictDefaults === 'log') it.logger.warn($defaultMsg); + else throw new Error($defaultMsg); + } + out += ' var vErrors = null; '; + out += ' var errors = 0; '; + out += ' if (rootData === undefined) rootData = data; '; + } else { + var $lvl = it.level, + $dataLvl = it.dataLevel, + $data = 'data' + ($dataLvl || ''); + if ($id) it.baseId = it.resolve.url(it.baseId, $id); + if ($async && !it.async) throw new Error('async schema in sync schema'); + out += ' var errs_' + ($lvl) + ' = errors;'; + } + var $valid = 'valid' + $lvl, + $breakOnError = !it.opts.allErrors, + $closingBraces1 = '', + $closingBraces2 = ''; + var $errorKeyword; + var $typeSchema = it.schema.type, + $typeIsArray = Array.isArray($typeSchema); + if ($typeSchema && it.opts.nullable && it.schema.nullable === true) { + if ($typeIsArray) { + if ($typeSchema.indexOf('null') == -1) $typeSchema = $typeSchema.concat('null'); + } else if ($typeSchema != 'null') { + $typeSchema = [$typeSchema, 'null']; + $typeIsArray = true; + } + } + if ($typeIsArray && $typeSchema.length == 1) { + $typeSchema = $typeSchema[0]; + $typeIsArray = false; + } + if (it.schema.$ref && $refKeywords) { + if (it.opts.extendRefs == 'fail') { + throw new Error('$ref: validation keywords used in schema at path "' + it.errSchemaPath + '" (see option extendRefs)'); + } else if (it.opts.extendRefs !== true) { + $refKeywords = false; + it.logger.warn('$ref: keywords ignored in schema at path "' + it.errSchemaPath + '"'); + } + } + if (it.schema.$comment && it.opts.$comment) { + out += ' ' + (it.RULES.all.$comment.code(it, '$comment')); + } + if ($typeSchema) { + if (it.opts.coerceTypes) { + var $coerceToTypes = it.util.coerceToTypes(it.opts.coerceTypes, $typeSchema); + } + var $rulesGroup = it.RULES.types[$typeSchema]; + if ($coerceToTypes || $typeIsArray || $rulesGroup === true || ($rulesGroup && !$shouldUseGroup($rulesGroup))) { + var $schemaPath = it.schemaPath + '.type', + $errSchemaPath = it.errSchemaPath + '/type'; + var $schemaPath = it.schemaPath + '.type', + $errSchemaPath = it.errSchemaPath + '/type', + $method = $typeIsArray ? 'checkDataTypes' : 'checkDataType'; + out += ' if (' + (it.util[$method]($typeSchema, $data, true)) + ') { '; + if ($coerceToTypes) { + var $dataType = 'dataType' + $lvl, + $coerced = 'coerced' + $lvl; + out += ' var ' + ($dataType) + ' = typeof ' + ($data) + '; '; + if (it.opts.coerceTypes == 'array') { + out += ' if (' + ($dataType) + ' == \'object\' && Array.isArray(' + ($data) + ')) ' + ($dataType) + ' = \'array\'; '; + } + out += ' var ' + ($coerced) + ' = undefined; '; + var $bracesCoercion = ''; + var arr1 = $coerceToTypes; + if (arr1) { + var $type, $i = -1, + l1 = arr1.length - 1; + while ($i < l1) { + $type = arr1[$i += 1]; + if ($i) { + out += ' if (' + ($coerced) + ' === undefined) { '; + $bracesCoercion += '}'; + } + if (it.opts.coerceTypes == 'array' && $type != 'array') { + out += ' if (' + ($dataType) + ' == \'array\' && ' + ($data) + '.length == 1) { ' + ($coerced) + ' = ' + ($data) + ' = ' + ($data) + '[0]; ' + ($dataType) + ' = typeof ' + ($data) + '; } '; + } + if ($type == 'string') { + out += ' if (' + ($dataType) + ' == \'number\' || ' + ($dataType) + ' == \'boolean\') ' + ($coerced) + ' = \'\' + ' + ($data) + '; else if (' + ($data) + ' === null) ' + ($coerced) + ' = \'\'; '; + } else if ($type == 'number' || $type == 'integer') { + out += ' if (' + ($dataType) + ' == \'boolean\' || ' + ($data) + ' === null || (' + ($dataType) + ' == \'string\' && ' + ($data) + ' && ' + ($data) + ' == +' + ($data) + ' '; + if ($type == 'integer') { + out += ' && !(' + ($data) + ' % 1)'; + } + out += ')) ' + ($coerced) + ' = +' + ($data) + '; '; + } else if ($type == 'boolean') { + out += ' if (' + ($data) + ' === \'false\' || ' + ($data) + ' === 0 || ' + ($data) + ' === null) ' + ($coerced) + ' = false; else if (' + ($data) + ' === \'true\' || ' + ($data) + ' === 1) ' + ($coerced) + ' = true; '; + } else if ($type == 'null') { + out += ' if (' + ($data) + ' === \'\' || ' + ($data) + ' === 0 || ' + ($data) + ' === false) ' + ($coerced) + ' = null; '; + } else if (it.opts.coerceTypes == 'array' && $type == 'array') { + out += ' if (' + ($dataType) + ' == \'string\' || ' + ($dataType) + ' == \'number\' || ' + ($dataType) + ' == \'boolean\' || ' + ($data) + ' == null) ' + ($coerced) + ' = [' + ($data) + ']; '; + } + } + } + out += ' ' + ($bracesCoercion) + ' if (' + ($coerced) + ' === undefined) { '; + var $$outStack = $$outStack || []; + $$outStack.push(out); + out = ''; /* istanbul ignore else */ + if (it.createErrors !== false) { + out += ' { keyword: \'' + ($errorKeyword || 'type') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { type: \''; + if ($typeIsArray) { + out += '' + ($typeSchema.join(",")); + } else { + out += '' + ($typeSchema); + } + out += '\' } '; + if (it.opts.messages !== false) { + out += ' , message: \'should be '; + if ($typeIsArray) { + out += '' + ($typeSchema.join(",")); + } else { + out += '' + ($typeSchema); + } + out += '\' '; + } + if (it.opts.verbose) { + out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; + } + out += ' } '; + } else { + out += ' {} '; + } + var __err = out; + out = $$outStack.pop(); + if (!it.compositeRule && $breakOnError) { + /* istanbul ignore if */ + if (it.async) { + out += ' throw new ValidationError([' + (__err) + ']); '; + } else { + out += ' validate.errors = [' + (__err) + ']; return false; '; + } + } else { + out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; + } + out += ' } else { '; + var $parentData = $dataLvl ? 'data' + (($dataLvl - 1) || '') : 'parentData', + $parentDataProperty = $dataLvl ? it.dataPathArr[$dataLvl] : 'parentDataProperty'; + out += ' ' + ($data) + ' = ' + ($coerced) + '; '; + if (!$dataLvl) { + out += 'if (' + ($parentData) + ' !== undefined)'; + } + out += ' ' + ($parentData) + '[' + ($parentDataProperty) + '] = ' + ($coerced) + '; } '; + } else { + var $$outStack = $$outStack || []; + $$outStack.push(out); + out = ''; /* istanbul ignore else */ + if (it.createErrors !== false) { + out += ' { keyword: \'' + ($errorKeyword || 'type') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { type: \''; + if ($typeIsArray) { + out += '' + ($typeSchema.join(",")); + } else { + out += '' + ($typeSchema); + } + out += '\' } '; + if (it.opts.messages !== false) { + out += ' , message: \'should be '; + if ($typeIsArray) { + out += '' + ($typeSchema.join(",")); + } else { + out += '' + ($typeSchema); + } + out += '\' '; + } + if (it.opts.verbose) { + out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; + } + out += ' } '; + } else { + out += ' {} '; + } + var __err = out; + out = $$outStack.pop(); + if (!it.compositeRule && $breakOnError) { + /* istanbul ignore if */ + if (it.async) { + out += ' throw new ValidationError([' + (__err) + ']); '; + } else { + out += ' validate.errors = [' + (__err) + ']; return false; '; + } + } else { + out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; + } + } + out += ' } '; + } + } + if (it.schema.$ref && !$refKeywords) { + out += ' ' + (it.RULES.all.$ref.code(it, '$ref')) + ' '; + if ($breakOnError) { + out += ' } if (errors === '; + if ($top) { + out += '0'; + } else { + out += 'errs_' + ($lvl); + } + out += ') { '; + $closingBraces2 += '}'; + } + } else { + var arr2 = it.RULES; + if (arr2) { + var $rulesGroup, i2 = -1, + l2 = arr2.length - 1; + while (i2 < l2) { + $rulesGroup = arr2[i2 += 1]; + if ($shouldUseGroup($rulesGroup)) { + if ($rulesGroup.type) { + out += ' if (' + (it.util.checkDataType($rulesGroup.type, $data)) + ') { '; + } + if (it.opts.useDefaults) { + if ($rulesGroup.type == 'object' && it.schema.properties) { + var $schema = it.schema.properties, + $schemaKeys = Object.keys($schema); + var arr3 = $schemaKeys; + if (arr3) { + var $propertyKey, i3 = -1, + l3 = arr3.length - 1; + while (i3 < l3) { + $propertyKey = arr3[i3 += 1]; + var $sch = $schema[$propertyKey]; + if ($sch.default !== undefined) { + var $passData = $data + it.util.getProperty($propertyKey); + if (it.compositeRule) { + if (it.opts.strictDefaults) { + var $defaultMsg = 'default is ignored for: ' + $passData; + if (it.opts.strictDefaults === 'log') it.logger.warn($defaultMsg); + else throw new Error($defaultMsg); + } + } else { + out += ' if (' + ($passData) + ' === undefined '; + if (it.opts.useDefaults == 'empty') { + out += ' || ' + ($passData) + ' === null || ' + ($passData) + ' === \'\' '; + } + out += ' ) ' + ($passData) + ' = '; + if (it.opts.useDefaults == 'shared') { + out += ' ' + (it.useDefault($sch.default)) + ' '; + } else { + out += ' ' + (JSON.stringify($sch.default)) + ' '; + } + out += '; '; + } + } + } + } + } else if ($rulesGroup.type == 'array' && Array.isArray(it.schema.items)) { + var arr4 = it.schema.items; + if (arr4) { + var $sch, $i = -1, + l4 = arr4.length - 1; + while ($i < l4) { + $sch = arr4[$i += 1]; + if ($sch.default !== undefined) { + var $passData = $data + '[' + $i + ']'; + if (it.compositeRule) { + if (it.opts.strictDefaults) { + var $defaultMsg = 'default is ignored for: ' + $passData; + if (it.opts.strictDefaults === 'log') it.logger.warn($defaultMsg); + else throw new Error($defaultMsg); + } + } else { + out += ' if (' + ($passData) + ' === undefined '; + if (it.opts.useDefaults == 'empty') { + out += ' || ' + ($passData) + ' === null || ' + ($passData) + ' === \'\' '; + } + out += ' ) ' + ($passData) + ' = '; + if (it.opts.useDefaults == 'shared') { + out += ' ' + (it.useDefault($sch.default)) + ' '; + } else { + out += ' ' + (JSON.stringify($sch.default)) + ' '; + } + out += '; '; + } + } + } + } + } + } + var arr5 = $rulesGroup.rules; + if (arr5) { + var $rule, i5 = -1, + l5 = arr5.length - 1; + while (i5 < l5) { + $rule = arr5[i5 += 1]; + if ($shouldUseRule($rule)) { + var $code = $rule.code(it, $rule.keyword, $rulesGroup.type); + if ($code) { + out += ' ' + ($code) + ' '; + if ($breakOnError) { + $closingBraces1 += '}'; + } + } + } + } + } + if ($breakOnError) { + out += ' ' + ($closingBraces1) + ' '; + $closingBraces1 = ''; + } + if ($rulesGroup.type) { + out += ' } '; + if ($typeSchema && $typeSchema === $rulesGroup.type && !$coerceToTypes) { + out += ' else { '; + var $schemaPath = it.schemaPath + '.type', + $errSchemaPath = it.errSchemaPath + '/type'; + var $$outStack = $$outStack || []; + $$outStack.push(out); + out = ''; /* istanbul ignore else */ + if (it.createErrors !== false) { + out += ' { keyword: \'' + ($errorKeyword || 'type') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { type: \''; + if ($typeIsArray) { + out += '' + ($typeSchema.join(",")); + } else { + out += '' + ($typeSchema); + } + out += '\' } '; + if (it.opts.messages !== false) { + out += ' , message: \'should be '; + if ($typeIsArray) { + out += '' + ($typeSchema.join(",")); + } else { + out += '' + ($typeSchema); + } + out += '\' '; + } + if (it.opts.verbose) { + out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; + } + out += ' } '; + } else { + out += ' {} '; + } + var __err = out; + out = $$outStack.pop(); + if (!it.compositeRule && $breakOnError) { + /* istanbul ignore if */ + if (it.async) { + out += ' throw new ValidationError([' + (__err) + ']); '; + } else { + out += ' validate.errors = [' + (__err) + ']; return false; '; + } + } else { + out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; + } + out += ' } '; + } + } + if ($breakOnError) { + out += ' if (errors === '; + if ($top) { + out += '0'; + } else { + out += 'errs_' + ($lvl); + } + out += ') { '; + $closingBraces2 += '}'; + } + } + } + } + } + if ($breakOnError) { + out += ' ' + ($closingBraces2) + ' '; + } + if ($top) { + if ($async) { + out += ' if (errors === 0) return data; '; + out += ' else throw new ValidationError(vErrors); '; + } else { + out += ' validate.errors = vErrors; '; + out += ' return errors === 0; '; + } + out += ' }; return validate;'; + } else { + out += ' var ' + ($valid) + ' = errors === errs_' + ($lvl) + ';'; + } + out = it.util.cleanUpCode(out); + if ($top) { + out = it.util.finalCleanUpCode(out, $async); + } + + function $shouldUseGroup($rulesGroup) { + var rules = $rulesGroup.rules; + for (var i = 0; i < rules.length; i++) + if ($shouldUseRule(rules[i])) return true; + } + + function $shouldUseRule($rule) { + return it.schema[$rule.keyword] !== undefined || ($rule.implements && $ruleImplementsSomeKeyword($rule)); + } + + function $ruleImplementsSomeKeyword($rule) { + var impl = $rule.implements; + for (var i = 0; i < impl.length; i++) + if (it.schema[impl[i]] !== undefined) return true; + } + return out; +} diff --git a/user/themes/goku/node_modules/ajv/lib/keyword.js b/user/themes/goku/node_modules/ajv/lib/keyword.js new file mode 100644 index 00000000..5fec19a6 --- /dev/null +++ b/user/themes/goku/node_modules/ajv/lib/keyword.js @@ -0,0 +1,146 @@ +'use strict'; + +var IDENTIFIER = /^[a-z_$][a-z0-9_$-]*$/i; +var customRuleCode = require('./dotjs/custom'); +var definitionSchema = require('./definition_schema'); + +module.exports = { + add: addKeyword, + get: getKeyword, + remove: removeKeyword, + validate: validateKeyword +}; + + +/** + * Define custom keyword + * @this Ajv + * @param {String} keyword custom keyword, should be unique (including different from all standard, custom and macro keywords). + * @param {Object} definition keyword definition object with properties `type` (type(s) which the keyword applies to), `validate` or `compile`. + * @return {Ajv} this for method chaining + */ +function addKeyword(keyword, definition) { + /* jshint validthis: true */ + /* eslint no-shadow: 0 */ + var RULES = this.RULES; + if (RULES.keywords[keyword]) + throw new Error('Keyword ' + keyword + ' is already defined'); + + if (!IDENTIFIER.test(keyword)) + throw new Error('Keyword ' + keyword + ' is not a valid identifier'); + + if (definition) { + this.validateKeyword(definition, true); + + var dataType = definition.type; + if (Array.isArray(dataType)) { + for (var i=0; i ../ajv-dist/bower.json + cd ../ajv-dist + + if [[ `git status --porcelain` ]]; then + echo "Changes detected. Updating master branch..." + git add -A + git commit -m "updated by travis build #$TRAVIS_BUILD_NUMBER" + git push --quiet origin master > /dev/null 2>&1 + fi + + echo "Publishing tag..." + + git tag $TRAVIS_TAG + git push --tags > /dev/null 2>&1 + + echo "Done" +fi diff --git a/user/themes/goku/node_modules/ajv/scripts/travis-gh-pages b/user/themes/goku/node_modules/ajv/scripts/travis-gh-pages new file mode 100755 index 00000000..46ded161 --- /dev/null +++ b/user/themes/goku/node_modules/ajv/scripts/travis-gh-pages @@ -0,0 +1,23 @@ +#!/usr/bin/env bash + +set -e + +if [[ "$TRAVIS_BRANCH" == "master" && "$TRAVIS_PULL_REQUEST" == "false" && $TRAVIS_JOB_NUMBER =~ ".3" ]]; then + git diff --name-only $TRAVIS_COMMIT_RANGE | grep -qE '\.md$|^LICENSE$|travis-gh-pages$' && { + rm -rf ../gh-pages + git clone -b gh-pages --single-branch https://${GITHUB_TOKEN}@github.com/epoberezkin/ajv.git ../gh-pages + mkdir -p ../gh-pages/_source + cp *.md ../gh-pages/_source + cp LICENSE ../gh-pages/_source + currentDir=$(pwd) + cd ../gh-pages + $currentDir/node_modules/.bin/gh-pages-generator + # remove logo from README + sed -i -E "s/]+ajv_logo[^>]+>//" index.md + git config user.email "$GIT_USER_EMAIL" + git config user.name "$GIT_USER_NAME" + git add . + git commit -am "updated by travis build #$TRAVIS_BUILD_NUMBER" + git push --quiet origin gh-pages > /dev/null 2>&1 + } +fi diff --git a/user/themes/goku/node_modules/amdefine/LICENSE b/user/themes/goku/node_modules/amdefine/LICENSE new file mode 100644 index 00000000..9b25ee00 --- /dev/null +++ b/user/themes/goku/node_modules/amdefine/LICENSE @@ -0,0 +1,58 @@ +amdefine is released under two licenses: new BSD, and MIT. You may pick the +license that best suits your development needs. The text of both licenses are +provided below. + + +The "New" BSD License: +---------------------- + +Copyright (c) 2011-2016, The Dojo Foundation +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + * 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. + * Neither the name of the Dojo Foundation nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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. + + + +MIT License +----------- + +Copyright (c) 2011-2016, The Dojo Foundation + +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. diff --git a/user/themes/goku/node_modules/amdefine/README.md b/user/themes/goku/node_modules/amdefine/README.md new file mode 100644 index 00000000..037a6e81 --- /dev/null +++ b/user/themes/goku/node_modules/amdefine/README.md @@ -0,0 +1,171 @@ +# amdefine + +A module that can be used to implement AMD's define() in Node. This allows you +to code to the AMD API and have the module work in node programs without +requiring those other programs to use AMD. + +## Usage + +**1)** Update your package.json to indicate amdefine as a dependency: + +```javascript + "dependencies": { + "amdefine": ">=0.1.0" + } +``` + +Then run `npm install` to get amdefine into your project. + +**2)** At the top of each module that uses define(), place this code: + +```javascript +if (typeof define !== 'function') { var define = require('amdefine')(module) } +``` + +**Only use these snippets** when loading amdefine. If you preserve the basic structure, +with the braces, it will be stripped out when using the [RequireJS optimizer](#optimizer). + +You can add spaces, line breaks and even require amdefine with a local path, but +keep the rest of the structure to get the stripping behavior. + +As you may know, because `if` statements in JavaScript don't have their own scope, the var +declaration in the above snippet is made whether the `if` expression is truthy or not. If +RequireJS is loaded then the declaration is superfluous because `define` is already already +declared in the same scope in RequireJS. Fortunately JavaScript handles multiple `var` +declarations of the same variable in the same scope gracefully. + +If you want to deliver amdefine.js with your code rather than specifying it as a dependency +with npm, then just download the latest release and refer to it using a relative path: + +[Latest Version](https://github.com/jrburke/amdefine/raw/latest/amdefine.js) + +### amdefine/intercept + +Consider this very experimental. + +Instead of pasting the piece of text for the amdefine setup of a `define` +variable in each module you create or consume, you can use `amdefine/intercept` +instead. It will automatically insert the above snippet in each .js file loaded +by Node. + +**Warning**: you should only use this if you are creating an application that +is consuming AMD style defined()'d modules that are distributed via npm and want +to run that code in Node. + +For library code where you are not sure if it will be used by others in Node or +in the browser, then explicitly depending on amdefine and placing the code +snippet above is suggested path, instead of using `amdefine/intercept`. The +intercept module affects all .js files loaded in the Node app, and it is +inconsiderate to modify global state like that unless you are also controlling +the top level app. + +#### Why distribute AMD-style modules via npm? + +npm has a lot of weaknesses for front-end use (installed layout is not great, +should have better support for the `baseUrl + moduleID + '.js' style of loading, +single file JS installs), but some people want a JS package manager and are +willing to live with those constraints. If that is you, but still want to author +in AMD style modules to get dynamic require([]), better direct source usage and +powerful loader plugin support in the browser, then this tool can help. + +#### amdefine/intercept usage + +Just require it in your top level app module (for example index.js, server.js): + +```javascript +require('amdefine/intercept'); +``` + +The module does not return a value, so no need to assign the result to a local +variable. + +Then just require() code as you normally would with Node's require(). Any .js +loaded after the intercept require will have the amdefine check injected in +the .js source as it is loaded. It does not modify the source on disk, just +prepends some content to the text of the module as it is loaded by Node. + +#### How amdefine/intercept works + +It overrides the `Module._extensions['.js']` in Node to automatically prepend +the amdefine snippet above. So, it will affect any .js file loaded by your +app. + +## define() usage + +It is best if you use the anonymous forms of define() in your module: + +```javascript +define(function (require) { + var dependency = require('dependency'); +}); +``` + +or + +```javascript +define(['dependency'], function (dependency) { + +}); +``` + +## RequireJS optimizer integration. + +Version 1.0.3 of the [RequireJS optimizer](http://requirejs.org/docs/optimization.html) +will have support for stripping the `if (typeof define !== 'function')` check +mentioned above, so you can include this snippet for code that runs in the +browser, but avoid taking the cost of the if() statement once the code is +optimized for deployment. + +## Node 0.4 Support + +If you want to support Node 0.4, then add `require` as the second parameter to amdefine: + +```javascript +//Only if you want Node 0.4. If using 0.5 or later, use the above snippet. +if (typeof define !== 'function') { var define = require('amdefine')(module, require) } +``` + +## Limitations + +### Synchronous vs Asynchronous + +amdefine creates a define() function that is callable by your code. It will +execute and trace dependencies and call the factory function *synchronously*, +to keep the behavior in line with Node's synchronous dependency tracing. + +The exception: calling AMD's callback-style require() from inside a factory +function. The require callback is called on process.nextTick(): + +```javascript +define(function (require) { + require(['a'], function(a) { + //'a' is loaded synchronously, but + //this callback is called on process.nextTick(). + }); +}); +``` + +### Loader Plugins + +Loader plugins are supported as long as they call their load() callbacks +synchronously. So ones that do network requests will not work. However plugins +like [text](http://requirejs.org/docs/api.html#text) can load text files locally. + +The plugin API's `load.fromText()` is **not supported** in amdefine, so this means +transpiler plugins like the [CoffeeScript loader plugin](https://github.com/jrburke/require-cs) +will not work. This may be fixable, but it is a bit complex, and I do not have +enough node-fu to figure it out yet. See the source for amdefine.js if you want +to get an idea of the issues involved. + +## Tests + +To run the tests, cd to **tests** and run: + +``` +node all.js +node all-intercept.js +``` + +## License + +New BSD and MIT. Check the LICENSE file for all the details. diff --git a/user/themes/goku/node_modules/amdefine/amdefine.js b/user/themes/goku/node_modules/amdefine/amdefine.js new file mode 100644 index 00000000..ca830ba4 --- /dev/null +++ b/user/themes/goku/node_modules/amdefine/amdefine.js @@ -0,0 +1,301 @@ +/** vim: et:ts=4:sw=4:sts=4 + * @license amdefine 1.0.1 Copyright (c) 2011-2016, The Dojo Foundation All Rights Reserved. + * Available via the MIT or new BSD license. + * see: http://github.com/jrburke/amdefine for details + */ + +/*jslint node: true */ +/*global module, process */ +'use strict'; + +/** + * Creates a define for node. + * @param {Object} module the "module" object that is defined by Node for the + * current module. + * @param {Function} [requireFn]. Node's require function for the current module. + * It only needs to be passed in Node versions before 0.5, when module.require + * did not exist. + * @returns {Function} a define function that is usable for the current node + * module. + */ +function amdefine(module, requireFn) { + 'use strict'; + var defineCache = {}, + loaderCache = {}, + alreadyCalled = false, + path = require('path'), + makeRequire, stringRequire; + + /** + * Trims the . and .. from an array of path segments. + * It will keep a leading path segment if a .. will become + * the first path segment, to help with module name lookups, + * which act like paths, but can be remapped. But the end result, + * all paths that use this function should look normalized. + * NOTE: this method MODIFIES the input array. + * @param {Array} ary the array of path segments. + */ + function trimDots(ary) { + var i, part; + for (i = 0; ary[i]; i+= 1) { + part = ary[i]; + if (part === '.') { + ary.splice(i, 1); + i -= 1; + } else if (part === '..') { + if (i === 1 && (ary[2] === '..' || ary[0] === '..')) { + //End of the line. Keep at least one non-dot + //path segment at the front so it can be mapped + //correctly to disk. Otherwise, there is likely + //no path mapping for a path starting with '..'. + //This can still fail, but catches the most reasonable + //uses of .. + break; + } else if (i > 0) { + ary.splice(i - 1, 2); + i -= 2; + } + } + } + } + + function normalize(name, baseName) { + var baseParts; + + //Adjust any relative paths. + if (name && name.charAt(0) === '.') { + //If have a base name, try to normalize against it, + //otherwise, assume it is a top-level require that will + //be relative to baseUrl in the end. + if (baseName) { + baseParts = baseName.split('/'); + baseParts = baseParts.slice(0, baseParts.length - 1); + baseParts = baseParts.concat(name.split('/')); + trimDots(baseParts); + name = baseParts.join('/'); + } + } + + return name; + } + + /** + * Create the normalize() function passed to a loader plugin's + * normalize method. + */ + function makeNormalize(relName) { + return function (name) { + return normalize(name, relName); + }; + } + + function makeLoad(id) { + function load(value) { + loaderCache[id] = value; + } + + load.fromText = function (id, text) { + //This one is difficult because the text can/probably uses + //define, and any relative paths and requires should be relative + //to that id was it would be found on disk. But this would require + //bootstrapping a module/require fairly deeply from node core. + //Not sure how best to go about that yet. + throw new Error('amdefine does not implement load.fromText'); + }; + + return load; + } + + makeRequire = function (systemRequire, exports, module, relId) { + function amdRequire(deps, callback) { + if (typeof deps === 'string') { + //Synchronous, single module require('') + return stringRequire(systemRequire, exports, module, deps, relId); + } else { + //Array of dependencies with a callback. + + //Convert the dependencies to modules. + deps = deps.map(function (depName) { + return stringRequire(systemRequire, exports, module, depName, relId); + }); + + //Wait for next tick to call back the require call. + if (callback) { + process.nextTick(function () { + callback.apply(null, deps); + }); + } + } + } + + amdRequire.toUrl = function (filePath) { + if (filePath.indexOf('.') === 0) { + return normalize(filePath, path.dirname(module.filename)); + } else { + return filePath; + } + }; + + return amdRequire; + }; + + //Favor explicit value, passed in if the module wants to support Node 0.4. + requireFn = requireFn || function req() { + return module.require.apply(module, arguments); + }; + + function runFactory(id, deps, factory) { + var r, e, m, result; + + if (id) { + e = loaderCache[id] = {}; + m = { + id: id, + uri: __filename, + exports: e + }; + r = makeRequire(requireFn, e, m, id); + } else { + //Only support one define call per file + if (alreadyCalled) { + throw new Error('amdefine with no module ID cannot be called more than once per file.'); + } + alreadyCalled = true; + + //Use the real variables from node + //Use module.exports for exports, since + //the exports in here is amdefine exports. + e = module.exports; + m = module; + r = makeRequire(requireFn, e, m, module.id); + } + + //If there are dependencies, they are strings, so need + //to convert them to dependency values. + if (deps) { + deps = deps.map(function (depName) { + return r(depName); + }); + } + + //Call the factory with the right dependencies. + if (typeof factory === 'function') { + result = factory.apply(m.exports, deps); + } else { + result = factory; + } + + if (result !== undefined) { + m.exports = result; + if (id) { + loaderCache[id] = m.exports; + } + } + } + + stringRequire = function (systemRequire, exports, module, id, relId) { + //Split the ID by a ! so that + var index = id.indexOf('!'), + originalId = id, + prefix, plugin; + + if (index === -1) { + id = normalize(id, relId); + + //Straight module lookup. If it is one of the special dependencies, + //deal with it, otherwise, delegate to node. + if (id === 'require') { + return makeRequire(systemRequire, exports, module, relId); + } else if (id === 'exports') { + return exports; + } else if (id === 'module') { + return module; + } else if (loaderCache.hasOwnProperty(id)) { + return loaderCache[id]; + } else if (defineCache[id]) { + runFactory.apply(null, defineCache[id]); + return loaderCache[id]; + } else { + if(systemRequire) { + return systemRequire(originalId); + } else { + throw new Error('No module with ID: ' + id); + } + } + } else { + //There is a plugin in play. + prefix = id.substring(0, index); + id = id.substring(index + 1, id.length); + + plugin = stringRequire(systemRequire, exports, module, prefix, relId); + + if (plugin.normalize) { + id = plugin.normalize(id, makeNormalize(relId)); + } else { + //Normalize the ID normally. + id = normalize(id, relId); + } + + if (loaderCache[id]) { + return loaderCache[id]; + } else { + plugin.load(id, makeRequire(systemRequire, exports, module, relId), makeLoad(id), {}); + + return loaderCache[id]; + } + } + }; + + //Create a define function specific to the module asking for amdefine. + function define(id, deps, factory) { + if (Array.isArray(id)) { + factory = deps; + deps = id; + id = undefined; + } else if (typeof id !== 'string') { + factory = id; + id = deps = undefined; + } + + if (deps && !Array.isArray(deps)) { + factory = deps; + deps = undefined; + } + + if (!deps) { + deps = ['require', 'exports', 'module']; + } + + //Set up properties for this module. If an ID, then use + //internal cache. If no ID, then use the external variables + //for this node module. + if (id) { + //Put the module in deep freeze until there is a + //require call for it. + defineCache[id] = [id, deps, factory]; + } else { + runFactory(id, deps, factory); + } + } + + //define.require, which has access to all the values in the + //cache. Useful for AMD modules that all have IDs in the file, + //but need to finally export a value to node based on one of those + //IDs. + define.require = function (id) { + if (loaderCache[id]) { + return loaderCache[id]; + } + + if (defineCache[id]) { + runFactory.apply(null, defineCache[id]); + return loaderCache[id]; + } + }; + + define.amd = {}; + + return define; +} + +module.exports = amdefine; diff --git a/user/themes/goku/node_modules/amdefine/intercept.js b/user/themes/goku/node_modules/amdefine/intercept.js new file mode 100644 index 00000000..771a9830 --- /dev/null +++ b/user/themes/goku/node_modules/amdefine/intercept.js @@ -0,0 +1,36 @@ +/*jshint node: true */ +var inserted, + Module = require('module'), + fs = require('fs'), + existingExtFn = Module._extensions['.js'], + amdefineRegExp = /amdefine\.js/; + +inserted = "if (typeof define !== 'function') {var define = require('amdefine')(module)}"; + +//From the node/lib/module.js source: +function stripBOM(content) { + // Remove byte order marker. This catches EF BB BF (the UTF-8 BOM) + // because the buffer-to-string conversion in `fs.readFileSync()` + // translates it to FEFF, the UTF-16 BOM. + if (content.charCodeAt(0) === 0xFEFF) { + content = content.slice(1); + } + return content; +} + +//Also adapted from the node/lib/module.js source: +function intercept(module, filename) { + var content = stripBOM(fs.readFileSync(filename, 'utf8')); + + if (!amdefineRegExp.test(module.id)) { + content = inserted + content; + } + + module._compile(content, filename); +} + +intercept._id = 'amdefine/intercept'; + +if (!existingExtFn._id || existingExtFn._id !== intercept._id) { + Module._extensions['.js'] = intercept; +} diff --git a/user/themes/goku/node_modules/amdefine/package.json b/user/themes/goku/node_modules/amdefine/package.json new file mode 100644 index 00000000..a5547f08 --- /dev/null +++ b/user/themes/goku/node_modules/amdefine/package.json @@ -0,0 +1,48 @@ +{ + "_from": "amdefine@>=0.0.4", + "_id": "amdefine@1.0.1", + "_inBundle": false, + "_integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", + "_location": "/amdefine", + "_phantomChildren": {}, + "_requested": { + "type": "range", + "registry": true, + "raw": "amdefine@>=0.0.4", + "name": "amdefine", + "escapedName": "amdefine", + "rawSpec": ">=0.0.4", + "saveSpec": null, + "fetchSpec": ">=0.0.4" + }, + "_requiredBy": [ + "/source-map" + ], + "_resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "_shasum": "4a5282ac164729e93619bcfd3ad151f817ce91f5", + "_spec": "amdefine@>=0.0.4", + "_where": "/srv/http/berryfarmprojects.org.uk/stay-grav/user/themes/goku/node_modules/source-map", + "author": { + "name": "James Burke", + "email": "jrburke@gmail.com", + "url": "http://github.com/jrburke" + }, + "bugs": { + "url": "https://github.com/jrburke/amdefine/issues" + }, + "bundleDependencies": false, + "deprecated": false, + "description": "Provide AMD's define() API for declaring modules in the AMD format", + "engines": { + "node": ">=0.4.2" + }, + "homepage": "http://github.com/jrburke/amdefine", + "license": "BSD-3-Clause OR MIT", + "main": "./amdefine.js", + "name": "amdefine", + "repository": { + "type": "git", + "url": "git+https://github.com/jrburke/amdefine.git" + }, + "version": "1.0.1" +} diff --git a/user/themes/goku/node_modules/ansi-regex/index.js b/user/themes/goku/node_modules/ansi-regex/index.js new file mode 100644 index 00000000..b9574ed7 --- /dev/null +++ b/user/themes/goku/node_modules/ansi-regex/index.js @@ -0,0 +1,4 @@ +'use strict'; +module.exports = function () { + return /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-PRZcf-nqry=><]/g; +}; diff --git a/user/themes/goku/node_modules/ansi-regex/license b/user/themes/goku/node_modules/ansi-regex/license new file mode 100644 index 00000000..654d0bfe --- /dev/null +++ b/user/themes/goku/node_modules/ansi-regex/license @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) Sindre Sorhus (sindresorhus.com) + +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. diff --git a/user/themes/goku/node_modules/ansi-regex/package.json b/user/themes/goku/node_modules/ansi-regex/package.json new file mode 100644 index 00000000..dded437b --- /dev/null +++ b/user/themes/goku/node_modules/ansi-regex/package.json @@ -0,0 +1,109 @@ +{ + "_from": "ansi-regex@^2.0.0", + "_id": "ansi-regex@2.1.1", + "_inBundle": false, + "_integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "_location": "/ansi-regex", + "_phantomChildren": {}, + "_requested": { + "type": "range", + "registry": true, + "raw": "ansi-regex@^2.0.0", + "name": "ansi-regex", + "escapedName": "ansi-regex", + "rawSpec": "^2.0.0", + "saveSpec": null, + "fetchSpec": "^2.0.0" + }, + "_requiredBy": [ + "/has-ansi", + "/strip-ansi" + ], + "_resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "_shasum": "c3b33ab5ee360d86e0e628f0468ae7ef27d654df", + "_spec": "ansi-regex@^2.0.0", + "_where": "/srv/http/berryfarmprojects.org.uk/stay-grav/user/themes/goku/node_modules/has-ansi", + "author": { + "name": "Sindre Sorhus", + "email": "sindresorhus@gmail.com", + "url": "sindresorhus.com" + }, + "bugs": { + "url": "https://github.com/chalk/ansi-regex/issues" + }, + "bundleDependencies": false, + "deprecated": false, + "description": "Regular expression for matching ANSI escape codes", + "devDependencies": { + "ava": "0.17.0", + "xo": "0.16.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "files": [ + "index.js" + ], + "homepage": "https://github.com/chalk/ansi-regex#readme", + "keywords": [ + "ansi", + "styles", + "color", + "colour", + "colors", + "terminal", + "console", + "cli", + "string", + "tty", + "escape", + "formatting", + "rgb", + "256", + "shell", + "xterm", + "command-line", + "text", + "regex", + "regexp", + "re", + "match", + "test", + "find", + "pattern" + ], + "license": "MIT", + "maintainers": [ + { + "name": "Sindre Sorhus", + "email": "sindresorhus@gmail.com", + "url": "sindresorhus.com" + }, + { + "name": "Joshua Appelman", + "email": "jappelman@xebia.com", + "url": "jbnicolai.com" + }, + { + "name": "JD Ballard", + "email": "i.am.qix@gmail.com", + "url": "github.com/qix-" + } + ], + "name": "ansi-regex", + "repository": { + "type": "git", + "url": "git+https://github.com/chalk/ansi-regex.git" + }, + "scripts": { + "test": "xo && ava --verbose", + "view-supported": "node fixtures/view-codes.js" + }, + "version": "2.1.1", + "xo": { + "rules": { + "guard-for-in": 0, + "no-loop-func": 0 + } + } +} diff --git a/user/themes/goku/node_modules/ansi-regex/readme.md b/user/themes/goku/node_modules/ansi-regex/readme.md new file mode 100644 index 00000000..6a928edf --- /dev/null +++ b/user/themes/goku/node_modules/ansi-regex/readme.md @@ -0,0 +1,39 @@ +# ansi-regex [![Build Status](https://travis-ci.org/chalk/ansi-regex.svg?branch=master)](https://travis-ci.org/chalk/ansi-regex) + +> Regular expression for matching [ANSI escape codes](http://en.wikipedia.org/wiki/ANSI_escape_code) + + +## Install + +``` +$ npm install --save ansi-regex +``` + + +## Usage + +```js +const ansiRegex = require('ansi-regex'); + +ansiRegex().test('\u001b[4mcake\u001b[0m'); +//=> true + +ansiRegex().test('cake'); +//=> false + +'\u001b[4mcake\u001b[0m'.match(ansiRegex()); +//=> ['\u001b[4m', '\u001b[0m'] +``` + +## FAQ + +### Why do you test for codes not in the ECMA 48 standard? + +Some of the codes we run as a test are codes that we acquired finding various lists of non-standard or manufacturer specific codes. If I recall correctly, we test for both standard and non-standard codes, as most of them follow the same or similar format and can be safely matched in strings without the risk of removing actual string content. There are a few non-standard control codes that do not follow the traditional format (i.e. they end in numbers) thus forcing us to exclude them from the test because we cannot reliably match them. + +On the historical side, those ECMA standards were established in the early 90's whereas the VT100, for example, was designed in the mid/late 70's. At that point in time, control codes were still pretty ungoverned and engineers used them for a multitude of things, namely to activate hardware ports that may have been proprietary. Somewhere else you see a similar 'anarchy' of codes is in the x86 architecture for processors; there are a ton of "interrupts" that can mean different things on certain brands of processors, most of which have been phased out. + + +## License + +MIT © [Sindre Sorhus](http://sindresorhus.com) diff --git a/user/themes/goku/node_modules/ansi-styles/index.js b/user/themes/goku/node_modules/ansi-styles/index.js new file mode 100644 index 00000000..78945278 --- /dev/null +++ b/user/themes/goku/node_modules/ansi-styles/index.js @@ -0,0 +1,65 @@ +'use strict'; + +function assembleStyles () { + var styles = { + modifiers: { + reset: [0, 0], + bold: [1, 22], // 21 isn't widely supported and 22 does the same thing + dim: [2, 22], + italic: [3, 23], + underline: [4, 24], + inverse: [7, 27], + hidden: [8, 28], + strikethrough: [9, 29] + }, + colors: { + black: [30, 39], + red: [31, 39], + green: [32, 39], + yellow: [33, 39], + blue: [34, 39], + magenta: [35, 39], + cyan: [36, 39], + white: [37, 39], + gray: [90, 39] + }, + bgColors: { + bgBlack: [40, 49], + bgRed: [41, 49], + bgGreen: [42, 49], + bgYellow: [43, 49], + bgBlue: [44, 49], + bgMagenta: [45, 49], + bgCyan: [46, 49], + bgWhite: [47, 49] + } + }; + + // fix humans + styles.colors.grey = styles.colors.gray; + + Object.keys(styles).forEach(function (groupName) { + var group = styles[groupName]; + + Object.keys(group).forEach(function (styleName) { + var style = group[styleName]; + + styles[styleName] = group[styleName] = { + open: '\u001b[' + style[0] + 'm', + close: '\u001b[' + style[1] + 'm' + }; + }); + + Object.defineProperty(styles, groupName, { + value: group, + enumerable: false + }); + }); + + return styles; +} + +Object.defineProperty(module, 'exports', { + enumerable: true, + get: assembleStyles +}); diff --git a/user/themes/goku/node_modules/ansi-styles/license b/user/themes/goku/node_modules/ansi-styles/license new file mode 100644 index 00000000..654d0bfe --- /dev/null +++ b/user/themes/goku/node_modules/ansi-styles/license @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) Sindre Sorhus (sindresorhus.com) + +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. diff --git a/user/themes/goku/node_modules/ansi-styles/package.json b/user/themes/goku/node_modules/ansi-styles/package.json new file mode 100644 index 00000000..bdeb00b2 --- /dev/null +++ b/user/themes/goku/node_modules/ansi-styles/package.json @@ -0,0 +1,90 @@ +{ + "_from": "ansi-styles@^2.2.1", + "_id": "ansi-styles@2.2.1", + "_inBundle": false, + "_integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "_location": "/ansi-styles", + "_phantomChildren": {}, + "_requested": { + "type": "range", + "registry": true, + "raw": "ansi-styles@^2.2.1", + "name": "ansi-styles", + "escapedName": "ansi-styles", + "rawSpec": "^2.2.1", + "saveSpec": null, + "fetchSpec": "^2.2.1" + }, + "_requiredBy": [ + "/chalk" + ], + "_resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "_shasum": "b432dd3358b634cf75e1e4664368240533c1ddbe", + "_spec": "ansi-styles@^2.2.1", + "_where": "/srv/http/berryfarmprojects.org.uk/stay-grav/user/themes/goku/node_modules/chalk", + "author": { + "name": "Sindre Sorhus", + "email": "sindresorhus@gmail.com", + "url": "sindresorhus.com" + }, + "bugs": { + "url": "https://github.com/chalk/ansi-styles/issues" + }, + "bundleDependencies": false, + "deprecated": false, + "description": "ANSI escape codes for styling strings in the terminal", + "devDependencies": { + "mocha": "*" + }, + "engines": { + "node": ">=0.10.0" + }, + "files": [ + "index.js" + ], + "homepage": "https://github.com/chalk/ansi-styles#readme", + "keywords": [ + "ansi", + "styles", + "color", + "colour", + "colors", + "terminal", + "console", + "cli", + "string", + "tty", + "escape", + "formatting", + "rgb", + "256", + "shell", + "xterm", + "log", + "logging", + "command-line", + "text" + ], + "license": "MIT", + "maintainers": [ + { + "name": "Sindre Sorhus", + "email": "sindresorhus@gmail.com", + "url": "sindresorhus.com" + }, + { + "name": "Joshua Appelman", + "email": "jappelman@xebia.com", + "url": "jbnicolai.com" + } + ], + "name": "ansi-styles", + "repository": { + "type": "git", + "url": "git+https://github.com/chalk/ansi-styles.git" + }, + "scripts": { + "test": "mocha" + }, + "version": "2.2.1" +} diff --git a/user/themes/goku/node_modules/ansi-styles/readme.md b/user/themes/goku/node_modules/ansi-styles/readme.md new file mode 100644 index 00000000..3f933f61 --- /dev/null +++ b/user/themes/goku/node_modules/ansi-styles/readme.md @@ -0,0 +1,86 @@ +# ansi-styles [![Build Status](https://travis-ci.org/chalk/ansi-styles.svg?branch=master)](https://travis-ci.org/chalk/ansi-styles) + +> [ANSI escape codes](http://en.wikipedia.org/wiki/ANSI_escape_code#Colors_and_Styles) for styling strings in the terminal + +You probably want the higher-level [chalk](https://github.com/chalk/chalk) module for styling your strings. + +![](screenshot.png) + + +## Install + +``` +$ npm install --save ansi-styles +``` + + +## Usage + +```js +var ansi = require('ansi-styles'); + +console.log(ansi.green.open + 'Hello world!' + ansi.green.close); +``` + + +## API + +Each style has an `open` and `close` property. + + +## Styles + +### Modifiers + +- `reset` +- `bold` +- `dim` +- `italic` *(not widely supported)* +- `underline` +- `inverse` +- `hidden` +- `strikethrough` *(not widely supported)* + +### Colors + +- `black` +- `red` +- `green` +- `yellow` +- `blue` +- `magenta` +- `cyan` +- `white` +- `gray` + +### Background colors + +- `bgBlack` +- `bgRed` +- `bgGreen` +- `bgYellow` +- `bgBlue` +- `bgMagenta` +- `bgCyan` +- `bgWhite` + + +## Advanced usage + +By default you get a map of styles, but the styles are also available as groups. They are non-enumerable so they don't show up unless you access them explicitly. This makes it easier to expose only a subset in a higher-level module. + +- `ansi.modifiers` +- `ansi.colors` +- `ansi.bgColors` + + +###### Example + +```js +console.log(ansi.colors.green.open); +``` + + +## License + +MIT © [Sindre Sorhus](http://sindresorhus.com) diff --git a/user/themes/goku/node_modules/aproba/LICENSE b/user/themes/goku/node_modules/aproba/LICENSE new file mode 100644 index 00000000..f4be44d8 --- /dev/null +++ b/user/themes/goku/node_modules/aproba/LICENSE @@ -0,0 +1,14 @@ +Copyright (c) 2015, Rebecca Turner + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + diff --git a/user/themes/goku/node_modules/aproba/README.md b/user/themes/goku/node_modules/aproba/README.md new file mode 100644 index 00000000..0bfc594c --- /dev/null +++ b/user/themes/goku/node_modules/aproba/README.md @@ -0,0 +1,94 @@ +aproba +====== + +A ridiculously light-weight function argument validator + +``` +var validate = require("aproba") + +function myfunc(a, b, c) { + // `a` must be a string, `b` a number, `c` a function + validate('SNF', arguments) // [a,b,c] is also valid +} + +myfunc('test', 23, function () {}) // ok +myfunc(123, 23, function () {}) // type error +myfunc('test', 23) // missing arg error +myfunc('test', 23, function () {}, true) // too many args error + +``` + +Valid types are: + +| type | description +| :--: | :---------- +| * | matches any type +| A | `Array.isArray` OR an `arguments` object +| S | typeof == string +| N | typeof == number +| F | typeof == function +| O | typeof == object and not type A and not type E +| B | typeof == boolean +| E | `instanceof Error` OR `null` **(special: see below)** +| Z | == `null` + +Validation failures throw one of three exception types, distinguished by a +`code` property of `EMISSINGARG`, `EINVALIDTYPE` or `ETOOMANYARGS`. + +If you pass in an invalid type then it will throw with a code of +`EUNKNOWNTYPE`. + +If an **error** argument is found and is not null then the remaining +arguments are optional. That is, if you say `ESO` then that's like using a +non-magical `E` in: `E|ESO|ZSO`. + +### But I have optional arguments?! + +You can provide more than one signature by separating them with pipes `|`. +If any signature matches the arguments then they'll be considered valid. + +So for example, say you wanted to write a signature for +`fs.createWriteStream`. The docs for it describe it thusly: + +``` +fs.createWriteStream(path[, options]) +``` + +This would be a signature of `SO|S`. That is, a string and and object, or +just a string. + +Now, if you read the full `fs` docs, you'll see that actually path can ALSO +be a buffer. And options can be a string, that is: +``` +path | +options | +``` + +To reproduce this you have to fully enumerate all of the possible +combinations and that implies a signature of `SO|SS|OO|OS|S|O`. The +awkwardness is a feature: It reminds you of the complexity you're adding to +your API when you do this sort of thing. + + +### Browser support + +This has no dependencies and should work in browsers, though you'll have +noisier stack traces. + +### Why this exists + +I wanted a very simple argument validator. It needed to do two things: + +1. Be more concise and easier to use than assertions + +2. Not encourage an infinite bikeshed of DSLs + +This is why types are specified by a single character and there's no such +thing as an optional argument. + +This is not intended to validate user data. This is specifically about +asserting the interface of your functions. + +If you need greater validation, I encourage you to write them by hand or +look elsewhere. + diff --git a/user/themes/goku/node_modules/aproba/index.js b/user/themes/goku/node_modules/aproba/index.js new file mode 100644 index 00000000..6f3f797c --- /dev/null +++ b/user/themes/goku/node_modules/aproba/index.js @@ -0,0 +1,105 @@ +'use strict' + +function isArguments (thingy) { + return thingy != null && typeof thingy === 'object' && thingy.hasOwnProperty('callee') +} + +var types = { + '*': {label: 'any', check: function () { return true }}, + A: {label: 'array', check: function (thingy) { return Array.isArray(thingy) || isArguments(thingy) }}, + S: {label: 'string', check: function (thingy) { return typeof thingy === 'string' }}, + N: {label: 'number', check: function (thingy) { return typeof thingy === 'number' }}, + F: {label: 'function', check: function (thingy) { return typeof thingy === 'function' }}, + O: {label: 'object', check: function (thingy) { return typeof thingy === 'object' && thingy != null && !types.A.check(thingy) && !types.E.check(thingy) }}, + B: {label: 'boolean', check: function (thingy) { return typeof thingy === 'boolean' }}, + E: {label: 'error', check: function (thingy) { return thingy instanceof Error }}, + Z: {label: 'null', check: function (thingy) { return thingy == null }} +} + +function addSchema (schema, arity) { + var group = arity[schema.length] = arity[schema.length] || [] + if (group.indexOf(schema) === -1) group.push(schema) +} + +var validate = module.exports = function (rawSchemas, args) { + if (arguments.length !== 2) throw wrongNumberOfArgs(['SA'], arguments.length) + if (!rawSchemas) throw missingRequiredArg(0, 'rawSchemas') + if (!args) throw missingRequiredArg(1, 'args') + if (!types.S.check(rawSchemas)) throw invalidType(0, ['string'], rawSchemas) + if (!types.A.check(args)) throw invalidType(1, ['array'], args) + var schemas = rawSchemas.split('|') + var arity = {} + + schemas.forEach(function (schema) { + for (var ii = 0; ii < schema.length; ++ii) { + var type = schema[ii] + if (!types[type]) throw unknownType(ii, type) + } + if (/E.*E/.test(schema)) throw moreThanOneError(schema) + addSchema(schema, arity) + if (/E/.test(schema)) { + addSchema(schema.replace(/E.*$/, 'E'), arity) + addSchema(schema.replace(/E/, 'Z'), arity) + if (schema.length === 1) addSchema('', arity) + } + }) + var matching = arity[args.length] + if (!matching) { + throw wrongNumberOfArgs(Object.keys(arity), args.length) + } + for (var ii = 0; ii < args.length; ++ii) { + var newMatching = matching.filter(function (schema) { + var type = schema[ii] + var typeCheck = types[type].check + return typeCheck(args[ii]) + }) + if (!newMatching.length) { + var labels = matching.map(function (schema) { + return types[schema[ii]].label + }).filter(function (schema) { return schema != null }) + throw invalidType(ii, labels, args[ii]) + } + matching = newMatching + } +} + +function missingRequiredArg (num) { + return newException('EMISSINGARG', 'Missing required argument #' + (num + 1)) +} + +function unknownType (num, type) { + return newException('EUNKNOWNTYPE', 'Unknown type ' + type + ' in argument #' + (num + 1)) +} + +function invalidType (num, expectedTypes, value) { + var valueType + Object.keys(types).forEach(function (typeCode) { + if (types[typeCode].check(value)) valueType = types[typeCode].label + }) + return newException('EINVALIDTYPE', 'Argument #' + (num + 1) + ': Expected ' + + englishList(expectedTypes) + ' but got ' + valueType) +} + +function englishList (list) { + return list.join(', ').replace(/, ([^,]+)$/, ' or $1') +} + +function wrongNumberOfArgs (expected, got) { + var english = englishList(expected) + var args = expected.every(function (ex) { return ex.length === 1 }) + ? 'argument' + : 'arguments' + return newException('EWRONGARGCOUNT', 'Expected ' + english + ' ' + args + ' but got ' + got) +} + +function moreThanOneError (schema) { + return newException('ETOOMANYERRORTYPES', + 'Only one error type per argument signature is allowed, more than one found in "' + schema + '"') +} + +function newException (code, msg) { + var e = new Error(msg) + e.code = code + if (Error.captureStackTrace) Error.captureStackTrace(e, validate) + return e +} diff --git a/user/themes/goku/node_modules/aproba/package.json b/user/themes/goku/node_modules/aproba/package.json new file mode 100644 index 00000000..2ead7b61 --- /dev/null +++ b/user/themes/goku/node_modules/aproba/package.json @@ -0,0 +1,62 @@ +{ + "_from": "aproba@^1.0.3", + "_id": "aproba@1.2.0", + "_inBundle": false, + "_integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", + "_location": "/aproba", + "_phantomChildren": {}, + "_requested": { + "type": "range", + "registry": true, + "raw": "aproba@^1.0.3", + "name": "aproba", + "escapedName": "aproba", + "rawSpec": "^1.0.3", + "saveSpec": null, + "fetchSpec": "^1.0.3" + }, + "_requiredBy": [ + "/gauge" + ], + "_resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "_shasum": "6802e6264efd18c790a1b0d517f0f2627bf2c94a", + "_spec": "aproba@^1.0.3", + "_where": "/srv/http/berryfarmprojects.org.uk/stay-grav/user/themes/goku/node_modules/gauge", + "author": { + "name": "Rebecca Turner", + "email": "me@re-becca.org" + }, + "bugs": { + "url": "https://github.com/iarna/aproba/issues" + }, + "bundleDependencies": false, + "dependencies": {}, + "deprecated": false, + "description": "A ridiculously light-weight argument validator (now browser friendly)", + "devDependencies": { + "standard": "^10.0.3", + "tap": "^10.0.2" + }, + "directories": { + "test": "test" + }, + "files": [ + "index.js" + ], + "homepage": "https://github.com/iarna/aproba", + "keywords": [ + "argument", + "validate" + ], + "license": "ISC", + "main": "index.js", + "name": "aproba", + "repository": { + "type": "git", + "url": "git+https://github.com/iarna/aproba.git" + }, + "scripts": { + "test": "standard && tap -j3 test/*.js" + }, + "version": "1.2.0" +} diff --git a/user/themes/goku/node_modules/are-we-there-yet/CHANGES.md b/user/themes/goku/node_modules/are-we-there-yet/CHANGES.md new file mode 100644 index 00000000..21f3b1c1 --- /dev/null +++ b/user/themes/goku/node_modules/are-we-there-yet/CHANGES.md @@ -0,0 +1,37 @@ +Hi, figured we could actually use a changelog now: + +## 1.1.5 2018-05-24 + +* [#92](https://github.com/iarna/are-we-there-yet/pull/92) Fix bug where + `finish` would throw errors when including `TrackerStream` objects in + `TrackerGroup` collections. (@brianloveswords) + +## 1.1.4 2017-04-21 + +* Fix typo in package.json + +## 1.1.3 2017-04-21 + +* Improve documentation and limit files included in the distribution. + +## 1.1.2 2016-03-15 + +* Add tracker group cycle detection and tests for it + +## 1.1.1 2016-01-29 + +* Fix a typo in stream completion tracker + +## 1.1.0 2016-01-29 + +* Rewrote completion percent computation to be low impact– no more walking a + tree of completion groups every time we need this info. Previously, with + medium sized tree of completion groups, even a relatively modest number of + calls to the top level `completed()` method would result in absurd numbers + of calls overall as it walked down the tree. We now, instead, keep track as + we bubble up changes, so the computation is limited to when data changes and + to the depth of that one branch, instead of _every_ node. (Plus, we were already + incurring _this_ cost, since we already bubbled out changes.) +* Moved different tracker types out to their own files. +* Made tests test for TOO MANY events too. +* Standarized the source code formatting diff --git a/user/themes/goku/node_modules/are-we-there-yet/LICENSE b/user/themes/goku/node_modules/are-we-there-yet/LICENSE new file mode 100644 index 00000000..af458806 --- /dev/null +++ b/user/themes/goku/node_modules/are-we-there-yet/LICENSE @@ -0,0 +1,5 @@ +Copyright (c) 2015, Rebecca Turner + +Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/user/themes/goku/node_modules/are-we-there-yet/README.md b/user/themes/goku/node_modules/are-we-there-yet/README.md new file mode 100644 index 00000000..7e2b42d8 --- /dev/null +++ b/user/themes/goku/node_modules/are-we-there-yet/README.md @@ -0,0 +1,195 @@ +are-we-there-yet +---------------- + +Track complex hiearchies of asynchronous task completion statuses. This is +intended to give you a way of recording and reporting the progress of the big +recursive fan-out and gather type workflows that are so common in async. + +What you do with this completion data is up to you, but the most common use case is to +feed it to one of the many progress bar modules. + +Most progress bar modules include a rudamentary version of this, but my +needs were more complex. + +Usage +===== + +```javascript +var TrackerGroup = require("are-we-there-yet").TrackerGroup + +var top = new TrackerGroup("program") + +var single = top.newItem("one thing", 100) +single.completeWork(20) + +console.log(top.completed()) // 0.2 + +fs.stat("file", function(er, stat) { + if (er) throw er + var stream = top.newStream("file", stat.size) + console.log(top.completed()) // now 0.1 as single is 50% of the job and is 20% complete + // and 50% * 20% == 10% + fs.createReadStream("file").pipe(stream).on("data", function (chunk) { + // do stuff with chunk + }) + top.on("change", function (name) { + // called each time a chunk is read from "file" + // top.completed() will start at 0.1 and fill up to 0.6 as the file is read + }) +}) +``` + +Shared Methods +============== + +* var completed = tracker.completed() + +Implemented in: `Tracker`, `TrackerGroup`, `TrackerStream` + +Returns the ratio of completed work to work to be done. Range of 0 to 1. + +* tracker.finish() + +Implemented in: `Tracker`, `TrackerGroup` + +Marks the tracker as completed. With a TrackerGroup this marks all of its +components as completed. + +Marks all of the components of this tracker as finished, which in turn means +that `tracker.completed()` for this will now be 1. + +This will result in one or more `change` events being emitted. + +Events +====== + +All tracker objects emit `change` events with the following arguments: + +``` +function (name, completed, tracker) +``` + +`name` is the name of the tracker that originally emitted the event, +or if it didn't have one, the first containing tracker group that had one. + +`completed` is the percent complete (as returned by `tracker.completed()` method). + +`tracker` is the tracker object that you are listening for events on. + +TrackerGroup +============ + +* var tracker = new TrackerGroup(**name**) + + * **name** *(optional)* - The name of this tracker group, used in change + notifications if the component updating didn't have a name. Defaults to undefined. + +Creates a new empty tracker aggregation group. These are trackers whose +completion status is determined by the completion status of other trackers. + +* tracker.addUnit(**otherTracker**, **weight**) + + * **otherTracker** - Any of the other are-we-there-yet tracker objects + * **weight** *(optional)* - The weight to give the tracker, defaults to 1. + +Adds the **otherTracker** to this aggregation group. The weight determines +how long you expect this tracker to take to complete in proportion to other +units. So for instance, if you add one tracker with a weight of 1 and +another with a weight of 2, you're saying the second will take twice as long +to complete as the first. As such, the first will account for 33% of the +completion of this tracker and the second will account for the other 67%. + +Returns **otherTracker**. + +* var subGroup = tracker.newGroup(**name**, **weight**) + +The above is exactly equivalent to: + +```javascript + var subGroup = tracker.addUnit(new TrackerGroup(name), weight) +``` + +* var subItem = tracker.newItem(**name**, **todo**, **weight**) + +The above is exactly equivalent to: + +```javascript + var subItem = tracker.addUnit(new Tracker(name, todo), weight) +``` + +* var subStream = tracker.newStream(**name**, **todo**, **weight**) + +The above is exactly equivalent to: + +```javascript + var subStream = tracker.addUnit(new TrackerStream(name, todo), weight) +``` + +* console.log( tracker.debug() ) + +Returns a tree showing the completion of this tracker group and all of its +children, including recursively entering all of the children. + +Tracker +======= + +* var tracker = new Tracker(**name**, **todo**) + + * **name** *(optional)* The name of this counter to report in change + events. Defaults to undefined. + * **todo** *(optional)* The amount of work todo (a number). Defaults to 0. + +Ordinarily these are constructed as a part of a tracker group (via +`newItem`). + +* var completed = tracker.completed() + +Returns the ratio of completed work to work to be done. Range of 0 to 1. If +total work to be done is 0 then it will return 0. + +* tracker.addWork(**todo**) + + * **todo** A number to add to the amount of work to be done. + +Increases the amount of work to be done, thus decreasing the completion +percentage. Triggers a `change` event. + +* tracker.completeWork(**completed**) + + * **completed** A number to add to the work complete + +Increase the amount of work complete, thus increasing the completion percentage. +Will never increase the work completed past the amount of work todo. That is, +percentages > 100% are not allowed. Triggers a `change` event. + +* tracker.finish() + +Marks this tracker as finished, tracker.completed() will now be 1. Triggers +a `change` event. + +TrackerStream +============= + +* var tracker = new TrackerStream(**name**, **size**, **options**) + + * **name** *(optional)* The name of this counter to report in change + events. Defaults to undefined. + * **size** *(optional)* The number of bytes being sent through this stream. + * **options** *(optional)* A hash of stream options + +The tracker stream object is a pass through stream that updates an internal +tracker object each time a block passes through. It's intended to track +downloads, file extraction and other related activities. You use it by piping +your data source into it and then using it as your data source. + +If your data has a length attribute then that's used as the amount of work +completed when the chunk is passed through. If it does not (eg, object +streams) then each chunk counts as completing 1 unit of work, so your size +should be the total number of objects being streamed. + +* tracker.addWork(**todo**) + + * **todo** Increase the expected overall size by **todo** bytes. + +Increases the amount of work to be done, thus decreasing the completion +percentage. Triggers a `change` event. diff --git a/user/themes/goku/node_modules/are-we-there-yet/index.js b/user/themes/goku/node_modules/are-we-there-yet/index.js new file mode 100644 index 00000000..57d8743f --- /dev/null +++ b/user/themes/goku/node_modules/are-we-there-yet/index.js @@ -0,0 +1,4 @@ +'use strict' +exports.TrackerGroup = require('./tracker-group.js') +exports.Tracker = require('./tracker.js') +exports.TrackerStream = require('./tracker-stream.js') diff --git a/user/themes/goku/node_modules/are-we-there-yet/package.json b/user/themes/goku/node_modules/are-we-there-yet/package.json new file mode 100644 index 00000000..87dc5c94 --- /dev/null +++ b/user/themes/goku/node_modules/are-we-there-yet/package.json @@ -0,0 +1,63 @@ +{ + "_from": "are-we-there-yet@~1.1.2", + "_id": "are-we-there-yet@1.1.5", + "_inBundle": false, + "_integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", + "_location": "/are-we-there-yet", + "_phantomChildren": {}, + "_requested": { + "type": "range", + "registry": true, + "raw": "are-we-there-yet@~1.1.2", + "name": "are-we-there-yet", + "escapedName": "are-we-there-yet", + "rawSpec": "~1.1.2", + "saveSpec": null, + "fetchSpec": "~1.1.2" + }, + "_requiredBy": [ + "/npmlog" + ], + "_resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", + "_shasum": "4b35c2944f062a8bfcda66410760350fe9ddfc21", + "_spec": "are-we-there-yet@~1.1.2", + "_where": "/srv/http/berryfarmprojects.org.uk/stay-grav/user/themes/goku/node_modules/npmlog", + "author": { + "name": "Rebecca Turner", + "url": "http://re-becca.org" + }, + "bugs": { + "url": "https://github.com/iarna/are-we-there-yet/issues" + }, + "bundleDependencies": false, + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + }, + "deprecated": false, + "description": "Keep track of the overall completion of many disparate processes", + "devDependencies": { + "standard": "^11.0.1", + "tap": "^12.0.1" + }, + "files": [ + "index.js", + "tracker-base.js", + "tracker-group.js", + "tracker-stream.js", + "tracker.js", + "CHANGES.md" + ], + "homepage": "https://github.com/iarna/are-we-there-yet", + "license": "ISC", + "main": "index.js", + "name": "are-we-there-yet", + "repository": { + "type": "git", + "url": "git+https://github.com/iarna/are-we-there-yet.git" + }, + "scripts": { + "test": "standard && tap test/*.js" + }, + "version": "1.1.5" +} diff --git a/user/themes/goku/node_modules/are-we-there-yet/tracker-base.js b/user/themes/goku/node_modules/are-we-there-yet/tracker-base.js new file mode 100644 index 00000000..6f436875 --- /dev/null +++ b/user/themes/goku/node_modules/are-we-there-yet/tracker-base.js @@ -0,0 +1,11 @@ +'use strict' +var EventEmitter = require('events').EventEmitter +var util = require('util') + +var trackerId = 0 +var TrackerBase = module.exports = function (name) { + EventEmitter.call(this) + this.id = ++trackerId + this.name = name +} +util.inherits(TrackerBase, EventEmitter) diff --git a/user/themes/goku/node_modules/are-we-there-yet/tracker-group.js b/user/themes/goku/node_modules/are-we-there-yet/tracker-group.js new file mode 100644 index 00000000..9759e122 --- /dev/null +++ b/user/themes/goku/node_modules/are-we-there-yet/tracker-group.js @@ -0,0 +1,107 @@ +'use strict' +var util = require('util') +var TrackerBase = require('./tracker-base.js') +var Tracker = require('./tracker.js') +var TrackerStream = require('./tracker-stream.js') + +var TrackerGroup = module.exports = function (name) { + TrackerBase.call(this, name) + this.parentGroup = null + this.trackers = [] + this.completion = {} + this.weight = {} + this.totalWeight = 0 + this.finished = false + this.bubbleChange = bubbleChange(this) +} +util.inherits(TrackerGroup, TrackerBase) + +function bubbleChange (trackerGroup) { + return function (name, completed, tracker) { + trackerGroup.completion[tracker.id] = completed + if (trackerGroup.finished) return + trackerGroup.emit('change', name || trackerGroup.name, trackerGroup.completed(), trackerGroup) + } +} + +TrackerGroup.prototype.nameInTree = function () { + var names = [] + var from = this + while (from) { + names.unshift(from.name) + from = from.parentGroup + } + return names.join('/') +} + +TrackerGroup.prototype.addUnit = function (unit, weight) { + if (unit.addUnit) { + var toTest = this + while (toTest) { + if (unit === toTest) { + throw new Error( + 'Attempted to add tracker group ' + + unit.name + ' to tree that already includes it ' + + this.nameInTree(this)) + } + toTest = toTest.parentGroup + } + unit.parentGroup = this + } + this.weight[unit.id] = weight || 1 + this.totalWeight += this.weight[unit.id] + this.trackers.push(unit) + this.completion[unit.id] = unit.completed() + unit.on('change', this.bubbleChange) + if (!this.finished) this.emit('change', unit.name, this.completion[unit.id], unit) + return unit +} + +TrackerGroup.prototype.completed = function () { + if (this.trackers.length === 0) return 0 + var valPerWeight = 1 / this.totalWeight + var completed = 0 + for (var ii = 0; ii < this.trackers.length; ii++) { + var trackerId = this.trackers[ii].id + completed += valPerWeight * this.weight[trackerId] * this.completion[trackerId] + } + return completed +} + +TrackerGroup.prototype.newGroup = function (name, weight) { + return this.addUnit(new TrackerGroup(name), weight) +} + +TrackerGroup.prototype.newItem = function (name, todo, weight) { + return this.addUnit(new Tracker(name, todo), weight) +} + +TrackerGroup.prototype.newStream = function (name, todo, weight) { + return this.addUnit(new TrackerStream(name, todo), weight) +} + +TrackerGroup.prototype.finish = function () { + this.finished = true + if (!this.trackers.length) this.addUnit(new Tracker(), 1, true) + for (var ii = 0; ii < this.trackers.length; ii++) { + var tracker = this.trackers[ii] + tracker.finish() + tracker.removeListener('change', this.bubbleChange) + } + this.emit('change', this.name, 1, this) +} + +var buffer = ' ' +TrackerGroup.prototype.debug = function (depth) { + depth = depth || 0 + var indent = depth ? buffer.substr(0, depth) : '' + var output = indent + (this.name || 'top') + ': ' + this.completed() + '\n' + this.trackers.forEach(function (tracker) { + if (tracker instanceof TrackerGroup) { + output += tracker.debug(depth + 1) + } else { + output += indent + ' ' + tracker.name + ': ' + tracker.completed() + '\n' + } + }) + return output +} diff --git a/user/themes/goku/node_modules/are-we-there-yet/tracker-stream.js b/user/themes/goku/node_modules/are-we-there-yet/tracker-stream.js new file mode 100644 index 00000000..e1cf8505 --- /dev/null +++ b/user/themes/goku/node_modules/are-we-there-yet/tracker-stream.js @@ -0,0 +1,36 @@ +'use strict' +var util = require('util') +var stream = require('readable-stream') +var delegate = require('delegates') +var Tracker = require('./tracker.js') + +var TrackerStream = module.exports = function (name, size, options) { + stream.Transform.call(this, options) + this.tracker = new Tracker(name, size) + this.name = name + this.id = this.tracker.id + this.tracker.on('change', delegateChange(this)) +} +util.inherits(TrackerStream, stream.Transform) + +function delegateChange (trackerStream) { + return function (name, completion, tracker) { + trackerStream.emit('change', name, completion, trackerStream) + } +} + +TrackerStream.prototype._transform = function (data, encoding, cb) { + this.tracker.completeWork(data.length ? data.length : 1) + this.push(data) + cb() +} + +TrackerStream.prototype._flush = function (cb) { + this.tracker.finish() + cb() +} + +delegate(TrackerStream.prototype, 'tracker') + .method('completed') + .method('addWork') + .method('finish') diff --git a/user/themes/goku/node_modules/are-we-there-yet/tracker.js b/user/themes/goku/node_modules/are-we-there-yet/tracker.js new file mode 100644 index 00000000..68c2339b --- /dev/null +++ b/user/themes/goku/node_modules/are-we-there-yet/tracker.js @@ -0,0 +1,30 @@ +'use strict' +var util = require('util') +var TrackerBase = require('./tracker-base.js') + +var Tracker = module.exports = function (name, todo) { + TrackerBase.call(this, name) + this.workDone = 0 + this.workTodo = todo || 0 +} +util.inherits(Tracker, TrackerBase) + +Tracker.prototype.completed = function () { + return this.workTodo === 0 ? 0 : this.workDone / this.workTodo +} + +Tracker.prototype.addWork = function (work) { + this.workTodo += work + this.emit('change', this.name, this.completed(), this) +} + +Tracker.prototype.completeWork = function (work) { + this.workDone += work + if (this.workDone > this.workTodo) this.workDone = this.workTodo + this.emit('change', this.name, this.completed(), this) +} + +Tracker.prototype.finish = function () { + this.workTodo = this.workDone = 1 + this.emit('change', this.name, 1, this) +} diff --git a/user/themes/goku/node_modules/array-find-index/index.js b/user/themes/goku/node_modules/array-find-index/index.js new file mode 100644 index 00000000..e2dcd9a0 --- /dev/null +++ b/user/themes/goku/node_modules/array-find-index/index.js @@ -0,0 +1,25 @@ +'use strict'; +module.exports = function (arr, predicate, ctx) { + if (typeof Array.prototype.findIndex === 'function') { + return arr.findIndex(predicate, ctx); + } + + if (typeof predicate !== 'function') { + throw new TypeError('predicate must be a function'); + } + + var list = Object(arr); + var len = list.length; + + if (len === 0) { + return -1; + } + + for (var i = 0; i < len; i++) { + if (predicate.call(ctx, list[i], i, list)) { + return i; + } + } + + return -1; +}; diff --git a/user/themes/goku/node_modules/array-find-index/license b/user/themes/goku/node_modules/array-find-index/license new file mode 100644 index 00000000..654d0bfe --- /dev/null +++ b/user/themes/goku/node_modules/array-find-index/license @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) Sindre Sorhus (sindresorhus.com) + +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. diff --git a/user/themes/goku/node_modules/array-find-index/package.json b/user/themes/goku/node_modules/array-find-index/package.json new file mode 100644 index 00000000..afbbb79e --- /dev/null +++ b/user/themes/goku/node_modules/array-find-index/package.json @@ -0,0 +1,67 @@ +{ + "_from": "array-find-index@^1.0.1", + "_id": "array-find-index@1.0.2", + "_inBundle": false, + "_integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=", + "_location": "/array-find-index", + "_phantomChildren": {}, + "_requested": { + "type": "range", + "registry": true, + "raw": "array-find-index@^1.0.1", + "name": "array-find-index", + "escapedName": "array-find-index", + "rawSpec": "^1.0.1", + "saveSpec": null, + "fetchSpec": "^1.0.1" + }, + "_requiredBy": [ + "/currently-unhandled" + ], + "_resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", + "_shasum": "df010aa1287e164bbda6f9723b0a96a1ec4187a1", + "_spec": "array-find-index@^1.0.1", + "_where": "/srv/http/berryfarmprojects.org.uk/stay-grav/user/themes/goku/node_modules/currently-unhandled", + "author": { + "name": "Sindre Sorhus", + "email": "sindresorhus@gmail.com", + "url": "sindresorhus.com" + }, + "bugs": { + "url": "https://github.com/sindresorhus/array-find-index/issues" + }, + "bundleDependencies": false, + "deprecated": false, + "description": "ES2015 `Array#findIndex()` ponyfill", + "devDependencies": { + "ava": "*", + "xo": "*" + }, + "engines": { + "node": ">=0.10.0" + }, + "files": [ + "index.js" + ], + "homepage": "https://github.com/sindresorhus/array-find-index#readme", + "keywords": [ + "es2015", + "ponyfill", + "polyfill", + "shim", + "find", + "index", + "findindex", + "array" + ], + "license": "MIT", + "name": "array-find-index", + "repository": { + "type": "git", + "url": "git+https://github.com/sindresorhus/array-find-index.git" + }, + "scripts": { + "test": "xo && ava" + }, + "version": "1.0.2" +} diff --git a/user/themes/goku/node_modules/array-find-index/readme.md b/user/themes/goku/node_modules/array-find-index/readme.md new file mode 100644 index 00000000..31663411 --- /dev/null +++ b/user/themes/goku/node_modules/array-find-index/readme.md @@ -0,0 +1,30 @@ +# array-find-index [![Build Status](https://travis-ci.org/sindresorhus/array-find-index.svg?branch=master)](https://travis-ci.org/sindresorhus/array-find-index) + +> ES2015 [`Array#findIndex()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex) [ponyfill](https://ponyfill.com) + + +## Install + +``` +$ npm install --save array-find-index +``` + + +## Usage + +```js +const arrayFindIndex = require('array-find-index'); + +arrayFindIndex(['rainbow', 'unicorn', 'pony'], x => x === 'unicorn'); +//=> 1 +``` + + +## API + +Same as `Array#findIndex()`, but with the input array as the first argument. + + +## License + +MIT © [Sindre Sorhus](https://sindresorhus.com) diff --git a/user/themes/goku/node_modules/asn1/LICENSE b/user/themes/goku/node_modules/asn1/LICENSE new file mode 100644 index 00000000..9b5dcdb7 --- /dev/null +++ b/user/themes/goku/node_modules/asn1/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2011 Mark Cavage, All rights reserved. + +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 diff --git a/user/themes/goku/node_modules/asn1/README.md b/user/themes/goku/node_modules/asn1/README.md new file mode 100644 index 00000000..2208210a --- /dev/null +++ b/user/themes/goku/node_modules/asn1/README.md @@ -0,0 +1,50 @@ +node-asn1 is a library for encoding and decoding ASN.1 datatypes in pure JS. +Currently BER encoding is supported; at some point I'll likely have to do DER. + +## Usage + +Mostly, if you're *actually* needing to read and write ASN.1, you probably don't +need this readme to explain what and why. If you have no idea what ASN.1 is, +see this: ftp://ftp.rsa.com/pub/pkcs/ascii/layman.asc + +The source is pretty much self-explanatory, and has read/write methods for the +common types out there. + +### Decoding + +The following reads an ASN.1 sequence with a boolean. + + var Ber = require('asn1').Ber; + + var reader = new Ber.Reader(Buffer.from([0x30, 0x03, 0x01, 0x01, 0xff])); + + reader.readSequence(); + console.log('Sequence len: ' + reader.length); + if (reader.peek() === Ber.Boolean) + console.log(reader.readBoolean()); + +### Encoding + +The following generates the same payload as above. + + var Ber = require('asn1').Ber; + + var writer = new Ber.Writer(); + + writer.startSequence(); + writer.writeBoolean(true); + writer.endSequence(); + + console.log(writer.buffer); + +## Installation + + npm install asn1 + +## License + +MIT. + +## Bugs + +See . diff --git a/user/themes/goku/node_modules/asn1/lib/ber/errors.js b/user/themes/goku/node_modules/asn1/lib/ber/errors.js new file mode 100644 index 00000000..4557b8ae --- /dev/null +++ b/user/themes/goku/node_modules/asn1/lib/ber/errors.js @@ -0,0 +1,13 @@ +// Copyright 2011 Mark Cavage All rights reserved. + + +module.exports = { + + newInvalidAsn1Error: function (msg) { + var e = new Error(); + e.name = 'InvalidAsn1Error'; + e.message = msg || ''; + return e; + } + +}; diff --git a/user/themes/goku/node_modules/asn1/lib/ber/index.js b/user/themes/goku/node_modules/asn1/lib/ber/index.js new file mode 100644 index 00000000..387d1326 --- /dev/null +++ b/user/themes/goku/node_modules/asn1/lib/ber/index.js @@ -0,0 +1,27 @@ +// Copyright 2011 Mark Cavage All rights reserved. + +var errors = require('./errors'); +var types = require('./types'); + +var Reader = require('./reader'); +var Writer = require('./writer'); + + +// --- Exports + +module.exports = { + + Reader: Reader, + + Writer: Writer + +}; + +for (var t in types) { + if (types.hasOwnProperty(t)) + module.exports[t] = types[t]; +} +for (var e in errors) { + if (errors.hasOwnProperty(e)) + module.exports[e] = errors[e]; +} diff --git a/user/themes/goku/node_modules/asn1/lib/ber/reader.js b/user/themes/goku/node_modules/asn1/lib/ber/reader.js new file mode 100644 index 00000000..8a7e4ca0 --- /dev/null +++ b/user/themes/goku/node_modules/asn1/lib/ber/reader.js @@ -0,0 +1,262 @@ +// Copyright 2011 Mark Cavage All rights reserved. + +var assert = require('assert'); +var Buffer = require('safer-buffer').Buffer; + +var ASN1 = require('./types'); +var errors = require('./errors'); + + +// --- Globals + +var newInvalidAsn1Error = errors.newInvalidAsn1Error; + + + +// --- API + +function Reader(data) { + if (!data || !Buffer.isBuffer(data)) + throw new TypeError('data must be a node Buffer'); + + this._buf = data; + this._size = data.length; + + // These hold the "current" state + this._len = 0; + this._offset = 0; +} + +Object.defineProperty(Reader.prototype, 'length', { + enumerable: true, + get: function () { return (this._len); } +}); + +Object.defineProperty(Reader.prototype, 'offset', { + enumerable: true, + get: function () { return (this._offset); } +}); + +Object.defineProperty(Reader.prototype, 'remain', { + get: function () { return (this._size - this._offset); } +}); + +Object.defineProperty(Reader.prototype, 'buffer', { + get: function () { return (this._buf.slice(this._offset)); } +}); + + +/** + * Reads a single byte and advances offset; you can pass in `true` to make this + * a "peek" operation (i.e., get the byte, but don't advance the offset). + * + * @param {Boolean} peek true means don't move offset. + * @return {Number} the next byte, null if not enough data. + */ +Reader.prototype.readByte = function (peek) { + if (this._size - this._offset < 1) + return null; + + var b = this._buf[this._offset] & 0xff; + + if (!peek) + this._offset += 1; + + return b; +}; + + +Reader.prototype.peek = function () { + return this.readByte(true); +}; + + +/** + * Reads a (potentially) variable length off the BER buffer. This call is + * not really meant to be called directly, as callers have to manipulate + * the internal buffer afterwards. + * + * As a result of this call, you can call `Reader.length`, until the + * next thing called that does a readLength. + * + * @return {Number} the amount of offset to advance the buffer. + * @throws {InvalidAsn1Error} on bad ASN.1 + */ +Reader.prototype.readLength = function (offset) { + if (offset === undefined) + offset = this._offset; + + if (offset >= this._size) + return null; + + var lenB = this._buf[offset++] & 0xff; + if (lenB === null) + return null; + + if ((lenB & 0x80) === 0x80) { + lenB &= 0x7f; + + if (lenB === 0) + throw newInvalidAsn1Error('Indefinite length not supported'); + + if (lenB > 4) + throw newInvalidAsn1Error('encoding too long'); + + if (this._size - offset < lenB) + return null; + + this._len = 0; + for (var i = 0; i < lenB; i++) + this._len = (this._len << 8) + (this._buf[offset++] & 0xff); + + } else { + // Wasn't a variable length + this._len = lenB; + } + + return offset; +}; + + +/** + * Parses the next sequence in this BER buffer. + * + * To get the length of the sequence, call `Reader.length`. + * + * @return {Number} the sequence's tag. + */ +Reader.prototype.readSequence = function (tag) { + var seq = this.peek(); + if (seq === null) + return null; + if (tag !== undefined && tag !== seq) + throw newInvalidAsn1Error('Expected 0x' + tag.toString(16) + + ': got 0x' + seq.toString(16)); + + var o = this.readLength(this._offset + 1); // stored in `length` + if (o === null) + return null; + + this._offset = o; + return seq; +}; + + +Reader.prototype.readInt = function () { + return this._readTag(ASN1.Integer); +}; + + +Reader.prototype.readBoolean = function () { + return (this._readTag(ASN1.Boolean) === 0 ? false : true); +}; + + +Reader.prototype.readEnumeration = function () { + return this._readTag(ASN1.Enumeration); +}; + + +Reader.prototype.readString = function (tag, retbuf) { + if (!tag) + tag = ASN1.OctetString; + + var b = this.peek(); + if (b === null) + return null; + + if (b !== tag) + throw newInvalidAsn1Error('Expected 0x' + tag.toString(16) + + ': got 0x' + b.toString(16)); + + var o = this.readLength(this._offset + 1); // stored in `length` + + if (o === null) + return null; + + if (this.length > this._size - o) + return null; + + this._offset = o; + + if (this.length === 0) + return retbuf ? Buffer.alloc(0) : ''; + + var str = this._buf.slice(this._offset, this._offset + this.length); + this._offset += this.length; + + return retbuf ? str : str.toString('utf8'); +}; + +Reader.prototype.readOID = function (tag) { + if (!tag) + tag = ASN1.OID; + + var b = this.readString(tag, true); + if (b === null) + return null; + + var values = []; + var value = 0; + + for (var i = 0; i < b.length; i++) { + var byte = b[i] & 0xff; + + value <<= 7; + value += byte & 0x7f; + if ((byte & 0x80) === 0) { + values.push(value); + value = 0; + } + } + + value = values.shift(); + values.unshift(value % 40); + values.unshift((value / 40) >> 0); + + return values.join('.'); +}; + + +Reader.prototype._readTag = function (tag) { + assert.ok(tag !== undefined); + + var b = this.peek(); + + if (b === null) + return null; + + if (b !== tag) + throw newInvalidAsn1Error('Expected 0x' + tag.toString(16) + + ': got 0x' + b.toString(16)); + + var o = this.readLength(this._offset + 1); // stored in `length` + if (o === null) + return null; + + if (this.length > 4) + throw newInvalidAsn1Error('Integer too long: ' + this.length); + + if (this.length > this._size - o) + return null; + this._offset = o; + + var fb = this._buf[this._offset]; + var value = 0; + + for (var i = 0; i < this.length; i++) { + value <<= 8; + value |= (this._buf[this._offset++] & 0xff); + } + + if ((fb & 0x80) === 0x80 && i !== 4) + value -= (1 << (i * 8)); + + return value >> 0; +}; + + + +// --- Exported API + +module.exports = Reader; diff --git a/user/themes/goku/node_modules/asn1/lib/ber/types.js b/user/themes/goku/node_modules/asn1/lib/ber/types.js new file mode 100644 index 00000000..8aea0001 --- /dev/null +++ b/user/themes/goku/node_modules/asn1/lib/ber/types.js @@ -0,0 +1,36 @@ +// Copyright 2011 Mark Cavage All rights reserved. + + +module.exports = { + EOC: 0, + Boolean: 1, + Integer: 2, + BitString: 3, + OctetString: 4, + Null: 5, + OID: 6, + ObjectDescriptor: 7, + External: 8, + Real: 9, // float + Enumeration: 10, + PDV: 11, + Utf8String: 12, + RelativeOID: 13, + Sequence: 16, + Set: 17, + NumericString: 18, + PrintableString: 19, + T61String: 20, + VideotexString: 21, + IA5String: 22, + UTCTime: 23, + GeneralizedTime: 24, + GraphicString: 25, + VisibleString: 26, + GeneralString: 28, + UniversalString: 29, + CharacterString: 30, + BMPString: 31, + Constructor: 32, + Context: 128 +}; diff --git a/user/themes/goku/node_modules/asn1/lib/ber/writer.js b/user/themes/goku/node_modules/asn1/lib/ber/writer.js new file mode 100644 index 00000000..3515acf7 --- /dev/null +++ b/user/themes/goku/node_modules/asn1/lib/ber/writer.js @@ -0,0 +1,317 @@ +// Copyright 2011 Mark Cavage All rights reserved. + +var assert = require('assert'); +var Buffer = require('safer-buffer').Buffer; +var ASN1 = require('./types'); +var errors = require('./errors'); + + +// --- Globals + +var newInvalidAsn1Error = errors.newInvalidAsn1Error; + +var DEFAULT_OPTS = { + size: 1024, + growthFactor: 8 +}; + + +// --- Helpers + +function merge(from, to) { + assert.ok(from); + assert.equal(typeof (from), 'object'); + assert.ok(to); + assert.equal(typeof (to), 'object'); + + var keys = Object.getOwnPropertyNames(from); + keys.forEach(function (key) { + if (to[key]) + return; + + var value = Object.getOwnPropertyDescriptor(from, key); + Object.defineProperty(to, key, value); + }); + + return to; +} + + + +// --- API + +function Writer(options) { + options = merge(DEFAULT_OPTS, options || {}); + + this._buf = Buffer.alloc(options.size || 1024); + this._size = this._buf.length; + this._offset = 0; + this._options = options; + + // A list of offsets in the buffer where we need to insert + // sequence tag/len pairs. + this._seq = []; +} + +Object.defineProperty(Writer.prototype, 'buffer', { + get: function () { + if (this._seq.length) + throw newInvalidAsn1Error(this._seq.length + ' unended sequence(s)'); + + return (this._buf.slice(0, this._offset)); + } +}); + +Writer.prototype.writeByte = function (b) { + if (typeof (b) !== 'number') + throw new TypeError('argument must be a Number'); + + this._ensure(1); + this._buf[this._offset++] = b; +}; + + +Writer.prototype.writeInt = function (i, tag) { + if (typeof (i) !== 'number') + throw new TypeError('argument must be a Number'); + if (typeof (tag) !== 'number') + tag = ASN1.Integer; + + var sz = 4; + + while ((((i & 0xff800000) === 0) || ((i & 0xff800000) === 0xff800000 >> 0)) && + (sz > 1)) { + sz--; + i <<= 8; + } + + if (sz > 4) + throw newInvalidAsn1Error('BER ints cannot be > 0xffffffff'); + + this._ensure(2 + sz); + this._buf[this._offset++] = tag; + this._buf[this._offset++] = sz; + + while (sz-- > 0) { + this._buf[this._offset++] = ((i & 0xff000000) >>> 24); + i <<= 8; + } + +}; + + +Writer.prototype.writeNull = function () { + this.writeByte(ASN1.Null); + this.writeByte(0x00); +}; + + +Writer.prototype.writeEnumeration = function (i, tag) { + if (typeof (i) !== 'number') + throw new TypeError('argument must be a Number'); + if (typeof (tag) !== 'number') + tag = ASN1.Enumeration; + + return this.writeInt(i, tag); +}; + + +Writer.prototype.writeBoolean = function (b, tag) { + if (typeof (b) !== 'boolean') + throw new TypeError('argument must be a Boolean'); + if (typeof (tag) !== 'number') + tag = ASN1.Boolean; + + this._ensure(3); + this._buf[this._offset++] = tag; + this._buf[this._offset++] = 0x01; + this._buf[this._offset++] = b ? 0xff : 0x00; +}; + + +Writer.prototype.writeString = function (s, tag) { + if (typeof (s) !== 'string') + throw new TypeError('argument must be a string (was: ' + typeof (s) + ')'); + if (typeof (tag) !== 'number') + tag = ASN1.OctetString; + + var len = Buffer.byteLength(s); + this.writeByte(tag); + this.writeLength(len); + if (len) { + this._ensure(len); + this._buf.write(s, this._offset); + this._offset += len; + } +}; + + +Writer.prototype.writeBuffer = function (buf, tag) { + if (typeof (tag) !== 'number') + throw new TypeError('tag must be a number'); + if (!Buffer.isBuffer(buf)) + throw new TypeError('argument must be a buffer'); + + this.writeByte(tag); + this.writeLength(buf.length); + this._ensure(buf.length); + buf.copy(this._buf, this._offset, 0, buf.length); + this._offset += buf.length; +}; + + +Writer.prototype.writeStringArray = function (strings) { + if ((!strings instanceof Array)) + throw new TypeError('argument must be an Array[String]'); + + var self = this; + strings.forEach(function (s) { + self.writeString(s); + }); +}; + +// This is really to solve DER cases, but whatever for now +Writer.prototype.writeOID = function (s, tag) { + if (typeof (s) !== 'string') + throw new TypeError('argument must be a string'); + if (typeof (tag) !== 'number') + tag = ASN1.OID; + + if (!/^([0-9]+\.){3,}[0-9]+$/.test(s)) + throw new Error('argument is not a valid OID string'); + + function encodeOctet(bytes, octet) { + if (octet < 128) { + bytes.push(octet); + } else if (octet < 16384) { + bytes.push((octet >>> 7) | 0x80); + bytes.push(octet & 0x7F); + } else if (octet < 2097152) { + bytes.push((octet >>> 14) | 0x80); + bytes.push(((octet >>> 7) | 0x80) & 0xFF); + bytes.push(octet & 0x7F); + } else if (octet < 268435456) { + bytes.push((octet >>> 21) | 0x80); + bytes.push(((octet >>> 14) | 0x80) & 0xFF); + bytes.push(((octet >>> 7) | 0x80) & 0xFF); + bytes.push(octet & 0x7F); + } else { + bytes.push(((octet >>> 28) | 0x80) & 0xFF); + bytes.push(((octet >>> 21) | 0x80) & 0xFF); + bytes.push(((octet >>> 14) | 0x80) & 0xFF); + bytes.push(((octet >>> 7) | 0x80) & 0xFF); + bytes.push(octet & 0x7F); + } + } + + var tmp = s.split('.'); + var bytes = []; + bytes.push(parseInt(tmp[0], 10) * 40 + parseInt(tmp[1], 10)); + tmp.slice(2).forEach(function (b) { + encodeOctet(bytes, parseInt(b, 10)); + }); + + var self = this; + this._ensure(2 + bytes.length); + this.writeByte(tag); + this.writeLength(bytes.length); + bytes.forEach(function (b) { + self.writeByte(b); + }); +}; + + +Writer.prototype.writeLength = function (len) { + if (typeof (len) !== 'number') + throw new TypeError('argument must be a Number'); + + this._ensure(4); + + if (len <= 0x7f) { + this._buf[this._offset++] = len; + } else if (len <= 0xff) { + this._buf[this._offset++] = 0x81; + this._buf[this._offset++] = len; + } else if (len <= 0xffff) { + this._buf[this._offset++] = 0x82; + this._buf[this._offset++] = len >> 8; + this._buf[this._offset++] = len; + } else if (len <= 0xffffff) { + this._buf[this._offset++] = 0x83; + this._buf[this._offset++] = len >> 16; + this._buf[this._offset++] = len >> 8; + this._buf[this._offset++] = len; + } else { + throw newInvalidAsn1Error('Length too long (> 4 bytes)'); + } +}; + +Writer.prototype.startSequence = function (tag) { + if (typeof (tag) !== 'number') + tag = ASN1.Sequence | ASN1.Constructor; + + this.writeByte(tag); + this._seq.push(this._offset); + this._ensure(3); + this._offset += 3; +}; + + +Writer.prototype.endSequence = function () { + var seq = this._seq.pop(); + var start = seq + 3; + var len = this._offset - start; + + if (len <= 0x7f) { + this._shift(start, len, -2); + this._buf[seq] = len; + } else if (len <= 0xff) { + this._shift(start, len, -1); + this._buf[seq] = 0x81; + this._buf[seq + 1] = len; + } else if (len <= 0xffff) { + this._buf[seq] = 0x82; + this._buf[seq + 1] = len >> 8; + this._buf[seq + 2] = len; + } else if (len <= 0xffffff) { + this._shift(start, len, 1); + this._buf[seq] = 0x83; + this._buf[seq + 1] = len >> 16; + this._buf[seq + 2] = len >> 8; + this._buf[seq + 3] = len; + } else { + throw newInvalidAsn1Error('Sequence too long'); + } +}; + + +Writer.prototype._shift = function (start, len, shift) { + assert.ok(start !== undefined); + assert.ok(len !== undefined); + assert.ok(shift); + + this._buf.copy(this._buf, start + shift, start, start + len); + this._offset += shift; +}; + +Writer.prototype._ensure = function (len) { + assert.ok(len); + + if (this._size - this._offset < len) { + var sz = this._size * this._options.growthFactor; + if (sz - this._offset < len) + sz += len; + + var buf = Buffer.alloc(sz); + + this._buf.copy(buf, 0, 0, this._offset); + this._buf = buf; + this._size = sz; + } +}; + + + +// --- Exported API + +module.exports = Writer; diff --git a/user/themes/goku/node_modules/asn1/lib/index.js b/user/themes/goku/node_modules/asn1/lib/index.js new file mode 100644 index 00000000..ede3ab23 --- /dev/null +++ b/user/themes/goku/node_modules/asn1/lib/index.js @@ -0,0 +1,20 @@ +// Copyright 2011 Mark Cavage All rights reserved. + +// If you have no idea what ASN.1 or BER is, see this: +// ftp://ftp.rsa.com/pub/pkcs/ascii/layman.asc + +var Ber = require('./ber/index'); + + + +// --- Exported API + +module.exports = { + + Ber: Ber, + + BerReader: Ber.Reader, + + BerWriter: Ber.Writer + +}; diff --git a/user/themes/goku/node_modules/asn1/package.json b/user/themes/goku/node_modules/asn1/package.json new file mode 100644 index 00000000..5c0b5e24 --- /dev/null +++ b/user/themes/goku/node_modules/asn1/package.json @@ -0,0 +1,75 @@ +{ + "_from": "asn1@~0.2.3", + "_id": "asn1@0.2.4", + "_inBundle": false, + "_integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "_location": "/asn1", + "_phantomChildren": {}, + "_requested": { + "type": "range", + "registry": true, + "raw": "asn1@~0.2.3", + "name": "asn1", + "escapedName": "asn1", + "rawSpec": "~0.2.3", + "saveSpec": null, + "fetchSpec": "~0.2.3" + }, + "_requiredBy": [ + "/sshpk" + ], + "_resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "_shasum": "8d2475dfab553bb33e77b54e59e880bb8ce23136", + "_spec": "asn1@~0.2.3", + "_where": "/srv/http/berryfarmprojects.org.uk/stay-grav/user/themes/goku/node_modules/sshpk", + "author": { + "name": "Joyent", + "url": "joyent.com" + }, + "bugs": { + "url": "https://github.com/joyent/node-asn1/issues" + }, + "bundleDependencies": false, + "contributors": [ + { + "name": "Mark Cavage", + "email": "mcavage@gmail.com" + }, + { + "name": "David Gwynne", + "email": "loki@animata.net" + }, + { + "name": "Yunong Xiao", + "email": "yunong@joyent.com" + }, + { + "name": "Alex Wilson", + "email": "alex.wilson@joyent.com" + } + ], + "dependencies": { + "safer-buffer": "~2.1.0" + }, + "deprecated": false, + "description": "Contains parsers and serializers for ASN.1 (currently BER only)", + "devDependencies": { + "eslint": "2.13.1", + "eslint-plugin-joyent": "~1.3.0", + "faucet": "0.0.1", + "istanbul": "^0.3.6", + "tape": "^3.5.0" + }, + "homepage": "https://github.com/joyent/node-asn1#readme", + "license": "MIT", + "main": "lib/index.js", + "name": "asn1", + "repository": { + "type": "git", + "url": "git://github.com/joyent/node-asn1.git" + }, + "scripts": { + "test": "tape ./test/ber/*.test.js" + }, + "version": "0.2.4" +} diff --git a/user/themes/goku/node_modules/assert-plus/AUTHORS b/user/themes/goku/node_modules/assert-plus/AUTHORS new file mode 100644 index 00000000..1923524f --- /dev/null +++ b/user/themes/goku/node_modules/assert-plus/AUTHORS @@ -0,0 +1,6 @@ +Dave Eddy +Fred Kuo +Lars-Magnus Skog +Mark Cavage +Patrick Mooney +Rob Gulewich diff --git a/user/themes/goku/node_modules/assert-plus/CHANGES.md b/user/themes/goku/node_modules/assert-plus/CHANGES.md new file mode 100644 index 00000000..57d92bfd --- /dev/null +++ b/user/themes/goku/node_modules/assert-plus/CHANGES.md @@ -0,0 +1,14 @@ +# assert-plus Changelog + +## 1.0.0 + +- *BREAKING* assert.number (and derivatives) now accept Infinity as valid input +- Add assert.finite check. Previous assert.number callers should use this if + they expect Infinity inputs to throw. + +## 0.2.0 + +- Fix `assert.object(null)` so it throws +- Fix optional/arrayOf exports for non-type-of asserts +- Add optiona/arrayOf exports for Stream/Date/Regex/uuid +- Add basic unit test coverage diff --git a/user/themes/goku/node_modules/assert-plus/README.md b/user/themes/goku/node_modules/assert-plus/README.md new file mode 100644 index 00000000..ec200d16 --- /dev/null +++ b/user/themes/goku/node_modules/assert-plus/README.md @@ -0,0 +1,162 @@ +# assert-plus + +This library is a super small wrapper over node's assert module that has two +things: (1) the ability to disable assertions with the environment variable +NODE\_NDEBUG, and (2) some API wrappers for argument testing. Like +`assert.string(myArg, 'myArg')`. As a simple example, most of my code looks +like this: + +```javascript + var assert = require('assert-plus'); + + function fooAccount(options, callback) { + assert.object(options, 'options'); + assert.number(options.id, 'options.id'); + assert.bool(options.isManager, 'options.isManager'); + assert.string(options.name, 'options.name'); + assert.arrayOfString(options.email, 'options.email'); + assert.func(callback, 'callback'); + + // Do stuff + callback(null, {}); + } +``` + +# API + +All methods that *aren't* part of node's core assert API are simply assumed to +take an argument, and then a string 'name' that's not a message; `AssertionError` +will be thrown if the assertion fails with a message like: + + AssertionError: foo (string) is required + at test (/home/mark/work/foo/foo.js:3:9) + at Object. (/home/mark/work/foo/foo.js:15:1) + at Module._compile (module.js:446:26) + at Object..js (module.js:464:10) + at Module.load (module.js:353:31) + at Function._load (module.js:311:12) + at Array.0 (module.js:484:10) + at EventEmitter._tickCallback (node.js:190:38) + +from: + +```javascript + function test(foo) { + assert.string(foo, 'foo'); + } +``` + +There you go. You can check that arrays are of a homogeneous type with `Arrayof$Type`: + +```javascript + function test(foo) { + assert.arrayOfString(foo, 'foo'); + } +``` + +You can assert IFF an argument is not `undefined` (i.e., an optional arg): + +```javascript + assert.optionalString(foo, 'foo'); +``` + +Lastly, you can opt-out of assertion checking altogether by setting the +environment variable `NODE_NDEBUG=1`. This is pseudo-useful if you have +lots of assertions, and don't want to pay `typeof ()` taxes to v8 in +production. Be advised: The standard functions re-exported from `assert` are +also disabled in assert-plus if NDEBUG is specified. Using them directly from +the `assert` module avoids this behavior. + +The complete list of APIs is: + +* assert.array +* assert.bool +* assert.buffer +* assert.func +* assert.number +* assert.finite +* assert.object +* assert.string +* assert.stream +* assert.date +* assert.regexp +* assert.uuid +* assert.arrayOfArray +* assert.arrayOfBool +* assert.arrayOfBuffer +* assert.arrayOfFunc +* assert.arrayOfNumber +* assert.arrayOfFinite +* assert.arrayOfObject +* assert.arrayOfString +* assert.arrayOfStream +* assert.arrayOfDate +* assert.arrayOfRegexp +* assert.arrayOfUuid +* assert.optionalArray +* assert.optionalBool +* assert.optionalBuffer +* assert.optionalFunc +* assert.optionalNumber +* assert.optionalFinite +* assert.optionalObject +* assert.optionalString +* assert.optionalStream +* assert.optionalDate +* assert.optionalRegexp +* assert.optionalUuid +* assert.optionalArrayOfArray +* assert.optionalArrayOfBool +* assert.optionalArrayOfBuffer +* assert.optionalArrayOfFunc +* assert.optionalArrayOfNumber +* assert.optionalArrayOfFinite +* assert.optionalArrayOfObject +* assert.optionalArrayOfString +* assert.optionalArrayOfStream +* assert.optionalArrayOfDate +* assert.optionalArrayOfRegexp +* assert.optionalArrayOfUuid +* assert.AssertionError +* assert.fail +* assert.ok +* assert.equal +* assert.notEqual +* assert.deepEqual +* assert.notDeepEqual +* assert.strictEqual +* assert.notStrictEqual +* assert.throws +* assert.doesNotThrow +* assert.ifError + +# Installation + + npm install assert-plus + +## License + +The MIT License (MIT) +Copyright (c) 2012 Mark Cavage + +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. + +## Bugs + +See . diff --git a/user/themes/goku/node_modules/assert-plus/assert.js b/user/themes/goku/node_modules/assert-plus/assert.js new file mode 100644 index 00000000..26f944ee --- /dev/null +++ b/user/themes/goku/node_modules/assert-plus/assert.js @@ -0,0 +1,211 @@ +// Copyright (c) 2012, Mark Cavage. All rights reserved. +// Copyright 2015 Joyent, Inc. + +var assert = require('assert'); +var Stream = require('stream').Stream; +var util = require('util'); + + +///--- Globals + +/* JSSTYLED */ +var UUID_REGEXP = /^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$/; + + +///--- Internal + +function _capitalize(str) { + return (str.charAt(0).toUpperCase() + str.slice(1)); +} + +function _toss(name, expected, oper, arg, actual) { + throw new assert.AssertionError({ + message: util.format('%s (%s) is required', name, expected), + actual: (actual === undefined) ? typeof (arg) : actual(arg), + expected: expected, + operator: oper || '===', + stackStartFunction: _toss.caller + }); +} + +function _getClass(arg) { + return (Object.prototype.toString.call(arg).slice(8, -1)); +} + +function noop() { + // Why even bother with asserts? +} + + +///--- Exports + +var types = { + bool: { + check: function (arg) { return typeof (arg) === 'boolean'; } + }, + func: { + check: function (arg) { return typeof (arg) === 'function'; } + }, + string: { + check: function (arg) { return typeof (arg) === 'string'; } + }, + object: { + check: function (arg) { + return typeof (arg) === 'object' && arg !== null; + } + }, + number: { + check: function (arg) { + return typeof (arg) === 'number' && !isNaN(arg); + } + }, + finite: { + check: function (arg) { + return typeof (arg) === 'number' && !isNaN(arg) && isFinite(arg); + } + }, + buffer: { + check: function (arg) { return Buffer.isBuffer(arg); }, + operator: 'Buffer.isBuffer' + }, + array: { + check: function (arg) { return Array.isArray(arg); }, + operator: 'Array.isArray' + }, + stream: { + check: function (arg) { return arg instanceof Stream; }, + operator: 'instanceof', + actual: _getClass + }, + date: { + check: function (arg) { return arg instanceof Date; }, + operator: 'instanceof', + actual: _getClass + }, + regexp: { + check: function (arg) { return arg instanceof RegExp; }, + operator: 'instanceof', + actual: _getClass + }, + uuid: { + check: function (arg) { + return typeof (arg) === 'string' && UUID_REGEXP.test(arg); + }, + operator: 'isUUID' + } +}; + +function _setExports(ndebug) { + var keys = Object.keys(types); + var out; + + /* re-export standard assert */ + if (process.env.NODE_NDEBUG) { + out = noop; + } else { + out = function (arg, msg) { + if (!arg) { + _toss(msg, 'true', arg); + } + }; + } + + /* standard checks */ + keys.forEach(function (k) { + if (ndebug) { + out[k] = noop; + return; + } + var type = types[k]; + out[k] = function (arg, msg) { + if (!type.check(arg)) { + _toss(msg, k, type.operator, arg, type.actual); + } + }; + }); + + /* optional checks */ + keys.forEach(function (k) { + var name = 'optional' + _capitalize(k); + if (ndebug) { + out[name] = noop; + return; + } + var type = types[k]; + out[name] = function (arg, msg) { + if (arg === undefined || arg === null) { + return; + } + if (!type.check(arg)) { + _toss(msg, k, type.operator, arg, type.actual); + } + }; + }); + + /* arrayOf checks */ + keys.forEach(function (k) { + var name = 'arrayOf' + _capitalize(k); + if (ndebug) { + out[name] = noop; + return; + } + var type = types[k]; + var expected = '[' + k + ']'; + out[name] = function (arg, msg) { + if (!Array.isArray(arg)) { + _toss(msg, expected, type.operator, arg, type.actual); + } + var i; + for (i = 0; i < arg.length; i++) { + if (!type.check(arg[i])) { + _toss(msg, expected, type.operator, arg, type.actual); + } + } + }; + }); + + /* optionalArrayOf checks */ + keys.forEach(function (k) { + var name = 'optionalArrayOf' + _capitalize(k); + if (ndebug) { + out[name] = noop; + return; + } + var type = types[k]; + var expected = '[' + k + ']'; + out[name] = function (arg, msg) { + if (arg === undefined || arg === null) { + return; + } + if (!Array.isArray(arg)) { + _toss(msg, expected, type.operator, arg, type.actual); + } + var i; + for (i = 0; i < arg.length; i++) { + if (!type.check(arg[i])) { + _toss(msg, expected, type.operator, arg, type.actual); + } + } + }; + }); + + /* re-export built-in assertions */ + Object.keys(assert).forEach(function (k) { + if (k === 'AssertionError') { + out[k] = assert[k]; + return; + } + if (ndebug) { + out[k] = noop; + return; + } + out[k] = assert[k]; + }); + + /* export ourselves (for unit tests _only_) */ + out._setExports = _setExports; + + return out; +} + +module.exports = _setExports(process.env.NODE_NDEBUG); diff --git a/user/themes/goku/node_modules/assert-plus/package.json b/user/themes/goku/node_modules/assert-plus/package.json new file mode 100644 index 00000000..b5f558ff --- /dev/null +++ b/user/themes/goku/node_modules/assert-plus/package.json @@ -0,0 +1,87 @@ +{ + "_from": "assert-plus@^1.0.0", + "_id": "assert-plus@1.0.0", + "_inBundle": false, + "_integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "_location": "/assert-plus", + "_phantomChildren": {}, + "_requested": { + "type": "range", + "registry": true, + "raw": "assert-plus@^1.0.0", + "name": "assert-plus", + "escapedName": "assert-plus", + "rawSpec": "^1.0.0", + "saveSpec": null, + "fetchSpec": "^1.0.0" + }, + "_requiredBy": [ + "/dashdash", + "/getpass", + "/http-signature", + "/jsprim", + "/sshpk", + "/verror" + ], + "_resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "_shasum": "f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525", + "_spec": "assert-plus@^1.0.0", + "_where": "/srv/http/berryfarmprojects.org.uk/stay-grav/user/themes/goku/node_modules/http-signature", + "author": { + "name": "Mark Cavage", + "email": "mcavage@gmail.com" + }, + "bugs": { + "url": "https://github.com/mcavage/node-assert-plus/issues" + }, + "bundleDependencies": false, + "contributors": [ + { + "name": "Dave Eddy", + "email": "dave@daveeddy.com" + }, + { + "name": "Fred Kuo", + "email": "fred.kuo@joyent.com" + }, + { + "name": "Lars-Magnus Skog", + "email": "ralphtheninja@riseup.net" + }, + { + "name": "Mark Cavage", + "email": "mcavage@gmail.com" + }, + { + "name": "Patrick Mooney", + "email": "pmooney@pfmooney.com" + }, + { + "name": "Rob Gulewich", + "email": "robert.gulewich@joyent.com" + } + ], + "dependencies": {}, + "deprecated": false, + "description": "Extra assertions on top of node's assert module", + "devDependencies": { + "faucet": "0.0.1", + "tape": "4.2.2" + }, + "engines": { + "node": ">=0.8" + }, + "homepage": "https://github.com/mcavage/node-assert-plus#readme", + "license": "MIT", + "main": "./assert.js", + "name": "assert-plus", + "optionalDependencies": {}, + "repository": { + "type": "git", + "url": "git+https://github.com/mcavage/node-assert-plus.git" + }, + "scripts": { + "test": "tape tests/*.js | ./node_modules/.bin/faucet" + }, + "version": "1.0.0" +} diff --git a/user/themes/goku/node_modules/async-foreach/LICENSE-MIT b/user/themes/goku/node_modules/async-foreach/LICENSE-MIT new file mode 100644 index 00000000..7505716b --- /dev/null +++ b/user/themes/goku/node_modules/async-foreach/LICENSE-MIT @@ -0,0 +1,22 @@ +Copyright (c) 2011 "Cowboy" Ben Alman + +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. diff --git a/user/themes/goku/node_modules/async-foreach/README.md b/user/themes/goku/node_modules/async-foreach/README.md new file mode 100644 index 00000000..f5742049 --- /dev/null +++ b/user/themes/goku/node_modules/async-foreach/README.md @@ -0,0 +1,195 @@ +# JavaScript Sync/Async forEach + +An optionally-asynchronous forEach with an interesting interface. + +## Getting Started + +This code should work just fine in Node.js: + +First, install the module with: `npm install async-foreach` + +```javascript +var forEach = require('async-foreach').forEach; +forEach(["a", "b", "c"], function(item, index, arr) { + console.log("each", item, index, arr); +}); +// logs: +// each a 0 ["a", "b", "c"] +// each b 1 ["a", "b", "c"] +// each c 2 ["a", "b", "c"] +``` + +Or in the browser: + +```html + + +``` + +In the browser, you can attach the forEach method to any object. + +```html + + + +``` + +## The General Idea (Why I thought this was worth sharing) + +The idea is to allow the callback to decide _at runtime_ whether the loop will be synchronous or asynchronous. By using `this` in a creative way (in situations where that value isn't already spoken for), an entire control API can be offered without over-complicating function signatures. + +```javascript +forEach(arr, function(item, index) { + // Synchronous. +}); + +forEach(arr, function(item, index) { + // Only when `this.async` is called does iteration becomes asynchronous. The + // loop won't be continued until the `done` function is executed. + var done = this.async(); + // Continue in one second. + setTimeout(done, 1000); +}); + +forEach(arr, function(item, index) { + // Break out of synchronous iteration early by returning false. + return index !== 1; +}); + +forEach(arr, function(item, index) { + // Break out of asynchronous iteration early... + var done = this.async(); + // ...by passing false to the done function. + setTimeout(function() { + done(index !== 1); + }); +}); +``` + +## Examples +See the unit tests for more examples. + +```javascript +// Generic "done" callback. +function allDone(notAborted, arr) { + console.log("done", notAborted, arr); +} + +// Synchronous. +forEach(["a", "b", "c"], function(item, index, arr) { + console.log("each", item, index, arr); +}, allDone); +// logs: +// each a 0 ["a", "b", "c"] +// each b 1 ["a", "b", "c"] +// each c 2 ["a", "b", "c"] +// done true ["a", "b", "c"] + +// Synchronous with early abort. +forEach(["a", "b", "c"], function(item, index, arr) { + console.log("each", item, index, arr); + if (item === "b") { return false; } +}, allDone); +// logs: +// each a 0 ["a", "b", "c"] +// each b 1 ["a", "b", "c"] +// done false ["a", "b", "c"] + +// Asynchronous. +forEach(["a", "b", "c"], function(item, index, arr) { + console.log("each", item, index, arr); + var done = this.async(); + setTimeout(function() { + done(); + }, 500); +}, allDone); +// logs: +// each a 0 ["a", "b", "c"] +// each b 1 ["a", "b", "c"] +// each c 2 ["a", "b", "c"] +// done true ["a", "b", "c"] + +// Asynchronous with early abort. +forEach(["a", "b", "c"], function(item, index, arr) { + console.log("each", item, index, arr); + var done = this.async(); + setTimeout(function() { + done(item !== "b"); + }, 500); +}, allDone); +// logs: +// each a 0 ["a", "b", "c"] +// each b 1 ["a", "b", "c"] +// done false ["a", "b", "c"] + +// Not actually asynchronous. +forEach(["a", "b", "c"], function(item, index, arr) { + console.log("each", item, index, arr); + var done = this.async() + done(); +}, allDone); +// logs: +// each a 0 ["a", "b", "c"] +// each b 1 ["a", "b", "c"] +// each c 2 ["a", "b", "c"] +// done true ["a", "b", "c"] + +// Not actually asynchronous with early abort. +forEach(["a", "b", "c"], function(item, index, arr) { + console.log("each", item, index, arr); + var done = this.async(); + done(item !== "b"); +}, allDone); +// logs: +// each a 0 ["a", "b", "c"] +// each b 1 ["a", "b", "c"] +// done false ["a", "b", "c"] +``` + +## Contributing +In lieu of a formal styleguide, take care to maintain the existing coding style. Add unit tests for any new or changed functionality. Lint and test your code using [grunt](https://github.com/cowboy/grunt). + +_Also, please don't edit files in the "dist" subdirectory as they are generated via grunt. You'll find source code in the "lib" subdirectory!_ + +## Release History + +04/29/2013 +v0.1.3 +Removed hard Node.js version dependency. + +11/17/2011 +v0.1.2 +Adding sparse array support. +Invalid length properties are now sanitized. +This closes issue #1 (like a boss). + +11/11/2011 +v0.1.1 +Refactored code to be much simpler. Yay for unit tests! + +11/11/2011 +v0.1.0 +Initial Release. + +## License +Copyright (c) 2012 "Cowboy" Ben Alman +Licensed under the MIT license. + diff --git a/user/themes/goku/node_modules/async-foreach/dist/ba-foreach.js b/user/themes/goku/node_modules/async-foreach/dist/ba-foreach.js new file mode 100644 index 00000000..64c6eb8f --- /dev/null +++ b/user/themes/goku/node_modules/async-foreach/dist/ba-foreach.js @@ -0,0 +1,58 @@ +/* JavaScript Sync/Async forEach - v0.1.2 - 1/10/2012 + * http://github.com/cowboy/javascript-sync-async-foreach + * Copyright (c) 2012 "Cowboy" Ben Alman; Licensed MIT */ + +(function(exports) { + + // Iterate synchronously or asynchronously. + exports.forEach = function(arr, eachFn, doneFn) { + var i = -1; + // Resolve array length to a valid (ToUint32) number. + var len = arr.length >>> 0; + + // This IIFE is called once now, and then again, by name, for each loop + // iteration. + (function next(result) { + // This flag will be set to true if `this.async` is called inside the + // eachFn` callback. + var async; + // Was false returned from the `eachFn` callback or passed to the + // `this.async` done function? + var abort = result === false; + + // Increment counter variable and skip any indices that don't exist. This + // allows sparse arrays to be iterated. + do { ++i; } while (!(i in arr) && i !== len); + + // Exit if result passed to `this.async` done function or returned from + // the `eachFn` callback was false, or when done iterating. + if (abort || i === len) { + // If a `doneFn` callback was specified, invoke that now. Pass in a + // boolean value representing "not aborted" state along with the array. + if (doneFn) { + doneFn(!abort, arr); + } + return; + } + + // Invoke the `eachFn` callback, setting `this` inside the callback to a + // custom object that contains one method, and passing in the array item, + // index, and the array. + result = eachFn.call({ + // If `this.async` is called inside the `eachFn` callback, set the async + // flag and return a function that can be used to continue iterating. + async: function() { + async = true; + return next; + } + }, arr[i], i, arr); + + // If the async flag wasn't set, continue by calling `next` synchronously, + // passing in the result of the `eachFn` callback. + if (!async) { + next(result); + } + }()); + }; + +}(typeof exports === "object" && exports || this)); \ No newline at end of file diff --git a/user/themes/goku/node_modules/async-foreach/dist/ba-foreach.min.js b/user/themes/goku/node_modules/async-foreach/dist/ba-foreach.min.js new file mode 100644 index 00000000..c218a915 --- /dev/null +++ b/user/themes/goku/node_modules/async-foreach/dist/ba-foreach.min.js @@ -0,0 +1,4 @@ +/* JavaScript Sync/Async forEach - v0.1.2 - 1/10/2012 + * http://github.com/cowboy/javascript-sync-async-foreach + * Copyright (c) 2012 "Cowboy" Ben Alman; Licensed MIT */ +(function(a){a.forEach=function(a,b,c){var d=-1,e=a.length>>>0;(function f(g){var h,j=g===!1;do++d;while(!(d in a)&&d!==e);if(j||d===e){c&&c(!j,a);return}g=b.call({async:function(){return h=!0,f}},a[d],d,a),h||f(g)})()}})(typeof exports=="object"&&exports||this) \ No newline at end of file diff --git a/user/themes/goku/node_modules/async-foreach/grunt.js b/user/themes/goku/node_modules/async-foreach/grunt.js new file mode 100644 index 00000000..079a23af --- /dev/null +++ b/user/themes/goku/node_modules/async-foreach/grunt.js @@ -0,0 +1,48 @@ +/*global config:true, task:true*/ +config.init({ + pkg: '', + meta: { + title: 'JavaScript Sync/Async forEach', + license: ['MIT'], + copyright: 'Copyright (c) 2012 "Cowboy" Ben Alman', + banner: '/* {{meta.title}} - v{{pkg.version}} - {{today "m/d/yyyy"}}\n' + + ' * {{pkg.homepage}}\n' + + ' * {{{meta.copyright}}}; Licensed {{join meta.license}} */' + }, + concat: { + 'dist/ba-foreach.js': ['', ''] + }, + min: { + 'dist/ba-foreach.min.js': ['', 'dist/ba-foreach.js'] + }, + test: { + files: ['test/**/*.js'] + }, + lint: { + files: ['grunt.js', 'lib/**/*.js', 'test/**/*.js'] + }, + watch: { + files: '', + tasks: 'lint:files test:files' + }, + jshint: { + options: { + curly: true, + eqeqeq: true, + immed: true, + latedef: true, + newcap: true, + noarg: true, + sub: true, + undef: true, + eqnull: true + }, + globals: { + exports: true + } + }, + uglify: {} +}); + +// Default task. +task.registerTask('default', 'lint:files test:files concat min'); diff --git a/user/themes/goku/node_modules/async-foreach/lib/foreach.js b/user/themes/goku/node_modules/async-foreach/lib/foreach.js new file mode 100644 index 00000000..9ee98b00 --- /dev/null +++ b/user/themes/goku/node_modules/async-foreach/lib/foreach.js @@ -0,0 +1,63 @@ +/*! + * Sync/Async forEach + * https://github.com/cowboy/javascript-sync-async-foreach + * + * Copyright (c) 2012 "Cowboy" Ben Alman + * Licensed under the MIT license. + * http://benalman.com/about/license/ + */ + +(function(exports) { + + // Iterate synchronously or asynchronously. + exports.forEach = function(arr, eachFn, doneFn) { + var i = -1; + // Resolve array length to a valid (ToUint32) number. + var len = arr.length >>> 0; + + // This IIFE is called once now, and then again, by name, for each loop + // iteration. + (function next(result) { + // This flag will be set to true if `this.async` is called inside the + // eachFn` callback. + var async; + // Was false returned from the `eachFn` callback or passed to the + // `this.async` done function? + var abort = result === false; + + // Increment counter variable and skip any indices that don't exist. This + // allows sparse arrays to be iterated. + do { ++i; } while (!(i in arr) && i !== len); + + // Exit if result passed to `this.async` done function or returned from + // the `eachFn` callback was false, or when done iterating. + if (abort || i === len) { + // If a `doneFn` callback was specified, invoke that now. Pass in a + // boolean value representing "not aborted" state along with the array. + if (doneFn) { + doneFn(!abort, arr); + } + return; + } + + // Invoke the `eachFn` callback, setting `this` inside the callback to a + // custom object that contains one method, and passing in the array item, + // index, and the array. + result = eachFn.call({ + // If `this.async` is called inside the `eachFn` callback, set the async + // flag and return a function that can be used to continue iterating. + async: function() { + async = true; + return next; + } + }, arr[i], i, arr); + + // If the async flag wasn't set, continue by calling `next` synchronously, + // passing in the result of the `eachFn` callback. + if (!async) { + next(result); + } + }()); + }; + +}(typeof exports === "object" && exports || this)); \ No newline at end of file diff --git a/user/themes/goku/node_modules/async-foreach/package.json b/user/themes/goku/node_modules/async-foreach/package.json new file mode 100644 index 00000000..1eebbe0c --- /dev/null +++ b/user/themes/goku/node_modules/async-foreach/package.json @@ -0,0 +1,55 @@ +{ + "_from": "async-foreach@^0.1.3", + "_id": "async-foreach@0.1.3", + "_inBundle": false, + "_integrity": "sha1-NhIfhFwFeBct5Bmpfb6x0W7DRUI=", + "_location": "/async-foreach", + "_phantomChildren": {}, + "_requested": { + "type": "range", + "registry": true, + "raw": "async-foreach@^0.1.3", + "name": "async-foreach", + "escapedName": "async-foreach", + "rawSpec": "^0.1.3", + "saveSpec": null, + "fetchSpec": "^0.1.3" + }, + "_requiredBy": [ + "/node-sass" + ], + "_resolved": "https://registry.npmjs.org/async-foreach/-/async-foreach-0.1.3.tgz", + "_shasum": "36121f845c0578172de419a97dbeb1d16ec34542", + "_spec": "async-foreach@^0.1.3", + "_where": "/srv/http/berryfarmprojects.org.uk/stay-grav/user/themes/goku/node_modules/node-sass", + "author": { + "name": "\"Cowboy\" Ben Alman", + "url": "http://benalman.com/" + }, + "bugs": { + "url": "https://github.com/cowboy/javascript-sync-async-foreach/issues" + }, + "bundleDependencies": false, + "dependencies": {}, + "deprecated": false, + "description": "An optionally-asynchronous forEach with an interesting interface.", + "devDependencies": {}, + "engines": { + "node": "*" + }, + "homepage": "http://github.com/cowboy/javascript-sync-async-foreach", + "keywords": [ + "array", + "loop", + "sync", + "async", + "foreach" + ], + "main": "lib/foreach", + "name": "async-foreach", + "repository": { + "type": "git", + "url": "git://github.com/cowboy/javascript-sync-async-foreach.git" + }, + "version": "0.1.3" +} diff --git a/user/themes/goku/node_modules/async-foreach/test/foreach_test.js b/user/themes/goku/node_modules/async-foreach/test/foreach_test.js new file mode 100644 index 00000000..be18c43a --- /dev/null +++ b/user/themes/goku/node_modules/async-foreach/test/foreach_test.js @@ -0,0 +1,200 @@ +/*global require:true, setTimeout:true */ +var forEach = require('../lib/foreach').forEach; + +exports['foreach'] = { + setUp: function(done) { + this.order = []; + this.track = function() { + [].push.apply(this.order, arguments); + }; + done(); + }, + 'Synchronous': function(test) { + test.expect(1); + var that = this; + + var arr = ["a", "b", "c"]; + forEach(arr, function(item, index, arr) { + that.track("each", item, index, arr); + }); + + test.deepEqual(that.order, [ + "each", "a", 0, arr, + "each", "b", 1, arr, + "each", "c", 2, arr + ], "should call eachFn for each array item, in order."); + test.done(); + }, + 'Synchronous, done': function(test) { + test.expect(1); + var that = this; + + var arr = ["a", "b", "c"]; + forEach(arr, function(item, index, arr) { + that.track("each", item, index, arr); + }, function(notAborted, arr) { + that.track("done", notAborted, arr); + }); + + test.deepEqual(that.order, [ + "each", "a", 0, arr, + "each", "b", 1, arr, + "each", "c", 2, arr, + "done", true, arr + ], "should call eachFn for each array item, in order, followed by doneFn."); + test.done(); + }, + 'Synchronous, early abort': function(test) { + test.expect(1); + var that = this; + + var arr = ["a", "b", "c"]; + forEach(arr, function(item, index, arr) { + that.track("each", item, index, arr); + if (item === "b") { return false; } + }, function(notAborted, arr) { + that.track("done", notAborted, arr); + }); + + test.deepEqual(that.order, [ + "each", "a", 0, arr, + "each", "b", 1, arr, + "done", false, arr + ], "should call eachFn for each array item, in order, followed by doneFn."); + test.done(); + }, + 'Asynchronous': function(test) { + test.expect(1); + var that = this; + + var arr = ["a", "b", "c"]; + forEach(arr, function(item, index, arr) { + that.track("each", item, index, arr); + var done = this.async(); + setTimeout(done, 10); + }); + + setTimeout(function() { + test.deepEqual(that.order, [ + "each", "a", 0, arr, + "each", "b", 1, arr, + "each", "c", 2, arr + ], "should call eachFn for each array item, in order."); + test.done(); + }, 100); + }, + 'Asynchronous, done': function(test) { + test.expect(1); + var that = this; + + var arr = ["a", "b", "c"]; + forEach(arr, function(item, index, arr) { + that.track("each", item, index, arr); + var done = this.async(); + setTimeout(done, 10); + }, function(notAborted, arr) { + that.track("done", notAborted, arr); + test.deepEqual(that.order, [ + "each", "a", 0, arr, + "each", "b", 1, arr, + "each", "c", 2, arr, + "done", true, arr + ], "should call eachFn for each array item, in order, followed by doneFn."); + test.done(); + }); + }, + 'Asynchronous, early abort': function(test) { + test.expect(1); + var that = this; + + var arr = ["a", "b", "c"]; + forEach(arr, function(item, index, arr) { + that.track("each", item, index, arr); + var done = this.async(); + setTimeout(function() { + done(item !== "b"); + }, 10); + }, function(notAborted, arr) { + that.track("done", notAborted, arr); + test.deepEqual(that.order, [ + "each", "a", 0, arr, + "each", "b", 1, arr, + "done", false, arr + ], "should call eachFn for each array item, in order, followed by doneFn."); + test.done(); + }); + }, + 'Not actually asynchronous': function(test) { + test.expect(1); + var that = this; + + var arr = ["a", "b", "c"]; + forEach(arr, function(item, index, arr) { + that.track("each", item, index, arr); + var done = this.async(); + done(); + }, function(notAborted, arr) { + that.track("done", notAborted, arr); + test.deepEqual(that.order, [ + "each", "a", 0, arr, + "each", "b", 1, arr, + "each", "c", 2, arr, + "done", true, arr + ], "should call eachFn for each array item, in order, followed by doneFn."); + test.done(); + }); + }, + 'Not actually asynchronous, early abort': function(test) { + test.expect(1); + var that = this; + + var arr = ["a", "b", "c"]; + forEach(arr, function(item, index, arr) { + that.track("each", item, index, arr); + var done = this.async(); + done(item !== "b"); + }, function(notAborted, arr) { + that.track("done", notAborted, arr); + test.deepEqual(that.order, [ + "each", "a", 0, arr, + "each", "b", 1, arr, + "done", false, arr + ], "should call eachFn for each array item, in order, followed by doneFn."); + test.done(); + }); + }, + 'Sparse array support': function(test) { + test.expect(1); + var that = this; + + var arr = []; + arr[0] = "a"; + arr[9] = "z"; + + forEach(arr, function(item, index, arr) { + that.track("each", item, index, arr); + }); + + test.deepEqual(that.order, [ + "each", "a", 0, arr, + "each", "z", 9, arr + ], "should skip nonexistent array items."); + test.done(); + }, + 'Invalid length sanitization': function(test) { + test.expect(1); + var that = this; + + var obj = {length: 4294967299, 0: "a", 2: "b", 3: "c" }; + + forEach(obj, function(item, index, arr) { + that.track("each", item, index, arr); + }); + + test.deepEqual(that.order, [ + "each", "a", 0, obj, + "each", "b", 2, obj + ], "should sanitize length property (ToUint32)."); + test.done(); + } +}; diff --git a/user/themes/goku/node_modules/asynckit/LICENSE b/user/themes/goku/node_modules/asynckit/LICENSE new file mode 100644 index 00000000..c9eca5dd --- /dev/null +++ b/user/themes/goku/node_modules/asynckit/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2016 Alex Indigo + +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. diff --git a/user/themes/goku/node_modules/asynckit/README.md b/user/themes/goku/node_modules/asynckit/README.md new file mode 100644 index 00000000..ddcc7e6b --- /dev/null +++ b/user/themes/goku/node_modules/asynckit/README.md @@ -0,0 +1,233 @@ +# asynckit [![NPM Module](https://img.shields.io/npm/v/asynckit.svg?style=flat)](https://www.npmjs.com/package/asynckit) + +Minimal async jobs utility library, with streams support. + +[![PhantomJS Build](https://img.shields.io/travis/alexindigo/asynckit/v0.4.0.svg?label=browser&style=flat)](https://travis-ci.org/alexindigo/asynckit) +[![Linux Build](https://img.shields.io/travis/alexindigo/asynckit/v0.4.0.svg?label=linux:0.12-6.x&style=flat)](https://travis-ci.org/alexindigo/asynckit) +[![Windows Build](https://img.shields.io/appveyor/ci/alexindigo/asynckit/v0.4.0.svg?label=windows:0.12-6.x&style=flat)](https://ci.appveyor.com/project/alexindigo/asynckit) + +[![Coverage Status](https://img.shields.io/coveralls/alexindigo/asynckit/v0.4.0.svg?label=code+coverage&style=flat)](https://coveralls.io/github/alexindigo/asynckit?branch=master) +[![Dependency Status](https://img.shields.io/david/alexindigo/asynckit/v0.4.0.svg?style=flat)](https://david-dm.org/alexindigo/asynckit) +[![bitHound Overall Score](https://www.bithound.io/github/alexindigo/asynckit/badges/score.svg)](https://www.bithound.io/github/alexindigo/asynckit) + + + +AsyncKit provides harness for `parallel` and `serial` iterators over list of items represented by arrays or objects. +Optionally it accepts abort function (should be synchronously return by iterator for each item), and terminates left over jobs upon an error event. For specific iteration order built-in (`ascending` and `descending`) and custom sort helpers also supported, via `asynckit.serialOrdered` method. + +It ensures async operations to keep behavior more stable and prevent `Maximum call stack size exceeded` errors, from sync iterators. + +| compression | size | +| :----------------- | -------: | +| asynckit.js | 12.34 kB | +| asynckit.min.js | 4.11 kB | +| asynckit.min.js.gz | 1.47 kB | + + +## Install + +```sh +$ npm install --save asynckit +``` + +## Examples + +### Parallel Jobs + +Runs iterator over provided array in parallel. Stores output in the `result` array, +on the matching positions. In unlikely event of an error from one of the jobs, +will terminate rest of the active jobs (if abort function is provided) +and return error along with salvaged data to the main callback function. + +#### Input Array + +```javascript +var parallel = require('asynckit').parallel + , assert = require('assert') + ; + +var source = [ 1, 1, 4, 16, 64, 32, 8, 2 ] + , expectedResult = [ 2, 2, 8, 32, 128, 64, 16, 4 ] + , expectedTarget = [ 1, 1, 2, 4, 8, 16, 32, 64 ] + , target = [] + ; + +parallel(source, asyncJob, function(err, result) +{ + assert.deepEqual(result, expectedResult); + assert.deepEqual(target, expectedTarget); +}); + +// async job accepts one element from the array +// and a callback function +function asyncJob(item, cb) +{ + // different delays (in ms) per item + var delay = item * 25; + + // pretend different jobs take different time to finish + // and not in consequential order + var timeoutId = setTimeout(function() { + target.push(item); + cb(null, item * 2); + }, delay); + + // allow to cancel "leftover" jobs upon error + // return function, invoking of which will abort this job + return clearTimeout.bind(null, timeoutId); +} +``` + +More examples could be found in [test/test-parallel-array.js](test/test-parallel-array.js). + +#### Input Object + +Also it supports named jobs, listed via object. + +```javascript +var parallel = require('asynckit/parallel') + , assert = require('assert') + ; + +var source = { first: 1, one: 1, four: 4, sixteen: 16, sixtyFour: 64, thirtyTwo: 32, eight: 8, two: 2 } + , expectedResult = { first: 2, one: 2, four: 8, sixteen: 32, sixtyFour: 128, thirtyTwo: 64, eight: 16, two: 4 } + , expectedTarget = [ 1, 1, 2, 4, 8, 16, 32, 64 ] + , expectedKeys = [ 'first', 'one', 'two', 'four', 'eight', 'sixteen', 'thirtyTwo', 'sixtyFour' ] + , target = [] + , keys = [] + ; + +parallel(source, asyncJob, function(err, result) +{ + assert.deepEqual(result, expectedResult); + assert.deepEqual(target, expectedTarget); + assert.deepEqual(keys, expectedKeys); +}); + +// supports full value, key, callback (shortcut) interface +function asyncJob(item, key, cb) +{ + // different delays (in ms) per item + var delay = item * 25; + + // pretend different jobs take different time to finish + // and not in consequential order + var timeoutId = setTimeout(function() { + keys.push(key); + target.push(item); + cb(null, item * 2); + }, delay); + + // allow to cancel "leftover" jobs upon error + // return function, invoking of which will abort this job + return clearTimeout.bind(null, timeoutId); +} +``` + +More examples could be found in [test/test-parallel-object.js](test/test-parallel-object.js). + +### Serial Jobs + +Runs iterator over provided array sequentially. Stores output in the `result` array, +on the matching positions. In unlikely event of an error from one of the jobs, +will not proceed to the rest of the items in the list +and return error along with salvaged data to the main callback function. + +#### Input Array + +```javascript +var serial = require('asynckit/serial') + , assert = require('assert') + ; + +var source = [ 1, 1, 4, 16, 64, 32, 8, 2 ] + , expectedResult = [ 2, 2, 8, 32, 128, 64, 16, 4 ] + , expectedTarget = [ 0, 1, 2, 3, 4, 5, 6, 7 ] + , target = [] + ; + +serial(source, asyncJob, function(err, result) +{ + assert.deepEqual(result, expectedResult); + assert.deepEqual(target, expectedTarget); +}); + +// extended interface (item, key, callback) +// also supported for arrays +function asyncJob(item, key, cb) +{ + target.push(key); + + // it will be automatically made async + // even it iterator "returns" in the same event loop + cb(null, item * 2); +} +``` + +More examples could be found in [test/test-serial-array.js](test/test-serial-array.js). + +#### Input Object + +Also it supports named jobs, listed via object. + +```javascript +var serial = require('asynckit').serial + , assert = require('assert') + ; + +var source = [ 1, 1, 4, 16, 64, 32, 8, 2 ] + , expectedResult = [ 2, 2, 8, 32, 128, 64, 16, 4 ] + , expectedTarget = [ 0, 1, 2, 3, 4, 5, 6, 7 ] + , target = [] + ; + +var source = { first: 1, one: 1, four: 4, sixteen: 16, sixtyFour: 64, thirtyTwo: 32, eight: 8, two: 2 } + , expectedResult = { first: 2, one: 2, four: 8, sixteen: 32, sixtyFour: 128, thirtyTwo: 64, eight: 16, two: 4 } + , expectedTarget = [ 1, 1, 4, 16, 64, 32, 8, 2 ] + , target = [] + ; + + +serial(source, asyncJob, function(err, result) +{ + assert.deepEqual(result, expectedResult); + assert.deepEqual(target, expectedTarget); +}); + +// shortcut interface (item, callback) +// works for object as well as for the arrays +function asyncJob(item, cb) +{ + target.push(item); + + // it will be automatically made async + // even it iterator "returns" in the same event loop + cb(null, item * 2); +} +``` + +More examples could be found in [test/test-serial-object.js](test/test-serial-object.js). + +_Note: Since _object_ is an _unordered_ collection of properties, +it may produce unexpected results with sequential iterations. +Whenever order of the jobs' execution is important please use `serialOrdered` method._ + +### Ordered Serial Iterations + +TBD + +For example [compare-property](compare-property) package. + +### Streaming interface + +TBD + +## Want to Know More? + +More examples can be found in [test folder](test/). + +Or open an [issue](https://github.com/alexindigo/asynckit/issues) with questions and/or suggestions. + +## License + +AsyncKit is licensed under the MIT license. diff --git a/user/themes/goku/node_modules/asynckit/bench.js b/user/themes/goku/node_modules/asynckit/bench.js new file mode 100644 index 00000000..c612f1a5 --- /dev/null +++ b/user/themes/goku/node_modules/asynckit/bench.js @@ -0,0 +1,76 @@ +/* eslint no-console: "off" */ + +var asynckit = require('./') + , async = require('async') + , assert = require('assert') + , expected = 0 + ; + +var Benchmark = require('benchmark'); +var suite = new Benchmark.Suite; + +var source = []; +for (var z = 1; z < 100; z++) +{ + source.push(z); + expected += z; +} + +suite +// add tests + +.add('async.map', function(deferred) +{ + var total = 0; + + async.map(source, + function(i, cb) + { + setImmediate(function() + { + total += i; + cb(null, total); + }); + }, + function(err, result) + { + assert.ifError(err); + assert.equal(result[result.length - 1], expected); + deferred.resolve(); + }); +}, {'defer': true}) + + +.add('asynckit.parallel', function(deferred) +{ + var total = 0; + + asynckit.parallel(source, + function(i, cb) + { + setImmediate(function() + { + total += i; + cb(null, total); + }); + }, + function(err, result) + { + assert.ifError(err); + assert.equal(result[result.length - 1], expected); + deferred.resolve(); + }); +}, {'defer': true}) + + +// add listeners +.on('cycle', function(ev) +{ + console.log(String(ev.target)); +}) +.on('complete', function() +{ + console.log('Fastest is ' + this.filter('fastest').map('name')); +}) +// run async +.run({ 'async': true }); diff --git a/user/themes/goku/node_modules/asynckit/index.js b/user/themes/goku/node_modules/asynckit/index.js new file mode 100644 index 00000000..455f9454 --- /dev/null +++ b/user/themes/goku/node_modules/asynckit/index.js @@ -0,0 +1,6 @@ +module.exports = +{ + parallel : require('./parallel.js'), + serial : require('./serial.js'), + serialOrdered : require('./serialOrdered.js') +}; diff --git a/user/themes/goku/node_modules/asynckit/lib/abort.js b/user/themes/goku/node_modules/asynckit/lib/abort.js new file mode 100644 index 00000000..114367e5 --- /dev/null +++ b/user/themes/goku/node_modules/asynckit/lib/abort.js @@ -0,0 +1,29 @@ +// API +module.exports = abort; + +/** + * Aborts leftover active jobs + * + * @param {object} state - current state object + */ +function abort(state) +{ + Object.keys(state.jobs).forEach(clean.bind(state)); + + // reset leftover jobs + state.jobs = {}; +} + +/** + * Cleans up leftover job by invoking abort function for the provided job id + * + * @this state + * @param {string|number} key - job id to abort + */ +function clean(key) +{ + if (typeof this.jobs[key] == 'function') + { + this.jobs[key](); + } +} diff --git a/user/themes/goku/node_modules/asynckit/lib/async.js b/user/themes/goku/node_modules/asynckit/lib/async.js new file mode 100644 index 00000000..7f1288a4 --- /dev/null +++ b/user/themes/goku/node_modules/asynckit/lib/async.js @@ -0,0 +1,34 @@ +var defer = require('./defer.js'); + +// API +module.exports = async; + +/** + * Runs provided callback asynchronously + * even if callback itself is not + * + * @param {function} callback - callback to invoke + * @returns {function} - augmented callback + */ +function async(callback) +{ + var isAsync = false; + + // check if async happened + defer(function() { isAsync = true; }); + + return function async_callback(err, result) + { + if (isAsync) + { + callback(err, result); + } + else + { + defer(function nextTick_callback() + { + callback(err, result); + }); + } + }; +} diff --git a/user/themes/goku/node_modules/asynckit/lib/defer.js b/user/themes/goku/node_modules/asynckit/lib/defer.js new file mode 100644 index 00000000..b67110c7 --- /dev/null +++ b/user/themes/goku/node_modules/asynckit/lib/defer.js @@ -0,0 +1,26 @@ +module.exports = defer; + +/** + * Runs provided function on next iteration of the event loop + * + * @param {function} fn - function to run + */ +function defer(fn) +{ + var nextTick = typeof setImmediate == 'function' + ? setImmediate + : ( + typeof process == 'object' && typeof process.nextTick == 'function' + ? process.nextTick + : null + ); + + if (nextTick) + { + nextTick(fn); + } + else + { + setTimeout(fn, 0); + } +} diff --git a/user/themes/goku/node_modules/asynckit/lib/iterate.js b/user/themes/goku/node_modules/asynckit/lib/iterate.js new file mode 100644 index 00000000..5d2839a5 --- /dev/null +++ b/user/themes/goku/node_modules/asynckit/lib/iterate.js @@ -0,0 +1,75 @@ +var async = require('./async.js') + , abort = require('./abort.js') + ; + +// API +module.exports = iterate; + +/** + * Iterates over each job object + * + * @param {array|object} list - array or object (named list) to iterate over + * @param {function} iterator - iterator to run + * @param {object} state - current job status + * @param {function} callback - invoked when all elements processed + */ +function iterate(list, iterator, state, callback) +{ + // store current index + var key = state['keyedList'] ? state['keyedList'][state.index] : state.index; + + state.jobs[key] = runJob(iterator, key, list[key], function(error, output) + { + // don't repeat yourself + // skip secondary callbacks + if (!(key in state.jobs)) + { + return; + } + + // clean up jobs + delete state.jobs[key]; + + if (error) + { + // don't process rest of the results + // stop still active jobs + // and reset the list + abort(state); + } + else + { + state.results[key] = output; + } + + // return salvaged results + callback(error, state.results); + }); +} + +/** + * Runs iterator over provided job element + * + * @param {function} iterator - iterator to invoke + * @param {string|number} key - key/index of the element in the list of jobs + * @param {mixed} item - job description + * @param {function} callback - invoked after iterator is done with the job + * @returns {function|mixed} - job abort function or something else + */ +function runJob(iterator, key, item, callback) +{ + var aborter; + + // allow shortcut if iterator expects only two arguments + if (iterator.length == 2) + { + aborter = iterator(item, async(callback)); + } + // otherwise go with full three arguments + else + { + aborter = iterator(item, key, async(callback)); + } + + return aborter; +} diff --git a/user/themes/goku/node_modules/asynckit/lib/readable_asynckit.js b/user/themes/goku/node_modules/asynckit/lib/readable_asynckit.js new file mode 100644 index 00000000..78ad240f --- /dev/null +++ b/user/themes/goku/node_modules/asynckit/lib/readable_asynckit.js @@ -0,0 +1,91 @@ +var streamify = require('./streamify.js') + , defer = require('./defer.js') + ; + +// API +module.exports = ReadableAsyncKit; + +/** + * Base constructor for all streams + * used to hold properties/methods + */ +function ReadableAsyncKit() +{ + ReadableAsyncKit.super_.apply(this, arguments); + + // list of active jobs + this.jobs = {}; + + // add stream methods + this.destroy = destroy; + this._start = _start; + this._read = _read; +} + +/** + * Destroys readable stream, + * by aborting outstanding jobs + * + * @returns {void} + */ +function destroy() +{ + if (this.destroyed) + { + return; + } + + this.destroyed = true; + + if (typeof this.terminator == 'function') + { + this.terminator(); + } +} + +/** + * Starts provided jobs in async manner + * + * @private + */ +function _start() +{ + // first argument – runner function + var runner = arguments[0] + // take away first argument + , args = Array.prototype.slice.call(arguments, 1) + // second argument - input data + , input = args[0] + // last argument - result callback + , endCb = streamify.callback.call(this, args[args.length - 1]) + ; + + args[args.length - 1] = endCb; + // third argument - iterator + args[1] = streamify.iterator.call(this, args[1]); + + // allow time for proper setup + defer(function() + { + if (!this.destroyed) + { + this.terminator = runner.apply(null, args); + } + else + { + endCb(null, Array.isArray(input) ? [] : {}); + } + }.bind(this)); +} + + +/** + * Implement _read to comply with Readable streams + * Doesn't really make sense for flowing object mode + * + * @private + */ +function _read() +{ + +} diff --git a/user/themes/goku/node_modules/asynckit/lib/readable_parallel.js b/user/themes/goku/node_modules/asynckit/lib/readable_parallel.js new file mode 100644 index 00000000..5d2929f7 --- /dev/null +++ b/user/themes/goku/node_modules/asynckit/lib/readable_parallel.js @@ -0,0 +1,25 @@ +var parallel = require('../parallel.js'); + +// API +module.exports = ReadableParallel; + +/** + * Streaming wrapper to `asynckit.parallel` + * + * @param {array|object} list - array or object (named list) to iterate over + * @param {function} iterator - iterator to run + * @param {function} callback - invoked when all elements processed + * @returns {stream.Readable#} + */ +function ReadableParallel(list, iterator, callback) +{ + if (!(this instanceof ReadableParallel)) + { + return new ReadableParallel(list, iterator, callback); + } + + // turn on object mode + ReadableParallel.super_.call(this, {objectMode: true}); + + this._start(parallel, list, iterator, callback); +} diff --git a/user/themes/goku/node_modules/asynckit/lib/readable_serial.js b/user/themes/goku/node_modules/asynckit/lib/readable_serial.js new file mode 100644 index 00000000..78226982 --- /dev/null +++ b/user/themes/goku/node_modules/asynckit/lib/readable_serial.js @@ -0,0 +1,25 @@ +var serial = require('../serial.js'); + +// API +module.exports = ReadableSerial; + +/** + * Streaming wrapper to `asynckit.serial` + * + * @param {array|object} list - array or object (named list) to iterate over + * @param {function} iterator - iterator to run + * @param {function} callback - invoked when all elements processed + * @returns {stream.Readable#} + */ +function ReadableSerial(list, iterator, callback) +{ + if (!(this instanceof ReadableSerial)) + { + return new ReadableSerial(list, iterator, callback); + } + + // turn on object mode + ReadableSerial.super_.call(this, {objectMode: true}); + + this._start(serial, list, iterator, callback); +} diff --git a/user/themes/goku/node_modules/asynckit/lib/readable_serial_ordered.js b/user/themes/goku/node_modules/asynckit/lib/readable_serial_ordered.js new file mode 100644 index 00000000..3de89c47 --- /dev/null +++ b/user/themes/goku/node_modules/asynckit/lib/readable_serial_ordered.js @@ -0,0 +1,29 @@ +var serialOrdered = require('../serialOrdered.js'); + +// API +module.exports = ReadableSerialOrdered; +// expose sort helpers +module.exports.ascending = serialOrdered.ascending; +module.exports.descending = serialOrdered.descending; + +/** + * Streaming wrapper to `asynckit.serialOrdered` + * + * @param {array|object} list - array or object (named list) to iterate over + * @param {function} iterator - iterator to run + * @param {function} sortMethod - custom sort function + * @param {function} callback - invoked when all elements processed + * @returns {stream.Readable#} + */ +function ReadableSerialOrdered(list, iterator, sortMethod, callback) +{ + if (!(this instanceof ReadableSerialOrdered)) + { + return new ReadableSerialOrdered(list, iterator, sortMethod, callback); + } + + // turn on object mode + ReadableSerialOrdered.super_.call(this, {objectMode: true}); + + this._start(serialOrdered, list, iterator, sortMethod, callback); +} diff --git a/user/themes/goku/node_modules/asynckit/lib/state.js b/user/themes/goku/node_modules/asynckit/lib/state.js new file mode 100644 index 00000000..cbea7ad8 --- /dev/null +++ b/user/themes/goku/node_modules/asynckit/lib/state.js @@ -0,0 +1,37 @@ +// API +module.exports = state; + +/** + * Creates initial state object + * for iteration over list + * + * @param {array|object} list - list to iterate over + * @param {function|null} sortMethod - function to use for keys sort, + * or `null` to keep them as is + * @returns {object} - initial state object + */ +function state(list, sortMethod) +{ + var isNamedList = !Array.isArray(list) + , initState = + { + index : 0, + keyedList: isNamedList || sortMethod ? Object.keys(list) : null, + jobs : {}, + results : isNamedList ? {} : [], + size : isNamedList ? Object.keys(list).length : list.length + } + ; + + if (sortMethod) + { + // sort array keys based on it's values + // sort object's keys just on own merit + initState.keyedList.sort(isNamedList ? sortMethod : function(a, b) + { + return sortMethod(list[a], list[b]); + }); + } + + return initState; +} diff --git a/user/themes/goku/node_modules/asynckit/lib/streamify.js b/user/themes/goku/node_modules/asynckit/lib/streamify.js new file mode 100644 index 00000000..f56a1c92 --- /dev/null +++ b/user/themes/goku/node_modules/asynckit/lib/streamify.js @@ -0,0 +1,141 @@ +var async = require('./async.js'); + +// API +module.exports = { + iterator: wrapIterator, + callback: wrapCallback +}; + +/** + * Wraps iterators with long signature + * + * @this ReadableAsyncKit# + * @param {function} iterator - function to wrap + * @returns {function} - wrapped function + */ +function wrapIterator(iterator) +{ + var stream = this; + + return function(item, key, cb) + { + var aborter + , wrappedCb = async(wrapIteratorCallback.call(stream, cb, key)) + ; + + stream.jobs[key] = wrappedCb; + + // it's either shortcut (item, cb) + if (iterator.length == 2) + { + aborter = iterator(item, wrappedCb); + } + // or long format (item, key, cb) + else + { + aborter = iterator(item, key, wrappedCb); + } + + return aborter; + }; +} + +/** + * Wraps provided callback function + * allowing to execute snitch function before + * real callback + * + * @this ReadableAsyncKit# + * @param {function} callback - function to wrap + * @returns {function} - wrapped function + */ +function wrapCallback(callback) +{ + var stream = this; + + var wrapped = function(error, result) + { + return finisher.call(stream, error, result, callback); + }; + + return wrapped; +} + +/** + * Wraps provided iterator callback function + * makes sure snitch only called once, + * but passes secondary calls to the original callback + * + * @this ReadableAsyncKit# + * @param {function} callback - callback to wrap + * @param {number|string} key - iteration key + * @returns {function} wrapped callback + */ +function wrapIteratorCallback(callback, key) +{ + var stream = this; + + return function(error, output) + { + // don't repeat yourself + if (!(key in stream.jobs)) + { + callback(error, output); + return; + } + + // clean up jobs + delete stream.jobs[key]; + + return streamer.call(stream, error, {key: key, value: output}, callback); + }; +} + +/** + * Stream wrapper for iterator callback + * + * @this ReadableAsyncKit# + * @param {mixed} error - error response + * @param {mixed} output - iterator output + * @param {function} callback - callback that expects iterator results + */ +function streamer(error, output, callback) +{ + if (error && !this.error) + { + this.error = error; + this.pause(); + this.emit('error', error); + // send back value only, as expected + callback(error, output && output.value); + return; + } + + // stream stuff + this.push(output); + + // back to original track + // send back value only, as expected + callback(error, output && output.value); +} + +/** + * Stream wrapper for finishing callback + * + * @this ReadableAsyncKit# + * @param {mixed} error - error response + * @param {mixed} output - iterator output + * @param {function} callback - callback that expects final results + */ +function finisher(error, output, callback) +{ + // signal end of the stream + // only for successfully finished streams + if (!error) + { + this.push(null); + } + + // back to original track + callback(error, output); +} diff --git a/user/themes/goku/node_modules/asynckit/lib/terminator.js b/user/themes/goku/node_modules/asynckit/lib/terminator.js new file mode 100644 index 00000000..d6eb9921 --- /dev/null +++ b/user/themes/goku/node_modules/asynckit/lib/terminator.js @@ -0,0 +1,29 @@ +var abort = require('./abort.js') + , async = require('./async.js') + ; + +// API +module.exports = terminator; + +/** + * Terminates jobs in the attached state context + * + * @this AsyncKitState# + * @param {function} callback - final callback to invoke after termination + */ +function terminator(callback) +{ + if (!Object.keys(this.jobs).length) + { + return; + } + + // fast forward iteration index + this.index = this.size; + + // abort jobs + abort(this); + + // send back results we have so far + async(callback)(null, this.results); +} diff --git a/user/themes/goku/node_modules/asynckit/package.json b/user/themes/goku/node_modules/asynckit/package.json new file mode 100644 index 00000000..ba3099b8 --- /dev/null +++ b/user/themes/goku/node_modules/asynckit/package.json @@ -0,0 +1,91 @@ +{ + "_from": "asynckit@^0.4.0", + "_id": "asynckit@0.4.0", + "_inBundle": false, + "_integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "_location": "/asynckit", + "_phantomChildren": {}, + "_requested": { + "type": "range", + "registry": true, + "raw": "asynckit@^0.4.0", + "name": "asynckit", + "escapedName": "asynckit", + "rawSpec": "^0.4.0", + "saveSpec": null, + "fetchSpec": "^0.4.0" + }, + "_requiredBy": [ + "/form-data" + ], + "_resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "_shasum": "c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79", + "_spec": "asynckit@^0.4.0", + "_where": "/srv/http/berryfarmprojects.org.uk/stay-grav/user/themes/goku/node_modules/form-data", + "author": { + "name": "Alex Indigo", + "email": "iam@alexindigo.com" + }, + "bugs": { + "url": "https://github.com/alexindigo/asynckit/issues" + }, + "bundleDependencies": false, + "dependencies": {}, + "deprecated": false, + "description": "Minimal async jobs utility library, with streams support", + "devDependencies": { + "browserify": "^13.0.0", + "browserify-istanbul": "^2.0.0", + "coveralls": "^2.11.9", + "eslint": "^2.9.0", + "istanbul": "^0.4.3", + "obake": "^0.1.2", + "phantomjs-prebuilt": "^2.1.7", + "pre-commit": "^1.1.3", + "reamde": "^1.1.0", + "rimraf": "^2.5.2", + "size-table": "^0.2.0", + "tap-spec": "^4.1.1", + "tape": "^4.5.1" + }, + "homepage": "https://github.com/alexindigo/asynckit#readme", + "keywords": [ + "async", + "jobs", + "parallel", + "serial", + "iterator", + "array", + "object", + "stream", + "destroy", + "terminate", + "abort" + ], + "license": "MIT", + "main": "index.js", + "name": "asynckit", + "pre-commit": [ + "clean", + "lint", + "test", + "browser", + "report", + "size" + ], + "repository": { + "type": "git", + "url": "git+https://github.com/alexindigo/asynckit.git" + }, + "scripts": { + "browser": "browserify -t browserify-istanbul test/lib/browserify_adjustment.js test/test-*.js | obake --coverage | tap-spec", + "clean": "rimraf coverage", + "debug": "tape test/test-*.js", + "lint": "eslint *.js lib/*.js test/*.js", + "report": "istanbul report", + "size": "browserify index.js | size-table asynckit", + "test": "istanbul cover --reporter=json tape -- 'test/test-*.js' | tap-spec", + "win-test": "tape test/test-*.js" + }, + "version": "0.4.0" +} diff --git a/user/themes/goku/node_modules/asynckit/parallel.js b/user/themes/goku/node_modules/asynckit/parallel.js new file mode 100644 index 00000000..3c50344d --- /dev/null +++ b/user/themes/goku/node_modules/asynckit/parallel.js @@ -0,0 +1,43 @@ +var iterate = require('./lib/iterate.js') + , initState = require('./lib/state.js') + , terminator = require('./lib/terminator.js') + ; + +// Public API +module.exports = parallel; + +/** + * Runs iterator over provided array elements in parallel + * + * @param {array|object} list - array or object (named list) to iterate over + * @param {function} iterator - iterator to run + * @param {function} callback - invoked when all elements processed + * @returns {function} - jobs terminator + */ +function parallel(list, iterator, callback) +{ + var state = initState(list); + + while (state.index < (state['keyedList'] || list).length) + { + iterate(list, iterator, state, function(error, result) + { + if (error) + { + callback(error, result); + return; + } + + // looks like it's the last one + if (Object.keys(state.jobs).length === 0) + { + callback(null, state.results); + return; + } + }); + + state.index++; + } + + return terminator.bind(state, callback); +} diff --git a/user/themes/goku/node_modules/asynckit/serial.js b/user/themes/goku/node_modules/asynckit/serial.js new file mode 100644 index 00000000..6cd949a6 --- /dev/null +++ b/user/themes/goku/node_modules/asynckit/serial.js @@ -0,0 +1,17 @@ +var serialOrdered = require('./serialOrdered.js'); + +// Public API +module.exports = serial; + +/** + * Runs iterator over provided array elements in series + * + * @param {array|object} list - array or object (named list) to iterate over + * @param {function} iterator - iterator to run + * @param {function} callback - invoked when all elements processed + * @returns {function} - jobs terminator + */ +function serial(list, iterator, callback) +{ + return serialOrdered(list, iterator, null, callback); +} diff --git a/user/themes/goku/node_modules/asynckit/serialOrdered.js b/user/themes/goku/node_modules/asynckit/serialOrdered.js new file mode 100644 index 00000000..607eafea --- /dev/null +++ b/user/themes/goku/node_modules/asynckit/serialOrdered.js @@ -0,0 +1,75 @@ +var iterate = require('./lib/iterate.js') + , initState = require('./lib/state.js') + , terminator = require('./lib/terminator.js') + ; + +// Public API +module.exports = serialOrdered; +// sorting helpers +module.exports.ascending = ascending; +module.exports.descending = descending; + +/** + * Runs iterator over provided sorted array elements in series + * + * @param {array|object} list - array or object (named list) to iterate over + * @param {function} iterator - iterator to run + * @param {function} sortMethod - custom sort function + * @param {function} callback - invoked when all elements processed + * @returns {function} - jobs terminator + */ +function serialOrdered(list, iterator, sortMethod, callback) +{ + var state = initState(list, sortMethod); + + iterate(list, iterator, state, function iteratorHandler(error, result) + { + if (error) + { + callback(error, result); + return; + } + + state.index++; + + // are we there yet? + if (state.index < (state['keyedList'] || list).length) + { + iterate(list, iterator, state, iteratorHandler); + return; + } + + // done here + callback(null, state.results); + }); + + return terminator.bind(state, callback); +} + +/* + * -- Sort methods + */ + +/** + * sort helper to sort array elements in ascending order + * + * @param {mixed} a - an item to compare + * @param {mixed} b - an item to compare + * @returns {number} - comparison result + */ +function ascending(a, b) +{ + return a < b ? -1 : a > b ? 1 : 0; +} + +/** + * sort helper to sort array elements in descending order + * + * @param {mixed} a - an item to compare + * @param {mixed} b - an item to compare + * @returns {number} - comparison result + */ +function descending(a, b) +{ + return -1 * ascending(a, b); +} diff --git a/user/themes/goku/node_modules/asynckit/stream.js b/user/themes/goku/node_modules/asynckit/stream.js new file mode 100644 index 00000000..d43465f9 --- /dev/null +++ b/user/themes/goku/node_modules/asynckit/stream.js @@ -0,0 +1,21 @@ +var inherits = require('util').inherits + , Readable = require('stream').Readable + , ReadableAsyncKit = require('./lib/readable_asynckit.js') + , ReadableParallel = require('./lib/readable_parallel.js') + , ReadableSerial = require('./lib/readable_serial.js') + , ReadableSerialOrdered = require('./lib/readable_serial_ordered.js') + ; + +// API +module.exports = +{ + parallel : ReadableParallel, + serial : ReadableSerial, + serialOrdered : ReadableSerialOrdered, +}; + +inherits(ReadableAsyncKit, Readable); + +inherits(ReadableParallel, ReadableAsyncKit); +inherits(ReadableSerial, ReadableAsyncKit); +inherits(ReadableSerialOrdered, ReadableAsyncKit); diff --git a/user/themes/goku/node_modules/aws-sign2/LICENSE b/user/themes/goku/node_modules/aws-sign2/LICENSE new file mode 100644 index 00000000..a4a9aee0 --- /dev/null +++ b/user/themes/goku/node_modules/aws-sign2/LICENSE @@ -0,0 +1,55 @@ +Apache License + +Version 2.0, January 2004 + +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + +"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: + +You must give any other recipients of the Work or Derivative Works a copy of this License; and + +You must cause any modified files to carry prominent notices stating that You changed the files; and + +You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and + +If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS \ No newline at end of file diff --git a/user/themes/goku/node_modules/aws-sign2/README.md b/user/themes/goku/node_modules/aws-sign2/README.md new file mode 100644 index 00000000..763564e0 --- /dev/null +++ b/user/themes/goku/node_modules/aws-sign2/README.md @@ -0,0 +1,4 @@ +aws-sign +======== + +AWS signing. Originally pulled from LearnBoost/knox, maintained as vendor in request, now a standalone module. diff --git a/user/themes/goku/node_modules/aws-sign2/index.js b/user/themes/goku/node_modules/aws-sign2/index.js new file mode 100644 index 00000000..fb35f6db --- /dev/null +++ b/user/themes/goku/node_modules/aws-sign2/index.js @@ -0,0 +1,212 @@ + +/*! + * Copyright 2010 LearnBoost + * + * 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. + */ + +/** + * Module dependencies. + */ + +var crypto = require('crypto') + , parse = require('url').parse + ; + +/** + * Valid keys. + */ + +var keys = + [ 'acl' + , 'location' + , 'logging' + , 'notification' + , 'partNumber' + , 'policy' + , 'requestPayment' + , 'torrent' + , 'uploadId' + , 'uploads' + , 'versionId' + , 'versioning' + , 'versions' + , 'website' + ] + +/** + * Return an "Authorization" header value with the given `options` + * in the form of "AWS :" + * + * @param {Object} options + * @return {String} + * @api private + */ + +function authorization (options) { + return 'AWS ' + options.key + ':' + sign(options) +} + +module.exports = authorization +module.exports.authorization = authorization + +/** + * Simple HMAC-SHA1 Wrapper + * + * @param {Object} options + * @return {String} + * @api private + */ + +function hmacSha1 (options) { + return crypto.createHmac('sha1', options.secret).update(options.message).digest('base64') +} + +module.exports.hmacSha1 = hmacSha1 + +/** + * Create a base64 sha1 HMAC for `options`. + * + * @param {Object} options + * @return {String} + * @api private + */ + +function sign (options) { + options.message = stringToSign(options) + return hmacSha1(options) +} +module.exports.sign = sign + +/** + * Create a base64 sha1 HMAC for `options`. + * + * Specifically to be used with S3 presigned URLs + * + * @param {Object} options + * @return {String} + * @api private + */ + +function signQuery (options) { + options.message = queryStringToSign(options) + return hmacSha1(options) +} +module.exports.signQuery= signQuery + +/** + * Return a string for sign() with the given `options`. + * + * Spec: + * + * \n + * \n + * \n + * \n + * [headers\n] + * + * + * @param {Object} options + * @return {String} + * @api private + */ + +function stringToSign (options) { + var headers = options.amazonHeaders || '' + if (headers) headers += '\n' + var r = + [ options.verb + , options.md5 + , options.contentType + , options.date ? options.date.toUTCString() : '' + , headers + options.resource + ] + return r.join('\n') +} +module.exports.stringToSign = stringToSign + +/** + * Return a string for sign() with the given `options`, but is meant exclusively + * for S3 presigned URLs + * + * Spec: + * + * \n + * + * + * @param {Object} options + * @return {String} + * @api private + */ + +function queryStringToSign (options){ + return 'GET\n\n\n' + options.date + '\n' + options.resource +} +module.exports.queryStringToSign = queryStringToSign + +/** + * Perform the following: + * + * - ignore non-amazon headers + * - lowercase fields + * - sort lexicographically + * - trim whitespace between ":" + * - join with newline + * + * @param {Object} headers + * @return {String} + * @api private + */ + +function canonicalizeHeaders (headers) { + var buf = [] + , fields = Object.keys(headers) + ; + for (var i = 0, len = fields.length; i < len; ++i) { + var field = fields[i] + , val = headers[field] + , field = field.toLowerCase() + ; + if (0 !== field.indexOf('x-amz')) continue + buf.push(field + ':' + val) + } + return buf.sort().join('\n') +} +module.exports.canonicalizeHeaders = canonicalizeHeaders + +/** + * Perform the following: + * + * - ignore non sub-resources + * - sort lexicographically + * + * @param {String} resource + * @return {String} + * @api private + */ + +function canonicalizeResource (resource) { + var url = parse(resource, true) + , path = url.pathname + , buf = [] + ; + + Object.keys(url.query).forEach(function(key){ + if (!~keys.indexOf(key)) return + var val = '' == url.query[key] ? '' : '=' + encodeURIComponent(url.query[key]) + buf.push(key + val) + }) + + return path + (buf.length ? '?' + buf.sort().join('&') : '') +} +module.exports.canonicalizeResource = canonicalizeResource diff --git a/user/themes/goku/node_modules/aws-sign2/package.json b/user/themes/goku/node_modules/aws-sign2/package.json new file mode 100644 index 00000000..7ef83a90 --- /dev/null +++ b/user/themes/goku/node_modules/aws-sign2/package.json @@ -0,0 +1,50 @@ +{ + "_from": "aws-sign2@~0.7.0", + "_id": "aws-sign2@0.7.0", + "_inBundle": false, + "_integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "_location": "/aws-sign2", + "_phantomChildren": {}, + "_requested": { + "type": "range", + "registry": true, + "raw": "aws-sign2@~0.7.0", + "name": "aws-sign2", + "escapedName": "aws-sign2", + "rawSpec": "~0.7.0", + "saveSpec": null, + "fetchSpec": "~0.7.0" + }, + "_requiredBy": [ + "/request" + ], + "_resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "_shasum": "b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8", + "_spec": "aws-sign2@~0.7.0", + "_where": "/srv/http/berryfarmprojects.org.uk/stay-grav/user/themes/goku/node_modules/request", + "author": { + "name": "Mikeal Rogers", + "email": "mikeal.rogers@gmail.com", + "url": "http://www.futurealoof.com" + }, + "bugs": { + "url": "https://github.com/mikeal/aws-sign/issues" + }, + "bundleDependencies": false, + "dependencies": {}, + "deprecated": false, + "description": "AWS signing. Originally pulled from LearnBoost/knox, maintained as vendor in request, now a standalone module.", + "devDependencies": {}, + "engines": { + "node": "*" + }, + "homepage": "https://github.com/mikeal/aws-sign#readme", + "license": "Apache-2.0", + "main": "index.js", + "name": "aws-sign2", + "optionalDependencies": {}, + "repository": { + "url": "git+https://github.com/mikeal/aws-sign.git" + }, + "version": "0.7.0" +} diff --git a/user/themes/goku/node_modules/aws4/.travis.yml b/user/themes/goku/node_modules/aws4/.travis.yml new file mode 100644 index 00000000..178bf31e --- /dev/null +++ b/user/themes/goku/node_modules/aws4/.travis.yml @@ -0,0 +1,9 @@ +language: node_js +node_js: + - "0.10" + - "0.12" + - "4" + - "6" + - "8" + - "10" + - "12" diff --git a/user/themes/goku/node_modules/aws4/LICENSE b/user/themes/goku/node_modules/aws4/LICENSE new file mode 100644 index 00000000..4f321e59 --- /dev/null +++ b/user/themes/goku/node_modules/aws4/LICENSE @@ -0,0 +1,19 @@ +Copyright 2013 Michael Hart (michael.hart.au@gmail.com) + +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. diff --git a/user/themes/goku/node_modules/aws4/README.md b/user/themes/goku/node_modules/aws4/README.md new file mode 100644 index 00000000..6b002d02 --- /dev/null +++ b/user/themes/goku/node_modules/aws4/README.md @@ -0,0 +1,523 @@ +aws4 +---- + +[![Build Status](https://secure.travis-ci.org/mhart/aws4.png?branch=master)](http://travis-ci.org/mhart/aws4) + +A small utility to sign vanilla node.js http(s) request options using Amazon's +[AWS Signature Version 4](http://docs.amazonwebservices.com/general/latest/gr/signature-version-4.html). + +Can also be used [in the browser](./browser). + +This signature is supported by nearly all Amazon services, including +[S3](http://docs.aws.amazon.com/AmazonS3/latest/API/), +[EC2](http://docs.aws.amazon.com/AWSEC2/latest/APIReference/), +[DynamoDB](http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/API.html), +[Kinesis](http://docs.aws.amazon.com/kinesis/latest/APIReference/), +[Lambda](http://docs.aws.amazon.com/lambda/latest/dg/API_Reference.html), +[SQS](http://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/), +[SNS](http://docs.aws.amazon.com/sns/latest/api/), +[IAM](http://docs.aws.amazon.com/IAM/latest/APIReference/), +[STS](http://docs.aws.amazon.com/STS/latest/APIReference/), +[RDS](http://docs.aws.amazon.com/AmazonRDS/latest/APIReference/), +[CloudWatch](http://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/), +[CloudWatch Logs](http://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/), +[CodeDeploy](http://docs.aws.amazon.com/codedeploy/latest/APIReference/), +[CloudFront](http://docs.aws.amazon.com/AmazonCloudFront/latest/APIReference/), +[CloudTrail](http://docs.aws.amazon.com/awscloudtrail/latest/APIReference/), +[ElastiCache](http://docs.aws.amazon.com/AmazonElastiCache/latest/APIReference/), +[EMR](http://docs.aws.amazon.com/ElasticMapReduce/latest/API/), +[Glacier](http://docs.aws.amazon.com/amazonglacier/latest/dev/amazon-glacier-api.html), +[CloudSearch](http://docs.aws.amazon.com/cloudsearch/latest/developerguide/APIReq.html), +[Elastic Load Balancing](http://docs.aws.amazon.com/ElasticLoadBalancing/latest/APIReference/), +[Elastic Transcoder](http://docs.aws.amazon.com/elastictranscoder/latest/developerguide/api-reference.html), +[CloudFormation](http://docs.aws.amazon.com/AWSCloudFormation/latest/APIReference/), +[Elastic Beanstalk](http://docs.aws.amazon.com/elasticbeanstalk/latest/api/), +[Storage Gateway](http://docs.aws.amazon.com/storagegateway/latest/userguide/AWSStorageGatewayAPI.html), +[Data Pipeline](http://docs.aws.amazon.com/datapipeline/latest/APIReference/), +[Direct Connect](http://docs.aws.amazon.com/directconnect/latest/APIReference/), +[Redshift](http://docs.aws.amazon.com/redshift/latest/APIReference/), +[OpsWorks](http://docs.aws.amazon.com/opsworks/latest/APIReference/), +[SES](http://docs.aws.amazon.com/ses/latest/APIReference/), +[SWF](http://docs.aws.amazon.com/amazonswf/latest/apireference/), +[AutoScaling](http://docs.aws.amazon.com/AutoScaling/latest/APIReference/), +[Mobile Analytics](http://docs.aws.amazon.com/mobileanalytics/latest/ug/server-reference.html), +[Cognito Identity](http://docs.aws.amazon.com/cognitoidentity/latest/APIReference/), +[Cognito Sync](http://docs.aws.amazon.com/cognitosync/latest/APIReference/), +[Container Service](http://docs.aws.amazon.com/AmazonECS/latest/APIReference/), +[AppStream](http://docs.aws.amazon.com/appstream/latest/developerguide/appstream-api-rest.html), +[Key Management Service](http://docs.aws.amazon.com/kms/latest/APIReference/), +[Config](http://docs.aws.amazon.com/config/latest/APIReference/), +[CloudHSM](http://docs.aws.amazon.com/cloudhsm/latest/dg/api-ref.html), +[Route53](http://docs.aws.amazon.com/Route53/latest/APIReference/requests-rest.html) and +[Route53 Domains](http://docs.aws.amazon.com/Route53/latest/APIReference/requests-rpc.html). + +Indeed, the only AWS services that *don't* support v4 as of 2014-12-30 are +[Import/Export](http://docs.aws.amazon.com/AWSImportExport/latest/DG/api-reference.html) and +[SimpleDB](http://docs.aws.amazon.com/AmazonSimpleDB/latest/DeveloperGuide/SDB_API.html) +(they only support [AWS Signature Version 2](https://github.com/mhart/aws2)). + +It also provides defaults for a number of core AWS headers and +request parameters, making it very easy to query AWS services, or +build out a fully-featured AWS library. + +Example +------- + +```javascript +var http = require('http'), + https = require('https'), + aws4 = require('aws4') + +// given an options object you could pass to http.request +var opts = {host: 'sqs.us-east-1.amazonaws.com', path: '/?Action=ListQueues'} + +// alternatively (as aws4 can infer the host): +opts = {service: 'sqs', region: 'us-east-1', path: '/?Action=ListQueues'} + +// alternatively (as us-east-1 is default): +opts = {service: 'sqs', path: '/?Action=ListQueues'} + +aws4.sign(opts) // assumes AWS credentials are available in process.env + +console.log(opts) +/* +{ + host: 'sqs.us-east-1.amazonaws.com', + path: '/?Action=ListQueues', + headers: { + Host: 'sqs.us-east-1.amazonaws.com', + 'X-Amz-Date': '20121226T061030Z', + Authorization: 'AWS4-HMAC-SHA256 Credential=ABCDEF/20121226/us-east-1/sqs/aws4_request, ...' + } +} +*/ + +// we can now use this to query AWS using the standard node.js http API +http.request(opts, function(res) { res.pipe(process.stdout) }).end() +/* + + +... +*/ +``` + +More options +------------ + +```javascript +// you can also pass AWS credentials in explicitly (otherwise taken from process.env) +aws4.sign(opts, {accessKeyId: '', secretAccessKey: ''}) + +// can also add the signature to query strings +aws4.sign({service: 's3', path: '/my-bucket?X-Amz-Expires=12345', signQuery: true}) + +// create a utility function to pipe to stdout (with https this time) +function request(o) { https.request(o, function(res) { res.pipe(process.stdout) }).end(o.body || '') } + +// aws4 can infer the HTTP method if a body is passed in +// method will be POST and Content-Type: 'application/x-www-form-urlencoded; charset=utf-8' +request(aws4.sign({service: 'iam', body: 'Action=ListGroups&Version=2010-05-08'})) +/* + +... +*/ + +// can specify any custom option or header as per usual +request(aws4.sign({ + service: 'dynamodb', + region: 'ap-southeast-2', + method: 'POST', + path: '/', + headers: { + 'Content-Type': 'application/x-amz-json-1.0', + 'X-Amz-Target': 'DynamoDB_20120810.ListTables' + }, + body: '{}' +})) +/* +{"TableNames":[]} +... +*/ + +// works with all other services that support Signature Version 4 + +request(aws4.sign({service: 's3', path: '/', signQuery: true})) +/* + +... +*/ + +request(aws4.sign({service: 'ec2', path: '/?Action=DescribeRegions&Version=2014-06-15'})) +/* + +... +*/ + +request(aws4.sign({service: 'sns', path: '/?Action=ListTopics&Version=2010-03-31'})) +/* + +... +*/ + +request(aws4.sign({service: 'sts', path: '/?Action=GetSessionToken&Version=2011-06-15'})) +/* + +... +*/ + +request(aws4.sign({service: 'cloudsearch', path: '/?Action=ListDomainNames&Version=2013-01-01'})) +/* + +... +*/ + +request(aws4.sign({service: 'ses', path: '/?Action=ListIdentities&Version=2010-12-01'})) +/* + +... +*/ + +request(aws4.sign({service: 'autoscaling', path: '/?Action=DescribeAutoScalingInstances&Version=2011-01-01'})) +/* + +... +*/ + +request(aws4.sign({service: 'elasticloadbalancing', path: '/?Action=DescribeLoadBalancers&Version=2012-06-01'})) +/* + +... +*/ + +request(aws4.sign({service: 'cloudformation', path: '/?Action=ListStacks&Version=2010-05-15'})) +/* + +... +*/ + +request(aws4.sign({service: 'elasticbeanstalk', path: '/?Action=ListAvailableSolutionStacks&Version=2010-12-01'})) +/* + +... +*/ + +request(aws4.sign({service: 'rds', path: '/?Action=DescribeDBInstances&Version=2012-09-17'})) +/* + +... +*/ + +request(aws4.sign({service: 'monitoring', path: '/?Action=ListMetrics&Version=2010-08-01'})) +/* + +... +*/ + +request(aws4.sign({service: 'redshift', path: '/?Action=DescribeClusters&Version=2012-12-01'})) +/* + +... +*/ + +request(aws4.sign({service: 'cloudfront', path: '/2014-05-31/distribution'})) +/* + +... +*/ + +request(aws4.sign({service: 'elasticache', path: '/?Action=DescribeCacheClusters&Version=2014-07-15'})) +/* + +... +*/ + +request(aws4.sign({service: 'elasticmapreduce', path: '/?Action=DescribeJobFlows&Version=2009-03-31'})) +/* + +... +*/ + +request(aws4.sign({service: 'route53', path: '/2013-04-01/hostedzone'})) +/* + +... +*/ + +request(aws4.sign({service: 'appstream', path: '/applications'})) +/* +{"_links":{"curie":[{"href":"http://docs.aws.amazon.com/appstream/latest/... +... +*/ + +request(aws4.sign({service: 'cognito-sync', path: '/identitypools'})) +/* +{"Count":0,"IdentityPoolUsages":[],"MaxResults":16,"NextToken":null} +... +*/ + +request(aws4.sign({service: 'elastictranscoder', path: '/2012-09-25/pipelines'})) +/* +{"NextPageToken":null,"Pipelines":[]} +... +*/ + +request(aws4.sign({service: 'lambda', path: '/2014-11-13/functions/'})) +/* +{"Functions":[],"NextMarker":null} +... +*/ + +request(aws4.sign({service: 'ecs', path: '/?Action=ListClusters&Version=2014-11-13'})) +/* + +... +*/ + +request(aws4.sign({service: 'glacier', path: '/-/vaults', headers: {'X-Amz-Glacier-Version': '2012-06-01'}})) +/* +{"Marker":null,"VaultList":[]} +... +*/ + +request(aws4.sign({service: 'storagegateway', body: '{}', headers: { + 'Content-Type': 'application/x-amz-json-1.1', + 'X-Amz-Target': 'StorageGateway_20120630.ListGateways' +}})) +/* +{"Gateways":[]} +... +*/ + +request(aws4.sign({service: 'datapipeline', body: '{}', headers: { + 'Content-Type': 'application/x-amz-json-1.1', + 'X-Amz-Target': 'DataPipeline.ListPipelines' +}})) +/* +{"hasMoreResults":false,"pipelineIdList":[]} +... +*/ + +request(aws4.sign({service: 'opsworks', body: '{}', headers: { + 'Content-Type': 'application/x-amz-json-1.1', + 'X-Amz-Target': 'OpsWorks_20130218.DescribeStacks' +}})) +/* +{"Stacks":[]} +... +*/ + +request(aws4.sign({service: 'route53domains', body: '{}', headers: { + 'Content-Type': 'application/x-amz-json-1.1', + 'X-Amz-Target': 'Route53Domains_v20140515.ListDomains' +}})) +/* +{"Domains":[]} +... +*/ + +request(aws4.sign({service: 'kinesis', body: '{}', headers: { + 'Content-Type': 'application/x-amz-json-1.1', + 'X-Amz-Target': 'Kinesis_20131202.ListStreams' +}})) +/* +{"HasMoreStreams":false,"StreamNames":[]} +... +*/ + +request(aws4.sign({service: 'cloudtrail', body: '{}', headers: { + 'Content-Type': 'application/x-amz-json-1.1', + 'X-Amz-Target': 'CloudTrail_20131101.DescribeTrails' +}})) +/* +{"trailList":[]} +... +*/ + +request(aws4.sign({service: 'logs', body: '{}', headers: { + 'Content-Type': 'application/x-amz-json-1.1', + 'X-Amz-Target': 'Logs_20140328.DescribeLogGroups' +}})) +/* +{"logGroups":[]} +... +*/ + +request(aws4.sign({service: 'codedeploy', body: '{}', headers: { + 'Content-Type': 'application/x-amz-json-1.1', + 'X-Amz-Target': 'CodeDeploy_20141006.ListApplications' +}})) +/* +{"applications":[]} +... +*/ + +request(aws4.sign({service: 'directconnect', body: '{}', headers: { + 'Content-Type': 'application/x-amz-json-1.1', + 'X-Amz-Target': 'OvertureService.DescribeConnections' +}})) +/* +{"connections":[]} +... +*/ + +request(aws4.sign({service: 'kms', body: '{}', headers: { + 'Content-Type': 'application/x-amz-json-1.1', + 'X-Amz-Target': 'TrentService.ListKeys' +}})) +/* +{"Keys":[],"Truncated":false} +... +*/ + +request(aws4.sign({service: 'config', body: '{}', headers: { + 'Content-Type': 'application/x-amz-json-1.1', + 'X-Amz-Target': 'StarlingDoveService.DescribeDeliveryChannels' +}})) +/* +{"DeliveryChannels":[]} +... +*/ + +request(aws4.sign({service: 'cloudhsm', body: '{}', headers: { + 'Content-Type': 'application/x-amz-json-1.1', + 'X-Amz-Target': 'CloudHsmFrontendService.ListAvailableZones' +}})) +/* +{"AZList":["us-east-1a","us-east-1b","us-east-1c"]} +... +*/ + +request(aws4.sign({ + service: 'swf', + body: '{"registrationStatus":"REGISTERED"}', + headers: { + 'Content-Type': 'application/x-amz-json-1.0', + 'X-Amz-Target': 'SimpleWorkflowService.ListDomains' + } +})) +/* +{"domainInfos":[]} +... +*/ + +request(aws4.sign({ + service: 'cognito-identity', + body: '{"MaxResults": 1}', + headers: { + 'Content-Type': 'application/x-amz-json-1.1', + 'X-Amz-Target': 'AWSCognitoIdentityService.ListIdentityPools' + } +})) +/* +{"IdentityPools":[]} +... +*/ + +request(aws4.sign({ + service: 'mobileanalytics', + path: '/2014-06-05/events', + body: JSON.stringify({events:[{ + eventType: 'a', + timestamp: new Date().toISOString(), + session: {}, + }]}), + headers: { + 'Content-Type': 'application/json', + 'X-Amz-Client-Context': JSON.stringify({ + client: {client_id: 'a', app_title: 'a'}, + custom: {}, + env: {platform: 'a'}, + services: {}, + }), + } +})) +/* +(HTTP 202, empty response) +*/ + +// Generate CodeCommit Git access password +var signer = new aws4.RequestSigner({ + service: 'codecommit', + host: 'git-codecommit.us-east-1.amazonaws.com', + method: 'GIT', + path: '/v1/repos/MyAwesomeRepo', +}) +var password = signer.getDateTime() + 'Z' + signer.signature() +``` + +API +--- + +### aws4.sign(requestOptions, [credentials]) + +This calculates and populates the `Authorization` header of +`requestOptions`, and any other necessary AWS headers and/or request +options. Returns `requestOptions` as a convenience for chaining. + +`requestOptions` is an object holding the same options that the node.js +[http.request](http://nodejs.org/docs/latest/api/http.html#http_http_request_options_callback) +function takes. + +The following properties of `requestOptions` are used in the signing or +populated if they don't already exist: + +- `hostname` or `host` (will be determined from `service` and `region` if not given) +- `method` (will use `'GET'` if not given or `'POST'` if there is a `body`) +- `path` (will use `'/'` if not given) +- `body` (will use `''` if not given) +- `service` (will be calculated from `hostname` or `host` if not given) +- `region` (will be calculated from `hostname` or `host` or use `'us-east-1'` if not given) +- `headers['Host']` (will use `hostname` or `host` or be calculated if not given) +- `headers['Content-Type']` (will use `'application/x-www-form-urlencoded; charset=utf-8'` + if not given and there is a `body`) +- `headers['Date']` (used to calculate the signature date if given, otherwise `new Date` is used) + +Your AWS credentials (which can be found in your +[AWS console](https://portal.aws.amazon.com/gp/aws/securityCredentials)) +can be specified in one of two ways: + +- As the second argument, like this: + +```javascript +aws4.sign(requestOptions, { + secretAccessKey: "", + accessKeyId: "", + sessionToken: "" +}) +``` + +- From `process.env`, such as this: + +``` +export AWS_SECRET_ACCESS_KEY="" +export AWS_ACCESS_KEY_ID="" +export AWS_SESSION_TOKEN="" +``` + +(will also use `AWS_ACCESS_KEY` and `AWS_SECRET_KEY` if available) + +The `sessionToken` property and `AWS_SESSION_TOKEN` environment variable are optional for signing +with [IAM STS temporary credentials](http://docs.aws.amazon.com/STS/latest/UsingSTS/using-temp-creds.html). + +Installation +------------ + +With [npm](http://npmjs.org/) do: + +``` +npm install aws4 +``` + +Can also be used [in the browser](./browser). + +Thanks +------ + +Thanks to [@jed](https://github.com/jed) for his +[dynamo-client](https://github.com/jed/dynamo-client) lib where I first +committed and subsequently extracted this code. + +Also thanks to the +[official node.js AWS SDK](https://github.com/aws/aws-sdk-js) for giving +me a start on implementing the v4 signature. + diff --git a/user/themes/goku/node_modules/aws4/aws4.js b/user/themes/goku/node_modules/aws4/aws4.js new file mode 100644 index 00000000..1caafe38 --- /dev/null +++ b/user/themes/goku/node_modules/aws4/aws4.js @@ -0,0 +1,341 @@ +var aws4 = exports, + url = require('url'), + querystring = require('querystring'), + crypto = require('crypto'), + lru = require('./lru'), + credentialsCache = lru(1000) + +// http://docs.amazonwebservices.com/general/latest/gr/signature-version-4.html + +function hmac(key, string, encoding) { + return crypto.createHmac('sha256', key).update(string, 'utf8').digest(encoding) +} + +function hash(string, encoding) { + return crypto.createHash('sha256').update(string, 'utf8').digest(encoding) +} + +// This function assumes the string has already been percent encoded +function encodeRfc3986(urlEncodedString) { + return urlEncodedString.replace(/[!'()*]/g, function(c) { + return '%' + c.charCodeAt(0).toString(16).toUpperCase() + }) +} + +// request: { path | body, [host], [method], [headers], [service], [region] } +// credentials: { accessKeyId, secretAccessKey, [sessionToken] } +function RequestSigner(request, credentials) { + + if (typeof request === 'string') request = url.parse(request) + + var headers = request.headers = (request.headers || {}), + hostParts = this.matchHost(request.hostname || request.host || headers.Host || headers.host) + + this.request = request + this.credentials = credentials || this.defaultCredentials() + + this.service = request.service || hostParts[0] || '' + this.region = request.region || hostParts[1] || 'us-east-1' + + // SES uses a different domain from the service name + if (this.service === 'email') this.service = 'ses' + + if (!request.method && request.body) + request.method = 'POST' + + if (!headers.Host && !headers.host) { + headers.Host = request.hostname || request.host || this.createHost() + + // If a port is specified explicitly, use it as is + if (request.port) + headers.Host += ':' + request.port + } + if (!request.hostname && !request.host) + request.hostname = headers.Host || headers.host + + this.isCodeCommitGit = this.service === 'codecommit' && request.method === 'GIT' +} + +RequestSigner.prototype.matchHost = function(host) { + var match = (host || '').match(/([^\.]+)\.(?:([^\.]*)\.)?amazonaws\.com(\.cn)?$/) + var hostParts = (match || []).slice(1, 3) + + // ES's hostParts are sometimes the other way round, if the value that is expected + // to be region equals ‘es’ switch them back + // e.g. search-cluster-name-aaaa00aaaa0aaa0aaaaaaa0aaa.us-east-1.es.amazonaws.com + if (hostParts[1] === 'es') + hostParts = hostParts.reverse() + + return hostParts +} + +// http://docs.aws.amazon.com/general/latest/gr/rande.html +RequestSigner.prototype.isSingleRegion = function() { + // Special case for S3 and SimpleDB in us-east-1 + if (['s3', 'sdb'].indexOf(this.service) >= 0 && this.region === 'us-east-1') return true + + return ['cloudfront', 'ls', 'route53', 'iam', 'importexport', 'sts'] + .indexOf(this.service) >= 0 +} + +RequestSigner.prototype.createHost = function() { + var region = this.isSingleRegion() ? '' : + (this.service === 's3' && this.region !== 'us-east-1' ? '-' : '.') + this.region, + service = this.service === 'ses' ? 'email' : this.service + return service + region + '.amazonaws.com' +} + +RequestSigner.prototype.prepareRequest = function() { + this.parsePath() + + var request = this.request, headers = request.headers, query + + if (request.signQuery) { + + this.parsedPath.query = query = this.parsedPath.query || {} + + if (this.credentials.sessionToken) + query['X-Amz-Security-Token'] = this.credentials.sessionToken + + if (this.service === 's3' && !query['X-Amz-Expires']) + query['X-Amz-Expires'] = 86400 + + if (query['X-Amz-Date']) + this.datetime = query['X-Amz-Date'] + else + query['X-Amz-Date'] = this.getDateTime() + + query['X-Amz-Algorithm'] = 'AWS4-HMAC-SHA256' + query['X-Amz-Credential'] = this.credentials.accessKeyId + '/' + this.credentialString() + query['X-Amz-SignedHeaders'] = this.signedHeaders() + + } else { + + if (!request.doNotModifyHeaders && !this.isCodeCommitGit) { + if (request.body && !headers['Content-Type'] && !headers['content-type']) + headers['Content-Type'] = 'application/x-www-form-urlencoded; charset=utf-8' + + if (request.body && !headers['Content-Length'] && !headers['content-length']) + headers['Content-Length'] = Buffer.byteLength(request.body) + + if (this.credentials.sessionToken && !headers['X-Amz-Security-Token'] && !headers['x-amz-security-token']) + headers['X-Amz-Security-Token'] = this.credentials.sessionToken + + if (this.service === 's3' && !headers['X-Amz-Content-Sha256'] && !headers['x-amz-content-sha256']) + headers['X-Amz-Content-Sha256'] = hash(this.request.body || '', 'hex') + + if (headers['X-Amz-Date'] || headers['x-amz-date']) + this.datetime = headers['X-Amz-Date'] || headers['x-amz-date'] + else + headers['X-Amz-Date'] = this.getDateTime() + } + + delete headers.Authorization + delete headers.authorization + } +} + +RequestSigner.prototype.sign = function() { + if (!this.parsedPath) this.prepareRequest() + + if (this.request.signQuery) { + this.parsedPath.query['X-Amz-Signature'] = this.signature() + } else { + this.request.headers.Authorization = this.authHeader() + } + + this.request.path = this.formatPath() + + return this.request +} + +RequestSigner.prototype.getDateTime = function() { + if (!this.datetime) { + var headers = this.request.headers, + date = new Date(headers.Date || headers.date || new Date) + + this.datetime = date.toISOString().replace(/[:\-]|\.\d{3}/g, '') + + // Remove the trailing 'Z' on the timestamp string for CodeCommit git access + if (this.isCodeCommitGit) this.datetime = this.datetime.slice(0, -1) + } + return this.datetime +} + +RequestSigner.prototype.getDate = function() { + return this.getDateTime().substr(0, 8) +} + +RequestSigner.prototype.authHeader = function() { + return [ + 'AWS4-HMAC-SHA256 Credential=' + this.credentials.accessKeyId + '/' + this.credentialString(), + 'SignedHeaders=' + this.signedHeaders(), + 'Signature=' + this.signature(), + ].join(', ') +} + +RequestSigner.prototype.signature = function() { + var date = this.getDate(), + cacheKey = [this.credentials.secretAccessKey, date, this.region, this.service].join(), + kDate, kRegion, kService, kCredentials = credentialsCache.get(cacheKey) + if (!kCredentials) { + kDate = hmac('AWS4' + this.credentials.secretAccessKey, date) + kRegion = hmac(kDate, this.region) + kService = hmac(kRegion, this.service) + kCredentials = hmac(kService, 'aws4_request') + credentialsCache.set(cacheKey, kCredentials) + } + return hmac(kCredentials, this.stringToSign(), 'hex') +} + +RequestSigner.prototype.stringToSign = function() { + return [ + 'AWS4-HMAC-SHA256', + this.getDateTime(), + this.credentialString(), + hash(this.canonicalString(), 'hex'), + ].join('\n') +} + +RequestSigner.prototype.canonicalString = function() { + if (!this.parsedPath) this.prepareRequest() + + var pathStr = this.parsedPath.path, + query = this.parsedPath.query, + headers = this.request.headers, + queryStr = '', + normalizePath = this.service !== 's3', + decodePath = this.service === 's3' || this.request.doNotEncodePath, + decodeSlashesInPath = this.service === 's3', + firstValOnly = this.service === 's3', + bodyHash + + if (this.service === 's3' && this.request.signQuery) { + bodyHash = 'UNSIGNED-PAYLOAD' + } else if (this.isCodeCommitGit) { + bodyHash = '' + } else { + bodyHash = headers['X-Amz-Content-Sha256'] || headers['x-amz-content-sha256'] || + hash(this.request.body || '', 'hex') + } + + if (query) { + var reducedQuery = Object.keys(query).reduce(function(obj, key) { + if (!key) return obj + obj[key] = !Array.isArray(query[key]) ? query[key] : + (firstValOnly ? query[key][0] : query[key].slice().sort()) + return obj + }, {}) + var encodedQueryPieces = [] + Object.keys(reducedQuery).forEach(function(key) { + var encodedPrefix = encodeURIComponent(key) + '=' + if (!Array.isArray(reducedQuery[key])) { + encodedQueryPieces.push(encodeRfc3986(encodedPrefix + encodeURIComponent(reducedQuery[key]))) + } else { + reducedQuery[key].forEach(function(val) { encodedQueryPieces.push(encodeRfc3986(encodedPrefix + encodeURIComponent(val))) }) + } + }) + queryStr = encodedQueryPieces.sort().join('&') + } + if (pathStr !== '/') { + if (normalizePath) pathStr = pathStr.replace(/\/{2,}/g, '/') + pathStr = pathStr.split('/').reduce(function(path, piece) { + if (normalizePath && piece === '..') { + path.pop() + } else if (!normalizePath || piece !== '.') { + if (decodePath) piece = decodeURIComponent(piece).replace(/\+/g, ' ') + path.push(encodeRfc3986(encodeURIComponent(piece))) + } + return path + }, []).join('/') + if (pathStr[0] !== '/') pathStr = '/' + pathStr + if (decodeSlashesInPath) pathStr = pathStr.replace(/%2F/g, '/') + } + + return [ + this.request.method || 'GET', + pathStr, + queryStr, + this.canonicalHeaders() + '\n', + this.signedHeaders(), + bodyHash, + ].join('\n') +} + +RequestSigner.prototype.canonicalHeaders = function() { + var headers = this.request.headers + function trimAll(header) { + return header.toString().trim().replace(/\s+/g, ' ') + } + return Object.keys(headers) + .sort(function(a, b) { return a.toLowerCase() < b.toLowerCase() ? -1 : 1 }) + .map(function(key) { return key.toLowerCase() + ':' + trimAll(headers[key]) }) + .join('\n') +} + +RequestSigner.prototype.signedHeaders = function() { + return Object.keys(this.request.headers) + .map(function(key) { return key.toLowerCase() }) + .sort() + .join(';') +} + +RequestSigner.prototype.credentialString = function() { + return [ + this.getDate(), + this.region, + this.service, + 'aws4_request', + ].join('/') +} + +RequestSigner.prototype.defaultCredentials = function() { + var env = process.env + return { + accessKeyId: env.AWS_ACCESS_KEY_ID || env.AWS_ACCESS_KEY, + secretAccessKey: env.AWS_SECRET_ACCESS_KEY || env.AWS_SECRET_KEY, + sessionToken: env.AWS_SESSION_TOKEN, + } +} + +RequestSigner.prototype.parsePath = function() { + var path = this.request.path || '/' + + // S3 doesn't always encode characters > 127 correctly and + // all services don't encode characters > 255 correctly + // So if there are non-reserved chars (and it's not already all % encoded), just encode them all + if (/[^0-9A-Za-z;,/?:@&=+$\-_.!~*'()#%]/.test(path)) { + path = encodeURI(decodeURI(path)) + } + + var queryIx = path.indexOf('?'), + query = null + + if (queryIx >= 0) { + query = querystring.parse(path.slice(queryIx + 1)) + path = path.slice(0, queryIx) + } + + this.parsedPath = { + path: path, + query: query, + } +} + +RequestSigner.prototype.formatPath = function() { + var path = this.parsedPath.path, + query = this.parsedPath.query + + if (!query) return path + + // Services don't support empty query string keys + if (query[''] != null) delete query[''] + + return path + '?' + encodeRfc3986(querystring.stringify(query)) +} + +aws4.RequestSigner = RequestSigner + +aws4.sign = function(request, credentials) { + return new RequestSigner(request, credentials).sign() +} diff --git a/user/themes/goku/node_modules/aws4/lru.js b/user/themes/goku/node_modules/aws4/lru.js new file mode 100644 index 00000000..333f66a4 --- /dev/null +++ b/user/themes/goku/node_modules/aws4/lru.js @@ -0,0 +1,96 @@ +module.exports = function(size) { + return new LruCache(size) +} + +function LruCache(size) { + this.capacity = size | 0 + this.map = Object.create(null) + this.list = new DoublyLinkedList() +} + +LruCache.prototype.get = function(key) { + var node = this.map[key] + if (node == null) return undefined + this.used(node) + return node.val +} + +LruCache.prototype.set = function(key, val) { + var node = this.map[key] + if (node != null) { + node.val = val + } else { + if (!this.capacity) this.prune() + if (!this.capacity) return false + node = new DoublyLinkedNode(key, val) + this.map[key] = node + this.capacity-- + } + this.used(node) + return true +} + +LruCache.prototype.used = function(node) { + this.list.moveToFront(node) +} + +LruCache.prototype.prune = function() { + var node = this.list.pop() + if (node != null) { + delete this.map[node.key] + this.capacity++ + } +} + + +function DoublyLinkedList() { + this.firstNode = null + this.lastNode = null +} + +DoublyLinkedList.prototype.moveToFront = function(node) { + if (this.firstNode == node) return + + this.remove(node) + + if (this.firstNode == null) { + this.firstNode = node + this.lastNode = node + node.prev = null + node.next = null + } else { + node.prev = null + node.next = this.firstNode + node.next.prev = node + this.firstNode = node + } +} + +DoublyLinkedList.prototype.pop = function() { + var lastNode = this.lastNode + if (lastNode != null) { + this.remove(lastNode) + } + return lastNode +} + +DoublyLinkedList.prototype.remove = function(node) { + if (this.firstNode == node) { + this.firstNode = node.next + } else if (node.prev != null) { + node.prev.next = node.next + } + if (this.lastNode == node) { + this.lastNode = node.prev + } else if (node.next != null) { + node.next.prev = node.prev + } +} + + +function DoublyLinkedNode(key, val) { + this.key = key + this.val = val + this.prev = null + this.next = null +} diff --git a/user/themes/goku/node_modules/aws4/package.json b/user/themes/goku/node_modules/aws4/package.json new file mode 100644 index 00000000..bff64816 --- /dev/null +++ b/user/themes/goku/node_modules/aws4/package.json @@ -0,0 +1,104 @@ +{ + "_from": "aws4@^1.8.0", + "_id": "aws4@1.9.0", + "_inBundle": false, + "_integrity": "sha512-Uvq6hVe90D0B2WEnUqtdgY1bATGz3mw33nH9Y+dmA+w5DHvUmBgkr5rM/KCHpCsiFNRUfokW/szpPPgMK2hm4A==", + "_location": "/aws4", + "_phantomChildren": {}, + "_requested": { + "type": "range", + "registry": true, + "raw": "aws4@^1.8.0", + "name": "aws4", + "escapedName": "aws4", + "rawSpec": "^1.8.0", + "saveSpec": null, + "fetchSpec": "^1.8.0" + }, + "_requiredBy": [ + "/request" + ], + "_resolved": "https://registry.npmjs.org/aws4/-/aws4-1.9.0.tgz", + "_shasum": "24390e6ad61386b0a747265754d2a17219de862c", + "_spec": "aws4@^1.8.0", + "_where": "/srv/http/berryfarmprojects.org.uk/stay-grav/user/themes/goku/node_modules/request", + "author": { + "name": "Michael Hart", + "email": "michael.hart.au@gmail.com", + "url": "http://github.com/mhart" + }, + "bugs": { + "url": "https://github.com/mhart/aws4/issues" + }, + "bundleDependencies": false, + "deprecated": false, + "description": "Signs and prepares requests using AWS Signature Version 4", + "devDependencies": { + "mocha": "^2.4.5", + "should": "^8.2.2" + }, + "homepage": "https://github.com/mhart/aws4#readme", + "keywords": [ + "amazon", + "aws", + "signature", + "s3", + "ec2", + "autoscaling", + "cloudformation", + "elasticloadbalancing", + "elb", + "elasticbeanstalk", + "cloudsearch", + "dynamodb", + "kinesis", + "lambda", + "glacier", + "sqs", + "sns", + "iam", + "sts", + "ses", + "swf", + "storagegateway", + "datapipeline", + "directconnect", + "redshift", + "opsworks", + "rds", + "monitoring", + "cloudtrail", + "cloudfront", + "codedeploy", + "elasticache", + "elasticmapreduce", + "elastictranscoder", + "emr", + "cloudwatch", + "mobileanalytics", + "cognitoidentity", + "cognitosync", + "cognito", + "containerservice", + "ecs", + "appstream", + "keymanagementservice", + "kms", + "config", + "cloudhsm", + "route53", + "route53domains", + "logs" + ], + "license": "MIT", + "main": "aws4.js", + "name": "aws4", + "repository": { + "type": "git", + "url": "git+https://github.com/mhart/aws4.git" + }, + "scripts": { + "test": "mocha ./test/fast.js -b -t 100s -R list" + }, + "version": "1.9.0" +} diff --git a/user/themes/goku/node_modules/balanced-match/.npmignore b/user/themes/goku/node_modules/balanced-match/.npmignore new file mode 100644 index 00000000..ae5d8c36 --- /dev/null +++ b/user/themes/goku/node_modules/balanced-match/.npmignore @@ -0,0 +1,5 @@ +test +.gitignore +.travis.yml +Makefile +example.js diff --git a/user/themes/goku/node_modules/balanced-match/LICENSE.md b/user/themes/goku/node_modules/balanced-match/LICENSE.md new file mode 100644 index 00000000..2cdc8e41 --- /dev/null +++ b/user/themes/goku/node_modules/balanced-match/LICENSE.md @@ -0,0 +1,21 @@ +(MIT) + +Copyright (c) 2013 Julian Gruber <julian@juliangruber.com> + +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. diff --git a/user/themes/goku/node_modules/balanced-match/README.md b/user/themes/goku/node_modules/balanced-match/README.md new file mode 100644 index 00000000..08e918c0 --- /dev/null +++ b/user/themes/goku/node_modules/balanced-match/README.md @@ -0,0 +1,91 @@ +# balanced-match + +Match balanced string pairs, like `{` and `}` or `` and ``. Supports regular expressions as well! + +[![build status](https://secure.travis-ci.org/juliangruber/balanced-match.svg)](http://travis-ci.org/juliangruber/balanced-match) +[![downloads](https://img.shields.io/npm/dm/balanced-match.svg)](https://www.npmjs.org/package/balanced-match) + +[![testling badge](https://ci.testling.com/juliangruber/balanced-match.png)](https://ci.testling.com/juliangruber/balanced-match) + +## Example + +Get the first matching pair of braces: + +```js +var balanced = require('balanced-match'); + +console.log(balanced('{', '}', 'pre{in{nested}}post')); +console.log(balanced('{', '}', 'pre{first}between{second}post')); +console.log(balanced(/\s+\{\s+/, /\s+\}\s+/, 'pre { in{nest} } post')); +``` + +The matches are: + +```bash +$ node example.js +{ start: 3, end: 14, pre: 'pre', body: 'in{nested}', post: 'post' } +{ start: 3, + end: 9, + pre: 'pre', + body: 'first', + post: 'between{second}post' } +{ start: 3, end: 17, pre: 'pre', body: 'in{nest}', post: 'post' } +``` + +## API + +### var m = balanced(a, b, str) + +For the first non-nested matching pair of `a` and `b` in `str`, return an +object with those keys: + +* **start** the index of the first match of `a` +* **end** the index of the matching `b` +* **pre** the preamble, `a` and `b` not included +* **body** the match, `a` and `b` not included +* **post** the postscript, `a` and `b` not included + +If there's no match, `undefined` will be returned. + +If the `str` contains more `a` than `b` / there are unmatched pairs, the first match that was closed will be used. For example, `{{a}` will match `['{', 'a', '']` and `{a}}` will match `['', 'a', '}']`. + +### var r = balanced.range(a, b, str) + +For the first non-nested matching pair of `a` and `b` in `str`, return an +array with indexes: `[ , ]`. + +If there's no match, `undefined` will be returned. + +If the `str` contains more `a` than `b` / there are unmatched pairs, the first match that was closed will be used. For example, `{{a}` will match `[ 1, 3 ]` and `{a}}` will match `[0, 2]`. + +## Installation + +With [npm](https://npmjs.org) do: + +```bash +npm install balanced-match +``` + +## License + +(MIT) + +Copyright (c) 2013 Julian Gruber <julian@juliangruber.com> + +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. diff --git a/user/themes/goku/node_modules/balanced-match/index.js b/user/themes/goku/node_modules/balanced-match/index.js new file mode 100644 index 00000000..1685a762 --- /dev/null +++ b/user/themes/goku/node_modules/balanced-match/index.js @@ -0,0 +1,59 @@ +'use strict'; +module.exports = balanced; +function balanced(a, b, str) { + if (a instanceof RegExp) a = maybeMatch(a, str); + if (b instanceof RegExp) b = maybeMatch(b, str); + + var r = range(a, b, str); + + return r && { + start: r[0], + end: r[1], + pre: str.slice(0, r[0]), + body: str.slice(r[0] + a.length, r[1]), + post: str.slice(r[1] + b.length) + }; +} + +function maybeMatch(reg, str) { + var m = str.match(reg); + return m ? m[0] : null; +} + +balanced.range = range; +function range(a, b, str) { + var begs, beg, left, right, result; + var ai = str.indexOf(a); + var bi = str.indexOf(b, ai + 1); + var i = ai; + + if (ai >= 0 && bi > 0) { + begs = []; + left = str.length; + + while (i >= 0 && !result) { + if (i == ai) { + begs.push(i); + ai = str.indexOf(a, i + 1); + } else if (begs.length == 1) { + result = [ begs.pop(), bi ]; + } else { + beg = begs.pop(); + if (beg < left) { + left = beg; + right = bi; + } + + bi = str.indexOf(b, i + 1); + } + + i = ai < bi && ai >= 0 ? ai : bi; + } + + if (begs.length) { + result = [ left, right ]; + } + } + + return result; +} diff --git a/user/themes/goku/node_modules/balanced-match/package.json b/user/themes/goku/node_modules/balanced-match/package.json new file mode 100644 index 00000000..9e62ae8d --- /dev/null +++ b/user/themes/goku/node_modules/balanced-match/package.json @@ -0,0 +1,77 @@ +{ + "_from": "balanced-match@^1.0.0", + "_id": "balanced-match@1.0.0", + "_inBundle": false, + "_integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "_location": "/balanced-match", + "_phantomChildren": {}, + "_requested": { + "type": "range", + "registry": true, + "raw": "balanced-match@^1.0.0", + "name": "balanced-match", + "escapedName": "balanced-match", + "rawSpec": "^1.0.0", + "saveSpec": null, + "fetchSpec": "^1.0.0" + }, + "_requiredBy": [ + "/brace-expansion" + ], + "_resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "_shasum": "89b4d199ab2bee49de164ea02b89ce462d71b767", + "_spec": "balanced-match@^1.0.0", + "_where": "/srv/http/berryfarmprojects.org.uk/stay-grav/user/themes/goku/node_modules/brace-expansion", + "author": { + "name": "Julian Gruber", + "email": "mail@juliangruber.com", + "url": "http://juliangruber.com" + }, + "bugs": { + "url": "https://github.com/juliangruber/balanced-match/issues" + }, + "bundleDependencies": false, + "dependencies": {}, + "deprecated": false, + "description": "Match balanced character pairs, like \"{\" and \"}\"", + "devDependencies": { + "matcha": "^0.7.0", + "tape": "^4.6.0" + }, + "homepage": "https://github.com/juliangruber/balanced-match", + "keywords": [ + "match", + "regexp", + "test", + "balanced", + "parse" + ], + "license": "MIT", + "main": "index.js", + "name": "balanced-match", + "repository": { + "type": "git", + "url": "git://github.com/juliangruber/balanced-match.git" + }, + "scripts": { + "bench": "make bench", + "test": "make test" + }, + "testling": { + "files": "test/*.js", + "browsers": [ + "ie/8..latest", + "firefox/20..latest", + "firefox/nightly", + "chrome/25..latest", + "chrome/canary", + "opera/12..latest", + "opera/next", + "safari/5.1..latest", + "ipad/6.0..latest", + "iphone/6.0..latest", + "android-browser/4.2..latest" + ] + }, + "version": "1.0.0" +} diff --git a/user/themes/goku/node_modules/bcrypt-pbkdf/CONTRIBUTING.md b/user/themes/goku/node_modules/bcrypt-pbkdf/CONTRIBUTING.md new file mode 100644 index 00000000..401d34ed --- /dev/null +++ b/user/themes/goku/node_modules/bcrypt-pbkdf/CONTRIBUTING.md @@ -0,0 +1,13 @@ +# Contributing + +This repository uses [cr.joyent.us](https://cr.joyent.us) (Gerrit) for new +changes. Anyone can submit changes. To get started, see the [cr.joyent.us user +guide](https://github.com/joyent/joyent-gerrit/blob/master/docs/user/README.md). +This repo does not use GitHub pull requests. + +See the [Joyent Engineering +Guidelines](https://github.com/joyent/eng/blob/master/docs/index.md) for general +best practices expected in this repository. + +If you're changing something non-trivial or user-facing, you may want to submit +an issue first. diff --git a/user/themes/goku/node_modules/bcrypt-pbkdf/LICENSE b/user/themes/goku/node_modules/bcrypt-pbkdf/LICENSE new file mode 100644 index 00000000..fc58d2ab --- /dev/null +++ b/user/themes/goku/node_modules/bcrypt-pbkdf/LICENSE @@ -0,0 +1,66 @@ +The Blowfish portions are under the following license: + +Blowfish block cipher for OpenBSD +Copyright 1997 Niels Provos +All rights reserved. + +Implementation advice by David Mazieres . + +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. +3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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 bcrypt_pbkdf portions are under the following license: + +Copyright (c) 2013 Ted Unangst + +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + + +Performance improvements (Javascript-specific): + +Copyright 2016, Joyent Inc +Author: Alex Wilson + +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/user/themes/goku/node_modules/bcrypt-pbkdf/README.md b/user/themes/goku/node_modules/bcrypt-pbkdf/README.md new file mode 100644 index 00000000..7551f335 --- /dev/null +++ b/user/themes/goku/node_modules/bcrypt-pbkdf/README.md @@ -0,0 +1,45 @@ +Port of the OpenBSD `bcrypt_pbkdf` function to pure Javascript. `npm`-ified +version of [Devi Mandiri's port](https://github.com/devi/tmp/blob/master/js/bcrypt_pbkdf.js), +with some minor performance improvements. The code is copied verbatim (and +un-styled) from Devi's work. + +This product includes software developed by Niels Provos. + +## API + +### `bcrypt_pbkdf.pbkdf(pass, passlen, salt, saltlen, key, keylen, rounds)` + +Derive a cryptographic key of arbitrary length from a given password and salt, +using the OpenBSD `bcrypt_pbkdf` function. This is a combination of Blowfish and +SHA-512. + +See [this article](http://www.tedunangst.com/flak/post/bcrypt-pbkdf) for +further information. + +Parameters: + + * `pass`, a Uint8Array of length `passlen` + * `passlen`, an integer Number + * `salt`, a Uint8Array of length `saltlen` + * `saltlen`, an integer Number + * `key`, a Uint8Array of length `keylen`, will be filled with output + * `keylen`, an integer Number + * `rounds`, an integer Number, number of rounds of the PBKDF to run + +### `bcrypt_pbkdf.hash(sha2pass, sha2salt, out)` + +Calculate a Blowfish hash, given SHA2-512 output of a password and salt. Used as +part of the inner round function in the PBKDF. + +Parameters: + + * `sha2pass`, a Uint8Array of length 64 + * `sha2salt`, a Uint8Array of length 64 + * `out`, a Uint8Array of length 32, will be filled with output + +## License + +This source form is a 1:1 port from the OpenBSD `blowfish.c` and `bcrypt_pbkdf.c`. +As a result, it retains the original copyright and license. The two files are +under slightly different (but compatible) licenses, and are here combined in +one file. For each of the full license texts see `LICENSE`. diff --git a/user/themes/goku/node_modules/bcrypt-pbkdf/index.js b/user/themes/goku/node_modules/bcrypt-pbkdf/index.js new file mode 100644 index 00000000..b1b5ad4b --- /dev/null +++ b/user/themes/goku/node_modules/bcrypt-pbkdf/index.js @@ -0,0 +1,556 @@ +'use strict'; + +var crypto_hash_sha512 = require('tweetnacl').lowlevel.crypto_hash; + +/* + * This file is a 1:1 port from the OpenBSD blowfish.c and bcrypt_pbkdf.c. As a + * result, it retains the original copyright and license. The two files are + * under slightly different (but compatible) licenses, and are here combined in + * one file. + * + * Credit for the actual porting work goes to: + * Devi Mandiri + */ + +/* + * The Blowfish portions are under the following license: + * + * Blowfish block cipher for OpenBSD + * Copyright 1997 Niels Provos + * All rights reserved. + * + * Implementation advice by David Mazieres . + * + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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 bcrypt_pbkdf portions are under the following license: + * + * Copyright (c) 2013 Ted Unangst + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * Performance improvements (Javascript-specific): + * + * Copyright 2016, Joyent Inc + * Author: Alex Wilson + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +// Ported from OpenBSD bcrypt_pbkdf.c v1.9 + +var BLF_J = 0; + +var Blowfish = function() { + this.S = [ + new Uint32Array([ + 0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, + 0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99, + 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16, + 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, + 0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee, + 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013, + 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, + 0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e, + 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60, + 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, + 0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce, + 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a, + 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, + 0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677, + 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193, + 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, + 0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88, + 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239, + 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, + 0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0, + 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3, + 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, + 0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88, + 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe, + 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, + 0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d, + 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b, + 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, + 0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba, + 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463, + 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, + 0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09, + 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3, + 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, + 0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279, + 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8, + 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, + 0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82, + 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db, + 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, + 0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0, + 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b, + 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, + 0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8, + 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4, + 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, + 0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7, + 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c, + 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, + 0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1, + 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299, + 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, + 0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477, + 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf, + 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, + 0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af, + 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa, + 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, + 0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41, + 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915, + 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, + 0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915, + 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664, + 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a]), + new Uint32Array([ + 0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, + 0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266, + 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, + 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, + 0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6, + 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1, + 0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, + 0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1, + 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, + 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, + 0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff, + 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd, + 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, + 0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7, + 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, + 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, + 0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf, + 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af, + 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, + 0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87, + 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, + 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, + 0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16, + 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd, + 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, + 0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509, + 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, + 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, + 0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f, + 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a, + 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, + 0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960, + 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, + 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, + 0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802, + 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84, + 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, + 0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf, + 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, + 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, + 0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50, + 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7, + 0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, + 0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281, + 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, + 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, + 0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128, + 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73, + 0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, + 0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0, + 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, + 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, + 0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3, + 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285, + 0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, + 0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061, + 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, + 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, + 0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735, + 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc, + 0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, + 0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340, + 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, + 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7]), + new Uint32Array([ + 0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, + 0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068, + 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af, + 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, + 0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45, + 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504, + 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, + 0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb, + 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee, + 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, + 0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42, + 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b, + 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, + 0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb, + 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527, + 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, + 0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33, + 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c, + 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, + 0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc, + 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17, + 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, + 0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b, + 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115, + 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, + 0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728, + 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0, + 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, + 0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37, + 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d, + 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, + 0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b, + 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3, + 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, + 0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d, + 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c, + 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, + 0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9, + 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a, + 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, + 0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d, + 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc, + 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, + 0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61, + 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, + 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, + 0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2, + 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c, + 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, + 0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633, + 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10, + 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, + 0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52, + 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027, + 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, + 0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62, + 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634, + 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, + 0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24, + 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc, + 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, + 0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c, + 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837, + 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0]), + new Uint32Array([ + 0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, + 0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe, + 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b, + 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, + 0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8, + 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6, + 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, + 0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22, + 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4, + 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, + 0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9, + 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59, + 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, + 0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51, + 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28, + 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, + 0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b, + 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28, + 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, + 0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd, + 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a, + 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, + 0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb, + 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f, + 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, + 0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32, + 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680, + 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, + 0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae, + 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb, + 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, + 0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47, + 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370, + 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, + 0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84, + 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048, + 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, + 0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd, + 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9, + 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, + 0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38, + 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f, + 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, + 0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525, + 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1, + 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, + 0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964, + 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e, + 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, + 0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d, + 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f, + 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, + 0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02, + 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc, + 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, + 0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a, + 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6, + 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, + 0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0, + 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060, + 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, + 0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9, + 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f, + 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6]) + ]; + this.P = new Uint32Array([ + 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, + 0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89, + 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c, + 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, + 0x9216d5d9, 0x8979fb1b]); +}; + +function F(S, x8, i) { + return (((S[0][x8[i+3]] + + S[1][x8[i+2]]) ^ + S[2][x8[i+1]]) + + S[3][x8[i]]); +}; + +Blowfish.prototype.encipher = function(x, x8) { + if (x8 === undefined) { + x8 = new Uint8Array(x.buffer); + if (x.byteOffset !== 0) + x8 = x8.subarray(x.byteOffset); + } + x[0] ^= this.P[0]; + for (var i = 1; i < 16; i += 2) { + x[1] ^= F(this.S, x8, 0) ^ this.P[i]; + x[0] ^= F(this.S, x8, 4) ^ this.P[i+1]; + } + var t = x[0]; + x[0] = x[1] ^ this.P[17]; + x[1] = t; +}; + +Blowfish.prototype.decipher = function(x) { + var x8 = new Uint8Array(x.buffer); + if (x.byteOffset !== 0) + x8 = x8.subarray(x.byteOffset); + x[0] ^= this.P[17]; + for (var i = 16; i > 0; i -= 2) { + x[1] ^= F(this.S, x8, 0) ^ this.P[i]; + x[0] ^= F(this.S, x8, 4) ^ this.P[i-1]; + } + var t = x[0]; + x[0] = x[1] ^ this.P[0]; + x[1] = t; +}; + +function stream2word(data, databytes){ + var i, temp = 0; + for (i = 0; i < 4; i++, BLF_J++) { + if (BLF_J >= databytes) BLF_J = 0; + temp = (temp << 8) | data[BLF_J]; + } + return temp; +}; + +Blowfish.prototype.expand0state = function(key, keybytes) { + var d = new Uint32Array(2), i, k; + var d8 = new Uint8Array(d.buffer); + + for (i = 0, BLF_J = 0; i < 18; i++) { + this.P[i] ^= stream2word(key, keybytes); + } + BLF_J = 0; + + for (i = 0; i < 18; i += 2) { + this.encipher(d, d8); + this.P[i] = d[0]; + this.P[i+1] = d[1]; + } + + for (i = 0; i < 4; i++) { + for (k = 0; k < 256; k += 2) { + this.encipher(d, d8); + this.S[i][k] = d[0]; + this.S[i][k+1] = d[1]; + } + } +}; + +Blowfish.prototype.expandstate = function(data, databytes, key, keybytes) { + var d = new Uint32Array(2), i, k; + + for (i = 0, BLF_J = 0; i < 18; i++) { + this.P[i] ^= stream2word(key, keybytes); + } + + for (i = 0, BLF_J = 0; i < 18; i += 2) { + d[0] ^= stream2word(data, databytes); + d[1] ^= stream2word(data, databytes); + this.encipher(d); + this.P[i] = d[0]; + this.P[i+1] = d[1]; + } + + for (i = 0; i < 4; i++) { + for (k = 0; k < 256; k += 2) { + d[0] ^= stream2word(data, databytes); + d[1] ^= stream2word(data, databytes); + this.encipher(d); + this.S[i][k] = d[0]; + this.S[i][k+1] = d[1]; + } + } + BLF_J = 0; +}; + +Blowfish.prototype.enc = function(data, blocks) { + for (var i = 0; i < blocks; i++) { + this.encipher(data.subarray(i*2)); + } +}; + +Blowfish.prototype.dec = function(data, blocks) { + for (var i = 0; i < blocks; i++) { + this.decipher(data.subarray(i*2)); + } +}; + +var BCRYPT_BLOCKS = 8, + BCRYPT_HASHSIZE = 32; + +function bcrypt_hash(sha2pass, sha2salt, out) { + var state = new Blowfish(), + cdata = new Uint32Array(BCRYPT_BLOCKS), i, + ciphertext = new Uint8Array([79,120,121,99,104,114,111,109,97,116,105, + 99,66,108,111,119,102,105,115,104,83,119,97,116,68,121,110,97,109, + 105,116,101]); //"OxychromaticBlowfishSwatDynamite" + + state.expandstate(sha2salt, 64, sha2pass, 64); + for (i = 0; i < 64; i++) { + state.expand0state(sha2salt, 64); + state.expand0state(sha2pass, 64); + } + + for (i = 0; i < BCRYPT_BLOCKS; i++) + cdata[i] = stream2word(ciphertext, ciphertext.byteLength); + for (i = 0; i < 64; i++) + state.enc(cdata, cdata.byteLength / 8); + + for (i = 0; i < BCRYPT_BLOCKS; i++) { + out[4*i+3] = cdata[i] >>> 24; + out[4*i+2] = cdata[i] >>> 16; + out[4*i+1] = cdata[i] >>> 8; + out[4*i+0] = cdata[i]; + } +}; + +function bcrypt_pbkdf(pass, passlen, salt, saltlen, key, keylen, rounds) { + var sha2pass = new Uint8Array(64), + sha2salt = new Uint8Array(64), + out = new Uint8Array(BCRYPT_HASHSIZE), + tmpout = new Uint8Array(BCRYPT_HASHSIZE), + countsalt = new Uint8Array(saltlen+4), + i, j, amt, stride, dest, count, + origkeylen = keylen; + + if (rounds < 1) + return -1; + if (passlen === 0 || saltlen === 0 || keylen === 0 || + keylen > (out.byteLength * out.byteLength) || saltlen > (1<<20)) + return -1; + + stride = Math.floor((keylen + out.byteLength - 1) / out.byteLength); + amt = Math.floor((keylen + stride - 1) / stride); + + for (i = 0; i < saltlen; i++) + countsalt[i] = salt[i]; + + crypto_hash_sha512(sha2pass, pass, passlen); + + for (count = 1; keylen > 0; count++) { + countsalt[saltlen+0] = count >>> 24; + countsalt[saltlen+1] = count >>> 16; + countsalt[saltlen+2] = count >>> 8; + countsalt[saltlen+3] = count; + + crypto_hash_sha512(sha2salt, countsalt, saltlen + 4); + bcrypt_hash(sha2pass, sha2salt, tmpout); + for (i = out.byteLength; i--;) + out[i] = tmpout[i]; + + for (i = 1; i < rounds; i++) { + crypto_hash_sha512(sha2salt, tmpout, tmpout.byteLength); + bcrypt_hash(sha2pass, sha2salt, tmpout); + for (j = 0; j < out.byteLength; j++) + out[j] ^= tmpout[j]; + } + + amt = Math.min(amt, keylen); + for (i = 0; i < amt; i++) { + dest = i * stride + (count - 1); + if (dest >= origkeylen) + break; + key[dest] = out[i]; + } + keylen -= i; + } + + return 0; +}; + +module.exports = { + BLOCKS: BCRYPT_BLOCKS, + HASHSIZE: BCRYPT_HASHSIZE, + hash: bcrypt_hash, + pbkdf: bcrypt_pbkdf +}; diff --git a/user/themes/goku/node_modules/bcrypt-pbkdf/package.json b/user/themes/goku/node_modules/bcrypt-pbkdf/package.json new file mode 100644 index 00000000..223ea4db --- /dev/null +++ b/user/themes/goku/node_modules/bcrypt-pbkdf/package.json @@ -0,0 +1,44 @@ +{ + "_from": "bcrypt-pbkdf@^1.0.0", + "_id": "bcrypt-pbkdf@1.0.2", + "_inBundle": false, + "_integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "_location": "/bcrypt-pbkdf", + "_phantomChildren": {}, + "_requested": { + "type": "range", + "registry": true, + "raw": "bcrypt-pbkdf@^1.0.0", + "name": "bcrypt-pbkdf", + "escapedName": "bcrypt-pbkdf", + "rawSpec": "^1.0.0", + "saveSpec": null, + "fetchSpec": "^1.0.0" + }, + "_requiredBy": [ + "/sshpk" + ], + "_resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "_shasum": "a4301d389b6a43f9b67ff3ca11a3f6637e360e9e", + "_spec": "bcrypt-pbkdf@^1.0.0", + "_where": "/srv/http/berryfarmprojects.org.uk/stay-grav/user/themes/goku/node_modules/sshpk", + "bugs": { + "url": "https://github.com/joyent/node-bcrypt-pbkdf/issues" + }, + "bundleDependencies": false, + "dependencies": { + "tweetnacl": "^0.14.3" + }, + "deprecated": false, + "description": "Port of the OpenBSD bcrypt_pbkdf function to pure JS", + "devDependencies": {}, + "homepage": "https://github.com/joyent/node-bcrypt-pbkdf#readme", + "license": "BSD-3-Clause", + "main": "index.js", + "name": "bcrypt-pbkdf", + "repository": { + "type": "git", + "url": "git://github.com/joyent/node-bcrypt-pbkdf.git" + }, + "version": "1.0.2" +} diff --git a/user/themes/goku/node_modules/block-stream/LICENCE b/user/themes/goku/node_modules/block-stream/LICENCE new file mode 100644 index 00000000..74489e2e --- /dev/null +++ b/user/themes/goku/node_modules/block-stream/LICENCE @@ -0,0 +1,25 @@ +Copyright (c) Isaac Z. Schlueter +All rights reserved. + +The BSD License + +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 THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS +``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 THE FOUNDATION 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. diff --git a/user/themes/goku/node_modules/block-stream/LICENSE b/user/themes/goku/node_modules/block-stream/LICENSE new file mode 100644 index 00000000..19129e31 --- /dev/null +++ b/user/themes/goku/node_modules/block-stream/LICENSE @@ -0,0 +1,15 @@ +The ISC License + +Copyright (c) Isaac Z. Schlueter and Contributors + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/user/themes/goku/node_modules/block-stream/README.md b/user/themes/goku/node_modules/block-stream/README.md new file mode 100644 index 00000000..c16e9c46 --- /dev/null +++ b/user/themes/goku/node_modules/block-stream/README.md @@ -0,0 +1,14 @@ +# block-stream + +A stream of blocks. + +Write data into it, and it'll output data in buffer blocks the size you +specify, padding with zeroes if necessary. + +```javascript +var block = new BlockStream(512) +fs.createReadStream("some-file").pipe(block) +block.pipe(fs.createWriteStream("block-file")) +``` + +When `.end()` or `.flush()` is called, it'll pad the block with zeroes. diff --git a/user/themes/goku/node_modules/block-stream/block-stream.js b/user/themes/goku/node_modules/block-stream/block-stream.js new file mode 100644 index 00000000..008de035 --- /dev/null +++ b/user/themes/goku/node_modules/block-stream/block-stream.js @@ -0,0 +1,209 @@ +// write data to it, and it'll emit data in 512 byte blocks. +// if you .end() or .flush(), it'll emit whatever it's got, +// padded with nulls to 512 bytes. + +module.exports = BlockStream + +var Stream = require("stream").Stream + , inherits = require("inherits") + , assert = require("assert").ok + , debug = process.env.DEBUG ? console.error : function () {} + +function BlockStream (size, opt) { + this.writable = this.readable = true + this._opt = opt || {} + this._chunkSize = size || 512 + this._offset = 0 + this._buffer = [] + this._bufferLength = 0 + if (this._opt.nopad) this._zeroes = false + else { + this._zeroes = new Buffer(this._chunkSize) + for (var i = 0; i < this._chunkSize; i ++) { + this._zeroes[i] = 0 + } + } +} + +inherits(BlockStream, Stream) + +BlockStream.prototype.write = function (c) { + // debug(" BS write", c) + if (this._ended) throw new Error("BlockStream: write after end") + if (c && !Buffer.isBuffer(c)) c = new Buffer(c + "") + if (c.length) { + this._buffer.push(c) + this._bufferLength += c.length + } + // debug("pushed onto buffer", this._bufferLength) + if (this._bufferLength >= this._chunkSize) { + if (this._paused) { + // debug(" BS paused, return false, need drain") + this._needDrain = true + return false + } + this._emitChunk() + } + return true +} + +BlockStream.prototype.pause = function () { + // debug(" BS pausing") + this._paused = true +} + +BlockStream.prototype.resume = function () { + // debug(" BS resume") + this._paused = false + return this._emitChunk() +} + +BlockStream.prototype.end = function (chunk) { + // debug("end", chunk) + if (typeof chunk === "function") cb = chunk, chunk = null + if (chunk) this.write(chunk) + this._ended = true + this.flush() +} + +BlockStream.prototype.flush = function () { + this._emitChunk(true) +} + +BlockStream.prototype._emitChunk = function (flush) { + // debug("emitChunk flush=%j emitting=%j paused=%j", flush, this._emitting, this._paused) + + // emit a chunk + if (flush && this._zeroes) { + // debug(" BS push zeroes", this._bufferLength) + // push a chunk of zeroes + var padBytes = (this._bufferLength % this._chunkSize) + if (padBytes !== 0) padBytes = this._chunkSize - padBytes + if (padBytes > 0) { + // debug("padBytes", padBytes, this._zeroes.slice(0, padBytes)) + this._buffer.push(this._zeroes.slice(0, padBytes)) + this._bufferLength += padBytes + // debug(this._buffer[this._buffer.length - 1].length, this._bufferLength) + } + } + + if (this._emitting || this._paused) return + this._emitting = true + + // debug(" BS entering loops") + var bufferIndex = 0 + while (this._bufferLength >= this._chunkSize && + (flush || !this._paused)) { + // debug(" BS data emission loop", this._bufferLength) + + var out + , outOffset = 0 + , outHas = this._chunkSize + + while (outHas > 0 && (flush || !this._paused) ) { + // debug(" BS data inner emit loop", this._bufferLength) + var cur = this._buffer[bufferIndex] + , curHas = cur.length - this._offset + // debug("cur=", cur) + // debug("curHas=%j", curHas) + // If it's not big enough to fill the whole thing, then we'll need + // to copy multiple buffers into one. However, if it is big enough, + // then just slice out the part we want, to save unnecessary copying. + // Also, need to copy if we've already done some copying, since buffers + // can't be joined like cons strings. + if (out || curHas < outHas) { + out = out || new Buffer(this._chunkSize) + cur.copy(out, outOffset, + this._offset, this._offset + Math.min(curHas, outHas)) + } else if (cur.length === outHas && this._offset === 0) { + // shortcut -- cur is exactly long enough, and no offset. + out = cur + } else { + // slice out the piece of cur that we need. + out = cur.slice(this._offset, this._offset + outHas) + } + + if (curHas > outHas) { + // means that the current buffer couldn't be completely output + // update this._offset to reflect how much WAS written + this._offset += outHas + outHas = 0 + } else { + // output the entire current chunk. + // toss it away + outHas -= curHas + outOffset += curHas + bufferIndex ++ + this._offset = 0 + } + } + + this._bufferLength -= this._chunkSize + assert(out.length === this._chunkSize) + // debug("emitting data", out) + // debug(" BS emitting, paused=%j", this._paused, this._bufferLength) + this.emit("data", out) + out = null + } + // debug(" BS out of loops", this._bufferLength) + + // whatever is left, it's not enough to fill up a block, or we're paused + this._buffer = this._buffer.slice(bufferIndex) + if (this._paused) { + // debug(" BS paused, leaving", this._bufferLength) + this._needsDrain = true + this._emitting = false + return + } + + // if flushing, and not using null-padding, then need to emit the last + // chunk(s) sitting in the queue. We know that it's not enough to + // fill up a whole block, because otherwise it would have been emitted + // above, but there may be some offset. + var l = this._buffer.length + if (flush && !this._zeroes && l) { + if (l === 1) { + if (this._offset) { + this.emit("data", this._buffer[0].slice(this._offset)) + } else { + this.emit("data", this._buffer[0]) + } + } else { + var outHas = this._bufferLength + , out = new Buffer(outHas) + , outOffset = 0 + for (var i = 0; i < l; i ++) { + var cur = this._buffer[i] + , curHas = cur.length - this._offset + cur.copy(out, outOffset, this._offset) + this._offset = 0 + outOffset += curHas + this._bufferLength -= curHas + } + this.emit("data", out) + } + // truncate + this._buffer.length = 0 + this._bufferLength = 0 + this._offset = 0 + } + + // now either drained or ended + // debug("either draining, or ended", this._bufferLength, this._ended) + // means that we've flushed out all that we can so far. + if (this._needDrain) { + // debug("emitting drain", this._bufferLength) + this._needDrain = false + this.emit("drain") + } + + if ((this._bufferLength === 0) && this._ended && !this._endEmitted) { + // debug("emitting end", this._bufferLength) + this._endEmitted = true + this.emit("end") + } + + this._emitting = false + + // debug(" BS no longer emitting", flush, this._paused, this._emitting, this._bufferLength, this._chunkSize) +} diff --git a/user/themes/goku/node_modules/block-stream/package.json b/user/themes/goku/node_modules/block-stream/package.json new file mode 100644 index 00000000..b76133a4 --- /dev/null +++ b/user/themes/goku/node_modules/block-stream/package.json @@ -0,0 +1,60 @@ +{ + "_from": "block-stream@*", + "_id": "block-stream@0.0.9", + "_inBundle": false, + "_integrity": "sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=", + "_location": "/block-stream", + "_phantomChildren": {}, + "_requested": { + "type": "range", + "registry": true, + "raw": "block-stream@*", + "name": "block-stream", + "escapedName": "block-stream", + "rawSpec": "*", + "saveSpec": null, + "fetchSpec": "*" + }, + "_requiredBy": [ + "/tar" + ], + "_resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz", + "_shasum": "13ebfe778a03205cfe03751481ebb4b3300c126a", + "_spec": "block-stream@*", + "_where": "/srv/http/berryfarmprojects.org.uk/stay-grav/user/themes/goku/node_modules/tar", + "author": { + "name": "Isaac Z. Schlueter", + "email": "i@izs.me", + "url": "http://blog.izs.me/" + }, + "bugs": { + "url": "https://github.com/isaacs/block-stream/issues" + }, + "bundleDependencies": false, + "dependencies": { + "inherits": "~2.0.0" + }, + "deprecated": false, + "description": "a stream of blocks", + "devDependencies": { + "tap": "^5.7.1" + }, + "engines": { + "node": "0.4 || >=0.5.8" + }, + "files": [ + "block-stream.js" + ], + "homepage": "https://github.com/isaacs/block-stream#readme", + "license": "ISC", + "main": "block-stream.js", + "name": "block-stream", + "repository": { + "type": "git", + "url": "git://github.com/isaacs/block-stream.git" + }, + "scripts": { + "test": "tap test/*.js --cov" + }, + "version": "0.0.9" +} diff --git a/user/themes/goku/node_modules/brace-expansion/LICENSE b/user/themes/goku/node_modules/brace-expansion/LICENSE new file mode 100644 index 00000000..de322667 --- /dev/null +++ b/user/themes/goku/node_modules/brace-expansion/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2013 Julian Gruber + +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. diff --git a/user/themes/goku/node_modules/brace-expansion/README.md b/user/themes/goku/node_modules/brace-expansion/README.md new file mode 100644 index 00000000..6b4e0e16 --- /dev/null +++ b/user/themes/goku/node_modules/brace-expansion/README.md @@ -0,0 +1,129 @@ +# brace-expansion + +[Brace expansion](https://www.gnu.org/software/bash/manual/html_node/Brace-Expansion.html), +as known from sh/bash, in JavaScript. + +[![build status](https://secure.travis-ci.org/juliangruber/brace-expansion.svg)](http://travis-ci.org/juliangruber/brace-expansion) +[![downloads](https://img.shields.io/npm/dm/brace-expansion.svg)](https://www.npmjs.org/package/brace-expansion) +[![Greenkeeper badge](https://badges.greenkeeper.io/juliangruber/brace-expansion.svg)](https://greenkeeper.io/) + +[![testling badge](https://ci.testling.com/juliangruber/brace-expansion.png)](https://ci.testling.com/juliangruber/brace-expansion) + +## Example + +```js +var expand = require('brace-expansion'); + +expand('file-{a,b,c}.jpg') +// => ['file-a.jpg', 'file-b.jpg', 'file-c.jpg'] + +expand('-v{,,}') +// => ['-v', '-v', '-v'] + +expand('file{0..2}.jpg') +// => ['file0.jpg', 'file1.jpg', 'file2.jpg'] + +expand('file-{a..c}.jpg') +// => ['file-a.jpg', 'file-b.jpg', 'file-c.jpg'] + +expand('file{2..0}.jpg') +// => ['file2.jpg', 'file1.jpg', 'file0.jpg'] + +expand('file{0..4..2}.jpg') +// => ['file0.jpg', 'file2.jpg', 'file4.jpg'] + +expand('file-{a..e..2}.jpg') +// => ['file-a.jpg', 'file-c.jpg', 'file-e.jpg'] + +expand('file{00..10..5}.jpg') +// => ['file00.jpg', 'file05.jpg', 'file10.jpg'] + +expand('{{A..C},{a..c}}') +// => ['A', 'B', 'C', 'a', 'b', 'c'] + +expand('ppp{,config,oe{,conf}}') +// => ['ppp', 'pppconfig', 'pppoe', 'pppoeconf'] +``` + +## API + +```js +var expand = require('brace-expansion'); +``` + +### var expanded = expand(str) + +Return an array of all possible and valid expansions of `str`. If none are +found, `[str]` is returned. + +Valid expansions are: + +```js +/^(.*,)+(.+)?$/ +// {a,b,...} +``` + +A comma separated list of options, like `{a,b}` or `{a,{b,c}}` or `{,a,}`. + +```js +/^-?\d+\.\.-?\d+(\.\.-?\d+)?$/ +// {x..y[..incr]} +``` + +A numeric sequence from `x` to `y` inclusive, with optional increment. +If `x` or `y` start with a leading `0`, all the numbers will be padded +to have equal length. Negative numbers and backwards iteration work too. + +```js +/^-?\d+\.\.-?\d+(\.\.-?\d+)?$/ +// {x..y[..incr]} +``` + +An alphabetic sequence from `x` to `y` inclusive, with optional increment. +`x` and `y` must be exactly one character, and if given, `incr` must be a +number. + +For compatibility reasons, the string `${` is not eligible for brace expansion. + +## Installation + +With [npm](https://npmjs.org) do: + +```bash +npm install brace-expansion +``` + +## Contributors + +- [Julian Gruber](https://github.com/juliangruber) +- [Isaac Z. Schlueter](https://github.com/isaacs) + +## Sponsors + +This module is proudly supported by my [Sponsors](https://github.com/juliangruber/sponsors)! + +Do you want to support modules like this to improve their quality, stability and weigh in on new features? Then please consider donating to my [Patreon](https://www.patreon.com/juliangruber). Not sure how much of my modules you're using? Try [feross/thanks](https://github.com/feross/thanks)! + +## License + +(MIT) + +Copyright (c) 2013 Julian Gruber <julian@juliangruber.com> + +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. diff --git a/user/themes/goku/node_modules/brace-expansion/index.js b/user/themes/goku/node_modules/brace-expansion/index.js new file mode 100644 index 00000000..0478be81 --- /dev/null +++ b/user/themes/goku/node_modules/brace-expansion/index.js @@ -0,0 +1,201 @@ +var concatMap = require('concat-map'); +var balanced = require('balanced-match'); + +module.exports = expandTop; + +var escSlash = '\0SLASH'+Math.random()+'\0'; +var escOpen = '\0OPEN'+Math.random()+'\0'; +var escClose = '\0CLOSE'+Math.random()+'\0'; +var escComma = '\0COMMA'+Math.random()+'\0'; +var escPeriod = '\0PERIOD'+Math.random()+'\0'; + +function numeric(str) { + return parseInt(str, 10) == str + ? parseInt(str, 10) + : str.charCodeAt(0); +} + +function escapeBraces(str) { + return str.split('\\\\').join(escSlash) + .split('\\{').join(escOpen) + .split('\\}').join(escClose) + .split('\\,').join(escComma) + .split('\\.').join(escPeriod); +} + +function unescapeBraces(str) { + return str.split(escSlash).join('\\') + .split(escOpen).join('{') + .split(escClose).join('}') + .split(escComma).join(',') + .split(escPeriod).join('.'); +} + + +// Basically just str.split(","), but handling cases +// where we have nested braced sections, which should be +// treated as individual members, like {a,{b,c},d} +function parseCommaParts(str) { + if (!str) + return ['']; + + var parts = []; + var m = balanced('{', '}', str); + + if (!m) + return str.split(','); + + var pre = m.pre; + var body = m.body; + var post = m.post; + var p = pre.split(','); + + p[p.length-1] += '{' + body + '}'; + var postParts = parseCommaParts(post); + if (post.length) { + p[p.length-1] += postParts.shift(); + p.push.apply(p, postParts); + } + + parts.push.apply(parts, p); + + return parts; +} + +function expandTop(str) { + if (!str) + return []; + + // I don't know why Bash 4.3 does this, but it does. + // Anything starting with {} will have the first two bytes preserved + // but *only* at the top level, so {},a}b will not expand to anything, + // but a{},b}c will be expanded to [a}c,abc]. + // One could argue that this is a bug in Bash, but since the goal of + // this module is to match Bash's rules, we escape a leading {} + if (str.substr(0, 2) === '{}') { + str = '\\{\\}' + str.substr(2); + } + + return expand(escapeBraces(str), true).map(unescapeBraces); +} + +function identity(e) { + return e; +} + +function embrace(str) { + return '{' + str + '}'; +} +function isPadded(el) { + return /^-?0\d/.test(el); +} + +function lte(i, y) { + return i <= y; +} +function gte(i, y) { + return i >= y; +} + +function expand(str, isTop) { + var expansions = []; + + var m = balanced('{', '}', str); + if (!m || /\$$/.test(m.pre)) return [str]; + + var isNumericSequence = /^-?\d+\.\.-?\d+(?:\.\.-?\d+)?$/.test(m.body); + var isAlphaSequence = /^[a-zA-Z]\.\.[a-zA-Z](?:\.\.-?\d+)?$/.test(m.body); + var isSequence = isNumericSequence || isAlphaSequence; + var isOptions = m.body.indexOf(',') >= 0; + if (!isSequence && !isOptions) { + // {a},b} + if (m.post.match(/,.*\}/)) { + str = m.pre + '{' + m.body + escClose + m.post; + return expand(str); + } + return [str]; + } + + var n; + if (isSequence) { + n = m.body.split(/\.\./); + } else { + n = parseCommaParts(m.body); + if (n.length === 1) { + // x{{a,b}}y ==> x{a}y x{b}y + n = expand(n[0], false).map(embrace); + if (n.length === 1) { + var post = m.post.length + ? expand(m.post, false) + : ['']; + return post.map(function(p) { + return m.pre + n[0] + p; + }); + } + } + } + + // at this point, n is the parts, and we know it's not a comma set + // with a single entry. + + // no need to expand pre, since it is guaranteed to be free of brace-sets + var pre = m.pre; + var post = m.post.length + ? expand(m.post, false) + : ['']; + + var N; + + if (isSequence) { + var x = numeric(n[0]); + var y = numeric(n[1]); + var width = Math.max(n[0].length, n[1].length) + var incr = n.length == 3 + ? Math.abs(numeric(n[2])) + : 1; + var test = lte; + var reverse = y < x; + if (reverse) { + incr *= -1; + test = gte; + } + var pad = n.some(isPadded); + + N = []; + + for (var i = x; test(i, y); i += incr) { + var c; + if (isAlphaSequence) { + c = String.fromCharCode(i); + if (c === '\\') + c = ''; + } else { + c = String(i); + if (pad) { + var need = width - c.length; + if (need > 0) { + var z = new Array(need + 1).join('0'); + if (i < 0) + c = '-' + z + c.slice(1); + else + c = z + c; + } + } + } + N.push(c); + } + } else { + N = concatMap(n, function(el) { return expand(el, false) }); + } + + for (var j = 0; j < N.length; j++) { + for (var k = 0; k < post.length; k++) { + var expansion = pre + N[j] + post[k]; + if (!isTop || isSequence || expansion) + expansions.push(expansion); + } + } + + return expansions; +} + diff --git a/user/themes/goku/node_modules/brace-expansion/package.json b/user/themes/goku/node_modules/brace-expansion/package.json new file mode 100644 index 00000000..159bd8df --- /dev/null +++ b/user/themes/goku/node_modules/brace-expansion/package.json @@ -0,0 +1,75 @@ +{ + "_from": "brace-expansion@^1.1.7", + "_id": "brace-expansion@1.1.11", + "_inBundle": false, + "_integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "_location": "/brace-expansion", + "_phantomChildren": {}, + "_requested": { + "type": "range", + "registry": true, + "raw": "brace-expansion@^1.1.7", + "name": "brace-expansion", + "escapedName": "brace-expansion", + "rawSpec": "^1.1.7", + "saveSpec": null, + "fetchSpec": "^1.1.7" + }, + "_requiredBy": [ + "/minimatch" + ], + "_resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "_shasum": "3c7fcbf529d87226f3d2f52b966ff5271eb441dd", + "_spec": "brace-expansion@^1.1.7", + "_where": "/srv/http/berryfarmprojects.org.uk/stay-grav/user/themes/goku/node_modules/minimatch", + "author": { + "name": "Julian Gruber", + "email": "mail@juliangruber.com", + "url": "http://juliangruber.com" + }, + "bugs": { + "url": "https://github.com/juliangruber/brace-expansion/issues" + }, + "bundleDependencies": false, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + }, + "deprecated": false, + "description": "Brace expansion as known from sh/bash", + "devDependencies": { + "matcha": "^0.7.0", + "tape": "^4.6.0" + }, + "homepage": "https://github.com/juliangruber/brace-expansion", + "keywords": [], + "license": "MIT", + "main": "index.js", + "name": "brace-expansion", + "repository": { + "type": "git", + "url": "git://github.com/juliangruber/brace-expansion.git" + }, + "scripts": { + "bench": "matcha test/perf/bench.js", + "gentest": "bash test/generate.sh", + "test": "tape test/*.js" + }, + "testling": { + "files": "test/*.js", + "browsers": [ + "ie/8..latest", + "firefox/20..latest", + "firefox/nightly", + "chrome/25..latest", + "chrome/canary", + "opera/12..latest", + "opera/next", + "safari/5.1..latest", + "ipad/6.0..latest", + "iphone/6.0..latest", + "android-browser/4.2..latest" + ] + }, + "version": "1.1.11" +} diff --git a/user/themes/goku/node_modules/bulma/CHANGELOG.md b/user/themes/goku/node_modules/bulma/CHANGELOG.md new file mode 100644 index 00000000..00f04f6b --- /dev/null +++ b/user/themes/goku/node_modules/bulma/CHANGELOG.md @@ -0,0 +1,1371 @@ +# Bulma Changelog + +## 0.8.0 + +### Big update + +#### Larger form controls + +Controls and buttons are now `2.5em` high. You can revert this resizing by setting these previous values: + +```sass +$control-height: 2.25em +$control-padding-vertical: calc(0.375em - #{$control-border-width}) +$control-padding-horizontal: calc(0.625em - #{$control-border-width}) +$button-padding-vertical: calc(0.375em - #{$button-border-width}) +$button-padding-horizontal: 0.75em +``` + +#### Light and dark colors + +Each main color (`"primary"`, `"info"`, `"success"`, `"warning"`, `"danger"`) now has a `*-light` and `*-dark` version. They are calculated using 2 new color functions: + +* `findLightColor()` which finds the light version of a color +* `findDarkolor()` which finds the dark version of a color + +The light colors are used by the `button` element, while the light and dark colors are used by the `message` component. + +#### Panel colors + +The `panel` component is now available in all the different colors. + +#### 4-value color map + +The `$colors` Sass map now accepts, for each of its values, a map of up to **4** values. For example: the key `"info"` now has the `($info, $info-invert, $info-light, $info-dark)` map. + +If you provide a `$custom-colors` map, you can decide to provide a map of 1, 2, 3 or 4 values for each value. If fewer than 4 are provided, Bulma will calculate the remaining ones: + +```scss +$custom-colors: ( + "lime": (lime), + "tomato": (tomato, white), + "orange": ($orange, $orange-invert, $orange-light), + "lavender": ($lavender, $lavender-invert, $lavender-light, $lavender-dark) +); +``` + +This is processed by the updated `mergeColorMaps()` Sass function. + +#### Scheme variables + +There are 6 new `$scheme` derived variables: `$scheme-main` `$scheme-main-bis` `$scheme-main-ter` `$scheme-invert` `$scheme-invert-bis` `$scheme-invert-ter` +They replace the `$white` and `$black` occurences in the codebase. This makes it easy to create a "Dark mode" simply by swapping the values: + +```sass +$scheme-main: $black +$scheme-invert: $white +// etc. +``` + +That is also why most of the codebase now references **derived** variables (`$text`, `$background`, `$border` etc.) instead of **initial** ones (`$grey`, `$grey-lighter`, `$grey-darker` etc.): updating the derived variables will affect all elements and components directly. + +#### Initial variables + +* `$green: hsl(141, 53%, 53%)` +* `$cyan: hsl(204, 71%, 53%)` +* `$red: hsl(348, 86%, 61%)` + +#### Derived variables + +* `$primary-invert: findColorInvert($primary)` +* `$primary-light: findLightColor($primary)` +* `$primary-dark: findDarkColor($primary)` +* `$info-invert: findColorInvert($info)` +* `$info-light: findLightColor($info)` +* `$info-dark: findDarkColor($info)` +* `$success-invert: findColorInvert($success)` +* `$success-light: findLightColor($success)` +* `$success-dark: findDarkColor($success)` +* `$warning-invert: findColorInvert($warning)` +* `$warning-light: findLightColor($warning)` +* `$warning-dark: findDarkColor($warning)` +* `$danger-invert: findColorInvert($danger)` +* `$danger-light: findLightColor($danger)` +* `$danger-dark: findDarkColor($danger)` +* `$light-invert: findColorInvert($light)` +* `$dark-invert: findColorInvert($dark)` + +* `$scheme-main: $white` +* `$scheme-main-bis: $white-bis` +* `$scheme-main-ter: $white-ter` +* `$scheme-invert: $black` +* `$scheme-invert-bis: $black-bis` +* `$scheme-invert-ter: $black-ter` + +### Other variables + +* `$control-height: 2.5em` +* `$control-padding-vertical: calc(0.5em - #{$control-border-width})` +* `$control-padding-horizontal: calc(0.75em - #{$control-border-width})` +* `$media-border-color: rgba($border, 0.5)` +* `$notification-code-background-color: $scheme-main` +* `$panel-radius: $radius-large` +* `$panel-shadow: 0 0.5em 1em -0.125em rgba($scheme-invert, 0.1), 0 0px 0 1px rgba($scheme-invert, 0.02)` +* `$textarea-padding: $control-padding-horizontal` +* `$textarea-max-height: 40em` +* `$textarea-min-height: 8em` + +### Bug fixes + +* Fix #2647 -> Missing meta tags in snippet +* Fix #2031, Fix #2483 -> Invalid output when declaring a custom shade map +* Fix #2060 -> `height: auto` on HTML `audio` element breaks height of element +* Fix #706 -> Derive `-invert` variables using `findColorInvert()` +* #1608 Fix #1552 -> `.container.is-fluid` margins + +### New features + +* #2563 `.image` has a new `.is-fullwidth` modifier + +## 0.7.5 + +### Deprecation warning + +The `form.sass` file is **deprecated**. It has moved into its own `/form` folder. If you were importing `form.sass`, please import `sass/form/_all.sass` now. +If you were simply importing the whole of Bulma with `@import "~/bulma/bulma.sass"` or similar, you won't have to change anything, and everything will work as bbefore. + +### New features + +#### Support for overriding the `font-family` + +You can now specify a different `font-family` for the `.title`, `.subtitle` and `.button` by using the variables `$title-family`, `$subtitle-family` and `$button-family` respectively. + +Simply set a value when importing Bulma: + +```scss +$title-family: "Georgia", serif; +``` + +* #2375 Add `.is-relative` helper +* #2321 Make `.navbar` focus behave like hover for the navigation +* #2290 Fix #1186 -> Reset the offset on columns +* #2231 Add `.has-text-weight-medium` helper +* #2224 Add customizable border radius to progress bar +* #2480 Add `$footer-color` variable + +### Improvements + +* #2396 Update docs with webpack 4 example +* #2381 Make centered buttons have equal margin +* Fix #2297 -> Remove `.container` fixed width values, use `flex-grow` +* #2478 Move form.sass into its own folder + +### Bug fixes + +* #2420 Fix #2414 -> Fix `align` attribute in `td/th` being ignored +* #2463 Remove duplicate `.has-addons` in `tag.sass` +* #2253 Fix `$gap` variable default value +* #2273 Fix #2258 -> Fix Indeterminate Progress Bar animation in Firefox +* #2175 Proper aligning for `.tabs` within `.content` +* #2476 Fix #2441 -> Correct active pagination link text colour on hero + +Fix #1979 -> Correct loading spinner color when a button is: + +* outlined and hovered/focused +* outlined, inverted and hovered/focused + +### New variables + +#### Initial variables + +* `$block-spacing` + +#### Base + +* `$body-font-size` +* `$small-font-size` +* `$pre-font-size` +* `$pre-padding` +* `$pre-code-font-size` + +#### Components + +* `$card-header-padding` +* `$card-content-padding` +* `$card-media-margin` +* `$dropdown-menu-min-width` +* `$dropdown-content-padding-bottom` +* `$dropdown-content-padding-top` +* `$level-item-spacing` +* `$menu-list-line-height` +* `$menu-list-link-padding` +* `$menu-nested-list-margin` +* `$menu-nested-list-padding-left` +* `$menu-label-font-size` +* `$menu-label-letter-spacing` +* `$menu-label-spacing` +* `$pagination-item-font-size` +* `$pagination-item-margin` +* `$pagination-item-padding-left` +* `$pagination-item-padding-right` +* `$panel-margin` +* `$panel-tabs-font-size` + +#### Elements + +* `$container-offset` + +#### Grid + +* `$tile-spacing` + +## 0.7.3 + +### New features + +* #2145 Fix #372 -> New indeterminate progress bars +* #2206 Fix #2046 -> New variables `$table-head-background-color`, `$table-body-background-color` and `$table-foot-background-color` for the `.table` element +* #592 -> Give arbitrary elements access to the image/ratio classes +* #1682 Fix #1681 -> Adds disabled styles for `
                                                            ` +* #2201 Fix #1875 -> `.buttons` and `.tags` group sizing (`.are-small`, `.are-medium`, `.are-large`) + +### Improvements + +* #1978 Fix #1696 -> Force `box-sizing: border-box` on `details` element +* #2167 Fix #1878 -> New `$footer-padding` variable +* #2168 -> New `$input-placeholder-color` and `$input-disabled-placeholder-color` variables + +### Bug fixes + +* #2157 Fix #1656 -> Allow border radius if only one `.control` in `.field` +* #2091 Fix #2091 -> Remove CSS rule which causes `.tag.has-addons` to not work correctly +* #2186 Fix #1130 -> Prevent `.dropdown` links underlining in `.message` component +* Fix #2154 -> Move `.hero.is-fullheight-with-navbar` to `navbar.sass` file + +### Deprecation + +* `.control.has-icon` deprecated in favor of `.control.has-icons` + +## 0.7.2 + +### New features + +* #1884 New `$navbar-burger-color` variable +* #1679 Add breakpoint based column gaps +* #1905 Fix `modal` for IE11 #1902 +* #1919 New `is-arrowless` class for navbar items +* #1949 New `is-fullheight-with-navbar` class for heros +* #1764 New `.is-sr-only` helper +* #2109 Add and use `$navbar-breakpoint` variable +* New variables `$control-height`, `$control-line-height`, `$pagination-min-width`, `$input-height` +* #1720 Add list element feature +* #2123 Add `.content ol` types: `.is-lower-roman`, `.is-upper-roman`, `.is-lower-alpha`, `.is-upper-alpha`, and support for the `type=` HTML attribute + +### Improvements + +* #1964 Allow `.notification` to have a `.dropdown-item` +* #1999 Change `$border` to `$grey-lighter` in mixins +* #2085 `.media-content` will allow scrolling horizontally if the content is too wide +* #1744 Fix #1710 by using `$table-striped-row-even-hover-background-color` only for even rows +* #2074 Allow `