commit fdfcfbd2a64006e5c90747efe15fcc207b861134 Author: Kévin Tessier Date: Wed Apr 11 17:57:57 2018 +0200 first commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..29301fc --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +# media # +*.mp3 +*.mov diff --git a/.htaccess b/.htaccess new file mode 100644 index 0000000..3d233a7 --- /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 /ethica + +## 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 + "; + } + // line 51 + echo " env, $this->getAttribute($this->getAttribute(($context["plugin"] ?? null), "premium", array()), "product_permalink", array()), "html", null, true); + echo "\" target=\"_blank\" data-gumroad-single-product=\"true\"> "; + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("Buy Now"), "html", null, true); + echo " + "; + } else { + // line 53 + echo " env, $this->getAttribute(($context["plugin"] ?? null), "slug", array()), "html", null, true); + echo "\" data-plugin-action=\"start-package-installation\"> "; + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.INSTALL_PLUGIN"), "html", null, true); + echo " + "; + } + // line 55 + echo " +"; + } + // line 57 + echo " +"; + // line 58 + $this->loadTemplate("partials/modal-changes-detected.html.twig", "partials/plugins-details.html.twig", 58)->display($context); + // line 59 + $this->loadTemplate("partials/modal-add-package.html.twig", "partials/plugins-details.html.twig", 59)->display(array_merge($context, array("type" => "plugin"))); + // line 60 + $this->loadTemplate("partials/modal-update-packages.html.twig", "partials/plugins-details.html.twig", 60)->display(array_merge($context, array("type" => "plugin"))); + // line 61 + $this->loadTemplate("partials/modal-remove-package.html.twig", "partials/plugins-details.html.twig", 61)->display(array_merge($context, array("type" => "plugin", "package" => ($context["plugin"] ?? null)))); + // line 62 + $this->loadTemplate("partials/modal-reinstall-package.html.twig", "partials/plugins-details.html.twig", 62)->display(array_merge($context, array("type" => "plugin", "package" => ($context["plugin"] ?? null)))); + } + + public function getTemplateName() + { + return "partials/plugins-details.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 174 => 62, 172 => 61, 170 => 60, 168 => 59, 166 => 58, 163 => 57, 159 => 55, 151 => 53, 143 => 51, 139 => 49, 136 => 48, 133 => 47, 131 => 46, 128 => 45, 124 => 43, 117 => 40, 111 => 38, 109 => 37, 105 => 35, 103 => 34, 100 => 33, 97 => 32, 94 => 31, 92 => 30, 88 => 28, 86 => 27, 82 => 26, 78 => 24, 74 => 23, 69 => 22, 61 => 18, 58 => 17, 52 => 15, 49 => 14, 43 => 12, 41 => 11, 37 => 10, 30 => 6, 27 => 5, 25 => 4, 23 => 3, 21 => 2, 19 => 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 Twig_Source("{% set gpm = admin.gpm() %} +{% set installed = gpm.isPluginInstalled(admin.route) %} +{% set isTestingRelease = gpm.isTestingRelease(plugin.slug) %} +{% set gumroad_loaded = false %} + +
+
+ +

+ {{ plugin.name|e }} + {% if admin.isTeamGrav(plugin) %} + + {% endif %} + {% if admin.isPremiumProduct(plugin) %} + {{ \"PLUGIN_ADMIN.PREMIUM_PRODUCT\"|tu }} + {% endif %} + {% if plugin.symlink %} + + + + {% endif %} + {{ plugin.version ? 'v' ~ plugin.version|e }} + {% if isTestingRelease %}test release{% endif %} +

+
+ + {% include 'partials/plugin-data.html.twig' with { plugin: plugin } %} +
+ +{% if (installed) %} + {% set data = admin.data('plugins/' ~ admin.route) %} + {% include 'partials/blueprints.html.twig' with { data: data, blueprints: data.blueprints } %} + + {% if (plugin.form.fields.enabled.type != 'hidden' and plugin.form.fields.tabs.fields.login.fields.enabled.type != 'hidden') %} + + {% endif %} + +{% else %} +
+ {% if (plugin.premium and not admin.license(plugin.slug)) %} + {% if not gumroad_loaded %} + {% set gumroad_loaded = true %} + + {% endif %} + {{ \"Buy Now\"|tu }} + {% else %} + {{ \"PLUGIN_ADMIN.INSTALL_PLUGIN\"|tu }} + {% endif %} +
+{% endif %} + +{% include 'partials/modal-changes-detected.html.twig' %} +{% include 'partials/modal-add-package.html.twig' with { type: 'plugin' } %} +{% include 'partials/modal-update-packages.html.twig' with { type: 'plugin' } %} +{% include 'partials/modal-remove-package.html.twig' with { type: 'plugin', package: plugin } %} +{% include 'partials/modal-reinstall-package.html.twig' with { type: 'plugin', package: plugin } %} +", "partials/plugins-details.html.twig", "/home/kevin/Sites/static-ethica.net/user/plugins/admin/themes/grav/templates/partials/plugins-details.html.twig"); + } +} diff --git a/cache/twig/05/056bc0d4f9a265a4a5605055305ba3ad27d5884c3b152201a9921e47a1a573be.php b/cache/twig/05/056bc0d4f9a265a4a5605055305ba3ad27d5884c3b152201a9921e47a1a573be.php new file mode 100644 index 0000000..1d706c4 --- /dev/null +++ b/cache/twig/05/056bc0d4f9a265a4a5605055305ba3ad27d5884c3b152201a9921e47a1a573be.php @@ -0,0 +1,109 @@ +parent = false; + + $this->blocks = array( + ); + } + + protected function doDisplay(array $context, array $blocks = array()) + { + // line 1 + if ($this->getAttribute(($context["field"] ?? null), "fields", array())) { + // line 2 + echo "
+ "; + // line 3 + $context['_parent'] = $context; + $context['_seq'] = twig_ensure_traversable($this->getAttribute($context["field"], "fields", array())); + $context['loop'] = array( + 'parent' => $context['_parent'], + 'index0' => 0, + 'index' => 1, + 'first' => true, + ); + if (is_array($context['_seq']) || (is_object($context['_seq']) && $context['_seq'] instanceof Countable)) { + $length = count($context['_seq']); + $context['loop']['revindex0'] = $length - 1; + $context['loop']['revindex'] = $length; + $context['loop']['length'] = $length; + $context['loop']['last'] = 1 === $length; + } + foreach ($context['_seq'] as $context["_key"] => $context["field"]) { + // line 4 + echo " "; + if ($this->getAttribute($context["field"], "type", array())) { + // line 5 + echo " "; + $context["value"] = (($this->getAttribute($context["field"], "name", array())) ? ($this->getAttribute(($context["data"] ?? null), "value", array(0 => $this->getAttribute($context["field"], "name", array())), "method")) : ($this->getAttribute(($context["data"] ?? null), "toArray", array()))); + // line 6 + echo " "; + $this->loadTemplate(array(0 => (((("forms/fields/" . $this->getAttribute($context["field"], "type", array())) . "/") . $this->getAttribute($context["field"], "type", array())) . ".html.twig"), 1 => "forms/fields/text/text.html.twig"), "forms/fields/tab/tab.html.twig", 6)->display($context); + // line 7 + echo " "; + } + // line 8 + echo " "; + ++$context['loop']['index0']; + ++$context['loop']['index']; + $context['loop']['first'] = false; + if (isset($context['loop']['length'])) { + --$context['loop']['revindex0']; + --$context['loop']['revindex']; + $context['loop']['last'] = 0 === $context['loop']['revindex0']; + } + } + $_parent = $context['_parent']; + unset($context['_seq'], $context['_iterated'], $context['_key'], $context['field'], $context['_parent'], $context['loop']); + $context = array_intersect_key($context, $_parent) + $_parent; + // line 9 + echo "
+"; + } + } + + public function getTemplateName() + { + return "forms/fields/tab/tab.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 67 => 9, 53 => 8, 50 => 7, 47 => 6, 44 => 5, 41 => 4, 24 => 3, 21 => 2, 19 => 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 Twig_Source("{% if field.fields %} +
+ {% for field in field.fields %} + {% if field.type %} + {% set 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 %} +
+{% endif %} +", "forms/fields/tab/tab.html.twig", "/mnt/data/Sites/static-ethica.net/user/plugins/admin/themes/grav/templates/forms/fields/tab/tab.html.twig"); + } +} diff --git a/cache/twig/05/05ead202ad3065c9eeb26eedf5949cd728a7e6fa513c6913a83ae0e94afea90d.php b/cache/twig/05/05ead202ad3065c9eeb26eedf5949cd728a7e6fa513c6913a83ae0e94afea90d.php new file mode 100644 index 0000000..d46efeb --- /dev/null +++ b/cache/twig/05/05ead202ad3065c9eeb26eedf5949cd728a7e6fa513c6913a83ae0e94afea90d.php @@ -0,0 +1,209 @@ +parent = $this->loadTemplate("forms/field.html.twig", "forms/fields/textarea/textarea.html.twig", 1); + $this->blocks = array( + 'input' => array($this, 'block_input'), + 'input_attributes' => array($this, 'block_input_attributes'), + ); + } + + protected function doGetParent(array $context) + { + return "forms/field.html.twig"; + } + + protected function doDisplay(array $context, array $blocks = array()) + { + $this->parent->display($context, array_merge($this->blocks, $blocks)); + } + + // line 3 + public function block_input($context, array $blocks = array()) + { + // line 4 + echo "
env, ((($context["form_field_wrapper_classes"] ?? null)) ? (($context["form_field_wrapper_classes"] ?? null)) : ("form-textarea-wrapper")), "html", null, true); + echo " "; + echo twig_escape_filter($this->env, $this->getAttribute(($context["field"] ?? null), "size", array()), "html", null, true); + echo " "; + echo twig_escape_filter($this->env, $this->getAttribute(($context["field"] ?? null), "wrapper_classes", array()), "html", null, true); + echo "\"> + +
+"; + } + + // line 9 + public function block_input_attributes($context, array $blocks = array()) + { + // line 10 + echo " class=\""; + echo twig_escape_filter($this->env, ($context["form_field_textarea_classes"] ?? null), "html", null, true); + echo " "; + echo twig_escape_filter($this->env, $this->getAttribute(($context["field"] ?? null), "classes", array()), "html", null, true); + echo "\" + "; + // line 11 + if ($this->getAttribute(($context["field"] ?? null), "id", array(), "any", true, true)) { + echo "id=\""; + echo twig_escape_filter($this->env, $this->getAttribute(($context["field"] ?? null), "id", array())); + echo "\" "; + } + // line 12 + echo " "; + if ($this->getAttribute(($context["field"] ?? null), "style", array(), "any", true, true)) { + echo "style=\""; + echo twig_escape_filter($this->env, $this->getAttribute(($context["field"] ?? null), "style", array())); + echo "\" "; + } + // line 13 + echo " "; + if (($this->getAttribute(($context["field"] ?? null), "disabled", array()) || ($context["isDisabledToggleable"] ?? null))) { + echo "disabled=\"disabled\""; + } + // line 14 + echo " "; + if ($this->getAttribute(($context["field"] ?? null), "placeholder", array())) { + echo "placeholder=\""; + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Common\Twig\TwigExtension')->translate($this->getAttribute(($context["field"] ?? null), "placeholder", array())), "html", null, true); + echo "\""; + } + // line 15 + echo " "; + if (twig_in_filter($this->getAttribute(($context["field"] ?? null), "autofocus", array()), array(0 => "on", 1 => "true", 2 => 1))) { + echo "autofocus=\"autofocus\""; + } + // line 16 + echo " "; + if (twig_in_filter($this->getAttribute(($context["field"] ?? null), "novalidate", array()), array(0 => "on", 1 => "true", 2 => 1))) { + echo "novalidate=\"novalidate\""; + } + // line 17 + echo " "; + if (twig_in_filter($this->getAttribute(($context["field"] ?? null), "readonly", array()), array(0 => "on", 1 => "true", 2 => 1))) { + echo "readonly=\"readonly\""; + } + // line 18 + echo " "; + if (twig_in_filter($this->getAttribute(($context["field"] ?? null), "autocomplete", array()), array(0 => "on", 1 => "off"))) { + echo "autocomplete=\""; + echo twig_escape_filter($this->env, $this->getAttribute(($context["field"] ?? null), "autocomplete", array()), "html", null, true); + echo "\""; + } + // line 19 + echo " "; + if (twig_in_filter($this->getAttribute($this->getAttribute(($context["field"] ?? null), "validate", array()), "required", array()), array(0 => "on", 1 => "true", 2 => 1))) { + echo "required=\"required\""; + } + // line 20 + echo " "; + if ($this->getAttribute($this->getAttribute(($context["field"] ?? null), "validate", array()), "pattern", array())) { + echo "pattern=\""; + echo twig_escape_filter($this->env, $this->getAttribute($this->getAttribute(($context["field"] ?? null), "validate", array()), "pattern", array()), "html", null, true); + echo "\""; + } + // line 21 + echo " "; + if ($this->getAttribute($this->getAttribute(($context["field"] ?? null), "validate", array()), "message", array())) { + echo "title=\""; + if ($this->getAttribute($this->getAttribute($this->getAttribute($this->getAttribute(($context["grav"] ?? null), "twig", array(), "any", false, true), "twig", array(), "any", false, true), "filters", array(), "any", false, true), "tu", array(), "array", true, true)) { + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter($this->getAttribute($this->getAttribute(($context["field"] ?? null), "validate", array()), "message", array()))); + } else { + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Common\Twig\TwigExtension')->translate($this->getAttribute($this->getAttribute(($context["field"] ?? null), "validate", array()), "message", array()))); + } + echo "\""; + } + // line 22 + echo " "; + if ($this->getAttribute(($context["field"] ?? null), "rows", array(), "any", true, true)) { + echo "rows=\""; + echo twig_escape_filter($this->env, $this->getAttribute(($context["field"] ?? null), "rows", array()), "html", null, true); + echo "\""; + } + // line 23 + echo " "; + if ($this->getAttribute(($context["field"] ?? null), "cols", array(), "any", true, true)) { + echo "cols=\""; + echo twig_escape_filter($this->env, $this->getAttribute(($context["field"] ?? null), "cols", array()), "html", null, true); + echo "\""; + } + // line 24 + echo " "; + } + + public function getTemplateName() + { + return "forms/fields/textarea/textarea.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 152 => 24, 145 => 23, 138 => 22, 127 => 21, 120 => 20, 115 => 19, 108 => 18, 103 => 17, 98 => 16, 93 => 15, 86 => 14, 81 => 13, 74 => 12, 68 => 11, 61 => 10, 58 => 9, 50 => 25, 47 => 9, 42 => 7, 32 => 4, 29 => 3, 11 => 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 Twig_Source("{% extends \"forms/field.html.twig\" %} + +{% block input %} +
+ +
+{% endblock %} +", "forms/fields/textarea/textarea.html.twig", "/home/kevin/Sites/static-ethica.net/user/plugins/form/templates/forms/fields/textarea/textarea.html.twig"); + } +} diff --git a/cache/twig/08/08d5266f3f07dda8f46425e0dc9853b3b099d3478a7c095c0e3bc91d88f7ecc2.php b/cache/twig/08/08d5266f3f07dda8f46425e0dc9853b3b099d3478a7c095c0e3bc91d88f7ecc2.php new file mode 100644 index 0000000..7f6e0db --- /dev/null +++ b/cache/twig/08/08d5266f3f07dda8f46425e0dc9853b3b099d3478a7c095c0e3bc91d88f7ecc2.php @@ -0,0 +1,49 @@ +parent = false; + + $this->blocks = array( + ); + } + + protected function doDisplay(array $context, array $blocks = array()) + { + // line 1 + echo twig_escape_filter($this->env, $this->getAttribute($this->getAttribute($this->getAttribute(($context["config"] ?? null), "plugins", array()), "admin", array()), "twofa_enabled", array()), "html", null, true); + } + + public function getTemplateName() + { + return "{{ config.plugins.admin.twofa_enabled }}"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 19 => 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 Twig_Source("{{ config.plugins.admin.twofa_enabled }}", "{{ config.plugins.admin.twofa_enabled }}", ""); + } +} diff --git a/cache/twig/0b/0b8471b9f41874e16558e54a1e3d8eee9f3cc3d0bf72b44a1769678811205e38.php b/cache/twig/0b/0b8471b9f41874e16558e54a1e3d8eee9f3cc3d0bf72b44a1769678811205e38.php new file mode 100644 index 0000000..4fe7830 --- /dev/null +++ b/cache/twig/0b/0b8471b9f41874e16558e54a1e3d8eee9f3cc3d0bf72b44a1769678811205e38.php @@ -0,0 +1,121 @@ +parent = false; + + $this->blocks = array( + ); + } + + protected function doDisplay(array $context, array $blocks = array()) + { + // line 1 + if ($this->env->getExtension('Grav\Common\Twig\TwigExtension')->authorize(array(0 => "admin.statistics", 1 => "admin.super"))) { + // line 2 + echo "
env, twig_jsonencode_filter(array("series" => array(0 => $this->getAttribute($this->getAttribute(($context["popularity"] ?? null), "getDailyChartData", array()), "data", array(), "array")), "labels" => $this->getAttribute($this->getAttribute(($context["popularity"] ?? null), "getDailyChartData", array()), "labels", array(), "array"))), "html_attr"); + echo "\"> +
+

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

+
+
+
+ + "; + // line 9 + echo twig_escape_filter($this->env, $this->getAttribute(($context["popularity"] ?? null), "getDailyTotal", array()), "html", null, true); + echo " + "; + // line 10 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.TODAY"), "html", null, true); + echo " + + + "; + // line 13 + echo twig_escape_filter($this->env, $this->getAttribute(($context["popularity"] ?? null), "getWeeklyTotal", array()), "html", null, true); + echo " + "; + // line 14 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.WEEK"), "html", null, true); + echo " + + + "; + // line 17 + echo twig_escape_filter($this->env, $this->getAttribute(($context["popularity"] ?? null), "getMonthlyTotal", array()), "html", null, true); + echo " + "; + // line 18 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.MONTH"), "html", null, true); + echo " + +
+
+
+
+"; + } + } + + public function getTemplateName() + { + return "partials/dashboard-statistics.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 59 => 18, 55 => 17, 49 => 14, 45 => 13, 39 => 10, 35 => 9, 27 => 4, 21 => 2, 19 => 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 Twig_Source("{% if authorize(['admin.statistics', 'admin.super']) %} +
+
+

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

+
+
+
+ + {{ popularity.getDailyTotal }} + {{ \"PLUGIN_ADMIN.TODAY\"|tu }} + + + {{ popularity.getWeeklyTotal }} + {{ \"PLUGIN_ADMIN.WEEK\"|tu }} + + + {{ popularity.getMonthlyTotal }} + {{ \"PLUGIN_ADMIN.MONTH\"|tu }} + +
+
+
+
+{% endif %} +", "partials/dashboard-statistics.html.twig", "/mnt/data/Sites/static-ethica.net/user/plugins/admin/themes/grav/templates/partials/dashboard-statistics.html.twig"); + } +} diff --git a/cache/twig/0c/0cb5f91895635a9559b9b709c0df21d522ceaee0b82bc5424bc85fc5e63b79d7.php b/cache/twig/0c/0cb5f91895635a9559b9b709c0df21d522ceaee0b82bc5424bc85fc5e63b79d7.php new file mode 100644 index 0000000..7fe7432 --- /dev/null +++ b/cache/twig/0c/0cb5f91895635a9559b9b709c0df21d522ceaee0b82bc5424bc85fc5e63b79d7.php @@ -0,0 +1,185 @@ +parent = $this->loadTemplate("forms/field.html.twig", "forms/fields/themeselect/themeselect.html.twig", 1); + $this->blocks = array( + 'global_attributes' => array($this, 'block_global_attributes'), + 'input' => array($this, 'block_input'), + ); + } + + protected function doGetParent(array $context) + { + return "forms/field.html.twig"; + } + + protected function doDisplay(array $context, array $blocks = array()) + { + // line 3 + $context["options"] = array(); + // line 4 + $context['_parent'] = $context; + $context['_seq'] = twig_ensure_traversable($this->getAttribute(($context["admin"] ?? null), "themes", array())); + foreach ($context['_seq'] as $context["slug"] => $context["package"]) { + // line 5 + $context["option"] = array($context["slug"] => $this->getAttribute($this->getAttribute($context["package"], "toArray", array(), "method"), "name", array())); + // line 6 + $context["options"] = twig_array_merge(($context["options"] ?? null), ($context["option"] ?? null)); + } + $_parent = $context['_parent']; + unset($context['_seq'], $context['_iterated'], $context['slug'], $context['package'], $context['_parent'], $context['loop']); + $context = array_intersect_key($context, $_parent) + $_parent; + // line 1 + $this->parent->display($context, array_merge($this->blocks, $blocks)); + } + + // line 9 + public function block_global_attributes($context, array $blocks = array()) + { + // line 10 + echo " data-grav-selectize=\""; + echo twig_escape_filter($this->env, twig_jsonencode_filter((($this->getAttribute(($context["field"] ?? null), "selectize", array(), "any", true, true)) ? ($this->getAttribute(($context["field"] ?? null), "selectize", array())) : (array()))), "html_attr"); + echo "\" + data-grav-field=\"select\" + data-grav-disabled=\""; + // line 12 + echo (((null === ($context["originalValue"] ?? null))) ? ("true") : ("false")); + echo "\" + data-grav-default=\""; + // line 13 + echo twig_escape_filter($this->env, twig_jsonencode_filter($this->getAttribute(($context["field"] ?? null), "default", array())), "html_attr"); + echo "\" +"; + } + + // line 16 + public function block_input($context, array $blocks = array()) + { + // line 17 + echo "
env, $this->getAttribute(($context["field"] ?? null), "size", array()), "html", null, true); + echo "\"> + +
+"; + } + + public function getTemplateName() + { + return "forms/fields/themeselect/themeselect.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 122 => 27, 107 => 25, 103 => 24, 96 => 23, 91 => 22, 86 => 21, 81 => 20, 77 => 19, 71 => 18, 66 => 17, 63 => 16, 57 => 13, 53 => 12, 47 => 10, 44 => 9, 40 => 1, 34 => 6, 32 => 5, 28 => 4, 26 => 3, 11 => 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 Twig_Source("{% extends \"forms/field.html.twig\" %} + +{% set options = {} %} +{% for slug, package in admin.themes %} + {% set option = {(slug): package.toArray().name} %} + {% set options = options|merge(option) %} +{% endfor %} + +{% block global_attributes %} + data-grav-selectize=\"{{ (field.selectize is defined ? field.selectize : {})|json_encode()|e('html_attr') }}\" + data-grav-field=\"select\" + data-grav-disabled=\"{{ originalValue is null ? 'true' : 'false' }}\" + data-grav-default=\"{{ field.default|json_encode()|e('html_attr') }}\" +{% endblock %} + +{% block input %} +
+ +
+{% endblock %} + + +", "forms/fields/themeselect/themeselect.html.twig", "/mnt/data/Sites/static-ethica.net/user/plugins/admin/themes/grav/templates/forms/fields/themeselect/themeselect.html.twig"); + } +} diff --git a/cache/twig/0f/0f7af880b778a16f24a311f3f46bb7b7281950c37dd86d7bfc29309432147627.php b/cache/twig/0f/0f7af880b778a16f24a311f3f46bb7b7281950c37dd86d7bfc29309432147627.php new file mode 100644 index 0000000..3704392 --- /dev/null +++ b/cache/twig/0f/0f7af880b778a16f24a311f3f46bb7b7281950c37dd86d7bfc29309432147627.php @@ -0,0 +1,164 @@ +parent = false; + + $this->blocks = array( + ); + } + + protected function doDisplay(array $context, array $blocks = array()) + { + // line 1 + echo "
+
+
+

"; + // line 6 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.REINSTALL_THE", array(0 => $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter(("PLUGIN_ADMIN." . twig_upper_filter($this->env, ($context["type"] ?? null))))))); + echo "

+

+ "; + // line 8 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.CONFIRM_REINSTALL", array(0 => $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter(("PLUGIN_ADMIN." . twig_upper_filter($this->env, ($context["type"] ?? null))))))); + echo " +

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

"; + // line 31 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.REINSTALLED_SUCCESSFULLY", array(0 => $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter(("PLUGIN_ADMIN." . twig_upper_filter($this->env, ($context["type"] ?? null))))))); + echo "

+
+ +
+

"; + // line 35 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.ERROR_REINSTALLING_THE", array(0 => $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter(("PLUGIN_ADMIN." . twig_upper_filter($this->env, ($context["type"] ?? null))))))); + echo "

+
+
+
+"; + } + + public function getTemplateName() + { + return "partials/modal-reinstall-package.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 91 => 35, 84 => 31, 75 => 25, 69 => 22, 65 => 21, 61 => 20, 57 => 19, 53 => 18, 49 => 17, 44 => 15, 37 => 11, 31 => 8, 26 => 6, 19 => 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 Twig_Source("
+
+
+

{{ \"PLUGIN_ADMIN.REINSTALL_THE\"|tu([(\"PLUGIN_ADMIN.\" ~ type|upper)|tu])|e }}

+

+ {{ \"PLUGIN_ADMIN.CONFIRM_REINSTALL\"|tu([(\"PLUGIN_ADMIN.\" ~ type|upper)|tu])|e }} +

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

{{ \"PLUGIN_ADMIN.REINSTALLED_SUCCESSFULLY\"|tu([(\"PLUGIN_ADMIN.\" ~ type|upper)|tu])|e }}

+
+ +
+

{{ \"PLUGIN_ADMIN.ERROR_REINSTALLING_THE\"|tu([(\"PLUGIN_ADMIN.\" ~ type|upper)|tu])|e }}

+
+
+
+", "partials/modal-reinstall-package.html.twig", "/home/kevin/Sites/static-ethica.net/user/plugins/admin/themes/grav/templates/partials/modal-reinstall-package.html.twig"); + } +} diff --git a/cache/twig/15/15962f8b7e50d93e0f7ee266bb1d741bee9581f4a7662c4d98c36e1bcb97bc83.php b/cache/twig/15/15962f8b7e50d93e0f7ee266bb1d741bee9581f4a7662c4d98c36e1bcb97bc83.php new file mode 100644 index 0000000..2276052 --- /dev/null +++ b/cache/twig/15/15962f8b7e50d93e0f7ee266bb1d741bee9581f4a7662c4d98c36e1bcb97bc83.php @@ -0,0 +1,156 @@ +parent = $this->loadTemplate("partials/base.html.twig", "partials/login.html.twig", 1); + $this->blocks = array( + 'messages' => array($this, 'block_messages'), + 'body' => array($this, 'block_body'), + 'instructions' => array($this, 'block_instructions'), + 'form' => array($this, 'block_form'), + ); + } + + protected function doGetParent(array $context) + { + return "partials/base.html.twig"; + } + + protected function doDisplay(array $context, array $blocks = array()) + { + // line 2 + $context["scope"] = ((($context["scope"] ?? null)) ? (($context["scope"] ?? null)) : ("data.")); + // line 1 + $this->parent->display($context, array_merge($this->blocks, $blocks)); + } + + // line 3 + public function block_messages($context, array $blocks = array()) + { + } + + // line 5 + public function block_body($context, array $blocks = array()) + { + // line 6 + echo " +
env, ($context["classes"] ?? null), "html", null, true); + echo "\"> +

+ "; + // line 9 + echo twig_escape_filter($this->env, ($context["title"] ?? null), "html", null, true); + echo " +

+ + "; + // line 12 + $this->loadTemplate("partials/messages.html.twig", "partials/login.html.twig", 12)->display($context); + // line 13 + echo " + "; + // line 14 + $this->displayBlock('instructions', $context, $blocks); + // line 15 + echo " + "; + // line 16 + $context["redirect"] = ((($context["redirect"] ?? null)) ? (($context["redirect"] ?? null)) : ($this->getAttribute(($context["uri"] ?? null), "route", array(0 => false), "method"))); + // line 17 + echo " +
env, ($context["base_url_relative"] ?? null), "html", null, true); + echo "\"> +
+ "; + // line 20 + $this->displayBlock('form', $context, $blocks); + // line 21 + echo " env, ($context["redirect"] ?? null), "html", null, true); + echo "\" /> + "; + // line 22 + echo $this->env->getExtension('Grav\Common\Twig\TwigExtension')->nonceFieldFunc("admin-form", "admin-nonce"); + echo " +
+
+
+ +"; + } + + // line 14 + public function block_instructions($context, array $blocks = array()) + { + } + + // line 20 + public function block_form($context, array $blocks = array()) + { + } + + public function getTemplateName() + { + return "partials/login.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 98 => 20, 93 => 14, 83 => 22, 78 => 21, 76 => 20, 71 => 18, 68 => 17, 66 => 16, 63 => 15, 61 => 14, 58 => 13, 56 => 12, 50 => 9, 45 => 7, 42 => 6, 39 => 5, 34 => 3, 30 => 1, 28 => 2, 11 => 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 Twig_Source("{% extends 'partials/base.html.twig' %} +{% set scope = scope ?: 'data.' %} +{% block messages %}{% endblock %} + +{% block body %} + +
+

+ {{ title }} +

+ + {% include 'partials/messages.html.twig' %} + + {% block instructions %}{% endblock %} + + {% set redirect = redirect ?: uri.route(false) %} + +
+
+ {% block form %}{% endblock %} + + {{ nonce_field('admin-form', 'admin-nonce')|raw }} +
+
+
+ +{% endblock %} +", "partials/login.html.twig", "/mnt/data/Sites/static-ethica.net/user/plugins/admin/themes/grav/templates/partials/login.html.twig"); + } +} diff --git a/cache/twig/16/163e1498525bc34b95708ae6da1c707263e172795bd86c5d9aeedb08c2c3db98.php b/cache/twig/16/163e1498525bc34b95708ae6da1c707263e172795bd86c5d9aeedb08c2c3db98.php new file mode 100644 index 0000000..37366ea --- /dev/null +++ b/cache/twig/16/163e1498525bc34b95708ae6da1c707263e172795bd86c5d9aeedb08c2c3db98.php @@ -0,0 +1,42 @@ +parent = false; + + $this->blocks = array( + ); + } + + protected function doDisplay(array $context, array $blocks = array()) + { + } + + public function getTemplateName() + { + return "empty.html.twig"; + } + + public function getDebugInfo() + { + return array (); + } + + /** @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 Twig_Source("", "empty.html.twig", "/mnt/data/Sites/static-ethica.net/user/plugins/admin/themes/grav/templates/empty.html.twig"); + } +} diff --git a/cache/twig/18/1871fb2d2d03e7d0d43215bff69c642d0ec876390d460ab66bd8aca68306844d.php b/cache/twig/18/1871fb2d2d03e7d0d43215bff69c642d0ec876390d460ab66bd8aca68306844d.php new file mode 100644 index 0000000..0cef359 --- /dev/null +++ b/cache/twig/18/1871fb2d2d03e7d0d43215bff69c642d0ec876390d460ab66bd8aca68306844d.php @@ -0,0 +1,337 @@ +parent = $this->loadTemplate("partials/base.html.twig", "themes.html.twig", 1); + $this->blocks = array( + 'stylesheets' => array($this, 'block_stylesheets'), + 'javascripts' => array($this, 'block_javascripts'), + 'titlebar' => array($this, 'block_titlebar'), + 'messages' => array($this, 'block_messages'), + 'content' => array($this, 'block_content'), + ); + } + + protected function doGetParent(array $context) + { + return "partials/base.html.twig"; + } + + protected function doDisplay(array $context, array $blocks = array()) + { + // line 3 + if ($this->getAttribute(($context["admin"] ?? null), "route", array())) { + // line 4 + $context["installing"] = (is_string($__internal_62b8b8f4b6426054e58af8cd2a95667079b12a0ceba7720cb80827bece622b94 = $this->getAttribute(($context["admin"] ?? null), "route", array())) && is_string($__internal_38d13f1312ef9f9145aa02a0def90d44714d34cd7c0e01a4dd2513f054c9a8ba = "install") && ('' === $__internal_38d13f1312ef9f9145aa02a0def90d44714d34cd7c0e01a4dd2513f054c9a8ba || 0 === strpos($__internal_62b8b8f4b6426054e58af8cd2a95667079b12a0ceba7720cb80827bece622b94, $__internal_38d13f1312ef9f9145aa02a0def90d44714d34cd7c0e01a4dd2513f054c9a8ba))); + // line 6 + if (($context["installing"] ?? null)) { + // line 7 + $context["title"] = $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.THEMES"); + } else { + // line 9 + $context["installed"] = true; + // line 12 + $context["package"] = $this->getAttribute($this->getAttribute(($context["admin"] ?? null), "themes", array(0 => true), "method"), $this->getAttribute(($context["admin"] ?? null), "route", array()), array(), "array"); + // line 13 + if ( !($context["package"] ?? null)) { + // line 14 + $context["package"] = $this->getAttribute($this->getAttribute(($context["admin"] ?? null), "themes", array(0 => false), "method"), $this->getAttribute(($context["admin"] ?? null), "route", array()), array(), "array"); + // line 15 + $context["installed"] = false; + } + // line 18 + $context["theme"] = $this->getAttribute(($context["package"] ?? null), "toArray", array(), "method"); + // line 19 + $context["title"] = (($this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.THEME") . ": ") . twig_escape_filter($this->env, $this->getAttribute(($context["theme"] ?? null), "name", array()))); + } + } else { + // line 22 + $context["title"] = $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.THEMES"); + } + // line 25 + if (($this->getAttribute(($context["admin"] ?? null), "route", array()) || ($context["installing"] ?? null))) { + } + // line 1 + $this->parent->display($context, array_merge($this->blocks, $blocks)); + } + + // line 26 + public function block_stylesheets($context, array $blocks = array()) + { + // line 27 + echo " "; + $this->getAttribute(($context["assets"] ?? null), "addCss", array(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 = array()) + { + // line 32 + echo " "; + $this->displayParentBlock("javascripts", $context, $blocks); + echo " + "; + } + + // line 36 + public function block_titlebar($context, array $blocks = array()) + { + // line 37 + echo " "; + if (( !$this->getAttribute(($context["admin"] ?? null), "route", array()) || ($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\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\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\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.ADD"), "html", null, true); + echo " + "; + // line 44 + if ($this->env->getExtension('Grav\Common\Twig\TwigExtension')->authorize(array(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\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\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\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.THEME"), "html", null, true); + echo ": "; + echo twig_escape_filter($this->env, $this->getAttribute(($context["theme"] ?? null), "name", array())); + echo "

+ "; + } + } + + // line 65 + public function block_messages($context, array $blocks = array()) + { + // line 66 + echo " "; + $this->displayParentBlock("messages", $context, $blocks); + echo " + "; + // line 67 + if ($this->getAttribute($this->getAttribute($this->getAttribute($this->getAttribute(($context["config"] ?? null), "plugins", array()), "admin", array()), "notifications", array()), "themes", array())) { + // line 68 + echo "
+ "; + } + } + + // line 72 + public function block_content($context, array $blocks = array()) + { + // line 73 + echo "
+ "; + // line 74 + if (( !$this->getAttribute(($context["admin"] ?? null), "route", array()) || ($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 ( 223 => 82, 220 => 81, 217 => 80, 211 => 78, 208 => 77, 205 => 76, 202 => 75, 200 => 74, 197 => 73, 194 => 72, 188 => 68, 186 => 67, 181 => 66, 178 => 65, 168 => 61, 160 => 58, 157 => 57, 151 => 54, 145 => 53, 142 => 52, 139 => 51, 134 => 49, 131 => 48, 128 => 47, 122 => 45, 120 => 44, 114 => 43, 107 => 42, 99 => 40, 97 => 39, 94 => 38, 91 => 37, 88 => 36, 81 => 32, 78 => 31, 71 => 28, 68 => 27, 65 => 26, 61 => 1, 58 => 25, 55 => 22, 51 => 19, 49 => 18, 46 => 15, 44 => 14, 42 => 13, 40 => 12, 38 => 9, 35 => 7, 33 => 6, 31 => 4, 29 => 3, 11 => 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 Twig_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", "/home/kevin/Sites/static-ethica.net/user/plugins/admin/themes/grav/templates/themes.html.twig"); + } +} diff --git a/cache/twig/1a/1a075714b0524735995c5a1c05a5d1cc23bb446792abf7269fa0fd2cf16f5e8e.php b/cache/twig/1a/1a075714b0524735995c5a1c05a5d1cc23bb446792abf7269fa0fd2cf16f5e8e.php new file mode 100644 index 0000000..fb0f9af --- /dev/null +++ b/cache/twig/1a/1a075714b0524735995c5a1c05a5d1cc23bb446792abf7269fa0fd2cf16f5e8e.php @@ -0,0 +1,235 @@ +parent = $this->loadTemplate("forms/field.html.twig", "forms/fields/select/select.html.twig", 1); + $this->blocks = array( + 'global_attributes' => array($this, 'block_global_attributes'), + 'input' => array($this, 'block_input'), + ); + } + + protected function doGetParent(array $context) + { + return "forms/field.html.twig"; + } + + protected function doDisplay(array $context, array $blocks = array()) + { + $this->parent->display($context, array_merge($this->blocks, $blocks)); + } + + // line 3 + public function block_global_attributes($context, array $blocks = array()) + { + // line 4 + echo " data-grav-selectize=\""; + echo twig_escape_filter($this->env, twig_jsonencode_filter((($this->getAttribute(($context["field"] ?? null), "selectize", array(), "any", true, true)) ? ($this->getAttribute(($context["field"] ?? null), "selectize", array())) : (array()))), "html_attr"); + echo "\" + "; + // line 5 + $this->displayParentBlock("global_attributes", $context, $blocks); + echo " +"; + } + + // line 8 + public function block_input($context, array $blocks = array()) + { + // line 9 + echo "
env, ((($context["form_field_wrapper_classes"] ?? null)) ? (($context["form_field_wrapper_classes"] ?? null)) : ("form-select-wrapper")), "html", null, true); + echo " "; + echo twig_escape_filter($this->env, $this->getAttribute(($context["field"] ?? null), "size", array()), "html", null, true); + echo " "; + echo twig_escape_filter($this->env, $this->getAttribute(($context["field"] ?? null), "wrapper_classes", array()), "html", null, true); + echo "\"> + +
+"; + } + + public function getTemplateName() + { + return "forms/fields/select/select.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 169 => 32, 150 => 30, 147 => 29, 144 => 28, 140 => 27, 137 => 26, 127 => 25, 124 => 24, 118 => 22, 115 => 21, 108 => 20, 103 => 19, 98 => 18, 93 => 17, 88 => 16, 83 => 15, 78 => 14, 71 => 13, 65 => 12, 59 => 11, 55 => 10, 46 => 9, 43 => 8, 37 => 5, 32 => 4, 29 => 3, 11 => 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 Twig_Source("{% extends \"forms/field.html.twig\" %} + +{% block global_attributes %} + data-grav-selectize=\"{{ (field.selectize is defined ? field.selectize : {})|json_encode()|e('html_attr') }}\" + {{ parent() }} +{% endblock %} + +{% block input %} +
+ +
+{% endblock %} +", "forms/fields/select/select.html.twig", "/mnt/data/Sites/static-ethica.net/user/plugins/form/templates/forms/fields/select/select.html.twig"); + } +} diff --git a/cache/twig/1b/1b245494d0236888490a1c5d8c5b9114de0179d7f3d238506b3c3cb9b27db17f.php b/cache/twig/1b/1b245494d0236888490a1c5d8c5b9114de0179d7f3d238506b3c3cb9b27db17f.php new file mode 100644 index 0000000..6742222 --- /dev/null +++ b/cache/twig/1b/1b245494d0236888490a1c5d8c5b9114de0179d7f3d238506b3c3cb9b27db17f.php @@ -0,0 +1,55 @@ +parent = false; + + $this->blocks = array( + ); + } + + protected function doDisplay(array $context, array $blocks = array()) + { + // line 1 + echo "

"; + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.AVATAR_BY"), "html", null, true); + echo " gravatar.com. "; + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.AVATAR_UPLOAD_OWN"), "html", null, true); + echo "

+"; + } + + public function getTemplateName() + { + return "partials/userinfo-avatar-credit.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 19 => 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 Twig_Source("

{{ \"PLUGIN_ADMIN.AVATAR_BY\"|tu }} gravatar.com. {{ \"PLUGIN_ADMIN.AVATAR_UPLOAD_OWN\"|tu }}

+", "partials/userinfo-avatar-credit.html.twig", "/home/kevin/Sites/static-ethica.net/user/plugins/admin/themes/grav/templates/partials/userinfo-avatar-credit.html.twig"); + } +} diff --git a/cache/twig/1e/1ebcf6b6e46d932616cc1ef32d4d1726001728cb865d1750f0ce78e0c6fd39c7.php b/cache/twig/1e/1ebcf6b6e46d932616cc1ef32d4d1726001728cb865d1750f0ce78e0c6fd39c7.php new file mode 100644 index 0000000..4ab9b6a --- /dev/null +++ b/cache/twig/1e/1ebcf6b6e46d932616cc1ef32d4d1726001728cb865d1750f0ce78e0c6fd39c7.php @@ -0,0 +1,119 @@ +parent = $this->loadTemplate("forms/fields/pages/pages.html.twig", "forms/fields/parents/parents.html.twig", 1); + $this->blocks = array( + 'input' => array($this, 'block_input'), + ); + } + + protected function doGetParent(array $context) + { + return "forms/fields/pages/pages.html.twig"; + } + + protected function doDisplay(array $context, array $blocks = array()) + { + $this->parent->display($context, array_merge($this->blocks, $blocks)); + } + + // line 3 + public function block_input($context, array $blocks = array()) + { + // line 4 + echo " "; + $context["last_page_route"] = $this->getAttribute($this->getAttribute(($context["admin"] ?? null), "page", array()), "getLastPageRoute", array()); + // line 5 + echo " "; + $context["show_slug_val"] = true; + // line 6 + echo " "; + $context["show_fullpath_val"] = false; + // line 7 + echo " + "; + // line 8 + $context["show_parents"] = $this->getAttribute(($context["config"] ?? null), "get", array(0 => "plugins.admin.pages.show_parents"), "method"); + // line 9 + echo " "; + if ((($context["show_parents"] ?? null) == "folder")) { + // line 10 + echo " "; + $context["show_slug_val"] = false; + // line 11 + echo " "; + } elseif ((($context["show_parents"] ?? null) == "fullpath")) { + // line 12 + echo " "; + $context["show_fullpath_val"] = true; + // line 13 + echo " "; + } + // line 14 + echo " + "; + // line 15 + $context["defaults"] = array("show_root" => true, "show_all" => true, "show_slug" => ($context["show_slug_val"] ?? null), "show_fullpath" => ($context["show_fullpath_val"] ?? null), "default" => ($context["last_page_route"] ?? null)); + // line 16 + echo " "; + $context["field"] = twig_array_merge(($context["field"] ?? null), ($context["defaults"] ?? null)); + // line 17 + echo " "; + $this->displayParentBlock("input", $context, $blocks); + echo " +"; + } + + public function getTemplateName() + { + return "forms/fields/parents/parents.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 68 => 17, 65 => 16, 63 => 15, 60 => 14, 57 => 13, 54 => 12, 51 => 11, 48 => 10, 45 => 9, 43 => 8, 40 => 7, 37 => 6, 34 => 5, 31 => 4, 28 => 3, 11 => 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 Twig_Source("{% extends \"forms/fields/pages/pages.html.twig\" %} + +{% block input %} + {% set last_page_route = admin.page.getLastPageRoute %} + {% set show_slug_val = true %} + {% set show_fullpath_val = false %} + + {% set show_parents = config.get('plugins.admin.pages.show_parents') %} + {% if show_parents == 'folder' %} + {% set show_slug_val = false %} + {% elseif show_parents == 'fullpath' %} + {% set show_fullpath_val = true %} + {% endif %} + + {% set defaults = {show_root:true, show_all:true, show_slug:show_slug_val, show_fullpath:show_fullpath_val, default:last_page_route} %} + {% set field = field|merge(defaults) %} + {{ parent() }} +{% endblock %} +", "forms/fields/parents/parents.html.twig", "/mnt/data/Sites/static-ethica.net/user/plugins/admin/themes/grav/templates/forms/fields/parents/parents.html.twig"); + } +} diff --git a/cache/twig/20/2061e249bf57b4ee5737347427d69fb5da6eac4588fcb17dac6ef668425ade46.php b/cache/twig/20/2061e249bf57b4ee5737347427d69fb5da6eac4588fcb17dac6ef668425ade46.php new file mode 100644 index 0000000..768905a --- /dev/null +++ b/cache/twig/20/2061e249bf57b4ee5737347427d69fb5da6eac4588fcb17dac6ef668425ade46.php @@ -0,0 +1,277 @@ +parent = false; + + $this->blocks = array( + ); + } + + protected function doDisplay(array $context, array $blocks = array()) + { + // line 1 + echo "
+
+
+

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

+ +
+

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

+
+ +
+

"; + // line 17 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\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\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\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\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\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\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.CONTINUE"), "html", null, true); + echo " +
          +
          + +
          +

          + "; + // line 53 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\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\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.INSTALLING_DEPENDENCIES"), "html", null, true); + echo " + +

            +
            + +
            +

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

            + +
              +
              + +
              +

              + "; + // line 81 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\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 ( 150 => 81, 138 => 72, 128 => 65, 119 => 59, 110 => 53, 99 => 47, 95 => 46, 86 => 40, 75 => 34, 71 => 33, 63 => 28, 56 => 24, 49 => 20, 43 => 17, 34 => 11, 27 => 7, 19 => 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 Twig_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", "/mnt/data/Sites/static-ethica.net/user/plugins/admin/themes/grav/templates/partials/modal-update-packages.html.twig"); + } +} diff --git a/cache/twig/21/211c79a5ee840efb86a9d9d10829fe8c2254a0e5f5105146d6725657f0f53a9b.php b/cache/twig/21/211c79a5ee840efb86a9d9d10829fe8c2254a0e5f5105146d6725657f0f53a9b.php new file mode 100644 index 0000000..6eb5f1b --- /dev/null +++ b/cache/twig/21/211c79a5ee840efb86a9d9d10829fe8c2254a0e5f5105146d6725657f0f53a9b.php @@ -0,0 +1,89 @@ +parent = $this->loadTemplate("partials/base.html.twig", "error.html.twig", 1); + $this->blocks = array( + 'content' => array($this, 'block_content'), + ); + } + + protected function doGetParent(array $context) + { + return "partials/base.html.twig"; + } + + protected function doDisplay(array $context, array $blocks = array()) + { + $this->parent->display($context, array_merge($this->blocks, $blocks)); + } + + // line 3 + public function block_content($context, array $blocks = array()) + { + // line 4 + echo "\t
                              +\t\t
                              +\t\t\t

                              "; + // line 6 + echo $this->env->getExtension('Grav\Common\Twig\TwigExtension')->translate("ERROR"); + echo " "; + echo $this->getAttribute($this->getAttribute(($context["page"] ?? null), "header", array()), "http_response_code", array()); + echo "

                              +\t\t\t

                              +\t\t\t\t"; + // line 8 + echo $this->getAttribute(($context["page"] ?? null), "content", array()); + echo " +\t\t\t

                              +\t\t
                              +\t
                              +"; + } + + public function getTemplateName() + { + return "error.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 42 => 8, 35 => 6, 31 => 4, 28 => 3, 11 => 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 Twig_Source("{% extends 'partials/base.html.twig' %} + +{% block content %} +\t
                              +\t\t
                              +\t\t\t

                              {{ 'ERROR'|t }} {{ page.header.http_response_code }}

                              +\t\t\t

                              +\t\t\t\t{{ page.content }} +\t\t\t

                              +\t\t
                              +\t
                              +{% endblock %} +", "error.html.twig", "/mnt/data/Sites/static-ethica.net/user/themes/ethica/templates/error.html.twig"); + } +} diff --git a/cache/twig/22/22bd1662b7e19e313f53cdf31140abec9af39f70a826230f9d601e12216e3a63.php b/cache/twig/22/22bd1662b7e19e313f53cdf31140abec9af39f70a826230f9d601e12216e3a63.php new file mode 100644 index 0000000..ebd899c --- /dev/null +++ b/cache/twig/22/22bd1662b7e19e313f53cdf31140abec9af39f70a826230f9d601e12216e3a63.php @@ -0,0 +1,86 @@ +parent = false; + + $this->blocks = array( + ); + } + + protected function doDisplay(array $context, array $blocks = array()) + { + // line 1 + $this->getAttribute(($context["assets"] ?? null), "add", array(0 => "jquery", 1 => 101), "method"); + // line 2 + if ($this->env->getExtension('Grav\Common\Twig\TwigExtension')->authorize(array(0 => "admin.login", 1 => "admin.super"))) { + // line 3 + $this->getAttribute(($context["assets"] ?? null), "addJs", array(0 => (($context["theme_url"] ?? null) . "/js/vendor.min.js"), 1 => array("loading" => "defer")), "method"); + // line 4 + $this->getAttribute(($context["assets"] ?? null), "addJs", array(0 => (($context["theme_url"] ?? null) . "/js/admin.min.js"), 1 => array("loading" => "defer")), "method"); + // line 5 + echo " +"; + // line 6 + if ((($this->getAttribute(($context["browser"] ?? null), "getBrowser", array()) == "msie") || ($this->getAttribute(($context["browser"] ?? null), "getBrowser", array()) == "edge"))) { + // line 7 + echo " "; + $this->getAttribute(($context["assets"] ?? null), "addJs", array(0 => (($context["theme_url"] ?? null) . "/js/form-attr.polyfill.js")), "method"); + } + // line 9 + echo " +"; + // line 10 + try { + $this->loadTemplate("partials/javascripts-extra.html.twig", "partials/javascripts.html.twig", 10)->display($context); + } catch (Twig_Error_Loader $e) { + // ignore missing template + } + + } + } + + public function getTemplateName() + { + return "partials/javascripts.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 39 => 10, 36 => 9, 32 => 7, 30 => 6, 27 => 5, 25 => 4, 23 => 3, 21 => 2, 19 => 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 Twig_Source("{% do assets.add('jquery',101) %} +{% if authorize(['admin.login', 'admin.super']) %} +{% do assets.addJs(theme_url~'/js/vendor.min.js', { 'loading':'defer' }) %} +{% do assets.addJs(theme_url~'/js/admin.min.js' , { 'loading':'defer' }) %} + +{% if browser.getBrowser == 'msie' or browser.getBrowser == 'edge' %} + {% do assets.addJs(theme_url~'/js/form-attr.polyfill.js') %} +{% endif %} + +{% include 'partials/javascripts-extra.html.twig' ignore missing %} +{% endif %} +", "partials/javascripts.html.twig", "/mnt/data/Sites/static-ethica.net/user/plugins/admin/themes/grav/templates/partials/javascripts.html.twig"); + } +} diff --git a/cache/twig/24/249075002a9f60ec52754438c718b55a97075d0f2e30662dfdb5c9eccafafc9c.php b/cache/twig/24/249075002a9f60ec52754438c718b55a97075d0f2e30662dfdb5c9eccafafc9c.php new file mode 100644 index 0000000..804f314 --- /dev/null +++ b/cache/twig/24/249075002a9f60ec52754438c718b55a97075d0f2e30662dfdb5c9eccafafc9c.php @@ -0,0 +1,151 @@ +parent = false; + + $this->blocks = array( + ); + } + + protected function doDisplay(array $context, array $blocks = array()) + { + // line 1 + $context["value"] = $this->env->getExtension('Grav\Common\Twig\TwigExtension')->evaluateStringFunc($this->env, $context, $this->getAttribute(($context["field"] ?? null), "condition", array())); + // line 2 + $context["value"] = (((($context["value"] ?? null) == "true")) ? (1) : (($context["value"] ?? null))); + // line 3 + $context["value"] = (((($context["value"] ?? null) == "false")) ? (0) : (($context["value"] ?? null))); + // line 4 + echo " +"; + // line 5 + if (($context["value"] ?? null)) { + // line 6 + echo " "; + if ($this->getAttribute(($context["field"] ?? null), "classes", array())) { + // line 7 + echo "
                              env, $this->getAttribute(($context["field"] ?? null), "classes", array()), "html", null, true); + echo "\"> + "; + } + // line 9 + echo " + "; + // line 10 + if ($this->getAttribute(($context["field"] ?? null), "fields", array())) { + // line 11 + echo " "; + $context['_parent'] = $context; + $context['_seq'] = twig_ensure_traversable($this->getAttribute($context["field"], "fields", array())); + $context['loop'] = array( + 'parent' => $context['_parent'], + 'index0' => 0, + 'index' => 1, + 'first' => true, + ); + if (is_array($context['_seq']) || (is_object($context['_seq']) && $context['_seq'] instanceof Countable)) { + $length = count($context['_seq']); + $context['loop']['revindex0'] = $length - 1; + $context['loop']['revindex'] = $length; + $context['loop']['length'] = $length; + $context['loop']['last'] = 1 === $length; + } + foreach ($context['_seq'] as $context["_key"] => $context["field"]) { + // line 12 + echo " "; + if ($this->getAttribute($context["field"], "type", array())) { + // line 13 + echo " "; + $context["value"] = $this->getAttribute(($context["data"] ?? null), "value", array(0 => $this->getAttribute($context["field"], "name", array())), "method"); + // line 14 + echo " "; + $this->loadTemplate(array(0 => (((("forms/fields/" . $this->getAttribute($context["field"], "type", array())) . "/") . $this->getAttribute($context["field"], "type", array())) . ".html.twig"), 1 => "forms/fields/text/text.html.twig"), "forms/fields/conditional/conditional.html.twig", 14)->display($context); + // line 15 + echo " "; + } + // line 16 + echo " "; + ++$context['loop']['index0']; + ++$context['loop']['index']; + $context['loop']['first'] = false; + if (isset($context['loop']['length'])) { + --$context['loop']['revindex0']; + --$context['loop']['revindex']; + $context['loop']['last'] = 0 === $context['loop']['revindex0']; + } + } + $_parent = $context['_parent']; + unset($context['_seq'], $context['_iterated'], $context['_key'], $context['field'], $context['_parent'], $context['loop']); + $context = array_intersect_key($context, $_parent) + $_parent; + // line 17 + echo " "; + } + // line 18 + echo " + "; + // line 19 + if ($this->getAttribute(($context["field"] ?? null), "classes", array())) { + // line 20 + echo "
                              + "; + } + } + } + + public function getTemplateName() + { + return "forms/fields/conditional/conditional.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 96 => 20, 94 => 19, 91 => 18, 88 => 17, 74 => 16, 71 => 15, 68 => 14, 65 => 13, 62 => 12, 44 => 11, 42 => 10, 39 => 9, 33 => 7, 30 => 6, 28 => 5, 25 => 4, 23 => 3, 21 => 2, 19 => 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 Twig_Source("{% set value = evaluate(field.condition) %} +{% set value = value == 'true' ? 1 : value %} +{% set value = value == 'false' ? 0 : value %} + +{% if value %} + {% if field.classes %} +
                              + {% endif %} + + {% if field.fields %} + {% for field in field.fields %} + {% if field.type %} + {% set value = data.value(field.name) %} + {% include [\"forms/fields/#{field.type}/#{field.type}.html.twig\", 'forms/fields/text/text.html.twig'] %} + {% endif %} + {% endfor %} + {% endif %} + + {% if field.classes %} +
                              + {% endif %} +{% endif %} +", "forms/fields/conditional/conditional.html.twig", "/home/kevin/Sites/static-ethica.net/user/plugins/form/templates/forms/fields/conditional/conditional.html.twig"); + } +} diff --git a/cache/twig/2d/2d6fd692de5c8f454faf6e54c63704d917a377f3327e783f3e0db6aa11b4e7fc.php b/cache/twig/2d/2d6fd692de5c8f454faf6e54c63704d917a377f3327e783f3e0db6aa11b4e7fc.php new file mode 100644 index 0000000..20a81b4 --- /dev/null +++ b/cache/twig/2d/2d6fd692de5c8f454faf6e54c63704d917a377f3327e783f3e0db6aa11b4e7fc.php @@ -0,0 +1,165 @@ +parent = $this->loadTemplate("forms/field.html.twig", "forms/fields/text/text.html.twig", 1); + $this->blocks = array( + 'prepend' => array($this, 'block_prepend'), + 'input_attributes' => array($this, 'block_input_attributes'), + 'append' => array($this, 'block_append'), + 'input' => array($this, 'block_input'), + ); + } + + protected function doGetParent(array $context) + { + return "forms/field.html.twig"; + } + + protected function doDisplay(array $context, array $blocks = array()) + { + $this->parent->display($context, array_merge($this->blocks, $blocks)); + } + + // line 3 + public function block_prepend($context, array $blocks = array()) + { + // line 4 + if ($this->getAttribute(($context["field"] ?? null), "prepend", array())) { + // line 5 + echo "
                              + "; + // line 6 + if ($this->getAttribute($this->getAttribute($this->getAttribute($this->getAttribute(($context["grav"] ?? null), "twig", array(), "any", false, true), "twig", array(), "any", false, true), "filters", array(), "any", false, true), "tu", array(), "array", true, true)) { + // line 7 + echo $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter($this->getAttribute(($context["field"] ?? null), "prepend", array())); + } else { + // line 9 + echo $this->env->getExtension('Grav\Common\Twig\TwigExtension')->translate($this->getAttribute(($context["field"] ?? null), "prepend", array())); + } + // line 11 + echo "
                              +"; + } + } + + // line 15 + public function block_input_attributes($context, array $blocks = array()) + { + // line 16 + echo " type=\"text\" + "; + // line 17 + $this->displayParentBlock("input_attributes", $context, $blocks); + echo " +"; + } + + // line 20 + public function block_append($context, array $blocks = array()) + { + // line 21 + echo " "; + if ($this->getAttribute(($context["field"] ?? null), "append", array())) { + // line 22 + echo "
                              + "; + // line 23 + if ($this->getAttribute($this->getAttribute($this->getAttribute($this->getAttribute(($context["grav"] ?? null), "twig", array(), "any", false, true), "twig", array(), "any", false, true), "filters", array(), "any", false, true), "tu", array(), "array", true, true)) { + // line 24 + echo $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter($this->getAttribute(($context["field"] ?? null), "append", array())); + } else { + // line 26 + echo $this->env->getExtension('Grav\Common\Twig\TwigExtension')->translate($this->getAttribute(($context["field"] ?? null), "append", array())); + } + // line 28 + echo "
                              + "; + } + } + + // line 32 + public function block_input($context, array $blocks = array()) + { + // line 33 + if (($this->getAttribute(($context["field"] ?? null), "prepend", array()) || $this->getAttribute(($context["field"] ?? null), "append", array()))) { + // line 34 + echo " "; + $context["field"] = twig_array_merge(($context["field"] ?? null), array("wrapper_classes" => "form-input-addon-wrapper")); + } + // line 36 + $this->displayParentBlock("input", $context, $blocks); + echo " +"; + } + + public function getTemplateName() + { + return "forms/fields/text/text.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 97 => 36, 93 => 34, 91 => 33, 88 => 32, 82 => 28, 79 => 26, 76 => 24, 74 => 23, 71 => 22, 68 => 21, 65 => 20, 59 => 17, 56 => 16, 53 => 15, 47 => 11, 44 => 9, 41 => 7, 39 => 6, 36 => 5, 34 => 4, 31 => 3, 11 => 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 Twig_Source("{% extends \"forms/field.html.twig\" %} + +{% block prepend %} +{% if field.prepend %} +
                              + {% if grav.twig.twig.filters['tu'] is defined %} + {{- field.prepend|tu|raw -}} + {% else %} + {{- field.prepend|t|raw -}} + {% endif %} +
                              +{% endif %} +{% endblock %} + +{% block input_attributes %} + type=\"text\" + {{ parent() }} +{% endblock %} + +{% block append %} + {% if field.append %} +
                              + {% if grav.twig.twig.filters['tu'] is defined %} + {{- field.append|tu|raw -}} + {% else %} + {{- field.append|t|raw -}} + {% endif %} +
                              + {% endif %} +{% endblock %} + +{% block input %} +{% if field.prepend or field.append %} + {% set field = field|merge({'wrapper_classes': 'form-input-addon-wrapper'}) %} +{% endif %} +{{ parent() }} +{% endblock %}", "forms/fields/text/text.html.twig", "/mnt/data/Sites/static-ethica.net/user/plugins/form/templates/forms/fields/text/text.html.twig"); + } +} diff --git a/cache/twig/32/3220e3522bdfdf445a0730924be239728a8c1dfa3f3a99f4a67dae3c389e4c5c.php b/cache/twig/32/3220e3522bdfdf445a0730924be239728a8c1dfa3f3a99f4a67dae3c389e4c5c.php new file mode 100644 index 0000000..93d9153 --- /dev/null +++ b/cache/twig/32/3220e3522bdfdf445a0730924be239728a8c1dfa3f3a99f4a67dae3c389e4c5c.php @@ -0,0 +1,92 @@ +parent = $this->loadTemplate("forms/field.html.twig", "forms/fields/selectize/selectize.html.twig", 1); + $this->blocks = array( + 'global_attributes' => array($this, 'block_global_attributes'), + 'input_attributes' => array($this, 'block_input_attributes'), + ); + } + + protected function doGetParent(array $context) + { + return "forms/field.html.twig"; + } + + protected function doDisplay(array $context, array $blocks = array()) + { + $this->parent->display($context, array_merge($this->blocks, $blocks)); + } + + // line 3 + public function block_global_attributes($context, array $blocks = array()) + { + // line 4 + echo " data-grav-selectize=\""; + echo twig_escape_filter($this->env, twig_jsonencode_filter((($this->getAttribute(($context["field"] ?? null), "selectize", array(), "any", true, true)) ? (twig_array_merge(twig_array_merge($this->getAttribute(($context["field"] ?? null), "selectize", array()), array("create" => true)), array("items" => ($context["value"] ?? null)))) : (array("create" => true)))), "html_attr"); + echo "\" + "; + // line 5 + $this->displayParentBlock("global_attributes", $context, $blocks); + echo " +"; + } + + // line 8 + public function block_input_attributes($context, array $blocks = array()) + { + // line 9 + echo " type=\"text\" + "; + // line 10 + $this->displayParentBlock("input_attributes", $context, $blocks); + echo " +"; + } + + public function getTemplateName() + { + return "forms/fields/selectize/selectize.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 49 => 10, 46 => 9, 43 => 8, 37 => 5, 32 => 4, 29 => 3, 11 => 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 Twig_Source("{% extends \"forms/field.html.twig\" %} + +{% block global_attributes %} + data-grav-selectize=\"{{ (field.selectize is defined ? field.selectize|merge({'create': true})|merge({'items':value}) : {'create': true})|json_encode()|e('html_attr') }}\" + {{ parent() }} +{% endblock %} + +{% block input_attributes %} + type=\"text\" + {{ parent() }} +{% endblock %} +", "forms/fields/selectize/selectize.html.twig", "/mnt/data/Sites/static-ethica.net/user/plugins/admin/themes/grav/templates/forms/fields/selectize/selectize.html.twig"); + } +} diff --git a/cache/twig/32/32706ad0899a349c388ab2d21b166dd92cb8d43e5be0aba0eb8ef4e2bdd9edab.php b/cache/twig/32/32706ad0899a349c388ab2d21b166dd92cb8d43e5be0aba0eb8ef4e2bdd9edab.php new file mode 100644 index 0000000..7c95ea1 --- /dev/null +++ b/cache/twig/32/32706ad0899a349c388ab2d21b166dd92cb8d43e5be0aba0eb8ef4e2bdd9edab.php @@ -0,0 +1,286 @@ +parent = false; + + $this->blocks = array( + ); + } + + protected function doDisplay(array $context, array $blocks = array()) + { + // line 1 + echo " + "; + // line 2 + if ($this->getAttribute(($context["plugin"] ?? null), "author", array())) { + // line 3 + echo " + + + + "; + } + // line 17 + echo " "; + if ($this->getAttribute(($context["plugin"] ?? null), "homepage", array())) { + // line 18 + echo " + + + + "; + } + // line 23 + echo " "; + if ($this->getAttribute(($context["plugin"] ?? null), "demo", array())) { + // line 24 + echo " + + + + "; + } + // line 29 + echo " "; + if ($this->getAttribute(($context["plugin"] ?? null), "bugs", array())) { + // line 30 + echo " + + + + "; + } + // line 35 + echo " "; + if ($this->getAttribute(($context["plugin"] ?? null), "keywords", array())) { + // line 36 + echo " + + + + "; + } + // line 41 + echo " "; + if ($this->getAttribute(($context["plugin"] ?? null), "license", array())) { + // line 42 + echo " + + + + "; + } + // line 47 + echo " + "; + // line 48 + if ($this->getAttribute(($context["plugin"] ?? null), "description", array())) { + // line 49 + echo " + + + + "; + } + // line 54 + echo " + "; + // line 55 + if (($this->getAttribute(($context["plugin"] ?? null), "readme", array()) || $this->getAttribute(($context["plugin"] ?? null), "homepage", array()))) { + // line 56 + echo " "; + $context["readme_link"] = (($this->getAttribute(($context["plugin"] ?? null), "readme", array())) ? ($this->getAttribute(($context["plugin"] ?? null), "readme", array())) : ((($this->getAttribute(($context["plugin"] ?? null), "docs", array(), "any", true, true)) ? (_twig_default_filter($this->getAttribute(($context["plugin"] ?? null), "docs", array()), ($this->getAttribute(($context["plugin"] ?? null), "homepage", array()) . "/blob/master/README.md"))) : (($this->getAttribute(($context["plugin"] ?? null), "homepage", array()) . "/blob/master/README.md"))))); + // line 57 + echo " + + + + "; + } + // line 62 + echo " +
                              "; + // line 4 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.AUTHOR"), "html", null, true); + echo ": + "; + // line 6 + if ($this->getAttribute($this->getAttribute(($context["plugin"] ?? null), "author", array()), "url", array())) { + // line 7 + echo " env, $this->getAttribute($this->getAttribute(($context["plugin"] ?? null), "author", array()), "url", array()), "html", null, true); + echo "\" target=\"_blank\">"; + echo twig_escape_filter($this->env, $this->getAttribute($this->getAttribute(($context["plugin"] ?? null), "author", array()), "name", array()), "html", null, true); + echo " + "; + } else { + // line 9 + echo " "; + echo twig_escape_filter($this->env, $this->getAttribute($this->getAttribute(($context["plugin"] ?? null), "author", array()), "name", array()), "html", null, true); + echo " + "; + } + // line 11 + echo " "; + if ($this->getAttribute($this->getAttribute(($context["plugin"] ?? null), "author", array()), "email", array())) { + // line 12 + echo " - env, $this->getAttribute($this->getAttribute(($context["plugin"] ?? null), "author", array()), "email", array()), "html", null, true); + echo "\">"; + echo twig_escape_filter($this->env, $this->getAttribute($this->getAttribute(($context["plugin"] ?? null), "author", array()), "email", array()), "html", null, true); + echo " + "; + } + // line 14 + echo "
                              "; + // line 19 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.HOMEPAGE"), "html", null, true); + echo ":env, $this->getAttribute(($context["plugin"] ?? null), "homepage", array()), "html", null, true); + echo "\" target=\"_blank\">"; + echo twig_escape_filter($this->env, $this->getAttribute(($context["plugin"] ?? null), "homepage", array()), "html", null, true); + echo "
                              "; + // line 25 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.DEMO"), "html", null, true); + echo ":env, $this->getAttribute(($context["plugin"] ?? null), "demo", array()), "html", null, true); + echo "\" target=\"_blank\">"; + echo twig_escape_filter($this->env, $this->getAttribute(($context["plugin"] ?? null), "demo", array()), "html", null, true); + echo "
                              "; + // line 31 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.BUG_TRACKER"), "html", null, true); + echo ":env, $this->getAttribute(($context["plugin"] ?? null), "bugs", array()), "html", null, true); + echo "\" target=\"_blank\">"; + echo twig_escape_filter($this->env, $this->getAttribute(($context["plugin"] ?? null), "bugs", array()), "html", null, true); + echo "
                              "; + // line 37 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.KEYWORDS"), "html", null, true); + echo ":"; + // line 38 + echo twig_escape_filter($this->env, twig_join_filter($this->getAttribute(($context["plugin"] ?? null), "keywords", array()), ", "), "html", null, true); + echo "
                              "; + // line 43 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.LICENSE"), "html", null, true); + echo ":"; + // line 44 + echo twig_escape_filter($this->env, $this->getAttribute(($context["plugin"] ?? null), "license", array()), "html", null, true); + echo "
                              "; + // line 50 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.DESCRIPTION"), "html", null, true); + echo ":"; + // line 51 + echo $this->getAttribute(($context["plugin"] ?? null), "description_html", array()); + echo "
                              "; + // line 58 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.README"), "html", null, true); + echo ":env, ($context["readme_link"] ?? null), "html", null, true); + echo "\" target=\"_blank\">"; + echo twig_escape_filter($this->env, ($context["readme_link"] ?? null), "html", null, true); + echo "
                              +"; + } + + public function getTemplateName() + { + return "partials/plugin-data.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 191 => 62, 183 => 59, 179 => 58, 176 => 57, 173 => 56, 171 => 55, 168 => 54, 162 => 51, 158 => 50, 155 => 49, 153 => 48, 150 => 47, 144 => 44, 140 => 43, 137 => 42, 134 => 41, 128 => 38, 124 => 37, 121 => 36, 118 => 35, 110 => 32, 106 => 31, 103 => 30, 100 => 29, 92 => 26, 88 => 25, 85 => 24, 82 => 23, 74 => 20, 70 => 19, 67 => 18, 64 => 17, 59 => 14, 51 => 12, 48 => 11, 42 => 9, 34 => 7, 32 => 6, 27 => 4, 24 => 3, 22 => 2, 19 => 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 Twig_Source(" + {% if plugin.author %} + + + + + {% endif %} + {% if plugin.homepage %} + + + + + {% endif %} + {% if plugin.demo %} + + + + + {% endif %} + {% if plugin.bugs %} + + + + + {% endif %} + {% if plugin.keywords %} + + + + + {% endif %} + {% if plugin.license %} + + + + + {% endif %} + + {% if plugin.description %} + + + + + {% endif %} + + {% if plugin.readme or plugin.homepage %} + {% set readme_link = plugin.readme ?: plugin.docs|default(plugin.homepage ~ '/blob/master/README.md') %} + + + + + {% endif %} + +
                              {{ \"PLUGIN_ADMIN.AUTHOR\"|tu }}: + {% if plugin.author.url %} + {{ plugin.author.name }} + {% else %} + {{ plugin.author.name }} + {% endif %} + {% if plugin.author.email %} + - {{ plugin.author.email }} + {% endif %} +
                              {{ \"PLUGIN_ADMIN.HOMEPAGE\"|tu }}:{{ plugin.homepage }}
                              {{ \"PLUGIN_ADMIN.DEMO\"|tu }}:{{ plugin.demo }}
                              {{ \"PLUGIN_ADMIN.BUG_TRACKER\"|tu }}:{{ plugin.bugs }}
                              {{ \"PLUGIN_ADMIN.KEYWORDS\"|tu }}:{{ plugin.keywords|join(', ') }}
                              {{ \"PLUGIN_ADMIN.LICENSE\"|tu }}:{{ plugin.license }}
                              {{ \"PLUGIN_ADMIN.DESCRIPTION\"|tu }}:{{ plugin.description_html|raw }}
                              {{ \"PLUGIN_ADMIN.README\"|tu }}:{{ readme_link }}
                              +", "partials/plugin-data.html.twig", "/home/kevin/Sites/static-ethica.net/user/plugins/admin/themes/grav/templates/partials/plugin-data.html.twig"); + } +} diff --git a/cache/twig/33/3345d74fa4b4e9babe88c7bfb1c1c78ce1788b071932fc020257888c188d2bbe.php b/cache/twig/33/3345d74fa4b4e9babe88c7bfb1c1c78ce1788b071932fc020257888c188d2bbe.php new file mode 100644 index 0000000..39587d8 --- /dev/null +++ b/cache/twig/33/3345d74fa4b4e9babe88c7bfb1c1c78ce1788b071932fc020257888c188d2bbe.php @@ -0,0 +1,131 @@ +parent = false; + + $this->blocks = array( + 'content' => array($this, 'block_content'), + ); + } + + protected function doDisplay(array $context, array $blocks = array()) + { + // line 2 + echo " + "; + // line 3 + $this->displayBlock('content', $context, $blocks); + } + + public function block_content($context, array $blocks = array()) + { + // line 4 + echo " +

                              "; + // line 5 + echo $this->getAttribute(($context["header"] ?? null), "title", array()); + echo "

                              + + "; + // line 7 + echo $this->getAttribute(($context["page"] ?? null), "content", array()); + echo " + "; + // line 8 + $context['_parent'] = $context; + $context['_seq'] = twig_ensure_traversable($this->getAttribute(($context["page"] ?? null), "collection", array(), "method")); + foreach ($context['_seq'] as $context["_key"] => $context["module"]) { + // line 9 + echo " +
                              getAttribute($this, "pageLinkName", array(0 => $this->getAttribute($context["module"], "folder", array())), "method"); + echo "\" class=\"column\"> + "; + // line 11 + echo $this->getAttribute($context["module"], "content", array()); + echo " +
                              + "; + } + $_parent = $context['_parent']; + unset($context['_seq'], $context['_iterated'], $context['_key'], $context['module'], $context['_parent'], $context['loop']); + $context = array_intersect_key($context, $_parent) + $_parent; + // line 14 + echo " "; + } + + // line 1 + public function getpageLinkName($__text__ = null, ...$__varargs__) + { + $context = $this->env->mergeGlobals(array( + "text" => $__text__, + "varargs" => $__varargs__, + )); + + $blocks = array(); + + ob_start(); + try { + echo twig_replace_filter(twig_lower_filter($this->env, ($context["text"] ?? null)), array("01._" => "", "02._" => "", "03._" => "", "04._" => "", "05._" => "", "06._" => "", "07._" => "", "08._" => "", "09._" => "")); + } catch (Exception $e) { + ob_end_clean(); + + throw $e; + } catch (Throwable $e) { + ob_end_clean(); + + throw $e; + } + + return ('' === $tmp = ob_get_clean()) ? '' : new Twig_Markup($tmp, $this->env->getCharset()); + } + + public function getTemplateName() + { + return "modular/contenu.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 65 => 1, 61 => 14, 52 => 11, 48 => 10, 45 => 9, 41 => 8, 37 => 7, 32 => 5, 29 => 4, 23 => 3, 20 => 2,); + } + + /** @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 Twig_Source("{% macro pageLinkName(text) %}{{ text|lower|replace({'01._':'','02._':'','03._':'','04._':'','05._':'','06._':'','07._':'','08._':'','09._':''}) }}{% endmacro %} + + {% block content %} + +

                              {{ header.title }}

                              + + {{ page.content }} + {% for module in page.collection() %} + +
                              + {{ module.content }} +
                              + {% endfor %} + {% endblock %} +", "modular/contenu.html.twig", "/home/kevin/Sites/static-ethica.net/user/themes/ethica/templates/modular/contenu.html.twig"); + } +} diff --git a/cache/twig/34/34258c785f8d6ac43fe789c598d3dcab5c32d5d37edb27b2584ea8119f847c79.php b/cache/twig/34/34258c785f8d6ac43fe789c598d3dcab5c32d5d37edb27b2584ea8119f847c79.php new file mode 100644 index 0000000..740295f --- /dev/null +++ b/cache/twig/34/34258c785f8d6ac43fe789c598d3dcab5c32d5d37edb27b2584ea8119f847c79.php @@ -0,0 +1,50 @@ +parent = false; + + $this->blocks = array( + ); + } + + protected function doDisplay(array $context, array $blocks = array()) + { + // line 1 + echo " +"; + } + + public function getTemplateName() + { + return "partials/nav-toggle.html.twig"; + } + + public function getDebugInfo() + { + return array ( 19 => 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 Twig_Source(" +", "partials/nav-toggle.html.twig", "/mnt/data/Sites/static-ethica.net/user/plugins/admin/themes/grav/templates/partials/nav-toggle.html.twig"); + } +} diff --git a/cache/twig/34/346d7cd87606adfb29b0fd0a7c6aa0e900a3bb52eac7d59554bd22a582eac49a.php b/cache/twig/34/346d7cd87606adfb29b0fd0a7c6aa0e900a3bb52eac7d59554bd22a582eac49a.php new file mode 100644 index 0000000..e3bbb6d --- /dev/null +++ b/cache/twig/34/346d7cd87606adfb29b0fd0a7c6aa0e900a3bb52eac7d59554bd22a582eac49a.php @@ -0,0 +1,99 @@ +parent = false; + + $this->blocks = array( + ); + } + + protected function doDisplay(array $context, array $blocks = array()) + { + // line 1 + $this->getAttribute(($context["assets"] ?? null), "addCss", array(0 => (($context["theme_url"] ?? null) . "/css-compiled/nucleus.css")), "method"); + // line 2 + $this->getAttribute(($context["assets"] ?? null), "addCss", array(0 => (($context["theme_url"] ?? null) . "/css-compiled/template.css")), "method"); + // line 3 + $this->getAttribute(($context["assets"] ?? null), "addCss", array(0 => (($context["theme_url"] ?? null) . "/css-compiled/preset.css")), "method"); + // line 4 + if ($this->getAttribute($this->getAttribute($this->getAttribute(($context["config"] ?? null), "plugins", array()), "admin", array()), "google_fonts", array())) { + // line 5 + echo " "; + $this->getAttribute(($context["assets"] ?? null), "addCss", array(0 => (($context["theme_url"] ?? null) . "/css-compiled/fonts.css")), "method"); + } else { + // line 7 + echo " "; + $this->getAttribute(($context["assets"] ?? null), "addCss", array(0 => (($context["theme_url"] ?? null) . "/css-compiled/simple-fonts.css")), "method"); + } + // line 9 + $this->getAttribute(($context["assets"] ?? null), "addCss", array(0 => (($context["theme_url"] ?? null) . "/css/font-awesome.min.css")), "method"); + // line 10 + $this->getAttribute(($context["assets"] ?? null), "addCss", array(0 => (($context["theme_url"] ?? null) . "/css/chartist.min.css")), "method"); + // line 11 + $this->getAttribute(($context["assets"] ?? null), "addCss", array(0 => (($context["theme_url"] ?? null) . "/css/selectize.min.css")), "method"); + // line 12 + $this->getAttribute(($context["assets"] ?? null), "addCss", array(0 => (($context["theme_url"] ?? null) . "/css/hint.base.min.css")), "method"); + // line 13 + $this->getAttribute(($context["assets"] ?? null), "addCss", array(0 => (($context["theme_url"] ?? null) . "/css/iconpicker.css")), "method"); + // line 14 + if (((($this->getAttribute(($context["browser"] ?? null), "getBrowser", array()) == "msie") && ($this->getAttribute(($context["browser"] ?? null), "getVersion", array()) >= 8)) && ($this->getAttribute(($context["browser"] ?? null), "getVersion", array()) <= 9))) { + // line 15 + echo " "; + $this->getAttribute(($context["assets"] ?? null), "addCss", array(0 => (($context["theme_url"] ?? null) . "/css/nucleus-ie9.css")), "method"); + // line 16 + echo " "; + $this->getAttribute(($context["assets"] ?? null), "addCss", array(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 ( 50 => 16, 47 => 15, 45 => 14, 43 => 13, 41 => 12, 39 => 11, 37 => 10, 35 => 9, 31 => 7, 27 => 5, 25 => 4, 23 => 3, 21 => 2, 19 => 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 Twig_Source("{% do assets.addCss(theme_url~'/css-compiled/nucleus.css') %} +{% do assets.addCss(theme_url~'/css-compiled/template.css') %} +{% do assets.addCss(theme_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/font-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", "/mnt/data/Sites/static-ethica.net/user/plugins/admin/themes/grav/templates/partials/stylesheets.html.twig"); + } +} diff --git a/cache/twig/34/34f0e0266b4db11a668b3b4b838de63bef49bdad2bad0967770a2814fd06e149.php b/cache/twig/34/34f0e0266b4db11a668b3b4b838de63bef49bdad2bad0967770a2814fd06e149.php new file mode 100644 index 0000000..5c5d4d5 --- /dev/null +++ b/cache/twig/34/34f0e0266b4db11a668b3b4b838de63bef49bdad2bad0967770a2814fd06e149.php @@ -0,0 +1,74 @@ +parent = $this->loadTemplate("forms/field.html.twig", "forms/fields/password/password.html.twig", 1); + $this->blocks = array( + 'input_attributes' => array($this, 'block_input_attributes'), + ); + } + + protected function doGetParent(array $context) + { + return "forms/field.html.twig"; + } + + protected function doDisplay(array $context, array $blocks = array()) + { + $this->parent->display($context, array_merge($this->blocks, $blocks)); + } + + // line 3 + public function block_input_attributes($context, array $blocks = array()) + { + // line 4 + echo " type=\"password\" + class=\"input\" + "; + // line 6 + $this->displayParentBlock("input_attributes", $context, $blocks); + echo " +"; + } + + public function getTemplateName() + { + return "forms/fields/password/password.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 35 => 6, 31 => 4, 28 => 3, 11 => 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 Twig_Source("{% extends \"forms/field.html.twig\" %} + +{% block input_attributes %} + type=\"password\" + class=\"input\" + {{ parent() }} +{% endblock %} +", "forms/fields/password/password.html.twig", "/mnt/data/Sites/static-ethica.net/user/plugins/form/templates/forms/fields/password/password.html.twig"); + } +} diff --git a/cache/twig/36/36452fe32afb9294dbd59d63d8d2ffb5355ff13b8e22ab7543592527527d54e2.php b/cache/twig/36/36452fe32afb9294dbd59d63d8d2ffb5355ff13b8e22ab7543592527527d54e2.php new file mode 100644 index 0000000..4108656 --- /dev/null +++ b/cache/twig/36/36452fe32afb9294dbd59d63d8d2ffb5355ff13b8e22ab7543592527527d54e2.php @@ -0,0 +1,247 @@ +parent = $this->loadTemplate("forms/field.html.twig", "forms/fields/range/range.html.twig", 1); + $this->blocks = array( + 'input_attributes' => array($this, 'block_input_attributes'), + 'append' => array($this, 'block_append'), + ); + } + + protected function doGetParent(array $context) + { + return "forms/field.html.twig"; + } + + protected function doDisplay(array $context, array $blocks = array()) + { + $this->parent->display($context, array_merge($this->blocks, $blocks)); + } + + // line 3 + public function block_input_attributes($context, array $blocks = array()) + { + // line 4 + echo " type=\"range\" + class=\"rangefield "; + // line 5 + if ($this->getAttribute(($context["field"] ?? null), "classes", array(), "any", true, true)) { + echo twig_escape_filter($this->env, $this->getAttribute(($context["field"] ?? null), "classes", array()), "html", null, true); + echo " "; + } + echo "\" + "; + // line 6 + if ($this->getAttribute($this->getAttribute(($context["field"] ?? null), "validate", array()), "min", array())) { + echo "min=\""; + echo twig_escape_filter($this->env, $this->getAttribute($this->getAttribute(($context["field"] ?? null), "validate", array()), "min", array()), "html", null, true); + echo "\""; + } + // line 7 + echo " "; + if ($this->getAttribute($this->getAttribute(($context["field"] ?? null), "validate", array()), "max", array())) { + echo "max=\""; + echo twig_escape_filter($this->env, $this->getAttribute($this->getAttribute(($context["field"] ?? null), "validate", array()), "max", array()), "html", null, true); + echo "\""; + } + // line 8 + echo " "; + if ($this->getAttribute($this->getAttribute(($context["field"] ?? null), "validate", array()), "step", array())) { + echo "step=\""; + echo twig_escape_filter($this->env, $this->getAttribute($this->getAttribute(($context["field"] ?? null), "validate", array()), "step", array()), "html", null, true); + echo "\""; + } + // line 9 + echo " "; + if ($this->getAttribute(($context["field"] ?? null), "id", array(), "any", true, true)) { + // line 10 + echo " id=\"range_"; + echo twig_escape_filter($this->env, twig_replace_filter(twig_escape_filter($this->env, $this->getAttribute(($context["field"] ?? null), "id", array())), ".", "_"), "html", null, true); + echo "\" + oninput=\"number_"; + // line 11 + echo twig_escape_filter($this->env, twig_replace_filter(twig_escape_filter($this->env, $this->getAttribute(($context["field"] ?? null), "id", array())), ".", "_"), "html", null, true); + echo "_output.value = this.value\" + "; + } else { + // line 13 + echo " id=\"range_"; + echo twig_escape_filter($this->env, twig_replace_filter(twig_escape_filter($this->env, $this->getAttribute(($context["field"] ?? null), "name", array())), ".", "_"), "html", null, true); + echo "\" + oninput=\"number_"; + // line 14 + echo twig_escape_filter($this->env, twig_replace_filter(twig_escape_filter($this->env, $this->getAttribute(($context["field"] ?? null), "name", array())), ".", "_"), "html", null, true); + echo "_output.value = this.value\" + "; + } + // line 16 + echo " "; + $this->displayParentBlock("input_attributes", $context, $blocks); + echo " +"; + } + + // line 18 + public function block_append($context, array $blocks = array()) + { + // line 19 + echo " getAttribute(($context["field"] ?? null), "classes", array(), "any", true, true)) { + echo twig_escape_filter($this->env, $this->getAttribute(($context["field"] ?? null), "classes", array()), "html", null, true); + echo " "; + } + echo "\" + "; + // line 22 + if ($this->getAttribute($this->getAttribute(($context["field"] ?? null), "validate", array()), "min", array())) { + echo "min=\""; + echo twig_escape_filter($this->env, $this->getAttribute($this->getAttribute(($context["field"] ?? null), "validate", array()), "min", array()), "html", null, true); + echo "\""; + } + // line 23 + echo " "; + if ($this->getAttribute($this->getAttribute(($context["field"] ?? null), "validate", array()), "max", array())) { + echo "max=\""; + echo twig_escape_filter($this->env, $this->getAttribute($this->getAttribute(($context["field"] ?? null), "validate", array()), "max", array()), "html", null, true); + echo "\""; + } + // line 24 + echo " "; + if ($this->getAttribute($this->getAttribute(($context["field"] ?? null), "validate", array()), "step", array())) { + echo "step=\""; + echo twig_escape_filter($this->env, $this->getAttribute($this->getAttribute(($context["field"] ?? null), "validate", array()), "step", array()), "html", null, true); + echo "\""; + } + // line 25 + echo " "; + if (($context["value"] ?? null)) { + // line 26 + echo " value=\""; + echo twig_escape_filter($this->env, ($context["value"] ?? null), "html", null, true); + echo "\" + "; + } elseif ($this->getAttribute( // line 27 +($context["field"] ?? null), "default", array())) { + // line 28 + echo " value=\""; + echo twig_escape_filter($this->env, $this->getAttribute(($context["field"] ?? null), "default", array()), "html", null, true); + echo "\" + "; + } else { + // line 30 + echo " value=\"0\" + "; + } + // line 32 + echo " "; + if ($this->getAttribute(($context["field"] ?? null), "id", array(), "any", true, true)) { + // line 33 + echo " id=\"number_"; + echo twig_escape_filter($this->env, twig_replace_filter(twig_escape_filter($this->env, $this->getAttribute(($context["field"] ?? null), "id", array())), ".", "_"), "html", null, true); + echo "_output\" + oninput=\"range_"; + // line 34 + echo twig_escape_filter($this->env, twig_replace_filter(twig_escape_filter($this->env, $this->getAttribute(($context["field"] ?? null), "id", array())), ".", "_"), "html", null, true); + echo ".value = this.value\" + "; + } else { + // line 36 + echo " id=\"number_"; + echo twig_escape_filter($this->env, twig_replace_filter(twig_escape_filter($this->env, $this->getAttribute(($context["field"] ?? null), "name", array())), ".", "_"), "html", null, true); + echo "_output\" + oninput=\"range_"; + // line 37 + echo twig_escape_filter($this->env, twig_replace_filter(twig_escape_filter($this->env, $this->getAttribute(($context["field"] ?? null), "name", array())), ".", "_"), "html", null, true); + echo ".value = this.value\" + "; + } + // line 39 + echo " /> + "; + // line 40 + echo twig_escape_filter($this->env, $this->getAttribute(($context["field"] ?? null), "append", array()), "html", null, true); + echo " + +"; + } + + public function getTemplateName() + { + return "forms/fields/range/range.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 172 => 40, 169 => 39, 164 => 37, 159 => 36, 154 => 34, 149 => 33, 146 => 32, 142 => 30, 136 => 28, 134 => 27, 129 => 26, 126 => 25, 119 => 24, 112 => 23, 106 => 22, 99 => 21, 95 => 19, 92 => 18, 85 => 16, 80 => 14, 75 => 13, 70 => 11, 65 => 10, 62 => 9, 55 => 8, 48 => 7, 42 => 6, 35 => 5, 32 => 4, 29 => 3, 11 => 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 Twig_Source("{% extends \"forms/field.html.twig\" %} + +{% block input_attributes %} + type=\"range\" + class=\"rangefield {% if field.classes is defined %}{{ field.classes }} {% endif %}\" + {% if field.validate.min %}min=\"{{ field.validate.min }}\"{% endif %} + {% if field.validate.max %}max=\"{{ field.validate.max }}\"{% endif %} + {% if field.validate.step %}step=\"{{ field.validate.step }}\"{% endif %} + {% if field.id is defined %} + id=\"range_{{ field.id|e|replace('.', '_') }}\" + oninput=\"number_{{ field.id|e|replace('.', '_') }}_output.value = this.value\" + {% else %} + id=\"range_{{ field.name|e|replace('.', '_') }}\" + oninput=\"number_{{ field.name|e|replace('.', '_') }}_output.value = this.value\" + {% endif %} + {{ parent() }} +{% endblock %} +{% block append %} + + {{ field.append }} + +{% endblock append %} +", "forms/fields/range/range.html.twig", "/mnt/data/Sites/static-ethica.net/user/plugins/admin/themes/grav/templates/forms/fields/range/range.html.twig"); + } +} diff --git a/cache/twig/37/377ae461c61bf6fa60f6a06747e00ac50ee64aa52088073c7eb404c85bfce83f.php b/cache/twig/37/377ae461c61bf6fa60f6a06747e00ac50ee64aa52088073c7eb404c85bfce83f.php new file mode 100644 index 0000000..70b1dc4 --- /dev/null +++ b/cache/twig/37/377ae461c61bf6fa60f6a06747e00ac50ee64aa52088073c7eb404c85bfce83f.php @@ -0,0 +1,396 @@ +parent = false; + + $this->blocks = array( + ); + } + + protected function doDisplay(array $context, array $blocks = array()) + { + // line 1 + if ($this->env->getExtension('Grav\Common\Twig\TwigExtension')->authorize(array(0 => "admin.login", 1 => "admin.super"))) { + // line 2 + echo " +"; + } + } + + public function getTemplateName() + { + return "partials/nav.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 262 => 90, 258 => 88, 251 => 87, 248 => 86, 241 => 82, 236 => 80, 231 => 79, 228 => 78, 220 => 73, 214 => 70, 209 => 68, 204 => 67, 201 => 66, 193 => 61, 187 => 58, 182 => 56, 177 => 55, 174 => 54, 171 => 53, 165 => 52, 160 => 49, 153 => 46, 147 => 45, 140 => 44, 138 => 43, 134 => 42, 130 => 41, 124 => 40, 119 => 39, 116 => 38, 111 => 37, 108 => 36, 100 => 31, 95 => 29, 90 => 27, 85 => 26, 82 => 25, 74 => 22, 69 => 21, 67 => 20, 60 => 18, 56 => 17, 51 => 14, 49 => 13, 46 => 12, 44 => 11, 40 => 9, 38 => 8, 34 => 6, 30 => 4, 28 => 3, 21 => 2, 19 => 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 Twig_Source("{% if authorize(['admin.login', 'admin.super']) %} + +{% endif %} +", "partials/nav.html.twig", "/mnt/data/Sites/static-ethica.net/user/plugins/admin/themes/grav/templates/partials/nav.html.twig"); + } +} diff --git a/cache/twig/37/37f41e0b088533c946e465f472cebd1b732df5de6cea09669fff6096f730ea88.php b/cache/twig/37/37f41e0b088533c946e465f472cebd1b732df5de6cea09669fff6096f730ea88.php new file mode 100644 index 0000000..5e405d3 --- /dev/null +++ b/cache/twig/37/37f41e0b088533c946e465f472cebd1b732df5de6cea09669fff6096f730ea88.php @@ -0,0 +1,162 @@ +parent = false; + + $this->blocks = array( + ); + } + + protected function doDisplay(array $context, array $blocks = array()) + { + // line 1 + $context["value"] = (((null === ($context["value"] ?? null))) ? ($this->getAttribute(($context["field"] ?? null), "default", array())) : (($context["value"] ?? null))); + // line 2 + echo " +"; + // line 3 + if ($this->getAttribute(($context["context"] ?? null), "folderExists", array())) { + // line 4 + echo "
                              getAttribute(($context["field"] ?? null), "classes", array(), "any", true, true)) { + echo twig_escape_filter($this->env, $this->getAttribute(($context["field"] ?? null), "classes", array()), "html", null, true); + } + echo "\"> +
                              + +
                              +
                              + "; + // line 9 + $context["uploadLimit"] = (($this->getAttribute($this->getAttribute($this->getAttribute($this->getAttribute(($context["grav"] ?? null), "config", array()), "system", array()), "media", array()), "upload_limit", array()) / 1024) / 1024); + // line 10 + echo " "; + $context["dropzoneSettings"] = array("maxFileSize" => ($context["uploadLimit"] ?? null)); + // line 11 + echo "
                              env, ($context["base_url"] ?? null), "html", null, true); + echo "/media/"; + echo twig_escape_filter($this->env, twig_trim_filter($this->getAttribute(($context["admin"] ?? null), "route", array()), "/"), "html", null, true); + echo ".json\" + data-media-local=\""; + // line 14 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Common\Twig\TwigExtension')->rtrimFilter(($context["base_url_relative_frontend"] ?? null), "/"), "html", null, true); + echo "/"; + echo twig_escape_filter($this->env, twig_trim_filter($this->getAttribute(($context["admin"] ?? null), "route", array()), "/"), "html", null, true); + echo "\" + data-media-path=\""; + // line 15 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Common\Twig\TwigExtension')->urlFunc($this->getAttribute(($context["context"] ?? null), "relativePagePath", array())), "html", null, true); + echo "\" + data-dropzone-options=\""; + // line 16 + echo twig_escape_filter($this->env, twig_jsonencode_filter(($context["dropzoneSettings"] ?? null)), "html_attr"); + echo "\" + data-dropzone-field=\""; + // line 17 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Common\Twig\TwigExtension')->fieldNameFilter((($context["scope"] ?? null) . $this->getAttribute(($context["field"] ?? null), "name", array()))), "html", null, true); + echo "\">
                              + + "; + // line 19 + if (($this->getAttribute($this->getAttribute(($context["admin"] ?? null), "session", array()), "expert", array()) == "0")) { + // line 20 + echo " env, $this->env->getExtension('Grav\Common\Twig\TwigExtension')->fieldNameFilter((($context["scope"] ?? null) . $this->getAttribute(($context["field"] ?? null), "name", array()))), "html", null, true); + echo "\" value=\""; + echo twig_escape_filter($this->env, ($context["value"] ?? null)); + echo "\" /> + "; + } + // line 22 + echo "
                              +
                              +"; + } else { + // line 25 + echo "
                              +
                              +
                              + "; + // line 28 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.CANNOT_ADD_MEDIA_FILES_PAGE_NOT_SAVED"), "html", null, true); + echo " +
                              +
                              +
                              +"; + } + } + + public function getTemplateName() + { + return "forms/fields/pagemedia/pagemedia.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 94 => 28, 89 => 25, 84 => 22, 76 => 20, 74 => 19, 69 => 17, 65 => 16, 61 => 15, 55 => 14, 49 => 13, 45 => 11, 42 => 10, 40 => 9, 34 => 6, 26 => 4, 24 => 3, 21 => 2, 19 => 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 Twig_Source("{% set value = (value is null ? field.default : value) %} + +{% if context.folderExists %} +
                              +
                              + +
                              +
                              + {% set uploadLimit = grav.config.system.media.upload_limit / 1024 / 1024 %} + {% set dropzoneSettings = { maxFileSize: uploadLimit } %} +
                              + + {% if admin.session.expert == '0' %} + + {% endif %} +
                              +
                              +{% else %} +
                              +
                              +
                              + {{ \"PLUGIN_ADMIN.CANNOT_ADD_MEDIA_FILES_PAGE_NOT_SAVED\"|tu }} +
                              +
                              +
                              +{% endif %} +", "forms/fields/pagemedia/pagemedia.html.twig", "/mnt/data/Sites/static-ethica.net/user/plugins/admin/themes/grav/templates/forms/fields/pagemedia/pagemedia.html.twig"); + } +} diff --git a/cache/twig/3e/3eb87e39a766f1d7305e357c0e31a3fe94b1fc728ae90a2cc7abb3067ef2114b.php b/cache/twig/3e/3eb87e39a766f1d7305e357c0e31a3fe94b1fc728ae90a2cc7abb3067ef2114b.php new file mode 100644 index 0000000..5513d3f --- /dev/null +++ b/cache/twig/3e/3eb87e39a766f1d7305e357c0e31a3fe94b1fc728ae90a2cc7abb3067ef2114b.php @@ -0,0 +1,360 @@ +parent = false; + + $this->blocks = array( + ); + } + + protected function doDisplay(array $context, array $blocks = array()) + { + // 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(array_merge($context, array("list_view" => "themes"))); + // line 6 + echo "

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

                              +
                              +
                              + env, $this->env->getExtension('Grav\Plugin\Admin\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", array(0 => !($context["installing"] ?? null)), "method"), "toArray", array()))); + $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", array(0 => "system.pages.theme"), "method") == $context["slug"])) { + $context["state"] = "active"; + } + // line 20 + echo " "; + $context["isTestingRelease"] = $this->getAttribute($this->getAttribute(($context["admin"] ?? null), "gpm", array()), "isTestingRelease", array(0 => $context["slug"]), "method"); + // line 21 + echo " "; + $context["releaseDate"] = (($this->getAttribute($context["theme"], "date", array())) ? ($this->getAttribute($context["theme"], "date", array())) : ($this->getAttribute($this->getAttribute($this->getAttribute(($context["admin"] ?? null), "gpm", array()), "findPackage", array(0 => $context["slug"], 1 => true), "method"), "date", array()))); + // 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", array()), "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", array()), "name", array()), "html", null, true); + echo "\" data-gpm-official=\""; + echo (($this->getAttribute(($context["admin"] ?? null), "isTeamGrav", array(0 => $context["theme"]), "method")) ? ("1") : ("2")); + echo "\" data-gpm-updatable=\""; + echo (($this->getAttribute($this->getAttribute(($context["admin"] ?? null), "gpm", array()), "isUpdatable", array(0 => $context["slug"]), "method")) ? ("1") : ("2")); + echo "\" data-gpm-enabled=\""; + echo (($this->getAttribute(($context["data"] ?? null), "get", array(0 => "enabled"), "method")) ? ("1") : ("2")); + echo "\" data-gpm-testing=\""; + echo ((($context["isTestingRelease"] ?? null)) ? ("1") : ("2")); + echo "\"> +
                              + env, $this->getAttribute($context["theme"], "icon", array()), "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", array()), "html", null, true); + echo " + "; + // line 27 + if ($this->getAttribute(($context["admin"] ?? null), "isTeamGrav", array(0 => $context["theme"]), "method")) { + // line 28 + echo " env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.GRAV_OFFICIAL_THEME"), "html", null, true); + echo "\"> + "; + } + // line 30 + echo " "; + if ($this->getAttribute(($context["admin"] ?? null), "isPremiumProduct", array(0 => $context["theme"]), "method")) { + // line 31 + echo " "; + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.PREMIUM_PRODUCT"), "html", null, true); + echo " + "; + } + // line 33 + echo " "; + if ($this->getAttribute($context["theme"], "symlink", array())) { + // line 34 + echo " env, $this->env->getExtension('Grav\Plugin\Admin\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", array()), "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", array()))) : ($this->getAttribute($context["theme"], "thumbnail", array()))); + // 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\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.ACTIVE_THEME"), "html", null, true); + echo " +
                              + "; + } else { + // line 54 + echo " env, $this->getAttribute(($context["uri"] ?? null), "addNonce", array(0 => (((((($context["base_url_relative"] ?? null) . "/themes/") . $context["slug"]) . "/task") . $this->getAttribute($this->getAttribute(($context["config"] ?? null), "system", array()), "param_sep", array())) . "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\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\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\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\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\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\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(array_merge($context, array("type" => "theme"))); + // line 82 + $this->loadTemplate("partials/modal-update-packages.html.twig", "partials/themes-list.html.twig", 82)->display(array_merge($context, array("type" => "theme"))); + } + + public function getTemplateName() + { + return "partials/themes-list.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 248 => 82, 246 => 81, 238 => 76, 234 => 75, 227 => 71, 221 => 68, 216 => 66, 210 => 62, 201 => 60, 195 => 58, 189 => 55, 184 => 54, 178 => 51, 175 => 50, 173 => 49, 166 => 47, 163 => 46, 161 => 45, 151 => 43, 149 => 42, 145 => 40, 141 => 39, 136 => 38, 128 => 34, 125 => 33, 119 => 31, 116 => 30, 110 => 28, 108 => 27, 100 => 26, 96 => 25, 75 => 23, 72 => 22, 69 => 21, 66 => 20, 61 => 19, 56 => 18, 53 => 17, 48 => 16, 40 => 11, 33 => 7, 30 => 6, 28 => 5, 24 => 3, 22 => 2, 19 => 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 Twig_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", "/home/kevin/Sites/static-ethica.net/user/plugins/admin/themes/grav/templates/partials/themes-list.html.twig"); + } +} diff --git a/cache/twig/41/41e8de888da6e7c93303b372f6e1f966bad06bcd6e142f0fdd7e958983966cab.php b/cache/twig/41/41e8de888da6e7c93303b372f6e1f966bad06bcd6e142f0fdd7e958983966cab.php new file mode 100644 index 0000000..4b6a6b6 --- /dev/null +++ b/cache/twig/41/41e8de888da6e7c93303b372f6e1f966bad06bcd6e142f0fdd7e958983966cab.php @@ -0,0 +1,166 @@ +parent = false; + + $this->blocks = array( + ); + } + + protected function doDisplay(array $context, array $blocks = array()) + { + // line 1 + if ((twig_test_empty($this->getAttribute(($context["field"] ?? null), "security", array())) || $this->env->getExtension('Grav\Common\Twig\TwigExtension')->authorize($this->env->getExtension('Grav\Common\Twig\TwigExtension')->arrayFunc($this->getAttribute(($context["field"] ?? null), "security", array()))))) { + // line 2 + echo " + "; + // line 3 + if (($this->getAttribute(($context["field"] ?? null), "title", array()) || $this->getAttribute(($context["field"] ?? null), "underline", array()))) { + // line 4 + echo "

                              getAttribute(($context["field"] ?? null), "underline", array())) { + echo "class=\"no_underline\""; + } + echo ">"; + if ($this->getAttribute($this->getAttribute($this->getAttribute($this->getAttribute(($context["grav"] ?? null), "twig", array(), "any", false, true), "twig", array(), "any", false, true), "filters", array(), "any", false, true), "tu", array(), "array", true, true)) { + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter($this->getAttribute(($context["field"] ?? null), "title", array())), "html", null, true); + } else { + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Common\Twig\TwigExtension')->translate($this->getAttribute(($context["field"] ?? null), "title", array())), "html", null, true); + } + echo "

                              + "; + } + // line 6 + echo " + "; + // line 7 + if ($this->getAttribute(($context["field"] ?? null), "text", array())) { + // line 8 + echo "

                              "; + if ($this->getAttribute($this->getAttribute($this->getAttribute($this->getAttribute(($context["grav"] ?? null), "twig", array(), "any", false, true), "twig", array(), "any", false, true), "filters", array(), "any", false, true), "tu", array(), "array", true, true)) { + echo $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter($this->getAttribute(($context["field"] ?? null), "text", array())); + } else { + echo $this->env->getExtension('Grav\Common\Twig\TwigExtension')->translate($this->getAttribute(($context["field"] ?? null), "text", array())); + } + echo "

                              + "; + } + // line 10 + echo " + "; + // line 11 + if ($this->getAttribute(($context["field"] ?? null), "fields", array())) { + // line 12 + echo "
                              env, $this->getAttribute(($context["field"] ?? null), "field_classes", array()), "html", null, true); + echo "\"> + "; + // line 13 + $context['_parent'] = $context; + $context['_seq'] = twig_ensure_traversable($this->getAttribute($context["field"], "fields", array())); + $context['loop'] = array( + 'parent' => $context['_parent'], + 'index0' => 0, + 'index' => 1, + 'first' => true, + ); + if (is_array($context['_seq']) || (is_object($context['_seq']) && $context['_seq'] instanceof Countable)) { + $length = count($context['_seq']); + $context['loop']['revindex0'] = $length - 1; + $context['loop']['revindex'] = $length; + $context['loop']['length'] = $length; + $context['loop']['last'] = 1 === $length; + } + foreach ($context['_seq'] as $context["_key"] => $context["field"]) { + // line 14 + echo " "; + if ($this->getAttribute($context["field"], "type", array())) { + // line 15 + echo " "; + $context["value"] = (($this->getAttribute($context["field"], "name", array())) ? ($this->getAttribute(($context["data"] ?? null), "value", array(0 => $this->getAttribute($context["field"], "name", array())), "method")) : ($this->getAttribute(($context["data"] ?? null), "toArray", array()))); + // line 16 + echo " "; + $this->loadTemplate(array(0 => (((("forms/fields/" . $this->getAttribute($context["field"], "type", array())) . "/") . $this->getAttribute($context["field"], "type", array())) . ".html.twig"), 1 => "forms/fields/text/text.html.twig"), "forms/fields/section/section.html.twig", 16)->display($context); + // line 17 + echo " "; + } + // line 18 + echo " "; + ++$context['loop']['index0']; + ++$context['loop']['index']; + $context['loop']['first'] = false; + if (isset($context['loop']['length'])) { + --$context['loop']['revindex0']; + --$context['loop']['revindex']; + $context['loop']['last'] = 0 === $context['loop']['revindex0']; + } + } + $_parent = $context['_parent']; + unset($context['_seq'], $context['_iterated'], $context['_key'], $context['field'], $context['_parent'], $context['loop']); + $context = array_intersect_key($context, $_parent) + $_parent; + // line 19 + echo "
                              + "; + } + // line 21 + echo " +"; + } + } + + public function getTemplateName() + { + return "forms/fields/section/section.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 112 => 21, 108 => 19, 94 => 18, 91 => 17, 88 => 16, 85 => 15, 82 => 14, 65 => 13, 60 => 12, 58 => 11, 55 => 10, 45 => 8, 43 => 7, 40 => 6, 26 => 4, 24 => 3, 21 => 2, 19 => 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 Twig_Source("{% if field.security is empty or authorize(array(field.security)) %} + + {% if field.title or field.underline %} +

                              {% if grav.twig.twig.filters['tu'] is defined %}{{ field.title|tu }}{% else %}{{ field.title|t }}{% endif %}

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

                              {% if grav.twig.twig.filters['tu'] is defined %}{{ field.text|tu|raw }}{% else %}{{ field.text|t|raw }}{% endif %}

                              + {% endif %} + + {% if field.fields %} +
                              + {% for field in field.fields %} + {% if field.type %} + {% set 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 %} +
                              + {% endif %} + +{% endif %} +", "forms/fields/section/section.html.twig", "/mnt/data/Sites/static-ethica.net/user/plugins/admin/themes/grav/templates/forms/fields/section/section.html.twig"); + } +} diff --git a/cache/twig/43/432c6f1e39fa917e282dcd5ff6e1d2bb86c775443f1df2c79809c205ab6635ed.php b/cache/twig/43/432c6f1e39fa917e282dcd5ff6e1d2bb86c775443f1df2c79809c205ab6635ed.php new file mode 100644 index 0000000..9f4df1e --- /dev/null +++ b/cache/twig/43/432c6f1e39fa917e282dcd5ff6e1d2bb86c775443f1df2c79809c205ab6635ed.php @@ -0,0 +1,83 @@ +parent = false; + + $this->blocks = array( + ); + } + + protected function doDisplay(array $context, array $blocks = array()) + { + // line 1 + $context["langobj"] = $this->getAttribute(($context["grav"] ?? null), "language", array(), "array"); + // line 2 + $context['_parent'] = $context; + $context['_seq'] = twig_ensure_traversable($this->getAttribute(($context["langswitcher"] ?? null), "languages", array())); + foreach ($context['_seq'] as $context["_key"] => $context["key"]) { + // line 3 + if (($context["key"] == $this->getAttribute(($context["langswitcher"] ?? null), "current", array()))) { + // line 4 + echo "\t"; + $context["lang_url"] = $this->getAttribute(($context["page"] ?? null), "url", array()); + } else { + // line 6 + echo "\t"; + $context["lang_url"] = (((((($context["base_url_simple"] ?? null) . $this->getAttribute(($context["langobj"] ?? null), "getLanguageURLPrefix", array(0 => $context["key"]), "method")) . $this->getAttribute(($context["langswitcher"] ?? null), "page_route", array())) . $this->getAttribute(($context["page"] ?? null), "urlExtension", array()))) ? ((((($context["base_url_simple"] ?? null) . $this->getAttribute(($context["langobj"] ?? null), "getLanguageURLPrefix", array(0 => $context["key"]), "method")) . $this->getAttribute(($context["langswitcher"] ?? null), "page_route", array())) . $this->getAttribute(($context["page"] ?? null), "urlExtension", array()))) : ("/")); + } + // line 8 + echo "getAttribute(($context["uri"] ?? null), "params", array())); + echo "\" /> +"; + } + $_parent = $context['_parent']; + unset($context['_seq'], $context['_iterated'], $context['_key'], $context['key'], $context['_parent'], $context['loop']); + $context = array_intersect_key($context, $_parent) + $_parent; + } + + public function getTemplateName() + { + return "partials/langswitcher.hreflang.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 35 => 8, 31 => 6, 27 => 4, 25 => 3, 21 => 2, 19 => 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 Twig_Source("{% set langobj = grav['language'] %} +{% for key in langswitcher.languages %} +{% if key == langswitcher.current %} +\t{% set lang_url = page.url %} +{% else %} +\t{% set lang_url = base_url_simple ~ langobj.getLanguageURLPrefix(key) ~ langswitcher.page_route ~ page.urlExtension ?: '/' %} +{% endif %} + +{% endfor %} +", "partials/langswitcher.hreflang.html.twig", "/home/kevin/Sites/static-ethica.net/user/plugins/langswitcher/templates/partials/langswitcher.hreflang.html.twig"); + } +} diff --git a/cache/twig/44/44194b75ec8eacb0e0b74538a26b8821ea99e66a7b0bf01b43c526170a6e5a19.php b/cache/twig/44/44194b75ec8eacb0e0b74538a26b8821ea99e66a7b0bf01b43c526170a6e5a19.php new file mode 100644 index 0000000..c46e274 --- /dev/null +++ b/cache/twig/44/44194b75ec8eacb0e0b74538a26b8821ea99e66a7b0bf01b43c526170a6e5a19.php @@ -0,0 +1,512 @@ +parent = $this->loadTemplate("forms/field.html.twig", "forms/fields/multilevel/multilevel.html.twig", 1); + $this->blocks = array( + 'global_attributes' => array($this, 'block_global_attributes'), + 'input' => array($this, 'block_input'), + ); + } + + protected function doGetParent(array $context) + { + return "forms/field.html.twig"; + } + + protected function doDisplay(array $context, array $blocks = array()) + { + $this->parent->display($context, array_merge($this->blocks, $blocks)); + } + + // line 3 + public function block_global_attributes($context, array $blocks = array()) + { + // line 4 + echo " data-grav-array-name=\""; + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Common\Twig\TwigExtension')->fieldNameFilter((($context["scope"] ?? null) . $this->getAttribute(($context["field"] ?? null), "name", array()))), "html", null, true); + echo "\" + data-grav-array-keyname=\""; + // line 5 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter(twig_escape_filter($this->env, $this->getAttribute(($context["field"] ?? null), "placeholder_key", array()))), "html", null, true); + echo "\" + data-grav-array-valuename=\""; + // line 6 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter(twig_escape_filter($this->env, $this->getAttribute(($context["field"] ?? null), "placeholder_value", array()))), "html", null, true); + echo "\" + "; + // line 7 + $this->displayParentBlock("global_attributes", $context, $blocks); + echo " +"; + } + + // line 89 + public function block_input($context, array $blocks = array()) + { + // line 90 + echo "
                              env, $this->env->getExtension('Grav\Common\Twig\TwigExtension')->randomStringFunc(), "html", null, true); + echo "\" data-grav-multilevel-field data-grav-array-type=\"container\" data-grav-array-mode=\"value_only\""; + echo (((twig_length_filter($this->env, ($context["value"] ?? null)) <= 1)) ? (" class=\"one-child\"") : ("")); + echo "> + "; + // line 91 + if (twig_length_filter($this->env, ($context["value"] ?? null))) { + // line 92 + echo " "; + $context['_parent'] = $context; + $context['_seq'] = twig_ensure_traversable(($context["value"] ?? null)); + foreach ($context['_seq'] as $context["key"] => $context["content"]) { + // line 93 + echo "
                              + "; + // line 94 + echo $this->getAttribute($this, "renderer", array(0 => $context["key"], 1 => $context["content"], 2 => ($context["field"] ?? null), 3 => ($context["scope"] ?? null), 4 => 0, 5 => (("[" . $context["key"]) . "]"), 6 => true), "method"); + echo " +
                              + "; + } + $_parent = $context['_parent']; + unset($context['_seq'], $context['_iterated'], $context['key'], $context['content'], $context['_parent'], $context['loop']); + $context = array_intersect_key($context, $_parent) + $_parent; + } else { + // line 99 + echo "
                              +
                              + + env, $this->env->getExtension('Grav\Common\Twig\TwigExtension')->fieldNameFilter((($context["scope"] ?? null) . $this->getAttribute(($context["field"] ?? null), "name", array()))), "html", null, true); + echo "\" + placeholder=\"Enter value\" + value=\"\" /> + + + + +
                              +
                              "; + } + // line 115 + echo "
                              +"; + } + + // line 11 + public function getfield($__value__ = null, $__key__ = null, $__level__ = null, $__globalvars__ = null, $__disable_name__ = null, $__hidden__ = null, ...$__varargs__) + { + $context = $this->env->mergeGlobals(array( + "value" => $__value__, + "key" => $__key__, + "level" => $__level__, + "globalvars" => $__globalvars__, + "disable_name" => $__disable_name__, + "hidden" => $__hidden__, + "varargs" => $__varargs__, + )); + + $blocks = array(); + + ob_start(); + try { + // line 12 + echo " "; + $context["name"] = ((("data[" . twig_replace_filter($this->getAttribute($this->getAttribute(($context["globalvars"] ?? null), "field", array()), "name", array()), array("." => "]["))) . "]") . ($context["key"] ?? null)); + // line 13 + echo "
                              + env, ($context["name"] ?? null), "html", null, true); + echo "\""; + } + // line 18 + echo " data-attr-name=\""; + echo twig_escape_filter($this->env, ($context["name"] ?? null), "html", null, true); + echo "\" + placeholder=\""; + // line 19 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter(twig_escape_filter($this->env, $this->getAttribute(($context["field"] ?? null), "placeholder_value", array()))), "html", null, true); + echo "\" + style=\"margin-left: "; + // line 20 + echo twig_escape_filter($this->env, (($context["level"] ?? null) * 50), "html", null, true); + echo "px\" + value=\""; + // line 21 + echo twig_escape_filter($this->env, ($context["value"] ?? null), "html", null, true); + echo "\" /> + + + env, ($context["level"] ?? null), "html", null, true); + echo "\"> + env, ($context["level"] ?? null), "html", null, true); + echo "\"> +
                              + "; + } catch (Exception $e) { + ob_end_clean(); + + throw $e; + } catch (Throwable $e) { + ob_end_clean(); + + throw $e; + } + + return ('' === $tmp = ob_get_clean()) ? '' : new Twig_Markup($tmp, $this->env->getCharset()); + } + + // line 10 + public function getrenderer($__key__ = null, $__content__ = null, $__field__ = null, $__scope__ = null, $__level__ = null, $__parent_key__ = null, $__up_level__ = null, ...$__varargs__) + { + $context = $this->env->mergeGlobals(array( + "key" => $__key__, + "content" => $__content__, + "field" => $__field__, + "scope" => $__scope__, + "level" => $__level__, + "parent_key" => $__parent_key__, + "up_level" => $__up_level__, + "varargs" => $__varargs__, + )); + + $blocks = array(); + + ob_start(); + try { + // line 11 + echo " "; + // line 28 + echo " + "; + // line 29 + if ((($context["level"] ?? null) == 0)) { + // line 30 + echo " + "; + // line 31 + echo $this->getAttribute($this, "field", array(0 => ($context["key"] ?? null), 1 => "", 2 => ($context["level"] ?? null), 3 => $context, 4 => true, 5 => ((is_numeric(($context["key"] ?? null))) ? (true) : (false))), "method"); + echo " + + "; + // line 33 + if ( !twig_test_iterable(($context["content"] ?? null))) { + // line 34 + echo " "; + $context["level2"] = (($context["level"] ?? null) + 1); + // line 35 + echo " +
                              +
                              + "; + // line 38 + echo $this->getAttribute($this, "field", array(0 => ($context["content"] ?? null), 1 => (("[" . ($context["key"] ?? null)) . "]"), 2 => ($context["level2"] ?? null), 3 => $context), "method"); + echo " +
                              +
                              + "; + } + // line 42 + echo " "; + } + // line 43 + echo " + "; + // line 44 + if (($context["up_level"] ?? null)) { + // line 45 + echo " "; + $context["level"] = (($context["level"] ?? null) + 1); + // line 46 + echo " "; + } + // line 47 + echo "
                              + "; + // line 48 + $context["unique_child"] = (((is_array(($context["content"] ?? null)) && ($this->getAttribute(($context["content"] ?? null), "length", array()) > 1))) ? (true) : (false)); + // line 49 + echo " + "; + // line 50 + $context['_parent'] = $context; + $context['_seq'] = twig_ensure_traversable(($context["content"] ?? null)); + foreach ($context['_seq'] as $context["inner_key"] => $context["inner_content"]) { + // line 51 + echo "
                              + "; + // line 52 + if ( !is_numeric($context["inner_key"])) { + // line 53 + echo " "; + if ((twig_length_filter($this->env, ($context["content"] ?? null)) > 1)) { + // line 54 + echo " "; + echo $this->getAttribute($this, "field", array(0 => $context["inner_key"], 1 => ($context["parent_key"] ?? null), 2 => ($context["level"] ?? null), 3 => $context, 4 => true), "method"); + echo " + "; + } else { + // line 56 + echo " "; + echo $this->getAttribute($this, "field", array(0 => $context["inner_key"], 1 => ($context["parent_key"] ?? null), 2 => ($context["level"] ?? null), 3 => $context), "method"); + echo " + "; + } + // line 58 + echo " "; + $context["level2"] = (($context["level"] ?? null) + 1); + // line 59 + echo " "; + $context["up_level"] = true; + // line 60 + echo " "; + } else { + // line 61 + echo " "; + $context["up_level"] = false; + // line 62 + echo " "; + $context["level2"] = ($context["level"] ?? null); + // line 63 + echo " "; + } + // line 64 + echo " + "; + // line 65 + if ( !twig_test_iterable($context["inner_content"])) { + // line 66 + echo " + "; + // line 67 + if ( !is_numeric($context["inner_key"])) { + // line 68 + echo "
                              +
                              + "; + } + // line 71 + echo " + "; + // line 72 + $context["last_key"] = ((is_numeric($context["inner_key"])) ? ("") : ($context["inner_key"])); + // line 73 + echo " "; + echo $this->getAttribute($this, "field", array(0 => $context["inner_content"], 1 => (((($context["parent_key"] ?? null) . "[") . $context["inner_key"]) . "]"), 2 => ($context["level2"] ?? null), 3 => $context), "method"); + echo " + + "; + // line 75 + if ( !is_numeric($context["inner_key"])) { + // line 76 + echo "
                              +
                              + "; + } + // line 79 + echo " "; + } else { + // line 80 + echo " + "; + // line 81 + $context["inner_parent_key"] = (((($context["parent_key"] ?? null) . "[") . $context["inner_key"]) . "]"); + // line 82 + echo " "; + echo $this->getAttribute($this, "renderer", array(0 => $context["inner_key"], 1 => $context["inner_content"], 2 => ($context["field"] ?? null), 3 => ($context["scope"] ?? null), 4 => ($context["level"] ?? null), 5 => ($context["inner_parent_key"] ?? null), 6 => ($context["up_level"] ?? null)), "method"); + echo " + "; + } + // line 84 + echo "
                              + "; + } + $_parent = $context['_parent']; + unset($context['_seq'], $context['_iterated'], $context['inner_key'], $context['inner_content'], $context['_parent'], $context['loop']); + $context = array_intersect_key($context, $_parent) + $_parent; + // line 86 + echo "
                              +"; + } catch (Exception $e) { + ob_end_clean(); + + throw $e; + } catch (Throwable $e) { + ob_end_clean(); + + throw $e; + } + + return ('' === $tmp = ob_get_clean()) ? '' : new Twig_Markup($tmp, $this->env->getCharset()); + } + + public function getTemplateName() + { + return "forms/fields/multilevel/multilevel.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 354 => 86, 347 => 84, 341 => 82, 339 => 81, 336 => 80, 333 => 79, 328 => 76, 326 => 75, 320 => 73, 318 => 72, 315 => 71, 310 => 68, 308 => 67, 305 => 66, 303 => 65, 300 => 64, 297 => 63, 294 => 62, 291 => 61, 288 => 60, 285 => 59, 282 => 58, 276 => 56, 270 => 54, 267 => 53, 265 => 52, 262 => 51, 258 => 50, 255 => 49, 253 => 48, 250 => 47, 247 => 46, 244 => 45, 242 => 44, 239 => 43, 236 => 42, 229 => 38, 224 => 35, 221 => 34, 219 => 33, 214 => 31, 211 => 30, 209 => 29, 206 => 28, 204 => 11, 186 => 10, 168 => 25, 164 => 24, 158 => 21, 154 => 20, 150 => 19, 145 => 18, 139 => 17, 131 => 14, 126 => 13, 123 => 12, 106 => 11, 101 => 115, 89 => 105, 81 => 99, 71 => 94, 68 => 93, 63 => 92, 61 => 91, 54 => 90, 51 => 89, 45 => 7, 41 => 6, 37 => 5, 32 => 4, 29 => 3, 11 => 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 Twig_Source("{% extends \"forms/field.html.twig\" %} + +{% block global_attributes %} + data-grav-array-name=\"{{ (scope ~ field.name)|fieldName }}\" + data-grav-array-keyname=\"{{ field.placeholder_key|e|tu }}\" + data-grav-array-valuename=\"{{ field.placeholder_value|e|tu }}\" + {{ parent() }} +{% endblock %} + +{% macro renderer(key, content, field, scope, level, parent_key, up_level) %} + {% macro field(value, key, level, globalvars, disable_name, hidden) %} + {% set name = 'data[' ~ globalvars.field.name|replace({'.': ']['}) ~ ']' ~ key %} +
                              + + + + + +
                              + {% endmacro %} + + {% if level == 0 %} + + {{ _self.field(key, '', level, _context, true, (is_numeric(key) ? true : false)) }} + + {% if content is not iterable %} + {% set level2 = level + 1 %} + +
                              +
                              + {{ _self.field(content, '[' ~ key ~ ']', level2, _context) }} +
                              +
                              + {% endif %} + {% endif %} + + {% if up_level %} + {% set level = level + 1 %} + {% endif %} +
                              + {% set unique_child = (is_array(content) and content.length > 1) ? true : false %} + + {% for inner_key, inner_content in content -%} +
                              + {% if not is_numeric(inner_key) %} + {% if (content|length > 1) %} + {{ _self.field(inner_key, parent_key, level, _context, true) }} + {% else %} + {{ _self.field(inner_key, parent_key, level, _context) }} + {% endif %} + {% set level2 = level + 1 %} + {% set up_level = true %} + {% else %} + {% set up_level = false %} + {% set level2 = level %} + {% endif %} + + {% if inner_content is not iterable %} + + {% if not is_numeric(inner_key) %} +
                              +
                              + {% endif %} + + {% set last_key = (is_numeric(inner_key)) ? '' : inner_key %} + {{ _self.field(inner_content, parent_key ~ '[' ~ inner_key ~ ']', level2, _context) }} + + {% if not is_numeric(inner_key) %} +
                              +
                              + {% endif %} + {% else %} + + {% set inner_parent_key = parent_key ~ '[' ~ inner_key ~ ']' %} + {{ _self.renderer(inner_key, inner_content, field, scope, level, inner_parent_key, up_level) }} + {% endif %} +
                              + {% endfor %} +
                              +{% endmacro %} + +{% block input %} +
                              + {% if value|length %} + {% for key, content in value -%} +
                              + {{ _self.renderer(key, content, field, scope, 0, '[' ~ key ~ ']', true) }} +
                              + {% endfor %} + {%- else -%} + {# Empty value, mock the entry field#} +
                              +
                              + + + + + + +
                              +
                              + {%- endif %} +
                              +{% endblock %} +", "forms/fields/multilevel/multilevel.html.twig", "/mnt/data/Sites/static-ethica.net/user/plugins/admin/themes/grav/templates/forms/fields/multilevel/multilevel.html.twig"); + } +} diff --git a/cache/twig/47/47c8bb036f24cda65e5bfbbf55689341313601125c8862e7f07edd7d6f2c4d49.php b/cache/twig/47/47c8bb036f24cda65e5bfbbf55689341313601125c8862e7f07edd7d6f2c4d49.php new file mode 100644 index 0000000..a77d02d --- /dev/null +++ b/cache/twig/47/47c8bb036f24cda65e5bfbbf55689341313601125c8862e7f07edd7d6f2c4d49.php @@ -0,0 +1,77 @@ +parent = $this->loadTemplate("forms/field.html.twig", "forms/fields/email/email.html.twig", 1); + $this->blocks = array( + 'input_attributes' => array($this, 'block_input_attributes'), + ); + } + + protected function doGetParent(array $context) + { + return "forms/field.html.twig"; + } + + protected function doDisplay(array $context, array $blocks = array()) + { + $this->parent->display($context, array_merge($this->blocks, $blocks)); + } + + // line 3 + public function block_input_attributes($context, array $blocks = array()) + { + // line 4 + echo " type=\"email\" + "; + // line 5 + if (twig_in_filter($this->getAttribute(($context["field"] ?? null), "multiple", array()), array(0 => "on", 1 => "true", 2 => 1))) { + echo "multiple=\"multiple\""; + } + // line 6 + echo " "; + $this->displayParentBlock("input_attributes", $context, $blocks); + echo " +"; + } + + public function getTemplateName() + { + return "forms/fields/email/email.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 38 => 6, 34 => 5, 31 => 4, 28 => 3, 11 => 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 Twig_Source("{% extends \"forms/field.html.twig\" %} + +{% block input_attributes %} + type=\"email\" + {% if field.multiple in ['on', 'true', 1] %}multiple=\"multiple\"{% endif %} + {{ parent() }} +{% endblock %}", "forms/fields/email/email.html.twig", "/home/kevin/Sites/static-ethica.net/user/plugins/form/templates/forms/fields/email/email.html.twig"); + } +} diff --git a/cache/twig/49/496d55c030d8d0acf77af172547f07daba7d039cd929b3fdb16ad94a8d9a713f.php b/cache/twig/49/496d55c030d8d0acf77af172547f07daba7d039cd929b3fdb16ad94a8d9a713f.php new file mode 100644 index 0000000..0ba5184 --- /dev/null +++ b/cache/twig/49/496d55c030d8d0acf77af172547f07daba7d039cd929b3fdb16ad94a8d9a713f.php @@ -0,0 +1,137 @@ +parent = $this->loadTemplate("forms/field.html.twig", "forms/fields/2fa_secret/2fa_secret.html.twig", 1); + $this->blocks = array( + 'input' => array($this, 'block_input'), + ); + } + + protected function doGetParent(array $context) + { + return "forms/field.html.twig"; + } + + protected function doDisplay(array $context, array $blocks = array()) + { + $this->parent->display($context, array_merge($this->blocks, $blocks)); + } + + // line 3 + public function block_input($context, array $blocks = array()) + { + // line 4 + echo "
                              + "; + // line 5 + $this->getAttribute(($context["admin"] ?? null), "get2FAData", array(0 => ($context["value"] ?? null)), "method"); + // line 6 + echo " "; + $context["data"] = $this->getAttribute(($context["admin"] ?? null), "json_response", array()); + // line 7 + echo " "; + if (($this->getAttribute(($context["data"] ?? null), "status", array()) == "success")) { + // line 8 + echo " + env, $this->getAttribute(($context["data"] ?? null), "image", array()), "html", null, true); + echo "\" /> +
                              + "; + // line 11 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.2FA_SECRET"), "html", null, true); + echo ": "; + echo twig_escape_filter($this->env, $this->getAttribute(($context["data"] ?? null), "secret", array()), "html", null, true); + echo " +
                              +
                              + +
                              + env, $this->env->getExtension('Grav\Common\Twig\TwigExtension')->fieldNameFilter((($context["scope"] ?? null) . $this->getAttribute(($context["field"] ?? null), "name", array()))), "html", null, true); + echo "\" data-2fa-value value=\""; + echo twig_escape_filter($this->env, twig_replace_filter($this->getAttribute(($context["data"] ?? null), "secret", array()), array(" " => "")), "html", null, true); + echo "\" /> + + "; + } else { + // line 19 + echo "
                              +

                              "; + // line 20 + echo twig_escape_filter($this->env, $this->getAttribute(($context["data"] ?? null), "message", array()), "html", null, true); + echo "

                              +
                              + "; + } + // line 23 + echo "
                              +"; + } + + public function getTemplateName() + { + return "forms/fields/2fa_secret/2fa_secret.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 82 => 23, 76 => 20, 73 => 19, 65 => 16, 58 => 14, 50 => 11, 45 => 9, 42 => 8, 39 => 7, 36 => 6, 34 => 5, 31 => 4, 28 => 3, 11 => 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 Twig_Source("{% extends \"forms/field.html.twig\" %} + +{% block input %} +
                              + {% do admin.get2FAData(value) %} + {% set data = admin.json_response %} + {% if data.status == 'success' %} + + +
                              + {{ 'PLUGIN_ADMIN.2FA_SECRET'|tu }}: {{ data.secret }} +
                              +
                              + +
                              + + + {% else %} +
                              +

                              {{ data.message }}

                              +
                              + {% endif %} +
                              +{% endblock %} +", "forms/fields/2fa_secret/2fa_secret.html.twig", "/home/kevin/Sites/static-ethica.net/user/plugins/admin/themes/grav/templates/forms/fields/2fa_secret/2fa_secret.html.twig"); + } +} diff --git a/cache/twig/4f/4f83a5fa7d47ca2e9a349c9decc95bc26b0e689e724d372c7490bf9b7be6caae.php b/cache/twig/4f/4f83a5fa7d47ca2e9a349c9decc95bc26b0e689e724d372c7490bf9b7be6caae.php new file mode 100644 index 0000000..235eeb8 --- /dev/null +++ b/cache/twig/4f/4f83a5fa7d47ca2e9a349c9decc95bc26b0e689e724d372c7490bf9b7be6caae.php @@ -0,0 +1,53 @@ +parent = false; + + $this->blocks = array( + ); + } + + protected function doDisplay(array $context, array $blocks = array()) + { + // line 1 + echo "env, $this->getAttribute($this->getAttribute(($context["admin"] ?? null), "user", array()), "avatarUrl", array(), "method"), "html", null, true); + echo "?s=47\" /> +"; + } + + public function getTemplateName() + { + return "partials/nav-user-avatar.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 19 => 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 Twig_Source(" +", "partials/nav-user-avatar.html.twig", "/mnt/data/Sites/static-ethica.net/user/plugins/admin/themes/grav/templates/partials/nav-user-avatar.html.twig"); + } +} diff --git a/cache/twig/50/50b7414f5ac7ebf35072ffca56a848c16a2831e5a9d0ac1aed2ce44f886ee0e7.php b/cache/twig/50/50b7414f5ac7ebf35072ffca56a848c16a2831e5a9d0ac1aed2ce44f886ee0e7.php new file mode 100644 index 0000000..cb06996 --- /dev/null +++ b/cache/twig/50/50b7414f5ac7ebf35072ffca56a848c16a2831e5a9d0ac1aed2ce44f886ee0e7.php @@ -0,0 +1,263 @@ +parent = $this->loadTemplate("partials/base.html.twig", "user.html.twig", 1); + $this->blocks = array( + 'titlebar' => array($this, 'block_titlebar'), + 'content' => array($this, 'block_content'), + ); + } + + protected function doGetParent(array $context) + { + return "partials/base.html.twig"; + } + + protected function doDisplay(array $context, array $blocks = array()) + { + // line 3 + if ($this->getAttribute(($context["admin"] ?? null), "route", array())) { + // line 4 + $context["user"] = $this->getAttribute(($context["admin"] ?? null), "data", array(0 => ("users/" . $this->getAttribute(($context["admin"] ?? null), "route", array()))), "method"); + // line 5 + $context["title"] = (($this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.USER") . ": ") . twig_escape_filter($this->env, $this->getAttribute(($context["admin"] ?? null), "route", array()))); + } else { + // line 7 + $context["title"] = $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN_PRO.USERS"); + } + // line 1 + $this->parent->display($context, array_merge($this->blocks, $blocks)); + } + + // line 10 + public function block_titlebar($context, array $blocks = array()) + { + // line 11 + echo " "; + if ( !$this->getAttribute(($context["admin"] ?? null), "route", array())) { + // line 12 + echo " "; + if ($this->env->getExtension('Grav\Common\Twig\TwigExtension')->authorize(array(0 => "admin.users", 1 => "admin.super"))) { + // line 13 + echo " +

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

                              + "; + } else { + // line 18 + echo "

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

                              + "; + } + // line 20 + echo " "; + } else { + // line 21 + echo " "; + if (($this->env->getExtension('Grav\Common\Twig\TwigExtension')->authorize(array(0 => "admin.users", 1 => "admin.super")) || ($this->getAttribute($this->getAttribute(($context["grav"] ?? null), "user", array()), "username", array()) == $this->getAttribute(($context["user"] ?? null), "username", array())))) { + // line 22 + echo "
                              + "; + // line 23 + if ($this->getAttribute($this->getAttribute($this->getAttribute(($context["config"] ?? null), "plugins", array()), "admin-pro", array(), "array"), "enabled", array())) { + // line 24 + echo " env, ($context["base_url"] ?? null), "html", null, true); + echo "/users\"> "; + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.BACK"), "html", null, true); + echo " + "; + } + // line 26 + echo " +
                              +

                              "; + // line 28 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.USER"), "html", null, true); + echo ": "; + echo twig_escape_filter($this->env, $this->getAttribute(($context["user"] ?? null), "username", array())); + echo "

                              + "; + } else { + // line 30 + echo "

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

                              + "; + } + // line 32 + echo " "; + } + } + + // line 35 + public function block_content($context, array $blocks = array()) + { + // line 36 + echo " "; + if (($this->env->getExtension('Grav\Common\Twig\TwigExtension')->authorize(array(0 => "admin.users", 1 => "admin.super")) || ($this->getAttribute($this->getAttribute(($context["grav"] ?? null), "user", array()), "username", array()) == $this->getAttribute(($context["user"] ?? null), "username", array())))) { + // line 37 + echo "
                              + "; + // line 38 + if ( !$this->getAttribute(($context["admin"] ?? null), "route", array())) { + // line 39 + echo " "; + $this->loadTemplate("partials/users-list.html.twig", "user.html.twig", 39)->display($context); + // line 40 + echo " +
                              + "; + // line 42 + $this->loadTemplate("partials/blueprints-new.html.twig", "user.html.twig", 42)->display(array_merge($context, array("blueprints" => $this->getAttribute(($context["admin"] ?? null), "blueprints", array(0 => "user/account_new"), "method")))); + // line 43 + echo "
                              + "; + } else { + // line 45 + echo " "; + $this->loadTemplate("partials/blueprints.html.twig", "user.html.twig", 45)->display(array_merge($context, array("data" => ($context["user"] ?? null), "blueprints" => $this->getAttribute(($context["user"] ?? null), "blueprints", array())))); + // line 46 + echo " "; + } + // line 47 + echo "
                              + +
                              +
                              +

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

                              +

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

                              +
                              + +
                              +
                              + "; + } + } + + public function getTemplateName() + { + return "user.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 163 => 58, 159 => 57, 152 => 53, 147 => 51, 141 => 47, 138 => 46, 135 => 45, 131 => 43, 129 => 42, 125 => 40, 122 => 39, 120 => 38, 117 => 37, 114 => 36, 111 => 35, 106 => 32, 100 => 30, 93 => 28, 87 => 26, 79 => 24, 77 => 23, 74 => 22, 71 => 21, 68 => 20, 62 => 18, 57 => 16, 52 => 14, 49 => 13, 46 => 12, 43 => 11, 40 => 10, 36 => 1, 33 => 7, 30 => 5, 28 => 4, 26 => 3, 11 => 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 Twig_Source("{% extends 'partials/base.html.twig' %} + +{% if admin.route %} + {% set user = admin.data('users/' ~ admin.route) %} + {% set title = \"PLUGIN_ADMIN.USER\"|tu ~ \": \" ~ admin.route|e %} +{% else %} + {% set title = \"PLUGIN_ADMIN_PRO.USERS\"|tu %} +{% endif %} + +{% block titlebar %} + {% if not admin.route %} + {% if authorize(['admin.users', 'admin.super']) %} + +

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

                              + {% else %} +

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

                              + {% endif %} + {% else %} + {% if authorize(['admin.users', 'admin.super']) or grav.user.username == user.username %} +
                              + {% if config.plugins[\"admin-pro\"].enabled %} + {{ \"PLUGIN_ADMIN.BACK\"|tu }} + {% endif %} + +
                              +

                              {{ \"PLUGIN_ADMIN.USER\"|tu }}: {{ user.username|e }}

                              + {% else %} +

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

                              + {% endif %} + {% endif %} +{% endblock %} + +{% block content %} + {% if authorize(['admin.users', 'admin.super']) or grav.user.username == user.username %} +
                              + {% if not admin.route %} + {% include 'partials/users-list.html.twig' %} + +
                              + {% include 'partials/blueprints-new.html.twig' with { blueprints: admin.blueprints('user/account_new') } %} +
                              + {% else %} + {% include 'partials/blueprints.html.twig' with { data: user, blueprints: user.blueprints } %} + {% endif %} +
                              + +
                              +
                              +

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

                              +

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

                              +
                              + +
                              +
                              + {% endif %} +{% endblock %} + +", "user.html.twig", "/home/kevin/Sites/static-ethica.net/user/plugins/admin/themes/grav/templates/user.html.twig"); + } +} diff --git a/cache/twig/52/52f6b950ea942afeeb5a7fc8c73a8c8d1569a70cc89fd44ff94debb91f0ff279.php b/cache/twig/52/52f6b950ea942afeeb5a7fc8c73a8c8d1569a70cc89fd44ff94debb91f0ff279.php new file mode 100644 index 0000000..fccb121 --- /dev/null +++ b/cache/twig/52/52f6b950ea942afeeb5a7fc8c73a8c8d1569a70cc89fd44ff94debb91f0ff279.php @@ -0,0 +1,54 @@ +parent = false; + + $this->blocks = array( + ); + } + + protected function doDisplay(array $context, array $blocks = array()) + { + // line 1 + echo $this->env->getExtension('Grav\Common\Twig\TwigExtension')->translate("PLUGIN_ERROR.ERROR_MESSAGE"); + echo " + +"; + } + + public function getTemplateName() + { + return "@Page:/mnt/data/Sites/static-ethica.net/user/plugins/error/pages"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 19 => 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 Twig_Source("{{ 'PLUGIN_ERROR.ERROR_MESSAGE'|t }} + +", "@Page:/mnt/data/Sites/static-ethica.net/user/plugins/error/pages", ""); + } +} diff --git a/cache/twig/53/53d18a9c1445d63f9fc442e4a7e62f624cc9510839295bfce8606a877f0e83a2.php b/cache/twig/53/53d18a9c1445d63f9fc442e4a7e62f624cc9510839295bfce8606a877f0e83a2.php new file mode 100644 index 0000000..24af7d1 --- /dev/null +++ b/cache/twig/53/53d18a9c1445d63f9fc442e4a7e62f624cc9510839295bfce8606a877f0e83a2.php @@ -0,0 +1,87 @@ +parent = false; + + $this->blocks = array( + ); + } + + protected function doDisplay(array $context, array $blocks = array()) + { + // line 1 + $context['_parent'] = $context; + $context['_seq'] = twig_ensure_traversable($this->getAttribute(($context["page"] ?? null), "metadata", array())); + foreach ($context['_seq'] as $context["_key"] => $context["meta"]) { + // line 2 + echo "getAttribute($context["meta"], "name", array())) { + echo "name=\""; + echo $this->getAttribute($context["meta"], "name", array()); + echo "\" "; + } + if ($this->getAttribute($context["meta"], "http_equiv", array())) { + echo "http-equiv=\""; + echo $this->getAttribute($context["meta"], "http_equiv", array()); + echo "\" "; + } + if ($this->getAttribute($context["meta"], "charset", array())) { + echo "charset=\""; + echo $this->getAttribute($context["meta"], "charset", array()); + echo "\" "; + } + if ($this->getAttribute($context["meta"], "property", array())) { + echo "property=\""; + echo $this->getAttribute($context["meta"], "property", array()); + echo "\" "; + } + if ($this->getAttribute($context["meta"], "content", array())) { + echo "content=\""; + echo $this->getAttribute($context["meta"], "content", array()); + 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 ( 23 => 2, 19 => 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 Twig_Source("{% for meta in page.metadata %} + +{% endfor %} +", "partials/metadata.html.twig", "/mnt/data/Sites/static-ethica.net/user/themes/ethica/templates/partials/metadata.html.twig"); + } +} diff --git a/cache/twig/5a/5a33dbae7ff280ee6e22eab599ef5bfed04c72e87641aea13b8a91bae4715858.php b/cache/twig/5a/5a33dbae7ff280ee6e22eab599ef5bfed04c72e87641aea13b8a91bae4715858.php new file mode 100644 index 0000000..93ea102 --- /dev/null +++ b/cache/twig/5a/5a33dbae7ff280ee6e22eab599ef5bfed04c72e87641aea13b8a91bae4715858.php @@ -0,0 +1,178 @@ +parent = false; + + $this->blocks = array( + ); + } + + protected function doDisplay(array $context, array $blocks = array()) + { + // line 1 + echo "
                              +
                              +
                              +

                              "; + // line 6 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.REMOVE_THE", array(0 => $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter(("PLUGIN_ADMIN." . twig_upper_filter($this->env, ($context["type"] ?? null)))))), "html", null, true); + echo "

                              +

                              + "; + // line 8 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.CONFIRM_REMOVAL", array(0 => $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter(("PLUGIN_ADMIN." . twig_upper_filter($this->env, ($context["type"] ?? null)))))), "html", null, true); + echo " +

                              + +
                              + + +
                              +
                              + +
                              +

                              "; + // line 18 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.REMOVED_SUCCESSFULLY", array(0 => $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter(("PLUGIN_ADMIN." . twig_upper_filter($this->env, ($context["type"] ?? null)))))), "html", null, true); + echo "

                              +

                              + "; + // line 20 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.ADDITIONAL_DEPENDENCIES_CAN_BE_REMOVED", array(0 => $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter(("PLUGIN_ADMIN." . twig_upper_filter($this->env, ($context["type"] ?? null)))))), "html", null, true); + echo " +

                              +
                              +
                                +
                                + +
                                + +
                                +

                                "; + // line 31 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.REMOVED_SUCCESSFULLY", array(0 => $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter(("PLUGIN_ADMIN." . twig_upper_filter($this->env, ($context["type"] ?? null)))))), "html", null, true); + echo "

                                + +
                                + +
                                +

                                "; + // line 38 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.ERROR_REMOVING_THE", array(0 => $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter(("PLUGIN_ADMIN." . twig_upper_filter($this->env, ($context["type"] ?? null)))))), "html", null, true); + echo "

                                +
                                + +
                                +
                                +
                                +
                                +"; + } + + public function getTemplateName() + { + return "partials/modal-remove-package.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 98 => 40, 93 => 38, 83 => 33, 78 => 31, 68 => 26, 59 => 20, 54 => 18, 42 => 13, 38 => 12, 31 => 8, 26 => 6, 19 => 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 Twig_Source("
                                +
                                +
                                +

                                {{ \"PLUGIN_ADMIN.REMOVE_THE\"|tu([(\"PLUGIN_ADMIN.\" ~ type|upper)|tu]) }}

                                +

                                + {{ \"PLUGIN_ADMIN.CONFIRM_REMOVAL\"|tu([(\"PLUGIN_ADMIN.\" ~ type|upper)|tu]) }} +

                                + +
                                + + +
                                +
                                + +
                                +

                                {{ \"PLUGIN_ADMIN.REMOVED_SUCCESSFULLY\"|tu([(\"PLUGIN_ADMIN.\" ~ type|upper)|tu]) }}

                                +

                                + {{ \"PLUGIN_ADMIN.ADDITIONAL_DEPENDENCIES_CAN_BE_REMOVED\"|tu([(\"PLUGIN_ADMIN.\" ~ type|upper)|tu]) }} +

                                +
                                +
                                  +
                                  + +
                                  + +
                                  +

                                  {{ \"PLUGIN_ADMIN.REMOVED_SUCCESSFULLY\"|tu([(\"PLUGIN_ADMIN.\" ~ type|upper)|tu]) }}

                                  + +
                                  + +
                                  +

                                  {{ \"PLUGIN_ADMIN.ERROR_REMOVING_THE\"|tu([(\"PLUGIN_ADMIN.\" ~ type|upper)|tu]) }}

                                  +
                                  + +
                                  +
                                  +
                                  +
                                  +", "partials/modal-remove-package.html.twig", "/home/kevin/Sites/static-ethica.net/user/plugins/admin/themes/grav/templates/partials/modal-remove-package.html.twig"); + } +} diff --git a/cache/twig/5b/5bee15b1862b472f001ab0795da57fc8a2dae97b31aa96841531e2324baa735c.php b/cache/twig/5b/5bee15b1862b472f001ab0795da57fc8a2dae97b31aa96841531e2324baa735c.php new file mode 100644 index 0000000..649ac4e --- /dev/null +++ b/cache/twig/5b/5bee15b1862b472f001ab0795da57fc8a2dae97b31aa96841531e2324baa735c.php @@ -0,0 +1,61 @@ +parent = false; + + $this->blocks = array( + ); + } + + protected function doDisplay(array $context, array $blocks = array()) + { + // line 1 + $context["value"] = (((null === ($context["value"] ?? null))) ? ((($this->getAttribute(($context["field"] ?? null), "evaluate", array())) ? ($this->env->getExtension('Grav\Common\Twig\TwigExtension')->evaluateStringFunc($this->env, $context, $this->getAttribute(($context["field"] ?? null), "default", array()))) : ($this->getAttribute(($context["field"] ?? null), "default", array())))) : (($context["value"] ?? null))); + // line 2 + echo " +env, $this->env->getExtension('Grav\Common\Twig\TwigExtension')->fieldNameFilter((($context["scope"] ?? null) . $this->getAttribute(($context["field"] ?? null), "name", array()))), "html", null, true); + echo "\" value=\""; + echo twig_escape_filter($this->env, twig_join_filter(($context["value"] ?? null), ", "), "html", null, true); + echo "\" /> +"; + } + + public function getTemplateName() + { + return "forms/fields/hidden/hidden.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 24 => 3, 21 => 2, 19 => 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 Twig_Source("{% set value = (value is null ? (field.evaluate ? evaluate(field.default) : field.default) : value) %} + + +", "forms/fields/hidden/hidden.html.twig", "/mnt/data/Sites/static-ethica.net/user/plugins/form/templates/forms/fields/hidden/hidden.html.twig"); + } +} diff --git a/cache/twig/63/630978b1576372100e8d899f8f548a1b00db4ea04bcb128a6a5a947530291c76.php b/cache/twig/63/630978b1576372100e8d899f8f548a1b00db4ea04bcb128a6a5a947530291c76.php new file mode 100644 index 0000000..7732aa5 --- /dev/null +++ b/cache/twig/63/630978b1576372100e8d899f8f548a1b00db4ea04bcb128a6a5a947530291c76.php @@ -0,0 +1,167 @@ +parent = $this->loadTemplate("forms/field.html.twig", "forms/fields/dateformat/dateformat.html.twig", 1); + $this->blocks = array( + 'global_attributes' => array($this, 'block_global_attributes'), + 'input' => array($this, 'block_input'), + ); + } + + protected function doGetParent(array $context) + { + return "forms/field.html.twig"; + } + + protected function doDisplay(array $context, array $blocks = array()) + { + $this->parent->display($context, array_merge($this->blocks, $blocks)); + } + + // line 3 + public function block_global_attributes($context, array $blocks = array()) + { + // line 4 + echo " data-grav-selectize=\""; + echo twig_escape_filter($this->env, twig_jsonencode_filter((($this->getAttribute(($context["field"] ?? null), "selectize", array(), "any", true, true)) ? ($this->getAttribute(($context["field"] ?? null), "selectize", array())) : (array()))), "html_attr"); + echo "\" + data-grav-field=\"select\" + "; + // line 6 + $this->displayParentBlock("global_attributes", $context, $blocks); + echo " +"; + } + + // line 9 + public function block_input($context, array $blocks = array()) + { + // line 10 + echo "
                                  env, $this->getAttribute(($context["field"] ?? null), "size", array()), "html", null, true); + echo "\"> + +
                                  +"; + } + + public function getTemplateName() + { + return "forms/fields/dateformat/dateformat.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 111 => 22, 96 => 20, 92 => 19, 89 => 18, 82 => 17, 77 => 16, 72 => 15, 67 => 14, 62 => 13, 58 => 12, 52 => 11, 47 => 10, 44 => 9, 38 => 6, 32 => 4, 29 => 3, 11 => 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 Twig_Source("{% extends \"forms/field.html.twig\" %} + +{% block global_attributes %} + data-grav-selectize=\"{{ (field.selectize is defined ? field.selectize : {})|json_encode()|e('html_attr') }}\" + data-grav-field=\"select\" + {{ parent() }} +{% endblock %} + +{% block input %} +
                                  + +
                                  +{% endblock %} +", "forms/fields/dateformat/dateformat.html.twig", "/mnt/data/Sites/static-ethica.net/user/plugins/admin/themes/grav/templates/forms/fields/dateformat/dateformat.html.twig"); + } +} diff --git a/cache/twig/64/643db05024d01591ea436850a24957db0f6bdb695d7633a6c9aa508503b2ecff.php b/cache/twig/64/643db05024d01591ea436850a24957db0f6bdb695d7633a6c9aa508503b2ecff.php new file mode 100644 index 0000000..c876a96 --- /dev/null +++ b/cache/twig/64/643db05024d01591ea436850a24957db0f6bdb695d7633a6c9aa508503b2ecff.php @@ -0,0 +1,132 @@ +parent = false; + + $this->blocks = array( + ); + } + + protected function doDisplay(array $context, array $blocks = array()) + { + // line 1 + $context["taxonomies"] = (((null === ($context["taxonomies"] ?? null))) ? ((($this->getAttribute(($context["field"] ?? null), "taxonomies", array())) ? ($this->getAttribute(($context["field"] ?? null), "taxonomies", array())) : ($this->getAttribute($this->getAttribute(($context["admin"] ?? null), "data", array(0 => "config/site"), "method"), "taxonomies", array())))) : (($context["taxonomies"] ?? null))); + // line 2 + $context["parentname"] = $this->getAttribute(($context["field"] ?? null), "name", array()); + // line 3 + echo " +"; + // line 4 + $context['_parent'] = $context; + $context['_seq'] = twig_ensure_traversable(($context["taxonomies"] ?? null)); + $context['loop'] = array( + 'parent' => $context['_parent'], + 'index0' => 0, + 'index' => 1, + 'first' => true, + ); + if (is_array($context['_seq']) || (is_object($context['_seq']) && $context['_seq'] instanceof Countable)) { + $length = count($context['_seq']); + $context['loop']['revindex0'] = $length - 1; + $context['loop']['revindex'] = $length; + $context['loop']['length'] = $length; + $context['loop']['last'] = 1 === $length; + } + foreach ($context['_seq'] as $context["_key"] => $context["name"]) { + // line 5 + echo " + "; + // line 6 + $context["value"] = $this->env->getExtension('Grav\Common\Twig\TwigExtension')->arrayFunc((($this->getAttribute(($context["data"] ?? null), "value", array(0 => ("header.taxonomy." . $context["name"])), "method", true, true)) ? (_twig_default_filter($this->getAttribute(($context["data"] ?? null), "value", array(0 => ("header.taxonomy." . $context["name"])), "method"), array())) : (array()))); + // line 7 + echo " "; + $context["sub_taxonomies"] = twig_get_array_keys_filter((($this->getAttribute($this->getAttribute($this->getAttribute(($context["grav"] ?? null), "taxonomy", array(), "any", false, true), "taxonomy", array(), "any", false, true), $context["name"], array(), "any", true, true)) ? (_twig_default_filter($this->getAttribute($this->getAttribute($this->getAttribute(($context["grav"] ?? null), "taxonomy", array(), "any", false, true), "taxonomy", array(), "any", false, true), $context["name"]), array())) : (array()))); + // line 8 + echo " "; + $context["list"] = array_unique(twig_array_merge(twig_array_merge(array(), ($context["sub_taxonomies"] ?? null)), ($context["value"] ?? null))); + // line 9 + echo " + "; + // line 10 + $context["field"] = array("type" => "select", "classes" => "fancy create", "label" => twig_capitalize_string_filter($this->env, // line 13 +$context["name"]), "name" => (( // line 14 +($context["parentname"] ?? null) . ".") . $context["name"]), "multiple" => true, "options" => // line 16 +($context["list"] ?? null), "style" => $this->getAttribute( // line 17 +($context["field"] ?? null), "style", array()), "selectize" => array("create" => true)); + // line 22 + echo " + "; + // line 23 + $this->loadTemplate(array(0 => "forms/fields/select/select.html.twig"), "forms/fields/taxonomy/taxonomy.html.twig", 23)->display($context); + ++$context['loop']['index0']; + ++$context['loop']['index']; + $context['loop']['first'] = false; + if (isset($context['loop']['length'])) { + --$context['loop']['revindex0']; + --$context['loop']['revindex']; + $context['loop']['last'] = 0 === $context['loop']['revindex0']; + } + } + $_parent = $context['_parent']; + unset($context['_seq'], $context['_iterated'], $context['_key'], $context['name'], $context['_parent'], $context['loop']); + $context = array_intersect_key($context, $_parent) + $_parent; + } + + public function getTemplateName() + { + return "forms/fields/taxonomy/taxonomy.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 66 => 23, 63 => 22, 61 => 17, 60 => 16, 59 => 14, 58 => 13, 57 => 10, 54 => 9, 51 => 8, 48 => 7, 46 => 6, 43 => 5, 26 => 4, 23 => 3, 21 => 2, 19 => 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 Twig_Source("{% set taxonomies = (taxonomies is null ? (field.taxonomies ? field.taxonomies : admin.data('config/site').taxonomies) : taxonomies) %} +{% set parentname = field.name %} + +{% for name in taxonomies %} + + {% set value = array(data.value('header.taxonomy.' ~ name)|default([])) %} + {% set sub_taxonomies = attribute(grav.taxonomy.taxonomy, name)|default([])|keys %} + {% set list = []|merge(sub_taxonomies)|merge(value)|array_unique %} + + {% set field = { + type: 'select', + classes: 'fancy create', + label: name|capitalize, + name: parentname ~ '.' ~ name, + multiple: true, + options: list, + style: field.style, + selectize: { + create: true + } + } %} + + {% include ['forms/fields/select/select.html.twig'] %} +{% endfor %} +", "forms/fields/taxonomy/taxonomy.html.twig", "/mnt/data/Sites/static-ethica.net/user/plugins/admin/themes/grav/templates/forms/fields/taxonomy/taxonomy.html.twig"); + } +} diff --git a/cache/twig/64/64c5de290a9459b388a2f97f9bcfa3df3957dd315894fd4d76d7fe152216b3dc.php b/cache/twig/64/64c5de290a9459b388a2f97f9bcfa3df3957dd315894fd4d76d7fe152216b3dc.php new file mode 100644 index 0000000..4db3713 --- /dev/null +++ b/cache/twig/64/64c5de290a9459b388a2f97f9bcfa3df3957dd315894fd4d76d7fe152216b3dc.php @@ -0,0 +1,507 @@ +parent = false; + + $this->blocks = array( + ); + } + + protected function doDisplay(array $context, array $blocks = array()) + { + // line 2 + $context["default"] = $this->getAttribute($this->getAttribute(($context["mediaembed"] ?? null), "config", array()), "media", array()); + // line 3 + $context["oembed"] = $this->getAttribute(($context["mediaembed"] ?? null), "service", array()); + // line 4 + echo " +"; + // line 6 + if ( !$this->getAttribute(($context["mediaembed"] ?? null), "success", array())) { + // line 7 + echo " "; + if ($this->getAttribute(($context["default"] ?? null), "responsive", array())) { + // line 8 + echo " "; + $context["class"] = "-responsive mediaembed-msod"; + // line 9 + echo " "; + } else { + // line 10 + echo " "; + $context["class"] = ((" mediaembed-msod\" style=\"max-width: " . $this->getAttribute(($context["default"] ?? null), "width", array())) . "px;"); + // line 11 + echo " "; + } + // line 12 + echo " + + +"; + } else { + // line 21 + echo " "; + $context["response"] = $this->getAttribute(($context["oembed"] ?? null), "attributes", array()); + // line 22 + echo " "; + // line 23 + echo " "; + if (((twig_test_empty($this->getAttribute(($context["response"] ?? null), "width", array())) || !$this->getAttribute(($context["response"] ?? null), "width", array(), "any", true, true)) || ($this->getAttribute(($context["response"] ?? null), "width", array()) == 0))) { + // line 24 + echo " "; + $context["response"] = twig_array_merge(($context["response"] ?? null), array("width" => (($this->getAttribute(($context["default"] ?? null), "width", array(), "any", true, true)) ? (_twig_default_filter($this->getAttribute(($context["default"] ?? null), "width", array()), 1)) : (1)))); + // line 25 + echo " "; + } + // line 26 + echo " + "; + // line 27 + if (((twig_test_empty($this->getAttribute(($context["response"] ?? null), "height", array())) || !$this->getAttribute(($context["response"] ?? null), "height", array(), "any", true, true)) || ($this->getAttribute(($context["response"] ?? null), "height", array()) == 0))) { + // line 28 + echo " "; + $context["response"] = twig_array_merge(($context["response"] ?? null), array("height" => (($this->getAttribute(($context["default"] ?? null), "height", array(), "any", true, true)) ? (_twig_default_filter($this->getAttribute(($context["default"] ?? null), "height", array()), 1)) : (1)))); + // line 29 + echo " "; + } + // line 30 + echo " + "; + // line 31 + $context["width"] = $this->getAttribute(($context["response"] ?? null), "width", array()); + // line 32 + echo " "; + $context["height"] = $this->getAttribute(($context["response"] ?? null), "height", array()); + // line 33 + echo " "; + $context["ratio"] = (($context["height"] ?? null) / ($context["width"] ?? null)); + // line 34 + echo " + "; + // line 36 + echo " "; + if ($this->getAttribute(($context["default"] ?? null), "adjust", array())) { + // line 37 + echo " "; + // line 38 + echo " "; + if ((((($context["width"] ?? null) * ($context["ratio"] ?? null)) > $this->getAttribute(($context["default"] ?? null), "height", array())) || ((($context["height"] ?? null) / ($context["ratio"] ?? null)) > $this->getAttribute(($context["default"] ?? null), "width", array())))) { + // line 39 + echo " "; + // line 40 + echo " "; + $context["width"] = (($this->getAttribute(($context["default"] ?? null), "width", array(), "any", true, true)) ? (_twig_default_filter($this->getAttribute(($context["default"] ?? null), "width", array()), 1)) : (1)); + // line 41 + echo " "; + $context["height"] = twig_round(($this->getAttribute(($context["default"] ?? null), "width", array()) * ($context["ratio"] ?? null))); + // line 42 + echo " "; + } + // line 43 + echo " "; + } else { + // line 44 + echo " "; + $context["width"] = (($this->getAttribute(($context["default"] ?? null), "width", array(), "any", true, true)) ? (_twig_default_filter($this->getAttribute(($context["default"] ?? null), "width", array()), 1)) : (1)); + // line 45 + echo " "; + $context["height"] = (($this->getAttribute(($context["default"] ?? null), "height", array(), "any", true, true)) ? (_twig_default_filter($this->getAttribute(($context["default"] ?? null), "height", array()), 1)) : (1)); + // line 46 + echo " "; + } + // line 47 + echo " + "; + // line 49 + echo " "; + $context["ratio"] = (($context["height"] ?? null) / ($context["width"] ?? null)); + // line 50 + echo " "; + $context["container_styles"] = (("padding-bottom: " . sprintf("%.2f", (($context["ratio"] ?? null) * 100))) . "%;"); + // line 51 + echo " + "; + // line 53 + echo " "; + if ($this->getAttribute(($context["default"] ?? null), "responsive", array())) { + // line 54 + echo " "; + $context["responsive"] = "-responsive"; + // line 55 + echo " + "; + // line 56 + $context["width"] = 1920; + // line 57 + echo " "; + $context["height"] = twig_round((($context["width"] ?? null) * ($context["ratio"] ?? null))); + // line 58 + echo " "; + } else { + // line 59 + echo " "; + $context["styles"] = ((((" style=\"max-width: " . ($context["width"] ?? null)) . "px; max-height: ") . ($context["height"] ?? null)) . "px;\""); + // line 60 + echo " "; + } + // line 61 + echo " + "; + // line 63 + echo " "; + if ($this->getAttribute(($context["default"] ?? null), "preview", array())) { + // line 64 + echo " "; + $context["lazyload"] = " lazyload"; + // line 65 + echo " "; + $context["lazyload_script"] = " onclick=\"lazyload(this)\""; + // line 66 + echo " "; + } + // line 67 + echo " +
                                  getAttribute(($context["oembed"] ?? null), "type", array()); + echo " mediaembed-"; + echo twig_lower_filter($this->env, $this->getAttribute(($context["oembed"] ?? null), "name", array())); + echo ($context["lazyload"] ?? null); + echo "\""; + echo ($context["styles"] ?? null); + echo "> +
                                  + "; + // line 71 + echo " + "; + // line 73 + echo " "; + if (($this->getAttribute(($context["oembed"] ?? null), "type", array()) == "photo")) { + // line 74 + echo " "; + $context["title"] = (((($this->getAttribute($this->getAttribute(($context["oembed"] ?? null), "getOembed", array(), "method"), "provider_name", array()) . ": “") . $this->getAttribute(($context["oembed"] ?? null), "title", array())) . "” by ") . $this->getAttribute(($context["oembed"] ?? null), "author", array())); + // line 75 + echo " getAttribute(($context["oembed"] ?? null), "author", array(0 => "url"), "method"); + echo "\" title=\""; + echo ($context["title"] ?? null); + echo "\"> + getAttribute(($context["oembed"] ?? null), "url", array()); + echo "\" alt=\""; + echo $this->getAttribute(($context["oembed"] ?? null), "title", array()); + echo "\"> + + + "; + // line 80 + echo " "; + } elseif (($this->getAttribute(($context["oembed"] ?? null), "type", array()) == "video")) { + // line 81 + echo " getAttribute(($context["oembed"] ?? null), "getEmbedCode", array()); + echo "\" alt=\""; + echo $this->getAttribute($this->getAttribute(($context["mediaembed"] ?? null), "raw", array()), "alt", array()); + echo "\" title=\""; + echo $this->getAttribute($this->getAttribute(($context["mediaembed"] ?? null), "raw", array()), "title", array()); + echo "\" class=\"mediaembed-media\""; + echo ($context["lazyload_script"] ?? null); + echo "> + "; + // line 83 + echo " + + "; + // line 90 + echo " "; + if (($this->getAttribute(($context["default"] ?? null), "preview", array()) && $this->getAttribute(($context["oembed"] ?? null), "thumbnail", array()))) { + // line 91 + echo " getAttribute(($context["oembed"] ?? null), "thumbnail", array()); + echo "\" alt=\""; + echo $this->getAttribute($this->getAttribute(($context["mediaembed"] ?? null), "raw", array()), "alt", array()); + echo "\" title=\""; + echo $this->getAttribute($this->getAttribute(($context["mediaembed"] ?? null), "raw", array()), "title", array()); + echo "\" class=\"mediaembed-thumbnail\" /> + "; + } else { + // line 93 + echo " "; + // line 94 + echo " "; + } + // line 95 + echo " + "; + // line 97 + echo " getAttribute(($context["mediaembed"] ?? null), "uid", array()); + echo "\" class=\"mediaembed-input\" /> + + "; + // line 100 + echo " + + + + + "; + // line 110 + echo " "; + } elseif (($this->getAttribute(($context["oembed"] ?? null), "type", array()) == "link")) { + // line 111 + echo " "; + $context["title"] = (((($this->getAttribute($this->getAttribute(($context["oembed"] ?? null), "getOembed", array(), "method"), "provider_name", array()) . ": “") . (($this->getAttribute($this->getAttribute($this->getAttribute(($context["oembed"] ?? null), "mediaembed", array(), "any", false, true), "raw", array(), "any", false, true), "title", array(), "any", true, true)) ? (_twig_default_filter($this->getAttribute($this->getAttribute($this->getAttribute(($context["oembed"] ?? null), "mediaembed", array(), "any", false, true), "raw", array(), "any", false, true), "title", array()), ($context["title"] ?? null))) : (($context["title"] ?? null)))) . "” by ") . $this->getAttribute(($context["oembed"] ?? null), "author", array())); + // line 112 + echo " getAttribute($this->getAttribute(($context["mediaembed"] ?? null), "raw", array()), "src", array()); + echo "\" alt=\""; + echo $this->getAttribute($this->getAttribute(($context["mediaembed"] ?? null), "raw", array()), "alt", array()); + echo "\" title=\""; + echo ($context["title"] ?? null); + echo "\">"; + echo twig_escape_filter($this->env, $this->getAttribute($this->getAttribute(($context["mediaembed"] ?? null), "raw", array()), "src", array())); + echo " + "; + // line 114 + echo " "; + } elseif (($this->getAttribute(($context["oembed"] ?? null), "type", array()) == "rich")) { + // line 115 + echo "
                                  "; + echo $this->getAttribute(($context["oembed"] ?? null), "getEmbedCode", array(), "method"); + echo "
                                  + + "; + // line 118 + echo " "; + } else { + // line 119 + echo " "; + // line 120 + echo " getAttribute($this->getAttribute(($context["mediaembed"] ?? null), "raw", array()), "src", array()); + echo "\" alt=\""; + echo $this->getAttribute($this->getAttribute(($context["mediaembed"] ?? null), "raw", array()), "alt", array()); + echo "\" title=\""; + echo $this->getAttribute($this->getAttribute(($context["mediaembed"] ?? null), "raw", array()), "title", array()); + echo "\">"; + echo twig_escape_filter($this->env, $this->getAttribute($this->getAttribute(($context["mediaembed"] ?? null), "raw", array()), "src", array())); + echo " + "; + } + // line 122 + echo "
                                  +
                                  +"; + } + } + + public function getTemplateName() + { + return "partials/mediaembed.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 350 => 122, 338 => 120, 336 => 119, 333 => 118, 327 => 115, 324 => 114, 313 => 112, 310 => 111, 307 => 110, 301 => 106, 289 => 101, 286 => 100, 280 => 97, 277 => 95, 274 => 94, 272 => 93, 262 => 91, 259 => 90, 247 => 84, 244 => 83, 233 => 81, 230 => 80, 222 => 76, 215 => 75, 212 => 74, 209 => 73, 206 => 71, 202 => 69, 191 => 68, 188 => 67, 185 => 66, 182 => 65, 179 => 64, 176 => 63, 173 => 61, 170 => 60, 167 => 59, 164 => 58, 161 => 57, 159 => 56, 156 => 55, 153 => 54, 150 => 53, 147 => 51, 144 => 50, 141 => 49, 138 => 47, 135 => 46, 132 => 45, 129 => 44, 126 => 43, 123 => 42, 120 => 41, 117 => 40, 115 => 39, 112 => 38, 110 => 37, 107 => 36, 104 => 34, 101 => 33, 98 => 32, 96 => 31, 93 => 30, 90 => 29, 87 => 28, 85 => 27, 82 => 26, 79 => 25, 76 => 24, 73 => 23, 71 => 22, 68 => 21, 61 => 16, 51 => 15, 46 => 13, 43 => 12, 40 => 11, 37 => 10, 34 => 9, 31 => 8, 28 => 7, 26 => 6, 23 => 4, 21 => 3, 19 => 2,); + } + + /** @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 Twig_Source("{# Shortcut variables #} +{% set default = mediaembed.config.media %} +{% set oembed = mediaembed.service %} + +{# Processing error #} +{% if not mediaembed.success %} + {% if default.responsive %} + {% set class = \"-responsive mediaembed-msod\" %} + {% else %} + {% set class = \" mediaembed-msod\\\" style=\\\"max-width: \" ~ default.width ~ \"px;\" %} + {% endif %} + +
                                  +

                                  +

                                  Unable to process oEmbed media:{{ mediaembed.raw.src|e }}

                                  +

                                  Error:{{ mediaembed.message }}

                                  +
                                  + +{# Setup block #} +{% else %} + {% set response = oembed.attributes %} + {# Normalize response #} + {% if (response.width is empty) or not (response.width is defined) or (response.width == 0) %} + {% set response = response|merge({'width' : default.width|default(1)}) %} + {% endif %} + + {% if (response.height is empty) or not (response.height is defined) or (response.height == 0) %} + {% set response = response|merge({'height' : default.height|default(1)}) %} + {% endif %} + + {% set width = response.width %} + {% set height = response.height %} + {% set ratio = height / width %} + + {# Adjust OEmbed media dimensions or restrict them? #} + {% if default.adjust %} + {# Check if computed height is larger than default setting #} + {% if (width * ratio) > default.height or (height / ratio) > default.width %} + {# Rescale width and height #} + {% set width = default.width|default(1) %} + {% set height = (default.width * ratio)|round %} + {% endif %} + {% else %} + {% set width = default.width|default(1) %} + {% set height = default.height|default(1) %} + {% endif %} + + {# Recompute aspect ratio #} + {% set ratio = height / width %} + {% set container_styles = \"padding-bottom: \" ~ \"%.2f\"|format(ratio * 100) ~ \"%;\" %} + + {# Embed responsive OEmbed media #} + {% if default.responsive %} + {% set responsive = \"-responsive\" %} + + {% set width = 1920 %} + {% set height = (width * ratio)|round %} + {% else %} + {% set styles = \" style=\\\"max-width: \" ~ width ~ \"px; max-height: \" ~ height ~ \"px;\\\"\" %} + {% endif %} + + {# Setup lazy loading media for those with preview enabled #} + {% if default.preview %} + {% set lazyload = \" lazyload\" %} + {% set lazyload_script = \" onclick=\\\"lazyload(this)\\\"\" %} + {% endif %} + +
                                  +
                                  + {# Embed content according to media type #} + + {# -- Photo -- #} + {% if oembed.type == \"photo\" %} + {% set title = oembed.getOembed().provider_name ~ ': “' ~ oembed.title ~ '” by ' ~ oembed.author %} + + \"{{ + + + {# -- Video -- #} + {% elseif oembed.type == \"video\" %} + + {# JavaScript lazy-loading #} + + + {# Show Thumbnail #} + {% if default.preview and oembed.thumbnail %} + \"{{ + {% else %} + {# Show placeholder #} + {% endif %} + + {# Toggle for loading iframe content #} + + + {# Implement JavaScript-less lazyload technique #} + + + + + + {# -- Link -- #} + {% elseif oembed.type == \"link\" %} + {% set title = oembed.getOembed().provider_name ~ ': “' ~ oembed.mediaembed.raw.title|default(title) ~ '” by ' ~ oembed.author %} + {{ mediaembed.raw.src|e }} + {# -- Rich media -- #} + {% elseif oembed.type == \"rich\" %} +
                                  {{ oembed.getEmbedCode() }}
                                  + + {# -- Nothing from above -- #} + {% else %} + {# Show at least a link for the user #} + {{ mediaembed.raw.src|e }} + {% endif %} +
                                  +
                                  +{% endif %} +", "partials/mediaembed.html.twig", "/home/kevin/Sites/static-ethica.net/user/plugins/mediaembed/templates/partials/mediaembed.html.twig"); + } +} diff --git a/cache/twig/65/654ab5d63cb06d78d96dd05f667cd17631eeeeb935b913c995f482043c31c0af.php b/cache/twig/65/654ab5d63cb06d78d96dd05f667cd17631eeeeb935b913c995f482043c31c0af.php new file mode 100644 index 0000000..c0e238e --- /dev/null +++ b/cache/twig/65/654ab5d63cb06d78d96dd05f667cd17631eeeeb935b913c995f482043c31c0af.php @@ -0,0 +1,211 @@ +parent = false; + + $this->blocks = array( + ); + } + + protected function doDisplay(array $context, array $blocks = array()) + { + // line 1 + $context["form_id"] = ((($context["form_id"] ?? null)) ? (($context["form_id"] ?? null)) : ("blueprints")); + // line 2 + $context["scope"] = ((($context["scope"] ?? null)) ? (($context["scope"] ?? null)) : ("data.")); + // line 3 + echo " +"; + // line 4 + if ($this->getAttribute(($context["admin"] ?? null), "findFormFields", array(0 => "file", 1 => $this->getAttribute(($context["blueprints"] ?? null), "fields", array())), "method")) { + // line 5 + echo " "; + $context["multipart"] = " enctype=\"multipart/form-data\""; + } + // line 7 + echo " +
                                  env, ($context["form_id"] ?? null), "html", null, true); + echo "\" method=\"post\" data-grav-form=\""; + echo twig_escape_filter($this->env, ($context["form_id"] ?? null), "html", null, true); + echo "\" data-grav-keepalive=\"true\""; + echo ($context["multipart"] ?? null); + echo "> + "; + // line 9 + $context['_parent'] = $context; + $context['_seq'] = twig_ensure_traversable($this->getAttribute(($context["blueprints"] ?? null), "fields", array())); + $context['loop'] = array( + 'parent' => $context['_parent'], + 'index0' => 0, + 'index' => 1, + 'first' => true, + ); + if (is_array($context['_seq']) || (is_object($context['_seq']) && $context['_seq'] instanceof Countable)) { + $length = count($context['_seq']); + $context['loop']['revindex0'] = $length - 1; + $context['loop']['revindex'] = $length; + $context['loop']['length'] = $length; + $context['loop']['last'] = 1 === $length; + } + foreach ($context['_seq'] as $context["_key"] => $context["field"]) { + // line 10 + echo " "; + if ($this->getAttribute($context["field"], "type", array())) { + // line 11 + echo " "; + $context["value"] = (($this->getAttribute($context["field"], "name", array())) ? ($this->getAttribute(($context["data"] ?? null), "value", array(0 => $this->getAttribute($context["field"], "name", array())), "method")) : ($this->getAttribute(($context["data"] ?? null), "toArray", array()))); + // line 12 + echo "
                                  env, $this->getAttribute($context["field"], "type", array()), "html", null, true); + echo "\"> + "; + // line 13 + $this->loadTemplate(array(0 => (((("forms/fields/" . $this->getAttribute($context["field"], "type", array())) . "/") . $this->getAttribute($context["field"], "type", array())) . ".html.twig"), 1 => "forms/fields/text/text.html.twig"), "partials/blueprints.html.twig", 13)->display($context); + // line 14 + echo "
                                  + "; + } + // line 16 + echo " "; + ++$context['loop']['index0']; + ++$context['loop']['index']; + $context['loop']['first'] = false; + if (isset($context['loop']['length'])) { + --$context['loop']['revindex0']; + --$context['loop']['revindex']; + $context['loop']['last'] = 0 === $context['loop']['revindex0']; + } + } + $_parent = $context['_parent']; + unset($context['_seq'], $context['_iterated'], $context['_key'], $context['field'], $context['_parent'], $context['loop']); + $context = array_intersect_key($context, $_parent) + $_parent; + // line 17 + echo " + "; + // line 18 + if ($this->getAttribute(($context["data"] ?? null), "extra", array())) { + // line 19 + echo " "; + $context['_parent'] = $context; + $context['_seq'] = twig_ensure_traversable($this->getAttribute(($context["data"] ?? null), "extra", array())); + $context['loop'] = array( + 'parent' => $context['_parent'], + 'index0' => 0, + 'index' => 1, + 'first' => true, + ); + if (is_array($context['_seq']) || (is_object($context['_seq']) && $context['_seq'] instanceof Countable)) { + $length = count($context['_seq']); + $context['loop']['revindex0'] = $length - 1; + $context['loop']['revindex'] = $length; + $context['loop']['length'] = $length; + $context['loop']['last'] = 1 === $length; + } + foreach ($context['_seq'] as $context["name"] => $context["value"]) { + // line 20 + echo " "; + if (!twig_in_filter($context["name"], array(0 => "_json", 1 => "task", 2 => "admin-nonce"))) { + // line 21 + echo " "; + $context["field"] = array("name" => ("_json." . $context["name"])); + // line 22 + echo " "; + $context["value"] = twig_jsonencode_filter($context["value"]); + // line 23 + echo " "; + $this->loadTemplate("forms/fields/hidden/hidden.html.twig", "partials/blueprints.html.twig", 23)->display($context); + // line 24 + echo " "; + } + // line 25 + echo " "; + ++$context['loop']['index0']; + ++$context['loop']['index']; + $context['loop']['first'] = false; + if (isset($context['loop']['length'])) { + --$context['loop']['revindex0']; + --$context['loop']['revindex']; + $context['loop']['last'] = 0 === $context['loop']['revindex0']; + } + } + $_parent = $context['_parent']; + unset($context['_seq'], $context['_iterated'], $context['name'], $context['value'], $context['_parent'], $context['loop']); + $context = array_intersect_key($context, $_parent) + $_parent; + // line 26 + echo " "; + } + // line 27 + echo " + "; + // line 28 + echo $this->env->getExtension('Grav\Common\Twig\TwigExtension')->nonceFieldFunc("admin-form", "admin-nonce"); + echo " +
                                  +"; + } + + public function getTemplateName() + { + return "partials/blueprints.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 149 => 28, 146 => 27, 143 => 26, 129 => 25, 126 => 24, 123 => 23, 120 => 22, 117 => 21, 114 => 20, 96 => 19, 94 => 18, 91 => 17, 77 => 16, 73 => 14, 71 => 13, 66 => 12, 63 => 11, 60 => 10, 43 => 9, 35 => 8, 32 => 7, 28 => 5, 26 => 4, 23 => 3, 21 => 2, 19 => 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 Twig_Source("{% set form_id = form_id ? form_id : 'blueprints' %} +{% set scope = scope ?: 'data.' %} + +{% if admin.findFormFields('file', blueprints.fields) %} + {% set multipart = ' enctype=\"multipart/form-data\"' %} +{% endif %} + +
                                  + {% for field in blueprints.fields %} + {% if field.type %} + {% set 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 %} + + {% if data.extra %} + {% for name, value in data.extra %} + {% if name not in ['_json','task','admin-nonce'] %} + {% set field = {name: '_json.' ~ name} %} + {% set value = value|raw|json_encode %} + {% include 'forms/fields/hidden/hidden.html.twig' %} + {% endif %} + {% endfor %} + {% endif %} + + {{ nonce_field('admin-form', 'admin-nonce')|raw }} +
                                  +", "partials/blueprints.html.twig", "/mnt/data/Sites/static-ethica.net/user/plugins/admin/themes/grav/templates/partials/blueprints.html.twig"); + } +} diff --git a/cache/twig/67/676f23a260cefd0edb3db208e1e2801ebcc5ceb7190f1d999a2e7007da65b5c4.php b/cache/twig/67/676f23a260cefd0edb3db208e1e2801ebcc5ceb7190f1d999a2e7007da65b5c4.php new file mode 100644 index 0000000..c3b466a --- /dev/null +++ b/cache/twig/67/676f23a260cefd0edb3db208e1e2801ebcc5ceb7190f1d999a2e7007da65b5c4.php @@ -0,0 +1,128 @@ +parent = false; + + $this->blocks = array( + 'content' => array($this, 'block_content'), + ); + } + + protected function doDisplay(array $context, array $blocks = array()) + { + // line 2 + echo " + "; + // line 3 + $this->displayBlock('content', $context, $blocks); + } + + public function block_content($context, array $blocks = array()) + { + // line 4 + echo "
                                  +

                                  "; + // line 5 + echo $this->getAttribute(($context["header"] ?? null), "title", array()); + echo "

                                  + "; + // line 6 + echo $this->getAttribute(($context["page"] ?? null), "content", array()); + echo " +
                                  + "; + // line 8 + $context['_parent'] = $context; + $context['_seq'] = twig_ensure_traversable($this->getAttribute(($context["page"] ?? null), "collection", array(), "method")); + foreach ($context['_seq'] as $context["_key"] => $context["module"]) { + // line 9 + echo "
                                  getAttribute($this, "pageLinkName", array(0 => $this->getAttribute($context["module"], "folder", array())), "method"); + echo "\" class=\"mutli-column\"> + "; + // line 10 + echo $this->getAttribute($context["module"], "content", array()); + echo " +
                                  + "; + } + $_parent = $context['_parent']; + unset($context['_seq'], $context['_iterated'], $context['_key'], $context['module'], $context['_parent'], $context['loop']); + $context = array_intersect_key($context, $_parent) + $_parent; + // line 13 + echo " "; + } + + // line 1 + public function getpageLinkName($__text__ = null, ...$__varargs__) + { + $context = $this->env->mergeGlobals(array( + "text" => $__text__, + "varargs" => $__varargs__, + )); + + $blocks = array(); + + ob_start(); + try { + echo twig_replace_filter(twig_lower_filter($this->env, ($context["text"] ?? null)), array("01._" => "", "02._" => "", "03._" => "", "04._" => "", "05._" => "", "06._" => "", "07._" => "", "08._" => "", "09._" => "")); + } catch (Exception $e) { + ob_end_clean(); + + throw $e; + } catch (Throwable $e) { + ob_end_clean(); + + throw $e; + } + + return ('' === $tmp = ob_get_clean()) ? '' : new Twig_Markup($tmp, $this->env->getCharset()); + } + + public function getTemplateName() + { + return "modular/contenu-multi.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 63 => 1, 59 => 13, 50 => 10, 45 => 9, 41 => 8, 36 => 6, 32 => 5, 29 => 4, 23 => 3, 20 => 2,); + } + + /** @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 Twig_Source("{% macro pageLinkName(text) %}{{ text|lower|replace({'01._':'','02._':'','03._':'','04._':'','05._':'','06._':'','07._':'','08._':'','09._':''}) }}{% endmacro %} + + {% block content %} +
                                  +

                                  {{ header.title }}

                                  + {{ page.content }} +
                                  + {% for module in page.collection() %} +
                                  + {{ module.content }} +
                                  + {% endfor %} + {% endblock %} +", "modular/contenu-multi.html.twig", "/home/kevin/Sites/static-ethica.net/user/themes/ethica/templates/modular/contenu-multi.html.twig"); + } +} diff --git a/cache/twig/68/68556e0c0fe68c1a072bb7bef8f2c4e36532e88e2189d5aed3dc55ea40fc61f2.php b/cache/twig/68/68556e0c0fe68c1a072bb7bef8f2c4e36532e88e2189d5aed3dc55ea40fc61f2.php new file mode 100644 index 0000000..8aa6fae --- /dev/null +++ b/cache/twig/68/68556e0c0fe68c1a072bb7bef8f2c4e36532e88e2189d5aed3dc55ea40fc61f2.php @@ -0,0 +1,146 @@ +parent = false; + + $this->blocks = array( + ); + } + + protected function doDisplay(array $context, array $blocks = array()) + { + // line 1 + $context["form_id"] = ((($context["form_id"] ?? null)) ? (($context["form_id"] ?? null)) : ("blueprints")); + // line 2 + $context["scope"] = ((($context["scope"] ?? null)) ? (($context["scope"] ?? null)) : ("data.")); + // line 3 + echo " +
                                  env, ($context["form_id"] ?? null), "html", null, true); + echo "\" method=\"post\" data-grav-form=\""; + echo twig_escape_filter($this->env, ($context["form_id"] ?? null), "html", null, true); + echo "\" data-grav-keepalive=\"true\"> + "; + // line 5 + $context['_parent'] = $context; + $context['_seq'] = twig_ensure_traversable($this->getAttribute(($context["blueprints"] ?? null), "fields", array())); + $context['loop'] = array( + 'parent' => $context['_parent'], + 'index0' => 0, + 'index' => 1, + 'first' => true, + ); + if (is_array($context['_seq']) || (is_object($context['_seq']) && $context['_seq'] instanceof Countable)) { + $length = count($context['_seq']); + $context['loop']['revindex0'] = $length - 1; + $context['loop']['revindex'] = $length; + $context['loop']['length'] = $length; + $context['loop']['last'] = 1 === $length; + } + foreach ($context['_seq'] as $context["_key"] => $context["field"]) { + // line 6 + echo " "; + if ($this->getAttribute($context["field"], "type", array())) { + // line 7 + echo " "; + $context["value"] = (($this->getAttribute($context["field"], "name", array())) ? ($this->getAttribute(($context["data"] ?? null), "value", array(0 => $this->getAttribute($context["field"], "name", array())), "method")) : ($this->getAttribute(($context["data"] ?? null), "toArray", array()))); + // line 8 + echo "
                                  env, $this->getAttribute($context["field"], "type", array()), "html", null, true); + echo "\"> + "; + // line 9 + $this->loadTemplate(array(0 => (((("forms/fields/" . $this->getAttribute($context["field"], "type", array())) . "/") . $this->getAttribute($context["field"], "type", array())) . ".html.twig"), 1 => "forms/fields/text/text.html.twig"), "partials/blueprints-new-folder.html.twig", 9)->display($context); + // line 10 + echo "
                                  + "; + } + // line 12 + echo " "; + ++$context['loop']['index0']; + ++$context['loop']['index']; + $context['loop']['first'] = false; + if (isset($context['loop']['length'])) { + --$context['loop']['revindex0']; + --$context['loop']['revindex']; + $context['loop']['last'] = 0 === $context['loop']['revindex0']; + } + } + $_parent = $context['_parent']; + unset($context['_seq'], $context['_iterated'], $context['_key'], $context['field'], $context['_parent'], $context['loop']); + $context = array_intersect_key($context, $_parent) + $_parent; + // line 13 + echo " + +
                                  + +
                                  + + "; + // line 19 + echo $this->env->getExtension('Grav\Common\Twig\TwigExtension')->nonceFieldFunc("admin-form", "admin-nonce"); + echo " + +
                                  +"; + } + + public function getTemplateName() + { + return "partials/blueprints-new-folder.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 91 => 19, 85 => 16, 80 => 13, 66 => 12, 62 => 10, 60 => 9, 55 => 8, 52 => 7, 49 => 6, 32 => 5, 26 => 4, 23 => 3, 21 => 2, 19 => 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 Twig_Source("{% set form_id = form_id ? form_id : 'blueprints' %} +{% set scope = scope ?: 'data.' %} + +
                                  + {% for field in blueprints.fields %} + {% if field.type %} + {% set 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 %} + + +
                                  + +
                                  + + {{ nonce_field('admin-form', 'admin-nonce')|raw }} + +
                                  +", "partials/blueprints-new-folder.html.twig", "/mnt/data/Sites/static-ethica.net/user/plugins/admin/themes/grav/templates/partials/blueprints-new-folder.html.twig"); + } +} diff --git a/cache/twig/6e/6e2b4f6ad25cdff6a0326eb019d85dc7d7a8ea03b9c2473ceffe49bd98a749d0.php b/cache/twig/6e/6e2b4f6ad25cdff6a0326eb019d85dc7d7a8ea03b9c2473ceffe49bd98a749d0.php new file mode 100644 index 0000000..1a580e4 --- /dev/null +++ b/cache/twig/6e/6e2b4f6ad25cdff6a0326eb019d85dc7d7a8ea03b9c2473ceffe49bd98a749d0.php @@ -0,0 +1,375 @@ +parent = $this->loadTemplate("partials/base.html.twig", "config.html.twig", 1); + $this->blocks = array( + 'stylesheets' => array($this, 'block_stylesheets'), + 'javascripts' => array($this, 'block_javascripts'), + 'titlebar' => array($this, 'block_titlebar'), + 'content_top' => array($this, 'block_content_top'), + 'content' => array($this, 'block_content'), + ); + } + + protected function doGetParent(array $context) + { + return "partials/base.html.twig"; + } + + protected function doDisplay(array $context, array $blocks = array()) + { + // line 3 + $context["config_slug"] = twig_escape_filter($this->env, $this->getAttribute(($context["uri"] ?? null), "basename", array())); + // line 4 + $context["isInfo"] = (($context["config_slug"] ?? null) == "info"); + // line 6 + $context["tab_title_string"] = ("PLUGIN_ADMIN." . twig_upper_filter($this->env, ($context["config_slug"] ?? null))); + // line 7 + $context["tab_title"] = ((($this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter(($context["tab_title_string"] ?? null)) == ($context["tab_title_string"] ?? null))) ? (twig_capitalize_string_filter($this->env, ($context["config_slug"] ?? null))) : ($this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter(($context["tab_title_string"] ?? null)))); + // line 8 + $context["title"] = (($this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.CONFIGURATION") . ": ") . ($context["tab_title"] ?? null)); + // line 10 + if ( !($context["isInfo"] ?? null)) { + // line 11 + $context["data"] = $this->getAttribute(($context["admin"] ?? null), "data", array(0 => ("config/" . ($context["config_slug"] ?? null))), "method"); + } + // line 1 + $this->parent->display($context, array_merge($this->blocks, $blocks)); + } + + // line 14 + public function block_stylesheets($context, array $blocks = array()) + { + // line 15 + echo " "; + $this->getAttribute(($context["assets"] ?? null), "addCss", array(0 => (($context["theme_url"] ?? null) . "/css/codemirror/codemirror.css")), "method"); + // line 16 + echo " "; + $this->displayParentBlock("stylesheets", $context, $blocks); + echo " +"; + } + + // line 19 + public function block_javascripts($context, array $blocks = array()) + { + // line 20 + echo " "; + $this->displayParentBlock("javascripts", $context, $blocks); + echo " +"; + } + + // line 23 + public function block_titlebar($context, array $blocks = array()) + { + // line 24 + echo "
                                  + env, ($context["base_url"] ?? null), "html", null, true); + echo "\"> "; + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.BACK"), "html", null, true); + echo " + "; + // line 26 + if ($this->getAttribute($this->getAttribute(($context["data"] ?? null), "file", array()), "filename", array())) { + // line 27 + echo " + "; + } + // line 29 + echo "
                                  +

                                  "; + // line 30 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.CONFIGURATION"), "html", null, true); + echo " - "; + echo twig_escape_filter($this->env, ($context["tab_title"] ?? null), "html", null, true); + echo "

                                  +"; + } + + // line 33 + public function block_content_top($context, array $blocks = array()) + { + // line 34 + echo " "; + if ($this->getAttribute($this->getAttribute(($context["data"] ?? null), "file", array()), "filename", array())) { + // line 35 + echo "
                                  "; + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.SAVE_LOCATION"), "html", null, true); + echo ": "; + echo twig_escape_filter($this->env, twig_replace_filter($this->getAttribute($this->getAttribute(($context["data"] ?? null), "file", array()), "filename", array()), array(($context["base_path"] ?? null) => "")), "html", null, true); + echo "
                                  + "; + } + // line 37 + echo " +
                                  +
                                  + + "; + // line 41 + if ($this->env->getExtension('Grav\Common\Twig\TwigExtension')->authorize(array(0 => "admin.configuration_system", 1 => "admin.super"))) { + // line 42 + echo " env, ($context["base_url_relative"] ?? null), "html", null, true); + echo "/config/system\"> + "; + // line 43 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.SYSTEM"), "html", null, true); + echo " + + "; + } + // line 46 + echo " + "; + // line 47 + if ($this->env->getExtension('Grav\Common\Twig\TwigExtension')->authorize(array(0 => "admin.configuration_site", 1 => "admin.super"))) { + // line 48 + echo " env, ($context["base_url_relative"] ?? null), "html", null, true); + echo "/config/site\"> + "; + // line 49 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.SITE"), "html", null, true); + echo " + + "; + } + // line 52 + echo " + "; + // line 53 + $context['_parent'] = $context; + $context['_seq'] = twig_ensure_traversable($this->getAttribute(($context["admin"] ?? null), "configurations", array())); + foreach ($context['_seq'] as $context["_key"] => $context["configuration"]) { + // line 54 + echo " "; + if ($this->env->getExtension('Grav\Common\Twig\TwigExtension')->authorize(array(0 => ("admin.configuration_" . $context["configuration"]), 1 => "admin.super"))) { + // line 55 + echo " "; + $context["current_blueprints"] = $this->getAttribute($this->getAttribute($this->getAttribute(($context["admin"] ?? null), "data", array(0 => ("config/" . $context["configuration"])), "method"), "blueprints", array()), "toArray", array(), "method"); + // line 56 + echo " "; + if ((((($context["configuration"] != "system") && ($context["configuration"] != "site")) && !$this->getAttribute($this->getAttribute(($context["current_blueprints"] ?? null), "form", array()), "hidden", array())) && ( !twig_test_empty($this->getAttribute($this->getAttribute(($context["current_blueprints"] ?? null), "form", array()), "fields", array())) || !twig_test_empty($this->getAttribute($this->getAttribute(($context["current_blueprints"] ?? null), "form", array()), "field", array()))))) { + // line 57 + echo " env, ($context["base_url_relative"] ?? null), "html", null, true); + echo "/config/"; + echo twig_escape_filter($this->env, $context["configuration"], "html", null, true); + echo "\"> + "; + // line 58 + $context["configuration_string"] = ("PLUGIN_ADMIN." . twig_upper_filter($this->env, $context["configuration"])); + // line 59 + echo " "; + echo twig_escape_filter($this->env, ((($this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter(($context["configuration_string"] ?? null)) == ($context["configuration_string"] ?? null))) ? (twig_capitalize_string_filter($this->env, $context["configuration"])) : ($this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter(($context["configuration_string"] ?? null)))), "html", null, true); + echo " + + "; + } + // line 62 + echo " "; + } + // line 63 + echo " "; + } + $_parent = $context['_parent']; + unset($context['_seq'], $context['_iterated'], $context['_key'], $context['configuration'], $context['_parent'], $context['loop']); + $context = array_intersect_key($context, $_parent) + $_parent; + // line 64 + echo " + "; + // line 65 + if ($this->env->getExtension('Grav\Common\Twig\TwigExtension')->authorize(array(0 => "admin.configuration_info", 1 => "admin.super"))) { + // line 66 + echo " env, ($context["base_url_relative"] ?? null), "html", null, true); + echo "/config/info\"> + "; + // line 67 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.INFO"), "html", null, true); + echo " + + "; + } + // line 70 + echo " +
                                  +
                                  +"; + } + + // line 75 + public function block_content($context, array $blocks = array()) + { + // line 76 + echo " "; + if ($this->env->getExtension('Grav\Common\Twig\TwigExtension')->authorize(array(0 => ("admin.configuration_" . ($context["config_slug"] ?? null)), 1 => "admin.super"))) { + // line 77 + echo " "; + if (($context["isInfo"] ?? null)) { + // line 78 + echo "
                                  + "; + // line 79 + echo $this->getAttribute(($context["admin"] ?? null), "phpinfo", array()); + echo " +
                                  + "; + } else { + // line 82 + echo " "; + $this->loadTemplate("partials/blueprints.html.twig", "config.html.twig", 82)->display(array_merge($context, array("blueprints" => $this->getAttribute(($context["data"] ?? null), "blueprints", array()), "data" => ($context["data"] ?? null)))); + // line 83 + echo " "; + } + // line 84 + echo " "; + } + // line 85 + echo " "; + $this->loadTemplate("partials/modal-changes-detected.html.twig", "config.html.twig", 85)->display($context); + } + + public function getTemplateName() + { + return "config.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 258 => 85, 255 => 84, 252 => 83, 249 => 82, 243 => 79, 240 => 78, 237 => 77, 234 => 76, 231 => 75, 224 => 70, 218 => 67, 209 => 66, 207 => 65, 204 => 64, 198 => 63, 195 => 62, 188 => 59, 186 => 58, 175 => 57, 172 => 56, 169 => 55, 166 => 54, 162 => 53, 159 => 52, 153 => 49, 144 => 48, 142 => 47, 139 => 46, 133 => 43, 124 => 42, 122 => 41, 116 => 37, 108 => 35, 105 => 34, 102 => 33, 94 => 30, 91 => 29, 85 => 27, 83 => 26, 77 => 25, 74 => 24, 71 => 23, 64 => 20, 61 => 19, 54 => 16, 51 => 15, 48 => 14, 44 => 1, 41 => 11, 39 => 10, 37 => 8, 35 => 7, 33 => 6, 31 => 4, 29 => 3, 11 => 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 Twig_Source("{% extends 'partials/base.html.twig' %} + +{% set config_slug = uri.basename|e %} +{% set isInfo = (config_slug == 'info') %} + +{% set tab_title_string = \"PLUGIN_ADMIN.\" ~ config_slug|upper %} +{% set tab_title = (tab_title_string|tu == tab_title_string ? config_slug|capitalize : tab_title_string|tu) %} +{% set title = \"PLUGIN_ADMIN.CONFIGURATION\"|tu ~ \": \" ~ tab_title %} + +{% if not isInfo %} + {% set data = admin.data('config/' ~ config_slug) %} +{% endif %} + +{% block stylesheets %} + {% do assets.addCss(theme_url ~ '/css/codemirror/codemirror.css') %} + {{ parent() }} +{% endblock %} + +{% block javascripts %} + {{ parent() }} +{% endblock %} + +{% block titlebar %} +
                                  + {{ \"PLUGIN_ADMIN.BACK\"|tu }} + {% if data.file.filename %} + + {% endif %} +
                                  +

                                  {{ \"PLUGIN_ADMIN.CONFIGURATION\"|tu }} - {{ tab_title }}

                                  +{% endblock %} + +{% block content_top %} + {% if data.file.filename %} +
                                  {{ \"PLUGIN_ADMIN.SAVE_LOCATION\"|tu }}: {{ data.file.filename|replace({(base_path):''}) }}
                                  + {% endif %} + +
                                  +
                                  + + {% if authorize(['admin.configuration_system', 'admin.super']) %} + + {{ \"PLUGIN_ADMIN.SYSTEM\"|tu }} + + {% endif %} + + {% if authorize(['admin.configuration_site', 'admin.super']) %} + + {{ \"PLUGIN_ADMIN.SITE\"|tu }} + + {% endif %} + + {% for configuration in admin.configurations %} + {% if authorize(['admin.configuration_' ~ configuration, 'admin.super']) %} + {% set current_blueprints = admin.data('config/' ~ configuration).blueprints.toArray() %} + {% if configuration != 'system' and configuration != 'site' and not current_blueprints.form.hidden and (current_blueprints.form.fields is not empty or current_blueprints.form.field is not empty) %} + + {% set configuration_string = \"PLUGIN_ADMIN.\" ~ configuration|upper %} + {{ (configuration_string|tu == configuration_string ? configuration|capitalize : configuration_string|tu) }} + + {% endif %} + {% endif %} + {% endfor %} + + {% if authorize(['admin.configuration_info', 'admin.super']) %} + + {{ \"PLUGIN_ADMIN.INFO\"|tu }} + + {% endif %} + +
                                  +
                                  +{% endblock %} + +{% block content %} + {% if authorize(['admin.configuration_' ~ config_slug, 'admin.super']) %} + {% if isInfo %} +
                                  + {{ admin.phpinfo|raw }} +
                                  + {% else %} + {% include 'partials/blueprints.html.twig' with { blueprints: data.blueprints, data: data } %} + {% endif %} + {% endif %} + {% include 'partials/modal-changes-detected.html.twig' %} +{% endblock %} +", "config.html.twig", "/mnt/data/Sites/static-ethica.net/user/plugins/admin/themes/grav/templates/config.html.twig"); + } +} diff --git a/cache/twig/70/70f43dfe84522797170fbabc2f5ec4773f604b47a66bc351394460ffec625d4a.php b/cache/twig/70/70f43dfe84522797170fbabc2f5ec4773f604b47a66bc351394460ffec625d4a.php new file mode 100644 index 0000000..4e800f6 --- /dev/null +++ b/cache/twig/70/70f43dfe84522797170fbabc2f5ec4773f604b47a66bc351394460ffec625d4a.php @@ -0,0 +1,147 @@ +parent = false; + + $this->blocks = array( + ); + } + + protected function doDisplay(array $context, array $blocks = array()) + { + // line 1 + if ($this->getAttribute($this->getAttribute(($context["grav"] ?? null), "twig", array()), "plugins_quick_tray", array())) { + // line 2 + echo "
                                    + "; + // line 3 + $context['_parent'] = $context; + $context['_seq'] = twig_ensure_traversable($this->getAttribute($this->getAttribute(($context["grav"] ?? null), "twig", array()), "plugins_quick_tray", array())); + foreach ($context['_seq'] as $context["label"] => $context["item"]) { + // line 4 + echo " "; + if ($this->env->getExtension('Grav\Common\Twig\TwigExtension')->authorize(((($this->getAttribute($context["item"], "authorize", array(), "any", true, true) && twig_test_iterable($this->getAttribute($context["item"], "authorize", array())))) ? ($this->getAttribute($context["item"], "authorize", array())) : (array(0 => (($this->getAttribute($context["item"], "authorize", array())) ? ($this->getAttribute($context["item"], "authorize", array())) : (("admin." . (($this->getAttribute($context["item"], "location", array())) ? ($this->getAttribute($context["item"], "location", array())) : ($this->getAttribute($context["item"], "route", array())))))), 1 => "admin.super"))))) { + // line 5 + echo " "; + $context["data_tags"] = ""; + // line 6 + echo " "; + if ($this->getAttribute($context["item"], "data", array())) { + // line 7 + echo " "; + $context['_parent'] = $context; + $context['_seq'] = twig_ensure_traversable($this->getAttribute($context["item"], "data", array())); + foreach ($context['_seq'] as $context["key"] => $context["value"]) { + // line 8 + echo " "; + $context["data_tags"] = (((((($context["data_tags"] ?? null) . " data-") . $context["key"]) . "=\"") . $context["value"]) . "\""); + // line 9 + 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 10 + echo " "; + } + // line 11 + echo "
                                  • env, $this->getAttribute($context["item"], "class", array()), "html", null, true); + echo " hint--bottom\" data-hint=\""; + echo twig_escape_filter($this->env, $this->getAttribute($context["item"], "hint", array()), "html", null, true); + echo "\" "; + echo ($context["data_tags"] ?? null); + echo "> + "; + // line 12 + if ($this->getAttribute($context["item"], "route", array())) { + // line 13 + echo " env, $this->env->getExtension('Grav\Common\Twig\TwigExtension')->urlFunc($this->getAttribute($context["item"], "route", array())), "html", null, true); + echo "\"> + env, $this->getAttribute($context["item"], "icon", array()), "html", null, true); + echo "\"> + + "; + } else { + // line 17 + echo " env, $this->getAttribute($context["item"], "icon", array()), "html", null, true); + echo "\"> + "; + } + // line 19 + echo "
                                  • + "; + } + // line 21 + 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 22 + echo "
                                  +"; + } + } + + public function getTemplateName() + { + return "partials/nav-quick-tray.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 92 => 22, 86 => 21, 82 => 19, 76 => 17, 70 => 14, 65 => 13, 63 => 12, 54 => 11, 51 => 10, 45 => 9, 42 => 8, 37 => 7, 34 => 6, 31 => 5, 28 => 4, 24 => 3, 21 => 2, 19 => 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 Twig_Source("{% 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 %} +
                                  +{% endif %} +", "partials/nav-quick-tray.html.twig", "/mnt/data/Sites/static-ethica.net/user/plugins/admin/themes/grav/templates/partials/nav-quick-tray.html.twig"); + } +} diff --git a/cache/twig/71/719efc56339fcc27c1a6b85ed9f811ea6fc8e966735807b7f684cbfb1b42e76c.php b/cache/twig/71/719efc56339fcc27c1a6b85ed9f811ea6fc8e966735807b7f684cbfb1b42e76c.php new file mode 100644 index 0000000..9872471 --- /dev/null +++ b/cache/twig/71/719efc56339fcc27c1a6b85ed9f811ea6fc8e966735807b7f684cbfb1b42e76c.php @@ -0,0 +1,364 @@ +parent = $this->loadTemplate("forms/field.html.twig", "forms/fields/array/array.html.twig", 1); + $this->blocks = array( + 'global_attributes' => array($this, 'block_global_attributes'), + 'input' => array($this, 'block_input'), + ); + } + + protected function doGetParent(array $context) + { + return "forms/field.html.twig"; + } + + protected function doDisplay(array $context, array $blocks = array()) + { + $this->parent->display($context, array_merge($this->blocks, $blocks)); + } + + // line 3 + public function block_global_attributes($context, array $blocks = array()) + { + // line 4 + echo " data-grav-array-name=\""; + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Common\Twig\TwigExtension')->fieldNameFilter((($context["scope"] ?? null) . $this->getAttribute(($context["field"] ?? null), "name", array()))), "html", null, true); + echo "\" + data-grav-array-keyname=\""; + // line 5 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter(twig_escape_filter($this->env, $this->getAttribute(($context["field"] ?? null), "placeholder_key", array()))), "html", null, true); + echo "\" + data-grav-array-valuename=\""; + // line 6 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter(twig_escape_filter($this->env, $this->getAttribute(($context["field"] ?? null), "placeholder_value", array()))), "html", null, true); + echo "\" + "; + // line 7 + $this->displayParentBlock("global_attributes", $context, $blocks); + echo " +"; + } + + // line 42 + public function block_input($context, array $blocks = array()) + { + // line 43 + echo " "; + $context["array_field"] = $this; + // line 44 + echo "
                                  getAttribute(($context["field"] ?? null), "value_only", array())) { + echo " data-grav-array-mode=\"value_only\""; + } + echo (((twig_length_filter($this->env, ($context["value"] ?? null)) <= 1)) ? (" class=\"one-child\"") : ("")); + echo "> + "; + // line 45 + if (twig_length_filter($this->env, ($context["value"] ?? null))) { + // line 46 + echo " "; + $context['_parent'] = $context; + $context['_seq'] = twig_ensure_traversable(($context["value"] ?? null)); + foreach ($context['_seq'] as $context["key"] => $context["text"]) { + // line 47 + if ( !twig_test_iterable($context["text"])) { + // line 48 + echo " "; + echo $context["array_field"]->getrenderer($context["key"], $context["text"], ($context["field"] ?? null), ($context["scope"] ?? null)); + echo " + "; + } else { + // line 50 + echo " "; + // line 51 + echo " "; + $context['_parent'] = $context; + $context['_seq'] = twig_ensure_traversable($context["text"]); + foreach ($context['_seq'] as $context["subkey"] => $context["subtext"]) { + // line 52 + echo $context["array_field"]->getrenderer(((($context["key"] . "[") . $context["subkey"]) . "]"), $context["subtext"], ($context["field"] ?? null), ($context["scope"] ?? null)); + echo " + "; + } + $_parent = $context['_parent']; + unset($context['_seq'], $context['_iterated'], $context['subkey'], $context['subtext'], $context['_parent'], $context['loop']); + $context = array_intersect_key($context, $_parent) + $_parent; + // line 54 + echo " "; + } + // line 55 + echo " "; + } + $_parent = $context['_parent']; + unset($context['_seq'], $context['_iterated'], $context['key'], $context['text'], $context['_parent'], $context['loop']); + $context = array_intersect_key($context, $_parent) + $_parent; + } else { + // line 58 + echo "
                                  + + "; + // line 60 + if (($this->getAttribute(($context["field"] ?? null), "value_only", array()) != true)) { + // line 61 + echo " getAttribute(($context["field"] ?? null), "disabled", array()) || ($context["isDisabledToggleable"] ?? null))) { + echo "disabled=\"disabled\""; + } + // line 65 + echo " placeholder=\""; + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter(twig_escape_filter($this->env, $this->getAttribute(($context["field"] ?? null), "placeholder_key", array()))), "html", null, true); + echo "\" /> + "; + } + // line 67 + echo " env, $this->env->getExtension('Grav\Common\Twig\TwigExtension')->fieldNameFilter((($context["scope"] ?? null) . $this->getAttribute(($context["field"] ?? null), "name", array()))), "html", null, true); + echo "\" + "; + // line 71 + if (($this->getAttribute(($context["field"] ?? null), "disabled", array()) || ($context["isDisabledToggleable"] ?? null))) { + echo "disabled=\"disabled\""; + } + // line 72 + echo " placeholder=\""; + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter(twig_escape_filter($this->env, $this->getAttribute(($context["field"] ?? null), "placeholder_value", array()))), "html", null, true); + echo "\" /> + + +
                                  "; + } + // line 77 + echo "
                                  +"; + } + + // line 10 + public function getrenderer($__key__ = null, $__text__ = null, $__field__ = null, $__scope__ = null, ...$__varargs__) + { + $context = $this->env->mergeGlobals(array( + "key" => $__key__, + "text" => $__text__, + "field" => $__field__, + "scope" => $__scope__, + "varargs" => $__varargs__, + )); + + $blocks = array(); + + ob_start(); + try { + // line 11 + echo " + "; + // line 12 + if ( !twig_test_iterable(($context["text"] ?? null))) { + // line 13 + echo "
                                  getAttribute(($context["field"] ?? null), "value_only", array())) { + echo " array-field-value_only"; + } + echo "\" + data-grav-array-type=\"row\"> + + "; + // line 16 + if (($this->getAttribute(($context["field"] ?? null), "value_only", array()) != true)) { + // line 17 + echo " "; + if (((($context["key"] ?? null) == "0") && (($context["text"] ?? null) == ""))) { + // line 18 + echo " "; + $context["key"] = ""; + // line 19 + echo " "; + } + // line 20 + echo " + env, ($context["key"] ?? null), "html", null, true); + echo "\" + "; + // line 24 + if (($this->getAttribute(($context["field"] ?? null), "disabled", array()) || ($context["isDisabledToggleable"] ?? null))) { + echo "disabled=\"disabled\""; + } + // line 25 + echo " placeholder=\""; + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter(twig_escape_filter($this->env, $this->getAttribute(($context["field"] ?? null), "placeholder_key", array()))), "html", null, true); + echo "\" /> + "; + } + // line 27 + echo " + env, ((($this->env->getExtension('Grav\Common\Twig\TwigExtension')->fieldNameFilter((($context["scope"] ?? null) . $this->getAttribute(($context["field"] ?? null), "name", array()))) . "[") . ($context["key"] ?? null)) . "]"), "html", null, true); + echo "\" + placeholder=\""; + // line 32 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter(twig_escape_filter($this->env, $this->getAttribute(($context["field"] ?? null), "placeholder_value", array()))), "html", null, true); + echo "\" + "; + // line 33 + if (($this->getAttribute(($context["field"] ?? null), "disabled", array()) || ($context["isDisabledToggleable"] ?? null))) { + echo "disabled=\"disabled\""; + } + // line 34 + echo " value="; + if ((($context["text"] ?? null) == "true")) { + echo "true"; + } elseif ((($context["text"] ?? null) == "false")) { + echo "false"; + } else { + echo "\""; + echo twig_escape_filter($this->env, twig_join_filter(($context["text"] ?? null), ", ")); + echo "\""; + } + echo " /> + + + +
                                  + "; + } + } catch (Exception $e) { + ob_end_clean(); + + throw $e; + } catch (Throwable $e) { + ob_end_clean(); + + throw $e; + } + + return ('' === $tmp = ob_get_clean()) ? '' : new Twig_Markup($tmp, $this->env->getCharset()); + } + + public function getTemplateName() + { + return "forms/fields/array/array.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 229 => 34, 225 => 33, 221 => 32, 217 => 31, 211 => 27, 205 => 25, 201 => 24, 197 => 23, 192 => 20, 189 => 19, 186 => 18, 183 => 17, 181 => 16, 172 => 13, 170 => 12, 167 => 11, 152 => 10, 147 => 77, 139 => 72, 135 => 71, 131 => 70, 126 => 67, 120 => 65, 116 => 64, 111 => 61, 109 => 60, 105 => 58, 98 => 55, 95 => 54, 87 => 52, 82 => 51, 80 => 50, 74 => 48, 72 => 47, 67 => 46, 65 => 45, 57 => 44, 54 => 43, 51 => 42, 45 => 7, 41 => 6, 37 => 5, 32 => 4, 29 => 3, 11 => 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 Twig_Source("{% extends \"forms/field.html.twig\" %} + +{% block global_attributes %} + data-grav-array-name=\"{{ (scope ~ field.name)|fieldName }}\" + data-grav-array-keyname=\"{{ field.placeholder_key|e|tu }}\" + data-grav-array-valuename=\"{{ field.placeholder_value|e|tu }}\" + {{ parent() }} +{% endblock %} + +{% macro renderer(key, text, field, scope) %} + + {% if text is not iterable %} +
                                  + + {% if field.value_only != true %} + {% if key == '0' and text == '' %} + {% set key = '' %} + {% endif %} + + + {% endif %} + + + + + +
                                  + {% endif %} +{% endmacro %} + +{% block input %} + {% import _self as array_field %} +
                                  + {% if value|length %} + {% for key, text in value -%} + {% if text is not iterable %} + {{ array_field.renderer(key, text, field, scope) }} + {% else %} + {# Backward compatibility for nested arrays (metas) which are not supported anymore #} + {% for subkey, subtext in text -%} + {{ array_field.renderer(key ~ '[' ~ subkey ~ ']', subtext, field, scope) }} + {% endfor %} + {% endif %} + {% endfor %} + {%- else -%} + {# Empty value, mock the entry field#} +
                                  + + {% if field.value_only != true %} + + {% endif %} + + + +
                                  + {%- endif %} +
                                  +{% endblock %} +", "forms/fields/array/array.html.twig", "/mnt/data/Sites/static-ethica.net/user/plugins/admin/themes/grav/templates/forms/fields/array/array.html.twig"); + } +} diff --git a/cache/twig/71/71b2ab4570bd5879e342930f82b524a5fe062ff7f7e734b4b98b6a5037390e62.php b/cache/twig/71/71b2ab4570bd5879e342930f82b524a5fe062ff7f7e734b4b98b6a5037390e62.php new file mode 100644 index 0000000..0cc77ca --- /dev/null +++ b/cache/twig/71/71b2ab4570bd5879e342930f82b524a5fe062ff7f7e734b4b98b6a5037390e62.php @@ -0,0 +1,65 @@ +parent = false; + + $this->blocks = array( + ); + } + + protected function doDisplay(array $context, array $blocks = array()) + { + // line 1 + if ($this->getAttribute(($context["data"] ?? null), "avatar", array())) { + // line 2 + echo " +"; + } else { + // line 4 + echo " +"; + } + } + + public function getTemplateName() + { + return "partials/userinfo-avatar.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 27 => 4, 21 => 2, 19 => 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 Twig_Source("{% if data.avatar %} + +{% else %} + +{% endif %}", "partials/userinfo-avatar.html.twig", "/home/kevin/Sites/static-ethica.net/user/plugins/admin/themes/grav/templates/partials/userinfo-avatar.html.twig"); + } +} diff --git a/cache/twig/72/721bda27f6c7963a7ceed98b3ea94dd2804f33e40520412dcd1cf01f340ed146.php b/cache/twig/72/721bda27f6c7963a7ceed98b3ea94dd2804f33e40520412dcd1cf01f340ed146.php new file mode 100644 index 0000000..a299657 --- /dev/null +++ b/cache/twig/72/721bda27f6c7963a7ceed98b3ea94dd2804f33e40520412dcd1cf01f340ed146.php @@ -0,0 +1,270 @@ +parent = false; + + $this->blocks = array( + ); + } + + protected function doDisplay(array $context, array $blocks = array()) + { + // line 1 + echo "
                                  env, $this->getAttribute(($context["field"] ?? null), "class", array()), "html", null, true); + echo " "; + echo twig_escape_filter($this->env, $this->getAttribute(($context["field"] ?? null), "classes", array()), "html", null, true); + echo "\"> + +"; + // line 3 + if ($this->getAttribute(($context["field"] ?? null), "fields", array())) { + // line 4 + echo " + "; + // line 5 + $context["tabsKey"] = twig_join_filter(twig_get_array_keys_filter($this->getAttribute(($context["field"] ?? null), "fields", array())), "."); + // line 6 + echo " "; + $context["storedValue"] = $this->env->getExtension('Grav\Common\Twig\TwigExtension')->jsonDecodeFilter(_twig_default_filter($this->env->getExtension('Grav\Common\Twig\TwigExtension')->getCookie("grav-tabs-state"), "{}")); + // line 7 + echo " "; + $context["storedTab"] = $this->getAttribute(($context["storedValue"] ?? null), ("tab-" . ($context["tabsKey"] ?? null))); + // line 8 + echo " + "; + // line 9 + if (twig_test_empty(($context["storedTab"] ?? null))) { + // line 10 + echo " "; + if ($this->getAttribute($this->getAttribute(($context["uri"] ?? null), "params", array()), "tab", array())) { + // line 11 + echo " "; + $context["active"] = $this->getAttribute($this->getAttribute(($context["uri"] ?? null), "params", array()), "tab", array()); + // line 12 + echo " "; + } elseif ($this->getAttribute(($context["field"] ?? null), "active", array())) { + // line 13 + echo " "; + $context["active"] = $this->getAttribute(($context["field"] ?? null), "active", array()); + // line 14 + echo " "; + } else { + // line 15 + echo " "; + $context["active"] = 1; + // line 16 + echo " "; + } + // line 17 + echo " "; + } + // line 18 + echo " +
                                  + "; + // line 20 + $context['_parent'] = $context; + $context['_seq'] = twig_ensure_traversable($this->getAttribute(($context["field"] ?? null), "fields", array())); + $context['loop'] = array( + 'parent' => $context['_parent'], + 'index0' => 0, + 'index' => 1, + 'first' => true, + ); + if (is_array($context['_seq']) || (is_object($context['_seq']) && $context['_seq'] instanceof Countable)) { + $length = count($context['_seq']); + $context['loop']['revindex0'] = $length - 1; + $context['loop']['revindex'] = $length; + $context['loop']['length'] = $length; + $context['loop']['last'] = 1 === $length; + } + foreach ($context['_seq'] as $context["_key"] => $context["tab"]) { + // line 21 + echo " "; + if ((($this->getAttribute($context["tab"], "type", array()) == "tab") && (twig_test_empty($this->getAttribute($context["tab"], "security", array())) || $this->env->getExtension('Grav\Common\Twig\TwigExtension')->authorize($this->env->getExtension('Grav\Common\Twig\TwigExtension')->arrayFunc($this->getAttribute($context["tab"], "security", array())))))) { + // line 22 + echo " getAttribute($context["tab"], "name", array()))) || (($context["active"] ?? null) == $this->getAttribute($context["loop"], "index", array())))) ? ("active") : ("")); + echo "\" href=\"#\" data-tabid=\"tab-"; + echo twig_escape_filter($this->env, (($context["tabsKey"] ?? null) . $this->getAttribute($context["loop"], "index", array())), "html", null, true); + echo "\" data-tabkey=\"tab-"; + echo twig_escape_filter($this->env, ($context["tabsKey"] ?? null), "html", null, true); + echo "\" data-scope=\""; + echo twig_escape_filter($this->env, (($context["scope"] ?? null) . $this->getAttribute($context["tab"], "name", array())), "html", null, true); + echo "\"> + + "; + // line 24 + if ($this->getAttribute($this->getAttribute($this->getAttribute($this->getAttribute(($context["grav"] ?? null), "twig", array(), "any", false, true), "twig", array(), "any", false, true), "filters", array(), "any", false, true), "tu", array(), "array", true, true)) { + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter($this->getAttribute($context["tab"], "title", array())), "html", null, true); + } else { + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Common\Twig\TwigExtension')->translate($this->getAttribute($context["tab"], "title", array())), "html", null, true); + } + // line 25 + echo " + + "; + } + // line 28 + echo " "; + ++$context['loop']['index0']; + ++$context['loop']['index']; + $context['loop']['first'] = false; + if (isset($context['loop']['length'])) { + --$context['loop']['revindex0']; + --$context['loop']['revindex']; + $context['loop']['last'] = 0 === $context['loop']['revindex0']; + } + } + $_parent = $context['_parent']; + unset($context['_seq'], $context['_iterated'], $context['_key'], $context['tab'], $context['_parent'], $context['loop']); + $context = array_intersect_key($context, $_parent) + $_parent; + // line 29 + echo "
                                  +
                                  + "; + // line 31 + $context['_parent'] = $context; + $context['_seq'] = twig_ensure_traversable($this->getAttribute($context["field"], "fields", array())); + $context['loop'] = array( + 'parent' => $context['_parent'], + 'index0' => 0, + 'index' => 1, + 'first' => true, + ); + if (is_array($context['_seq']) || (is_object($context['_seq']) && $context['_seq'] instanceof Countable)) { + $length = count($context['_seq']); + $context['loop']['revindex0'] = $length - 1; + $context['loop']['revindex'] = $length; + $context['loop']['length'] = $length; + $context['loop']['last'] = 1 === $length; + } + foreach ($context['_seq'] as $context["_key"] => $context["field"]) { + // line 32 + echo " "; + if (($this->getAttribute($context["field"], "type", array()) == "tab")) { + // line 33 + echo " "; + if ((twig_test_empty($this->getAttribute($context["field"], "security", array())) || $this->env->getExtension('Grav\Common\Twig\TwigExtension')->authorize($this->env->getExtension('Grav\Common\Twig\TwigExtension')->arrayFunc($this->getAttribute($context["field"], "security", array()))))) { + // line 34 + echo " "; + $context["value"] = (($this->getAttribute($context["field"], "name", array())) ? ($this->getAttribute(($context["data"] ?? null), "value", array(0 => $this->getAttribute($context["field"], "name", array())), "method")) : ($this->getAttribute(($context["data"] ?? null), "toArray", array()))); + // line 35 + echo "
                                  env, (($context["tabsKey"] ?? null) . $this->getAttribute($context["loop"], "index", array())), "html", null, true); + echo "\" class=\"tab__content "; + echo ((((($context["storedTab"] ?? null) == (($context["scope"] ?? null) . $this->getAttribute($context["field"], "name", array()))) || (($context["active"] ?? null) == $this->getAttribute($context["loop"], "index", array())))) ? ("active") : ("")); + echo "\"> + "; + // line 36 + $this->loadTemplate(array(0 => (((("forms/fields/" . $this->getAttribute($context["field"], "type", array())) . "/") . $this->getAttribute($context["field"], "type", array())) . ".html.twig"), 1 => "forms/fields/text/text.html.twig"), "forms/fields/tabs/tabs.html.twig", 36)->display($context); + // line 37 + echo "
                                  + "; + } + // line 39 + echo " "; + } + // line 40 + echo " "; + ++$context['loop']['index0']; + ++$context['loop']['index']; + $context['loop']['first'] = false; + if (isset($context['loop']['length'])) { + --$context['loop']['revindex0']; + --$context['loop']['revindex']; + $context['loop']['last'] = 0 === $context['loop']['revindex0']; + } + } + $_parent = $context['_parent']; + unset($context['_seq'], $context['_iterated'], $context['_key'], $context['field'], $context['_parent'], $context['loop']); + $context = array_intersect_key($context, $_parent) + $_parent; + // line 41 + echo "
                                  +"; + } + // line 43 + echo "
                                  + +"; + } + + public function getTemplateName() + { + return "forms/fields/tabs/tabs.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 194 => 43, 190 => 41, 176 => 40, 173 => 39, 169 => 37, 167 => 36, 160 => 35, 157 => 34, 154 => 33, 151 => 32, 134 => 31, 130 => 29, 116 => 28, 111 => 25, 105 => 24, 93 => 22, 90 => 21, 73 => 20, 69 => 18, 66 => 17, 63 => 16, 60 => 15, 57 => 14, 54 => 13, 51 => 12, 48 => 11, 45 => 10, 43 => 9, 40 => 8, 37 => 7, 34 => 6, 32 => 5, 29 => 4, 27 => 3, 19 => 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 Twig_Source("
                                  + +{% if field.fields %} + + {% set tabsKey = field.fields|keys|join('.') %} + {% set storedValue = 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 field.fields %} + {% if tab.type == 'tab' and (tab.security is empty or authorize(array(tab.security))) %} + + + {% if grav.twig.twig.filters['tu'] is defined %}{{ tab.title|tu }}{% else %}{{ tab.title|t }}{% endif %} + + + {% endif %} + {% endfor %} +
                                  +
                                  + {% for field in field.fields %} + {% if field.type == 'tab' %} + {% if field.security is empty or authorize(array(field.security)) %} + {% set 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 %} + {% endif %} + {% endfor %} +
                                  +{% endif %} +
                                  + +", "forms/fields/tabs/tabs.html.twig", "/mnt/data/Sites/static-ethica.net/user/plugins/admin/themes/grav/templates/forms/fields/tabs/tabs.html.twig"); + } +} diff --git a/cache/twig/73/732ba2a54de1fb5f609c26abad068b332dffe5edcdcc94aae7697bcb8d046b2a.php b/cache/twig/73/732ba2a54de1fb5f609c26abad068b332dffe5edcdcc94aae7697bcb8d046b2a.php new file mode 100644 index 0000000..694bdf9 --- /dev/null +++ b/cache/twig/73/732ba2a54de1fb5f609c26abad068b332dffe5edcdcc94aae7697bcb8d046b2a.php @@ -0,0 +1,86 @@ +parent = false; + + $this->blocks = array( + ); + } + + protected function doDisplay(array $context, array $blocks = array()) + { + // line 1 + echo "
                                  +
                                  env, ($context["base_url"] ?? null), "html", null, true); + echo "/ajax.json/task:gpmRelease\"> + getAttribute($this->getAttribute($this->getAttribute(($context["config"] ?? null), "system", array()), "gpm", array()), "releases", array()) == "stable")) { + echo " checked=\"checked\""; + } + echo "> + + getAttribute($this->getAttribute($this->getAttribute(($context["config"] ?? null), "system", array()), "gpm", array()), "releases", array()) == "testing")) { + echo " checked=\"checked\""; + } + echo "> + + +
                                  +
                                  +"; + } + + public function getTemplateName() + { + return "partials/release-toggle.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 42 => 6, 36 => 5, 32 => 4, 26 => 3, 22 => 2, 19 => 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 Twig_Source("
                                  +
                                  + + + + + +
                                  +
                                  +", "partials/release-toggle.html.twig", "/home/kevin/Sites/static-ethica.net/user/plugins/admin/themes/grav/templates/partials/release-toggle.html.twig"); + } +} diff --git a/cache/twig/76/768752318193597c21159cc9ea38529a9ec030ca57790790173c0f0c5c8814c5.php b/cache/twig/76/768752318193597c21159cc9ea38529a9ec030ca57790790173c0f0c5c8814c5.php new file mode 100644 index 0000000..9e36c25 --- /dev/null +++ b/cache/twig/76/768752318193597c21159cc9ea38529a9ec030ca57790790173c0f0c5c8814c5.php @@ -0,0 +1,193 @@ +parent = $this->loadTemplate("forms/field.html.twig", "forms/fields/key/key.html.twig", 1); + $this->blocks = array( + 'input' => array($this, 'block_input'), + 'input_attributes' => array($this, 'block_input_attributes'), + ); + } + + protected function doGetParent(array $context) + { + return "forms/field.html.twig"; + } + + protected function doDisplay(array $context, array $blocks = array()) + { + $this->parent->display($context, array_merge($this->blocks, $blocks)); + } + + // line 3 + public function block_input($context, array $blocks = array()) + { + // line 4 + echo "
                                  env, $this->getAttribute(($context["field"] ?? null), "size", array()), "html", null, true); + echo "\"> + env, twig_join_filter(twig_escape_filter($this->env, ($context["value"] ?? null), "html_attr"), ", "), "html", null, true); + echo "\" + data-key-observe=\""; + // line 8 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Common\Twig\TwigExtension')->fieldNameFilter((($context["scope"] ?? null) . $this->getAttribute(($context["field"] ?? null), "name", array()))), "html", null, true); + echo "\" + "; + // line 9 + $this->displayBlock('input_attributes', $context, $blocks); + // line 24 + echo " /> +
                                  +"; + } + + // line 9 + public function block_input_attributes($context, array $blocks = array()) + { + // line 10 + echo " "; + if ($this->getAttribute(($context["field"] ?? null), "classes", array(), "any", true, true)) { + echo "class=\""; + echo twig_escape_filter($this->env, $this->getAttribute(($context["field"] ?? null), "classes", array()), "html", null, true); + echo "\" "; + } + // line 11 + echo " "; + if ($this->getAttribute(($context["field"] ?? null), "id", array(), "any", true, true)) { + echo "id=\""; + echo twig_escape_filter($this->env, $this->getAttribute(($context["field"] ?? null), "id", array())); + echo "\" "; + } + // line 12 + echo " "; + if ($this->getAttribute(($context["field"] ?? null), "style", array(), "any", true, true)) { + echo "style=\""; + echo twig_escape_filter($this->env, $this->getAttribute(($context["field"] ?? null), "style", array())); + echo "\" "; + } + // line 13 + echo " "; + if (($this->getAttribute(($context["field"] ?? null), "disabled", array()) || ($context["isDisabledToggleable"] ?? null))) { + echo "disabled=\"disabled\""; + } + // line 14 + echo " "; + if ($this->getAttribute(($context["field"] ?? null), "placeholder", array())) { + echo "placeholder=\""; + echo twig_escape_filter($this->env, $this->getAttribute(($context["field"] ?? null), "placeholder", array()), "html", null, true); + echo "\""; + } + // line 15 + echo " "; + if (twig_in_filter($this->getAttribute(($context["field"] ?? null), "autofocus", array()), array(0 => "on", 1 => "true", 2 => 1))) { + echo "autofocus=\"autofocus\""; + } + // line 16 + echo " "; + if (twig_in_filter($this->getAttribute(($context["field"] ?? null), "novalidate", array()), array(0 => "on", 1 => "true", 2 => 1))) { + echo "novalidate=\"novalidate\""; + } + // line 17 + echo " "; + if (twig_in_filter($this->getAttribute(($context["field"] ?? null), "readonly", array()), array(0 => "on", 1 => "true", 2 => 1))) { + echo "readonly=\"readonly\""; + } + // line 18 + echo " "; + if (twig_in_filter($this->getAttribute(($context["field"] ?? null), "autocomplete", array()), array(0 => "on", 1 => "off"))) { + echo "autocomplete=\""; + echo twig_escape_filter($this->env, $this->getAttribute(($context["field"] ?? null), "autocomplete", array()), "html", null, true); + echo "\""; + } + // line 19 + echo " "; + if (twig_in_filter($this->getAttribute($this->getAttribute(($context["field"] ?? null), "validate", array()), "required", array()), array(0 => "on", 1 => "true", 2 => 1))) { + echo "required=\"required\""; + } + // line 20 + echo " "; + if ($this->getAttribute($this->getAttribute(($context["field"] ?? null), "validate", array()), "pattern", array())) { + echo "pattern=\""; + echo twig_escape_filter($this->env, $this->getAttribute($this->getAttribute(($context["field"] ?? null), "validate", array()), "pattern", array()), "html", null, true); + echo "\""; + } + // line 21 + echo " "; + if ($this->getAttribute($this->getAttribute(($context["field"] ?? null), "validate", array()), "message", array())) { + echo "title=\""; + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Common\Twig\TwigExtension')->translate(twig_escape_filter($this->env, $this->getAttribute($this->getAttribute(($context["field"] ?? null), "validate", array()), "message", array()))), "html", null, true); + echo "\" + "; + } elseif ($this->getAttribute( // line 22 +($context["field"] ?? null), "title", array(), "any", true, true)) { + echo "title=\""; + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Common\Twig\TwigExtension')->translate(twig_escape_filter($this->env, $this->getAttribute(($context["field"] ?? null), "title", array()))), "html", null, true); + echo "\" "; + } + // line 23 + echo " "; + } + + public function getTemplateName() + { + return "forms/fields/key/key.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 138 => 23, 132 => 22, 125 => 21, 118 => 20, 113 => 19, 106 => 18, 101 => 17, 96 => 16, 91 => 15, 84 => 14, 79 => 13, 72 => 12, 65 => 11, 58 => 10, 55 => 9, 49 => 24, 47 => 9, 43 => 8, 39 => 7, 32 => 4, 29 => 3, 11 => 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 Twig_Source("{% extends \"forms/field.html.twig\" %} + +{% block input %} +
                                  + +
                                  +{% endblock %}", "forms/fields/key/key.html.twig", "/home/kevin/Sites/static-ethica.net/user/plugins/admin/themes/grav/templates/forms/fields/key/key.html.twig"); + } +} diff --git a/cache/twig/77/775dc2270033e61a58bd68c219b171020d128f4e1a1acea76f6a386bb6d68cfd.php b/cache/twig/77/775dc2270033e61a58bd68c219b171020d128f4e1a1acea76f6a386bb6d68cfd.php new file mode 100644 index 0000000..59ed3c7 --- /dev/null +++ b/cache/twig/77/775dc2270033e61a58bd68c219b171020d128f4e1a1acea76f6a386bb6d68cfd.php @@ -0,0 +1,54 @@ +parent = $this->loadTemplate("partials/base-root.html.twig", "partials/base.html.twig", 1); + $this->blocks = array( + ); + } + + protected function doGetParent(array $context) + { + return "partials/base-root.html.twig"; + } + + protected function doDisplay(array $context, array $blocks = array()) + { + $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 ( 11 => 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 Twig_Source("{% extends 'partials/base-root.html.twig' %} +", "partials/base.html.twig", "/mnt/data/Sites/static-ethica.net/user/plugins/admin/themes/grav/templates/partials/base.html.twig"); + } +} diff --git a/cache/twig/7b/7b5649072aeeea16bc4914745c7ff2d378f30cff13593f188eefa7bf5cfab52b.php b/cache/twig/7b/7b5649072aeeea16bc4914745c7ff2d378f30cff13593f188eefa7bf5cfab52b.php new file mode 100644 index 0000000..52728f2 --- /dev/null +++ b/cache/twig/7b/7b5649072aeeea16bc4914745c7ff2d378f30cff13593f188eefa7bf5cfab52b.php @@ -0,0 +1,277 @@ +parent = false; + + $this->blocks = array( + ); + } + + protected function doDisplay(array $context, array $blocks = array()) + { + // line 1 + echo "
                                  +
                                  +
                                  +

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

                                  + +
                                  +

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

                                  +
                                  + +
                                  +

                                  "; + // line 17 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\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\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\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\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\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\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.CONTINUE"), "html", null, true); + echo " +
                                          +
                                          + +
                                          +

                                          + "; + // line 53 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\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\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.INSTALLING_DEPENDENCIES"), "html", null, true); + echo " + +

                                            +
                                            + +
                                            +

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

                                            + +
                                              +
                                              + +
                                              +

                                              + "; + // line 81 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\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 ( 150 => 81, 138 => 72, 128 => 65, 119 => 59, 110 => 53, 99 => 47, 95 => 46, 86 => 40, 75 => 34, 71 => 33, 63 => 28, 56 => 24, 49 => 20, 43 => 17, 34 => 11, 27 => 7, 19 => 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 Twig_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", "/home/kevin/Sites/static-ethica.net/user/plugins/admin/themes/grav/templates/partials/modal-add-package.html.twig"); + } +} diff --git a/cache/twig/7d/7d6489d000cdf92ca8caf73155304553df3e8dea2db3430b8f424d2fef0804f3.php b/cache/twig/7d/7d6489d000cdf92ca8caf73155304553df3e8dea2db3430b8f424d2fef0804f3.php new file mode 100644 index 0000000..d5938c4 --- /dev/null +++ b/cache/twig/7d/7d6489d000cdf92ca8caf73155304553df3e8dea2db3430b8f424d2fef0804f3.php @@ -0,0 +1,338 @@ +parent = $this->loadTemplate("forms/field.html.twig", "forms/fields/permissions/permissions.html.twig", 1); + $this->blocks = array( + 'global_attributes' => array($this, 'block_global_attributes'), + 'input' => array($this, 'block_input'), + ); + } + + protected function doGetParent(array $context) + { + return "forms/field.html.twig"; + } + + protected function doDisplay(array $context, array $blocks = array()) + { + // line 3 + $context["value"] = (((null === ($context["value"] ?? null))) ? ($this->getAttribute(($context["field"] ?? null), "default", array())) : (($context["value"] ?? null))); + // line 4 + $context["value"] = (((($context["value"] ?? null) === false)) ? (0) : (($context["value"] ?? null))); + // line 1 + $this->parent->display($context, array_merge($this->blocks, $blocks)); + } + + // line 6 + public function block_global_attributes($context, array $blocks = array()) + { + // line 7 + echo " data-grav-disabled=\""; + echo (((null === ($context["originalValue"] ?? null))) ? ("true") : ("false")); + echo "\" + data-grav-default=\""; + // line 8 + echo twig_escape_filter($this->env, twig_jsonencode_filter($this->getAttribute(($context["field"] ?? null), "default", array())), "html_attr"); + echo "\" +"; + } + + // line 16 + public function block_input($context, array $blocks = array()) + { + // line 17 + echo "
                                                              + "; + // line 18 + $context["permissions"] = $this->getAttribute(($context["admin"] ?? null), "getPermissions", array()); + // line 19 + echo " "; + $context['_parent'] = $context; + $context['_seq'] = twig_ensure_traversable(($context["value"] ?? null)); + foreach ($context['_seq'] as $context["index_existing_permission"] => $context["value_existing_permission"]) { + // line 20 + echo " "; + $context['_parent'] = $context; + $context['_seq'] = twig_ensure_traversable($context["value_existing_permission"]); + foreach ($context['_seq'] as $context["index_segment1"] => $context["value_segment1"]) { + // line 21 + echo " "; + $context["permissions"] = twig_array_merge(($context["permissions"] ?? null), array((($context["index_existing_permission"] . ".") . $context["index_segment1"]) => "boolean")); + // line 22 + echo " "; + } + $_parent = $context['_parent']; + unset($context['_seq'], $context['_iterated'], $context['index_segment1'], $context['value_segment1'], $context['_parent'], $context['loop']); + $context = array_intersect_key($context, $_parent) + $_parent; + // line 23 + echo " "; + } + $_parent = $context['_parent']; + unset($context['_seq'], $context['_iterated'], $context['index_existing_permission'], $context['value_existing_permission'], $context['_parent'], $context['loop']); + $context = array_intersect_key($context, $_parent) + $_parent; + // line 24 + echo " + "; + // line 25 + $context['_parent'] = $context; + $context['_seq'] = twig_ensure_traversable(($context["permissions"] ?? null)); + foreach ($context['_seq'] as $context["permission"] => $context["type"]) { + // line 26 + echo "
                                                              + "; + // line 27 + $context["permission_segments"] = twig_split_filter($this->env, $context["permission"], "."); + // line 28 + echo " "; + $context["permission_value"] = $this->getAttribute($this->getAttribute(($context["value"] ?? null), $this->getAttribute(($context["permission_segments"] ?? null), 0, array(), "array"), array(), "array"), $this->getAttribute(($context["permission_segments"] ?? null), 1, array(), "array"), array(), "array"); + // line 29 + echo " "; + if (twig_in_filter(($context["permission_value"] ?? null), array(0 => "on", 1 => "true", 2 => 1))) { + // line 30 + echo " "; + $context["permission_value"] = "true"; + // line 31 + echo " "; + } + // line 32 + echo " + env, $context["permission"], "html", null, true); + echo "\" /> + +
                                                              + "; + // line 36 + $context["options"] = array("true" => "PLUGIN_ADMIN.YES", "false" => "PLUGIN_ADMIN.NO", "" => "PLUGIN_ADMIN.NOT_SET"); + // line 37 + echo " + "; + // line 38 + $context["maxLen"] = 0; + // line 39 + echo " "; + $context['_parent'] = $context; + $context['_seq'] = twig_ensure_traversable(($context["options"] ?? null)); + foreach ($context['_seq'] as $context["value"] => $context["text"]) { + // line 40 + echo " "; + $context["translation"] = (($this->getAttribute($this->getAttribute($this->getAttribute($this->getAttribute(($context["grav"] ?? null), "twig", array(), "any", false, true), "twig", array(), "any", false, true), "filters", array(), "any", false, true), "tu", array(), "array", true, true)) ? ($this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter($context["text"])) : ($this->env->getExtension('Grav\Common\Twig\TwigExtension')->translate($context["text"]))); + // line 41 + echo " "; + $context["maxLen"] = max(twig_length_filter($this->env, ($context["translation"] ?? null)), ($context["maxLen"] ?? null)); + // line 42 + echo " "; + } + $_parent = $context['_parent']; + unset($context['_seq'], $context['_iterated'], $context['value'], $context['text'], $context['_parent'], $context['loop']); + $context = array_intersect_key($context, $_parent) + $_parent; + // line 43 + echo " + "; + // line 44 + $context['_parent'] = $context; + $context['_seq'] = twig_ensure_traversable(($context["options"] ?? null)); + foreach ($context['_seq'] as $context["key"] => $context["text"]) { + // line 45 + echo " "; + $context["id"] = (((("toggle_" . $this->getAttribute(($context["field"] ?? null), "name", array())) . ".") . $context["permission"]) . $context["key"]); + // line 46 + echo " "; + $context["translation"] = twig_trim_filter((($this->getAttribute($this->getAttribute($this->getAttribute($this->getAttribute(($context["grav"] ?? null), "twig", array(), "any", false, true), "twig", array(), "any", false, true), "filters", array(), "any", false, true), "tu", array(), "array", true, true)) ? ($this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter($context["text"])) : ($this->env->getExtension('Grav\Common\Twig\TwigExtension')->translate($context["text"])))); + // line 47 + echo " + env, $context["key"], "html", null, true); + echo "\" + id=\""; + // line 50 + echo twig_escape_filter($this->env, ($context["id"] ?? null), "html", null, true); + echo "\" + name=\""; + // line 51 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Common\Twig\TwigExtension')->fieldNameFilter((((($context["scope"] ?? null) . $this->getAttribute(($context["field"] ?? null), "name", array())) . ".") . $context["permission"])), "html", null, true); + echo "\" + class=\""; + // line 52 + echo ((("true" == ("" . $context["key"]))) ? ("highlight") : ("")); + echo "\" + "; + // line 53 + if (($this->env->getExtension('Grav\Common\Twig\TwigExtension')->fieldNameFilter($context["key"]) == ("" . $this->env->getExtension('Grav\Common\Twig\TwigExtension')->fieldNameFilter(($context["permission_value"] ?? null))))) { + // line 54 + echo " checked=\"checked\" + "; + } + // line 56 + echo " "; + if (twig_in_filter($this->getAttribute($this->getAttribute(($context["field"] ?? null), "validate", array()), "required", array()), array(0 => "on", 1 => "true", 2 => 1))) { + echo "required=\"required\""; + } + // line 57 + echo " /> + + + "; + } + $_parent = $context['_parent']; + unset($context['_seq'], $context['_iterated'], $context['key'], $context['text'], $context['_parent'], $context['loop']); + $context = array_intersect_key($context, $_parent) + $_parent; + // line 61 + echo " +
                                                              +
                                                              + "; + } + $_parent = $context['_parent']; + unset($context['_seq'], $context['_iterated'], $context['permission'], $context['type'], $context['_parent'], $context['loop']); + $context = array_intersect_key($context, $_parent) + $_parent; + // line 65 + echo "
                                                              +"; + } + + // line 11 + public function getspanToggle($__input__ = null, $__length__ = null, ...$__varargs__) + { + $context = $this->env->mergeGlobals(array( + "input" => $__input__, + "length" => $__length__, + "varargs" => $__varargs__, + )); + + $blocks = array(); + + ob_start(); + try { + // line 12 + echo " "; + $context["space"] = $this->env->getExtension('Grav\Common\Twig\TwigExtension')->repeatFunc("  ", ((($context["length"] ?? null) - twig_length_filter($this->env, ($context["input"] ?? null))) / 2)); + // line 13 + echo " "; + echo ((($context["space"] ?? null) . ($context["input"] ?? null)) . ($context["space"] ?? null)); + echo " +"; + } catch (Exception $e) { + ob_end_clean(); + + throw $e; + } catch (Throwable $e) { + ob_end_clean(); + + throw $e; + } + + return ('' === $tmp = ob_get_clean()) ? '' : new Twig_Markup($tmp, $this->env->getCharset()); + } + + public function getTemplateName() + { + return "forms/fields/permissions/permissions.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 226 => 13, 223 => 12, 210 => 11, 205 => 65, 196 => 61, 186 => 59, 182 => 57, 177 => 56, 173 => 54, 171 => 53, 167 => 52, 163 => 51, 159 => 50, 155 => 49, 151 => 47, 148 => 46, 145 => 45, 141 => 44, 138 => 43, 132 => 42, 129 => 41, 126 => 40, 121 => 39, 119 => 38, 116 => 37, 114 => 36, 108 => 33, 105 => 32, 102 => 31, 99 => 30, 96 => 29, 93 => 28, 91 => 27, 88 => 26, 84 => 25, 81 => 24, 75 => 23, 69 => 22, 66 => 21, 61 => 20, 56 => 19, 54 => 18, 51 => 17, 48 => 16, 42 => 8, 37 => 7, 34 => 6, 30 => 1, 28 => 4, 26 => 3, 11 => 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 Twig_Source("{% extends \"forms/field.html.twig\" %} + +{% set value = (value is null ? field.default : value) %} +{% set value = (value is same as(false) ? 0 : value) %} + +{% block global_attributes %} + data-grav-disabled=\"{{ originalValue is null ? 'true' : 'false' }}\" + data-grav-default=\"{{ field.default|json_encode()|e('html_attr') }}\" +{% endblock %} + +{% macro spanToggle(input, length) %} + {% set space = repeat('  ', (length - input|length) / 2) %} + {{ (space ~ input ~ space)|raw }} +{% endmacro %} + +{% block input %} +
                                                              + {% set permissions = admin.getPermissions %} + {% for index_existing_permission, value_existing_permission in value %} + {% for index_segment1, value_segment1 in value_existing_permission %} + {% set permissions = permissions|merge({ (index_existing_permission ~ \".\" ~ index_segment1): \"boolean\"}) %} + {% endfor %} + {% endfor %} + + {% for permission, type in permissions %} +
                                                              + {% set permission_segments = permission|split('.') %} + {% set permission_value = value[permission_segments[0]][permission_segments[1]] %} + {% if permission_value in ['on', 'true', 1] %} + {% set permission_value = 'true' %} + {% endif %} + + + +
                                                              + {% set options = { true: 'PLUGIN_ADMIN.YES', false: 'PLUGIN_ADMIN.NO', '': 'PLUGIN_ADMIN.NOT_SET' } %} + + {% set maxLen = 0 %} + {% for value, text in options %} + {% set translation = grav.twig.twig.filters['tu'] is defined ? text|tu : text|t %} + {% set maxLen = max(translation|length, maxLen) %} + {% endfor %} + + {% for key, text in options %} + {% set id = \"toggle_\" ~ field.name ~ \".\" ~ permission ~ key %} + {% set translation = (grav.twig.twig.filters['tu'] is defined ? text|tu : text|t)|trim %} + + + + + {% endfor %} + +
                                                              +
                                                              + {% endfor %} +
                                                              +{% endblock %} + + +", "forms/fields/permissions/permissions.html.twig", "/home/kevin/Sites/static-ethica.net/user/plugins/admin/themes/grav/templates/forms/fields/permissions/permissions.html.twig"); + } +} diff --git a/cache/twig/8c/8c51dcd48e6989f2981bdb0e3013b3f8aa577a010cdff5b0a848ebee1c4fb777.php b/cache/twig/8c/8c51dcd48e6989f2981bdb0e3013b3f8aa577a010cdff5b0a848ebee1c4fb777.php new file mode 100644 index 0000000..f86e1be --- /dev/null +++ b/cache/twig/8c/8c51dcd48e6989f2981bdb0e3013b3f8aa577a010cdff5b0a848ebee1c4fb777.php @@ -0,0 +1,309 @@ +parent = false; + + $this->blocks = array( + ); + } + + protected function doDisplay(array $context, array $blocks = array()) + { + // line 1 + $this->loadTemplate("login.html.twig", "login.html.twig", 1, "1539425397")->display(array_merge($context, array("title" => "Grav Admin Login"))); + } + + public function getTemplateName() + { + return "login.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 19 => 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 Twig_Source("{% embed 'partials/login.html.twig' with {title:'Grav Admin Login'} %} + + {% block form %} + + {% if grav.user.username and grav.user.authenticated %} + +
                                                              + +
                                                              + + {% else %} + {% 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 %} + +
                                                              + {% if notAuthorized %} + {{ 'PLUGIN_ADMIN.BACK'|tu }} + + {% else %} + {% if not authenticated %} + {{ 'PLUGIN_ADMIN.LOGIN_BTN_FORGOT'|tu }} + + {% else %} + + {% endif %} + {% endif %} +
                                                              + + + + {% endif %} + + {% endblock %} + +{% endembed %} +", "login.html.twig", "/mnt/data/Sites/static-ethica.net/user/plugins/admin/themes/grav/templates/login.html.twig"); + } +} + + +/* login.html.twig */ +class __TwigTemplate_31a5220dc52086498ad3c55b8de8ecbb39f98539caf1dd351e857e2cc92192e9_1539425397 extends Twig_Template +{ + public function __construct(Twig_Environment $env) + { + parent::__construct($env); + + $this->parent = $this->loadTemplate("partials/login.html.twig", "login.html.twig", 1); + $this->blocks = array( + 'form' => array($this, 'block_form'), + ); + } + + protected function doGetParent(array $context) + { + return "partials/login.html.twig"; + } + + protected function doDisplay(array $context, array $blocks = array()) + { + $this->parent->display($context, array_merge($this->blocks, $blocks)); + } + + // line 3 + public function block_form($context, array $blocks = array()) + { + // line 4 + echo " + "; + // line 5 + if (($this->getAttribute($this->getAttribute(($context["grav"] ?? null), "user", array()), "username", array()) && $this->getAttribute($this->getAttribute(($context["grav"] ?? null), "user", array()), "authenticated", array()))) { + // line 6 + echo " +
                                                              + +
                                                              + + "; + } else { + // line 12 + echo " "; + $context['_parent'] = $context; + $context['_seq'] = twig_ensure_traversable($this->getAttribute(($context["form"] ?? null), "fields", array())); + $context['loop'] = array( + 'parent' => $context['_parent'], + 'index0' => 0, + 'index' => 1, + 'first' => true, + ); + if (is_array($context['_seq']) || (is_object($context['_seq']) && $context['_seq'] instanceof Countable)) { + $length = count($context['_seq']); + $context['loop']['revindex0'] = $length - 1; + $context['loop']['revindex'] = $length; + $context['loop']['length'] = $length; + $context['loop']['last'] = 1 === $length; + } + foreach ($context['_seq'] as $context["_key"] => $context["field"]) { + // line 13 + echo " "; + if ($this->getAttribute($context["field"], "type", array())) { + // line 14 + echo "
                                                              + "; + // line 15 + $this->loadTemplate(array(0 => (((("forms/fields/" . $this->getAttribute($context["field"], "type", array())) . "/") . $this->getAttribute($context["field"], "type", array())) . ".html.twig"), 1 => "forms/fields/text/text.html.twig"), "login.html.twig", 15)->display($context); + // line 16 + echo "
                                                              + "; + } + // line 18 + echo " "; + ++$context['loop']['index0']; + ++$context['loop']['index']; + $context['loop']['first'] = false; + if (isset($context['loop']['length'])) { + --$context['loop']['revindex0']; + --$context['loop']['revindex']; + $context['loop']['last'] = 0 === $context['loop']['revindex0']; + } + } + $_parent = $context['_parent']; + unset($context['_seq'], $context['_iterated'], $context['_key'], $context['field'], $context['_parent'], $context['loop']); + $context = array_intersect_key($context, $_parent) + $_parent; + // line 19 + echo " +
                                                              + "; + // line 21 + if (($context["notAuthorized"] ?? null)) { + // line 22 + echo " "; + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.BACK"), "html", null, true); + echo " + + "; + } else { + // line 25 + echo " "; + if ( !($context["authenticated"] ?? null)) { + // line 26 + echo " env, ($context["base_url_relative"] ?? null), "html", null, true); + echo "/forgot\"> "; + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.LOGIN_BTN_FORGOT"), "html", null, true); + echo " + + "; + } else { + // line 29 + echo " + "; + } + // line 31 + echo " "; + } + // line 32 + echo "
                                                              + + + + "; + } + // line 41 + echo " + "; + } + + public function getTemplateName() + { + return "login.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 234 => 41, 223 => 32, 220 => 31, 214 => 29, 209 => 27, 202 => 26, 199 => 25, 194 => 23, 189 => 22, 187 => 21, 183 => 19, 169 => 18, 165 => 16, 163 => 15, 160 => 14, 157 => 13, 139 => 12, 132 => 8, 128 => 6, 126 => 5, 123 => 4, 120 => 3, 19 => 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 Twig_Source("{% embed 'partials/login.html.twig' with {title:'Grav Admin Login'} %} + + {% block form %} + + {% if grav.user.username and grav.user.authenticated %} + +
                                                              + +
                                                              + + {% else %} + {% 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 %} + +
                                                              + {% if notAuthorized %} + {{ 'PLUGIN_ADMIN.BACK'|tu }} + + {% else %} + {% if not authenticated %} + {{ 'PLUGIN_ADMIN.LOGIN_BTN_FORGOT'|tu }} + + {% else %} + + {% endif %} + {% endif %} +
                                                              + + + + {% endif %} + + {% endblock %} + +{% endembed %} +", "login.html.twig", "/mnt/data/Sites/static-ethica.net/user/plugins/admin/themes/grav/templates/login.html.twig"); + } +} diff --git a/cache/twig/8d/8d3a5b5346442d7676dfda9ff45d4ef62ebd3763b0bf2ef2b32adba37b7510db.php b/cache/twig/8d/8d3a5b5346442d7676dfda9ff45d4ef62ebd3763b0bf2ef2b32adba37b7510db.php new file mode 100644 index 0000000..1a030d2 --- /dev/null +++ b/cache/twig/8d/8d3a5b5346442d7676dfda9ff45d4ef62ebd3763b0bf2ef2b32adba37b7510db.php @@ -0,0 +1,223 @@ +parent = $this->loadTemplate("forms/field.html.twig", "forms/fields/checkboxes/checkboxes.html.twig", 1); + $this->blocks = array( + 'global_attributes' => array($this, 'block_global_attributes'), + 'input' => array($this, 'block_input'), + ); + } + + protected function doGetParent(array $context) + { + return "forms/field.html.twig"; + } + + protected function doDisplay(array $context, array $blocks = array()) + { + // line 3 + $context["originalValue"] = ($context["value"] ?? null); + // line 4 + $context["value"] = (((null === ($context["value"] ?? null))) ? ($this->getAttribute(($context["field"] ?? null), "default", array())) : (($context["value"] ?? null))); + // line 5 + if ((($this->getAttribute(($context["field"] ?? null), "use", array()) == "keys") && $this->getAttribute(($context["field"] ?? null), "default", array()))) { + // line 6 + $context["value"] = twig_array_merge($this->getAttribute(($context["field"] ?? null), "default", array()), ($context["value"] ?? null)); + } + // line 1 + $this->parent->display($context, array_merge($this->blocks, $blocks)); + } + + // line 9 + public function block_global_attributes($context, array $blocks = array()) + { + // line 10 + echo " "; + $this->displayParentBlock("global_attributes", $context, $blocks); + echo " + data-grav-keys=\""; + // line 11 + echo ((($this->getAttribute(($context["field"] ?? null), "use", array()) == "keys")) ? ("true") : ("false")); + echo "\" + data-grav-field-name=\""; + // line 12 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Common\Twig\TwigExtension')->fieldNameFilter((($context["scope"] ?? null) . $this->getAttribute(($context["field"] ?? null), "name", array()))), "html", null, true); + echo "\" +"; + } + + // line 15 + public function block_input($context, array $blocks = array()) + { + // line 16 + echo " "; + $context['_parent'] = $context; + $context['_seq'] = twig_ensure_traversable($this->getAttribute(($context["field"] ?? null), "options", array())); + foreach ($context['_seq'] as $context["key"] => $context["text"]) { + // line 17 + echo " + "; + // line 18 + $context["id"] = (((($this->getAttribute(($context["field"] ?? null), "id", array(), "any", true, true)) ? (_twig_default_filter($this->getAttribute(($context["field"] ?? null), "id", array()), $this->getAttribute(($context["field"] ?? null), "name", array()))) : ($this->getAttribute(($context["field"] ?? null), "name", array()))) . "-") . $context["key"]); + // line 19 + echo " "; + $context["name"] = ((($this->getAttribute(($context["field"] ?? null), "use", array()) == "keys")) ? ($context["key"]) : (($context["id"] ?? null))); + // line 20 + echo " "; + $context["val"] = ((($this->getAttribute(($context["field"] ?? null), "use", array()) == "keys")) ? ("1") : ($context["key"])); + // line 21 + echo " "; + $context["checked"] = ((($this->getAttribute(($context["field"] ?? null), "use", array()) == "keys")) ? ($this->getAttribute(($context["value"] ?? null), $context["key"], array(), "array")) : (twig_in_filter($context["key"], ($context["value"] ?? null)))); + // line 22 + echo " "; + $context["help"] = ((twig_in_filter($context["key"], twig_get_array_keys_filter($this->getAttribute(($context["field"] ?? null), "help_options", array())))) ? ($this->getAttribute($this->getAttribute(($context["field"] ?? null), "help_options", array()), $context["key"], array(), "array")) : (false)); + // line 23 + echo " +
                                                              env, ($context["form_field_wrapper_classes"] ?? null), "html", null, true); + echo " "; + echo twig_escape_filter($this->env, $this->getAttribute(($context["field"] ?? null), "wrapper_classes", array()), "html", null, true); + echo "\"> + env, ($context["id"] ?? null)); + echo "\" + value=\""; + // line 27 + echo twig_escape_filter($this->env, ($context["val"] ?? null)); + echo "\" + name=\""; + // line 28 + echo twig_escape_filter($this->env, ((($this->env->getExtension('Grav\Common\Twig\TwigExtension')->fieldNameFilter((($context["scope"] ?? null) . $this->getAttribute(($context["field"] ?? null), "name", array()))) . "[") . ($context["name"] ?? null)) . "]"), "html", null, true); + echo "\" + "; + // line 29 + if (($context["checked"] ?? null)) { + echo "checked=\"checked\""; + } + // line 30 + echo " "; + if ($this->getAttribute(($context["field"] ?? null), "classes", array(), "any", true, true)) { + echo "class=\""; + echo twig_escape_filter($this->env, $this->getAttribute(($context["field"] ?? null), "classes", array()), "html", null, true); + echo "\" "; + } + // line 31 + echo " "; + if (($this->getAttribute(($context["field"] ?? null), "disabled", array()) || ($context["isDisabledToggleable"] ?? null))) { + echo "disabled=\"disabled\""; + } + // line 32 + echo " + > + +
                                                              + "; + } + $_parent = $context['_parent']; + unset($context['_seq'], $context['_iterated'], $context['key'], $context['text'], $context['_parent'], $context['loop']); + $context = array_intersect_key($context, $_parent) + $_parent; + } + + public function getTemplateName() + { + return "forms/fields/checkboxes/checkboxes.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 144 => 40, 138 => 38, 130 => 36, 128 => 35, 124 => 34, 120 => 32, 115 => 31, 108 => 30, 104 => 29, 100 => 28, 96 => 27, 92 => 26, 85 => 24, 82 => 23, 79 => 22, 76 => 21, 73 => 20, 70 => 19, 68 => 18, 65 => 17, 60 => 16, 57 => 15, 51 => 12, 47 => 11, 42 => 10, 39 => 9, 35 => 1, 32 => 6, 30 => 5, 28 => 4, 26 => 3, 11 => 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 Twig_Source("{% extends \"forms/field.html.twig\" %} + +{% set originalValue = value %} +{% set value = (value is null ? field.default : value) %} +{% if field.use == 'keys' and field.default %} + {% set value = field.default|merge(value) %} +{% endif %} + +{% block global_attributes %} + {{ parent() }} + data-grav-keys=\"{{ field.use == 'keys' ? 'true' : 'false' }}\" + data-grav-field-name=\"{{ (scope ~ field.name)|fieldName }}\" +{% endblock %} + +{% block input %} + {% for key, text in field.options %} + + {% set id = field.id|default(field.name) ~ '-' ~ key %} + {% set name = field.use == 'keys' ? key : id %} + {% set val = field.use == 'keys' ? '1' : key %} + {% set checked = (field.use == 'keys' ? value[key] : key in value) %} + {% set help = (key in field.help_options|keys ? field.help_options[key] : false) %} + +
                                                              + + +
                                                              + {% endfor %} +{% endblock %} +", "forms/fields/checkboxes/checkboxes.html.twig", "/mnt/data/Sites/static-ethica.net/user/plugins/form/templates/forms/fields/checkboxes/checkboxes.html.twig"); + } +} diff --git a/cache/twig/93/934c02f4ed205f8ab5801e28a16909875d946cfb47c99afa4a10f4286bb69ce8.php b/cache/twig/93/934c02f4ed205f8ab5801e28a16909875d946cfb47c99afa4a10f4286bb69ce8.php new file mode 100644 index 0000000..ead4bfc --- /dev/null +++ b/cache/twig/93/934c02f4ed205f8ab5801e28a16909875d946cfb47c99afa4a10f4286bb69ce8.php @@ -0,0 +1,54 @@ +parent = false; + + $this->blocks = array( + ); + } + + protected function doDisplay(array $context, array $blocks = array()) + { + // line 1 + echo $this->env->getExtension('Grav\Common\Twig\TwigExtension')->translate("PLUGIN_ERROR.ERROR_MESSAGE"); + echo " + +"; + } + + public function getTemplateName() + { + return "@Page:/home/kevin/Sites/static-ethica.net/user/plugins/error/pages"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 19 => 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 Twig_Source("{{ 'PLUGIN_ERROR.ERROR_MESSAGE'|t }} + +", "@Page:/home/kevin/Sites/static-ethica.net/user/plugins/error/pages", ""); + } +} diff --git a/cache/twig/95/95ec9d7d4df4e318fe893b25ecbd5bfb10d814b80fdf216567ca2fa5ccd9f90f.php b/cache/twig/95/95ec9d7d4df4e318fe893b25ecbd5bfb10d814b80fdf216567ca2fa5ccd9f90f.php new file mode 100644 index 0000000..449e8e2 --- /dev/null +++ b/cache/twig/95/95ec9d7d4df4e318fe893b25ecbd5bfb10d814b80fdf216567ca2fa5ccd9f90f.php @@ -0,0 +1,356 @@ +parent = $this->loadTemplate("partials/base.html.twig", "plugins.html.twig", 1); + $this->blocks = array( + 'stylesheets' => array($this, 'block_stylesheets'), + 'javascripts' => array($this, 'block_javascripts'), + 'titlebar' => array($this, 'block_titlebar'), + 'messages' => array($this, 'block_messages'), + 'content' => array($this, 'block_content'), + ); + } + + protected function doGetParent(array $context) + { + return "partials/base.html.twig"; + } + + protected function doDisplay(array $context, array $blocks = array()) + { + // line 3 + $context["plugin_slug"] = $this->getAttribute(($context["admin"] ?? null), "route", array()); + // line 5 + if (($context["plugin_slug"] ?? null)) { + // line 6 + $context["installing"] = (is_string($__internal_f0cf81ce7681fda8f066184e9e8db4d5ef6086c109b9ff8a4ae05616dbb88373 = ($context["plugin_slug"] ?? null)) && is_string($__internal_5b12cae85121d9d6f71768c3760ec691341315eb682041435a4f11a2de7a791d = "install") && ('' === $__internal_5b12cae85121d9d6f71768c3760ec691341315eb682041435a4f11a2de7a791d || 0 === strpos($__internal_f0cf81ce7681fda8f066184e9e8db4d5ef6086c109b9ff8a4ae05616dbb88373, $__internal_5b12cae85121d9d6f71768c3760ec691341315eb682041435a4f11a2de7a791d))); + // line 8 + if (($context["installing"] ?? null)) { + // line 9 + $context["title"] = $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.PLUGINS"); + } else { + // line 11 + $context["installed"] = true; + // line 14 + $context["package"] = $this->getAttribute($this->getAttribute(($context["admin"] ?? null), "plugins", array(0 => true), "method"), $this->getAttribute(($context["admin"] ?? null), "route", array()), array(), "array"); + // line 15 + if ( !($context["package"] ?? null)) { + // line 16 + $context["package"] = $this->getAttribute($this->getAttribute(($context["admin"] ?? null), "plugins", array(0 => false), "method"), $this->getAttribute(($context["admin"] ?? null), "route", array()), array(), "array"); + // line 17 + $context["installed"] = false; + } + // line 20 + $context["plugin"] = $this->getAttribute(($context["package"] ?? null), "toArray", array(), "method"); + // line 21 + $context["title"] = (($this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.PLUGIN") . ": ") . twig_escape_filter($this->env, $this->getAttribute(($context["plugin"] ?? null), "name", array()))); + } + } else { + // line 24 + $context["title"] = $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.PLUGINS"); + } + // line 27 + if (($this->getAttribute(($context["admin"] ?? null), "route", array()) || ($context["installing"] ?? null))) { + } + // line 1 + $this->parent->display($context, array_merge($this->blocks, $blocks)); + } + + // line 28 + public function block_stylesheets($context, array $blocks = array()) + { + // line 29 + echo " "; + $this->getAttribute(($context["assets"] ?? null), "addCss", array(0 => (($context["theme_url"] ?? null) . "/css/codemirror/codemirror.css")), "method"); + // line 30 + echo " "; + $this->displayParentBlock("stylesheets", $context, $blocks); + echo " + "; + } + + // line 33 + public function block_javascripts($context, array $blocks = array()) + { + // line 34 + echo " "; + $this->displayParentBlock("javascripts", $context, $blocks); + echo " + "; + } + + // line 38 + public function block_titlebar($context, array $blocks = array()) + { + // line 39 + echo " "; + if (( !$this->getAttribute(($context["admin"] ?? null), "route", array()) || ($context["installing"] ?? null))) { + // line 40 + echo "
                                                              + "; + // line 41 + if (($context["installing"] ?? null)) { + // line 42 + echo " env, ($context["base_url_relative"] ?? null), "html", null, true); + echo "/plugins\"> "; + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.BACK"), "html", null, true); + echo " + "; + } else { + // line 44 + echo " env, ($context["base_url"] ?? null), "html", null, true); + echo "\"> "; + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.BACK"), "html", null, true); + echo " + env, ($context["base_url_relative"] ?? null), "html", null, true); + echo "/plugins/install\"> "; + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.ADD"), "html", null, true); + echo " + "; + // line 46 + if ($this->env->getExtension('Grav\Common\Twig\TwigExtension')->authorize(array(0 => "admin.maintenance", 1 => "admin.super"))) { + // line 47 + echo " + "; + } + // line 49 + echo " "; + } + // line 50 + echo "
                                                              +

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

                                                              + "; + } else { + // line 53 + echo " "; + if (($context["installed"] ?? null)) { + // line 54 + echo "
                                                              + env, ($context["base_url_relative"] ?? null), "html", null, true); + echo "/plugins\"> "; + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.BACK_TO_PLUGINS"), "html", null, true); + echo " + "; + // line 56 + try { + $this->loadTemplate((("plugins/" . $this->getAttribute(($context["admin"] ?? null), "route", array())) . "-buttons.html.twig"), "plugins.html.twig", 56)->display($context); + } catch (Twig_Error_Loader $e) { + // ignore missing template + } + + // line 57 + echo " +
                                                              + "; + } else { + // line 60 + echo " + "; + } + // line 64 + echo " +

                                                              "; + // line 65 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.PLUGIN"), "html", null, true); + echo ": "; + echo twig_escape_filter($this->env, $this->getAttribute(($context["plugin"] ?? null), "name", array())); + echo "

                                                              + "; + } + } + + // line 69 + public function block_messages($context, array $blocks = array()) + { + // line 70 + echo " "; + $this->displayParentBlock("messages", $context, $blocks); + echo " + "; + // line 71 + if ($this->getAttribute($this->getAttribute($this->getAttribute($this->getAttribute(($context["config"] ?? null), "plugins", array()), "admin", array()), "notifications", array()), "plugins", array())) { + // line 72 + echo "
                                                              + "; + } + } + + // line 76 + public function block_content($context, array $blocks = array()) + { + // line 77 + echo "
                                                              + "; + // line 78 + if (( !$this->getAttribute(($context["admin"] ?? null), "route", array()) || ($context["installing"] ?? null))) { + // line 79 + echo " "; + $this->loadTemplate("partials/plugins-list.html.twig", "plugins.html.twig", 79)->display($context); + // line 80 + echo " "; + } else { + // line 81 + echo " "; + if ((null === ($context["plugin"] ?? null))) { + // line 82 + 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 84 + echo " + "; + // line 85 + $this->loadTemplate("partials/plugins-details.html.twig", "plugins.html.twig", 85)->display($context); + // line 86 + echo " "; + } + // line 87 + echo "
                                                              +"; + } + + public function getTemplateName() + { + return "plugins.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 237 => 87, 234 => 86, 232 => 85, 229 => 84, 223 => 82, 220 => 81, 217 => 80, 214 => 79, 212 => 78, 209 => 77, 206 => 76, 200 => 72, 198 => 71, 193 => 70, 190 => 69, 181 => 65, 178 => 64, 170 => 61, 167 => 60, 160 => 57, 153 => 56, 147 => 55, 144 => 54, 141 => 53, 136 => 51, 133 => 50, 130 => 49, 124 => 47, 122 => 46, 116 => 45, 109 => 44, 101 => 42, 99 => 41, 96 => 40, 93 => 39, 90 => 38, 83 => 34, 80 => 33, 73 => 30, 70 => 29, 67 => 28, 63 => 1, 60 => 27, 57 => 24, 53 => 21, 51 => 20, 48 => 17, 46 => 16, 44 => 15, 42 => 14, 40 => 11, 37 => 9, 35 => 8, 33 => 6, 31 => 5, 29 => 3, 11 => 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 Twig_Source("{% extends 'partials/base.html.twig' %} + +{% set plugin_slug = admin.route %} + +{% if plugin_slug %} + {% set installing = plugin_slug starts with 'install' %} + + {% if installing %} + {% set title = \"PLUGIN_ADMIN.PLUGINS\"|tu %} + {% else %} + {% set installed = true %} + + {# Try installed packages first, then remote #} + {% set package = admin.plugins(true)[admin.route] %} + {% if (not package) %} + {% set package = admin.plugins(false)[admin.route] %} + {% set installed = false %} + {% endif %} + + {% set plugin = package.toArray() %} + {% set title = \"PLUGIN_ADMIN.PLUGIN\"|tu ~ \": \" ~ plugin.name|e %} + {% endif %} +{% else %} + {% set title = \"PLUGIN_ADMIN.PLUGINS\"|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.PLUGINS\"|tu }}

                                                              + {% else %} + {% if (installed) %} +
                                                              + {{ \"PLUGIN_ADMIN.BACK_TO_PLUGINS\"|tu }} + {% include 'plugins/'~admin.route~'-buttons.html.twig' ignore missing %} + +
                                                              + {% else %} + + {% endif %} + +

                                                              {{ \"PLUGIN_ADMIN.PLUGIN\"|tu }}: {{ plugin.name|e }}

                                                              + {% endif %} +{% endblock %} + +{% block messages %} + {{ parent() }} + {% if config.plugins.admin.notifications.plugins %} +
                                                              + {% endif %} +{% endblock %} + +{% block content %} +
                                                              + {% if not admin.route or installing %} + {% include 'partials/plugins-list.html.twig' %} + {% else %} + {% if plugin is null %} + {{redirect_me(base_url_relative ~ '/404')}} + {% endif %} + + {% include 'partials/plugins-details.html.twig' %} + {% endif %} +
                                                              +{% endblock %} +", "plugins.html.twig", "/home/kevin/Sites/static-ethica.net/user/plugins/admin/themes/grav/templates/plugins.html.twig"); + } +} diff --git a/cache/twig/a1/a111ffac106480d70a72dba293e74dc76562004ca3ba8cbf17675b9e15bb3c32.php b/cache/twig/a1/a111ffac106480d70a72dba293e74dc76562004ca3ba8cbf17675b9e15bb3c32.php new file mode 100644 index 0000000..920a018 --- /dev/null +++ b/cache/twig/a1/a111ffac106480d70a72dba293e74dc76562004ca3ba8cbf17675b9e15bb3c32.php @@ -0,0 +1,89 @@ +parent = false; + + $this->blocks = array( + ); + } + + protected function doDisplay(array $context, array $blocks = array()) + { + // line 1 + $context["legend"] = array("VISIBLE" => "", "NON_ROUTABLE" => "not-routable", "NON_VISIBLE" => "not-visible", "MODULAR" => "modular"); + // line 2 + echo "
                                                              + "; + // line 3 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.LEGEND"), "html", null, true); + echo ": +
                                                                + "; + // line 5 + $context['_parent'] = $context; + $context['_seq'] = twig_ensure_traversable(($context["legend"] ?? null)); + foreach ($context['_seq'] as $context["key"] => $context["class"]) { + // line 6 + echo "
                                                              • env, $context["class"], "html", null, true); + echo "\"> "; + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter(("PLUGIN_ADMIN." . $context["key"])), "html", null, true); + echo "
                                                              • + "; + } + $_parent = $context['_parent']; + unset($context['_seq'], $context['_iterated'], $context['key'], $context['class'], $context['_parent'], $context['loop']); + $context = array_intersect_key($context, $_parent) + $_parent; + // line 8 + echo "
                                                              +
                                                              + + +"; + } + + public function getTemplateName() + { + return "partials/page-legend.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 44 => 8, 33 => 6, 29 => 5, 24 => 3, 21 => 2, 19 => 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 Twig_Source("{% set legend = {'VISIBLE':'', 'NON_ROUTABLE':'not-routable', 'NON_VISIBLE':'not-visible', 'MODULAR':'modular'} %} +
                                                              + {{ 'PLUGIN_ADMIN.LEGEND'|tu }}: +
                                                                + {% for key, class in legend %} +
                                                              • {{ ('PLUGIN_ADMIN.'~key)|tu }}
                                                              • + {% endfor %} +
                                                              +
                                                              + + +", "partials/page-legend.html.twig", "/mnt/data/Sites/static-ethica.net/user/plugins/admin/themes/grav/templates/partials/page-legend.html.twig"); + } +} diff --git a/cache/twig/a9/a9ef454ed7233f7dbc31ae8e11d5c917b4ec0aa1c5e1bd2b043791fd1ad330a1.php b/cache/twig/a9/a9ef454ed7233f7dbc31ae8e11d5c917b4ec0aa1c5e1bd2b043791fd1ad330a1.php new file mode 100644 index 0000000..7cc1191 --- /dev/null +++ b/cache/twig/a9/a9ef454ed7233f7dbc31ae8e11d5c917b4ec0aa1c5e1bd2b043791fd1ad330a1.php @@ -0,0 +1,108 @@ +parent = false; + + $this->blocks = array( + ); + } + + protected function doDisplay(array $context, array $blocks = array()) + { + // line 1 + $context["admin_messages"] = twig_array_merge($this->getAttribute(($context["admin"] ?? null), "messages", array()), $this->getAttribute(($context["admin"] ?? null), "getTempMessages", array(), "method")); + // line 2 + $context["form_message"] = $this->getAttribute(($context["form"] ?? null), "message", array()); + // 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", array())); + echo " alert\">"; + echo $this->getAttribute($context["message"], "message", array()); + 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", array())); + echo " alert\">"; + echo $this->getAttribute($context["message"], "message", array()); + 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 ( 63 => 14, 53 => 12, 49 => 11, 44 => 9, 42 => 8, 32 => 6, 28 => 5, 23 => 3, 21 => 2, 19 => 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 Twig_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", "/mnt/data/Sites/static-ethica.net/user/plugins/admin/themes/grav/templates/partials/messages.html.twig"); + } +} diff --git a/cache/twig/aa/aaab75792f569c46fa615c07b11a280129befc59c135accab1661b56ee376e04.php b/cache/twig/aa/aaab75792f569c46fa615c07b11a280129befc59c135accab1661b56ee376e04.php new file mode 100644 index 0000000..0bec0f8 --- /dev/null +++ b/cache/twig/aa/aaab75792f569c46fa615c07b11a280129befc59c135accab1661b56ee376e04.php @@ -0,0 +1,496 @@ +parent = false; + + $this->blocks = array( + 'field' => array($this, 'block_field'), + 'contents' => array($this, 'block_contents'), + 'label' => array($this, 'block_label'), + 'global_attributes' => array($this, 'block_global_attributes'), + 'group' => array($this, 'block_group'), + 'input' => array($this, 'block_input'), + 'prepend' => array($this, 'block_prepend'), + 'input_attributes' => array($this, 'block_input_attributes'), + 'append' => array($this, 'block_append'), + ); + } + + protected function doDisplay(array $context, array $blocks = array()) + { + // line 1 + $context["originalValue"] = ((array_key_exists("originalValue", $context)) ? (($context["originalValue"] ?? null)) : (($context["value"] ?? null))); + // line 2 + $context["toggleableChecked"] = ($this->getAttribute(($context["field"] ?? null), "toggleable", array()) && ( !(null === ($context["originalValue"] ?? null)) && !twig_test_empty(($context["originalValue"] ?? null)))); + // line 3 + $context["isDisabledToggleable"] = ($this->getAttribute(($context["field"] ?? null), "toggleable", array()) && !($context["toggleableChecked"] ?? null)); + // line 4 + $context["value"] = (((null === ($context["value"] ?? null))) ? ($this->getAttribute(($context["field"] ?? null), "default", array())) : (($context["value"] ?? null))); + // line 5 + $context["vertical"] = ($this->getAttribute(($context["field"] ?? null), "style", array()) == "vertical"); + // line 6 + $context["field_name"] = $this->env->getExtension('Grav\Common\Twig\TwigExtension')->fieldNameFilter((($context["scope"] ?? null) . $this->getAttribute(($context["field"] ?? null), "name", array()))); + // line 7 + echo " +"; + // line 8 + if (($this->getAttribute(($context["field"] ?? null), "yaml", array()) && twig_test_iterable(($context["value"] ?? null)))) { + // line 9 + echo " "; + $context["value"] = $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->toYamlFilter(($context["value"] ?? null)); + } + // line 11 + echo " +"; + // line 12 + $this->displayBlock('field', $context, $blocks); + } + + public function block_field($context, array $blocks = array()) + { + // line 13 + echo "
                                                              getAttribute(($context["field"] ?? null), "toggleable", array())) { + echo " form-field-toggleable"; + } + echo " "; + echo twig_escape_filter($this->env, $this->getAttribute(($context["field"] ?? null), "outerclasses", array()), "html", null, true); + echo " "; + echo twig_escape_filter($this->env, $this->getAttribute(($context["field"] ?? null), "field_classes", array()), "html", null, true); + echo "\"> + "; + // line 14 + $this->displayBlock('contents', $context, $blocks); + // line 89 + echo "
                                                              +"; + } + + // line 14 + public function block_contents($context, array $blocks = array()) + { + // line 15 + echo "
                                                              + "; + // line 16 + if ($this->getAttribute(($context["field"] ?? null), "toggleable", array())) { + // line 17 + echo " env, ($context["field_name"] ?? null), "html", null, true); + echo "\"> + env, $this->getAttribute(($context["field"] ?? null), "name", array()), "html", null, true); + echo "\" + "; + // line 20 + if (($context["toggleableChecked"] ?? null)) { + echo "value=\"1\""; + } + // line 21 + echo " name=\"toggleable_"; + echo twig_escape_filter($this->env, ($context["field_name"] ?? null), "html", null, true); + echo "\" + "; + // line 22 + if (($context["toggleableChecked"] ?? null)) { + echo "checked=\"checked\""; + } + // line 23 + echo " > + + + "; + } + // line 27 + echo " getAttribute(($context["field"] ?? null), "toggleable", array())) ? (((" class=\"toggleable\" for=\"toggleable_" . $this->getAttribute(($context["field"] ?? null), "name", array())) . "\"")) : ("")); + echo "> + "; + // line 28 + $this->displayBlock('label', $context, $blocks); + // line 36 + echo " + "; + // line 37 + if ($this->getAttribute(($context["field"] ?? null), "sublabel", array())) { + // line 38 + echo "
                                                              + "; + // line 39 + echo $this->env->getExtension('Grav\Common\Twig\TwigExtension')->markdownFilter($this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter($this->getAttribute(($context["field"] ?? null), "sublabel", array()))); + echo " +
                                                              + "; + } + // line 42 + echo "
                                                              +
                                                              displayBlock('global_attributes', $context, $blocks); + // line 49 + echo " > + "; + // line 50 + $this->displayBlock('group', $context, $blocks); + // line 82 + echo " "; + if ($this->getAttribute(($context["field"] ?? null), "description", array())) { + // line 83 + echo "
                                                              env, $this->getAttribute(($context["field"] ?? null), "size", array()), "html", null, true); + echo " "; + echo twig_escape_filter($this->env, $this->getAttribute(($context["field"] ?? null), "wrapper_classes", array()), "html", null, true); + echo "\"> + "; + // line 84 + echo $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter($this->getAttribute(($context["field"] ?? null), "description", array())); + echo " +
                                                              + "; + } + // line 87 + echo "
                                                              + "; + } + + // line 28 + public function block_label($context, array $blocks = array()) + { + // line 29 + echo " "; + if ($this->getAttribute(($context["field"] ?? null), "help", array())) { + // line 30 + echo " env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter($this->getAttribute(($context["field"] ?? null), "help", array())), "html"); + echo "\">"; + echo $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter($this->getAttribute(($context["field"] ?? null), "label", array())); + echo " + "; + } else { + // line 32 + echo " "; + echo $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter($this->getAttribute(($context["field"] ?? null), "label", array())); + echo " + "; + } + // line 34 + echo " "; + echo ((twig_in_filter($this->getAttribute($this->getAttribute(($context["field"] ?? null), "validate", array()), "required", array()), array(0 => "on", 1 => "true", 2 => 1))) ? ("*") : ("")); + echo " + "; + } + + // line 44 + public function block_global_attributes($context, array $blocks = array()) + { + // line 45 + echo " data-grav-field=\""; + echo twig_escape_filter($this->env, $this->getAttribute(($context["field"] ?? null), "type", array()), "html", null, true); + echo "\" + data-grav-disabled=\""; + // line 46 + echo twig_escape_filter($this->env, ($context["toggleableChecked"] ?? null), "html", null, true); + echo "\" + data-grav-default=\""; + // line 47 + echo twig_escape_filter($this->env, twig_jsonencode_filter($this->getAttribute(($context["field"] ?? null), "default", array())), "html_attr"); + echo "\" + "; + } + + // line 50 + public function block_group($context, array $blocks = array()) + { + // line 51 + echo " "; + $this->displayBlock('input', $context, $blocks); + // line 81 + echo " "; + } + + // line 51 + public function block_input($context, array $blocks = array()) + { + // line 52 + echo "
                                                              env, $this->getAttribute(($context["field"] ?? null), "size", array()), "html", null, true); + echo " "; + echo twig_escape_filter($this->env, $this->getAttribute(($context["field"] ?? null), "wrapper_classes", array()), "html", null, true); + echo "\"> + "; + // line 53 + $this->displayBlock('prepend', $context, $blocks); + // line 54 + echo " env, ($context["field_name"] ?? null), "html", null, true); + echo "\" + value=\""; + // line 57 + echo twig_escape_filter($this->env, twig_join_filter(($context["value"] ?? null), ", "), "html", null, true); + echo "\" + "; + // line 58 + if ($this->getAttribute(($context["field"] ?? null), "key", array())) { + // line 59 + echo " data-key-observe=\""; + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Common\Twig\TwigExtension')->fieldNameFilter((($context["scope"] ?? null) . ($context["field_name"] ?? null))), "html", null, true); + echo "\" + "; + } + // line 61 + echo " "; + // line 62 + echo " "; + $this->displayBlock('input_attributes', $context, $blocks); + // line 77 + echo " /> + "; + // line 78 + $this->displayBlock('append', $context, $blocks); + // line 79 + echo "
                                                              + "; + } + + // line 53 + public function block_prepend($context, array $blocks = array()) + { + } + + // line 62 + public function block_input_attributes($context, array $blocks = array()) + { + // line 63 + echo " "; + if ($this->getAttribute(($context["field"] ?? null), "classes", array(), "any", true, true)) { + echo "class=\""; + echo twig_escape_filter($this->env, $this->getAttribute(($context["field"] ?? null), "classes", array()), "html", null, true); + echo "\" "; + } + // line 64 + echo " "; + if ($this->getAttribute(($context["field"] ?? null), "id", array(), "any", true, true)) { + echo "id=\""; + echo twig_escape_filter($this->env, $this->getAttribute(($context["field"] ?? null), "id", array())); + echo "\" "; + } + // line 65 + echo " "; + if ($this->getAttribute(($context["field"] ?? null), "style", array(), "any", true, true)) { + echo "style=\""; + echo twig_escape_filter($this->env, $this->getAttribute(($context["field"] ?? null), "style", array())); + echo "\" "; + } + // line 66 + echo " "; + if (($this->getAttribute(($context["field"] ?? null), "disabled", array()) || ($context["isDisabledToggleable"] ?? null))) { + echo "disabled=\"disabled\""; + } + // line 67 + echo " "; + if ($this->getAttribute(($context["field"] ?? null), "placeholder", array())) { + echo "placeholder=\""; + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter($this->getAttribute(($context["field"] ?? null), "placeholder", array())), "html", null, true); + echo "\""; + } + // line 68 + echo " "; + if (twig_in_filter($this->getAttribute(($context["field"] ?? null), "autofocus", array()), array(0 => "on", 1 => "true", 2 => 1))) { + echo "autofocus=\"autofocus\""; + } + // line 69 + echo " "; + if (twig_in_filter($this->getAttribute(($context["field"] ?? null), "novalidate", array()), array(0 => "on", 1 => "true", 2 => 1))) { + echo "novalidate=\"novalidate\""; + } + // line 70 + echo " "; + if (twig_in_filter($this->getAttribute(($context["field"] ?? null), "readonly", array()), array(0 => "on", 1 => "true", 2 => 1))) { + echo "readonly=\"readonly\""; + } + // line 71 + echo " "; + if (twig_in_filter($this->getAttribute(($context["field"] ?? null), "autocomplete", array()), array(0 => "on", 1 => "off"))) { + echo "autocomplete=\""; + echo twig_escape_filter($this->env, $this->getAttribute(($context["field"] ?? null), "autocomplete", array()), "html", null, true); + echo "\""; + } + // line 72 + echo " "; + if (twig_in_filter($this->getAttribute($this->getAttribute(($context["field"] ?? null), "validate", array()), "required", array()), array(0 => "on", 1 => "true", 2 => 1))) { + echo "required=\"required\""; + } + // line 73 + echo " "; + if ($this->getAttribute($this->getAttribute(($context["field"] ?? null), "validate", array()), "pattern", array())) { + echo "pattern=\""; + echo twig_escape_filter($this->env, $this->getAttribute($this->getAttribute(($context["field"] ?? null), "validate", array()), "pattern", array()), "html", null, true); + echo "\""; + } + // line 74 + echo " "; + if ($this->getAttribute($this->getAttribute(($context["field"] ?? null), "validate", array()), "message", array())) { + echo "title=\""; + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter(twig_escape_filter($this->env, $this->getAttribute($this->getAttribute(($context["field"] ?? null), "validate", array()), "message", array()))), "html", null, true); + echo "\" + "; + } elseif ($this->getAttribute( // line 75 +($context["field"] ?? null), "title", array(), "any", true, true)) { + echo "title=\""; + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter(twig_escape_filter($this->env, $this->getAttribute(($context["field"] ?? null), "title", array()))), "html", null, true); + echo "\" "; + } + // line 76 + echo " "; + } + + // line 78 + public function block_append($context, array $blocks = array()) + { + } + + public function getTemplateName() + { + return "forms/field.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 375 => 78, 371 => 76, 365 => 75, 358 => 74, 351 => 73, 346 => 72, 339 => 71, 334 => 70, 329 => 69, 324 => 68, 317 => 67, 312 => 66, 305 => 65, 298 => 64, 291 => 63, 288 => 62, 283 => 53, 278 => 79, 276 => 78, 273 => 77, 270 => 62, 268 => 61, 262 => 59, 260 => 58, 256 => 57, 251 => 56, 248 => 54, 246 => 53, 239 => 52, 236 => 51, 232 => 81, 229 => 51, 226 => 50, 220 => 47, 216 => 46, 211 => 45, 208 => 44, 201 => 34, 195 => 32, 187 => 30, 184 => 29, 181 => 28, 176 => 87, 170 => 84, 163 => 83, 160 => 82, 158 => 50, 155 => 49, 153 => 44, 147 => 43, 144 => 42, 138 => 39, 135 => 38, 133 => 37, 130 => 36, 128 => 28, 123 => 27, 117 => 24, 114 => 23, 110 => 22, 105 => 21, 101 => 20, 97 => 19, 91 => 17, 89 => 16, 82 => 15, 79 => 14, 74 => 89, 72 => 14, 58 => 13, 52 => 12, 49 => 11, 45 => 9, 43 => 8, 40 => 7, 38 => 6, 36 => 5, 34 => 4, 32 => 3, 30 => 2, 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 Twig_Source("{% set originalValue = originalValue is defined ? originalValue : value %} +{% set toggleableChecked = field.toggleable and (originalValue is not null and originalValue is not empty) %} +{% set isDisabledToggleable = field.toggleable and not toggleableChecked %} +{% set value = (value is null ? field.default : value) %} +{% set vertical = field.style == 'vertical' %} +{% set field_name = (scope ~ field.name)|fieldName %} + +{% if field.yaml and value is iterable %} + {% set value = value|toYaml %} +{% endif %} + +{% block field %} +
                                                              + {% block contents %} +
                                                              + {% if field.toggleable %} + + + + + {% endif %} + + {% block label %} + {% if field.help %} + {{ field.label|tu|raw }} + {% else %} + {{ field.label|tu|raw }} + {% endif %} + {{ field.validate.required in ['on', 'true', 1] ? '*' }} + {% endblock %} + + {% if field.sublabel %} +
                                                              + {{ field.sublabel|tu|markdown|raw }} +
                                                              + {% endif %} +
                                                              +
                                                              + {% block group %} + {% block input %} +
                                                              + {% block prepend %}{% endblock prepend %} + + {% block append %}{% endblock append %} +
                                                              + {% endblock %} + {% endblock %} + {% if field.description %} +
                                                              + {{ field.description|tu|raw }} +
                                                              + {% endif %} +
                                                              + {% endblock %} +
                                                              +{% endblock %} +", "forms/field.html.twig", "/mnt/data/Sites/static-ethica.net/user/plugins/admin/themes/grav/templates/forms/field.html.twig"); + } +} diff --git a/cache/twig/ae/aeb5f05e4b2386a60361fa72599d0b0cace27f8f2d4a521a703f5a68530b51dc.php b/cache/twig/ae/aeb5f05e4b2386a60361fa72599d0b0cace27f8f2d4a521a703f5a68530b51dc.php new file mode 100644 index 0000000..7dd3fc7 --- /dev/null +++ b/cache/twig/ae/aeb5f05e4b2386a60361fa72599d0b0cace27f8f2d4a521a703f5a68530b51dc.php @@ -0,0 +1,147 @@ +parent = false; + + $this->blocks = array( + ); + } + + protected function doDisplay(array $context, array $blocks = array()) + { + // line 1 + $context["form_id"] = ((($context["form_id"] ?? null)) ? (($context["form_id"] ?? null)) : ("page-move")); + // line 2 + $context["scope"] = ((($context["scope"] ?? null)) ? (($context["scope"] ?? null)) : ("data.")); + // line 3 + echo " +
                                                              env, ($context["form_id"] ?? null), "html", null, true); + echo "\" method=\"post\" data-grav-form=\""; + echo twig_escape_filter($this->env, ($context["form_id"] ?? null), "html", null, true); + echo "\" data-page-move> + "; + // line 5 + $context['_parent'] = $context; + $context['_seq'] = twig_ensure_traversable($this->getAttribute(($context["blueprints"] ?? null), "fields", array())); + $context['loop'] = array( + 'parent' => $context['_parent'], + 'index0' => 0, + 'index' => 1, + 'first' => true, + ); + if (is_array($context['_seq']) || (is_object($context['_seq']) && $context['_seq'] instanceof Countable)) { + $length = count($context['_seq']); + $context['loop']['revindex0'] = $length - 1; + $context['loop']['revindex'] = $length; + $context['loop']['length'] = $length; + $context['loop']['last'] = 1 === $length; + } + foreach ($context['_seq'] as $context["_key"] => $context["field"]) { + // line 6 + echo " "; + if ($this->getAttribute($context["field"], "type", array())) { + // line 7 + echo " "; + $context["value"] = (($this->getAttribute($context["field"], "name", array())) ? ($this->getAttribute(($context["data"] ?? null), "value", array(0 => $this->getAttribute($context["field"], "name", array())), "method")) : ($this->getAttribute(($context["data"] ?? null), "toArray", array()))); + // line 8 + echo "
                                                              env, $this->getAttribute($context["field"], "type", array()), "html", null, true); + echo "\"> + "; + // line 9 + $this->loadTemplate(array(0 => (((("forms/fields/" . $this->getAttribute($context["field"], "type", array())) . "/") . $this->getAttribute($context["field"], "type", array())) . ".html.twig"), 1 => "forms/fields/text/text.html.twig"), "partials/page-move.html.twig", 9)->display($context); + // line 10 + echo "
                                                              + "; + } + // line 12 + echo " "; + ++$context['loop']['index0']; + ++$context['loop']['index']; + $context['loop']['first'] = false; + if (isset($context['loop']['length'])) { + --$context['loop']['revindex0']; + --$context['loop']['revindex']; + $context['loop']['last'] = 0 === $context['loop']['revindex0']; + } + } + $_parent = $context['_parent']; + unset($context['_seq'], $context['_iterated'], $context['_key'], $context['field'], $context['_parent'], $context['loop']); + $context = array_intersect_key($context, $_parent) + $_parent; + // line 13 + echo " + "; + // line 14 + echo $this->env->getExtension('Grav\Common\Twig\TwigExtension')->nonceFieldFunc("admin-form", "admin-nonce"); + echo " + +
                                                              + + +
                                                              +
                                                              +"; + } + + public function getTemplateName() + { + return "partials/page-move.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 93 => 18, 89 => 17, 83 => 14, 80 => 13, 66 => 12, 62 => 10, 60 => 9, 55 => 8, 52 => 7, 49 => 6, 32 => 5, 26 => 4, 23 => 3, 21 => 2, 19 => 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 Twig_Source("{% set form_id = form_id ? form_id : 'page-move' %} +{% set scope = scope ?: 'data.' %} + +
                                                              + {% for field in blueprints.fields %} + {% if field.type %} + {% set 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 %} + + {{ nonce_field('admin-form', 'admin-nonce')|raw }} + +
                                                              + + +
                                                              +
                                                              +", "partials/page-move.html.twig", "/mnt/data/Sites/static-ethica.net/user/plugins/admin/themes/grav/templates/partials/page-move.html.twig"); + } +} diff --git a/cache/twig/ae/aef6fb2127795c7010db5033b32f378aa015920bc09f1e816cf537ea4d8d1173.php b/cache/twig/ae/aef6fb2127795c7010db5033b32f378aa015920bc09f1e816cf537ea4d8d1173.php new file mode 100644 index 0000000..e0f0ec9 --- /dev/null +++ b/cache/twig/ae/aef6fb2127795c7010db5033b32f378aa015920bc09f1e816cf537ea4d8d1173.php @@ -0,0 +1,216 @@ +parent = false; + + $this->blocks = array( + 'label' => array($this, 'block_label'), + 'field' => array($this, 'block_field'), + ); + } + + protected function doDisplay(array $context, array $blocks = array()) + { + // line 1 + $context["value"] = (((null === ($context["value"] ?? null))) ? ($this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter($this->getAttribute(($context["field"] ?? null), "default", array()))) : (($context["value"] ?? null))); + // line 2 + if ( !($context["codemirrorOptions"] ?? null)) { + // line 3 + echo " "; + $context["codemirrorOptions"] = twig_array_merge(array("mode" => "gfm", "ignore" => array(0 => "code", 1 => "preview")), (($this->getAttribute(($context["field"] ?? null), "codemirror", array(), "any", true, true)) ? (_twig_default_filter($this->getAttribute(($context["field"] ?? null), "codemirror", array()), array())) : (array()))); + } + // line 5 + echo " +"; + // line 6 + $this->displayBlock('label', $context, $blocks); + // line 12 + $this->displayBlock('field', $context, $blocks); + } + + // line 6 + public function block_label($context, array $blocks = array()) + { + // line 7 + echo " "; + if ($this->getAttribute(($context["field"] ?? null), "label", array())) { + // line 8 + echo " "; + $context["hint"] = (($this->getAttribute(($context["field"] ?? null), "help", array())) ? ((("data-hint=\"" . $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter($this->getAttribute(($context["field"] ?? null), "help", array()))) . "\"")) : ("")); + // line 9 + echo "
                                                              env, ($context["hint"] ?? null), "html", null, true); + echo ">"; + echo $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter($this->getAttribute(($context["field"] ?? null), "label", array())); + echo "
                                                              + "; + } + } + + // line 12 + public function block_field($context, array $blocks = array()) + { + // line 13 + echo "
                                                              env, (($this->getAttribute(($context["field"] ?? null), "classes", array(), "any", true, true)) ? (_twig_default_filter($this->getAttribute(($context["field"] ?? null), "classes", array()), "")) : ("")), "html", null, true); + echo "\"> +
                                                              +
                                                              + +
                                                              + "; + // line 32 + if (( !$this->getAttribute(($context["field"] ?? null), "resizer", array(), "any", true, true) || !twig_in_filter($this->getAttribute(($context["field"] ?? null), "resizer", array()), array(0 => "off", 1 => "false", 2 => 0)))) { + echo "
                                                              "; + } + // line 33 + echo "
                                                              +
                                                              +"; + } + + public function getTemplateName() + { + return "forms/fields/editor/editor.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 149 => 33, 145 => 32, 138 => 30, 129 => 29, 124 => 28, 119 => 27, 114 => 26, 109 => 25, 102 => 24, 97 => 23, 90 => 22, 83 => 21, 77 => 20, 73 => 19, 68 => 17, 60 => 13, 57 => 12, 47 => 9, 44 => 8, 41 => 7, 38 => 6, 34 => 12, 32 => 6, 29 => 5, 25 => 3, 23 => 2, 21 => 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 Twig_Source("{% set value = (value is null ? field.default|tu : value) %} +{% if not codemirrorOptions %} + {% set codemirrorOptions = {'mode': 'gfm', 'ignore': ['code', 'preview']}|merge(field.codemirror|default({})) %} +{% endif %} + +{% block label %} + {% if field.label %} + {% set hint = field.help ? 'data-hint=\"' ~ field.help|tu|raw ~ '\"': '' %} +
                                                              {{ field.label|tu|raw }}
                                                              + {% endif %} +{% endblock %} +{% block field %} +
                                                              +
                                                              +
                                                              + +
                                                              + {% if field.resizer is not defined or field.resizer not in ['off', 'false', 0] %}
                                                              {% endif %} +
                                                              +
                                                              +{% endblock %} +", "forms/fields/editor/editor.html.twig", "/mnt/data/Sites/static-ethica.net/user/plugins/admin/themes/grav/templates/forms/fields/editor/editor.html.twig"); + } +} diff --git a/cache/twig/b1/b18f57dfabce59fde3f42b1cf1b07212b4f3dda9ac5dd2f02aa9fe3ff5a4a867.php b/cache/twig/b1/b18f57dfabce59fde3f42b1cf1b07212b4f3dda9ac5dd2f02aa9fe3ff5a4a867.php new file mode 100644 index 0000000..592a9b8 --- /dev/null +++ b/cache/twig/b1/b18f57dfabce59fde3f42b1cf1b07212b4f3dda9ac5dd2f02aa9fe3ff5a4a867.php @@ -0,0 +1,149 @@ +parent = false; + + $this->blocks = array( + ); + } + + protected function doDisplay(array $context, array $blocks = array()) + { + // line 1 + if ($this->env->getExtension('Grav\Common\Twig\TwigExtension')->authorize(array(0 => "admin.maintenance", 1 => "admin.super"))) { + // line 2 + echo " "; + $context["backup"] = $this->getAttribute(($context["admin"] ?? null), "lastBackup", array(), "method"); + // line 3 + echo " +
                                                              +
                                                              +

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

                                                              +
                                                              +
                                                              env, twig_jsonencode_filter(array("series" => array(0 => 100, 1 => 0))), "html_attr"); + echo "\"> +
                                                              +
                                                              + -"; + // line 11 + echo twig_escape_filter($this->env, twig_lower_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.UPDATED")), "html", null, true); + echo " +
                                                              +

                                                               

                                                              +
                                                              +
                                                              env, twig_jsonencode_filter(array("series" => array(0 => $this->getAttribute(($context["backup"] ?? null), "chart_fill", array()), 1 => $this->getAttribute(($context["backup"] ?? null), "chart_empty", array())))), "html_attr"); + echo "\"> +
                                                              +
                                                              + "; + // line 18 + echo $this->getAttribute(($context["backup"] ?? null), "days", array()); + echo ""; + echo twig_escape_filter($this->env, twig_lower_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.DAYS")), "html", null, true); + echo " +
                                                              +

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

                                                              +
                                                              +
                                                              + +
                                                              + "; + // line 25 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.UPDATE"), "html", null, true); + echo " + +
                                                              +
                                                              +
                                                              + + "; + // line 31 + $this->loadTemplate("partials/modal-update-packages.html.twig", "partials/dashboard-maintenance.html.twig", 31)->display(array_merge($context, array("type" => "plugin"))); + // line 32 + echo " +"; + } + } + + public function getTemplateName() + { + return "partials/dashboard-maintenance.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 84 => 32, 82 => 31, 72 => 26, 68 => 25, 60 => 20, 53 => 18, 47 => 15, 40 => 11, 34 => 8, 29 => 6, 24 => 3, 21 => 2, 19 => 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 Twig_Source("{% if authorize(['admin.maintenance', 'admin.super']) %} + {% set backup = admin.lastBackup() %} + +
                                                              +
                                                              +

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

                                                              +
                                                              +
                                                              +
                                                              +
                                                              + -{{ \"PLUGIN_ADMIN.UPDATED\"|tu|lower }} +
                                                              +

                                                               

                                                              +
                                                              +
                                                              +
                                                              +
                                                              + {{ backup.days|raw }}{{ \"PLUGIN_ADMIN.DAYS\"|tu|lower }} +
                                                              +

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

                                                              +
                                                              +
                                                              + +
                                                              + {{ \"PLUGIN_ADMIN.UPDATE\"|tu }} + +
                                                              +
                                                              +
                                                              + + {% include 'partials/modal-update-packages.html.twig' with { type: 'plugin' } %} + +{% endif %} +", "partials/dashboard-maintenance.html.twig", "/mnt/data/Sites/static-ethica.net/user/plugins/admin/themes/grav/templates/partials/dashboard-maintenance.html.twig"); + } +} diff --git a/cache/twig/b8/b86bb10cf6982d6681f8542d8b57c295a3ded88da8fb884d127da8003f42e7e4.php b/cache/twig/b8/b86bb10cf6982d6681f8542d8b57c295a3ded88da8fb884d127da8003f42e7e4.php new file mode 100644 index 0000000..2e55734 --- /dev/null +++ b/cache/twig/b8/b86bb10cf6982d6681f8542d8b57c295a3ded88da8fb884d127da8003f42e7e4.php @@ -0,0 +1,100 @@ +parent = false; + + $this->blocks = array( + ); + } + + protected function doDisplay(array $context, array $blocks = array()) + { + // line 1 + echo "
                                                              +
                                                              + "; + // line 3 + $this->loadTemplate("partials/userinfo-avatar.html.twig", "forms/fields/userinfo/userinfo.html.twig", 3)->display($context); + // line 4 + echo "
                                                              +
                                                              +

                                                              "; + // line 6 + echo twig_escape_filter($this->env, $this->getAttribute(($context["data"] ?? null), "fullname", array()), "html", null, true); + echo "

                                                              +
                                                              + env, $this->getAttribute(($context["data"] ?? null), "email", array()), "html", null, true); + echo "\">"; + echo twig_escape_filter($this->env, $this->getAttribute(($context["data"] ?? null), "email", array()), "html", null, true); + echo " + "; + // line 9 + if ($this->getAttribute(($context["data"] ?? null), "title", array())) { + // line 10 + echo " - "; + echo twig_escape_filter($this->env, $this->getAttribute(($context["data"] ?? null), "title", array()), "html", null, true); + echo " + "; + } + // line 12 + echo "
                                                              + "; + // line 13 + $this->loadTemplate("partials/userinfo-avatar-credit.html.twig", "forms/fields/userinfo/userinfo.html.twig", 13)->display($context); + // line 14 + echo "
                                                              +
                                                              +"; + } + + public function getTemplateName() + { + return "forms/fields/userinfo/userinfo.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 53 => 14, 51 => 13, 48 => 12, 42 => 10, 40 => 9, 34 => 8, 29 => 6, 25 => 4, 23 => 3, 19 => 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 Twig_Source("
                                                              +
                                                              + {% include 'partials/userinfo-avatar.html.twig' %} +
                                                              +
                                                              +

                                                              {{ data.fullname }}

                                                              +
                                                              + {{ data.email }} + {% if data.title %} + - {{ data.title }} + {% endif %} +
                                                              + {% include 'partials/userinfo-avatar-credit.html.twig' %} +
                                                              +
                                                              +", "forms/fields/userinfo/userinfo.html.twig", "/home/kevin/Sites/static-ethica.net/user/plugins/admin/themes/grav/templates/forms/fields/userinfo/userinfo.html.twig"); + } +} diff --git a/cache/twig/be/beff29a63c74de8922d7ce27d387ac2dd6c0a881d21868ecc062b757db714249.php b/cache/twig/be/beff29a63c74de8922d7ce27d387ac2dd6c0a881d21868ecc062b757db714249.php new file mode 100644 index 0000000..a6ed13b --- /dev/null +++ b/cache/twig/be/beff29a63c74de8922d7ce27d387ac2dd6c0a881d21868ecc062b757db714249.php @@ -0,0 +1,167 @@ +parent = false; + + $this->blocks = array( + ); + } + + protected function doDisplay(array $context, array $blocks = array()) + { + // line 1 + if ($this->env->getExtension('Grav\Common\Twig\TwigExtension')->authorize(array(0 => "admin.login", 1 => "admin.super"))) { + // line 2 + $context["notifications"] = ((((($this->getAttribute($this->getAttribute($this->getAttribute($this->getAttribute(($context["config"] ?? null), "plugins", array()), "admin", array()), "widgets", array()), "dashboard-notifications", array(), "array") || $this->getAttribute($this->getAttribute($this->getAttribute($this->getAttribute(($context["config"] ?? null), "plugins", array()), "admin", array()), "notifications", array()), "dashboard", array())) || $this->getAttribute($this->getAttribute($this->getAttribute($this->getAttribute(($context["config"] ?? null), "plugins", array()), "admin", array()), "notifications", array()), "plugins", array())) || $this->getAttribute($this->getAttribute($this->getAttribute($this->getAttribute(($context["config"] ?? null), "plugins", array()), "admin", array()), "notifications", array()), "themes", array()))) ? (1) : (0)); + // line 3 + echo " +"; + } + } + + public function getTemplateName() + { + return "partials/javascript-config.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 105 => 29, 94 => 27, 90 => 26, 82 => 21, 77 => 19, 73 => 18, 69 => 17, 65 => 16, 61 => 15, 56 => 14, 50 => 12, 48 => 11, 44 => 10, 40 => 9, 36 => 8, 32 => 7, 28 => 6, 23 => 3, 21 => 2, 19 => 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 Twig_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 %} + +{% endif %} +", "partials/javascript-config.html.twig", "/mnt/data/Sites/static-ethica.net/user/plugins/admin/themes/grav/templates/partials/javascript-config.html.twig"); + } +} diff --git a/cache/twig/bf/bf416c75832660643ab0d6a162c0808961d66cdf768f72887eebafed9b001e18.php b/cache/twig/bf/bf416c75832660643ab0d6a162c0808961d66cdf768f72887eebafed9b001e18.php new file mode 100644 index 0000000..efe7ac5 --- /dev/null +++ b/cache/twig/bf/bf416c75832660643ab0d6a162c0808961d66cdf768f72887eebafed9b001e18.php @@ -0,0 +1,171 @@ +parent = false; + + $this->blocks = array( + ); + } + + protected function doDisplay(array $context, array $blocks = array()) + { + // line 1 + echo "
                                                                +"; + // line 2 + $context['_parent'] = $context; + $context['_seq'] = twig_ensure_traversable($this->getAttribute(($context["langswitcher"] ?? null), "languages", array())); + foreach ($context['_seq'] as $context["_key"] => $context["language"]) { + // line 3 + echo " + "; + // line 4 + $context["show_language"] = true; + // line 5 + echo " "; + if (($context["language"] == $this->getAttribute(($context["langswitcher"] ?? null), "current", array()))) { + // line 6 + echo " "; + $context["lang_url"] = $this->getAttribute(($context["page"] ?? null), "url", array()); + // line 7 + echo " "; + $context["active_class"] = " active"; + // line 8 + echo " "; + } else { + // line 9 + echo " "; + $context["base_lang_url"] = (($context["base_url_simple"] ?? null) . $this->getAttribute($this->getAttribute(($context["grav"] ?? null), "language", array()), "getLanguageURLPrefix", array(0 => $context["language"]), "method")); + // line 10 + echo " "; + $context["lang_url"] = ((($context["base_lang_url"] ?? null) . $this->getAttribute(($context["langswitcher"] ?? null), "page_route", array())) . $this->getAttribute(($context["page"] ?? null), "urlExtension", array())); + // line 11 + echo " "; + $context["untranslated_pages_behavior"] = $this->getAttribute($this->getAttribute($this->getAttribute($this->getAttribute(($context["grav"] ?? null), "config", array()), "plugins", array()), "langswitcher", array()), "untranslated_pages_behavior", array()); + // line 12 + echo " "; + if ((($context["untranslated_pages_behavior"] ?? null) != "none")) { + // line 13 + echo " "; + $context["translated_page"] = $this->getAttribute($this->getAttribute(($context["langswitcher"] ?? null), "translated_pages", array()), $context["language"], array(), "array"); + // line 14 + echo " "; + if (( !($context["translated_page"] ?? null) || !$this->getAttribute(($context["translated_page"] ?? null), "published", array()))) { + // line 15 + echo " "; + if ((($context["untranslated_pages_behavior"] ?? null) == "redirect")) { + // line 16 + echo " "; + $context["lang_url"] = (($context["base_lang_url"] ?? null) . "/"); + // line 17 + echo " "; + } elseif ((($context["untranslated_pages_behavior"] ?? null) == "hide")) { + // line 18 + echo " "; + $context["show_language"] = false; + // line 19 + echo " "; + } + // line 20 + echo " "; + } + // line 21 + echo " "; + } + // line 22 + echo " "; + $context["active_class"] = ""; + // line 23 + echo " "; + } + // line 24 + echo " + "; + // line 25 + if (($context["show_language"] ?? null)) { + // line 26 + echo "
                                                              • getAttribute(($context["uri"] ?? null), "params", array())); + echo "\" class=\"external"; + echo ($context["active_class"] ?? null); + echo "\">"; + echo twig_capitalize_string_filter($this->env, call_user_func_array($this->env->getFunction('native_name')->getCallable(), array($context["language"]))); + echo "
                                                              • + "; + } + // line 28 + echo " +"; + } + $_parent = $context['_parent']; + unset($context['_seq'], $context['_iterated'], $context['_key'], $context['language'], $context['_parent'], $context['loop']); + $context = array_intersect_key($context, $_parent) + $_parent; + // line 30 + echo "
                                                              +"; + } + + public function getTemplateName() + { + return "partials/langswitcher.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 110 => 30, 103 => 28, 93 => 26, 91 => 25, 88 => 24, 85 => 23, 82 => 22, 79 => 21, 76 => 20, 73 => 19, 70 => 18, 67 => 17, 64 => 16, 61 => 15, 58 => 14, 55 => 13, 52 => 12, 49 => 11, 46 => 10, 43 => 9, 40 => 8, 37 => 7, 34 => 6, 31 => 5, 29 => 4, 26 => 3, 22 => 2, 19 => 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 Twig_Source("
                                                                +{% for language in langswitcher.languages %} + + {% set show_language = true %} + {% if language == langswitcher.current %} + {% set lang_url = page.url %} + {% set active_class = ' active' %} + {% else %} + {% set base_lang_url = base_url_simple ~ grav.language.getLanguageURLPrefix(language) %} + {% set lang_url = base_lang_url ~ langswitcher.page_route ~ page.urlExtension %} + {% set untranslated_pages_behavior = grav.config.plugins.langswitcher.untranslated_pages_behavior %} + {% if untranslated_pages_behavior != 'none' %} + {% set translated_page = langswitcher.translated_pages[language] %} + {% if (not translated_page) or (not translated_page.published) %} + {% if untranslated_pages_behavior == 'redirect' %} + {% set lang_url = base_lang_url ~ '/' %} + {% elseif untranslated_pages_behavior == 'hide' %} + {% set show_language = false %} + {% endif %} + {% endif %} + {% endif %} + {% set active_class = '' %} + {% endif %} + + {% if show_language %} +
                                                              • {{ native_name(language)|capitalize }}
                                                              • + {% endif %} + +{% endfor %} +
                                                              +", "partials/langswitcher.html.twig", "/home/kevin/Sites/static-ethica.net/user/themes/ethica/templates/partials/langswitcher.html.twig"); + } +} diff --git a/cache/twig/c3/c3536cdec3e321d3569e6b10f9d5dec8656ef13e9b9c660e76a460829e79a7b9.php b/cache/twig/c3/c3536cdec3e321d3569e6b10f9d5dec8656ef13e9b9c660e76a460829e79a7b9.php new file mode 100644 index 0000000..0b60f51 --- /dev/null +++ b/cache/twig/c3/c3536cdec3e321d3569e6b10f9d5dec8656ef13e9b9c660e76a460829e79a7b9.php @@ -0,0 +1,150 @@ +parent = $this->loadTemplate("forms/field.html.twig", "forms/fields/datetime/datetime.html.twig", 1); + $this->blocks = array( + 'input' => array($this, 'block_input'), + 'input_attributes' => array($this, 'block_input_attributes'), + ); + } + + protected function doGetParent(array $context) + { + return "forms/field.html.twig"; + } + + protected function doDisplay(array $context, array $blocks = array()) + { + // line 3 + $context["value"] = (((null === ($context["value"] ?? null))) ? ($this->getAttribute(($context["field"] ?? null), "default", array())) : (($context["value"] ?? null))); + // line 4 + $context["default_php_dateformat"] = $this->getAttribute(($context["admin"] ?? null), "guessDateFormat", array(0 => ($context["value"] ?? null)), "method"); + // line 5 + $context["php_dateformat"] = (($this->getAttribute(($context["field"] ?? null), "format", array())) ? ($this->getAttribute(($context["field"] ?? null), "format", array())) : ((($this->getAttribute($this->getAttribute(($context["admin"] ?? null), "page", array()), "dateformat", array())) ? ($this->getAttribute($this->getAttribute(($context["admin"] ?? null), "page", array()), "dateformat", array())) : ((($this->getAttribute($this->getAttribute($this->getAttribute($this->getAttribute(($context["config"] ?? null), "system", array()), "pages", array()), "dateformat", array()), "default", array())) ? ($this->getAttribute($this->getAttribute($this->getAttribute($this->getAttribute(($context["config"] ?? null), "system", array()), "pages", array()), "dateformat", array()), "default", array())) : (($context["default_php_dateformat"] ?? null))))))); + // line 6 + $context["js_dateformat"] = $this->getAttribute(($context["admin"] ?? null), "dateformatToMomentJS", array(0 => ($context["php_dateformat"] ?? null)), "method"); + // line 7 + $context["value"] = (((null === ($context["value"] ?? null))) ? (($context["value"] ?? null)) : (twig_date_format_filter($this->env, ($context["value"] ?? null), ($context["php_dateformat"] ?? null)))); + // line 1 + $this->parent->display($context, array_merge($this->blocks, $blocks)); + } + + // line 9 + public function block_input($context, array $blocks = array()) + { + // line 10 + echo "
                                                              env, $this->getAttribute(($context["field"] ?? null), "size", array()), "html", null, true); + echo "\"> + env, $this->env->getExtension('Grav\Common\Twig\TwigExtension')->fieldNameFilter((($context["scope"] ?? null) . $this->getAttribute(($context["field"] ?? null), "name", array()))), "html", null, true); + echo "\" + value=\""; + // line 13 + echo twig_escape_filter($this->env, twig_join_filter(($context["value"] ?? null), ", "), "html", null, true); + echo "\" + "; + // line 14 + $this->displayBlock('input_attributes', $context, $blocks); + // line 21 + echo " /> + + + +
                                                              +"; + } + + // line 14 + public function block_input_attributes($context, array $blocks = array()) + { + // line 15 + echo " type=\"text\" + data-grav-datetime=\""; + // line 16 + echo twig_escape_filter($this->env, twig_jsonencode_filter(array("format" => ($context["js_dateformat"] ?? null))), "html_attr"); + echo "\" + "; + // line 17 + if ($this->getAttribute($this->getAttribute(($context["field"] ?? null), "validate", array()), "min", array())) { + echo "min=\""; + echo twig_escape_filter($this->env, (((null === $this->getAttribute($this->getAttribute(($context["field"] ?? null), "validate", array()), "min", array()))) ? ($this->getAttribute($this->getAttribute(($context["field"] ?? null), "validate", array()), "min", array())) : (twig_date_format_filter($this->env, $this->getAttribute($this->getAttribute(($context["field"] ?? null), "validate", array()), "min", array()), ($context["php_dateformat"] ?? null)))), "html", null, true); + echo "\""; + } + // line 18 + echo " "; + if ($this->getAttribute($this->getAttribute(($context["field"] ?? null), "validate", array()), "max", array())) { + echo "max=\""; + echo twig_escape_filter($this->env, (((null === $this->getAttribute($this->getAttribute(($context["field"] ?? null), "validate", array()), "max", array()))) ? ($this->getAttribute($this->getAttribute(($context["field"] ?? null), "validate", array()), "max", array())) : (twig_date_format_filter($this->env, $this->getAttribute($this->getAttribute(($context["field"] ?? null), "validate", array()), "max", array()), ($context["php_dateformat"] ?? null)))), "html", null, true); + echo "\""; + } + // line 19 + echo " "; + $this->displayParentBlock("input_attributes", $context, $blocks); + echo " + "; + } + + public function getTemplateName() + { + return "forms/fields/datetime/datetime.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 91 => 19, 84 => 18, 78 => 17, 74 => 16, 71 => 15, 68 => 14, 59 => 21, 57 => 14, 53 => 13, 49 => 12, 43 => 10, 40 => 9, 36 => 1, 34 => 7, 32 => 6, 30 => 5, 28 => 4, 26 => 3, 11 => 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 Twig_Source("{% extends \"forms/field.html.twig\" %} + +{% set value = (value is null ? field.default : value) %} +{% set default_php_dateformat = admin.guessDateFormat(value) %} +{% set php_dateformat = field.format ?: admin.page.dateformat ?: config.system.pages.dateformat.default ?: default_php_dateformat %} +{% set js_dateformat = admin.dateformatToMomentJS(php_dateformat) %} +{% set value = (value is null ? value : value|date(php_dateformat)) %} + +{% block input %} +
                                                              + + + + +
                                                              +{% endblock %} +", "forms/fields/datetime/datetime.html.twig", "/mnt/data/Sites/static-ethica.net/user/plugins/admin/themes/grav/templates/forms/fields/datetime/datetime.html.twig"); + } +} diff --git a/cache/twig/c3/c39576bf7e338d2db8a01734a28691e416318cf45eb59e62793eba12e4cccf00.php b/cache/twig/c3/c39576bf7e338d2db8a01734a28691e416318cf45eb59e62793eba12e4cccf00.php new file mode 100644 index 0000000..28cb8e5 --- /dev/null +++ b/cache/twig/c3/c39576bf7e338d2db8a01734a28691e416318cf45eb59e62793eba12e4cccf00.php @@ -0,0 +1,122 @@ +parent = false; + + $this->blocks = array( + ); + } + + protected function doDisplay(array $context, array $blocks = array()) + { + // line 1 + if ($this->env->getExtension('Grav\Common\Twig\TwigExtension')->authorize(array(0 => "admin.pages", 1 => "admin.super"))) { + // line 2 + echo "
                                                              + +

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

                                                              + + "; + // line 8 + $context['_parent'] = $context; + $context['_seq'] = twig_ensure_traversable($this->getAttribute(($context["admin"] ?? null), "latestPages", array())); + foreach ($context['_seq'] as $context["_key"] => $context["latest"]) { + if ($this->getAttribute(($context["admin"] ?? null), "latestPages", array())) { + // line 9 + echo " + + + + "; + } + } + $_parent = $context['_parent']; + unset($context['_seq'], $context['_iterated'], $context['_key'], $context['latest'], $context['_parent'], $context['loop']); + $context = array_intersect_key($context, $_parent) + $_parent; + // line 15 + echo "
                                                              + env, ($context["base_url"] ?? null), "html", null, true); + echo "/pages/"; + echo twig_escape_filter($this->env, twig_trim_filter($this->getAttribute($context["latest"], "route", array()), "/"), "html", null, true); + echo "\"> "; + echo twig_escape_filter($this->env, $this->getAttribute($context["latest"], "title", array())); + echo ""; + // line 12 + echo twig_escape_filter($this->env, $this->getAttribute($context["latest"], "route", array()), "html", null, true); + echo ""; + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->adminNicetimeFilter($this->getAttribute($context["latest"], "modified", array())), "html", null, true); + echo "
                                                              +
                                                              +"; + } else { + // line 18 + echo "
                                                              You don't have sufficient access to view the dashboard...
                                                              +"; + } + } + + public function getTemplateName() + { + return "partials/dashboard-pages.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 71 => 18, 66 => 15, 54 => 12, 46 => 11, 42 => 9, 37 => 8, 32 => 6, 25 => 4, 21 => 2, 19 => 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 Twig_Source("{% if authorize(['admin.pages', 'admin.super']) %} +
                                                              + +

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

                                                              + + {% for latest in admin.latestPages if admin.latestPages %} + + + + + {% endfor %} +
                                                              + {{ latest.title|e }}{{ latest.route }}{{ latest.modified|adminNicetime }}
                                                              +
                                                              +{% else %} +
                                                              You don't have sufficient access to view the dashboard...
                                                              +{% endif %} +", "partials/dashboard-pages.html.twig", "/mnt/data/Sites/static-ethica.net/user/plugins/admin/themes/grav/templates/partials/dashboard-pages.html.twig"); + } +} diff --git a/cache/twig/c3/c3d6c64fb670f8a9494ba77a1fb2155059144c780aa355f72f5915c89cf2f2de.php b/cache/twig/c3/c3d6c64fb670f8a9494ba77a1fb2155059144c780aa355f72f5915c89cf2f2de.php new file mode 100644 index 0000000..d873308 --- /dev/null +++ b/cache/twig/c3/c3d6c64fb670f8a9494ba77a1fb2155059144c780aa355f72f5915c89cf2f2de.php @@ -0,0 +1,111 @@ +parent = false; + + $this->blocks = array( + ); + } + + protected function doDisplay(array $context, array $blocks = array()) + { + // line 1 + if ($this->getAttribute(($context["field"] ?? null), "fields", array())) { + // line 2 + echo "
                                                              env, ($context["cols"] ?? null), "html", null, true); + echo "\"> + "; + // line 3 + $context['_parent'] = $context; + $context['_seq'] = twig_ensure_traversable($this->getAttribute($context["field"], "fields", array())); + $context['loop'] = array( + 'parent' => $context['_parent'], + 'index0' => 0, + 'index' => 1, + 'first' => true, + ); + if (is_array($context['_seq']) || (is_object($context['_seq']) && $context['_seq'] instanceof Countable)) { + $length = count($context['_seq']); + $context['loop']['revindex0'] = $length - 1; + $context['loop']['revindex'] = $length; + $context['loop']['length'] = $length; + $context['loop']['last'] = 1 === $length; + } + foreach ($context['_seq'] as $context["_key"] => $context["field"]) { + // line 4 + echo " "; + if ($this->getAttribute($context["field"], "type", array())) { + // line 5 + echo " "; + $context["value"] = (($this->getAttribute($context["field"], "name", array())) ? ($this->getAttribute(($context["data"] ?? null), "value", array(0 => $this->getAttribute($context["field"], "name", array())), "method")) : ($this->getAttribute(($context["data"] ?? null), "toArray", array()))); + // line 6 + echo " "; + $this->loadTemplate(array(0 => (((("forms/fields/" . $this->getAttribute($context["field"], "type", array())) . "/") . $this->getAttribute($context["field"], "type", array())) . ".html.twig"), 1 => "forms/fields/text/text.html.twig"), "forms/fields/column/column.html.twig", 6)->display($context); + // line 7 + echo " "; + } + // line 8 + echo " "; + ++$context['loop']['index0']; + ++$context['loop']['index']; + $context['loop']['first'] = false; + if (isset($context['loop']['length'])) { + --$context['loop']['revindex0']; + --$context['loop']['revindex']; + $context['loop']['last'] = 0 === $context['loop']['revindex0']; + } + } + $_parent = $context['_parent']; + unset($context['_seq'], $context['_iterated'], $context['_key'], $context['field'], $context['_parent'], $context['loop']); + $context = array_intersect_key($context, $_parent) + $_parent; + // line 9 + echo "
                                                              +"; + } + } + + public function getTemplateName() + { + return "forms/fields/column/column.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 69 => 9, 55 => 8, 52 => 7, 49 => 6, 46 => 5, 43 => 4, 26 => 3, 21 => 2, 19 => 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 Twig_Source("{% if field.fields %} +
                                                              + {% for field in field.fields %} + {% if field.type %} + {% set 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 %} +
                                                              +{% endif %} +", "forms/fields/column/column.html.twig", "/mnt/data/Sites/static-ethica.net/user/plugins/admin/themes/grav/templates/forms/fields/column/column.html.twig"); + } +} diff --git a/cache/twig/c7/c7982d74853bf295cdf3023e53e5a1a9b796c507d0aa1caeef0542163787fd12.php b/cache/twig/c7/c7982d74853bf295cdf3023e53e5a1a9b796c507d0aa1caeef0542163787fd12.php new file mode 100644 index 0000000..9f34b54 --- /dev/null +++ b/cache/twig/c7/c7982d74853bf295cdf3023e53e5a1a9b796c507d0aa1caeef0542163787fd12.php @@ -0,0 +1,131 @@ +parent = false; + + $this->blocks = array( + 'content' => array($this, 'block_content'), + ); + } + + protected function doDisplay(array $context, array $blocks = array()) + { + // line 2 + echo " + "; + // line 3 + $this->displayBlock('content', $context, $blocks); + } + + public function block_content($context, array $blocks = array()) + { + // line 4 + echo " +

                                                              "; + // line 5 + echo $this->getAttribute(($context["header"] ?? null), "title", array()); + echo "

                                                              + + "; + // line 7 + echo $this->getAttribute(($context["page"] ?? null), "content", array()); + echo " + "; + // line 8 + $context['_parent'] = $context; + $context['_seq'] = twig_ensure_traversable($this->getAttribute(($context["page"] ?? null), "collection", array(), "method")); + foreach ($context['_seq'] as $context["_key"] => $context["module"]) { + // line 9 + echo " +
                                                              getAttribute($this, "pageLinkName", array(0 => $this->getAttribute($context["module"], "folder", array())), "method"); + echo "\" class=\"column\"> + "; + // line 11 + echo $this->getAttribute($context["module"], "content", array()); + echo " +
                                                              + "; + } + $_parent = $context['_parent']; + unset($context['_seq'], $context['_iterated'], $context['_key'], $context['module'], $context['_parent'], $context['loop']); + $context = array_intersect_key($context, $_parent) + $_parent; + // line 14 + echo " "; + } + + // line 1 + public function getpageLinkName($__text__ = null, ...$__varargs__) + { + $context = $this->env->mergeGlobals(array( + "text" => $__text__, + "varargs" => $__varargs__, + )); + + $blocks = array(); + + ob_start(); + try { + echo twig_replace_filter(twig_lower_filter($this->env, ($context["text"] ?? null)), array("01._" => "", "02._" => "", "03._" => "", "04._" => "", "05._" => "", "06._" => "", "07._" => "", "08._" => "", "09._" => "")); + } catch (Exception $e) { + ob_end_clean(); + + throw $e; + } catch (Throwable $e) { + ob_end_clean(); + + throw $e; + } + + return ('' === $tmp = ob_get_clean()) ? '' : new Twig_Markup($tmp, $this->env->getCharset()); + } + + public function getTemplateName() + { + return "modular/contenu.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 65 => 1, 61 => 14, 52 => 11, 48 => 10, 45 => 9, 41 => 8, 37 => 7, 32 => 5, 29 => 4, 23 => 3, 20 => 2,); + } + + /** @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 Twig_Source("{% macro pageLinkName(text) %}{{ text|lower|replace({'01._':'','02._':'','03._':'','04._':'','05._':'','06._':'','07._':'','08._':'','09._':''}) }}{% endmacro %} + + {% block content %} + +

                                                              {{ header.title }}

                                                              + + {{ page.content }} + {% for module in page.collection() %} + +
                                                              + {{ module.content }} +
                                                              + {% endfor %} + {% endblock %} +", "modular/contenu.html.twig", "/mnt/data/Sites/static-ethica.net/user/themes/ethica/templates/modular/contenu.html.twig"); + } +} diff --git a/cache/twig/c9/c900e684ce7966574d1030e7eefc81ed169a3b7d67555113b4ac3ac9351c8f75.php b/cache/twig/c9/c900e684ce7966574d1030e7eefc81ed169a3b7d67555113b4ac3ac9351c8f75.php new file mode 100644 index 0000000..bc9bf57 --- /dev/null +++ b/cache/twig/c9/c900e684ce7966574d1030e7eefc81ed169a3b7d67555113b4ac3ac9351c8f75.php @@ -0,0 +1,123 @@ +parent = false; + + $this->blocks = array( + 'content' => array($this, 'block_content'), + ); + } + + protected function doDisplay(array $context, array $blocks = array()) + { + // line 2 + echo " + "; + // line 3 + $this->displayBlock('content', $context, $blocks); + } + + public function block_content($context, array $blocks = array()) + { + // line 4 + echo "

                                                              "; + echo $this->getAttribute(($context["header"] ?? null), "title", array()); + echo "

                                                              + "; + // line 5 + echo $this->getAttribute(($context["page"] ?? null), "content", array()); + echo " + "; + // line 6 + $context['_parent'] = $context; + $context['_seq'] = twig_ensure_traversable($this->getAttribute(($context["page"] ?? null), "collection", array(), "method")); + foreach ($context['_seq'] as $context["_key"] => $context["module"]) { + // line 7 + echo "
                                                              getAttribute($this, "pageLinkName", array(0 => $this->getAttribute($context["module"], "folder", array())), "method"); + echo "\"> + "; + // line 8 + echo $this->getAttribute($context["module"], "content", array()); + echo " +
                                                              + "; + } + $_parent = $context['_parent']; + unset($context['_seq'], $context['_iterated'], $context['_key'], $context['module'], $context['_parent'], $context['loop']); + $context = array_intersect_key($context, $_parent) + $_parent; + // line 11 + echo " "; + } + + // line 1 + public function getpageLinkName($__text__ = null, ...$__varargs__) + { + $context = $this->env->mergeGlobals(array( + "text" => $__text__, + "varargs" => $__varargs__, + )); + + $blocks = array(); + + ob_start(); + try { + echo twig_replace_filter(twig_lower_filter($this->env, ($context["text"] ?? null)), array("01._" => "", "02._" => "", "03._" => "", "04._" => "", "05._" => "", "06._" => "", "07._" => "", "08._" => "", "09._" => "")); + } catch (Exception $e) { + ob_end_clean(); + + throw $e; + } catch (Throwable $e) { + ob_end_clean(); + + throw $e; + } + + return ('' === $tmp = ob_get_clean()) ? '' : new Twig_Markup($tmp, $this->env->getCharset()); + } + + public function getTemplateName() + { + return "modular/article.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 60 => 1, 56 => 11, 47 => 8, 42 => 7, 38 => 6, 34 => 5, 29 => 4, 23 => 3, 20 => 2,); + } + + /** @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 Twig_Source("{% macro pageLinkName(text) %}{{ text|lower|replace({'01._':'','02._':'','03._':'','04._':'','05._':'','06._':'','07._':'','08._':'','09._':''}) }}{% endmacro %} + + {% block content %} +

                                                              {{ header.title }}

                                                              + {{ page.content }} + {% for module in page.collection() %} +
                                                              + {{ module.content }} +
                                                              + {% endfor %} + {% endblock %} +", "modular/article.html.twig", "/home/kevin/Sites/static-ethica.net/user/themes/ethica/templates/modular/article.html.twig"); + } +} diff --git a/cache/twig/cb/cbfb323831993a8a763ab7e15f40ff52d839d41c2d4fcd5f18390df015a92ece.php b/cache/twig/cb/cbfb323831993a8a763ab7e15f40ff52d839d41c2d4fcd5f18390df015a92ece.php new file mode 100644 index 0000000..969d137 --- /dev/null +++ b/cache/twig/cb/cbfb323831993a8a763ab7e15f40ff52d839d41c2d4fcd5f18390df015a92ece.php @@ -0,0 +1,516 @@ +parent = false; + + $this->blocks = array( + 'head' => array($this, 'block_head'), + 'stylesheets' => array($this, 'block_stylesheets'), + 'javascripts' => array($this, 'block_javascripts'), + 'body' => array($this, 'block_body'), + 'page' => array($this, 'block_page'), + 'navigation' => array($this, 'block_navigation'), + 'titlebar' => array($this, 'block_titlebar'), + 'messages' => array($this, 'block_messages'), + 'widgets' => array($this, 'block_widgets'), + 'content_top' => array($this, 'block_content_top'), + 'content' => array($this, 'block_content'), + 'content_bottom' => array($this, 'block_content_bottom'), + 'footer' => array($this, 'block_footer'), + 'bottom' => array($this, 'block_bottom'), + ); + } + + protected function doDisplay(array $context, array $blocks = array()) + { + // line 1 + if (($this->getAttribute(($context["uri"] ?? null), "extension", array(), "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 32 + echo " + "; + // line 33 + $this->displayBlock('body', $context, $blocks); + // line 115 + echo " +"; + } + } + + // line 5 + public function block_head($context, array $blocks = array()) + { + // 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", array())) { + echo twig_escape_filter($this->env, $this->getAttribute(($context["header"] ?? null), "title", array()), "html", null, true); + echo " | "; + } + } + echo twig_escape_filter($this->env, $this->getAttribute(($context["site"] ?? null), "title", array()), "html", null, true); + echo " + "; + // line 8 + if ($this->getAttribute(($context["header"] ?? null), "description", array())) { + // line 9 + echo " env, $this->getAttribute(($context["header"] ?? null), "description", array()), "html", null, true); + echo "\"> + "; + } else { + // line 11 + echo " env, $this->getAttribute(($context["site"] ?? null), "description", array()), "html", null, true); + echo "\"> + "; + } + // line 13 + echo " "; + if ($this->getAttribute(($context["header"] ?? null), "robots", array())) { + // line 14 + echo " env, $this->getAttribute(($context["header"] ?? null), "robots", array()), "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 25 + echo " + "; + // line 26 + $this->loadTemplate("partials/javascript-config.html.twig", "partials/base-root.html.twig", 26)->display($context); + // line 27 + echo " "; + $this->displayBlock('javascripts', $context, $blocks); + // line 31 + echo " "; + } + + // line 21 + public function block_stylesheets($context, array $blocks = array()) + { + // line 22 + echo " "; + $this->loadTemplate("partials/stylesheets.html.twig", "partials/base-root.html.twig", 22)->display($context); + // line 23 + echo " "; + echo $this->getAttribute(($context["assets"] ?? null), "css", array(), "method"); + echo " + "; + } + + // line 27 + public function block_javascripts($context, array $blocks = array()) + { + // line 28 + echo " "; + $this->loadTemplate("partials/javascripts.html.twig", "partials/base-root.html.twig", 28)->display($context); + // line 29 + echo " "; + echo $this->getAttribute(($context["assets"] ?? null), "js", array(), "method"); + echo " + "; + } + + // line 33 + public function block_body($context, array $blocks = array()) + { + // line 34 + echo " getAttribute($this->getAttribute($this->getAttribute($this->getAttribute(($context["config"] ?? null), "plugins", array()), "admin", array()), "sidebar", array()), "size", array()) == "small")) ? ("sidebar-closed") : ("")); + echo " "; + echo twig_escape_filter($this->env, $this->getAttribute($this->getAttribute($this->getAttribute(($context["config"] ?? null), "plugins", array()), "admin", array()), "body_classes", array()), "html", null, true); + echo "\"> + "; + // line 35 + $this->displayBlock('page', $context, $blocks); + // line 112 + echo " "; + $this->displayBlock('bottom', $context, $blocks); + // line 113 + echo " + "; + } + + // line 35 + public function block_page($context, array $blocks = array()) + { + // line 36 + echo "
                                                              + + "; + // line 38 + $this->displayBlock('navigation', $context, $blocks); + // line 41 + echo " +
                                                              + "; + // line 43 + $this->loadTemplate("partials/nav-toggle.html.twig", "partials/base-root.html.twig", 43)->display($context); + // line 44 + echo "
                                                              + "; + // line 45 + $this->displayBlock('titlebar', $context, $blocks); + // line 46 + echo "
                                                              + +
                                                              +
                                                              getAttribute($this->getAttribute($this->getAttribute(($context["config"] ?? null), "plugins", array()), "admin", array()), "content_padding", array())) { + echo "content-padding"; + } + echo "\"> + "; + // line 50 + $this->displayBlock('messages', $context, $blocks); + // line 53 + echo " + "; + // line 54 + $this->displayBlock('widgets', $context, $blocks); + // line 55 + echo "
                                                              + "; + // line 56 + $this->displayBlock('content_top', $context, $blocks); + // line 57 + echo "
                                                              "; + // line 58 + $this->displayBlock('content', $context, $blocks); + // line 59 + echo "
                                                              + "; + // line 60 + if ($this->getAttribute($this->getAttribute($this->getAttribute(($context["config"] ?? null), "plugins", array()), "admin", array()), "show_github_msg", array())) { + // line 61 + echo " + "; + } + // line 63 + echo " "; + $this->displayBlock('content_bottom', $context, $blocks); + // line 64 + echo "
                                                              + "; + // line 65 + $this->displayBlock('footer', $context, $blocks); + // line 70 + echo "
                                                              +
                                                              + +
                                                              +
                                                              +

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

                                                              +
                                                              + +
                                                              +
                                                              +
                                                              +
                                                              +

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

                                                              + + +
                                                              +
                                                              +
                                                              +
                                                              +

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

                                                              +

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

                                                              +
                                                              +
                                                              + + +
                                                              +
                                                              +
                                                              + +
                                                              +
                                                              +
                                                              + "; + } + + // line 38 + public function block_navigation($context, array $blocks = array()) + { + // line 39 + echo " "; + $this->loadTemplate("partials/nav.html.twig", "partials/base-root.html.twig", 39)->display($context); + // line 40 + echo " "; + } + + // line 45 + public function block_titlebar($context, array $blocks = array()) + { + } + + // line 50 + public function block_messages($context, array $blocks = array()) + { + // line 51 + echo " "; + $this->loadTemplate("partials/messages.html.twig", "partials/base-root.html.twig", 51)->display($context); + // line 52 + echo " "; + } + + // line 54 + public function block_widgets($context, array $blocks = array()) + { + } + + // line 56 + public function block_content_top($context, array $blocks = array()) + { + } + + // line 58 + public function block_content($context, array $blocks = array()) + { + } + + // line 63 + public function block_content_bottom($context, array $blocks = array()) + { + } + + // line 65 + public function block_footer($context, array $blocks = array()) + { + // line 66 + echo "
                                                              + Grav v"; + // line 67 + 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\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\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.BY")), "html", null, true); + echo " RocketTheme. +
                                                              + "; + } + + // line 112 + public function block_bottom($context, array $blocks = array()) + { + } + + public function getTemplateName() + { + return "partials/base-root.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 369 => 112, 356 => 67, 353 => 66, 350 => 65, 345 => 63, 340 => 58, 335 => 56, 330 => 54, 326 => 52, 323 => 51, 320 => 50, 315 => 45, 311 => 40, 308 => 39, 305 => 38, 292 => 103, 288 => 102, 281 => 98, 276 => 96, 267 => 90, 258 => 84, 249 => 78, 243 => 75, 236 => 70, 234 => 65, 231 => 64, 228 => 63, 222 => 61, 220 => 60, 217 => 59, 215 => 58, 213 => 57, 211 => 56, 208 => 55, 206 => 54, 203 => 53, 201 => 50, 195 => 49, 190 => 46, 188 => 45, 185 => 44, 183 => 43, 179 => 41, 177 => 38, 173 => 36, 170 => 35, 165 => 113, 162 => 112, 160 => 35, 153 => 34, 150 => 33, 143 => 29, 140 => 28, 137 => 27, 130 => 23, 127 => 22, 124 => 21, 120 => 31, 117 => 27, 115 => 26, 112 => 25, 110 => 21, 104 => 19, 101 => 18, 97 => 16, 91 => 14, 88 => 13, 82 => 11, 76 => 9, 74 => 8, 61 => 7, 58 => 6, 55 => 5, 49 => 115, 47 => 33, 44 => 32, 42 => 5, 37 => 2, 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 Twig_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' %} + {{ assets.css()|raw }} + {% endblock %} + + {% include 'partials/javascript-config.html.twig' %} + {% block javascripts %} + {% include 'partials/javascripts.html.twig' %} + {{ assets.js()|raw }} + {% endblock %} + {% endblock %} + + {% block body %} + + {% block page %} +
                                                              + + {% block navigation %} + {% include 'partials/nav.html.twig' %} + {% endblock %} + +
                                                              + {% include 'partials/nav-toggle.html.twig' %} +
                                                              + {% block titlebar %}{% endblock %} +
                                                              + +
                                                              +
                                                              + {% 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 %} +
                                                              + Grav v{{ constant('GRAV_VERSION') }} - Admin v{{ admin_version }} - {{ \"PLUGIN_ADMIN.WAS_MADE_WITH\"|tu|lower }} {{ \"PLUGIN_ADMIN.BY\"|tu|lower }} RocketTheme. +
                                                              + {% endblock %} +
                                                              +
                                                              + +
                                                              +
                                                              +

                                                              {{ \"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 page %} + {% block bottom %}{% endblock %} + + {% endblock body %} + +{% endif %} +", "partials/base-root.html.twig", "/mnt/data/Sites/static-ethica.net/user/plugins/admin/themes/grav/templates/partials/base-root.html.twig"); + } +} diff --git a/cache/twig/cc/cc21b3138fe61543eee6f52c8583f2ff586e746cff671318483068ba76476085.php b/cache/twig/cc/cc21b3138fe61543eee6f52c8583f2ff586e746cff671318483068ba76476085.php new file mode 100644 index 0000000..71b2466 --- /dev/null +++ b/cache/twig/cc/cc21b3138fe61543eee6f52c8583f2ff586e746cff671318483068ba76476085.php @@ -0,0 +1,80 @@ +parent = false; + + $this->blocks = array( + ); + } + + protected function doDisplay(array $context, array $blocks = array()) + { + // line 1 + echo "
                                                              +

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

                                                              + +
                                                              +
                                                              +
                                                                +
                                                                +
                                                                + +"; + } + + public function getTemplateName() + { + return "partials/dashboard-feed.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 23 => 3, 19 => 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 Twig_Source("
                                                                +

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

                                                                + +
                                                                +
                                                                +
                                                                  +
                                                                  +
                                                                  + +", "partials/dashboard-feed.html.twig", "/mnt/data/Sites/static-ethica.net/user/plugins/admin/themes/grav/templates/partials/dashboard-feed.html.twig"); + } +} diff --git a/cache/twig/cf/cf3b0cb9b85161e32027dd416a647e59957d6c5c45a1e3b092d26b4775437031.php b/cache/twig/cf/cf3b0cb9b85161e32027dd416a647e59957d6c5c45a1e3b092d26b4775437031.php new file mode 100644 index 0000000..a1d288a --- /dev/null +++ b/cache/twig/cf/cf3b0cb9b85161e32027dd416a647e59957d6c5c45a1e3b092d26b4775437031.php @@ -0,0 +1,353 @@ +parent = false; + + $this->blocks = array( + ); + } + + protected function doDisplay(array $context, array $blocks = array()) + { + // line 1 + $context["gumroad_loaded"] = false; + // line 2 + echo "
                                                                  +"; + // line 3 + if (($context["installing"] ?? null)) { + // line 4 + echo " "; + $this->loadTemplate("partials/release-toggle.html.twig", "partials/plugins-list.html.twig", 4)->display($context); + } + // line 6 + $this->loadTemplate("partials/list-sort.html.twig", "partials/plugins-list.html.twig", 6)->display(array_merge($context, array("list_view" => "plugins"))); + // line 7 + echo "

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

                                                                  +
                                                                  +
                                                                  + env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.RESOURCE_FILTER"), "html", null, true); + echo "\" data-gpm-filter> +
                                                                  +
                                                                  + + + "; + // line 17 + $context['_parent'] = $context; + $context['_seq'] = twig_ensure_traversable($this->env->getExtension('Grav\Common\Twig\TwigExtension')->ksortFilter($this->getAttribute($this->getAttribute(($context["admin"] ?? null), "plugins", array(0 => !($context["installing"] ?? null)), "method"), "toArray", array()))); + $context['_iterated'] = false; + $context['loop'] = array( + 'parent' => $context['_parent'], + 'index0' => 0, + 'index' => 1, + 'first' => true, + ); + if (is_array($context['_seq']) || (is_object($context['_seq']) && $context['_seq'] instanceof Countable)) { + $length = count($context['_seq']); + $context['loop']['revindex0'] = $length - 1; + $context['loop']['revindex'] = $length; + $context['loop']['length'] = $length; + $context['loop']['last'] = 1 === $length; + } + foreach ($context['_seq'] as $context["slug"] => $context["plugin"]) { + // line 18 + echo " "; + $context["data"] = $this->getAttribute(($context["admin"] ?? null), "data", array(0 => ("plugins/" . $context["slug"])), "method"); + // line 19 + echo " "; + $context["isTestingRelease"] = $this->getAttribute($this->getAttribute(($context["admin"] ?? null), "gpm", array()), "isTestingRelease", array(0 => $context["slug"]), "method"); + // line 20 + echo " "; + $context["releaseDate"] = (($this->getAttribute($context["plugin"], "date", array())) ? ($this->getAttribute($context["plugin"], "date", array())) : ($this->getAttribute($this->getAttribute($this->getAttribute(($context["admin"] ?? null), "gpm", array()), "findPackage", array(0 => $context["slug"], 1 => true), "method"), "date", array()))); + // line 21 + echo " + env, twig_urlencode_filter($context["slug"]), "html", null, true); + echo "\" data-gpm-name=\""; + echo twig_escape_filter($this->env, $this->getAttribute($context["plugin"], "name", array()), "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["plugin"], "author", array()), "name", array()), "html", null, true); + echo "\" data-gpm-official=\""; + echo (($this->getAttribute(($context["admin"] ?? null), "isTeamGrav", array(0 => $context["plugin"]), "method")) ? ("1") : ("2")); + echo "\" data-gpm-updatable=\""; + echo (($this->getAttribute($this->getAttribute(($context["admin"] ?? null), "gpm", array()), "isUpdatable", array(0 => $context["slug"]), "method")) ? ("1") : ("2")); + echo "\" data-gpm-enabled=\""; + echo (($this->getAttribute(($context["data"] ?? null), "get", array(0 => "enabled"), "method")) ? ("1") : ("2")); + echo "\" data-gpm-testing=\""; + echo ((($context["isTestingRelease"] ?? null)) ? ("1") : ("2")); + echo "\"> + + + + + "; + $context['_iterated'] = true; + ++$context['loop']['index0']; + ++$context['loop']['index']; + $context['loop']['first'] = false; + if (isset($context['loop']['length'])) { + --$context['loop']['revindex0']; + --$context['loop']['revindex']; + $context['loop']['last'] = 0 === $context['loop']['revindex0']; + } + } + if (!$context['_iterated']) { + // line 69 + echo " + "; + } + $_parent = $context['_parent']; + unset($context['_seq'], $context['_iterated'], $context['slug'], $context['plugin'], $context['_parent'], $context['loop']); + $context = array_intersect_key($context, $_parent) + $_parent; + // line 71 + echo "
                                                                  + env, $this->getAttribute($context["plugin"], "icon", array()), "html", null, true); + echo "\"> + env, ($context["base_url_relative"] ?? null), "html", null, true); + echo "/plugins/"; + echo twig_escape_filter($this->env, twig_urlencode_filter($context["slug"]), "html", null, true); + echo "\">"; + echo twig_escape_filter($this->env, $this->getAttribute($context["plugin"], "name", array()), "html", null, true); + echo " + "; + // line 26 + if ($this->getAttribute(($context["admin"] ?? null), "isTeamGrav", array(0 => $context["plugin"]), "method")) { + // line 27 + echo " env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.GRAV_OFFICIAL_PLUGIN"), "html", null, true); + echo "\"> + "; + } + // line 29 + echo " "; + if ($this->getAttribute(($context["admin"] ?? null), "isPremiumProduct", array(0 => $context["plugin"]), "method")) { + // line 30 + echo " "; + if ( !($context["gumroad_loaded"] ?? null)) { + // line 31 + echo " "; + $context["gumroad_loaded"] = true; + // line 32 + echo " + "; + } + // line 34 + echo " "; + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.PREMIUM_PRODUCT"), "html", null, true); + echo " + "; + } + // line 36 + echo " "; + if ($this->getAttribute($context["plugin"], "symlink", array())) { + // line 37 + echo " env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.PLUGIN_SYMBOLICALLY_LINKED"), "html", null, true); + echo "\"> + + + "; + } + // line 41 + echo " v"; + echo twig_escape_filter($this->env, $this->getAttribute($context["plugin"], "version", array()), "html", null, true); + echo " + "; + // line 42 + if (($context["isTestingRelease"] ?? null)) { + echo "test release"; + } + // line 43 + echo " + "; + // line 45 + if (( !($context["installing"] ?? null) && (($this->getAttribute($this->getAttribute($this->getAttribute($this->getAttribute($context["plugin"], "form", array()), "fields", array()), "enabled", array()), "type", array()) != "hidden") && ($this->getAttribute($this->getAttribute($this->getAttribute($this->getAttribute($this->getAttribute($this->getAttribute($this->getAttribute($this->getAttribute($context["plugin"], "form", array()), "fields", array()), "tabs", array()), "fields", array()), "login", array()), "fields", array()), "enabled", array()), "type", array()) != "hidden")))) { + // line 46 + echo " getAttribute(($context["data"] ?? null), "get", array(0 => "enabled"), "method")) ? ("enabled") : ("disabled")); + echo "\" href=\""; + echo twig_escape_filter($this->env, $this->getAttribute(($context["uri"] ?? null), "addNonce", array(0 => (((((($context["base_url_relative"] ?? null) . "/plugins/") . $context["slug"]) . "/task") . $this->getAttribute($this->getAttribute(($context["config"] ?? null), "system", array()), "param_sep", array())) . (($this->getAttribute(($context["data"] ?? null), "get", array(0 => "enabled"), "method")) ? ("disable") : ("enable"))), 1 => "admin-form", 2 => "admin-nonce"), "method"), "html", null, true); + echo "\"> + getAttribute(($context["data"] ?? null), "get", array(0 => "enabled"), "method")) ? ("on") : ("off")); + echo "\"> + + "; + } elseif ( // line 49 +($context["installing"] ?? null)) { + // line 50 + echo " "; + if (($this->getAttribute($context["plugin"], "premium", array()) && !$this->getAttribute(($context["admin"] ?? null), "license", array(0 => $this->getAttribute($context["plugin"], "slug", array())), "method"))) { + // line 51 + echo " "; + if ( !($context["gumroad_loaded"] ?? null)) { + // line 52 + echo " "; + $context["gumroad_loaded"] = true; + // line 53 + echo " + "; + } + // line 55 + echo " env, $this->getAttribute($this->getAttribute($context["plugin"], "premium", array()), "product_permalink", array()), "html", null, true); + echo "\" target=\"_blank\" data-gumroad-single-product=\"true\"> "; + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("Buy Now"), "html", null, true); + echo " + "; + } else { + // line 57 + echo " env, $this->getAttribute($context["plugin"], "slug", array()), "html", null, true); + echo "\" data-plugin-action=\"start-package-installation\"> "; + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.INSTALL"), "html", null, true); + echo " + "; + } + // line 59 + echo " "; + } + // line 60 + echo " + +
                                                                  + "; + // line 64 + $this->loadTemplate("partials/plugin-data.html.twig", "partials/plugins-list.html.twig", 64)->display(array_merge($context, array("plugin" => $context["plugin"]))); + // line 65 + echo "
                                                                  +
                                                                  "; + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.OFFLINE_WARNING"), "html", null, true); + echo "
                                                                  + +"; + // line 73 + $this->loadTemplate("partials/modal-add-package.html.twig", "partials/plugins-list.html.twig", 73)->display(array_merge($context, array("type" => "plugin"))); + // line 74 + $this->loadTemplate("partials/modal-update-packages.html.twig", "partials/plugins-list.html.twig", 74)->display(array_merge($context, array("type" => "plugin"))); + } + + public function getTemplateName() + { + return "partials/plugins-list.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 249 => 74, 247 => 73, 243 => 71, 234 => 69, 218 => 65, 216 => 64, 210 => 60, 207 => 59, 199 => 57, 191 => 55, 187 => 53, 184 => 52, 181 => 51, 178 => 50, 176 => 49, 171 => 47, 164 => 46, 162 => 45, 158 => 43, 154 => 42, 149 => 41, 141 => 37, 138 => 36, 132 => 34, 128 => 32, 125 => 31, 122 => 30, 119 => 29, 113 => 27, 111 => 26, 103 => 25, 99 => 24, 80 => 22, 77 => 21, 74 => 20, 71 => 19, 68 => 18, 50 => 17, 42 => 12, 35 => 8, 32 => 7, 30 => 6, 26 => 4, 24 => 3, 21 => 2, 19 => 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 Twig_Source("{% set gumroad_loaded = false %} +
                                                                  +{% if installing %} + {% include 'partials/release-toggle.html.twig' %} +{% endif %} +{% include 'partials/list-sort.html.twig' with { list_view: 'plugins' } %} +

                                                                  + {{ installing ? \"PLUGIN_ADMIN.AVAILABLE_PLUGINS\"|tu : \"PLUGIN_ADMIN.INSTALLED_PLUGINS\"|tu }} +

                                                                  +
                                                                  +
                                                                  + +
                                                                  +
                                                                  + + + {% for slug, plugin in admin.plugins(not installing).toArray|ksort %} + {% set data = admin.data('plugins/' ~ slug) %} + {% set isTestingRelease = admin.gpm.isTestingRelease(slug) %} + {% set releaseDate = plugin.date ?: admin.gpm.findPackage(slug, true).date %} + + + + + + + {% else %} + + {% endfor %} +
                                                                  + + {{ plugin.name }} + {% if admin.isTeamGrav(plugin) %} + + {% endif %} + {% if admin.isPremiumProduct(plugin) %} + {% if not gumroad_loaded %} + {% set gumroad_loaded = true %} + + {% endif %} + {{ \"PLUGIN_ADMIN.PREMIUM_PRODUCT\"|tu }} + {% endif %} + {% if plugin.symlink %} + + + + {% endif %} + v{{ plugin.version }} + {% if isTestingRelease %}test release{% endif %} + + {% if (not installing and (plugin.form.fields.enabled.type != 'hidden' and plugin.form.fields.tabs.fields.login.fields.enabled.type != 'hidden')) %} + + + + {% elseif (installing) %} + {% if (plugin.premium and not admin.license(plugin.slug)) %} + {% if not gumroad_loaded %} + {% set gumroad_loaded = true %} + + {% endif %} + {{ \"Buy Now\"|tu }} + {% else %} + {{ \"PLUGIN_ADMIN.INSTALL\"|tu }} + {% endif %} + {% endif %} + + +
                                                                  + {% include 'partials/plugin-data.html.twig' with { plugin: plugin } %} +
                                                                  +
                                                                  {{ \"PLUGIN_ADMIN.OFFLINE_WARNING\"|tu }}
                                                                  + +{% include 'partials/modal-add-package.html.twig' with { type: 'plugin' } %} +{% include 'partials/modal-update-packages.html.twig' with { type: 'plugin' } %} +", "partials/plugins-list.html.twig", "/home/kevin/Sites/static-ethica.net/user/plugins/admin/themes/grav/templates/partials/plugins-list.html.twig"); + } +} diff --git a/cache/twig/d3/d38c2a3feafc68f0e26004b4f501c61d46ea0cf8277373e8bc3f5a518315406a.php b/cache/twig/d3/d38c2a3feafc68f0e26004b4f501c61d46ea0cf8277373e8bc3f5a518315406a.php new file mode 100644 index 0000000..0c80030 --- /dev/null +++ b/cache/twig/d3/d38c2a3feafc68f0e26004b4f501c61d46ea0cf8277373e8bc3f5a518315406a.php @@ -0,0 +1,430 @@ +parent = $this->loadTemplate("forms/field.html.twig", "forms/fields/file/file.html.twig", 1); + $this->blocks = array( + 'input' => array($this, 'block_input'), + 'input_attributes' => array($this, 'block_input_attributes'), + ); + } + + protected function doGetParent(array $context) + { + return "forms/field.html.twig"; + } + + protected function doDisplay(array $context, array $blocks = array()) + { + // line 2 + $context["defaults"] = $this->getAttribute($this->getAttribute(($context["config"] ?? null), "plugins", array()), "form", array()); + // line 3 + $context["files"] = twig_array_merge($this->getAttribute(($context["defaults"] ?? null), "files", array()), ((array_key_exists("field", $context)) ? (_twig_default_filter(($context["field"] ?? null), array())) : (array()))); + // line 4 + $context["limit"] = (( !$this->getAttribute(($context["field"] ?? null), "multiple", array())) ? (1) : ($this->getAttribute(($context["files"] ?? null), "limit", array()))); + // line 1 + $this->parent->display($context, array_merge($this->blocks, $blocks)); + } + + // line 58 + public function block_input($context, array $blocks = array()) + { + // line 59 + echo " "; + $context["page_can_upload"] = (($context["exists"] ?? null) || (((($context["type"] ?? null) == "page") && !($context["exists"] ?? null)) && !((is_string($__internal_5580c43648a4fc9a18c8763bb999454bcc9945e307af12771de71cef4b0d1fed = $this->getAttribute(($context["field"] ?? null), "destination", array())) && is_string($__internal_cbf4f73522fb2686fe8def785eb1f01a20b9f57d4f16281c5573cbf67f140404 = "@self") && ('' === $__internal_cbf4f73522fb2686fe8def785eb1f01a20b9f57d4f16281c5573cbf67f140404 || 0 === strpos($__internal_5580c43648a4fc9a18c8763bb999454bcc9945e307af12771de71cef4b0d1fed, $__internal_cbf4f73522fb2686fe8def785eb1f01a20b9f57d4f16281c5573cbf67f140404))) || (is_string($__internal_749820261fa3bb7394026710d9844f890294484dd9ed82221dc3ede90833cf77 = $this->getAttribute(($context["field"] ?? null), "destination", array())) && is_string($__internal_4cf70ad0a071196763609576a813d32d11fc5d725194baeef5931fe85ef905b5 = "self@") && ('' === $__internal_4cf70ad0a071196763609576a813d32d11fc5d725194baeef5931fe85ef905b5 || 0 === strpos($__internal_749820261fa3bb7394026710d9844f890294484dd9ed82221dc3ede90833cf77, $__internal_4cf70ad0a071196763609576a813d32d11fc5d725194baeef5931fe85ef905b5)))))); + // line 60 + echo " "; + if (( !array_key_exists("type", $context) || ($context["page_can_upload"] ?? null))) { + // line 61 + echo " + "; + // line 62 + $context["settings"] = array("name" => $this->getAttribute(($context["field"] ?? null), "name", array()), "paramName" => ($this->env->getExtension('Grav\Common\Twig\TwigExtension')->fieldNameFilter((($context["scope"] ?? null) . $this->getAttribute(($context["field"] ?? null), "name", array()))) . (($this->getAttribute(($context["files"] ?? null), "multiple", array())) ? ("[]") : (""))), "limit" => ($context["limit"] ?? null), "filesize" => (($this->getAttribute($this->getAttribute($this->getAttribute(($context["config"] ?? null), "system", array()), "media", array()), "upload_limit", array()) / 1024) / 1024), "accept" => $this->getAttribute(($context["files"] ?? null), "accept", array())); + // line 63 + echo " +
                                                                  getAttribute(($context["field"] ?? null), "fancy", array()) === false)) { + echo "form-input-file"; + } + echo " "; + echo twig_escape_filter($this->env, (($this->getAttribute(($context["field"] ?? null), "size", array(), "any", true, true)) ? (_twig_default_filter($this->getAttribute(($context["field"] ?? null), "size", array()), "xlarge")) : ("xlarge")), "html", null, true); + echo "\" data-grav-file-settings=\""; + echo twig_escape_filter($this->env, twig_jsonencode_filter(($context["settings"] ?? null)), "html_attr"); + echo "\" "; + if (($context["file_url_add"] ?? null)) { + echo "data-file-url-add=\""; + echo twig_escape_filter($this->env, ($context["file_url_add"] ?? null), "html", null, true); + echo "\""; + } + echo " "; + if (($context["file_url_remove"] ?? null)) { + echo "data-file-url-remove=\""; + echo twig_escape_filter($this->env, ($context["file_url_remove"] ?? null), "html", null, true); + echo "\""; + } + echo "> + displayBlock('input_attributes', $context, $blocks); + // line 75 + echo " /> + + "; + // line 77 + $context['_parent'] = $context; + $context['_seq'] = twig_ensure_traversable(($context["value"] ?? null)); + foreach ($context['_seq'] as $context["path"] => $context["file"]) { + // line 78 + echo " "; + echo $this->getAttribute($this, "preview", array(0 => $context["path"], 1 => $context["file"], 2 => $context), "method"); + echo " + "; + } + $_parent = $context['_parent']; + unset($context['_seq'], $context['_iterated'], $context['path'], $context['file'], $context['_parent'], $context['loop']); + $context = array_intersect_key($context, $_parent) + $_parent; + // line 80 + echo " "; + $this->loadTemplate("forms/fields/hidden/hidden.html.twig", "forms/fields/file/file.html.twig", 80)->display(array_merge($context, array("field" => array("name" => ("_json." . $this->getAttribute(($context["field"] ?? null), "name", array()))), "value" => twig_jsonencode_filter(($context["value"] ?? null))))); + // line 81 + echo "
                                                                  + + "; + } else { + // line 84 + echo " "; + echo $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.CANNOT_ADD_FILES_PAGE_NOT_SAVED"); + echo " + "; + } + } + + // line 67 + public function block_input_attributes($context, array $blocks = array()) + { + // line 68 + echo " type=\"file\" + "; + // line 69 + if ($this->getAttribute(($context["files"] ?? null), "multiple", array())) { + echo "multiple=\"multiple\""; + } + // line 70 + echo " "; + if ($this->getAttribute(($context["files"] ?? null), "accept", array())) { + echo "accept=\""; + echo twig_escape_filter($this->env, twig_join_filter($this->getAttribute(($context["files"] ?? null), "accept", array()), ","), "html", null, true); + echo "\""; + } + // line 71 + echo " "; + if (($this->getAttribute(($context["field"] ?? null), "disabled", array()) || ($context["isDisabledToggleable"] ?? null))) { + echo "disabled=\"disabled\""; + } + // line 72 + echo " "; + if ($this->getAttribute(($context["field"] ?? null), "random_name", array())) { + echo "random=\"true\""; + } + // line 73 + echo " "; + $this->displayParentBlock("input_attributes", $context, $blocks); + echo " + "; + } + + // line 6 + public function getbytesToSize($__bytes__ = null, ...$__varargs__) + { + $context = $this->env->mergeGlobals(array( + "bytes" => $__bytes__, + "varargs" => $__varargs__, + )); + + $blocks = array(); + + ob_start(); + try { + // line 7 + ob_start(); + // line 8 + echo " "; + $context["kilobyte"] = 1024; + // line 9 + echo " "; + $context["megabyte"] = (($context["kilobyte"] ?? null) * 1024); + // line 10 + echo " "; + $context["gigabyte"] = (($context["megabyte"] ?? null) * 1024); + // line 11 + echo " "; + $context["terabyte"] = (($context["gigabyte"] ?? null) * 1024); + // line 12 + echo " + "; + // line 13 + if ((($context["bytes"] ?? null) < ($context["kilobyte"] ?? null))) { + // line 14 + echo " "; + echo twig_escape_filter($this->env, (($context["bytes"] ?? null) . " B"), "html", null, true); + echo " + "; + } elseif (( // line 15 +($context["bytes"] ?? null) < ($context["megabyte"] ?? null))) { + // line 16 + echo " "; + echo twig_escape_filter($this->env, (twig_number_format_filter($this->env, (($context["bytes"] ?? null) / ($context["kilobyte"] ?? null)), 2, ".") . " KB"), "html", null, true); + echo " + "; + } elseif (( // line 17 +($context["bytes"] ?? null) < ($context["gigabyte"] ?? null))) { + // line 18 + echo " "; + echo twig_escape_filter($this->env, (twig_number_format_filter($this->env, (($context["bytes"] ?? null) / ($context["megabyte"] ?? null)), 2, ".") . " MB"), "html", null, true); + echo " + "; + } elseif (( // line 19 +($context["bytes"] ?? null) < ($context["terabyte"] ?? null))) { + // line 20 + echo " "; + echo twig_escape_filter($this->env, (twig_number_format_filter($this->env, (($context["bytes"] ?? null) / ($context["gigabyte"] ?? null)), 2, ".") . " GB"), "html", null, true); + echo " + "; + } else { + // line 22 + echo " "; + echo twig_escape_filter($this->env, (twig_number_format_filter($this->env, (($context["bytes"] ?? null) / ($context["terabyte"] ?? null)), 2, ".") . " TB"), "html", null, true); + echo " + "; + } + // line 24 + echo " "; + echo trim(preg_replace('/>\s+<', ob_get_clean())); + } catch (Exception $e) { + ob_end_clean(); + + throw $e; + } catch (Throwable $e) { + ob_end_clean(); + + throw $e; + } + + return ('' === $tmp = ob_get_clean()) ? '' : new Twig_Markup($tmp, $this->env->getCharset()); + } + + // line 27 + public function getpreview($__path__ = null, $__value__ = null, $__global__ = null, ...$__varargs__) + { + $context = $this->env->mergeGlobals(array( + "path" => $__path__, + "value" => $__value__, + "global" => $__global__, + "varargs" => $__varargs__, + )); + + $blocks = array(); + + ob_start(); + try { + // line 28 + echo " "; + if (($context["value"] ?? null)) { + // line 29 + echo " "; + $context["uri"] = $this->getAttribute($this->getAttribute(($context["global"] ?? null), "grav", array()), "uri", array()); + // line 30 + echo " "; + $context["files"] = $this->getAttribute(($context["global"] ?? null), "files", array()); + // line 31 + echo " "; + $context["config"] = $this->getAttribute($this->getAttribute(($context["global"] ?? null), "grav", array()), "config", array()); + // line 32 + echo " "; + $context["route"] = $this->getAttribute($this->getAttribute(($context["global"] ?? null), "context", array()), "route", array(), "method"); + // line 33 + echo " + "; + // line 34 + $context["type"] = (($this->getAttribute(($context["global"] ?? null), "blueprint_type", array())) ? ($this->getAttribute(($context["global"] ?? null), "blueprint_type", array())) : ((($this->getAttribute($this->getAttribute(($context["global"] ?? null), "admin", array()), "location", array())) ? ($this->getAttribute($this->getAttribute(($context["global"] ?? null), "admin", array()), "location", array())) : ("config")))); + // line 35 + echo " + "; + // line 36 + $context["blueprint_name"] = $this->getAttribute($this->getAttribute(($context["global"] ?? null), "blueprints", array()), "getFilename", array()); + // line 37 + echo " "; + if ((($context["type"] ?? null) == "pages")) { + // line 38 + echo " "; + $context["blueprint_name"] = ((($context["type"] ?? null) . "/") . ($context["blueprint_name"] ?? null)); + // line 39 + echo " "; + } + // line 40 + echo " "; + $context["blueprint"] = base64_encode(($context["blueprint_name"] ?? null)); + // line 41 + echo " "; + $context["real_path"] = $this->getAttribute($this->getAttribute(($context["global"] ?? null), "admin", array()), "getPagePathFromToken", array(0 => ($context["path"] ?? null)), "method"); + // line 42 + echo " "; + $context["remove"] = (($this->getAttribute(($context["global"] ?? null), "file_url_remove", array())) ? ($this->getAttribute(($context["global"] ?? null), "file_url_remove", array())) : (($this->getAttribute(($context["global"] ?? null), "base_url_relative", array()) . "/media.json"))); + // line 43 + echo " "; + $context["remove"] = $this->getAttribute(($context["uri"] ?? null), "addNonce", array(0 => ((((((((((((((((((((( // line 44 +($context["remove"] ?? null) . "/route") . $this->getAttribute($this->getAttribute( // line 45 +($context["config"] ?? null), "system", array()), "param_sep", array())) . base64_encode((($this->getAttribute(($context["global"] ?? null), "base_path", array()) . "/") . ($context["real_path"] ?? null)))) . "/task") . $this->getAttribute($this->getAttribute( // line 46 +($context["config"] ?? null), "system", array()), "param_sep", array())) . "removeFileFromBlueprint") . "/proute") . $this->getAttribute($this->getAttribute( // line 47 +($context["config"] ?? null), "system", array()), "param_sep", array())) . base64_encode(($context["route"] ?? null))) . "/blueprint") . $this->getAttribute($this->getAttribute( // line 48 +($context["config"] ?? null), "system", array()), "param_sep", array())) . ($context["blueprint"] ?? null)) . "/type") . $this->getAttribute($this->getAttribute( // line 49 +($context["config"] ?? null), "system", array()), "param_sep", array())) . ($context["type"] ?? null)) . "/field") . $this->getAttribute($this->getAttribute( // line 50 +($context["config"] ?? null), "system", array()), "param_sep", array())) . $this->getAttribute(($context["files"] ?? null), "name", array())) . "/path") . $this->getAttribute($this->getAttribute( // line 51 +($context["config"] ?? null), "system", array()), "param_sep", array())) . base64_encode($this->getAttribute(($context["value"] ?? null), "path", array()))), 1 => "admin-form", 2 => "admin-nonce"), "method"); + // line 52 + echo " + "; + // line 53 + $context["file"] = twig_array_merge(($context["value"] ?? null), array("remove" => ($context["remove"] ?? null), "path" => ((($this->getAttribute(($context["uri"] ?? null), "rootUrl", array()) == "/")) ? ("/") : ((($this->getAttribute(($context["uri"] ?? null), "rootUrl", array()) . "/") . ($context["real_path"] ?? null)))))); + // line 54 + echo "
                                                                  env, twig_jsonencode_filter(($context["file"] ?? null)), "html_attr"); + echo "\">
                                                                  + "; + } + } catch (Exception $e) { + ob_end_clean(); + + throw $e; + } catch (Throwable $e) { + ob_end_clean(); + + throw $e; + } + + return ('' === $tmp = ob_get_clean()) ? '' : new Twig_Markup($tmp, $this->env->getCharset()); + } + + public function getTemplateName() + { + return "forms/fields/file/file.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 299 => 54, 297 => 53, 294 => 52, 292 => 51, 291 => 50, 290 => 49, 289 => 48, 288 => 47, 287 => 46, 286 => 45, 285 => 44, 283 => 43, 280 => 42, 277 => 41, 274 => 40, 271 => 39, 268 => 38, 265 => 37, 263 => 36, 260 => 35, 258 => 34, 255 => 33, 252 => 32, 249 => 31, 246 => 30, 243 => 29, 240 => 28, 226 => 27, 210 => 24, 204 => 22, 198 => 20, 196 => 19, 191 => 18, 189 => 17, 184 => 16, 182 => 15, 177 => 14, 175 => 13, 172 => 12, 169 => 11, 166 => 10, 163 => 9, 160 => 8, 158 => 7, 146 => 6, 139 => 73, 134 => 72, 129 => 71, 122 => 70, 118 => 69, 115 => 68, 112 => 67, 104 => 84, 99 => 81, 96 => 80, 87 => 78, 83 => 77, 79 => 75, 76 => 67, 53 => 64, 50 => 63, 48 => 62, 45 => 61, 42 => 60, 39 => 59, 36 => 58, 32 => 1, 30 => 4, 28 => 3, 26 => 2, 11 => 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 Twig_Source("{% extends \"forms/field.html.twig\" %} +{% set defaults = config.plugins.form %} +{% set files = defaults.files|merge(field|default([])) %} +{% set limit = not field.multiple ? 1 : files.limit %} + +{% macro bytesToSize(bytes) -%} + {% spaceless %} + {% set kilobyte = 1024 %} + {% set megabyte = kilobyte * 1024 %} + {% set gigabyte = megabyte * 1024 %} + {% set terabyte = gigabyte * 1024 %} + + {% if bytes < kilobyte %} + {{ bytes ~ ' B' }} + {% elseif bytes < megabyte %} + {{ (bytes / kilobyte)|number_format(2, '.') ~ ' KB' }} + {% elseif bytes < gigabyte %} + {{ (bytes / megabyte)|number_format(2, '.') ~ ' MB' }} + {% elseif bytes < terabyte %} + {{ (bytes / gigabyte)|number_format(2, '.') ~ ' GB' }} + {% else %} + {{ (bytes / terabyte)|number_format(2, '.') ~ ' TB' }} + {% endif %} + {% endspaceless %} +{%- endmacro %} + +{% macro preview(path, value, global) %} + {% if value %} + {% set uri = global.grav.uri %} + {% set files = global.files %} + {% set config = global.grav.config %} + {% set route = global.context.route() %} + + {% set type = global.blueprint_type ? global.blueprint_type : global.admin.location ? global.admin.location : 'config' %} + + {% set blueprint_name = global.blueprints.getFilename %} + {% if type == 'pages' %} + {% set blueprint_name = type ~ '/' ~ blueprint_name %} + {% endif %} + {% set blueprint = base64_encode(blueprint_name) %} + {% set real_path = global.admin.getPagePathFromToken(path) %} + {% set remove = global.file_url_remove ? global.file_url_remove : (global.base_url_relative ~ '/media.json') %} + {% set remove = uri.addNonce( + remove ~ + '/route' ~ config.system.param_sep ~ base64_encode(global.base_path ~ '/' ~ real_path) ~ + '/task' ~ config.system.param_sep ~ 'removeFileFromBlueprint' ~ + '/proute' ~ config.system.param_sep ~ base64_encode(route) ~ + '/blueprint' ~ config.system.param_sep ~ blueprint ~ + '/type' ~ config.system.param_sep ~ type ~ + '/field' ~ config.system.param_sep ~ files.name ~ + '/path' ~ config.system.param_sep ~ base64_encode(value.path), 'admin-form', 'admin-nonce') %} + + {% set file = value|merge({remove: remove, path: (uri.rootUrl == '/' ? '/' : uri.rootUrl ~ '/' ~ real_path) }) %} +
                                                                  + {% endif %} +{% endmacro %} + +{% block input %} + {% set page_can_upload = exists or (type == 'page' and not exists and not (field.destination starts with '@self' or field.destination starts with 'self@')) %} + {% if type is not defined or page_can_upload %} + + {% set settings = {name: field.name, paramName: (scope ~ field.name)|fieldName ~ (files.multiple ? '[]' : ''), limit: limit, filesize: (config.system.media.upload_limit / 1024 / 1024), accept: files.accept} %} + +
                                                                  + + + {% for path, file in value %} + {{ _self.preview(path, file, _context) }} + {% endfor %} + {% include 'forms/fields/hidden/hidden.html.twig' with {field: {name: '_json.' ~ field.name}, value:value|raw|json_encode} %} +
                                                                  + + {% else %} + {{ \"PLUGIN_ADMIN.CANNOT_ADD_FILES_PAGE_NOT_SAVED\"|tu|raw }} + {% endif %} +{% endblock %} +", "forms/fields/file/file.html.twig", "/home/kevin/Sites/static-ethica.net/user/plugins/admin/themes/grav/templates/forms/fields/file/file.html.twig"); + } +} diff --git a/cache/twig/d4/d41c80ca21097269a6cf978a04c934034addda62f9fbf8c28b1a309a7e7cb349.php b/cache/twig/d4/d41c80ca21097269a6cf978a04c934034addda62f9fbf8c28b1a309a7e7cb349.php new file mode 100644 index 0000000..e8b0b48 --- /dev/null +++ b/cache/twig/d4/d41c80ca21097269a6cf978a04c934034addda62f9fbf8c28b1a309a7e7cb349.php @@ -0,0 +1,104 @@ +parent = false; + + $this->blocks = array( + ); + } + + protected function doDisplay(array $context, array $blocks = array()) + { + // line 1 + echo "
                                                                  +"; + // line 2 + if ($this->getAttribute(($context["field"] ?? null), "fields", array())) { + // line 3 + echo " "; + $context["cols"] = twig_length_filter($this->env, $this->getAttribute(($context["field"] ?? null), "fields", array())); + // line 4 + echo " "; + $context['_parent'] = $context; + $context['_seq'] = twig_ensure_traversable($this->getAttribute($context["field"], "fields", array())); + $context['loop'] = array( + 'parent' => $context['_parent'], + 'index0' => 0, + 'index' => 1, + 'first' => true, + ); + if (is_array($context['_seq']) || (is_object($context['_seq']) && $context['_seq'] instanceof Countable)) { + $length = count($context['_seq']); + $context['loop']['revindex0'] = $length - 1; + $context['loop']['revindex'] = $length; + $context['loop']['length'] = $length; + $context['loop']['last'] = 1 === $length; + } + foreach ($context['_seq'] as $context["_key"] => $context["field"]) { + // line 5 + echo " "; + $this->loadTemplate(array(0 => (((("forms/fields/" . $this->getAttribute($context["field"], "type", array())) . "/") . $this->getAttribute($context["field"], "type", array())) . ".html.twig"), 1 => "forms/fields/column/column.html.twig"), "forms/fields/columns/columns.html.twig", 5)->display(array_merge($context, array("cols" => ($context["cols"] ?? null)))); + // line 6 + echo " "; + ++$context['loop']['index0']; + ++$context['loop']['index']; + $context['loop']['first'] = false; + if (isset($context['loop']['length'])) { + --$context['loop']['revindex0']; + --$context['loop']['revindex']; + $context['loop']['last'] = 0 === $context['loop']['revindex0']; + } + } + $_parent = $context['_parent']; + unset($context['_seq'], $context['_iterated'], $context['_key'], $context['field'], $context['_parent'], $context['loop']); + $context = array_intersect_key($context, $_parent) + $_parent; + } + // line 8 + echo "
                                                                  + +"; + } + + public function getTemplateName() + { + return "forms/fields/columns/columns.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 63 => 8, 48 => 6, 45 => 5, 27 => 4, 24 => 3, 22 => 2, 19 => 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 Twig_Source("
                                                                  +{% if field.fields %} + {% set cols = field.fields|length %} + {% for field in field.fields %} + {% include [\"forms/fields/#{field.type}/#{field.type}.html.twig\", 'forms/fields/column/column.html.twig'] with {'cols':cols} %} + {% endfor %} +{% endif %} +
                                                                  + +", "forms/fields/columns/columns.html.twig", "/mnt/data/Sites/static-ethica.net/user/plugins/admin/themes/grav/templates/forms/fields/columns/columns.html.twig"); + } +} diff --git a/cache/twig/d6/d68b20570ab91f74938b89dc64e4d522873986cef82f12af0589efb1ed69d40b.php b/cache/twig/d6/d68b20570ab91f74938b89dc64e4d522873986cef82f12af0589efb1ed69d40b.php new file mode 100644 index 0000000..3d06bd7 --- /dev/null +++ b/cache/twig/d6/d68b20570ab91f74938b89dc64e4d522873986cef82f12af0589efb1ed69d40b.php @@ -0,0 +1,101 @@ +parent = false; + + $this->blocks = array( + ); + } + + protected function doDisplay(array $context, array $blocks = array()) + { + // line 1 + echo "
                                                                  + +
                                                                  +
                                                                  +"; + } + + public function getTemplateName() + { + return "partials/list-sort.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 56 => 10, 49 => 9, 42 => 8, 36 => 7, 32 => 6, 27 => 4, 23 => 3, 19 => 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 Twig_Source("
                                                                  + +
                                                                  +
                                                                  +", "partials/list-sort.html.twig", "/home/kevin/Sites/static-ethica.net/user/plugins/admin/themes/grav/templates/partials/list-sort.html.twig"); + } +} diff --git a/cache/twig/d6/d6af130f63ce9e2af25fb0f151a0d41030afc550f238cea774a510f840ea833d.php b/cache/twig/d6/d6af130f63ce9e2af25fb0f151a0d41030afc550f238cea774a510f840ea833d.php new file mode 100644 index 0000000..8cfd75a --- /dev/null +++ b/cache/twig/d6/d6af130f63ce9e2af25fb0f151a0d41030afc550f238cea774a510f840ea833d.php @@ -0,0 +1,309 @@ +parent = $this->loadTemplate("forms/field.html.twig", "forms/fields/toggle/toggle.html.twig", 1); + $this->blocks = array( + 'global_attributes' => array($this, 'block_global_attributes'), + 'input' => array($this, 'block_input'), + ); + } + + protected function doGetParent(array $context) + { + return "forms/field.html.twig"; + } + + protected function doDisplay(array $context, array $blocks = array()) + { + // line 3 + $context["value"] = (((null === ($context["value"] ?? null))) ? ($this->getAttribute(($context["field"] ?? null), "default", array())) : (($context["value"] ?? null))); + // line 4 + $context["value"] = (((($context["value"] ?? null) === false)) ? (0) : (($context["value"] ?? null))); + // line 6 + $context["has_hidden"] = false; + // line 7 + $context['_parent'] = $context; + $context['_seq'] = twig_ensure_traversable($this->getAttribute(($context["field"] ?? null), "options", array())); + foreach ($context['_seq'] as $context["key"] => $context["text"]) { + // line 8 + if (twig_test_empty($context["key"])) { + // line 9 + $context["has_hidden"] = true; + } + } + $_parent = $context['_parent']; + unset($context['_seq'], $context['_iterated'], $context['key'], $context['text'], $context['_parent'], $context['loop']); + $context = array_intersect_key($context, $_parent) + $_parent; + // line 1 + $this->parent->display($context, array_merge($this->blocks, $blocks)); + } + + // line 13 + public function block_global_attributes($context, array $blocks = array()) + { + // line 14 + echo " "; + $this->displayParentBlock("global_attributes", $context, $blocks); + echo " + data-grav-field-name=\""; + // line 15 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Common\Twig\TwigExtension')->fieldNameFilter((($context["scope"] ?? null) . $this->getAttribute(($context["field"] ?? null), "name", array()))), "html", null, true); + echo "\" +"; + } + + // line 23 + public function block_input($context, array $blocks = array()) + { + // line 24 + echo " +
                                                                  env, $this->getAttribute(($context["field"] ?? null), "size", array()), "html", null, true); + echo " switch-"; + echo twig_escape_filter($this->env, twig_length_filter($this->env, $this->getAttribute(($context["field"] ?? null), "options", array())), "html", null, true); + echo " "; + echo twig_escape_filter($this->env, $this->getAttribute(($context["field"] ?? null), "classes", array()), "html", null, true); + echo "\"> + "; + // line 26 + $context["maxLen"] = 0; + // line 27 + echo " "; + $context['_parent'] = $context; + $context['_seq'] = twig_ensure_traversable($this->getAttribute(($context["field"] ?? null), "options", array())); + foreach ($context['_seq'] as $context["_key"] => $context["text"]) { + // line 28 + echo " "; + $context["translation"] = (($this->getAttribute($this->getAttribute($this->getAttribute($this->getAttribute(($context["grav"] ?? null), "twig", array(), "any", false, true), "twig", array(), "any", false, true), "filters", array(), "any", false, true), "tu", array(), "array", true, true)) ? ($this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter($context["text"])) : ($this->env->getExtension('Grav\Common\Twig\TwigExtension')->translate($context["text"]))); + // line 29 + echo " "; + $context["maxLen"] = max(twig_length_filter($this->env, ($context["translation"] ?? null)), ($context["maxLen"] ?? null)); + // line 30 + echo " "; + } + $_parent = $context['_parent']; + unset($context['_seq'], $context['_iterated'], $context['_key'], $context['text'], $context['_parent'], $context['loop']); + $context = array_intersect_key($context, $_parent) + $_parent; + // line 31 + echo " + "; + // line 32 + $context['_parent'] = $context; + $context['_seq'] = twig_ensure_traversable($this->getAttribute(($context["field"] ?? null), "options", array())); + foreach ($context['_seq'] as $context["key"] => $context["text"]) { + // line 33 + echo " "; + $context["id"] = (("toggle_" . $this->getAttribute(($context["field"] ?? null), "name", array())) . $context["key"]); + // line 34 + echo " "; + $context["translation"] = twig_trim_filter((($this->getAttribute($this->getAttribute($this->getAttribute($this->getAttribute(($context["grav"] ?? null), "twig", array(), "any", false, true), "twig", array(), "any", false, true), "filters", array(), "any", false, true), "tu", array(), "array", true, true)) ? ($this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter($context["text"])) : ($this->env->getExtension('Grav\Common\Twig\TwigExtension')->translate($context["text"])))); + // line 35 + echo " + env, $context["key"], "html", null, true); + echo "\" + id=\""; + // line 38 + echo twig_escape_filter($this->env, ($context["id"] ?? null), "html", null, true); + echo "\" + name=\""; + // line 39 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Common\Twig\TwigExtension')->fieldNameFilter((($context["scope"] ?? null) . $this->getAttribute(($context["field"] ?? null), "name", array()))), "html", null, true); + echo "\" + "; + // line 40 + if ($this->getAttribute(($context["field"] ?? null), "highlight", array(), "any", true, true)) { + // line 41 + echo " class=\""; + echo ((($this->getAttribute(($context["field"] ?? null), "highlight", array()) == ("" . $context["key"]))) ? ("highlight") : ("")); + echo "\" + "; + } + // line 43 + echo " "; + if (($this->getAttribute(($context["field"] ?? null), "disabled", array()) || ($context["isDisabledToggleable"] ?? null))) { + echo "disabled=\"disabled\""; + } + // line 44 + echo " "; + if ($this->getAttribute(($context["field"] ?? null), "toggleable", array())) { + // line 45 + echo " "; + if ((("" . $context["key"]) == ("" . ($context["value"] ?? null)))) { + // line 46 + echo " checked=\"checked\" + "; + } elseif (( // line 47 +array_key_exists("value", $context) && (($context["key"] == 1) || ($context["key"] == "1")))) { + // line 48 + echo " checked=\"checked\" + "; + } + // line 50 + echo " "; + } else { + // line 51 + echo " "; + if ((("" . $context["key"]) == ("" . ($context["value"] ?? null)))) { + // line 52 + echo " checked=\"checked\" + "; + } + // line 54 + echo " "; + } + // line 55 + echo " "; + if (twig_in_filter($this->getAttribute($this->getAttribute(($context["field"] ?? null), "validate", array()), "required", array()), array(0 => "on", 1 => "true", 2 => 1))) { + echo "required=\"required\""; + } + // line 56 + echo " /> + + "; + } + $_parent = $context['_parent']; + unset($context['_seq'], $context['_iterated'], $context['key'], $context['text'], $context['_parent'], $context['loop']); + $context = array_intersect_key($context, $_parent) + $_parent; + // line 59 + echo "
                                                                  +"; + } + + // line 18 + public function getspanToggle($__input__ = null, $__length__ = null, ...$__varargs__) + { + $context = $this->env->mergeGlobals(array( + "input" => $__input__, + "length" => $__length__, + "varargs" => $__varargs__, + )); + + $blocks = array(); + + ob_start(); + try { + // line 19 + echo " "; + $context["space"] = $this->env->getExtension('Grav\Common\Twig\TwigExtension')->repeatFunc("  ", ((($context["length"] ?? null) - twig_length_filter($this->env, ($context["input"] ?? null))) / 2)); + // line 20 + echo " "; + echo ((($context["space"] ?? null) . ($context["input"] ?? null)) . ($context["space"] ?? null)); + echo " +"; + } catch (Exception $e) { + ob_end_clean(); + + throw $e; + } catch (Throwable $e) { + ob_end_clean(); + + throw $e; + } + + return ('' === $tmp = ob_get_clean()) ? '' : new Twig_Markup($tmp, $this->env->getCharset()); + } + + public function getTemplateName() + { + return "forms/fields/toggle/toggle.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 205 => 20, 202 => 19, 189 => 18, 184 => 59, 174 => 57, 171 => 56, 166 => 55, 163 => 54, 159 => 52, 156 => 51, 153 => 50, 149 => 48, 147 => 47, 144 => 46, 141 => 45, 138 => 44, 133 => 43, 127 => 41, 125 => 40, 121 => 39, 117 => 38, 113 => 37, 109 => 35, 106 => 34, 103 => 33, 99 => 32, 96 => 31, 90 => 30, 87 => 29, 84 => 28, 79 => 27, 77 => 26, 69 => 25, 66 => 24, 63 => 23, 57 => 15, 52 => 14, 49 => 13, 45 => 1, 38 => 9, 36 => 8, 32 => 7, 30 => 6, 28 => 4, 26 => 3, 11 => 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 Twig_Source("{% extends \"forms/field.html.twig\" %} + +{% set value = (value is null ? field.default : value) %} +{% 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 %} + +{% macro spanToggle(input, length) %} + {% set space = repeat('  ', (length - input|length) / 2) %} + {{ (space ~ input ~ space)|raw }} +{% endmacro %} + +{% block input %} + +
                                                                  + {% set maxLen = 0 %} + {% for text in field.options %} + {% set translation = grav.twig.twig.filters['tu'] is defined ? text|tu : text|t %} + {% set maxLen = max(translation|length, maxLen) %} + {% endfor %} + + {% for key, text in field.options %} + {% set id = \"toggle_\" ~ field.name ~ key %} + {% set translation = (grav.twig.twig.filters['tu'] is defined ? text|tu : text|t)|trim %} + + + + {% endfor %} +
                                                                  +{% endblock %} +", "forms/fields/toggle/toggle.html.twig", "/mnt/data/Sites/static-ethica.net/user/plugins/admin/themes/grav/templates/forms/fields/toggle/toggle.html.twig"); + } +} diff --git a/cache/twig/da/dab20ec36a7b52270a47f67ec166359ea8e95b09fdc42c3096e7daf3e253b4c8.php b/cache/twig/da/dab20ec36a7b52270a47f67ec166359ea8e95b09fdc42c3096e7daf3e253b4c8.php new file mode 100644 index 0000000..8b5ae4b --- /dev/null +++ b/cache/twig/da/dab20ec36a7b52270a47f67ec166359ea8e95b09fdc42c3096e7daf3e253b4c8.php @@ -0,0 +1,811 @@ +parent = $this->loadTemplate("forms/field.html.twig", "forms/fields/list/list.html.twig", 1); + $this->blocks = array( + 'contents' => array($this, 'block_contents'), + 'global_attributes' => array($this, 'block_global_attributes'), + '__internal_fa367a566ec58bda83f7abdb372be4a69271c84232c5182b50529b9a3a7d944c' => array($this, 'block___internal_fa367a566ec58bda83f7abdb372be4a69271c84232c5182b50529b9a3a7d944c'), + ); + } + + protected function doGetParent(array $context) + { + return "forms/field.html.twig"; + } + + protected function doDisplay(array $context, array $blocks = array()) + { + // line 3 + $context["value"] = (((null === ($context["value"] ?? null))) ? ($this->getAttribute(($context["field"] ?? null), "default", array())) : (($context["value"] ?? null))); + // line 4 + $context["name"] = $this->getAttribute(($context["field"] ?? null), "name", array()); + // line 5 + $context["btnLabel"] = (($this->getAttribute(($context["field"] ?? null), "btnLabel", array(), "any", true, true)) ? ($this->getAttribute(($context["field"] ?? null), "btnLabel", array())) : ("PLUGIN_ADMIN.ADD_ITEM")); + // line 6 + $context["btnSortLabel"] = (($this->getAttribute(($context["field"] ?? null), "btnSortLabel", array(), "any", true, true)) ? ($this->getAttribute(($context["field"] ?? null), "btnSortLabel", array())) : ("PLUGIN_ADMIN.SORT_BY")); + // line 7 + $context["fieldControls"] = (($this->getAttribute(($context["field"] ?? null), "controls", array(), "any", true, true)) ? (_twig_default_filter($this->getAttribute(($context["field"] ?? null), "controls", array()), "bottom")) : ("bottom")); + // line 1 + $this->parent->display($context, array_merge($this->blocks, $blocks)); + } + + // line 9 + public function block_contents($context, array $blocks = array()) + { + // line 10 + echo "
                                                                  + "; + // line 11 + if ($this->getAttribute(($context["field"] ?? null), "toggleable", array())) { + // line 12 + echo " env, $this->env->getExtension('Grav\Common\Twig\TwigExtension')->fieldNameFilter((($context["scope"] ?? null) . $this->getAttribute(($context["field"] ?? null), "name", array()))), "html", null, true); + echo "\"> + env, $this->getAttribute(($context["field"] ?? null), "name", array()), "html", null, true); + echo "\" + "; + // line 15 + if (($context["toggleableChecked"] ?? null)) { + echo "value=\"1\""; + } + // line 16 + echo " name=\"toggleable_"; + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Common\Twig\TwigExtension')->fieldNameFilter((($context["scope"] ?? null) . $this->getAttribute(($context["field"] ?? null), "name", array()))), "html", null, true); + echo "\" + "; + // line 17 + if (($context["toggleableChecked"] ?? null)) { + echo "checked=\"checked\""; + } + // line 18 + echo " > + + + "; + } + // line 22 + echo " getAttribute(($context["field"] ?? null), "toggleable", array())) ? (((" class=\"toggleable\" for=\"toggleable_" . $this->getAttribute(($context["field"] ?? null), "name", array())) . "\"")) : ("")); + echo "> + "; + // line 23 + if ($this->getAttribute(($context["field"] ?? null), "help", array())) { + // line 24 + echo " env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter(twig_escape_filter($this->env, $this->getAttribute(($context["field"] ?? null), "help", array()))), "html", null, true); + echo "\">"; + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter($this->getAttribute(($context["field"] ?? null), "label", array())), "html", null, true); + echo " + "; + } else { + // line 26 + echo " "; + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter($this->getAttribute(($context["field"] ?? null), "label", array())), "html", null, true); + echo " + "; + } + // line 28 + echo " "; + echo ((twig_in_filter($this->getAttribute($this->getAttribute(($context["field"] ?? null), "validate", array()), "required", array()), array(0 => "on", 1 => "true", 2 => 1))) ? ("*") : ("")); + echo " + +
                                                                  +
                                                                  displayBlock('global_attributes', $context, $blocks); + // line 37 + echo " > + +
                                                                  env, $this->getAttribute(($context["field"] ?? null), "size", array()), "html", null, true); + echo "\" data-type=\"collection\" + "; + // line 40 + if ($this->getAttribute(($context["field"] ?? null), "selectunique", array())) { + // line 41 + echo " data-select-unique=\""; + echo twig_escape_filter($this->env, twig_jsonencode_filter($this->getAttribute(($context["field"] ?? null), "selectunique", array())), "html_attr"); + echo "\" + data-max=\""; + // line 42 + echo twig_escape_filter($this->env, twig_length_filter($this->env, $this->getAttribute(($context["field"] ?? null), "selectunique", array())), "html", null, true); + echo "\" + "; + } + // line 44 + echo " "; + if ($this->getAttribute(($context["field"] ?? null), "min", array(), "any", true, true)) { + echo "data-min=\""; + echo twig_escape_filter($this->env, $this->getAttribute(($context["field"] ?? null), "min", array()), "html", null, true); + echo "\""; + } + // line 45 + echo " "; + if (($this->getAttribute(($context["field"] ?? null), "max", array(), "any", true, true) && !$this->getAttribute(($context["field"] ?? null), "selectunique", array()))) { + echo "data-max=\""; + echo twig_escape_filter($this->env, $this->getAttribute(($context["field"] ?? null), "max", array()), "html", null, true); + echo "\""; + } + // line 46 + echo " > + "; + // line 47 + if (twig_in_filter(($context["fieldControls"] ?? null), array(0 => "top", 1 => "both"))) { + // line 48 + echo "
                                                                  env, ($context["value"] ?? null))) ? (" hidden") : ("")); + echo "\"> + + + "; + // line 53 + if ($this->getAttribute(($context["field"] ?? null), "sortby", array())) { + // line 54 + echo " + "; + } + // line 57 + echo " +
                                                                  + "; + } + // line 61 + echo "
                                                                    getAttribute(($context["field"] ?? null), "classes", array(), "any", true, true)) { + echo "class=\""; + echo twig_escape_filter($this->env, $this->getAttribute(($context["field"] ?? null), "classes", array()), "html", null, true); + echo "\""; + } + echo " data-collection-holder=\""; + echo twig_escape_filter($this->env, ($context["name"] ?? null), "html", null, true); + echo "\" + "; + // line 62 + if (($this->getAttribute(($context["field"] ?? null), "sort", array()) === false)) { + // line 63 + echo " data-collection-nosort + "; + } + // line 64 + echo "> + "; + // line 65 + if ($this->getAttribute(($context["field"] ?? null), "fields", array())) { + // line 66 + echo " "; + $context['_parent'] = $context; + $context['_seq'] = twig_ensure_traversable(($context["value"] ?? null)); + $context['loop'] = array( + 'parent' => $context['_parent'], + 'index0' => 0, + 'index' => 1, + 'first' => true, + ); + if (is_array($context['_seq']) || (is_object($context['_seq']) && $context['_seq'] instanceof Countable)) { + $length = count($context['_seq']); + $context['loop']['revindex0'] = $length - 1; + $context['loop']['revindex'] = $length; + $context['loop']['length'] = $length; + $context['loop']['last'] = 1 === $length; + } + foreach ($context['_seq'] as $context["key"] => $context["val"]) { + // line 67 + echo " "; + $context["itemName"] = ((($context["name"] ?? null)) ? (((($context["name"] ?? null) . ".") . $context["key"])) : ($context["key"])); + // line 68 + echo "
                                                                  • env, ($context["itemName"] ?? null), "html", null, true); + echo "\" data-collection-key=\""; + echo twig_escape_filter($this->env, $context["key"], "html", null, true); + echo "\" class=\""; + echo (((( !$this->getAttribute(($context["field"] ?? null), "collapsible", array(), "any", true, true) || $this->getAttribute(($context["field"] ?? null), "collapsible", array())) && $this->getAttribute(($context["field"] ?? null), "collapsed", array()))) ? ("collection-collapsed") : ("")); + echo "\"> +
                                                                    + "; + // line 70 + $context['_parent'] = $context; + $context['_seq'] = twig_ensure_traversable($this->getAttribute(($context["field"] ?? null), "fields", array())); + $context['loop'] = array( + 'parent' => $context['_parent'], + 'index0' => 0, + 'index' => 1, + 'first' => true, + ); + if (is_array($context['_seq']) || (is_object($context['_seq']) && $context['_seq'] instanceof Countable)) { + $length = count($context['_seq']); + $context['loop']['revindex0'] = $length - 1; + $context['loop']['revindex'] = $length; + $context['loop']['length'] = $length; + $context['loop']['last'] = 1 === $length; + } + foreach ($context['_seq'] as $context["childName"] => $context["child"]) { + // line 71 + echo " "; + if ((is_string($__internal_004f109a1dedba3b99942a2e2f50dedbd8d4e54e41a52c0baf829c07b95da843 = $context["childName"]) && is_string($__internal_588207aa49ca2b7de9a005ace90cc6a700160f109d3bc705e814ac969e54bd49 = ".") && ('' === $__internal_588207aa49ca2b7de9a005ace90cc6a700160f109d3bc705e814ac969e54bd49 || 0 === strpos($__internal_004f109a1dedba3b99942a2e2f50dedbd8d4e54e41a52c0baf829c07b95da843, $__internal_588207aa49ca2b7de9a005ace90cc6a700160f109d3bc705e814ac969e54bd49)))) { + // line 72 + echo " "; + $context["childKey"] = twig_trim_filter($context["childName"], "."); + // line 73 + echo " "; + $context["childValue"] = $this->getAttribute($context["val"], twig_slice($this->env, $context["childName"], 1, null), array(), "array"); + // line 74 + echo " "; + $context["childName"] = (($context["itemName"] ?? null) . $context["childName"]); + // line 75 + echo " "; + } else { + // line 76 + echo " "; + $context["childKey"] = $context["childName"]; + // line 77 + echo " "; + $context["childValue"] = $this->getAttribute(($context["data"] ?? null), "value", array(0 => (($context["scope"] ?? null) . $context["childName"])), "method"); + // line 78 + echo " "; + $context["childName"] = twig_replace_filter($context["childName"], array("*" => $context["key"])); + // line 79 + echo " "; + } + // line 80 + echo " "; + $context["child"] = twig_array_merge($context["child"], array("name" => $context["childName"])); + // line 81 + echo " + "; + // line 82 + if (($this->getAttribute($context["child"], "type", array()) == "key")) { + // line 83 + echo " "; + // line 84 + $this->loadTemplate("forms/fields/key/key.html.twig", "forms/fields/list/list.html.twig", 84)->display(array_merge($context, array("field" => // line 85 +$context["child"], "value" => $context["key"]))); + // line 87 + echo " "; + } elseif (($this->getAttribute($context["child"], "key", array()) == true)) { + // line 88 + echo " "; + $this->loadTemplate(array(0 => (((("forms/fields/" . $this->getAttribute( // line 89 +$context["child"], "type", array())) . "/") . $this->getAttribute($context["child"], "type", array())) . ".html.twig"), 1 => "forms/fields/key/key.html.twig"), "forms/fields/list/list.html.twig", 88)->display(array_merge($context, array("field" => // line 91 +$context["child"], "value" => $context["key"]))); + // line 93 + echo " "; + } elseif ($this->getAttribute($context["child"], "type", array())) { + // line 94 + echo " "; + $context["originalValue"] = ($context["childValue"] ?? null); + // line 95 + echo " "; + // line 96 + $this->loadTemplate(array(0 => (((("forms/fields/" . $this->getAttribute( // line 97 +$context["child"], "type", array())) . "/") . $this->getAttribute($context["child"], "type", array())) . ".html.twig"), 1 => "forms/fields/text/text.html.twig"), "forms/fields/list/list.html.twig", 96)->display(array_merge($context, array("field" => // line 99 +$context["child"], "value" => ($context["childValue"] ?? null)))); + // line 101 + echo " "; + } + // line 102 + echo " "; + ++$context['loop']['index0']; + ++$context['loop']['index']; + $context['loop']['first'] = false; + if (isset($context['loop']['length'])) { + --$context['loop']['revindex0']; + --$context['loop']['revindex']; + $context['loop']['last'] = 0 === $context['loop']['revindex0']; + } + } + $_parent = $context['_parent']; + unset($context['_seq'], $context['_iterated'], $context['childName'], $context['child'], $context['_parent'], $context['loop']); + $context = array_intersect_key($context, $_parent) + $_parent; + // line 103 + echo "
                                                                    + "; + // line 104 + if (( !$this->getAttribute(($context["field"] ?? null), "collapsible", array(), "any", true, true) || $this->getAttribute(($context["field"] ?? null), "collapsible", array()))) { + // line 105 + echo " getAttribute(($context["field"] ?? null), "collapsed", array())) ? ("right") : ("down")); + echo "\" data-action=\""; + echo (($this->getAttribute(($context["field"] ?? null), "collapsed", array())) ? ("expand") : ("collapse")); + echo "\"> +
                                                                    + "; + } + // line 108 + echo " +
                                                                    +
                                                                  • + "; + ++$context['loop']['index0']; + ++$context['loop']['index']; + $context['loop']['first'] = false; + if (isset($context['loop']['length'])) { + --$context['loop']['revindex0']; + --$context['loop']['revindex']; + $context['loop']['last'] = 0 === $context['loop']['revindex0']; + } + } + $_parent = $context['_parent']; + unset($context['_seq'], $context['_iterated'], $context['key'], $context['val'], $context['_parent'], $context['loop']); + $context = array_intersect_key($context, $_parent) + $_parent; + // line 112 + echo " "; + } + // line 113 + echo "
                                                                  + "; + // line 114 + if (twig_in_filter(($context["fieldControls"] ?? null), array(0 => "bottom", 1 => "both"))) { + // line 115 + echo "
                                                                  + "; + // line 116 + if (( !$this->getAttribute(($context["field"] ?? null), "collapsible", array(), "any", true, true) || $this->getAttribute(($context["field"] ?? null), "collapsible", array()))) { + // line 117 + echo " + + "; + } + // line 122 + echo " "; + if ($this->getAttribute(($context["field"] ?? null), "sortby", array())) { + // line 123 + echo " + "; + } + // line 126 + echo " +
                                                                  + "; + } + // line 131 + $context["itemName"] = ((($context["name"] ?? null)) ? ((($context["name"] ?? null) . ".*")) : ("*")); + // line 132 + echo "
                                                                  env, twig_replace_filter( $this->renderBlock("__internal_fa367a566ec58bda83f7abdb372be4a69271c84232c5182b50529b9a3a7d944c", $context, $blocks), array(" " => " ", " +" => " ")), "html_attr"); + // line 178 + echo "\">
                                                                  + +
                                                                  env, ($context["name"] ?? null), "html", null, true); + echo "\">
                                                                  +
                                                                  +
                                                                  +"; + } + + // line 32 + public function block_global_attributes($context, array $blocks = array()) + { + // line 33 + echo " data-grav-field=\""; + echo twig_escape_filter($this->env, $this->getAttribute(($context["field"] ?? null), "type", array()), "html", null, true); + echo "\" + data-grav-disabled=\""; + // line 34 + echo twig_escape_filter($this->env, ($context["toggleableChecked"] ?? null), "html", null, true); + echo "\" + data-grav-default=\""; + // line 35 + echo twig_escape_filter($this->env, twig_jsonencode_filter($this->getAttribute(($context["field"] ?? null), "default", array())), "html_attr"); + echo "\" + "; + } + + // line 132 + public function block___internal_fa367a566ec58bda83f7abdb372be4a69271c84232c5182b50529b9a3a7d944c($context, array $blocks = array()) + { + // line 133 + echo "
                                                                • env, ($context["itemName"] ?? null), "html", null, true); + echo "\"> + "; + // line 134 + if ( !($this->getAttribute(($context["field"] ?? null), "sort", array()) === false)) { + // line 135 + echo "
                                                                  + "; + } + // line 137 + if ($this->getAttribute(($context["field"] ?? null), "fields", array())) { + // line 138 + $context['_parent'] = $context; + $context['_seq'] = twig_ensure_traversable($this->getAttribute(($context["field"] ?? null), "fields", array())); + $context['loop'] = array( + 'parent' => $context['_parent'], + 'index0' => 0, + 'index' => 1, + 'first' => true, + ); + if (is_array($context['_seq']) || (is_object($context['_seq']) && $context['_seq'] instanceof Countable)) { + $length = count($context['_seq']); + $context['loop']['revindex0'] = $length - 1; + $context['loop']['revindex'] = $length; + $context['loop']['length'] = $length; + $context['loop']['last'] = 1 === $length; + } + foreach ($context['_seq'] as $context["childName"] => $context["child"]) { + // line 139 + if ((is_string($__internal_852c17c1704693e7c6e9af566f2e623f6796c522f1770732de468704aafec224 = $context["childName"]) && is_string($__internal_1fd3117e41976d0a6cfeb2f5794dd66c10aba38cd2269d0a81184a3af2dfa5f6 = ".") && ('' === $__internal_1fd3117e41976d0a6cfeb2f5794dd66c10aba38cd2269d0a81184a3af2dfa5f6 || 0 === strpos($__internal_852c17c1704693e7c6e9af566f2e623f6796c522f1770732de468704aafec224, $__internal_1fd3117e41976d0a6cfeb2f5794dd66c10aba38cd2269d0a81184a3af2dfa5f6)))) { + // line 140 + $context["childKey"] = twig_trim_filter($context["childName"], "."); + // line 141 + $context["childName"] = (($context["itemName"] ?? null) . $context["childName"]); + } else { + // line 143 + $context["childKey"] = $context["childName"]; + // line 144 + $context["childName"] = twig_replace_filter($context["childName"], array("*" => ($context["key"] ?? null))); + } + // line 146 + $context["child"] = twig_array_merge($context["child"], array("name" => $context["childName"])); + // line 148 + if (($this->getAttribute($context["child"], "type", array()) == "key")) { + // line 150 + $this->loadTemplate("forms/fields/key/key.html.twig", "forms/fields/list/list.html.twig", 150)->display(array_merge($context, array("field" => // line 151 +$context["child"], "value" => null))); + } elseif (($this->getAttribute( // line 153 +$context["child"], "key", array()) == true)) { + // line 155 + $this->loadTemplate(array(0 => (((("forms/fields/" . $this->getAttribute( // line 156 +$context["child"], "type", array())) . "/") . $this->getAttribute($context["child"], "type", array())) . ".html.twig"), 1 => "forms/fields/key/key.html.twig"), "forms/fields/list/list.html.twig", 155)->display(array_merge($context, array("field" => // line 158 +$context["child"], "value" => null))); + } elseif ($this->getAttribute( // line 160 +$context["child"], "type", array())) { + // line 162 + $this->loadTemplate(array(0 => (((("forms/fields/" . $this->getAttribute( // line 163 +$context["child"], "type", array())) . "/") . $this->getAttribute($context["child"], "type", array())) . ".html.twig"), 1 => "forms/fields/text/text.html.twig"), "forms/fields/list/list.html.twig", 162)->display(array_merge($context, array("field" => // line 165 +$context["child"], "value" => null))); + } + ++$context['loop']['index0']; + ++$context['loop']['index']; + $context['loop']['first'] = false; + if (isset($context['loop']['length'])) { + --$context['loop']['revindex0']; + --$context['loop']['revindex']; + $context['loop']['last'] = 0 === $context['loop']['revindex0']; + } + } + $_parent = $context['_parent']; + unset($context['_seq'], $context['_iterated'], $context['childName'], $context['child'], $context['_parent'], $context['loop']); + $context = array_intersect_key($context, $_parent) + $_parent; + // line 169 + echo "
                                                                  + "; + // line 170 + if (( !$this->getAttribute(($context["field"] ?? null), "collapsible", array(), "any", true, true) || $this->getAttribute(($context["field"] ?? null), "collapsible", array()))) { + // line 171 + echo " +
                                                                  + "; + } + // line 174 + echo " +
                                                                  "; + } + // line 177 + echo "
                                                                • "; + } + + public function getTemplateName() + { + return "forms/fields/list/list.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 597 => 177, 593 => 174, 588 => 171, 586 => 170, 583 => 169, 568 => 165, 567 => 163, 566 => 162, 564 => 160, 562 => 158, 561 => 156, 560 => 155, 558 => 153, 556 => 151, 555 => 150, 553 => 148, 551 => 146, 548 => 144, 546 => 143, 543 => 141, 541 => 140, 539 => 139, 522 => 138, 520 => 137, 516 => 135, 514 => 134, 509 => 133, 506 => 132, 500 => 35, 496 => 34, 491 => 33, 488 => 32, 480 => 180, 476 => 178, 472 => 132, 470 => 131, 460 => 127, 457 => 126, 444 => 124, 435 => 123, 432 => 122, 423 => 120, 414 => 118, 411 => 117, 409 => 116, 406 => 115, 404 => 114, 401 => 113, 398 => 112, 381 => 108, 372 => 105, 370 => 104, 367 => 103, 353 => 102, 350 => 101, 348 => 99, 347 => 97, 346 => 96, 344 => 95, 341 => 94, 338 => 93, 336 => 91, 335 => 89, 333 => 88, 330 => 87, 328 => 85, 327 => 84, 325 => 83, 323 => 82, 320 => 81, 317 => 80, 314 => 79, 311 => 78, 308 => 77, 305 => 76, 302 => 75, 299 => 74, 296 => 73, 293 => 72, 290 => 71, 273 => 70, 263 => 68, 260 => 67, 242 => 66, 240 => 65, 237 => 64, 233 => 63, 231 => 62, 220 => 61, 210 => 58, 207 => 57, 194 => 55, 185 => 54, 183 => 53, 175 => 52, 166 => 50, 160 => 48, 158 => 47, 155 => 46, 148 => 45, 141 => 44, 136 => 42, 131 => 41, 129 => 40, 125 => 39, 121 => 37, 119 => 32, 113 => 31, 106 => 28, 100 => 26, 92 => 24, 90 => 23, 85 => 22, 79 => 19, 76 => 18, 72 => 17, 67 => 16, 63 => 15, 59 => 14, 53 => 12, 51 => 11, 44 => 10, 41 => 9, 37 => 1, 35 => 7, 33 => 6, 31 => 5, 29 => 4, 27 => 3, 11 => 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 Twig_Source("{% extends \"forms/field.html.twig\" %} + +{% set value = (value is null ? field.default : value) %} +{% set name = field.name %} +{% set btnLabel = field.btnLabel is defined ? field.btnLabel : \"PLUGIN_ADMIN.ADD_ITEM\" %} +{% set btnSortLabel = field.btnSortLabel is defined ? field.btnSortLabel : \"PLUGIN_ADMIN.SORT_BY\" %} +{% set fieldControls = field.controls|default('bottom') %} + +{% block contents %} +
                                                                  + {% if field.toggleable %} + + + + + {% endif %} + + {% if field.help %} + {{ field.label|tu }} + {% else %} + {{ field.label|tu }} + {% endif %} + {{ field.validate.required in ['on', 'true', 1] ? '*' }} + +
                                                                  +
                                                                  + +
                                                                  + {% if fieldControls in ['top', 'both'] %} +
                                                                  + + + {% if field.sortby %} + + {% endif %} + +
                                                                  + {% endif %} +
                                                                    + {% if field.fields %} + {% for key, val in value %} + {% set itemName = name ? name ~ '.' ~ key : key %} +
                                                                  • +
                                                                    + {% for childName, child in field.fields %} + {% if childName starts with '.' %} + {% set childKey = childName|trim('.') %} + {% set childValue = val[childName[1:]] %} + {% set childName = itemName ~ childName %} + {% else %} + {% set childKey = childName %} + {% set childValue = data.value(scope ~ childName) %} + {% set childName = childName|replace({'*': key}) %} + {% endif %} + {% set child = child|merge({ name: childName }) %} + + {% if child.type == 'key' %} + {% + include 'forms/fields/key/key.html.twig' + with { field: child, value: key } + %} + {% elseif child.key == true %} + {% include [ + \"forms/fields/#{child.type}/#{child.type}.html.twig\", + 'forms/fields/key/key.html.twig' + ] with { field: child, value: key } + %} + {% elseif child.type %} + {% set originalValue = childValue %} + {% + include [ + \"forms/fields/#{child.type}/#{child.type}.html.twig\", + 'forms/fields/text/text.html.twig' + ] with { field: child, value: childValue } + %} + {% endif %} + {% endfor %} +
                                                                    + {% if field.collapsible is not defined or field.collapsible %} + +
                                                                    + {% endif %} + +
                                                                    +
                                                                  • + {% endfor %} + {% endif %} +
                                                                  + {% if fieldControls in ['bottom', 'both'] %} +
                                                                  + {% if field.collapsible is not defined or field.collapsible %} + + + {% endif %} + {% if field.sortby %} + + {% endif %} + +
                                                                  + {% endif %} + + {%- set itemName = name ? name ~ '.*' : '*' -%} +
                                                                  + {% if field.sort is not same as(false) %} +
                                                                  + {% endif %} + {%- if field.fields -%} + {%- for childName, child in field.fields -%} + {%- if childName starts with '.' -%} + {%- set childKey = childName|trim('.') -%} + {%- set childName = itemName ~ childName -%} + {%- else %} + {%- set childKey = childName -%} + {%- set childName = childName|replace({'*': key}) -%} + {%- endif %} + {%- set child = child|merge({ name: childName }) -%} + + {%- if child.type == 'key' -%} + {%- + include 'forms/fields/key/key.html.twig' + with { field: child, value: null } + -%} + {%- elseif child.key == true -%} + {%- + include [ + \"forms/fields/#{child.type}/#{child.type}.html.twig\", + 'forms/fields/key/key.html.twig' + ] with { field: child, value: null } + -%} + {%- elseif child.type -%} + {%- + include [ + \"forms/fields/#{child.type}/#{child.type}.html.twig\", + 'forms/fields/text/text.html.twig' + ] with { field: child, value: null } + -%} + {%- endif -%} + {%- endfor %} +
                                                                  + {% if field.collapsible is not defined or field.collapsible %} + +
                                                                  + {% endif %} + +
                                                                  + {%- endif -%} + + {%- endfilter -%}\">
                                                                  + +
                                                                  +
                                                                  +
                                                                  +{% endblock %} + +", "forms/fields/list/list.html.twig", "/home/kevin/Sites/static-ethica.net/user/plugins/admin/themes/grav/templates/forms/fields/list/list.html.twig"); + } +} diff --git a/cache/twig/df/df835f321be51afeb87ddb460bf279876ed2a9bb5a0550f92dbb1441b2134074.php b/cache/twig/df/df835f321be51afeb87ddb460bf279876ed2a9bb5a0550f92dbb1441b2134074.php new file mode 100644 index 0000000..7d82914 --- /dev/null +++ b/cache/twig/df/df835f321be51afeb87ddb460bf279876ed2a9bb5a0550f92dbb1441b2134074.php @@ -0,0 +1,75 @@ +parent = false; + + $this->blocks = array( + ); + } + + protected function doDisplay(array $context, array $blocks = array()) + { + // line 1 + echo "getAttribute(($context["field"] ?? null), "disabled", array()) || ($context["isDisabledToggleable"] ?? null))) { + echo "disabled=\"disabled\""; + } + // line 7 + echo " name=\""; + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Common\Twig\TwigExtension')->fieldNameFilter((($context["scope"] ?? null) . $this->getAttribute(($context["field"] ?? null), "name", array()))), "html", null, true); + echo "\" + value=\""; + // line 8 + echo twig_escape_filter($this->env, $this->getAttribute(($context["blueprints"] ?? null), "name", array()), "html", null, true); + echo "\" /> +"; + } + + public function getTemplateName() + { + return "forms/fields/blueprint/blueprint.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 35 => 8, 30 => 7, 26 => 6, 19 => 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 Twig_Source(" +", "forms/fields/blueprint/blueprint.html.twig", "/mnt/data/Sites/static-ethica.net/user/plugins/admin/themes/grav/templates/forms/fields/blueprint/blueprint.html.twig"); + } +} diff --git a/cache/twig/df/dff720ade6169bc0a60d6febe5623bfe07ea1ac0c971020e27be33916124f114.php b/cache/twig/df/dff720ade6169bc0a60d6febe5623bfe07ea1ac0c971020e27be33916124f114.php new file mode 100644 index 0000000..b8e1a88 --- /dev/null +++ b/cache/twig/df/dff720ade6169bc0a60d6febe5623bfe07ea1ac0c971020e27be33916124f114.php @@ -0,0 +1,171 @@ +parent = false; + + $this->blocks = array( + ); + } + + protected function doDisplay(array $context, array $blocks = array()) + { + // line 1 + echo "
                                                                    +"; + // line 2 + $context['_parent'] = $context; + $context['_seq'] = twig_ensure_traversable($this->getAttribute(($context["langswitcher"] ?? null), "languages", array())); + foreach ($context['_seq'] as $context["_key"] => $context["language"]) { + // line 3 + echo " + "; + // line 4 + $context["show_language"] = true; + // line 5 + echo " "; + if (($context["language"] == $this->getAttribute(($context["langswitcher"] ?? null), "current", array()))) { + // line 6 + echo " "; + $context["lang_url"] = $this->getAttribute(($context["page"] ?? null), "url", array()); + // line 7 + echo " "; + $context["active_class"] = " active"; + // line 8 + echo " "; + } else { + // line 9 + echo " "; + $context["base_lang_url"] = (($context["base_url_simple"] ?? null) . $this->getAttribute($this->getAttribute(($context["grav"] ?? null), "language", array()), "getLanguageURLPrefix", array(0 => $context["language"]), "method")); + // line 10 + echo " "; + $context["lang_url"] = ((($context["base_lang_url"] ?? null) . $this->getAttribute(($context["langswitcher"] ?? null), "page_route", array())) . $this->getAttribute(($context["page"] ?? null), "urlExtension", array())); + // line 11 + echo " "; + $context["untranslated_pages_behavior"] = $this->getAttribute($this->getAttribute($this->getAttribute($this->getAttribute(($context["grav"] ?? null), "config", array()), "plugins", array()), "langswitcher", array()), "untranslated_pages_behavior", array()); + // line 12 + echo " "; + if ((($context["untranslated_pages_behavior"] ?? null) != "none")) { + // line 13 + echo " "; + $context["translated_page"] = $this->getAttribute($this->getAttribute(($context["langswitcher"] ?? null), "translated_pages", array()), $context["language"], array(), "array"); + // line 14 + echo " "; + if (( !($context["translated_page"] ?? null) || !$this->getAttribute(($context["translated_page"] ?? null), "published", array()))) { + // line 15 + echo " "; + if ((($context["untranslated_pages_behavior"] ?? null) == "redirect")) { + // line 16 + echo " "; + $context["lang_url"] = (($context["base_lang_url"] ?? null) . "/"); + // line 17 + echo " "; + } elseif ((($context["untranslated_pages_behavior"] ?? null) == "hide")) { + // line 18 + echo " "; + $context["show_language"] = false; + // line 19 + echo " "; + } + // line 20 + echo " "; + } + // line 21 + echo " "; + } + // line 22 + echo " "; + $context["active_class"] = ""; + // line 23 + echo " "; + } + // line 24 + echo " + "; + // line 25 + if (($context["show_language"] ?? null)) { + // line 26 + echo "
                                                                  • getAttribute(($context["uri"] ?? null), "params", array())); + echo "\" class=\"external"; + echo ($context["active_class"] ?? null); + echo "\">"; + echo twig_capitalize_string_filter($this->env, call_user_func_array($this->env->getFunction('native_name')->getCallable(), array($context["language"]))); + echo "
                                                                  • + "; + } + // line 28 + echo " +"; + } + $_parent = $context['_parent']; + unset($context['_seq'], $context['_iterated'], $context['_key'], $context['language'], $context['_parent'], $context['loop']); + $context = array_intersect_key($context, $_parent) + $_parent; + // line 30 + echo "
                                                                  +"; + } + + public function getTemplateName() + { + return "partials/langswitcher.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 110 => 30, 103 => 28, 93 => 26, 91 => 25, 88 => 24, 85 => 23, 82 => 22, 79 => 21, 76 => 20, 73 => 19, 70 => 18, 67 => 17, 64 => 16, 61 => 15, 58 => 14, 55 => 13, 52 => 12, 49 => 11, 46 => 10, 43 => 9, 40 => 8, 37 => 7, 34 => 6, 31 => 5, 29 => 4, 26 => 3, 22 => 2, 19 => 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 Twig_Source("
                                                                    +{% for language in langswitcher.languages %} + + {% set show_language = true %} + {% if language == langswitcher.current %} + {% set lang_url = page.url %} + {% set active_class = ' active' %} + {% else %} + {% set base_lang_url = base_url_simple ~ grav.language.getLanguageURLPrefix(language) %} + {% set lang_url = base_lang_url ~ langswitcher.page_route ~ page.urlExtension %} + {% set untranslated_pages_behavior = grav.config.plugins.langswitcher.untranslated_pages_behavior %} + {% if untranslated_pages_behavior != 'none' %} + {% set translated_page = langswitcher.translated_pages[language] %} + {% if (not translated_page) or (not translated_page.published) %} + {% if untranslated_pages_behavior == 'redirect' %} + {% set lang_url = base_lang_url ~ '/' %} + {% elseif untranslated_pages_behavior == 'hide' %} + {% set show_language = false %} + {% endif %} + {% endif %} + {% endif %} + {% set active_class = '' %} + {% endif %} + + {% if show_language %} +
                                                                  • {{ native_name(language)|capitalize }}
                                                                  • + {% endif %} + +{% endfor %} +
                                                                  +", "partials/langswitcher.html.twig", "/home/kevin/Sites/static-ethica.net/user/plugins/langswitcher/templates/partials/langswitcher.html.twig"); + } +} diff --git a/cache/twig/e2/e2fa6490ae1f5519abd906825c1f45188fec02a6ab1419fc50159bb44d88e469.php b/cache/twig/e2/e2fa6490ae1f5519abd906825c1f45188fec02a6ab1419fc50159bb44d88e469.php new file mode 100644 index 0000000..b1c5d70 --- /dev/null +++ b/cache/twig/e2/e2fa6490ae1f5519abd906825c1f45188fec02a6ab1419fc50159bb44d88e469.php @@ -0,0 +1,93 @@ +parent = false; + + $this->blocks = array( + ); + } + + protected function doDisplay(array $context, array $blocks = array()) + { + // line 1 + echo "
                                                                  + You are offline +
                                                                  + +"; + } + + public function getTemplateName() + { + return "partials/nav-user-details.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 45 => 10, 37 => 9, 33 => 7, 31 => 6, 25 => 5, 19 => 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 Twig_Source("
                                                                  + You are offline +
                                                                  + +", "partials/nav-user-details.html.twig", "/mnt/data/Sites/static-ethica.net/user/plugins/admin/themes/grav/templates/partials/nav-user-details.html.twig"); + } +} diff --git a/cache/twig/e7/e75bff12bc1ba233e5039aff5a4ef7bc6d23c7b4b250837b1fc67ad4ea09bcd7.php b/cache/twig/e7/e75bff12bc1ba233e5039aff5a4ef7bc6d23c7b4b250837b1fc67ad4ea09bcd7.php new file mode 100644 index 0000000..96a1150 --- /dev/null +++ b/cache/twig/e7/e75bff12bc1ba233e5039aff5a4ef7bc6d23c7b4b250837b1fc67ad4ea09bcd7.php @@ -0,0 +1,356 @@ +parent = false; + + $this->blocks = array( + 'head' => array($this, 'block_head'), + 'stylesheets' => array($this, 'block_stylesheets'), + 'javascripts' => array($this, 'block_javascripts'), + 'header' => array($this, 'block_header'), + 'header_navigation' => array($this, 'block_header_navigation'), + 'body' => array($this, 'block_body'), + 'content' => array($this, 'block_content'), + 'footer' => array($this, 'block_footer'), + 'bottom' => array($this, 'block_bottom'), + ); + } + + protected function doDisplay(array $context, array $blocks = array()) + { + // line 1 + $context["theme_config"] = $this->getAttribute($this->getAttribute(($context["config"] ?? null), "themes", array()), $this->getAttribute($this->getAttribute($this->getAttribute(($context["config"] ?? null), "system", array()), "pages", array()), "theme", array())); + // line 2 + echo " +getAttribute($this->getAttribute(($context["grav"] ?? null), "language", array()), "getLanguage", array())) ? ($this->getAttribute($this->getAttribute(($context["grav"] ?? null), "language", array()), "getLanguage", array())) : ("fr")); + echo "\"> + +"; + // line 5 + $this->displayBlock('head', $context, $blocks); + // line 34 + echo " + + + + "; + // line 38 + $this->displayBlock('header', $context, $blocks); + // line 65 + echo " + "; + // line 66 + $this->displayBlock('body', $context, $blocks); + // line 75 + echo " + "; + // line 76 + $this->displayBlock('footer', $context, $blocks); + // line 80 + echo " + "; + // line 81 + $this->displayBlock('bottom', $context, $blocks); + // line 84 + echo " + +"; + } + + // line 5 + public function block_head($context, array $blocks = array()) + { + // line 6 + echo " + "; + // line 7 + if ($this->getAttribute(($context["header"] ?? null), "title", array())) { + echo twig_escape_filter($this->env, $this->getAttribute(($context["header"] ?? null), "title", array()), "html"); + echo " | "; + } + echo $this->env->getExtension('Grav\Common\Twig\TwigExtension')->translate($this->getAttribute($this->getAttribute(($context["config"] ?? null), "site", array()), "title", array()), "html"); + echo " + "; + // line 8 + $this->loadTemplate("partials/metadata.html.twig", "partials/base.html.twig", 8)->display($context); + // line 9 + echo " + env->getExtension('Grav\Common\Twig\TwigExtension')->urlFunc("theme://images/favicon.png"); + echo "\" /> + getAttribute(($context["page"] ?? null), "url", array(0 => true, 1 => true), "method"); + echo "\" /> + + + + "; + // line 15 + $this->displayBlock('stylesheets', $context, $blocks); + // line 23 + echo " "; + echo $this->getAttribute(($context["assets"] ?? null), "css", array(), "method"); + echo " + + "; + // line 25 + $this->displayBlock('javascripts', $context, $blocks); + // line 32 + echo " "; + echo $this->getAttribute(($context["assets"] ?? null), "js", array(), "method"); + echo " + "; + } + + // line 15 + public function block_stylesheets($context, array $blocks = array()) + { + // line 16 + echo " "; + $this->getAttribute(($context["assets"] ?? null), "addCss", array(0 => "theme://css/jquery.bxslider.css", 1 => 101), "method"); + // line 17 + echo " "; + $this->getAttribute(($context["assets"] ?? null), "addCss", array(0 => "theme://css/style.css", 1 => 101), "method"); + // line 18 + echo " "; + $this->getAttribute(($context["assets"] ?? null), "addCss", array(0 => "theme://css-compiled/template.css", 1 => 101), "method"); + // line 19 + echo " "; + $this->getAttribute(($context["assets"] ?? null), "addCss", array(0 => "theme://css/jquery.mCustomScrollbar.css", 1 => 101), "method"); + // line 20 + echo " "; + $this->getAttribute(($context["assets"] ?? null), "addCss", array(0 => "theme://css/media-queries.css", 1 => 101), "method"); + // line 21 + echo " + "; + } + + // line 25 + public function block_javascripts($context, array $blocks = array()) + { + // line 26 + echo " "; + $this->getAttribute(($context["assets"] ?? null), "addJs", array(0 => "jquery", 1 => 101), "method"); + // line 27 + echo " "; + $this->getAttribute(($context["assets"] ?? null), "addJs", array(0 => "theme://js/jquery.mCustomScrollbar.concat.min.js"), "method"); + // line 28 + echo " "; + $this->getAttribute(($context["assets"] ?? null), "addJs", array(0 => "theme://js/jquery.bxslider.min.js"), "method"); + // line 29 + echo " "; + $this->getAttribute(($context["assets"] ?? null), "addJs", array(0 => "theme://js/script.js"), "method"); + // line 30 + echo " + "; + } + + // line 38 + public function block_header($context, array $blocks = array()) + { + // line 39 + echo "
                                                                  + +
                                                                  +
                                                                  +
                                                                  +
                                                                  +
                                                                  + "; + // line 54 + $this->displayBlock('header_navigation', $context, $blocks); + // line 55 + echo "
                                                                  + +
                                                                  +
                                                                  + "; + } + + // line 54 + public function block_header_navigation($context, array $blocks = array()) + { + } + + // line 66 + public function block_body($context, array $blocks = array()) + { + // line 67 + echo " +
                                                                  +
                                                                  + "; + // line 70 + $this->displayBlock('content', $context, $blocks); + // line 71 + echo "
                                                                  +
                                                                  + + "; + } + + // line 70 + public function block_content($context, array $blocks = array()) + { + } + + // line 76 + public function block_footer($context, array $blocks = array()) + { + // line 77 + echo "
                                                                  +
                                                                  + "; + } + + // line 81 + public function block_bottom($context, array $blocks = array()) + { + // line 82 + echo " "; + echo $this->getAttribute(($context["assets"] ?? null), "js", array(0 => "bottom"), "method"); + echo " + "; + } + + public function getTemplateName() + { + return "partials/base.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 238 => 82, 235 => 81, 229 => 77, 226 => 76, 221 => 70, 214 => 71, 212 => 70, 207 => 67, 204 => 66, 199 => 54, 186 => 55, 184 => 54, 166 => 41, 162 => 39, 159 => 38, 154 => 30, 151 => 29, 148 => 28, 145 => 27, 142 => 26, 139 => 25, 134 => 21, 131 => 20, 128 => 19, 125 => 18, 122 => 17, 119 => 16, 116 => 15, 109 => 32, 107 => 25, 101 => 23, 99 => 15, 92 => 11, 88 => 10, 85 => 9, 83 => 8, 75 => 7, 72 => 6, 69 => 5, 63 => 84, 61 => 81, 58 => 80, 56 => 76, 53 => 75, 51 => 66, 48 => 65, 46 => 38, 40 => 34, 38 => 5, 33 => 3, 30 => 2, 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 Twig_Source("{% set theme_config = attribute(config.themes, config.system.pages.theme) %} + + + +{% block head %} + + {% if header.title %}{{ header.title|e('html') }} | {% endif %}{{ config.site.title|t('html') }} + {% include 'partials/metadata.html.twig' %} + + + + + + + {% block stylesheets %} + {% do assets.addCss('theme://css/jquery.bxslider.css', 101) %} + {% do assets.addCss('theme://css/style.css', 101) %} + {% do assets.addCss('theme://css-compiled/template.css', 101) %} + {% do assets.addCss('theme://css/jquery.mCustomScrollbar.css', 101) %} + {% do assets.addCss('theme://css/media-queries.css', 101) %} + + {% endblock %} + {{ assets.css() }} + + {% block javascripts %} + {% do assets.addJs('jquery', 101) %} + {% do assets.addJs('theme://js/jquery.mCustomScrollbar.concat.min.js') %} + {% do assets.addJs('theme://js/jquery.bxslider.min.js') %} + {% do assets.addJs('theme://js/script.js') %} + + {% endblock %} + {{ assets.js() }} + {% endblock head %} + + + + + {% block header %} +
                                                                  +
                                                                  +

                                                                  {{ config.site.title|t }}

                                                                  +
                                                                  + Fr + / + En +
                                                                  + +
                                                                  +
                                                                  +
                                                                  +
                                                                  +
                                                                  +
                                                                  + {% block header_navigation %}{% endblock %} +
                                                                  + +
                                                                  +
                                                                  + {% endblock %} + + {% block body %} + +
                                                                  +
                                                                  + {% block content %}{% endblock %} +
                                                                  +
                                                                  + + {% endblock %} + + {% block footer %} +
                                                                  +
                                                                  + {% endblock %} + + {% block bottom %} + {{ assets.js('bottom') }} + {% endblock %} + + +", "partials/base.html.twig", "/mnt/data/Sites/static-ethica.net/user/themes/ethica/templates/partials/base.html.twig"); + } +} diff --git a/cache/twig/e9/e9d9bb91025a14b1bf2f779369740ef130aae36eb0e56a844ac649aedc09a776.php b/cache/twig/e9/e9d9bb91025a14b1bf2f779369740ef130aae36eb0e56a844ac649aedc09a776.php new file mode 100644 index 0000000..e125120 --- /dev/null +++ b/cache/twig/e9/e9d9bb91025a14b1bf2f779369740ef130aae36eb0e56a844ac649aedc09a776.php @@ -0,0 +1,85 @@ +parent = false; + + $this->blocks = array( + ); + } + + protected function doDisplay(array $context, array $blocks = array()) + { + // line 1 + echo "
                                                                  +
                                                                  +

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

                                                                  +

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

                                                                  +
                                                                  + +
                                                                  +
                                                                  "; + } + + public function getTemplateName() + { + return "partials/modal-changes-detected.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 39 => 10, 35 => 9, 28 => 5, 23 => 3, 19 => 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 Twig_Source("
                                                                  +
                                                                  +

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

                                                                  +

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

                                                                  +
                                                                  + +
                                                                  +
                                                                  ", "partials/modal-changes-detected.html.twig", "/mnt/data/Sites/static-ethica.net/user/plugins/admin/themes/grav/templates/partials/modal-changes-detected.html.twig"); + } +} diff --git a/cache/twig/eb/ebb26371377726351e39fa62042644bee39971ef14fc2417888368101fc8bfea.php b/cache/twig/eb/ebb26371377726351e39fa62042644bee39971ef14fc2417888368101fc8bfea.php new file mode 100644 index 0000000..0bbd40a --- /dev/null +++ b/cache/twig/eb/ebb26371377726351e39fa62042644bee39971ef14fc2417888368101fc8bfea.php @@ -0,0 +1,1567 @@ +parent = $this->loadTemplate("partials/base.html.twig", "pages.html.twig", 1); + $this->blocks = array( + 'stylesheets' => array($this, 'block_stylesheets'), + 'javascripts' => array($this, 'block_javascripts'), + 'titlebar' => array($this, 'block_titlebar'), + 'content' => array($this, 'block_content'), + 'bottom' => array($this, 'block_bottom'), + ); + } + + protected function doGetParent(array $context) + { + return "partials/base.html.twig"; + } + + protected function doDisplay(array $context, array $blocks = array()) + { + // line 7 + if ($this->getAttribute(($context["admin"] ?? null), "route", array())) { + // line 8 + $context["context"] = $this->getAttribute(($context["admin"] ?? null), "page", array(0 => true), "method"); + } + // line 11 + if ($this->getAttribute(($context["uri"] ?? null), "param", array(0 => "new"), "method")) { + // line 12 + $context["mode"] = "new"; + } elseif ( // line 13 +($context["context"] ?? null)) { + // line 14 + $context["mode"] = "edit"; + // line 15 + if ($this->getAttribute(($context["context"] ?? null), "exists", array())) { + // line 16 + $context["page_url"] = ((($context["base_url"] ?? null) . "/pages") . (($this->getAttribute($this->getAttribute($this->getAttribute(($context["context"] ?? null), "header", array()), "routes", array()), "default", array())) ? ($this->getAttribute($this->getAttribute($this->getAttribute(($context["context"] ?? null), "header", array()), "routes", array()), "default", array())) : ($this->getAttribute(($context["context"] ?? null), "rawRoute", array())))); + // line 17 + $context["exists"] = true; + // line 18 + $context["title"] = (((($this->getAttribute(($context["context"] ?? null), "exists", array())) ? ($this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.EDIT")) : ($this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.CREATE"))) . " ") . (($this->getAttribute($this->getAttribute(($context["context"] ?? null), "header", array()), "title", array())) ? ($this->getAttribute($this->getAttribute(($context["context"] ?? null), "header", array()), "title", array())) : ($this->getAttribute(($context["context"] ?? null), "title", array())))); + } else { + // line 20 + $context["title"] = $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.ADD_PAGE"); + } + } else { + // line 23 + $context["mode"] = "list"; + // line 24 + $context["title"] = $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.PAGES"); + } + // line 27 + $context["modular"] = (($this->getAttribute(($context["context"] ?? null), "modular", array())) ? ("modular_") : ("")); + // line 28 + $context["warn"] = $this->getAttribute($this->getAttribute($this->getAttribute($this->getAttribute(($context["config"] ?? null), "plugins", array()), "admin", array()), "warnings", array()), "delete_page", array()); + // line 29 + $context["admin_lang"] = (($this->getAttribute($this->getAttribute(($context["admin"] ?? null), "session", array()), "admin_lang", array())) ? ($this->getAttribute($this->getAttribute(($context["admin"] ?? null), "session", array()), "admin_lang", array())) : ("en")); + // line 30 + $context["page_lang"] = $this->getAttribute(($context["context"] ?? null), "language", array()); + // line 31 + $context["type"] = "page"; + // line 44 + $context["preview_html"] = ((($this->env->getExtension('Grav\Common\Twig\TwigExtension')->rtrimFilter(($context["base_url_relative_frontend"] ?? null), "/") . (($this->getAttribute(($context["context"] ?? null), "home", array())) ? ("") : ($this->getAttribute(($context["context"] ?? null), "route", array()))))) ? (($this->env->getExtension('Grav\Common\Twig\TwigExtension')->rtrimFilter(($context["base_url_relative_frontend"] ?? null), "/") . (($this->getAttribute(($context["context"] ?? null), "home", array())) ? ("") : ($this->getAttribute(($context["context"] ?? null), "route", array()))))) : ("/")); + // line 45 + $context["preview_target"] = $this->getAttribute($this->getAttribute($this->getAttribute(($context["config"] ?? null), "plugins", array()), "admin", array()), "frontend_pages_target", array()); + // line 46 + $context["preview_link"] = (($this->getAttribute(($context["context"] ?? null), "routable", array())) ? ((((((("env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.PREVIEW")) . "\"> ")) : ("")); + // line 1 + $this->parent->display($context, array_merge($this->blocks, $blocks)); + } + + // line 33 + public function block_stylesheets($context, array $blocks = array()) + { + // line 34 + echo " "; + if ((($context["mode"] ?? null) == "edit")) { + // line 35 + echo " "; + $this->getAttribute(($context["assets"] ?? null), "addCss", array(0 => (($context["theme_url"] ?? null) . "/css/codemirror/codemirror.css")), "method"); + // line 36 + echo " "; + } + // line 37 + echo " "; + $this->displayParentBlock("stylesheets", $context, $blocks); + echo " +"; + } + + // line 40 + public function block_javascripts($context, array $blocks = array()) + { + // line 41 + echo " "; + $this->displayParentBlock("javascripts", $context, $blocks); + echo " +"; + } + + // line 121 + public function block_titlebar($context, array $blocks = array()) + { + // line 122 + echo "
                                                                  + "; + // line 123 + if ((($context["mode"] ?? null) == "list")) { + // line 124 + echo " env, ($context["base_url"] ?? null), "html", null, true); + echo "\"> "; + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.BACK"), "html", null, true); + echo " + + "; + // line 126 + $context['_parent'] = $context; + $context['_seq'] = twig_ensure_traversable($this->getAttribute($this->getAttribute($this->getAttribute(($context["config"] ?? null), "plugins", array()), "admin", array()), "add_modals", array())); + foreach ($context['_seq'] as $context["key"] => $context["add_modal"]) { + // line 127 + echo " "; + if (($this->env->getExtension('Grav\Common\Twig\TwigExtension')->definedDefaultFilter($this->getAttribute($context["add_modal"], "show_in", array()), "bar") == "bar")) { + // line 128 + echo " env, $this->getAttribute($context["add_modal"], "link_classes", array()), "html", null, true); + echo "\" href=\"#modal-add_modal-"; + echo twig_escape_filter($this->env, $context["key"], "html", null, true); + echo "\" data-remodal-target=\"modal-add_modal-"; + echo twig_escape_filter($this->env, $context["key"], "html", null, true); + echo "\"> "; + echo twig_escape_filter($this->env, $this->getAttribute($context["add_modal"], "label", array()), "html", null, true); + echo " + "; + } + // line 130 + echo " "; + } + $_parent = $context['_parent']; + unset($context['_seq'], $context['_iterated'], $context['key'], $context['add_modal'], $context['_parent'], $context['loop']); + $context = array_intersect_key($context, $_parent) + $_parent; + // line 131 + echo " +
                                                                  + + + +
                                                                  + + "; + // line 153 + if ($this->getAttribute(($context["admin"] ?? null), "multilang", array())) { + // line 154 + echo "
                                                                  + + "; + // line 160 + if ((twig_length_filter($this->env, $this->getAttribute(($context["admin"] ?? null), "languages_enabled", array())) > 1)) { + // line 161 + echo " + + "; + } + // line 173 + echo "
                                                                  + "; + } + // line 175 + echo " + "; + } elseif (( // line 176 +($context["mode"] ?? null) == "edit")) { + // line 177 + echo " + "; + // line 178 + echo ($context["preview_link"] ?? null); + echo " + + env, ($context["base_url"] ?? null), "html", null, true); + echo "/pages\" title=\""; + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.BACK"), "html", null, true); + echo "\"> + + "; + // line 182 + $context["siblings"] = $this->getAttribute($this->getAttribute(($context["context"] ?? null), "parent", array(), "method"), "children", array(), "method"); + // line 183 + echo " + "; + // line 184 + if ( !$this->getAttribute(($context["siblings"] ?? null), "isFirst", array(0 => $this->getAttribute(($context["context"] ?? null), "path", array())), "method")) { + // line 185 + echo " "; + $context["sib"] = $this->getAttribute(($context["siblings"] ?? null), "nextSibling", array(0 => $this->getAttribute(($context["context"] ?? null), "path", array())), "method"); + // line 186 + echo " "; + $context["sib_url"] = ((($context["base_url"] ?? null) . "/pages") . (($this->getAttribute($this->getAttribute($this->getAttribute(($context["sib"] ?? null), "header", array()), "routes", array()), "default", array())) ? ($this->getAttribute($this->getAttribute($this->getAttribute(($context["sib"] ?? null), "header", array()), "routes", array()), "default", array())) : ($this->getAttribute(($context["sib"] ?? null), "rawRoute", array())))); + // line 187 + echo " env, ($context["sib_url"] ?? null), "html", null, true); + echo "\" title=\""; + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.PREVIOUS"), "html", null, true); + echo "\"> + "; + } + // line 189 + echo " + "; + // line 190 + if ( !$this->getAttribute(($context["siblings"] ?? null), "isLast", array(0 => $this->getAttribute(($context["context"] ?? null), "path", array())), "method")) { + // line 191 + echo " "; + $context["sib"] = $this->getAttribute(($context["siblings"] ?? null), "prevSibling", array(0 => $this->getAttribute(($context["context"] ?? null), "path", array())), "method"); + // line 192 + echo " "; + $context["sib_url"] = ((($context["base_url"] ?? null) . "/pages") . (($this->getAttribute($this->getAttribute($this->getAttribute(($context["sib"] ?? null), "header", array()), "routes", array()), "default", array())) ? ($this->getAttribute($this->getAttribute($this->getAttribute(($context["sib"] ?? null), "header", array()), "routes", array()), "default", array())) : ($this->getAttribute(($context["sib"] ?? null), "rawRoute", array())))); + // line 193 + echo " env, ($context["sib_url"] ?? null), "html", null, true); + echo "\" title=\""; + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.NEXT"), "html", null, true); + echo "\"> + "; + } + // line 195 + echo " + "; + // line 196 + if (($context["exists"] ?? null)) { + // line 197 + echo "
                                                                  + + + +
                                                                  + + env, $this->getAttribute(($context["uri"] ?? null), "addNonce", array(0 => (((($context["page_url"] ?? null) . "/task") . $this->getAttribute($this->getAttribute(($context["config"] ?? null), "system", array()), "param_sep", array())) . "copy"), 1 => "admin-form", 2 => "admin-nonce"), "method"), "html", null, true); + echo "\" class=\"page-copy\" > "; + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.COPY"), "html", null, true); + echo " + "; + // line 214 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.MOVE"), "html", null, true); + echo " + "; + // line 215 + if ($this->getAttribute($this->getAttribute($this->getAttribute(($context["config"] ?? null), "plugins", array()), "admin-pro", array(), "array"), "enabled", array())) { + // line 216 + echo " "; + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN_PRO.REVISIONS"), "html", null, true); + echo " + "; + } + // line 218 + echo " "; + if (($context["warn"] ?? null)) { + // line 219 + echo " env, $this->getAttribute(($context["uri"] ?? null), "addNonce", array(0 => (((($context["page_url"] ?? null) . "/task") . $this->getAttribute($this->getAttribute(($context["config"] ?? null), "system", array()), "param_sep", array())) . "delete"), 1 => "admin-form", 2 => "admin-nonce"), "method"), "html", null, true); + echo "\"> "; + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.DELETE"), "html", null, true); + echo " + "; + } else { + // line 221 + echo " env, $this->getAttribute(($context["uri"] ?? null), "addNonce", array(0 => ((($this->getAttribute(($context["uri"] ?? null), "route", array(0 => true), "method") . "/task") . $this->getAttribute($this->getAttribute(($context["config"] ?? null), "system", array()), "param_sep", array())) . "delete"), 1 => "admin-form", 2 => "admin-nonce"), "method"), "html", null, true); + echo "\" class=\"page-delete\" > + "; + } + // line 223 + echo " "; + } + // line 224 + echo " +
                                                                  + + "; + // line 227 + if ((($context["exists"] ?? null) && $this->getAttribute(($context["admin"] ?? null), "multilang", array()))) { + // line 228 + echo " "; + if ($this->getAttribute(($context["context"] ?? null), "untranslatedLanguages", array())) { + // line 229 + echo " +
                                                                    + "; + // line 233 + $context['_parent'] = $context; + $context['_seq'] = twig_ensure_traversable($this->getAttribute(($context["context"] ?? null), "untranslatedLanguages", array())); + foreach ($context['_seq'] as $context["_key"] => $context["langCode"]) { + // line 234 + echo " "; + $context["langName"] = $this->getAttribute($this->getAttribute(($context["admin"] ?? null), "siteLanguages", array()), $context["langCode"], array(), "array"); + // line 235 + echo " "; + if (($context["langCode"] != ($context["page_lang"] ?? null))) { + // line 236 + echo "
                                                                  • + "; + } + // line 238 + echo " "; + } + $_parent = $context['_parent']; + unset($context['_seq'], $context['_iterated'], $context['_key'], $context['langCode'], $context['_parent'], $context['loop']); + $context = array_intersect_key($context, $_parent) + $_parent; + // line 239 + echo "
                                                                  + "; + } + // line 241 + echo " "; + } + // line 242 + echo "
                                                                  + + + "; + } + // line 246 + echo "
                                                                  + "; + // line 247 + if ((($context["mode"] ?? null) == "new")) { + // line 248 + echo "

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

                                                                  + "; + } elseif (( // line 249 +($context["mode"] ?? null) == "edit")) { + // line 250 + echo "

                                                                  + "; + // line 251 + echo twig_escape_filter($this->env, $this->getAttribute(($context["context"] ?? null), "menu", array()), "html", null, true); + echo " +

                                                                  + "; + } else { + // line 254 + echo "

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

                                                                  + "; + } + } + + // line 258 + public function block_content($context, array $blocks = array()) + { + // line 259 + echo "
                                                                  + "; + // line 260 + if ((($context["mode"] ?? null) == "new")) { + // line 261 + echo " "; + $this->loadTemplate("partials/blueprints-new.html.twig", "pages.html.twig", 261)->display(array_merge($context, array("blueprints" => $this->getAttribute(($context["admin"] ?? null), "blueprints", array(0 => "pages/page"), "method"), "data" => ($context["context"] ?? null)))); + // line 262 + echo " "; + } elseif ((($context["mode"] ?? null) == "edit")) { + // line 263 + echo "
                                                                  +
                                                                  + + "; + // line 266 + if (($this->getAttribute(($context["admin"] ?? null), "multilang", array()) && ($context["page_lang"] ?? null))) { + // line 267 + echo "
                                                                  + + "; + // line 275 + if ((($context["exists"] ?? null) && (twig_length_filter($this->env, $this->getAttribute(($context["context"] ?? null), "translatedLanguages", array())) > 1))) { + // line 276 + echo " +
                                                                    + "; + // line 280 + $context['_parent'] = $context; + $context['_seq'] = twig_ensure_traversable($this->getAttribute(($context["context"] ?? null), "translatedLanguages", array())); + foreach ($context['_seq'] as $context["language"] => $context["route"]) { + // line 281 + echo " "; + if (($context["language"] != ($context["page_lang"] ?? null))) { + // line 282 + echo "
                                                                  • + "; + } + // line 284 + echo " "; + } + $_parent = $context['_parent']; + unset($context['_seq'], $context['_iterated'], $context['language'], $context['route'], $context['_parent'], $context['loop']); + $context = array_intersect_key($context, $_parent) + $_parent; + // line 285 + echo "
                                                                  + "; + } + // line 287 + echo "
                                                                  + "; + } + // line 289 + echo " + "; + // line 290 + if ($this->getAttribute($this->getAttribute(($context["context"] ?? null), "blueprints", array()), "fields", array())) { + // line 291 + echo " "; + $context["normalText"] = $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.NORMAL"); + // line 292 + echo " "; + $context["expertText"] = $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.EXPERT"); + // line 293 + echo " "; + $context["maxLen"] = max(array(0 => twig_length_filter($this->env, ($context["normalText"] ?? null)), 1 => twig_length_filter($this->env, ($context["expertText"] ?? null)))); + // line 294 + echo " "; + $context["normalText"] = $this->getAttribute($this, "spanToggle", array(0 => ($context["normalText"] ?? null), 1 => ($context["maxLen"] ?? null)), "method"); + // line 295 + echo " "; + $context["expertText"] = $this->getAttribute($this, "spanToggle", array(0 => ($context["expertText"] ?? null), 1 => ($context["maxLen"] ?? null)), "method"); + // line 296 + echo "
                                                                  +
                                                                  + env, ($context["base_url"] ?? null), "html", null, true); + echo "/pages/"; + echo twig_escape_filter($this->env, twig_trim_filter($this->getAttribute(($context["admin"] ?? null), "route", array()), "/"), "html", null, true); + echo "/mode"; + echo twig_escape_filter($this->env, $this->getAttribute($this->getAttribute(($context["config"] ?? null), "system", array()), "param_sep", array()), "html", null, true); + echo "normal\" id=\"normal\" name=\"mode-switch\" class=\"highlight\" "; + if (($this->getAttribute($this->getAttribute(($context["admin"] ?? null), "session", array()), "expert", array()) == "0")) { + echo " checked=\"checked\""; + } + echo "> + + env, ($context["base_url"] ?? null), "html", null, true); + echo "/pages/"; + echo twig_escape_filter($this->env, twig_trim_filter($this->getAttribute(($context["admin"] ?? null), "route", array()), "/"), "html", null, true); + echo "/mode"; + echo twig_escape_filter($this->env, $this->getAttribute($this->getAttribute(($context["config"] ?? null), "system", array()), "param_sep", array()), "html", null, true); + echo "expert\" id=\"expert\" name=\"mode-switch\" class=\"highlight\" "; + if (($this->getAttribute($this->getAttribute(($context["admin"] ?? null), "session", array()), "expert", array()) == "1")) { + echo " checked=\"checked\""; + } + echo "> + + +
                                                                  +
                                                                  + "; + } + // line 306 + echo " +
                                                                  + + "; + // line 309 + if (($this->getAttribute($this->getAttribute(($context["context"] ?? null), "blueprints", array()), "fields", array()) && ($this->getAttribute($this->getAttribute(($context["admin"] ?? null), "session", array()), "expert", array()) == "0"))) { + // line 310 + echo " "; + $this->loadTemplate("partials/blueprints.html.twig", "pages.html.twig", 310)->display(array_merge($context, array("blueprints" => $this->getAttribute(($context["context"] ?? null), "blueprints", array()), "data" => ($context["context"] ?? null)))); + // line 311 + echo " "; + } else { + // line 312 + echo " "; + $this->loadTemplate("partials/blueprints-raw.html.twig", "pages.html.twig", 312)->display(array_merge($context, array("blueprints" => $this->getAttribute(($context["admin"] ?? null), "blueprints", array(0 => (("admin/pages/" . ($context["modular"] ?? null)) . "raw")), "method"), "data" => ($context["context"] ?? null)))); + // line 313 + echo " "; + } + // line 314 + echo "
                                                                  + "; + } else { + // line 316 + echo "
                                                                  +
                                                                  + env, twig_jsonencode_filter(array(0 => array("id" => "mode", "name" => $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.PAGE_MODES")), 1 => array("id" => "type", "name" => $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.PAGE_TYPES")), 2 => array("id" => "access", "name" => $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.ACCESS_LEVELS")))), "html_attr"); + echo "\" data-filter-types=\""; + echo twig_escape_filter($this->env, twig_jsonencode_filter(twig_array_merge($this->getAttribute(($context["admin"] ?? null), "types", array()), $this->getAttribute(($context["admin"] ?? null), "modularTypes", array()))), "html_attr"); + echo "\" data-filter-access-levels=\""; + echo twig_escape_filter($this->env, twig_jsonencode_filter($this->getAttribute(($context["admin"] ?? null), "accessLevels", array())), "html_attr"); + echo "\" placeholder=\""; + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.ADD_FILTERS"), "html", null, true); + echo "\" class=\"page-filter\" name=\"page-filter\" /> +
                                                                  +
                                                                  + env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.SEARCH_PAGES"), "html", null, true); + echo "\" name=\"page-search\" /> +
                                                                  +
                                                                  + "; + // line 324 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.EXPAND_ALL"), "html", null, true); + echo " + "; + // line 325 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.COLLAPSE_ALL"), "html", null, true); + echo " +
                                                                  +
                                                                  +
                                                                  +
                                                                    + "; + // line 330 + echo $this->getAttribute($this, "loop", array(0 => ($context["pages"] ?? null), 1 => 0, 2 => $context), "method"); + echo " +
                                                                  + "; + // line 332 + $this->loadTemplate("partials/page-legend.html.twig", "pages.html.twig", 332)->display($context); + // line 333 + echo "
                                                                  + "; + } + // line 335 + echo "
                                                                  + + "; + // line 337 + if (($context["context"] ?? null)) { + // line 338 + echo " "; + $context["obj_data"] = $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->cloneFunc(($context["context"] ?? null)); + // line 339 + echo " + "; + // line 340 + if ((($context["mode"] ?? null) == "edit")) { + // line 341 + echo " "; + $this->getAttribute(($context["obj_data"] ?? null), "folder", array(0 => ""), "method"); + // line 342 + echo " "; + } + // line 343 + echo " "; + } + // line 344 + echo " + "; + // line 345 + if (((($context["mode"] ?? null) == "list") || (($context["mode"] ?? null) == "edit"))) { + // line 346 + echo "
                                                                  + "; + // line 347 + $this->loadTemplate("partials/blueprints-new.html.twig", "pages.html.twig", 347)->display(array_merge($context, array("blueprints" => $this->getAttribute(($context["admin"] ?? null), "blueprints", array(0 => "admin/pages/new"), "method"), "data" => ($context["obj_data"] ?? null), "form_id" => "new-page"))); + // line 348 + echo "
                                                                  + +
                                                                  + "; + // line 351 + $this->loadTemplate("partials/blueprints-new-folder.html.twig", "pages.html.twig", 351)->display(array_merge($context, array("blueprints" => $this->getAttribute(($context["admin"] ?? null), "blueprints", array(0 => "admin/pages/new_folder"), "method"), "data" => ($context["obj_data"] ?? null), "form_id" => "new-folder"))); + // line 352 + echo "
                                                                  + +
                                                                  + "; + // line 355 + $this->loadTemplate("partials/blueprints-new.html.twig", "pages.html.twig", 355)->display(array_merge($context, array("blueprints" => $this->getAttribute(($context["admin"] ?? null), "blueprints", array(0 => "admin/pages/modular_new"), "method"), "data" => ($context["obj_data"] ?? null), "form_id" => "new-modular"))); + // line 356 + echo "
                                                                  + + "; + // line 358 + $context['_parent'] = $context; + $context['_seq'] = twig_ensure_traversable($this->getAttribute($this->getAttribute($this->getAttribute(($context["config"] ?? null), "plugins", array()), "admin", array()), "add_modals", array())); + $context['loop'] = array( + 'parent' => $context['_parent'], + 'index0' => 0, + 'index' => 1, + 'first' => true, + ); + if (is_array($context['_seq']) || (is_object($context['_seq']) && $context['_seq'] instanceof Countable)) { + $length = count($context['_seq']); + $context['loop']['revindex0'] = $length - 1; + $context['loop']['revindex'] = $length; + $context['loop']['length'] = $length; + $context['loop']['last'] = 1 === $length; + } + foreach ($context['_seq'] as $context["key"] => $context["add_modal"]) { + // line 359 + echo "
                                                                  env, $this->env->getExtension('Grav\Common\Twig\TwigExtension')->definedDefaultFilter($this->getAttribute($context["add_modal"], "modal_classes", array()), ""), "html", null, true); + echo "\" data-remodal-id=\"modal-add_modal-"; + echo twig_escape_filter($this->env, $context["key"], "html", null, true); + echo "\" data-remodal-options=\"hashTracking: false\"> + "; + // line 360 + $this->loadTemplate($this->env->getExtension('Grav\Common\Twig\TwigExtension')->definedDefaultFilter($this->getAttribute($context["add_modal"], "template", array()), "partials/blueprints-new.html.twig"), "pages.html.twig", 360)->display(array_merge($context, twig_array_merge(array("blueprints" => $this->getAttribute(($context["admin"] ?? null), "blueprints", array(0 => $this->getAttribute($context["add_modal"], "blueprint", array())), "method"), "data" => ($context["context"] ?? null), "form_id" => "add-modal"), $this->env->getExtension('Grav\Common\Twig\TwigExtension')->definedDefaultFilter($this->getAttribute($context["add_modal"], "with", array()), array())))); + // line 361 + echo "
                                                                  + "; + ++$context['loop']['index0']; + ++$context['loop']['index']; + $context['loop']['first'] = false; + if (isset($context['loop']['length'])) { + --$context['loop']['revindex0']; + --$context['loop']['revindex']; + $context['loop']['last'] = 0 === $context['loop']['revindex0']; + } + } + $_parent = $context['_parent']; + unset($context['_seq'], $context['_iterated'], $context['key'], $context['add_modal'], $context['_parent'], $context['loop']); + $context = array_intersect_key($context, $_parent) + $_parent; + // line 363 + echo " "; + } + // line 364 + echo " + + "; + // line 366 + if ((($context["mode"] ?? null) == "edit")) { + // line 367 + echo "
                                                                  + + "; + // line 369 + $this->loadTemplate("partials/page-move.html.twig", "pages.html.twig", 369)->display(array_merge($context, array("blueprints" => $this->getAttribute(($context["admin"] ?? null), "blueprints", array(0 => "admin/pages/move"), "method"), "data" => ($context["context"] ?? null)))); + // line 370 + echo "
                                                                  +
                                                                  + "; + // line 372 + try { + $this->loadTemplate(array(0 => "partials/page-revisions.html.twig", 1 => "empty.html.twig"), "pages.html.twig", 372)->display(array_merge($context, array("data" => ($context["context"] ?? null)))); + } catch (Twig_Error_Loader $e) { + // ignore missing template + } + + // line 373 + echo "
                                                                  + "; + } + // line 375 + echo " + "; + // line 376 + $this->loadTemplate("partials/modal-changes-detected.html.twig", "pages.html.twig", 376)->display($context); + // line 377 + echo " +
                                                                  +
                                                                  +

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

                                                                  +

                                                                  + "; + // line 382 + if (($context["context"] ?? null)) { + // line 383 + echo " "; + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.PAGE"), "html", null, true); + echo ": "; + echo twig_escape_filter($this->env, $this->getAttribute(($context["context"] ?? null), "title", array()), "html", null, true); + echo " + "; + } + // line 385 + echo "

                                                                  +

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

                                                                  +
                                                                  +
                                                                  + + "; + // line 392 + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.CONTINUE"), "html", null, true); + echo " +
                                                                  +
                                                                  +
                                                                  + + "; + // line 397 + try { + $this->loadTemplate("partials/admin-pro-pages-addons.html.twig", "pages.html.twig", 397)->display($context); + } catch (Twig_Error_Loader $e) { + // ignore missing template + } + + // line 398 + echo " +"; + } + + // line 401 + public function block_bottom($context, array $blocks = array()) + { + // line 402 + echo " +"; + } + + // line 3 + public function getspanToggle($__input__ = null, $__length__ = null, ...$__varargs__) + { + $context = $this->env->mergeGlobals(array( + "input" => $__input__, + "length" => $__length__, + "varargs" => $__varargs__, + )); + + $blocks = array(); + + ob_start(); + try { + // line 4 + echo " "; + echo (($this->env->getExtension('Grav\Common\Twig\TwigExtension')->repeatFunc("  ", ((($context["length"] ?? null) - twig_length_filter($this->env, ($context["input"] ?? null))) / 2)) . ($context["input"] ?? null)) . $this->env->getExtension('Grav\Common\Twig\TwigExtension')->repeatFunc("  ", ((($context["length"] ?? null) - twig_length_filter($this->env, ($context["input"] ?? null))) / 2))); + echo " +"; + } catch (Exception $e) { + ob_end_clean(); + + throw $e; + } catch (Throwable $e) { + ob_end_clean(); + + throw $e; + } + + return ('' === $tmp = ob_get_clean()) ? '' : new Twig_Markup($tmp, $this->env->getCharset()); + } + + // line 48 + public function getloop($__page__ = null, $__depth__ = null, $__twig_vars__ = null, ...$__varargs__) + { + $context = $this->env->mergeGlobals(array( + "page" => $__page__, + "depth" => $__depth__, + "twig_vars" => $__twig_vars__, + "varargs" => $__varargs__, + )); + + $blocks = array(); + + ob_start(); + try { + // line 49 + echo " "; + $context["separator"] = $this->getAttribute($this->getAttribute($this->getAttribute(($context["twig_vars"] ?? null), "config", array(), "array"), "system", array()), "param_sep", array()); + // line 50 + echo " "; + $context["display_field"] = $this->getAttribute($this->getAttribute($this->getAttribute($this->getAttribute(($context["twig_vars"] ?? null), "config", array(), "array"), "plugins", array()), "admin", array()), "pages_list_display_field", array()); + // line 51 + echo " "; + $context["base_url"] = $this->getAttribute(($context["twig_vars"] ?? null), "base_url_relative", array(), "array"); + // line 52 + echo " "; + $context["base_url_simple"] = $this->getAttribute(($context["twig_vars"] ?? null), "base_url_simple", array(), "array"); + // line 53 + echo " "; + $context["admin_route"] = $this->getAttribute(($context["twig_vars"] ?? null), "admin_route", array(), "array"); + // line 54 + echo " "; + $context["admin_lang"] = $this->getAttribute(($context["twig_vars"] ?? null), "admin_lang", array(), "array"); + // line 55 + echo " "; + $context["warn"] = $this->getAttribute(($context["twig_vars"] ?? null), "warn", array(), "array"); + // line 56 + echo " "; + $context["uri"] = $this->getAttribute(($context["twig_vars"] ?? null), "uri", array(), "array"); + // line 57 + echo " + "; + // line 58 + if ((($this->getAttribute($this->getAttribute($this->getAttribute(($context["page"] ?? null), "header", array()), "admin", array()), "children_display_order", array()) == "collection") && $this->getAttribute($this->getAttribute($this->getAttribute($this->getAttribute(($context["page"] ?? null), "header", array()), "content", array()), "order", array()), "by", array()))) { + // line 59 + echo " "; + if ($this->getAttribute($this->getAttribute($this->getAttribute($this->getAttribute(($context["page"] ?? null), "header", array()), "content", array()), "order", array()), "custom", array())) { + // line 60 + echo " "; + $context["pcol"] = $this->getAttribute($this->getAttribute(($context["page"] ?? null), "children", array(), "method"), "order", array(0 => $this->getAttribute($this->getAttribute($this->getAttribute($this->getAttribute(($context["page"] ?? null), "header", array()), "content", array()), "order", array()), "by", array()), 1 => (($this->getAttribute($this->getAttribute($this->getAttribute($this->getAttribute(($context["page"] ?? null), "header", array(), "any", false, true), "content", array(), "any", false, true), "order", array(), "any", false, true), "dir", array(), "any", true, true)) ? (_twig_default_filter($this->getAttribute($this->getAttribute($this->getAttribute($this->getAttribute(($context["page"] ?? null), "header", array(), "any", false, true), "content", array(), "any", false, true), "order", array(), "any", false, true), "dir", array()), "asc")) : ("asc")), 2 => $this->getAttribute($this->getAttribute($this->getAttribute($this->getAttribute(($context["page"] ?? null), "header", array()), "content", array()), "order", array()), "custom", array())), "method"); + // line 61 + echo " "; + } else { + // line 62 + echo " "; + $context["pcol"] = $this->getAttribute($this->getAttribute(($context["page"] ?? null), "children", array(), "method"), "order", array(0 => $this->getAttribute($this->getAttribute($this->getAttribute($this->getAttribute(($context["page"] ?? null), "header", array()), "content", array()), "order", array()), "by", array()), 1 => (($this->getAttribute($this->getAttribute($this->getAttribute($this->getAttribute(($context["page"] ?? null), "header", array(), "any", false, true), "content", array(), "any", false, true), "order", array(), "any", false, true), "dir", array(), "any", true, true)) ? (_twig_default_filter($this->getAttribute($this->getAttribute($this->getAttribute($this->getAttribute(($context["page"] ?? null), "header", array(), "any", false, true), "content", array(), "any", false, true), "order", array(), "any", false, true), "dir", array()), "asc")) : ("asc"))), "method"); + // line 63 + echo " "; + } + // line 64 + echo " "; + } else { + // line 65 + echo " "; + $context["pcol"] = $this->getAttribute(($context["page"] ?? null), "children", array(), "method"); + // line 66 + echo " "; + } + // line 67 + echo " + "; + // line 68 + $context['_parent'] = $context; + $context['_seq'] = twig_ensure_traversable(($context["pcol"] ?? null)); + foreach ($context['_seq'] as $context["_key"] => $context["p"]) { + // line 69 + echo " "; + $context["description"] = (((((( !$this->getAttribute($context["p"], "page", array())) ? (($this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.FOLDER") . " • ")) : (($this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.PAGE") . " • "))) . (($this->getAttribute( // line 70 +$context["p"], "modular", array())) ? (($this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.MODULAR") . " • ")) : (""))) . (($this->getAttribute( // line 71 +$context["p"], "routable", array())) ? (($this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.ROUTABLE") . " • ")) : (($this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.NON_ROUTABLE") . " • ")))) . (($this->getAttribute( // line 72 +$context["p"], "visible", array())) ? (($this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.VISIBLE") . " • ")) : (($this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.NON_VISIBLE") . " • ")))) . (($this->getAttribute( // line 73 +$context["p"], "published", array())) ? (($this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.PUBLISHED") . " • ")) : (($this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.NON_PUBLISHED") . " • ")))); + // line 74 + echo " "; + // line 75 + echo " "; + // line 76 + echo " "; + // line 77 + echo " "; + // line 78 + echo " "; + // line 79 + echo " "; + // line 80 + echo " + "; + // line 81 + $context["page_url"] = $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->getPageUrl($context, $context["p"]); + // line 82 + echo " +
                                                                • env, $this->getAttribute($context["p"], "route", array()), "html", null, true); + echo "\"> +
                                                                  + getAttribute($this->getAttribute($context["p"], "children", array(0 => 0), "method"), "count", array()) > 0)) ? ("data-toggle=\"children\"") : ("")); + echo "> + getAttribute($this->getAttribute($context["p"], "children", array(0 => 0), "method"), "count", array()) > 0)) ? ("children-closed") : ("")); + echo " "; + echo (($this->getAttribute($context["p"], "modular", array())) ? ("modular") : ((( !$this->getAttribute($context["p"], "routable", array())) ? ("not-routable") : ((( !$this->getAttribute($context["p"], "visible", array())) ? ("not-visible") : ((( !$this->getAttribute($context["p"], "page", array())) ? ("folder") : ("")))))))); + echo "\"> + +
                                                                  +
                                                                  + + "; + // line 91 + $context["page_label"] = $this->env->getExtension('Grav\Common\Twig\TwigExtension')->definedDefaultFilter($this->env->getExtension('Grav\Common\Twig\TwigExtension')->definedDefaultFilter($this->getAttribute($this->getAttribute($context["p"], "header", array()), ($context["display_field"] ?? null)), $this->getAttribute($context["p"], ($context["display_field"] ?? null))), $this->getAttribute($context["p"], "title", array())); + // line 92 + echo " env, ($context["page_url"] ?? null), "html", null, true); + echo "\" class=\"page-edit\">"; + echo twig_escape_filter($this->env, ($context["page_label"] ?? null)); + echo " + + "; + // line 94 + if ($this->getAttribute($context["p"], "language", array())) { + // line 95 + echo " getAttribute($context["p"], "language", array()) == ($context["admin_lang"] ?? null))) { + echo "info"; + } + echo "\">"; + echo twig_escape_filter($this->env, $this->getAttribute($context["p"], "language", array()), "html", null, true); + echo " + "; + } + // line 97 + echo " "; + if ($this->getAttribute($context["p"], "home", array())) { + // line 98 + echo " + "; + } + // line 100 + echo "
                                                                  +

                                                                  "; + // line 101 + echo twig_escape_filter($this->env, (($this->getAttribute($this->getAttribute($this->getAttribute($context["p"], "header", array()), "routes", array()), "default", array())) ? ($this->getAttribute($this->getAttribute($this->getAttribute($context["p"], "header", array()), "routes", array()), "default", array())) : ($this->getAttribute($context["p"], "route", array()))), "html", null, true); + echo " "; + echo twig_escape_filter($this->env, $this->getAttribute($context["p"], "template", array(), "method"), "html", null, true); + echo "

                                                                  +
                                                                  + + "; + // line 104 + if (($context["warn"] ?? null)) { + // line 105 + echo " env, $this->getAttribute(($context["uri"] ?? null), "addNonce", array(0 => (((($context["page_url"] ?? null) . "/task") . ($context["separator"] ?? null)) . "delete"), 1 => "admin-form", 2 => "admin-nonce"), "method"), "html", null, true); + echo "\" class=\"page-delete\" > + "; + } else { + // line 107 + echo " env, $this->getAttribute(($context["uri"] ?? null), "addNonce", array(0 => (((($context["page_url"] ?? null) . "/task") . ($context["separator"] ?? null)) . "delete"), 1 => "admin-form", 2 => "admin-nonce"), "method"), "html", null, true); + echo "\" class=\"page-delete\" > + "; + } + // line 109 + echo " +
                                                                  + "; + // line 111 + if (($this->getAttribute($this->getAttribute($context["p"], "children", array(), "method"), "count", array()) > 0)) { + // line 112 + echo "
                                                                    env, (($context["depth"] ?? null) + 1), "html", null, true); + echo "\" style=\"display:none;\"> + "; + // line 113 + echo $this->getAttribute($this, "loop", array(0 => $context["p"], 1 => (($context["depth"] ?? null) + 1), 2 => ($context["twig_vars"] ?? null)), "method"); + echo " +
                                                                  + "; + } + // line 116 + 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 Twig_Markup($tmp, $this->env->getCharset()); + } + + public function getTemplateName() + { + return "pages.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 1116 => 116, 1110 => 113, 1105 => 112, 1103 => 111, 1099 => 109, 1093 => 107, 1087 => 105, 1085 => 104, 1077 => 101, 1074 => 100, 1070 => 98, 1067 => 97, 1057 => 95, 1055 => 94, 1047 => 92, 1045 => 91, 1041 => 90, 1032 => 86, 1028 => 85, 1023 => 83, 1020 => 82, 1018 => 81, 1015 => 80, 1013 => 79, 1011 => 78, 1009 => 77, 1007 => 76, 1005 => 75, 1003 => 74, 1001 => 73, 1000 => 72, 999 => 71, 998 => 70, 996 => 69, 992 => 68, 989 => 67, 986 => 66, 983 => 65, 980 => 64, 977 => 63, 974 => 62, 971 => 61, 968 => 60, 965 => 59, 963 => 58, 960 => 57, 957 => 56, 954 => 55, 951 => 54, 948 => 53, 945 => 52, 942 => 51, 939 => 50, 936 => 49, 922 => 48, 904 => 4, 891 => 3, 884 => 402, 881 => 401, 876 => 398, 869 => 397, 861 => 392, 857 => 391, 850 => 387, 846 => 385, 838 => 383, 836 => 382, 831 => 380, 826 => 377, 824 => 376, 821 => 375, 817 => 373, 810 => 372, 806 => 370, 804 => 369, 800 => 367, 798 => 366, 794 => 364, 791 => 363, 776 => 361, 774 => 360, 767 => 359, 750 => 358, 746 => 356, 744 => 355, 739 => 352, 737 => 351, 732 => 348, 730 => 347, 727 => 346, 725 => 345, 722 => 344, 719 => 343, 716 => 342, 713 => 341, 711 => 340, 708 => 339, 705 => 338, 703 => 337, 699 => 335, 695 => 333, 693 => 332, 688 => 330, 680 => 325, 676 => 324, 670 => 321, 658 => 318, 654 => 316, 650 => 314, 647 => 313, 644 => 312, 641 => 311, 638 => 310, 636 => 309, 631 => 306, 623 => 301, 611 => 300, 607 => 299, 595 => 298, 591 => 296, 588 => 295, 585 => 294, 582 => 293, 579 => 292, 576 => 291, 574 => 290, 571 => 289, 567 => 287, 563 => 285, 557 => 284, 547 => 282, 544 => 281, 540 => 280, 534 => 276, 532 => 275, 529 => 274, 523 => 272, 517 => 270, 515 => 269, 511 => 267, 509 => 266, 504 => 263, 501 => 262, 498 => 261, 496 => 260, 493 => 259, 490 => 258, 482 => 254, 476 => 251, 473 => 250, 471 => 249, 466 => 248, 464 => 247, 461 => 246, 455 => 242, 452 => 241, 448 => 239, 442 => 238, 432 => 236, 429 => 235, 426 => 234, 422 => 233, 416 => 229, 413 => 228, 411 => 227, 407 => 226, 403 => 224, 400 => 223, 394 => 221, 386 => 219, 383 => 218, 377 => 216, 375 => 215, 371 => 214, 365 => 213, 360 => 210, 354 => 208, 352 => 207, 348 => 206, 344 => 205, 335 => 199, 331 => 197, 329 => 196, 326 => 195, 318 => 193, 315 => 192, 312 => 191, 310 => 190, 307 => 189, 299 => 187, 296 => 186, 293 => 185, 291 => 184, 288 => 183, 286 => 182, 279 => 180, 274 => 178, 271 => 177, 269 => 176, 266 => 175, 262 => 173, 258 => 171, 252 => 170, 244 => 168, 241 => 167, 238 => 166, 234 => 165, 228 => 161, 226 => 160, 220 => 158, 218 => 157, 213 => 154, 211 => 153, 206 => 150, 200 => 149, 188 => 147, 185 => 146, 180 => 145, 174 => 143, 172 => 142, 168 => 141, 164 => 140, 155 => 134, 150 => 131, 144 => 130, 132 => 128, 129 => 127, 125 => 126, 117 => 124, 115 => 123, 112 => 122, 109 => 121, 102 => 41, 99 => 40, 92 => 37, 89 => 36, 86 => 35, 83 => 34, 80 => 33, 76 => 1, 74 => 46, 72 => 45, 70 => 44, 68 => 31, 66 => 30, 64 => 29, 62 => 28, 60 => 27, 57 => 24, 55 => 23, 51 => 20, 48 => 18, 46 => 17, 44 => 16, 42 => 15, 40 => 14, 38 => 13, 36 => 12, 34 => 11, 31 => 8, 29 => 7, 11 => 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 Twig_Source("{% extends 'partials/base.html.twig' %} + +{% macro spanToggle(input, length) %} + {{ (repeat('  ', (length - input|length) / 2) ~ input ~ repeat('  ', (length - input|length) / 2))|raw }} +{% endmacro %} + +{% if admin.route %} + {% set context = admin.page(true) %} +{% endif %} + +{% if uri.param('new') %} + {% set mode = 'new' %} +{% elseif context %} + {% set mode = 'edit' %} + {% if context.exists %} + {% set page_url = base_url ~ '/pages' ~ (context.header.routes.default ?: context.rawRoute) %} + {% set exists = true %} + {% set title = (context.exists ? \"PLUGIN_ADMIN.EDIT\"|tu : \"PLUGIN_ADMIN.CREATE\"|tu ) ~ \" \" ~ (context.header.title ?: context.title) %} + {% else %} + {% set title = \"PLUGIN_ADMIN.ADD_PAGE\"|tu %} + {% endif %} +{% else %} + {% set mode = 'list' %} + {% set title = \"PLUGIN_ADMIN.PAGES\"|tu %} +{% endif %} + +{% set modular = context.modular ? 'modular_' : '' %} +{% set warn = config.plugins.admin.warnings.delete_page %} +{% set admin_lang = admin.session.admin_lang ?: 'en' %} +{% set page_lang = context.language %} +{% set type = 'page' %} + +{% block stylesheets %} + {% if mode == 'edit' %} + {% do assets.addCss(theme_url~'/css/codemirror/codemirror.css') %} + {% endif %} + {{ parent() }} +{% endblock %} + +{% block javascripts %} + {{ parent() }} +{% endblock %} + +{% set preview_html = (base_url_relative_frontend|rtrim('/') ~ (context.home ? '' : context.route)) ?: '/' %} +{% set preview_target = config.plugins.admin.frontend_pages_target %} +{% set preview_link = context.routable ? ' ' : '' %} + +{% macro loop(page, depth, twig_vars) %} + {% set separator = twig_vars['config'].system.param_sep %} + {% set display_field = twig_vars['config'].plugins.admin.pages_list_display_field %} + {% set base_url = twig_vars['base_url_relative'] %} + {% set base_url_simple = twig_vars['base_url_simple'] %} + {% set admin_route = twig_vars['admin_route'] %} + {% set admin_lang = twig_vars['admin_lang'] %} + {% set warn = twig_vars['warn'] %} + {% set uri = twig_vars['uri'] %} + + {% if page.header.admin.children_display_order == 'collection' and page.header.content.order.by %} + {% if page.header.content.order.custom %} + {% set pcol = page.children().order(page.header.content.order.by, page.header.content.order.dir|default('asc'), page.header.content.order.custom) %} + {% else %} + {% set pcol = page.children().order(page.header.content.order.by, page.header.content.order.dir|default('asc')) %} + {% endif %} + {% else %} + {% set pcol = page.children() %} + {% endif %} + + {% for p in pcol %} + {% set description = (not p.page ? \"PLUGIN_ADMIN.FOLDER\"|tu ~ ' • ' : \"PLUGIN_ADMIN.PAGE\"|tu ~ ' • ') ~ + (p.modular ? \"PLUGIN_ADMIN.MODULAR\"|tu ~ ' • ' : '') ~ + (p.routable ? \"PLUGIN_ADMIN.ROUTABLE\"|tu ~ ' • ' : \"PLUGIN_ADMIN.NON_ROUTABLE\"|tu ~ ' • ') ~ + (p.visible ? \"PLUGIN_ADMIN.VISIBLE\"|tu ~ ' • ' : \"PLUGIN_ADMIN.NON_VISIBLE\"|tu ~ ' • ') ~ + (p.published ? \"PLUGIN_ADMIN.PUBLISHED\"|tu ~ ' • ' : \"PLUGIN_ADMIN.NON_PUBLISHED\"|tu ~ ' • ') %} + {#{% set page_route = p.rawRoute|trim('/') %}#} + {#{% if p.language and p.language != admin_lang %}#} + {#{% set page_url = base_url_simple ~ '/' ~ p.language ~ '/' ~ admin_route ~ '/pages/' ~ page_route %}#} + {#{% else %}#} + {#{% set page_url = base_url ~ '/pages/' ~ page_route %}#} + {#{% endif %}#} + + {% set page_url = getPageUrl(p) %} + +
                                                                • +
                                                                  + 0 ? 'data-toggle=\"children\"' : ''}}> + 0 ? 'children-closed' : ''}} {{ p.modular ? 'modular' : (not p.routable ? 'not-routable' : (not p.visible ? 'not-visible' : (not p.page ? 'folder' : ''))) }}\"> + +
                                                                  +
                                                                  + + {% set page_label = attribute(p.header, display_field)|defined(attribute(p, display_field))|defined(p.title) %} + {{ page_label|e }} + + {% if p.language %} + {{p.language}} + {% endif %} + {% if p.home %} + + {% endif %} +
                                                                  +

                                                                  {{ p.header.routes.default ?: p.route }} {{ p.template() }}

                                                                  +
                                                                  + + {% if warn %} + + {% else %} + + {% endif %} + +
                                                                  + {% if p.children().count > 0 %} +
                                                                    + {{ _self.loop(p, depth + 1, twig_vars) }} +
                                                                  + {% endif %} +
                                                                • + {% endfor %} +{% endmacro %} + + +{% block titlebar %} +
                                                                  + {% if mode == 'list' %} + {{ \"PLUGIN_ADMIN.BACK\"|tu }} + + {% for key, add_modal in config.plugins.admin.add_modals %} + {% if add_modal.show_in|defined('bar') == 'bar' %} + {{ add_modal.label }} + {% endif %} + {% endfor %} + +
                                                                  + + + +
                                                                  + + {% if admin.multilang %} +
                                                                  + + {% if admin.languages_enabled|length > 1 %} + +
                                                                    + {% for langCode in admin.languages_enabled %} + {% set langName = admin.siteLanguages[langCode] %} + {% if langCode != admin_lang %} +
                                                                  • {{ langName[:1]|upper ~ langName[1:] }}
                                                                  • + {% endif %} + {% endfor %} +
                                                                  + {% endif %} +
                                                                  + {% endif %} + + {% elseif mode == 'edit' %} + + {{ preview_link|raw }} + + + + {% set siblings = context.parent().children() %} + + {% if not siblings.isFirst(context.path) %} + {% set sib = siblings.nextSibling(context.path) %} + {% set sib_url = base_url ~ '/pages' ~ (sib.header.routes.default ?: sib.rawRoute) %} + + {% endif %} + + {% if not siblings.isLast(context.path) %} + {% set sib = siblings.prevSibling(context.path) %} + {% set sib_url = base_url ~ '/pages' ~ (sib.header.routes.default ?: sib.rawRoute) %} + + {% endif %} + + {% if exists %} +
                                                                  + + + +
                                                                  + + {{ \"PLUGIN_ADMIN.COPY\"|tu }} + {{ \"PLUGIN_ADMIN.MOVE\"|tu }} + {% if config.plugins['admin-pro'].enabled %} + {{ \"PLUGIN_ADMIN_PRO.REVISIONS\"|tu }} + {% endif %} + {% if warn %} + {{ \"PLUGIN_ADMIN.DELETE\"|tu }} + {% else %} + + {% endif %} + {% endif %} + +
                                                                  + + {% if exists and admin.multilang %} + {% if context.untranslatedLanguages %} + +
                                                                    + {% for langCode in context.untranslatedLanguages %} + {% set langName = admin.siteLanguages[langCode] %} + {% if langCode != page_lang %} +
                                                                  • + {% endif %} + {% endfor %} +
                                                                  + {% endif %} + {% endif %} +
                                                                  + + + {% endif %} +
                                                                  + {% if mode == 'new' %} +

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

                                                                  + {% elseif mode == 'edit' %} +

                                                                  + {{ context.menu }} +

                                                                  + {% else %} +

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

                                                                  + {% endif %} +{% endblock %} + +{% block content %} +
                                                                  + {% if mode == 'new' %} + {% include 'partials/blueprints-new.html.twig' with { blueprints: admin.blueprints('pages/page'), data: context } %} + {% elseif mode == 'edit' %} +
                                                                  +
                                                                  + + {% if admin.multilang and page_lang %} +
                                                                  + + {% if exists and context.translatedLanguages|length > 1 %} + +
                                                                    + {% for language, route in context.translatedLanguages %} + {% if language != page_lang %} +
                                                                  • + {% endif %} + {% endfor %} +
                                                                  + {% endif %} +
                                                                  + {% endif %} + + {% if context.blueprints.fields %} + {% set normalText = \"PLUGIN_ADMIN.NORMAL\"|tu %} + {% set expertText = \"PLUGIN_ADMIN.EXPERT\"|tu %} + {% set maxLen = max([normalText|length, expertText|length]) %} + {% set normalText = _self.spanToggle(normalText, maxLen) %} + {% set expertText = _self.spanToggle(expertText, maxLen) %} +
                                                                  +
                                                                  + + + + + +
                                                                  +
                                                                  + {% endif %} + +
                                                                  + + {% if context.blueprints.fields and admin.session.expert == '0' %} + {% include 'partials/blueprints.html.twig' with { blueprints: context.blueprints, data: context } %} + {% else %} + {% include 'partials/blueprints-raw.html.twig' with { blueprints: admin.blueprints('admin/pages/'~modular~'raw'), data: context } %} + {% endif %} +
                                                                  + {% else %} +
                                                                  +
                                                                  + +
                                                                  +
                                                                  + +
                                                                  +
                                                                  + {{ \"PLUGIN_ADMIN.EXPAND_ALL\"|tu }} + {{ \"PLUGIN_ADMIN.COLLAPSE_ALL\"|tu }} +
                                                                  +
                                                                  +
                                                                  +
                                                                    + {{ _self.loop(pages, 0, _context) }} +
                                                                  + {% include 'partials/page-legend.html.twig' %} +
                                                                  + {% endif %} +
                                                                  + + {% if context %} + {% set obj_data = clone(context) %} + + {% if mode == 'edit' %} + {% do obj_data.folder('') %} + {% endif %} + {% endif %} + + {% if mode == 'list' or mode == 'edit' %} +
                                                                  + {% include 'partials/blueprints-new.html.twig' with { blueprints: admin.blueprints('admin/pages/new'), data: obj_data, form_id:'new-page' } %} +
                                                                  + +
                                                                  + {% include 'partials/blueprints-new-folder.html.twig' with { blueprints: admin.blueprints('admin/pages/new_folder'), data: obj_data, form_id:'new-folder' } %} +
                                                                  + +
                                                                  + {% include 'partials/blueprints-new.html.twig' with { blueprints: admin.blueprints('admin/pages/modular_new'), data: obj_data, form_id:'new-modular' } %} +
                                                                  + + {% for key, add_modal in config.plugins.admin.add_modals %} +
                                                                  + {% include add_modal.template|defined('partials/blueprints-new.html.twig') with { blueprints: admin.blueprints(add_modal.blueprint), data: context, form_id:'add-modal' }|merge(add_modal.with|defined({})) %} +
                                                                  + {% endfor %} + {% endif %} + + + {% if mode == 'edit' %} +
                                                                  + + {% include 'partials/page-move.html.twig' with { blueprints: admin.blueprints('admin/pages/move'), data: context } %} +
                                                                  +
                                                                  + {% include ['partials/page-revisions.html.twig', 'empty.html.twig'] ignore missing with { data: context } %} +
                                                                  + {% endif %} + + {% include 'partials/modal-changes-detected.html.twig' %} + +
                                                                  +
                                                                  +

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

                                                                  +

                                                                  + {% if context %} + {{ \"PLUGIN_ADMIN.PAGE\"|tu }}: {{ context.title }} + {% endif %} +

                                                                  +

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

                                                                  +
                                                                  +
                                                                  + + {{ \"PLUGIN_ADMIN.CONTINUE\"|tu }} +
                                                                  +
                                                                  +
                                                                  + + {% include 'partials/admin-pro-pages-addons.html.twig' ignore missing %} + +{% endblock %} + +{% block bottom %} + +{% endblock %} +", "pages.html.twig", "/mnt/data/Sites/static-ethica.net/user/plugins/admin/themes/grav/templates/pages.html.twig"); + } +} diff --git a/cache/twig/eb/ebdf4b0b7a11851ed7d2c5fa2a4794de775422c501c926062b22055f4f06fea7.php b/cache/twig/eb/ebdf4b0b7a11851ed7d2c5fa2a4794de775422c501c926062b22055f4f06fea7.php new file mode 100644 index 0000000..be9d709 --- /dev/null +++ b/cache/twig/eb/ebdf4b0b7a11851ed7d2c5fa2a4794de775422c501c926062b22055f4f06fea7.php @@ -0,0 +1,366 @@ +parent = $this->loadTemplate("partials/base.html.twig", "dashboard.html.twig", 1); + $this->blocks = array( + 'titlebar' => array($this, 'block_titlebar'), + 'widgets' => array($this, 'block_widgets'), + 'content' => array($this, 'block_content'), + 'content_bottom' => array($this, 'block_content_bottom'), + ); + } + + protected function doGetParent(array $context) + { + return "partials/base.html.twig"; + } + + protected function doDisplay(array $context, array $blocks = array()) + { + // line 3 + $context["title"] = $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.DASHBOARD"); + // line 5 + $context["clear_cache_url"] = (((($context["base_url_relative"] ?? null) . "/cache.json/task") . $this->getAttribute($this->getAttribute(($context["config"] ?? null), "system", array()), "param_sep", array())) . twig_escape_filter($this->env, "clearCache", "html_attr")); + // line 1 + $this->parent->display($context, array_merge($this->blocks, $blocks)); + } + + // line 7 + public function block_titlebar($context, array $blocks = array()) + { + // line 8 + echo "
                                                                  + "; + // line 9 + if ($this->env->getExtension('Grav\Common\Twig\TwigExtension')->authorize(array(0 => "admin.maintenance", 1 => "admin.super", 2 => "admin.cache"))) { + // line 10 + echo "
                                                                  + + + +
                                                                  + "; + } + // line 24 + echo " "; + if ($this->env->getExtension('Grav\Common\Twig\TwigExtension')->authorize(array(0 => "admin.maintenance", 1 => "admin.super"))) { + // line 25 + echo " + "; + } + // line 27 + echo "
                                                                  +

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

                                                                  +"; + } + + // line 31 + public function block_widgets($context, array $blocks = array()) + { + // line 32 + echo " "; + if ($this->getAttribute($this->getAttribute($this->getAttribute($this->getAttribute(($context["config"] ?? null), "plugins", array()), "admin", array()), "notifications", array()), "dashboard", array())) { + // line 33 + echo "
                                                                  + "; + } + // line 35 + echo " +
                                                                  + "; + // line 37 + if ($this->getAttribute($this->getAttribute(($context["grav"] ?? null), "twig", array()), "plugins_hooked_dashboard_widgets_top", array())) { + // line 38 + echo " "; + $context['_parent'] = $context; + $context['_seq'] = twig_ensure_traversable($this->getAttribute($this->getAttribute(($context["grav"] ?? null), "twig", array()), "plugins_hooked_dashboard_widgets_top", array())); + $context['loop'] = array( + 'parent' => $context['_parent'], + 'index0' => 0, + 'index' => 1, + 'first' => true, + ); + if (is_array($context['_seq']) || (is_object($context['_seq']) && $context['_seq'] instanceof Countable)) { + $length = count($context['_seq']); + $context['loop']['revindex0'] = $length - 1; + $context['loop']['revindex'] = $length; + $context['loop']['length'] = $length; + $context['loop']['last'] = 1 === $length; + } + foreach ($context['_seq'] as $context["_key"] => $context["widget"]) { + // line 39 + echo " "; + if (($this->getAttribute($this->getAttribute($this->getAttribute($this->getAttribute(($context["config"] ?? null), "plugins", array()), "admin", array()), "widgets", array()), $this->getAttribute($context["widget"], "template", array())) == true)) { + // line 40 + echo "
                                                                  + "; + // line 41 + $this->loadTemplate((("partials/" . $this->getAttribute($context["widget"], "template", array())) . ".html.twig"), "dashboard.html.twig", 41)->display($context); + // line 42 + echo "
                                                                  + "; + } + // line 44 + echo " "; + ++$context['loop']['index0']; + ++$context['loop']['index']; + $context['loop']['first'] = false; + if (isset($context['loop']['length'])) { + --$context['loop']['revindex0']; + --$context['loop']['revindex']; + $context['loop']['last'] = 0 === $context['loop']['revindex0']; + } + } + $_parent = $context['_parent']; + unset($context['_seq'], $context['_iterated'], $context['_key'], $context['widget'], $context['_parent'], $context['loop']); + $context = array_intersect_key($context, $_parent) + $_parent; + // line 45 + echo " "; + } + // line 46 + echo "
                                                                  +"; + } + + // line 49 + public function block_content($context, array $blocks = array()) + { + // line 50 + if ($this->getAttribute($this->getAttribute(($context["grav"] ?? null), "twig", array()), "plugins_hooked_dashboard_widgets_main", array())) { + // line 51 + $context['_parent'] = $context; + $context['_seq'] = twig_ensure_traversable($this->getAttribute($this->getAttribute(($context["grav"] ?? null), "twig", array()), "plugins_hooked_dashboard_widgets_main", array())); + $context['loop'] = array( + 'parent' => $context['_parent'], + 'index0' => 0, + 'index' => 1, + 'first' => true, + ); + if (is_array($context['_seq']) || (is_object($context['_seq']) && $context['_seq'] instanceof Countable)) { + $length = count($context['_seq']); + $context['loop']['revindex0'] = $length - 1; + $context['loop']['revindex'] = $length; + $context['loop']['length'] = $length; + $context['loop']['last'] = 1 === $length; + } + foreach ($context['_seq'] as $context["_key"] => $context["widget"]) { + // line 52 + if (($this->getAttribute($this->getAttribute($this->getAttribute($this->getAttribute(($context["config"] ?? null), "plugins", array()), "admin", array()), "widgets", array()), $this->getAttribute($context["widget"], "template", array())) == true)) { + // line 53 + echo " "; + $this->loadTemplate((("partials/" . $this->getAttribute($context["widget"], "template", array())) . ".html.twig"), "dashboard.html.twig", 53)->display($context); + // line 54 + echo " "; + } + ++$context['loop']['index0']; + ++$context['loop']['index']; + $context['loop']['first'] = false; + if (isset($context['loop']['length'])) { + --$context['loop']['revindex0']; + --$context['loop']['revindex']; + $context['loop']['last'] = 0 === $context['loop']['revindex0']; + } + } + $_parent = $context['_parent']; + unset($context['_seq'], $context['_iterated'], $context['_key'], $context['widget'], $context['_parent'], $context['loop']); + $context = array_intersect_key($context, $_parent) + $_parent; + } + } + + // line 59 + public function block_content_bottom($context, array $blocks = array()) + { + // line 60 + echo "
                                                                  "; + // line 61 + if ($this->getAttribute($this->getAttribute(($context["grav"] ?? null), "twig", array()), "plugins_hooked_dashboard_widgets_bottom", array())) { + // line 62 + $context['_parent'] = $context; + $context['_seq'] = twig_ensure_traversable($this->getAttribute($this->getAttribute(($context["grav"] ?? null), "twig", array()), "plugins_hooked_dashboard_widgets_bottom", array())); + $context['loop'] = array( + 'parent' => $context['_parent'], + 'index0' => 0, + 'index' => 1, + 'first' => true, + ); + if (is_array($context['_seq']) || (is_object($context['_seq']) && $context['_seq'] instanceof Countable)) { + $length = count($context['_seq']); + $context['loop']['revindex0'] = $length - 1; + $context['loop']['revindex'] = $length; + $context['loop']['length'] = $length; + $context['loop']['last'] = 1 === $length; + } + foreach ($context['_seq'] as $context["_key"] => $context["widget"]) { + // line 63 + if (($this->getAttribute($this->getAttribute($this->getAttribute($this->getAttribute(($context["config"] ?? null), "plugins", array()), "admin", array()), "widgets", array()), $this->getAttribute($context["widget"], "template", array())) == true)) { + // line 64 + echo " "; + $this->loadTemplate((("partials/" . $this->getAttribute($context["widget"], "template", array())) . ".html.twig"), "dashboard.html.twig", 64)->display($context); + // line 65 + echo " "; + } + ++$context['loop']['index0']; + ++$context['loop']['index']; + $context['loop']['first'] = false; + if (isset($context['loop']['length'])) { + --$context['loop']['revindex0']; + --$context['loop']['revindex']; + $context['loop']['last'] = 0 === $context['loop']['revindex0']; + } + } + $_parent = $context['_parent']; + unset($context['_seq'], $context['_iterated'], $context['_key'], $context['widget'], $context['_parent'], $context['loop']); + $context = array_intersect_key($context, $_parent) + $_parent; + } + // line 68 + echo "
                                                                  +"; + } + + public function getTemplateName() + { + return "dashboard.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 266 => 68, 250 => 65, 247 => 64, 245 => 63, 228 => 62, 226 => 61, 224 => 60, 221 => 59, 203 => 54, 200 => 53, 198 => 52, 181 => 51, 179 => 50, 176 => 49, 171 => 46, 168 => 45, 154 => 44, 150 => 42, 148 => 41, 145 => 40, 142 => 39, 124 => 38, 122 => 37, 118 => 35, 114 => 33, 111 => 32, 108 => 31, 102 => 28, 99 => 27, 93 => 25, 90 => 24, 81 => 20, 75 => 19, 69 => 18, 63 => 17, 57 => 16, 47 => 11, 44 => 10, 42 => 9, 39 => 8, 36 => 7, 32 => 1, 30 => 5, 28 => 3, 11 => 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 Twig_Source("{% extends 'partials/base.html.twig' %} + +{% set title = \"PLUGIN_ADMIN.DASHBOARD\"|tu %} + +{% set clear_cache_url = base_url_relative ~ '/cache.json/task' ~ config.system.param_sep ~ 'clearCache'|e('html_attr') %} + +{% block titlebar %} +
                                                                  + {% if authorize(['admin.maintenance', 'admin.super', 'admin.cache']) %} + + {% endif %} + {% if authorize(['admin.maintenance', 'admin.super']) %} + + {% endif %} +
                                                                  +

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

                                                                  +{% endblock %} + +{% block widgets %} + {% if config.plugins.admin.notifications.dashboard %} +
                                                                  + {% endif %} + +
                                                                  + {% if grav.twig.plugins_hooked_dashboard_widgets_top %} + {% for widget in grav.twig.plugins_hooked_dashboard_widgets_top %} + {% if attribute(config.plugins.admin.widgets, widget.template) == true %} +
                                                                  + {% include 'partials/' ~ widget.template ~ '.html.twig' %} +
                                                                  + {% endif %} + {% endfor %} + {% endif %} +
                                                                  +{% endblock %} + +{% block content %} + {%- if grav.twig.plugins_hooked_dashboard_widgets_main -%} + {%- for widget in grav.twig.plugins_hooked_dashboard_widgets_main -%} + {%- if attribute(config.plugins.admin.widgets, widget.template) == true %} + {% include 'partials/' ~ widget.template ~ '.html.twig' %} + {% endif -%} + {%- endfor -%} + {%- endif -%} +{% endblock %} + +{% block content_bottom %} +
                                                                  + {%- if grav.twig.plugins_hooked_dashboard_widgets_bottom -%} + {%- for widget in grav.twig.plugins_hooked_dashboard_widgets_bottom -%} + {%- if attribute(config.plugins.admin.widgets, widget.template) == true %} + {% include 'partials/' ~ widget.template ~ '.html.twig' %} + {% endif -%} + {%- endfor -%} + {%- endif -%} +
                                                                  +{% endblock %} +", "dashboard.html.twig", "/mnt/data/Sites/static-ethica.net/user/plugins/admin/themes/grav/templates/dashboard.html.twig"); + } +} diff --git a/cache/twig/ec/ec0d1e84273aeda9689a24d3595e53120b3099207f72ec026047ab2f0c2bda9b.php b/cache/twig/ec/ec0d1e84273aeda9689a24d3595e53120b3099207f72ec026047ab2f0c2bda9b.php new file mode 100644 index 0000000..49d91e4 --- /dev/null +++ b/cache/twig/ec/ec0d1e84273aeda9689a24d3595e53120b3099207f72ec026047ab2f0c2bda9b.php @@ -0,0 +1,283 @@ +parent = $this->loadTemplate("forms/field.html.twig", "forms/fields/pages/pages.html.twig", 1); + $this->blocks = array( + 'global_attributes' => array($this, 'block_global_attributes'), + 'input' => array($this, 'block_input'), + ); + } + + protected function doGetParent(array $context) + { + return "forms/field.html.twig"; + } + + protected function doDisplay(array $context, array $blocks = array()) + { + $this->parent->display($context, array_merge($this->blocks, $blocks)); + } + + // line 17 + public function block_global_attributes($context, array $blocks = array()) + { + // line 18 + echo " data-grav-selectize=\""; + echo twig_escape_filter($this->env, twig_jsonencode_filter((($this->getAttribute(($context["field"] ?? null), "selectize", array(), "any", true, true)) ? ($this->getAttribute(($context["field"] ?? null), "selectize", array())) : (array()))), "html_attr"); + echo "\" + data-grav-field=\"select\" + data-grav-disabled=\""; + // line 20 + echo (((null === ($context["originalValue"] ?? null))) ? ("true") : ("false")); + echo "\" + data-grav-default=\""; + // line 21 + echo twig_escape_filter($this->env, twig_jsonencode_filter($this->getAttribute(($context["field"] ?? null), "default", array())), "html_attr"); + echo "\" +"; + } + + // line 24 + public function block_input($context, array $blocks = array()) + { + // line 25 + echo " + "; + // line 26 + $context["start_page"] = (($this->getAttribute(($context["field"] ?? null), "start_route", array())) ? ($this->getAttribute(($context["pages"] ?? null), "find", array(0 => $this->getAttribute(($context["field"] ?? null), "start_route", array())), "method")) : (null)); + // line 27 + echo " "; + $context["show_all"] = ((($this->getAttribute(($context["field"] ?? null), "show_all", array()) === false)) ? (false) : (true)); + // line 28 + echo " "; + $context["show_fullpath"] = ((($this->getAttribute(($context["field"] ?? null), "show_fullpath", array()) === true)) ? (true) : (false)); + // line 29 + echo " "; + $context["show_slug"] = ((($this->getAttribute(($context["field"] ?? null), "show_slug", array()) === true)) ? (true) : (false)); + // line 30 + echo " "; + $context["show_modular"] = ((($this->getAttribute(($context["field"] ?? null), "show_modular", array()) === true)) ? (true) : (false)); + // line 31 + echo " "; + $context["limit_levels"] = (($this->getAttribute(($context["field"] ?? null), "limit_levels", array())) ? ($this->getAttribute(($context["field"] ?? null), "limit_levels", array())) : (false)); + // line 32 + echo " + "; + // line 33 + $context["page_list"] = $this->getAttribute($this->getAttribute(($context["grav"] ?? null), "pages", array()), "getList", array(0 => ($context["start_page"] ?? null), 1 => 0, 2 => true, 3 => ($context["show_all"] ?? null), 4 => ($context["show_fullpath"] ?? null), 5 => ($context["show_slug"] ?? null), 6 => ($context["show_modular"] ?? null), 7 => ($context["limit_levels"] ?? null)), "method"); + // line 34 + echo " +
                                                                  env, $this->getAttribute(($context["field"] ?? null), "size", array()), "html", null, true); + echo "\"> + +
                                                                  +"; + } + + // line 3 + public function getpage_options($__globals__ = null, $__pages_list__ = null, ...$__varargs__) + { + $context = $this->env->mergeGlobals(array( + "globals" => $__globals__, + "pages_list" => $__pages_list__, + "varargs" => $__varargs__, + )); + + $blocks = array(); + + ob_start(); + try { + // line 4 + echo " "; + $context["field"] = $this->getAttribute(($context["globals"] ?? null), "field", array()); + // line 5 + echo " "; + $context["value"] = $this->getAttribute(($context["globals"] ?? null), "value", array()); + // line 6 + echo " "; + if (($this->getAttribute(($context["field"] ?? null), "options", array()) && (($context["depth"] ?? null) == 0))) { + // line 7 + echo " "; + $context['_parent'] = $context; + $context['_seq'] = twig_ensure_traversable($this->getAttribute(($context["field"] ?? null), "options", array())); + foreach ($context['_seq'] as $context["key"] => $context["value"]) { + // line 8 + 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 10 + echo " "; + } + // line 11 + echo " + "; + // line 12 + $context['_parent'] = $context; + $context['_seq'] = twig_ensure_traversable(($context["pages_list"] ?? null)); + foreach ($context['_seq'] as $context["page_route"] => $context["option"]) { + // line 13 + echo " + "; + } + $_parent = $context['_parent']; + unset($context['_seq'], $context['_iterated'], $context['page_route'], $context['option'], $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 Twig_Markup($tmp, $this->env->getCharset()); + } + + public function getTemplateName() + { + return "forms/fields/pages/pages.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 179 => 13, 175 => 12, 172 => 11, 169 => 10, 158 => 8, 153 => 7, 150 => 6, 147 => 5, 144 => 4, 131 => 3, 122 => 46, 118 => 44, 116 => 43, 113 => 42, 108 => 41, 103 => 40, 98 => 39, 93 => 38, 89 => 37, 83 => 36, 79 => 35, 76 => 34, 74 => 33, 71 => 32, 68 => 31, 65 => 30, 62 => 29, 59 => 28, 56 => 27, 54 => 26, 51 => 25, 48 => 24, 42 => 21, 38 => 20, 32 => 18, 29 => 17, 11 => 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 Twig_Source("{% extends \"forms/field.html.twig\" %} + +{% macro page_options(globals, pages_list) %} + {% set field = globals.field %} + {% set value = globals.value %} + {% if field.options and depth == 0 %} + {% for key, value in field.options %} + + {% endfor %} + {% endif %} + + {% for page_route, option in pages_list %} + + {% endfor %} +{% endmacro %} + +{% block global_attributes %} + data-grav-selectize=\"{{ (field.selectize is defined ? field.selectize : {})|json_encode|e('html_attr') }}\" + data-grav-field=\"select\" + data-grav-disabled=\"{{ originalValue is null ? 'true' : 'false' }}\" + data-grav-default=\"{{ field.default|json_encode|e('html_attr') }}\" +{% endblock %} + +{% block input %} + + {% set start_page = field.start_route ? pages.find(field.start_route) : null %} + {% set show_all = field.show_all is same as(false) ? false : true %} + {% set show_fullpath = field.show_fullpath is same as(true) ? true : false %} + {% set show_slug = field.show_slug is same as(true) ? true : false %} + {% set show_modular = field.show_modular is same as(true) ? true : false %} + {% set limit_levels = field.limit_levels ?: false %} + + {% set page_list = grav.pages.getList(start_page, 0, true, show_all, show_fullpath, show_slug, show_modular, limit_levels) %} + +
                                                                  + +
                                                                  +{% endblock %} + +", "forms/fields/pages/pages.html.twig", "/mnt/data/Sites/static-ethica.net/user/plugins/admin/themes/grav/templates/forms/fields/pages/pages.html.twig"); + } +} diff --git a/cache/twig/f1/f1e3343fa7d7fa28d5fc0a6c7ab48fa38aba2f51a955aa9065cc713c7c0b1e7c.php b/cache/twig/f1/f1e3343fa7d7fa28d5fc0a6c7ab48fa38aba2f51a955aa9065cc713c7c0b1e7c.php new file mode 100644 index 0000000..628e3d7 --- /dev/null +++ b/cache/twig/f1/f1e3343fa7d7fa28d5fc0a6c7ab48fa38aba2f51a955aa9065cc713c7c0b1e7c.php @@ -0,0 +1,76 @@ +parent = false; + + $this->blocks = array( + ); + } + + protected function doDisplay(array $context, array $blocks = array()) + { + // line 1 + echo "
                                                                  +

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

                                                                  +
                                                                  +
                                                                  +
                                                                    +
                                                                    +
                                                                    +"; + } + + public function getTemplateName() + { + return "partials/dashboard-notifications.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 23 => 3, 19 => 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 Twig_Source("
                                                                    +

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

                                                                    +
                                                                    +
                                                                    +
                                                                      +
                                                                      +
                                                                      +", "partials/dashboard-notifications.html.twig", "/mnt/data/Sites/static-ethica.net/user/plugins/admin/themes/grav/templates/partials/dashboard-notifications.html.twig"); + } +} diff --git a/cache/twig/f6/f65dbbfd481166d28c3d415addc40988926e185cd6b9e6d071ebb0f180407d39.php b/cache/twig/f6/f65dbbfd481166d28c3d415addc40988926e185cd6b9e6d071ebb0f180407d39.php new file mode 100644 index 0000000..488765e --- /dev/null +++ b/cache/twig/f6/f65dbbfd481166d28c3d415addc40988926e185cd6b9e6d071ebb0f180407d39.php @@ -0,0 +1,146 @@ +parent = false; + + $this->blocks = array( + ); + } + + protected function doDisplay(array $context, array $blocks = array()) + { + // line 1 + $context["form_id"] = ((($context["form_id"] ?? null)) ? (($context["form_id"] ?? null)) : ("blueprints")); + // line 2 + $context["scope"] = ((($context["scope"] ?? null)) ? (($context["scope"] ?? null)) : ("data.")); + // line 3 + echo " +
                                                                      env, ($context["form_id"] ?? null), "html", null, true); + echo "\" method=\"post\" data-grav-form=\""; + echo twig_escape_filter($this->env, ($context["form_id"] ?? null), "html", null, true); + echo "\" data-grav-keepalive=\"true\"> + "; + // line 5 + $context['_parent'] = $context; + $context['_seq'] = twig_ensure_traversable($this->getAttribute(($context["blueprints"] ?? null), "fields", array())); + $context['loop'] = array( + 'parent' => $context['_parent'], + 'index0' => 0, + 'index' => 1, + 'first' => true, + ); + if (is_array($context['_seq']) || (is_object($context['_seq']) && $context['_seq'] instanceof Countable)) { + $length = count($context['_seq']); + $context['loop']['revindex0'] = $length - 1; + $context['loop']['revindex'] = $length; + $context['loop']['length'] = $length; + $context['loop']['last'] = 1 === $length; + } + foreach ($context['_seq'] as $context["_key"] => $context["field"]) { + // line 6 + echo " "; + if ($this->getAttribute($context["field"], "type", array())) { + // line 7 + echo " "; + $context["value"] = (($this->getAttribute($context["field"], "name", array())) ? ($this->getAttribute(($context["data"] ?? null), "value", array(0 => $this->getAttribute($context["field"], "name", array())), "method")) : ($this->getAttribute(($context["data"] ?? null), "toArray", array()))); + // line 8 + echo "
                                                                      env, $this->getAttribute($context["field"], "type", array()), "html", null, true); + echo "\"> + "; + // line 9 + $this->loadTemplate(array(0 => (((("forms/fields/" . $this->getAttribute($context["field"], "type", array())) . "/") . $this->getAttribute($context["field"], "type", array())) . ".html.twig"), 1 => "forms/fields/text/text.html.twig"), "partials/blueprints-new.html.twig", 9)->display($context); + // line 10 + echo "
                                                                      + "; + } + // line 12 + echo " "; + ++$context['loop']['index0']; + ++$context['loop']['index']; + $context['loop']['first'] = false; + if (isset($context['loop']['length'])) { + --$context['loop']['revindex0']; + --$context['loop']['revindex']; + $context['loop']['last'] = 0 === $context['loop']['revindex0']; + } + } + $_parent = $context['_parent']; + unset($context['_seq'], $context['_iterated'], $context['_key'], $context['field'], $context['_parent'], $context['loop']); + $context = array_intersect_key($context, $_parent) + $_parent; + // line 13 + echo " + +
                                                                      + +
                                                                      + + "; + // line 19 + echo $this->env->getExtension('Grav\Common\Twig\TwigExtension')->nonceFieldFunc("admin-form", "admin-nonce"); + echo " + +
                                                                      +"; + } + + public function getTemplateName() + { + return "partials/blueprints-new.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 91 => 19, 85 => 16, 80 => 13, 66 => 12, 62 => 10, 60 => 9, 55 => 8, 52 => 7, 49 => 6, 32 => 5, 26 => 4, 23 => 3, 21 => 2, 19 => 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 Twig_Source("{% set form_id = form_id ? form_id : 'blueprints' %} +{% set scope = scope ?: 'data.' %} + +
                                                                      + {% for field in blueprints.fields %} + {% if field.type %} + {% set 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 %} + + +
                                                                      + +
                                                                      + + {{ nonce_field('admin-form', 'admin-nonce')|raw }} + +
                                                                      +", "partials/blueprints-new.html.twig", "/mnt/data/Sites/static-ethica.net/user/plugins/admin/themes/grav/templates/partials/blueprints-new.html.twig"); + } +} diff --git a/cache/twig/f6/f66ceec93dc9e6bc47780ce2db3d513899132edcd675cfd4ddb7fdd45329a6bd.php b/cache/twig/f6/f66ceec93dc9e6bc47780ce2db3d513899132edcd675cfd4ddb7fdd45329a6bd.php new file mode 100644 index 0000000..354e19b --- /dev/null +++ b/cache/twig/f6/f66ceec93dc9e6bc47780ce2db3d513899132edcd675cfd4ddb7fdd45329a6bd.php @@ -0,0 +1,128 @@ +parent = false; + + $this->blocks = array( + 'content' => array($this, 'block_content'), + ); + } + + protected function doDisplay(array $context, array $blocks = array()) + { + // line 2 + echo " + "; + // line 3 + $this->displayBlock('content', $context, $blocks); + } + + public function block_content($context, array $blocks = array()) + { + // line 4 + echo "
                                                                      +

                                                                      "; + // line 5 + echo $this->getAttribute(($context["header"] ?? null), "title", array()); + echo "

                                                                      + "; + // line 6 + echo $this->getAttribute(($context["page"] ?? null), "content", array()); + echo " +
                                                                      + "; + // line 8 + $context['_parent'] = $context; + $context['_seq'] = twig_ensure_traversable($this->getAttribute(($context["page"] ?? null), "collection", array(), "method")); + foreach ($context['_seq'] as $context["_key"] => $context["module"]) { + // line 9 + echo "
                                                                      getAttribute($this, "pageLinkName", array(0 => $this->getAttribute($context["module"], "folder", array())), "method"); + echo "\" class=\"mutli-column\"> + "; + // line 10 + echo $this->getAttribute($context["module"], "content", array()); + echo " +
                                                                      + "; + } + $_parent = $context['_parent']; + unset($context['_seq'], $context['_iterated'], $context['_key'], $context['module'], $context['_parent'], $context['loop']); + $context = array_intersect_key($context, $_parent) + $_parent; + // line 13 + echo " "; + } + + // line 1 + public function getpageLinkName($__text__ = null, ...$__varargs__) + { + $context = $this->env->mergeGlobals(array( + "text" => $__text__, + "varargs" => $__varargs__, + )); + + $blocks = array(); + + ob_start(); + try { + echo twig_replace_filter(twig_lower_filter($this->env, ($context["text"] ?? null)), array("01._" => "", "02._" => "", "03._" => "", "04._" => "", "05._" => "", "06._" => "", "07._" => "", "08._" => "", "09._" => "")); + } catch (Exception $e) { + ob_end_clean(); + + throw $e; + } catch (Throwable $e) { + ob_end_clean(); + + throw $e; + } + + return ('' === $tmp = ob_get_clean()) ? '' : new Twig_Markup($tmp, $this->env->getCharset()); + } + + public function getTemplateName() + { + return "modular/contenu-multi.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 63 => 1, 59 => 13, 50 => 10, 45 => 9, 41 => 8, 36 => 6, 32 => 5, 29 => 4, 23 => 3, 20 => 2,); + } + + /** @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 Twig_Source("{% macro pageLinkName(text) %}{{ text|lower|replace({'01._':'','02._':'','03._':'','04._':'','05._':'','06._':'','07._':'','08._':'','09._':''}) }}{% endmacro %} + + {% block content %} +
                                                                      +

                                                                      {{ header.title }}

                                                                      + {{ page.content }} +
                                                                      + {% for module in page.collection() %} +
                                                                      + {{ module.content }} +
                                                                      + {% endfor %} + {% endblock %} +", "modular/contenu-multi.html.twig", "/mnt/data/Sites/static-ethica.net/user/themes/ethica/templates/modular/contenu-multi.html.twig"); + } +} diff --git a/cache/twig/f9/f9b5017d2d9799f0db18a737fc29183a378d4d5f95bc0b5eef4a5d54b8a1a79a.php b/cache/twig/f9/f9b5017d2d9799f0db18a737fc29183a378d4d5f95bc0b5eef4a5d54b8a1a79a.php new file mode 100644 index 0000000..e798652 --- /dev/null +++ b/cache/twig/f9/f9b5017d2d9799f0db18a737fc29183a378d4d5f95bc0b5eef4a5d54b8a1a79a.php @@ -0,0 +1,113 @@ +parent = false; + + $this->blocks = array( + ); + } + + protected function doDisplay(array $context, array $blocks = array()) + { + // line 1 + if ($this->getAttribute($this->getAttribute($this->getAttribute(($context["config"] ?? null), "plugins", array()), "admin", array()), "logo_text", array())) { + // line 2 + echo "

                                                                      +\tenv, ($context["base_url_relative"] ?? null), "html", null, true); + echo "\"> +\t\t"; + // line 4 + echo twig_escape_filter($this->env, $this->getAttribute($this->getAttribute($this->getAttribute(($context["config"] ?? null), "plugins", array()), "admin", array()), "logo_text", array()), "html", null, true); + echo " +\t +\tenv, ($context["base_url_relative_frontend"] ?? null), "html", null, true); + echo "\"> +

                                                                      +"; + } else { + // line 9 + echo " +"; + } + // line 17 + echo " + + + + + +"; + } + + public function getTemplateName() + { + return "partials/logo.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 55 => 17, 49 => 14, 42 => 10, 39 => 9, 33 => 6, 28 => 4, 24 => 3, 21 => 2, 19 => 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 Twig_Source("{% if config.plugins.admin.logo_text %} +

                                                                      +\t +\t\t{{ config.plugins.admin.logo_text }} +\t +\t +

                                                                      +{% else %} +
                                                                      +\t + +\t\t +\t +\t +
                                                                      +{% endif %} + + + + + + +", "partials/logo.html.twig", "/mnt/data/Sites/static-ethica.net/user/plugins/admin/themes/grav/templates/partials/logo.html.twig"); + } +} diff --git a/cache/twig/ff/ff7b0ce4ec8a413ba37fe4c70668b235c585141acc962245fc06dd4cfafd30b4.php b/cache/twig/ff/ff7b0ce4ec8a413ba37fe4c70668b235c585141acc962245fc06dd4cfafd30b4.php new file mode 100644 index 0000000..3dd8455 --- /dev/null +++ b/cache/twig/ff/ff7b0ce4ec8a413ba37fe4c70668b235c585141acc962245fc06dd4cfafd30b4.php @@ -0,0 +1,242 @@ +parent = $this->loadTemplate("partials/base.html.twig", "home.html.twig", 1); + $this->blocks = array( + 'javascripts' => array($this, 'block_javascripts'), + 'header_navigation' => array($this, 'block_header_navigation'), + 'content' => array($this, 'block_content'), + ); + } + + protected function doGetParent(array $context) + { + return "partials/base.html.twig"; + } + + protected function doDisplay(array $context, array $blocks = array()) + { + // line 3 + $context["show_onpage_menu"] = (($this->getAttribute(($context["header"] ?? null), "onpage_menu", array()) == true) || (null === $this->getAttribute(($context["header"] ?? null), "onpage_menu", array()))); + // line 4 + $context["cc"] = $this->getAttribute(($context["taxonomy"] ?? null), "findTaxonomy", array(0 => array("category" => "sous-menu")), "method"); + // line 1 + $this->parent->display($context, array_merge($this->blocks, $blocks)); + } + + // line 8 + public function block_javascripts($context, array $blocks = array()) + { + // line 9 + echo " "; + if (($context["show_onpage_menu"] ?? null)) { + // line 10 + echo " "; + } + // line 11 + echo " "; + $this->displayParentBlock("javascripts", $context, $blocks); + echo " +"; + } + + // line 14 + public function block_header_navigation($context, array $blocks = array()) + { + // line 15 + echo " "; + if (($context["show_onpage_menu"] ?? null)) { + // line 16 + echo " + "; + } else { + // line 32 + echo " "; + $this->displayParentBlock("header_navigation", $context, $blocks); + echo " + "; + } + } + + // line 36 + public function block_content($context, array $blocks = array()) + { + // line 37 + echo " "; + echo $this->getAttribute(($context["page"] ?? null), "content", array()); + echo " + "; + // line 38 + $context['_parent'] = $context; + $context['_seq'] = twig_ensure_traversable($this->getAttribute(($context["page"] ?? null), "collection", array(), "method")); + foreach ($context['_seq'] as $context["_key"] => $context["module"]) { + // line 39 + echo "
                                                                      getAttribute($this, "pageLinkName", array(0 => $this->getAttribute($context["module"], "folder", array())), "method"); + echo "\" class=\"column \"> + "; + // line 40 + echo $this->getAttribute($context["module"], "content", array()); + echo " +
                                                                      + "; + } + $_parent = $context['_parent']; + unset($context['_seq'], $context['_iterated'], $context['_key'], $context['module'], $context['_parent'], $context['loop']); + $context = array_intersect_key($context, $_parent) + $_parent; + } + + // line 6 + public function getpageLinkName($__text__ = null, ...$__varargs__) + { + $context = $this->env->mergeGlobals(array( + "text" => $__text__, + "varargs" => $__varargs__, + )); + + $blocks = array(); + + ob_start(); + try { + echo twig_replace_filter(twig_lower_filter($this->env, ($context["text"] ?? null)), array("01._" => "", "02._" => "", "03._" => "", "04._" => "", "05._" => "", "06._" => "", "07._" => "", "08._" => "", "09._" => "")); + } catch (Exception $e) { + ob_end_clean(); + + throw $e; + } catch (Throwable $e) { + ob_end_clean(); + + throw $e; + } + + return ('' === $tmp = ob_get_clean()) ? '' : new Twig_Markup($tmp, $this->env->getCharset()); + } + + public function getTemplateName() + { + return "home.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 147 => 6, 136 => 40, 131 => 39, 127 => 38, 122 => 37, 119 => 36, 111 => 32, 106 => 29, 99 => 27, 93 => 26, 85 => 23, 82 => 22, 79 => 21, 75 => 20, 69 => 19, 64 => 18, 60 => 17, 57 => 16, 54 => 15, 51 => 14, 44 => 11, 41 => 10, 38 => 9, 35 => 8, 31 => 1, 29 => 4, 27 => 3, 11 => 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 Twig_Source("{% extends 'partials/base.html.twig' %} + +{% set show_onpage_menu = header.onpage_menu == true or header.onpage_menu is null %} +{% set cc = taxonomy.findTaxonomy({'category':'sous-menu'}) %} + +{% macro pageLinkName(text) %}{{ text|lower|replace({'01._':'','02._':'','03._':'','04._':'','05._':'','06._':'','07._':'','08._':'','09._':''}) }}{% endmacro %} + +{% block javascripts %} + {% if show_onpage_menu %} + {% endif %} + {{ parent() }} +{% endblock %} + +{% block header_navigation %} + {% if show_onpage_menu %} +
                                                                        + {% for module in page.collection() %} +
                                                                      • + {{ module.menu }} + {% for child in module.collection %} + {% if child in cc %} +
                                                                          + {{ child.menu }} +
                                                                        + {% endif %} + {% endfor %} +
                                                                      • + {% endfor %} + +
                                                                      + {% else %} + {{ parent() }} + {% endif %} +{% endblock %} + +{% block content %} + {{ page.content }} + {% for module in page.collection() %} +
                                                                      + {{ module.content }} +
                                                                      + {% endfor %} +{% endblock %} +", "home.html.twig", "/mnt/data/Sites/static-ethica.net/user/themes/ethica/templates/home.html.twig"); + } +} diff --git a/cache/twig/ff/ffb161266ef718b362f1a63059c92f28726484aba26b23c90d383419feaf962c.php b/cache/twig/ff/ffb161266ef718b362f1a63059c92f28726484aba26b23c90d383419feaf962c.php new file mode 100644 index 0000000..1dbea25 --- /dev/null +++ b/cache/twig/ff/ffb161266ef718b362f1a63059c92f28726484aba26b23c90d383419feaf962c.php @@ -0,0 +1,272 @@ +parent = false; + + $this->blocks = array( + ); + } + + protected function doDisplay(array $context, array $blocks = array()) + { + // line 1 + $context["value"] = (((null === ($context["value"] ?? null))) ? ($this->getAttribute(($context["field"] ?? null), "default", array())) : (($context["value"] ?? null))); + // line 2 + $context["siblings"] = $this->getAttribute($this->getAttribute(($context["data"] ?? null), "parent", array()), "children", array()); + // line 3 + $context["canOrder"] = $this->getAttribute(($context["data"] ?? null), "order", array()); + // line 4 + $context["vertical"] = ($this->getAttribute(($context["field"] ?? null), "style", array()) == "vertical"); + // line 5 + echo " +
                                                                      +
                                                                      + +
                                                                      +
                                                                      +
                                                                      env, $this->getAttribute(($context["field"] ?? null), "size", array()), "html", null, true); + echo "\"> + + getAttribute(($context["field"] ?? null), "disabled", array()) || ($context["isDisabledToggleable"] ?? null))) { + echo "disabled=\"disabled\""; + } + // line 24 + echo " name=\""; + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Common\Twig\TwigExtension')->fieldNameFilter((($context["scope"] ?? null) . $this->getAttribute(($context["field"] ?? null), "name", array()))), "html", null, true); + echo "\" + value=\"\" /> + "; + // line 26 + if ( !($context["canOrder"] ?? null)) { + // line 27 + echo "
                                                                      "; + echo $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.ORDERING_DISABLED_BECAUSE_PAGE_NO_PREFIX"); + echo "
                                                                      + "; + } + // line 29 + echo " + "; + // line 30 + if ((twig_length_filter($this->env, ($context["siblings"] ?? null)) < 200)) { + // line 31 + echo " "; + $context["sortable_count"] = 0; + // line 32 + echo "\t\t\t\t
                                                                        env, $this->getAttribute(($context["field"] ?? null), "classes", array()), "html", null, true); + echo "\"> +\t\t\t "; + // line 33 + $context['_parent'] = $context; + $context['_seq'] = twig_ensure_traversable(($context["siblings"] ?? null)); + $context['loop'] = array( + 'parent' => $context['_parent'], + 'index0' => 0, + 'index' => 1, + 'first' => true, + ); + foreach ($context['_seq'] as $context["_key"] => $context["page"]) { + if ($this->getAttribute($context["page"], "order", array())) { + // line 34 + echo "\t\t\t\t\t
                                                                      • env, $this->getAttribute($context["page"], "slug", array()), "html", null, true); + echo "\" "; + echo ((($this->getAttribute($context["page"], "slug", array()) == $this->getAttribute(($context["data"] ?? null), "slug", array()))) ? ("data-active-id") : ("")); + echo ">"; + echo twig_escape_filter($this->env, $this->getAttribute($context["page"], "order", array()), "html", null, true); + echo " "; + echo twig_escape_filter($this->env, $this->getAttribute($context["page"], "title", array())); + echo " env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->getPageUrl($context, $context["page"]), "html", null, true); + echo "\">
                                                                      • + "; + // line 35 + $context["sortable_count"] = $this->getAttribute($context["loop"], "index", array()); + // line 36 + echo " "; + ++$context['loop']['index0']; + ++$context['loop']['index']; + $context['loop']['first'] = false; + } + } + $_parent = $context['_parent']; + unset($context['_seq'], $context['_iterated'], $context['_key'], $context['page'], $context['_parent'], $context['loop']); + $context = array_intersect_key($context, $_parent) + $_parent; + // line 37 + echo "\t\t\t\t
                                                                      + "; + // line 38 + if ((($context["sortable_count"] ?? null) < twig_length_filter($this->env, ($context["siblings"] ?? null)))) { + // line 39 + echo " +
                                                                        + "; + // line 41 + $context['_parent'] = $context; + $context['_seq'] = twig_ensure_traversable(($context["siblings"] ?? null)); + foreach ($context['_seq'] as $context["_key"] => $context["page"]) { + if ( !$this->getAttribute($context["page"], "order", array())) { + // line 42 + echo "
                                                                      • getAttribute($context["page"], "slug", array()) == $this->getAttribute(($context["data"] ?? null), "slug", array()))) ? ("data-active-id") : ("")); + echo ">"; + echo twig_escape_filter($this->env, $this->getAttribute($context["page"], "title", array())); + echo " env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->getPageUrl($context, $context["page"]), "html", null, true); + echo "\">
                                                                      • + "; + } + } + $_parent = $context['_parent']; + unset($context['_seq'], $context['_iterated'], $context['_key'], $context['page'], $context['_parent'], $context['loop']); + $context = array_intersect_key($context, $_parent) + $_parent; + // line 44 + echo "
                                                                      + "; + } + // line 46 + echo "\t\t\t"; + } else { + // line 47 + echo "
                                                                      "; + echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.ORDERING_DISABLED_BECAUSE_TOO_MANY_SIBLINGS"), "html", null, true); + echo "
                                                                      +\t\t\t"; + } + // line 49 + echo "
                                                                      +
                                                                      +
                                                                      +"; + } + + public function getTemplateName() + { + return "forms/fields/order/order.html.twig"; + } + + public function isTraitable() + { + return false; + } + + public function getDebugInfo() + { + return array ( 188 => 49, 182 => 47, 179 => 46, 175 => 44, 161 => 42, 156 => 41, 152 => 39, 150 => 38, 147 => 37, 137 => 36, 135 => 35, 122 => 34, 111 => 33, 106 => 32, 103 => 31, 101 => 30, 98 => 29, 92 => 27, 90 => 26, 84 => 24, 80 => 23, 72 => 18, 66 => 17, 59 => 14, 53 => 12, 45 => 10, 43 => 9, 36 => 7, 30 => 6, 27 => 5, 25 => 4, 23 => 3, 21 => 2, 19 => 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 Twig_Source("{% set value = (value is null ? field.default : value) %} +{% set siblings = data.parent.children %} +{% set canOrder = data.order %} +{% set vertical = field.style == 'vertical' %} + +
                                                                      +
                                                                      + +
                                                                      +
                                                                      +
                                                                      + + + {% if not canOrder %} +
                                                                      {{ \"PLUGIN_ADMIN.ORDERING_DISABLED_BECAUSE_PAGE_NO_PREFIX\"|tu|raw }}
                                                                      + {% endif %} + + {% if siblings|length < 200 %} + {% set sortable_count = 0 %} +\t\t\t\t
                                                                        +\t\t\t {% for page in siblings if page.order %} +\t\t\t\t\t
                                                                      • {{ page.order }} {{ page.title|e }}
                                                                      • + {% set sortable_count = loop.index %} + {% endfor %} +\t\t\t\t
                                                                      + {% if sortable_count < siblings|length %} + +
                                                                        + {% for page in siblings if not page.order %} +
                                                                      • {{ page.title|e }}
                                                                      • + {% endfor %} +
                                                                      + {% endif %} +\t\t\t{% else %} +
                                                                      {{ \"PLUGIN_ADMIN.ORDERING_DISABLED_BECAUSE_TOO_MANY_SIBLINGS\"|tu }}
                                                                      +\t\t\t{% endif %} +
                                                                      +
                                                                      +
                                                                      +", "forms/fields/order/order.html.twig", "/mnt/data/Sites/static-ethica.net/user/plugins/admin/themes/grav/templates/forms/fields/order/order.html.twig"); + } +} diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..9fb3b9c --- /dev/null +++ b/composer.json @@ -0,0 +1,68 @@ +{ + "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": "http://getgrav.org", + "license": "MIT", + "require": { + "php": ">=5.5.9", + "twig/twig": "~1.24", + "erusev/parsedown": "~1.6", + "erusev/parsedown-extra": "~0.7", + "symfony/yaml": "~2.8", + "symfony/console": "~2.8", + "symfony/event-dispatcher": "~2.8", + "symfony/var-dumper": "~2.8", + "symfony/polyfill-iconv": "~1.0", + "doctrine/cache": "1.6.*", + "doctrine/collections": "1.3", + "filp/whoops": "~2.0", + "matthiasmullie/minify": "^1.3", + "monolog/monolog": "~1.0", + "gregwar/image": "2.*", + "donatj/phpuseragentparser": "~0.3", + "pimple/pimple": "~3.0", + "rockettheme/toolbox": "~1.0", + "maximebf/debugbar": "~1.10", + "ext-mbstring": "*", + "ext-openssl": "*", + "ext-curl": "*", + "ext-zip": "*", + "league/climate": "^3.2", + "antoligy/dom-string-iterators": "^1.0", + "miljar/php-exif": "^0.6.3", + "composer/ca-bundle": "^1.0" + }, + "require-dev": { + "codeception/codeception": "^2.1", + "phpunit/php-code-coverage": "~2.0", + "fzaninotto/faker": "^1.5", + "victorjonsson/markdowndocs": "dev-master" + }, + "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": { + "post-create-project-cmd": "bin/grav install", + "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 0000000..138dd9f --- /dev/null +++ b/composer.lock @@ -0,0 +1,3536 @@ +{ + "_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": "24c56b5fbd83e5c8173f1c38c2805b68", + "packages": [ + { + "name": "antoligy/dom-string-iterators", + "version": "v1.0.0", + "source": { + "type": "git", + "url": "https://github.com/antoligy/dom-string-iterators.git", + "reference": "9a624b082493fee9b972840dbd677494edb94cf7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/antoligy/dom-string-iterators/zipball/9a624b082493fee9b972840dbd677494edb94cf7", + "reference": "9a624b082493fee9b972840dbd677494edb94cf7", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Public Domain" + ], + "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": "2015-11-04T17:33:14+00:00" + }, + { + "name": "composer/ca-bundle", + "version": "1.0.8", + "source": { + "type": "git", + "url": "https://github.com/composer/ca-bundle.git", + "reference": "9dd73a03951357922d8aee6cc084500de93e2343" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/ca-bundle/zipball/9dd73a03951357922d8aee6cc084500de93e2343", + "reference": "9dd73a03951357922d8aee6cc084500de93e2343", + "shasum": "" + }, + "require": { + "ext-openssl": "*", + "ext-pcre": "*", + "php": "^5.3.2 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.5", + "psr/log": "^1.0", + "symfony/process": "^2.5 || ^3.0" + }, + "suggest": { + "symfony/process": "This is necessary to reliably check whether openssl_x509_parse is vulnerable on older php versions, but can be ignored on PHP 5.5.6+" + }, + "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": "2017-09-11T07:24:36+00:00" + }, + { + "name": "doctrine/cache", + "version": "v1.6.2", + "source": { + "type": "git", + "url": "https://github.com/doctrine/cache.git", + "reference": "eb152c5100571c7a45470ff2a35095ab3f3b900b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/cache/zipball/eb152c5100571c7a45470ff2a35095ab3f3b900b", + "reference": "eb152c5100571c7a45470ff2a35095ab3f3b900b", + "shasum": "" + }, + "require": { + "php": "~5.5|~7.0" + }, + "conflict": { + "doctrine/common": ">2.2,<2.4" + }, + "require-dev": { + "phpunit/phpunit": "~4.8|~5.0", + "predis/predis": "~1.0", + "satooshi/php-coveralls": "~0.6" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.6.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": "http://www.doctrine-project.org", + "keywords": [ + "cache", + "caching" + ], + "time": "2017-07-22T12:49:21+00:00" + }, + { + "name": "doctrine/collections", + "version": "v1.3.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/collections.git", + "reference": "6c1e4eef75f310ea1b3e30945e9f06e652128b8a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/collections/zipball/6c1e4eef75f310ea1b3e30945e9f06e652128b8a", + "reference": "6c1e4eef75f310ea1b3e30945e9f06e652128b8a", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + }, + "autoload": { + "psr-0": { + "Doctrine\\Common\\Collections\\": "lib/" + } + }, + "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": "Collections Abstraction library", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "array", + "collections", + "iterator" + ], + "time": "2015-04-14T22:21:58+00:00" + }, + { + "name": "donatj/phpuseragentparser", + "version": "v0.7.0", + "source": { + "type": "git", + "url": "https://github.com/donatj/PhpUserAgent.git", + "reference": "73c819d4c7de034f1bfb7c7a36259192d7d7472a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/donatj/PhpUserAgent/zipball/73c819d4c7de034f1bfb7c7a36259192d7d7472a", + "reference": "73c819d4c7de034f1bfb7c7a36259192d7d7472a", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "require-dev": { + "camspiers/json-pretty": "0.1.*", + "donatj/drop": "*", + "phpunit/phpunit": ">=4.8" + }, + "type": "library", + "autoload": { + "files": [ + "Source/UserAgentParser.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jesse G. Donat", + "email": "donatj@gmail.com", + "homepage": "http://donatstudios.com", + "role": "Developer" + } + ], + "description": "Simple, streamlined PHP user-agent parser", + "homepage": "http://donatstudios.com/PHP-Parser-HTTP_USER_AGENT", + "keywords": [ + "browser", + "browser detection", + "parser", + "user agent", + "useragent" + ], + "time": "2017-03-01T22:19:13+00:00" + }, + { + "name": "erusev/parsedown", + "version": "1.6.3", + "source": { + "type": "git", + "url": "https://github.com/erusev/parsedown.git", + "reference": "728952b90a333b5c6f77f06ea9422b94b585878d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/erusev/parsedown/zipball/728952b90a333b5c6f77f06ea9422b94b585878d", + "reference": "728952b90a333b5c6f77f06ea9422b94b585878d", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "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-05-14T14:47:48+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.1.10", + "source": { + "type": "git", + "url": "https://github.com/filp/whoops.git", + "reference": "ffbbd2c06c64b08fb47974eed5dbce4ca2bb0eec" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/filp/whoops/zipball/ffbbd2c06c64b08fb47974eed5dbce4ca2bb0eec", + "reference": "ffbbd2c06c64b08fb47974eed5dbce4ca2bb0eec", + "shasum": "" + }, + "require": { + "php": "^5.5.9 || ^7.0", + "psr/log": "^1.0.1" + }, + "require-dev": { + "mockery/mockery": "0.9.*", + "phpunit/phpunit": "^4.8 || ^5.0", + "symfony/var-dumper": "^2.6 || ^3.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.0-dev" + } + }, + "autoload": { + "psr-4": { + "Whoops\\": "src/Whoops/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Filipe Dobreira", + "homepage": "https://github.com/filp", + "role": "Developer" + } + ], + "description": "php error handling for cool kids", + "homepage": "https://filp.github.io/whoops/", + "keywords": [ + "error", + "exception", + "handling", + "library", + "whoops", + "zf2" + ], + "time": "2017-08-03T18:23:40+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.21", + "target-dir": "Gregwar/Image", + "source": { + "type": "git", + "url": "https://github.com/Gregwar/Image.git", + "reference": "c9899e4c71009338f89a8c63c12c681692533ede" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Gregwar/Image/zipball/c9899e4c71009338f89a8c63c12c681692533ede", + "reference": "c9899e4c71009338f89a8c63c12c681692533ede", + "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": "2017-01-24T09:29:39+00:00" + }, + { + "name": "league/climate", + "version": "3.2.1", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/climate.git", + "reference": "b103fc8faa3780c802cc507d5f0ff534ecc94fb5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/climate/zipball/b103fc8faa3780c802cc507d5f0ff534ecc94fb5", + "reference": "b103fc8faa3780c802cc507d5f0ff534ecc94fb5", + "shasum": "" + }, + "require": { + "php": ">=5.4.0", + "seld/cli-prompt": "~1.0" + }, + "require-dev": { + "mikey179/vfsstream": "~1.4", + "mockery/mockery": "~0.9", + "phpunit/phpunit": "~4.6" + }, + "type": "library", + "autoload": { + "psr-4": { + "League\\CLImate\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Joe Tannenbaum", + "email": "hey@joe.codes", + "homepage": "http://joe.codes/", + "role": "Developer" + } + ], + "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": "2016-04-04T20:24:59+00:00" + }, + { + "name": "matthiasmullie/minify", + "version": "1.3.52", + "source": { + "type": "git", + "url": "https://github.com/matthiasmullie/minify.git", + "reference": "134b25a63d83a80ae128aedc9a99987e064b4382" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/matthiasmullie/minify/zipball/134b25a63d83a80ae128aedc9a99987e064b4382", + "reference": "134b25a63d83a80ae128aedc9a99987e064b4382", + "shasum": "" + }, + "require": { + "ext-pcre": "*", + "matthiasmullie/path-converter": "~1.1", + "php": ">=5.3.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "~1.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", + "email": "minify@mullie.eu", + "homepage": "http://www.mullie.eu", + "role": "Developer" + } + ], + "description": "CSS & JS minifier", + "homepage": "http://www.minifier.org", + "keywords": [ + "JS", + "css", + "javascript", + "minifier", + "minify" + ], + "time": "2017-09-15T13:02:11+00:00" + }, + { + "name": "matthiasmullie/path-converter", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/matthiasmullie/path-converter.git", + "reference": "08551ec1b156e923c242a10ab484bd4d6ead6631" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/matthiasmullie/path-converter/zipball/08551ec1b156e923c242a10ab484bd4d6ead6631", + "reference": "08551ec1b156e923c242a10ab484bd4d6ead6631", + "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", + "email": "pathconverter@mullie.eu", + "homepage": "http://www.mullie.eu", + "role": "Developer" + } + ], + "description": "Relative path converter", + "homepage": "http://github.com/matthiasmullie/path-converter", + "keywords": [ + "converter", + "path", + "paths", + "relative" + ], + "time": "2017-01-26T08:54:49+00:00" + }, + { + "name": "maximebf/debugbar", + "version": "v1.14.0", + "source": { + "type": "git", + "url": "https://github.com/maximebf/php-debugbar.git", + "reference": "e23a98f2d65607d8aa6c7b409a513f8fdf4acdde" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/maximebf/php-debugbar/zipball/e23a98f2d65607d8aa6c7b409a513f8fdf4acdde", + "reference": "e23a98f2d65607d8aa6c7b409a513f8fdf4acdde", + "shasum": "" + }, + "require": { + "php": ">=5.3.0", + "psr/log": "^1.0", + "symfony/var-dumper": "^2.6|^3.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-08-17T07:17:00+00:00" + }, + { + "name": "miljar/php-exif", + "version": "v0.6.3", + "source": { + "type": "git", + "url": "https://github.com/PHPExif/php-exif.git", + "reference": "e43cc30608824d7f3466653b52bbbb71874b5b02" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHPExif/php-exif/zipball/e43cc30608824d7f3466653b52bbbb71874b5b02", + "reference": "e43cc30608824d7f3466653b52bbbb71874b5b02", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "require-dev": { + "phpmd/phpmd": "~2.2", + "phpunit/phpunit": "3.7.*", + "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", + "homepage": "http://theanalogguy.be", + "role": "Developer" + } + ], + "description": "Object-Oriented EXIF parsing", + "keywords": [ + "IPTC", + "exif", + "exiftool", + "jpeg", + "tiff" + ], + "time": "2017-02-06T14:40:26+00:00" + }, + { + "name": "monolog/monolog", + "version": "1.23.0", + "source": { + "type": "git", + "url": "https://github.com/Seldaek/monolog.git", + "reference": "fd8c787753b3a2ad11bc60c063cff1358a32a3b4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/fd8c787753b3a2ad11bc60c063cff1358a32a3b4", + "reference": "fd8c787753b3a2ad11bc60c063cff1358a32a3b4", + "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": "2017-06-19T01:22:40+00:00" + }, + { + "name": "pimple/pimple", + "version": "v3.2.2", + "source": { + "type": "git", + "url": "https://github.com/silexphp/Pimple.git", + "reference": "4d45fb62d96418396ec58ba76e6f065bca16e10a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/silexphp/Pimple/zipball/4d45fb62d96418396ec58ba76e6f065bca16e10a", + "reference": "4d45fb62d96418396ec58ba76e6f065bca16e10a", + "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": "2017-07-23T07:32:15+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/log", + "version": "1.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/4ebe3a8bf773a19edfe0a84b6585ba3d401b724d", + "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d", + "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": "2016-10-10T12:19:37+00:00" + }, + { + "name": "rockettheme/toolbox", + "version": "1.3.8", + "source": { + "type": "git", + "url": "https://github.com/rockettheme/toolbox.git", + "reference": "2f7c83780bbcf527e057f15efe755e10694eb2bc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/rockettheme/toolbox/zipball/2f7c83780bbcf527e057f15efe755e10694eb2bc", + "reference": "2f7c83780bbcf527e057f15efe755e10694eb2bc", + "shasum": "" + }, + "require": { + "php": ">=5.4.0", + "pimple/pimple": "~3.0", + "symfony/event-dispatcher": ">2.5", + "symfony/yaml": ">2.5" + }, + "require-dev": { + "phpunit/phpunit": "~5.1.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "RocketTheme\\Toolbox\\ArrayTraits\\": "ArrayTraits/src", + "RocketTheme\\Toolbox\\Blueprints\\": "Blueprints/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": "2017-09-23T13:39:25+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": "v2.8.27", + "source": { + "type": "git", + "url": "https://github.com/symfony/console.git", + "reference": "c0807a2ca978e64d8945d373a9221a5c35d1a253" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/console/zipball/c0807a2ca978e64d8945d373a9221a5c35d1a253", + "reference": "c0807a2ca978e64d8945d373a9221a5c35d1a253", + "shasum": "" + }, + "require": { + "php": ">=5.3.9", + "symfony/debug": "^2.7.2|~3.0.0", + "symfony/polyfill-mbstring": "~1.0" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/event-dispatcher": "~2.1|~3.0.0", + "symfony/process": "~2.1|~3.0.0" + }, + "suggest": { + "psr/log": "For using the console logger", + "symfony/event-dispatcher": "", + "symfony/process": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.8-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": "2017-08-27T14:29:03+00:00" + }, + { + "name": "symfony/debug", + "version": "v3.0.9", + "source": { + "type": "git", + "url": "https://github.com/symfony/debug.git", + "reference": "697c527acd9ea1b2d3efac34d9806bf255278b0a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/debug/zipball/697c527acd9ea1b2d3efac34d9806bf255278b0a", + "reference": "697c527acd9ea1b2d3efac34d9806bf255278b0a", + "shasum": "" + }, + "require": { + "php": ">=5.5.9", + "psr/log": "~1.0" + }, + "conflict": { + "symfony/http-kernel": ">=2.3,<2.3.24|~2.4.0|>=2.5,<2.5.9|>=2.6,<2.6.2" + }, + "require-dev": { + "symfony/class-loader": "~2.8|~3.0", + "symfony/http-kernel": "~2.8|~3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Debug\\": "" + }, + "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 Debug Component", + "homepage": "https://symfony.com", + "time": "2016-07-30T07:22:48+00:00" + }, + { + "name": "symfony/event-dispatcher", + "version": "v2.8.27", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher.git", + "reference": "1377400fd641d7d1935981546aaef780ecd5bf6d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/1377400fd641d7d1935981546aaef780ecd5bf6d", + "reference": "1377400fd641d7d1935981546aaef780ecd5bf6d", + "shasum": "" + }, + "require": { + "php": ">=5.3.9" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/config": "^2.0.5|~3.0.0", + "symfony/dependency-injection": "~2.6|~3.0.0", + "symfony/expression-language": "~2.6|~3.0.0", + "symfony/stopwatch": "~2.3|~3.0.0" + }, + "suggest": { + "symfony/dependency-injection": "", + "symfony/http-kernel": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.8-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": "2017-06-02T07:47:27+00:00" + }, + { + "name": "symfony/polyfill-iconv", + "version": "v1.5.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-iconv.git", + "reference": "1ea0e08453819ecc7130e1fb0ee10862c2f33ed0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/1ea0e08453819ecc7130e1fb0ee10862c2f33ed0", + "reference": "1ea0e08453819ecc7130e1fb0ee10862c2f33ed0", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "suggest": { + "ext-iconv": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.5-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": "2017-06-14T15:44:48+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.5.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "7c8fae0ac1d216eb54349e6a8baa57d515fe8803" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/7c8fae0ac1d216eb54349e6a8baa57d515fe8803", + "reference": "7c8fae0ac1d216eb54349e6a8baa57d515fe8803", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.5-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": "2017-06-14T15:44:48+00:00" + }, + { + "name": "symfony/var-dumper", + "version": "v2.8.27", + "source": { + "type": "git", + "url": "https://github.com/symfony/var-dumper.git", + "reference": "83ebf3e92c0b2231fa63b8e584a2a3d3cd9876ef" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/83ebf3e92c0b2231fa63b8e584a2a3d3cd9876ef", + "reference": "83ebf3e92c0b2231fa63b8e584a2a3d3cd9876ef", + "shasum": "" + }, + "require": { + "php": ">=5.3.9", + "symfony/polyfill-mbstring": "~1.0" + }, + "conflict": { + "phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0" + }, + "require-dev": { + "ext-iconv": "*", + "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-symfony_debug": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.8-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": "2017-08-27T14:29:03+00:00" + }, + { + "name": "symfony/yaml", + "version": "v2.8.27", + "source": { + "type": "git", + "url": "https://github.com/symfony/yaml.git", + "reference": "4c29dec8d489c4e37cf87ccd7166cd0b0e6a45c5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/yaml/zipball/4c29dec8d489c4e37cf87ccd7166cd0b0e6a45c5", + "reference": "4c29dec8d489c4e37cf87ccd7166cd0b0e6a45c5", + "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-06-01T20:52:29+00:00" + }, + { + "name": "twig/twig", + "version": "v1.35.0", + "source": { + "type": "git", + "url": "https://github.com/twigphp/Twig.git", + "reference": "daa657073e55b0a78cce8fdd22682fddecc6385f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/daa657073e55b0a78cce8fdd22682fddecc6385f", + "reference": "daa657073e55b0a78cce8fdd22682fddecc6385f", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "psr/container": "^1.0", + "symfony/debug": "~2.7", + "symfony/phpunit-bridge": "~3.3@dev" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.35-dev" + } + }, + "autoload": { + "psr-0": { + "Twig_": "lib/" + }, + "psr-4": { + "Twig\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com", + "homepage": "http://fabien.potencier.org", + "role": "Lead Developer" + }, + { + "name": "Armin Ronacher", + "email": "armin.ronacher@active-4.com", + "role": "Project Founder" + }, + { + "name": "Twig Team", + "homepage": "http://twig.sensiolabs.org/contributors", + "role": "Contributors" + } + ], + "description": "Twig, the flexible, fast, and secure template language for PHP", + "homepage": "http://twig.sensiolabs.org", + "keywords": [ + "templating" + ], + "time": "2017-09-27T18:06:46+00:00" + } + ], + "packages-dev": [ + { + "name": "behat/gherkin", + "version": "v4.4.5", + "source": { + "type": "git", + "url": "https://github.com/Behat/Gherkin.git", + "reference": "5c14cff4f955b17d20d088dec1bde61c0539ec74" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Behat/Gherkin/zipball/5c14cff4f955b17d20d088dec1bde61c0539ec74", + "reference": "5c14cff4f955b17d20d088dec1bde61c0539ec74", + "shasum": "" + }, + "require": { + "php": ">=5.3.1" + }, + "require-dev": { + "phpunit/phpunit": "~4.5|~5", + "symfony/phpunit-bridge": "~2.7|~3", + "symfony/yaml": "~2.3|~3" + }, + "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": "2016-10-30T11:50:56+00:00" + }, + { + "name": "codeception/codeception", + "version": "2.3.5", + "source": { + "type": "git", + "url": "https://github.com/Codeception/Codeception.git", + "reference": "e807cd458eb9f7ae7464f33ad835a2f54aa73194" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Codeception/Codeception/zipball/e807cd458eb9f7ae7464f33ad835a2f54aa73194", + "reference": "e807cd458eb9f7ae7464f33ad835a2f54aa73194", + "shasum": "" + }, + "require": { + "behat/gherkin": "~4.4.0", + "ext-json": "*", + "ext-mbstring": "*", + "facebook/webdriver": ">=1.1.3 <2.0", + "guzzlehttp/guzzle": ">=4.1.4 <7.0", + "guzzlehttp/psr7": "~1.0", + "php": ">=5.4.0 <8.0", + "phpunit/php-code-coverage": ">=2.2.4 <6.0", + "phpunit/phpunit": ">4.8.20 <7.0", + "phpunit/phpunit-mock-objects": ">2.3 <5.0", + "sebastian/comparator": ">1.1 <3.0", + "sebastian/diff": "^1.4", + "stecman/symfony-console-completion": "^0.7.0", + "symfony/browser-kit": ">=2.7 <4.0", + "symfony/console": ">=2.7 <4.0", + "symfony/css-selector": ">=2.7 <4.0", + "symfony/dom-crawler": ">=2.7.5 <4.0", + "symfony/event-dispatcher": ">=2.7 <4.0", + "symfony/finder": ">=2.7 <4.0", + "symfony/yaml": ">=2.7 <4.0" + }, + "require-dev": { + "codeception/specify": "~0.3", + "facebook/graph-sdk": "~5.3", + "flow/jsonpath": "~0.2", + "league/factory-muffin": "^3.0", + "league/factory-muffin-faker": "^1.0", + "mongodb/mongodb": "^1.0", + "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 <4.0", + "vlucas/phpdotenv": "^2.4.0" + }, + "suggest": { + "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", + "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": "2017-08-10T20:28:02+00:00" + }, + { + "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": "facebook/webdriver", + "version": "1.4.1", + "source": { + "type": "git", + "url": "https://github.com/facebook/php-webdriver.git", + "reference": "eadb0b7a7c3e6578185197fd40158b08c3164c83" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/facebook/php-webdriver/zipball/eadb0b7a7c3e6578185197fd40158b08c3164c83", + "reference": "eadb0b7a7c3e6578185197fd40158b08c3164c83", + "shasum": "" + }, + "require": { + "ext-curl": "*", + "ext-zip": "*", + "php": "^5.5 || ~7.0", + "symfony/process": "^2.8 || ^3.1" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^2.0", + "php-mock/php-mock-phpunit": "^1.1", + "phpunit/phpunit": "4.6.* || ~5.0", + "satooshi/php-coveralls": "^1.0", + "squizlabs/php_codesniffer": "^2.6" + }, + "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": "2017-04-28T14:54:49+00:00" + }, + { + "name": "fzaninotto/faker", + "version": "v1.7.1", + "source": { + "type": "git", + "url": "https://github.com/fzaninotto/Faker.git", + "reference": "d3ed4cc37051c1ca52d22d76b437d14809fc7e0d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/fzaninotto/Faker/zipball/d3ed4cc37051c1ca52d22d76b437d14809fc7e0d", + "reference": "d3ed4cc37051c1ca52d22d76b437d14809fc7e0d", + "shasum": "" + }, + "require": { + "php": "^5.3.3 || ^7.0" + }, + "require-dev": { + "ext-intl": "*", + "phpunit/phpunit": "^4.0 || ^5.0", + "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": "2017-08-15T16:48:10+00:00" + }, + { + "name": "guzzlehttp/guzzle", + "version": "6.3.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle.git", + "reference": "f4db5a78a5ea468d4831de7f0bf9d9415e348699" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/f4db5a78a5ea468d4831de7f0bf9d9415e348699", + "reference": "f4db5a78a5ea468d4831de7f0bf9d9415e348699", + "shasum": "" + }, + "require": { + "guzzlehttp/promises": "^1.0", + "guzzlehttp/psr7": "^1.4", + "php": ">=5.5" + }, + "require-dev": { + "ext-curl": "*", + "phpunit/phpunit": "^4.0 || ^5.0", + "psr/log": "^1.0" + }, + "suggest": { + "psr/log": "Required for using the Log middleware" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "6.2-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": "2017-06-22T18:50:49+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": "guzzlehttp/psr7", + "version": "1.4.2", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "f5b8a8512e2b58b0071a7280e39f14f72e05d87c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/f5b8a8512e2b58b0071a7280e39f14f72e05d87c", + "reference": "f5b8a8512e2b58b0071a7280e39f14f72e05d87c", + "shasum": "" + }, + "require": { + "php": ">=5.4.0", + "psr/http-message": "~1.0" + }, + "provide": { + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-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", + "request", + "response", + "stream", + "uri", + "url" + ], + "time": "2017-03-20T17:10:46+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": "3.2.2", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", + "reference": "4aada1f93c72c35e22fb1383b47fee43b8f1d157" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/4aada1f93c72c35e22fb1383b47fee43b8f1d157", + "reference": "4aada1f93c72c35e22fb1383b47fee43b8f1d157", + "shasum": "" + }, + "require": { + "php": ">=5.5", + "phpdocumentor/reflection-common": "^1.0@dev", + "phpdocumentor/type-resolver": "^0.3.0", + "webmozart/assert": "^1.0" + }, + "require-dev": { + "mockery/mockery": "^0.9.4", + "phpunit/phpunit": "^4.4" + }, + "type": "library", + "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": "2017-08-08T06:39:58+00:00" + }, + { + "name": "phpdocumentor/type-resolver", + "version": "0.3.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/TypeResolver.git", + "reference": "fb3933512008d8162b3cdf9e18dba9309b7c3773" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/fb3933512008d8162b3cdf9e18dba9309b7c3773", + "reference": "fb3933512008d8162b3cdf9e18dba9309b7c3773", + "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-06-03T08:32:36+00:00" + }, + { + "name": "phpspec/prophecy", + "version": "v1.7.2", + "source": { + "type": "git", + "url": "https://github.com/phpspec/prophecy.git", + "reference": "c9b8c6088acd19d769d4cc0ffa60a9fe34344bd6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/c9b8c6088acd19d769d4cc0ffa60a9fe34344bd6", + "reference": "c9b8c6088acd19d769d4cc0ffa60a9fe34344bd6", + "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", + "sebastian/recursion-context": "^1.0|^2.0|^3.0" + }, + "require-dev": { + "phpspec/phpspec": "^2.5|^3.2", + "phpunit/phpunit": "^4.8 || ^5.6.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.7.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": "2017-09-04T11:05:03+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.9", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", + "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", + "shasum": "" + }, + "require": { + "php": "^5.3.3 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" + }, + "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": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "time": "2017-02-26T11:10:40+00:00" + }, + { + "name": "phpunit/php-token-stream", + "version": "1.4.11", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-token-stream.git", + "reference": "e03f8f67534427a787e21a385a67ec3ca6978ea7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/e03f8f67534427a787e21a385a67ec3ca6978ea7", + "reference": "e03f8f67534427a787e21a385a67ec3ca6978ea7", + "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": "2017-02-27T10:12:30+00:00" + }, + { + "name": "phpunit/phpunit", + "version": "4.8.36", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "46023de9a91eec7dfb06cc56cb4e260017298517" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/46023de9a91eec7dfb06cc56cb4e260017298517", + "reference": "46023de9a91eec7dfb06cc56cb4e260017298517", + "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-06-21T08:07:12+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": "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": "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.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "7f066a26a962dbe58ddea9f72a4e82874a3975a4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/7f066a26a962dbe58ddea9f72a4e82874a3975a4", + "reference": "7f066a26a962dbe58ddea9f72a4e82874a3975a4", + "shasum": "" + }, + "require": { + "php": "^5.3.3 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" + }, + "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": "2017-05-22T07:24:03+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.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "b19cc3298482a335a95f3016d2f8a6950f0fbcd7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/b19cc3298482a335a95f3016d2f8a6950f0fbcd7", + "reference": "b19cc3298482a335a95f3016d2f8a6950f0fbcd7", + "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": "2016-10-03T07:41:43+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": "stecman/symfony-console-completion", + "version": "0.7.0", + "source": { + "type": "git", + "url": "https://github.com/stecman/symfony-console-completion.git", + "reference": "5461d43e53092b3d3b9dbd9d999f2054730f4bbb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/stecman/symfony-console-completion/zipball/5461d43e53092b3d3b9dbd9d999f2054730f4bbb", + "reference": "5461d43e53092b3d3b9dbd9d999f2054730f4bbb", + "shasum": "" + }, + "require": { + "php": ">=5.3.2", + "symfony/console": "~2.3 || ~3.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "0.6.x-dev" + } + }, + "autoload": { + "psr-4": { + "Stecman\\Component\\Symfony\\Console\\BashCompletion\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Stephen Holdaway", + "email": "stephen@stecman.co.nz" + } + ], + "description": "Automatic BASH completion for Symfony Console Component based applications.", + "time": "2016-02-24T05:08:54+00:00" + }, + { + "name": "symfony/browser-kit", + "version": "v3.3.9", + "source": { + "type": "git", + "url": "https://github.com/symfony/browser-kit.git", + "reference": "aee7120b058c268363e606ff5fe8271da849a1b5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/browser-kit/zipball/aee7120b058c268363e606ff5fe8271da849a1b5", + "reference": "aee7120b058c268363e606ff5fe8271da849a1b5", + "shasum": "" + }, + "require": { + "php": "^5.5.9|>=7.0.8", + "symfony/dom-crawler": "~2.8|~3.0" + }, + "require-dev": { + "symfony/css-selector": "~2.8|~3.0", + "symfony/process": "~2.8|~3.0" + }, + "suggest": { + "symfony/process": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.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": "2017-07-29T21:54:42+00:00" + }, + { + "name": "symfony/css-selector", + "version": "v3.3.9", + "source": { + "type": "git", + "url": "https://github.com/symfony/css-selector.git", + "reference": "c5f5263ed231f164c58368efbce959137c7d9488" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/c5f5263ed231f164c58368efbce959137c7d9488", + "reference": "c5f5263ed231f164c58368efbce959137c7d9488", + "shasum": "" + }, + "require": { + "php": "^5.5.9|>=7.0.8" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.3-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\CssSelector\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jean-François Simon", + "email": "jeanfrancois.simon@sensiolabs.com" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony CssSelector Component", + "homepage": "https://symfony.com", + "time": "2017-07-29T21:54:42+00:00" + }, + { + "name": "symfony/dom-crawler", + "version": "v3.3.9", + "source": { + "type": "git", + "url": "https://github.com/symfony/dom-crawler.git", + "reference": "6b511d7329b203a620f09a2288818d27dcc915ae" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/6b511d7329b203a620f09a2288818d27dcc915ae", + "reference": "6b511d7329b203a620f09a2288818d27dcc915ae", + "shasum": "" + }, + "require": { + "php": "^5.5.9|>=7.0.8", + "symfony/polyfill-mbstring": "~1.0" + }, + "require-dev": { + "symfony/css-selector": "~2.8|~3.0" + }, + "suggest": { + "symfony/css-selector": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.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": "2017-09-11T15:55:22+00:00" + }, + { + "name": "symfony/finder", + "version": "v3.3.9", + "source": { + "type": "git", + "url": "https://github.com/symfony/finder.git", + "reference": "b2260dbc80f3c4198f903215f91a1ac7fe9fe09e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/finder/zipball/b2260dbc80f3c4198f903215f91a1ac7fe9fe09e", + "reference": "b2260dbc80f3c4198f903215f91a1ac7fe9fe09e", + "shasum": "" + }, + "require": { + "php": "^5.5.9|>=7.0.8" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.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": "2017-07-29T21:54:42+00:00" + }, + { + "name": "symfony/process", + "version": "v3.3.9", + "source": { + "type": "git", + "url": "https://github.com/symfony/process.git", + "reference": "b7666e9b438027a1ea0e1ee813ec5042d5d7f6f0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/process/zipball/b7666e9b438027a1ea0e1ee813ec5042d5d7f6f0", + "reference": "b7666e9b438027a1ea0e1ee813ec5042d5d7f6f0", + "shasum": "" + }, + "require": { + "php": "^5.5.9|>=7.0.8" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.3-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": "2017-07-29T21:54:42+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.2.0", + "source": { + "type": "git", + "url": "https://github.com/webmozart/assert.git", + "reference": "2db61e59ff05fe5126d152bd0655c9ea113e550f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozart/assert/zipball/2db61e59ff05fe5126d152bd0655c9ea113e550f", + "reference": "2db61e59ff05fe5126d152bd0655c9ea113e550f", + "shasum": "" + }, + "require": { + "php": "^5.3.3 || ^7.0" + }, + "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": "2016-11-23T20:04:58+00:00" + } + ], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": { + "victorjonsson/markdowndocs": 20 + }, + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "php": ">=5.5.9", + "ext-mbstring": "*", + "ext-openssl": "*", + "ext-curl": "*", + "ext-zip": "*" + }, + "platform-dev": [] +} diff --git a/images/.gitkeep b/images/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/images/0/1/3/0/3/01303267ac266a0a30f67dd9180150be56cb6c53-spinozapp006.jpeg b/images/0/1/3/0/3/01303267ac266a0a30f67dd9180150be56cb6c53-spinozapp006.jpeg new file mode 100644 index 0000000..5e4c4d2 Binary files /dev/null and b/images/0/1/3/0/3/01303267ac266a0a30f67dd9180150be56cb6c53-spinozapp006.jpeg differ diff --git a/images/0/3/e/0/a/03e0ad16d752611274eee99c70fc6ea56d7db379-a2010connexions.jpeg b/images/0/3/e/0/a/03e0ad16d752611274eee99c70fc6ea56d7db379-a2010connexions.jpeg new file mode 100644 index 0000000..7ac902c Binary files /dev/null and b/images/0/3/e/0/a/03e0ad16d752611274eee99c70fc6ea56d7db379-a2010connexions.jpeg differ diff --git a/images/0/5/3/3/6/05336aa5a2541097a4695a04b49473279c90d8b6-d2013marse12345alllinksethicamodif.jpeg b/images/0/5/3/3/6/05336aa5a2541097a4695a04b49473279c90d8b6-d2013marse12345alllinksethicamodif.jpeg new file mode 100644 index 0000000..d5f64ee Binary files /dev/null and b/images/0/5/3/3/6/05336aa5a2541097a4695a04b49473279c90d8b6-d2013marse12345alllinksethicamodif.jpeg differ diff --git a/images/0/5/3/3/6/05336aa5a2541097a4695a04b49473279c90d8b6-d2013marse12345alllinksethicamodif.jpeg.xmp b/images/0/5/3/3/6/05336aa5a2541097a4695a04b49473279c90d8b6-d2013marse12345alllinksethicamodif.jpeg.xmp new file mode 100644 index 0000000..f9f32f3 --- /dev/null +++ b/images/0/5/3/3/6/05336aa5a2541097a4695a04b49473279c90d8b6-d2013marse12345alllinksethicamodif.jpeg.xmp @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/images/0/5/a/5/9/05a59c372ee7643d4219f88596c71da239b3c327-e1p17-cor2a.jpeg b/images/0/5/a/5/9/05a59c372ee7643d4219f88596c71da239b3c327-e1p17-cor2a.jpeg new file mode 100644 index 0000000..f727d84 Binary files /dev/null and b/images/0/5/a/5/9/05a59c372ee7643d4219f88596c71da239b3c327-e1p17-cor2a.jpeg differ diff --git a/images/0/9/d/7/f/09d7fc0d95cc230216fd1f3ddc9746ac3bb0c5d1-01-logoscam.jpeg b/images/0/9/d/7/f/09d7fc0d95cc230216fd1f3ddc9746ac3bb0c5d1-01-logoscam.jpeg new file mode 100644 index 0000000..a611eef Binary files /dev/null and b/images/0/9/d/7/f/09d7fc0d95cc230216fd1f3ddc9746ac3bb0c5d1-01-logoscam.jpeg differ diff --git a/images/0/a/4/e/8/0a4e8aee9bb4e29708a30644ac5566400bd136dd-notedessinehd.jpeg b/images/0/a/4/e/8/0a4e8aee9bb4e29708a30644ac5566400bd136dd-notedessinehd.jpeg new file mode 100644 index 0000000..682413b Binary files /dev/null and b/images/0/a/4/e/8/0a4e8aee9bb4e29708a30644ac5566400bd136dd-notedessinehd.jpeg differ diff --git a/images/0/b/1/e/8/0b1e89b9c731fc3ee31fc057680c3aa810d229eb-11-logo2015.jpeg b/images/0/b/1/e/8/0b1e89b9c731fc3ee31fc057680c3aa810d229eb-11-logo2015.jpeg new file mode 100644 index 0000000..b7abeb5 Binary files /dev/null and b/images/0/b/1/e/8/0b1e89b9c731fc3ee31fc057680c3aa810d229eb-11-logo2015.jpeg differ diff --git a/images/0/c/b/b/0/0cbb0f0970d2caf5006d6fec7379d32b2a01d2db-alibertedepenser003.jpeg b/images/0/c/b/b/0/0cbb0f0970d2caf5006d6fec7379d32b2a01d2db-alibertedepenser003.jpeg new file mode 100644 index 0000000..9fd1c2d Binary files /dev/null and b/images/0/c/b/b/0/0cbb0f0970d2caf5006d6fec7379d32b2a01d2db-alibertedepenser003.jpeg differ diff --git a/images/0/d/8/5/e/0d85efbb39ab9bf4ddb00253f86dcb56106866a1-spinoza10.jpeg b/images/0/d/8/5/e/0d85efbb39ab9bf4ddb00253f86dcb56106866a1-spinoza10.jpeg new file mode 100644 index 0000000..21f10cc Binary files /dev/null and b/images/0/d/8/5/e/0d85efbb39ab9bf4ddb00253f86dcb56106866a1-spinoza10.jpeg differ diff --git a/images/0/e/0/8/1/0e0813567a992242e475b3ffcf3ca60b824b3fa8-nuit03.jpeg b/images/0/e/0/8/1/0e0813567a992242e475b3ffcf3ca60b824b3fa8-nuit03.jpeg new file mode 100644 index 0000000..e0609db Binary files /dev/null and b/images/0/e/0/8/1/0e0813567a992242e475b3ffcf3ca60b824b3fa8-nuit03.jpeg differ diff --git a/images/1/0/7/9/5/107955b88be6eb65752eb3151937aa3165cea0c2-dalli01.jpeg b/images/1/0/7/9/5/107955b88be6eb65752eb3151937aa3165cea0c2-dalli01.jpeg new file mode 100644 index 0000000..de7c004 Binary files /dev/null and b/images/1/0/7/9/5/107955b88be6eb65752eb3151937aa3165cea0c2-dalli01.jpeg differ diff --git a/images/1/2/f/b/e/12fbee37c40c19951c964f601e92e9bdeb9e2a62-e1def1.jpeg b/images/1/2/f/b/e/12fbee37c40c19951c964f601e92e9bdeb9e2a62-e1def1.jpeg new file mode 100644 index 0000000..7526347 Binary files /dev/null and b/images/1/2/f/b/e/12fbee37c40c19951c964f601e92e9bdeb9e2a62-e1def1.jpeg differ diff --git a/images/1/6/a/5/c/16a5c982bac05d26d82384d91c1d048f0ddc838a-e1p17-cor2a.jpeg b/images/1/6/a/5/c/16a5c982bac05d26d82384d91c1d048f0ddc838a-e1p17-cor2a.jpeg new file mode 100644 index 0000000..f727d84 Binary files /dev/null and b/images/1/6/a/5/c/16a5c982bac05d26d82384d91c1d048f0ddc838a-e1p17-cor2a.jpeg differ diff --git a/images/1/7/0/9/c/1709cbbf93ce7e24c3569233a4d501c86abe48f1-f1e1d1.jpeg b/images/1/7/0/9/c/1709cbbf93ce7e24c3569233a4d501c86abe48f1-f1e1d1.jpeg new file mode 100644 index 0000000..d70dd4f Binary files /dev/null and b/images/1/7/0/9/c/1709cbbf93ce7e24c3569233a4d501c86abe48f1-f1e1d1.jpeg differ diff --git a/images/1/d/1/7/c/1d17c4c10513a2ece3ea1455d0cc113934ed4bed-d2013marse12345alllinksethicamodif.jpeg b/images/1/d/1/7/c/1d17c4c10513a2ece3ea1455d0cc113934ed4bed-d2013marse12345alllinksethicamodif.jpeg new file mode 100644 index 0000000..d5f64ee Binary files /dev/null and b/images/1/d/1/7/c/1d17c4c10513a2ece3ea1455d0cc113934ed4bed-d2013marse12345alllinksethicamodif.jpeg differ diff --git a/images/1/d/2/5/a/1d25aeef99d8a551404f85d6987703b281dd6b86-00-matrice-logo.png b/images/1/d/2/5/a/1d25aeef99d8a551404f85d6987703b281dd6b86-00-matrice-logo.png new file mode 100644 index 0000000..1594ece Binary files /dev/null and b/images/1/d/2/5/a/1d25aeef99d8a551404f85d6987703b281dd6b86-00-matrice-logo.png differ diff --git a/images/1/f/e/e/4/1fee4b4459896f6cc2636747703a2e241bcb8fde-e1d103.jpeg b/images/1/f/e/e/4/1fee4b4459896f6cc2636747703a2e241bcb8fde-e1d103.jpeg new file mode 100644 index 0000000..7dc0519 Binary files /dev/null and b/images/1/f/e/e/4/1fee4b4459896f6cc2636747703a2e241bcb8fde-e1d103.jpeg differ diff --git a/images/2/2/1/1/b/2211b32a59296e4fd09ad1f052672be3bd98fbb1-spinoza08.jpeg b/images/2/2/1/1/b/2211b32a59296e4fd09ad1f052672be3bd98fbb1-spinoza08.jpeg new file mode 100644 index 0000000..dded06c Binary files /dev/null and b/images/2/2/1/1/b/2211b32a59296e4fd09ad1f052672be3bd98fbb1-spinoza08.jpeg differ diff --git a/images/2/2/1/a/e/221ae8390225c4ae278aed465b5cd2562b97e566-commentairephilosophe.jpeg b/images/2/2/1/a/e/221ae8390225c4ae278aed465b5cd2562b97e566-commentairephilosophe.jpeg new file mode 100644 index 0000000..d8658aa Binary files /dev/null and b/images/2/2/1/a/e/221ae8390225c4ae278aed465b5cd2562b97e566-commentairephilosophe.jpeg differ diff --git a/images/2/8/f/1/c/28f1ca264dc1014b0c2ad7a0bd88cceece08f6cb-10-tygryzemail.jpeg b/images/2/8/f/1/c/28f1ca264dc1014b0c2ad7a0bd88cceece08f6cb-10-tygryzemail.jpeg new file mode 100644 index 0000000..c68b1c0 Binary files /dev/null and b/images/2/8/f/1/c/28f1ca264dc1014b0c2ad7a0bd88cceece08f6cb-10-tygryzemail.jpeg differ diff --git a/images/2/9/2/3/3/2923399d82ed90a99d6197caf0774fa372c382b0-spinoza01.jpeg b/images/2/9/2/3/3/2923399d82ed90a99d6197caf0774fa372c382b0-spinoza01.jpeg new file mode 100644 index 0000000..7e1089d Binary files /dev/null and b/images/2/9/2/3/3/2923399d82ed90a99d6197caf0774fa372c382b0-spinoza01.jpeg differ diff --git a/images/2/9/d/4/d/29d4d50056b0277236f5403663287c0ddb0fe99f-libertedepenser003.jpeg b/images/2/9/d/4/d/29d4d50056b0277236f5403663287c0ddb0fe99f-libertedepenser003.jpeg new file mode 100644 index 0000000..cdfa9b2 Binary files /dev/null and b/images/2/9/d/4/d/29d4d50056b0277236f5403663287c0ddb0fe99f-libertedepenser003.jpeg differ diff --git a/images/2/a/0/e/a/2a0eae90e11647fb792266429fe6f05c651ab680-mga4415.jpeg b/images/2/a/0/e/a/2a0eae90e11647fb792266429fe6f05c651ab680-mga4415.jpeg new file mode 100644 index 0000000..3232485 Binary files /dev/null and b/images/2/a/0/e/a/2a0eae90e11647fb792266429fe6f05c651ab680-mga4415.jpeg differ diff --git a/images/2/c/2/0/6/2c206bb8d4c4bce512e8cec4467b7a5e33b17b3f-spinoza05.jpeg b/images/2/c/2/0/6/2c206bb8d4c4bce512e8cec4467b7a5e33b17b3f-spinoza05.jpeg new file mode 100644 index 0000000..3934313 Binary files /dev/null and b/images/2/c/2/0/6/2c206bb8d4c4bce512e8cec4467b7a5e33b17b3f-spinoza05.jpeg differ diff --git a/images/2/c/7/6/3/2c763fab532c10d510060d5e657e59ede4ac13d8-f1e1d1.jpeg b/images/2/c/7/6/3/2c763fab532c10d510060d5e657e59ede4ac13d8-f1e1d1.jpeg new file mode 100644 index 0000000..d70dd4f Binary files /dev/null and b/images/2/c/7/6/3/2c763fab532c10d510060d5e657e59ede4ac13d8-f1e1d1.jpeg differ diff --git a/images/2/f/b/3/f/2fb3fa552f7322c1366196edb177ab0a3f95d4a3-spinoza06.jpeg b/images/2/f/b/3/f/2fb3fa552f7322c1366196edb177ab0a3f95d4a3-spinoza06.jpeg new file mode 100644 index 0000000..d2a754b Binary files /dev/null and b/images/2/f/b/3/f/2fb3fa552f7322c1366196edb177ab0a3f95d4a3-spinoza06.jpeg differ diff --git a/images/3/5/3/9/0/35390873e103ce16babf9bb93812a2092ff3127d-thumb-mp4.png b/images/3/5/3/9/0/35390873e103ce16babf9bb93812a2092ff3127d-thumb-mp4.png new file mode 100644 index 0000000..5a7db8b Binary files /dev/null and b/images/3/5/3/9/0/35390873e103ce16babf9bb93812a2092ff3127d-thumb-mp4.png differ diff --git a/images/3/8/b/f/1/38bf12131f19f9ee9084516aa899325e5b300ab5-logoeu.png b/images/3/8/b/f/1/38bf12131f19f9ee9084516aa899325e5b300ab5-logoeu.png new file mode 100644 index 0000000..f48d61f Binary files /dev/null and b/images/3/8/b/f/1/38bf12131f19f9ee9084516aa899325e5b300ab5-logoeu.png differ diff --git a/images/3/d/3/5/5/3d3555099ea4cf73084acf186280b71f1f2193c8-spinozapp007.jpeg b/images/3/d/3/5/5/3d3555099ea4cf73084acf186280b71f1f2193c8-spinozapp007.jpeg new file mode 100644 index 0000000..44ba619 Binary files /dev/null and b/images/3/d/3/5/5/3d3555099ea4cf73084acf186280b71f1f2193c8-spinozapp007.jpeg differ diff --git a/images/3/f/a/3/9/3fa3917ff0741e59cf4714764f6c40bfa596fa6e-2013trajectoire02.jpeg b/images/3/f/a/3/9/3fa3917ff0741e59cf4714764f6c40bfa596fa6e-2013trajectoire02.jpeg new file mode 100644 index 0000000..4f8c635 Binary files /dev/null and b/images/3/f/a/3/9/3fa3917ff0741e59cf4714764f6c40bfa596fa6e-2013trajectoire02.jpeg differ diff --git a/images/4/4/2/4/1/44241e7b165ab0894c3b86f609a1e9c052dc2a06-2011proj5.jpeg b/images/4/4/2/4/1/44241e7b165ab0894c3b86f609a1e9c052dc2a06-2011proj5.jpeg new file mode 100644 index 0000000..ec6a04e Binary files /dev/null and b/images/4/4/2/4/1/44241e7b165ab0894c3b86f609a1e9c052dc2a06-2011proj5.jpeg differ diff --git a/images/4/a/c/6/5/4ac6509e3fc577450fd0f4912782520fcefddffc-mga4241.jpeg b/images/4/a/c/6/5/4ac6509e3fc577450fd0f4912782520fcefddffc-mga4241.jpeg new file mode 100644 index 0000000..94c22cd Binary files /dev/null and b/images/4/a/c/6/5/4ac6509e3fc577450fd0f4912782520fcefddffc-mga4241.jpeg differ diff --git a/images/4/f/2/a/1/4f2a1c58267d8fd8840855fc62e21eded8c9dec0-e2015ethique01modif.jpeg b/images/4/f/2/a/1/4f2a1c58267d8fd8840855fc62e21eded8c9dec0-e2015ethique01modif.jpeg new file mode 100644 index 0000000..61cadda Binary files /dev/null and b/images/4/f/2/a/1/4f2a1c58267d8fd8840855fc62e21eded8c9dec0-e2015ethique01modif.jpeg differ diff --git a/images/5/1/3/7/3/513735fa4bd3738092d0b04c8e9a5a5fbc79966b-spinoza04.jpeg b/images/5/1/3/7/3/513735fa4bd3738092d0b04c8e9a5a5fbc79966b-spinoza04.jpeg new file mode 100644 index 0000000..861b91c Binary files /dev/null and b/images/5/1/3/7/3/513735fa4bd3738092d0b04c8e9a5a5fbc79966b-spinoza04.jpeg differ diff --git a/images/5/5/c/b/2/55cb2ba910c40c1b1a03f473b694210988cf7df4-00-matrice-logo.png b/images/5/5/c/b/2/55cb2ba910c40c1b1a03f473b694210988cf7df4-00-matrice-logo.png new file mode 100644 index 0000000..1594ece Binary files /dev/null and b/images/5/5/c/b/2/55cb2ba910c40c1b1a03f473b694210988cf7df4-00-matrice-logo.png differ diff --git a/images/5/6/a/7/b/56a7bfd884b07f62fa783774438dbacc53948cdc-spinoza01.jpeg b/images/5/6/a/7/b/56a7bfd884b07f62fa783774438dbacc53948cdc-spinoza01.jpeg new file mode 100644 index 0000000..9037ffa Binary files /dev/null and b/images/5/6/a/7/b/56a7bfd884b07f62fa783774438dbacc53948cdc-spinoza01.jpeg differ diff --git a/images/5/c/5/c/9/5c5c939b4e7a7f8356b425b99ccf7f3f34175a46-thumb-mp3.png b/images/5/c/5/c/9/5c5c939b4e7a7f8356b425b99ccf7f3f34175a46-thumb-mp3.png new file mode 100644 index 0000000..02e2f07 Binary files /dev/null and b/images/5/c/5/c/9/5c5c939b4e7a7f8356b425b99ccf7f3f34175a46-thumb-mp3.png differ diff --git a/images/5/f/d/7/d/5fd7de27225a28392a84b1251011dd928f8f101d-spinoza03.jpeg b/images/5/f/d/7/d/5fd7de27225a28392a84b1251011dd928f8f101d-spinoza03.jpeg new file mode 100644 index 0000000..b59f65b Binary files /dev/null and b/images/5/f/d/7/d/5fd7de27225a28392a84b1251011dd928f8f101d-spinoza03.jpeg differ diff --git a/images/6/1/2/0/3/61203c35e0e0b2824b067987d77dfb3cbef38a08-libertedepenser004.jpeg b/images/6/1/2/0/3/61203c35e0e0b2824b067987d77dfb3cbef38a08-libertedepenser004.jpeg new file mode 100644 index 0000000..d563da2 Binary files /dev/null and b/images/6/1/2/0/3/61203c35e0e0b2824b067987d77dfb3cbef38a08-libertedepenser004.jpeg differ diff --git a/images/6/2/0/7/8/6207845f92e48d146191c05cb74886517c777aec-spinoza04.jpeg b/images/6/2/0/7/8/6207845f92e48d146191c05cb74886517c777aec-spinoza04.jpeg new file mode 100644 index 0000000..0796608 Binary files /dev/null and b/images/6/2/0/7/8/6207845f92e48d146191c05cb74886517c777aec-spinoza04.jpeg differ diff --git a/images/6/2/1/1/5/621152edd6c936abbdf26ef1fd5b2c5b330d9982-11-logo2015.jpeg b/images/6/2/1/1/5/621152edd6c936abbdf26ef1fd5b2c5b330d9982-11-logo2015.jpeg new file mode 100644 index 0000000..b7abeb5 Binary files /dev/null and b/images/6/2/1/1/5/621152edd6c936abbdf26ef1fd5b2c5b330d9982-11-logo2015.jpeg differ diff --git a/images/6/2/f/2/1/62f219528272836e6f112b7b5e56e6f7d37aae57-logoupjv-bleu.png b/images/6/2/f/2/1/62f219528272836e6f112b7b5e56e6f7d37aae57-logoupjv-bleu.png new file mode 100644 index 0000000..6b4da57 Binary files /dev/null and b/images/6/2/f/2/1/62f219528272836e6f112b7b5e56e6f7d37aae57-logoupjv-bleu.png differ diff --git a/images/6/4/0/b/6/640b61625759723d0739859097160c028a145bdd-libertedepenser002.jpeg b/images/6/4/0/b/6/640b61625759723d0739859097160c028a145bdd-libertedepenser002.jpeg new file mode 100644 index 0000000..c786813 Binary files /dev/null and b/images/6/4/0/b/6/640b61625759723d0739859097160c028a145bdd-libertedepenser002.jpeg differ diff --git a/images/6/5/6/b/9/656b93c2a07e55a9e1cbdaccb0ac0338decebe7d-e1p17-cor2b.jpeg b/images/6/5/6/b/9/656b93c2a07e55a9e1cbdaccb0ac0338decebe7d-e1p17-cor2b.jpeg new file mode 100644 index 0000000..a411811 Binary files /dev/null and b/images/6/5/6/b/9/656b93c2a07e55a9e1cbdaccb0ac0338decebe7d-e1p17-cor2b.jpeg differ diff --git a/images/6/5/8/0/8/658089894a94aa16d5f5f36f7785a45ee8a05cc0-nuittrouble2.jpeg b/images/6/5/8/0/8/658089894a94aa16d5f5f36f7785a45ee8a05cc0-nuittrouble2.jpeg new file mode 100644 index 0000000..b2735e5 Binary files /dev/null and b/images/6/5/8/0/8/658089894a94aa16d5f5f36f7785a45ee8a05cc0-nuittrouble2.jpeg differ diff --git a/images/6/b/5/c/1/6b5c146a49ea12a54385b8d515e607ac9e267de7-spinoza07.jpeg b/images/6/b/5/c/1/6b5c146a49ea12a54385b8d515e607ac9e267de7-spinoza07.jpeg new file mode 100644 index 0000000..156ac05 Binary files /dev/null and b/images/6/b/5/c/1/6b5c146a49ea12a54385b8d515e607ac9e267de7-spinoza07.jpeg differ diff --git a/images/6/d/e/5/f/6de5f47f5e32e8050ce80c354151f969e50ccb7c-cordoba01.jpeg b/images/6/d/e/5/f/6de5f47f5e32e8050ce80c354151f969e50ccb7c-cordoba01.jpeg new file mode 100644 index 0000000..3eabcb7 Binary files /dev/null and b/images/6/d/e/5/f/6de5f47f5e32e8050ce80c354151f969e50ccb7c-cordoba01.jpeg differ diff --git a/images/6/e/6/4/6/6e64697ea1d7ea4747098632af42598f9b5e2d8d-003pourphoto2.jpeg b/images/6/e/6/4/6/6e64697ea1d7ea4747098632af42598f9b5e2d8d-003pourphoto2.jpeg new file mode 100644 index 0000000..a5a79e2 Binary files /dev/null and b/images/6/e/6/4/6/6e64697ea1d7ea4747098632af42598f9b5e2d8d-003pourphoto2.jpeg differ diff --git a/images/6/f/c/f/0/6fcf04999fa9df44853f1cacfa529ed4d0d04b1e-hoteleden.jpeg b/images/6/f/c/f/0/6fcf04999fa9df44853f1cacfa529ed4d0d04b1e-hoteleden.jpeg new file mode 100644 index 0000000..c36cc42 Binary files /dev/null and b/images/6/f/c/f/0/6fcf04999fa9df44853f1cacfa529ed4d0d04b1e-hoteleden.jpeg differ diff --git a/images/7/0/e/5/c/70e5ceb119ea79653006b62a40a78ad5ae379adf-e2014cprpyfavepfontana01modif.jpeg b/images/7/0/e/5/c/70e5ceb119ea79653006b62a40a78ad5ae379adf-e2014cprpyfavepfontana01modif.jpeg new file mode 100644 index 0000000..197127e Binary files /dev/null and b/images/7/0/e/5/c/70e5ceb119ea79653006b62a40a78ad5ae379adf-e2014cprpyfavepfontana01modif.jpeg differ diff --git a/images/7/1/a/4/1/71a41f94b8b9740ee2d8ea9a9b1a1f67044d6b30-nuit03.jpeg b/images/7/1/a/4/1/71a41f94b8b9740ee2d8ea9a9b1a1f67044d6b30-nuit03.jpeg new file mode 100644 index 0000000..e0609db Binary files /dev/null and b/images/7/1/a/4/1/71a41f94b8b9740ee2d8ea9a9b1a1f67044d6b30-nuit03.jpeg differ diff --git a/images/7/9/5/c/4/795c4cbefa68907a06a806f2ba6d001174539ead-e1d103.jpeg b/images/7/9/5/c/4/795c4cbefa68907a06a806f2ba6d001174539ead-e1d103.jpeg new file mode 100644 index 0000000..7dc0519 Binary files /dev/null and b/images/7/9/5/c/4/795c4cbefa68907a06a806f2ba6d001174539ead-e1d103.jpeg differ diff --git a/images/7/a/8/e/c/7a8ec963b04888e955c66964274ec64a53d05a18-ethique01-1detailweb.jpeg b/images/7/a/8/e/c/7a8ec963b04888e955c66964274ec64a53d05a18-ethique01-1detailweb.jpeg new file mode 100644 index 0000000..37a0e46 Binary files /dev/null and b/images/7/a/8/e/c/7a8ec963b04888e955c66964274ec64a53d05a18-ethique01-1detailweb.jpeg differ diff --git a/images/7/d/4/5/b/7d45baba39ce0662851863abb8050a37a4d8f0a3-e2014cprpyfavepfontana01.jpeg b/images/7/d/4/5/b/7d45baba39ce0662851863abb8050a37a4d8f0a3-e2014cprpyfavepfontana01.jpeg new file mode 100644 index 0000000..8375148 Binary files /dev/null and b/images/7/d/4/5/b/7d45baba39ce0662851863abb8050a37a4d8f0a3-e2014cprpyfavepfontana01.jpeg differ diff --git a/images/7/d/8/3/8/7d838a22dd616420d49d4563ea65845c1e050d08-2013trajectoire01.jpeg b/images/7/d/8/3/8/7d838a22dd616420d49d4563ea65845c1e050d08-2013trajectoire01.jpeg new file mode 100644 index 0000000..10d0b34 Binary files /dev/null and b/images/7/d/8/3/8/7d838a22dd616420d49d4563ea65845c1e050d08-2013trajectoire01.jpeg differ diff --git a/images/7/f/9/d/c/7f9dc558d769421ce8721886a4750c1ae2c5138e-spinozapp009.jpeg b/images/7/f/9/d/c/7f9dc558d769421ce8721886a4750c1ae2c5138e-spinozapp009.jpeg new file mode 100644 index 0000000..08dd717 Binary files /dev/null and b/images/7/f/9/d/c/7f9dc558d769421ce8721886a4750c1ae2c5138e-spinozapp009.jpeg differ diff --git a/images/7/f/e/8/d/7fe8d0bc6a00bba3fe03910417fe8438db8a6537-affectslight.jpeg b/images/7/f/e/8/d/7fe8d0bc6a00bba3fe03910417fe8438db8a6537-affectslight.jpeg new file mode 100644 index 0000000..b1c6fdb Binary files /dev/null and b/images/7/f/e/8/d/7fe8d0bc6a00bba3fe03910417fe8438db8a6537-affectslight.jpeg differ diff --git a/images/8/2/1/d/6/821d69f5513f6412ae6f16ac2bd3472fd7212379-spinoza08.jpeg b/images/8/2/1/d/6/821d69f5513f6412ae6f16ac2bd3472fd7212379-spinoza08.jpeg new file mode 100644 index 0000000..8281a98 Binary files /dev/null and b/images/8/2/1/d/6/821d69f5513f6412ae6f16ac2bd3472fd7212379-spinoza08.jpeg differ diff --git a/images/8/2/4/f/c/824fcf9d63149e76d83295c14d8a00b7ed883174-commentairephilosophe.jpeg b/images/8/2/4/f/c/824fcf9d63149e76d83295c14d8a00b7ed883174-commentairephilosophe.jpeg new file mode 100644 index 0000000..d8658aa Binary files /dev/null and b/images/8/2/4/f/c/824fcf9d63149e76d83295c14d8a00b7ed883174-commentairephilosophe.jpeg differ diff --git a/images/8/b/5/e/d/8b5ed4d9cfa559bc299ac45f6658688bad81cf69-dalli01.jpeg b/images/8/b/5/e/d/8b5ed4d9cfa559bc299ac45f6658688bad81cf69-dalli01.jpeg new file mode 100644 index 0000000..de7c004 Binary files /dev/null and b/images/8/b/5/e/d/8b5ed4d9cfa559bc299ac45f6658688bad81cf69-dalli01.jpeg differ diff --git a/images/8/b/c/6/9/8bc69d6dc5f995d6b5d90e40100db77e2c18b44b-spinozapp001.jpeg b/images/8/b/c/6/9/8bc69d6dc5f995d6b5d90e40100db77e2c18b44b-spinozapp001.jpeg new file mode 100644 index 0000000..7d3cd58 Binary files /dev/null and b/images/8/b/c/6/9/8bc69d6dc5f995d6b5d90e40100db77e2c18b44b-spinozapp001.jpeg differ diff --git a/images/8/f/e/f/6/8fef630c9d6034a6b6e0efa58725fa12fbf57477-e1def7.jpeg b/images/8/f/e/f/6/8fef630c9d6034a6b6e0efa58725fa12fbf57477-e1def7.jpeg new file mode 100644 index 0000000..54c1434 Binary files /dev/null and b/images/8/f/e/f/6/8fef630c9d6034a6b6e0efa58725fa12fbf57477-e1def7.jpeg differ diff --git a/images/9/0/8/a/9/908a91f31238ca807543ae5bb6baf3c8aee0a82d-bptitephysiquehdmodif.jpeg b/images/9/0/8/a/9/908a91f31238ca807543ae5bb6baf3c8aee0a82d-bptitephysiquehdmodif.jpeg new file mode 100644 index 0000000..dbde78c Binary files /dev/null and b/images/9/0/8/a/9/908a91f31238ca807543ae5bb6baf3c8aee0a82d-bptitephysiquehdmodif.jpeg differ diff --git a/images/9/7/b/8/b/97b8be9477449a07071f2926f5f93abe09df2691-a2010connexionsmodif.jpeg b/images/9/7/b/8/b/97b8be9477449a07071f2926f5f93abe09df2691-a2010connexionsmodif.jpeg new file mode 100644 index 0000000..a3f67b0 Binary files /dev/null and b/images/9/7/b/8/b/97b8be9477449a07071f2926f5f93abe09df2691-a2010connexionsmodif.jpeg differ diff --git a/images/9/9/4/3/6/994366e35aabafdb56ea862cdcac0bbbd3558cc6-2013trajectoire01.jpeg b/images/9/9/4/3/6/994366e35aabafdb56ea862cdcac0bbbd3558cc6-2013trajectoire01.jpeg new file mode 100644 index 0000000..10d0b34 Binary files /dev/null and b/images/9/9/4/3/6/994366e35aabafdb56ea862cdcac0bbbd3558cc6-2013trajectoire01.jpeg differ diff --git a/images/9/9/f/0/8/99f0843e8caa985421f20fc62aa8f25763c55270-commentairephilosopheweb.jpeg b/images/9/9/f/0/8/99f0843e8caa985421f20fc62aa8f25763c55270-commentairephilosopheweb.jpeg new file mode 100644 index 0000000..6a798a1 Binary files /dev/null and b/images/9/9/f/0/8/99f0843e8caa985421f20fc62aa8f25763c55270-commentairephilosopheweb.jpeg differ diff --git a/images/9/a/0/5/d/9a05da05df8898c845629da2e7d2fd9ba17c7a1e-libertedepenser001.jpeg b/images/9/a/0/5/d/9a05da05df8898c845629da2e7d2fd9ba17c7a1e-libertedepenser001.jpeg new file mode 100644 index 0000000..f0dec72 Binary files /dev/null and b/images/9/a/0/5/d/9a05da05df8898c845629da2e7d2fd9ba17c7a1e-libertedepenser001.jpeg differ diff --git a/images/9/a/2/f/3/9a2f3da890bea773bba18b89c013e010dc001e06-2011proj6.jpeg b/images/9/a/2/f/3/9a2f3da890bea773bba18b89c013e010dc001e06-2011proj6.jpeg new file mode 100644 index 0000000..8dc1b52 Binary files /dev/null and b/images/9/a/2/f/3/9a2f3da890bea773bba18b89c013e010dc001e06-2011proj6.jpeg differ diff --git a/images/a/0/d/d/d/a0ddd78fe06e8e257a15979de0ddd53619c54c2c-projhist.jpeg b/images/a/0/d/d/d/a0ddd78fe06e8e257a15979de0ddd53619c54c2c-projhist.jpeg new file mode 100644 index 0000000..f342518 Binary files /dev/null and b/images/a/0/d/d/d/a0ddd78fe06e8e257a15979de0ddd53619c54c2c-projhist.jpeg differ diff --git a/images/a/2/a/7/3/a2a738c79041698ef780bfff1c4e935caf3ccaf2-spinoza07.jpeg b/images/a/2/a/7/3/a2a738c79041698ef780bfff1c4e935caf3ccaf2-spinoza07.jpeg new file mode 100644 index 0000000..d5790e6 Binary files /dev/null and b/images/a/2/a/7/3/a2a738c79041698ef780bfff1c4e935caf3ccaf2-spinoza07.jpeg differ diff --git a/images/a/7/3/d/4/a73d41b8eb636c4f11f38c6fd352e7c7b552d7d5-bcahiermodif.jpeg b/images/a/7/3/d/4/a73d41b8eb636c4f11f38c6fd352e7c7b552d7d5-bcahiermodif.jpeg new file mode 100644 index 0000000..5351416 Binary files /dev/null and b/images/a/7/3/d/4/a73d41b8eb636c4f11f38c6fd352e7c7b552d7d5-bcahiermodif.jpeg differ diff --git a/images/a/d/5/e/a/ad5ea987d2b973735b18bf1d95348e161fd51bb4-spinozapp008.jpeg b/images/a/d/5/e/a/ad5ea987d2b973735b18bf1d95348e161fd51bb4-spinozapp008.jpeg new file mode 100644 index 0000000..d1c0f96 Binary files /dev/null and b/images/a/d/5/e/a/ad5ea987d2b973735b18bf1d95348e161fd51bb4-spinozapp008.jpeg differ diff --git a/images/a/f/3/b/7/af3b735166a03263591b53706002ae34bf87c949-2013trajectoire02.jpeg b/images/a/f/3/b/7/af3b735166a03263591b53706002ae34bf87c949-2013trajectoire02.jpeg new file mode 100644 index 0000000..4f8c635 Binary files /dev/null and b/images/a/f/3/b/7/af3b735166a03263591b53706002ae34bf87c949-2013trajectoire02.jpeg differ diff --git a/images/a/f/9/0/2/af90200aebca738339a40921d5a3a7ba274c0a7f-e1def1.jpeg b/images/a/f/9/0/2/af90200aebca738339a40921d5a3a7ba274c0a7f-e1def1.jpeg new file mode 100644 index 0000000..7526347 Binary files /dev/null and b/images/a/f/9/0/2/af90200aebca738339a40921d5a3a7ba274c0a7f-e1def1.jpeg differ diff --git a/images/a/f/e/d/5/afed52af041e1ad334889afaaf566924ca4de133-commentairephilosopheweb.jpeg b/images/a/f/e/d/5/afed52af041e1ad334889afaaf566924ca4de133-commentairephilosopheweb.jpeg new file mode 100644 index 0000000..6a798a1 Binary files /dev/null and b/images/a/f/e/d/5/afed52af041e1ad334889afaaf566924ca4de133-commentairephilosopheweb.jpeg differ diff --git a/images/b/2/8/1/6/b2816731e1283abd9c751db85393d576c85702cb-spinozapp005.jpeg b/images/b/2/8/1/6/b2816731e1283abd9c751db85393d576c85702cb-spinozapp005.jpeg new file mode 100644 index 0000000..dfe1425 Binary files /dev/null and b/images/b/2/8/1/6/b2816731e1283abd9c751db85393d576c85702cb-spinozapp005.jpeg differ diff --git a/images/b/2/c/b/b/b2cbb2f19009c4f332c4c1e1038448034aedf2bd-cordoba01.jpeg b/images/b/2/c/b/b/b2cbb2f19009c4f332c4c1e1038448034aedf2bd-cordoba01.jpeg new file mode 100644 index 0000000..2662c8c Binary files /dev/null and b/images/b/2/c/b/b/b2cbb2f19009c4f332c4c1e1038448034aedf2bd-cordoba01.jpeg differ diff --git a/images/b/7/2/3/d/b723d570c446096984511c61ec581c8b6c4089f3-2011proj6.jpeg b/images/b/7/2/3/d/b723d570c446096984511c61ec581c8b6c4089f3-2011proj6.jpeg new file mode 100644 index 0000000..8dc1b52 Binary files /dev/null and b/images/b/7/2/3/d/b723d570c446096984511c61ec581c8b6c4089f3-2011proj6.jpeg differ diff --git a/images/b/7/c/f/6/b7cf6f50d421d0229493f9805daa859da9f66587-01-logoscam.jpeg b/images/b/7/c/f/6/b7cf6f50d421d0229493f9805daa859da9f66587-01-logoscam.jpeg new file mode 100644 index 0000000..a611eef Binary files /dev/null and b/images/b/7/c/f/6/b7cf6f50d421d0229493f9805daa859da9f66587-01-logoscam.jpeg differ diff --git a/images/b/8/1/6/a/b816adfc758d03a698d47808c786cd0fe613c342-logo-hdf.jpeg b/images/b/8/1/6/a/b816adfc758d03a698d47808c786cd0fe613c342-logo-hdf.jpeg new file mode 100644 index 0000000..852d981 Binary files /dev/null and b/images/b/8/1/6/a/b816adfc758d03a698d47808c786cd0fe613c342-logo-hdf.jpeg differ diff --git a/images/b/9/0/8/b/b908ba8f22a8efac4036cd97e3740009cf504125-spinoza12.jpeg b/images/b/9/0/8/b/b908ba8f22a8efac4036cd97e3740009cf504125-spinoza12.jpeg new file mode 100644 index 0000000..cba34da Binary files /dev/null and b/images/b/9/0/8/b/b908ba8f22a8efac4036cd97e3740009cf504125-spinoza12.jpeg differ diff --git a/images/b/9/8/e/d/b98edb6a2b004c048f0819b86c31ad8d3b4ba641-logoeu.png b/images/b/9/8/e/d/b98edb6a2b004c048f0819b86c31ad8d3b4ba641-logoeu.png new file mode 100644 index 0000000..f48d61f Binary files /dev/null and b/images/b/9/8/e/d/b98edb6a2b004c048f0819b86c31ad8d3b4ba641-logoeu.png differ diff --git a/images/b/9/e/0/6/b9e067f6c540daf815cea7869e05b6fb1c13df86-projhist.jpeg b/images/b/9/e/0/6/b9e067f6c540daf815cea7869e05b6fb1c13df86-projhist.jpeg new file mode 100644 index 0000000..f342518 Binary files /dev/null and b/images/b/9/e/0/6/b9e067f6c540daf815cea7869e05b6fb1c13df86-projhist.jpeg differ diff --git a/images/b/d/9/6/3/bd96360b6ae8bac7169fab574b6a2762ff34400b-spinoza03.jpeg b/images/b/d/9/6/3/bd96360b6ae8bac7169fab574b6a2762ff34400b-spinoza03.jpeg new file mode 100644 index 0000000..0a69eec Binary files /dev/null and b/images/b/d/9/6/3/bd96360b6ae8bac7169fab574b6a2762ff34400b-spinoza03.jpeg differ diff --git a/images/c/2/a/4/3/c2a434b495d064bba5ecebbc68a99de4dde9e92b-10-tygryzemail.jpeg b/images/c/2/a/4/3/c2a434b495d064bba5ecebbc68a99de4dde9e92b-10-tygryzemail.jpeg new file mode 100644 index 0000000..c68b1c0 Binary files /dev/null and b/images/c/2/a/4/3/c2a434b495d064bba5ecebbc68a99de4dde9e92b-10-tygryzemail.jpeg differ diff --git a/images/c/7/0/4/2/c70427012c749f9440744ac3b0568d31f54ab885-hoteleden.jpeg b/images/c/7/0/4/2/c70427012c749f9440744ac3b0568d31f54ab885-hoteleden.jpeg new file mode 100644 index 0000000..c36cc42 Binary files /dev/null and b/images/c/7/0/4/2/c70427012c749f9440744ac3b0568d31f54ab885-hoteleden.jpeg differ diff --git a/images/c/b/6/f/d/cb6fd28c4c4718afcc7e2e00a26249dfdb813153-affectslight.jpeg b/images/c/b/6/f/d/cb6fd28c4c4718afcc7e2e00a26249dfdb813153-affectslight.jpeg new file mode 100644 index 0000000..b1c6fdb Binary files /dev/null and b/images/c/b/6/f/d/cb6fd28c4c4718afcc7e2e00a26249dfdb813153-affectslight.jpeg differ diff --git a/images/c/d/2/4/1/cd2414ba3a4b2561aac3fd7f27b4be595af51a27-ethique01-1.jpeg b/images/c/d/2/4/1/cd2414ba3a4b2561aac3fd7f27b4be595af51a27-ethique01-1.jpeg new file mode 100644 index 0000000..bac295b Binary files /dev/null and b/images/c/d/2/4/1/cd2414ba3a4b2561aac3fd7f27b4be595af51a27-ethique01-1.jpeg differ diff --git a/images/c/d/7/f/4/cd7f45f739576cf2712a028f89ba4ab07e79715d-003pourphoto2.jpeg b/images/c/d/7/f/4/cd7f45f739576cf2712a028f89ba4ab07e79715d-003pourphoto2.jpeg new file mode 100644 index 0000000..a5a79e2 Binary files /dev/null and b/images/c/d/7/f/4/cd7f45f739576cf2712a028f89ba4ab07e79715d-003pourphoto2.jpeg differ diff --git a/images/d/1/7/c/a/d17ca8563598125785a02c5a741371b15e724908-2011proj5.jpeg b/images/d/1/7/c/a/d17ca8563598125785a02c5a741371b15e724908-2011proj5.jpeg new file mode 100644 index 0000000..ec6a04e Binary files /dev/null and b/images/d/1/7/c/a/d17ca8563598125785a02c5a741371b15e724908-2011proj5.jpeg differ diff --git a/images/d/4/5/1/7/d45176eb31c56e145ef1b543703f66a5c4fd2c03-thumb-pdf.png b/images/d/4/5/1/7/d45176eb31c56e145ef1b543703f66a5c4fd2c03-thumb-pdf.png new file mode 100644 index 0000000..16f2aa7 Binary files /dev/null and b/images/d/4/5/1/7/d45176eb31c56e145ef1b543703f66a5c4fd2c03-thumb-pdf.png differ diff --git a/images/d/5/8/3/2/d58329c47d8f0ad2799443816ed0600119be900d-e1p17-cor2b.jpeg b/images/d/5/8/3/2/d58329c47d8f0ad2799443816ed0600119be900d-e1p17-cor2b.jpeg new file mode 100644 index 0000000..a411811 Binary files /dev/null and b/images/d/5/8/3/2/d58329c47d8f0ad2799443816ed0600119be900d-e1p17-cor2b.jpeg differ diff --git a/images/d/5/b/5/6/d5b56dbfac983520f655594d44c5bb5837cd964c-04--logo-fmshblanc.png b/images/d/5/b/5/6/d5b56dbfac983520f655594d44c5bb5837cd964c-04--logo-fmshblanc.png new file mode 100644 index 0000000..fbf8ca8 Binary files /dev/null and b/images/d/5/b/5/6/d5b56dbfac983520f655594d44c5bb5837cd964c-04--logo-fmshblanc.png differ diff --git a/images/d/7/2/4/4/d7244ebda932c8d9dde16f4b14c2ad89c19b4486-e1def7.jpeg b/images/d/7/2/4/4/d7244ebda932c8d9dde16f4b14c2ad89c19b4486-e1def7.jpeg new file mode 100644 index 0000000..54c1434 Binary files /dev/null and b/images/d/7/2/4/4/d7244ebda932c8d9dde16f4b14c2ad89c19b4486-e1def7.jpeg differ diff --git a/images/d/c/7/d/d/dc7dd4e661c0ba22354930bfa9b7619fa116bfe3-nuittrouble2.jpeg b/images/d/c/7/d/d/dc7dd4e661c0ba22354930bfa9b7619fa116bfe3-nuittrouble2.jpeg new file mode 100644 index 0000000..b2735e5 Binary files /dev/null and b/images/d/c/7/d/d/dc7dd4e661c0ba22354930bfa9b7619fa116bfe3-nuittrouble2.jpeg differ diff --git a/images/d/f/c/f/0/dfcf05491a1672d32fb11f24a20da77ec2b6d4cf-spinoza06.jpeg b/images/d/f/c/f/0/dfcf05491a1672d32fb11f24a20da77ec2b6d4cf-spinoza06.jpeg new file mode 100644 index 0000000..896bcbf Binary files /dev/null and b/images/d/f/c/f/0/dfcf05491a1672d32fb11f24a20da77ec2b6d4cf-spinoza06.jpeg differ diff --git a/images/e/2/6/5/e/e265e5f9bd54f34832e713953e0b8ef2ddd36990-spinoza12.jpeg b/images/e/2/6/5/e/e265e5f9bd54f34832e713953e0b8ef2ddd36990-spinoza12.jpeg new file mode 100644 index 0000000..e1e22f6 Binary files /dev/null and b/images/e/2/6/5/e/e265e5f9bd54f34832e713953e0b8ef2ddd36990-spinoza12.jpeg differ diff --git a/images/e/3/a/a/b/e3aabaa66a258568c336eb36f3fa366a4a331a1e-dalli03.jpeg b/images/e/3/a/a/b/e3aabaa66a258568c336eb36f3fa366a4a331a1e-dalli03.jpeg new file mode 100644 index 0000000..58625e2 Binary files /dev/null and b/images/e/3/a/a/b/e3aabaa66a258568c336eb36f3fa366a4a331a1e-dalli03.jpeg differ diff --git a/images/e/4/0/b/9/e40b93dbe089352f5edd5bd64f5506de709d6f01-e1p17a.jpeg b/images/e/4/0/b/9/e40b93dbe089352f5edd5bd64f5506de709d6f01-e1p17a.jpeg new file mode 100644 index 0000000..2417dee Binary files /dev/null and b/images/e/4/0/b/9/e40b93dbe089352f5edd5bd64f5506de709d6f01-e1p17a.jpeg differ diff --git a/images/e/5/5/c/3/e55c30eeb6df53cdb88da4b579f8585fd512fc85-04--logo-fmshblanc.png b/images/e/5/5/c/3/e55c30eeb6df53cdb88da4b579f8585fd512fc85-04--logo-fmshblanc.png new file mode 100644 index 0000000..fbf8ca8 Binary files /dev/null and b/images/e/5/5/c/3/e55c30eeb6df53cdb88da4b579f8585fd512fc85-04--logo-fmshblanc.png differ diff --git a/images/e/5/8/0/8/e58084d7f639cc7705fe8ed619ba4c50e0881d39-spinozapp002.jpeg b/images/e/5/8/0/8/e58084d7f639cc7705fe8ed619ba4c50e0881d39-spinozapp002.jpeg new file mode 100644 index 0000000..c10b72a Binary files /dev/null and b/images/e/5/8/0/8/e58084d7f639cc7705fe8ed619ba4c50e0881d39-spinozapp002.jpeg differ diff --git a/images/e/5/9/4/4/e5944d3b6d14eae13dfd4f801277a38886176aa9-ptitephysique4b.jpeg b/images/e/5/9/4/4/e5944d3b6d14eae13dfd4f801277a38886176aa9-ptitephysique4b.jpeg new file mode 100644 index 0000000..48055f0 Binary files /dev/null and b/images/e/5/9/4/4/e5944d3b6d14eae13dfd4f801277a38886176aa9-ptitephysique4b.jpeg differ diff --git a/images/e/8/5/9/c/e859c96d90d8565703a08d74792a0cbce60da381-thumb-pdf.png b/images/e/8/5/9/c/e859c96d90d8565703a08d74792a0cbce60da381-thumb-pdf.png new file mode 100644 index 0000000..16f2aa7 Binary files /dev/null and b/images/e/8/5/9/c/e859c96d90d8565703a08d74792a0cbce60da381-thumb-pdf.png differ diff --git a/images/e/9/3/d/c/e93dc3d06ea2322e5018885429fba2ede4a36d53-logo-hdf.jpeg b/images/e/9/3/d/c/e93dc3d06ea2322e5018885429fba2ede4a36d53-logo-hdf.jpeg new file mode 100644 index 0000000..852d981 Binary files /dev/null and b/images/e/9/3/d/c/e93dc3d06ea2322e5018885429fba2ede4a36d53-logo-hdf.jpeg differ diff --git a/images/e/a/a/a/c/eaaacac8968aa1d9f9f5e6827b55d4b2cd0bd4d1-spinoza10.jpeg b/images/e/a/a/a/c/eaaacac8968aa1d9f9f5e6827b55d4b2cd0bd4d1-spinoza10.jpeg new file mode 100644 index 0000000..b202d0d Binary files /dev/null and b/images/e/a/a/a/c/eaaacac8968aa1d9f9f5e6827b55d4b2cd0bd4d1-spinoza10.jpeg differ diff --git a/images/e/a/b/4/d/eab4d18bb9f3daf8eb3752a131c6df6002e0aa9c-notedessinehd.jpeg b/images/e/a/b/4/d/eab4d18bb9f3daf8eb3752a131c6df6002e0aa9c-notedessinehd.jpeg new file mode 100644 index 0000000..682413b Binary files /dev/null and b/images/e/a/b/4/d/eab4d18bb9f3daf8eb3752a131c6df6002e0aa9c-notedessinehd.jpeg differ diff --git a/images/e/b/8/e/a/eb8eadc43f920b1d260281b0440173ebce193173-spinoza05.jpeg b/images/e/b/8/e/a/eb8eadc43f920b1d260281b0440173ebce193173-spinoza05.jpeg new file mode 100644 index 0000000..695982a Binary files /dev/null and b/images/e/b/8/e/a/eb8eadc43f920b1d260281b0440173ebce193173-spinoza05.jpeg differ diff --git a/images/e/d/6/0/d/ed60dd1c9794bccfb1cb9c4bdd968d5c547d0971-spinozapp003.jpeg b/images/e/d/6/0/d/ed60dd1c9794bccfb1cb9c4bdd968d5c547d0971-spinozapp003.jpeg new file mode 100644 index 0000000..eca6fb3 Binary files /dev/null and b/images/e/d/6/0/d/ed60dd1c9794bccfb1cb9c4bdd968d5c547d0971-spinozapp003.jpeg differ diff --git a/images/f/5/9/d/5/f59d5478682283da4e8aedebf83070ea582256b4-logoupjv-bleu.png b/images/f/5/9/d/5/f59d5478682283da4e8aedebf83070ea582256b4-logoupjv-bleu.png new file mode 100644 index 0000000..6b4da57 Binary files /dev/null and b/images/f/5/9/d/5/f59d5478682283da4e8aedebf83070ea582256b4-logoupjv-bleu.png differ diff --git a/images/f/7/a/6/b/f7a6bed45ed2b9aa3262e08872c530cc2fc1cc39-e1p17a.jpeg b/images/f/7/a/6/b/f7a6bed45ed2b9aa3262e08872c530cc2fc1cc39-e1p17a.jpeg new file mode 100644 index 0000000..2417dee Binary files /dev/null and b/images/f/7/a/6/b/f7a6bed45ed2b9aa3262e08872c530cc2fc1cc39-e1p17a.jpeg differ diff --git a/images/f/f/1/7/5/ff17540294aa7411cb43318a1be2b9b290cde372-spinozapp004.jpeg b/images/f/f/1/7/5/ff17540294aa7411cb43318a1be2b9b290cde372-spinozapp004.jpeg new file mode 100644 index 0000000..dd344e0 Binary files /dev/null and b/images/f/f/1/7/5/ff17540294aa7411cb43318a1be2b9b290cde372-spinozapp004.jpeg differ diff --git a/index.php b/index.php new file mode 100644 index 0000000..68c9049 --- /dev/null +++ b/index.php @@ -0,0 +1,56 @@ +bin/grav install"); +} + +if (PHP_SAPI == 'cli-server') { + if (!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
                                                                      "); + } +} + +use Grav\Common\Grav; +use RocketTheme\Toolbox\Event\Event; + +if (version_compare($ver = PHP_VERSION, $req = GRAV_PHP_MIN, '<')) { + die(sprintf('You are running PHP %s, but Grav needs at least PHP %s to run.', $ver, $req)); +} + +// Register the auto-loader. +$loader = require_once $autoload; + +// 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 (\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 0000000..e69de29 diff --git a/logs/popularity/daily.json b/logs/popularity/daily.json new file mode 100644 index 0000000..8bedbae --- /dev/null +++ b/logs/popularity/daily.json @@ -0,0 +1 @@ +{"11-12-2017":6,"12-12-2017":226,"18-12-2017":2,"19-12-2017":329,"20-12-2017":3,"21-12-2017":1,"24-12-2017":2,"11-01-2018":5,"22-01-2018":281,"25-01-2018":1,"29-01-2018":296,"30-01-2018":18,"31-01-2018":4,"08-02-2018":1,"09-02-2018":3,"14-02-2018":57,"15-02-2018":82,"16-02-2018":28,"17-02-2018":117,"19-02-2018":28,"20-02-2018":324,"21-02-2018":62,"27-02-2018":103,"28-02-2018":229,"06-03-2018":25,"22-03-2018":145,"23-03-2018":31,"24-03-2018":130,"25-03-2018":94,"11-04-2018":19} \ No newline at end of file diff --git a/logs/popularity/monthly.json b/logs/popularity/monthly.json new file mode 100644 index 0000000..26a0d1c --- /dev/null +++ b/logs/popularity/monthly.json @@ -0,0 +1 @@ +{"11-2017":956,"12-2017":2103,"01-2018":605,"02-2018":1034,"03-2018":425,"04-2018":19} \ No newline at end of file diff --git a/logs/popularity/totals.json b/logs/popularity/totals.json new file mode 100644 index 0000000..de1969f --- /dev/null +++ b/logs/popularity/totals.json @@ -0,0 +1 @@ +{"\/":5098,"\/home-2":6,"\/home-en":35,"\/home-fr":3} \ No newline at end of file diff --git a/logs/popularity/visitors.json b/logs/popularity/visitors.json new file mode 100644 index 0000000..028348d --- /dev/null +++ b/logs/popularity/visitors.json @@ -0,0 +1 @@ +{"127.0.0.1":1523460088} \ No newline at end of file diff --git a/robots.txt b/robots.txt new file mode 100644 index 0000000..3b558d6 --- /dev/null +++ b/robots.txt @@ -0,0 +1,11 @@ +User-agent: * +Disallow: /backup/ +Disallow: /bin/ +Disallow: /cache/ +Disallow: /grav/ +Disallow: /logs/ +Disallow: /system/ +Disallow: /vendor/ +Disallow: /user/ +Allow: /user/pages/ +Allow: /user/themes/ diff --git a/system/assets/debugger.css b/system/assets/debugger.css new file mode 100644 index 0000000..556da6a --- /dev/null +++ b/system/assets/debugger.css @@ -0,0 +1,54 @@ +div.phpdebugbar { + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; +} + +.phpdebugbar pre { + padding: 1rem; +} + +.phpdebugbar div.phpdebugbar-header > div > * { + padding: 5px 15px; +} + +.phpdebugbar div.phpdebugbar-header > div.phpdebugbar-header-right > * { + padding: 5px 8px; +} + +.phpdebugbar div.phpdebugbar-header, .phpdebugbar a.phpdebugbar-restore-btn { + background-image: url(grav.png); +} + +.phpdebugbar a.phpdebugbar-restore-btn { + width: 13px; +} + +.phpdebugbar a.phpdebugbar-tab.phpdebugbar-active { + background: #3DB9EC; + color: #fff; + margin-top: -1px; + padding-top: 6px; +} + +.phpdebugbar .phpdebugbar-widgets-toolbar { + padding-left: 5px; +} + +.phpdebugbar input[type=text] { + padding: 0; + display: inline; +} + +.phpdebugbar dl.phpdebugbar-widgets-varlist, ul.phpdebugbar-widgets-timeline li span.phpdebugbar-widgets-label { + font-family: "DejaVu Sans Mono", Menlo, Monaco, Consolas, Courier, monospace; + font-size: 12px; +} + +ul.phpdebugbar-widgets-timeline li span.phpdebugbar-widgets-label { + text-shadow: -1px -1px 0 #fff, 1px -1px 0 #fff, -1px 1px 0 #fff, 1px 1px 0 #fff; + top: 0; +} + +.phpdebugbar pre, .phpdebugbar code { + margin: 0; + font-size: 14px; +} diff --git a/system/assets/grav.png b/system/assets/grav.png new file mode 100644 index 0000000..3379934 Binary files /dev/null and b/system/assets/grav.png differ diff --git a/system/assets/jquery/jquery-2.1.4.min.js b/system/assets/jquery/jquery-2.1.4.min.js new file mode 100644 index 0000000..49990d6 --- /dev/null +++ b/system/assets/jquery/jquery-2.1.4.min.js @@ -0,0 +1,4 @@ +/*! jQuery v2.1.4 | (c) 2005, 2015 jQuery Foundation, Inc. | jquery.org/license */ +!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k={},l=a.document,m="2.1.4",n=function(a,b){return new n.fn.init(a,b)},o=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,p=/^-ms-/,q=/-([\da-z])/gi,r=function(a,b){return b.toUpperCase()};n.fn=n.prototype={jquery:m,constructor:n,selector:"",length:0,toArray:function(){return d.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=n.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return n.each(this,a,b)},map:function(a){return this.pushStack(n.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},n.extend=n.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||n.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(a=arguments[h]))for(b in a)c=g[b],d=a[b],g!==d&&(j&&d&&(n.isPlainObject(d)||(e=n.isArray(d)))?(e?(e=!1,f=c&&n.isArray(c)?c:[]):f=c&&n.isPlainObject(c)?c:{},g[b]=n.extend(j,f,d)):void 0!==d&&(g[b]=d));return g},n.extend({expando:"jQuery"+(m+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===n.type(a)},isArray:Array.isArray,isWindow:function(a){return null!=a&&a===a.window},isNumeric:function(a){return!n.isArray(a)&&a-parseFloat(a)+1>=0},isPlainObject:function(a){return"object"!==n.type(a)||a.nodeType||n.isWindow(a)?!1:a.constructor&&!j.call(a.constructor.prototype,"isPrototypeOf")?!1:!0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(a){var b,c=eval;a=n.trim(a),a&&(1===a.indexOf("use strict")?(b=l.createElement("script"),b.text=a,l.head.appendChild(b).parentNode.removeChild(b)):c(a))},camelCase:function(a){return a.replace(p,"ms-").replace(q,r)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=s(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(o,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(s(Object(a))?n.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){return null==b?-1:g.call(b,a,c)},merge:function(a,b){for(var c=+b.length,d=0,e=a.length;c>d;d++)a[e++]=b[d];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=s(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(c=a[b],b=a,a=c),n.isFunction(a)?(e=d.call(arguments,2),f=function(){return a.apply(b||this,e.concat(d.call(arguments)))},f.guid=a.guid=a.guid||n.guid++,f):void 0},now:Date.now,support:k}),n.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function s(a){var b="length"in a&&a.length,c=n.type(a);return"function"===c||n.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var t=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+1*new Date,v=a.document,w=0,x=0,y=ha(),z=ha(),A=ha(),B=function(a,b){return a===b&&(l=!0),0},C=1<<31,D={}.hasOwnProperty,E=[],F=E.pop,G=E.push,H=E.push,I=E.slice,J=function(a,b){for(var c=0,d=a.length;d>c;c++)if(a[c]===b)return c;return-1},K="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",L="[\\x20\\t\\r\\n\\f]",M="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",N=M.replace("w","w#"),O="\\["+L+"*("+M+")(?:"+L+"*([*^$|!~]?=)"+L+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+N+"))|)"+L+"*\\]",P=":("+M+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+O+")*)|.*)\\)|)",Q=new RegExp(L+"+","g"),R=new RegExp("^"+L+"+|((?:^|[^\\\\])(?:\\\\.)*)"+L+"+$","g"),S=new RegExp("^"+L+"*,"+L+"*"),T=new RegExp("^"+L+"*([>+~]|"+L+")"+L+"*"),U=new RegExp("="+L+"*([^\\]'\"]*?)"+L+"*\\]","g"),V=new RegExp(P),W=new RegExp("^"+N+"$"),X={ID:new RegExp("^#("+M+")"),CLASS:new RegExp("^\\.("+M+")"),TAG:new RegExp("^("+M.replace("w","w*")+")"),ATTR:new RegExp("^"+O),PSEUDO:new RegExp("^"+P),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+L+"*(even|odd|(([+-]|)(\\d*)n|)"+L+"*(?:([+-]|)"+L+"*(\\d+)|))"+L+"*\\)|)","i"),bool:new RegExp("^(?:"+K+")$","i"),needsContext:new RegExp("^"+L+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+L+"*((?:-\\d)?\\d*)"+L+"*\\)|)(?=[^-]|$)","i")},Y=/^(?:input|select|textarea|button)$/i,Z=/^h\d$/i,$=/^[^{]+\{\s*\[native \w/,_=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,aa=/[+~]/,ba=/'|\\/g,ca=new RegExp("\\\\([\\da-f]{1,6}"+L+"?|("+L+")|.)","ig"),da=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)},ea=function(){m()};try{H.apply(E=I.call(v.childNodes),v.childNodes),E[v.childNodes.length].nodeType}catch(fa){H={apply:E.length?function(a,b){G.apply(a,I.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function ga(a,b,d,e){var f,h,j,k,l,o,r,s,w,x;if((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,d=d||[],k=b.nodeType,"string"!=typeof a||!a||1!==k&&9!==k&&11!==k)return d;if(!e&&p){if(11!==k&&(f=_.exec(a)))if(j=f[1]){if(9===k){if(h=b.getElementById(j),!h||!h.parentNode)return d;if(h.id===j)return d.push(h),d}else if(b.ownerDocument&&(h=b.ownerDocument.getElementById(j))&&t(b,h)&&h.id===j)return d.push(h),d}else{if(f[2])return H.apply(d,b.getElementsByTagName(a)),d;if((j=f[3])&&c.getElementsByClassName)return H.apply(d,b.getElementsByClassName(j)),d}if(c.qsa&&(!q||!q.test(a))){if(s=r=u,w=b,x=1!==k&&a,1===k&&"object"!==b.nodeName.toLowerCase()){o=g(a),(r=b.getAttribute("id"))?s=r.replace(ba,"\\$&"):b.setAttribute("id",s),s="[id='"+s+"'] ",l=o.length;while(l--)o[l]=s+ra(o[l]);w=aa.test(a)&&pa(b.parentNode)||b,x=o.join(",")}if(x)try{return H.apply(d,w.querySelectorAll(x)),d}catch(y){}finally{r||b.removeAttribute("id")}}}return i(a.replace(R,"$1"),b,d,e)}function ha(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function ia(a){return a[u]=!0,a}function ja(a){var b=n.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function ka(a,b){var c=a.split("|"),e=a.length;while(e--)d.attrHandle[c[e]]=b}function la(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||C)-(~a.sourceIndex||C);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function ma(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function na(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function oa(a){return ia(function(b){return b=+b,ia(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function pa(a){return a&&"undefined"!=typeof a.getElementsByTagName&&a}c=ga.support={},f=ga.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},m=ga.setDocument=function(a){var b,e,g=a?a.ownerDocument||a:v;return g!==n&&9===g.nodeType&&g.documentElement?(n=g,o=g.documentElement,e=g.defaultView,e&&e!==e.top&&(e.addEventListener?e.addEventListener("unload",ea,!1):e.attachEvent&&e.attachEvent("onunload",ea)),p=!f(g),c.attributes=ja(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ja(function(a){return a.appendChild(g.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=$.test(g.getElementsByClassName),c.getById=ja(function(a){return o.appendChild(a).id=u,!g.getElementsByName||!g.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c=b.getElementById(a);return c&&c.parentNode?[c]:[]}},d.filter.ID=function(a){var b=a.replace(ca,da);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(ca,da);return function(a){var c="undefined"!=typeof a.getAttributeNode&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return"undefined"!=typeof b.getElementsByTagName?b.getElementsByTagName(a):c.qsa?b.querySelectorAll(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=$.test(g.querySelectorAll))&&(ja(function(a){o.appendChild(a).innerHTML="",a.querySelectorAll("[msallowcapture^='']").length&&q.push("[*^$]="+L+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+L+"*(?:value|"+K+")"),a.querySelectorAll("[id~="+u+"-]").length||q.push("~="),a.querySelectorAll(":checked").length||q.push(":checked"),a.querySelectorAll("a#"+u+"+*").length||q.push(".#.+[+~]")}),ja(function(a){var b=g.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+L+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=$.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ja(function(a){c.disconnectedMatch=s.call(a,"div"),s.call(a,"[s!='']:x"),r.push("!=",P)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=$.test(o.compareDocumentPosition),t=b||$.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===g||a.ownerDocument===v&&t(v,a)?-1:b===g||b.ownerDocument===v&&t(v,b)?1:k?J(k,a)-J(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,e=a.parentNode,f=b.parentNode,h=[a],i=[b];if(!e||!f)return a===g?-1:b===g?1:e?-1:f?1:k?J(k,a)-J(k,b):0;if(e===f)return la(a,b);c=a;while(c=c.parentNode)h.unshift(c);c=b;while(c=c.parentNode)i.unshift(c);while(h[d]===i[d])d++;return d?la(h[d],i[d]):h[d]===v?-1:i[d]===v?1:0},g):n},ga.matches=function(a,b){return ga(a,null,null,b)},ga.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(U,"='$1']"),!(!c.matchesSelector||!p||r&&r.test(b)||q&&q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return ga(b,n,null,[a]).length>0},ga.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},ga.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&D.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},ga.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},ga.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=ga.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=ga.selectors={cacheLength:50,createPseudo:ia,match:X,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(ca,da),a[3]=(a[3]||a[4]||a[5]||"").replace(ca,da),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||ga.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&ga.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return X.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&V.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(ca,da).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+L+")"+a+"("+L+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||"undefined"!=typeof a.getAttribute&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=ga.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e.replace(Q," ")+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h;if(q){if(f){while(p){l=b;while(l=l[p])if(h?l.nodeName.toLowerCase()===r:1===l.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){k=q[u]||(q[u]={}),j=k[a]||[],n=j[0]===w&&j[1],m=j[0]===w&&j[2],l=n&&q.childNodes[n];while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if(1===l.nodeType&&++m&&l===b){k[a]=[w,n,m];break}}else if(s&&(j=(b[u]||(b[u]={}))[a])&&j[0]===w)m=j[1];else while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if((h?l.nodeName.toLowerCase()===r:1===l.nodeType)&&++m&&(s&&((l[u]||(l[u]={}))[a]=[w,m]),l===b))break;return m-=e,m===d||m%d===0&&m/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||ga.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?ia(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=J(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:ia(function(a){var b=[],c=[],d=h(a.replace(R,"$1"));return d[u]?ia(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),b[0]=null,!c.pop()}}),has:ia(function(a){return function(b){return ga(a,b).length>0}}),contains:ia(function(a){return a=a.replace(ca,da),function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:ia(function(a){return W.test(a||"")||ga.error("unsupported lang: "+a),a=a.replace(ca,da).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Z.test(a.nodeName)},input:function(a){return Y.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:oa(function(){return[0]}),last:oa(function(a,b){return[b-1]}),eq:oa(function(a,b,c){return[0>c?c+b:c]}),even:oa(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:oa(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:oa(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:oa(function(a,b,c){for(var d=0>c?c+b:c;++db;b++)d+=a[b].value;return d}function sa(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(i=b[u]||(b[u]={}),(h=i[d])&&h[0]===w&&h[1]===f)return j[2]=h[2];if(i[d]=j,j[2]=a(b,c,g))return!0}}}function ta(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function ua(a,b,c){for(var d=0,e=b.length;e>d;d++)ga(a,b[d],c);return c}function va(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function wa(a,b,c,d,e,f){return d&&!d[u]&&(d=wa(d)),e&&!e[u]&&(e=wa(e,f)),ia(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||ua(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:va(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=va(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?J(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=va(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):H.apply(g,r)})}function xa(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=sa(function(a){return a===b},h,!0),l=sa(function(a){return J(b,a)>-1},h,!0),m=[function(a,c,d){var e=!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d));return b=null,e}];f>i;i++)if(c=d.relative[a[i].type])m=[sa(ta(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return wa(i>1&&ta(m),i>1&&ra(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(R,"$1"),c,e>i&&xa(a.slice(i,e)),f>e&&xa(a=a.slice(e)),f>e&&ra(a))}m.push(c)}return ta(m)}function ya(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,m,o,p=0,q="0",r=f&&[],s=[],t=j,u=f||e&&d.find.TAG("*",k),v=w+=null==t?1:Math.random()||.1,x=u.length;for(k&&(j=g!==n&&g);q!==x&&null!=(l=u[q]);q++){if(e&&l){m=0;while(o=a[m++])if(o(l,g,h)){i.push(l);break}k&&(w=v)}c&&((l=!o&&l)&&p--,f&&r.push(l))}if(p+=q,c&&q!==p){m=0;while(o=b[m++])o(r,s,g,h);if(f){if(p>0)while(q--)r[q]||s[q]||(s[q]=F.call(i));s=va(s)}H.apply(i,s),k&&!f&&s.length>0&&p+b.length>1&&ga.uniqueSort(i)}return k&&(w=v,j=t),r};return c?ia(f):f}return h=ga.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=xa(b[c]),f[u]?d.push(f):e.push(f);f=A(a,ya(e,d)),f.selector=a}return f},i=ga.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(ca,da),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=X.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(ca,da),aa.test(j[0].type)&&pa(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&ra(j),!a)return H.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,aa.test(a)&&pa(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ja(function(a){return 1&a.compareDocumentPosition(n.createElement("div"))}),ja(function(a){return a.innerHTML="","#"===a.firstChild.getAttribute("href")})||ka("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ja(function(a){return a.innerHTML="",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||ka("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),ja(function(a){return null==a.getAttribute("disabled")})||ka(K,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),ga}(a);n.find=t,n.expr=t.selectors,n.expr[":"]=n.expr.pseudos,n.unique=t.uniqueSort,n.text=t.getText,n.isXMLDoc=t.isXML,n.contains=t.contains;var u=n.expr.match.needsContext,v=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,w=/^.[^:#\[\.,]*$/;function x(a,b,c){if(n.isFunction(b))return n.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return n.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(w.test(b))return n.filter(b,a,c);b=n.filter(b,a)}return n.grep(a,function(a){return g.call(b,a)>=0!==c})}n.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?n.find.matchesSelector(d,a)?[d]:[]:n.find.matches(a,n.grep(b,function(a){return 1===a.nodeType}))},n.fn.extend({find:function(a){var b,c=this.length,d=[],e=this;if("string"!=typeof a)return this.pushStack(n(a).filter(function(){for(b=0;c>b;b++)if(n.contains(e[b],this))return!0}));for(b=0;c>b;b++)n.find(a,e[b],d);return d=this.pushStack(c>1?n.unique(d):d),d.selector=this.selector?this.selector+" "+a:a,d},filter:function(a){return this.pushStack(x(this,a||[],!1))},not:function(a){return this.pushStack(x(this,a||[],!0))},is:function(a){return!!x(this,"string"==typeof a&&u.test(a)?n(a):a||[],!1).length}});var y,z=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,A=n.fn.init=function(a,b){var c,d;if(!a)return this;if("string"==typeof a){if(c="<"===a[0]&&">"===a[a.length-1]&&a.length>=3?[null,a,null]:z.exec(a),!c||!c[1]&&b)return!b||b.jquery?(b||y).find(a):this.constructor(b).find(a);if(c[1]){if(b=b instanceof n?b[0]:b,n.merge(this,n.parseHTML(c[1],b&&b.nodeType?b.ownerDocument||b:l,!0)),v.test(c[1])&&n.isPlainObject(b))for(c in b)n.isFunction(this[c])?this[c](b[c]):this.attr(c,b[c]);return this}return d=l.getElementById(c[2]),d&&d.parentNode&&(this.length=1,this[0]=d),this.context=l,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):n.isFunction(a)?"undefined"!=typeof y.ready?y.ready(a):a(n):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),n.makeArray(a,this))};A.prototype=n.fn,y=n(l);var B=/^(?:parents|prev(?:Until|All))/,C={children:!0,contents:!0,next:!0,prev:!0};n.extend({dir:function(a,b,c){var d=[],e=void 0!==c;while((a=a[b])&&9!==a.nodeType)if(1===a.nodeType){if(e&&n(a).is(c))break;d.push(a)}return d},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}}),n.fn.extend({has:function(a){var b=n(a,this),c=b.length;return this.filter(function(){for(var a=0;c>a;a++)if(n.contains(this,b[a]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=u.test(a)||"string"!=typeof a?n(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&n.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?n.unique(f):f)},index:function(a){return a?"string"==typeof a?g.call(n(a),this[0]):g.call(this,a.jquery?a[0]:a):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(n.unique(n.merge(this.get(),n(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function D(a,b){while((a=a[b])&&1!==a.nodeType);return a}n.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return n.dir(a,"parentNode")},parentsUntil:function(a,b,c){return n.dir(a,"parentNode",c)},next:function(a){return D(a,"nextSibling")},prev:function(a){return D(a,"previousSibling")},nextAll:function(a){return n.dir(a,"nextSibling")},prevAll:function(a){return n.dir(a,"previousSibling")},nextUntil:function(a,b,c){return n.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return n.dir(a,"previousSibling",c)},siblings:function(a){return n.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return n.sibling(a.firstChild)},contents:function(a){return a.contentDocument||n.merge([],a.childNodes)}},function(a,b){n.fn[a]=function(c,d){var e=n.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=n.filter(d,e)),this.length>1&&(C[a]||n.unique(e),B.test(a)&&e.reverse()),this.pushStack(e)}});var E=/\S+/g,F={};function G(a){var b=F[a]={};return n.each(a.match(E)||[],function(a,c){b[c]=!0}),b}n.Callbacks=function(a){a="string"==typeof a?F[a]||G(a):n.extend({},a);var b,c,d,e,f,g,h=[],i=!a.once&&[],j=function(l){for(b=a.memory&&l,c=!0,g=e||0,e=0,f=h.length,d=!0;h&&f>g;g++)if(h[g].apply(l[0],l[1])===!1&&a.stopOnFalse){b=!1;break}d=!1,h&&(i?i.length&&j(i.shift()):b?h=[]:k.disable())},k={add:function(){if(h){var c=h.length;!function g(b){n.each(b,function(b,c){var d=n.type(c);"function"===d?a.unique&&k.has(c)||h.push(c):c&&c.length&&"string"!==d&&g(c)})}(arguments),d?f=h.length:b&&(e=c,j(b))}return this},remove:function(){return h&&n.each(arguments,function(a,b){var c;while((c=n.inArray(b,h,c))>-1)h.splice(c,1),d&&(f>=c&&f--,g>=c&&g--)}),this},has:function(a){return a?n.inArray(a,h)>-1:!(!h||!h.length)},empty:function(){return h=[],f=0,this},disable:function(){return h=i=b=void 0,this},disabled:function(){return!h},lock:function(){return i=void 0,b||k.disable(),this},locked:function(){return!i},fireWith:function(a,b){return!h||c&&!i||(b=b||[],b=[a,b.slice?b.slice():b],d?i.push(b):j(b)),this},fire:function(){return k.fireWith(this,arguments),this},fired:function(){return!!c}};return k},n.extend({Deferred:function(a){var b=[["resolve","done",n.Callbacks("once memory"),"resolved"],["reject","fail",n.Callbacks("once memory"),"rejected"],["notify","progress",n.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return n.Deferred(function(c){n.each(b,function(b,f){var g=n.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&n.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?n.extend(a,d):d}},e={};return d.pipe=d.then,n.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=d.call(arguments),e=c.length,f=1!==e||a&&n.isFunction(a.promise)?e:0,g=1===f?a:n.Deferred(),h=function(a,b,c){return function(e){b[a]=this,c[a]=arguments.length>1?d.call(arguments):e,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(e>1)for(i=new Array(e),j=new Array(e),k=new Array(e);e>b;b++)c[b]&&n.isFunction(c[b].promise)?c[b].promise().done(h(b,k,c)).fail(g.reject).progress(h(b,j,i)):--f;return f||g.resolveWith(k,c),g.promise()}});var H;n.fn.ready=function(a){return n.ready.promise().done(a),this},n.extend({isReady:!1,readyWait:1,holdReady:function(a){a?n.readyWait++:n.ready(!0)},ready:function(a){(a===!0?--n.readyWait:n.isReady)||(n.isReady=!0,a!==!0&&--n.readyWait>0||(H.resolveWith(l,[n]),n.fn.triggerHandler&&(n(l).triggerHandler("ready"),n(l).off("ready"))))}});function I(){l.removeEventListener("DOMContentLoaded",I,!1),a.removeEventListener("load",I,!1),n.ready()}n.ready.promise=function(b){return H||(H=n.Deferred(),"complete"===l.readyState?setTimeout(n.ready):(l.addEventListener("DOMContentLoaded",I,!1),a.addEventListener("load",I,!1))),H.promise(b)},n.ready.promise();var J=n.access=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===n.type(c)){e=!0;for(h in c)n.access(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,n.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(n(a),c)})),b))for(;i>h;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f};n.acceptData=function(a){return 1===a.nodeType||9===a.nodeType||!+a.nodeType};function K(){Object.defineProperty(this.cache={},0,{get:function(){return{}}}),this.expando=n.expando+K.uid++}K.uid=1,K.accepts=n.acceptData,K.prototype={key:function(a){if(!K.accepts(a))return 0;var b={},c=a[this.expando];if(!c){c=K.uid++;try{b[this.expando]={value:c},Object.defineProperties(a,b)}catch(d){b[this.expando]=c,n.extend(a,b)}}return this.cache[c]||(this.cache[c]={}),c},set:function(a,b,c){var d,e=this.key(a),f=this.cache[e];if("string"==typeof b)f[b]=c;else if(n.isEmptyObject(f))n.extend(this.cache[e],b);else for(d in b)f[d]=b[d];return f},get:function(a,b){var c=this.cache[this.key(a)];return void 0===b?c:c[b]},access:function(a,b,c){var d;return void 0===b||b&&"string"==typeof b&&void 0===c?(d=this.get(a,b),void 0!==d?d:this.get(a,n.camelCase(b))):(this.set(a,b,c),void 0!==c?c:b)},remove:function(a,b){var c,d,e,f=this.key(a),g=this.cache[f];if(void 0===b)this.cache[f]={};else{n.isArray(b)?d=b.concat(b.map(n.camelCase)):(e=n.camelCase(b),b in g?d=[b,e]:(d=e,d=d in g?[d]:d.match(E)||[])),c=d.length;while(c--)delete g[d[c]]}},hasData:function(a){return!n.isEmptyObject(this.cache[a[this.expando]]||{})},discard:function(a){a[this.expando]&&delete this.cache[a[this.expando]]}};var L=new K,M=new K,N=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,O=/([A-Z])/g;function P(a,b,c){var d;if(void 0===c&&1===a.nodeType)if(d="data-"+b.replace(O,"-$1").toLowerCase(),c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:N.test(c)?n.parseJSON(c):c}catch(e){}M.set(a,b,c)}else c=void 0;return c}n.extend({hasData:function(a){return M.hasData(a)||L.hasData(a)},data:function(a,b,c){ +return M.access(a,b,c)},removeData:function(a,b){M.remove(a,b)},_data:function(a,b,c){return L.access(a,b,c)},_removeData:function(a,b){L.remove(a,b)}}),n.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=M.get(f),1===f.nodeType&&!L.get(f,"hasDataAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=n.camelCase(d.slice(5)),P(f,d,e[d])));L.set(f,"hasDataAttrs",!0)}return e}return"object"==typeof a?this.each(function(){M.set(this,a)}):J(this,function(b){var c,d=n.camelCase(a);if(f&&void 0===b){if(c=M.get(f,a),void 0!==c)return c;if(c=M.get(f,d),void 0!==c)return c;if(c=P(f,d,void 0),void 0!==c)return c}else this.each(function(){var c=M.get(this,d);M.set(this,d,b),-1!==a.indexOf("-")&&void 0!==c&&M.set(this,a,b)})},null,b,arguments.length>1,null,!0)},removeData:function(a){return this.each(function(){M.remove(this,a)})}}),n.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=L.get(a,b),c&&(!d||n.isArray(c)?d=L.access(a,b,n.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=n.queue(a,b),d=c.length,e=c.shift(),f=n._queueHooks(a,b),g=function(){n.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return L.get(a,c)||L.access(a,c,{empty:n.Callbacks("once memory").add(function(){L.remove(a,[b+"queue",c])})})}}),n.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.lengthx",k.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue}();var U="undefined";k.focusinBubbles="onfocusin"in a;var V=/^key/,W=/^(?:mouse|pointer|contextmenu)|click/,X=/^(?:focusinfocus|focusoutblur)$/,Y=/^([^.]*)(?:\.(.+)|)$/;function Z(){return!0}function $(){return!1}function _(){try{return l.activeElement}catch(a){}}n.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=L.get(a);if(r){c.handler&&(f=c,c=f.handler,e=f.selector),c.guid||(c.guid=n.guid++),(i=r.events)||(i=r.events={}),(g=r.handle)||(g=r.handle=function(b){return typeof n!==U&&n.event.triggered!==b.type?n.event.dispatch.apply(a,arguments):void 0}),b=(b||"").match(E)||[""],j=b.length;while(j--)h=Y.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o&&(l=n.event.special[o]||{},o=(e?l.delegateType:l.bindType)||o,l=n.event.special[o]||{},k=n.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&n.expr.match.needsContext.test(e),namespace:p.join(".")},f),(m=i[o])||(m=i[o]=[],m.delegateCount=0,l.setup&&l.setup.call(a,d,p,g)!==!1||a.addEventListener&&a.addEventListener(o,g,!1)),l.add&&(l.add.call(a,k),k.handler.guid||(k.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,k):m.push(k),n.event.global[o]=!0)}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=L.hasData(a)&&L.get(a);if(r&&(i=r.events)){b=(b||"").match(E)||[""],j=b.length;while(j--)if(h=Y.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=n.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,m=i[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),g=f=m.length;while(f--)k=m[f],!e&&q!==k.origType||c&&c.guid!==k.guid||h&&!h.test(k.namespace)||d&&d!==k.selector&&("**"!==d||!k.selector)||(m.splice(f,1),k.selector&&m.delegateCount--,l.remove&&l.remove.call(a,k));g&&!m.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||n.removeEvent(a,o,r.handle),delete i[o])}else for(o in i)n.event.remove(a,o+b[j],c,d,!0);n.isEmptyObject(i)&&(delete r.handle,L.remove(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,m,o,p=[d||l],q=j.call(b,"type")?b.type:b,r=j.call(b,"namespace")?b.namespace.split("."):[];if(g=h=d=d||l,3!==d.nodeType&&8!==d.nodeType&&!X.test(q+n.event.triggered)&&(q.indexOf(".")>=0&&(r=q.split("."),q=r.shift(),r.sort()),k=q.indexOf(":")<0&&"on"+q,b=b[n.expando]?b:new n.Event(q,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=r.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+r.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:n.makeArray(c,[b]),o=n.event.special[q]||{},e||!o.trigger||o.trigger.apply(d,c)!==!1)){if(!e&&!o.noBubble&&!n.isWindow(d)){for(i=o.delegateType||q,X.test(i+q)||(g=g.parentNode);g;g=g.parentNode)p.push(g),h=g;h===(d.ownerDocument||l)&&p.push(h.defaultView||h.parentWindow||a)}f=0;while((g=p[f++])&&!b.isPropagationStopped())b.type=f>1?i:o.bindType||q,m=(L.get(g,"events")||{})[b.type]&&L.get(g,"handle"),m&&m.apply(g,c),m=k&&g[k],m&&m.apply&&n.acceptData(g)&&(b.result=m.apply(g,c),b.result===!1&&b.preventDefault());return b.type=q,e||b.isDefaultPrevented()||o._default&&o._default.apply(p.pop(),c)!==!1||!n.acceptData(d)||k&&n.isFunction(d[q])&&!n.isWindow(d)&&(h=d[k],h&&(d[k]=null),n.event.triggered=q,d[q](),n.event.triggered=void 0,h&&(d[k]=h)),b.result}},dispatch:function(a){a=n.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(L.get(this,"events")||{})[a.type]||[],k=n.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=n.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,c=0;while((g=f.handlers[c++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(g.namespace))&&(a.handleObj=g,a.data=g.data,e=((n.event.special[g.origType]||{}).handle||g.handler).apply(f.elem,i),void 0!==e&&(a.result=e)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(!a.button||"click"!==a.type))for(;i!==this;i=i.parentNode||this)if(i.disabled!==!0||"click"!==a.type){for(d=[],c=0;h>c;c++)f=b[c],e=f.selector+" ",void 0===d[e]&&(d[e]=f.needsContext?n(e,this).index(i)>=0:n.find(e,this,null,[i]).length),d[e]&&d.push(f);d.length&&g.push({elem:i,handlers:d})}return h]*)\/>/gi,ba=/<([\w:]+)/,ca=/<|&#?\w+;/,da=/<(?:script|style|link)/i,ea=/checked\s*(?:[^=]|=\s*.checked.)/i,fa=/^$|\/(?:java|ecma)script/i,ga=/^true\/(.*)/,ha=/^\s*\s*$/g,ia={option:[1,""],thead:[1,"","
                                                                      "],col:[2,"","
                                                                      "],tr:[2,"","
                                                                      "],td:[3,"","
                                                                      "],_default:[0,"",""]};ia.optgroup=ia.option,ia.tbody=ia.tfoot=ia.colgroup=ia.caption=ia.thead,ia.th=ia.td;function ja(a,b){return n.nodeName(a,"table")&&n.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function ka(a){return a.type=(null!==a.getAttribute("type"))+"/"+a.type,a}function la(a){var b=ga.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function ma(a,b){for(var c=0,d=a.length;d>c;c++)L.set(a[c],"globalEval",!b||L.get(b[c],"globalEval"))}function na(a,b){var c,d,e,f,g,h,i,j;if(1===b.nodeType){if(L.hasData(a)&&(f=L.access(a),g=L.set(b,f),j=f.events)){delete g.handle,g.events={};for(e in j)for(c=0,d=j[e].length;d>c;c++)n.event.add(b,e,j[e][c])}M.hasData(a)&&(h=M.access(a),i=n.extend({},h),M.set(b,i))}}function oa(a,b){var c=a.getElementsByTagName?a.getElementsByTagName(b||"*"):a.querySelectorAll?a.querySelectorAll(b||"*"):[];return void 0===b||b&&n.nodeName(a,b)?n.merge([a],c):c}function pa(a,b){var c=b.nodeName.toLowerCase();"input"===c&&T.test(a.type)?b.checked=a.checked:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}n.extend({clone:function(a,b,c){var d,e,f,g,h=a.cloneNode(!0),i=n.contains(a.ownerDocument,a);if(!(k.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||n.isXMLDoc(a)))for(g=oa(h),f=oa(a),d=0,e=f.length;e>d;d++)pa(f[d],g[d]);if(b)if(c)for(f=f||oa(a),g=g||oa(h),d=0,e=f.length;e>d;d++)na(f[d],g[d]);else na(a,h);return g=oa(h,"script"),g.length>0&&ma(g,!i&&oa(a,"script")),h},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,k=b.createDocumentFragment(),l=[],m=0,o=a.length;o>m;m++)if(e=a[m],e||0===e)if("object"===n.type(e))n.merge(l,e.nodeType?[e]:e);else if(ca.test(e)){f=f||k.appendChild(b.createElement("div")),g=(ba.exec(e)||["",""])[1].toLowerCase(),h=ia[g]||ia._default,f.innerHTML=h[1]+e.replace(aa,"<$1>")+h[2],j=h[0];while(j--)f=f.lastChild;n.merge(l,f.childNodes),f=k.firstChild,f.textContent=""}else l.push(b.createTextNode(e));k.textContent="",m=0;while(e=l[m++])if((!d||-1===n.inArray(e,d))&&(i=n.contains(e.ownerDocument,e),f=oa(k.appendChild(e),"script"),i&&ma(f),c)){j=0;while(e=f[j++])fa.test(e.type||"")&&c.push(e)}return k},cleanData:function(a){for(var b,c,d,e,f=n.event.special,g=0;void 0!==(c=a[g]);g++){if(n.acceptData(c)&&(e=c[L.expando],e&&(b=L.cache[e]))){if(b.events)for(d in b.events)f[d]?n.event.remove(c,d):n.removeEvent(c,d,b.handle);L.cache[e]&&delete L.cache[e]}delete M.cache[c[M.expando]]}}}),n.fn.extend({text:function(a){return J(this,function(a){return void 0===a?n.text(this):this.empty().each(function(){(1===this.nodeType||11===this.nodeType||9===this.nodeType)&&(this.textContent=a)})},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=ja(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=ja(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?n.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||n.cleanData(oa(c)),c.parentNode&&(b&&n.contains(c.ownerDocument,c)&&ma(oa(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++)1===a.nodeType&&(n.cleanData(oa(a,!1)),a.textContent="");return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return n.clone(this,a,b)})},html:function(a){return J(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a&&1===b.nodeType)return b.innerHTML;if("string"==typeof a&&!da.test(a)&&!ia[(ba.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(aa,"<$1>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(n.cleanData(oa(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,n.cleanData(oa(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,l=this.length,m=this,o=l-1,p=a[0],q=n.isFunction(p);if(q||l>1&&"string"==typeof p&&!k.checkClone&&ea.test(p))return this.each(function(c){var d=m.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(l&&(c=n.buildFragment(a,this[0].ownerDocument,!1,this),d=c.firstChild,1===c.childNodes.length&&(c=d),d)){for(f=n.map(oa(c,"script"),ka),g=f.length;l>j;j++)h=c,j!==o&&(h=n.clone(h,!0,!0),g&&n.merge(f,oa(h,"script"))),b.call(this[j],h,j);if(g)for(i=f[f.length-1].ownerDocument,n.map(f,la),j=0;g>j;j++)h=f[j],fa.test(h.type||"")&&!L.access(h,"globalEval")&&n.contains(i,h)&&(h.src?n._evalUrl&&n._evalUrl(h.src):n.globalEval(h.textContent.replace(ha,"")))}return this}}),n.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){n.fn[a]=function(a){for(var c,d=[],e=n(a),g=e.length-1,h=0;g>=h;h++)c=h===g?this:this.clone(!0),n(e[h])[b](c),f.apply(d,c.get());return this.pushStack(d)}});var qa,ra={};function sa(b,c){var d,e=n(c.createElement(b)).appendTo(c.body),f=a.getDefaultComputedStyle&&(d=a.getDefaultComputedStyle(e[0]))?d.display:n.css(e[0],"display");return e.detach(),f}function ta(a){var b=l,c=ra[a];return c||(c=sa(a,b),"none"!==c&&c||(qa=(qa||n("'); + return true; + } + + return false; + } + + /** + * Generate HTML from item URL + * + * @access public + * @param Item $item + * @return bool + */ + public function generateHtmlFromUrl(Item $item) + { + if (preg_match('/youtube\.com\/watch\?v=(.*)/', $item->getUrl(), $matches)) { + $item->setContent(''); + return true; + } + + return false; + } +} diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Logging/Logger.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Logging/Logger.php new file mode 100644 index 0000000..caec463 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Logging/Logger.php @@ -0,0 +1,114 @@ +format('Y-m-d H:i:s').'] '.$message; + } + } + + /** + * Get all logged messages. + * + * @static + * + * @return array + */ + public static function getMessages() + { + return self::$messages; + } + + /** + * Remove all logged messages. + * + * @static + */ + public static function deleteMessages() + { + self::$messages = array(); + } + + /** + * Set a different timezone. + * + * @static + * + * @see http://php.net/manual/en/timezones.php + * + * @param string $timezone Timezone + */ + public static function setTimeZone($timezone) + { + self::$timezone = $timezone ?: self::$timezone; + } + + /** + * Get all messages serialized into a string. + * + * @static + * + * @return string + */ + public static function toString() + { + return implode(PHP_EOL, self::$messages).PHP_EOL; + } +} diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Parser/Atom.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Parser/Atom.php new file mode 100644 index 0000000..bb2d40a --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Parser/Atom.php @@ -0,0 +1,378 @@ + 'http://www.w3.org/2005/Atom', + ); + + /** + * Get the path to the items XML tree. + * + * @param SimpleXMLElement $xml Feed xml + * @return SimpleXMLElement[] + */ + public function getItemsTree(SimpleXMLElement $xml) + { + return XmlParser::getXPathResult($xml, 'atom:entry', $this->namespaces) + ?: XmlParser::getXPathResult($xml, 'entry'); + } + + /** + * Find the feed url. + * + * @param SimpleXMLElement $xml Feed xml + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findFeedUrl(SimpleXMLElement $xml, Feed $feed) + { + $feed->setFeedUrl($this->getUrl($xml, 'self')); + } + + /** + * Find the site url. + * + * @param SimpleXMLElement $xml Feed xml + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findSiteUrl(SimpleXMLElement $xml, Feed $feed) + { + $feed->setSiteUrl($this->getUrl($xml, 'alternate', true)); + } + + /** + * Find the feed description. + * + * @param SimpleXMLElement $xml Feed xml + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findFeedDescription(SimpleXMLElement $xml, Feed $feed) + { + $description = XmlParser::getXPathResult($xml, 'atom:subtitle', $this->namespaces) + ?: XmlParser::getXPathResult($xml, 'subtitle'); + + $feed->setDescription(XmlParser::getValue($description)); + } + + /** + * Find the feed logo url. + * + * @param SimpleXMLElement $xml Feed xml + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findFeedLogo(SimpleXMLElement $xml, Feed $feed) + { + $logo = XmlParser::getXPathResult($xml, 'atom:logo', $this->namespaces) + ?: XmlParser::getXPathResult($xml, 'logo'); + + $feed->setLogo(XmlParser::getValue($logo)); + } + + /** + * Find the feed icon. + * + * @param SimpleXMLElement $xml Feed xml + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findFeedIcon(SimpleXMLElement $xml, Feed $feed) + { + $icon = XmlParser::getXPathResult($xml, 'atom:icon', $this->namespaces) + ?: XmlParser::getXPathResult($xml, 'icon'); + + $feed->setIcon(XmlParser::getValue($icon)); + } + + /** + * Find the feed title. + * + * @param SimpleXMLElement $xml Feed xml + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findFeedTitle(SimpleXMLElement $xml, Feed $feed) + { + $title = XmlParser::getXPathResult($xml, 'atom:title', $this->namespaces) + ?: XmlParser::getXPathResult($xml, 'title'); + + $feed->setTitle(Filter::stripWhiteSpace(XmlParser::getValue($title)) ?: $feed->getSiteUrl()); + } + + /** + * Find the feed language. + * + * @param SimpleXMLElement $xml Feed xml + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findFeedLanguage(SimpleXMLElement $xml, Feed $feed) + { + $language = XmlParser::getXPathResult($xml, '*[not(self::atom:entry)]/@xml:lang', $this->namespaces) + ?: XmlParser::getXPathResult($xml, '@xml:lang'); + + $feed->setLanguage(XmlParser::getValue($language)); + } + + /** + * Find the feed id. + * + * @param SimpleXMLElement $xml Feed xml + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findFeedId(SimpleXMLElement $xml, Feed $feed) + { + $id = XmlParser::getXPathResult($xml, 'atom:id', $this->namespaces) + ?: XmlParser::getXPathResult($xml, 'id'); + + $feed->setId(XmlParser::getValue($id)); + } + + /** + * Find the feed date. + * + * @param SimpleXMLElement $xml Feed xml + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findFeedDate(SimpleXMLElement $xml, Feed $feed) + { + $updated = XmlParser::getXPathResult($xml, 'atom:updated', $this->namespaces) + ?: XmlParser::getXPathResult($xml, 'updated'); + + $feed->setDate($this->getDateParser()->getDateTime(XmlParser::getValue($updated))); + } + + /** + * Find the item published date. + * + * @param SimpleXMLElement $entry Feed item + * @param Item $item Item object + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findItemPublishedDate(SimpleXMLElement $entry, Item $item, Feed $feed) + { + $date = XmlParser::getXPathResult($entry, 'atom:published', $this->namespaces) + ?: XmlParser::getXPathResult($entry, 'published'); + + $item->setPublishedDate(!empty($date) ? $this->getDateParser()->getDateTime((string) current($date)) : null); + } + + /** + * Find the item updated date. + * + * @param SimpleXMLElement $entry Feed item + * @param Item $item Item object + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findItemUpdatedDate(SimpleXMLElement $entry, Item $item, Feed $feed) + { + $date = XmlParser::getXPathResult($entry, 'atom:updated', $this->namespaces) + ?: XmlParser::getXPathResult($entry, 'updated'); + + $item->setUpdatedDate(!empty($date) ? $this->getDateParser()->getDateTime((string) current($date)) : null); + } + + /** + * Find the item title. + * + * @param SimpleXMLElement $entry Feed item + * @param Item $item Item object + */ + public function findItemTitle(SimpleXMLElement $entry, Item $item) + { + $title = XmlParser::getXPathResult($entry, 'atom:title', $this->namespaces) + ?: XmlParser::getXPathResult($entry, 'title'); + + $item->setTitle(Filter::stripWhiteSpace(XmlParser::getValue($title)) ?: $item->getUrl()); + } + + /** + * Find the item author. + * + * @param SimpleXMLElement $xml Feed + * @param SimpleXMLElement $entry Feed item + * @param \PicoFeed\Parser\Item $item Item object + */ + public function findItemAuthor(SimpleXMLElement $xml, SimpleXMLElement $entry, Item $item) + { + $author = XmlParser::getXPathResult($entry, 'atom:author/atom:name', $this->namespaces) + ?: XmlParser::getXPathResult($entry, 'author/name') + ?: XmlParser::getXPathResult($xml, 'atom:author/atom:name', $this->namespaces) + ?: XmlParser::getXPathResult($xml, 'author/name'); + + $item->setAuthor(XmlParser::getValue($author)); + } + + /** + * Find the item content. + * + * @param SimpleXMLElement $entry Feed item + * @param \PicoFeed\Parser\Item $item Item object + */ + public function findItemContent(SimpleXMLElement $entry, Item $item) + { + $item->setContent($this->getContent($entry)); + } + + /** + * Find the item URL. + * + * @param SimpleXMLElement $entry Feed item + * @param \PicoFeed\Parser\Item $item Item object + */ + public function findItemUrl(SimpleXMLElement $entry, Item $item) + { + $item->setUrl($this->getUrl($entry, 'alternate', true)); + } + + /** + * Genereate the item id. + * + * @param SimpleXMLElement $entry Feed item + * @param \PicoFeed\Parser\Item $item Item object + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findItemId(SimpleXMLElement $entry, Item $item, Feed $feed) + { + $id = XmlParser::getXPathResult($entry, 'atom:id', $this->namespaces) + ?: XmlParser::getXPathResult($entry, 'id'); + + if (!empty($id)) { + $item->setId($this->generateId(XmlParser::getValue($id))); + } else { + $item->setId($this->generateId( + $item->getTitle(), $item->getUrl(), $item->getContent() + )); + } + } + + /** + * Find the item enclosure. + * + * @param SimpleXMLElement $entry Feed item + * @param \PicoFeed\Parser\Item $item Item object + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findItemEnclosure(SimpleXMLElement $entry, Item $item, Feed $feed) + { + $enclosure = $this->findLink($entry, 'enclosure'); + + if ($enclosure) { + $item->setEnclosureUrl(Url::resolve((string) $enclosure['href'], $feed->getSiteUrl())); + $item->setEnclosureType((string) $enclosure['type']); + } + } + + /** + * Find the item language. + * + * @param SimpleXMLElement $entry Feed item + * @param \PicoFeed\Parser\Item $item Item object + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findItemLanguage(SimpleXMLElement $entry, Item $item, Feed $feed) + { + $language = XmlParser::getXPathResult($entry, './/@xml:lang'); + $item->setLanguage(XmlParser::getValue($language) ?: $feed->getLanguage()); + } + + /** + * Find the item categories. + * + * @param SimpleXMLElement $entry Feed item + * @param Item $item Item object + * @param Feed $feed Feed object + */ + public function findItemCategories(SimpleXMLElement $entry, Item $item, Feed $feed) + { + $categories = XmlParser::getXPathResult($entry, 'atom:category/@term', $this->namespaces) + ?: XmlParser::getXPathResult($entry, 'category/@term'); + $item->setCategoriesFromXml($categories); + } + + /** + * Get the URL from a link tag. + * + * @param SimpleXMLElement $xml XML tag + * @param string $rel Link relationship: alternate, enclosure, related, self, via + * @return string + */ + private function getUrl(SimpleXMLElement $xml, $rel, $fallback = false) + { + $link = $this->findLink($xml, $rel); + + if ($link) { + return (string) $link['href']; + } + + if ($fallback) { + $link = $this->findLink($xml, ''); + return $link ? (string) $link['href'] : ''; + } + + return ''; + } + + /** + * Get a link tag that match a relationship. + * + * @param SimpleXMLElement $xml XML tag + * @param string $rel Link relationship: alternate, enclosure, related, self, via + * @return SimpleXMLElement|null + */ + private function findLink(SimpleXMLElement $xml, $rel) + { + $links = XmlParser::getXPathResult($xml, 'atom:link', $this->namespaces) + ?: XmlParser::getXPathResult($xml, 'link'); + + foreach ($links as $link) { + if ($rel === (string) $link['rel']) { + return $link; + } + } + + return null; + } + + /** + * Get the entry content. + * + * @param SimpleXMLElement $entry XML Entry + * @return string + */ + private function getContent(SimpleXMLElement $entry) + { + $content = current( + XmlParser::getXPathResult($entry, 'atom:content', $this->namespaces) + ?: XmlParser::getXPathResult($entry, 'content') + ); + + if (!empty($content) && count($content->children())) { + $xml_string = ''; + + foreach ($content->children() as $child) { + $xml_string .= $child->asXML(); + } + + return $xml_string; + } elseif (trim((string) $content) !== '') { + return (string) $content; + } + + $summary = XmlParser::getXPathResult($entry, 'atom:summary', $this->namespaces) + ?: XmlParser::getXPathResult($entry, 'summary'); + + return (string) current($summary); + } +} diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Parser/DateParser.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Parser/DateParser.php new file mode 100644 index 0000000..0e5b80e --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Parser/DateParser.php @@ -0,0 +1,128 @@ + length ]. + * + * @var array + */ + public $formats = array( + DATE_ATOM => null, + DATE_RSS => null, + DATE_COOKIE => null, + DATE_ISO8601 => null, + DATE_RFC822 => null, + DATE_RFC850 => null, + DATE_RFC1036 => null, + DATE_RFC1123 => null, + DATE_RFC2822 => null, + DATE_RFC3339 => null, + 'l, d M Y H:i:s' => null, + 'D, d M Y H:i:s' => 25, + 'D, d M Y h:i:s' => 25, + 'D M d Y H:i:s' => 24, + 'j M Y H:i:s' => 20, + 'Y-m-d H:i:s' => 19, + 'Y-m-d\TH:i:s' => 19, + 'd/m/Y H:i:s' => 19, + 'D, d M Y' => 16, + 'Y-m-d' => 10, + 'd-m-Y' => 10, + 'm-d-Y' => 10, + 'd.m.Y' => 10, + 'm.d.Y' => 10, + 'd/m/Y' => 10, + 'm/d/Y' => 10, + ); + + /** + * Try to parse all date format for broken feeds. + * + * @param string $value Original date format + * + * @return DateTime + */ + public function getDateTime($value) + { + $value = trim($value); + + foreach ($this->formats as $format => $length) { + $truncated_value = $value; + if ($length !== null) { + $truncated_value = substr($truncated_value, 0, $length); + } + + $date = $this->getValidDate($format, $truncated_value); + if ($date !== false) { + return $date; + } + } + + return $this->getCurrentDateTime(); + } + + /** + * Get a valid date from a given format. + * + * @param string $format Date format + * @param string $value Original date value + * + * @return DateTime|bool + */ + public function getValidDate($format, $value) + { + $date = DateTime::createFromFormat($format, $value, $this->getTimeZone()); + + if ($date !== false) { + $errors = DateTime::getLastErrors(); + + if ($errors['error_count'] === 0 && $errors['warning_count'] === 0) { + return $date; + } + } + + return false; + } + + /** + * Get the current datetime. + * + * @return DateTime + */ + public function getCurrentDateTime() + { + return new DateTime('now', $this->getTimeZone()); + } + + /** + * Get DateTimeZone instance + * + * @access public + * @return DateTimeZone + */ + public function getTimeZone() + { + return new DateTimeZone($this->config->getTimezone() ?: $this->timezone); + } +} diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Parser/Feed.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Parser/Feed.php new file mode 100644 index 0000000..a56e71c --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Parser/Feed.php @@ -0,0 +1,315 @@ +$property.PHP_EOL; + } + + $output .= 'Feed::date = '.$this->date->format(DATE_RFC822).PHP_EOL; + $output .= 'Feed::isRTL() = '.($this->isRTL() ? 'true' : 'false').PHP_EOL; + $output .= 'Feed::items = '.count($this->items).' items'.PHP_EOL; + + foreach ($this->items as $item) { + $output .= '----'.PHP_EOL; + $output .= $item; + } + + return $output; + } + + /** + * Get title. + */ + public function getTitle() + { + return $this->title; + } + + /** + * Get description. + */ + public function getDescription() + { + return $this->description; + } + + /** + * Get the logo url. + */ + public function getLogo() + { + return $this->logo; + } + + /** + * Get the icon url. + */ + public function getIcon() + { + return $this->icon; + } + + /** + * Get feed url. + */ + public function getFeedUrl() + { + return $this->feedUrl; + } + + /** + * Get site url. + */ + public function getSiteUrl() + { + return $this->siteUrl; + } + + /** + * Get date. + */ + public function getDate() + { + return $this->date; + } + + /** + * Get language. + */ + public function getLanguage() + { + return $this->language; + } + + /** + * Get id. + */ + public function getId() + { + return $this->id; + } + + /** + * Get feed items. + */ + public function getItems() + { + return $this->items; + } + + /** + * Return true if the feed is "Right to Left". + * + * @return bool + */ + public function isRTL() + { + return Parser::isLanguageRTL($this->language); + } + + /** + * Set feed items. + * + * @param Item[] $items + * @return Feed + */ + public function setItems(array $items) + { + $this->items = $items; + return $this; + } + + /** + * Set feed id. + * + * @param string $id + * @return Feed + */ + public function setId($id) + { + $this->id = $id; + return $this; + } + + /** + * Set feed title. + * + * @param string $title + * @return Feed + */ + public function setTitle($title) + { + $this->title = $title; + return $this; + } + + /** + * Set feed description. + * + * @param string $description + * @return Feed + */ + public function setDescription($description) + { + $this->description = $description; + return $this; + } + + /** + * Set feed url. + * + * @param string $feedUrl + * @return Feed + */ + public function setFeedUrl($feedUrl) + { + $this->feedUrl = $feedUrl; + return $this; + } + + /** + * Set feed website url. + * + * @param string $siteUrl + * @return Feed + */ + public function setSiteUrl($siteUrl) + { + $this->siteUrl = $siteUrl; + return $this; + } + + /** + * Set feed date. + * + * @param \DateTime $date + * @return Feed + */ + public function setDate($date) + { + $this->date = $date; + return $this; + } + + /** + * Set feed language. + * + * @param string $language + * @return Feed + */ + public function setLanguage($language) + { + $this->language = $language; + return $this; + } + + /** + * Set feed logo. + * + * @param string $logo + * @return Feed + */ + public function setLogo($logo) + { + $this->logo = $logo; + return $this; + } + + /** + * Set feed icon. + * + * @param string $icon + * @return Feed + */ + public function setIcon($icon) + { + $this->icon = $icon; + return $this; + } +} diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Parser/Item.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Parser/Item.php new file mode 100644 index 0000000..2ce772d --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Parser/Item.php @@ -0,0 +1,533 @@ +namespaces); + } + + /** + * Get specific XML tag or attribute value. + * + * @param string $tag Tag name (examples: guid, media:content) + * @param string $attribute Tag attribute + * + * @return array|false Tag values or error + */ + public function getTag($tag, $attribute = '') + { + if ($attribute !== '') { + $attribute = '/@'.$attribute; + } + + $query = './/'.$tag.$attribute; + $elements = XmlParser::getXPathResult($this->xml, $query, $this->namespaces); + + if ($elements === false) { // xPath error + return false; + } + + return array_map(function ($element) { return (string) $element;}, $elements); + } + + /** + * Return item information. + * + * @return string + */ + public function __toString() + { + $output = ''; + + foreach (array('id', 'title', 'url', 'language', 'author', 'enclosureUrl', 'enclosureType') as $property) { + $output .= 'Item::'.$property.' = '.$this->$property.PHP_EOL; + } + + $publishedDate = $this->publishedDate != null ? $this->publishedDate->format(DATE_RFC822) : null; + $updatedDate = $this->updatedDate != null ? $this->updatedDate->format(DATE_RFC822) : null; + + $categoryString = $this->categories != null ? implode(',', $this->categories) : null; + + $output .= 'Item::date = '.$this->date->format(DATE_RFC822).PHP_EOL; + $output .= 'Item::publishedDate = '.$publishedDate.PHP_EOL; + $output .= 'Item::updatedDate = '.$updatedDate.PHP_EOL; + $output .= 'Item::isRTL() = '.($this->isRTL() ? 'true' : 'false').PHP_EOL; + $output .= 'Item::categories = ['.$categoryString.']'.PHP_EOL; + $output .= 'Item::content = '.strlen($this->content).' bytes'.PHP_EOL; + + return $output; + } + + /** + * Get title. + * + * @return string + */ + public function getTitle() + { + return $this->title; + } + + /** + * Get URL + * + * @access public + * @return string + */ + public function getUrl() + { + return $this->url; + } + + /** + * Set URL + * + * @access public + * @param string $url + * @return Item + */ + public function setUrl($url) + { + $this->url = $url; + return $this; + } + + /** + * Get id. + * + * @return string + */ + public function getId() + { + return $this->id; + } + + /** + * Get date. + * + * @return \DateTime + */ + public function getDate() + { + return $this->date; + } + + /** + * Get published date. + * + * @return \DateTime + */ + public function getPublishedDate() + { + return $this->publishedDate; + } + + /** + * Get updated date. + * + * @return \DateTime + */ + public function getUpdatedDate() + { + return $this->updatedDate; + } + + /** + * Get content. + * + * @return string + */ + public function getContent() + { + return $this->content; + } + + /** + * Set content + * + * @access public + * @param string $value + * @return Item + */ + public function setContent($value) + { + $this->content = $value; + return $this; + } + + /** + * Get enclosure url. + * + * @return string + */ + public function getEnclosureUrl() + { + return $this->enclosureUrl; + } + + /** + * Get enclosure type. + * + * @return string + */ + public function getEnclosureType() + { + return $this->enclosureType; + } + + /** + * Get language. + * + * @return string + */ + public function getLanguage() + { + return $this->language; + } + + /** + * Get categories. + * + * @return array + */ + public function getCategories() + { + return $this->categories; + } + + /** + * Get author. + * + * @return string + */ + public function getAuthor() + { + return $this->author; + } + + /** + * Return true if the item is "Right to Left". + * + * @return bool + */ + public function isRTL() + { + return Parser::isLanguageRTL($this->language); + } + + /** + * Set item id. + * + * @param string $id + * @return Item + */ + public function setId($id) + { + $this->id = $id; + return $this; + } + + /** + * Set item title. + * + * @param string $title + * @return Item + */ + public function setTitle($title) + { + $this->title = $title; + return $this; + } + + /** + * Set author. + * + * @param string $author + * @return Item + */ + public function setAuthor($author) + { + $this->author = $author; + return $this; + } + + /** + * Set item date. + * + * @param \DateTime $date + * @return Item + */ + public function setDate($date) + { + $this->date = $date; + return $this; + } + + /** + * Set item published date. + * + * @param \DateTime $publishedDate + * @return Item + */ + public function setPublishedDate($publishedDate) + { + $this->publishedDate = $publishedDate; + return $this; + } + + /** + * Set item updated date. + * + * @param \DateTime $updatedDate + * @return Item + */ + public function setUpdatedDate($updatedDate) + { + $this->updatedDate = $updatedDate; + return $this; + } + + /** + * Set enclosure url. + * + * @param string $enclosureUrl + * @return Item + */ + public function setEnclosureUrl($enclosureUrl) + { + $this->enclosureUrl = $enclosureUrl; + return $this; + } + + /** + * Set enclosure type. + * + * @param string $enclosureType + * @return Item + */ + public function setEnclosureType($enclosureType) + { + $this->enclosureType = $enclosureType; + return $this; + } + + /** + * Set item language. + * + * @param string $language + * @return Item + */ + public function setLanguage($language) + { + $this->language = $language; + return $this; + } + + /** + * Set item categories. + * + * @param array $categories + * @return Item + */ + public function setCategories($categories) + { + $this->categories = $categories; + return $this; + } + + /** + * Set item categories from xml. + * + * @param |SimpleXMLElement[] $categories + * @return Item + */ + public function setCategoriesFromXml($categories) + { + if ($categories !== false) { + $this->setCategories( + array_map( + function ($element) { + return trim((string) $element); + }, + $categories + ) + ); + } + + return $this; + } + + /** + * Set raw XML. + * + * @param \SimpleXMLElement $xml + * @return Item + */ + public function setXml($xml) + { + $this->xml = $xml; + return $this; + } + + /** + * Get raw XML. + * + * @return \SimpleXMLElement + */ + public function getXml() + { + return $this->xml; + } + + /** + * Set XML namespaces. + * + * @param array $namespaces + * @return Item + */ + public function setNamespaces($namespaces) + { + $this->namespaces = $namespaces; + return $this; + } + + /** + * Get XML namespaces. + * + * @return array + */ + public function getNamespaces() + { + return $this->namespaces; + } +} diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Parser/MalformedXmlException.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Parser/MalformedXmlException.php new file mode 100644 index 0000000..efaf0ff --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Parser/MalformedXmlException.php @@ -0,0 +1,13 @@ +fallback_url = $fallback_url; + $xml_encoding = XmlParser::getEncodingFromXmlTag($content); + + // Strip XML tag to avoid multiple encoding/decoding in the next XML processing + $this->content = Filter::stripXmlTag($content); + + // Encode everything in UTF-8 + Logger::setMessage(get_called_class().': HTTP Encoding "'.$http_encoding.'" ; XML Encoding "'.$xml_encoding.'"'); + $this->content = Encoding::convert($this->content, $xml_encoding ?: $http_encoding); + + $this->itemPostProcessor = new ItemPostProcessor($this->config); + $this->itemPostProcessor->register(new ContentGeneratorProcessor($this->config)); + $this->itemPostProcessor->register(new ContentFilterProcessor($this->config)); + } + + /** + * Parse the document. + * @return Feed + * @throws MalformedXmlException + */ + public function execute() + { + Logger::setMessage(get_called_class().': begin parsing'); + + $xml = XmlParser::getSimpleXml($this->content); + + if ($xml === false) { + Logger::setMessage(get_called_class().': Applying XML workarounds'); + $this->content = Filter::normalizeData($this->content); + $xml = XmlParser::getSimpleXml($this->content); + + if ($xml === false) { + Logger::setMessage(get_called_class().': XML parsing error'); + Logger::setMessage(XmlParser::getErrors()); + throw new MalformedXmlException('XML parsing error'); + } + } + + $this->used_namespaces = $xml->getNamespaces(true); + $xml = $this->registerSupportedNamespaces($xml); + + $feed = new Feed(); + + $this->findFeedUrl($xml, $feed); + $this->checkFeedUrl($feed); + + $this->findSiteUrl($xml, $feed); + $this->checkSiteUrl($feed); + + $this->findFeedTitle($xml, $feed); + $this->findFeedDescription($xml, $feed); + $this->findFeedLanguage($xml, $feed); + $this->findFeedId($xml, $feed); + $this->findFeedDate($xml, $feed); + $this->findFeedLogo($xml, $feed); + $this->findFeedIcon($xml, $feed); + + foreach ($this->getItemsTree($xml) as $entry) { + $entry = $this->registerSupportedNamespaces($entry); + + $item = new Item(); + $item->xml = $entry; + $item->namespaces = $this->used_namespaces; + + $this->findItemAuthor($xml, $entry, $item); + + $this->findItemUrl($entry, $item); + $this->checkItemUrl($feed, $item); + + $this->findItemTitle($entry, $item); + $this->findItemContent($entry, $item); + + // Id generation can use the item url/title/content (order is important) + $this->findItemId($entry, $item, $feed); + $this->findItemDate($entry, $item, $feed); + $this->findItemEnclosure($entry, $item, $feed); + $this->findItemLanguage($entry, $item, $feed); + $this->findItemCategories($entry, $item, $feed); + + $this->itemPostProcessor->execute($feed, $item); + $feed->items[] = $item; + } + + Logger::setMessage(get_called_class().PHP_EOL.$feed); + + return $feed; + } + + /** + * Check if the feed url is correct. + * + * @param Feed $feed Feed object + */ + public function checkFeedUrl(Feed $feed) + { + if ($feed->getFeedUrl() === '') { + $feed->feedUrl = $this->fallback_url; + } else { + $feed->feedUrl = Url::resolve($feed->getFeedUrl(), $this->fallback_url); + } + } + + /** + * Check if the site url is correct. + * + * @param Feed $feed Feed object + */ + public function checkSiteUrl(Feed $feed) + { + if ($feed->getSiteUrl() === '') { + $feed->siteUrl = Url::base($feed->getFeedUrl()); + } else { + $feed->siteUrl = Url::resolve($feed->getSiteUrl(), $this->fallback_url); + } + } + + /** + * Check if the item url is correct. + * + * @param Feed $feed Feed object + * @param Item $item Item object + */ + public function checkItemUrl(Feed $feed, Item $item) + { + $item->url = Url::resolve($item->getUrl(), $feed->getSiteUrl()); + } + + /** + * Find the item date. + * + * @param SimpleXMLElement $entry Feed item + * @param Item $item Item object + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findItemDate(SimpleXMLElement $entry, Item $item, Feed $feed) + { + $this->findItemPublishedDate($entry, $item, $feed); + $this->findItemUpdatedDate($entry, $item, $feed); + + if ($item->getPublishedDate() === null) { + // Use the updated date if available, otherwise use the feed date + $item->setPublishedDate($item->getUpdatedDate() ?: $feed->getDate()); + } + + if ($item->getUpdatedDate() === null) { + // Use the published date as fallback + $item->setUpdatedDate($item->getPublishedDate()); + } + + // Use the most recent of published and updated dates + $item->setDate(max($item->getPublishedDate(), $item->getUpdatedDate())); + } + + /** + * Get Item Post Processor instance + * + * @access public + * @return ItemPostProcessor + */ + public function getItemPostProcessor() + { + return $this->itemPostProcessor; + } + + /** + * Get DateParser instance + * + * @access public + * @return DateParser + */ + public function getDateParser() + { + if ($this->dateParser === null) { + $this->dateParser = new DateParser($this->config); + } + + return $this->dateParser; + } + + /** + * Generate a unique id for an entry (hash all arguments). + * + * @return string + */ + public function generateId() + { + return hash($this->hash_algo, implode(func_get_args())); + } + + /** + * Return true if the given language is "Right to Left". + * + * @static + * @param string $language Language: fr-FR, en-US + * @return bool + */ + public static function isLanguageRTL($language) + { + $language = strtolower($language); + + $rtl_languages = array( + 'ar', // Arabic (ar-**) + 'fa', // Farsi (fa-**) + 'ur', // Urdu (ur-**) + 'ps', // Pashtu (ps-**) + 'syr', // Syriac (syr-**) + 'dv', // Divehi (dv-**) + 'he', // Hebrew (he-**) + 'yi', // Yiddish (yi-**) + ); + + foreach ($rtl_languages as $prefix) { + if (strpos($language, $prefix) === 0) { + return true; + } + } + + return false; + } + + /** + * Set Hash algorithm used for id generation. + * + * @param string $algo Algorithm name + * @return \PicoFeed\Parser\Parser + */ + public function setHashAlgo($algo) + { + $this->hash_algo = $algo ?: $this->hash_algo; + return $this; + } + + /** + * Set config object. + * + * @param \PicoFeed\Config\Config $config Config instance + * @return \PicoFeed\Parser\Parser + */ + public function setConfig($config) + { + $this->config = $config; + $this->itemPostProcessor->setConfig($config); + return $this; + } + + /** + * Enable the content grabber. + * + * @return \PicoFeed\Parser\Parser + */ + public function disableContentFiltering() + { + $this->itemPostProcessor->unregister('PicoFeed\Processor\ContentFilterProcessor'); + return $this; + } + + /** + * Enable the content grabber. + * + * @param bool $needsRuleFile true if only pages with rule files should be + * scraped + * @param null|\Closure $scraperCallback Callback function that gets called for each + * scraper execution + * @return \PicoFeed\Parser\Parser + */ + public function enableContentGrabber($needsRuleFile = false, $scraperCallback = null) + { + $processor = new ScraperProcessor($this->config); + + if ($needsRuleFile) { + $processor->getScraper()->disableCandidateParser(); + } + + if ($scraperCallback !== null) { + $processor->setExecutionCallback($scraperCallback); + } + + $this->itemPostProcessor->register($processor); + return $this; + } + + /** + * Set ignored URLs for the content grabber. + * + * @param array $urls URLs + * @return \PicoFeed\Parser\Parser + */ + public function setGrabberIgnoreUrls(array $urls) + { + $this->itemPostProcessor->getProcessor('PicoFeed\Processor\ScraperProcessor')->ignoreUrls($urls); + return $this; + } + + /** + * Register all supported namespaces to be used within an xpath query. + * + * @param SimpleXMLElement $xml Feed xml + * @return SimpleXMLElement + */ + public function registerSupportedNamespaces(SimpleXMLElement $xml) + { + foreach ($this->namespaces as $prefix => $ns) { + $xml->registerXPathNamespace($prefix, $ns); + } + + return $xml; + } +} diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Parser/ParserException.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Parser/ParserException.php new file mode 100644 index 0000000..b5fbb69 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Parser/ParserException.php @@ -0,0 +1,15 @@ + 'http://purl.org/rss/1.0/', + 'dc' => 'http://purl.org/dc/elements/1.1/', + 'content' => 'http://purl.org/rss/1.0/modules/content/', + 'feedburner' => 'http://rssnamespace.org/feedburner/ext/1.0', + ); + + /** + * Get the path to the items XML tree. + * + * @param SimpleXMLElement $xml Feed xml + * @return SimpleXMLElement[] + */ + public function getItemsTree(SimpleXMLElement $xml) + { + return XmlParser::getXPathResult($xml, 'rss:item', $this->namespaces) + ?: XmlParser::getXPathResult($xml, 'item') + ?: $xml->item; + } + + /** + * Find the feed url. + * + * @param SimpleXMLElement $xml Feed xml + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findFeedUrl(SimpleXMLElement $xml, Feed $feed) + { + $feed->setFeedUrl(''); + } + + /** + * Find the site url. + * + * @param SimpleXMLElement $xml Feed xml + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findSiteUrl(SimpleXMLElement $xml, Feed $feed) + { + $value = XmlParser::getXPathResult($xml, 'rss:channel/rss:link', $this->namespaces) + ?: XmlParser::getXPathResult($xml, 'channel/link') + ?: $xml->channel->link; + + $feed->setSiteUrl(XmlParser::getValue($value)); + } + + /** + * Find the feed description. + * + * @param SimpleXMLElement $xml Feed xml + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findFeedDescription(SimpleXMLElement $xml, Feed $feed) + { + $description = XmlParser::getXPathResult($xml, 'rss:channel/rss:description', $this->namespaces) + ?: XmlParser::getXPathResult($xml, 'channel/description') + ?: $xml->channel->description; + + $feed->setDescription(XmlParser::getValue($description)); + } + + /** + * Find the feed logo url. + * + * @param SimpleXMLElement $xml Feed xml + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findFeedLogo(SimpleXMLElement $xml, Feed $feed) + { + $logo = XmlParser::getXPathResult($xml, 'rss:image/rss:url', $this->namespaces) + ?: XmlParser::getXPathResult($xml, 'image/url'); + + $feed->setLogo(XmlParser::getValue($logo)); + } + + /** + * Find the feed icon. + * + * @param SimpleXMLElement $xml Feed xml + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findFeedIcon(SimpleXMLElement $xml, Feed $feed) + { + $feed->setIcon(''); + } + + /** + * Find the feed title. + * + * @param SimpleXMLElement $xml Feed xml + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findFeedTitle(SimpleXMLElement $xml, Feed $feed) + { + $title = XmlParser::getXPathResult($xml, 'rss:channel/rss:title', $this->namespaces) + ?: XmlParser::getXPathResult($xml, 'channel/title') + ?: $xml->channel->title; + + $feed->setTitle(Filter::stripWhiteSpace(XmlParser::getValue($title)) ?: $feed->getSiteUrl()); + } + + /** + * Find the feed language. + * + * @param SimpleXMLElement $xml Feed xml + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findFeedLanguage(SimpleXMLElement $xml, Feed $feed) + { + $language = XmlParser::getXPathResult($xml, 'rss:channel/dc:language', $this->namespaces) + ?: XmlParser::getXPathResult($xml, 'channel/dc:language', $this->namespaces); + + $feed->setLanguage(XmlParser::getValue($language)); + } + + /** + * Find the feed id. + * + * @param SimpleXMLElement $xml Feed xml + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findFeedId(SimpleXMLElement $xml, Feed $feed) + { + $feed->setId($feed->getFeedUrl() ?: $feed->getSiteUrl()); + } + + /** + * Find the feed date. + * + * @param SimpleXMLElement $xml Feed xml + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findFeedDate(SimpleXMLElement $xml, Feed $feed) + { + $date = XmlParser::getXPathResult($xml, 'rss:channel/dc:date', $this->namespaces) + ?: XmlParser::getXPathResult($xml, 'channel/dc:date', $this->namespaces); + + $feed->setDate($this->getDateParser()->getDateTime(XmlParser::getValue($date))); + } + + /** + * Find the item published date. + * + * @param SimpleXMLElement $entry Feed item + * @param Item $item Item object + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findItemPublishedDate(SimpleXMLElement $entry, Item $item, Feed $feed) + { + $date = XmlParser::getXPathResult($entry, 'dc:date', $this->namespaces); + + $item->setPublishedDate(!empty($date) ? $this->getDateParser()->getDateTime(XmlParser::getValue($date)) : null); + } + + /** + * Find the item updated date. + * + * @param SimpleXMLElement $entry Feed item + * @param Item $item Item object + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findItemUpdatedDate(SimpleXMLElement $entry, Item $item, Feed $feed) + { + if ($item->publishedDate === null) { + $this->findItemPublishedDate($entry, $item, $feed); + } + $item->setUpdatedDate($item->getPublishedDate()); // No updated date in RSS 1.0 specifications + } + + /** + * Find the item title. + * + * @param SimpleXMLElement $entry Feed item + * @param \PicoFeed\Parser\Item $item Item object + */ + public function findItemTitle(SimpleXMLElement $entry, Item $item) + { + $title = XmlParser::getXPathResult($entry, 'rss:title', $this->namespaces) + ?: XmlParser::getXPathResult($entry, 'title') + ?: $entry->title; + + $item->setTitle(Filter::stripWhiteSpace(XmlParser::getValue($title)) ?: $item->getUrl()); + } + + /** + * Find the item author. + * + * @param SimpleXMLElement $xml Feed + * @param SimpleXMLElement $entry Feed item + * @param \PicoFeed\Parser\Item $item Item object + */ + public function findItemAuthor(SimpleXMLElement $xml, SimpleXMLElement $entry, Item $item) + { + $author = XmlParser::getXPathResult($entry, 'dc:creator', $this->namespaces) + ?: XmlParser::getXPathResult($xml, 'rss:channel/dc:creator', $this->namespaces) + ?: XmlParser::getXPathResult($xml, 'channel/dc:creator', $this->namespaces); + + $item->setAuthor(XmlParser::getValue($author)); + } + + /** + * Find the item content. + * + * @param SimpleXMLElement $entry Feed item + * @param \PicoFeed\Parser\Item $item Item object + */ + public function findItemContent(SimpleXMLElement $entry, Item $item) + { + $content = XmlParser::getXPathResult($entry, 'content:encoded', $this->namespaces); + + if (XmlParser::getValue($content) === '') { + $content = XmlParser::getXPathResult($entry, 'rss:description', $this->namespaces) + ?: XmlParser::getXPathResult($entry, 'description') + ?: $entry->description; + } + + $item->setContent(XmlParser::getValue($content)); + } + + /** + * Find the item URL. + * + * @param SimpleXMLElement $entry Feed item + * @param \PicoFeed\Parser\Item $item Item object + */ + public function findItemUrl(SimpleXMLElement $entry, Item $item) + { + $link = XmlParser::getXPathResult($entry, 'feedburner:origLink', $this->namespaces) + ?: XmlParser::getXPathResult($entry, 'rss:link', $this->namespaces) + ?: XmlParser::getXPathResult($entry, 'link') + ?: $entry->link; + + $item->setUrl(XmlParser::getValue($link)); + } + + /** + * Genereate the item id. + * + * @param SimpleXMLElement $entry Feed item + * @param \PicoFeed\Parser\Item $item Item object + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findItemId(SimpleXMLElement $entry, Item $item, Feed $feed) + { + $item->setId($this->generateId( + $item->getTitle(), $item->getUrl(), $item->getContent() + )); + } + + /** + * Find the item enclosure. + * + * @param SimpleXMLElement $entry Feed item + * @param \PicoFeed\Parser\Item $item Item object + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findItemEnclosure(SimpleXMLElement $entry, Item $item, Feed $feed) + { + } + + /** + * Find the item language. + * + * @param SimpleXMLElement $entry Feed item + * @param \PicoFeed\Parser\Item $item Item object + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findItemLanguage(SimpleXMLElement $entry, Item $item, Feed $feed) + { + $language = XmlParser::getXPathResult($entry, 'dc:language', $this->namespaces); + + $item->setLanguage(XmlParser::getValue($language) ?: $feed->getLanguage()); + } + + /** + * Find the item categories. + * + * @param SimpleXMLElement $entry Feed item + * @param Item $item Item object + * @param Feed $feed Feed object + */ + public function findItemCategories(SimpleXMLElement $entry, Item $item, Feed $feed) + { + $categories = XmlParser::getXPathResult($entry, 'dc:subject', $this->namespaces); + $item->setCategoriesFromXml($categories); + } +} diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Parser/Rss20.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Parser/Rss20.php new file mode 100644 index 0000000..57054b1 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Parser/Rss20.php @@ -0,0 +1,317 @@ + 'http://purl.org/dc/elements/1.1/', + 'content' => 'http://purl.org/rss/1.0/modules/content/', + 'feedburner' => 'http://rssnamespace.org/feedburner/ext/1.0', + 'atom' => 'http://www.w3.org/2005/Atom', + ); + + /** + * Get the path to the items XML tree. + * + * @param SimpleXMLElement $xml Feed xml + * @return SimpleXMLElement[] + */ + public function getItemsTree(SimpleXMLElement $xml) + { + return XmlParser::getXPathResult($xml, 'channel/item'); + } + + /** + * Find the feed url. + * + * @param SimpleXMLElement $xml Feed xml + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findFeedUrl(SimpleXMLElement $xml, Feed $feed) + { + $feed->setFeedUrl(''); + } + + /** + * Find the site url. + * + * @param SimpleXMLElement $xml Feed xml + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findSiteUrl(SimpleXMLElement $xml, Feed $feed) + { + $value = XmlParser::getXPathResult($xml, 'channel/link'); + $feed->setSiteUrl(XmlParser::getValue($value)); + } + + /** + * Find the feed description. + * + * @param SimpleXMLElement $xml Feed xml + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findFeedDescription(SimpleXMLElement $xml, Feed $feed) + { + $value = XmlParser::getXPathResult($xml, 'channel/description'); + $feed->setDescription(XmlParser::getValue($value)); + } + + /** + * Find the feed logo url. + * + * @param SimpleXMLElement $xml Feed xml + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findFeedLogo(SimpleXMLElement $xml, Feed $feed) + { + $value = XmlParser::getXPathResult($xml, 'channel/image/url'); + $feed->setLogo(XmlParser::getValue($value)); + } + + /** + * Find the feed icon. + * + * @param SimpleXMLElement $xml Feed xml + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findFeedIcon(SimpleXMLElement $xml, Feed $feed) + { + $feed->setIcon(''); + } + + /** + * Find the feed title. + * + * @param SimpleXMLElement $xml Feed xml + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findFeedTitle(SimpleXMLElement $xml, Feed $feed) + { + $title = XmlParser::getXPathResult($xml, 'channel/title'); + $feed->setTitle(Filter::stripWhiteSpace(XmlParser::getValue($title)) ?: $feed->getSiteUrl()); + } + + /** + * Find the feed language. + * + * @param SimpleXMLElement $xml Feed xml + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findFeedLanguage(SimpleXMLElement $xml, Feed $feed) + { + $value = XmlParser::getXPathResult($xml, 'channel/language'); + $feed->setLanguage(XmlParser::getValue($value)); + } + + /** + * Find the feed id. + * + * @param SimpleXMLElement $xml Feed xml + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findFeedId(SimpleXMLElement $xml, Feed $feed) + { + $feed->setId($feed->getFeedUrl() ?: $feed->getSiteUrl()); + } + + /** + * Find the feed date. + * + * @param SimpleXMLElement $xml Feed xml + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findFeedDate(SimpleXMLElement $xml, Feed $feed) + { + $publish_date = XmlParser::getXPathResult($xml, 'channel/pubDate'); + $update_date = XmlParser::getXPathResult($xml, 'channel/lastBuildDate'); + + $published = !empty($publish_date) ? $this->getDateParser()->getDateTime(XmlParser::getValue($publish_date)) : null; + $updated = !empty($update_date) ? $this->getDateParser()->getDateTime(XmlParser::getValue($update_date)) : null; + + if ($published === null && $updated === null) { + $feed->setDate($this->getDateParser()->getCurrentDateTime()); // We use the current date if there is no date for the feed + } elseif ($published !== null && $updated !== null) { + $feed->setDate(max($published, $updated)); // We use the most recent date between published and updated + } else { + $feed->setDate($updated ?: $published); + } + } + + /** + * Find the item published date. + * + * @param SimpleXMLElement $entry Feed item + * @param Item $item Item object + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findItemPublishedDate(SimpleXMLElement $entry, Item $item, Feed $feed) + { + $date = XmlParser::getXPathResult($entry, 'pubDate'); + + $item->setPublishedDate(!empty($date) ? $this->getDateParser()->getDateTime(XmlParser::getValue($date)) : null); + } + + /** + * Find the item updated date. + * + * @param SimpleXMLElement $entry Feed item + * @param Item $item Item object + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findItemUpdatedDate(SimpleXMLElement $entry, Item $item, Feed $feed) + { + if ($item->publishedDate === null) { + $this->findItemPublishedDate($entry, $item, $feed); + } + $item->setUpdatedDate($item->getPublishedDate()); // No updated date in RSS 2.0 specifications + } + + /** + * Find the item title. + * + * @param SimpleXMLElement $entry Feed item + * @param \PicoFeed\Parser\Item $item Item object + */ + public function findItemTitle(SimpleXMLElement $entry, Item $item) + { + $value = XmlParser::getXPathResult($entry, 'title'); + $item->setTitle(Filter::stripWhiteSpace(XmlParser::getValue($value)) ?: $item->getUrl()); + } + + /** + * Find the item author. + * + * @param SimpleXMLElement $xml Feed + * @param SimpleXMLElement $entry Feed item + * @param \PicoFeed\Parser\Item $item Item object + */ + public function findItemAuthor(SimpleXMLElement $xml, SimpleXMLElement $entry, Item $item) + { + $value = XmlParser::getXPathResult($entry, 'dc:creator', $this->namespaces) + ?: XmlParser::getXPathResult($entry, 'author') + ?: XmlParser::getXPathResult($xml, 'channel/dc:creator', $this->namespaces) + ?: XmlParser::getXPathResult($xml, 'channel/managingEditor'); + + $item->setAuthor(XmlParser::getValue($value)); + } + + /** + * Find the item content. + * + * @param SimpleXMLElement $entry Feed item + * @param \PicoFeed\Parser\Item $item Item object + */ + public function findItemContent(SimpleXMLElement $entry, Item $item) + { + $content = XmlParser::getXPathResult($entry, 'content:encoded', $this->namespaces); + + if (XmlParser::getValue($content) === '') { + $content = XmlParser::getXPathResult($entry, 'description'); + } + + $item->setContent(XmlParser::getValue($content)); + } + + /** + * Find the item URL. + * + * @param SimpleXMLElement $entry Feed item + * @param \PicoFeed\Parser\Item $item Item object + */ + public function findItemUrl(SimpleXMLElement $entry, Item $item) + { + $link = XmlParser::getXPathResult($entry, 'feedburner:origLink', $this->namespaces) + ?: XmlParser::getXPathResult($entry, 'link') + ?: XmlParser::getXPathResult($entry, 'atom:link/@href', $this->namespaces); + + if (!empty($link)) { + $item->setUrl(XmlParser::getValue($link)); + } else { + $link = XmlParser::getXPathResult($entry, 'guid'); + $link = XmlParser::getValue($link); + + if (filter_var($link, FILTER_VALIDATE_URL) !== false) { + $item->setUrl($link); + } + } + } + + /** + * Genereate the item id. + * + * @param SimpleXMLElement $entry Feed item + * @param \PicoFeed\Parser\Item $item Item object + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findItemId(SimpleXMLElement $entry, Item $item, Feed $feed) + { + $id = XmlParser::getValue(XmlParser::getXPathResult($entry, 'guid')); + + if ($id) { + $item->setId($this->generateId($id)); + } else { + $item->setId($this->generateId( + $item->getTitle(), $item->getUrl(), $item->getContent() + )); + } + } + + /** + * Find the item enclosure. + * + * @param SimpleXMLElement $entry Feed item + * @param \PicoFeed\Parser\Item $item Item object + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findItemEnclosure(SimpleXMLElement $entry, Item $item, Feed $feed) + { + if (isset($entry->enclosure)) { + $type = XmlParser::getXPathResult($entry, 'enclosure/@type'); + $url = XmlParser::getXPathResult($entry, 'feedburner:origEnclosureLink', $this->namespaces) + ?: XmlParser::getXPathResult($entry, 'enclosure/@url'); + + $item->setEnclosureUrl(Url::resolve(XmlParser::getValue($url), $feed->getSiteUrl())); + $item->setEnclosureType(XmlParser::getValue($type)); + } + } + + /** + * Find the item language. + * + * @param SimpleXMLElement $entry Feed item + * @param \PicoFeed\Parser\Item $item Item object + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findItemLanguage(SimpleXMLElement $entry, Item $item, Feed $feed) + { + $language = XmlParser::getXPathResult($entry, 'dc:language', $this->namespaces); + $item->setLanguage(XmlParser::getValue($language) ?: $feed->getLanguage()); + } + + /** + * Find the item categories. + * + * @param SimpleXMLElement $entry Feed item + * @param Item $item Item object + * @param Feed $feed Feed object + */ + public function findItemCategories(SimpleXMLElement $entry, Item $item, Feed $feed) + { + $categories = XmlParser::getXPathResult($entry, 'category'); + $item->setCategoriesFromXml($categories); + } +} diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Parser/Rss91.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Parser/Rss91.php new file mode 100644 index 0000000..058fca1 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Parser/Rss91.php @@ -0,0 +1,13 @@ +childNodes->length === 0) { + return false; + } + + return $dom; + } + + /** + * Small wrapper around ZendXml to turn their exceptions into PicoFeed exceptions + * + * @static + * @access private + * @param string $input + * @param DOMDocument $dom + * @throws XmlEntityException + * @return SimpleXMLElement|DomDocument|boolean + */ + private static function scan($input, $dom = null) + { + try { + return Security::scan($input, $dom); + } catch(RuntimeException $e) { + throw new XmlEntityException($e->getMessage()); + } + } + + /** + * Load HTML document by using a DomDocument instance or return false on failure. + * + * @static + * @access public + * @param string $input XML content + * @return DOMDocument + */ + public static function getHtmlDocument($input) + { + $dom = new DomDocument(); + + if (empty($input)) { + return $dom; + } + + libxml_use_internal_errors(true); + + if (version_compare(PHP_VERSION, '5.4.0', '>=')) { + $dom->loadHTML($input, LIBXML_NONET); + } else { + $dom->loadHTML($input); + } + + return $dom; + } + + /** + * Convert a HTML document to XML. + * + * @static + * @access public + * @param string $html HTML document + * @return string + */ + public static function htmlToXml($html) + { + $dom = self::getHtmlDocument(''.$html); + return $dom->saveXML($dom->getElementsByTagName('body')->item(0)); + } + + /** + * Get XML parser errors. + * + * @static + * @access public + * @return string + */ + public static function getErrors() + { + $errors = array(); + + foreach (libxml_get_errors() as $error) { + $errors[] = sprintf('XML error: %s (Line: %d - Column: %d - Code: %d)', + $error->message, + $error->line, + $error->column, + $error->code + ); + } + + return implode(', ', $errors); + } + + /** + * Get the encoding from a xml tag. + * + * @static + * @access public + * @param string $data Input data + * @return string + */ + public static function getEncodingFromXmlTag($data) + { + $encoding = ''; + + if (strpos($data, '')); + $data = str_replace("'", '"', $data); + + $p1 = strpos($data, 'encoding='); + $p2 = strpos($data, '"', $p1 + 10); + + if ($p1 !== false && $p2 !== false) { + $encoding = substr($data, $p1 + 10, $p2 - $p1 - 10); + $encoding = strtolower($encoding); + } + } + + return $encoding; + } + + /** + * Get the charset from a meta tag. + * + * @static + * @access public + * @param string $data Input data + * @return string + */ + public static function getEncodingFromMetaTag($data) + { + $encoding = ''; + + if (preg_match('/;]+)/i', $data, $match) === 1) { + $encoding = strtolower($match[1]); + } + + return $encoding; + } + + /** + * Rewrite XPath query to use namespace-uri and local-name derived from prefix. + * + * @static + * @access public + * @param string $query XPath query + * @param array $ns Prefix to namespace URI mapping + * @return string + */ + public static function replaceXPathPrefixWithNamespaceURI($query, array $ns) + { + return preg_replace_callback('/([A-Z0-9]+):([A-Z0-9]+)/iu', function ($matches) use ($ns) { + // don't try to map the special prefix XML + if (strtolower($matches[1]) === 'xml') { + return $matches[0]; + } + + return '*[namespace-uri()="'.$ns[$matches[1]].'" and local-name()="'.$matches[2].'"]'; + }, + $query); + } + + /** + * Get the result elements of a XPath query. + * + * @static + * @access public + * @param SimpleXMLElement $xml XML element + * @param string $query XPath query + * @param array $ns Prefix to namespace URI mapping + * @return SimpleXMLElement[] + */ + public static function getXPathResult(SimpleXMLElement $xml, $query, array $ns = array()) + { + if (!empty($ns)) { + $query = static::replaceXPathPrefixWithNamespaceURI($query, $ns); + } + + return $xml->xpath($query); + } + + /** + * Get the first Xpath result or SimpleXMLElement value + * + * @static + * @access public + * @param mixed $value + * @return string + */ + public static function getValue($value) + { + $result = ''; + + if (is_array($value) && count($value) > 0) { + $result = (string) $value[0]; + } elseif (is_a($value, 'SimpleXMLElement')) { + return $result = (string) $value; + } + + return trim($result); + } +} diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/PicoFeedException.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/PicoFeedException.php new file mode 100644 index 0000000..2de9e4b --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/PicoFeedException.php @@ -0,0 +1,14 @@ +config->getContentFiltering(true)) { + $filter = Filter::html($item->getContent(), $feed->getSiteUrl()); + $filter->setConfig($this->config); + $item->setContent($filter->execute()); + } else { + Logger::setMessage(get_called_class().': Content filtering disabled'); + } + + return false; + } +} diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Processor/ContentGeneratorProcessor.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Processor/ContentGeneratorProcessor.php new file mode 100644 index 0000000..49adf9c --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Processor/ContentGeneratorProcessor.php @@ -0,0 +1,49 @@ +generators as $generator) { + $className = '\PicoFeed\Generator\\'.ucfirst($generator).'ContentGenerator'; + $object = new $className($this->config); + + if ($object->execute($item)) { + return true; + } + } + + return false; + } +} diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Processor/ItemPostProcessor.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Processor/ItemPostProcessor.php new file mode 100644 index 0000000..7b092b5 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Processor/ItemPostProcessor.php @@ -0,0 +1,106 @@ +processors as $processor) { + if ($processor->execute($feed, $item)) { + return true; + } + } + + return false; + } + + /** + * Register a new Item post-processor + * + * @access public + * @param ItemProcessorInterface $processor + * @return ItemPostProcessor + */ + public function register(ItemProcessorInterface $processor) + { + $this->processors[get_class($processor)] = $processor; + return $this; + } + + /** + * Remove Processor instance + * + * @access public + * @param string $class + * @return ItemPostProcessor + */ + public function unregister($class) + { + if (isset($this->processors[$class])) { + unset($this->processors[$class]); + } + + return $this; + } + + /** + * Checks whether a specific processor is registered or not + * + * @access public + * @param string $class + * @return bool + */ + public function hasProcessor($class) + { + return isset($this->processors[$class]); + } + + /** + * Get Processor instance + * + * @access public + * @param string $class + * @return ItemProcessorInterface|null + */ + public function getProcessor($class) + { + return isset($this->processors[$class]) ? $this->processors[$class] : null; + } + + public function setConfig(Config $config) + { + foreach ($this->processors as $processor) { + $processor->setConfig($config); + } + + return false; + } +} diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Processor/ItemProcessorInterface.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Processor/ItemProcessorInterface.php new file mode 100644 index 0000000..5d53226 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Processor/ItemProcessorInterface.php @@ -0,0 +1,25 @@ +executionCallback = $executionCallback; + return $this; + } + + /** + * Execute Item Processor + * + * @access public + * @param Feed $feed + * @param Item $item + * @return bool + */ + public function execute(Feed $feed, Item $item) + { + if (!in_array($item->getUrl(), $this->ignoredUrls)) { + $scraper = $this->getScraper(); + $scraper->setUrl($item->getUrl()); + $scraper->execute(); + + if ($this->executionCallback && is_callable($this->executionCallback)) { + call_user_func($this->executionCallback, $feed, $item, $scraper); + } + + if ($scraper->hasRelevantContent()) { + $item->setContent($scraper->getFilteredContent()); + } + } + + return false; + } + + /** + * Ignore list of URLs + * + * @access public + * @param array $urls + * @return $this + */ + public function ignoreUrls(array $urls) + { + $this->ignoredUrls = $urls; + return $this; + } + + /** + * Returns Scraper instance + * + * @access public + * @return Scraper + */ + public function getScraper() + { + if ($this->scraper === null) { + $this->scraper = new Scraper($this->config); + } + + return $this->scraper; + } +} diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Reader/Favicon.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Reader/Favicon.php new file mode 100644 index 0000000..d4ca07d --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Reader/Favicon.php @@ -0,0 +1,186 @@ +content; + } + + /** + * Get the icon file type (available only after the download). + * + * @return string + */ + public function getType() + { + foreach ($this->types as $type) { + if (strpos($this->content_type, $type) === 0) { + return $type; + } + } + + return 'image/x-icon'; + } + + /** + * Get data URI (http://en.wikipedia.org/wiki/Data_URI_scheme). + * + * @return string + */ + public function getDataUri() + { + if (empty($this->content)) { + return ''; + } + + return sprintf( + 'data:%s;base64,%s', + $this->getType(), + base64_encode($this->content) + ); + } + + /** + * Download and check if a resource exists. + * + * @param string $url URL + * @return \PicoFeed\Client\Client Client instance + */ + public function download($url) + { + $client = Client::getInstance(); + $client->setConfig($this->config); + + Logger::setMessage(get_called_class().' Download => '.$url); + + try { + $client->execute($url); + } catch (ClientException $e) { + Logger::setMessage(get_called_class().' Download Failed => '.$e->getMessage()); + } + + return $client; + } + + /** + * Check if a remote file exists. + * + * @param string $url URL + * @return bool + */ + public function exists($url) + { + return $this->download($url)->getContent() !== ''; + } + + /** + * Get the icon link for a website. + * + * @param string $website_link URL + * @param string $favicon_link optional URL + * @return string + */ + public function find($website_link, $favicon_link = '') + { + $website = new Url($website_link); + + if ($favicon_link !== '') { + $icons = array($favicon_link); + } else { + $icons = $this->extract($this->download($website->getBaseUrl('/'))->getContent()); + $icons[] = $website->getBaseUrl('/favicon.ico'); + } + + foreach ($icons as $icon_link) { + $icon_link = Url::resolve($icon_link, $website); + $resource = $this->download($icon_link); + $this->content = $resource->getContent(); + $this->content_type = $resource->getContentType(); + + if ($this->content !== '') { + return $icon_link; + } elseif ($favicon_link !== '') { + return $this->find($website_link); + } + } + + return ''; + } + + /** + * Extract the icon links from the HTML. + * + * @param string $html HTML + * @return array + */ + public function extract($html) + { + $icons = array(); + + if (empty($html)) { + return $icons; + } + + $dom = XmlParser::getHtmlDocument($html); + + $xpath = new DOMXpath($dom); + $elements = $xpath->query('//link[@rel="icon" or @rel="shortcut icon" or @rel="Shortcut Icon" or @rel="icon shortcut"]'); + + for ($i = 0; $i < $elements->length; ++$i) { + $icons[] = $elements->item($i)->getAttribute('href'); + } + + return $icons; + } +} diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Reader/Reader.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Reader/Reader.php new file mode 100644 index 0000000..596b02d --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Reader/Reader.php @@ -0,0 +1,189 @@ + '//feed', + 'Rss20' => '//rss[@version="2.0"]', + 'Rss92' => '//rss[@version="0.92"]', + 'Rss91' => '//rss[@version="0.91"]', + 'Rss10' => '//rdf', + ); + + /** + * Download a feed (no discovery). + * + * @param string $url Feed url + * @param string $last_modified Last modified HTTP header + * @param string $etag Etag HTTP header + * @param string $username HTTP basic auth username + * @param string $password HTTP basic auth password + * + * @return \PicoFeed\Client\Client + */ + public function download($url, $last_modified = '', $etag = '', $username = '', $password = '') + { + $url = $this->prependScheme($url); + + return Client::getInstance() + ->setConfig($this->config) + ->setLastModified($last_modified) + ->setEtag($etag) + ->setUsername($username) + ->setPassword($password) + ->execute($url); + } + + /** + * Discover and download a feed. + * + * @param string $url Feed or website url + * @param string $last_modified Last modified HTTP header + * @param string $etag Etag HTTP header + * @param string $username HTTP basic auth username + * @param string $password HTTP basic auth password + * @return Client + * @throws SubscriptionNotFoundException + */ + public function discover($url, $last_modified = '', $etag = '', $username = '', $password = '') + { + $client = $this->download($url, $last_modified, $etag, $username, $password); + + // It's already a feed or the feed was not modified + if (!$client->isModified() || $this->detectFormat($client->getContent())) { + return $client; + } + + // Try to find a subscription + $links = $this->find($client->getUrl(), $client->getContent()); + + if (empty($links)) { + throw new SubscriptionNotFoundException('Unable to find a subscription'); + } + + return $this->download($links[0], $last_modified, $etag, $username, $password); + } + + /** + * Find feed urls inside a HTML document. + * + * @param string $url Website url + * @param string $html HTML content + * + * @return array List of feed links + */ + public function find($url, $html) + { + Logger::setMessage(get_called_class().': Try to discover subscriptions'); + + $dom = XmlParser::getHtmlDocument($html); + $xpath = new DOMXPath($dom); + $links = array(); + + $queries = array( + '//link[@type="application/rss+xml"]', + '//link[@type="application/atom+xml"]', + ); + + foreach ($queries as $query) { + $nodes = $xpath->query($query); + + foreach ($nodes as $node) { + $link = $node->getAttribute('href'); + + if (!empty($link)) { + $feedUrl = new Url($link); + $siteUrl = new Url($url); + + $links[] = $feedUrl->getAbsoluteUrl($feedUrl->isRelativeUrl() ? $siteUrl->getBaseUrl() : ''); + } + } + } + + Logger::setMessage(get_called_class().': '.implode(', ', $links)); + + return $links; + } + + /** + * Get a parser instance. + * + * @param string $url Site url + * @param string $content Feed content + * @param string $encoding HTTP encoding + * @return \PicoFeed\Parser\Parser + * @throws UnsupportedFeedFormatException + */ + public function getParser($url, $content, $encoding) + { + $format = $this->detectFormat($content); + + if (empty($format)) { + throw new UnsupportedFeedFormatException('Unable to detect feed format'); + } + + $className = '\PicoFeed\Parser\\'.$format; + + $parser = new $className($content, $encoding, $url); + $parser->setHashAlgo($this->config->getParserHashAlgo()); + $parser->setConfig($this->config); + + return $parser; + } + + /** + * Detect the feed format. + * + * @param string $content Feed content + * @return string + */ + public function detectFormat($content) + { + $dom = XmlParser::getHtmlDocument($content); + $xpath = new DOMXPath($dom); + + foreach ($this->formats as $parser_name => $query) { + $nodes = $xpath->query($query); + + if ($nodes->length === 1) { + return $parser_name; + } + } + + return ''; + } + + /** + * Add the prefix "http://" if the end-user just enter a domain name. + * + * @param string $url Url + * @return string + */ + public function prependScheme($url) + { + if (!preg_match('%^https?://%', $url)) { + $url = 'http://'.$url; + } + + return $url; + } +} diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Reader/ReaderException.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Reader/ReaderException.php new file mode 100644 index 0000000..4f03dbe --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Reader/ReaderException.php @@ -0,0 +1,14 @@ + array( + '%.*%' => array( + 'test_url' => 'http://combat.blog.lemonde.fr/2013/08/31/teddy-riner-le-rookie-devenu-rambo/#xtor=RSS-3208', + 'body' => array( + '//div[@class="entry-content"]', + ), + 'strip' => array( + '//*[contains(@class, "fb-like") or contains(@class, "social")]' + ), + ) + ) +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/.blogs.nytimes.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/.blogs.nytimes.com.php new file mode 100644 index 0000000..ee641b0 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/.blogs.nytimes.com.php @@ -0,0 +1,15 @@ + array( + '%.*%' => array( + 'title' => '//header/h1', + 'test_url' => 'http://bits.blogs.nytimes.com/2012/01/16/wikipedia-plans-to-go-dark-on-wednesday-to-protest-sopa/', + 'body' => array( + '//div[@class="postContent"]', + ), + 'strip' => array( + '//*[@class="shareToolsBox"]', + ), + ) + ) +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/.igen.fr.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/.igen.fr.php new file mode 100644 index 0000000..f2028f4 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/.igen.fr.php @@ -0,0 +1,13 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.igen.fr/ailleurs/2014/05/nvidia-va-delaisser-les-smartphones-grand-public-86031', + 'body' => array( + '//div[contains(@class, "field-name-body")]' + ), + 'strip' => array( + ), + ) + ) +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/.nytimes.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/.nytimes.com.php new file mode 100644 index 0000000..ed27bb5 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/.nytimes.com.php @@ -0,0 +1,11 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.nytimes.com/2011/05/15/world/middleeast/15prince.html', + 'body' => array( + '//div[@class="articleBody"]', + ), + ) + ) +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/.over-blog.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/.over-blog.com.php new file mode 100644 index 0000000..cc5d83c --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/.over-blog.com.php @@ -0,0 +1,11 @@ + array( + '%.*%' => array( + 'test_url' => 'http://eliascarpe.over-blog.com/2015/12/re-upload-projets-d-avenir.html', + 'body' => array( + '//div[contains(concat(" ", normalize-space(@class), " "), " ob-section ")]', + ), + ) + ) +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/.phoronix.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/.phoronix.com.php new file mode 100644 index 0000000..66713f7 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/.phoronix.com.php @@ -0,0 +1,12 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.phoronix.com/scan.php?page=article&item=amazon_ec2_bare&num=1', + 'body' => array( + '//div[@class="content"]', + ), + 'strip' => array(), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/.slate.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/.slate.com.php new file mode 100644 index 0000000..a795bca --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/.slate.com.php @@ -0,0 +1,20 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.slate.com/articles/business/moneybox/2013/08/microsoft_ceo_steve_ballmer_retires_a_firsthand_account_of_the_company_s.html', + 'body' => array( + '//div[@class="sl-art-body"]', + ), + 'strip' => array( + '//*[contains(@class, "social") or contains(@class, "comments") or contains(@class, "sl-article-floatin-tools") or contains(@class, "sl-art-pag")]', + '//*[@id="mys_slate_logged_in"]', + '//*[@id="sl_article_tools_myslate_bottom"]', + '//*[@id="mys_myslate"]', + '//*[@class="sl-viral-container"]', + '//*[@class="sl-art-creds-cntr"]', + '//*[@class="sl-art-ad-midflex"]', + ) + ) + ) +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/.theguardian.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/.theguardian.com.php new file mode 100644 index 0000000..e0d6f3f --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/.theguardian.com.php @@ -0,0 +1,14 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.theguardian.com/sustainable-business/2015/feb/02/2015-hyper-transparency-global-business', + 'body' => array( + '//div[contains(@class, "content__main-column--article")]', + ), + 'strip' => array( + '//div[contains(@class, "meta-container")]', + ), + ) + ) +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/.wikipedia.org.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/.wikipedia.org.php new file mode 100644 index 0000000..7b8f76e --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/.wikipedia.org.php @@ -0,0 +1,29 @@ + array( + '%.*%' => array( + 'test_url' => 'https://en.wikipedia.org/wiki/Grace_Hopper', + 'body' => array( + '//div[@id="bodyContent"]', + ), + 'strip' => array( + "//div[@id='toc']", + "//div[@id='catlinks']", + "//div[@id='jump-to-nav']", + "//div[@class='thumbcaption']//div[@class='magnify']", + "//table[@class='navbox']", + "//table[contains(@class, 'infobox')]", + "//div[@class='dablink']", + "//div[@id='contentSub']", + "//div[@id='siteSub']", + "//table[@id='persondata']", + "//table[contains(@class, 'metadata')]", + "//*[contains(@class, 'noprint')]", + "//*[contains(@class, 'printfooter')]", + "//*[contains(@class, 'editsection')]", + "//*[contains(@class, 'error')]", + "//span[@title='pronunciation:']", + ), + ) + ) +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/.wired.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/.wired.com.php new file mode 100644 index 0000000..952b09a --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/.wired.com.php @@ -0,0 +1,44 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.wired.com/gamelife/2013/09/ouya-free-the-games/', + 'body' => array( + '//div[@data-js="gallerySlides"]', + '//div[starts-with(@class,"post")]', + ), + 'strip' => array( + '//h1', + '//nav', + '//button', + '//figure[starts-with(@class,"rad-slide")]', + '//figure[starts-with(@class,"end-slate")]', + '//div[contains(@class,"mobile-")]', + '//div[starts-with(@class,"mob-gallery-launcher")]', + '//div[contains(@id,"mobile-")]', + '//span[contains(@class,"slide-count")]', + '//div[contains(@class,"show-ipad")]', + '//img[contains(@id,"-hero-bg")]', + '//div[@data-js="overlayWrap"]', + '//ul[contains(@class,"metadata")]', + '//div[@class="opening center"]', + '//p[contains(@class="byline-mob"]', + '//div[@id="o-gallery"]', + '//div[starts-with(@class,"sm-col")]', + '//div[contains(@class,"pad-b-huge")]', + '//a[contains(@class,"visually-hidden")]', + '//*[@class="social"]', + '//i', + '//div[@data-js="mobGalleryAd"]', + '//div[contains(@class,"footer")]', + '//div[contains(@data-js,"fader")]', + '//div[@id="sharing"]', + '//div[contains(@id,"related")]', + '//div[@id="most-pop"]', + '//ul[@id="article-tags"]', + '//style', + '//section[contains(@class,"footer")]' + ), + ) + ) +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/.wsj.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/.wsj.com.php new file mode 100644 index 0000000..f6e6cc1 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/.wsj.com.php @@ -0,0 +1,15 @@ + array( + '%.*%' => array( + 'test_url' => 'http://online.wsj.com/article/SB10001424127887324108204579023143974408428.html', + 'body' => array( + '//div[@class="articlePage"]', + ), + 'strip' => array( + '//*[@id="articleThumbnail_2"]', + '//*[@class="socialByline"]', + ) + ) + ) +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/01net.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/01net.com.php new file mode 100644 index 0000000..6d144f0 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/01net.com.php @@ -0,0 +1,18 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.01net.com/editorial/624550/twitter-rachete-madbits-un-specialiste-francais-de-lanalyse-dimages/', + 'body' => array( + '//div[@class="article_ventre_box"]', + ), + 'strip' => array( + '//link', + '//*[contains(@class, "article_navigation")]', + '//h1', + '//*[contains(@class, "article_toolbarMain")]', + '//*[contains(@class, "article_imagehaute_box")]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/abstrusegoose.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/abstrusegoose.com.php new file mode 100644 index 0000000..752d041 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/abstrusegoose.com.php @@ -0,0 +1,8 @@ + array( + '%.*%' => array( + '%alt="(.+)" title="(.+)" */>%' => '/>
                                                                      $1
                                                                      $2', + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/adventuregamers.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/adventuregamers.com.php new file mode 100644 index 0000000..98d384e --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/adventuregamers.com.php @@ -0,0 +1,23 @@ + array( + '%^/news.*%' => array( + 'test_url' => 'http://www.adventuregamers.com/news/view/31079', + 'body' => array( + '//div[@class="bodytext"]', + ) + ), + '%^/videos.*%' => array( + 'test_url' => 'http://www.adventuregamers.com/videos/view/31056', + 'body' => array( + '//iframe', + ) + ), + '%^/articles.*%' => array( + 'test_url' => 'http://www.adventuregamers.com/articles/view/31049', + 'body' => array( + '//div[@class="cleft"]', + ) + ) + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/alainonline.net.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/alainonline.net.php new file mode 100644 index 0000000..f440b23 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/alainonline.net.php @@ -0,0 +1,14 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.alainonline.net/news_details.php?lang=arabic&sid=18907', + 'body' => array( + '//div[@class="news_details"]', + ), + 'strip' => array( + '//div[@class="news_details"]/div/div[last()]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/aljazeera.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/aljazeera.com.php new file mode 100644 index 0000000..c02eb21 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/aljazeera.com.php @@ -0,0 +1,25 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.aljazeera.com/news/2015/09/xi-jinping-seattle-china-150922230118373.html', + 'body' => array( + '//article[@id="main-story"]', + ), + 'strip' => array( + '//script', + '//header', + '//ul', + '//section[contains(@class,"profile")]', + '//a[@target="_self"]', + '//div[contains(@id,"_2")]', + '//div[contains(@id,"_3")]', + '//img[@class="viewMode"]', + '//table[contains(@class,"in-article-item")]', + '//div[@data-embed-type="Brightcove"]', + '//div[@class="QuoteContainer"]', + '//div[@class="BottomByLine"]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/allafrica.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/allafrica.com.php new file mode 100644 index 0000000..e8a506d --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/allafrica.com.php @@ -0,0 +1,20 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.aljazeera.com/news/2015/09/xi-jinping-seattle-china-150922230118373.html', + 'body' => array( + '//div[@class="story-body"]', + ), + 'strip' => array( + '//p[@class="kindofstory"]', + '//cite[@class="byline"]', + '//div[@class="useful-top"]', + '//div[contains(@class,"related-topics")]', + '//links', + '//sharebar', + '//related-topics', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/allgemeine-zeitung.de.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/allgemeine-zeitung.de.php new file mode 100644 index 0000000..8ede99b --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/allgemeine-zeitung.de.php @@ -0,0 +1,23 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.allgemeine-zeitung.de/lokales/polizei/mainz-gonsenheim-unbekannte-rauben-esso-tankstelle-in-kurt-schumacher-strasse-aus_14913147.htm', + 'body' => array( + '//div[contains(@class, "article")][1]', + ), + 'strip' => array( + '//read/h1', + '//*[@id="t-map"]', + '//*[contains(@class, "modules")]', + '//*[contains(@class, "adsense")]', + '//*[contains(@class, "linkbox")]', + '//*[contains(@class, "info")]', + '//*[@class="skip"]', + '//*[@class="funcs"]', + '//span[@class="nd address"]', + '//a[contains(@href, "abo-und-services")]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/amazingsuperpowers.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/amazingsuperpowers.com.php new file mode 100644 index 0000000..3214c62 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/amazingsuperpowers.com.php @@ -0,0 +1,8 @@ + array( + '%.*%' => array( + '%title="(.+)" */>%' => '/>
                                                                      $1', + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/anythingcomic.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/anythingcomic.com.php new file mode 100644 index 0000000..51247f7 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/anythingcomic.com.php @@ -0,0 +1,13 @@ + array( + '%.*%' => array( + 'body' => array( + '//img[@id="comic_image"]', + '//div[@class="comment-wrapper"][position()=1]', + ), + 'strip' => array(), + 'test_url' => 'http://www.anythingcomic.com/comics/2108929/stress-free/', + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/ap.org.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/ap.org.php new file mode 100644 index 0000000..5bb2bb6 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/ap.org.php @@ -0,0 +1,13 @@ + array( + '%.*%' => array( + 'test_url' => 'http://hosted.ap.org/dynamic/stories/A/AS_CHINA_GAO_ZHISHENG?SITE=AP&SECTION=HOME&TEMPLATE=DEFAULT', + 'body' => array( + '//img[@class="ap-smallphoto-img"]', + '//span[@class="entry-content"]', + ), + 'strip' => array(), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/areadvd.de.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/areadvd.de.php new file mode 100644 index 0000000..fc56922 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/areadvd.de.php @@ -0,0 +1,10 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.areadvd.de/news/daily-deals-angebote-bei-lautsprecher-teufel-3/', + 'body' => array('//div[contains(@class,"entry")]'), + 'strip' => array(), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/arstechnica.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/arstechnica.com.php new file mode 100644 index 0000000..55e01ce --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/arstechnica.com.php @@ -0,0 +1,25 @@ + array( + '%.*%' => array( + 'test_url' => 'http://arstechnica.com/tech-policy/2015/09/judge-warners-2m-happy-birthday-copyright-is-bogus/', + 'body' => array( + '//article', + ), + 'strip' => array( + '//h4[@class="post-upperdek"]', + '//h1', + '//ul[@class="lSPager lSGallery"]', + '//div[@class="lSAction"]', + '//section[@class="post-meta"]', + '//figcaption', + '//aside', + '//div[@class="gallery-image-credit"]', + '//section[@class="article-author"]', + '//*[contains(@id,"social-")]', + '//div[contains(@id,"footer")]', + ), + ), + ), +); + diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/awkwardzombie.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/awkwardzombie.com.php new file mode 100644 index 0000000..5ab7051 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/awkwardzombie.com.php @@ -0,0 +1,10 @@ + array( + '%/index.php.*comic=.*%' => array( + 'test_url' => 'http://www.awkwardzombie.com/index.php?comic=041315', + 'body' => array('//*[@id="comic"]/img'), + 'strip' => array(), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/backchannel.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/backchannel.com.php new file mode 100644 index 0000000..bc5932a --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/backchannel.com.php @@ -0,0 +1,18 @@ + array( + '%.*%' => array( + 'test_url' => 'https://medium.com/lessons-learned/917b8b63ae3e', + 'body' => array( + '//div[contains(@class,"section-inner")]', + ), + 'strip' => array( + '//div[contains(@class,"metabar")]', + '//img[contains(@class,"thumbnail")]', + '//h1', + '//blockquote', + '//p[contains(@class,"graf-after--h4")]' + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/bangkokpost.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/bangkokpost.com.php new file mode 100644 index 0000000..165515b --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/bangkokpost.com.php @@ -0,0 +1,19 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.bangkokpost.com/news/politics/704204/new-us-ambassador-arrives-in-bangkok', + 'body' => array( + '//article/div[@class="articleContents"]', + ), + 'strip' => array( + '//h2', + '//h4', + '//div[@class="text-size"]', + '//div[@class="relate-story"]', + '//div[@class="text-ads"]', + '//ul', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/bgr.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/bgr.com.php new file mode 100644 index 0000000..7507a2f --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/bgr.com.php @@ -0,0 +1,15 @@ + array( + '%.*%' => array( + 'test_url' => 'http://bgr.com/2015/09/27/iphone-6s-waterproof-testing/', + 'body' => array( + '//img[contains(@class,"img")]', + '//div[@class="text-column"]', + ), + 'strip' => array( + '//strong', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/bigfootjustice.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/bigfootjustice.com.php new file mode 100644 index 0000000..d06ed12 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/bigfootjustice.com.php @@ -0,0 +1,8 @@ + array( + '%.*%' => array( + '%-150x150%' => '', + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/bigpicture.ru.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/bigpicture.ru.php new file mode 100644 index 0000000..55c4089 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/bigpicture.ru.php @@ -0,0 +1,31 @@ + array( + '%.*%' => array( + 'test_url' => 'http://bigpicture.ru/?p=556658', + 'body' => array( + '//div[@class="article container"]', + ), + 'strip' => array( + '//script', + '//form', + '//style', + '//h1', + '//*[@class="wp-smiley"]', + '//div[@class="ipmd"]', + '//div[@class="tags"]', + '//div[@class="social-button"]', + '//div[@class="bottom-share"]', + '//div[@class="raccoonbox"]', + '//div[@class="yndadvert"]', + '//div[@class="we-recommend"]', + '//div[@class="relap-bigpicture_ru-wrapper"]', + '//div[@id="mmail"]', + '//div[@id="mobile-ads-cut"]', + '//div[@id="liquidstorm-alt-html"]', + '//div[contains(@class, "post-tags")]', + '//*[contains(text(),"Смотрите также")]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/bizjournals.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/bizjournals.com.php new file mode 100644 index 0000000..d1cc3da --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/bizjournals.com.php @@ -0,0 +1,12 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.bizjournals.com/milwaukee/news/2015/09/30/bucks-will-hike-prices-on-best-seats-at-new-arena.html', + 'body' => array( + '//figure/div/a/img', + '//p[@class="content__segment"]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/biztimes.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/biztimes.com.php new file mode 100644 index 0000000..d21aa98 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/biztimes.com.php @@ -0,0 +1,22 @@ + array( + '%.*%' => array( + 'test_url' => 'https://www.biztimes.com/2017/02/10/settlement-would-revive-fowler-lake-condo-project-in-oconomowoc/', + 'body' => array( + '//h2/span[@class="subhead"]', + '//div[contains(@class,"article-content")]', + ), + 'strip' => array( + '//script', + '//div[contains(@class,"mobile-article-content")]', + '//div[contains(@class,"sharedaddy")]', + '//div[contains(@class,"author-details")]', + '//div[@class="row ad"]', + '//div[contains(@class,"relatedposts")]', + '//div[@class="col-lg-12"]', + '//div[contains(@class,"widget")]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/bleepingcomputer.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/bleepingcomputer.com.php new file mode 100644 index 0000000..7b74060 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/bleepingcomputer.com.php @@ -0,0 +1,15 @@ + array( + '%.*%' => array( + 'test_url' => 'https://www.bleepingcomputer.com/news/google/chromes-sandbox-feature-infringes-on-three-patents-so-google-must-now-pay-20m/', + 'body' => array( + '//div[@class="article_section"]', + ), + 'strip' => array( + '//*[@itemprop="headline"]', + '//div[@class="cz-news-story-title-section"]' + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/blog.fefe.de.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/blog.fefe.de.php new file mode 100644 index 0000000..39c88ae --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/blog.fefe.de.php @@ -0,0 +1,13 @@ + array( + '%.*%' => array( + 'test_url' => 'http://blog.fefe.de/?ts=ad706a73', + 'body' => array( + '/html/body/ul', + ), + 'strip' => array( + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/blog.mapillary.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/blog.mapillary.com.php new file mode 100644 index 0000000..ce01651 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/blog.mapillary.com.php @@ -0,0 +1,11 @@ + array( + '%.*%' => array( + 'test_url' => 'http://blog.mapillary.com/update/2015/08/26/traffic-sign-updates.html', + 'body' => array( + '//div[contains(@class, "blog-post__content")]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/brewers.mlb.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/brewers.mlb.com.php new file mode 100644 index 0000000..be406fa --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/brewers.mlb.com.php @@ -0,0 +1,22 @@ + array( + '%.*%' => array( + 'test_url' => 'http://m.brewers.mlb.com/news/article/161364798', + 'body' => array( + '//article[contains(@class,"article")]', + ), + 'strip' => array( + '//div[contains(@class,"ad-slot")]', + '//h1', + '//span[@class="timestamp"]', + '//div[contains(@class,"contributor-bottom")]', + '//div[contains(@class,"video")]', + '//ul[contains(@class,"social")]', + '//p[@class="tagline"]', + '//div[contains(@class,"social")]', + '//div[@class="button-wrap"]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/buenosairesherald.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/buenosairesherald.com.php new file mode 100644 index 0000000..4e73e79 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/buenosairesherald.com.php @@ -0,0 +1,17 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.buenosairesherald.com/article/199344/manzur-named-next-governor-of-tucum%C3%A1n', + 'body' => array( + '//div[@style="float:none"]', + ), + 'strip' => array( + '//div[contains(@class, "bz_alias_short_desc_container"]', + '//td[@id="bz_show_bug_column_1"]', + '//table[@id="attachment_table"]', + '//table[@class="bz_comment_table"]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/bunicomic.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/bunicomic.com.php new file mode 100644 index 0000000..ad83e43 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/bunicomic.com.php @@ -0,0 +1,13 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.bunicomic.com/comic/buni-623/', + 'body' => array( + '//div[@class="comic-table"]', + ), + 'strip' => array( + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/buttersafe.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/buttersafe.com.php new file mode 100644 index 0000000..1f313cd --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/buttersafe.com.php @@ -0,0 +1,13 @@ + array( + '%.*%' => array( + 'test_url' => 'http://buttersafe.com/2015/04/21/the-incredible-flexible-man/', + 'body' => array( + '//div[@id="comic"]', + '//div[@class="post-comic"]', + ), + 'strip' => array(), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/cad-comic.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/cad-comic.com.php new file mode 100644 index 0000000..a631c97 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/cad-comic.com.php @@ -0,0 +1,12 @@ + array( + '%/cad/.+%' => array( + 'test_url' => 'http://www.cad-comic.com/cad/20150417', + 'body' => array( + '//*[@id="content"]/img', + ), + 'strip' => array(), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/chaoslife.findchaos.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/chaoslife.findchaos.com.php new file mode 100644 index 0000000..ea6191e --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/chaoslife.findchaos.com.php @@ -0,0 +1,10 @@ + array( + '%.*%' => array( + 'test_url' => 'http://chaoslife.findchaos.com/pets-in-the-wild', + 'body' => array('//div[@id="comic"]'), + 'strip' => array(), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/chinafile.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/chinafile.com.php new file mode 100644 index 0000000..450117b --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/chinafile.com.php @@ -0,0 +1,18 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.chinafile.com/books/shanghai-faithful?utm_source=feedburner&utm_medium=feed&utm_campaign=Feed%3A+chinafile%2FAll+%28ChinaFile%29', + 'body' => array( + '//div[contains(@class,"pane-featured-photo-panel-pane-1")]', + '//div[contains(@class,"video-above-fold")]', + '//div[@class="sc-media"]', + '//div[contains(@class,"field-name-body")]', + ), + 'strip' => array( + '//div[contains(@class,"cboxes")]', + '//div[contains(@class,"l-middle")]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/cliquerefresh.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/cliquerefresh.com.php new file mode 100644 index 0000000..9dcc7e5 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/cliquerefresh.com.php @@ -0,0 +1,10 @@ + array( + '%/comic.*%' => array( + 'test_url' => 'http://cliquerefresh.com/comic/078-stating-the-obvious/', + 'body' => array('//div[@class="comicImg"]/img | //div[@class="comicImg"]/a/img'), + 'strip' => array(), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/cnet.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/cnet.com.php new file mode 100644 index 0000000..60767a5 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/cnet.com.php @@ -0,0 +1,37 @@ + array( + '%^/products.*%' => array( + 'test_url' => 'http://www.cnet.com/products/fibaro-flood-sensor/#ftag=CADf328eec', + 'body' => array( + '//li[contains(@class,"slide first"] || //figure[contains(@class,(promoFigure))]', + '//div[@class="quickInfo"]', + '//div[@class="col-6 ratings"]', + '//div[@id="editorReview"]', + ), + 'strip' => array( + '//script', + '//a[@class="clickToEnlarge"]', + '//div[@section="topSharebar"]', + '//div[contains(@class,"related")]', + '//div[contains(@class,"ad-")]', + '//div[@section="shortcodeGallery"]', + ), + ), + '%.*%' => array( + 'test_url' => 'http://cnet.com.feedsportal.com/c/34938/f/645093/s/4a340866/sc/28/l/0L0Scnet0N0Cnews0Cman0Eclaims0Eonline0Epsychic0Emade0Ehim0Ebuy0E10Emillion0Epowerball0Ewinning0Eticket0C0Tftag0FCAD590Aa51e/story01.htm', + 'body' => array( + '//p[@itemprop="description"]', + '//div[@itemprop="articleBody"]', + ), + 'strip' => array( + '//script', + '//a[@class="clickToEnlarge"]', + '//div[@section="topSharebar"]', + '//div[contains(@class,"related")]', + '//div[contains(@class,"ad-")]', + '//div[@section="shortcodeGallery"]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/consomac.fr.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/consomac.fr.php new file mode 100644 index 0000000..9209f9c --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/consomac.fr.php @@ -0,0 +1,13 @@ + array( + '%.*%' => array( + 'test_url' => 'http://consomac.fr/news-2430-l-iphone-6-toujours-un-secret-bien-garde.html', + 'body' => array( + '//div[contains(@id, "newscontent")]', + ), + 'strip' => array( + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/cowbirdsinlove.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/cowbirdsinlove.com.php new file mode 100644 index 0000000..3214c62 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/cowbirdsinlove.com.php @@ -0,0 +1,8 @@ + array( + '%.*%' => array( + '%title="(.+)" */>%' => '/>
                                                                      $1', + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/crash.net.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/crash.net.php new file mode 100644 index 0000000..9d9b35a --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/crash.net.php @@ -0,0 +1,28 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.crash.net/motogp/interview/247550/1/exclusive-andrea-dovizioso-interview.html', + 'body' => array( + '//div[@id="content"]', + ), + 'strip' => array( + '//script', + '//style', + '//*[@title="Social Networking"]', + '//*[@class="crash-ad2"]', + '//*[@class="clearfix"]', + '//*[@class="crash-ad2"]', + '//*[contains(@id, "divCB"]', + '//*[@class="pnlComment"]', + '//*[@class="comments-tabs"]', + '//*[contains(@class, "ad-twocol"]', + '//*[@class="stories-list"]', + '//*[contains(@class, "btn")]', + '//*[@class="content"]', + '//h3', + ), + ), + ), +); + diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/csmonitor.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/csmonitor.com.php new file mode 100644 index 0000000..481e4b0 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/csmonitor.com.php @@ -0,0 +1,19 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.csmonitor.com/USA/Politics/2015/0925/John-Boehner-steps-down-Self-sacrificing-but-will-it-lead-to-better-government', + 'body' => array( + '//h2[@id="summary"]', + '//div[@class="flex-video youtube"]', + '//div[contains(@class,"eza-body")]', + ), + 'strip' => array( + '//span[@id="breadcrumb"]', + '//div[@id="byline-wrapper"]', + '//div[@class="injection"]', + '//*[contains(@class,"promo_link")]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/dailyjs.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/dailyjs.com.php new file mode 100644 index 0000000..20eb1d7 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/dailyjs.com.php @@ -0,0 +1,19 @@ + array( + '%.*%' => array( + 'test_url' => 'http://dailyjs.com/2014/08/07/p5js/', + 'body' => array( + '//div[@id="post"]', + ), + 'strip' => array( + '//h2[@class="post"]', + '//div[@class="meta"]', + '//*[contains(@class, "addthis_toolbox")]', + '//*[contains(@class, "addthis_default_style")]', + '//*[@class="navigation small"]', + '//*[@id="related"]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/dailyreporter.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/dailyreporter.com.php new file mode 100644 index 0000000..db3fc0e --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/dailyreporter.com.php @@ -0,0 +1,15 @@ + array( + '%.*%' => array( + 'test_url' => 'http://dailyreporter.com/2016/01/09/us-supreme-court-case-could-weaken-government-workers-unions/', + 'body' => array( + '//div[contains(@class, "entry-content")]', + ), + 'strip' => array( + '//div[@class="dmcss_login_form"]', + '//*[contains(@class, "sharedaddy")]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/dailytech.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/dailytech.com.php new file mode 100644 index 0000000..5d1df4a --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/dailytech.com.php @@ -0,0 +1,13 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.dailytech.com/Apples+First+Fixes+to+iOS+9+Land+w+iOS++901+Release/article37495.htm', + 'body' => array( + '//div[@class="NewsBodyImage"]', + '//span[@id="lblSummary"]', + '//span[@id="lblBody"]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/degroupnews.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/degroupnews.com.php new file mode 100644 index 0000000..91f5c56 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/degroupnews.com.php @@ -0,0 +1,14 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.degroupnews.com/medias/vodsvod/amazon-concurrence-la-chromecast-de-google-avec-fire-tv-stick', + 'body' => array( + '//div[@class="contenu"]', + ), + 'strip' => array( + '//div[contains(@class, "a2a")]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/derstandard.at.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/derstandard.at.php new file mode 100644 index 0000000..7e95a51 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/derstandard.at.php @@ -0,0 +1,14 @@ + array( + '%.*%' => array( + 'test_url' => 'http://derstandard.at/2000010267354/The-Witcher-3-Hohe-Hardware-Anforderungen-fuer-PC-Spieler?ref=rss', + 'body' => array( + '//div[@class="copytext"]', + '//ul[@id="media-list"]', + ), + 'strip' => array( + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/dilbert.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/dilbert.com.php new file mode 100644 index 0000000..b8e9b3d --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/dilbert.com.php @@ -0,0 +1,11 @@ + array( + '%.*%' => array( + 'body' => array( + '//img[@class="img-responsive img-comic"]', + ), + 'test_url' => 'http://dilbert.com/strip/2016-01-28', + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/discovermagazine.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/discovermagazine.com.php new file mode 100644 index 0000000..ae0dfe7 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/discovermagazine.com.php @@ -0,0 +1,26 @@ + array( + '%.*%' => array( + 'test_url' => 'http://blogs.discovermagazine.com/neuroskeptic/2017/01/25/publishers-jeffrey-beall/', + 'body' => array( + '//div[@class="contentWell"]', + ), + 'strip' => array( + '//h1', + '//div[@class="breadcrumbs"]', + '//div[@class="mobile"]', + '//div[@class="fromIssue"]', + '//div[contains(@class,"belowDeck")]', + '//div[@class="meta"]', + '//div[@class="shareIcons"]', + '//div[@class="categories"]', + '//div[@class="navigation"]', + '//div[@class="heading"]', + '//div[contains(@id,"-ad")]', + '//div[@class="relatedArticles"]', + '//div[@id="disqus_thread"]' + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/distrowatch.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/distrowatch.com.php new file mode 100644 index 0000000..aefc8f8 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/distrowatch.com.php @@ -0,0 +1,13 @@ + array( + '%.*%' => array( + 'test_url' => 'http://distrowatch.com/?newsid=08355', + 'body' => array( + '//td[@class="NewsText"][1]', + ), + 'strip' => array( + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/dozodomo.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/dozodomo.com.php new file mode 100644 index 0000000..e116695 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/dozodomo.com.php @@ -0,0 +1,15 @@ + array( + '%.*%' => array( + 'test_url' => 'http://dozodomo.com/bento/2014/03/04/lart-des-maki-de-takayo-kiyota/', + 'body' => array( + '//div[@class="joke"]', + '//div[@class="story-cover"]', + '//div[@class="story-content"]', + ), + 'strip' => array( + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/drawingboardcomic.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/drawingboardcomic.com.php new file mode 100644 index 0000000..cd30f2e --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/drawingboardcomic.com.php @@ -0,0 +1,15 @@ + array( + '%.*%' => array( + 'body' => array('//img[@id="comicimage"]'), + 'strip' => array(), + 'test_url' => 'http://drawingboardcomic.com/index.php?comic=208', + ), + ), + 'filter' => array( + '%.*%' => array( + '%title="(.+)" */>%' => '/>
                                                                      $1', + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/e-w-e.ru.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/e-w-e.ru.php new file mode 100644 index 0000000..8139cc9 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/e-w-e.ru.php @@ -0,0 +1,22 @@ + array( + '%.*%' => array( + 'test_url' => 'http://e-w-e.ru/16-prekrasnyx-izobretenij-zhenshhin/', + 'body' => array( + '//div[contains(@class, "post_text")]', + ), + 'strip' => array( + '//script', + '//form', + '//style', + '//*[@class="views_post"]', + '//*[@class="adman_mobile"]', + '//*[@class="adman_desctop"]', + '//*[contains(@rel, "nofollow")]', + '//*[contains(@class, "wp-smiley")]', + '//*[contains(text(),"Источник:")]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/economist.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/economist.com.php new file mode 100644 index 0000000..522032f --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/economist.com.php @@ -0,0 +1,25 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.economist.com/blogs/buttonwood/2017/02/mixed-signals?fsrc=rss', + 'body' => array( + '//article', + ), + 'strip' => array( + '//span[@class="blog-post__siblings-list-header "]', + '//h1', + '//aside', + '//div[@class="blog-post__asideable-wrapper"]', + '//div[@class="share_inline_header"]', + '//div[@id="column-right"]', + '//div[contains(@class,"blog-post__siblings-list-aside")]', + '//div[@class="video-player__wrapper"]', + '//div[@class="blog-post__bottom-panel"]', + '//div[contains(@class,"latest-updates-panel__container")]', + '//div[contains(@class,"blog-post__asideable-content")]', + '//div[@aria-label="Advertisement"]' + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/encyclopedie.naheulbeuk.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/encyclopedie.naheulbeuk.com.php new file mode 100644 index 0000000..19bcbde --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/encyclopedie.naheulbeuk.com.php @@ -0,0 +1,13 @@ + array( + '%.*%' => array( + 'test_url' => 'http://encyclopedie.naheulbeuk.com/article.php3?id_article=352', + 'body' => array( + '//td//h1[@class="titre-texte"]', + '//td//div[@class="surtitre"]', + '//td//div[@class="texte"]', + ), + ) + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/endlessorigami.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/endlessorigami.com.php new file mode 100644 index 0000000..d06ed12 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/endlessorigami.com.php @@ -0,0 +1,8 @@ + array( + '%.*%' => array( + '%-150x150%' => '', + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/engadget.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/engadget.com.php new file mode 100644 index 0000000..cf9e448 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/engadget.com.php @@ -0,0 +1,10 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.engadget.com/2015/04/20/dark-matter-discovery/?ncid=rss_truncated', + 'body' => array('//div[@id="page_body"]/div[@class="container@m-"]'), + 'strip' => array('//aside[@role="banner"]'), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/escapistmagazine.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/escapistmagazine.com.php new file mode 100644 index 0000000..e86b59c --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/escapistmagazine.com.php @@ -0,0 +1,45 @@ + array( + '%/articles/view/comicsandcosplay/comics/critical-miss.*%' => array( + 'body' => array('//*[@class="body"]/span/img | //div[@class="folder_nav_links"]/following::p'), + 'test_url' => 'http://www.escapistmagazine.com/articles/view/comicsandcosplay/comics/critical-miss/13776-Critical-Miss-on-Framerates?utm_source=rss&utm_medium=rss&utm_campaign=articles', + 'strip' => array(), + ), + '%/articles/view/comicsandcosplay/comics/namegame.*%' => array( + 'body' => array('//*[@class="body"]/span/p/img[@height != "120"]'), + 'test_url' => 'http://www.escapistmagazine.com/articles/view/comicsandcosplay/comics/namegame/9759-Leaving-the-Nest?utm_source=rss&utm_medium=rss&utm_campaign=articles', + 'strip' => array(), + ), + '%/articles/view/comicsandcosplay/comics/stolen-pixels.*%' => array( + 'body' => array('//*[@class="body"]/span/p[2]/img'), + 'test_url' => 'http://www.escapistmagazine.com/articles/view/comicsandcosplay/comics/stolen-pixels/8866-Stolen-Pixels-258-Where-the-Boys-Are?utm_source=rss&utm_medium=rss&utm_campaign=articles', + 'strip' => array(), + ), + '%/articles/view/comicsandcosplay/comics/bumhugparade.*%' => array( + 'body' => array('//*[@class="body"]/span/p[2]/img'), + 'test_url' => 'http://www.escapistmagazine.com/articles/view/comicsandcosplay/comics/bumhugparade/8262-Bumhug-Parade-13?utm_source=rss&utm_medium=rss&utm_campaign=articles', + 'strip' => array(), + ), + '%/articles/view/comicsandcosplay.*/comics/escapistradiotheater%' => array( + 'body' => array('//*[@class="body"]/span/p[2]/img'), + 'test_url' => 'http://www.escapistmagazine.com/articles/view/comicsandcosplay/comics/escapistradiotheater/8265-The-Escapist-Radio-Theater-13?utm_source=rss&utm_medium=rss&utm_campaign=articles', + 'strip' => array(), + ), + '%/articles/view/comicsandcosplay/comics/paused.*%' => array( + 'body' => array('//*[@class="body"]/span/p[2]/img | //*[@class="body"]/span/div/img'), + 'test_url' => 'http://www.escapistmagazine.com/articles/view/comicsandcosplay/comics/paused/8263-Paused-16?utm_source=rss&utm_medium=rss&utm_campaign=articles', + 'strip' => array(), + ), + '%/articles/view/comicsandcosplay/comics/fraughtwithperil.*%' => array( + 'body' => array('//*[@class="body"]'), + 'test_url' => 'http://www.escapistmagazine.com/articles/view/comicsandcosplay/comics/fraughtwithperil/12166-The-Escapist-Presents-Escapist-Comics-Critical-Miss-B-lyeh-Fhlop?utm_source=rss&utm_medium=rss&utm_campaign=articles', + 'strip' => array(), + ), + '%/articles/view/video-games/columns/.*%' => array( + 'body' => array('//*[@id="article_content"]'), + 'test_url' => 'http://www.escapistmagazine.com/articles/view/video-games/columns/experienced-points/13971-What-50-Shades-and-Batman-Have-in-Common.2', + 'strip' => array(), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/espn.go.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/espn.go.com.php new file mode 100644 index 0000000..76a20f7 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/espn.go.com.php @@ -0,0 +1,11 @@ + array( + '%.*%' => array( + 'test_url' => 'http://espn.go.com/nfl/story/_/id/13388208/jason-whitlock-chip-kelly-controversy', + 'body' => array( + '//p', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/exocomics.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/exocomics.com.php new file mode 100644 index 0000000..5adc59f --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/exocomics.com.php @@ -0,0 +1,15 @@ + array( + '%.*%' => array( + 'body' => array('//a[@class="comic"]/img'), + 'strip' => array(), + 'test_url' => 'http://www.exocomics.com/379', + ), + ), + 'filter' => array( + '%.*%' => array( + '%title="(.+)" */>%' => '/>
                                                                      $1', + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/explosm.net.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/explosm.net.php new file mode 100644 index 0000000..3fdf02c --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/explosm.net.php @@ -0,0 +1,13 @@ + array( + '%.*%' => array( + 'test_url' => 'http://explosm.net/comics/3803/', + 'body' => array( + '//div[@id="comic-container"]', + ), + 'strip' => array( + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/extrafabulouscomics.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/extrafabulouscomics.com.php new file mode 100644 index 0000000..12697cc --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/extrafabulouscomics.com.php @@ -0,0 +1,8 @@ + array( + '%.*%' => array( + '%-150x150%' => '', + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/factroom.ru.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/factroom.ru.php new file mode 100644 index 0000000..a572061 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/factroom.ru.php @@ -0,0 +1,27 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.factroom.ru/life/20-facts-about-oil', + 'body' => array( + '//div[@class="post"]', + ), + 'strip' => array( + '//script', + '//form', + '//style', + '//h1', + '//div[@id="yandex_ad2"]', + '//*[@class="jp-relatedposts"]', + '//div[contains(@class, "likely-desktop")]', + '//div[contains(@class, "likely-mobile")]', + '//p[last()]', + '//div[contains(@class, "facebook")]', + '//div[contains(@class, "desktop-underpost-direct")]', + '//div[contains(@class, "source-box")]', + '//div[contains(@class, "under-likely-desktop")]', + '//div[contains(@class, "mobile-down-post")]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/fastcodesign.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/fastcodesign.com.php new file mode 100644 index 0000000..74e70a8 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/fastcodesign.com.php @@ -0,0 +1,13 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.fastcodesign.com/3026548/exposure/peek-inside-the-worlds-forbidden-subway-tunnels', + 'body' => array( + '//article[contains(@class, "body prose")]', + ), + 'strip' => array( + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/fastcoexist.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/fastcoexist.com.php new file mode 100644 index 0000000..6916f28 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/fastcoexist.com.php @@ -0,0 +1,13 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.fastcoexist.com/3026114/take-a-seat-on-this-gates-funded-future-toilet-that-will-change-how-we-think-about-poop', + 'body' => array( + '//article[contains(@class, "body prose")]', + ), + 'strip' => array( + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/fastcompany.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/fastcompany.com.php new file mode 100644 index 0000000..e0869a2 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/fastcompany.com.php @@ -0,0 +1,13 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.fastcompany.com/3026712/fast-feed/elon-musk-an-apple-tesla-merger-is-very-unlikely', + 'body' => array( + '//article[contains(@class, "body prose")]', + ), + 'strip' => array( + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/ffworld.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/ffworld.com.php new file mode 100644 index 0000000..20a47b2 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/ffworld.com.php @@ -0,0 +1,13 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.ffworld.com/?rub=news&page=voir&id=2709', + 'body' => array( + '//div[@class="news_body"]', + ), + 'strip' => array( + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/foreignpolicy.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/foreignpolicy.com.php new file mode 100644 index 0000000..3cbcddc --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/foreignpolicy.com.php @@ -0,0 +1,21 @@ + array( + '%.*%' => array( + 'test_url' => 'http://foreignpolicy.com/2016/01/09/networking-giant-pulls-nsa-linked-code-exploited-by-hackers/', + 'body' => array( + '//article', + ), + 'strip' => array( + '//div[@id="post-category"]', + '//div[@id="desktop-right"]', + '//h1', + '//section[@class="article-meta"]', + '//div[@class="side-panel-wrapper"]', + '//*[contains(@class, "share-")]', + '//*[contains(@id, "taboola-")]', + '//div[@class="comments"]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/fossbytes.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/fossbytes.com.php new file mode 100644 index 0000000..6ce4725 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/fossbytes.com.php @@ -0,0 +1,18 @@ + array( + '%.*%' => array( + 'test_url' => 'http://fossbytes.com/fbi-hacked-1000-computers-to-shut-down-largest-child-pornography-site-on-the-dark-web/', + 'body' => array( + '//div[@class="entry-inner"]', + ), + 'strip' => array( + '//*[@class="at-above-post addthis_default_style addthis_toolbox at-wordpress-hide"]', + '//*[@class="at-below-post addthis_default_style addthis_toolbox at-wordpress-hide"]', + '//*[@class="at-below-post-recommended addthis_default_style addthis_toolbox at-wordpress-hide"]', + '//*[@class="code-block code-block-12 ai-desktop"]', + '//*[@class="code-block code-block-13 ai-tablet-phone"]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/fototelegraf.ru.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/fototelegraf.ru.php new file mode 100644 index 0000000..ca2f85a --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/fototelegraf.ru.php @@ -0,0 +1,19 @@ + array( + '%.*%' => array( + 'test_url' => 'http://fototelegraf.ru/?p=348232', + 'body' => array( + '//div[@class="post-content"]', + ), + 'strip' => array( + '//script', + '//form', + '//style', + '//div[@class="imageButtonsBlock"]', + '//div[@class="adOnPostBtwImg"]', + '//div[contains(@class, "post-tags")]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/fowllanguagecomics.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/fowllanguagecomics.com.php new file mode 100644 index 0000000..3f62f07 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/fowllanguagecomics.com.php @@ -0,0 +1,10 @@ + array( + '%.*%' => array( + 'body' => array('//*[@id="comic"] | //*[@class="post-image"]'), + 'strip' => array(), + 'test_url' => 'http://www.fowllanguagecomics.com/comic/working-out/', + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/geek.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/geek.com.php new file mode 100644 index 0000000..d9ccecc --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/geek.com.php @@ -0,0 +1,17 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.geek.com/news/the-11-best-ways-to-eat-eggs-1634076/', + 'body' => array( + '//div[@class="articleinfo"]/figure', + '//div[@class="articleinfo"]/article', + '//span[@class="by"]', + ), + 'strip' => array( + '//span[@class="red"]', + '//div[@class="on-target"]' + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/geektimes.ru.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/geektimes.ru.php new file mode 100644 index 0000000..1954138 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/geektimes.ru.php @@ -0,0 +1,12 @@ + array( + '%.*%' => array( + 'test_url' => 'https://geektimes.ru/post/289151/', + 'body' => array( + "//div[contains(concat(' ',normalize-space(@class),' '),' content ')]" + ), + 'strip' => array(), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/gerbilwithajetpack.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/gerbilwithajetpack.com.php new file mode 100644 index 0000000..44013b3 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/gerbilwithajetpack.com.php @@ -0,0 +1,12 @@ + array( + '%.*%' => array( + 'body' => array( + '//div[@id="comic-1"]', + '//div[@class="entry"]', + ), + 'test_url' => 'http://gerbilwithajetpack.com/passing-the-digital-buck/', + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/giantitp.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/giantitp.com.php new file mode 100644 index 0000000..d9c3ae5 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/giantitp.com.php @@ -0,0 +1,12 @@ + array( + '%/comics/oots.*%' => array( + 'test_url' => 'http://www.giantitp.com/comics/oots0989.html', + 'body' => array( + '//td[@align="center"]/img', + ), + 'strip' => array(), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/github.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/github.com.php new file mode 100644 index 0000000..726634f --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/github.com.php @@ -0,0 +1,14 @@ + array( + '%.*%' => array( + 'test_url' => 'https://github.com/audreyr/favicon-cheat-sheet', + 'body' => array( + '//article[contains(@class, "entry-content")]', + ), + 'strip' => array( + '//h1', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/gocomics.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/gocomics.com.php new file mode 100644 index 0000000..32960f0 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/gocomics.com.php @@ -0,0 +1,12 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.gocomics.com/pearlsbeforeswine/2015/05/30', + 'body' => array( + '//div[1]/p[1]/a[1]/img', + ), + 'strip' => array(), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/golem.de.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/golem.de.php new file mode 100644 index 0000000..8422483 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/golem.de.php @@ -0,0 +1,20 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.golem.de/news/breko-telekom-verzoegert-gezielt-den-vectoring-ausbau-1311-102974.html', + 'body' => array( + '//header[@class="cluster-header"]', + '//header[@class="paged-cluster-header"]', + '//div[@class="formatted"]', + ), + 'next_page' => array( + '//a[@id="atoc_next"]' + ), + 'strip' => array( + '//header[@class="cluster-header"]/a', + '//div[@id="iqadtile4"]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/gorabbit.ru.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/gorabbit.ru.php new file mode 100644 index 0000000..4e43248 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/gorabbit.ru.php @@ -0,0 +1,19 @@ + array( + '%.*%' => array( + 'test_url' => 'http://gorabbit.ru/article/10-oshchushcheniy-za-rulem-kogda-tolko-poluchil-voditelskie-prava', + 'body' => array( + '//div[@class="detail_text"]', + ), + 'strip' => array( + '//script', + '//form', + '//style', + '//div[@class="socials"]', + '//div[@id="cr_1"]', + '//div[@class="related_items"]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/habrahabr.ru.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/habrahabr.ru.php new file mode 100644 index 0000000..3f1ec16 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/habrahabr.ru.php @@ -0,0 +1,12 @@ + array( + '%.*%' => array( + 'test_url' => 'https://habrahabr.ru/company/pentestit/blog/328606/', + 'body' => array( + "//div[contains(concat(' ',normalize-space(@class),' '),' content ')]" + ), + 'strip' => array(), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/happletea.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/happletea.com.php new file mode 100644 index 0000000..75b0b83 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/happletea.com.php @@ -0,0 +1,18 @@ + array( + '%.*%' => array( + 'body' => array( + '//div[@id="comic"]', + '//div[@class="entry"]', + ), + 'strip' => array('//div[@class="ssba"]'), + 'test_url' => 'http://www.happletea.com/comic/mans-best-friend/', + ), + ), + 'filter' => array( + '%.*%' => array( + '%title="(.+)" */>%' => '/>
                                                                      $1', + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/hardware.fr.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/hardware.fr.php new file mode 100644 index 0000000..56aec4f --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/hardware.fr.php @@ -0,0 +1,11 @@ + array( + '%^/news.*%' => array( + 'test_url' => 'http://www.hardware.fr/news/14760/intel-lance-nouveaux-ssd-nand-3d.html', + 'body' => array( + '//div[@class="content_actualite"]/div[@class="md"]', + ) + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/heise.de.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/heise.de.php new file mode 100644 index 0000000..2055b3b --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/heise.de.php @@ -0,0 +1,12 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.heise.de/security/meldung/BND-300-Millionen-Euro-fuer-Fruehwarnsystem-gegen-Cyber-Attacken-2192237.html', + 'body' => array( + '//div[@class="meldung_wrapper"]', + '//div[@class="artikel_content"]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/hotshowlife.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/hotshowlife.com.php new file mode 100644 index 0000000..faf01f3 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/hotshowlife.com.php @@ -0,0 +1,23 @@ + array( + '%.*%' => array( + 'test_url' => 'https://hotshowlife.com/top-10-chempionov-produktov-po-szhiganiyu-kalorij/', + 'body' => array( + '//div[@class="entry-content"]', + ), + 'strip' => array( + '//script', + '//form', + '//style', + '//div[@class="ads2"]', + '//div[@class="mistape_caption"]', + '//div[contains(@class, "et_social_media_hidden")]', + '//div[contains(@class, "et_social_inline_bottom")]', + '//div[contains(@class, "avatar")]', + '//ul[contains(@class, "entry-tags")]', + '//div[contains(@class, "entry-meta")]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/huffingtonpost.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/huffingtonpost.com.php new file mode 100644 index 0000000..b52b07b --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/huffingtonpost.com.php @@ -0,0 +1,13 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.huffingtonpost.com/2014/02/20/centscere-social-media-syracuse_n_4823848.html', + 'body' => array( + '//article[@class="content")]', + ), + 'strip' => array( + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/imogenquest.net.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/imogenquest.net.php new file mode 100644 index 0000000..3214c62 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/imogenquest.net.php @@ -0,0 +1,8 @@ + array( + '%.*%' => array( + '%title="(.+)" */>%' => '/>
                                                                      $1', + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/indiehaven.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/indiehaven.com.php new file mode 100644 index 0000000..a40ce69 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/indiehaven.com.php @@ -0,0 +1,11 @@ + array( + '%.*%' => array( + 'test_url' => 'http://indiehaven.com/no-mans-sky-is-a-solo-space-adventure-and-im-ok-with-that/', + 'body' => array( + '//section[contains(@class, "entry-content")]', + ) + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/ing.dk.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/ing.dk.php new file mode 100644 index 0000000..5a021a0 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/ing.dk.php @@ -0,0 +1,12 @@ + array( + '%.*%' => array( + 'test_url' => 'http://ing.dk/artikel/smart-husisolering-og-styring-skal-mindske-japans-energikrise-164517', + 'body' => array( + '//section[contains(@class, "teaser")]', + '//section[contains(@class, "body")]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/invisiblebread.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/invisiblebread.com.php new file mode 100644 index 0000000..90f8759 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/invisiblebread.com.php @@ -0,0 +1,8 @@ + array( + '%.*%' => array( + '%()%' => '$1', + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/ir.amd.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/ir.amd.com.php new file mode 100644 index 0000000..af99fe9 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/ir.amd.com.php @@ -0,0 +1,10 @@ + array( + '%.*%' => array( + 'body' => array('//span[@class="ccbnTxt"]'), + 'strip' => array(), + 'test_url' => 'http://ir.amd.com/phoenix.zhtml?c=74093&p=RssLanding&cat=news&id=2055819', + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/japantimes.co.jp.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/japantimes.co.jp.php new file mode 100644 index 0000000..9959441 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/japantimes.co.jp.php @@ -0,0 +1,21 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.japantimes.co.jp/news/2015/09/27/world/social-issues-world/pope-meets-sex-abuse-victims-philadelphia-promises-accountability/', + 'body' => array( + '//article[@role="main"]', + ), + 'strip' => array( + '//script', + '//header', + '//div[contains(@class, "meta")]', + '//div[@class="clearfix"]', + '//div[@class="OUTBRAIN"]', + '//ul[@id="content_footer_menu"]', + '//div[@class="article_footer_ad"]', + '//div[@id="disqus_thread"]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/japantoday.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/japantoday.com.php new file mode 100644 index 0000000..22485d6 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/japantoday.com.php @@ -0,0 +1,15 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.japantoday.com/category/politics/view/japan-u-s-to-sign-new-base-environment-pact', + 'body' => array( + '//div[@id="article_container"]', + ), + 'strip' => array( + '//h2', + '//div[@id="article_info"]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/journaldugeek.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/journaldugeek.com.php new file mode 100644 index 0000000..876b269 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/journaldugeek.com.php @@ -0,0 +1,11 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www./2014/05/20/le-playstation-now-arrive-en-beta-fermee-aux-etats-unis/', + 'body' => array( + '//div[@class="post-content"]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/jsonline.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/jsonline.com.php new file mode 100644 index 0000000..5895256 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/jsonline.com.php @@ -0,0 +1,37 @@ + array( + '%.%/picture-gallery/%' => array( + 'test_url' => 'http://www.jsonline.com/picture-gallery/news/local/milwaukee/2017/02/22/photos-aclu-sues-milwaukee-police-over-profiling-stop-and-frisk/98250836/', + 'body' => array( + '//div[@class="priority-asset-gallery galleries standalone hasendslate"]', + ), + 'strip' => array( + '//div[@class="buy-photo-btn"]', + '//div[@class="gallery-thumbs thumbs pag-thumbs")]', + ), + ), + '%.*%' => array( + 'test_url' => 'http://www.jsonline.com/news/usandworld/as-many-as-a-million-expected-for-popes-last-mass-in-us-b99585180z1-329688131.html', + 'body' => array( + '//div[@itemprop="articleBody"]', + ), + 'strip' => array( + '//h1', + '//iframe', + '//span[@class="mycapture-small-btn mycapture-btn-with-text mycapture-expandable-photo-btn-small js-mycapture-btn-small"]', + '//div[@class="close-wrap"]', + '//div[contains(@class,"ui-video-wrapper")]', + '//div[contains(@class,"media-mob")]', + '//div[contains(@class,"left-mob")]', + '//div[contains(@class,"nerdbox")]', + '//p/span', + '//div[contains(@class,"oembed-asset")]', + '//*[contains(@class,"share")]', + '//div[contains(@class,"gallery-asset")]', + '//div[contains(@class,"oembed-asset")]', + '//div[@class="article-print-url"]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/justcoolidea.ru.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/justcoolidea.ru.php new file mode 100644 index 0000000..089ff29 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/justcoolidea.ru.php @@ -0,0 +1,19 @@ + array( + '%.*%' => array( + 'test_url' => 'http://justcoolidea.ru/idealnyj-sad-samodelnye-proekty-dlya-berezhlivogo-domovladeltsa/', + 'body' => array( + '//section[@class="entry-content"]', + ), + 'strip' => array( + '//script', + '//form', + '//style', + '//*[contains(@class, "essb_links")]', + '//*[contains(@rel, "nofollow")]', + '//*[contains(@class, "ads")]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/kanpai.fr.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/kanpai.fr.php new file mode 100644 index 0000000..c3a1abc --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/kanpai.fr.php @@ -0,0 +1,13 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.kanpai.fr/japon/comment-donner-lheure-en-japonais.html', + 'body' => array( + '//div[@class="single-left"]', + ), + 'strip' => array( + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/karriere.jobfinder.dk.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/karriere.jobfinder.dk.php new file mode 100644 index 0000000..25d6dfa --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/karriere.jobfinder.dk.php @@ -0,0 +1,12 @@ + array( + '%.*%' => array( + 'test_url' => 'http://karriere.jobfinder.dk/artikel/dansk-professor-skal-lede-smart-grid-forskning-20-millioner-dollars-763', + 'body' => array( + '//section[contains(@class, "teaser")]', + '//section[contains(@class, "body")]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/kodi.tv.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/kodi.tv.php new file mode 100644 index 0000000..439fc90 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/kodi.tv.php @@ -0,0 +1,11 @@ + array( + '%.*%' => array( + 'test_url' => 'https://kodi.tv/article/andwere-baaaaack', + 'body' => array( + '//div[@class="l-region--content"]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/koreaherald.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/koreaherald.com.php new file mode 100644 index 0000000..9651056 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/koreaherald.com.php @@ -0,0 +1,11 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.koreaherald.com/view.php?ud=20150926000018', + 'body' => array( + '//div[@id="articleText"]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/koreatimes.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/koreatimes.php new file mode 100644 index 0000000..f274b4a --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/koreatimes.php @@ -0,0 +1,14 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.koreatimes.co.kr/www/news/nation/2015/12/116_192409.html', + 'body' => array( + '//div[@id="p"]', + ), + 'strip' => array( + '//div[@id="webtalks_btn_listenDiv"]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/lastplacecomics.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/lastplacecomics.com.php new file mode 100644 index 0000000..12697cc --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/lastplacecomics.com.php @@ -0,0 +1,8 @@ + array( + '%.*%' => array( + '%-150x150%' => '', + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/legorafi.fr.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/legorafi.fr.php new file mode 100644 index 0000000..e6aae46 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/legorafi.fr.php @@ -0,0 +1,22 @@ + array( + '%.*%' => array( + 'test_url' => array( + 'http://www.legorafi.fr/2016/12/16/gorafi-magazine-bravo-vous-avez-bientot-presque-survecu-a-2016/', + 'http://www.legorafi.fr/2016/12/15/manuel-valls-promet-quune-fois-elu-il-debarrassera-la-france-de-manuel-valls/', + ), + 'body' => array( + '//section[@id="banner_magazine"]', + '//figure[@class="main_picture"]', + '//div[@class="content"]', + ), + 'strip' => array( + '//figcaption', + '//div[@class="sharebox"]', + '//div[@class="tags"]', + '//section[@class="taboola_article"]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/lejapon.fr.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/lejapon.fr.php new file mode 100644 index 0000000..8f2b293 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/lejapon.fr.php @@ -0,0 +1,17 @@ + array( + '%.*%' => array( + 'test_url' => 'http://lejapon.fr/guide-voyage-japon/5223/tokyo-sous-la-neige.htm', + 'body' => array( + '//div[@class="entry"]', + ), + 'strip' => array( + '//*[contains(@class, "addthis_toolbox")]', + '//*[contains(@class, "addthis_default_style")]', + '//*[@class="navigation small"]', + '//*[@id="related"]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/lesjoiesducode.fr.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/lesjoiesducode.fr.php new file mode 100644 index 0000000..369206a --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/lesjoiesducode.fr.php @@ -0,0 +1,13 @@ + array( + '%.*%' => array( + 'test_url' => 'http://lesjoiesducode.fr/post/75576211207/quand-lappli-ne-fonctionne-plus-sans-aucune-raison', + 'body' => array( + '//div[@class="blog-post-content"]', + ), + 'strip' => array( + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/lfg.co.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/lfg.co.php new file mode 100644 index 0000000..d978a5f --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/lfg.co.php @@ -0,0 +1,12 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.lfg.co/page/871/?utm_source=feedburner&utm_medium=feed&utm_campaign=Feed%3A+LookingForGroup+%28Looking+For+Group%29&utm_content=FeedBurner', + 'body' => array( + '//*[@id="comic"]/img | //*[@class="content"]', + ), + 'strip' => array(), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/lifehacker.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/lifehacker.com.php new file mode 100644 index 0000000..b9a6933 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/lifehacker.com.php @@ -0,0 +1,18 @@ + array( + '%.*%' => array( + 'test_url' => 'http://lifehacker.com/bring-water-bottle-caps-into-concerts-to-protect-your-d-1269334973', + 'body' => array( + '//div[contains(@class, "row")/img', + '//div[contains(@class, "content-column")]', + ), + 'strip' => array( + '//*[contains(@class, "meta")]', + '//span[contains(@class, "icon")]', + '//h1', + '//aside', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/lifehacker.ru.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/lifehacker.ru.php new file mode 100644 index 0000000..bc140f6 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/lifehacker.ru.php @@ -0,0 +1,22 @@ + array( + '%.*%' => array( + 'test_url' => 'http://lifehacker.ru/2016/03/03/polymail/', + 'body' => array( + '//div[@class="post-content"]', + ), + 'strip' => array( + '//script', + '//form', + '//style', + '//*[@class="wp-thumbnail-caption"]', + '//*[contains(@class, "social-likes")]', + '//*[@class="jp-relatedposts"]', + '//*[contains(@class, "wpappbox")]', + '//*[contains(@class, "icon__image")]', + '//div[@id="hypercomments_widget"]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/linux.org.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/linux.org.php new file mode 100644 index 0000000..2520d0d --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/linux.org.php @@ -0,0 +1,14 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.linux.org/threads/lua-the-scripting-interpreter.8352/', + 'body' => array( + '//div[@class="messageContent"]', + ), + 'strip' => array( + '//aside', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/linux.org.ru.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/linux.org.ru.php new file mode 100644 index 0000000..7fa0249 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/linux.org.ru.php @@ -0,0 +1,13 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.linux.org/threads/lua-the-scripting-interpreter.8352/', + 'body' => array( + '//div[@itemprop="articleBody"]', + ), + 'strip' => array( + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/linuxinsider.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/linuxinsider.com.php new file mode 100644 index 0000000..4e0a4cc --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/linuxinsider.com.php @@ -0,0 +1,20 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.linuxinsider.com/story/82526.html?rss=1', + 'body' => array( + '//div[@id="story"]', + ), + 'strip' => array( + '//script', + '//h1', + '//div[@id="story-toolbox1"]', + '//div[@id="story-byline"]', + '//div[@id="story"]/p', + '//div[@class="story-advertisement"]', + '//iframe', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/lists.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/lists.php new file mode 100644 index 0000000..c7051a2 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/lists.php @@ -0,0 +1,13 @@ + array( + '%.*%' => array( + 'test_url' => 'http://lists.freebsd.org/pipermail/freebsd-announce/2013-September/001504.html', + 'body' => array( + '//pre', + ), + 'strip' => array( + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/loadingartist.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/loadingartist.com.php new file mode 100644 index 0000000..d06ed12 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/loadingartist.com.php @@ -0,0 +1,8 @@ + array( + '%.*%' => array( + '%-150x150%' => '', + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/loldwell.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/loldwell.com.php new file mode 100644 index 0000000..d358e15 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/loldwell.com.php @@ -0,0 +1,10 @@ + array( + '%.*%' => array( + 'test_url' => 'http://loldwell.com/?comic=food-math-101', + 'body' => array('//*[@id="comic"]'), + 'strip' => array(), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/lukesurl.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/lukesurl.com.php new file mode 100644 index 0000000..816233d --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/lukesurl.com.php @@ -0,0 +1,15 @@ + array( + '%.*%' => array( + 'body' => array('//div[@id="comic"]//img'), + 'strip' => array(), + 'test_url' => 'http://www.lukesurl.com/archives/comic/665-3-of-clubs', + ), + ), + 'filter' => array( + '%.*%' => array( + '%title="(.+)" */>%' => '/>
                                                                      $1', + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/macg.co.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/macg.co.php new file mode 100644 index 0000000..bbe6dbc --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/macg.co.php @@ -0,0 +1,13 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.macg.co//logiciels/2014/05/feedly-sameliore-un-petit-peu-sur-mac-82205', + 'body' => array( + '//div[contains(@class, "field-name-body")]', + ), + 'strip' => array( + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/marc.info.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/marc.info.php new file mode 100644 index 0000000..5f582a6 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/marc.info.php @@ -0,0 +1,13 @@ + array( + '%.*%' => array( + 'test_url' => 'http://marc.info/?l=openbsd-misc&m=141987113202061&w=2', + 'body' => array( + '//pre', + ), + 'strip' => array( + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/marriedtothesea.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/marriedtothesea.com.php new file mode 100644 index 0000000..469640d --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/marriedtothesea.com.php @@ -0,0 +1,12 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.marriedtothesea.com/index.php?date=052915', + 'body' => array( + '//div[@align]/a/img', + ), + 'strip' => array(), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/marycagle.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/marycagle.com.php new file mode 100644 index 0000000..b8665e3 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/marycagle.com.php @@ -0,0 +1,13 @@ + array( + '%.*%' => array( + 'body' => array( + '//img[@id="cc-comic"]', + '//div[@class="cc-newsbody"]', + ), + 'strip' => array(), + 'test_url' => 'http://www.marycagle.com/letsspeakenglish/74-grim-reality/', + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/maximumble.thebookofbiff.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/maximumble.thebookofbiff.com.php new file mode 100644 index 0000000..8880054 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/maximumble.thebookofbiff.com.php @@ -0,0 +1,10 @@ + array( + '%.*%' => array( + 'test_url' => 'http://maximumble.thebookofbiff.com/2015/04/20/1084-change/', + 'body' => array('//div[@id="comic"]/div/a/img'), + 'strip' => array(), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/medium.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/medium.com.php new file mode 100644 index 0000000..e20860e --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/medium.com.php @@ -0,0 +1,19 @@ + array( + '%.*%' => array( + 'test_url' => 'https://medium.com/lessons-learned/917b8b63ae3e', + 'body' => array( + '//div[@class="section-content"]', + ), + 'strip' => array( + '//div[contains(@class,"metabar")]', + '//img[contains(@class,"thumbnail")]', + '//h1', + '//blockquote', + '//div[@class="aspectRatioPlaceholder-fill"]', + '//footer' + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/mercworks.net.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/mercworks.net.php new file mode 100644 index 0000000..c7a27de --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/mercworks.net.php @@ -0,0 +1,17 @@ + array( + '%.*%' => array( + 'body' => array('//div[@id="comic"]', + '//div[contains(@class,"entry-content")]', + ), + 'strip' => array(), + 'test_url' => 'http://mercworks.net/comicland/healthy-choice/', + ), + ), + 'filter' => array( + '%.*%' => array( + '%title="(.+)" */>%' => '/>
                                                                      $1', + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/metronieuws.nl.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/metronieuws.nl.php new file mode 100644 index 0000000..5011169 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/metronieuws.nl.php @@ -0,0 +1,10 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.metronieuws.nl/sport/2015/04/broer-fellaini-zorgde-bijna-voor-paniek-bij-mourinho', + 'body' => array('//div[contains(@class,"article-top")]/div[contains(@class,"image-component")] | //div[@class="article-full-width"]/div[1]'), + 'strip' => array(), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/milwaukeenns.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/milwaukeenns.php new file mode 100644 index 0000000..ddb29a5 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/milwaukeenns.php @@ -0,0 +1,14 @@ + array( + '%.*%' => array( + 'test_url' => 'http://milwaukeenns.org/2016/01/08/united-way-grant-enables-sdc-to-restore-free-tax-assistance-program/', + 'body' => array( + '//div[@class="pf-content"]', + ), + 'strip' => array( + '//div[@class="printfriendly"]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/mokepon.smackjeeves.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/mokepon.smackjeeves.com.php new file mode 100644 index 0000000..1ddcd40 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/mokepon.smackjeeves.com.php @@ -0,0 +1,10 @@ + array( + '%.*%' => array( + 'test_url' => 'http://mokepon.smackjeeves.com/comics/2120096/chapter-9-page-68/', + 'body' => array('//*[@id="comic_area_inner"]/img | //*[@id="comic_area_inner"]/a/img'), + 'strip' => array(), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/monandroid.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/monandroid.com.php new file mode 100644 index 0000000..f87560e --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/monandroid.com.php @@ -0,0 +1,13 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.monandroid.com/blog/tutoriel-avance-activer-le-stockage-fusionne-sur-android-6-marshamallow-t12.html', + 'body' => array( + '//div[@class="blog-post-body"]', + ), + 'strip' => array( + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/monwindows.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/monwindows.com.php new file mode 100644 index 0000000..b2b24d7 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/monwindows.com.php @@ -0,0 +1,13 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.monwindows.com/tout-savoir-sur-le-centre-d-action-de-windows-phone-8-1-t40574.html', + 'body' => array( + '//div[@class="blog-post-body"]', + ), + 'strip' => array( + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/moya-planeta.ru.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/moya-planeta.ru.php new file mode 100644 index 0000000..dd84284 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/moya-planeta.ru.php @@ -0,0 +1,21 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.moya-planeta.ru/travel/view/chto_yaponcu_horosho_russkomu_ne_ponyat_20432/', + 'body' => array( + '//div[@class="full_object"]', + ), + 'strip' => array( + '//div[@class="full_object_panel object_panel"]', + '//div[@class="full_object_panel_geo object_panel"]', + '//div[@class="full_object_title"]', + '//div[@class="full_object_social_likes"]', + '//div[@class="full_object_planeta_likes"]', + '//div[@class="full_object_go2comments"]', + '//div[@id="yandex_ad_R-163191-3"]', + '//div[@class="full_object_shop_article_recommend"]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/mrlovenstein.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/mrlovenstein.com.php new file mode 100644 index 0000000..b971091 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/mrlovenstein.com.php @@ -0,0 +1,9 @@ + array( + '%.*%' => array( + '%alt="(.+)" */>%' => '/>
                                                                      $1', + '%\.png%' => '_rollover.png', + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/muckrock.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/muckrock.com.php new file mode 100644 index 0000000..9e354a3 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/muckrock.com.php @@ -0,0 +1,20 @@ + array( + '%.*%' => array( + 'test_url' => 'https://www.muckrock.com/news/archives/2016/jan/13/5-concerns-private-prisons/', + 'body' => array( + '//div[@class="content"]', + ), + 'strip' => array( + '//div[@class="newsletter-widget"]', + '//div[@class="contributors"]', + '//time', + '//h1', + '//div[@class="secondary"]', + '//aside', + '//div[@class="articles__related"]' + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/mynorthshorenow.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/mynorthshorenow.com.php new file mode 100644 index 0000000..b630915 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/mynorthshorenow.com.php @@ -0,0 +1,27 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.mynorthshorenow.com/story/news/local/fox-point/2017/04/04/fox-point-building-board-approves-dunwood-commons-project/99875570/', + 'body' => array( + '//div[@itemprop="articleBody"]', + ), + 'strip' => array( + '//h1', + '//iframe', + '//span[@class="mycapture-small-btn mycapture-btn-with-text mycapture-expandable-photo-btn-small js-mycapture-btn-small"]', + '//div[@class="close-wrap"]', + '//div[contains(@class,"ui-video-wrapper")]', + '//div[contains(@class,"media-mob")]', + '//div[contains(@class,"left-mob")]', + '//div[contains(@class,"nerdbox")]', + '//p/span', + '//div[contains(@class,"oembed-asset")]', + '//*[contains(@class,"share")]', + '//div[contains(@class,"gallery-asset")]', + '//div[contains(@class,"oembed-asset")]', + '//div[@class="article-print-url"]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/nakedCapitalism.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/nakedCapitalism.php new file mode 100644 index 0000000..ec2d5fd --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/nakedCapitalism.php @@ -0,0 +1,11 @@ + array( + '%.*%' => array( + 'test_url' => 'http://feedproxy.google.com/~r/NakedCapitalism/~3/JOBxEHxN8ZI/mark-blyth-liberalism-undermined-democracy-failure-democratic-party.html', + 'body' => array( + '//div[@class="pf-content"]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/nasa.gov.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/nasa.gov.php new file mode 100644 index 0000000..c6692d0 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/nasa.gov.php @@ -0,0 +1,14 @@ + array( + '%.*%' => array( + 'test_url' => 'https://www.nasa.gov/image-feature/jpl/pia20514/coy-dione', + 'body' => array( + '//div[@class="article-body"]', + ), + 'strip' => array( + '//div[@class="title-bar"]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/nat-geo.ru.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/nat-geo.ru.php new file mode 100644 index 0000000..1a42d99 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/nat-geo.ru.php @@ -0,0 +1,11 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.nat-geo.ru/fact/868093-knidos-antichnyy-naukograd/', + 'body' => array( + '//div[@class="article-inner-text"]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/nationaljournal.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/nationaljournal.com.php new file mode 100644 index 0000000..5e612be --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/nationaljournal.com.php @@ -0,0 +1,15 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.nationaljournal.com/s/354962/south-carolina-evangelicals-outstrip-establishment?mref=home_top_main', + 'body' => array( + '//div[@class="section-body"]', + ), + 'strip' => array( + '//*[contains(@class, "-related")]', + '//*[contains(@class, "social")]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/nature.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/nature.com.php new file mode 100644 index 0000000..6b9e87f --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/nature.com.php @@ -0,0 +1,13 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.nature.com/doifinder/10.1038/nature.2015.18340', + 'body' => array( + '//div[contains(@class,"main-content")]', + ), + 'strip' => array(), + ), + ), +); + diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/nba.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/nba.com.php new file mode 100644 index 0000000..c8ea926 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/nba.com.php @@ -0,0 +1,15 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.nba.com/2015/news/09/25/knicks-jackson-to-spend-more-time-around-coaching-staff.ap/index.html?rss=true', + 'body' => array( + '//div[@class="paragraphs"]', + ), + 'strip' => array( + '//div[@id="nbaArticleSocialWrapper_bot"]', + '//h5', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/nedroid.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/nedroid.com.php new file mode 100644 index 0000000..3214c62 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/nedroid.com.php @@ -0,0 +1,8 @@ + array( + '%.*%' => array( + '%title="(.+)" */>%' => '/>
                                                                      $1', + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/networkworld.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/networkworld.com.php new file mode 100644 index 0000000..1852435 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/networkworld.com.php @@ -0,0 +1,20 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.networkworld.com/article/3020585/security/the-incident-response-fab-five.html', + 'body' => array( + '//figure/img[@class="hero-img"]', + '//section[@class="deck"]', + '//div[@itemprop="articleBody"] | //div[@itemprop="reviewBody"]', + '//div[@class="carousel-inside-crop"]', + ), + 'strip' => array( + '//script', + '//aside', + '//div[@class="credit"]', + '//div[@class="view-large"]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/neustadt-ticker.de.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/neustadt-ticker.de.php new file mode 100644 index 0000000..e0c0d19 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/neustadt-ticker.de.php @@ -0,0 +1,15 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.neustadt-ticker.de/41302/alltag/kultur/demo-auf-der-boehmischen', + 'body' => array( + '//div[@class="entry-content"]', + ), + 'strip' => array( + '//*[contains(@class, "sharedaddy")]', + '//*[contains(@class, "yarpp-related")]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/nextinpact.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/nextinpact.com.php new file mode 100644 index 0000000..29dd9d6 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/nextinpact.com.php @@ -0,0 +1,18 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.nextinpact.com/news/101122-3d-nand-intel-lance-six-nouvelles-gammes-ssd-pour-tous-usages.htm', + 'body' => array( + '//div[@class="container_article"]', + ), + 'strip' => array( + '//div[@class="infos_article"]', + '//div[@id="actu_auteur"]', + '//div[@id="soutenir_journaliste"]', + '//section[@id="bandeau_abonnez_vous"]', + '//br' + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/niceteethcomic.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/niceteethcomic.com.php new file mode 100644 index 0000000..f41e443 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/niceteethcomic.com.php @@ -0,0 +1,10 @@ + array( + '%/archives.*%' => array( + 'test_url' => 'http://niceteethcomic.com/archives/page119/', + 'body' => array('//*[@class="comicpane"]/a/img'), + 'strip' => array(), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/nichtlustig.de.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/nichtlustig.de.php new file mode 100644 index 0000000..4d083f9 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/nichtlustig.de.php @@ -0,0 +1,8 @@ + array( + '%.*%' => array( + '%.*static.nichtlustig.de/comics/full/(\\d+).*%s' => '', + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/oglaf.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/oglaf.com.php new file mode 100644 index 0000000..8b2b5b6 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/oglaf.com.php @@ -0,0 +1,19 @@ + array( + '%.*%' => array( + 'body' => array( + '//img[@id="strip"]', + '//a/div[@id="nx"]/..', + ), + 'strip' => array(), + 'test_url' => 'http://oglaf.com/slodging/', + ), + ), + 'filter' => array( + '%.*%' => array( + '%alt="(.+)" title="(.+)" */>%' => '/>
                                                                      $1
                                                                      $2
                                                                      ', + '%%' => 'Next page', + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/onhax.net.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/onhax.net.php new file mode 100644 index 0000000..213849d --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/onhax.net.php @@ -0,0 +1,15 @@ + array( + '%.*%' => array( + 'test_url' => 'http://onhax.net/process-lasso-8-9-1-4-pro-key-portable-is-here-latest', + 'body' => array( + '//div[@class="postcontent"]', + ), + 'strip' => array( + '//*[@class="sharedaddy sd-sharing-enabled"]', + '//*[@class="yarpp-related"]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/onmilwaukee.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/onmilwaukee.php new file mode 100644 index 0000000..f66ac4b --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/onmilwaukee.php @@ -0,0 +1,24 @@ + array( + '%.*%' => array( + 'test_url' => 'http://onmilwaukee.com/movies/articles/downerspelunking.html', + 'body' => array( + '//article[contains(@class, "show")]', + ), + 'strip' => array( + '//h1', + '//div[contains(@class,"-ad")]', + '//div[contains(@class,"_ad")]', + '//div[@id="pub_wrapper"]', + '//div[contains(@class,"share_tools")]', + '//div[@class="clearfix"]', + '//div[contains(@class,"image_control")]', + '//section[@class="ribboned"]', + '//div[contains(@class,"sidebar")]', + '//aside[@class="article_tag_list"]', + '//section[contains(@id,"more_posts")]' + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/openculture.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/openculture.com.php new file mode 100644 index 0000000..84f2bee --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/openculture.com.php @@ -0,0 +1,11 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.openculture.com/2017/03/are-we-living-inside-a-computer-simulation-watch-the-simulation-argument.html', + 'body' => array( + '//div[@class="entry"]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/opennet.ru.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/opennet.ru.php new file mode 100644 index 0000000..1fb7722 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/opennet.ru.php @@ -0,0 +1,13 @@ + array( + '%.*%' => array( + 'test_url' => 'https://www.opennet.ru/opennews/art.shtml?num=46549', + 'body' => array( + '//*[@id="r_memo"]', + ), + 'strip' => array( + ), + ) + ) +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/openrightsgroup.org.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/openrightsgroup.org.php new file mode 100644 index 0000000..94139a7 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/openrightsgroup.org.php @@ -0,0 +1,20 @@ + array( + '%.*%' => array( + 'test_url' => 'https://www.openrightsgroup.org/blog/2014/3-days-to-go-till-orgcon2014', + 'body' => array( + '//div[contains(@class, "content")]/div', + ), + 'strip' => array( + '//h2[1]', + '//div[@class="info"]', + '//div[@class="tags"]', + '//div[@class="comments"]', + '//div[@class="breadcrumbs"]', + '//h1[@class="pageTitle"]', + '//p[@class="bookmarkThis"]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/opensource.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/opensource.com.php new file mode 100644 index 0000000..60f3577 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/opensource.com.php @@ -0,0 +1,22 @@ + array( + '%.*%' => array( + 'test_url' => 'http://opensource.com/life/15/10/how-internet-things-will-change-way-we-think', + 'body' => array( + '//div[@id="article-template"]', + ), + 'strip' => array( + '//div[contains(@class,"os-article__sidebar")]', + '//div[@class="panel-pane pane-node-title"]', + '//div[@class="panel-pane pane-os-article-byline"]', + '//ul', + '//div[contains(@class,"-license")]', + '//div[contains(@class,"-tags")]', + '//div[@class="panel-pane pane-os-article-byline"]', + '//div[@class="os-article__content-below"]', + '//div[@id="comments"]' + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/optipess.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/optipess.com.php new file mode 100644 index 0000000..3214c62 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/optipess.com.php @@ -0,0 +1,8 @@ + array( + '%.*%' => array( + '%title="(.+)" */>%' => '/>
                                                                      $1', + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/osnews.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/osnews.com.php new file mode 100644 index 0000000..1d1396c --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/osnews.com.php @@ -0,0 +1,11 @@ + array( + '%.*%' => array( + 'test_url' => 'http://osnews.com/story/28863/Google_said_to_be_under_US_antitrust_scrutiny_over_Android', + 'body' => array( + '//div[@class="newscontent1"]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/pastebin.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/pastebin.com.php new file mode 100644 index 0000000..b20bf41 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/pastebin.com.php @@ -0,0 +1,13 @@ + array( + '%.*%' => array( + 'test_url' => 'http://pastebin.com/ed1pP9Ak', + 'body' => array( + '//div[@class="text"]', + ), + 'strip' => array( + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/peebleslab.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/peebleslab.com.php new file mode 100644 index 0000000..ce4891d --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/peebleslab.com.php @@ -0,0 +1,9 @@ + array( + '%.*%' => array( + // the extra space is required to strip the title cleanly + '%title="(.+) " */>%' => '/>
                                                                      $1', + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/penny-arcade.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/penny-arcade.com.php new file mode 100644 index 0000000..dd39983 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/penny-arcade.com.php @@ -0,0 +1,21 @@ + array( + '%/news/.*%' => array( + 'test_url' => 'http://penny-arcade.com/news/post/2015/04/15/101-part-two', + 'body' => array( + '//*[@class="postBody"]/*', + ), + 'strip' => array( + ), + ), + '%/comic/.*%' => array( + 'test_url' => 'http://penny-arcade.com/comic/2015/04/15', + 'body' => array( + '//*[@id="comicFrame"]/a/img', + ), + 'strip' => array( + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/pixelbeat.org.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/pixelbeat.org.php new file mode 100644 index 0000000..fa9052e --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/pixelbeat.org.php @@ -0,0 +1,12 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.pixelbeat.org/programming/sigpipe_handling.html#1425573246', + 'body' => array( + '//div[@class="contentText"]', + ), + 'strip' => array(), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/plus.google.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/plus.google.com.php new file mode 100644 index 0000000..5e48a6c --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/plus.google.com.php @@ -0,0 +1,11 @@ + array( + '%.*%' => array( + 'test_url' => 'https://plus.google.com/+LarryPage/posts/Lh8SKC6sED1', + 'body' => array( + '//div[@role="article"]/div[contains(@class, "eE")]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/popstrip.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/popstrip.com.php new file mode 100644 index 0000000..801a281 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/popstrip.com.php @@ -0,0 +1,8 @@ + array( + '%.*%' => array( + '%( '$1$2$1bonus.png"/>', + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/publicpolicyforum.org.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/publicpolicyforum.org.php new file mode 100644 index 0000000..5dc8be8 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/publicpolicyforum.org.php @@ -0,0 +1,15 @@ + array( + '%.*%' => array( + 'test_url' => 'https://publicpolicyforum.org/blog/going-extra-mile', + 'body' => array( + '//div[contains(@class,"field-name-post-date")]', + '//div[contains(@class,"field-name-body")]', + ), + 'strip' => array( + '//img[@src="http://publicpolicyforum.org/sites/default/files/logo3.jpg"]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/publy.ru.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/publy.ru.php new file mode 100644 index 0000000..bcfeeb9 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/publy.ru.php @@ -0,0 +1,24 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.publy.ru/post/19988', + 'body' => array( + '//div[@class="singlepost"]', + ), + 'strip' => array( + '//script', + '//form', + '//style', + '//*[@class="featured"]', + '//*[@class="toc_white no_bullets"]', + '//*[@class="toc_title"]', + '//*[@class="pba"]', + '//*[@class="comments"]', + '//*[contains(@class, "g-single")]', + '//*[@class="ts-fab-wrapper"]', + '//*[contains(@class, "wp_rp_wrap")]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/putaindecode.fr.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/putaindecode.fr.php new file mode 100644 index 0000000..9fa5568 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/putaindecode.fr.php @@ -0,0 +1,16 @@ + array( + '%.*%' => array( + 'test_url' => 'http://putaindecode.fr/posts/js/etat-lieux-js-modulaire-front/', + 'body' => array( + '//*[@class="putainde-Post-md"]', + ), + 'strip' => array( + '//*[contains(@class, "inlineimg")]', + '//*[contains(@class, "comment-respond")]', + '//header', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/recode.net.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/recode.net.php new file mode 100644 index 0000000..343cd12 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/recode.net.php @@ -0,0 +1,20 @@ + array( + '%.*%' => array( + 'test_url' => 'http://recode.net/2015/09/26/big-tech-rolls-out-red-carpet-for-indian-prime-minister-lobbies-behind-closed-doors/', + 'body' => array( + '//img[contains(@class,"attachment-large")]', + '//div[contains(@class,"postarea")]', + '//li[@class,"author"]', + ), + 'strip' => array( + '//script', + '//div[contains(@class,"sharedaddy")]', + '//div[@class="post-send-off"]', + '//div[@class="large-12 columns"]', + '//div[contains(@class,"inner-related-article")]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/retractionwatch.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/retractionwatch.com.php new file mode 100644 index 0000000..b97c73e --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/retractionwatch.com.php @@ -0,0 +1,18 @@ + array( + '%.*%' => array( + 'test_url' => 'http://retractionwatch.com/2015/11/12/psychologist-jens-forster-settles-case-by-agreeing-to-2-retractions/', + 'body' => array( + '//*[@class="main"]', + '//*[@class="entry-content"]', + ), + 'strip' => array( + '//*[contains(@class, "sharedaddy")]', + '//*[contains(@class, "jp-relatedposts")]', + '//p[@class="p1"]', + ) + ) + ) +); + diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/rockpapershotgun.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/rockpapershotgun.com.php new file mode 100644 index 0000000..7111078 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/rockpapershotgun.com.php @@ -0,0 +1,11 @@ + array( + '%.*%' => array( + 'test_url' => 'https://www.rockpapershotgun.com/2016/08/26/the-divisions-expansions-delayed-to-improve-the-game/', + 'body' => array( + '//div[@class="entry"]', + ) + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/rue89.nouvelobs.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/rue89.nouvelobs.com.php new file mode 100644 index 0000000..cb9116a --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/rue89.nouvelobs.com.php @@ -0,0 +1,13 @@ + array( + '%.*%' => array( + 'test_url' => 'http://rue89.feedsportal.com/c/33822/f/608948/s/30999fa0/sc/24/l/0L0Srue890N0C20A130C0A80C30A0Cfaisait0Eboris0Eboillon0Eex0Esarko0Eboy0E350A0E0A0A0A0Eeuros0Egare0Enord0E245315/story01.htm', + 'body' => array( + '//*[@id="article"]/div[contains(@class, "content")]', + ), + 'strip' => array( + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/rugbyrama.fr.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/rugbyrama.fr.php new file mode 100644 index 0000000..9915c23 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/rugbyrama.fr.php @@ -0,0 +1,20 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.rugbyrama.fr/rugby/top-14/2015-2016/top-14-hayman-coupe-du-monde-finale-2012-lutte.-voici-levan-chilachava-toulon_sto5283863/story.shtml', + 'body' => array( + '//div[@class="storyfull__content"]', + ), + 'strip' => array( + '//script', + '//form', + '//style', + '//*[@class="share-buttons"]', + '//*[@class="ad"]', + '//*[@class="hide-desktop"]', + '//*[@id="tracking_img"]', + ) + ) + ) +); \ No newline at end of file diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/satwcomic.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/satwcomic.com.php new file mode 100644 index 0000000..d63fc11 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/satwcomic.com.php @@ -0,0 +1,13 @@ + array( + '%.*%' => array( + 'test_url' => 'http://satwcomic.com/day-at-the-beach', + 'body' => array( + '//div[@class="container"]/center/a/img', + '//span[@itemprop="articleBody"]', + ), + 'strip' => array(), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/scrumalliance.org.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/scrumalliance.org.php new file mode 100644 index 0000000..7835fd9 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/scrumalliance.org.php @@ -0,0 +1,12 @@ + array( + '%.*%' => array( + 'test_url' => 'https://www.scrumalliance.org/community/articles/2015/march/an-introduction-to-agile-project-intake?feed=articles', + 'body' => array( + '//div[@class="article_content"]', + ), + 'strip' => array(), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/securityfocus.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/securityfocus.com.php new file mode 100644 index 0000000..0104514 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/securityfocus.com.php @@ -0,0 +1,17 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.securityfocus.com/archive/1/540139', + 'body' => array( + '//div[@id="vulnerability"]', + '//div[@class="comments_reply"]', + ), + 'strip' => array( + '//span[@class="title"]', + '//div[@id="logo_new"]', + '//div[@id="bannerAd"]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/sentfromthemoon.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/sentfromthemoon.com.php new file mode 100644 index 0000000..f435417 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/sentfromthemoon.com.php @@ -0,0 +1,18 @@ + array( + '%.*%' => array( + 'body' => array( + '//div[@class="comicpane"]/a/img', + '//div[@class="entry"]', + ), + 'strip' => array(), + 'test_url' => 'http://sentfromthemoon.com/archives/1417', + ), + ), + 'filter' => array( + '%.*%' => array( + '%title="(.+)" */>%' => '/>
                                                                      $1', + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/sitepoint.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/sitepoint.com.php new file mode 100644 index 0000000..ab0eb7d --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/sitepoint.com.php @@ -0,0 +1,13 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.sitepoint.com/creating-hello-world-app-swift/', + 'body' => array( + '//section[@class="article_body"]', + ), + 'strip' => array( + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/slashdot.org.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/slashdot.org.php new file mode 100644 index 0000000..89ced8b --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/slashdot.org.php @@ -0,0 +1,11 @@ + array( + '%.*%' => array( + 'test_url' => 'http://science.slashdot.org/story/15/04/20/0528253/pull-top-can-tabs-at-50-reach-historic-archaeological-status', + 'body' => array( + '//article/div[@class="body"] | //article[@class="layout-article"]/div[@class="elips"]', ), + 'strip' => array(), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/smallhousebliss.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/smallhousebliss.com.php new file mode 100644 index 0000000..8c13c44 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/smallhousebliss.com.php @@ -0,0 +1,19 @@ + array( + '%.*%' => array( + 'test_url' => 'http://smallhousebliss.com/2013/08/29/house-g-by-lode-architecture/', + 'body' => array( + '//div[@class="post-content"]', + ), + 'strip' => array( + '//*[contains(@class, "gallery")]', + '//*[contains(@class, "share")]', + '//*[contains(@class, "wpcnt")]', + '//*[contains(@class, "meta")]', + '//*[contains(@class, "postitle")]', + '//*[@id="nav-below"]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/smarthomewelt.de.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/smarthomewelt.de.php new file mode 100644 index 0000000..7463abc --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/smarthomewelt.de.php @@ -0,0 +1,10 @@ + array( + '%.*%' => array( + 'test_url' => 'http://smarthomewelt.de/apple-tv-amazon-echo-smart-home/', + 'body' => array('//div[@class="entry-inner"]/p | //div[@class="entry-inner"]/div[contains(@class,"wp-caption")]'), + 'strip' => array(), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/smashingmagazine.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/smashingmagazine.com.php new file mode 100644 index 0000000..cbe1072 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/smashingmagazine.com.php @@ -0,0 +1,10 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.smashingmagazine.com/2015/04/17/using-sketch-for-responsive-web-design-case-study/', + 'body' => array('//article[contains(@class,"post")]/p'), + 'strip' => array(), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/smbc-comics.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/smbc-comics.com.php new file mode 100644 index 0000000..42262dc --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/smbc-comics.com.php @@ -0,0 +1,14 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.smbc-comics.com/comic/the-troll-toll', + 'body' => array( + '//div[@id="cc-comicbody"]', + '//div[@id="aftercomic"]', + ), + 'strip' => array( + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/snopes.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/snopes.com.php new file mode 100644 index 0000000..b0fe655 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/snopes.com.php @@ -0,0 +1,22 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.snopes.com/bacca-brides-on-tour/', + 'body' => array( + '//article', + ), + 'strip' => array( + '//span[@itemprop="author"]', + '//div[contains(@class,"author-")]', + '//h1', + '//style', + '//div[contains(@class,"socialShares")]', + '//div[contains(@class,"ad-unit")]', + '//aside', + '//div[contains(@class,"boomtrain")]', + '//footer' + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/soundandvision.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/soundandvision.com.php new file mode 100644 index 0000000..6448bb0 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/soundandvision.com.php @@ -0,0 +1,21 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.soundandvision.com/content/james-guthrie-mixing-roger-waters-and-pink-floyd-51', + 'body' => array( + '//div[@id="left"]', + ), + 'strip' => array( + '//div[@class="meta"]', + '//div[@class="ratingsbox"]', + '//h1', + '//h2', + '//addthis', + '//comment-links', + '//div[@class="book-navigation"]', + '//div[@class="comment-links"]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/spiegel.de.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/spiegel.de.php new file mode 100644 index 0000000..e2e3db0 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/spiegel.de.php @@ -0,0 +1,11 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.spiegel.de/politik/ausland/afrika-angola-geht-gegen-islam-vor-und-schliesst-moscheen-a-935788.html', + 'body' => array( + '//div[contains(@class, "article-section")]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/stereophile.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/stereophile.com.php new file mode 100644 index 0000000..8e410be --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/stereophile.com.php @@ -0,0 +1,11 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.stereophile.com/content/2015-rocky-mountain-audio-fest-starts-friday', + 'body' => array( + '//div[@class="content clear-block"]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/stupidfox.net.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/stupidfox.net.php new file mode 100644 index 0000000..61182d7 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/stupidfox.net.php @@ -0,0 +1,13 @@ + array( + '%.*%' => array( + 'test_url' => 'http://stupidfox.net/134-sleepy-time', + 'body' => array( + '//div[@class="comicmid"]/center/a/img', + '//div[@class="stand_high"]', + ), + 'strip' => array(), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/subtraction.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/subtraction.com.php new file mode 100644 index 0000000..6d74427 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/subtraction.com.php @@ -0,0 +1,15 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.subtraction.com/2015/06/06/time-lapse-video-of-one-world-trade-center/', + 'body' => array('//article/div[@class="entry-content"]'), + 'strip' => array(), + ), + ), + 'filter' => array( + '%.*%' => array( + '%\+%' => '', + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/sz.de.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/sz.de.php new file mode 100644 index 0000000..90bde5a --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/sz.de.php @@ -0,0 +1,10 @@ + array( + '%.*%' => array( + 'test_url' => 'http://sz.de/1.2443161', + 'body' => array('//article[@id="sitecontent"]/section[@class="topenrichment"]//img | //article[@id="sitecontent"]/section[@class="body"]/section[@class="authors"]/preceding-sibling::*[not(contains(@class, "ad"))]'), + 'strip' => array(), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/takprosto.cc.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/takprosto.cc.php new file mode 100644 index 0000000..624ef90 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/takprosto.cc.php @@ -0,0 +1,21 @@ + array( + '%.*%' => array( + 'test_url' => 'http://takprosto.cc/kokteyl-dlya-pohudeniya-v-domashnih-usloviyah/', + 'body' => array( + '//div[contains(@class, "entry-contentt")]', + ), + 'strip' => array( + '//script', + '//form', + '//style', + '//*[@class="views_post"]', + '//*[contains(@class, "mailchimp-box")]', + '//*[contains(@class, "essb_links")]', + '//*[contains(@rel, "nofollow")]', + '//*[contains(@class, "ads")]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/techcrunch.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/techcrunch.com.php new file mode 100644 index 0000000..d6e620f --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/techcrunch.com.php @@ -0,0 +1,15 @@ + array( + '%.*%' => array( + 'test_url' => 'http://techcrunch.com/2013/08/31/indias-visa-maze/', + 'body' => array( + '//div[contains(@class, "media-container")]', + '//div[@class="body-copy"]', + ), + 'strip' => array( + '//*[contains(@class, "module-crunchbase")]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/the-ebook-reader.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/the-ebook-reader.com.php new file mode 100644 index 0000000..3b01eb9 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/the-ebook-reader.com.php @@ -0,0 +1,15 @@ + array( + '%.*%' => array( + 'test_url' => 'http://blog.the-ebook-reader.com/2015/09/25/kobo-glo-hd-and-kobo-touch-2-0-covers-and-cases-roundup/', + 'body' => array( + '//div[@class="entry"]', + ), + 'strip' => array( + '//div[@id="share"]', + '//div[contains(@class,"ItemCenter")]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/theatlantic.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/theatlantic.com.php new file mode 100644 index 0000000..bfad4ab --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/theatlantic.com.php @@ -0,0 +1,23 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.theatlantic.com/politics/archive/2015/09/what-does-it-mean-to-lament-the-poor-inside-panem/407317/', + 'body' => array( + '//picture[@class="img"]', + '//figure/figcaption/span', + '//div/p[@itemprop="description"]', + '//div[@class="article-body"]', + '//ul[@class="photos"]', + ), + 'strip' => array( + '//aside[@class="callout"]', + '//span[@class="credit"]', + '//figcaption[@class="credit"]', + '//aside[contains(@class,"partner-box")]', + '//div[contains(@class,"ad")]', + '//a[contains(@class,"social-icon")]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/theawkwardyeti.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/theawkwardyeti.com.php new file mode 100644 index 0000000..fd4f3d5 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/theawkwardyeti.com.php @@ -0,0 +1,12 @@ + array( + '%/comic/.*%' => array( + 'test_url' => 'http://theawkwardyeti.com/comic/things-to-do/', + 'body' => array( + '//div[@id="comic"]' + ), + 'strip' => array() + ) + ) +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/thecodinglove.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/thecodinglove.com.php new file mode 100644 index 0000000..c6ec5bf --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/thecodinglove.com.php @@ -0,0 +1,10 @@ + array( + '%.*%' => array( + 'test_url' => 'http://thecodinglove.com/post/116897934767', + 'body' => array('//div[@class="bodytype"]'), + 'strip' => array(), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/thedoghousediaries.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/thedoghousediaries.com.php new file mode 100644 index 0000000..d2f840d --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/thedoghousediaries.com.php @@ -0,0 +1,18 @@ + array( + '%.*%' => array( + 'body' => array( + '//div[@class="comicpane"]/a/img', + '//div[@class="entry"]', + ), + 'strip' => array(), + 'test_url' => 'http://thedoghousediaries.com/6023', + ), + ), + 'filter' => array( + '%.*%' => array( + '%title="(.+)" */>%' => '/>
                                                                      $1', + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/thegamercat.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/thegamercat.com.php new file mode 100644 index 0000000..f9b4637 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/thegamercat.com.php @@ -0,0 +1,10 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.thegamercat.com/comic/just-no/', + 'body' => array('//div[@id="comic"] | //div[@class="post-content"]/div[@class="entry"]/p'), + 'strip' => array(), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/thehindu.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/thehindu.com.php new file mode 100644 index 0000000..1e6735b --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/thehindu.com.php @@ -0,0 +1,19 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.thehindu.com/sci-tech/science/why-is-the-shape-of-cells-in-a-honeycomb-always-hexagonal/article7692306.ece?utm_source=RSS_Feed&utm_medium=RSS&utm_campaign=RSS_Syndication', + 'body' => array( + '//div/img[@class="main-image"]', + '//div[@class="photo-caption"]', + '//div[@class="articleLead"]', + '//p', + '//span[@class="upper"]', + ), + 'strip' => array( + '//div[@id="articleKeywords"]', + '//div[@class="photo-source"]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/thelocal.se.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/thelocal.se.php new file mode 100644 index 0000000..c3ec250 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/thelocal.se.php @@ -0,0 +1,17 @@ + array( + '%.*%' => array( + 'test_url' => 'www.thelocal.se/20161219/this-swede-can-memorize-hundreds-of-numbers-in-only-five-minutes', + 'body' => array( + '//div[@id="article-photo"]', + '//div[@id="article-description"]', + '//div[@id="article-body"]', + ), + 'strip' => array( + '//div[@id="article-info-middle"]', + ) + ) + ) +); + diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/themerepublic.net.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/themerepublic.net.php new file mode 100644 index 0000000..bc47b27 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/themerepublic.net.php @@ -0,0 +1,10 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.themerepublic.net/2015/04/david-lopez-pitoko.html?utm_source=feedburner&utm_medium=feed&utm_campaign=Feed%3A+blogspot%2FDngUJ+%28Theme+Republic%29&utm_content=FeedBurner', + 'body' => array('//*[@class="post-body"]'), + 'strip' => array(), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/themoscowtimes.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/themoscowtimes.com.php new file mode 100644 index 0000000..0f5bf75 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/themoscowtimes.com.php @@ -0,0 +1,18 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.themoscowtimes.com/business/article/535500.html', + 'body' => array( + '//div[@class="article_main_img"]', + '//div[@class="article_text"]', + ), + 'strip' => array( + '//div[@class="articlebottom"]', + '//p/b', + '//p/a[contains(@href, "/article.php?id=")]', + '//div[@class="disqus_wrap"]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/thenewslens.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/thenewslens.com.php new file mode 100644 index 0000000..7538170 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/thenewslens.com.php @@ -0,0 +1,21 @@ + array( + '%.*%' => array( + 'test_url' => 'http://international.thenewslens.com/post/255032/', + 'body' => array( + '//div[@class="article-section"]', + ), + 'strip' => array( + '//div[contains(@class,"ad-")]', + '//div[@class="article-title-box"]', + '//div[@class="function-box"]', + '//p/span', + '//aside', + '//footer', + '//div[@class="article-infoBot-box"]', + '//div[contains(@class,"standard-container")]' + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/theodd1sout.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/theodd1sout.com.php new file mode 100644 index 0000000..d06ed12 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/theodd1sout.com.php @@ -0,0 +1,8 @@ + array( + '%.*%' => array( + '%-150x150%' => '', + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/theonion.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/theonion.com.php new file mode 100644 index 0000000..acbfd36 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/theonion.com.php @@ -0,0 +1,12 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.theonion.com/article/wild-eyed-jim-harbaugh-informs-players-they-must-k-51397?utm_medium=RSS&utm_campaign=feeds', + 'body' => array( + '//div[@class="content-masthead"]/figure/div/noscript/img', + '//div[@class="content-text"]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/thestandard.com.hk.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/thestandard.com.hk.php new file mode 100644 index 0000000..1163b34 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/thestandard.com.hk.php @@ -0,0 +1,22 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.thestandard.com.hk/breaking_news_detail.asp?id=67156', + 'body' => array( + '//table/tr/td/span[@class="bodyCopy"]', + ), + 'strip' => array( + '//script', + '//br', + '//map[@name="gif_bar"]', + '//img[contains(@usemap,"gif_bar")]', + '//a', + '//span[@class="bodyHeadline"]', + '//i', + '//b', + '//table', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/threepanelsoul.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/threepanelsoul.com.php new file mode 100644 index 0000000..4af6196 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/threepanelsoul.com.php @@ -0,0 +1,11 @@ + array( + '%.*%' => array( + 'body' => array( + '//img[@id="cc-comic"]', + ), + 'test_url' => 'http://www.threepanelsoul.com/comic/uncloaking', + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/timesofindia.indiatimes.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/timesofindia.indiatimes.com.php new file mode 100644 index 0000000..1924680 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/timesofindia.indiatimes.com.php @@ -0,0 +1,14 @@ + array( + '%.*%' => array( + 'test_url' => 'http://timesofindia.indiatimes.com/city/mangaluru/Adani-UPCL-to-release-CSR-grant-of-Rs-3-74-crore-to-YellurGram-Panchayat/articleshow/50512116.cms', + 'body' => array( + '//div[@class="article_content clearfix"]', + '//section[@class="highlight clearfix"]', + ), + 'strip' => array( + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/travel-dealz.de.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/travel-dealz.de.php new file mode 100644 index 0000000..4ee4fcd --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/travel-dealz.de.php @@ -0,0 +1,15 @@ + array( + '%^/blog.*%' => array( + 'test_url' => 'http://travel-dealz.de/blog/venere-gutschein/', + 'body' => array('//div[@class="post-entry"]'), + 'strip' => array( + '//*[@id="jp-relatedposts"]', + '//*[@class="post-meta"]', + '//*[@class="post-data"]', + '//*[@id="author-meta"]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/treehugger.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/treehugger.com.php new file mode 100644 index 0000000..55eb7e0 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/treehugger.com.php @@ -0,0 +1,14 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.treehugger.com/uncategorized/top-ten-posts-week-bunnies-2.html', + 'body' => array( + '//div[contains(@class, "promo-image")]', + '//div[contains(@id, "entry-body")]', + ), + 'strip' => array( + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/treelobsters.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/treelobsters.com.php new file mode 100644 index 0000000..3214c62 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/treelobsters.com.php @@ -0,0 +1,8 @@ + array( + '%.*%' => array( + '%title="(.+)" */>%' => '/>
                                                                      $1', + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/twogag.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/twogag.com.php new file mode 100644 index 0000000..79f4f62 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/twogag.com.php @@ -0,0 +1,8 @@ + array( + '%.*%' => array( + '%http://www.twogag.com/comics-rss/([^.]+)\\.jpg%' => 'http://www.twogag.com/comics/$1.jpg', + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/twokinds.keenspot.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/twokinds.keenspot.com.php new file mode 100644 index 0000000..3428fcb --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/twokinds.keenspot.com.php @@ -0,0 +1,10 @@ + array( + '%.*%' => array( + 'test_url' => 'http://twokinds.keenspot.com/archive.php?p=0', + 'body' => array('//*[@class="comic"]/div/a/img | //*[@class="comic"]/div/img | //*[@id="cg_img"]/img | //*[@id="cg_img"]/a/img'), + 'strip' => array(), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/undeadly.org.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/undeadly.org.php new file mode 100644 index 0000000..8b15900 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/undeadly.org.php @@ -0,0 +1,14 @@ + array( + '%.*%' => array( + 'test_url' => 'http://undeadly.org/cgi?action=article&sid=20141101181155', + 'body' => array( + '/html/body/table[3]/tbody/tr/td[1]/table[2]/tr/td[1]', + ), + 'strip' => array( + '//font', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/upi.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/upi.com.php new file mode 100644 index 0000000..ec8d1a1 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/upi.com.php @@ -0,0 +1,15 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.upi.com/Top_News/US/2015/09/26/Tech-giants-Hollywood-stars-among-guests-at-state-dinner-for-Chinas-Xi-Jinping/4541443281006/', + 'body' => array( + '//div[@class="img"]', + '//div/article[@itemprop="articleBody"]', + ), + 'strip' => array( + '//div[@align="center"]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/usatoday.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/usatoday.com.php new file mode 100644 index 0000000..edd6aa4 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/usatoday.com.php @@ -0,0 +1,27 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.usatoday.com/story/life/music/2017/02/13/things-you-should-know-happened-grammy-awards-2017/97833734/', + 'body' => array( + '//div[@itemprop="articleBody"]', + ), + 'strip' => array( + '//script', + '//h1', + '//iframe', + '//span[@class="mycapture-small-btn mycapture-btn-with-text mycapture-expandable-photo-btn-small js-mycapture-btn-small"]', + '//div[@class="close-wrap"]', + '//div[contains(@class,"ui-video-wrapper")]', + '//div[contains(@class,"media-mob")]', + '//div[contains(@class,"left-mob")]', + '//div[contains(@class,"nerdbox")]', + '//div[contains(@class,"oembed-asset")]', + '//*[contains(@class,"share")]', + '//div[contains(@class,"gallery-asset")]', + '//div[contains(@class,"oembed-asset")]', + '//div[@class="article-print-url"]' + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/version2.dk.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/version2.dk.php new file mode 100644 index 0000000..a6d49f2 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/version2.dk.php @@ -0,0 +1,12 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.version2.dk/artikel/surface-pro-2-fungerer-bedre-til-arbejde-end-fornoejelse-55195', + 'body' => array( + '//section[contains(@class, "teaser")]', + '//section[contains(@class, "body")]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/vgcats.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/vgcats.com.php new file mode 100644 index 0000000..b2830a3 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/vgcats.com.php @@ -0,0 +1,15 @@ + array( + '%/comics.*%' => array( + 'test_url' => 'http://www.vgcats.com/comics/?strip_id=358', + 'body' => array('//*[@align="center"]/img'), + 'strip' => array(), + ), + '%/super.*%' => array( + 'test_url' => 'http://www.vgcats.com/super/?strip_id=84', + 'body' => array('//*[@align="center"]/p/img'), + 'strip' => array(), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/vuxml.org.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/vuxml.org.php new file mode 100644 index 0000000..b9bef7a --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/vuxml.org.php @@ -0,0 +1,17 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.vuxml.org/freebsd/a5f160fa-deee-11e4-99f8-080027ef73ec.html', + 'body' => array( + '//body', + ), + 'strip' => array( + '//h1', + '//div[@class="blurb"]', + '//hr', + '//p[@class="copyright"]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/wausaudailyherald.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/wausaudailyherald.com.php new file mode 100644 index 0000000..58aceea --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/wausaudailyherald.com.php @@ -0,0 +1,27 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.wausaudailyherald.com/story/news/2017/04/01/hundreds-gather-remember-attorney-killed-shooting-spree/99826062/?from=global&sessionKey=&autologin=', + 'body' => array( + '//div[@itemprop="articleBody"]', + ), + 'strip' => array( + '//h1', + '//iframe', + '//span[@class="mycapture-small-btn mycapture-btn-with-text mycapture-expandable-photo-btn-small js-mycapture-btn-small"]', + '//div[@class="close-wrap"]', + '//div[contains(@class,"ui-video-wrapper")]', + '//div[contains(@class,"media-mob")]', + '//div[contains(@class,"left-mob")]', + '//div[contains(@class,"nerdbox")]', + '//p/span', + '//div[contains(@class,"oembed-asset")]', + '//*[contains(@class,"share")]', + '//div[contains(@class,"gallery-asset")]', + '//div[contains(@class,"oembed-asset")]', + '//div[@class="article-print-url"]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.bbc.co.uk.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.bbc.co.uk.php new file mode 100644 index 0000000..98fc368 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.bbc.co.uk.php @@ -0,0 +1,33 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.bbc.co.uk/news/world-middle-east-23911833', + 'body' => array( + '//div[@class="story-body__inner"] | //div[@class="article"]', + '//div[@class="indPost"]', + ), + 'strip' => array( + '//form', + '//div[@id="headline"]', + '//*[@class="warning"]', + '//span[@class="off-screen"]', + '//span[@class="story-image-copyright"]', + '//ul[@class="story-body__unordered-list"]', + '//div[@class="ad_wrapper"]', + '//div[@id="article-sidebar"]', + '//div[@class="data-table-outer"]', + '//*[@class="story-date"]', + '//*[@class="story-header"]', + '//figure[contains(@class,"has-caption")]', + '//*[@class="story-related"]', + '//*[contains(@class, "byline")]', + '//p[contains(@class, "media-message")]', + '//*[contains(@class, "story-feature")]', + '//*[@id="video-carousel-container"]', + '//*[@id="also-related-links"]', + '//*[contains(@class, "share") or contains(@class, "hidden") or contains(@class, "hyper")]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.bdgest.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.bdgest.com.php new file mode 100644 index 0000000..41ef68d --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.bdgest.com.php @@ -0,0 +1,15 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.bdgest.com/chronique-6027-BD-Adrastee-Tome-2.html', + 'body' => array( + '//*[contains(@class, "chronique")]', + ), + 'strip' => array( + '//*[contains(@class, "post-review")]', + '//*[contains(@class, "footer-review")]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.bgr.in.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.bgr.in.php new file mode 100644 index 0000000..63ca069 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.bgr.in.php @@ -0,0 +1,23 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.bgr.in/news/xiaomi-redmi-3-with-13-megapixel-camera-snapdragon-616-launched-price-specifications-and-features/', + 'body' => array( + '//div[@class="article-content"]', + ), + 'strip' => array( + '//*[@class="article-meta"]', + '//*[@class="contentAdsense300"]', + '//*[@class="iwpl-social-hide"]', + '//iframe[@class="iframeads"]', + '//*[@class="disqus_thread"]', + '//*[@class="outb-mobile OUTBRAIN"]', + '//*[@class="wdt_smart_alerts"]', + '//*[@class="footnote"]', + '//*[@id="gadget-widget"]', + '//header[@class="article-title entry-header"]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.businessweek.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.businessweek.com.php new file mode 100644 index 0000000..0acc44e --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.businessweek.com.php @@ -0,0 +1,15 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.businessweek.com/articles/2013-09-18/elon-musks-hyperloop-will-work-says-some-very-smart-software', + 'body' => array( + '//div[@id="lead_graphic"]', + '//div[@id="article_body"]', + ), + 'strip' => array( + '//*[contains(@class, "related_item")]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.cnn.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.cnn.com.php new file mode 100644 index 0000000..31d03ed --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.cnn.com.php @@ -0,0 +1,24 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.cnn.com/2013/08/31/world/meast/syria-civil-war/index.html?hpt=hp_t1', + 'body' => array( + '//div[@class="cnn_strycntntlft"]', + ), + 'strip' => array( + '//div[@class="cnn_stryshrwdgtbtm"]', + '//div[@class="cnn_strybtmcntnt"]', + '//div[@class="cnn_strylftcntnt"]', + '//div[contains(@class, "cnnGalleryContainer")]', + '//div[contains(@class, "cnn_strylftcexpbx")]', + '//div[contains(@class, "articleGalleryNavContainer")]', + '//div[contains(@class, "cnnArticleGalleryCaptionControl")]', + '//div[contains(@class, "cnnArticleGalleryNavPrevNextDisabled")]', + '//div[contains(@class, "cnnArticleGalleryNavPrevNext")]', + '//div[contains(@class, "cnn_html_media_title_new")]', + '//div[contains(@id, "disqus")]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.developpez.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.developpez.com.php new file mode 100644 index 0000000..1535e43 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.developpez.com.php @@ -0,0 +1,21 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.developpez.com/actu/81757/Mozilla-annonce-la-disponibilite-de-Firefox-36-qui-passe-au-HTTP-2-et-permet-la-synchronisation-de-son-ecran-d-accueil/', + 'body' => array( + '//*[@itemprop="articleBody"]', + ), + 'strip' => array( + '//form', + '//div[@class="content"]/img', + '//a[last()]/following-sibling::*', + '//*[contains(@class,"actuTitle")]', + '//*[contains(@class,"date")]', + '//*[contains(@class,"inlineimg")]', + '//*[@id="signaler"]', + '//*[@id="signalerFrame"]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.egscomics.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.egscomics.com.php new file mode 100644 index 0000000..263f075 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.egscomics.com.php @@ -0,0 +1,12 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.egscomics.com/index.php?id=1690', + 'title' => '/html/head/title', + 'body' => array( + '//img[@id="comic"]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.fakingnews.firstpost.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.fakingnews.firstpost.com.php new file mode 100644 index 0000000..c948c77 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.fakingnews.firstpost.com.php @@ -0,0 +1,17 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.fakingnews.firstpost.com/2016/01/engineering-student-creates-record-in-a-decade-becomes-the-first-to-completely-exhaust-ball-pen-refill/', + 'body' => array( + '//div[@class="entry"]', + ), + 'strip' => array( + '//*[@class="socialshare_bar"]', + '//*[@class="authorbox"]', + '//*[@class="cf5_rps"]', + '//*[@class="60563 fb-comments fb-social-plugin"]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.forbes.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.forbes.com.php new file mode 100644 index 0000000..fd16ed5 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.forbes.com.php @@ -0,0 +1,20 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.forbes.com/sites/andygreenberg/2013/09/05/follow-the-bitcoins-how-we-got-busted-buying-drugs-on-silk-roads-black-market/', + 'body' => array( + '//div[@id="leftRail"]/div[contains(@class, body)]', + ), + 'strip' => array( + '//aside', + '//div[contains(@class, "entity_block")]', + '//div[contains(@class, "vestpocket") and not contains(@class, "body")]', + '//div[contains(@style, "display")]', + '//div[contains(@id, "comment")]', + '//div[contains(@class, "widget")]', + '//div[contains(@class, "pagination")]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.franceculture.fr.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.franceculture.fr.php new file mode 100644 index 0000000..f7ec0d8 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.franceculture.fr.php @@ -0,0 +1,14 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.franceculture.fr/emission-culture-eco-la-finance-aime-toujours-la-france-2016-01-08', + 'body' => array( + '//div[@class="text-zone"]', + ), + 'strip' => array( + '//ul[@class="tags"]', + ), + ) + ) +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.futura-sciences.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.futura-sciences.com.php new file mode 100644 index 0000000..ea94a0f --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.futura-sciences.com.php @@ -0,0 +1,19 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.futura-sciences.com/magazines/espace/infos/actu/d/astronautique-curiosity-franchi-succes-dune-dingo-gap-52289/#xtor=RSS-8', + 'body' => array( + '//div[contains(@class, "content fiche-")]', + ), + 'strip' => array( + '//h1', + '//*[contains(@class, "content-date")]', + '//*[contains(@class, "diaporama")]', + '//*[contains(@class, "slider")]', + '//*[contains(@class, "cartouche")]', + '//*[contains(@class, "noprint")]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.geekculture.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.geekculture.com.php new file mode 100644 index 0000000..3d0b6c7 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.geekculture.com.php @@ -0,0 +1,13 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.geekculture.com/joyoftech/joyarchives/2180.html', + 'body' => array( + '//p[contains(@class,"Maintext")][2]/a/img[contains(@src,"joyimages")]', + ), + 'strip' => array(), + ), + ), +); + diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.howtogeek.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.howtogeek.com.php new file mode 100644 index 0000000..6879e76 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.howtogeek.com.php @@ -0,0 +1,14 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.howtogeek.com/235283/what-is-a-wireless-hard-drive-and-should-i-get-one/', + 'body' => array( + '//div[@class="thecontent"]', + ), + 'strip' => array( + '//*[@class="relatedside"]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.lepoint.fr.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.lepoint.fr.php new file mode 100644 index 0000000..dcb7e48 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.lepoint.fr.php @@ -0,0 +1,18 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.lepoint.fr/c-est-arrive-aujourd-hui/19-septembre-1783-pour-la-premiere-fois-un-mouton-un-canard-et-un-coq-s-envoient-en-l-air-devant-louis-xvi-18-09-2012-1507704_494.php', + 'body' => array( + '//article', + ), + 'strip' => array( + '//*[contains(@class, "info_article")]', + '//*[contains(@class, "fildariane_titre")]', + '//*[contains(@class, "entete2_article")]', + '//*[contains(@class, "signature_article")]', + '//*[contains(@id, "share")]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.lesnumeriques.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.lesnumeriques.com.php new file mode 100644 index 0000000..0137e20 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.lesnumeriques.com.php @@ -0,0 +1,25 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.lesnumeriques.com/blender/kitchenaid-diamond-5ksb1585-p27473/test.html', + 'body' => array( + '//*[@id="product-content"]', + '//*[@id="news-content"]', + '//*[@id="article-content"]', + ), + 'strip' => array( + '//form', + '//div[contains(@class, "price-v4"])', + '//div[contains(@class, "authors-and-date")]', + '//div[contains(@class, "mini-product")]', + '//div[@id="articles-related-authors"]', + '//div[@id="tags-socials"]', + '//div[@id="user-reviews"]', + '//div[@id="product-reviews"]', + '//div[@id="publication-breadcrumbs-and-date"]', + '//div[@id="publication-breadcrumbs-and-date"]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.mac4ever.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.mac4ever.com.php new file mode 100644 index 0000000..60bc1bd --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.mac4ever.com.php @@ -0,0 +1,13 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.mac4ever.com/actu/87392_video-quand-steve-jobs-et-bill-gates-jouaient-au-bachelor-avec-le-mac', + 'body' => array( + '//div[contains(@class, "news-news-content")]', + ), + 'strip' => array( + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.makeuseof.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.makeuseof.com.php new file mode 100644 index 0000000..a274564 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.makeuseof.com.php @@ -0,0 +1,18 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.makeuseof.com/tag/having-problems-with-audio-in-windows-10-heres-a-likely-fix/', + 'body' => array( + '//div[@class="entry"]', + ), + 'strip' => array( + '//*[@class="new_sharebar"]', + '//*[@class="author"]', + '//*[@class="wdt_grouvi"]', + '//*[@class="wdt_smart_alerts"]', + '//*[@class="modal fade grouvi"]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.monsieur-le-chien.fr.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.monsieur-le-chien.fr.php new file mode 100644 index 0000000..5f5e987 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.monsieur-le-chien.fr.php @@ -0,0 +1,11 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.monsieur-le-chien.fr/index.php?planche=672', + 'body' => array( + '//img[starts-with(@src, "i/planches/")]', + ), + ) + ) +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.npr.org.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.npr.org.php new file mode 100644 index 0000000..ecc0213 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.npr.org.php @@ -0,0 +1,28 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.npr.org/blogs/thesalt/2013/09/17/223345977/auto-brewery-syndrome-apparently-you-can-make-beer-in-your-gut', + 'body' => array( + '//article[contains(@class,"story")]', + ), + 'strip' => array( + '//div[@class="story-tools"]', + '//h3[@class="slug"]', + '//div[@class="storytitle"]', + '//div[@id="story-meta"]', + '//a[@id="mainContent"]', + '//div[@class="credit-caption"]', + '//div[@class="enlarge_html"]', + '//button', + '//div[contains(@id,"pullquote")]', + '//div[contains(@class,"internallink")]', + '//div[contains(@class,"video")]', + '//div[@class="simplenodate"]', + '//div[contains(@class,"share-")]', + '//div[@class="tags"]', + '//aside' + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.numerama.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.numerama.com.php new file mode 100644 index 0000000..fe4971c --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.numerama.com.php @@ -0,0 +1,15 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.numerama.com/sciences/125959-recherches-ladn-recompensees-nobel-de-chimie.html', + 'body' => array( + '//article', + ), + 'strip' => array( + '//footer', + '//section[@class="related-article"]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.oneindia.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.oneindia.com.php new file mode 100644 index 0000000..320c214 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.oneindia.com.php @@ -0,0 +1,14 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.oneindia.com/india/b-luru-govt-likely-remove-word-eunuch-from-sec-36-a-karnataka-police-act-1981173.html', + 'body' => array( + '//div[@class="ecom-ad-content"]', + ), + 'strip' => array( + '//*[@id="view_cmtns"]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.pseudo-sciences.org.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.pseudo-sciences.org.php new file mode 100644 index 0000000..9e467ed --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.pseudo-sciences.org.php @@ -0,0 +1,16 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.pseudo-sciences.org/spip.php?article2275', + 'body' => array( + '//div[@id="art_main"]', + ), + 'strip' => array( + '//div[@id="art_print"]', + '//div[@id="art_chapo"]', + '//img[@class="puce"]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.sciencemag.org.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.sciencemag.org.php new file mode 100644 index 0000000..ae7a93a --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.sciencemag.org.php @@ -0,0 +1,16 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.sciencemag.org/news/2016/01/could-bright-foamy-wak$', + 'body' => array( + '//div[@class="row--hero"]', + '//article[contains(@class,"primary")]', + ), + 'strip' => array( + '//header[@class="article__header"]', + '//footer[@class="article__foot"]', + ), + ), + ) +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.slate.fr.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.slate.fr.php new file mode 100644 index 0000000..8c8dc89 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.slate.fr.php @@ -0,0 +1,19 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.slate.fr/monde/77034/allemagne-2013-couacs-campagne', + 'body' => array( + '//div[@class="article_content"]', + ), + 'strip' => array( + '//*[@id="slate_associated_bn"]', + '//*[@id="ligatus-article"]', + '//*[@id="article_sidebar"]', + '//div[contains(@id, "reseaux")]', + '//*[contains(@class, "smart") or contains(@class, "article_tags") or contains(@class, "article_reactions")]', + '//*[contains(@class, "OUTBRAIN") or contains(@class, "related_item") or contains(@class, "share")]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.universfreebox.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.universfreebox.com.php new file mode 100644 index 0000000..0747d0f --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.universfreebox.com.php @@ -0,0 +1,15 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.universfreebox.com/article/24305/4G-Bouygues-Telecom-lance-une-vente-flash-sur-son-forfait-Sensation-3Go', + 'body' => array( + '//div[@id="corps_corps"]', + ), + 'strip' => array( + '//*[@id="formulaire"]', + '//*[@id="commentaire"]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.zeit.de.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.zeit.de.php new file mode 100644 index 0000000..316c265 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.zeit.de.php @@ -0,0 +1,41 @@ + array( + '%^/zeit-magazin.*%' => array( + 'test_url' => 'http://www.zeit.de/zeit-magazin/2015/15/pegida-kathrin-oertel-lutz-bachmann', + 'body' => array( + '//article[@class="article"]', + ), + 'strip' => array( + '//header/div/h1', + '//header/div/div[@class="article__head__subtitle"]', + '//header/div/div[@class="article__column__author"]', + '//header/div/div[@class="article__column__author"]', + '//header/div/span[@class="article__head__meta-wrap"]', + '//form', + '//style', + '//div[contains(@class, "ad-tile")]', + '//div[@class="iqd-mobile-adplace"]', + '//div[@id="iq-artikelanker"]', + '//div[@id="js-social-services"]', + '//section[@id="js-comments"]', + '//aside', + ), + ), + '%.*%' => array( + 'test_url' => 'http://www.zeit.de/politik/ausland/2015-04/thessaloniki-krise-griechenland-yannis-boutaris/', + 'body' => array( + '//div[@class="article-body"]', + ), + 'strip' => array( + '//*[@class="articleheader"]', + '//*[@class="excerpt"]', + '//div[contains(@class, "ad")]', + '//div[@itemprop="video"]', + '//*[@class="articlemeta"]', + '//*[@class="articlemeta-clear"]', + '//*[@class="zol_inarticletools"]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/xkcd.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/xkcd.com.php new file mode 100644 index 0000000..8495726 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/xkcd.com.php @@ -0,0 +1,8 @@ + array( + '%.*%' => array( + '%alt="(.+)" */>%' => '/>
                                                                      $1', + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/ymatuhin.ru.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/ymatuhin.ru.php new file mode 100644 index 0000000..9fd83f1 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/ymatuhin.ru.php @@ -0,0 +1,21 @@ + array( + '%.*%' => array( + 'test_url' => 'https://ymatuhin.ru/tools/git-default-editor/', + 'body' => array( + '//section', + ), + 'strip' => array( + "//script", + "//style", + "//h1", + "//time", + "//aside", + "/html/body/section/ul", + "//amp-iframe", + "/html/body/section/h4" + ), + ) + ) +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/zdnet.com.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/zdnet.com.php new file mode 100644 index 0000000..79b35dd --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Rules/zdnet.com.php @@ -0,0 +1,23 @@ + array( + '%.*%' => array( + 'test_url' => 'http://zdnet.com.feedsportal.com/c/35462/f/675637/s/4a33c93e/sc/11/l/0L0Szdnet0N0Carticle0Cchina0Eus0Eagree0Eon0Ecybercrime0Ecooperation0Eamid0Econtinued0Etension0C0Tftag0FRSSbaffb68/story01.htm', + 'body' => array( + '//p[@class="summary"]', + '//div[contains(@class,"storyBody")]', + ), + 'strip' => array( + '//*[contains(@class,"ad-")]', + '//p/span', + '//script', + '//p[@class="summary"]', + '//div[contains(@class,"relatedContent")]', + '//div[contains(@class,"loader")]', + '//p[@class="photoDetails"]', + '//div[@class="thumbnailSlider"]', + '//div[@class="shortcodeGalleryWrapper"]', + ), + ), + ), +); diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Scraper/CandidateParser.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Scraper/CandidateParser.php new file mode 100644 index 0000000..0f74b3d --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Scraper/CandidateParser.php @@ -0,0 +1,281 @@ +dom = XmlParser::getHtmlDocument(''.$html); + $this->xpath = new DOMXPath($this->dom); + } + + /** + * Get the relevant content with the list of potential attributes. + * + * @return string + */ + public function execute() + { + $content = $this->findContentWithCandidates(); + + if (strlen($content) < 200) { + $content = $this->findContentWithArticle(); + } + + if (strlen($content) < 50) { + $content = $this->findContentWithBody(); + } + + return $this->stripGarbage($content); + } + + /** + * Find content based on the list of tag candidates. + * + * @return string + */ + public function findContentWithCandidates() + { + foreach ($this->candidatesAttributes as $candidate) { + Logger::setMessage(get_called_class().': Try this candidate: "'.$candidate.'"'); + + $nodes = $this->xpath->query('//*[(contains(@class, "'.$candidate.'") or @id="'.$candidate.'") and not (contains(@class, "nav") or contains(@class, "page"))]'); + + if ($nodes !== false && $nodes->length > 0) { + Logger::setMessage(get_called_class().': Find candidate "'.$candidate.'"'); + + return $this->dom->saveXML($nodes->item(0)); + } + } + + return ''; + } + + /** + * Find
                                                                      tag. + * + * @return string + */ + public function findContentWithArticle() + { + $nodes = $this->xpath->query('//article'); + + if ($nodes !== false && $nodes->length > 0) { + Logger::setMessage(get_called_class().': Find
                                                                      tag'); + + return $this->dom->saveXML($nodes->item(0)); + } + + return ''; + } + + /** + * Find tag. + * + * @return string + */ + public function findContentWithBody() + { + $nodes = $this->xpath->query('//body'); + + if ($nodes !== false && $nodes->length > 0) { + Logger::setMessage(get_called_class().' Find '); + + return $this->dom->saveXML($nodes->item(0)); + } + + return ''; + } + + /** + * Strip useless tags. + * + * @param string $content + * @return string + */ + public function stripGarbage($content) + { + $dom = XmlParser::getDomDocument($content); + + if ($dom !== false) { + $xpath = new DOMXPath($dom); + + $this->stripTags($xpath); + $this->stripAttributes($dom, $xpath); + + $content = $dom->saveXML($dom->documentElement); + } + + return $content; + } + + /** + * Remove blacklisted tags. + * + * @param DOMXPath $xpath + */ + public function stripTags(DOMXPath $xpath) + { + foreach ($this->stripTags as $tag) { + $nodes = $xpath->query('//'.$tag); + + if ($nodes !== false && $nodes->length > 0) { + Logger::setMessage(get_called_class().': Strip tag: "'.$tag.'"'); + + foreach ($nodes as $node) { + $node->parentNode->removeChild($node); + } + } + } + } + + /** + * Remove blacklisted attributes. + * + * @param DomDocument $dom + * @param DOMXPath $xpath + */ + public function stripAttributes(DomDocument $dom, DOMXPath $xpath) + { + foreach ($this->stripAttributes as $attribute) { + $nodes = $xpath->query('//*[contains(@class, "'.$attribute.'") or contains(@id, "'.$attribute.'")]'); + + if ($nodes !== false && $nodes->length > 0) { + Logger::setMessage(get_called_class().': Strip attribute: "'.$attribute.'"'); + + foreach ($nodes as $node) { + if ($this->shouldRemove($dom, $node)) { + $node->parentNode->removeChild($node); + } + } + } + } + } + + /** + * Find link for next page of the article. + * + * @return string + */ + public function findNextLink() + { + return null; + } + + /** + * Return false if the node should not be removed. + * + * @param DomDocument $dom + * @param \DomNode $node + * @return bool + */ + public function shouldRemove(DomDocument $dom, $node) + { + $document_length = strlen($dom->textContent); + $node_length = strlen($node->textContent); + + if ($document_length === 0) { + return true; + } + + $ratio = $node_length * 100 / $document_length; + + if ($ratio >= 90) { + Logger::setMessage(get_called_class().': Should not remove this node ('.$node->nodeName.') ratio: '.$ratio.'%'); + + return false; + } + + return true; + } +} diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Scraper/ParserInterface.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Scraper/ParserInterface.php new file mode 100644 index 0000000..3ded4b1 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Scraper/ParserInterface.php @@ -0,0 +1,20 @@ +getRulesFileList($hostname); + + foreach ($this->getRulesFolders() as $folder) { + $rule = $this->loadRuleFile($folder, $files); + + if (!empty($rule)) { + return $rule; + } + } + } + + return array(); + } + + /** + * Get the list of possible rules file names for a given hostname. + * + * @param string $hostname Hostname + * @return array + */ + public function getRulesFileList($hostname) + { + $files = array($hostname); // subdomain.domain.tld + $parts = explode('.', $hostname); + $len = count($parts); + + if ($len > 2) { + $subdomain = array_shift($parts); + $files[] = implode('.', $parts); // domain.tld + $files[] = '.'.implode('.', $parts); // .domain.tld + $files[] = $subdomain; // subdomain + } elseif ($len === 2) { + $files[] = '.'.implode('.', $parts); // .domain.tld + $files[] = $parts[0]; // domain + } + + return $files; + } + + /** + * Load a rule file from the defined folder. + * + * @param string $folder Rule directory + * @param array $files List of possible file names + * @return array + */ + public function loadRuleFile($folder, array $files) + { + foreach ($files as $file) { + $filename = $folder.'/'.$file.'.php'; + if (file_exists($filename)) { + Logger::setMessage(get_called_class().' Load rule: '.$file); + + return include $filename; + } + } + + return array(); + } + + /** + * Get the list of folders that contains rules. + * + * @return array + */ + public function getRulesFolders() + { + $folders = array(); + + if ($this->config !== null && $this->config->getGrabberRulesFolder() !== null) { + $folders[] = $this->config->getGrabberRulesFolder(); + } + + $folders[] = __DIR__ . '/../Rules'; + + return $folders; + } +} diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Scraper/RuleParser.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Scraper/RuleParser.php new file mode 100644 index 0000000..9beb59c --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Scraper/RuleParser.php @@ -0,0 +1,102 @@ +rules = $rules; + $this->dom = XmlParser::getHtmlDocument(''.$html); + $this->xpath = new DOMXPath($this->dom); + } + + /** + * Get the relevant content with predefined rules. + * + * @return string + */ + public function execute() + { + $this->stripTags(); + + return $this->findContent(); + } + + /** + * Remove HTML tags. + */ + public function stripTags() + { + if (isset($this->rules['strip']) && is_array($this->rules['strip'])) { + foreach ($this->rules['strip'] as $pattern) { + $nodes = $this->xpath->query($pattern); + + if ($nodes !== false && $nodes->length > 0) { + foreach ($nodes as $node) { + $node->parentNode->removeChild($node); + } + } + } + } + } + + /** + * Fetch content based on Xpath rules. + */ + public function findContent() + { + $content = ''; + if (isset($this->rules['body']) && is_array($this->rules['body'])) { + foreach ($this->rules['body'] as $pattern) { + $nodes = $this->xpath->query($pattern); + + if ($nodes !== false && $nodes->length > 0) { + foreach ($nodes as $node) { + $content .= $this->dom->saveXML($node); + } + } + } + } + + return $content; + } + + /** + * Fetch next link based on Xpath rules. + * + * @return string + */ + public function findNextLink() + { + if (isset($this->rules['next_page']) && is_array($this->rules['next_page'])) { + foreach ($this->rules['next_page'] as $pattern) { + $nodes = $this->xpath->query($pattern); + if ($nodes !== false && $nodes->length > 0) { + foreach ($nodes as $node) { + return $node->getAttribute('href'); + } + } + } + } + return null; + } +} diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Scraper/Scraper.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Scraper/Scraper.php new file mode 100644 index 0000000..29383b2 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Scraper/Scraper.php @@ -0,0 +1,282 @@ +enableCandidateParser = false; + return $this; + } + + /** + * Get encoding. + * + * @return string + */ + public function getEncoding() + { + return $this->encoding; + } + + /** + * Set encoding. + * + * @param string $encoding + * + * @return Scraper + */ + public function setEncoding($encoding) + { + $this->encoding = $encoding; + + return $this; + } + + /** + * Get URL to download. + * + * @return string + */ + public function getUrl() + { + return $this->url; + } + + /** + * Set URL to download. + * + * @param string $url URL + * + * @return Scraper + */ + public function setUrl($url) + { + $this->url = $url; + + return $this; + } + + /** + * Return true if the scraper found relevant content. + * + * @return bool + */ + public function hasRelevantContent() + { + return !empty($this->content); + } + + /** + * Get relevant content. + * + * @return string + */ + public function getRelevantContent() + { + return $this->content; + } + + /** + * Get raw content (unfiltered). + * + * @return string + */ + public function getRawContent() + { + return $this->html; + } + + /** + * Set raw content (unfiltered). + * + * @param string $html + * + * @return Scraper + */ + public function setRawContent($html) + { + $this->html = $html; + + return $this; + } + + /** + * Get filtered relevant content. + * + * @return string + */ + public function getFilteredContent() + { + $filter = Filter::html($this->content, $this->url); + $filter->setConfig($this->config); + + return $filter->execute(); + } + + /** + * Download the HTML content. + * + * @return bool + */ + public function download() + { + if (!empty($this->url)) { + + // Clear everything + $this->html = ''; + $this->content = ''; + $this->encoding = ''; + + try { + $client = Client::getInstance(); + $client->setConfig($this->config); + $client->setTimeout($this->config->getGrabberTimeout()); + $client->setUserAgent($this->config->getGrabberUserAgent()); + $client->execute($this->url); + + $this->url = $client->getUrl(); + $this->html = $client->getContent(); + $this->encoding = $client->getEncoding(); + + return true; + } catch (ClientException $e) { + Logger::setMessage(get_called_class().': '.$e->getMessage()); + } + } + + return false; + } + + /** + * Execute the scraper. + * + * @param string $pageContent + * @param int $recursionDepth + */ + public function execute($pageContent = '', $recursionDepth = 0) + { + $this->html = ''; + $this->encoding = ''; + $this->content = ''; + $this->download(); + $this->prepareHtml(); + + $parser = $this->getParser(); + + if ($parser !== null) { + $maxRecursions = $this->config->getMaxRecursions(); + if(!isset($maxRecursions)){ + $maxRecursions = 25; + } + $pageContent .= $parser->execute(); + // check if there is a link to next page and recursively get content (max 25 pages) + if((($nextLink = $parser->findNextLink()) !== null) && $recursionDepth < $maxRecursions){ + $nextLink = Url::resolve($nextLink,$this->url); + $this->setUrl($nextLink); + $this->execute($pageContent,$recursionDepth+1); + } + else{ + $this->content = $pageContent; + } + Logger::setMessage(get_called_class().': Content length: '.strlen($this->content).' bytes'); + } + } + + /** + * Get the parser. + * + * @return ParserInterface + */ + public function getParser() + { + $ruleLoader = new RuleLoader($this->config); + $rules = $ruleLoader->getRules($this->url); + + if (!empty($rules['grabber'])) { + Logger::setMessage(get_called_class().': Parse content with rules'); + + foreach ($rules['grabber'] as $pattern => $rule) { + $url = new Url($this->url); + $sub_url = $url->getFullPath(); + + if (preg_match($pattern, $sub_url)) { + Logger::setMessage(get_called_class().': Matched url '.$sub_url); + return new RuleParser($this->html, $rule); + } + } + } elseif ($this->enableCandidateParser) { + Logger::setMessage(get_called_class().': Parse content with candidates'); + } + + return new CandidateParser($this->html); + } + + /** + * Normalize encoding and strip head tag. + */ + public function prepareHtml() + { + $html_encoding = XmlParser::getEncodingFromMetaTag($this->html); + + $this->html = Encoding::convert($this->html, $html_encoding ?: $this->encoding); + $this->html = Filter::stripHeadTags($this->html); + + Logger::setMessage(get_called_class().': HTTP Encoding "'.$this->encoding.'" ; HTML Encoding "'.$html_encoding.'"'); + } +} diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Serialization/Subscription.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Serialization/Subscription.php new file mode 100644 index 0000000..12eccfd --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Serialization/Subscription.php @@ -0,0 +1,175 @@ +title = $title; + return $this; + } + + /** + * Get title + * + * @access public + * @return string + */ + public function getTitle() + { + return $this->title; + } + + /** + * Set feed URL + * + * @access public + * @param string $feedUrl + * @return Subscription + */ + public function setFeedUrl($feedUrl) + { + $this->feedUrl = $feedUrl; + return $this; + } + + /** + * Get feed URL + * + * @access public + * @return string + */ + public function getFeedUrl() + { + return $this->feedUrl; + } + + /** + * Set site URL + * + * @access public + * @param string $siteUrl + * @return Subscription + */ + public function setSiteUrl($siteUrl) + { + $this->siteUrl = $siteUrl; + return $this; + } + + /** + * Get site URL + * + * @access public + * @return string + */ + public function getSiteUrl() + { + return $this->siteUrl; + } + + /** + * Set category + * + * @access public + * @param string $category + * @return Subscription + */ + public function setCategory($category) + { + $this->category = $category; + return $this; + } + + /** + * Get category + * + * @access public + * @return string + */ + public function getCategory() + { + return $this->category; + } + + /** + * Set description + * + * @access public + * @param string $description + * @return Subscription + */ + public function setDescription($description) + { + $this->description = $description; + return $this; + } + + /** + * Get description + * + * @access public + * @return string + */ + public function getDescription() + { + return $this->description; + } + + /** + * Set type + * + * @access public + * @param string $type + * @return Subscription + */ + public function setType($type) + { + $this->type = $type; + return $this; + } + + /** + * Get type + * + * @access public + * @return string + */ + public function getType() + { + return $this->type; + } +} diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Serialization/SubscriptionList.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Serialization/SubscriptionList.php new file mode 100644 index 0000000..b173f89 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Serialization/SubscriptionList.php @@ -0,0 +1,75 @@ +title = $title; + return $this; + } + + /** + * Get title + * + * @access public + * @return string + */ + public function getTitle() + { + return $this->title; + } + + /** + * Add subscription + * + * @access public + * @param Subscription $subscription + * @return SubscriptionList + */ + public function addSubscription(Subscription $subscription) + { + $this->subscriptions[] = $subscription; + return $this; + } +} diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Serialization/SubscriptionListBuilder.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Serialization/SubscriptionListBuilder.php new file mode 100644 index 0000000..838e4cb --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Serialization/SubscriptionListBuilder.php @@ -0,0 +1,204 @@ +subscriptionList = $subscriptionList; + } + + /** + * Get object instance + * + * @static + * @access public + * @param SubscriptionList $subscriptionList + * @return SubscriptionListBuilder + */ + public static function create(SubscriptionList $subscriptionList) + { + return new static($subscriptionList); + } + + /** + * Build OPML feed + * + * @access public + * @param string $filename + * @return string + */ + public function build($filename = '') + { + $this->document = new DomDocument('1.0', 'UTF-8'); + $this->document->formatOutput = true; + + $opmlElement = $this->document->createElement('opml'); + $opmlElement->setAttribute('version', '1.0'); + + $headElement = $this->document->createElement('head'); + + if ($this->subscriptionList->getTitle() !== '') { + $titleElement = $this->document->createElement('title'); + $titleElement->appendChild($this->document->createTextNode($this->subscriptionList->getTitle())); + $headElement->appendChild($titleElement); + } + + $opmlElement->appendChild($headElement); + $opmlElement->appendChild($this->buildBody()); + $this->document->appendChild($opmlElement); + + if ($filename !== '') { + $this->document->save($filename); + return ''; + } + + return $this->document->saveXML(); + } + + /** + * Return true if the list has categories + * + * @access public + * @return bool + */ + public function hasCategories() + { + foreach ($this->subscriptionList->subscriptions as $subscription) { + if ($subscription->getCategory() !== '') { + return true; + } + } + + return false; + } + + /** + * Build OPML body + * + * @access protected + * @return DOMElement + */ + protected function buildBody() + { + $bodyElement = $this->document->createElement('body'); + + if ($this->hasCategories()) { + $this->buildCategories($bodyElement); + return $bodyElement; + } + + foreach ($this->subscriptionList->subscriptions as $subscription) { + $bodyElement->appendChild($this->buildSubscription($subscription)); + } + + return $bodyElement; + } + + /** + * Build categories section + * + * @access protected + * @param DOMElement $bodyElement + */ + protected function buildCategories(DOMElement $bodyElement) + { + $categories = $this->groupByCategories(); + + foreach ($categories as $category => $subscriptions) { + $bodyElement->appendChild($this->buildCategory($category, $subscriptions)); + } + } + + /** + * Build category tag + * + * @access protected + * @param string $category + * @param array $subscriptions + * @return DOMElement + */ + protected function buildCategory($category, array $subscriptions) + { + $outlineElement = $this->document->createElement('outline'); + $outlineElement->setAttribute('text', $category); + + foreach ($subscriptions as $subscription) { + $outlineElement->appendChild($this->buildSubscription($subscription)); + } + + return $outlineElement; + } + + /** + * Build subscription entry + * + * @access public + * @param Subscription $subscription + * @return DOMElement + */ + protected function buildSubscription(Subscription $subscription) + { + $outlineElement = $this->document->createElement('outline'); + $outlineElement->setAttribute('type', $subscription->getType() ?: 'rss'); + $outlineElement->setAttribute('text', $subscription->getTitle() ?: $subscription->getFeedUrl()); + $outlineElement->setAttribute('xmlUrl', $subscription->getFeedUrl()); + + if ($subscription->getTitle() !== '') { + $outlineElement->setAttribute('title', $subscription->getTitle()); + } + + if ($subscription->getDescription() !== '') { + $outlineElement->setAttribute('description', $subscription->getDescription()); + } + + if ($subscription->getSiteUrl() !== '') { + $outlineElement->setAttribute('htmlUrl', $subscription->getSiteUrl()); + } + + return $outlineElement; + } + + /** + * Group subscriptions by category + * + * @access private + * @return array + */ + private function groupByCategories() + { + $categories = array(); + + foreach ($this->subscriptionList->subscriptions as $subscription) { + $categories[$subscription->getCategory()][] = $subscription; + } + + return $categories; + } +} diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Serialization/SubscriptionListParser.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Serialization/SubscriptionListParser.php new file mode 100644 index 0000000..9085588 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Serialization/SubscriptionListParser.php @@ -0,0 +1,100 @@ +subscriptionList = new SubscriptionList(); + $this->data = trim($data); + } + + /** + * Get object instance + * + * @static + * @access public + * @param string $data + * @return SubscriptionListParser + */ + public static function create($data) + { + return new static($data); + } + + /** + * Parse a subscription list entry + * + * @access public + * @throws MalformedXmlException + * @return SubscriptionList + */ + public function parse() + { + $xml = XmlParser::getSimpleXml($this->data); + + if (! $xml || !isset($xml->head) || !isset($xml->body)) { + throw new MalformedXmlException('Unable to parse OPML file: invalid XML'); + } + + $this->parseTitle($xml->head); + $this->parseEntries($xml->body); + + return $this->subscriptionList; + } + + /** + * Parse title + * + * @access protected + * @param SimpleXMLElement $xml + */ + protected function parseTitle(SimpleXMLElement $xml) + { + $this->subscriptionList->setTitle((string) $xml->title); + } + + /** + * Parse entries + * + * @access protected + * @param SimpleXMLElement $body + */ + private function parseEntries(SimpleXMLElement $body) + { + foreach ($body->outline as $outlineElement) { + if (isset($outlineElement->outline)) { + $this->parseEntries($outlineElement); + } else { + $this->subscriptionList->subscriptions[] = SubscriptionParser::create($body, $outlineElement)->parse(); + } + } + } +} diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Serialization/SubscriptionParser.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Serialization/SubscriptionParser.php new file mode 100644 index 0000000..caff07c --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Serialization/SubscriptionParser.php @@ -0,0 +1,142 @@ +parentElement = $parentElement; + $this->outlineElement = $outlineElement; + $this->subscription = new Subscription(); + } + + /** + * Get object instance + * + * @static + * @access public + * @param SimpleXMLElement $parentElement + * @param SimpleXMLElement $outlineElement + * @return SubscriptionParser + */ + public static function create(SimpleXMLElement $parentElement, SimpleXMLElement $outlineElement) + { + return new static($parentElement, $outlineElement); + } + + /** + * Parse subscription entry + * + * @access public + * @return Subscription + */ + public function parse() + { + $this->subscription->setCategory($this->findCategory()); + $this->subscription->setTitle($this->findTitle()); + $this->subscription->setFeedUrl($this->findFeedUrl()); + $this->subscription->setSiteUrl($this->findSiteUrl()); + $this->subscription->setType($this->findType()); + $this->subscription->setDescription($this->findDescription()); + + return $this->subscription; + } + + /** + * Find category. + * + * @access protected + * @return string + */ + protected function findCategory() + { + return isset($this->parentElement['text']) ? (string) $this->parentElement['text'] : ''; + } + + /** + * Find title. + * + * @access protected + * @return string + */ + protected function findTitle() + { + return isset($this->outlineElement['title']) ? (string) $this->outlineElement['title'] : (string) $this->outlineElement['text']; + } + + /** + * Find feed url. + * + * @access protected + * @return string + */ + protected function findFeedUrl() + { + return (string) $this->outlineElement['xmlUrl']; + } + + /** + * Find site url. + * + * @access protected + * @return string + */ + protected function findSiteUrl() + { + return isset($this->outlineElement['htmlUrl']) ? (string) $this->outlineElement['htmlUrl'] : $this->findFeedUrl(); + } + + /** + * Find type. + * + * @access protected + * @return string + */ + protected function findType() + { + return isset($this->outlineElement['version']) ? (string) $this->outlineElement['version'] : + isset($this->outlineElement['type']) ? (string) $this->outlineElement['type'] : 'rss'; + } + + /** + * Find description. + * + * @access protected + * @return string + */ + protected function findDescription() + { + return isset($this->outlineElement['description']) ? (string) $this->outlineElement['description'] : $this->findTitle(); + } +} diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Syndication/AtomFeedBuilder.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Syndication/AtomFeedBuilder.php new file mode 100644 index 0000000..34f3780 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Syndication/AtomFeedBuilder.php @@ -0,0 +1,65 @@ +helper = new AtomHelper($this->getDocument()); + + $this->feedElement = $this->getDocument()->createElement('feed'); + $this->feedElement->setAttributeNodeNS(new DomAttr('xmlns', 'http://www.w3.org/2005/Atom')); + + $generator = $this->getDocument()->createElement('generator', 'PicoFeed'); + $generator->setAttribute('uri', 'https://github.com/miniflux/picoFeed'); + $this->feedElement->appendChild($generator); + + $this->helper + ->buildTitle($this->feedElement, $this->feedTitle) + ->buildId($this->feedElement, $this->feedUrl) + ->buildDate($this->feedElement, $this->feedDate) + ->buildLink($this->feedElement, $this->siteUrl) + ->buildLink($this->feedElement, $this->feedUrl, 'self', 'application/atom+xml') + ->buildAuthor($this->feedElement, $this->authorName, $this->authorEmail, $this->authorUrl) + ; + + foreach ($this->items as $item) { + $this->feedElement->appendChild($item->build()); + } + + $this->getDocument()->appendChild($this->feedElement); + + if ($filename !== '') { + $this->getDocument()->save($filename); + } + + return $this->getDocument()->saveXML(); + } +} diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Syndication/AtomHelper.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Syndication/AtomHelper.php new file mode 100644 index 0000000..def6b0b --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Syndication/AtomHelper.php @@ -0,0 +1,139 @@ +document = $document; + } + + /** + * Build node + * + * @access public + * @param DOMElement $element + * @param string $tag + * @param string $value + * @return AtomHelper + */ + public function buildNode(DOMElement $element, $tag, $value) + { + $node = $this->document->createElement($tag); + $node->appendChild($this->document->createTextNode($value)); + $element->appendChild($node); + return $this; + } + + /** + * Build title + * + * @access public + * @param DOMElement $element + * @param string $title + * @return AtomHelper + */ + public function buildTitle(DOMElement $element, $title) + { + return $this->buildNode($element, 'title', $title); + } + + /** + * Build id + * + * @access public + * @param DOMElement $element + * @param string $id + * @return AtomHelper + */ + public function buildId(DOMElement $element, $id) + { + return $this->buildNode($element, 'id', $id); + } + + /** + * Build date element + * + * @access public + * @param DOMElement $element + * @param DateTime $date + * @param string $type + * @return AtomHelper + */ + public function buildDate(DOMElement $element, DateTime $date, $type = 'updated') + { + return $this->buildNode($element, $type, $date->format(DateTime::ATOM)); + } + + /** + * Build link element + * + * @access public + * @param DOMElement $element + * @param string $url + * @param string $rel + * @param string $type + * @return AtomHelper + */ + public function buildLink(DOMElement $element, $url, $rel = 'alternate', $type = 'text/html') + { + $node = $this->document->createElement('link'); + $node->setAttribute('rel', $rel); + $node->setAttribute('type', $type); + $node->setAttribute('href', $url); + $element->appendChild($node); + + return $this; + } + + /** + * Build author element + * + * @access public + * @param DOMElement $element + * @param string $authorName + * @param string $authorEmail + * @param string $authorUrl + * @return AtomHelper + */ + public function buildAuthor(DOMElement $element, $authorName, $authorEmail, $authorUrl) + { + if (!empty($authorName)) { + $author = $this->document->createElement('author'); + $this->buildNode($author, 'name', $authorName); + + if (!empty($authorEmail)) { + $this->buildNode($author, 'email', $authorEmail); + } + + if (!empty($authorUrl)) { + $this->buildNode($author, 'uri', $authorUrl); + } + + $element->appendChild($author); + } + + return $this; + } +} diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Syndication/AtomItemBuilder.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Syndication/AtomItemBuilder.php new file mode 100644 index 0000000..dfdfe68 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Syndication/AtomItemBuilder.php @@ -0,0 +1,63 @@ +itemElement = $this->feedBuilder->getDocument()->createElement('entry'); + $this->helper = new AtomHelper($this->feedBuilder->getDocument()); + + if (!empty($this->itemId)) { + $this->helper->buildId($this->itemElement, $this->itemId); + } else { + $this->helper->buildId($this->itemElement, $this->itemUrl); + } + + $this->helper + ->buildTitle($this->itemElement, $this->itemTitle) + ->buildLink($this->itemElement, $this->itemUrl) + ->buildDate($this->itemElement, $this->itemUpdatedDate, 'updated') + ->buildDate($this->itemElement, $this->itemPublishedDate, 'published') + ->buildAuthor($this->itemElement, $this->authorName, $this->authorEmail, $this->authorUrl) + ; + + if (!empty($this->itemSummary)) { + $this->helper->buildNode($this->itemElement, 'summary', $this->itemSummary); + } + + if (!empty($this->itemContent)) { + $node = $this->feedBuilder->getDocument()->createElement('content'); + $node->setAttribute('type', 'html'); + $node->appendChild($this->feedBuilder->getDocument()->createCDATASection($this->itemContent)); + $this->itemElement->appendChild($node); + } + + return $this->itemElement; + } +} diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Syndication/FeedBuilder.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Syndication/FeedBuilder.php new file mode 100644 index 0000000..cf9d024 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Syndication/FeedBuilder.php @@ -0,0 +1,185 @@ +document = new DomDocument('1.0', 'UTF-8'); + $this->document->formatOutput = true; + } + + /** + * Get new object instance + * + * @access public + * @return static + */ + public static function create() + { + return new static(); + } + + /** + * Add feed title + * + * @access public + * @param string $title + * @return $this + */ + public function withTitle($title) + { + $this->feedTitle = $title; + return $this; + } + + /** + * Add feed url + * + * @access public + * @param string $url + * @return $this + */ + public function withFeedUrl($url) + { + $this->feedUrl = $url; + return $this; + } + + /** + * Add website url + * + * @access public + * @param string $url + * @return $this + */ + public function withSiteUrl($url) + { + $this->siteUrl = $url; + return $this; + } + + /** + * Add feed date + * + * @access public + * @param DateTime $date + * @return $this + */ + public function withDate(DateTime $date) + { + $this->feedDate = $date; + return $this; + } + + /** + * Add feed author + * + * @access public + * @param string $name + * @param string $email + * @param string $url + * @return $this + */ + public function withAuthor($name, $email = '', $url ='') + { + $this->authorName = $name; + $this->authorEmail = $email; + $this->authorUrl = $url; + return $this; + } + + /** + * Add feed item + * + * @access public + * @param ItemBuilder $item + * @return $this + */ + public function withItem(ItemBuilder $item) + { + $this->items[] = $item; + return $this; + } + + /** + * Get DOM document + * + * @access public + * @return DOMDocument + */ + public function getDocument() + { + return $this->document; + } + + /** + * Build feed + * + * @abstract + * @access public + * @param string $filename + * @return string + */ + abstract public function build($filename = ''); +} diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Syndication/ItemBuilder.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Syndication/ItemBuilder.php new file mode 100644 index 0000000..86985bc --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Syndication/ItemBuilder.php @@ -0,0 +1,209 @@ +feedBuilder = $feedBuilder; + } + + /** + * Get new object instance + * + * @access public + * @param FeedBuilder $feedBuilder + * @return static + */ + public static function create(FeedBuilder $feedBuilder) + { + return new static($feedBuilder); + } + + /** + * Add item title + * + * @access public + * @param string $title + * @return $this + */ + public function withTitle($title) + { + $this->itemTitle = $title; + return $this; + } + + /** + * Add item id + * + * @access public + * @param string $id + * @return $this + */ + public function withId($id) + { + $this->itemId = $id; + return $this; + } + + /** + * Add item url + * + * @access public + * @param string $url + * @return $this + */ + public function withUrl($url) + { + $this->itemUrl = $url; + return $this; + } + + /** + * Add item summary + * + * @access public + * @param string $summary + * @return $this + */ + public function withSummary($summary) + { + $this->itemSummary = $summary; + return $this; + } + + /** + * Add item content + * + * @access public + * @param string $content + * @return $this + */ + public function withContent($content) + { + $this->itemContent = $content; + return $this; + } + + /** + * Add item updated date + * + * @access public + * @param DateTime $date + * @return $this + */ + public function withUpdatedDate(DateTime $date) + { + $this->itemUpdatedDate = $date; + return $this; + } + + /** + * Add item published date + * + * @access public + * @param DateTime $date + * @return $this + */ + public function withPublishedDate(DateTime $date) + { + $this->itemPublishedDate = $date; + return $this; + } + + /** + * Add item author + * + * @access public + * @param string $name + * @param string $email + * @param string $url + * @return $this + */ + public function withAuthor($name, $email = '', $url ='') + { + $this->authorName = $name; + $this->authorEmail = $email; + $this->authorUrl = $url; + return $this; + } + + /** + * Build item + * + * @abstract + * @access public + * @return DOMElement + */ + abstract public function build(); +} diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Syndication/Rss20FeedBuilder.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Syndication/Rss20FeedBuilder.php new file mode 100644 index 0000000..bc3f513 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Syndication/Rss20FeedBuilder.php @@ -0,0 +1,76 @@ +helper = new Rss20Helper($this->getDocument()); + + $this->rssElement = $this->getDocument()->createElement('rss'); + $this->rssElement->setAttribute('version', '2.0'); + $this->rssElement->setAttributeNodeNS(new DomAttr('xmlns:content', 'http://purl.org/rss/1.0/modules/content/')); + $this->rssElement->setAttributeNodeNS(new DomAttr('xmlns:atom', 'http://www.w3.org/2005/Atom')); + + $this->channelElement = $this->getDocument()->createElement('channel'); + $this->helper + ->buildNode($this->channelElement, 'generator', 'PicoFeed (https://github.com/miniflux/picoFeed)') + ->buildTitle($this->channelElement, $this->feedTitle) + ->buildNode($this->channelElement, 'description', $this->feedTitle) + ->buildDate($this->channelElement, $this->feedDate) + ->buildAuthor($this->channelElement, 'webMaster', $this->authorName, $this->authorEmail) + ->buildLink($this->channelElement, $this->siteUrl) + ; + + $link = $this->getDocument()->createElement('atom:link'); + $link->setAttribute('href', $this->feedUrl); + $link->setAttribute('rel', 'self'); + $link->setAttribute('type', 'application/rss+xml'); + $this->channelElement->appendChild($link); + + foreach ($this->items as $item) { + $this->channelElement->appendChild($item->build()); + } + + $this->rssElement->appendChild($this->channelElement); + $this->getDocument()->appendChild($this->rssElement); + + if ($filename !== '') { + $this->getDocument()->save($filename); + } + + return $this->getDocument()->saveXML(); + } +} diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Syndication/Rss20Helper.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Syndication/Rss20Helper.php new file mode 100644 index 0000000..72a19e5 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Syndication/Rss20Helper.php @@ -0,0 +1,115 @@ +document = $document; + } + + /** + * Build node + * + * @access public + * @param DOMElement $element + * @param string $tag + * @param string $value + * @return $this + */ + public function buildNode(DOMElement $element, $tag, $value) + { + $node = $this->document->createElement($tag); + $node->appendChild($this->document->createTextNode($value)); + $element->appendChild($node); + return $this; + } + + /** + * Build title + * + * @access public + * @param DOMElement $element + * @param string $title + * @return $this + */ + public function buildTitle(DOMElement $element, $title) + { + return $this->buildNode($element, 'title', $title); + } + + /** + * Build date element + * + * @access public + * @param DOMElement $element + * @param DateTime $date + * @param string $type + * @return $this + */ + public function buildDate(DOMElement $element, DateTime $date, $type = 'pubDate') + { + return $this->buildNode($element, $type, $date->format(DateTime::RSS)); + } + + /** + * Build link element + * + * @access public + * @param DOMElement $element + * @param string $url + * @return $this + */ + public function buildLink(DOMElement $element, $url) + { + return $this->buildNode($element, 'link', $url); + } + + /** + * Build author element + * + * @access public + * @param DOMElement $element + * @param string $tag + * @param string $authorName + * @param string $authorEmail + * @return $this + */ + public function buildAuthor(DOMElement $element, $tag, $authorName, $authorEmail) + { + if (!empty($authorName)) { + $value = ''; + + if (!empty($authorEmail)) { + $value .= $authorEmail.' ('.$authorName.')'; + } else { + $value = $authorName; + } + + $this->buildNode($element, $tag, $value); + } + + return $this; + } +} diff --git a/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Syndication/Rss20ItemBuilder.php b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Syndication/Rss20ItemBuilder.php new file mode 100644 index 0000000..125dc6a --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/lib/PicoFeed/Syndication/Rss20ItemBuilder.php @@ -0,0 +1,67 @@ +itemElement = $this->feedBuilder->getDocument()->createElement('item'); + $this->helper = new Rss20Helper($this->feedBuilder->getDocument()); + + if (!empty($this->itemId)) { + $guid = $this->feedBuilder->getDocument()->createElement('guid'); + $guid->setAttribute('isPermaLink', 'false'); + $guid->appendChild($this->feedBuilder->getDocument()->createTextNode($this->itemId)); + $this->itemElement->appendChild($guid); + } else { + $guid = $this->feedBuilder->getDocument()->createElement('guid'); + $guid->setAttribute('isPermaLink', 'true'); + $guid->appendChild($this->feedBuilder->getDocument()->createTextNode($this->itemUrl)); + $this->itemElement->appendChild($guid); + } + + $this->helper + ->buildTitle($this->itemElement, $this->itemTitle) + ->buildLink($this->itemElement, $this->itemUrl) + ->buildDate($this->itemElement, $this->itemPublishedDate) + ->buildAuthor($this->itemElement, 'author', $this->authorName, $this->authorEmail) + ; + + if (!empty($this->itemSummary)) { + $this->helper->buildNode($this->itemElement, 'description', $this->itemSummary); + } + + if (!empty($this->itemContent)) { + $node = $this->feedBuilder->getDocument()->createElement('content:encoded'); + $node->appendChild($this->feedBuilder->getDocument()->createCDATASection($this->itemContent)); + $this->itemElement->appendChild($node); + } + + return $this->itemElement; + } +} diff --git a/user/plugins/admin/vendor/fguillot/picofeed/picofeed b/user/plugins/admin/vendor/fguillot/picofeed/picofeed new file mode 100644 index 0000000..8f35737 --- /dev/null +++ b/user/plugins/admin/vendor/fguillot/picofeed/picofeed @@ -0,0 +1,135 @@ +#!/usr/bin/env php +discover($url); + + $parser = $reader->getParser( + $resource->getUrl(), + $resource->getContent(), + $resource->getEncoding() + ); + + if ($disable_filtering) { + $parser->disableContentFiltering(); + } + + return $parser->execute(); + } + catch (PicoFeedException $e) { + echo 'Exception thrown ===> "'.$e->getMessage().'"'.PHP_EOL; + return false; + } +} + +function get_item($feed, $item_id) +{ + foreach ($feed->items as $item) { + if ($item->getId() === $item_id) { + echo $item; + echo "============= CONTENT ================\n"; + echo $item->getContent(); + echo "\n============= CONTENT ================\n"; + break; + } + } +} + +function dump_feed($url) +{ + $feed = get_feed($url); + echo $feed; +} + +function debug_feed($url) +{ + get_feed($url); + print_r(Logger::getMessages()); +} + +function dump_item($url, $item_id) +{ + $feed = get_feed($url); + + if ($feed !== false) { + get_item($feed, $item_id); + } +} + +function nofilter_item($url, $item_id) +{ + $feed = get_feed($url, true); + + if ($feed !== false) { + get_item($feed, $item_id); + } +} + +function grabber($url) +{ + $grabber = new Scraper(new Config); + $grabber->setUrl($url); + $grabber->execute(); + + print_r(Logger::getMessages()); + echo "============= CONTENT ================\n"; + echo $grabber->getRelevantContent().PHP_EOL; + echo "============= FILTERED ================\n"; + echo $grabber->getFilteredContent().PHP_EOL; +} + +function fetch_favicon($url) +{ + $favicon = new Favicon(); + echo $favicon->find($url) . PHP_EOL; +} + +// Parse command line arguments +if ($argc === 4) { + switch ($argv[1]) { + case 'item': + dump_item($argv[2], $argv[3]); + die; + case 'nofilter': + nofilter_item($argv[2], $argv[3]); + die; + } +} else if ($argc === 3) { + switch ($argv[1]) { + case 'feed': + dump_feed($argv[2]); + die; + case 'debug': + debug_feed($argv[2]); + die; + case 'grabber': + grabber($argv[2]); + die; + case 'favicon': + fetch_favicon($argv[2]); + die; + } +} + +printf("Usage:\n"); +printf("%s feed \n", $argv[0]); +printf("%s debug \n", $argv[0]); +printf("%s item \n", $argv[0]); +printf("%s nofilter \n", $argv[0]); +printf("%s grabber \n", $argv[0]); +printf("%s favicon \n", $argv[0]); diff --git a/user/plugins/admin/vendor/robthree/twofactorauth/LICENSE b/user/plugins/admin/vendor/robthree/twofactorauth/LICENSE new file mode 100644 index 0000000..75a9631 --- /dev/null +++ b/user/plugins/admin/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/admin/vendor/robthree/twofactorauth/README.md b/user/plugins/admin/vendor/robthree/twofactorauth/README.md new file mode 100644 index 0000000..d65eb19 --- /dev/null +++ b/user/plugins/admin/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 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/admin/vendor/robthree/twofactorauth/TwoFactorAuth.sln b/user/plugins/admin/vendor/robthree/twofactorauth/TwoFactorAuth.sln new file mode 100644 index 0000000..df901f6 --- /dev/null +++ b/user/plugins/admin/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/admin/vendor/robthree/twofactorauth/lib/Providers/Qr/BaseHTTPQRCodeProvider.php b/user/plugins/admin/vendor/robthree/twofactorauth/lib/Providers/Qr/BaseHTTPQRCodeProvider.php new file mode 100644 index 0000000..5cb3add --- /dev/null +++ b/user/plugins/admin/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/admin/vendor/robthree/twofactorauth/lib/Providers/Qr/GoogleQRCodeProvider.php b/user/plugins/admin/vendor/robthree/twofactorauth/lib/Providers/Qr/GoogleQRCodeProvider.php new file mode 100644 index 0000000..19e086b --- /dev/null +++ b/user/plugins/admin/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/admin/vendor/robthree/twofactorauth/lib/Providers/Qr/IQRCodeProvider.php b/user/plugins/admin/vendor/robthree/twofactorauth/lib/Providers/Qr/IQRCodeProvider.php new file mode 100644 index 0000000..83ed67b --- /dev/null +++ b/user/plugins/admin/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/admin/vendor/robthree/twofactorauth/lib/Providers/Qr/QRicketProvider.php b/user/plugins/admin/vendor/robthree/twofactorauth/lib/Providers/Qr/QRicketProvider.php new file mode 100644 index 0000000..59e27cc --- /dev/null +++ b/user/plugins/admin/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/admin/vendor/robthree/twofactorauth/lib/Providers/Rng/CSRNGProvider.php b/user/plugins/admin/vendor/robthree/twofactorauth/lib/Providers/Rng/CSRNGProvider.php new file mode 100644 index 0000000..8dba7fc --- /dev/null +++ b/user/plugins/admin/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/admin/vendor/robthree/twofactorauth/lib/Providers/Rng/IRNGProvider.php b/user/plugins/admin/vendor/robthree/twofactorauth/lib/Providers/Rng/IRNGProvider.php new file mode 100644 index 0000000..6be2800 --- /dev/null +++ b/user/plugins/admin/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/admin/vendor/robthree/twofactorauth/lib/Providers/Rng/OpenSSLRNGProvider.php b/user/plugins/admin/vendor/robthree/twofactorauth/lib/Providers/Rng/OpenSSLRNGProvider.php new file mode 100644 index 0000000..dc66c64 --- /dev/null +++ b/user/plugins/admin/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/admin/vendor/robthree/twofactorauth/lib/Providers/Rng/RNGException.php b/user/plugins/admin/vendor/robthree/twofactorauth/lib/Providers/Rng/RNGException.php new file mode 100644 index 0000000..eb5e913 --- /dev/null +++ b/user/plugins/admin/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/admin/vendor/robthree/twofactorauth/lib/Providers/Time/HttpTimeProvider.php b/user/plugins/admin/vendor/robthree/twofactorauth/lib/Providers/Time/HttpTimeProvider.php new file mode 100644 index 0000000..c761bd9 --- /dev/null +++ b/user/plugins/admin/vendor/robthree/twofactorauth/lib/Providers/Time/HttpTimeProvider.php @@ -0,0 +1,53 @@ +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)' + ) + ) + ); + } + } + + 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/admin/vendor/robthree/twofactorauth/lib/Providers/Time/ITimeProvider.php b/user/plugins/admin/vendor/robthree/twofactorauth/lib/Providers/Time/ITimeProvider.php new file mode 100644 index 0000000..a3b87a2 --- /dev/null +++ b/user/plugins/admin/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/admin/vendor/robthree/twofactorauth/lib/TwoFactorAuthException.php b/user/plugins/admin/vendor/robthree/twofactorauth/lib/TwoFactorAuthException.php new file mode 100644 index 0000000..af51b74 --- /dev/null +++ b/user/plugins/admin/vendor/robthree/twofactorauth/lib/TwoFactorAuthException.php @@ -0,0 +1,7 @@ + + + test + +XML; + +// SimpleXML use case +$simplexml = XmlSecurity::scan($xml); +printf ("SimpleXMLElement: %s\n", ($simplexml instanceof \SimpleXMLElement) ? 'yes' : 'no'); + +// DOMDocument use case +$dom = new \DOMDocument('1.0'); +$dom = XmlSecurity::scan($xml, $dom); +printf ("DOMDocument: %s\n", ($dom instanceof \DOMDocument) ? 'yes' : 'no'); +``` + + diff --git a/user/plugins/admin/vendor/zendframework/zendxml/library/ZendXml/Exception/ExceptionInterface.php b/user/plugins/admin/vendor/zendframework/zendxml/library/ZendXml/Exception/ExceptionInterface.php new file mode 100644 index 0000000..c55eb90 --- /dev/null +++ b/user/plugins/admin/vendor/zendframework/zendxml/library/ZendXml/Exception/ExceptionInterface.php @@ -0,0 +1,14 @@ + 0) { + return true; + } + return false; + }, E_WARNING); + $result = $dom->loadXml($xml, LIBXML_NONET); + restore_error_handler(); + + if (!$result) { + // Entity load to previous setting + if (!self::isPhpFpm()) { + libxml_disable_entity_loader($loadEntities); + libxml_use_internal_errors($useInternalXmlErrors); + } + return false; + } + + // Scan for potential XEE attacks using ENTITY, if not PHP-FPM + if (!self::isPhpFpm()) { + foreach ($dom->childNodes as $child) { + if ($child->nodeType === XML_DOCUMENT_TYPE_NODE) { + if ($child->entities->length > 0) { + throw new Exception\RuntimeException(self::ENTITY_DETECT); + } + } + } + } + + // Entity load to previous setting + if (!self::isPhpFpm()) { + libxml_disable_entity_loader($loadEntities); + libxml_use_internal_errors($useInternalXmlErrors); + } + + if (isset($simpleXml)) { + $result = simplexml_import_dom($dom); + if (!$result instanceof SimpleXMLElement) { + return false; + } + return $result; + } + return $dom; + } + + /** + * Scan XML file for potential XXE/XEE attacks + * + * @param string $file + * @param DOMDocument $dom + * @throws Exception\InvalidArgumentException + * @return SimpleXMLElement|DomDocument + */ + public static function scanFile($file, DOMDocument $dom = null) + { + if (!file_exists($file)) { + throw new Exception\InvalidArgumentException( + "The file $file specified doesn't exist" + ); + } + return self::scan(file_get_contents($file), $dom); + } + + /** + * Return true if PHP is running with PHP-FPM + * + * This method is mainly used to determine whether or not heuristic checks + * (vs libxml checks) should be made, due to threading issues in libxml; + * under php-fpm, threading becomes a concern. + * + * However, PHP versions 5.5.22+ and 5.6.6+ contain a patch to the + * libxml support in PHP that makes the libxml checks viable; in such + * versions, this method will return false to enforce those checks, which + * are more strict and accurate than the heuristic checks. + * + * @return boolean + */ + public static function isPhpFpm() + { + $isVulnerableVersion = ( + version_compare(PHP_VERSION, '5.5.22', 'lt') + || ( + version_compare(PHP_VERSION, '5.6', 'gte') + && version_compare(PHP_VERSION, '5.6.6', 'lt') + ) + ); + + if (substr(php_sapi_name(), 0, 3) === 'fpm' && $isVulnerableVersion) { + return true; + } + return false; + } + + /** + * Determine and return the string(s) to use for the $generator) { + $prefix = $generator('<' . '?xml'); + if (0 === strncmp($xml, $prefix, strlen($prefix))) { + return $encoding; + } + } + + // Fallback + return 'UTF-8'; + } + + /** + * Attempt to detect the specified XML encoding. + * + * Using the file's encoding, determines if an "encoding" attribute is + * present and well-formed in the XML declaration; if so, it returns a + * list with both the ASCII representation of that declaration and the + * original file encoding. + * + * If not, a list containing only the provided file encoding is returned. + * + * @param string $xml + * @param string $fileEncoding + * @return string[] Potential XML encodings + */ + protected static function detectXmlEncoding($xml, $fileEncoding) + { + $encodingMap = self::getAsciiEncodingMap(); + $generator = $encodingMap[$fileEncoding]; + $encAttr = $generator('encoding="'); + $quote = $generator('"'); + $close = $generator('>'); + + $closePos = strpos($xml, $close); + if (false === $closePos) { + return array($fileEncoding); + } + + $encPos = strpos($xml, $encAttr); + if (false === $encPos + || $encPos > $closePos + ) { + return array($fileEncoding); + } + + $encPos += strlen($encAttr); + $quotePos = strpos($xml, $quote, $encPos); + if (false === $quotePos) { + return array($fileEncoding); + } + + $encoding = self::substr($xml, $encPos, $quotePos); + return array( + // Following line works because we're only supporting 8-bit safe encodings at this time. + str_replace('\0', '', $encoding), // detected encoding + $fileEncoding, // file encoding + ); + } + + /** + * Return a list of BOM maps. + * + * Returns a list of common encoding -> BOM maps, along with the character + * length to compare against. + * + * @link https://en.wikipedia.org/wiki/Byte_order_mark + * @return array + */ + protected static function getBomMap() + { + return array( + array( + 'encoding' => 'UTF-32BE', + 'bom' => pack('CCCC', 0x00, 0x00, 0xfe, 0xff), + 'length' => 4, + ), + array( + 'encoding' => 'UTF-32LE', + 'bom' => pack('CCCC', 0xff, 0xfe, 0x00, 0x00), + 'length' => 4, + ), + array( + 'encoding' => 'GB-18030', + 'bom' => pack('CCCC', 0x84, 0x31, 0x95, 0x33), + 'length' => 4, + ), + array( + 'encoding' => 'UTF-16BE', + 'bom' => pack('CC', 0xfe, 0xff), + 'length' => 2, + ), + array( + 'encoding' => 'UTF-16LE', + 'bom' => pack('CC', 0xff, 0xfe), + 'length' => 2, + ), + array( + 'encoding' => 'UTF-8', + 'bom' => pack('CCC', 0xef, 0xbb, 0xbf), + 'length' => 3, + ), + ); + } + + /** + * Return a map of encoding => generator pairs. + * + * Returns a map of encoding => generator pairs, where the generator is a + * callable that accepts a string and returns the appropriate byte order + * sequence of that string for the encoding. + * + * @return array + */ + protected static function getAsciiEncodingMap() + { + return array( + 'UTF-32BE' => function ($ascii) { + return preg_replace('/(.)/', "\0\0\0\\1", $ascii); + }, + 'UTF-32LE' => function ($ascii) { + return preg_replace('/(.)/', "\\1\0\0\0", $ascii); + }, + 'UTF-32odd1' => function ($ascii) { + return preg_replace('/(.)/', "\0\\1\0\0", $ascii); + }, + 'UTF-32odd2' => function ($ascii) { + return preg_replace('/(.)/', "\0\0\\1\0", $ascii); + }, + 'UTF-16BE' => function ($ascii) { + return preg_replace('/(.)/', "\0\\1", $ascii); + }, + 'UTF-16LE' => function ($ascii) { + return preg_replace('/(.)/', "\\1\0", $ascii); + }, + 'UTF-8' => function ($ascii) { + return $ascii; + }, + 'GB-18030' => function ($ascii) { + return $ascii; + }, + ); + } + + /** + * Binary-safe substr. + * + * substr() is not binary-safe; this method loops by character to ensure + * multi-byte characters are aggregated correctly. + * + * @param string $string + * @param int $start + * @param int $end + * @return string + */ + protected static function substr($string, $start, $end) + { + $substr = ''; + for ($i = $start; $i < $end; $i += 1) { + $substr .= $string[$i]; + } + return $substr; + } +} diff --git a/user/plugins/config/media.yaml b/user/plugins/config/media.yaml new file mode 100644 index 0000000..e69de29 diff --git a/user/plugins/config/plugins/langswitcher.yaml b/user/plugins/config/plugins/langswitcher.yaml new file mode 100644 index 0000000..9dd2ff2 --- /dev/null +++ b/user/plugins/config/plugins/langswitcher.yaml @@ -0,0 +1,3 @@ +enabled: true +built_in_css: true +untranslated_pages_behavior: redirect diff --git a/user/plugins/config/plugins/markdown-notices.yaml b/user/plugins/config/plugins/markdown-notices.yaml new file mode 100644 index 0000000..90adf66 --- /dev/null +++ b/user/plugins/config/plugins/markdown-notices.yaml @@ -0,0 +1,7 @@ +enabled: true +built_in_css: true +level_classes: + - yellow + - red + - blue + - green diff --git a/user/plugins/config/plugins/mediaembed.yaml b/user/plugins/config/plugins/mediaembed.yaml new file mode 100644 index 0000000..938b85f --- /dev/null +++ b/user/plugins/config/plugins/mediaembed.yaml @@ -0,0 +1,141 @@ +enabled: true +link: false +built_in_css: true +built_in_js: true +media: + width: 640 + height: 390 + adjust: true + preview: true + responsive: true + protocol: 'http://' +services: + SoundCloud: + enabled: true + type: rich + example: 'https://soundcloud.com/semiseria/verruckert-ausschnitt' + url: 'w.soundcloud.com/player/?url=http://api.soundcloud.com/tracks/{:id}' + canonical: 'http://soundcloud.com/{:id}' + endpoint: 'http://soundcloud.com/oembed?url={:canonical}&format=json' + schemes: + - 'soundcloud.com/*' + - 'soundcloud.com/*/*' + - 'soundcloud.com/*/sets/*' + - 'soundcloud.com/groups/*' + - 'snd.sc/*' + params: + auto_play: false + buying: true + download: true + hide_related: false + liking: true + sharing: true + show_artwork: true + show_comments: true + show_playcount: true + show_user: true + visual: false + Spotify: + enabled: true + type: rich + canonical: 'http://open.spotify.com/track/{:id}' + endpoint: 'https://embed.spotify.com/oembed/?url={:canonical}&format=json' + schemes: + - 'open.spotify.com/track/*' + - 'spoti.fi/*' + Flickr: + enabled: true + type: photo + canonical: 'http://www.flickr.com/photos/{:id}' + endpoint: 'http://flickr.com/services/oembed?url={:canonical}&format=json' + schemes: + - 'flickr.com/photos/*' + - 'flic.kr/*' + Imgur: + enabled: true + type: rich + canonical: 'http://imgur.com/gallery/{:id}' + endpoint: 'http://api.imgur.com/oembed?url={:canonical}&format=json' + schemes: + - 'imgur.com/gallery/*' + - 'imgur.com/a/*' + - 'imgur.com/*' + Instagram: + enabled: true + type: rich + canonical: 'http://instagram.com/p/{:id}' + endpoint: 'http://api.instagram.com/oembed?url={:canonical}&format=json' + schemes: + - 'instagr.am/p/*' + - 'instagram.com/p/*' + Dailymotion: + enabled: true + type: video + url: 'www.dailymotion.com/embed/video/{:id}' + canonical: 'http://dailymotion.com/video/{:id}' + endpoint: 'http://www.dailymotion.com/services/oembed?url={:canonical}&format=json' + schemes: + - 'dailymotion.com/video/*' + - 'dailymotion.com/*/video/*' + - 'dai\.ly/*' + params: + quality: 1080 + YouTube: + enabled: true + type: video + url: 'www.youtube.com/embed/{:id}' + canonical: 'http://www.youtube.com/watch?v={:id}' + endpoint: 'http://www.youtube.com/oembed?url={:canonical}&format=json' + schemes: + - 'youtube.com/watch?*v=*' + - 'youtube.com/embed/*' + - 'youtube.com/v/*' + - 'youtube.com/?*v=*' + - 'youtu.be/*' + params: + autoplay: 0 + modestbranding: 1 + theme: light + Vimeo: + enabled: true + type: video + url: 'player.vimeo.com/video/{:id}' + canonical: 'https://vimeo.com/{:id}' + endpoint: 'http://vimeo.com/api/oembed.json?url={:canonical}' + schemes: + - 'vimeo.com/*' + - 'vimeo.com/channels/*/*' + - 'vimeo.com/groups/*/videos/*' + params: + autoplay: 0 + Github: + enabled: true + type: rich + canonical: 'https://gist.github.com/{:id}' + endpoint: 'https://gist.github.com/{:id}.json' + schemes: + - 'gist.github.com/*' + - 'gist.github.com/*/*' + - 'gist.github.com/*?*' + Slides: + enabled: true + type: rich + canonical: 'http://slides.com/{:id}' + endpoint: 'http://slides.com/{:id}' + schemes: + - 'slides.com/*' + - 'slid.es/*' + params: + style: light + width: 1920 + height: 1400 + Twitter: + enabled: true + type: rich + canonical: 'https://twitter.com/{:id}' + endpoint: 'https://api.twitter.com/1/statuses/oembed.json?url={:canonical}' + schemes: + - 'twitter.com/*' + - 'twitter.com/*/*' + GitHub: + enabled: true diff --git a/user/plugins/config/plugins/photoswipe.yaml b/user/plugins/config/plugins/photoswipe.yaml new file mode 100755 index 0000000..7d3585c --- /dev/null +++ b/user/plugins/config/plugins/photoswipe.yaml @@ -0,0 +1,2 @@ +enabled: true +active: true \ No newline at end of file diff --git a/user/plugins/config/plugins/unitegallery.yaml b/user/plugins/config/plugins/unitegallery.yaml new file mode 100644 index 0000000..9764c92 --- /dev/null +++ b/user/plugins/config/plugins/unitegallery.yaml @@ -0,0 +1,6 @@ +enabled: true +assets_in_meta: true +gallery_theme: default +gallery_div_id: unite-gallery +thumb_width: 600 +thumb_height: 600 diff --git a/user/plugins/config/security.yaml b/user/plugins/config/security.yaml new file mode 100644 index 0000000..dd3c5c3 --- /dev/null +++ b/user/plugins/config/security.yaml @@ -0,0 +1 @@ +salt: ZJijUxdDontm4k diff --git a/user/plugins/config/site.yaml b/user/plugins/config/site.yaml new file mode 100644 index 0000000..8e7d15e --- /dev/null +++ b/user/plugins/config/site.yaml @@ -0,0 +1,17 @@ +title: 'SITE.TITLE' +default_lang: fr +author: + name: 'Kevin Tessier' + email: kevin@figureslibres.io +taxonomies: + - category + - tag +metadata: + description: 'Grav is an easy to use, yet powerful, open source flat-file CMS' +summary: + enabled: true + format: short + size: 300 + delimiter: '===' +blog: + route: /blog diff --git a/user/plugins/config/streams.yaml b/user/plugins/config/streams.yaml new file mode 100644 index 0000000..e69de29 diff --git a/user/plugins/config/system.yaml b/user/plugins/config/system.yaml new file mode 100644 index 0000000..5a97f49 --- /dev/null +++ b/user/plugins/config/system.yaml @@ -0,0 +1,142 @@ +absolute_urls: false +param_sep: ':' +wrapped_site: false +reverse_proxy_setup: false +force_ssl: false +force_lowercase_urls: true +username_regex: '^[a-z0-9_-]{3,16}$' +pwd_regex: '(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,}' +intl_enabled: true +languages: + supported: + - en + - fr + include_default_lang: true + translations: true + translations_fallback: true + session_store_active: true + http_accept_language: true + override_locale: false +home: + alias: /home-fr + hide_in_urls: false + aliases: + en: /home-en + fr: /home-fr +pages: + theme: ethica + order: + by: default + dir: asc + list: + count: 20 + dateformat: + short: 'jS M Y' + long: 'F jS \a\t g:ia' + publish_dates: true + process: + markdown: true + twig: false + twig_first: false + never_cache_twig: false + events: + page: true + twig: true + markdown: + extra: false + auto_line_breaks: false + auto_url_links: true + escape_markup: true + special_chars: + '>': gt + '<': lt + types: + - txt + - xml + - html + - htm + - json + - rss + - atom + expires: 604800 + last_modified: false + etag: false + vary_accept_encoding: false + redirect_default_route: true + redirect_default_code: '302' + redirect_trailing_slash: true + ignore_files: + - .DS_Store + ignore_folders: + - .git + - .idea + ignore_hidden: true + url_taxonomy_filters: true + frontmatter: + process_twig: false + ignore_fields: + - form + - forms +cache: + enabled: false + check: + method: file + driver: auto + prefix: g + clear_images_by_default: true + cli_compatibility: false + lifetime: 604800 + gzip: false + allow_webserver_gzip: false +twig: + cache: true + debug: true + auto_reload: true + autoescape: false + undefined_functions: true + undefined_filters: true + umask_fix: false +assets: + css_pipeline: false + css_pipeline_include_externals: true + css_pipeline_before_excludes: true + css_minify: true + css_minify_windows: false + css_rewrite: true + js_pipeline: false + js_pipeline_include_externals: true + js_pipeline_before_excludes: true + js_minify: true + enable_asset_timestamp: false + collections: + jquery: 'system://assets/jquery/jquery-2.x.min.js' +errors: + display: '1' + log: true +debugger: + enabled: false + shutdown: + close_connection: true + twig: true +images: + default_image_quality: 85 + cache_all: false + cache_perms: '0755' + debug: false + auto_fix_orientation: false +media: + enable_media_timestamp: false + auto_metadata_exif: false + upload_limit: 2097152 +session: + enabled: true + timeout: 1800 + name: grav-site + secure: false + httponly: true + split: true +gpm: + releases: stable + method: auto + verify_peer: true + official_gpm_only: true diff --git a/user/plugins/email/CHANGELOG.md b/user/plugins/email/CHANGELOG.md new file mode 100644 index 0000000..be294b7 --- /dev/null +++ b/user/plugins/email/CHANGELOG.md @@ -0,0 +1,170 @@ +# v2.7.1 +## 12/05/2017 + +1. [](#new) + * Added new `onEmailSend()` event hook before sending [#70](https://github.com/getgrav/grav-plugin-email/pull/70) +1. [](#improved) + * Added examples of setting up Email plugin with various SMTP providers + * Updated RU language [#60](https://github.com/getgrav/grav-plugin-email/pull/60) + * Updated to SwiftMailer v5.4.8 + +# v2.7.0 +## 10/26/2017 + +1. [](#improved) + * Now uses a dedicated `logs/email.log` file when `debug: true` + * Improved the README.txt file with examples, and troubleshooting + * Changed default engine to `sendmail` as `mail` is deprecated and not functioning [swiftmailer#866](https://github.com/swiftmailer/swiftmailer/issues/866} + +# v2.6.2 +## 09/30/2017 + +1. [](#improved) + * Removed extraneous files from vendor folder + +# v2.6.1 +## 09/07/2017 + +1. [](#improved) + * Improved the error message when missing `from` in the configuration + * Silently catch malformed email exceptions + +# v2.6.0 +## 05/22/2017 + +1. [](#improved) + * Inherit options from plugin configuration [#39](https://github.com/getgrav/grav-plugin-email/pull/39) +1. [](#bugfix) + * Also process translation on the email subject [https://github.com/getgrav/grav-plugin-comments/issues/38](https://github.com/getgrav/grav-plugin-comments/issues/38) + +# v2.5.3 +## 01/03/2017 + +1. [](#improved) + * Updated to SwiftMailer 5.4.5 [#45](https://github.com/getgrav/grav-plugin-email/issues/45) + +# v2.5.2 +## 12/13/2016 + +1. [](#new) + * RC released as stable + +# v2.5.2-rc.1 +## 11/26/2016 + +1. [](#new) + * Added a new `process_markdown` option for emails in forms +1. [](#improved) + * Improved the `Utils::sendEmail()` method to take the email type as an option + +# v2.5.1 +## 10/19/2016 + +1. [](#improved) + * CLI command will fallback to use the `to` from email plugin config if not provided + * Explicit Composer based class loader to fix issues with class case + +# v2.5.0 +## 09/07/2016 + +1. [](#new) + * Added a new `bin/plugin email test-email` CLI command +1. [](#improved) + * Moved Email `Utils` class from Login to Email plugin + * Provide a sample base `email/base.html.twig` template for emails +1. [](#bugfix) + * Fix handling attachments with the updated file upload field + +# v2.4.3 +## 08/16/2016 + +1. [](#improved) + * Added Russian translation + * Updated Swiftmailer to 5.4.3 [#37](https://github.com/getgrav/grav-plugin-email/issues/37) + +# v2.4.2 +## 08/10/2016 + +1. [](#improved) + * Added Croatian translation + +# v2.4.1 +## 07/14/2016 + +1. [](#improved) + * Allow multiple email recipients (comma separated) [#31](https://github.com/getgrav/grav-plugin-email/issues/31) + * Added Danish and Spanish translations + +# v2.4.0 +## 05/11/2016 + +1. [](#improved) + * Now includes Swiftmailer v5.4.2 which introduces a number of bug fixes and improvements +1. [](#bugfix) + * Correct `starttls` implementation, bundled in TLS + +# v2.3.0 +## 04/20/2016 + +1. [](#improved) + * Added debug option to enable logging on SwiftMailer. + * Updated SwiftMailer from v5.1.0 to v5.4.1. + * Added an option in the Admin settings to enable `starttls` +1. [](#bugfix) + * Correctly name TLS in the Admin settings, the label was `TTS` (but the value was correctly named `tls`) + +# v2.2.0 +## 02/05/2016 + +1. [](#new) + * Allow to send attachments in forms + * Added French translation +1. [](#improved) + * Throw an exception when trying to send emails without a `from` or `to` parameters setup, to intercept less meaningful errors and provide a better description on how to fix the problem + * Changed SMTP password in admin to use a password field instead of plain text + +# v2.1.0 +## 12/18/2015 + +1. [](#new) + * Added missing `content_type` to email.yaml + * Added default values for CC and BCC + 1. [](#improved) + * Improved documentation of new email params in `README.md` + * Moved config setting of `mailer.default` to `mailer.engine` + +# v2.0.0 +## 12/11/2015 + +1. [](#new) + * Added support for from/sender name (Thomas Keitel) + * Added support for message content type (Thomas Keitel) + * Added support for reply addresses (Thomas Keitel) + * Added support for CC/BCC (Thomas Keitel) + * Added support for multiple body parts (Thomas Keitel) +1. [](#bugfix) + * Fix email engine selection (z38) + +# v1.0.0 +## 11/20/2015 + +1. [](#bugfix) + * Fix for issue with no body parameter specified + +# v0.2.1 +## 09/11/2015 + +1. [](#bugfix) + * Fix onFormProcessed event + +# 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/email/LICENSE b/user/plugins/email/LICENSE new file mode 100644 index 0000000..0e788c6 --- /dev/null +++ b/user/plugins/email/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 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/email/README.md b/user/plugins/email/README.md new file mode 100644 index 0000000..e499fb8 --- /dev/null +++ b/user/plugins/email/README.md @@ -0,0 +1,373 @@ +# Grav Email Plugin + +The **email plugin** for [Grav](http://github.com/getgrav/grav) adds the ability to send email. This is particularly useful for the **admin** and **login** plugins. + +# Installation + +The email plugin is easy to install with GPM. + +``` +$ bin/gpm install email +``` + +# Configuration + +By default, the plugin uses PHP Mail as the mail engine. + +``` +enabled: true +from: +from_name: +to: +to_name: +mailer: + engine: sendmail + smtp: + server: localhost + port: 25 + encryption: none + user: '' + password: '' + sendmail: + bin: '/usr/sbin/sendmail -bs' +content_type: text/html +debug: false +``` + +You can configure the Email plugin by using the Admin plugin, navigating to the Plugins list and choosing `Email`. + +That's the easiest route. Or you can also alter the Plugin configuration by copying the `user/plugins/email/email.yaml` file into `user/config/plugins/email.yaml` and make your modifications there. + +The first setting you'd likely change is your `Email from` / `Email to` names and emails. + +Also, you'd likely want to setup a SMTP server instead of using PHP Mail, as the latter is not 100% reliable and you might experience problems with emails. + +> NOTE: `engine: mail` has been deprecated from the SwiftMail library that this plugin uses as it does not funtion at all. Please use `smtp` if at all possibe, and `sendmail` if SMTP is not an option. + +### Mailtrap.io + +A good way to test emails is to use a SMTP server service that's built for testing emails, for example [https://mailtrap.io](https://mailtrap.io) + +Setup the Email plugin to use that SMTP server with the fake inbox data. For example enter this configuration in `user/config/plugins/email.yaml` or through the Admin panel: + +``` +mailer: + engine: smtp + smtp: + server: mailtrap.io + port: 2525 + encryption: none + user: YOUR_MAILTRAP_INBOX_USER + password: YOUR_MAILTRAP_INBOX_PASSWORD +``` + +That service will intercept emails and show them on their web-based interface instead of sending them for real. + +You can try and fine tune the emails there while testing. + +### Google Email + +A popular option for sending email is to simply use your Google Accounts SMTP server. To set this up you will need to do 2 things first: + +1. Enable IMAP in your Gmail `Settings` -> `Forwarding and POP/IMAP` -> `IMAP Access` +2. Enable `Less secure apps` in your [user account settings](https://myaccount.google.com/lesssecureapps) +3. If you have 2-factor authentication, you will need to create a unique application password to use rather than your personal password + +Then configure the Email plugin: + +``` +mailer: + engine: smtp + smtp: + server: smtp.gmail.com + port: 465 + encryption: ssl + user: 'YOUR_GOOGLE_EMAIL_ADDRESS' + password: 'YOUR_GOOGLE_PASSWORD' +``` + +> NOTE: Check your email sending limits: https://support.google.com/a/answer/166852?hl=en + +#### Sparkpost + +Generous email sending limits even in the free tier, and simple setup, make [Sparkpost](https://www.sparkpost.com) a great option for email sending. You just need to create an account, then setup a verified sending domain. Sparkpost does a nice job of making this process very easy and undertandable. Then just click on the SMTP Relay option to get your details for the configuration: + +``` +mailer: + engine: smtp + smtp: + server: smtp.sparkpostmail.com + port: 587 + encryption: tls + user: 'SMTP_Injection' + password: 'SEND_EMAIL_API_KEY' +``` + +Then try sending a test email... + +#### Sendgrid + +[Sendgrid](https://sendgrid.com) offers a very easy-to-setup serivce with 100 emails/day for free. The next level allows you to send 40k/email a day for just $10/month. Configuration is pretty simple, just create an account, then click SMTP integration and click the button to create an API key. The configuration is as follows: + +``` +mailer: + engine: smtp + smtp: + server: smtp.sendgrid.net + port: 587 + encryption: tls + user: 'apikey' + password: 'YOUR_SENDGRID_API_KEY' +``` + +#### Mailgun + +[Mailgun is a great service](https://www.mailgun.com/) that offers 10k/emails per month for free. Setup does require SPIF domain verification so that means you need to add at least a TXT entry in your DNS. This is pretty standard for SMTP sending services and does provide verification for remote email servers and makes your email sending more reliable. The Mailgun site, walks you through this process however, and the verification process is simple and fast. + +``` +mailer: + engine: smtp + smtp: + server: smtp.mailgun.org + port: 587 + encryption: tls + user: 'MAILGUN_EMAIL_ADDRESS' + password: 'MAILGUN_EMAIL_PASSWORD' +``` + +Adjust these configurations for your account. + +#### MailJet + +Mailjet is another great service that is easy to quickly setup and get started sending email. The free account gives you 200 emails/day or 600 emails/month. Just signup and setup your SPF and DKIM entries for your domain. Then click on the SMTP settings and use those to configure the email plugin: + +``` +mailer: + engine: smtp + smtp: + server: in-v3.mailjet.com + port: 587 + encryption: tls + user: 'MAILJUST_USERNAME_API_KEY' + password: 'MAILJUST_PASSWORD_SECRET_KEY' +``` + +It's that easy! + +#### Sendmail + +Although not as reliable as SMTP not providing as much debug information, sendmail is a simple option as long as your hosting provider is not blocking the default SMTP port `25`: + +``` +mailer: + engine: sendmail + sendmail: + bin: '/usr/sbin/sendmail -bs' +``` + +Simply adjust your binary command line to suite your environment + +### SMTP Email Services + +Solid SMTP options that even provide a FREE tier for low email volumes include: + +* SendGrid (100/day free) - https://sendgrid.com +* Mailgun - (10k/month free) - https://www.mailgun.com +* Mailjet - (6k/month free) - https://www.mailjet.com/ +* Sparkpost - (15k/month free) - https://www.sparkpost.com +* Amazon SES (62k/month free) - https://aws.amazon.com/ses/ + +If you are still unsure why should be using one in the first place, check out this article: https://zapier.com/learn/email-marketing/best-transactional-email-sending-services/ + +## Testing with CLI Command + +You can test your email configuration with the following CLI Command: + +``` +$ bin/plugin email test-email -t steve@apple.com +``` + +You can also pass in a configuration environment: + +``` +$ bin/plugin email test-email -t steve@apple.com -e mysite.com +``` + +This will use the email configuration you have located in `user/mysite.com/config/plugins/email.yaml`. Read the docs to find out more about environment-based configuration: https://learn.getgrav.org/advanced/environment-config + +# Programmatically send emails + +Add this code in your plugins: + +```php + + $to = 'email@test.com'; + $from = 'email@test.com'; + + $subject = 'Test'; + $content = 'Test'; + + $message = $this->grav['Email']->message($subject, $content, 'text/html') + ->setFrom($from) + ->setTo($to); + + $sent = $this->grav['Email']->send($message); +``` + +# Emails sent with Forms + +When executing email actions during form processing, action parameters are inherited from the global configuration but may also be overridden on a per-action basis. + +``` +title: Custom form + +form: + name: custom_form + fields: + + # Any fields you'd like to add to the form: + # Their values may be referenced in email actions via '{{ form.value.FIELDNAME|e }}' + + process: + - email: + subject: "[Custom form] {{ form.value.name|e }}" + body: "{% include 'forms/data.txt.twig' %}" + from: sender@example.com + from_name: 'Custom sender name' + to: recipient@example.com + to_name: 'Custom recipient name' + content_type: 'text/plain' + process_markdown: true +``` + +## Sending Attachments + +You can add file inputs to your form, and send those files via Email. +Just add an `attachments` field and list the file input fields names. You can have multiple file fields, and this will send all the files as attachments. Example: + +``` +form: + name: custom_form + fields: + + - + name: my-file + label: 'Add a file' + type: file + multiple: false + destination: user/data/files + accept: + - application/pdf + - application/x-pdf + - image/png + - text/plain + + process: + - + email: + body: '{% include "forms/data.html.twig" %}' + attachments: + - 'my-file' +``` + +## Additional action parameters + +To have more control over your generated email, you may also use the following additional parameters: + +* `reply_to`: Set one or more addresses that should be used to reply to the message. +* `cc` _(Carbon copy)_: Add one or more addresses to the delivery list. Many email clients will mark email in one's inbox differently depending on whether they are in the `To:` or `Cc:` list. +* `bcc` _(Blind carbon copy)_: Add one or more addresses to the delivery list that should (usually) not be listed in the message data, remaining invisible to other recipients. +* `charset`: Explicitly set a charset for the generated email body (only takes effect if `body` parameter is a string, defaults to `utf-8`) + +### Specifying email addresses + +Email-related parameters (`from`, `to`, `reply_to`, `cc`and `bcc`) allow different notations for single / multiple values: + +#### Single email address string + +``` +to: mail@example.com +``` + +#### Multiple email address strings + +``` +to: + - mail@example.com + - mail+1@example.com + - mail+2@example.com +``` + +#### Single email address with name + +``` +to: + mail: mail@example.com + name: Human-readable name +``` + +#### Multiple email addresses (with and without names) + +``` +to: + - + mail: mail@example.com + name: Human-readable name + - + mail: mail+2@example.com + name: Another human-readable name + - + mail+3@example.com + - + mail+4@example.com +``` + +## Multi-part MIME messages + +Apart from a simple string, an email body may contain different MIME parts (e.g. HTML body with plain text fallback). You may even specify a different charset for each part (default to `utf-8`): + +``` +body: + - + content_type: 'text/html' + body: "{% include 'forms/default/data.html.twig' %}" + - + content_type: 'text/plain' + body: "{% include 'forms/default/data.txt.twig' %}" + charset: 'iso-8859-1' +``` + +# Troubleshooting + +## Emails are not sent + +#### Debugging + +The first step in determining why emails are not sent is to enable debugging. This can be done via the `user/config/email.yaml` file or via the plugin settings in the admin. Just enable this and then try sending an email again. Then inspect the `logs/email.log` file for potential problems. + +#### ISP Port 25 blocking + +By default, when sending via PHP or Sendmail the machine running the webserver will attempt to send mail using the SMTP protocol. This uses port `25` which is often blocked by ISPs to protected against spamming. You can determine if this port is blocked by running this command in your temrinal (mac/linux only): + +``` +(echo >/dev/tcp/localhost/25) &>/dev/null && echo "TCP port 25 opened" || echo "TCP port 25 closed" +``` + +If it's blocked there are ways to configure relays to different ports, but the simplest solution is to use SMTP for mail sending. + + +#### Exceptions + +If you get an exception when sending email but you cannot see what the error is, you need to enable more verbose exception messages. In the `user/config/system.yaml` file ensure your have the following configuration: + +``` +errors: + display: 1 + log: true +``` + +## Configuration Issues + +As explained above in the Configuration section, if you're using the default settings, set the Plugin configuration to use a SMTP server. It can be [Gmail](https://www.digitalocean.com/community/tutorials/how-to-use-google-s-smtp-server) or another SMTP server you have at your disposal. + +This is the first thing to check. The reason is that PHP Mail, the default system used by the Plugin, is not 100% reliable and emails might not arrive. diff --git a/user/plugins/email/blueprints.yaml b/user/plugins/email/blueprints.yaml new file mode 100644 index 0000000..4c100e7 --- /dev/null +++ b/user/plugins/email/blueprints.yaml @@ -0,0 +1,181 @@ +name: Email +version: 2.7.1 +description: Enables the emailing system for Grav +icon: envelope +author: + name: Team Grav + email: devs@getgrav.org + url: http://getgrav.org +keywords: plugin, email, sender +homepage: https://github.com/getgrav/grav-plugin-email +bugs: https://github.com/getgrav/grav-plugin-email/issues +license: MIT + +dependencies: + - { name: grav, version: '>=1.1.9' } + +form: + validation: loose + fields: + enabled: + type: hidden + label: PLUGIN_ADMIN.PLUGIN_STATUS + highlight: 1 + default: 1 + options: + 1: PLUGIN_ADMIN.ENABLED + 0: PLUGIN_ADMIN.DISABLED + validate: + type: bool + + mailer.engine: + type: select + label: Mail Engine + size: medium + options: + none: Disabled + smtp: SMTP + sendmail: Sendmail + + content_type: + type: select + label: Content type + size: medium + default: 'text/html' + options: + 'text/plain': Plain text + 'text/html': HTML + + charset: + type: text + size: medium + label: Charset + placeholder: "Defaults to UTF-8" + + from: + type: email + size: medium + label: Email from + placeholder: "Default email from address" + validate: + required: true + type: email + + from_name: + type: text + size: medium + label: Email from name + placeholder: "Default email from name" + + to: + type: email + size: medium + label: Email to + placeholder: "Default email to address" + multiple: true + validate: + required: true + type: email + + to_name: + type: text + size: medium + label: Email to name + placeholder: "Default email to name" + + cc: + type: email + size: medium + label: Email CC + placeholder: "Default email CC address" + multiple: true + validate: + type: email + + cc_name: + type: text + size: medium + label: Email CC name + placeholder: "Default email CC name" + + bcc: + type: email + size: medium + label: Email BCC + placeholder: "Default email BCC address" + multiple: true + validate: + type: email + + reply_to: + type: email + size: medium + label: Email reply-to + placeholder: "Default email reply-to address" + multiple: true + validate: + type: email + + reply_to_name: + type: text + size: medium + label: Email reply-to name + placeholder: "Default email reply-to name" + + body: + type: textarea + size: medium + label: Email body + placeholder: "Defaults to a table of all form fields" + + mailer.smtp.server: + type: text + size: medium + label: SMTP server + placeholder: "e.g. smtp.google.com" + + mailer.smtp.port: + type: text + size: small + label: SMTP port + placeholder: "Defaults to 25 (plaintext) / 587 (encrypted)" + validate: + type: number + min: 1 + max: 65535 + + mailer.smtp.encryption: + type: select + size: medium + label: SMTP encryption + options: + none: None + ssl: SSL + tls: TLS + + mailer.smtp.user: + type: text + size: medium + label: SMTP login name + + mailer.smtp.password: + type: password + size: medium + label: SMTP password + + mailer.sendmail.bin: + type: text + size: medium + label: Path to sendmail + placeholder: "/usr/sbin/sendmail" + + debug: + type: toggle + label: Debug + highlight: 1 + default: 0 + options: + true: PLUGIN_ADMIN.ENABLED + false: PLUGIN_ADMIN.DISABLED + validate: + type: bool diff --git a/user/plugins/email/classes/Email.php b/user/plugins/email/classes/Email.php new file mode 100644 index 0000000..1af8b33 --- /dev/null +++ b/user/plugins/email/classes/Email.php @@ -0,0 +1,191 @@ +get('plugins.email.mailer.engine') != 'none'; + } + + /** + * Returns true if debugging on emails has been enabled. + * + * @return bool + */ + public function debug() + { + return Grav::instance()['config']->get('plugins.email.debug') == 'true'; + } + + /** + * Creates an email message. + * + * @param string $subject + * @param string $body + * @param string $contentType + * @param string $charset + * @return \Swift_Message + */ + public function message($subject = null, $body = null, $contentType = null, $charset = null) + { + return new \Swift_Message($subject, $body, $contentType, $charset); + } + + /** + * Creates an attachment. + * + * @param string $data + * @param string $filename + * @param string $contentType + * @return \Swift_Attachment + */ + public function attachment($data = null, $filename = null, $contentType = null) + { + return new \Swift_Attachment($data, $filename, $contentType); + } + + /** + * Creates an embedded attachment. + * + * @param string $data + * @param string $filename + * @param string $contentType + * @return \Swift_EmbeddedFile + */ + public function embedded($data = null, $filename = null, $contentType = null) + { + return new \Swift_EmbeddedFile($data, $filename, $contentType); + } + + /** + * Creates an image attachment. + * + * @param string $data + * @param string $filename + * @param string $contentType + * @return \Swift_Image + */ + public function image($data = null, $filename = null, $contentType = null) + { + return new \Swift_Image($data, $filename, $contentType); + } + + /** + * Send email. + * + * @param \Swift_Message $message + * @return int + */ + public function send($message) + { + $mailer = $this->getMailer(); + + $result = $mailer ? $mailer->send($message) : 0; + + // Check if emails and debugging are both enabled. + if ($mailer && $this->debug()) { + + $log = new Logger('email'); + $locator = Grav::instance()['locator']; + $log_file = $locator->findResource('log://email.log', true, true); + $log->pushHandler(new StreamHandler($log_file, Logger::DEBUG)); + + // Append the SwiftMailer log to the log. + $log->addDebug($this->getLogs()); + } + + return $result; + } + + /** + * Return debugging logs if enabled + * + * @return string + */ + public function getLogs() + { + if ($this->debug()) { + return $this->logger->dump(); + } + return ''; + } + + /** + * @internal + * @return null|\Swift_Mailer + */ + protected function getMailer() + { + if (!$this->enabled()) { + return null; + } + + if (!$this->mailer) { + /** @var Config $config */ + $config = Grav::instance()['config']; + $mailer = $config->get('plugins.email.mailer.engine'); + + // Create the Transport and initialize it. + switch ($mailer) { + case 'smtp': + $transport = \Swift_SmtpTransport::newInstance(); + + $options = $config->get('plugins.email.mailer.smtp'); + if (!empty($options['server'])) { + $transport->setHost($options['server']); + } + if (!empty($options['port'])) { + $transport->setPort($options['port']); + } + if (!empty($options['encryption']) && $options['encryption'] != 'none') { + $transport->setEncryption($options['encryption']); + } + if (!empty($options['user'])) { + $transport->setUsername($options['user']); + } + if (!empty($options['password'])) { + $transport->setPassword($options['password']); + } + break; + case 'sendmail': + default: + $options = $config->get('plugins.email.mailer.sendmail'); + $bin = !empty($options['bin']) ? $options['bin'] : '/usr/sbin/sendmail'; + $transport = \Swift_SendmailTransport::newInstance($bin); + break; + } + + // Create the Mailer using your created Transport + $this->mailer = \Swift_Mailer::newInstance($transport); + + // Register the logger if we're debugging. + if ($this->debug()) { + $this->logger = new \Swift_Plugins_Loggers_ArrayLogger(); + $this->mailer->registerPlugin(new \Swift_Plugins_LoggerPlugin($this->logger)); + } + } + + return $this->mailer; + } +} diff --git a/user/plugins/email/classes/Utils.php b/user/plugins/email/classes/Utils.php new file mode 100644 index 0000000..690babf --- /dev/null +++ b/user/plugins/email/classes/Utils.php @@ -0,0 +1,57 @@ +get('plugins.email.from'); + } + + if (!isset($grav['Email']) || empty($from)) { + throw new \RuntimeException($grav['language']->translate('PLUGIN_EMAIL.PLEASE_CONFIGURE_A_FROM_ADDRESS')); + } + + if (empty($to) || empty($subject) || empty($content)) { + return false; + } + + //Initialize twig if not yet initialized + $grav['twig']->init(); + + $body = $grav['twig']->processTemplate('email/base.html.twig', ['content' => $content]); + + $message = $grav['Email']->message($subject, $body, $mimetype) + ->setFrom($from) + ->setTo($to); + + $sent = $grav['Email']->send($message); + + if ($sent < 1) { + return false; + } else { + return true; + } + } +} diff --git a/user/plugins/email/cli/TestEmailCommand.php b/user/plugins/email/cli/TestEmailCommand.php new file mode 100644 index 0000000..f1047d7 --- /dev/null +++ b/user/plugins/email/cli/TestEmailCommand.php @@ -0,0 +1,98 @@ +setName('test-email') + ->setAliases(['testemail']) + ->addOption( + 'to', + 't', + InputOption::VALUE_REQUIRED, + 'An email address to send the email to' + ) + ->addOption( + 'env', + 'e', + InputOption::VALUE_OPTIONAL, + 'The environment to trigger a specific configuration. For example: localhost, mysite.dev, www.mysite.com' + ) + ->addOption( + 'subject', + 's', + InputOption::VALUE_OPTIONAL, + 'A subject for the email' + ) + ->addOption( + 'body', + 'b', + InputOption::VALUE_OPTIONAL, + 'The body of the email' + ) + ->setDescription('Sends a test email using the plugin\'s configuration') + ->setHelp('The test-email command sends a test email using the plugin\'s configuration'); + } + + /** + * @return int|null|void + */ + protected function serve() + { + $grav = Grav::instance(); + + $this->output->writeln(''); + $this->output->writeln('Current Configuration:'); + $this->output->writeln(''); + + dump($grav['config']->get('plugins.email')); + + $this->output->writeln(''); + + require_once __DIR__ . '/../vendor/autoload.php'; + + $grav['Email'] = new Email(); + + $email_to = $this->input->getOption('to') ?: $grav['config']->get('plugins.email.to'); + $subject = $this->input->getOption('subject'); + $body = $this->input->getOption('body'); + + if (!$subject) { + $subject = 'Testing Grav Email Plugin'; + } + + if (!$body) { + $configuration = print_r($grav['config']->get('plugins.email'), true); + $body = $grav['language']->translate(['PLUGIN_EMAIL.TEST_EMAIL_BODY', $configuration]); + } + + $sent = EmailUtils::sendEmail($subject, $body, $email_to); + + if ($sent) { + $this->output->writeln("Message sent successfully!"); + } else { + $this->output->writeln("Problem sending email..."); + } + + } +} diff --git a/user/plugins/email/composer.json b/user/plugins/email/composer.json new file mode 100644 index 0000000..182c714 --- /dev/null +++ b/user/plugins/email/composer.json @@ -0,0 +1,10 @@ +{ + "require": { + "swiftmailer/swiftmailer": "~5.4" + }, + "autoload": { + "psr-4": { + "Grav\\Plugin\\Email\\": "classes/" + } + } +} diff --git a/user/plugins/email/composer.lock b/user/plugins/email/composer.lock new file mode 100644 index 0000000..a993590 --- /dev/null +++ b/user/plugins/email/composer.lock @@ -0,0 +1,72 @@ +{ + "_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": "2244976b3750b669fab6abb506e9c591", + "packages": [ + { + "name": "swiftmailer/swiftmailer", + "version": "v5.4.8", + "source": { + "type": "git", + "url": "https://github.com/swiftmailer/swiftmailer.git", + "reference": "9a06dc570a0367850280eefd3f1dc2da45aef517" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/9a06dc570a0367850280eefd3f1dc2da45aef517", + "reference": "9a06dc570a0367850280eefd3f1dc2da45aef517", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "mockery/mockery": "~0.9.1", + "symfony/phpunit-bridge": "~3.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.4-dev" + } + }, + "autoload": { + "files": [ + "lib/swift_required.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Chris Corbyn" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Swiftmailer, free feature-rich PHP mailer", + "homepage": "http://swiftmailer.org", + "keywords": [ + "email", + "mail", + "mailer" + ], + "time": "2017-05-01T15:54:03+00:00" + } + ], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": [], + "platform-dev": [] +} diff --git a/user/plugins/email/email.php b/user/plugins/email/email.php new file mode 100644 index 0000000..6e2f1d3 --- /dev/null +++ b/user/plugins/email/email.php @@ -0,0 +1,323 @@ + ['onPluginsInitialized', 0], + 'onFormProcessed' => ['onFormProcessed', 0], + 'onTwigTemplatePaths' => ['onTwigTemplatePaths', 0] + ]; + } + + /** + * Initialize emailing. + */ + public function onPluginsInitialized() + { + require_once __DIR__ . '/vendor/autoload.php'; + + $this->email = new Email(); + + if ($this->email->enabled()) { + $this->grav['Email'] = $this->email; + } + } + + /** + * Add twig paths to plugin templates. + */ + public function onTwigTemplatePaths() + { + $twig = $this->grav['twig']; + $twig->twig_paths[] = __DIR__ . '/templates'; + } + + /** + * Send email when processing the form data. + * + * @param Event $event + */ + public function onFormProcessed(Event $event) + { + $form = $event['form']; + $action = $event['action']; + $params = $event['params']; + + if (!$this->email->enabled()) { + return; + } + + switch ($action) { + case 'email': + // Prepare Twig variables + $vars = array( + 'form' => $form + ); + + $grav = Grav::instance(); + $grav->fireEvent('onEmailSend', new Event(['params' => &$params, 'vars' => &$vars])); + + // Build message + $message = $this->buildMessage($params, $vars); + + if (isset($params['attachments'])) { + $filesToAttach = (array)$params['attachments']; + if ($filesToAttach) foreach ($filesToAttach as $fileToAttach) { + $filesValues = $form->value($fileToAttach); + + if ($filesValues) foreach($filesValues as $fileValues) { + if (isset($fileValues['file'])) { + $filename = $fileValues['file']; + } else { + $filename = ROOT_DIR . $fileValues['path']; + } + + $message->attach(\Swift_Attachment::fromPath($filename)); + } + } + } + + // Send e-mail + $this->email->send($message); + break; + } + } + + /** + * Build e-mail message. + * + * @param array $params + * @param array $vars + * @return \Swift_Message + */ + protected function buildMessage(array $params, array $vars = array()) + { + /** @var Twig $twig */ + $twig = $this->grav['twig']; + + // Extend parameters with defaults. + $params += array( + 'bcc' => $this->config->get('plugins.email.bcc', array()), + 'body' => $this->config->get('plugins.email.body', '{% include "forms/data.html.twig" %}'), + 'cc' => $this->config->get('plugins.email.cc', array()), + 'cc_name' => $this->config->get('plugins.email.cc_name'), + 'charset' => $this->config->get('plugins.email.charset', 'utf-8'), + 'from' => $this->config->get('plugins.email.from'), + 'from_name' => $this->config->get('plugins.email.from_name'), + 'content_type' => $this->config->get('plugins.email.content_type', 'text/html'), + 'reply_to' => $this->config->get('plugins.email.reply_to', array()), + 'reply_to_name' => $this->config->get('plugins.email.reply_to_name'), + 'subject' => !empty($vars['form']) && $vars['form'] instanceof Form ? $vars['form']->page()->title() : null, + 'to' => $this->config->get('plugins.email.to'), + 'to_name' => $this->config->get('plugins.email.to_name'), + 'process_markdown' => false, + ); + + // Create message object. + $message = $this->email->message(); + + if (!$params['to']) { + throw new \RuntimeException($this->grav['language']->translate('PLUGIN_EMAIL.PLEASE_CONFIGURE_A_TO_ADDRESS')); + } + if (!$params['from']) { + throw new \RuntimeException($this->grav['language']->translate('PLUGIN_EMAIL.PLEASE_CONFIGURE_A_FROM_ADDRESS')); + } + + // Process parameters. + foreach ($params as $key => $value) { + switch ($key) { + case 'bcc': + foreach ($this->parseAddressValue($value, $vars) as $address) { + try { + $message->addBcc($address->mail, $address->name); + } catch (Swift_RfcComplianceException $e) { + continue; + } + } + break; + + case 'body': + if (is_string($value)) { + $body = $twig->processString($value, $vars); + + if ($params['process_markdown']) { + $parsedown = new \Parsedown(); + $body = $parsedown->text($body); + } + + $content_type = !empty($params['content_type']) ? $twig->processString($params['content_type'], $vars) : null; + $charset = !empty($params['charset']) ? $twig->processString($params['charset'], $vars) : null; + + $message->setBody($body, $content_type, $charset); + } + elseif (is_array($value)) { + foreach ($value as $body_part) { + $body_part += array( + 'charset' => $params['charset'], + 'content_type' => $params['content_type'], + ); + + $body = !empty($body_part['body']) ? $twig->processString($body_part['body'], $vars) : null; + + if ($params['process_markdown']) { + $parsedown = new \Parsedown(); + $body = $parsedown->text($body); + } + + $content_type = !empty($body_part['content_type']) ? $twig->processString($body_part['content_type'], $vars) : null; + $charset = !empty($body_part['charset']) ? $twig->processString($body_part['charset'], $vars) : null; + + if (!$message->getBody()) { + $message->setBody($body, $content_type, $charset); + } + else { + $message->addPart($body, $content_type, $charset); + } + } + } + break; + + case 'cc': + if (is_string($value) && !empty($params['cc_name'])) { + $value = array( + 'mail' => $twig->processString($value, $vars), + 'name' => $twig->processString($params['cc_name'], $vars), + ); + } + + foreach ($this->parseAddressValue($value, $vars) as $address) { + try { + $message->addCc($address->mail, $address->name); + } catch (Swift_RfcComplianceException $e) { + continue; + } + } + break; + + case 'from': + if (is_string($value) && !empty($params['from_name'])) { + $value = array( + 'mail' => $twig->processString($value, $vars), + 'name' => $twig->processString($params['from_name'], $vars), + ); + } + + foreach ($this->parseAddressValue($value, $vars) as $address) { + try { + $message->addFrom($address->mail, $address->name); + } catch (Swift_RfcComplianceException $e) { + continue; + } + } + break; + + case 'reply_to': + if (is_string($value) && !empty($params['reply_to_name'])) { + $value = array( + 'mail' => $twig->processString($value, $vars), + 'name' => $twig->processString($params['reply_to_name'], $vars), + ); + } + + foreach ($this->parseAddressValue($value, $vars) as $address) { + try { + $message->addReplyTo($address->mail, $address->name); + } catch (Swift_RfcComplianceException $e) { + continue; + } + } + break; + + case 'subject': + $message->setSubject($twig->processString($this->grav['language']->translate($value), $vars)); + break; + + case 'to': + if (is_string($value) && !empty($params['to_name'])) { + $value = array( + 'mail' => $twig->processString($value, $vars), + 'name' => $twig->processString($params['to_name'], $vars), + ); + } + + foreach ($this->parseAddressValue($value, $vars) as $address) { + try { + $message->addTo($address->mail, $address->name); + } catch (Swift_RfcComplianceException $e) { + continue; + } + } + break; + } + } + + return $message; + } + + /** + * Return parsed e-mail address value. + * + * @param $value + * @param array $vars + * @return array + */ + protected function parseAddressValue($value, array $vars = array()) + { + $parsed = array(); + + /** @var Twig $twig */ + $twig = $this->grav['twig']; + + // Single e-mail address string + if (is_string($value)) { + $parsed[] = (object) array( + 'mail' => $twig->processString($value, $vars), + 'name' => null, + ); + } + + else { + // Cast value as array + $value = (array) $value; + + // Single e-mail address array + if (!empty($value['mail'])) { + $parsed[] = (object) array( + 'mail' => $twig->processString($value['mail'], $vars), + 'name' => !empty($value['name']) ? $twig->processString($value['name'], $vars) : NULL, + ); + } + + // Multiple addresses (either as strings or arrays) + elseif (!(empty($value['mail']) && !empty($value['name']))) { + foreach ($value as $y => $itemx) { + $addresses = $this->parseAddressValue($itemx, $vars); + + if (($address = reset($addresses))) { + $parsed[] = $address; + } + } + } + } + + return $parsed; + } +} diff --git a/user/plugins/email/email.yaml b/user/plugins/email/email.yaml new file mode 100644 index 0000000..78b9394 --- /dev/null +++ b/user/plugins/email/email.yaml @@ -0,0 +1,17 @@ +enabled: true +from: +from_name: +to: +to_name: +mailer: + engine: sendmail + smtp: + server: localhost + port: 25 + encryption: none + user: '' + password: '' + sendmail: + bin: '/usr/sbin/sendmail -bs' +content_type: text/html +debug: false \ No newline at end of file diff --git a/user/plugins/email/hebe.json b/user/plugins/email/hebe.json new file mode 100644 index 0000000..3831af4 --- /dev/null +++ b/user/plugins/email/hebe.json @@ -0,0 +1,15 @@ +{ + "project":"grav-plugin-email", + "platforms":{ + "grav":{ + "nodes":{ + "plugin":[ + { + "source":"/", + "destination":"/user/plugins/email" + } + ] + } + } + } +} diff --git a/user/plugins/email/languages.yaml b/user/plugins/email/languages.yaml new file mode 100644 index 0000000..2c6518a --- /dev/null +++ b/user/plugins/email/languages.yaml @@ -0,0 +1,56 @@ +en: + PLUGIN_EMAIL: + EMAIL_NOT_CONFIGURED: "Email not configured" + PLEASE_CONFIGURE_A_TO_ADDRESS: "Please configure a 'to' address in the Email Plugin settings, or in the form" + PLEASE_CONFIGURE_A_FROM_ADDRESS: "Please configure a 'from' address in the Email Plugin settings, or in the form" + TEST_EMAIL_BODY: "

                                                                      Testing Email

                                                                      This test email has been sent based on the following configuration:

                                                                      %1$s

                                                                      " + EMAIL_FOOTER: "GetGrav.org" + +da: + PLUGIN_EMAIL: + PLEASE_CONFIGURE_A_TO_ADDRESS: "Konfigurere venligst en 'til' email adresse i Email Plugin indstillingerne eller her i formularen" + PLEASE_CONFIGURE_A_FROM_ADDRESS: "Konfigurere venligst en 'fra' email adresse i Email Plugin indstillingerne eller her i formularen" + +de: + PLUGIN_EMAIL: + EMAIL_NOT_CONFIGURED: "E-Mail ist nicht konfiguriert" + PLEASE_CONFIGURE_A_TO_ADDRESS: "Bitte konfigurieren sie eine 'An' ('to') Adresse in den Email-Plugin-Einstellungen oder im Formular." + PLEASE_CONFIGURE_A_FROM_ADDRESS: "Bitte konfigurieren sie eine 'Von' ('from') Adresse in den Email-Plugin-Einstellungen oder im Formular." + +es: + PLUGIN_EMAIL: + PLEASE_CONFIGURE_A_TO_ADDRESS: "Por favor configura una dirección de 'remitente' en la configuración del Plugin de Email o en el formulario" + PLEASE_CONFIGURE_A_FROM_ADDRESS: "Por favor configura una dirección de 'destinatario' en la configuración del Plugin de Email o en el formulario" + +fr: + PLUGIN_EMAIL: + EMAIL_NOT_CONFIGURED: "L’e-mail n’est pas configuré" + PLEASE_CONFIGURE_A_TO_ADDRESS: "Veuillez configurer une adresse de 'destinataire' dans les paramètres du Plugin ou dans le formulaire." + PLEASE_CONFIGURE_A_FROM_ADDRESS: "Veuillez configurer une adresse 'd'expéditeur' dans les paramètres du Plugin ou dans le formulaire." + TEST_EMAIL_BODY: "

                                                                      E-mail de test

                                                                      Cet e-mail de test est basé sur la configuration suivante :

                                                                      %1$s

                                                                      " + EMAIL_FOOTER: "GetGrav.org" + +hr: + PLUGIN_EMAIL: + EMAIL_NOT_CONFIGURED: "Email nije konfiguriran" + PLEASE_CONFIGURE_A_TO_ADDRESS: "Konfigurirajte 'za' ('to') adresu u postavkama Email dodatka ili u obrascu" + PLEASE_CONFIGURE_A_FROM_ADDRESS: "Konfigurirajte 'od' ('from') adresu u postavkama Email dodatka ili u obrascu" + +it: + PLUGIN_EMAIL: + PLEASE_CONFIGURE_A_TO_ADDRESS: "Per favore, configura l'indirizzo di destinazione ('to') nella configurazione del Plugin Email, oppure direttamente nella form." + PLEASE_CONFIGURE_A_FROM_ADDRESS: "Per favore, configura l'indirizzo di provenienza ('from') nella configurazione del Plugin Email, oppure direttamente nella form" + +ro: + PLUGIN_EMAIL: + EMAIL_NOT_CONFIGURED: "Adresa de email nu este configurată" + PLEASE_CONFIGURE_A_TO_ADDRESS: "Vă rugam setați o adresă 'către' în setările modulului Email sau în formular" + PLEASE_CONFIGURE_A_FROM_ADDRESS: "Vă rugam setați o adresă 'de la' în setările modulului Email sau în formular" + +ru: + PLUGIN_EMAIL: + EMAIL_NOT_CONFIGURED: "Электронная почта не настроена" + PLEASE_CONFIGURE_A_TO_ADDRESS: "Пожалуйста настройте адрес получателя ('to') в настройках плагина Email Plugin, или на форме" + PLEASE_CONFIGURE_A_FROM_ADDRESS: "Пожалуйста настройте адрес отправителя ('from') в настройках плагина Email Plugin, или на форме" + TEST_EMAIL_BODY: "

                                                                      Тестирование электронной почты

                                                                      Это тестовое письмо отправлено на основе следующей конфигурации:

                                                                      %1$s

                                                                      " + EMAIL_FOOTER: "GetGrav.org" diff --git a/user/plugins/email/templates/email/base.html.twig b/user/plugins/email/templates/email/base.html.twig new file mode 100644 index 0000000..de554c2 --- /dev/null +++ b/user/plugins/email/templates/email/base.html.twig @@ -0,0 +1,210 @@ + + + + + + + + + + + + + + + + + + +
                                                                      +
                                                                      + + + + +
                                                                      + {{ content|raw }} +
                                                                      +
                                                                      +
                                                                      + + + + + + + + + + + + + + diff --git a/user/plugins/email/vendor/autoload.php b/user/plugins/email/vendor/autoload.php new file mode 100644 index 0000000..117c9c1 --- /dev/null +++ b/user/plugins/email/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])) { + foreach ($this->prefixDirsPsr4[$search] as $dir) { + $length = $this->prefixLengthsPsr4[$first][$search]; + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) { + 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/email/vendor/composer/LICENSE b/user/plugins/email/vendor/composer/LICENSE new file mode 100644 index 0000000..f0157a6 --- /dev/null +++ b/user/plugins/email/vendor/composer/LICENSE @@ -0,0 +1,56 @@ +Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: Composer +Upstream-Contact: Jordi Boggiano +Source: https://github.com/composer/composer + +Files: * +Copyright: 2016, Nils Adermann + 2016, Jordi Boggiano +License: Expat + +Files: src/Composer/Util/TlsHelper.php +Copyright: 2016, Nils Adermann + 2016, Jordi Boggiano + 2013, Evan Coury +License: Expat and BSD-2-Clause + +License: BSD-2-Clause + 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. + . + 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. + +License: Expat + 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/email/vendor/composer/autoload_classmap.php b/user/plugins/email/vendor/composer/autoload_classmap.php new file mode 100644 index 0000000..7a91153 --- /dev/null +++ b/user/plugins/email/vendor/composer/autoload_classmap.php @@ -0,0 +1,9 @@ + $vendorDir . '/swiftmailer/swiftmailer/lib/swift_required.php', +); diff --git a/user/plugins/email/vendor/composer/autoload_namespaces.php b/user/plugins/email/vendor/composer/autoload_namespaces.php new file mode 100644 index 0000000..b7fc012 --- /dev/null +++ b/user/plugins/email/vendor/composer/autoload_namespaces.php @@ -0,0 +1,9 @@ + array($baseDir . '/classes'), +); diff --git a/user/plugins/email/vendor/composer/autoload_real.php b/user/plugins/email/vendor/composer/autoload_real.php new file mode 100644 index 0000000..909cb26 --- /dev/null +++ b/user/plugins/email/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\ComposerStaticInitdec5d78def1384d1f20996ded9d7efbf::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\ComposerStaticInitdec5d78def1384d1f20996ded9d7efbf::$files; + } else { + $includeFiles = require __DIR__ . '/autoload_files.php'; + } + foreach ($includeFiles as $fileIdentifier => $file) { + composerRequiredec5d78def1384d1f20996ded9d7efbf($fileIdentifier, $file); + } + + return $loader; + } +} + +function composerRequiredec5d78def1384d1f20996ded9d7efbf($fileIdentifier, $file) +{ + if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { + require $file; + + $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true; + } +} diff --git a/user/plugins/email/vendor/composer/autoload_static.php b/user/plugins/email/vendor/composer/autoload_static.php new file mode 100644 index 0000000..6fe87ab --- /dev/null +++ b/user/plugins/email/vendor/composer/autoload_static.php @@ -0,0 +1,35 @@ + __DIR__ . '/..' . '/swiftmailer/swiftmailer/lib/swift_required.php', + ); + + public static $prefixLengthsPsr4 = array ( + 'G' => + array ( + 'Grav\\Plugin\\Email\\' => 18, + ), + ); + + public static $prefixDirsPsr4 = array ( + 'Grav\\Plugin\\Email\\' => + array ( + 0 => __DIR__ . '/../..' . '/classes', + ), + ); + + public static function getInitializer(ClassLoader $loader) + { + return \Closure::bind(function () use ($loader) { + $loader->prefixLengthsPsr4 = ComposerStaticInitdec5d78def1384d1f20996ded9d7efbf::$prefixLengthsPsr4; + $loader->prefixDirsPsr4 = ComposerStaticInitdec5d78def1384d1f20996ded9d7efbf::$prefixDirsPsr4; + + }, null, ClassLoader::class); + } +} diff --git a/user/plugins/email/vendor/composer/installed.json b/user/plugins/email/vendor/composer/installed.json new file mode 100644 index 0000000..e354048 --- /dev/null +++ b/user/plugins/email/vendor/composer/installed.json @@ -0,0 +1,58 @@ +[ + { + "name": "swiftmailer/swiftmailer", + "version": "v5.4.8", + "version_normalized": "5.4.8.0", + "source": { + "type": "git", + "url": "https://github.com/swiftmailer/swiftmailer.git", + "reference": "9a06dc570a0367850280eefd3f1dc2da45aef517" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/9a06dc570a0367850280eefd3f1dc2da45aef517", + "reference": "9a06dc570a0367850280eefd3f1dc2da45aef517", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "mockery/mockery": "~0.9.1", + "symfony/phpunit-bridge": "~3.2" + }, + "time": "2017-05-01T15:54:03+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.4-dev" + } + }, + "installation-source": "dist", + "autoload": { + "files": [ + "lib/swift_required.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Chris Corbyn" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Swiftmailer, free feature-rich PHP mailer", + "homepage": "http://swiftmailer.org", + "keywords": [ + "email", + "mail", + "mailer" + ] + } +] diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/CHANGES b/user/plugins/email/vendor/swiftmailer/swiftmailer/CHANGES new file mode 100644 index 0000000..e5b605b --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/CHANGES @@ -0,0 +1,267 @@ +Changelog +========= + +5.4.8 (2017-05-01) +------------------ + + * fixed encoding inheritance in addPart() + * fixed sorting MIME children when their types are equal + +5.4.7 (2017-04-20) +------------------ + + * fixed NTLMAuthenticator clobbering bcmath scale + +5.4.6 (2017-02-13) +------------------ + + * removed exceptions thrown in destructors as they lead to fatal errors + * switched to use sha256 by default in DKIM as per the RFC + * fixed an 'Undefined variable: pipes' PHP notice + * fixed long To headers when using the mail transport + * fixed NTLMAuthenticator when no domain is passed with the username + * prevented fatal error during unserialization of a message + * fixed a PHP warning when sending a message that has a length of a multiple of 8192 + +5.4.5 (2016-12-29) +------------------ + + * SECURITY FIX: fixed CVE-2016-10074 by disallowing potentially unsafe shell characters + + Prior to 5.4.5, the mail transport (Swift_Transport_MailTransport) was vulnerable to passing + arbitrary shell arguments if the "From", "ReturnPath" or "Sender" header came + from a non-trusted source, potentially allowing Remote Code Execution + * deprecated the mail transport + +5.4.4 (2016-11-23) +------------------ + + * reverted escaping command-line args to mail (PHP mail() function already does it) + +5.4.3 (2016-07-08) +------------------ + + * fixed SimpleHeaderSet::has()/get() when the 0 index is removed + * removed the need to have mcrypt installed + * fixed broken MIME header encoding with quotes/colons and non-ascii chars + * allowed mail transport send for messages without To header + * fixed PHP 7 support + +5.4.2 (2016-05-01) +------------------ + + * fixed support for IPv6 sockets + * added auto-retry when sending messages from the memory spool + * fixed consecutive read calls in Swift_ByteStream_FileByteStream + * added support for iso-8859-15 encoding + * fixed PHP mail extra params on missing reversePath + * added methods to set custom stream context options + * fixed charset changes in QpContentEncoderProxy + * added return-path header to the ignoredHeaders list of DKIMSigner + * fixed crlf for subject using mail + * fixed add soft line break only when necessary + * fixed escaping command-line args to mail + +5.4.1 (2015-06-06) +------------------ + + * made Swiftmailer exceptions confirm to PHP base exception constructor signature + * fixed MAIL FROM & RCPT TO headers to be RFC compliant + +5.4.0 (2015-03-14) +------------------ + + * added the possibility to add extra certs to PKCS#7 signature + * fix base64 encoding with streams + * added a new RESULT_SPOOLED status for SpoolTransport + * fixed getBody() on attachments when called more than once + * removed dots from generated filenames in filespool + +5.3.1 (2014-12-05) +------------------ + + * fixed cloning of messages with attachments + +5.3.0 (2014-10-04) +------------------ + + * fixed cloning when using signers + * reverted removal of Swift_Encoding + * drop support for PHP 5.2.x + +5.2.2 (2014-09-20) +------------------ + + * fixed Japanese support + * fixed the memory spool when the message changes when in the pool + * added support for cloning messages + * fixed PHP warning in the redirect plugin + * changed the way to and cc-ed email are sent to only use one transaction + +5.2.1 (2014-06-13) +------------------ + + * SECURITY FIX: fixed CLI escaping when using sendmail as a transport + + Prior to 5.2.1, the sendmail transport (Swift_Transport_SendmailTransport) + was vulnerable to an arbitrary shell execution if the "From" header came + from a non-trusted source and no "Return-Path" is configured. + + * fixed parameter in DKIMSigner + * fixed compatibility with PHP < 5.4 + +5.2.0 (2014-05-08) +------------------ + + * fixed Swift_ByteStream_FileByteStream::read() to match to the specification + * fixed from-charset and to-charset arguments in mbstring_convert_encoding() usages + * fixed infinite loop in StreamBuffer + * fixed NullTransport to return the number of ignored emails instead of 0 + * Use phpunit and mockery for unit testing (realityking) + +5.1.0 (2014-03-18) +------------------ + + * fixed data writing to stream when sending large messages + * added support for libopendkim (https://github.com/xdecock/php-opendkim) + * merged SignedMessage and Message + * added Gmail XOAuth2 authentication + * updated the list of known mime types + * added NTLM authentication + +5.0.3 (2013-12-03) +------------------ + + * fixed double-dot bug + * fixed DKIM signer + +5.0.2 (2013-08-30) +------------------ + + * handled correct exception type while reading IoBuffer output + +5.0.1 (2013-06-17) +------------------ + + * changed the spool to only start the transport when a mail has to be sent + * fixed compatibility with PHP 5.2 + * fixed LICENSE file + +5.0.0 (2013-04-30) +------------------ + + * changed the license from LGPL to MIT + +4.3.1 (2013-04-11) +------------------ + + * removed usage of the native QP encoder when the charset is not UTF-8 + * fixed usage of uniqid to avoid collisions + * made a performance improvement when tokenizing large headers + * fixed usage of the PHP native QP encoder on PHP 5.4.7+ + +4.3.0 (2013-01-08) +------------------ + + * made the temporary directory configurable via the TMPDIR env variable + * added S/MIME signer and encryption support + +4.2.2 (2012-10-25) +------------------ + + * added the possibility to throttle messages per second in ThrottlerPlugin (mostly for Amazon SES) + * switched mime.qpcontentencoder to automatically use the PHP native encoder on PHP 5.4.7+ + * allowed specifying a whitelist with regular expressions in RedirectingPlugin + +4.2.1 (2012-07-13) +------------------ + + * changed the coding standards to PSR-1/2 + * fixed issue with autoloading + * added NativeQpContentEncoder to enhance performance (for PHP 5.3+) + +4.2.0 (2012-06-29) +------------------ + + * added documentation about how to use the Japanese support introduced in 4.1.8 + * added a way to override the default configuration in a lazy way + * changed the PEAR init script to lazy-load the initialization + * fixed a bug when calling Swift_Preferences before anything else (regression introduced in 4.1.8) + +4.1.8 (2012-06-17) +------------------ + + * added Japanese iso-2022-jp support + * changed the init script to lazy-load the initialization + * fixed docblocks (@id) which caused some problems with libraries parsing the dobclocks + * fixed Swift_Mime_Headers_IdentificationHeader::setId() when passed an array of ids + * fixed encoding of email addresses in headers + * added replacements setter to the Decorator plugin + +4.1.7 (2012-04-26) +------------------ + + * fixed QpEncoder safeMapShareId property + +4.1.6 (2012-03-23) +------------------ + + * reduced the size of serialized Messages + +4.1.5 (2012-01-04) +------------------ + + * enforced Swift_Spool::queueMessage() to return a Boolean + * made an optimization to the memory spool: start the transport only when required + * prevented stream_socket_client() from generating an error and throw a Swift_TransportException instead + * fixed a PHP warning when calling to mail() when safe_mode is off + * many doc tweaks + +4.1.4 (2011-12-16) +------------------ + + * added a memory spool (Swift_MemorySpool) + * fixed too many opened files when sending emails with attachments + +4.1.3 (2011-10-27) +------------------ + + * added STARTTLS support + * added missing @return tags on fluent methods + * added a MessageLogger plugin that logs all sent messages + * added composer.json + +4.1.2 (2011-09-13) +------------------ + + * fixed wrong detection of magic_quotes_runtime + * fixed fatal errors when no To or Subject header has been set + * fixed charset on parameter header continuations + * added documentation about how to install Swiftmailer from the PEAR channel + * fixed various typos and markup problem in the documentation + * fixed warning when cache directory does not exist + * fixed "slashes are escaped" bug + * changed require_once() to require() in autoload + +4.1.1 (2011-07-04) +------------------ + + * added missing file in PEAR package + +4.1.0 (2011-06-30) +------------------ + + * documentation has been converted to ReST + +4.1.0 RC1 (2011-06-17) +---------------------- + +New features: + + * changed the Decorator Plugin to allow replacements in all headers + * added Swift_Mime_Grammar and Swift_Validate to validate an email address + * modified the autoloader to lazy-initialize Swiftmailer + * removed Swift_Mailer::batchSend() + * added NullTransport + * added new plugins: RedirectingPlugin and ImpersonatePlugin + * added a way to send messages asynchronously (Spool) diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/LICENSE b/user/plugins/email/vendor/swiftmailer/swiftmailer/LICENSE new file mode 100644 index 0000000..485f1d6 --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2013-2016 Fabien Potencier + +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/email/vendor/swiftmailer/swiftmailer/README b/user/plugins/email/vendor/swiftmailer/swiftmailer/README new file mode 100644 index 0000000..c3bf031 --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/README @@ -0,0 +1,15 @@ +Swift Mailer +------------ + +Swift Mailer is a component based mailing solution for PHP 5. +It is released under the MIT license. + +Homepage: http://swiftmailer.org +Documentation: http://swiftmailer.org/docs +Bugs: https://github.com/swiftmailer/swiftmailer/issues +Repository: https://github.com/swiftmailer/swiftmailer + +Swift Mailer is highly object-oriented by design and lends itself +to use in complex web application with a great deal of flexibility. + +For full details on usage, see the documentation. diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/VERSION b/user/plugins/email/vendor/swiftmailer/swiftmailer/VERSION new file mode 100644 index 0000000..6434642 --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/VERSION @@ -0,0 +1 @@ +Swift-5.4.8 diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/composer.json b/user/plugins/email/vendor/swiftmailer/swiftmailer/composer.json new file mode 100644 index 0000000..8335f58 --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/composer.json @@ -0,0 +1,37 @@ +{ + "name": "swiftmailer/swiftmailer", + "type": "library", + "description": "Swiftmailer, free feature-rich PHP mailer", + "keywords": ["mail","mailer","email"], + "homepage": "http://swiftmailer.org", + "license": "MIT", + "authors": [ + { + "name": "Chris Corbyn" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "mockery/mockery": "~0.9.1", + "symfony/phpunit-bridge": "~3.2" + }, + "autoload": { + "files": ["lib/swift_required.php"] + }, + "autoload-dev": { + "psr-0": { + "Swift_": "tests/unit" + } + }, + "extra": { + "branch-alias": { + "dev-master": "5.4-dev" + } + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift.php new file mode 100644 index 0000000..82c381b --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift.php @@ -0,0 +1,80 @@ +createDependenciesFor('mime.attachment') + ); + + $this->setBody($data); + $this->setFilename($filename); + if ($contentType) { + $this->setContentType($contentType); + } + } + + /** + * Create a new Attachment. + * + * @param string|Swift_OutputByteStream $data + * @param string $filename + * @param string $contentType + * + * @return Swift_Mime_Attachment + */ + public static function newInstance($data = null, $filename = null, $contentType = null) + { + return new self($data, $filename, $contentType); + } + + /** + * Create a new Attachment from a filesystem path. + * + * @param string $path + * @param string $contentType optional + * + * @return Swift_Mime_Attachment + */ + public static function fromPath($path, $contentType = null) + { + return self::newInstance()->setFile( + new Swift_ByteStream_FileByteStream($path), + $contentType + ); + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ByteStream/AbstractFilterableInputStream.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ByteStream/AbstractFilterableInputStream.php new file mode 100644 index 0000000..a7b0e3a --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ByteStream/AbstractFilterableInputStream.php @@ -0,0 +1,181 @@ +_filters[$key] = $filter; + } + + /** + * Remove an already present StreamFilter based on its $key. + * + * @param string $key + */ + public function removeFilter($key) + { + unset($this->_filters[$key]); + } + + /** + * Writes $bytes to the end of the stream. + * + * @param string $bytes + * + * @throws Swift_IoException + * + * @return int + */ + public function write($bytes) + { + $this->_writeBuffer .= $bytes; + foreach ($this->_filters as $filter) { + if ($filter->shouldBuffer($this->_writeBuffer)) { + return; + } + } + $this->_doWrite($this->_writeBuffer); + + return ++$this->_sequence; + } + + /** + * For any bytes that are currently buffered inside the stream, force them + * off the buffer. + * + * @throws Swift_IoException + */ + public function commit() + { + $this->_doWrite($this->_writeBuffer); + } + + /** + * Attach $is to this stream. + * + * The stream acts as an observer, receiving all data that is written. + * All {@link write()} and {@link flushBuffers()} operations will be mirrored. + * + * @param Swift_InputByteStream $is + */ + public function bind(Swift_InputByteStream $is) + { + $this->_mirrors[] = $is; + } + + /** + * Remove an already bound stream. + * + * If $is is not bound, no errors will be raised. + * If the stream currently has any buffered data it will be written to $is + * before unbinding occurs. + * + * @param Swift_InputByteStream $is + */ + public function unbind(Swift_InputByteStream $is) + { + foreach ($this->_mirrors as $k => $stream) { + if ($is === $stream) { + if ($this->_writeBuffer !== '') { + $stream->write($this->_writeBuffer); + } + unset($this->_mirrors[$k]); + } + } + } + + /** + * Flush the contents of the stream (empty it) and set the internal pointer + * to the beginning. + * + * @throws Swift_IoException + */ + public function flushBuffers() + { + if ($this->_writeBuffer !== '') { + $this->_doWrite($this->_writeBuffer); + } + $this->_flush(); + + foreach ($this->_mirrors as $stream) { + $stream->flushBuffers(); + } + } + + /** Run $bytes through all filters */ + private function _filter($bytes) + { + foreach ($this->_filters as $filter) { + $bytes = $filter->filter($bytes); + } + + return $bytes; + } + + /** Just write the bytes to the stream */ + private function _doWrite($bytes) + { + $this->_commit($this->_filter($bytes)); + + foreach ($this->_mirrors as $stream) { + $stream->write($bytes); + } + + $this->_writeBuffer = ''; + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ByteStream/ArrayByteStream.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ByteStream/ArrayByteStream.php new file mode 100644 index 0000000..ef05a6d --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ByteStream/ArrayByteStream.php @@ -0,0 +1,182 @@ +_array = $stack; + $this->_arraySize = count($stack); + } elseif (is_string($stack)) { + $this->write($stack); + } else { + $this->_array = array(); + } + } + + /** + * Reads $length bytes from the stream into a string and moves the pointer + * through the stream by $length. + * + * If less bytes exist than are requested the + * remaining bytes are given instead. If no bytes are remaining at all, boolean + * false is returned. + * + * @param int $length + * + * @return string + */ + public function read($length) + { + if ($this->_offset == $this->_arraySize) { + return false; + } + + // Don't use array slice + $end = $length + $this->_offset; + $end = $this->_arraySize < $end ? $this->_arraySize : $end; + $ret = ''; + for (; $this->_offset < $end; ++$this->_offset) { + $ret .= $this->_array[$this->_offset]; + } + + return $ret; + } + + /** + * Writes $bytes to the end of the stream. + * + * @param string $bytes + */ + public function write($bytes) + { + $to_add = str_split($bytes); + foreach ($to_add as $value) { + $this->_array[] = $value; + } + $this->_arraySize = count($this->_array); + + foreach ($this->_mirrors as $stream) { + $stream->write($bytes); + } + } + + /** + * Not used. + */ + public function commit() + { + } + + /** + * Attach $is to this stream. + * + * The stream acts as an observer, receiving all data that is written. + * All {@link write()} and {@link flushBuffers()} operations will be mirrored. + * + * @param Swift_InputByteStream $is + */ + public function bind(Swift_InputByteStream $is) + { + $this->_mirrors[] = $is; + } + + /** + * Remove an already bound stream. + * + * If $is is not bound, no errors will be raised. + * If the stream currently has any buffered data it will be written to $is + * before unbinding occurs. + * + * @param Swift_InputByteStream $is + */ + public function unbind(Swift_InputByteStream $is) + { + foreach ($this->_mirrors as $k => $stream) { + if ($is === $stream) { + unset($this->_mirrors[$k]); + } + } + } + + /** + * Move the internal read pointer to $byteOffset in the stream. + * + * @param int $byteOffset + * + * @return bool + */ + public function setReadPointer($byteOffset) + { + if ($byteOffset > $this->_arraySize) { + $byteOffset = $this->_arraySize; + } elseif ($byteOffset < 0) { + $byteOffset = 0; + } + + $this->_offset = $byteOffset; + } + + /** + * Flush the contents of the stream (empty it) and set the internal pointer + * to the beginning. + */ + public function flushBuffers() + { + $this->_offset = 0; + $this->_array = array(); + $this->_arraySize = 0; + + foreach ($this->_mirrors as $stream) { + $stream->flushBuffers(); + } + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ByteStream/FileByteStream.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ByteStream/FileByteStream.php new file mode 100644 index 0000000..9ed8523 --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ByteStream/FileByteStream.php @@ -0,0 +1,231 @@ +_path = $path; + $this->_mode = $writable ? 'w+b' : 'rb'; + + if (function_exists('get_magic_quotes_runtime') && @get_magic_quotes_runtime() == 1) { + $this->_quotes = true; + } + } + + /** + * Get the complete path to the file. + * + * @return string + */ + public function getPath() + { + return $this->_path; + } + + /** + * Reads $length bytes from the stream into a string and moves the pointer + * through the stream by $length. + * + * If less bytes exist than are requested the + * remaining bytes are given instead. If no bytes are remaining at all, boolean + * false is returned. + * + * @param int $length + * + * @throws Swift_IoException + * + * @return string|bool + */ + public function read($length) + { + $fp = $this->_getReadHandle(); + if (!feof($fp)) { + if ($this->_quotes) { + ini_set('magic_quotes_runtime', 0); + } + $bytes = fread($fp, $length); + if ($this->_quotes) { + ini_set('magic_quotes_runtime', 1); + } + $this->_offset = ftell($fp); + + // If we read one byte after reaching the end of the file + // feof() will return false and an empty string is returned + if ($bytes === '' && feof($fp)) { + $this->_resetReadHandle(); + + return false; + } + + return $bytes; + } + + $this->_resetReadHandle(); + + return false; + } + + /** + * Move the internal read pointer to $byteOffset in the stream. + * + * @param int $byteOffset + * + * @return bool + */ + public function setReadPointer($byteOffset) + { + if (isset($this->_reader)) { + $this->_seekReadStreamToPosition($byteOffset); + } + $this->_offset = $byteOffset; + } + + /** Just write the bytes to the file */ + protected function _commit($bytes) + { + fwrite($this->_getWriteHandle(), $bytes); + $this->_resetReadHandle(); + } + + /** Not used */ + protected function _flush() + { + } + + /** Get the resource for reading */ + private function _getReadHandle() + { + if (!isset($this->_reader)) { + $pointer = @fopen($this->_path, 'rb'); + if (!$pointer) { + throw new Swift_IoException( + 'Unable to open file for reading ['.$this->_path.']' + ); + } + $this->_reader = $pointer; + if ($this->_offset != 0) { + $this->_getReadStreamSeekableStatus(); + $this->_seekReadStreamToPosition($this->_offset); + } + } + + return $this->_reader; + } + + /** Get the resource for writing */ + private function _getWriteHandle() + { + if (!isset($this->_writer)) { + if (!$this->_writer = fopen($this->_path, $this->_mode)) { + throw new Swift_IoException( + 'Unable to open file for writing ['.$this->_path.']' + ); + } + } + + return $this->_writer; + } + + /** Force a reload of the resource for reading */ + private function _resetReadHandle() + { + if (isset($this->_reader)) { + fclose($this->_reader); + $this->_reader = null; + } + } + + /** Check if ReadOnly Stream is seekable */ + private function _getReadStreamSeekableStatus() + { + $metas = stream_get_meta_data($this->_reader); + $this->_seekable = $metas['seekable']; + } + + /** Streams in a readOnly stream ensuring copy if needed */ + private function _seekReadStreamToPosition($offset) + { + if ($this->_seekable === null) { + $this->_getReadStreamSeekableStatus(); + } + if ($this->_seekable === false) { + $currentPos = ftell($this->_reader); + if ($currentPos < $offset) { + $toDiscard = $offset - $currentPos; + fread($this->_reader, $toDiscard); + + return; + } + $this->_copyReadStream(); + } + fseek($this->_reader, $offset, SEEK_SET); + } + + /** Copy a readOnly Stream to ensure seekability */ + private function _copyReadStream() + { + if ($tmpFile = fopen('php://temp/maxmemory:4096', 'w+b')) { + /* We have opened a php:// Stream Should work without problem */ + } elseif (function_exists('sys_get_temp_dir') && is_writable(sys_get_temp_dir()) && ($tmpFile = tmpfile())) { + /* We have opened a tmpfile */ + } else { + throw new Swift_IoException('Unable to copy the file to make it seekable, sys_temp_dir is not writable, php://memory not available'); + } + $currentPos = ftell($this->_reader); + fclose($this->_reader); + $source = fopen($this->_path, 'rb'); + if (!$source) { + throw new Swift_IoException('Unable to open file for copying ['.$this->_path.']'); + } + fseek($tmpFile, 0, SEEK_SET); + while (!feof($source)) { + fwrite($tmpFile, fread($source, 4096)); + } + fseek($tmpFile, $currentPos, SEEK_SET); + fclose($source); + $this->_reader = $tmpFile; + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ByteStream/TemporaryFileByteStream.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ByteStream/TemporaryFileByteStream.php new file mode 100644 index 0000000..1c9a80c --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ByteStream/TemporaryFileByteStream.php @@ -0,0 +1,42 @@ +getPath())) === false) { + throw new Swift_IoException('Failed to get temporary file content.'); + } + + return $content; + } + + public function __destruct() + { + if (file_exists($this->getPath())) { + @unlink($this->getPath()); + } + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterReader.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterReader.php new file mode 100644 index 0000000..4267adb --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterReader.php @@ -0,0 +1,67 @@ + + */ +interface Swift_CharacterReader +{ + const MAP_TYPE_INVALID = 0x01; + const MAP_TYPE_FIXED_LEN = 0x02; + const MAP_TYPE_POSITIONS = 0x03; + + /** + * Returns the complete character map. + * + * @param string $string + * @param int $startOffset + * @param array $currentMap + * @param mixed $ignoredChars + * + * @return int + */ + public function getCharPositions($string, $startOffset, &$currentMap, &$ignoredChars); + + /** + * Returns the mapType, see constants. + * + * @return int + */ + public function getMapType(); + + /** + * Returns an integer which specifies how many more bytes to read. + * + * A positive integer indicates the number of more bytes to fetch before invoking + * this method again. + * + * A value of zero means this is already a valid character. + * A value of -1 means this cannot possibly be a valid character. + * + * @param int[] $bytes + * @param int $size + * + * @return int + */ + public function validateByteSequence($bytes, $size); + + /** + * Returns the number of bytes which should be read to start each character. + * + * For fixed width character sets this should be the number of octets-per-character. + * For multibyte character sets this will probably be 1. + * + * @return int + */ + public function getInitialByteSize(); +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterReader/GenericFixedWidthReader.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterReader/GenericFixedWidthReader.php new file mode 100644 index 0000000..6a18e1d --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterReader/GenericFixedWidthReader.php @@ -0,0 +1,97 @@ + + */ +class Swift_CharacterReader_GenericFixedWidthReader implements Swift_CharacterReader +{ + /** + * The number of bytes in a single character. + * + * @var int + */ + private $_width; + + /** + * Creates a new GenericFixedWidthReader using $width bytes per character. + * + * @param int $width + */ + public function __construct($width) + { + $this->_width = $width; + } + + /** + * Returns the complete character map. + * + * @param string $string + * @param int $startOffset + * @param array $currentMap + * @param mixed $ignoredChars + * + * @return int + */ + public function getCharPositions($string, $startOffset, &$currentMap, &$ignoredChars) + { + $strlen = strlen($string); + // % and / are CPU intensive, so, maybe find a better way + $ignored = $strlen % $this->_width; + $ignoredChars = $ignored ? substr($string, -$ignored) : ''; + $currentMap = $this->_width; + + return ($strlen - $ignored) / $this->_width; + } + + /** + * Returns the mapType. + * + * @return int + */ + public function getMapType() + { + return self::MAP_TYPE_FIXED_LEN; + } + + /** + * Returns an integer which specifies how many more bytes to read. + * + * A positive integer indicates the number of more bytes to fetch before invoking + * this method again. + * + * A value of zero means this is already a valid character. + * A value of -1 means this cannot possibly be a valid character. + * + * @param string $bytes + * @param int $size + * + * @return int + */ + public function validateByteSequence($bytes, $size) + { + $needed = $this->_width - $size; + + return $needed > -1 ? $needed : -1; + } + + /** + * Returns the number of bytes which should be read to start each character. + * + * @return int + */ + public function getInitialByteSize() + { + return $this->_width; + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterReader/UsAsciiReader.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterReader/UsAsciiReader.php new file mode 100644 index 0000000..67da48f --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterReader/UsAsciiReader.php @@ -0,0 +1,84 @@ + "\x07F") { + // Invalid char + $currentMap[$i + $startOffset] = $string[$i]; + } + } + + return $strlen; + } + + /** + * Returns mapType. + * + * @return int mapType + */ + public function getMapType() + { + return self::MAP_TYPE_INVALID; + } + + /** + * Returns an integer which specifies how many more bytes to read. + * + * A positive integer indicates the number of more bytes to fetch before invoking + * this method again. + * A value of zero means this is already a valid character. + * A value of -1 means this cannot possibly be a valid character. + * + * @param string $bytes + * @param int $size + * + * @return int + */ + public function validateByteSequence($bytes, $size) + { + $byte = reset($bytes); + if (1 == count($bytes) && $byte >= 0x00 && $byte <= 0x7F) { + return 0; + } + + return -1; + } + + /** + * Returns the number of bytes which should be read to start each character. + * + * @return int + */ + public function getInitialByteSize() + { + return 1; + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterReader/Utf8Reader.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterReader/Utf8Reader.php new file mode 100644 index 0000000..22746bd --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterReader/Utf8Reader.php @@ -0,0 +1,176 @@ + + */ +class Swift_CharacterReader_Utf8Reader implements Swift_CharacterReader +{ + /** Pre-computed for optimization */ + private static $length_map = array( + // N=0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x0N + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x1N + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x2N + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x3N + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x4N + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x5N + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x6N + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x7N + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x8N + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x9N + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xAN + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xBN + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xCN + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xDN + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 0xEN + 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 0, 0, // 0xFN + ); + + private static $s_length_map = array( + "\x00" => 1, "\x01" => 1, "\x02" => 1, "\x03" => 1, "\x04" => 1, "\x05" => 1, "\x06" => 1, "\x07" => 1, + "\x08" => 1, "\x09" => 1, "\x0a" => 1, "\x0b" => 1, "\x0c" => 1, "\x0d" => 1, "\x0e" => 1, "\x0f" => 1, + "\x10" => 1, "\x11" => 1, "\x12" => 1, "\x13" => 1, "\x14" => 1, "\x15" => 1, "\x16" => 1, "\x17" => 1, + "\x18" => 1, "\x19" => 1, "\x1a" => 1, "\x1b" => 1, "\x1c" => 1, "\x1d" => 1, "\x1e" => 1, "\x1f" => 1, + "\x20" => 1, "\x21" => 1, "\x22" => 1, "\x23" => 1, "\x24" => 1, "\x25" => 1, "\x26" => 1, "\x27" => 1, + "\x28" => 1, "\x29" => 1, "\x2a" => 1, "\x2b" => 1, "\x2c" => 1, "\x2d" => 1, "\x2e" => 1, "\x2f" => 1, + "\x30" => 1, "\x31" => 1, "\x32" => 1, "\x33" => 1, "\x34" => 1, "\x35" => 1, "\x36" => 1, "\x37" => 1, + "\x38" => 1, "\x39" => 1, "\x3a" => 1, "\x3b" => 1, "\x3c" => 1, "\x3d" => 1, "\x3e" => 1, "\x3f" => 1, + "\x40" => 1, "\x41" => 1, "\x42" => 1, "\x43" => 1, "\x44" => 1, "\x45" => 1, "\x46" => 1, "\x47" => 1, + "\x48" => 1, "\x49" => 1, "\x4a" => 1, "\x4b" => 1, "\x4c" => 1, "\x4d" => 1, "\x4e" => 1, "\x4f" => 1, + "\x50" => 1, "\x51" => 1, "\x52" => 1, "\x53" => 1, "\x54" => 1, "\x55" => 1, "\x56" => 1, "\x57" => 1, + "\x58" => 1, "\x59" => 1, "\x5a" => 1, "\x5b" => 1, "\x5c" => 1, "\x5d" => 1, "\x5e" => 1, "\x5f" => 1, + "\x60" => 1, "\x61" => 1, "\x62" => 1, "\x63" => 1, "\x64" => 1, "\x65" => 1, "\x66" => 1, "\x67" => 1, + "\x68" => 1, "\x69" => 1, "\x6a" => 1, "\x6b" => 1, "\x6c" => 1, "\x6d" => 1, "\x6e" => 1, "\x6f" => 1, + "\x70" => 1, "\x71" => 1, "\x72" => 1, "\x73" => 1, "\x74" => 1, "\x75" => 1, "\x76" => 1, "\x77" => 1, + "\x78" => 1, "\x79" => 1, "\x7a" => 1, "\x7b" => 1, "\x7c" => 1, "\x7d" => 1, "\x7e" => 1, "\x7f" => 1, + "\x80" => 0, "\x81" => 0, "\x82" => 0, "\x83" => 0, "\x84" => 0, "\x85" => 0, "\x86" => 0, "\x87" => 0, + "\x88" => 0, "\x89" => 0, "\x8a" => 0, "\x8b" => 0, "\x8c" => 0, "\x8d" => 0, "\x8e" => 0, "\x8f" => 0, + "\x90" => 0, "\x91" => 0, "\x92" => 0, "\x93" => 0, "\x94" => 0, "\x95" => 0, "\x96" => 0, "\x97" => 0, + "\x98" => 0, "\x99" => 0, "\x9a" => 0, "\x9b" => 0, "\x9c" => 0, "\x9d" => 0, "\x9e" => 0, "\x9f" => 0, + "\xa0" => 0, "\xa1" => 0, "\xa2" => 0, "\xa3" => 0, "\xa4" => 0, "\xa5" => 0, "\xa6" => 0, "\xa7" => 0, + "\xa8" => 0, "\xa9" => 0, "\xaa" => 0, "\xab" => 0, "\xac" => 0, "\xad" => 0, "\xae" => 0, "\xaf" => 0, + "\xb0" => 0, "\xb1" => 0, "\xb2" => 0, "\xb3" => 0, "\xb4" => 0, "\xb5" => 0, "\xb6" => 0, "\xb7" => 0, + "\xb8" => 0, "\xb9" => 0, "\xba" => 0, "\xbb" => 0, "\xbc" => 0, "\xbd" => 0, "\xbe" => 0, "\xbf" => 0, + "\xc0" => 2, "\xc1" => 2, "\xc2" => 2, "\xc3" => 2, "\xc4" => 2, "\xc5" => 2, "\xc6" => 2, "\xc7" => 2, + "\xc8" => 2, "\xc9" => 2, "\xca" => 2, "\xcb" => 2, "\xcc" => 2, "\xcd" => 2, "\xce" => 2, "\xcf" => 2, + "\xd0" => 2, "\xd1" => 2, "\xd2" => 2, "\xd3" => 2, "\xd4" => 2, "\xd5" => 2, "\xd6" => 2, "\xd7" => 2, + "\xd8" => 2, "\xd9" => 2, "\xda" => 2, "\xdb" => 2, "\xdc" => 2, "\xdd" => 2, "\xde" => 2, "\xdf" => 2, + "\xe0" => 3, "\xe1" => 3, "\xe2" => 3, "\xe3" => 3, "\xe4" => 3, "\xe5" => 3, "\xe6" => 3, "\xe7" => 3, + "\xe8" => 3, "\xe9" => 3, "\xea" => 3, "\xeb" => 3, "\xec" => 3, "\xed" => 3, "\xee" => 3, "\xef" => 3, + "\xf0" => 4, "\xf1" => 4, "\xf2" => 4, "\xf3" => 4, "\xf4" => 4, "\xf5" => 4, "\xf6" => 4, "\xf7" => 4, + "\xf8" => 5, "\xf9" => 5, "\xfa" => 5, "\xfb" => 5, "\xfc" => 6, "\xfd" => 6, "\xfe" => 0, "\xff" => 0, + ); + + /** + * Returns the complete character map. + * + * @param string $string + * @param int $startOffset + * @param array $currentMap + * @param mixed $ignoredChars + * + * @return int + */ + public function getCharPositions($string, $startOffset, &$currentMap, &$ignoredChars) + { + if (!isset($currentMap['i']) || !isset($currentMap['p'])) { + $currentMap['p'] = $currentMap['i'] = array(); + } + + $strlen = strlen($string); + $charPos = count($currentMap['p']); + $foundChars = 0; + $invalid = false; + for ($i = 0; $i < $strlen; ++$i) { + $char = $string[$i]; + $size = self::$s_length_map[$char]; + if ($size == 0) { + /* char is invalid, we must wait for a resync */ + $invalid = true; + continue; + } else { + if ($invalid == true) { + /* We mark the chars as invalid and start a new char */ + $currentMap['p'][$charPos + $foundChars] = $startOffset + $i; + $currentMap['i'][$charPos + $foundChars] = true; + ++$foundChars; + $invalid = false; + } + if (($i + $size) > $strlen) { + $ignoredChars = substr($string, $i); + break; + } + for ($j = 1; $j < $size; ++$j) { + $char = $string[$i + $j]; + if ($char > "\x7F" && $char < "\xC0") { + // Valid - continue parsing + } else { + /* char is invalid, we must wait for a resync */ + $invalid = true; + continue 2; + } + } + /* Ok we got a complete char here */ + $currentMap['p'][$charPos + $foundChars] = $startOffset + $i + $size; + $i += $j - 1; + ++$foundChars; + } + } + + return $foundChars; + } + + /** + * Returns mapType. + * + * @return int mapType + */ + public function getMapType() + { + return self::MAP_TYPE_POSITIONS; + } + + /** + * Returns an integer which specifies how many more bytes to read. + * + * A positive integer indicates the number of more bytes to fetch before invoking + * this method again. + * A value of zero means this is already a valid character. + * A value of -1 means this cannot possibly be a valid character. + * + * @param string $bytes + * @param int $size + * + * @return int + */ + public function validateByteSequence($bytes, $size) + { + if ($size < 1) { + return -1; + } + $needed = self::$length_map[$bytes[0]] - $size; + + return $needed > -1 ? $needed : -1; + } + + /** + * Returns the number of bytes which should be read to start each character. + * + * @return int + */ + public function getInitialByteSize() + { + return 1; + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterReaderFactory.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterReaderFactory.php new file mode 100644 index 0000000..15b6c69 --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterReaderFactory.php @@ -0,0 +1,26 @@ +init(); + } + + public function __wakeup() + { + $this->init(); + } + + public function init() + { + if (count(self::$_map) > 0) { + return; + } + + $prefix = 'Swift_CharacterReader_'; + + $singleByte = array( + 'class' => $prefix.'GenericFixedWidthReader', + 'constructor' => array(1), + ); + + $doubleByte = array( + 'class' => $prefix.'GenericFixedWidthReader', + 'constructor' => array(2), + ); + + $fourBytes = array( + 'class' => $prefix.'GenericFixedWidthReader', + 'constructor' => array(4), + ); + + // Utf-8 + self::$_map['utf-?8'] = array( + 'class' => $prefix.'Utf8Reader', + 'constructor' => array(), + ); + + //7-8 bit charsets + self::$_map['(us-)?ascii'] = $singleByte; + self::$_map['(iso|iec)-?8859-?[0-9]+'] = $singleByte; + self::$_map['windows-?125[0-9]'] = $singleByte; + self::$_map['cp-?[0-9]+'] = $singleByte; + self::$_map['ansi'] = $singleByte; + self::$_map['macintosh'] = $singleByte; + self::$_map['koi-?7'] = $singleByte; + self::$_map['koi-?8-?.+'] = $singleByte; + self::$_map['mik'] = $singleByte; + self::$_map['(cork|t1)'] = $singleByte; + self::$_map['v?iscii'] = $singleByte; + + //16 bits + self::$_map['(ucs-?2|utf-?16)'] = $doubleByte; + + //32 bits + self::$_map['(ucs-?4|utf-?32)'] = $fourBytes; + + // Fallback + self::$_map['.*'] = $singleByte; + } + + /** + * Returns a CharacterReader suitable for the charset applied. + * + * @param string $charset + * + * @return Swift_CharacterReader + */ + public function getReaderFor($charset) + { + $charset = trim(strtolower($charset)); + foreach (self::$_map as $pattern => $spec) { + $re = '/^'.$pattern.'$/D'; + if (preg_match($re, $charset)) { + if (!array_key_exists($pattern, self::$_loaded)) { + $reflector = new ReflectionClass($spec['class']); + if ($reflector->getConstructor()) { + $reader = $reflector->newInstanceArgs($spec['constructor']); + } else { + $reader = $reflector->newInstance(); + } + self::$_loaded[$pattern] = $reader; + } + + return self::$_loaded[$pattern]; + } + } + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterStream.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterStream.php new file mode 100644 index 0000000..717924f --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterStream.php @@ -0,0 +1,89 @@ +setCharacterReaderFactory($factory); + $this->setCharacterSet($charset); + } + + /** + * Set the character set used in this CharacterStream. + * + * @param string $charset + */ + public function setCharacterSet($charset) + { + $this->_charset = $charset; + $this->_charReader = null; + } + + /** + * Set the CharacterReaderFactory for multi charset support. + * + * @param Swift_CharacterReaderFactory $factory + */ + public function setCharacterReaderFactory(Swift_CharacterReaderFactory $factory) + { + $this->_charReaderFactory = $factory; + } + + /** + * Overwrite this character stream using the byte sequence in the byte stream. + * + * @param Swift_OutputByteStream $os output stream to read from + */ + public function importByteStream(Swift_OutputByteStream $os) + { + if (!isset($this->_charReader)) { + $this->_charReader = $this->_charReaderFactory + ->getReaderFor($this->_charset); + } + + $startLength = $this->_charReader->getInitialByteSize(); + while (false !== $bytes = $os->read($startLength)) { + $c = array(); + for ($i = 0, $len = strlen($bytes); $i < $len; ++$i) { + $c[] = self::$_byteMap[$bytes[$i]]; + } + $size = count($c); + $need = $this->_charReader + ->validateByteSequence($c, $size); + if ($need > 0 && + false !== $bytes = $os->read($need)) { + for ($i = 0, $len = strlen($bytes); $i < $len; ++$i) { + $c[] = self::$_byteMap[$bytes[$i]]; + } + } + $this->_array[] = $c; + ++$this->_array_size; + } + } + + /** + * Import a string a bytes into this CharacterStream, overwriting any existing + * data in the stream. + * + * @param string $string + */ + public function importString($string) + { + $this->flushContents(); + $this->write($string); + } + + /** + * Read $length characters from the stream and move the internal pointer + * $length further into the stream. + * + * @param int $length + * + * @return string + */ + public function read($length) + { + if ($this->_offset == $this->_array_size) { + return false; + } + + // Don't use array slice + $arrays = array(); + $end = $length + $this->_offset; + for ($i = $this->_offset; $i < $end; ++$i) { + if (!isset($this->_array[$i])) { + break; + } + $arrays[] = $this->_array[$i]; + } + $this->_offset += $i - $this->_offset; // Limit function calls + $chars = false; + foreach ($arrays as $array) { + $chars .= implode('', array_map('chr', $array)); + } + + return $chars; + } + + /** + * Read $length characters from the stream and return a 1-dimensional array + * containing there octet values. + * + * @param int $length + * + * @return int[] + */ + public function readBytes($length) + { + if ($this->_offset == $this->_array_size) { + return false; + } + $arrays = array(); + $end = $length + $this->_offset; + for ($i = $this->_offset; $i < $end; ++$i) { + if (!isset($this->_array[$i])) { + break; + } + $arrays[] = $this->_array[$i]; + } + $this->_offset += ($i - $this->_offset); // Limit function calls + + return call_user_func_array('array_merge', $arrays); + } + + /** + * Write $chars to the end of the stream. + * + * @param string $chars + */ + public function write($chars) + { + if (!isset($this->_charReader)) { + $this->_charReader = $this->_charReaderFactory->getReaderFor( + $this->_charset); + } + + $startLength = $this->_charReader->getInitialByteSize(); + + $fp = fopen('php://memory', 'w+b'); + fwrite($fp, $chars); + unset($chars); + fseek($fp, 0, SEEK_SET); + + $buffer = array(0); + $buf_pos = 1; + $buf_len = 1; + $has_datas = true; + do { + $bytes = array(); + // Buffer Filing + if ($buf_len - $buf_pos < $startLength) { + $buf = array_splice($buffer, $buf_pos); + $new = $this->_reloadBuffer($fp, 100); + if ($new) { + $buffer = array_merge($buf, $new); + $buf_len = count($buffer); + $buf_pos = 0; + } else { + $has_datas = false; + } + } + if ($buf_len - $buf_pos > 0) { + $size = 0; + for ($i = 0; $i < $startLength && isset($buffer[$buf_pos]); ++$i) { + ++$size; + $bytes[] = $buffer[$buf_pos++]; + } + $need = $this->_charReader->validateByteSequence( + $bytes, $size); + if ($need > 0) { + if ($buf_len - $buf_pos < $need) { + $new = $this->_reloadBuffer($fp, $need); + + if ($new) { + $buffer = array_merge($buffer, $new); + $buf_len = count($buffer); + } + } + for ($i = 0; $i < $need && isset($buffer[$buf_pos]); ++$i) { + $bytes[] = $buffer[$buf_pos++]; + } + } + $this->_array[] = $bytes; + ++$this->_array_size; + } + } while ($has_datas); + + fclose($fp); + } + + /** + * Move the internal pointer to $charOffset in the stream. + * + * @param int $charOffset + */ + public function setPointer($charOffset) + { + if ($charOffset > $this->_array_size) { + $charOffset = $this->_array_size; + } elseif ($charOffset < 0) { + $charOffset = 0; + } + $this->_offset = $charOffset; + } + + /** + * Empty the stream and reset the internal pointer. + */ + public function flushContents() + { + $this->_offset = 0; + $this->_array = array(); + $this->_array_size = 0; + } + + private function _reloadBuffer($fp, $len) + { + if (!feof($fp) && ($bytes = fread($fp, $len)) !== false) { + $buf = array(); + for ($i = 0, $len = strlen($bytes); $i < $len; ++$i) { + $buf[] = self::$_byteMap[$bytes[$i]]; + } + + return $buf; + } + + return false; + } + + private static function _initializeMaps() + { + if (!isset(self::$_charMap)) { + self::$_charMap = array(); + for ($byte = 0; $byte < 256; ++$byte) { + self::$_charMap[$byte] = chr($byte); + } + self::$_byteMap = array_flip(self::$_charMap); + } + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterStream/NgCharacterStream.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterStream/NgCharacterStream.php new file mode 100644 index 0000000..58bd140 --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterStream/NgCharacterStream.php @@ -0,0 +1,267 @@ + + */ +class Swift_CharacterStream_NgCharacterStream implements Swift_CharacterStream +{ + /** + * The char reader (lazy-loaded) for the current charset. + * + * @var Swift_CharacterReader + */ + private $_charReader; + + /** + * A factory for creating CharacterReader instances. + * + * @var Swift_CharacterReaderFactory + */ + private $_charReaderFactory; + + /** + * The character set this stream is using. + * + * @var string + */ + private $_charset; + + /** + * The data's stored as-is. + * + * @var string + */ + private $_datas = ''; + + /** + * Number of bytes in the stream. + * + * @var int + */ + private $_datasSize = 0; + + /** + * Map. + * + * @var mixed + */ + private $_map; + + /** + * Map Type. + * + * @var int + */ + private $_mapType = 0; + + /** + * Number of characters in the stream. + * + * @var int + */ + private $_charCount = 0; + + /** + * Position in the stream. + * + * @var int + */ + private $_currentPos = 0; + + /** + * Constructor. + * + * @param Swift_CharacterReaderFactory $factory + * @param string $charset + */ + public function __construct(Swift_CharacterReaderFactory $factory, $charset) + { + $this->setCharacterReaderFactory($factory); + $this->setCharacterSet($charset); + } + + /* -- Changing parameters of the stream -- */ + + /** + * Set the character set used in this CharacterStream. + * + * @param string $charset + */ + public function setCharacterSet($charset) + { + $this->_charset = $charset; + $this->_charReader = null; + $this->_mapType = 0; + } + + /** + * Set the CharacterReaderFactory for multi charset support. + * + * @param Swift_CharacterReaderFactory $factory + */ + public function setCharacterReaderFactory(Swift_CharacterReaderFactory $factory) + { + $this->_charReaderFactory = $factory; + } + + /** + * @see Swift_CharacterStream::flushContents() + */ + public function flushContents() + { + $this->_datas = null; + $this->_map = null; + $this->_charCount = 0; + $this->_currentPos = 0; + $this->_datasSize = 0; + } + + /** + * @see Swift_CharacterStream::importByteStream() + * + * @param Swift_OutputByteStream $os + */ + public function importByteStream(Swift_OutputByteStream $os) + { + $this->flushContents(); + $blocks = 512; + $os->setReadPointer(0); + while (false !== ($read = $os->read($blocks))) { + $this->write($read); + } + } + + /** + * @see Swift_CharacterStream::importString() + * + * @param string $string + */ + public function importString($string) + { + $this->flushContents(); + $this->write($string); + } + + /** + * @see Swift_CharacterStream::read() + * + * @param int $length + * + * @return string + */ + public function read($length) + { + if ($this->_currentPos >= $this->_charCount) { + return false; + } + $ret = false; + $length = $this->_currentPos + $length > $this->_charCount ? $this->_charCount - $this->_currentPos : $length; + switch ($this->_mapType) { + case Swift_CharacterReader::MAP_TYPE_FIXED_LEN: + $len = $length * $this->_map; + $ret = substr($this->_datas, + $this->_currentPos * $this->_map, + $len); + $this->_currentPos += $length; + break; + + case Swift_CharacterReader::MAP_TYPE_INVALID: + $ret = ''; + for (; $this->_currentPos < $length; ++$this->_currentPos) { + if (isset($this->_map[$this->_currentPos])) { + $ret .= '?'; + } else { + $ret .= $this->_datas[$this->_currentPos]; + } + } + break; + + case Swift_CharacterReader::MAP_TYPE_POSITIONS: + $end = $this->_currentPos + $length; + $end = $end > $this->_charCount ? $this->_charCount : $end; + $ret = ''; + $start = 0; + if ($this->_currentPos > 0) { + $start = $this->_map['p'][$this->_currentPos - 1]; + } + $to = $start; + for (; $this->_currentPos < $end; ++$this->_currentPos) { + if (isset($this->_map['i'][$this->_currentPos])) { + $ret .= substr($this->_datas, $start, $to - $start).'?'; + $start = $this->_map['p'][$this->_currentPos]; + } else { + $to = $this->_map['p'][$this->_currentPos]; + } + } + $ret .= substr($this->_datas, $start, $to - $start); + break; + } + + return $ret; + } + + /** + * @see Swift_CharacterStream::readBytes() + * + * @param int $length + * + * @return int[] + */ + public function readBytes($length) + { + $read = $this->read($length); + if ($read !== false) { + $ret = array_map('ord', str_split($read, 1)); + + return $ret; + } + + return false; + } + + /** + * @see Swift_CharacterStream::setPointer() + * + * @param int $charOffset + */ + public function setPointer($charOffset) + { + if ($this->_charCount < $charOffset) { + $charOffset = $this->_charCount; + } + $this->_currentPos = $charOffset; + } + + /** + * @see Swift_CharacterStream::write() + * + * @param string $chars + */ + public function write($chars) + { + if (!isset($this->_charReader)) { + $this->_charReader = $this->_charReaderFactory->getReaderFor( + $this->_charset); + $this->_map = array(); + $this->_mapType = $this->_charReader->getMapType(); + } + $ignored = ''; + $this->_datas .= $chars; + $this->_charCount += $this->_charReader->getCharPositions(substr($this->_datas, $this->_datasSize), $this->_datasSize, $this->_map, $ignored); + if ($ignored !== false) { + $this->_datasSize = strlen($this->_datas) - strlen($ignored); + } else { + $this->_datasSize = strlen($this->_datas); + } + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ConfigurableSpool.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ConfigurableSpool.php new file mode 100644 index 0000000..4ae5bac --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ConfigurableSpool.php @@ -0,0 +1,63 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * Base class for Spools (implements time and message limits). + * + * @author Fabien Potencier + */ +abstract class Swift_ConfigurableSpool implements Swift_Spool +{ + /** The maximum number of messages to send per flush */ + private $_message_limit; + + /** The time limit per flush */ + private $_time_limit; + + /** + * Sets the maximum number of messages to send per flush. + * + * @param int $limit + */ + public function setMessageLimit($limit) + { + $this->_message_limit = (int) $limit; + } + + /** + * Gets the maximum number of messages to send per flush. + * + * @return int The limit + */ + public function getMessageLimit() + { + return $this->_message_limit; + } + + /** + * Sets the time limit (in seconds) per flush. + * + * @param int $limit The limit + */ + public function setTimeLimit($limit) + { + $this->_time_limit = (int) $limit; + } + + /** + * Gets the time limit (in seconds) per flush. + * + * @return int The limit + */ + public function getTimeLimit() + { + return $this->_time_limit; + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/DependencyContainer.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/DependencyContainer.php new file mode 100644 index 0000000..befec9a --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/DependencyContainer.php @@ -0,0 +1,373 @@ +_store); + } + + /** + * Test if an item is registered in this container with the given name. + * + * @see register() + * + * @param string $itemName + * + * @return bool + */ + public function has($itemName) + { + return array_key_exists($itemName, $this->_store) + && isset($this->_store[$itemName]['lookupType']); + } + + /** + * Lookup the item with the given $itemName. + * + * @see register() + * + * @param string $itemName + * + * @throws Swift_DependencyException If the dependency is not found + * + * @return mixed + */ + public function lookup($itemName) + { + if (!$this->has($itemName)) { + throw new Swift_DependencyException( + 'Cannot lookup dependency "'.$itemName.'" since it is not registered.' + ); + } + + switch ($this->_store[$itemName]['lookupType']) { + case self::TYPE_ALIAS: + return $this->_createAlias($itemName); + case self::TYPE_VALUE: + return $this->_getValue($itemName); + case self::TYPE_INSTANCE: + return $this->_createNewInstance($itemName); + case self::TYPE_SHARED: + return $this->_createSharedInstance($itemName); + } + } + + /** + * Create an array of arguments passed to the constructor of $itemName. + * + * @param string $itemName + * + * @return array + */ + public function createDependenciesFor($itemName) + { + $args = array(); + if (isset($this->_store[$itemName]['args'])) { + $args = $this->_resolveArgs($this->_store[$itemName]['args']); + } + + return $args; + } + + /** + * Register a new dependency with $itemName. + * + * This method returns the current DependencyContainer instance because it + * requires the use of the fluid interface to set the specific details for the + * dependency. + * + * @see asNewInstanceOf(), asSharedInstanceOf(), asValue() + * + * @param string $itemName + * + * @return $this + */ + public function register($itemName) + { + $this->_store[$itemName] = array(); + $this->_endPoint = &$this->_store[$itemName]; + + return $this; + } + + /** + * Specify the previously registered item as a literal value. + * + * {@link register()} must be called before this will work. + * + * @param mixed $value + * + * @return $this + */ + public function asValue($value) + { + $endPoint = &$this->_getEndPoint(); + $endPoint['lookupType'] = self::TYPE_VALUE; + $endPoint['value'] = $value; + + return $this; + } + + /** + * Specify the previously registered item as an alias of another item. + * + * @param string $lookup + * + * @return $this + */ + public function asAliasOf($lookup) + { + $endPoint = &$this->_getEndPoint(); + $endPoint['lookupType'] = self::TYPE_ALIAS; + $endPoint['ref'] = $lookup; + + return $this; + } + + /** + * Specify the previously registered item as a new instance of $className. + * + * {@link register()} must be called before this will work. + * Any arguments can be set with {@link withDependencies()}, + * {@link addConstructorValue()} or {@link addConstructorLookup()}. + * + * @see withDependencies(), addConstructorValue(), addConstructorLookup() + * + * @param string $className + * + * @return $this + */ + public function asNewInstanceOf($className) + { + $endPoint = &$this->_getEndPoint(); + $endPoint['lookupType'] = self::TYPE_INSTANCE; + $endPoint['className'] = $className; + + return $this; + } + + /** + * Specify the previously registered item as a shared instance of $className. + * + * {@link register()} must be called before this will work. + * + * @param string $className + * + * @return $this + */ + public function asSharedInstanceOf($className) + { + $endPoint = &$this->_getEndPoint(); + $endPoint['lookupType'] = self::TYPE_SHARED; + $endPoint['className'] = $className; + + return $this; + } + + /** + * Specify a list of injected dependencies for the previously registered item. + * + * This method takes an array of lookup names. + * + * @see addConstructorValue(), addConstructorLookup() + * + * @param array $lookups + * + * @return $this + */ + public function withDependencies(array $lookups) + { + $endPoint = &$this->_getEndPoint(); + $endPoint['args'] = array(); + foreach ($lookups as $lookup) { + $this->addConstructorLookup($lookup); + } + + return $this; + } + + /** + * Specify a literal (non looked up) value for the constructor of the + * previously registered item. + * + * @see withDependencies(), addConstructorLookup() + * + * @param mixed $value + * + * @return $this + */ + public function addConstructorValue($value) + { + $endPoint = &$this->_getEndPoint(); + if (!isset($endPoint['args'])) { + $endPoint['args'] = array(); + } + $endPoint['args'][] = array('type' => 'value', 'item' => $value); + + return $this; + } + + /** + * Specify a dependency lookup for the constructor of the previously + * registered item. + * + * @see withDependencies(), addConstructorValue() + * + * @param string $lookup + * + * @return $this + */ + public function addConstructorLookup($lookup) + { + $endPoint = &$this->_getEndPoint(); + if (!isset($this->_endPoint['args'])) { + $endPoint['args'] = array(); + } + $endPoint['args'][] = array('type' => 'lookup', 'item' => $lookup); + + return $this; + } + + /** Get the literal value with $itemName */ + private function _getValue($itemName) + { + return $this->_store[$itemName]['value']; + } + + /** Resolve an alias to another item */ + private function _createAlias($itemName) + { + return $this->lookup($this->_store[$itemName]['ref']); + } + + /** Create a fresh instance of $itemName */ + private function _createNewInstance($itemName) + { + $reflector = new ReflectionClass($this->_store[$itemName]['className']); + if ($reflector->getConstructor()) { + return $reflector->newInstanceArgs( + $this->createDependenciesFor($itemName) + ); + } + + return $reflector->newInstance(); + } + + /** Create and register a shared instance of $itemName */ + private function _createSharedInstance($itemName) + { + if (!isset($this->_store[$itemName]['instance'])) { + $this->_store[$itemName]['instance'] = $this->_createNewInstance($itemName); + } + + return $this->_store[$itemName]['instance']; + } + + /** Get the current endpoint in the store */ + private function &_getEndPoint() + { + if (!isset($this->_endPoint)) { + throw new BadMethodCallException( + 'Component must first be registered by calling register()' + ); + } + + return $this->_endPoint; + } + + /** Get an argument list with dependencies resolved */ + private function _resolveArgs(array $args) + { + $resolved = array(); + foreach ($args as $argDefinition) { + switch ($argDefinition['type']) { + case 'lookup': + $resolved[] = $this->_lookupRecursive($argDefinition['item']); + break; + case 'value': + $resolved[] = $argDefinition['item']; + break; + } + } + + return $resolved; + } + + /** Resolve a single dependency with an collections */ + private function _lookupRecursive($item) + { + if (is_array($item)) { + $collection = array(); + foreach ($item as $k => $v) { + $collection[$k] = $this->_lookupRecursive($v); + } + + return $collection; + } + + return $this->lookup($item); + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/DependencyException.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/DependencyException.php new file mode 100644 index 0000000..799d38d --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/DependencyException.php @@ -0,0 +1,27 @@ +createDependenciesFor('mime.embeddedfile') + ); + + $this->setBody($data); + $this->setFilename($filename); + if ($contentType) { + $this->setContentType($contentType); + } + } + + /** + * Create a new EmbeddedFile. + * + * @param string|Swift_OutputByteStream $data + * @param string $filename + * @param string $contentType + * + * @return Swift_Mime_EmbeddedFile + */ + public static function newInstance($data = null, $filename = null, $contentType = null) + { + return new self($data, $filename, $contentType); + } + + /** + * Create a new EmbeddedFile from a filesystem path. + * + * @param string $path + * + * @return Swift_Mime_EmbeddedFile + */ + public static function fromPath($path) + { + return self::newInstance()->setFile( + new Swift_ByteStream_FileByteStream($path) + ); + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Encoder.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Encoder.php new file mode 100644 index 0000000..2073abc --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Encoder.php @@ -0,0 +1,28 @@ += $maxLineLength || 76 < $maxLineLength) { + $maxLineLength = 76; + } + + $encodedString = base64_encode($string); + $firstLine = ''; + + if (0 != $firstLineOffset) { + $firstLine = substr( + $encodedString, 0, $maxLineLength - $firstLineOffset + )."\r\n"; + $encodedString = substr( + $encodedString, $maxLineLength - $firstLineOffset + ); + } + + return $firstLine.trim(chunk_split($encodedString, $maxLineLength, "\r\n")); + } + + /** + * Does nothing. + */ + public function charsetChanged($charset) + { + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Encoder/QpEncoder.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Encoder/QpEncoder.php new file mode 100644 index 0000000..edec10c --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Encoder/QpEncoder.php @@ -0,0 +1,300 @@ + '=00', 1 => '=01', 2 => '=02', 3 => '=03', 4 => '=04', + 5 => '=05', 6 => '=06', 7 => '=07', 8 => '=08', 9 => '=09', + 10 => '=0A', 11 => '=0B', 12 => '=0C', 13 => '=0D', 14 => '=0E', + 15 => '=0F', 16 => '=10', 17 => '=11', 18 => '=12', 19 => '=13', + 20 => '=14', 21 => '=15', 22 => '=16', 23 => '=17', 24 => '=18', + 25 => '=19', 26 => '=1A', 27 => '=1B', 28 => '=1C', 29 => '=1D', + 30 => '=1E', 31 => '=1F', 32 => '=20', 33 => '=21', 34 => '=22', + 35 => '=23', 36 => '=24', 37 => '=25', 38 => '=26', 39 => '=27', + 40 => '=28', 41 => '=29', 42 => '=2A', 43 => '=2B', 44 => '=2C', + 45 => '=2D', 46 => '=2E', 47 => '=2F', 48 => '=30', 49 => '=31', + 50 => '=32', 51 => '=33', 52 => '=34', 53 => '=35', 54 => '=36', + 55 => '=37', 56 => '=38', 57 => '=39', 58 => '=3A', 59 => '=3B', + 60 => '=3C', 61 => '=3D', 62 => '=3E', 63 => '=3F', 64 => '=40', + 65 => '=41', 66 => '=42', 67 => '=43', 68 => '=44', 69 => '=45', + 70 => '=46', 71 => '=47', 72 => '=48', 73 => '=49', 74 => '=4A', + 75 => '=4B', 76 => '=4C', 77 => '=4D', 78 => '=4E', 79 => '=4F', + 80 => '=50', 81 => '=51', 82 => '=52', 83 => '=53', 84 => '=54', + 85 => '=55', 86 => '=56', 87 => '=57', 88 => '=58', 89 => '=59', + 90 => '=5A', 91 => '=5B', 92 => '=5C', 93 => '=5D', 94 => '=5E', + 95 => '=5F', 96 => '=60', 97 => '=61', 98 => '=62', 99 => '=63', + 100 => '=64', 101 => '=65', 102 => '=66', 103 => '=67', 104 => '=68', + 105 => '=69', 106 => '=6A', 107 => '=6B', 108 => '=6C', 109 => '=6D', + 110 => '=6E', 111 => '=6F', 112 => '=70', 113 => '=71', 114 => '=72', + 115 => '=73', 116 => '=74', 117 => '=75', 118 => '=76', 119 => '=77', + 120 => '=78', 121 => '=79', 122 => '=7A', 123 => '=7B', 124 => '=7C', + 125 => '=7D', 126 => '=7E', 127 => '=7F', 128 => '=80', 129 => '=81', + 130 => '=82', 131 => '=83', 132 => '=84', 133 => '=85', 134 => '=86', + 135 => '=87', 136 => '=88', 137 => '=89', 138 => '=8A', 139 => '=8B', + 140 => '=8C', 141 => '=8D', 142 => '=8E', 143 => '=8F', 144 => '=90', + 145 => '=91', 146 => '=92', 147 => '=93', 148 => '=94', 149 => '=95', + 150 => '=96', 151 => '=97', 152 => '=98', 153 => '=99', 154 => '=9A', + 155 => '=9B', 156 => '=9C', 157 => '=9D', 158 => '=9E', 159 => '=9F', + 160 => '=A0', 161 => '=A1', 162 => '=A2', 163 => '=A3', 164 => '=A4', + 165 => '=A5', 166 => '=A6', 167 => '=A7', 168 => '=A8', 169 => '=A9', + 170 => '=AA', 171 => '=AB', 172 => '=AC', 173 => '=AD', 174 => '=AE', + 175 => '=AF', 176 => '=B0', 177 => '=B1', 178 => '=B2', 179 => '=B3', + 180 => '=B4', 181 => '=B5', 182 => '=B6', 183 => '=B7', 184 => '=B8', + 185 => '=B9', 186 => '=BA', 187 => '=BB', 188 => '=BC', 189 => '=BD', + 190 => '=BE', 191 => '=BF', 192 => '=C0', 193 => '=C1', 194 => '=C2', + 195 => '=C3', 196 => '=C4', 197 => '=C5', 198 => '=C6', 199 => '=C7', + 200 => '=C8', 201 => '=C9', 202 => '=CA', 203 => '=CB', 204 => '=CC', + 205 => '=CD', 206 => '=CE', 207 => '=CF', 208 => '=D0', 209 => '=D1', + 210 => '=D2', 211 => '=D3', 212 => '=D4', 213 => '=D5', 214 => '=D6', + 215 => '=D7', 216 => '=D8', 217 => '=D9', 218 => '=DA', 219 => '=DB', + 220 => '=DC', 221 => '=DD', 222 => '=DE', 223 => '=DF', 224 => '=E0', + 225 => '=E1', 226 => '=E2', 227 => '=E3', 228 => '=E4', 229 => '=E5', + 230 => '=E6', 231 => '=E7', 232 => '=E8', 233 => '=E9', 234 => '=EA', + 235 => '=EB', 236 => '=EC', 237 => '=ED', 238 => '=EE', 239 => '=EF', + 240 => '=F0', 241 => '=F1', 242 => '=F2', 243 => '=F3', 244 => '=F4', + 245 => '=F5', 246 => '=F6', 247 => '=F7', 248 => '=F8', 249 => '=F9', + 250 => '=FA', 251 => '=FB', 252 => '=FC', 253 => '=FD', 254 => '=FE', + 255 => '=FF', + ); + + protected static $_safeMapShare = array(); + + /** + * A map of non-encoded ascii characters. + * + * @var string[] + */ + protected $_safeMap = array(); + + /** + * Creates a new QpEncoder for the given CharacterStream. + * + * @param Swift_CharacterStream $charStream to use for reading characters + * @param Swift_StreamFilter $filter if input should be canonicalized + */ + public function __construct(Swift_CharacterStream $charStream, Swift_StreamFilter $filter = null) + { + $this->_charStream = $charStream; + if (!isset(self::$_safeMapShare[$this->getSafeMapShareId()])) { + $this->initSafeMap(); + self::$_safeMapShare[$this->getSafeMapShareId()] = $this->_safeMap; + } else { + $this->_safeMap = self::$_safeMapShare[$this->getSafeMapShareId()]; + } + $this->_filter = $filter; + } + + public function __sleep() + { + return array('_charStream', '_filter'); + } + + public function __wakeup() + { + if (!isset(self::$_safeMapShare[$this->getSafeMapShareId()])) { + $this->initSafeMap(); + self::$_safeMapShare[$this->getSafeMapShareId()] = $this->_safeMap; + } else { + $this->_safeMap = self::$_safeMapShare[$this->getSafeMapShareId()]; + } + } + + protected function getSafeMapShareId() + { + return get_class($this); + } + + protected function initSafeMap() + { + foreach (array_merge( + array(0x09, 0x20), range(0x21, 0x3C), range(0x3E, 0x7E)) as $byte) { + $this->_safeMap[$byte] = chr($byte); + } + } + + /** + * Takes an unencoded string and produces a QP encoded string from it. + * + * QP encoded strings have a maximum line length of 76 characters. + * If the first line needs to be shorter, indicate the difference with + * $firstLineOffset. + * + * @param string $string to encode + * @param int $firstLineOffset, optional + * @param int $maxLineLength, optional 0 indicates the default of 76 chars + * + * @return string + */ + public function encodeString($string, $firstLineOffset = 0, $maxLineLength = 0) + { + if ($maxLineLength > 76 || $maxLineLength <= 0) { + $maxLineLength = 76; + } + + $thisLineLength = $maxLineLength - $firstLineOffset; + + $lines = array(); + $lNo = 0; + $lines[$lNo] = ''; + $currentLine = &$lines[$lNo++]; + $size = $lineLen = 0; + + $this->_charStream->flushContents(); + $this->_charStream->importString($string); + + // Fetching more than 4 chars at one is slower, as is fetching fewer bytes + // Conveniently 4 chars is the UTF-8 safe number since UTF-8 has up to 6 + // bytes per char and (6 * 4 * 3 = 72 chars per line) * =NN is 3 bytes + while (false !== $bytes = $this->_nextSequence()) { + // If we're filtering the input + if (isset($this->_filter)) { + // If we can't filter because we need more bytes + while ($this->_filter->shouldBuffer($bytes)) { + // Then collect bytes into the buffer + if (false === $moreBytes = $this->_nextSequence(1)) { + break; + } + + foreach ($moreBytes as $b) { + $bytes[] = $b; + } + } + // And filter them + $bytes = $this->_filter->filter($bytes); + } + + $enc = $this->_encodeByteSequence($bytes, $size); + + $i = strpos($enc, '=0D=0A'); + $newLineLength = $lineLen + ($i === false ? $size : $i); + + if ($currentLine && $newLineLength >= $thisLineLength) { + $lines[$lNo] = ''; + $currentLine = &$lines[$lNo++]; + $thisLineLength = $maxLineLength; + $lineLen = 0; + } + + $currentLine .= $enc; + + if ($i === false) { + $lineLen += $size; + } else { + // 6 is the length of '=0D=0A'. + $lineLen = $size - strrpos($enc, '=0D=0A') - 6; + } + } + + return $this->_standardize(implode("=\r\n", $lines)); + } + + /** + * Updates the charset used. + * + * @param string $charset + */ + public function charsetChanged($charset) + { + $this->_charStream->setCharacterSet($charset); + } + + /** + * Encode the given byte array into a verbatim QP form. + * + * @param int[] $bytes + * @param int $size + * + * @return string + */ + protected function _encodeByteSequence(array $bytes, &$size) + { + $ret = ''; + $size = 0; + foreach ($bytes as $b) { + if (isset($this->_safeMap[$b])) { + $ret .= $this->_safeMap[$b]; + ++$size; + } else { + $ret .= self::$_qpMap[$b]; + $size += 3; + } + } + + return $ret; + } + + /** + * Get the next sequence of bytes to read from the char stream. + * + * @param int $size number of bytes to read + * + * @return int[] + */ + protected function _nextSequence($size = 4) + { + return $this->_charStream->readBytes($size); + } + + /** + * Make sure CRLF is correct and HT/SPACE are in valid places. + * + * @param string $string + * + * @return string + */ + protected function _standardize($string) + { + $string = str_replace(array("\t=0D=0A", ' =0D=0A', '=0D=0A'), + array("=09\r\n", "=20\r\n", "\r\n"), $string + ); + switch ($end = ord(substr($string, -1))) { + case 0x09: + case 0x20: + $string = substr_replace($string, self::$_qpMap[$end], -1); + } + + return $string; + } + + /** + * Make a deep copy of object. + */ + public function __clone() + { + $this->_charStream = clone $this->_charStream; + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Encoder/Rfc2231Encoder.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Encoder/Rfc2231Encoder.php new file mode 100644 index 0000000..b0215e8 --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Encoder/Rfc2231Encoder.php @@ -0,0 +1,92 @@ +_charStream = $charStream; + } + + /** + * Takes an unencoded string and produces a string encoded according to + * RFC 2231 from it. + * + * @param string $string + * @param int $firstLineOffset + * @param int $maxLineLength optional, 0 indicates the default of 75 bytes + * + * @return string + */ + public function encodeString($string, $firstLineOffset = 0, $maxLineLength = 0) + { + $lines = array(); + $lineCount = 0; + $lines[] = ''; + $currentLine = &$lines[$lineCount++]; + + if (0 >= $maxLineLength) { + $maxLineLength = 75; + } + + $this->_charStream->flushContents(); + $this->_charStream->importString($string); + + $thisLineLength = $maxLineLength - $firstLineOffset; + + while (false !== $char = $this->_charStream->read(4)) { + $encodedChar = rawurlencode($char); + if (0 != strlen($currentLine) + && strlen($currentLine.$encodedChar) > $thisLineLength) { + $lines[] = ''; + $currentLine = &$lines[$lineCount++]; + $thisLineLength = $maxLineLength; + } + $currentLine .= $encodedChar; + } + + return implode("\r\n", $lines); + } + + /** + * Updates the charset used. + * + * @param string $charset + */ + public function charsetChanged($charset) + { + $this->_charStream->setCharacterSet($charset); + } + + /** + * Make a deep copy of object. + */ + public function __clone() + { + $this->_charStream = clone $this->_charStream; + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Encoding.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Encoding.php new file mode 100644 index 0000000..2458787 --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Encoding.php @@ -0,0 +1,62 @@ +lookup($key); + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/CommandEvent.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/CommandEvent.php new file mode 100644 index 0000000..674e6b5 --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/CommandEvent.php @@ -0,0 +1,65 @@ +_command = $command; + $this->_successCodes = $successCodes; + } + + /** + * Get the command which was sent to the server. + * + * @return string + */ + public function getCommand() + { + return $this->_command; + } + + /** + * Get the numeric response codes which indicate success for this command. + * + * @return int[] + */ + public function getSuccessCodes() + { + return $this->_successCodes; + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/CommandListener.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/CommandListener.php new file mode 100644 index 0000000..7545404 --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/CommandListener.php @@ -0,0 +1,24 @@ +_source = $source; + } + + /** + * Get the source object of this event. + * + * @return object + */ + public function getSource() + { + return $this->_source; + } + + /** + * Prevent this Event from bubbling any further up the stack. + * + * @param bool $cancel, optional + */ + public function cancelBubble($cancel = true) + { + $this->_bubbleCancelled = $cancel; + } + + /** + * Returns true if this Event will not bubble any further up the stack. + * + * @return bool + */ + public function bubbleCancelled() + { + return $this->_bubbleCancelled; + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/ResponseEvent.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/ResponseEvent.php new file mode 100644 index 0000000..2e92ba9 --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/ResponseEvent.php @@ -0,0 +1,65 @@ +_response = $response; + $this->_valid = $valid; + } + + /** + * Get the response which was received from the server. + * + * @return string + */ + public function getResponse() + { + return $this->_response; + } + + /** + * Get the success status of this Event. + * + * @return bool + */ + public function isValid() + { + return $this->_valid; + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/ResponseListener.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/ResponseListener.php new file mode 100644 index 0000000..c40919d --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/ResponseListener.php @@ -0,0 +1,24 @@ +_message = $message; + $this->_result = self::RESULT_PENDING; + } + + /** + * Get the Transport used to send the Message. + * + * @return Swift_Transport + */ + public function getTransport() + { + return $this->getSource(); + } + + /** + * Get the Message being sent. + * + * @return Swift_Mime_Message + */ + public function getMessage() + { + return $this->_message; + } + + /** + * Set the array of addresses that failed in sending. + * + * @param array $recipients + */ + public function setFailedRecipients($recipients) + { + $this->_failedRecipients = $recipients; + } + + /** + * Get an recipient addresses which were not accepted for delivery. + * + * @return string[] + */ + public function getFailedRecipients() + { + return $this->_failedRecipients; + } + + /** + * Set the result of sending. + * + * @param int $result + */ + public function setResult($result) + { + $this->_result = $result; + } + + /** + * Get the result of this Event. + * + * The return value is a bitmask from + * {@see RESULT_PENDING, RESULT_SUCCESS, RESULT_TENTATIVE, RESULT_FAILED} + * + * @return int + */ + public function getResult() + { + return $this->_result; + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/SendListener.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/SendListener.php new file mode 100644 index 0000000..d922e1b --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/SendListener.php @@ -0,0 +1,31 @@ +_eventMap = array( + 'Swift_Events_CommandEvent' => 'Swift_Events_CommandListener', + 'Swift_Events_ResponseEvent' => 'Swift_Events_ResponseListener', + 'Swift_Events_SendEvent' => 'Swift_Events_SendListener', + 'Swift_Events_TransportChangeEvent' => 'Swift_Events_TransportChangeListener', + 'Swift_Events_TransportExceptionEvent' => 'Swift_Events_TransportExceptionListener', + ); + } + + /** + * Create a new SendEvent for $source and $message. + * + * @param Swift_Transport $source + * @param Swift_Mime_Message + * + * @return Swift_Events_SendEvent + */ + public function createSendEvent(Swift_Transport $source, Swift_Mime_Message $message) + { + return new Swift_Events_SendEvent($source, $message); + } + + /** + * Create a new CommandEvent for $source and $command. + * + * @param Swift_Transport $source + * @param string $command That will be executed + * @param array $successCodes That are needed + * + * @return Swift_Events_CommandEvent + */ + public function createCommandEvent(Swift_Transport $source, $command, $successCodes = array()) + { + return new Swift_Events_CommandEvent($source, $command, $successCodes); + } + + /** + * Create a new ResponseEvent for $source and $response. + * + * @param Swift_Transport $source + * @param string $response + * @param bool $valid If the response is valid + * + * @return Swift_Events_ResponseEvent + */ + public function createResponseEvent(Swift_Transport $source, $response, $valid) + { + return new Swift_Events_ResponseEvent($source, $response, $valid); + } + + /** + * Create a new TransportChangeEvent for $source. + * + * @param Swift_Transport $source + * + * @return Swift_Events_TransportChangeEvent + */ + public function createTransportChangeEvent(Swift_Transport $source) + { + return new Swift_Events_TransportChangeEvent($source); + } + + /** + * Create a new TransportExceptionEvent for $source. + * + * @param Swift_Transport $source + * @param Swift_TransportException $ex + * + * @return Swift_Events_TransportExceptionEvent + */ + public function createTransportExceptionEvent(Swift_Transport $source, Swift_TransportException $ex) + { + return new Swift_Events_TransportExceptionEvent($source, $ex); + } + + /** + * Bind an event listener to this dispatcher. + * + * @param Swift_Events_EventListener $listener + */ + public function bindEventListener(Swift_Events_EventListener $listener) + { + foreach ($this->_listeners as $l) { + // Already loaded + if ($l === $listener) { + return; + } + } + $this->_listeners[] = $listener; + } + + /** + * Dispatch the given Event to all suitable listeners. + * + * @param Swift_Events_EventObject $evt + * @param string $target method + */ + public function dispatchEvent(Swift_Events_EventObject $evt, $target) + { + $this->_prepareBubbleQueue($evt); + $this->_bubble($evt, $target); + } + + /** Queue listeners on a stack ready for $evt to be bubbled up it */ + private function _prepareBubbleQueue(Swift_Events_EventObject $evt) + { + $this->_bubbleQueue = array(); + $evtClass = get_class($evt); + foreach ($this->_listeners as $listener) { + if (array_key_exists($evtClass, $this->_eventMap) + && ($listener instanceof $this->_eventMap[$evtClass])) { + $this->_bubbleQueue[] = $listener; + } + } + } + + /** Bubble $evt up the stack calling $target() on each listener */ + private function _bubble(Swift_Events_EventObject $evt, $target) + { + if (!$evt->bubbleCancelled() && $listener = array_shift($this->_bubbleQueue)) { + $listener->$target($evt); + $this->_bubble($evt, $target); + } + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/TransportChangeEvent.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/TransportChangeEvent.php new file mode 100644 index 0000000..a8972fd --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/TransportChangeEvent.php @@ -0,0 +1,27 @@ +getSource(); + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/TransportChangeListener.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/TransportChangeListener.php new file mode 100644 index 0000000..253165d --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/TransportChangeListener.php @@ -0,0 +1,45 @@ +_exception = $ex; + } + + /** + * Get the TransportException thrown. + * + * @return Swift_TransportException + */ + public function getException() + { + return $this->_exception; + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/TransportExceptionListener.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/TransportExceptionListener.php new file mode 100644 index 0000000..cc3c099 --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/TransportExceptionListener.php @@ -0,0 +1,24 @@ +createDependenciesFor('transport.failover') + ); + + $this->setTransports($transports); + } + + /** + * Create a new FailoverTransport instance. + * + * @param Swift_Transport[] $transports + * + * @return self + */ + public static function newInstance($transports = array()) + { + return new self($transports); + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/FileSpool.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/FileSpool.php new file mode 100644 index 0000000..c82c5db --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/FileSpool.php @@ -0,0 +1,208 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * Stores Messages on the filesystem. + * + * @author Fabien Potencier + * @author Xavier De Cock + */ +class Swift_FileSpool extends Swift_ConfigurableSpool +{ + /** The spool directory */ + private $_path; + + /** + * File WriteRetry Limit. + * + * @var int + */ + private $_retryLimit = 10; + + /** + * Create a new FileSpool. + * + * @param string $path + * + * @throws Swift_IoException + */ + public function __construct($path) + { + $this->_path = $path; + + if (!file_exists($this->_path)) { + if (!mkdir($this->_path, 0777, true)) { + throw new Swift_IoException(sprintf('Unable to create path "%s".', $this->_path)); + } + } + } + + /** + * Tests if this Spool mechanism has started. + * + * @return bool + */ + public function isStarted() + { + return true; + } + + /** + * Starts this Spool mechanism. + */ + public function start() + { + } + + /** + * Stops this Spool mechanism. + */ + public function stop() + { + } + + /** + * Allow to manage the enqueuing retry limit. + * + * Default, is ten and allows over 64^20 different fileNames + * + * @param int $limit + */ + public function setRetryLimit($limit) + { + $this->_retryLimit = $limit; + } + + /** + * Queues a message. + * + * @param Swift_Mime_Message $message The message to store + * + * @throws Swift_IoException + * + * @return bool + */ + public function queueMessage(Swift_Mime_Message $message) + { + $ser = serialize($message); + $fileName = $this->_path.'/'.$this->getRandomString(10); + for ($i = 0; $i < $this->_retryLimit; ++$i) { + /* We try an exclusive creation of the file. This is an atomic operation, it avoid locking mechanism */ + $fp = @fopen($fileName.'.message', 'x'); + if (false !== $fp) { + if (false === fwrite($fp, $ser)) { + return false; + } + + return fclose($fp); + } else { + /* The file already exists, we try a longer fileName */ + $fileName .= $this->getRandomString(1); + } + } + + throw new Swift_IoException(sprintf('Unable to create a file for enqueuing Message in "%s".', $this->_path)); + } + + /** + * Execute a recovery if for any reason a process is sending for too long. + * + * @param int $timeout in second Defaults is for very slow smtp responses + */ + public function recover($timeout = 900) + { + foreach (new DirectoryIterator($this->_path) as $file) { + $file = $file->getRealPath(); + + if (substr($file, -16) == '.message.sending') { + $lockedtime = filectime($file); + if ((time() - $lockedtime) > $timeout) { + rename($file, substr($file, 0, -8)); + } + } + } + } + + /** + * Sends messages using the given transport instance. + * + * @param Swift_Transport $transport A transport instance + * @param string[] $failedRecipients An array of failures by-reference + * + * @return int The number of sent e-mail's + */ + public function flushQueue(Swift_Transport $transport, &$failedRecipients = null) + { + $directoryIterator = new DirectoryIterator($this->_path); + + /* Start the transport only if there are queued files to send */ + if (!$transport->isStarted()) { + foreach ($directoryIterator as $file) { + if (substr($file->getRealPath(), -8) == '.message') { + $transport->start(); + break; + } + } + } + + $failedRecipients = (array) $failedRecipients; + $count = 0; + $time = time(); + foreach ($directoryIterator as $file) { + $file = $file->getRealPath(); + + if (substr($file, -8) != '.message') { + continue; + } + + /* We try a rename, it's an atomic operation, and avoid locking the file */ + if (rename($file, $file.'.sending')) { + $message = unserialize(file_get_contents($file.'.sending')); + + $count += $transport->send($message, $failedRecipients); + + unlink($file.'.sending'); + } else { + /* This message has just been catched by another process */ + continue; + } + + if ($this->getMessageLimit() && $count >= $this->getMessageLimit()) { + break; + } + + if ($this->getTimeLimit() && (time() - $time) >= $this->getTimeLimit()) { + break; + } + } + + return $count; + } + + /** + * Returns a random string needed to generate a fileName for the queue. + * + * @param int $count + * + * @return string + */ + protected function getRandomString($count) + { + // This string MUST stay FS safe, avoid special chars + $base = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-'; + $ret = ''; + $strlen = strlen($base); + for ($i = 0; $i < $count; ++$i) { + $ret .= $base[((int) rand(0, $strlen - 1))]; + } + + return $ret; + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/FileStream.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/FileStream.php new file mode 100644 index 0000000..0b24db1 --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/FileStream.php @@ -0,0 +1,24 @@ +setFile(new Swift_ByteStream_FileByteStream($path)); + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/InputByteStream.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/InputByteStream.php new file mode 100644 index 0000000..56efc75 --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/InputByteStream.php @@ -0,0 +1,75 @@ +_stream = $stream; + } + + /** + * Set a string into the cache under $itemKey for the namespace $nsKey. + * + * @see MODE_WRITE, MODE_APPEND + * + * @param string $nsKey + * @param string $itemKey + * @param string $string + * @param int $mode + */ + public function setString($nsKey, $itemKey, $string, $mode) + { + $this->_prepareCache($nsKey); + switch ($mode) { + case self::MODE_WRITE: + $this->_contents[$nsKey][$itemKey] = $string; + break; + case self::MODE_APPEND: + if (!$this->hasKey($nsKey, $itemKey)) { + $this->_contents[$nsKey][$itemKey] = ''; + } + $this->_contents[$nsKey][$itemKey] .= $string; + break; + default: + throw new Swift_SwiftException( + 'Invalid mode ['.$mode.'] used to set nsKey='. + $nsKey.', itemKey='.$itemKey + ); + } + } + + /** + * Set a ByteStream into the cache under $itemKey for the namespace $nsKey. + * + * @see MODE_WRITE, MODE_APPEND + * + * @param string $nsKey + * @param string $itemKey + * @param Swift_OutputByteStream $os + * @param int $mode + */ + public function importFromByteStream($nsKey, $itemKey, Swift_OutputByteStream $os, $mode) + { + $this->_prepareCache($nsKey); + switch ($mode) { + case self::MODE_WRITE: + $this->clearKey($nsKey, $itemKey); + case self::MODE_APPEND: + if (!$this->hasKey($nsKey, $itemKey)) { + $this->_contents[$nsKey][$itemKey] = ''; + } + while (false !== $bytes = $os->read(8192)) { + $this->_contents[$nsKey][$itemKey] .= $bytes; + } + break; + default: + throw new Swift_SwiftException( + 'Invalid mode ['.$mode.'] used to set nsKey='. + $nsKey.', itemKey='.$itemKey + ); + } + } + + /** + * Provides a ByteStream which when written to, writes data to $itemKey. + * + * NOTE: The stream will always write in append mode. + * + * @param string $nsKey + * @param string $itemKey + * @param Swift_InputByteStream $writeThrough + * + * @return Swift_InputByteStream + */ + public function getInputByteStream($nsKey, $itemKey, Swift_InputByteStream $writeThrough = null) + { + $is = clone $this->_stream; + $is->setKeyCache($this); + $is->setNsKey($nsKey); + $is->setItemKey($itemKey); + if (isset($writeThrough)) { + $is->setWriteThroughStream($writeThrough); + } + + return $is; + } + + /** + * Get data back out of the cache as a string. + * + * @param string $nsKey + * @param string $itemKey + * + * @return string + */ + public function getString($nsKey, $itemKey) + { + $this->_prepareCache($nsKey); + if ($this->hasKey($nsKey, $itemKey)) { + return $this->_contents[$nsKey][$itemKey]; + } + } + + /** + * Get data back out of the cache as a ByteStream. + * + * @param string $nsKey + * @param string $itemKey + * @param Swift_InputByteStream $is to write the data to + */ + public function exportToByteStream($nsKey, $itemKey, Swift_InputByteStream $is) + { + $this->_prepareCache($nsKey); + $is->write($this->getString($nsKey, $itemKey)); + } + + /** + * Check if the given $itemKey exists in the namespace $nsKey. + * + * @param string $nsKey + * @param string $itemKey + * + * @return bool + */ + public function hasKey($nsKey, $itemKey) + { + $this->_prepareCache($nsKey); + + return array_key_exists($itemKey, $this->_contents[$nsKey]); + } + + /** + * Clear data for $itemKey in the namespace $nsKey if it exists. + * + * @param string $nsKey + * @param string $itemKey + */ + public function clearKey($nsKey, $itemKey) + { + unset($this->_contents[$nsKey][$itemKey]); + } + + /** + * Clear all data in the namespace $nsKey if it exists. + * + * @param string $nsKey + */ + public function clearAll($nsKey) + { + unset($this->_contents[$nsKey]); + } + + /** + * Initialize the namespace of $nsKey if needed. + * + * @param string $nsKey + */ + private function _prepareCache($nsKey) + { + if (!array_key_exists($nsKey, $this->_contents)) { + $this->_contents[$nsKey] = array(); + } + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/KeyCache/DiskKeyCache.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/KeyCache/DiskKeyCache.php new file mode 100644 index 0000000..453f50a --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/KeyCache/DiskKeyCache.php @@ -0,0 +1,321 @@ +_stream = $stream; + $this->_path = $path; + + if (function_exists('get_magic_quotes_runtime') && @get_magic_quotes_runtime() == 1) { + $this->_quotes = true; + } + } + + /** + * Set a string into the cache under $itemKey for the namespace $nsKey. + * + * @see MODE_WRITE, MODE_APPEND + * + * @param string $nsKey + * @param string $itemKey + * @param string $string + * @param int $mode + * + * @throws Swift_IoException + */ + public function setString($nsKey, $itemKey, $string, $mode) + { + $this->_prepareCache($nsKey); + switch ($mode) { + case self::MODE_WRITE: + $fp = $this->_getHandle($nsKey, $itemKey, self::POSITION_START); + break; + case self::MODE_APPEND: + $fp = $this->_getHandle($nsKey, $itemKey, self::POSITION_END); + break; + default: + throw new Swift_SwiftException( + 'Invalid mode ['.$mode.'] used to set nsKey='. + $nsKey.', itemKey='.$itemKey + ); + break; + } + fwrite($fp, $string); + $this->_freeHandle($nsKey, $itemKey); + } + + /** + * Set a ByteStream into the cache under $itemKey for the namespace $nsKey. + * + * @see MODE_WRITE, MODE_APPEND + * + * @param string $nsKey + * @param string $itemKey + * @param Swift_OutputByteStream $os + * @param int $mode + * + * @throws Swift_IoException + */ + public function importFromByteStream($nsKey, $itemKey, Swift_OutputByteStream $os, $mode) + { + $this->_prepareCache($nsKey); + switch ($mode) { + case self::MODE_WRITE: + $fp = $this->_getHandle($nsKey, $itemKey, self::POSITION_START); + break; + case self::MODE_APPEND: + $fp = $this->_getHandle($nsKey, $itemKey, self::POSITION_END); + break; + default: + throw new Swift_SwiftException( + 'Invalid mode ['.$mode.'] used to set nsKey='. + $nsKey.', itemKey='.$itemKey + ); + break; + } + while (false !== $bytes = $os->read(8192)) { + fwrite($fp, $bytes); + } + $this->_freeHandle($nsKey, $itemKey); + } + + /** + * Provides a ByteStream which when written to, writes data to $itemKey. + * + * NOTE: The stream will always write in append mode. + * + * @param string $nsKey + * @param string $itemKey + * @param Swift_InputByteStream $writeThrough + * + * @return Swift_InputByteStream + */ + public function getInputByteStream($nsKey, $itemKey, Swift_InputByteStream $writeThrough = null) + { + $is = clone $this->_stream; + $is->setKeyCache($this); + $is->setNsKey($nsKey); + $is->setItemKey($itemKey); + if (isset($writeThrough)) { + $is->setWriteThroughStream($writeThrough); + } + + return $is; + } + + /** + * Get data back out of the cache as a string. + * + * @param string $nsKey + * @param string $itemKey + * + * @throws Swift_IoException + * + * @return string + */ + public function getString($nsKey, $itemKey) + { + $this->_prepareCache($nsKey); + if ($this->hasKey($nsKey, $itemKey)) { + $fp = $this->_getHandle($nsKey, $itemKey, self::POSITION_START); + if ($this->_quotes) { + ini_set('magic_quotes_runtime', 0); + } + $str = ''; + while (!feof($fp) && false !== $bytes = fread($fp, 8192)) { + $str .= $bytes; + } + if ($this->_quotes) { + ini_set('magic_quotes_runtime', 1); + } + $this->_freeHandle($nsKey, $itemKey); + + return $str; + } + } + + /** + * Get data back out of the cache as a ByteStream. + * + * @param string $nsKey + * @param string $itemKey + * @param Swift_InputByteStream $is to write the data to + */ + public function exportToByteStream($nsKey, $itemKey, Swift_InputByteStream $is) + { + if ($this->hasKey($nsKey, $itemKey)) { + $fp = $this->_getHandle($nsKey, $itemKey, self::POSITION_START); + if ($this->_quotes) { + ini_set('magic_quotes_runtime', 0); + } + while (!feof($fp) && false !== $bytes = fread($fp, 8192)) { + $is->write($bytes); + } + if ($this->_quotes) { + ini_set('magic_quotes_runtime', 1); + } + $this->_freeHandle($nsKey, $itemKey); + } + } + + /** + * Check if the given $itemKey exists in the namespace $nsKey. + * + * @param string $nsKey + * @param string $itemKey + * + * @return bool + */ + public function hasKey($nsKey, $itemKey) + { + return is_file($this->_path.'/'.$nsKey.'/'.$itemKey); + } + + /** + * Clear data for $itemKey in the namespace $nsKey if it exists. + * + * @param string $nsKey + * @param string $itemKey + */ + public function clearKey($nsKey, $itemKey) + { + if ($this->hasKey($nsKey, $itemKey)) { + $this->_freeHandle($nsKey, $itemKey); + unlink($this->_path.'/'.$nsKey.'/'.$itemKey); + } + } + + /** + * Clear all data in the namespace $nsKey if it exists. + * + * @param string $nsKey + */ + public function clearAll($nsKey) + { + if (array_key_exists($nsKey, $this->_keys)) { + foreach ($this->_keys[$nsKey] as $itemKey => $null) { + $this->clearKey($nsKey, $itemKey); + } + if (is_dir($this->_path.'/'.$nsKey)) { + rmdir($this->_path.'/'.$nsKey); + } + unset($this->_keys[$nsKey]); + } + } + + /** + * Initialize the namespace of $nsKey if needed. + * + * @param string $nsKey + */ + private function _prepareCache($nsKey) + { + $cacheDir = $this->_path.'/'.$nsKey; + if (!is_dir($cacheDir)) { + if (!mkdir($cacheDir)) { + throw new Swift_IoException('Failed to create cache directory '.$cacheDir); + } + $this->_keys[$nsKey] = array(); + } + } + + /** + * Get a file handle on the cache item. + * + * @param string $nsKey + * @param string $itemKey + * @param int $position + * + * @return resource + */ + private function _getHandle($nsKey, $itemKey, $position) + { + if (!isset($this->_keys[$nsKey][$itemKey])) { + $openMode = $this->hasKey($nsKey, $itemKey) ? 'r+b' : 'w+b'; + $fp = fopen($this->_path.'/'.$nsKey.'/'.$itemKey, $openMode); + $this->_keys[$nsKey][$itemKey] = $fp; + } + if (self::POSITION_START == $position) { + fseek($this->_keys[$nsKey][$itemKey], 0, SEEK_SET); + } elseif (self::POSITION_END == $position) { + fseek($this->_keys[$nsKey][$itemKey], 0, SEEK_END); + } + + return $this->_keys[$nsKey][$itemKey]; + } + + private function _freeHandle($nsKey, $itemKey) + { + $fp = $this->_getHandle($nsKey, $itemKey, self::POSITION_CURRENT); + fclose($fp); + $this->_keys[$nsKey][$itemKey] = null; + } + + /** + * Destructor. + */ + public function __destruct() + { + foreach ($this->_keys as $nsKey => $null) { + $this->clearAll($nsKey); + } + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/KeyCache/KeyCacheInputStream.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/KeyCache/KeyCacheInputStream.php new file mode 100644 index 0000000..af80bdc --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/KeyCache/KeyCacheInputStream.php @@ -0,0 +1,51 @@ +_keyCache = $keyCache; + } + + /** + * Specify a stream to write through for each write(). + * + * @param Swift_InputByteStream $is + */ + public function setWriteThroughStream(Swift_InputByteStream $is) + { + $this->_writeThrough = $is; + } + + /** + * Writes $bytes to the end of the stream. + * + * @param string $bytes + * @param Swift_InputByteStream $is optional + */ + public function write($bytes, Swift_InputByteStream $is = null) + { + $this->_keyCache->setString( + $this->_nsKey, $this->_itemKey, $bytes, Swift_KeyCache::MODE_APPEND + ); + if (isset($is)) { + $is->write($bytes); + } + if (isset($this->_writeThrough)) { + $this->_writeThrough->write($bytes); + } + } + + /** + * Not used. + */ + public function commit() + { + } + + /** + * Not used. + */ + public function bind(Swift_InputByteStream $is) + { + } + + /** + * Not used. + */ + public function unbind(Swift_InputByteStream $is) + { + } + + /** + * Flush the contents of the stream (empty it) and set the internal pointer + * to the beginning. + */ + public function flushBuffers() + { + $this->_keyCache->clearKey($this->_nsKey, $this->_itemKey); + } + + /** + * Set the nsKey which will be written to. + * + * @param string $nsKey + */ + public function setNsKey($nsKey) + { + $this->_nsKey = $nsKey; + } + + /** + * Set the itemKey which will be written to. + * + * @param string $itemKey + */ + public function setItemKey($itemKey) + { + $this->_itemKey = $itemKey; + } + + /** + * Any implementation should be cloneable, allowing the clone to access a + * separate $nsKey and $itemKey. + */ + public function __clone() + { + $this->_writeThrough = null; + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/LoadBalancedTransport.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/LoadBalancedTransport.php new file mode 100644 index 0000000..e151b8a --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/LoadBalancedTransport.php @@ -0,0 +1,45 @@ +createDependenciesFor('transport.loadbalanced') + ); + + $this->setTransports($transports); + } + + /** + * Create a new LoadBalancedTransport instance. + * + * @param array $transports + * + * @return self + */ + public static function newInstance($transports = array()) + { + return new self($transports); + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/MailTransport.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/MailTransport.php new file mode 100644 index 0000000..1855698 --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/MailTransport.php @@ -0,0 +1,47 @@ +createDependenciesFor('transport.mail') + ); + + $this->setExtraParams($extraParams); + } + + /** + * Create a new MailTransport instance. + * + * @param string $extraParams To be passed to mail() + * + * @return self + */ + public static function newInstance($extraParams = '-f%s') + { + return new self($extraParams); + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mailer.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mailer.php new file mode 100644 index 0000000..8314fe8 --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mailer.php @@ -0,0 +1,114 @@ +_transport = $transport; + } + + /** + * Create a new Mailer instance. + * + * @param Swift_Transport $transport + * + * @return self + */ + public static function newInstance(Swift_Transport $transport) + { + return new self($transport); + } + + /** + * Create a new class instance of one of the message services. + * + * For example 'mimepart' would create a 'message.mimepart' instance + * + * @param string $service + * + * @return object + */ + public function createMessage($service = 'message') + { + return Swift_DependencyContainer::getInstance() + ->lookup('message.'.$service); + } + + /** + * Send the given Message like it would be sent in a mail client. + * + * All recipients (with the exception of Bcc) will be able to see the other + * recipients this message was sent to. + * + * Recipient/sender data will be retrieved from the Message object. + * + * The return value is the number of recipients who were accepted for + * delivery. + * + * @param Swift_Mime_Message $message + * @param array $failedRecipients An array of failures by-reference + * + * @return int The number of successful recipients. Can be 0 which indicates failure + */ + public function send(Swift_Mime_Message $message, &$failedRecipients = null) + { + $failedRecipients = (array) $failedRecipients; + + if (!$this->_transport->isStarted()) { + $this->_transport->start(); + } + + $sent = 0; + + try { + $sent = $this->_transport->send($message, $failedRecipients); + } catch (Swift_RfcComplianceException $e) { + foreach ($message->getTo() as $address => $name) { + $failedRecipients[] = $address; + } + } + + return $sent; + } + + /** + * Register a plugin using a known unique key (e.g. myPlugin). + * + * @param Swift_Events_EventListener $plugin + */ + public function registerPlugin(Swift_Events_EventListener $plugin) + { + $this->_transport->registerPlugin($plugin); + } + + /** + * The Transport used to send messages. + * + * @return Swift_Transport + */ + public function getTransport() + { + return $this->_transport; + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mailer/ArrayRecipientIterator.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mailer/ArrayRecipientIterator.php new file mode 100644 index 0000000..e3e6cad --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mailer/ArrayRecipientIterator.php @@ -0,0 +1,55 @@ +_recipients = $recipients; + } + + /** + * Returns true only if there are more recipients to send to. + * + * @return bool + */ + public function hasNext() + { + return !empty($this->_recipients); + } + + /** + * Returns an array where the keys are the addresses of recipients and the + * values are the names. e.g. ('foo@bar' => 'Foo') or ('foo@bar' => NULL). + * + * @return array + */ + public function nextRecipient() + { + return array_splice($this->_recipients, 0, 1); + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mailer/RecipientIterator.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mailer/RecipientIterator.php new file mode 100644 index 0000000..650f3ec --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mailer/RecipientIterator.php @@ -0,0 +1,32 @@ + 'Foo') or ('foo@bar' => NULL). + * + * @return array + */ + public function nextRecipient(); +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/MemorySpool.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/MemorySpool.php new file mode 100644 index 0000000..2cafb67 --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/MemorySpool.php @@ -0,0 +1,110 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * Stores Messages in memory. + * + * @author Fabien Potencier + */ +class Swift_MemorySpool implements Swift_Spool +{ + protected $messages = array(); + private $flushRetries = 3; + + /** + * Tests if this Transport mechanism has started. + * + * @return bool + */ + public function isStarted() + { + return true; + } + + /** + * Starts this Transport mechanism. + */ + public function start() + { + } + + /** + * Stops this Transport mechanism. + */ + public function stop() + { + } + + /** + * @param int $retries + */ + public function setFlushRetries($retries) + { + $this->flushRetries = $retries; + } + + /** + * Stores a message in the queue. + * + * @param Swift_Mime_Message $message The message to store + * + * @return bool Whether the operation has succeeded + */ + public function queueMessage(Swift_Mime_Message $message) + { + //clone the message to make sure it is not changed while in the queue + $this->messages[] = clone $message; + + return true; + } + + /** + * Sends messages using the given transport instance. + * + * @param Swift_Transport $transport A transport instance + * @param string[] $failedRecipients An array of failures by-reference + * + * @return int The number of sent emails + */ + public function flushQueue(Swift_Transport $transport, &$failedRecipients = null) + { + if (!$this->messages) { + return 0; + } + + if (!$transport->isStarted()) { + $transport->start(); + } + + $count = 0; + $retries = $this->flushRetries; + while ($retries--) { + try { + while ($message = array_pop($this->messages)) { + $count += $transport->send($message, $failedRecipients); + } + } catch (Swift_TransportException $exception) { + if ($retries) { + // re-queue the message at the end of the queue to give a chance + // to the other messages to be sent, in case the failure was due to + // this message and not just the transport failing + array_unshift($this->messages, $message); + + // wait half a second before we try again + usleep(500000); + } else { + throw $exception; + } + } + } + + return $count; + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Message.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Message.php new file mode 100644 index 0000000..242cbf3 --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Message.php @@ -0,0 +1,289 @@ +createDependenciesFor('mime.message') + ); + + if (!isset($charset)) { + $charset = Swift_DependencyContainer::getInstance() + ->lookup('properties.charset'); + } + $this->setSubject($subject); + $this->setBody($body); + $this->setCharset($charset); + if ($contentType) { + $this->setContentType($contentType); + } + } + + /** + * Create a new Message. + * + * @param string $subject + * @param string $body + * @param string $contentType + * @param string $charset + * + * @return $this + */ + public static function newInstance($subject = null, $body = null, $contentType = null, $charset = null) + { + return new self($subject, $body, $contentType, $charset); + } + + /** + * Add a MimePart to this Message. + * + * @param string|Swift_OutputByteStream $body + * @param string $contentType + * @param string $charset + * + * @return $this + */ + public function addPart($body, $contentType = null, $charset = null) + { + return $this->attach(Swift_MimePart::newInstance($body, $contentType, $charset)->setEncoder($this->getEncoder())); + } + + /** + * Detach a signature handler from a message. + * + * @param Swift_Signer $signer + * + * @return $this + */ + public function attachSigner(Swift_Signer $signer) + { + if ($signer instanceof Swift_Signers_HeaderSigner) { + $this->headerSigners[] = $signer; + } elseif ($signer instanceof Swift_Signers_BodySigner) { + $this->bodySigners[] = $signer; + } + + return $this; + } + + /** + * Attach a new signature handler to the message. + * + * @param Swift_Signer $signer + * + * @return $this + */ + public function detachSigner(Swift_Signer $signer) + { + if ($signer instanceof Swift_Signers_HeaderSigner) { + foreach ($this->headerSigners as $k => $headerSigner) { + if ($headerSigner === $signer) { + unset($this->headerSigners[$k]); + + return $this; + } + } + } elseif ($signer instanceof Swift_Signers_BodySigner) { + foreach ($this->bodySigners as $k => $bodySigner) { + if ($bodySigner === $signer) { + unset($this->bodySigners[$k]); + + return $this; + } + } + } + + return $this; + } + + /** + * Get this message as a complete string. + * + * @return string + */ + public function toString() + { + if (empty($this->headerSigners) && empty($this->bodySigners)) { + return parent::toString(); + } + + $this->saveMessage(); + + $this->doSign(); + + $string = parent::toString(); + + $this->restoreMessage(); + + return $string; + } + + /** + * Write this message to a {@link Swift_InputByteStream}. + * + * @param Swift_InputByteStream $is + */ + public function toByteStream(Swift_InputByteStream $is) + { + if (empty($this->headerSigners) && empty($this->bodySigners)) { + parent::toByteStream($is); + + return; + } + + $this->saveMessage(); + + $this->doSign(); + + parent::toByteStream($is); + + $this->restoreMessage(); + } + + public function __wakeup() + { + Swift_DependencyContainer::getInstance()->createDependenciesFor('mime.message'); + } + + /** + * loops through signers and apply the signatures. + */ + protected function doSign() + { + foreach ($this->bodySigners as $signer) { + $altered = $signer->getAlteredHeaders(); + $this->saveHeaders($altered); + $signer->signMessage($this); + } + + foreach ($this->headerSigners as $signer) { + $altered = $signer->getAlteredHeaders(); + $this->saveHeaders($altered); + $signer->reset(); + + $signer->setHeaders($this->getHeaders()); + + $signer->startBody(); + $this->_bodyToByteStream($signer); + $signer->endBody(); + + $signer->addSignature($this->getHeaders()); + } + } + + /** + * save the message before any signature is applied. + */ + protected function saveMessage() + { + $this->savedMessage = array('headers' => array()); + $this->savedMessage['body'] = $this->getBody(); + $this->savedMessage['children'] = $this->getChildren(); + if (count($this->savedMessage['children']) > 0 && $this->getBody() != '') { + $this->setChildren(array_merge(array($this->_becomeMimePart()), $this->savedMessage['children'])); + $this->setBody(''); + } + } + + /** + * save the original headers. + * + * @param array $altered + */ + protected function saveHeaders(array $altered) + { + foreach ($altered as $head) { + $lc = strtolower($head); + + if (!isset($this->savedMessage['headers'][$lc])) { + $this->savedMessage['headers'][$lc] = $this->getHeaders()->getAll($head); + } + } + } + + /** + * Remove or restore altered headers. + */ + protected function restoreHeaders() + { + foreach ($this->savedMessage['headers'] as $name => $savedValue) { + $headers = $this->getHeaders()->getAll($name); + + foreach ($headers as $key => $value) { + if (!isset($savedValue[$key])) { + $this->getHeaders()->remove($name, $key); + } + } + } + } + + /** + * Restore message body. + */ + protected function restoreMessage() + { + $this->setBody($this->savedMessage['body']); + $this->setChildren($this->savedMessage['children']); + + $this->restoreHeaders(); + $this->savedMessage = array(); + } + + /** + * Clone Message Signers. + * + * @see Swift_Mime_SimpleMimeEntity::__clone() + */ + public function __clone() + { + parent::__clone(); + foreach ($this->bodySigners as $key => $bodySigner) { + $this->bodySigners[$key] = clone $bodySigner; + } + + foreach ($this->headerSigners as $key => $headerSigner) { + $this->headerSigners[$key] = clone $headerSigner; + } + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Attachment.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Attachment.php new file mode 100644 index 0000000..d5ba14b --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Attachment.php @@ -0,0 +1,149 @@ +setDisposition('attachment'); + $this->setContentType('application/octet-stream'); + $this->_mimeTypes = $mimeTypes; + } + + /** + * Get the nesting level used for this attachment. + * + * Always returns {@link LEVEL_MIXED}. + * + * @return int + */ + public function getNestingLevel() + { + return self::LEVEL_MIXED; + } + + /** + * Get the Content-Disposition of this attachment. + * + * By default attachments have a disposition of "attachment". + * + * @return string + */ + public function getDisposition() + { + return $this->_getHeaderFieldModel('Content-Disposition'); + } + + /** + * Set the Content-Disposition of this attachment. + * + * @param string $disposition + * + * @return $this + */ + public function setDisposition($disposition) + { + if (!$this->_setHeaderFieldModel('Content-Disposition', $disposition)) { + $this->getHeaders()->addParameterizedHeader('Content-Disposition', $disposition); + } + + return $this; + } + + /** + * Get the filename of this attachment when downloaded. + * + * @return string + */ + public function getFilename() + { + return $this->_getHeaderParameter('Content-Disposition', 'filename'); + } + + /** + * Set the filename of this attachment. + * + * @param string $filename + * + * @return $this + */ + public function setFilename($filename) + { + $this->_setHeaderParameter('Content-Disposition', 'filename', $filename); + $this->_setHeaderParameter('Content-Type', 'name', $filename); + + return $this; + } + + /** + * Get the file size of this attachment. + * + * @return int + */ + public function getSize() + { + return $this->_getHeaderParameter('Content-Disposition', 'size'); + } + + /** + * Set the file size of this attachment. + * + * @param int $size + * + * @return $this + */ + public function setSize($size) + { + $this->_setHeaderParameter('Content-Disposition', 'size', $size); + + return $this; + } + + /** + * Set the file that this attachment is for. + * + * @param Swift_FileStream $file + * @param string $contentType optional + * + * @return $this + */ + public function setFile(Swift_FileStream $file, $contentType = null) + { + $this->setFilename(basename($file->getPath())); + $this->setBody($file, $contentType); + if (!isset($contentType)) { + $extension = strtolower(substr($file->getPath(), strrpos($file->getPath(), '.') + 1)); + + if (array_key_exists($extension, $this->_mimeTypes)) { + $this->setContentType($this->_mimeTypes[$extension]); + } + } + + return $this; + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/CharsetObserver.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/CharsetObserver.php new file mode 100644 index 0000000..b49c3a8 --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/CharsetObserver.php @@ -0,0 +1,24 @@ += $maxLineLength || 76 < $maxLineLength) { + $maxLineLength = 76; + } + + $remainder = 0; + $base64ReadBufferRemainderBytes = null; + + // To reduce memory usage, the output buffer is streamed to the input buffer like so: + // Output Stream => base64encode => wrap line length => Input Stream + // HOWEVER it's important to note that base64_encode() should only be passed whole triplets of data (except for the final chunk of data) + // otherwise it will assume the input data has *ended* and it will incorrectly pad/terminate the base64 data mid-stream. + // We use $base64ReadBufferRemainderBytes to carry over 1-2 "remainder" bytes from the each chunk from OutputStream and pre-pend those onto the + // chunk of bytes read in the next iteration. + // When the OutputStream is empty, we must flush any remainder bytes. + while (true) { + $readBytes = $os->read(8192); + $atEOF = ($readBytes === false); + + if ($atEOF) { + $streamTheseBytes = $base64ReadBufferRemainderBytes; + } else { + $streamTheseBytes = $base64ReadBufferRemainderBytes.$readBytes; + } + $base64ReadBufferRemainderBytes = null; + $bytesLength = strlen($streamTheseBytes); + + if ($bytesLength === 0) { // no data left to encode + break; + } + + // if we're not on the last block of the ouput stream, make sure $streamTheseBytes ends with a complete triplet of data + // and carry over remainder 1-2 bytes to the next loop iteration + if (!$atEOF) { + $excessBytes = $bytesLength % 3; + if ($excessBytes !== 0) { + $base64ReadBufferRemainderBytes = substr($streamTheseBytes, -$excessBytes); + $streamTheseBytes = substr($streamTheseBytes, 0, $bytesLength - $excessBytes); + } + } + + $encoded = base64_encode($streamTheseBytes); + $encodedTransformed = ''; + $thisMaxLineLength = $maxLineLength - $remainder - $firstLineOffset; + + while ($thisMaxLineLength < strlen($encoded)) { + $encodedTransformed .= substr($encoded, 0, $thisMaxLineLength)."\r\n"; + $firstLineOffset = 0; + $encoded = substr($encoded, $thisMaxLineLength); + $thisMaxLineLength = $maxLineLength; + $remainder = 0; + } + + if (0 < $remainingLength = strlen($encoded)) { + $remainder += $remainingLength; + $encodedTransformed .= $encoded; + $encoded = null; + } + + $is->write($encodedTransformed); + + if ($atEOF) { + break; + } + } + } + + /** + * Get the name of this encoding scheme. + * Returns the string 'base64'. + * + * @return string + */ + public function getName() + { + return 'base64'; + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/NativeQpContentEncoder.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/NativeQpContentEncoder.php new file mode 100644 index 0000000..710b5ac --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/NativeQpContentEncoder.php @@ -0,0 +1,123 @@ +charset = $charset ? $charset : 'utf-8'; + } + + /** + * Notify this observer that the entity's charset has changed. + * + * @param string $charset + */ + public function charsetChanged($charset) + { + $this->charset = $charset; + } + + /** + * Encode $in to $out. + * + * @param Swift_OutputByteStream $os to read from + * @param Swift_InputByteStream $is to write to + * @param int $firstLineOffset + * @param int $maxLineLength 0 indicates the default length for this encoding + * + * @throws RuntimeException + */ + public function encodeByteStream(Swift_OutputByteStream $os, Swift_InputByteStream $is, $firstLineOffset = 0, $maxLineLength = 0) + { + if ($this->charset !== 'utf-8') { + throw new RuntimeException( + sprintf('Charset "%s" not supported. NativeQpContentEncoder only supports "utf-8"', $this->charset)); + } + + $string = ''; + + while (false !== $bytes = $os->read(8192)) { + $string .= $bytes; + } + + $is->write($this->encodeString($string)); + } + + /** + * Get the MIME name of this content encoding scheme. + * + * @return string + */ + public function getName() + { + return 'quoted-printable'; + } + + /** + * Encode a given string to produce an encoded string. + * + * @param string $string + * @param int $firstLineOffset if first line needs to be shorter + * @param int $maxLineLength 0 indicates the default length for this encoding + * + * @throws RuntimeException + * + * @return string + */ + public function encodeString($string, $firstLineOffset = 0, $maxLineLength = 0) + { + if ($this->charset !== 'utf-8') { + throw new RuntimeException( + sprintf('Charset "%s" not supported. NativeQpContentEncoder only supports "utf-8"', $this->charset)); + } + + return $this->_standardize(quoted_printable_encode($string)); + } + + /** + * Make sure CRLF is correct and HT/SPACE are in valid places. + * + * @param string $string + * + * @return string + */ + protected function _standardize($string) + { + // transform CR or LF to CRLF + $string = preg_replace('~=0D(?!=0A)|(?_name = $name; + $this->_canonical = $canonical; + } + + /** + * Encode a given string to produce an encoded string. + * + * @param string $string + * @param int $firstLineOffset ignored + * @param int $maxLineLength - 0 means no wrapping will occur + * + * @return string + */ + public function encodeString($string, $firstLineOffset = 0, $maxLineLength = 0) + { + if ($this->_canonical) { + $string = $this->_canonicalize($string); + } + + return $this->_safeWordWrap($string, $maxLineLength, "\r\n"); + } + + /** + * Encode stream $in to stream $out. + * + * @param Swift_OutputByteStream $os + * @param Swift_InputByteStream $is + * @param int $firstLineOffset ignored + * @param int $maxLineLength optional, 0 means no wrapping will occur + */ + public function encodeByteStream(Swift_OutputByteStream $os, Swift_InputByteStream $is, $firstLineOffset = 0, $maxLineLength = 0) + { + $leftOver = ''; + while (false !== $bytes = $os->read(8192)) { + $toencode = $leftOver.$bytes; + if ($this->_canonical) { + $toencode = $this->_canonicalize($toencode); + } + $wrapped = $this->_safeWordWrap($toencode, $maxLineLength, "\r\n"); + $lastLinePos = strrpos($wrapped, "\r\n"); + $leftOver = substr($wrapped, $lastLinePos); + $wrapped = substr($wrapped, 0, $lastLinePos); + + $is->write($wrapped); + } + if (strlen($leftOver)) { + $is->write($leftOver); + } + } + + /** + * Get the name of this encoding scheme. + * + * @return string + */ + public function getName() + { + return $this->_name; + } + + /** + * Not used. + */ + public function charsetChanged($charset) + { + } + + /** + * A safer (but weaker) wordwrap for unicode. + * + * @param string $string + * @param int $length + * @param string $le + * + * @return string + */ + private function _safeWordwrap($string, $length = 75, $le = "\r\n") + { + if (0 >= $length) { + return $string; + } + + $originalLines = explode($le, $string); + + $lines = array(); + $lineCount = 0; + + foreach ($originalLines as $originalLine) { + $lines[] = ''; + $currentLine = &$lines[$lineCount++]; + + //$chunks = preg_split('/(?<=[\ \t,\.!\?\-&\+\/])/', $originalLine); + $chunks = preg_split('/(?<=\s)/', $originalLine); + + foreach ($chunks as $chunk) { + if (0 != strlen($currentLine) + && strlen($currentLine.$chunk) > $length) { + $lines[] = ''; + $currentLine = &$lines[$lineCount++]; + } + $currentLine .= $chunk; + } + } + + return implode("\r\n", $lines); + } + + /** + * Canonicalize string input (fix CRLF). + * + * @param string $string + * + * @return string + */ + private function _canonicalize($string) + { + return str_replace( + array("\r\n", "\r", "\n"), + array("\n", "\n", "\r\n"), + $string + ); + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/QpContentEncoder.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/QpContentEncoder.php new file mode 100644 index 0000000..5cc907b --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/QpContentEncoder.php @@ -0,0 +1,134 @@ +_dotEscape = $dotEscape; + parent::__construct($charStream, $filter); + } + + public function __sleep() + { + return array('_charStream', '_filter', '_dotEscape'); + } + + protected function getSafeMapShareId() + { + return get_class($this).($this->_dotEscape ? '.dotEscape' : ''); + } + + protected function initSafeMap() + { + parent::initSafeMap(); + if ($this->_dotEscape) { + /* Encode . as =2e for buggy remote servers */ + unset($this->_safeMap[0x2e]); + } + } + + /** + * Encode stream $in to stream $out. + * + * QP encoded strings have a maximum line length of 76 characters. + * If the first line needs to be shorter, indicate the difference with + * $firstLineOffset. + * + * @param Swift_OutputByteStream $os output stream + * @param Swift_InputByteStream $is input stream + * @param int $firstLineOffset + * @param int $maxLineLength + */ + public function encodeByteStream(Swift_OutputByteStream $os, Swift_InputByteStream $is, $firstLineOffset = 0, $maxLineLength = 0) + { + if ($maxLineLength > 76 || $maxLineLength <= 0) { + $maxLineLength = 76; + } + + $thisLineLength = $maxLineLength - $firstLineOffset; + + $this->_charStream->flushContents(); + $this->_charStream->importByteStream($os); + + $currentLine = ''; + $prepend = ''; + $size = $lineLen = 0; + + while (false !== $bytes = $this->_nextSequence()) { + // If we're filtering the input + if (isset($this->_filter)) { + // If we can't filter because we need more bytes + while ($this->_filter->shouldBuffer($bytes)) { + // Then collect bytes into the buffer + if (false === $moreBytes = $this->_nextSequence(1)) { + break; + } + + foreach ($moreBytes as $b) { + $bytes[] = $b; + } + } + // And filter them + $bytes = $this->_filter->filter($bytes); + } + + $enc = $this->_encodeByteSequence($bytes, $size); + + $i = strpos($enc, '=0D=0A'); + $newLineLength = $lineLen + ($i === false ? $size : $i); + + if ($currentLine && $newLineLength >= $thisLineLength) { + $is->write($prepend.$this->_standardize($currentLine)); + $currentLine = ''; + $prepend = "=\r\n"; + $thisLineLength = $maxLineLength; + $lineLen = 0; + } + + $currentLine .= $enc; + + if ($i === false) { + $lineLen += $size; + } else { + // 6 is the length of '=0D=0A'. + $lineLen = $size - strrpos($enc, '=0D=0A') - 6; + } + } + if (strlen($currentLine)) { + $is->write($prepend.$this->_standardize($currentLine)); + } + } + + /** + * Get the name of this encoding scheme. + * Returns the string 'quoted-printable'. + * + * @return string + */ + public function getName() + { + return 'quoted-printable'; + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/QpContentEncoderProxy.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/QpContentEncoderProxy.php new file mode 100644 index 0000000..3214e1c --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/QpContentEncoderProxy.php @@ -0,0 +1,98 @@ + + */ +class Swift_Mime_ContentEncoder_QpContentEncoderProxy implements Swift_Mime_ContentEncoder +{ + /** + * @var Swift_Mime_ContentEncoder_QpContentEncoder + */ + private $safeEncoder; + + /** + * @var Swift_Mime_ContentEncoder_NativeQpContentEncoder + */ + private $nativeEncoder; + + /** + * @var null|string + */ + private $charset; + + /** + * Constructor. + * + * @param Swift_Mime_ContentEncoder_QpContentEncoder $safeEncoder + * @param Swift_Mime_ContentEncoder_NativeQpContentEncoder $nativeEncoder + * @param string|null $charset + */ + public function __construct(Swift_Mime_ContentEncoder_QpContentEncoder $safeEncoder, Swift_Mime_ContentEncoder_NativeQpContentEncoder $nativeEncoder, $charset) + { + $this->safeEncoder = $safeEncoder; + $this->nativeEncoder = $nativeEncoder; + $this->charset = $charset; + } + + /** + * Make a deep copy of object. + */ + public function __clone() + { + $this->safeEncoder = clone $this->safeEncoder; + $this->nativeEncoder = clone $this->nativeEncoder; + } + + /** + * {@inheritdoc} + */ + public function charsetChanged($charset) + { + $this->charset = $charset; + $this->safeEncoder->charsetChanged($charset); + } + + /** + * {@inheritdoc} + */ + public function encodeByteStream(Swift_OutputByteStream $os, Swift_InputByteStream $is, $firstLineOffset = 0, $maxLineLength = 0) + { + $this->getEncoder()->encodeByteStream($os, $is, $firstLineOffset, $maxLineLength); + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return 'quoted-printable'; + } + + /** + * {@inheritdoc} + */ + public function encodeString($string, $firstLineOffset = 0, $maxLineLength = 0) + { + return $this->getEncoder()->encodeString($string, $firstLineOffset, $maxLineLength); + } + + /** + * @return Swift_Mime_ContentEncoder + */ + private function getEncoder() + { + return 'utf-8' === $this->charset ? $this->nativeEncoder : $this->safeEncoder; + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/RawContentEncoder.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/RawContentEncoder.php new file mode 100644 index 0000000..0b8526e --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/RawContentEncoder.php @@ -0,0 +1,64 @@ + + */ +class Swift_Mime_ContentEncoder_RawContentEncoder implements Swift_Mime_ContentEncoder +{ + /** + * Encode a given string to produce an encoded string. + * + * @param string $string + * @param int $firstLineOffset ignored + * @param int $maxLineLength ignored + * + * @return string + */ + public function encodeString($string, $firstLineOffset = 0, $maxLineLength = 0) + { + return $string; + } + + /** + * Encode stream $in to stream $out. + * + * @param Swift_OutputByteStream $in + * @param Swift_InputByteStream $out + * @param int $firstLineOffset ignored + * @param int $maxLineLength ignored + */ + public function encodeByteStream(Swift_OutputByteStream $os, Swift_InputByteStream $is, $firstLineOffset = 0, $maxLineLength = 0) + { + while (false !== ($bytes = $os->read(8192))) { + $is->write($bytes); + } + } + + /** + * Get the name of this encoding scheme. + * + * @return string + */ + public function getName() + { + return 'raw'; + } + + /** + * Not used. + */ + public function charsetChanged($charset) + { + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/EmbeddedFile.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/EmbeddedFile.php new file mode 100644 index 0000000..6af7571 --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/EmbeddedFile.php @@ -0,0 +1,45 @@ +setDisposition('inline'); + $this->setId($this->getId()); + } + + /** + * Get the nesting level of this EmbeddedFile. + * + * Returns {@see LEVEL_RELATED}. + * + * @return int + */ + public function getNestingLevel() + { + return self::LEVEL_RELATED; + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/EncodingObserver.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/EncodingObserver.php new file mode 100644 index 0000000..cc44a6e --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/EncodingObserver.php @@ -0,0 +1,24 @@ +init(); + } + + public function __wakeup() + { + $this->init(); + } + + protected function init() + { + if (count(self::$_specials) > 0) { + return; + } + + self::$_specials = array( + '(', ')', '<', '>', '[', ']', + ':', ';', '@', ',', '.', '"', + ); + + /*** Refer to RFC 2822 for ABNF grammar ***/ + + // All basic building blocks + self::$_grammar['NO-WS-CTL'] = '[\x01-\x08\x0B\x0C\x0E-\x19\x7F]'; + self::$_grammar['WSP'] = '[ \t]'; + self::$_grammar['CRLF'] = '(?:\r\n)'; + self::$_grammar['FWS'] = '(?:(?:'.self::$_grammar['WSP'].'*'. + self::$_grammar['CRLF'].')?'.self::$_grammar['WSP'].')'; + self::$_grammar['text'] = '[\x00-\x08\x0B\x0C\x0E-\x7F]'; + self::$_grammar['quoted-pair'] = '(?:\\\\'.self::$_grammar['text'].')'; + self::$_grammar['ctext'] = '(?:'.self::$_grammar['NO-WS-CTL']. + '|[\x21-\x27\x2A-\x5B\x5D-\x7E])'; + // Uses recursive PCRE (?1) -- could be a weak point?? + self::$_grammar['ccontent'] = '(?:'.self::$_grammar['ctext'].'|'. + self::$_grammar['quoted-pair'].'|(?1))'; + self::$_grammar['comment'] = '(\((?:'.self::$_grammar['FWS'].'|'. + self::$_grammar['ccontent'].')*'.self::$_grammar['FWS'].'?\))'; + self::$_grammar['CFWS'] = '(?:(?:'.self::$_grammar['FWS'].'?'. + self::$_grammar['comment'].')*(?:(?:'.self::$_grammar['FWS'].'?'. + self::$_grammar['comment'].')|'.self::$_grammar['FWS'].'))'; + self::$_grammar['qtext'] = '(?:'.self::$_grammar['NO-WS-CTL']. + '|[\x21\x23-\x5B\x5D-\x7E])'; + self::$_grammar['qcontent'] = '(?:'.self::$_grammar['qtext'].'|'. + self::$_grammar['quoted-pair'].')'; + self::$_grammar['quoted-string'] = '(?:'.self::$_grammar['CFWS'].'?"'. + '('.self::$_grammar['FWS'].'?'.self::$_grammar['qcontent'].')*'. + self::$_grammar['FWS'].'?"'.self::$_grammar['CFWS'].'?)'; + self::$_grammar['atext'] = '[a-zA-Z0-9!#\$%&\'\*\+\-\/=\?\^_`\{\}\|~]'; + self::$_grammar['atom'] = '(?:'.self::$_grammar['CFWS'].'?'. + self::$_grammar['atext'].'+'.self::$_grammar['CFWS'].'?)'; + self::$_grammar['dot-atom-text'] = '(?:'.self::$_grammar['atext'].'+'. + '(\.'.self::$_grammar['atext'].'+)*)'; + self::$_grammar['dot-atom'] = '(?:'.self::$_grammar['CFWS'].'?'. + self::$_grammar['dot-atom-text'].'+'.self::$_grammar['CFWS'].'?)'; + self::$_grammar['word'] = '(?:'.self::$_grammar['atom'].'|'. + self::$_grammar['quoted-string'].')'; + self::$_grammar['phrase'] = '(?:'.self::$_grammar['word'].'+?)'; + self::$_grammar['no-fold-quote'] = '(?:"(?:'.self::$_grammar['qtext']. + '|'.self::$_grammar['quoted-pair'].')*")'; + self::$_grammar['dtext'] = '(?:'.self::$_grammar['NO-WS-CTL']. + '|[\x21-\x5A\x5E-\x7E])'; + self::$_grammar['no-fold-literal'] = '(?:\[(?:'.self::$_grammar['dtext']. + '|'.self::$_grammar['quoted-pair'].')*\])'; + + // Message IDs + self::$_grammar['id-left'] = '(?:'.self::$_grammar['dot-atom-text'].'|'. + self::$_grammar['no-fold-quote'].')'; + self::$_grammar['id-right'] = '(?:'.self::$_grammar['dot-atom-text'].'|'. + self::$_grammar['no-fold-literal'].')'; + + // Addresses, mailboxes and paths + self::$_grammar['local-part'] = '(?:'.self::$_grammar['dot-atom'].'|'. + self::$_grammar['quoted-string'].')'; + self::$_grammar['dcontent'] = '(?:'.self::$_grammar['dtext'].'|'. + self::$_grammar['quoted-pair'].')'; + self::$_grammar['domain-literal'] = '(?:'.self::$_grammar['CFWS'].'?\[('. + self::$_grammar['FWS'].'?'.self::$_grammar['dcontent'].')*?'. + self::$_grammar['FWS'].'?\]'.self::$_grammar['CFWS'].'?)'; + self::$_grammar['domain'] = '(?:'.self::$_grammar['dot-atom'].'|'. + self::$_grammar['domain-literal'].')'; + self::$_grammar['addr-spec'] = '(?:'.self::$_grammar['local-part'].'@'. + self::$_grammar['domain'].')'; + } + + /** + * Get the grammar defined for $name token. + * + * @param string $name exactly as written in the RFC + * + * @return string + */ + public function getDefinition($name) + { + if (array_key_exists($name, self::$_grammar)) { + return self::$_grammar[$name]; + } + + throw new Swift_RfcComplianceException( + "No such grammar '".$name."' defined." + ); + } + + /** + * Returns the tokens defined in RFC 2822 (and some related RFCs). + * + * @return array + */ + public function getGrammarDefinitions() + { + return self::$_grammar; + } + + /** + * Returns the current special characters used in the syntax which need to be escaped. + * + * @return array + */ + public function getSpecials() + { + return self::$_specials; + } + + /** + * Escape special characters in a string (convert to quoted-pairs). + * + * @param string $token + * @param string[] $include additional chars to escape + * @param string[] $exclude chars from escaping + * + * @return string + */ + public function escapeSpecials($token, $include = array(), $exclude = array()) + { + foreach (array_merge(array('\\'), array_diff(self::$_specials, $exclude), $include) as $char) { + $token = str_replace($char, '\\'.$char, $token); + } + + return $token; + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Header.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Header.php new file mode 100644 index 0000000..a8ddd27 --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Header.php @@ -0,0 +1,93 @@ +getName(), "\r\n"); + mb_internal_encoding($old); + + return $newstring; + } + + return parent::encodeString($string, $firstLineOffset, $maxLineLength); + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/HeaderEncoder/QpHeaderEncoder.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/HeaderEncoder/QpHeaderEncoder.php new file mode 100644 index 0000000..510dd66 --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/HeaderEncoder/QpHeaderEncoder.php @@ -0,0 +1,65 @@ +_safeMap[$byte] = chr($byte); + } + } + + /** + * Get the name of this encoding scheme. + * + * Returns the string 'Q'. + * + * @return string + */ + public function getName() + { + return 'Q'; + } + + /** + * Takes an unencoded string and produces a QP encoded string from it. + * + * @param string $string string to encode + * @param int $firstLineOffset optional + * @param int $maxLineLength optional, 0 indicates the default of 76 chars + * + * @return string + */ + public function encodeString($string, $firstLineOffset = 0, $maxLineLength = 0) + { + return str_replace(array(' ', '=20', "=\r\n"), array('_', '_', "\r\n"), + parent::encodeString($string, $firstLineOffset, $maxLineLength) + ); + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/HeaderFactory.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/HeaderFactory.php new file mode 100644 index 0000000..c65f26d --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/HeaderFactory.php @@ -0,0 +1,78 @@ +setGrammar($grammar); + } + + /** + * Set the character set used in this Header. + * + * @param string $charset + */ + public function setCharset($charset) + { + $this->clearCachedValueIf($charset != $this->_charset); + $this->_charset = $charset; + if (isset($this->_encoder)) { + $this->_encoder->charsetChanged($charset); + } + } + + /** + * Get the character set used in this Header. + * + * @return string + */ + public function getCharset() + { + return $this->_charset; + } + + /** + * Set the language used in this Header. + * + * For example, for US English, 'en-us'. + * This can be unspecified. + * + * @param string $lang + */ + public function setLanguage($lang) + { + $this->clearCachedValueIf($this->_lang != $lang); + $this->_lang = $lang; + } + + /** + * Get the language used in this Header. + * + * @return string + */ + public function getLanguage() + { + return $this->_lang; + } + + /** + * Set the encoder used for encoding the header. + * + * @param Swift_Mime_HeaderEncoder $encoder + */ + public function setEncoder(Swift_Mime_HeaderEncoder $encoder) + { + $this->_encoder = $encoder; + $this->setCachedValue(null); + } + + /** + * Get the encoder used for encoding this Header. + * + * @return Swift_Mime_HeaderEncoder + */ + public function getEncoder() + { + return $this->_encoder; + } + + /** + * Set the grammar used for the header. + * + * @param Swift_Mime_Grammar $grammar + */ + public function setGrammar(Swift_Mime_Grammar $grammar) + { + $this->_grammar = $grammar; + $this->setCachedValue(null); + } + + /** + * Get the grammar used for this Header. + * + * @return Swift_Mime_Grammar + */ + public function getGrammar() + { + return $this->_grammar; + } + + /** + * Get the name of this header (e.g. charset). + * + * @return string + */ + public function getFieldName() + { + return $this->_name; + } + + /** + * Set the maximum length of lines in the header (excluding EOL). + * + * @param int $lineLength + */ + public function setMaxLineLength($lineLength) + { + $this->clearCachedValueIf($this->_lineLength != $lineLength); + $this->_lineLength = $lineLength; + } + + /** + * Get the maximum permitted length of lines in this Header. + * + * @return int + */ + public function getMaxLineLength() + { + return $this->_lineLength; + } + + /** + * Get this Header rendered as a RFC 2822 compliant string. + * + * @throws Swift_RfcComplianceException + * + * @return string + */ + public function toString() + { + return $this->_tokensToString($this->toTokens()); + } + + /** + * Returns a string representation of this object. + * + * @return string + * + * @see toString() + */ + public function __toString() + { + return $this->toString(); + } + + /** + * Set the name of this Header field. + * + * @param string $name + */ + protected function setFieldName($name) + { + $this->_name = $name; + } + + /** + * Produces a compliant, formatted RFC 2822 'phrase' based on the string given. + * + * @param Swift_Mime_Header $header + * @param string $string as displayed + * @param string $charset of the text + * @param Swift_Mime_HeaderEncoder $encoder + * @param bool $shorten the first line to make remove for header name + * + * @return string + */ + protected function createPhrase(Swift_Mime_Header $header, $string, $charset, Swift_Mime_HeaderEncoder $encoder = null, $shorten = false) + { + // Treat token as exactly what was given + $phraseStr = $string; + // If it's not valid + if (!preg_match('/^'.$this->getGrammar()->getDefinition('phrase').'$/D', $phraseStr)) { + // .. but it is just ascii text, try escaping some characters + // and make it a quoted-string + if (preg_match('/^'.$this->getGrammar()->getDefinition('text').'*$/D', $phraseStr)) { + $phraseStr = $this->getGrammar()->escapeSpecials( + $phraseStr, array('"'), $this->getGrammar()->getSpecials() + ); + $phraseStr = '"'.$phraseStr.'"'; + } else { + // ... otherwise it needs encoding + // Determine space remaining on line if first line + if ($shorten) { + $usedLength = strlen($header->getFieldName().': '); + } else { + $usedLength = 0; + } + $phraseStr = $this->encodeWords($header, $string, $usedLength); + } + } + + return $phraseStr; + } + + /** + * Encode needed word tokens within a string of input. + * + * @param Swift_Mime_Header $header + * @param string $input + * @param string $usedLength optional + * + * @return string + */ + protected function encodeWords(Swift_Mime_Header $header, $input, $usedLength = -1) + { + $value = ''; + + $tokens = $this->getEncodableWordTokens($input); + + foreach ($tokens as $token) { + // See RFC 2822, Sect 2.2 (really 2.2 ??) + if ($this->tokenNeedsEncoding($token)) { + // Don't encode starting WSP + $firstChar = substr($token, 0, 1); + switch ($firstChar) { + case ' ': + case "\t": + $value .= $firstChar; + $token = substr($token, 1); + } + + if (-1 == $usedLength) { + $usedLength = strlen($header->getFieldName().': ') + strlen($value); + } + $value .= $this->getTokenAsEncodedWord($token, $usedLength); + + $header->setMaxLineLength(76); // Forcefully override + } else { + $value .= $token; + } + } + + return $value; + } + + /** + * Test if a token needs to be encoded or not. + * + * @param string $token + * + * @return bool + */ + protected function tokenNeedsEncoding($token) + { + return preg_match('~[\x00-\x08\x10-\x19\x7F-\xFF\r\n]~', $token); + } + + /** + * Splits a string into tokens in blocks of words which can be encoded quickly. + * + * @param string $string + * + * @return string[] + */ + protected function getEncodableWordTokens($string) + { + $tokens = array(); + + $encodedToken = ''; + // Split at all whitespace boundaries + foreach (preg_split('~(?=[\t ])~', $string) as $token) { + if ($this->tokenNeedsEncoding($token)) { + $encodedToken .= $token; + } else { + if (strlen($encodedToken) > 0) { + $tokens[] = $encodedToken; + $encodedToken = ''; + } + $tokens[] = $token; + } + } + if (strlen($encodedToken)) { + $tokens[] = $encodedToken; + } + + return $tokens; + } + + /** + * Get a token as an encoded word for safe insertion into headers. + * + * @param string $token token to encode + * @param int $firstLineOffset optional + * + * @return string + */ + protected function getTokenAsEncodedWord($token, $firstLineOffset = 0) + { + // Adjust $firstLineOffset to account for space needed for syntax + $charsetDecl = $this->_charset; + if (isset($this->_lang)) { + $charsetDecl .= '*'.$this->_lang; + } + $encodingWrapperLength = strlen( + '=?'.$charsetDecl.'?'.$this->_encoder->getName().'??=' + ); + + if ($firstLineOffset >= 75) { + //Does this logic need to be here? + $firstLineOffset = 0; + } + + $encodedTextLines = explode("\r\n", + $this->_encoder->encodeString( + $token, $firstLineOffset, 75 - $encodingWrapperLength, $this->_charset + ) + ); + + if (strtolower($this->_charset) !== 'iso-2022-jp') { + // special encoding for iso-2022-jp using mb_encode_mimeheader + foreach ($encodedTextLines as $lineNum => $line) { + $encodedTextLines[$lineNum] = '=?'.$charsetDecl. + '?'.$this->_encoder->getName(). + '?'.$line.'?='; + } + } + + return implode("\r\n ", $encodedTextLines); + } + + /** + * Generates tokens from the given string which include CRLF as individual tokens. + * + * @param string $token + * + * @return string[] + */ + protected function generateTokenLines($token) + { + return preg_split('~(\r\n)~', $token, -1, PREG_SPLIT_DELIM_CAPTURE); + } + + /** + * Set a value into the cache. + * + * @param string $value + */ + protected function setCachedValue($value) + { + $this->_cachedValue = $value; + } + + /** + * Get the value in the cache. + * + * @return string + */ + protected function getCachedValue() + { + return $this->_cachedValue; + } + + /** + * Clear the cached value if $condition is met. + * + * @param bool $condition + */ + protected function clearCachedValueIf($condition) + { + if ($condition) { + $this->setCachedValue(null); + } + } + + /** + * Generate a list of all tokens in the final header. + * + * @param string $string The string to tokenize + * + * @return array An array of tokens as strings + */ + protected function toTokens($string = null) + { + if (null === $string) { + $string = $this->getFieldBody(); + } + + $tokens = array(); + + // Generate atoms; split at all invisible boundaries followed by WSP + foreach (preg_split('~(?=[ \t])~', $string) as $token) { + $newTokens = $this->generateTokenLines($token); + foreach ($newTokens as $newToken) { + $tokens[] = $newToken; + } + } + + return $tokens; + } + + /** + * Takes an array of tokens which appear in the header and turns them into + * an RFC 2822 compliant string, adding FWSP where needed. + * + * @param string[] $tokens + * + * @return string + */ + private function _tokensToString(array $tokens) + { + $lineCount = 0; + $headerLines = array(); + $headerLines[] = $this->_name.': '; + $currentLine = &$headerLines[$lineCount++]; + + // Build all tokens back into compliant header + foreach ($tokens as $i => $token) { + // Line longer than specified maximum or token was just a new line + if (("\r\n" == $token) || + ($i > 0 && strlen($currentLine.$token) > $this->_lineLength) + && 0 < strlen($currentLine)) { + $headerLines[] = ''; + $currentLine = &$headerLines[$lineCount++]; + } + + // Append token to the line + if ("\r\n" != $token) { + $currentLine .= $token; + } + } + + // Implode with FWS (RFC 2822, 2.2.3) + return implode("\r\n", $headerLines)."\r\n"; + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/DateHeader.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/DateHeader.php new file mode 100644 index 0000000..4075cbf --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/DateHeader.php @@ -0,0 +1,125 @@ + + * + * + * + * @param string $name of Header + * @param Swift_Mime_Grammar $grammar + */ + public function __construct($name, Swift_Mime_Grammar $grammar) + { + $this->setFieldName($name); + parent::__construct($grammar); + } + + /** + * Get the type of Header that this instance represents. + * + * @see TYPE_TEXT, TYPE_PARAMETERIZED, TYPE_MAILBOX + * @see TYPE_DATE, TYPE_ID, TYPE_PATH + * + * @return int + */ + public function getFieldType() + { + return self::TYPE_DATE; + } + + /** + * Set the model for the field body. + * + * This method takes a UNIX timestamp. + * + * @param int $model + */ + public function setFieldBodyModel($model) + { + $this->setTimestamp($model); + } + + /** + * Get the model for the field body. + * + * This method returns a UNIX timestamp. + * + * @return mixed + */ + public function getFieldBodyModel() + { + return $this->getTimestamp(); + } + + /** + * Get the UNIX timestamp of the Date in this Header. + * + * @return int + */ + public function getTimestamp() + { + return $this->_timestamp; + } + + /** + * Set the UNIX timestamp of the Date in this Header. + * + * @param int $timestamp + */ + public function setTimestamp($timestamp) + { + if (null !== $timestamp) { + $timestamp = (int) $timestamp; + } + $this->clearCachedValueIf($this->_timestamp != $timestamp); + $this->_timestamp = $timestamp; + } + + /** + * Get the string value of the body in this Header. + * + * This is not necessarily RFC 2822 compliant since folding white space will + * not be added at this stage (see {@link toString()} for that). + * + * @see toString() + * + * @return string + */ + public function getFieldBody() + { + if (!$this->getCachedValue()) { + if (isset($this->_timestamp)) { + $this->setCachedValue(date('r', $this->_timestamp)); + } + } + + return $this->getCachedValue(); + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/IdentificationHeader.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/IdentificationHeader.php new file mode 100644 index 0000000..b114506 --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/IdentificationHeader.php @@ -0,0 +1,180 @@ +setFieldName($name); + parent::__construct($grammar); + } + + /** + * Get the type of Header that this instance represents. + * + * @see TYPE_TEXT, TYPE_PARAMETERIZED, TYPE_MAILBOX + * @see TYPE_DATE, TYPE_ID, TYPE_PATH + * + * @return int + */ + public function getFieldType() + { + return self::TYPE_ID; + } + + /** + * Set the model for the field body. + * + * This method takes a string ID, or an array of IDs. + * + * @param mixed $model + * + * @throws Swift_RfcComplianceException + */ + public function setFieldBodyModel($model) + { + $this->setId($model); + } + + /** + * Get the model for the field body. + * + * This method returns an array of IDs + * + * @return array + */ + public function getFieldBodyModel() + { + return $this->getIds(); + } + + /** + * Set the ID used in the value of this header. + * + * @param string|array $id + * + * @throws Swift_RfcComplianceException + */ + public function setId($id) + { + $this->setIds(is_array($id) ? $id : array($id)); + } + + /** + * Get the ID used in the value of this Header. + * + * If multiple IDs are set only the first is returned. + * + * @return string + */ + public function getId() + { + if (count($this->_ids) > 0) { + return $this->_ids[0]; + } + } + + /** + * Set a collection of IDs to use in the value of this Header. + * + * @param string[] $ids + * + * @throws Swift_RfcComplianceException + */ + public function setIds(array $ids) + { + $actualIds = array(); + + foreach ($ids as $id) { + $this->_assertValidId($id); + $actualIds[] = $id; + } + + $this->clearCachedValueIf($this->_ids != $actualIds); + $this->_ids = $actualIds; + } + + /** + * Get the list of IDs used in this Header. + * + * @return string[] + */ + public function getIds() + { + return $this->_ids; + } + + /** + * Get the string value of the body in this Header. + * + * This is not necessarily RFC 2822 compliant since folding white space will + * not be added at this stage (see {@see toString()} for that). + * + * @see toString() + * + * @throws Swift_RfcComplianceException + * + * @return string + */ + public function getFieldBody() + { + if (!$this->getCachedValue()) { + $angleAddrs = array(); + + foreach ($this->_ids as $id) { + $angleAddrs[] = '<'.$id.'>'; + } + + $this->setCachedValue(implode(' ', $angleAddrs)); + } + + return $this->getCachedValue(); + } + + /** + * Throws an Exception if the id passed does not comply with RFC 2822. + * + * @param string $id + * + * @throws Swift_RfcComplianceException + */ + private function _assertValidId($id) + { + if (!preg_match( + '/^'.$this->getGrammar()->getDefinition('id-left').'@'. + $this->getGrammar()->getDefinition('id-right').'$/D', + $id + )) { + throw new Swift_RfcComplianceException( + 'Invalid ID given <'.$id.'>' + ); + } + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/MailboxHeader.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/MailboxHeader.php new file mode 100644 index 0000000..e4567fc --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/MailboxHeader.php @@ -0,0 +1,351 @@ +setFieldName($name); + $this->setEncoder($encoder); + parent::__construct($grammar); + } + + /** + * Get the type of Header that this instance represents. + * + * @see TYPE_TEXT, TYPE_PARAMETERIZED, TYPE_MAILBOX + * @see TYPE_DATE, TYPE_ID, TYPE_PATH + * + * @return int + */ + public function getFieldType() + { + return self::TYPE_MAILBOX; + } + + /** + * Set the model for the field body. + * + * This method takes a string, or an array of addresses. + * + * @param mixed $model + * + * @throws Swift_RfcComplianceException + */ + public function setFieldBodyModel($model) + { + $this->setNameAddresses($model); + } + + /** + * Get the model for the field body. + * + * This method returns an associative array like {@link getNameAddresses()} + * + * @throws Swift_RfcComplianceException + * + * @return array + */ + public function getFieldBodyModel() + { + return $this->getNameAddresses(); + } + + /** + * Set a list of mailboxes to be shown in this Header. + * + * The mailboxes can be a simple array of addresses, or an array of + * key=>value pairs where (email => personalName). + * Example: + * + * setNameAddresses(array( + * 'chris@swiftmailer.org' => 'Chris Corbyn', + * 'mark@swiftmailer.org' //No associated personal name + * )); + * ?> + * + * + * @see __construct() + * @see setAddresses() + * @see setValue() + * + * @param string|string[] $mailboxes + * + * @throws Swift_RfcComplianceException + */ + public function setNameAddresses($mailboxes) + { + $this->_mailboxes = $this->normalizeMailboxes((array) $mailboxes); + $this->setCachedValue(null); //Clear any cached value + } + + /** + * Get the full mailbox list of this Header as an array of valid RFC 2822 strings. + * + * Example: + * + * 'Chris Corbyn', + * 'mark@swiftmailer.org' => 'Mark Corbyn') + * ); + * print_r($header->getNameAddressStrings()); + * // array ( + * // 0 => Chris Corbyn , + * // 1 => Mark Corbyn + * // ) + * ?> + * + * + * @see getNameAddresses() + * @see toString() + * + * @throws Swift_RfcComplianceException + * + * @return string[] + */ + public function getNameAddressStrings() + { + return $this->_createNameAddressStrings($this->getNameAddresses()); + } + + /** + * Get all mailboxes in this Header as key=>value pairs. + * + * The key is the address and the value is the name (or null if none set). + * Example: + * + * 'Chris Corbyn', + * 'mark@swiftmailer.org' => 'Mark Corbyn') + * ); + * print_r($header->getNameAddresses()); + * // array ( + * // chris@swiftmailer.org => Chris Corbyn, + * // mark@swiftmailer.org => Mark Corbyn + * // ) + * ?> + * + * + * @see getAddresses() + * @see getNameAddressStrings() + * + * @return string[] + */ + public function getNameAddresses() + { + return $this->_mailboxes; + } + + /** + * Makes this Header represent a list of plain email addresses with no names. + * + * Example: + * + * setAddresses( + * array('one@domain.tld', 'two@domain.tld', 'three@domain.tld') + * ); + * ?> + * + * + * @see setNameAddresses() + * @see setValue() + * + * @param string[] $addresses + * + * @throws Swift_RfcComplianceException + */ + public function setAddresses($addresses) + { + $this->setNameAddresses(array_values((array) $addresses)); + } + + /** + * Get all email addresses in this Header. + * + * @see getNameAddresses() + * + * @return string[] + */ + public function getAddresses() + { + return array_keys($this->_mailboxes); + } + + /** + * Remove one or more addresses from this Header. + * + * @param string|string[] $addresses + */ + public function removeAddresses($addresses) + { + $this->setCachedValue(null); + foreach ((array) $addresses as $address) { + unset($this->_mailboxes[$address]); + } + } + + /** + * Get the string value of the body in this Header. + * + * This is not necessarily RFC 2822 compliant since folding white space will + * not be added at this stage (see {@link toString()} for that). + * + * @see toString() + * + * @throws Swift_RfcComplianceException + * + * @return string + */ + public function getFieldBody() + { + // Compute the string value of the header only if needed + if (null === $this->getCachedValue()) { + $this->setCachedValue($this->createMailboxListString($this->_mailboxes)); + } + + return $this->getCachedValue(); + } + + /** + * Normalizes a user-input list of mailboxes into consistent key=>value pairs. + * + * @param string[] $mailboxes + * + * @return string[] + */ + protected function normalizeMailboxes(array $mailboxes) + { + $actualMailboxes = array(); + + foreach ($mailboxes as $key => $value) { + if (is_string($key)) { + //key is email addr + $address = $key; + $name = $value; + } else { + $address = $value; + $name = null; + } + $this->_assertValidAddress($address); + $actualMailboxes[$address] = $name; + } + + return $actualMailboxes; + } + + /** + * Produces a compliant, formatted display-name based on the string given. + * + * @param string $displayName as displayed + * @param bool $shorten the first line to make remove for header name + * + * @return string + */ + protected function createDisplayNameString($displayName, $shorten = false) + { + return $this->createPhrase($this, $displayName, $this->getCharset(), $this->getEncoder(), $shorten); + } + + /** + * Creates a string form of all the mailboxes in the passed array. + * + * @param string[] $mailboxes + * + * @throws Swift_RfcComplianceException + * + * @return string + */ + protected function createMailboxListString(array $mailboxes) + { + return implode(', ', $this->_createNameAddressStrings($mailboxes)); + } + + /** + * Redefine the encoding requirements for mailboxes. + * + * All "specials" must be encoded as the full header value will not be quoted + * + * @see RFC 2822 3.2.1 + * + * @param string $token + * + * @return bool + */ + protected function tokenNeedsEncoding($token) + { + return preg_match('/[()<>\[\]:;@\,."]/', $token) || parent::tokenNeedsEncoding($token); + } + + /** + * Return an array of strings conforming the the name-addr spec of RFC 2822. + * + * @param string[] $mailboxes + * + * @return string[] + */ + private function _createNameAddressStrings(array $mailboxes) + { + $strings = array(); + + foreach ($mailboxes as $email => $name) { + $mailboxStr = $email; + if (null !== $name) { + $nameStr = $this->createDisplayNameString($name, empty($strings)); + $mailboxStr = $nameStr.' <'.$mailboxStr.'>'; + } + $strings[] = $mailboxStr; + } + + return $strings; + } + + /** + * Throws an Exception if the address passed does not comply with RFC 2822. + * + * @param string $address + * + * @throws Swift_RfcComplianceException If invalid. + */ + private function _assertValidAddress($address) + { + if (!preg_match('/^'.$this->getGrammar()->getDefinition('addr-spec').'$/D', + $address)) { + throw new Swift_RfcComplianceException( + 'Address in mailbox given ['.$address. + '] does not comply with RFC 2822, 3.6.2.' + ); + } + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/OpenDKIMHeader.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/OpenDKIMHeader.php new file mode 100644 index 0000000..d749550 --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/OpenDKIMHeader.php @@ -0,0 +1,133 @@ + + */ +class Swift_Mime_Headers_OpenDKIMHeader implements Swift_Mime_Header +{ + /** + * The value of this Header. + * + * @var string + */ + private $_value; + + /** + * The name of this Header. + * + * @var string + */ + private $_fieldName; + + /** + * @param string $name + */ + public function __construct($name) + { + $this->_fieldName = $name; + } + + /** + * Get the type of Header that this instance represents. + * + * @see TYPE_TEXT, TYPE_PARAMETERIZED, TYPE_MAILBOX + * @see TYPE_DATE, TYPE_ID, TYPE_PATH + * + * @return int + */ + public function getFieldType() + { + return self::TYPE_TEXT; + } + + /** + * Set the model for the field body. + * + * This method takes a string for the field value. + * + * @param string $model + */ + public function setFieldBodyModel($model) + { + $this->setValue($model); + } + + /** + * Get the model for the field body. + * + * This method returns a string. + * + * @return string + */ + public function getFieldBodyModel() + { + return $this->getValue(); + } + + /** + * Get the (unencoded) value of this header. + * + * @return string + */ + public function getValue() + { + return $this->_value; + } + + /** + * Set the (unencoded) value of this header. + * + * @param string $value + */ + public function setValue($value) + { + $this->_value = $value; + } + + /** + * Get the value of this header prepared for rendering. + * + * @return string + */ + public function getFieldBody() + { + return $this->_value; + } + + /** + * Get this Header rendered as a RFC 2822 compliant string. + * + * @return string + */ + public function toString() + { + return $this->_fieldName.': '.$this->_value; + } + + /** + * Set the Header FieldName. + * + * @see Swift_Mime_Header::getFieldName() + */ + public function getFieldName() + { + return $this->_fieldName; + } + + /** + * Ignored. + */ + public function setCharset($charset) + { + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/ParameterizedHeader.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/ParameterizedHeader.php new file mode 100644 index 0000000..c1777d3 --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/ParameterizedHeader.php @@ -0,0 +1,258 @@ +_paramEncoder = $paramEncoder; + } + + /** + * Get the type of Header that this instance represents. + * + * @see TYPE_TEXT, TYPE_PARAMETERIZED, TYPE_MAILBOX + * @see TYPE_DATE, TYPE_ID, TYPE_PATH + * + * @return int + */ + public function getFieldType() + { + return self::TYPE_PARAMETERIZED; + } + + /** + * Set the character set used in this Header. + * + * @param string $charset + */ + public function setCharset($charset) + { + parent::setCharset($charset); + if (isset($this->_paramEncoder)) { + $this->_paramEncoder->charsetChanged($charset); + } + } + + /** + * Set the value of $parameter. + * + * @param string $parameter + * @param string $value + */ + public function setParameter($parameter, $value) + { + $this->setParameters(array_merge($this->getParameters(), array($parameter => $value))); + } + + /** + * Get the value of $parameter. + * + * @param string $parameter + * + * @return string + */ + public function getParameter($parameter) + { + $params = $this->getParameters(); + + return array_key_exists($parameter, $params) ? $params[$parameter] : null; + } + + /** + * Set an associative array of parameter names mapped to values. + * + * @param string[] $parameters + */ + public function setParameters(array $parameters) + { + $this->clearCachedValueIf($this->_params != $parameters); + $this->_params = $parameters; + } + + /** + * Returns an associative array of parameter names mapped to values. + * + * @return string[] + */ + public function getParameters() + { + return $this->_params; + } + + /** + * Get the value of this header prepared for rendering. + * + * @return string + */ + public function getFieldBody() //TODO: Check caching here + { + $body = parent::getFieldBody(); + foreach ($this->_params as $name => $value) { + if (null !== $value) { + // Add the parameter + $body .= '; '.$this->_createParameter($name, $value); + } + } + + return $body; + } + + /** + * Generate a list of all tokens in the final header. + * + * This doesn't need to be overridden in theory, but it is for implementation + * reasons to prevent potential breakage of attributes. + * + * @param string $string The string to tokenize + * + * @return array An array of tokens as strings + */ + protected function toTokens($string = null) + { + $tokens = parent::toTokens(parent::getFieldBody()); + + // Try creating any parameters + foreach ($this->_params as $name => $value) { + if (null !== $value) { + // Add the semi-colon separator + $tokens[count($tokens) - 1] .= ';'; + $tokens = array_merge($tokens, $this->generateTokenLines( + ' '.$this->_createParameter($name, $value) + )); + } + } + + return $tokens; + } + + /** + * Render a RFC 2047 compliant header parameter from the $name and $value. + * + * @param string $name + * @param string $value + * + * @return string + */ + private function _createParameter($name, $value) + { + $origValue = $value; + + $encoded = false; + // Allow room for parameter name, indices, "=" and DQUOTEs + $maxValueLength = $this->getMaxLineLength() - strlen($name.'=*N"";') - 1; + $firstLineOffset = 0; + + // If it's not already a valid parameter value... + if (!preg_match('/^'.self::TOKEN_REGEX.'$/D', $value)) { + // TODO: text, or something else?? + // ... and it's not ascii + if (!preg_match('/^'.$this->getGrammar()->getDefinition('text').'*$/D', $value)) { + $encoded = true; + // Allow space for the indices, charset and language + $maxValueLength = $this->getMaxLineLength() - strlen($name.'*N*="";') - 1; + $firstLineOffset = strlen( + $this->getCharset()."'".$this->getLanguage()."'" + ); + } + } + + // Encode if we need to + if ($encoded || strlen($value) > $maxValueLength) { + if (isset($this->_paramEncoder)) { + $value = $this->_paramEncoder->encodeString( + $origValue, $firstLineOffset, $maxValueLength, $this->getCharset() + ); + } else { + // We have to go against RFC 2183/2231 in some areas for interoperability + $value = $this->getTokenAsEncodedWord($origValue); + $encoded = false; + } + } + + $valueLines = isset($this->_paramEncoder) ? explode("\r\n", $value) : array($value); + + // Need to add indices + if (count($valueLines) > 1) { + $paramLines = array(); + foreach ($valueLines as $i => $line) { + $paramLines[] = $name.'*'.$i. + $this->_getEndOfParameterValue($line, true, $i == 0); + } + + return implode(";\r\n ", $paramLines); + } else { + return $name.$this->_getEndOfParameterValue( + $valueLines[0], $encoded, true + ); + } + } + + /** + * Returns the parameter value from the "=" and beyond. + * + * @param string $value to append + * @param bool $encoded + * @param bool $firstLine + * + * @return string + */ + private function _getEndOfParameterValue($value, $encoded = false, $firstLine = false) + { + if (!preg_match('/^'.self::TOKEN_REGEX.'$/D', $value)) { + $value = '"'.$value.'"'; + } + $prepend = '='; + if ($encoded) { + $prepend = '*='; + if ($firstLine) { + $prepend = '*='.$this->getCharset()."'".$this->getLanguage(). + "'"; + } + } + + return $prepend.$value; + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/PathHeader.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/PathHeader.php new file mode 100644 index 0000000..4a814b1 --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/PathHeader.php @@ -0,0 +1,143 @@ +setFieldName($name); + parent::__construct($grammar); + } + + /** + * Get the type of Header that this instance represents. + * + * @see TYPE_TEXT, TYPE_PARAMETERIZED, TYPE_MAILBOX + * @see TYPE_DATE, TYPE_ID, TYPE_PATH + * + * @return int + */ + public function getFieldType() + { + return self::TYPE_PATH; + } + + /** + * Set the model for the field body. + * This method takes a string for an address. + * + * @param string $model + * + * @throws Swift_RfcComplianceException + */ + public function setFieldBodyModel($model) + { + $this->setAddress($model); + } + + /** + * Get the model for the field body. + * This method returns a string email address. + * + * @return mixed + */ + public function getFieldBodyModel() + { + return $this->getAddress(); + } + + /** + * Set the Address which should appear in this Header. + * + * @param string $address + * + * @throws Swift_RfcComplianceException + */ + public function setAddress($address) + { + if (null === $address) { + $this->_address = null; + } elseif ('' == $address) { + $this->_address = ''; + } else { + $this->_assertValidAddress($address); + $this->_address = $address; + } + $this->setCachedValue(null); + } + + /** + * Get the address which is used in this Header (if any). + * + * Null is returned if no address is set. + * + * @return string + */ + public function getAddress() + { + return $this->_address; + } + + /** + * Get the string value of the body in this Header. + * + * This is not necessarily RFC 2822 compliant since folding white space will + * not be added at this stage (see {@link toString()} for that). + * + * @see toString() + * + * @return string + */ + public function getFieldBody() + { + if (!$this->getCachedValue()) { + if (isset($this->_address)) { + $this->setCachedValue('<'.$this->_address.'>'); + } + } + + return $this->getCachedValue(); + } + + /** + * Throws an Exception if the address passed does not comply with RFC 2822. + * + * @param string $address + * + * @throws Swift_RfcComplianceException If address is invalid + */ + private function _assertValidAddress($address) + { + if (!preg_match('/^'.$this->getGrammar()->getDefinition('addr-spec').'$/D', + $address)) { + throw new Swift_RfcComplianceException( + 'Address set in PathHeader does not comply with addr-spec of RFC 2822.' + ); + } + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/UnstructuredHeader.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/UnstructuredHeader.php new file mode 100644 index 0000000..86177f1 --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/UnstructuredHeader.php @@ -0,0 +1,112 @@ +setFieldName($name); + $this->setEncoder($encoder); + parent::__construct($grammar); + } + + /** + * Get the type of Header that this instance represents. + * + * @see TYPE_TEXT, TYPE_PARAMETERIZED, TYPE_MAILBOX + * @see TYPE_DATE, TYPE_ID, TYPE_PATH + * + * @return int + */ + public function getFieldType() + { + return self::TYPE_TEXT; + } + + /** + * Set the model for the field body. + * + * This method takes a string for the field value. + * + * @param string $model + */ + public function setFieldBodyModel($model) + { + $this->setValue($model); + } + + /** + * Get the model for the field body. + * + * This method returns a string. + * + * @return string + */ + public function getFieldBodyModel() + { + return $this->getValue(); + } + + /** + * Get the (unencoded) value of this header. + * + * @return string + */ + public function getValue() + { + return $this->_value; + } + + /** + * Set the (unencoded) value of this header. + * + * @param string $value + */ + public function setValue($value) + { + $this->clearCachedValueIf($this->_value != $value); + $this->_value = $value; + } + + /** + * Get the value of this header prepared for rendering. + * + * @return string + */ + public function getFieldBody() + { + if (!$this->getCachedValue()) { + $this->setCachedValue( + $this->encodeWords($this, $this->_value) + ); + } + + return $this->getCachedValue(); + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Message.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Message.php new file mode 100644 index 0000000..9b36d21 --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Message.php @@ -0,0 +1,223 @@ + 'Real Name'). + * + * If the second parameter is provided and the first is a string, then $name + * is associated with the address. + * + * @param mixed $address + * @param string $name optional + */ + public function setSender($address, $name = null); + + /** + * Get the sender address for this message. + * + * This has a higher significance than the From address. + * + * @return string + */ + public function getSender(); + + /** + * Set the From address of this message. + * + * It is permissible for multiple From addresses to be set using an array. + * + * If multiple From addresses are used, you SHOULD set the Sender address and + * according to RFC 2822, MUST set the sender address. + * + * An array can be used if display names are to be provided: i.e. + * array('email@address.com' => 'Real Name'). + * + * If the second parameter is provided and the first is a string, then $name + * is associated with the address. + * + * @param mixed $addresses + * @param string $name optional + */ + public function setFrom($addresses, $name = null); + + /** + * Get the From address(es) of this message. + * + * This method always returns an associative array where the keys are the + * addresses. + * + * @return string[] + */ + public function getFrom(); + + /** + * Set the Reply-To address(es). + * + * Any replies from the receiver will be sent to this address. + * + * It is permissible for multiple reply-to addresses to be set using an array. + * + * This method has the same synopsis as {@link setFrom()} and {@link setTo()}. + * + * If the second parameter is provided and the first is a string, then $name + * is associated with the address. + * + * @param mixed $addresses + * @param string $name optional + */ + public function setReplyTo($addresses, $name = null); + + /** + * Get the Reply-To addresses for this message. + * + * This method always returns an associative array where the keys provide the + * email addresses. + * + * @return string[] + */ + public function getReplyTo(); + + /** + * Set the To address(es). + * + * Recipients set in this field will receive a copy of this message. + * + * This method has the same synopsis as {@link setFrom()} and {@link setCc()}. + * + * If the second parameter is provided and the first is a string, then $name + * is associated with the address. + * + * @param mixed $addresses + * @param string $name optional + */ + public function setTo($addresses, $name = null); + + /** + * Get the To addresses for this message. + * + * This method always returns an associative array, whereby the keys provide + * the actual email addresses. + * + * @return string[] + */ + public function getTo(); + + /** + * Set the Cc address(es). + * + * Recipients set in this field will receive a 'carbon-copy' of this message. + * + * This method has the same synopsis as {@link setFrom()} and {@link setTo()}. + * + * @param mixed $addresses + * @param string $name optional + */ + public function setCc($addresses, $name = null); + + /** + * Get the Cc addresses for this message. + * + * This method always returns an associative array, whereby the keys provide + * the actual email addresses. + * + * @return string[] + */ + public function getCc(); + + /** + * Set the Bcc address(es). + * + * Recipients set in this field will receive a 'blind-carbon-copy' of this + * message. + * + * In other words, they will get the message, but any other recipients of the + * message will have no such knowledge of their receipt of it. + * + * This method has the same synopsis as {@link setFrom()} and {@link setTo()}. + * + * @param mixed $addresses + * @param string $name optional + */ + public function setBcc($addresses, $name = null); + + /** + * Get the Bcc addresses for this message. + * + * This method always returns an associative array, whereby the keys provide + * the actual email addresses. + * + * @return string[] + */ + public function getBcc(); +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/MimeEntity.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/MimeEntity.php new file mode 100644 index 0000000..30f460c --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/MimeEntity.php @@ -0,0 +1,117 @@ +setContentType('text/plain'); + if (null !== $charset) { + $this->setCharset($charset); + } + } + + /** + * Set the body of this entity, either as a string, or as an instance of + * {@link Swift_OutputByteStream}. + * + * @param mixed $body + * @param string $contentType optional + * @param string $charset optional + * + * @return $this + */ + public function setBody($body, $contentType = null, $charset = null) + { + if (isset($charset)) { + $this->setCharset($charset); + } + $body = $this->_convertString($body); + + parent::setBody($body, $contentType); + + return $this; + } + + /** + * Get the character set of this entity. + * + * @return string + */ + public function getCharset() + { + return $this->_getHeaderParameter('Content-Type', 'charset'); + } + + /** + * Set the character set of this entity. + * + * @param string $charset + * + * @return $this + */ + public function setCharset($charset) + { + $this->_setHeaderParameter('Content-Type', 'charset', $charset); + if ($charset !== $this->_userCharset) { + $this->_clearCache(); + } + $this->_userCharset = $charset; + parent::charsetChanged($charset); + + return $this; + } + + /** + * Get the format of this entity (i.e. flowed or fixed). + * + * @return string + */ + public function getFormat() + { + return $this->_getHeaderParameter('Content-Type', 'format'); + } + + /** + * Set the format of this entity (flowed or fixed). + * + * @param string $format + * + * @return $this + */ + public function setFormat($format) + { + $this->_setHeaderParameter('Content-Type', 'format', $format); + $this->_userFormat = $format; + + return $this; + } + + /** + * Test if delsp is being used for this entity. + * + * @return bool + */ + public function getDelSp() + { + return 'yes' == $this->_getHeaderParameter('Content-Type', 'delsp') ? true : false; + } + + /** + * Turn delsp on or off for this entity. + * + * @param bool $delsp + * + * @return $this + */ + public function setDelSp($delsp = true) + { + $this->_setHeaderParameter('Content-Type', 'delsp', $delsp ? 'yes' : null); + $this->_userDelSp = $delsp; + + return $this; + } + + /** + * Get the nesting level of this entity. + * + * @see LEVEL_TOP, LEVEL_ALTERNATIVE, LEVEL_MIXED, LEVEL_RELATED + * + * @return int + */ + public function getNestingLevel() + { + return $this->_nestingLevel; + } + + /** + * Receive notification that the charset has changed on this document, or a + * parent document. + * + * @param string $charset + */ + public function charsetChanged($charset) + { + $this->setCharset($charset); + } + + /** Fix the content-type and encoding of this entity */ + protected function _fixHeaders() + { + parent::_fixHeaders(); + if (count($this->getChildren())) { + $this->_setHeaderParameter('Content-Type', 'charset', null); + $this->_setHeaderParameter('Content-Type', 'format', null); + $this->_setHeaderParameter('Content-Type', 'delsp', null); + } else { + $this->setCharset($this->_userCharset); + $this->setFormat($this->_userFormat); + $this->setDelSp($this->_userDelSp); + } + } + + /** Set the nesting level of this entity */ + protected function _setNestingLevel($level) + { + $this->_nestingLevel = $level; + } + + /** Encode charset when charset is not utf-8 */ + protected function _convertString($string) + { + $charset = strtolower($this->getCharset()); + if (!in_array($charset, array('utf-8', 'iso-8859-1', 'iso-8859-15', ''))) { + // mb_convert_encoding must be the first one to check, since iconv cannot convert some words. + if (function_exists('mb_convert_encoding')) { + $string = mb_convert_encoding($string, $charset, 'utf-8'); + } elseif (function_exists('iconv')) { + $string = iconv('utf-8//TRANSLIT//IGNORE', $charset, $string); + } else { + throw new Swift_SwiftException('No suitable convert encoding function (use UTF-8 as your charset or install the mbstring or iconv extension).'); + } + + return $string; + } + + return $string; + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ParameterizedHeader.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ParameterizedHeader.php new file mode 100644 index 0000000..e15c6ef --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ParameterizedHeader.php @@ -0,0 +1,34 @@ +_encoder = $encoder; + $this->_paramEncoder = $paramEncoder; + $this->_grammar = $grammar; + $this->_charset = $charset; + } + + /** + * Create a new Mailbox Header with a list of $addresses. + * + * @param string $name + * @param array|string|null $addresses + * + * @return Swift_Mime_Header + */ + public function createMailboxHeader($name, $addresses = null) + { + $header = new Swift_Mime_Headers_MailboxHeader($name, $this->_encoder, $this->_grammar); + if (isset($addresses)) { + $header->setFieldBodyModel($addresses); + } + $this->_setHeaderCharset($header); + + return $header; + } + + /** + * Create a new Date header using $timestamp (UNIX time). + * + * @param string $name + * @param int|null $timestamp + * + * @return Swift_Mime_Header + */ + public function createDateHeader($name, $timestamp = null) + { + $header = new Swift_Mime_Headers_DateHeader($name, $this->_grammar); + if (isset($timestamp)) { + $header->setFieldBodyModel($timestamp); + } + $this->_setHeaderCharset($header); + + return $header; + } + + /** + * Create a new basic text header with $name and $value. + * + * @param string $name + * @param string $value + * + * @return Swift_Mime_Header + */ + public function createTextHeader($name, $value = null) + { + $header = new Swift_Mime_Headers_UnstructuredHeader($name, $this->_encoder, $this->_grammar); + if (isset($value)) { + $header->setFieldBodyModel($value); + } + $this->_setHeaderCharset($header); + + return $header; + } + + /** + * Create a new ParameterizedHeader with $name, $value and $params. + * + * @param string $name + * @param string $value + * @param array $params + * + * @return Swift_Mime_ParameterizedHeader + */ + public function createParameterizedHeader($name, $value = null, + $params = array()) + { + $header = new Swift_Mime_Headers_ParameterizedHeader($name, $this->_encoder, strtolower($name) == 'content-disposition' ? $this->_paramEncoder : null, $this->_grammar); + if (isset($value)) { + $header->setFieldBodyModel($value); + } + foreach ($params as $k => $v) { + $header->setParameter($k, $v); + } + $this->_setHeaderCharset($header); + + return $header; + } + + /** + * Create a new ID header for Message-ID or Content-ID. + * + * @param string $name + * @param string|array $ids + * + * @return Swift_Mime_Header + */ + public function createIdHeader($name, $ids = null) + { + $header = new Swift_Mime_Headers_IdentificationHeader($name, $this->_grammar); + if (isset($ids)) { + $header->setFieldBodyModel($ids); + } + $this->_setHeaderCharset($header); + + return $header; + } + + /** + * Create a new Path header with an address (path) in it. + * + * @param string $name + * @param string $path + * + * @return Swift_Mime_Header + */ + public function createPathHeader($name, $path = null) + { + $header = new Swift_Mime_Headers_PathHeader($name, $this->_grammar); + if (isset($path)) { + $header->setFieldBodyModel($path); + } + $this->_setHeaderCharset($header); + + return $header; + } + + /** + * Notify this observer that the entity's charset has changed. + * + * @param string $charset + */ + public function charsetChanged($charset) + { + $this->_charset = $charset; + $this->_encoder->charsetChanged($charset); + $this->_paramEncoder->charsetChanged($charset); + } + + /** + * Make a deep copy of object. + */ + public function __clone() + { + $this->_encoder = clone $this->_encoder; + $this->_paramEncoder = clone $this->_paramEncoder; + } + + /** Apply the charset to the Header */ + private function _setHeaderCharset(Swift_Mime_Header $header) + { + if (isset($this->_charset)) { + $header->setCharset($this->_charset); + } + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/SimpleHeaderSet.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/SimpleHeaderSet.php new file mode 100644 index 0000000..a06ce72 --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/SimpleHeaderSet.php @@ -0,0 +1,414 @@ +_factory = $factory; + if (isset($charset)) { + $this->setCharset($charset); + } + } + + /** + * Set the charset used by these headers. + * + * @param string $charset + */ + public function setCharset($charset) + { + $this->_charset = $charset; + $this->_factory->charsetChanged($charset); + $this->_notifyHeadersOfCharset($charset); + } + + /** + * Add a new Mailbox Header with a list of $addresses. + * + * @param string $name + * @param array|string $addresses + */ + public function addMailboxHeader($name, $addresses = null) + { + $this->_storeHeader($name, + $this->_factory->createMailboxHeader($name, $addresses)); + } + + /** + * Add a new Date header using $timestamp (UNIX time). + * + * @param string $name + * @param int $timestamp + */ + public function addDateHeader($name, $timestamp = null) + { + $this->_storeHeader($name, + $this->_factory->createDateHeader($name, $timestamp)); + } + + /** + * Add a new basic text header with $name and $value. + * + * @param string $name + * @param string $value + */ + public function addTextHeader($name, $value = null) + { + $this->_storeHeader($name, + $this->_factory->createTextHeader($name, $value)); + } + + /** + * Add a new ParameterizedHeader with $name, $value and $params. + * + * @param string $name + * @param string $value + * @param array $params + */ + public function addParameterizedHeader($name, $value = null, $params = array()) + { + $this->_storeHeader($name, $this->_factory->createParameterizedHeader($name, $value, $params)); + } + + /** + * Add a new ID header for Message-ID or Content-ID. + * + * @param string $name + * @param string|array $ids + */ + public function addIdHeader($name, $ids = null) + { + $this->_storeHeader($name, $this->_factory->createIdHeader($name, $ids)); + } + + /** + * Add a new Path header with an address (path) in it. + * + * @param string $name + * @param string $path + */ + public function addPathHeader($name, $path = null) + { + $this->_storeHeader($name, $this->_factory->createPathHeader($name, $path)); + } + + /** + * Returns true if at least one header with the given $name exists. + * + * If multiple headers match, the actual one may be specified by $index. + * + * @param string $name + * @param int $index + * + * @return bool + */ + public function has($name, $index = 0) + { + $lowerName = strtolower($name); + + if (!array_key_exists($lowerName, $this->_headers)) { + return false; + } + + if (func_num_args() < 2) { + // index was not specified, so we only need to check that there is at least one header value set + return (bool) count($this->_headers[$lowerName]); + } + + return array_key_exists($index, $this->_headers[$lowerName]); + } + + /** + * Set a header in the HeaderSet. + * + * The header may be a previously fetched header via {@link get()} or it may + * be one that has been created separately. + * + * If $index is specified, the header will be inserted into the set at this + * offset. + * + * @param Swift_Mime_Header $header + * @param int $index + */ + public function set(Swift_Mime_Header $header, $index = 0) + { + $this->_storeHeader($header->getFieldName(), $header, $index); + } + + /** + * Get the header with the given $name. + * + * If multiple headers match, the actual one may be specified by $index. + * Returns NULL if none present. + * + * @param string $name + * @param int $index + * + * @return Swift_Mime_Header + */ + public function get($name, $index = 0) + { + $name = strtolower($name); + + if (func_num_args() < 2) { + if ($this->has($name)) { + $values = array_values($this->_headers[$name]); + + return array_shift($values); + } + } else { + if ($this->has($name, $index)) { + return $this->_headers[$name][$index]; + } + } + } + + /** + * Get all headers with the given $name. + * + * @param string $name + * + * @return array + */ + public function getAll($name = null) + { + if (!isset($name)) { + $headers = array(); + foreach ($this->_headers as $collection) { + $headers = array_merge($headers, $collection); + } + + return $headers; + } + + $lowerName = strtolower($name); + if (!array_key_exists($lowerName, $this->_headers)) { + return array(); + } + + return $this->_headers[$lowerName]; + } + + /** + * Return the name of all Headers. + * + * @return array + */ + public function listAll() + { + $headers = $this->_headers; + if ($this->_canSort()) { + uksort($headers, array($this, '_sortHeaders')); + } + + return array_keys($headers); + } + + /** + * Remove the header with the given $name if it's set. + * + * If multiple headers match, the actual one may be specified by $index. + * + * @param string $name + * @param int $index + */ + public function remove($name, $index = 0) + { + $lowerName = strtolower($name); + unset($this->_headers[$lowerName][$index]); + } + + /** + * Remove all headers with the given $name. + * + * @param string $name + */ + public function removeAll($name) + { + $lowerName = strtolower($name); + unset($this->_headers[$lowerName]); + } + + /** + * Create a new instance of this HeaderSet. + * + * @return self + */ + public function newInstance() + { + return new self($this->_factory); + } + + /** + * Define a list of Header names as an array in the correct order. + * + * These Headers will be output in the given order where present. + * + * @param array $sequence + */ + public function defineOrdering(array $sequence) + { + $this->_order = array_flip(array_map('strtolower', $sequence)); + } + + /** + * Set a list of header names which must always be displayed when set. + * + * Usually headers without a field value won't be output unless set here. + * + * @param array $names + */ + public function setAlwaysDisplayed(array $names) + { + $this->_required = array_flip(array_map('strtolower', $names)); + } + + /** + * Notify this observer that the entity's charset has changed. + * + * @param string $charset + */ + public function charsetChanged($charset) + { + $this->setCharset($charset); + } + + /** + * Returns a string with a representation of all headers. + * + * @return string + */ + public function toString() + { + $string = ''; + $headers = $this->_headers; + if ($this->_canSort()) { + uksort($headers, array($this, '_sortHeaders')); + } + foreach ($headers as $collection) { + foreach ($collection as $header) { + if ($this->_isDisplayed($header) || $header->getFieldBody() != '') { + $string .= $header->toString(); + } + } + } + + return $string; + } + + /** + * Returns a string representation of this object. + * + * @return string + * + * @see toString() + */ + public function __toString() + { + return $this->toString(); + } + + /** Save a Header to the internal collection */ + private function _storeHeader($name, Swift_Mime_Header $header, $offset = null) + { + if (!isset($this->_headers[strtolower($name)])) { + $this->_headers[strtolower($name)] = array(); + } + if (!isset($offset)) { + $this->_headers[strtolower($name)][] = $header; + } else { + $this->_headers[strtolower($name)][$offset] = $header; + } + } + + /** Test if the headers can be sorted */ + private function _canSort() + { + return count($this->_order) > 0; + } + + /** uksort() algorithm for Header ordering */ + private function _sortHeaders($a, $b) + { + $lowerA = strtolower($a); + $lowerB = strtolower($b); + $aPos = array_key_exists($lowerA, $this->_order) ? $this->_order[$lowerA] : -1; + $bPos = array_key_exists($lowerB, $this->_order) ? $this->_order[$lowerB] : -1; + + if (-1 === $aPos && -1 === $bPos) { + // just be sure to be determinist here + return $a > $b ? -1 : 1; + } + + if ($aPos == -1) { + return 1; + } elseif ($bPos == -1) { + return -1; + } + + return $aPos < $bPos ? -1 : 1; + } + + /** Test if the given Header is always displayed */ + private function _isDisplayed(Swift_Mime_Header $header) + { + return array_key_exists(strtolower($header->getFieldName()), $this->_required); + } + + /** Notify all Headers of the new charset */ + private function _notifyHeadersOfCharset($charset) + { + foreach ($this->_headers as $headerGroup) { + foreach ($headerGroup as $header) { + $header->setCharset($charset); + } + } + } + + /** + * Make a deep copy of object. + */ + public function __clone() + { + $this->_factory = clone $this->_factory; + foreach ($this->_headers as $groupKey => $headerGroup) { + foreach ($headerGroup as $key => $header) { + $this->_headers[$groupKey][$key] = clone $header; + } + } + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/SimpleMessage.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/SimpleMessage.php new file mode 100644 index 0000000..72d40ce --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/SimpleMessage.php @@ -0,0 +1,655 @@ +getHeaders()->defineOrdering(array( + 'Return-Path', + 'Received', + 'DKIM-Signature', + 'DomainKey-Signature', + 'Sender', + 'Message-ID', + 'Date', + 'Subject', + 'From', + 'Reply-To', + 'To', + 'Cc', + 'Bcc', + 'MIME-Version', + 'Content-Type', + 'Content-Transfer-Encoding', + )); + $this->getHeaders()->setAlwaysDisplayed(array('Date', 'Message-ID', 'From')); + $this->getHeaders()->addTextHeader('MIME-Version', '1.0'); + $this->setDate(time()); + $this->setId($this->getId()); + $this->getHeaders()->addMailboxHeader('From'); + } + + /** + * Always returns {@link LEVEL_TOP} for a message instance. + * + * @return int + */ + public function getNestingLevel() + { + return self::LEVEL_TOP; + } + + /** + * Set the subject of this message. + * + * @param string $subject + * + * @return $this + */ + public function setSubject($subject) + { + if (!$this->_setHeaderFieldModel('Subject', $subject)) { + $this->getHeaders()->addTextHeader('Subject', $subject); + } + + return $this; + } + + /** + * Get the subject of this message. + * + * @return string + */ + public function getSubject() + { + return $this->_getHeaderFieldModel('Subject'); + } + + /** + * Set the date at which this message was created. + * + * @param int $date + * + * @return $this + */ + public function setDate($date) + { + if (!$this->_setHeaderFieldModel('Date', $date)) { + $this->getHeaders()->addDateHeader('Date', $date); + } + + return $this; + } + + /** + * Get the date at which this message was created. + * + * @return int + */ + public function getDate() + { + return $this->_getHeaderFieldModel('Date'); + } + + /** + * Set the return-path (the bounce address) of this message. + * + * @param string $address + * + * @return $this + */ + public function setReturnPath($address) + { + if (!$this->_setHeaderFieldModel('Return-Path', $address)) { + $this->getHeaders()->addPathHeader('Return-Path', $address); + } + + return $this; + } + + /** + * Get the return-path (bounce address) of this message. + * + * @return string + */ + public function getReturnPath() + { + return $this->_getHeaderFieldModel('Return-Path'); + } + + /** + * Set the sender of this message. + * + * This does not override the From field, but it has a higher significance. + * + * @param string $address + * @param string $name optional + * + * @return $this + */ + public function setSender($address, $name = null) + { + if (!is_array($address) && isset($name)) { + $address = array($address => $name); + } + + if (!$this->_setHeaderFieldModel('Sender', (array) $address)) { + $this->getHeaders()->addMailboxHeader('Sender', (array) $address); + } + + return $this; + } + + /** + * Get the sender of this message. + * + * @return string + */ + public function getSender() + { + return $this->_getHeaderFieldModel('Sender'); + } + + /** + * Add a From: address to this message. + * + * If $name is passed this name will be associated with the address. + * + * @param string $address + * @param string $name optional + * + * @return $this + */ + public function addFrom($address, $name = null) + { + $current = $this->getFrom(); + $current[$address] = $name; + + return $this->setFrom($current); + } + + /** + * Set the from address of this message. + * + * You may pass an array of addresses if this message is from multiple people. + * + * If $name is passed and the first parameter is a string, this name will be + * associated with the address. + * + * @param string|array $addresses + * @param string $name optional + * + * @return $this + */ + public function setFrom($addresses, $name = null) + { + if (!is_array($addresses) && isset($name)) { + $addresses = array($addresses => $name); + } + + if (!$this->_setHeaderFieldModel('From', (array) $addresses)) { + $this->getHeaders()->addMailboxHeader('From', (array) $addresses); + } + + return $this; + } + + /** + * Get the from address of this message. + * + * @return mixed + */ + public function getFrom() + { + return $this->_getHeaderFieldModel('From'); + } + + /** + * Add a Reply-To: address to this message. + * + * If $name is passed this name will be associated with the address. + * + * @param string $address + * @param string $name optional + * + * @return $this + */ + public function addReplyTo($address, $name = null) + { + $current = $this->getReplyTo(); + $current[$address] = $name; + + return $this->setReplyTo($current); + } + + /** + * Set the reply-to address of this message. + * + * You may pass an array of addresses if replies will go to multiple people. + * + * If $name is passed and the first parameter is a string, this name will be + * associated with the address. + * + * @param mixed $addresses + * @param string $name optional + * + * @return $this + */ + public function setReplyTo($addresses, $name = null) + { + if (!is_array($addresses) && isset($name)) { + $addresses = array($addresses => $name); + } + + if (!$this->_setHeaderFieldModel('Reply-To', (array) $addresses)) { + $this->getHeaders()->addMailboxHeader('Reply-To', (array) $addresses); + } + + return $this; + } + + /** + * Get the reply-to address of this message. + * + * @return string + */ + public function getReplyTo() + { + return $this->_getHeaderFieldModel('Reply-To'); + } + + /** + * Add a To: address to this message. + * + * If $name is passed this name will be associated with the address. + * + * @param string $address + * @param string $name optional + * + * @return $this + */ + public function addTo($address, $name = null) + { + $current = $this->getTo(); + $current[$address] = $name; + + return $this->setTo($current); + } + + /** + * Set the to addresses of this message. + * + * If multiple recipients will receive the message an array should be used. + * Example: array('receiver@domain.org', 'other@domain.org' => 'A name') + * + * If $name is passed and the first parameter is a string, this name will be + * associated with the address. + * + * @param mixed $addresses + * @param string $name optional + * + * @return $this + */ + public function setTo($addresses, $name = null) + { + if (!is_array($addresses) && isset($name)) { + $addresses = array($addresses => $name); + } + + if (!$this->_setHeaderFieldModel('To', (array) $addresses)) { + $this->getHeaders()->addMailboxHeader('To', (array) $addresses); + } + + return $this; + } + + /** + * Get the To addresses of this message. + * + * @return array + */ + public function getTo() + { + return $this->_getHeaderFieldModel('To'); + } + + /** + * Add a Cc: address to this message. + * + * If $name is passed this name will be associated with the address. + * + * @param string $address + * @param string $name optional + * + * @return $this + */ + public function addCc($address, $name = null) + { + $current = $this->getCc(); + $current[$address] = $name; + + return $this->setCc($current); + } + + /** + * Set the Cc addresses of this message. + * + * If $name is passed and the first parameter is a string, this name will be + * associated with the address. + * + * @param mixed $addresses + * @param string $name optional + * + * @return $this + */ + public function setCc($addresses, $name = null) + { + if (!is_array($addresses) && isset($name)) { + $addresses = array($addresses => $name); + } + + if (!$this->_setHeaderFieldModel('Cc', (array) $addresses)) { + $this->getHeaders()->addMailboxHeader('Cc', (array) $addresses); + } + + return $this; + } + + /** + * Get the Cc address of this message. + * + * @return array + */ + public function getCc() + { + return $this->_getHeaderFieldModel('Cc'); + } + + /** + * Add a Bcc: address to this message. + * + * If $name is passed this name will be associated with the address. + * + * @param string $address + * @param string $name optional + * + * @return $this + */ + public function addBcc($address, $name = null) + { + $current = $this->getBcc(); + $current[$address] = $name; + + return $this->setBcc($current); + } + + /** + * Set the Bcc addresses of this message. + * + * If $name is passed and the first parameter is a string, this name will be + * associated with the address. + * + * @param mixed $addresses + * @param string $name optional + * + * @return $this + */ + public function setBcc($addresses, $name = null) + { + if (!is_array($addresses) && isset($name)) { + $addresses = array($addresses => $name); + } + + if (!$this->_setHeaderFieldModel('Bcc', (array) $addresses)) { + $this->getHeaders()->addMailboxHeader('Bcc', (array) $addresses); + } + + return $this; + } + + /** + * Get the Bcc addresses of this message. + * + * @return array + */ + public function getBcc() + { + return $this->_getHeaderFieldModel('Bcc'); + } + + /** + * Set the priority of this message. + * + * The value is an integer where 1 is the highest priority and 5 is the lowest. + * + * @param int $priority + * + * @return $this + */ + public function setPriority($priority) + { + $priorityMap = array( + self::PRIORITY_HIGHEST => 'Highest', + self::PRIORITY_HIGH => 'High', + self::PRIORITY_NORMAL => 'Normal', + self::PRIORITY_LOW => 'Low', + self::PRIORITY_LOWEST => 'Lowest', + ); + $pMapKeys = array_keys($priorityMap); + if ($priority > max($pMapKeys)) { + $priority = max($pMapKeys); + } elseif ($priority < min($pMapKeys)) { + $priority = min($pMapKeys); + } + if (!$this->_setHeaderFieldModel('X-Priority', + sprintf('%d (%s)', $priority, $priorityMap[$priority]))) { + $this->getHeaders()->addTextHeader('X-Priority', + sprintf('%d (%s)', $priority, $priorityMap[$priority])); + } + + return $this; + } + + /** + * Get the priority of this message. + * + * The returned value is an integer where 1 is the highest priority and 5 + * is the lowest. + * + * @return int + */ + public function getPriority() + { + list($priority) = sscanf($this->_getHeaderFieldModel('X-Priority'), + '%[1-5]' + ); + + return isset($priority) ? $priority : 3; + } + + /** + * Ask for a delivery receipt from the recipient to be sent to $addresses. + * + * @param array $addresses + * + * @return $this + */ + public function setReadReceiptTo($addresses) + { + if (!$this->_setHeaderFieldModel('Disposition-Notification-To', $addresses)) { + $this->getHeaders() + ->addMailboxHeader('Disposition-Notification-To', $addresses); + } + + return $this; + } + + /** + * Get the addresses to which a read-receipt will be sent. + * + * @return string + */ + public function getReadReceiptTo() + { + return $this->_getHeaderFieldModel('Disposition-Notification-To'); + } + + /** + * Attach a {@link Swift_Mime_MimeEntity} such as an Attachment or MimePart. + * + * @param Swift_Mime_MimeEntity $entity + * + * @return $this + */ + public function attach(Swift_Mime_MimeEntity $entity) + { + $this->setChildren(array_merge($this->getChildren(), array($entity))); + + return $this; + } + + /** + * Remove an already attached entity. + * + * @param Swift_Mime_MimeEntity $entity + * + * @return $this + */ + public function detach(Swift_Mime_MimeEntity $entity) + { + $newChildren = array(); + foreach ($this->getChildren() as $child) { + if ($entity !== $child) { + $newChildren[] = $child; + } + } + $this->setChildren($newChildren); + + return $this; + } + + /** + * Attach a {@link Swift_Mime_MimeEntity} and return it's CID source. + * This method should be used when embedding images or other data in a message. + * + * @param Swift_Mime_MimeEntity $entity + * + * @return string + */ + public function embed(Swift_Mime_MimeEntity $entity) + { + $this->attach($entity); + + return 'cid:'.$entity->getId(); + } + + /** + * Get this message as a complete string. + * + * @return string + */ + public function toString() + { + if (count($children = $this->getChildren()) > 0 && $this->getBody() != '') { + $this->setChildren(array_merge(array($this->_becomeMimePart()), $children)); + $string = parent::toString(); + $this->setChildren($children); + } else { + $string = parent::toString(); + } + + return $string; + } + + /** + * Returns a string representation of this object. + * + * @see toString() + * + * @return string + */ + public function __toString() + { + return $this->toString(); + } + + /** + * Write this message to a {@link Swift_InputByteStream}. + * + * @param Swift_InputByteStream $is + */ + public function toByteStream(Swift_InputByteStream $is) + { + if (count($children = $this->getChildren()) > 0 && $this->getBody() != '') { + $this->setChildren(array_merge(array($this->_becomeMimePart()), $children)); + parent::toByteStream($is); + $this->setChildren($children); + } else { + parent::toByteStream($is); + } + } + + /** @see Swift_Mime_SimpleMimeEntity::_getIdField() */ + protected function _getIdField() + { + return 'Message-ID'; + } + + /** Turn the body of this message into a child of itself if needed */ + protected function _becomeMimePart() + { + $part = new parent($this->getHeaders()->newInstance(), $this->getEncoder(), + $this->_getCache(), $this->_getGrammar(), $this->_userCharset + ); + $part->setContentType($this->_userContentType); + $part->setBody($this->getBody()); + $part->setFormat($this->_userFormat); + $part->setDelSp($this->_userDelSp); + $part->_setNestingLevel($this->_getTopNestingLevel()); + + return $part; + } + + /** Get the highest nesting level nested inside this message */ + private function _getTopNestingLevel() + { + $highestLevel = $this->getNestingLevel(); + foreach ($this->getChildren() as $child) { + $childLevel = $child->getNestingLevel(); + if ($highestLevel < $childLevel) { + $highestLevel = $childLevel; + } + } + + return $highestLevel; + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/SimpleMimeEntity.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/SimpleMimeEntity.php new file mode 100644 index 0000000..a13f1b2 --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/SimpleMimeEntity.php @@ -0,0 +1,846 @@ + array(self::LEVEL_TOP, self::LEVEL_MIXED), + 'multipart/alternative' => array(self::LEVEL_MIXED, self::LEVEL_ALTERNATIVE), + 'multipart/related' => array(self::LEVEL_ALTERNATIVE, self::LEVEL_RELATED), + ); + + /** A set of filter rules to define what level an entity should be nested at */ + private $_compoundLevelFilters = array(); + + /** The nesting level of this entity */ + private $_nestingLevel = self::LEVEL_ALTERNATIVE; + + /** A KeyCache instance used during encoding and streaming */ + private $_cache; + + /** Direct descendants of this entity */ + private $_immediateChildren = array(); + + /** All descendants of this entity */ + private $_children = array(); + + /** The maximum line length of the body of this entity */ + private $_maxLineLength = 78; + + /** The order in which alternative mime types should appear */ + private $_alternativePartOrder = array( + 'text/plain' => 1, + 'text/html' => 2, + 'multipart/related' => 3, + ); + + /** The CID of this entity */ + private $_id; + + /** The key used for accessing the cache */ + private $_cacheKey; + + protected $_userContentType; + + /** + * Create a new SimpleMimeEntity with $headers, $encoder and $cache. + * + * @param Swift_Mime_HeaderSet $headers + * @param Swift_Mime_ContentEncoder $encoder + * @param Swift_KeyCache $cache + * @param Swift_Mime_Grammar $grammar + */ + public function __construct(Swift_Mime_HeaderSet $headers, Swift_Mime_ContentEncoder $encoder, Swift_KeyCache $cache, Swift_Mime_Grammar $grammar) + { + $this->_cacheKey = md5(uniqid(getmypid().mt_rand(), true)); + $this->_cache = $cache; + $this->_headers = $headers; + $this->_grammar = $grammar; + $this->setEncoder($encoder); + $this->_headers->defineOrdering(array('Content-Type', 'Content-Transfer-Encoding')); + + // This array specifies that, when the entire MIME document contains + // $compoundLevel, then for each child within $level, if its Content-Type + // is $contentType then it should be treated as if it's level is + // $neededLevel instead. I tried to write that unambiguously! :-\ + // Data Structure: + // array ( + // $compoundLevel => array( + // $level => array( + // $contentType => $neededLevel + // ) + // ) + // ) + + $this->_compoundLevelFilters = array( + (self::LEVEL_ALTERNATIVE + self::LEVEL_RELATED) => array( + self::LEVEL_ALTERNATIVE => array( + 'text/plain' => self::LEVEL_ALTERNATIVE, + 'text/html' => self::LEVEL_RELATED, + ), + ), + ); + + $this->_id = $this->getRandomId(); + } + + /** + * Generate a new Content-ID or Message-ID for this MIME entity. + * + * @return string + */ + public function generateId() + { + $this->setId($this->getRandomId()); + + return $this->_id; + } + + /** + * Get the {@link Swift_Mime_HeaderSet} for this entity. + * + * @return Swift_Mime_HeaderSet + */ + public function getHeaders() + { + return $this->_headers; + } + + /** + * Get the nesting level of this entity. + * + * @see LEVEL_TOP, LEVEL_MIXED, LEVEL_RELATED, LEVEL_ALTERNATIVE + * + * @return int + */ + public function getNestingLevel() + { + return $this->_nestingLevel; + } + + /** + * Get the Content-type of this entity. + * + * @return string + */ + public function getContentType() + { + return $this->_getHeaderFieldModel('Content-Type'); + } + + /** + * Set the Content-type of this entity. + * + * @param string $type + * + * @return $this + */ + public function setContentType($type) + { + $this->_setContentTypeInHeaders($type); + // Keep track of the value so that if the content-type changes automatically + // due to added child entities, it can be restored if they are later removed + $this->_userContentType = $type; + + return $this; + } + + /** + * Get the CID of this entity. + * + * The CID will only be present in headers if a Content-ID header is present. + * + * @return string + */ + public function getId() + { + $tmp = (array) $this->_getHeaderFieldModel($this->_getIdField()); + + return $this->_headers->has($this->_getIdField()) ? current($tmp) : $this->_id; + } + + /** + * Set the CID of this entity. + * + * @param string $id + * + * @return $this + */ + public function setId($id) + { + if (!$this->_setHeaderFieldModel($this->_getIdField(), $id)) { + $this->_headers->addIdHeader($this->_getIdField(), $id); + } + $this->_id = $id; + + return $this; + } + + /** + * Get the description of this entity. + * + * This value comes from the Content-Description header if set. + * + * @return string + */ + public function getDescription() + { + return $this->_getHeaderFieldModel('Content-Description'); + } + + /** + * Set the description of this entity. + * + * This method sets a value in the Content-ID header. + * + * @param string $description + * + * @return $this + */ + public function setDescription($description) + { + if (!$this->_setHeaderFieldModel('Content-Description', $description)) { + $this->_headers->addTextHeader('Content-Description', $description); + } + + return $this; + } + + /** + * Get the maximum line length of the body of this entity. + * + * @return int + */ + public function getMaxLineLength() + { + return $this->_maxLineLength; + } + + /** + * Set the maximum line length of lines in this body. + * + * Though not enforced by the library, lines should not exceed 1000 chars. + * + * @param int $length + * + * @return $this + */ + public function setMaxLineLength($length) + { + $this->_maxLineLength = $length; + + return $this; + } + + /** + * Get all children added to this entity. + * + * @return Swift_Mime_MimeEntity[] + */ + public function getChildren() + { + return $this->_children; + } + + /** + * Set all children of this entity. + * + * @param Swift_Mime_MimeEntity[] $children + * @param int $compoundLevel For internal use only + * + * @return $this + */ + public function setChildren(array $children, $compoundLevel = null) + { + // TODO: Try to refactor this logic + + $compoundLevel = isset($compoundLevel) ? $compoundLevel : $this->_getCompoundLevel($children); + $immediateChildren = array(); + $grandchildren = array(); + $newContentType = $this->_userContentType; + + foreach ($children as $child) { + $level = $this->_getNeededChildLevel($child, $compoundLevel); + if (empty($immediateChildren)) { + //first iteration + $immediateChildren = array($child); + } else { + $nextLevel = $this->_getNeededChildLevel($immediateChildren[0], $compoundLevel); + if ($nextLevel == $level) { + $immediateChildren[] = $child; + } elseif ($level < $nextLevel) { + // Re-assign immediateChildren to grandchildren + $grandchildren = array_merge($grandchildren, $immediateChildren); + // Set new children + $immediateChildren = array($child); + } else { + $grandchildren[] = $child; + } + } + } + + if ($immediateChildren) { + $lowestLevel = $this->_getNeededChildLevel($immediateChildren[0], $compoundLevel); + + // Determine which composite media type is needed to accommodate the + // immediate children + foreach ($this->_compositeRanges as $mediaType => $range) { + if ($lowestLevel > $range[0] && $lowestLevel <= $range[1]) { + $newContentType = $mediaType; + + break; + } + } + + // Put any grandchildren in a subpart + if (!empty($grandchildren)) { + $subentity = $this->_createChild(); + $subentity->_setNestingLevel($lowestLevel); + $subentity->setChildren($grandchildren, $compoundLevel); + array_unshift($immediateChildren, $subentity); + } + } + + $this->_immediateChildren = $immediateChildren; + $this->_children = $children; + $this->_setContentTypeInHeaders($newContentType); + $this->_fixHeaders(); + $this->_sortChildren(); + + return $this; + } + + /** + * Get the body of this entity as a string. + * + * @return string + */ + public function getBody() + { + return $this->_body instanceof Swift_OutputByteStream ? $this->_readStream($this->_body) : $this->_body; + } + + /** + * Set the body of this entity, either as a string, or as an instance of + * {@link Swift_OutputByteStream}. + * + * @param mixed $body + * @param string $contentType optional + * + * @return $this + */ + public function setBody($body, $contentType = null) + { + if ($body !== $this->_body) { + $this->_clearCache(); + } + + $this->_body = $body; + if (isset($contentType)) { + $this->setContentType($contentType); + } + + return $this; + } + + /** + * Get the encoder used for the body of this entity. + * + * @return Swift_Mime_ContentEncoder + */ + public function getEncoder() + { + return $this->_encoder; + } + + /** + * Set the encoder used for the body of this entity. + * + * @param Swift_Mime_ContentEncoder $encoder + * + * @return $this + */ + public function setEncoder(Swift_Mime_ContentEncoder $encoder) + { + if ($encoder !== $this->_encoder) { + $this->_clearCache(); + } + + $this->_encoder = $encoder; + $this->_setEncoding($encoder->getName()); + $this->_notifyEncoderChanged($encoder); + + return $this; + } + + /** + * Get the boundary used to separate children in this entity. + * + * @return string + */ + public function getBoundary() + { + if (!isset($this->_boundary)) { + $this->_boundary = '_=_swift_v4_'.time().'_'.md5(getmypid().mt_rand().uniqid('', true)).'_=_'; + } + + return $this->_boundary; + } + + /** + * Set the boundary used to separate children in this entity. + * + * @param string $boundary + * + * @throws Swift_RfcComplianceException + * + * @return $this + */ + public function setBoundary($boundary) + { + $this->_assertValidBoundary($boundary); + $this->_boundary = $boundary; + + return $this; + } + + /** + * Receive notification that the charset of this entity, or a parent entity + * has changed. + * + * @param string $charset + */ + public function charsetChanged($charset) + { + $this->_notifyCharsetChanged($charset); + } + + /** + * Receive notification that the encoder of this entity or a parent entity + * has changed. + * + * @param Swift_Mime_ContentEncoder $encoder + */ + public function encoderChanged(Swift_Mime_ContentEncoder $encoder) + { + $this->_notifyEncoderChanged($encoder); + } + + /** + * Get this entire entity as a string. + * + * @return string + */ + public function toString() + { + $string = $this->_headers->toString(); + $string .= $this->_bodyToString(); + + return $string; + } + + /** + * Get this entire entity as a string. + * + * @return string + */ + protected function _bodyToString() + { + $string = ''; + + if (isset($this->_body) && empty($this->_immediateChildren)) { + if ($this->_cache->hasKey($this->_cacheKey, 'body')) { + $body = $this->_cache->getString($this->_cacheKey, 'body'); + } else { + $body = "\r\n".$this->_encoder->encodeString($this->getBody(), 0, $this->getMaxLineLength()); + $this->_cache->setString($this->_cacheKey, 'body', $body, Swift_KeyCache::MODE_WRITE); + } + $string .= $body; + } + + if (!empty($this->_immediateChildren)) { + foreach ($this->_immediateChildren as $child) { + $string .= "\r\n\r\n--".$this->getBoundary()."\r\n"; + $string .= $child->toString(); + } + $string .= "\r\n\r\n--".$this->getBoundary()."--\r\n"; + } + + return $string; + } + + /** + * Returns a string representation of this object. + * + * @see toString() + * + * @return string + */ + public function __toString() + { + return $this->toString(); + } + + /** + * Write this entire entity to a {@see Swift_InputByteStream}. + * + * @param Swift_InputByteStream + */ + public function toByteStream(Swift_InputByteStream $is) + { + $is->write($this->_headers->toString()); + $is->commit(); + + $this->_bodyToByteStream($is); + } + + /** + * Write this entire entity to a {@link Swift_InputByteStream}. + * + * @param Swift_InputByteStream + */ + protected function _bodyToByteStream(Swift_InputByteStream $is) + { + if (empty($this->_immediateChildren)) { + if (isset($this->_body)) { + if ($this->_cache->hasKey($this->_cacheKey, 'body')) { + $this->_cache->exportToByteStream($this->_cacheKey, 'body', $is); + } else { + $cacheIs = $this->_cache->getInputByteStream($this->_cacheKey, 'body'); + if ($cacheIs) { + $is->bind($cacheIs); + } + + $is->write("\r\n"); + + if ($this->_body instanceof Swift_OutputByteStream) { + $this->_body->setReadPointer(0); + + $this->_encoder->encodeByteStream($this->_body, $is, 0, $this->getMaxLineLength()); + } else { + $is->write($this->_encoder->encodeString($this->getBody(), 0, $this->getMaxLineLength())); + } + + if ($cacheIs) { + $is->unbind($cacheIs); + } + } + } + } + + if (!empty($this->_immediateChildren)) { + foreach ($this->_immediateChildren as $child) { + $is->write("\r\n\r\n--".$this->getBoundary()."\r\n"); + $child->toByteStream($is); + } + $is->write("\r\n\r\n--".$this->getBoundary()."--\r\n"); + } + } + + /** + * Get the name of the header that provides the ID of this entity. + */ + protected function _getIdField() + { + return 'Content-ID'; + } + + /** + * Get the model data (usually an array or a string) for $field. + */ + protected function _getHeaderFieldModel($field) + { + if ($this->_headers->has($field)) { + return $this->_headers->get($field)->getFieldBodyModel(); + } + } + + /** + * Set the model data for $field. + */ + protected function _setHeaderFieldModel($field, $model) + { + if ($this->_headers->has($field)) { + $this->_headers->get($field)->setFieldBodyModel($model); + + return true; + } + + return false; + } + + /** + * Get the parameter value of $parameter on $field header. + */ + protected function _getHeaderParameter($field, $parameter) + { + if ($this->_headers->has($field)) { + return $this->_headers->get($field)->getParameter($parameter); + } + } + + /** + * Set the parameter value of $parameter on $field header. + */ + protected function _setHeaderParameter($field, $parameter, $value) + { + if ($this->_headers->has($field)) { + $this->_headers->get($field)->setParameter($parameter, $value); + + return true; + } + + return false; + } + + /** + * Re-evaluate what content type and encoding should be used on this entity. + */ + protected function _fixHeaders() + { + if (count($this->_immediateChildren)) { + $this->_setHeaderParameter('Content-Type', 'boundary', + $this->getBoundary() + ); + $this->_headers->remove('Content-Transfer-Encoding'); + } else { + $this->_setHeaderParameter('Content-Type', 'boundary', null); + $this->_setEncoding($this->_encoder->getName()); + } + } + + /** + * Get the KeyCache used in this entity. + * + * @return Swift_KeyCache + */ + protected function _getCache() + { + return $this->_cache; + } + + /** + * Get the grammar used for validation. + * + * @return Swift_Mime_Grammar + */ + protected function _getGrammar() + { + return $this->_grammar; + } + + /** + * Empty the KeyCache for this entity. + */ + protected function _clearCache() + { + $this->_cache->clearKey($this->_cacheKey, 'body'); + } + + /** + * Returns a random Content-ID or Message-ID. + * + * @return string + */ + protected function getRandomId() + { + $idLeft = md5(getmypid().'.'.time().'.'.uniqid(mt_rand(), true)); + $idRight = !empty($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : 'swift.generated'; + $id = $idLeft.'@'.$idRight; + + try { + $this->_assertValidId($id); + } catch (Swift_RfcComplianceException $e) { + $id = $idLeft.'@swift.generated'; + } + + return $id; + } + + private function _readStream(Swift_OutputByteStream $os) + { + $string = ''; + while (false !== $bytes = $os->read(8192)) { + $string .= $bytes; + } + + $os->setReadPointer(0); + + return $string; + } + + private function _setEncoding($encoding) + { + if (!$this->_setHeaderFieldModel('Content-Transfer-Encoding', $encoding)) { + $this->_headers->addTextHeader('Content-Transfer-Encoding', $encoding); + } + } + + private function _assertValidBoundary($boundary) + { + if (!preg_match('/^[a-z0-9\'\(\)\+_\-,\.\/:=\?\ ]{0,69}[a-z0-9\'\(\)\+_\-,\.\/:=\?]$/Di', $boundary)) { + throw new Swift_RfcComplianceException('Mime boundary set is not RFC 2046 compliant.'); + } + } + + private function _setContentTypeInHeaders($type) + { + if (!$this->_setHeaderFieldModel('Content-Type', $type)) { + $this->_headers->addParameterizedHeader('Content-Type', $type); + } + } + + private function _setNestingLevel($level) + { + $this->_nestingLevel = $level; + } + + private function _getCompoundLevel($children) + { + $level = 0; + foreach ($children as $child) { + $level |= $child->getNestingLevel(); + } + + return $level; + } + + private function _getNeededChildLevel($child, $compoundLevel) + { + $filter = array(); + foreach ($this->_compoundLevelFilters as $bitmask => $rules) { + if (($compoundLevel & $bitmask) === $bitmask) { + $filter = $rules + $filter; + } + } + + $realLevel = $child->getNestingLevel(); + $lowercaseType = strtolower($child->getContentType()); + + if (isset($filter[$realLevel]) && isset($filter[$realLevel][$lowercaseType])) { + return $filter[$realLevel][$lowercaseType]; + } + + return $realLevel; + } + + private function _createChild() + { + return new self($this->_headers->newInstance(), $this->_encoder, $this->_cache, $this->_grammar); + } + + private function _notifyEncoderChanged(Swift_Mime_ContentEncoder $encoder) + { + foreach ($this->_immediateChildren as $child) { + $child->encoderChanged($encoder); + } + } + + private function _notifyCharsetChanged($charset) + { + $this->_encoder->charsetChanged($charset); + $this->_headers->charsetChanged($charset); + foreach ($this->_immediateChildren as $child) { + $child->charsetChanged($charset); + } + } + + private function _sortChildren() + { + $shouldSort = false; + foreach ($this->_immediateChildren as $child) { + // NOTE: This include alternative parts moved into a related part + if ($child->getNestingLevel() == self::LEVEL_ALTERNATIVE) { + $shouldSort = true; + break; + } + } + + // Sort in order of preference, if there is one + if ($shouldSort) { + // Group the messages by order of preference + $sorted = array(); + foreach ($this->_immediateChildren as $child) { + $type = $child->getContentType(); + $level = array_key_exists($type, $this->_alternativePartOrder) ? $this->_alternativePartOrder[$type] : max($this->_alternativePartOrder) + 1; + + if (empty($sorted[$level])) { + $sorted[$level] = array(); + } + + $sorted[$level][] = $child; + } + + ksort($sorted); + + $this->_immediateChildren = array_reduce($sorted, 'array_merge', array()); + } + } + + /** + * Empties it's own contents from the cache. + */ + public function __destruct() + { + if ($this->_cache instanceof Swift_KeyCache) { + $this->_cache->clearAll($this->_cacheKey); + } + } + + /** + * Throws an Exception if the id passed does not comply with RFC 2822. + * + * @param string $id + * + * @throws Swift_RfcComplianceException + */ + private function _assertValidId($id) + { + if (!preg_match('/^'.$this->_grammar->getDefinition('id-left').'@'.$this->_grammar->getDefinition('id-right').'$/D', $id)) { + throw new Swift_RfcComplianceException('Invalid ID given <'.$id.'>'); + } + } + + /** + * Make a deep copy of object. + */ + public function __clone() + { + $this->_headers = clone $this->_headers; + $this->_encoder = clone $this->_encoder; + $this->_cacheKey = md5(uniqid(getmypid().mt_rand(), true)); + $children = array(); + foreach ($this->_children as $pos => $child) { + $children[$pos] = clone $child; + } + $this->setChildren($children); + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/MimePart.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/MimePart.php new file mode 100644 index 0000000..525b7ec --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/MimePart.php @@ -0,0 +1,59 @@ +createDependenciesFor('mime.part') + ); + + if (!isset($charset)) { + $charset = Swift_DependencyContainer::getInstance() + ->lookup('properties.charset'); + } + $this->setBody($body); + $this->setCharset($charset); + if ($contentType) { + $this->setContentType($contentType); + } + } + + /** + * Create a new MimePart. + * + * @param string $body + * @param string $contentType + * @param string $charset + * + * @return self + */ + public static function newInstance($body = null, $contentType = null, $charset = null) + { + return new self($body, $contentType, $charset); + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/NullTransport.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/NullTransport.php new file mode 100644 index 0000000..ddde335 --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/NullTransport.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * Pretends messages have been sent, but just ignores them. + * + * @author Fabien Potencier + */ +class Swift_NullTransport extends Swift_Transport_NullTransport +{ + public function __construct() + { + call_user_func_array( + array($this, 'Swift_Transport_NullTransport::__construct'), + Swift_DependencyContainer::getInstance() + ->createDependenciesFor('transport.null') + ); + } + + /** + * Create a new NullTransport instance. + * + * @return self + */ + public static function newInstance() + { + return new self(); + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/OutputByteStream.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/OutputByteStream.php new file mode 100644 index 0000000..1f26f9b --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/OutputByteStream.php @@ -0,0 +1,46 @@ +setThreshold($threshold); + $this->setSleepTime($sleep); + $this->_sleeper = $sleeper; + } + + /** + * Set the number of emails to send before restarting. + * + * @param int $threshold + */ + public function setThreshold($threshold) + { + $this->_threshold = $threshold; + } + + /** + * Get the number of emails to send before restarting. + * + * @return int + */ + public function getThreshold() + { + return $this->_threshold; + } + + /** + * Set the number of seconds to sleep for during a restart. + * + * @param int $sleep time + */ + public function setSleepTime($sleep) + { + $this->_sleep = $sleep; + } + + /** + * Get the number of seconds to sleep for during a restart. + * + * @return int + */ + public function getSleepTime() + { + return $this->_sleep; + } + + /** + * Invoked immediately before the Message is sent. + * + * @param Swift_Events_SendEvent $evt + */ + public function beforeSendPerformed(Swift_Events_SendEvent $evt) + { + } + + /** + * Invoked immediately after the Message is sent. + * + * @param Swift_Events_SendEvent $evt + */ + public function sendPerformed(Swift_Events_SendEvent $evt) + { + ++$this->_counter; + if ($this->_counter >= $this->_threshold) { + $transport = $evt->getTransport(); + $transport->stop(); + if ($this->_sleep) { + $this->sleep($this->_sleep); + } + $transport->start(); + $this->_counter = 0; + } + } + + /** + * Sleep for $seconds. + * + * @param int $seconds + */ + public function sleep($seconds) + { + if (isset($this->_sleeper)) { + $this->_sleeper->sleep($seconds); + } else { + sleep($seconds); + } + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/BandwidthMonitorPlugin.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/BandwidthMonitorPlugin.php new file mode 100644 index 0000000..f7e18d0 --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/BandwidthMonitorPlugin.php @@ -0,0 +1,164 @@ +getMessage(); + $message->toByteStream($this); + } + + /** + * Invoked immediately following a command being sent. + * + * @param Swift_Events_CommandEvent $evt + */ + public function commandSent(Swift_Events_CommandEvent $evt) + { + $command = $evt->getCommand(); + $this->_out += strlen($command); + } + + /** + * Invoked immediately following a response coming back. + * + * @param Swift_Events_ResponseEvent $evt + */ + public function responseReceived(Swift_Events_ResponseEvent $evt) + { + $response = $evt->getResponse(); + $this->_in += strlen($response); + } + + /** + * Called when a message is sent so that the outgoing counter can be increased. + * + * @param string $bytes + */ + public function write($bytes) + { + $this->_out += strlen($bytes); + foreach ($this->_mirrors as $stream) { + $stream->write($bytes); + } + } + + /** + * Not used. + */ + public function commit() + { + } + + /** + * Attach $is to this stream. + * + * The stream acts as an observer, receiving all data that is written. + * All {@link write()} and {@link flushBuffers()} operations will be mirrored. + * + * @param Swift_InputByteStream $is + */ + public function bind(Swift_InputByteStream $is) + { + $this->_mirrors[] = $is; + } + + /** + * Remove an already bound stream. + * + * If $is is not bound, no errors will be raised. + * If the stream currently has any buffered data it will be written to $is + * before unbinding occurs. + * + * @param Swift_InputByteStream $is + */ + public function unbind(Swift_InputByteStream $is) + { + foreach ($this->_mirrors as $k => $stream) { + if ($is === $stream) { + unset($this->_mirrors[$k]); + } + } + } + + /** + * Not used. + */ + public function flushBuffers() + { + foreach ($this->_mirrors as $stream) { + $stream->flushBuffers(); + } + } + + /** + * Get the total number of bytes sent to the server. + * + * @return int + */ + public function getBytesOut() + { + return $this->_out; + } + + /** + * Get the total number of bytes received from the server. + * + * @return int + */ + public function getBytesIn() + { + return $this->_in; + } + + /** + * Reset the internal counters to zero. + */ + public function reset() + { + $this->_out = 0; + $this->_in = 0; + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Decorator/Replacements.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Decorator/Replacements.php new file mode 100644 index 0000000..9f9f08b --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Decorator/Replacements.php @@ -0,0 +1,31 @@ + + * $replacements = array( + * "address1@domain.tld" => array("{a}" => "b", "{c}" => "d"), + * "address2@domain.tld" => array("{a}" => "x", "{c}" => "y") + * ) + * + * + * When using an instance of {@link Swift_Plugins_Decorator_Replacements}, + * the object should return just the array of replacements for the address + * given to {@link Swift_Plugins_Decorator_Replacements::getReplacementsFor()}. + * + * @param mixed $replacements Array or Swift_Plugins_Decorator_Replacements + */ + public function __construct($replacements) + { + $this->setReplacements($replacements); + } + + /** + * Sets replacements. + * + * @param mixed $replacements Array or Swift_Plugins_Decorator_Replacements + * + * @see __construct() + */ + public function setReplacements($replacements) + { + if (!($replacements instanceof Swift_Plugins_Decorator_Replacements)) { + $this->_replacements = (array) $replacements; + } else { + $this->_replacements = $replacements; + } + } + + /** + * Invoked immediately before the Message is sent. + * + * @param Swift_Events_SendEvent $evt + */ + public function beforeSendPerformed(Swift_Events_SendEvent $evt) + { + $message = $evt->getMessage(); + $this->_restoreMessage($message); + $to = array_keys($message->getTo()); + $address = array_shift($to); + if ($replacements = $this->getReplacementsFor($address)) { + $body = $message->getBody(); + $search = array_keys($replacements); + $replace = array_values($replacements); + $bodyReplaced = str_replace( + $search, $replace, $body + ); + if ($body != $bodyReplaced) { + $this->_originalBody = $body; + $message->setBody($bodyReplaced); + } + + foreach ($message->getHeaders()->getAll() as $header) { + $body = $header->getFieldBodyModel(); + $count = 0; + if (is_array($body)) { + $bodyReplaced = array(); + foreach ($body as $key => $value) { + $count1 = 0; + $count2 = 0; + $key = is_string($key) ? str_replace($search, $replace, $key, $count1) : $key; + $value = is_string($value) ? str_replace($search, $replace, $value, $count2) : $value; + $bodyReplaced[$key] = $value; + + if (!$count && ($count1 || $count2)) { + $count = 1; + } + } + } else { + $bodyReplaced = str_replace($search, $replace, $body, $count); + } + + if ($count) { + $this->_originalHeaders[$header->getFieldName()] = $body; + $header->setFieldBodyModel($bodyReplaced); + } + } + + $children = (array) $message->getChildren(); + foreach ($children as $child) { + list($type) = sscanf($child->getContentType(), '%[^/]/%s'); + if ('text' == $type) { + $body = $child->getBody(); + $bodyReplaced = str_replace( + $search, $replace, $body + ); + if ($body != $bodyReplaced) { + $child->setBody($bodyReplaced); + $this->_originalChildBodies[$child->getId()] = $body; + } + } + } + $this->_lastMessage = $message; + } + } + + /** + * Find a map of replacements for the address. + * + * If this plugin was provided with a delegate instance of + * {@link Swift_Plugins_Decorator_Replacements} then the call will be + * delegated to it. Otherwise, it will attempt to find the replacements + * from the array provided in the constructor. + * + * If no replacements can be found, an empty value (NULL) is returned. + * + * @param string $address + * + * @return array + */ + public function getReplacementsFor($address) + { + if ($this->_replacements instanceof Swift_Plugins_Decorator_Replacements) { + return $this->_replacements->getReplacementsFor($address); + } + + return isset($this->_replacements[$address]) ? $this->_replacements[$address] : null; + } + + /** + * Invoked immediately after the Message is sent. + * + * @param Swift_Events_SendEvent $evt + */ + public function sendPerformed(Swift_Events_SendEvent $evt) + { + $this->_restoreMessage($evt->getMessage()); + } + + /** Restore a changed message back to its original state */ + private function _restoreMessage(Swift_Mime_Message $message) + { + if ($this->_lastMessage === $message) { + if (isset($this->_originalBody)) { + $message->setBody($this->_originalBody); + $this->_originalBody = null; + } + if (!empty($this->_originalHeaders)) { + foreach ($message->getHeaders()->getAll() as $header) { + if (array_key_exists($header->getFieldName(), $this->_originalHeaders)) { + $header->setFieldBodyModel($this->_originalHeaders[$header->getFieldName()]); + } + } + $this->_originalHeaders = array(); + } + if (!empty($this->_originalChildBodies)) { + $children = (array) $message->getChildren(); + foreach ($children as $child) { + $id = $child->getId(); + if (array_key_exists($id, $this->_originalChildBodies)) { + $child->setBody($this->_originalChildBodies[$id]); + } + } + $this->_originalChildBodies = array(); + } + $this->_lastMessage = null; + } + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/ImpersonatePlugin.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/ImpersonatePlugin.php new file mode 100644 index 0000000..5834440 --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/ImpersonatePlugin.php @@ -0,0 +1,69 @@ +_sender = $sender; + } + + /** + * Invoked immediately before the Message is sent. + * + * @param Swift_Events_SendEvent $evt + */ + public function beforeSendPerformed(Swift_Events_SendEvent $evt) + { + $message = $evt->getMessage(); + $headers = $message->getHeaders(); + + // save current recipients + $headers->addPathHeader('X-Swift-Return-Path', $message->getReturnPath()); + + // replace them with the one to send to + $message->setReturnPath($this->_sender); + } + + /** + * Invoked immediately after the Message is sent. + * + * @param Swift_Events_SendEvent $evt + */ + public function sendPerformed(Swift_Events_SendEvent $evt) + { + $message = $evt->getMessage(); + + // restore original headers + $headers = $message->getHeaders(); + + if ($headers->has('X-Swift-Return-Path')) { + $message->setReturnPath($headers->get('X-Swift-Return-Path')->getAddress()); + $headers->removeAll('X-Swift-Return-Path'); + } + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Logger.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Logger.php new file mode 100644 index 0000000..d9bce89 --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Logger.php @@ -0,0 +1,36 @@ +_logger = $logger; + } + + /** + * Add a log entry. + * + * @param string $entry + */ + public function add($entry) + { + $this->_logger->add($entry); + } + + /** + * Clear the log contents. + */ + public function clear() + { + $this->_logger->clear(); + } + + /** + * Get this log as a string. + * + * @return string + */ + public function dump() + { + return $this->_logger->dump(); + } + + /** + * Invoked immediately following a command being sent. + * + * @param Swift_Events_CommandEvent $evt + */ + public function commandSent(Swift_Events_CommandEvent $evt) + { + $command = $evt->getCommand(); + $this->_logger->add(sprintf('>> %s', $command)); + } + + /** + * Invoked immediately following a response coming back. + * + * @param Swift_Events_ResponseEvent $evt + */ + public function responseReceived(Swift_Events_ResponseEvent $evt) + { + $response = $evt->getResponse(); + $this->_logger->add(sprintf('<< %s', $response)); + } + + /** + * Invoked just before a Transport is started. + * + * @param Swift_Events_TransportChangeEvent $evt + */ + public function beforeTransportStarted(Swift_Events_TransportChangeEvent $evt) + { + $transportName = get_class($evt->getSource()); + $this->_logger->add(sprintf('++ Starting %s', $transportName)); + } + + /** + * Invoked immediately after the Transport is started. + * + * @param Swift_Events_TransportChangeEvent $evt + */ + public function transportStarted(Swift_Events_TransportChangeEvent $evt) + { + $transportName = get_class($evt->getSource()); + $this->_logger->add(sprintf('++ %s started', $transportName)); + } + + /** + * Invoked just before a Transport is stopped. + * + * @param Swift_Events_TransportChangeEvent $evt + */ + public function beforeTransportStopped(Swift_Events_TransportChangeEvent $evt) + { + $transportName = get_class($evt->getSource()); + $this->_logger->add(sprintf('++ Stopping %s', $transportName)); + } + + /** + * Invoked immediately after the Transport is stopped. + * + * @param Swift_Events_TransportChangeEvent $evt + */ + public function transportStopped(Swift_Events_TransportChangeEvent $evt) + { + $transportName = get_class($evt->getSource()); + $this->_logger->add(sprintf('++ %s stopped', $transportName)); + } + + /** + * Invoked as a TransportException is thrown in the Transport system. + * + * @param Swift_Events_TransportExceptionEvent $evt + */ + public function exceptionThrown(Swift_Events_TransportExceptionEvent $evt) + { + $e = $evt->getException(); + $message = $e->getMessage(); + $code = $e->getCode(); + $this->_logger->add(sprintf('!! %s (code: %s)', $message, $code)); + $message .= PHP_EOL; + $message .= 'Log data:'.PHP_EOL; + $message .= $this->_logger->dump(); + $evt->cancelBubble(); + throw new Swift_TransportException($message, $code, $e->getPrevious()); + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Loggers/ArrayLogger.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Loggers/ArrayLogger.php new file mode 100644 index 0000000..865bb0a --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Loggers/ArrayLogger.php @@ -0,0 +1,72 @@ +_size = $size; + } + + /** + * Add a log entry. + * + * @param string $entry + */ + public function add($entry) + { + $this->_log[] = $entry; + while (count($this->_log) > $this->_size) { + array_shift($this->_log); + } + } + + /** + * Clear the log contents. + */ + public function clear() + { + $this->_log = array(); + } + + /** + * Get this log as a string. + * + * @return string + */ + public function dump() + { + return implode(PHP_EOL, $this->_log); + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Loggers/EchoLogger.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Loggers/EchoLogger.php new file mode 100644 index 0000000..3583297 --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Loggers/EchoLogger.php @@ -0,0 +1,58 @@ +_isHtml = $isHtml; + } + + /** + * Add a log entry. + * + * @param string $entry + */ + public function add($entry) + { + if ($this->_isHtml) { + printf('%s%s%s', htmlspecialchars($entry, ENT_QUOTES), '
                                                                      ', PHP_EOL); + } else { + printf('%s%s', $entry, PHP_EOL); + } + } + + /** + * Not implemented. + */ + public function clear() + { + } + + /** + * Not implemented. + */ + public function dump() + { + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/MessageLogger.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/MessageLogger.php new file mode 100644 index 0000000..5ff1d93 --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/MessageLogger.php @@ -0,0 +1,74 @@ +messages = array(); + } + + /** + * Get the message list. + * + * @return Swift_Mime_Message[] + */ + public function getMessages() + { + return $this->messages; + } + + /** + * Get the message count. + * + * @return int count + */ + public function countMessages() + { + return count($this->messages); + } + + /** + * Empty the message list. + */ + public function clear() + { + $this->messages = array(); + } + + /** + * Invoked immediately before the Message is sent. + * + * @param Swift_Events_SendEvent $evt + */ + public function beforeSendPerformed(Swift_Events_SendEvent $evt) + { + $this->messages[] = clone $evt->getMessage(); + } + + /** + * Invoked immediately after the Message is sent. + * + * @param Swift_Events_SendEvent $evt + */ + public function sendPerformed(Swift_Events_SendEvent $evt) + { + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Pop/Pop3Connection.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Pop/Pop3Connection.php new file mode 100644 index 0000000..fb99e4c --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Pop/Pop3Connection.php @@ -0,0 +1,31 @@ +_host = $host; + $this->_port = $port; + $this->_crypto = $crypto; + } + + /** + * Create a new PopBeforeSmtpPlugin for $host and $port. + * + * @param string $host + * @param int $port + * @param string $crypto as "tls" or "ssl" + * + * @return self + */ + public static function newInstance($host, $port = 110, $crypto = null) + { + return new self($host, $port, $crypto); + } + + /** + * Set a Pop3Connection to delegate to instead of connecting directly. + * + * @param Swift_Plugins_Pop_Pop3Connection $connection + * + * @return $this + */ + public function setConnection(Swift_Plugins_Pop_Pop3Connection $connection) + { + $this->_connection = $connection; + + return $this; + } + + /** + * Bind this plugin to a specific SMTP transport instance. + * + * @param Swift_Transport + */ + public function bindSmtp(Swift_Transport $smtp) + { + $this->_transport = $smtp; + } + + /** + * Set the connection timeout in seconds (default 10). + * + * @param int $timeout + * + * @return $this + */ + public function setTimeout($timeout) + { + $this->_timeout = (int) $timeout; + + return $this; + } + + /** + * Set the username to use when connecting (if needed). + * + * @param string $username + * + * @return $this + */ + public function setUsername($username) + { + $this->_username = $username; + + return $this; + } + + /** + * Set the password to use when connecting (if needed). + * + * @param string $password + * + * @return $this + */ + public function setPassword($password) + { + $this->_password = $password; + + return $this; + } + + /** + * Connect to the POP3 host and authenticate. + * + * @throws Swift_Plugins_Pop_Pop3Exception if connection fails + */ + public function connect() + { + if (isset($this->_connection)) { + $this->_connection->connect(); + } else { + if (!isset($this->_socket)) { + if (!$socket = fsockopen( + $this->_getHostString(), $this->_port, $errno, $errstr, $this->_timeout)) { + throw new Swift_Plugins_Pop_Pop3Exception( + sprintf('Failed to connect to POP3 host [%s]: %s', $this->_host, $errstr) + ); + } + $this->_socket = $socket; + + if (false === $greeting = fgets($this->_socket)) { + throw new Swift_Plugins_Pop_Pop3Exception( + sprintf('Failed to connect to POP3 host [%s]', trim($greeting)) + ); + } + + $this->_assertOk($greeting); + + if ($this->_username) { + $this->_command(sprintf("USER %s\r\n", $this->_username)); + $this->_command(sprintf("PASS %s\r\n", $this->_password)); + } + } + } + } + + /** + * Disconnect from the POP3 host. + */ + public function disconnect() + { + if (isset($this->_connection)) { + $this->_connection->disconnect(); + } else { + $this->_command("QUIT\r\n"); + if (!fclose($this->_socket)) { + throw new Swift_Plugins_Pop_Pop3Exception( + sprintf('POP3 host [%s] connection could not be stopped', $this->_host) + ); + } + $this->_socket = null; + } + } + + /** + * Invoked just before a Transport is started. + * + * @param Swift_Events_TransportChangeEvent $evt + */ + public function beforeTransportStarted(Swift_Events_TransportChangeEvent $evt) + { + if (isset($this->_transport)) { + if ($this->_transport !== $evt->getTransport()) { + return; + } + } + + $this->connect(); + $this->disconnect(); + } + + /** + * Not used. + */ + public function transportStarted(Swift_Events_TransportChangeEvent $evt) + { + } + + /** + * Not used. + */ + public function beforeTransportStopped(Swift_Events_TransportChangeEvent $evt) + { + } + + /** + * Not used. + */ + public function transportStopped(Swift_Events_TransportChangeEvent $evt) + { + } + + private function _command($command) + { + if (!fwrite($this->_socket, $command)) { + throw new Swift_Plugins_Pop_Pop3Exception( + sprintf('Failed to write command [%s] to POP3 host', trim($command)) + ); + } + + if (false === $response = fgets($this->_socket)) { + throw new Swift_Plugins_Pop_Pop3Exception( + sprintf('Failed to read from POP3 host after command [%s]', trim($command)) + ); + } + + $this->_assertOk($response); + + return $response; + } + + private function _assertOk($response) + { + if (substr($response, 0, 3) != '+OK') { + throw new Swift_Plugins_Pop_Pop3Exception( + sprintf('POP3 command failed [%s]', trim($response)) + ); + } + } + + private function _getHostString() + { + $host = $this->_host; + switch (strtolower($this->_crypto)) { + case 'ssl': + $host = 'ssl://'.$host; + break; + + case 'tls': + $host = 'tls://'.$host; + break; + } + + return $host; + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/RedirectingPlugin.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/RedirectingPlugin.php new file mode 100644 index 0000000..c3a1f86 --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/RedirectingPlugin.php @@ -0,0 +1,213 @@ +_recipient = $recipient; + $this->_whitelist = $whitelist; + } + + /** + * Set the recipient of all messages. + * + * @param mixed $recipient + */ + public function setRecipient($recipient) + { + $this->_recipient = $recipient; + } + + /** + * Get the recipient of all messages. + * + * @return mixed + */ + public function getRecipient() + { + return $this->_recipient; + } + + /** + * Set a list of regular expressions to whitelist certain recipients. + * + * @param array $whitelist + */ + public function setWhitelist(array $whitelist) + { + $this->_whitelist = $whitelist; + } + + /** + * Get the whitelist. + * + * @return array + */ + public function getWhitelist() + { + return $this->_whitelist; + } + + /** + * Invoked immediately before the Message is sent. + * + * @param Swift_Events_SendEvent $evt + */ + public function beforeSendPerformed(Swift_Events_SendEvent $evt) + { + $message = $evt->getMessage(); + $headers = $message->getHeaders(); + + // conditionally save current recipients + + if ($headers->has('to')) { + $headers->addMailboxHeader('X-Swift-To', $message->getTo()); + } + + if ($headers->has('cc')) { + $headers->addMailboxHeader('X-Swift-Cc', $message->getCc()); + } + + if ($headers->has('bcc')) { + $headers->addMailboxHeader('X-Swift-Bcc', $message->getBcc()); + } + + // Filter remaining headers against whitelist + $this->_filterHeaderSet($headers, 'To'); + $this->_filterHeaderSet($headers, 'Cc'); + $this->_filterHeaderSet($headers, 'Bcc'); + + // Add each hard coded recipient + $to = $message->getTo(); + if (null === $to) { + $to = array(); + } + + foreach ((array) $this->_recipient as $recipient) { + if (!array_key_exists($recipient, $to)) { + $message->addTo($recipient); + } + } + } + + /** + * Filter header set against a whitelist of regular expressions. + * + * @param Swift_Mime_HeaderSet $headerSet + * @param string $type + */ + private function _filterHeaderSet(Swift_Mime_HeaderSet $headerSet, $type) + { + foreach ($headerSet->getAll($type) as $headers) { + $headers->setNameAddresses($this->_filterNameAddresses($headers->getNameAddresses())); + } + } + + /** + * Filtered list of addresses => name pairs. + * + * @param array $recipients + * + * @return array + */ + private function _filterNameAddresses(array $recipients) + { + $filtered = array(); + + foreach ($recipients as $address => $name) { + if ($this->_isWhitelisted($address)) { + $filtered[$address] = $name; + } + } + + return $filtered; + } + + /** + * Matches address against whitelist of regular expressions. + * + * @param $recipient + * + * @return bool + */ + protected function _isWhitelisted($recipient) + { + if (in_array($recipient, (array) $this->_recipient)) { + return true; + } + + foreach ($this->_whitelist as $pattern) { + if (preg_match($pattern, $recipient)) { + return true; + } + } + + return false; + } + + /** + * Invoked immediately after the Message is sent. + * + * @param Swift_Events_SendEvent $evt + */ + public function sendPerformed(Swift_Events_SendEvent $evt) + { + $this->_restoreMessage($evt->getMessage()); + } + + private function _restoreMessage(Swift_Mime_Message $message) + { + // restore original headers + $headers = $message->getHeaders(); + + if ($headers->has('X-Swift-To')) { + $message->setTo($headers->get('X-Swift-To')->getNameAddresses()); + $headers->removeAll('X-Swift-To'); + } else { + $message->setTo(null); + } + + if ($headers->has('X-Swift-Cc')) { + $message->setCc($headers->get('X-Swift-Cc')->getNameAddresses()); + $headers->removeAll('X-Swift-Cc'); + } + + if ($headers->has('X-Swift-Bcc')) { + $message->setBcc($headers->get('X-Swift-Bcc')->getNameAddresses()); + $headers->removeAll('X-Swift-Bcc'); + } + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Reporter.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Reporter.php new file mode 100644 index 0000000..0f21b7d --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Reporter.php @@ -0,0 +1,32 @@ +_reporter = $reporter; + } + + /** + * Not used. + */ + public function beforeSendPerformed(Swift_Events_SendEvent $evt) + { + } + + /** + * Invoked immediately after the Message is sent. + * + * @param Swift_Events_SendEvent $evt + */ + public function sendPerformed(Swift_Events_SendEvent $evt) + { + $message = $evt->getMessage(); + $failures = array_flip($evt->getFailedRecipients()); + foreach ((array) $message->getTo() as $address => $null) { + $this->_reporter->notify($message, $address, array_key_exists($address, $failures) ? Swift_Plugins_Reporter::RESULT_FAIL : Swift_Plugins_Reporter::RESULT_PASS); + } + foreach ((array) $message->getCc() as $address => $null) { + $this->_reporter->notify($message, $address, array_key_exists($address, $failures) ? Swift_Plugins_Reporter::RESULT_FAIL : Swift_Plugins_Reporter::RESULT_PASS); + } + foreach ((array) $message->getBcc() as $address => $null) { + $this->_reporter->notify($message, $address, array_key_exists($address, $failures) ? Swift_Plugins_Reporter::RESULT_FAIL : Swift_Plugins_Reporter::RESULT_PASS); + } + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Reporters/HitReporter.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Reporters/HitReporter.php new file mode 100644 index 0000000..cad9d16 --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Reporters/HitReporter.php @@ -0,0 +1,59 @@ +_failures_cache[$address])) { + $this->_failures[] = $address; + $this->_failures_cache[$address] = true; + } + } + + /** + * Get an array of addresses for which delivery failed. + * + * @return array + */ + public function getFailedRecipients() + { + return $this->_failures; + } + + /** + * Clear the buffer (empty the list). + */ + public function clear() + { + $this->_failures = $this->_failures_cache = array(); + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Reporters/HtmlReporter.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Reporters/HtmlReporter.php new file mode 100644 index 0000000..c625935 --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Reporters/HtmlReporter.php @@ -0,0 +1,39 @@ +'.PHP_EOL; + echo 'PASS '.$address.PHP_EOL; + echo ''.PHP_EOL; + flush(); + } else { + echo '
                                                                      '.PHP_EOL; + echo 'FAIL '.$address.PHP_EOL; + echo '
                                                                      '.PHP_EOL; + flush(); + } + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Sleeper.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Sleeper.php new file mode 100644 index 0000000..595c0f6 --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Sleeper.php @@ -0,0 +1,24 @@ +_rate = $rate; + $this->_mode = $mode; + $this->_sleeper = $sleeper; + $this->_timer = $timer; + } + + /** + * Invoked immediately before the Message is sent. + * + * @param Swift_Events_SendEvent $evt + */ + public function beforeSendPerformed(Swift_Events_SendEvent $evt) + { + $time = $this->getTimestamp(); + if (!isset($this->_start)) { + $this->_start = $time; + } + $duration = $time - $this->_start; + + switch ($this->_mode) { + case self::BYTES_PER_MINUTE: + $sleep = $this->_throttleBytesPerMinute($duration); + break; + case self::MESSAGES_PER_SECOND: + $sleep = $this->_throttleMessagesPerSecond($duration); + break; + case self::MESSAGES_PER_MINUTE: + $sleep = $this->_throttleMessagesPerMinute($duration); + break; + default: + $sleep = 0; + break; + } + + if ($sleep > 0) { + $this->sleep($sleep); + } + } + + /** + * Invoked when a Message is sent. + * + * @param Swift_Events_SendEvent $evt + */ + public function sendPerformed(Swift_Events_SendEvent $evt) + { + parent::sendPerformed($evt); + ++$this->_messages; + } + + /** + * Sleep for $seconds. + * + * @param int $seconds + */ + public function sleep($seconds) + { + if (isset($this->_sleeper)) { + $this->_sleeper->sleep($seconds); + } else { + sleep($seconds); + } + } + + /** + * Get the current UNIX timestamp. + * + * @return int + */ + public function getTimestamp() + { + if (isset($this->_timer)) { + return $this->_timer->getTimestamp(); + } + + return time(); + } + + /** + * Get a number of seconds to sleep for. + * + * @param int $timePassed + * + * @return int + */ + private function _throttleBytesPerMinute($timePassed) + { + $expectedDuration = $this->getBytesOut() / ($this->_rate / 60); + + return (int) ceil($expectedDuration - $timePassed); + } + + /** + * Get a number of seconds to sleep for. + * + * @param int $timePassed + * + * @return int + */ + private function _throttleMessagesPerSecond($timePassed) + { + $expectedDuration = $this->_messages / ($this->_rate); + + return (int) ceil($expectedDuration - $timePassed); + } + + /** + * Get a number of seconds to sleep for. + * + * @param int $timePassed + * + * @return int + */ + private function _throttleMessagesPerMinute($timePassed) + { + $expectedDuration = $this->_messages / ($this->_rate / 60); + + return (int) ceil($expectedDuration - $timePassed); + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Timer.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Timer.php new file mode 100644 index 0000000..9c8deb3 --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Timer.php @@ -0,0 +1,24 @@ +register('properties.charset')->asValue($charset); + + return $this; + } + + /** + * Set the directory where temporary files can be saved. + * + * @param string $dir + * + * @return $this + */ + public function setTempDir($dir) + { + Swift_DependencyContainer::getInstance()->register('tempdir')->asValue($dir); + + return $this; + } + + /** + * Set the type of cache to use (i.e. "disk" or "array"). + * + * @param string $type + * + * @return $this + */ + public function setCacheType($type) + { + Swift_DependencyContainer::getInstance()->register('cache')->asAliasOf(sprintf('cache.%s', $type)); + + return $this; + } + + /** + * Set the QuotedPrintable dot escaper preference. + * + * @param bool $dotEscape + * + * @return $this + */ + public function setQPDotEscape($dotEscape) + { + $dotEscape = !empty($dotEscape); + Swift_DependencyContainer::getInstance() + ->register('mime.qpcontentencoder') + ->asNewInstanceOf('Swift_Mime_ContentEncoder_QpContentEncoder') + ->withDependencies(array('mime.charstream', 'mime.bytecanonicalizer')) + ->addConstructorValue($dotEscape); + + return $this; + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ReplacementFilterFactory.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ReplacementFilterFactory.php new file mode 100644 index 0000000..2897474 --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ReplacementFilterFactory.php @@ -0,0 +1,27 @@ +createDependenciesFor('transport.sendmail') + ); + + $this->setCommand($command); + } + + /** + * Create a new SendmailTransport instance. + * + * @param string $command + * + * @return self + */ + public static function newInstance($command = '/usr/sbin/sendmail -bs') + { + return new self($command); + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/SignedMessage.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/SignedMessage.php new file mode 100644 index 0000000..2e7a872 --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/SignedMessage.php @@ -0,0 +1,23 @@ + + * + * @deprecated + */ +class Swift_SignedMessage extends Swift_Message +{ +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signer.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signer.php new file mode 100644 index 0000000..2d8176d --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signer.php @@ -0,0 +1,20 @@ + + */ +interface Swift_Signer +{ + public function reset(); +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/BodySigner.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/BodySigner.php new file mode 100644 index 0000000..8e66e18 --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/BodySigner.php @@ -0,0 +1,33 @@ + + */ +interface Swift_Signers_BodySigner extends Swift_Signer +{ + /** + * Change the Swift_Signed_Message to apply the singing. + * + * @param Swift_Message $message + * + * @return self + */ + public function signMessage(Swift_Message $message); + + /** + * Return the list of header a signer might tamper. + * + * @return array + */ + public function getAlteredHeaders(); +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/DKIMSigner.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/DKIMSigner.php new file mode 100644 index 0000000..454e84b --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/DKIMSigner.php @@ -0,0 +1,712 @@ + + */ +class Swift_Signers_DKIMSigner implements Swift_Signers_HeaderSigner +{ + /** + * PrivateKey. + * + * @var string + */ + protected $_privateKey; + + /** + * DomainName. + * + * @var string + */ + protected $_domainName; + + /** + * Selector. + * + * @var string + */ + protected $_selector; + + /** + * Hash algorithm used. + * + * @see RFC6376 3.3: Signers MUST implement and SHOULD sign using rsa-sha256. + * + * @var string + */ + protected $_hashAlgorithm = 'rsa-sha256'; + + /** + * Body canon method. + * + * @var string + */ + protected $_bodyCanon = 'simple'; + + /** + * Header canon method. + * + * @var string + */ + protected $_headerCanon = 'simple'; + + /** + * Headers not being signed. + * + * @var array + */ + protected $_ignoredHeaders = array('return-path' => true); + + /** + * Signer identity. + * + * @var string + */ + protected $_signerIdentity; + + /** + * BodyLength. + * + * @var int + */ + protected $_bodyLen = 0; + + /** + * Maximum signedLen. + * + * @var int + */ + protected $_maxLen = PHP_INT_MAX; + + /** + * Embbed bodyLen in signature. + * + * @var bool + */ + protected $_showLen = false; + + /** + * When the signature has been applied (true means time()), false means not embedded. + * + * @var mixed + */ + protected $_signatureTimestamp = true; + + /** + * When will the signature expires false means not embedded, if sigTimestamp is auto + * Expiration is relative, otherwise it's absolute. + * + * @var int + */ + protected $_signatureExpiration = false; + + /** + * Must we embed signed headers? + * + * @var bool + */ + protected $_debugHeaders = false; + + // work variables + /** + * Headers used to generate hash. + * + * @var array + */ + protected $_signedHeaders = array(); + + /** + * If debugHeaders is set store debugData here. + * + * @var string + */ + private $_debugHeadersData = ''; + + /** + * Stores the bodyHash. + * + * @var string + */ + private $_bodyHash = ''; + + /** + * Stores the signature header. + * + * @var Swift_Mime_Headers_ParameterizedHeader + */ + protected $_dkimHeader; + + private $_bodyHashHandler; + + private $_headerHash; + + private $_headerCanonData = ''; + + private $_bodyCanonEmptyCounter = 0; + + private $_bodyCanonIgnoreStart = 2; + + private $_bodyCanonSpace = false; + + private $_bodyCanonLastChar = null; + + private $_bodyCanonLine = ''; + + private $_bound = array(); + + /** + * Constructor. + * + * @param string $privateKey + * @param string $domainName + * @param string $selector + */ + public function __construct($privateKey, $domainName, $selector) + { + $this->_privateKey = $privateKey; + $this->_domainName = $domainName; + $this->_signerIdentity = '@'.$domainName; + $this->_selector = $selector; + + // keep fallback hash algorithm sha1 if php version is lower than 5.4.8 + if (PHP_VERSION_ID < 50408) { + $this->_hashAlgorithm = 'rsa-sha1'; + } + } + + /** + * Instanciate DKIMSigner. + * + * @param string $privateKey + * @param string $domainName + * @param string $selector + * + * @return self + */ + public static function newInstance($privateKey, $domainName, $selector) + { + return new static($privateKey, $domainName, $selector); + } + + /** + * Reset the Signer. + * + * @see Swift_Signer::reset() + */ + public function reset() + { + $this->_headerHash = null; + $this->_signedHeaders = array(); + $this->_bodyHash = null; + $this->_bodyHashHandler = null; + $this->_bodyCanonIgnoreStart = 2; + $this->_bodyCanonEmptyCounter = 0; + $this->_bodyCanonLastChar = null; + $this->_bodyCanonSpace = false; + } + + /** + * Writes $bytes to the end of the stream. + * + * Writing may not happen immediately if the stream chooses to buffer. If + * you want to write these bytes with immediate effect, call {@link commit()} + * after calling write(). + * + * This method returns the sequence ID of the write (i.e. 1 for first, 2 for + * second, etc etc). + * + * @param string $bytes + * + * @throws Swift_IoException + * + * @return int + */ + // TODO fix return + public function write($bytes) + { + $this->_canonicalizeBody($bytes); + foreach ($this->_bound as $is) { + $is->write($bytes); + } + } + + /** + * For any bytes that are currently buffered inside the stream, force them + * off the buffer. + */ + public function commit() + { + // Nothing to do + return; + } + + /** + * Attach $is to this stream. + * The stream acts as an observer, receiving all data that is written. + * All {@link write()} and {@link flushBuffers()} operations will be mirrored. + * + * @param Swift_InputByteStream $is + */ + public function bind(Swift_InputByteStream $is) + { + // Don't have to mirror anything + $this->_bound[] = $is; + + return; + } + + /** + * Remove an already bound stream. + * If $is is not bound, no errors will be raised. + * If the stream currently has any buffered data it will be written to $is + * before unbinding occurs. + * + * @param Swift_InputByteStream $is + */ + public function unbind(Swift_InputByteStream $is) + { + // Don't have to mirror anything + foreach ($this->_bound as $k => $stream) { + if ($stream === $is) { + unset($this->_bound[$k]); + + return; + } + } + } + + /** + * Flush the contents of the stream (empty it) and set the internal pointer + * to the beginning. + * + * @throws Swift_IoException + */ + public function flushBuffers() + { + $this->reset(); + } + + /** + * Set hash_algorithm, must be one of rsa-sha256 | rsa-sha1. + * + * @param string $hash 'rsa-sha1' or 'rsa-sha256' + * + * @throws Swift_SwiftException + * + * @return $this + */ + public function setHashAlgorithm($hash) + { + switch ($hash) { + case 'rsa-sha1': + $this->_hashAlgorithm = 'rsa-sha1'; + break; + case 'rsa-sha256': + $this->_hashAlgorithm = 'rsa-sha256'; + if (!defined('OPENSSL_ALGO_SHA256')) { + throw new Swift_SwiftException('Unable to set sha256 as it is not supported by OpenSSL.'); + } + break; + default: + throw new Swift_SwiftException('Unable to set the hash algorithm, must be one of rsa-sha1 or rsa-sha256 (%s given).', $hash); + } + + return $this; + } + + /** + * Set the body canonicalization algorithm. + * + * @param string $canon + * + * @return $this + */ + public function setBodyCanon($canon) + { + if ($canon == 'relaxed') { + $this->_bodyCanon = 'relaxed'; + } else { + $this->_bodyCanon = 'simple'; + } + + return $this; + } + + /** + * Set the header canonicalization algorithm. + * + * @param string $canon + * + * @return $this + */ + public function setHeaderCanon($canon) + { + if ($canon == 'relaxed') { + $this->_headerCanon = 'relaxed'; + } else { + $this->_headerCanon = 'simple'; + } + + return $this; + } + + /** + * Set the signer identity. + * + * @param string $identity + * + * @return $this + */ + public function setSignerIdentity($identity) + { + $this->_signerIdentity = $identity; + + return $this; + } + + /** + * Set the length of the body to sign. + * + * @param mixed $len (bool or int) + * + * @return $this + */ + public function setBodySignedLen($len) + { + if ($len === true) { + $this->_showLen = true; + $this->_maxLen = PHP_INT_MAX; + } elseif ($len === false) { + $this->_showLen = false; + $this->_maxLen = PHP_INT_MAX; + } else { + $this->_showLen = true; + $this->_maxLen = (int) $len; + } + + return $this; + } + + /** + * Set the signature timestamp. + * + * @param int $time A timestamp + * + * @return $this + */ + public function setSignatureTimestamp($time) + { + $this->_signatureTimestamp = $time; + + return $this; + } + + /** + * Set the signature expiration timestamp. + * + * @param int $time A timestamp + * + * @return $this + */ + public function setSignatureExpiration($time) + { + $this->_signatureExpiration = $time; + + return $this; + } + + /** + * Enable / disable the DebugHeaders. + * + * @param bool $debug + * + * @return Swift_Signers_DKIMSigner + */ + public function setDebugHeaders($debug) + { + $this->_debugHeaders = (bool) $debug; + + return $this; + } + + /** + * Start Body. + */ + public function startBody() + { + // Init + switch ($this->_hashAlgorithm) { + case 'rsa-sha256': + $this->_bodyHashHandler = hash_init('sha256'); + break; + case 'rsa-sha1': + $this->_bodyHashHandler = hash_init('sha1'); + break; + } + $this->_bodyCanonLine = ''; + } + + /** + * End Body. + */ + public function endBody() + { + $this->_endOfBody(); + } + + /** + * Returns the list of Headers Tampered by this plugin. + * + * @return array + */ + public function getAlteredHeaders() + { + if ($this->_debugHeaders) { + return array('DKIM-Signature', 'X-DebugHash'); + } else { + return array('DKIM-Signature'); + } + } + + /** + * Adds an ignored Header. + * + * @param string $header_name + * + * @return Swift_Signers_DKIMSigner + */ + public function ignoreHeader($header_name) + { + $this->_ignoredHeaders[strtolower($header_name)] = true; + + return $this; + } + + /** + * Set the headers to sign. + * + * @param Swift_Mime_HeaderSet $headers + * + * @return Swift_Signers_DKIMSigner + */ + public function setHeaders(Swift_Mime_HeaderSet $headers) + { + $this->_headerCanonData = ''; + // Loop through Headers + $listHeaders = $headers->listAll(); + foreach ($listHeaders as $hName) { + // Check if we need to ignore Header + if (!isset($this->_ignoredHeaders[strtolower($hName)])) { + if ($headers->has($hName)) { + $tmp = $headers->getAll($hName); + foreach ($tmp as $header) { + if ($header->getFieldBody() != '') { + $this->_addHeader($header->toString()); + $this->_signedHeaders[] = $header->getFieldName(); + } + } + } + } + } + + return $this; + } + + /** + * Add the signature to the given Headers. + * + * @param Swift_Mime_HeaderSet $headers + * + * @return Swift_Signers_DKIMSigner + */ + public function addSignature(Swift_Mime_HeaderSet $headers) + { + // Prepare the DKIM-Signature + $params = array('v' => '1', 'a' => $this->_hashAlgorithm, 'bh' => base64_encode($this->_bodyHash), 'd' => $this->_domainName, 'h' => implode(': ', $this->_signedHeaders), 'i' => $this->_signerIdentity, 's' => $this->_selector); + if ($this->_bodyCanon != 'simple') { + $params['c'] = $this->_headerCanon.'/'.$this->_bodyCanon; + } elseif ($this->_headerCanon != 'simple') { + $params['c'] = $this->_headerCanon; + } + if ($this->_showLen) { + $params['l'] = $this->_bodyLen; + } + if ($this->_signatureTimestamp === true) { + $params['t'] = time(); + if ($this->_signatureExpiration !== false) { + $params['x'] = $params['t'] + $this->_signatureExpiration; + } + } else { + if ($this->_signatureTimestamp !== false) { + $params['t'] = $this->_signatureTimestamp; + } + if ($this->_signatureExpiration !== false) { + $params['x'] = $this->_signatureExpiration; + } + } + if ($this->_debugHeaders) { + $params['z'] = implode('|', $this->_debugHeadersData); + } + $string = ''; + foreach ($params as $k => $v) { + $string .= $k.'='.$v.'; '; + } + $string = trim($string); + $headers->addTextHeader('DKIM-Signature', $string); + // Add the last DKIM-Signature + $tmp = $headers->getAll('DKIM-Signature'); + $this->_dkimHeader = end($tmp); + $this->_addHeader(trim($this->_dkimHeader->toString())."\r\n b=", true); + $this->_endOfHeaders(); + if ($this->_debugHeaders) { + $headers->addTextHeader('X-DebugHash', base64_encode($this->_headerHash)); + } + $this->_dkimHeader->setValue($string.' b='.trim(chunk_split(base64_encode($this->_getEncryptedHash()), 73, ' '))); + + return $this; + } + + /* Private helpers */ + + protected function _addHeader($header, $is_sig = false) + { + switch ($this->_headerCanon) { + case 'relaxed': + // Prepare Header and cascade + $exploded = explode(':', $header, 2); + $name = strtolower(trim($exploded[0])); + $value = str_replace("\r\n", '', $exploded[1]); + $value = preg_replace("/[ \t][ \t]+/", ' ', $value); + $header = $name.':'.trim($value).($is_sig ? '' : "\r\n"); + case 'simple': + // Nothing to do + } + $this->_addToHeaderHash($header); + } + + /** + * @deprecated This method is currently useless in this class but it must be + * kept for BC reasons due to its "protected" scope. This method + * might be overridden by custom client code. + */ + protected function _endOfHeaders() + { + } + + protected function _canonicalizeBody($string) + { + $len = strlen($string); + $canon = ''; + $method = ($this->_bodyCanon == 'relaxed'); + for ($i = 0; $i < $len; ++$i) { + if ($this->_bodyCanonIgnoreStart > 0) { + --$this->_bodyCanonIgnoreStart; + continue; + } + switch ($string[$i]) { + case "\r": + $this->_bodyCanonLastChar = "\r"; + break; + case "\n": + if ($this->_bodyCanonLastChar == "\r") { + if ($method) { + $this->_bodyCanonSpace = false; + } + if ($this->_bodyCanonLine == '') { + ++$this->_bodyCanonEmptyCounter; + } else { + $this->_bodyCanonLine = ''; + $canon .= "\r\n"; + } + } else { + // Wooops Error + // todo handle it but should never happen + } + break; + case ' ': + case "\t": + if ($method) { + $this->_bodyCanonSpace = true; + break; + } + default: + if ($this->_bodyCanonEmptyCounter > 0) { + $canon .= str_repeat("\r\n", $this->_bodyCanonEmptyCounter); + $this->_bodyCanonEmptyCounter = 0; + } + if ($this->_bodyCanonSpace) { + $this->_bodyCanonLine .= ' '; + $canon .= ' '; + $this->_bodyCanonSpace = false; + } + $this->_bodyCanonLine .= $string[$i]; + $canon .= $string[$i]; + } + } + $this->_addToBodyHash($canon); + } + + protected function _endOfBody() + { + // Add trailing Line return if last line is non empty + if (strlen($this->_bodyCanonLine) > 0) { + $this->_addToBodyHash("\r\n"); + } + $this->_bodyHash = hash_final($this->_bodyHashHandler, true); + } + + private function _addToBodyHash($string) + { + $len = strlen($string); + if ($len > ($new_len = ($this->_maxLen - $this->_bodyLen))) { + $string = substr($string, 0, $new_len); + $len = $new_len; + } + hash_update($this->_bodyHashHandler, $string); + $this->_bodyLen += $len; + } + + private function _addToHeaderHash($header) + { + if ($this->_debugHeaders) { + $this->_debugHeadersData[] = trim($header); + } + $this->_headerCanonData .= $header; + } + + /** + * @throws Swift_SwiftException + * + * @return string + */ + private function _getEncryptedHash() + { + $signature = ''; + + switch ($this->_hashAlgorithm) { + case 'rsa-sha1': + $algorithm = OPENSSL_ALGO_SHA1; + break; + case 'rsa-sha256': + $algorithm = OPENSSL_ALGO_SHA256; + break; + } + $pkeyId = openssl_get_privatekey($this->_privateKey); + if (!$pkeyId) { + throw new Swift_SwiftException('Unable to load DKIM Private Key ['.openssl_error_string().']'); + } + if (openssl_sign($this->_headerCanonData, $signature, $pkeyId, $algorithm)) { + return $signature; + } + throw new Swift_SwiftException('Unable to sign DKIM Hash ['.openssl_error_string().']'); + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/DomainKeySigner.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/DomainKeySigner.php new file mode 100644 index 0000000..0365363 --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/DomainKeySigner.php @@ -0,0 +1,524 @@ + + */ +class Swift_Signers_DomainKeySigner implements Swift_Signers_HeaderSigner +{ + /** + * PrivateKey. + * + * @var string + */ + protected $_privateKey; + + /** + * DomainName. + * + * @var string + */ + protected $_domainName; + + /** + * Selector. + * + * @var string + */ + protected $_selector; + + /** + * Hash algorithm used. + * + * @var string + */ + protected $_hashAlgorithm = 'rsa-sha1'; + + /** + * Canonisation method. + * + * @var string + */ + protected $_canon = 'simple'; + + /** + * Headers not being signed. + * + * @var array + */ + protected $_ignoredHeaders = array(); + + /** + * Signer identity. + * + * @var string + */ + protected $_signerIdentity; + + /** + * Must we embed signed headers? + * + * @var bool + */ + protected $_debugHeaders = false; + + // work variables + /** + * Headers used to generate hash. + * + * @var array + */ + private $_signedHeaders = array(); + + /** + * Stores the signature header. + * + * @var Swift_Mime_Headers_ParameterizedHeader + */ + protected $_domainKeyHeader; + + /** + * Hash Handler. + * + * @var resource|null + */ + private $_hashHandler; + + private $_hash; + + private $_canonData = ''; + + private $_bodyCanonEmptyCounter = 0; + + private $_bodyCanonIgnoreStart = 2; + + private $_bodyCanonSpace = false; + + private $_bodyCanonLastChar = null; + + private $_bodyCanonLine = ''; + + private $_bound = array(); + + /** + * Constructor. + * + * @param string $privateKey + * @param string $domainName + * @param string $selector + */ + public function __construct($privateKey, $domainName, $selector) + { + $this->_privateKey = $privateKey; + $this->_domainName = $domainName; + $this->_signerIdentity = '@'.$domainName; + $this->_selector = $selector; + } + + /** + * Instanciate DomainKeySigner. + * + * @param string $privateKey + * @param string $domainName + * @param string $selector + * + * @return self + */ + public static function newInstance($privateKey, $domainName, $selector) + { + return new static($privateKey, $domainName, $selector); + } + + /** + * Resets internal states. + * + * @return $this + */ + public function reset() + { + $this->_hash = null; + $this->_hashHandler = null; + $this->_bodyCanonIgnoreStart = 2; + $this->_bodyCanonEmptyCounter = 0; + $this->_bodyCanonLastChar = null; + $this->_bodyCanonSpace = false; + + return $this; + } + + /** + * Writes $bytes to the end of the stream. + * + * Writing may not happen immediately if the stream chooses to buffer. If + * you want to write these bytes with immediate effect, call {@link commit()} + * after calling write(). + * + * This method returns the sequence ID of the write (i.e. 1 for first, 2 for + * second, etc etc). + * + * @param string $bytes + * + * @throws Swift_IoException + * + * @return $this + */ + public function write($bytes) + { + $this->_canonicalizeBody($bytes); + foreach ($this->_bound as $is) { + $is->write($bytes); + } + + return $this; + } + + /** + * For any bytes that are currently buffered inside the stream, force them + * off the buffer. + * + * @throws Swift_IoException + * + * @return $this + */ + public function commit() + { + // Nothing to do + return $this; + } + + /** + * Attach $is to this stream. + * The stream acts as an observer, receiving all data that is written. + * All {@link write()} and {@link flushBuffers()} operations will be mirrored. + * + * @param Swift_InputByteStream $is + * + * @return $this + */ + public function bind(Swift_InputByteStream $is) + { + // Don't have to mirror anything + $this->_bound[] = $is; + + return $this; + } + + /** + * Remove an already bound stream. + * If $is is not bound, no errors will be raised. + * If the stream currently has any buffered data it will be written to $is + * before unbinding occurs. + * + * @param Swift_InputByteStream $is + * + * @return $this + */ + public function unbind(Swift_InputByteStream $is) + { + // Don't have to mirror anything + foreach ($this->_bound as $k => $stream) { + if ($stream === $is) { + unset($this->_bound[$k]); + + break; + } + } + + return $this; + } + + /** + * Flush the contents of the stream (empty it) and set the internal pointer + * to the beginning. + * + * @throws Swift_IoException + * + * @return $this + */ + public function flushBuffers() + { + $this->reset(); + + return $this; + } + + /** + * Set hash_algorithm, must be one of rsa-sha256 | rsa-sha1 defaults to rsa-sha256. + * + * @param string $hash + * + * @return $this + */ + public function setHashAlgorithm($hash) + { + $this->_hashAlgorithm = 'rsa-sha1'; + + return $this; + } + + /** + * Set the canonicalization algorithm. + * + * @param string $canon simple | nofws defaults to simple + * + * @return $this + */ + public function setCanon($canon) + { + if ($canon == 'nofws') { + $this->_canon = 'nofws'; + } else { + $this->_canon = 'simple'; + } + + return $this; + } + + /** + * Set the signer identity. + * + * @param string $identity + * + * @return $this + */ + public function setSignerIdentity($identity) + { + $this->_signerIdentity = $identity; + + return $this; + } + + /** + * Enable / disable the DebugHeaders. + * + * @param bool $debug + * + * @return $this + */ + public function setDebugHeaders($debug) + { + $this->_debugHeaders = (bool) $debug; + + return $this; + } + + /** + * Start Body. + */ + public function startBody() + { + } + + /** + * End Body. + */ + public function endBody() + { + $this->_endOfBody(); + } + + /** + * Returns the list of Headers Tampered by this plugin. + * + * @return array + */ + public function getAlteredHeaders() + { + if ($this->_debugHeaders) { + return array('DomainKey-Signature', 'X-DebugHash'); + } + + return array('DomainKey-Signature'); + } + + /** + * Adds an ignored Header. + * + * @param string $header_name + * + * @return $this + */ + public function ignoreHeader($header_name) + { + $this->_ignoredHeaders[strtolower($header_name)] = true; + + return $this; + } + + /** + * Set the headers to sign. + * + * @param Swift_Mime_HeaderSet $headers + * + * @return $this + */ + public function setHeaders(Swift_Mime_HeaderSet $headers) + { + $this->_startHash(); + $this->_canonData = ''; + // Loop through Headers + $listHeaders = $headers->listAll(); + foreach ($listHeaders as $hName) { + // Check if we need to ignore Header + if (!isset($this->_ignoredHeaders[strtolower($hName)])) { + if ($headers->has($hName)) { + $tmp = $headers->getAll($hName); + foreach ($tmp as $header) { + if ($header->getFieldBody() != '') { + $this->_addHeader($header->toString()); + $this->_signedHeaders[] = $header->getFieldName(); + } + } + } + } + } + $this->_endOfHeaders(); + + return $this; + } + + /** + * Add the signature to the given Headers. + * + * @param Swift_Mime_HeaderSet $headers + * + * @return $this + */ + public function addSignature(Swift_Mime_HeaderSet $headers) + { + // Prepare the DomainKey-Signature Header + $params = array('a' => $this->_hashAlgorithm, 'b' => chunk_split(base64_encode($this->_getEncryptedHash()), 73, ' '), 'c' => $this->_canon, 'd' => $this->_domainName, 'h' => implode(': ', $this->_signedHeaders), 'q' => 'dns', 's' => $this->_selector); + $string = ''; + foreach ($params as $k => $v) { + $string .= $k.'='.$v.'; '; + } + $string = trim($string); + $headers->addTextHeader('DomainKey-Signature', $string); + + return $this; + } + + /* Private helpers */ + + protected function _addHeader($header) + { + switch ($this->_canon) { + case 'nofws': + // Prepare Header and cascade + $exploded = explode(':', $header, 2); + $name = strtolower(trim($exploded[0])); + $value = str_replace("\r\n", '', $exploded[1]); + $value = preg_replace("/[ \t][ \t]+/", ' ', $value); + $header = $name.':'.trim($value)."\r\n"; + case 'simple': + // Nothing to do + } + $this->_addToHash($header); + } + + protected function _endOfHeaders() + { + $this->_bodyCanonEmptyCounter = 1; + } + + protected function _canonicalizeBody($string) + { + $len = strlen($string); + $canon = ''; + $nofws = ($this->_canon == 'nofws'); + for ($i = 0; $i < $len; ++$i) { + if ($this->_bodyCanonIgnoreStart > 0) { + --$this->_bodyCanonIgnoreStart; + continue; + } + switch ($string[$i]) { + case "\r": + $this->_bodyCanonLastChar = "\r"; + break; + case "\n": + if ($this->_bodyCanonLastChar == "\r") { + if ($nofws) { + $this->_bodyCanonSpace = false; + } + if ($this->_bodyCanonLine == '') { + ++$this->_bodyCanonEmptyCounter; + } else { + $this->_bodyCanonLine = ''; + $canon .= "\r\n"; + } + } else { + // Wooops Error + throw new Swift_SwiftException('Invalid new line sequence in mail found \n without preceding \r'); + } + break; + case ' ': + case "\t": + case "\x09": //HTAB + if ($nofws) { + $this->_bodyCanonSpace = true; + break; + } + default: + if ($this->_bodyCanonEmptyCounter > 0) { + $canon .= str_repeat("\r\n", $this->_bodyCanonEmptyCounter); + $this->_bodyCanonEmptyCounter = 0; + } + $this->_bodyCanonLine .= $string[$i]; + $canon .= $string[$i]; + } + } + $this->_addToHash($canon); + } + + protected function _endOfBody() + { + if (strlen($this->_bodyCanonLine) > 0) { + $this->_addToHash("\r\n"); + } + $this->_hash = hash_final($this->_hashHandler, true); + } + + private function _addToHash($string) + { + $this->_canonData .= $string; + hash_update($this->_hashHandler, $string); + } + + private function _startHash() + { + // Init + switch ($this->_hashAlgorithm) { + case 'rsa-sha1': + $this->_hashHandler = hash_init('sha1'); + break; + } + $this->_bodyCanonLine = ''; + } + + /** + * @throws Swift_SwiftException + * + * @return string + */ + private function _getEncryptedHash() + { + $signature = ''; + $pkeyId = openssl_get_privatekey($this->_privateKey); + if (!$pkeyId) { + throw new Swift_SwiftException('Unable to load DomainKey Private Key ['.openssl_error_string().']'); + } + if (openssl_sign($this->_canonData, $signature, $pkeyId, OPENSSL_ALGO_SHA1)) { + return $signature; + } + throw new Swift_SwiftException('Unable to sign DomainKey Hash ['.openssl_error_string().']'); + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/HeaderSigner.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/HeaderSigner.php new file mode 100644 index 0000000..ef8832f --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/HeaderSigner.php @@ -0,0 +1,65 @@ + + */ +interface Swift_Signers_HeaderSigner extends Swift_Signer, Swift_InputByteStream +{ + /** + * Exclude an header from the signed headers. + * + * @param string $header_name + * + * @return self + */ + public function ignoreHeader($header_name); + + /** + * Prepare the Signer to get a new Body. + * + * @return self + */ + public function startBody(); + + /** + * Give the signal that the body has finished streaming. + * + * @return self + */ + public function endBody(); + + /** + * Give the headers already given. + * + * @param Swift_Mime_SimpleHeaderSet $headers + * + * @return self + */ + public function setHeaders(Swift_Mime_HeaderSet $headers); + + /** + * Add the header(s) to the headerSet. + * + * @param Swift_Mime_HeaderSet $headers + * + * @return self + */ + public function addSignature(Swift_Mime_HeaderSet $headers); + + /** + * Return the list of header a signer might tamper. + * + * @return array + */ + public function getAlteredHeaders(); +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/OpenDKIMSigner.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/OpenDKIMSigner.php new file mode 100644 index 0000000..8fdbaa4 --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/OpenDKIMSigner.php @@ -0,0 +1,190 @@ + + */ +class Swift_Signers_OpenDKIMSigner extends Swift_Signers_DKIMSigner +{ + private $_peclLoaded = false; + + private $_dkimHandler = null; + + private $dropFirstLF = true; + + const CANON_RELAXED = 1; + const CANON_SIMPLE = 2; + const SIG_RSA_SHA1 = 3; + const SIG_RSA_SHA256 = 4; + + public function __construct($privateKey, $domainName, $selector) + { + if (!extension_loaded('opendkim')) { + throw new Swift_SwiftException('php-opendkim extension not found'); + } + + $this->_peclLoaded = true; + + parent::__construct($privateKey, $domainName, $selector); + } + + public static function newInstance($privateKey, $domainName, $selector) + { + return new static($privateKey, $domainName, $selector); + } + + public function addSignature(Swift_Mime_HeaderSet $headers) + { + $header = new Swift_Mime_Headers_OpenDKIMHeader('DKIM-Signature'); + $headerVal = $this->_dkimHandler->getSignatureHeader(); + if (!$headerVal) { + throw new Swift_SwiftException('OpenDKIM Error: '.$this->_dkimHandler->getError()); + } + $header->setValue($headerVal); + $headers->set($header); + + return $this; + } + + public function setHeaders(Swift_Mime_HeaderSet $headers) + { + $bodyLen = $this->_bodyLen; + if (is_bool($bodyLen)) { + $bodyLen = -1; + } + $hash = $this->_hashAlgorithm == 'rsa-sha1' ? OpenDKIMSign::ALG_RSASHA1 : OpenDKIMSign::ALG_RSASHA256; + $bodyCanon = $this->_bodyCanon == 'simple' ? OpenDKIMSign::CANON_SIMPLE : OpenDKIMSign::CANON_RELAXED; + $headerCanon = $this->_headerCanon == 'simple' ? OpenDKIMSign::CANON_SIMPLE : OpenDKIMSign::CANON_RELAXED; + $this->_dkimHandler = new OpenDKIMSign($this->_privateKey, $this->_selector, $this->_domainName, $headerCanon, $bodyCanon, $hash, $bodyLen); + // Hardcode signature Margin for now + $this->_dkimHandler->setMargin(78); + + if (!is_numeric($this->_signatureTimestamp)) { + OpenDKIM::setOption(OpenDKIM::OPTS_FIXEDTIME, time()); + } else { + if (!OpenDKIM::setOption(OpenDKIM::OPTS_FIXEDTIME, $this->_signatureTimestamp)) { + throw new Swift_SwiftException('Unable to force signature timestamp ['.openssl_error_string().']'); + } + } + if (isset($this->_signerIdentity)) { + $this->_dkimHandler->setSigner($this->_signerIdentity); + } + $listHeaders = $headers->listAll(); + foreach ($listHeaders as $hName) { + // Check if we need to ignore Header + if (!isset($this->_ignoredHeaders[strtolower($hName)])) { + $tmp = $headers->getAll($hName); + if ($headers->has($hName)) { + foreach ($tmp as $header) { + if ($header->getFieldBody() != '') { + $htosign = $header->toString(); + $this->_dkimHandler->header($htosign); + $this->_signedHeaders[] = $header->getFieldName(); + } + } + } + } + } + + return $this; + } + + public function startBody() + { + if (!$this->_peclLoaded) { + return parent::startBody(); + } + $this->dropFirstLF = true; + $this->_dkimHandler->eoh(); + + return $this; + } + + public function endBody() + { + if (!$this->_peclLoaded) { + return parent::endBody(); + } + $this->_dkimHandler->eom(); + + return $this; + } + + public function reset() + { + $this->_dkimHandler = null; + parent::reset(); + + return $this; + } + + /** + * Set the signature timestamp. + * + * @param int $time + * + * @return $this + */ + public function setSignatureTimestamp($time) + { + $this->_signatureTimestamp = $time; + + return $this; + } + + /** + * Set the signature expiration timestamp. + * + * @param int $time + * + * @return $this + */ + public function setSignatureExpiration($time) + { + $this->_signatureExpiration = $time; + + return $this; + } + + /** + * Enable / disable the DebugHeaders. + * + * @param bool $debug + * + * @return $this + */ + public function setDebugHeaders($debug) + { + $this->_debugHeaders = (bool) $debug; + + return $this; + } + + // Protected + + protected function _canonicalizeBody($string) + { + if (!$this->_peclLoaded) { + return parent::_canonicalizeBody($string); + } + if (false && $this->dropFirstLF === true) { + if ($string[0] == "\r" && $string[1] == "\n") { + $string = substr($string, 2); + } + } + $this->dropFirstLF = false; + if (strlen($string)) { + $this->_dkimHandler->body($string); + } + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/SMimeSigner.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/SMimeSigner.php new file mode 100644 index 0000000..d13c02e --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/SMimeSigner.php @@ -0,0 +1,436 @@ + + */ +class Swift_Signers_SMimeSigner implements Swift_Signers_BodySigner +{ + protected $signCertificate; + protected $signPrivateKey; + protected $encryptCert; + protected $signThenEncrypt = true; + protected $signLevel; + protected $encryptLevel; + protected $signOptions; + protected $encryptOptions; + protected $encryptCipher; + protected $extraCerts = null; + + /** + * @var Swift_StreamFilters_StringReplacementFilterFactory + */ + protected $replacementFactory; + + /** + * @var Swift_Mime_HeaderFactory + */ + protected $headerFactory; + + /** + * Constructor. + * + * @param string|null $signCertificate + * @param string|null $signPrivateKey + * @param string|null $encryptCertificate + */ + public function __construct($signCertificate = null, $signPrivateKey = null, $encryptCertificate = null) + { + if (null !== $signPrivateKey) { + $this->setSignCertificate($signCertificate, $signPrivateKey); + } + + if (null !== $encryptCertificate) { + $this->setEncryptCertificate($encryptCertificate); + } + + $this->replacementFactory = Swift_DependencyContainer::getInstance() + ->lookup('transport.replacementfactory'); + + $this->signOptions = PKCS7_DETACHED; + + // Supported since php5.4 + if (defined('OPENSSL_CIPHER_AES_128_CBC')) { + $this->encryptCipher = OPENSSL_CIPHER_AES_128_CBC; + } else { + $this->encryptCipher = OPENSSL_CIPHER_RC2_128; + } + } + + /** + * Returns an new Swift_Signers_SMimeSigner instance. + * + * @param string $certificate + * @param string $privateKey + * + * @return self + */ + public static function newInstance($certificate = null, $privateKey = null) + { + return new self($certificate, $privateKey); + } + + /** + * Set the certificate location to use for signing. + * + * @see http://www.php.net/manual/en/openssl.pkcs7.flags.php + * + * @param string $certificate + * @param string|array $privateKey If the key needs an passphrase use array('file-location', 'passphrase') instead + * @param int $signOptions Bitwise operator options for openssl_pkcs7_sign() + * @param string $extraCerts A file containing intermediate certificates needed by the signing certificate + * + * @return $this + */ + public function setSignCertificate($certificate, $privateKey = null, $signOptions = PKCS7_DETACHED, $extraCerts = null) + { + $this->signCertificate = 'file://'.str_replace('\\', '/', realpath($certificate)); + + if (null !== $privateKey) { + if (is_array($privateKey)) { + $this->signPrivateKey = $privateKey; + $this->signPrivateKey[0] = 'file://'.str_replace('\\', '/', realpath($privateKey[0])); + } else { + $this->signPrivateKey = 'file://'.str_replace('\\', '/', realpath($privateKey)); + } + } + + $this->signOptions = $signOptions; + if (null !== $extraCerts) { + $this->extraCerts = str_replace('\\', '/', realpath($extraCerts)); + } + + return $this; + } + + /** + * Set the certificate location to use for encryption. + * + * @see http://www.php.net/manual/en/openssl.pkcs7.flags.php + * @see http://nl3.php.net/manual/en/openssl.ciphers.php + * + * @param string|array $recipientCerts Either an single X.509 certificate, or an assoc array of X.509 certificates. + * @param int $cipher + * + * @return $this + */ + public function setEncryptCertificate($recipientCerts, $cipher = null) + { + if (is_array($recipientCerts)) { + $this->encryptCert = array(); + + foreach ($recipientCerts as $cert) { + $this->encryptCert[] = 'file://'.str_replace('\\', '/', realpath($cert)); + } + } else { + $this->encryptCert = 'file://'.str_replace('\\', '/', realpath($recipientCerts)); + } + + if (null !== $cipher) { + $this->encryptCipher = $cipher; + } + + return $this; + } + + /** + * @return string + */ + public function getSignCertificate() + { + return $this->signCertificate; + } + + /** + * @return string + */ + public function getSignPrivateKey() + { + return $this->signPrivateKey; + } + + /** + * Set perform signing before encryption. + * + * The default is to first sign the message and then encrypt. + * But some older mail clients, namely Microsoft Outlook 2000 will work when the message first encrypted. + * As this goes against the official specs, its recommended to only use 'encryption -> signing' when specifically targeting these 'broken' clients. + * + * @param bool $signThenEncrypt + * + * @return $this + */ + public function setSignThenEncrypt($signThenEncrypt = true) + { + $this->signThenEncrypt = $signThenEncrypt; + + return $this; + } + + /** + * @return bool + */ + public function isSignThenEncrypt() + { + return $this->signThenEncrypt; + } + + /** + * Resets internal states. + * + * @return $this + */ + public function reset() + { + return $this; + } + + /** + * Change the Swift_Message to apply the signing. + * + * @param Swift_Message $message + * + * @return $this + */ + public function signMessage(Swift_Message $message) + { + if (null === $this->signCertificate && null === $this->encryptCert) { + return $this; + } + + // Store the message using ByteStream to a file{1} + // Remove all Children + // Sign file{1}, parse the new MIME headers and set them on the primary MimeEntity + // Set the singed-body as the new body (without boundary) + + $messageStream = new Swift_ByteStream_TemporaryFileByteStream(); + $this->toSMimeByteStream($messageStream, $message); + $message->setEncoder(Swift_DependencyContainer::getInstance()->lookup('mime.rawcontentencoder')); + + $message->setChildren(array()); + $this->streamToMime($messageStream, $message); + } + + /** + * Return the list of header a signer might tamper. + * + * @return array + */ + public function getAlteredHeaders() + { + return array('Content-Type', 'Content-Transfer-Encoding', 'Content-Disposition'); + } + + /** + * @param Swift_InputByteStream $inputStream + * @param Swift_Message $mimeEntity + */ + protected function toSMimeByteStream(Swift_InputByteStream $inputStream, Swift_Message $message) + { + $mimeEntity = $this->createMessage($message); + $messageStream = new Swift_ByteStream_TemporaryFileByteStream(); + + $mimeEntity->toByteStream($messageStream); + $messageStream->commit(); + + if (null !== $this->signCertificate && null !== $this->encryptCert) { + $temporaryStream = new Swift_ByteStream_TemporaryFileByteStream(); + + if ($this->signThenEncrypt) { + $this->messageStreamToSignedByteStream($messageStream, $temporaryStream); + $this->messageStreamToEncryptedByteStream($temporaryStream, $inputStream); + } else { + $this->messageStreamToEncryptedByteStream($messageStream, $temporaryStream); + $this->messageStreamToSignedByteStream($temporaryStream, $inputStream); + } + } elseif ($this->signCertificate !== null) { + $this->messageStreamToSignedByteStream($messageStream, $inputStream); + } else { + $this->messageStreamToEncryptedByteStream($messageStream, $inputStream); + } + } + + /** + * @param Swift_Message $message + * + * @return Swift_Message + */ + protected function createMessage(Swift_Message $message) + { + $mimeEntity = new Swift_Message('', $message->getBody(), $message->getContentType(), $message->getCharset()); + $mimeEntity->setChildren($message->getChildren()); + + $messageHeaders = $mimeEntity->getHeaders(); + $messageHeaders->remove('Message-ID'); + $messageHeaders->remove('Date'); + $messageHeaders->remove('Subject'); + $messageHeaders->remove('MIME-Version'); + $messageHeaders->remove('To'); + $messageHeaders->remove('From'); + + return $mimeEntity; + } + + /** + * @param Swift_FileStream $outputStream + * @param Swift_InputByteStream $inputStream + * + * @throws Swift_IoException + */ + protected function messageStreamToSignedByteStream(Swift_FileStream $outputStream, Swift_InputByteStream $inputStream) + { + $signedMessageStream = new Swift_ByteStream_TemporaryFileByteStream(); + + $args = array($outputStream->getPath(), $signedMessageStream->getPath(), $this->signCertificate, $this->signPrivateKey, array(), $this->signOptions); + if (null !== $this->extraCerts) { + $args[] = $this->extraCerts; + } + + if (!call_user_func_array('openssl_pkcs7_sign', $args)) { + throw new Swift_IoException(sprintf('Failed to sign S/Mime message. Error: "%s".', openssl_error_string())); + } + + $this->copyFromOpenSSLOutput($signedMessageStream, $inputStream); + } + + /** + * @param Swift_FileStream $outputStream + * @param Swift_InputByteStream $is + * + * @throws Swift_IoException + */ + protected function messageStreamToEncryptedByteStream(Swift_FileStream $outputStream, Swift_InputByteStream $is) + { + $encryptedMessageStream = new Swift_ByteStream_TemporaryFileByteStream(); + + if (!openssl_pkcs7_encrypt($outputStream->getPath(), $encryptedMessageStream->getPath(), $this->encryptCert, array(), 0, $this->encryptCipher)) { + throw new Swift_IoException(sprintf('Failed to encrypt S/Mime message. Error: "%s".', openssl_error_string())); + } + + $this->copyFromOpenSSLOutput($encryptedMessageStream, $is); + } + + /** + * @param Swift_OutputByteStream $fromStream + * @param Swift_InputByteStream $toStream + */ + protected function copyFromOpenSSLOutput(Swift_OutputByteStream $fromStream, Swift_InputByteStream $toStream) + { + $bufferLength = 4096; + $filteredStream = new Swift_ByteStream_TemporaryFileByteStream(); + $filteredStream->addFilter($this->replacementFactory->createFilter("\r\n", "\n"), 'CRLF to LF'); + $filteredStream->addFilter($this->replacementFactory->createFilter("\n", "\r\n"), 'LF to CRLF'); + + while (false !== ($buffer = $fromStream->read($bufferLength))) { + $filteredStream->write($buffer); + } + + $filteredStream->flushBuffers(); + + while (false !== ($buffer = $filteredStream->read($bufferLength))) { + $toStream->write($buffer); + } + + $toStream->commit(); + } + + /** + * Merges an OutputByteStream to Swift_Message. + * + * @param Swift_OutputByteStream $fromStream + * @param Swift_Message $message + */ + protected function streamToMime(Swift_OutputByteStream $fromStream, Swift_Message $message) + { + $bufferLength = 78; + $headerData = ''; + + $fromStream->setReadPointer(0); + + while (($buffer = $fromStream->read($bufferLength)) !== false) { + $headerData .= $buffer; + + if (false !== strpos($buffer, "\r\n\r\n")) { + break; + } + } + + $headersPosEnd = strpos($headerData, "\r\n\r\n"); + $headerData = trim($headerData); + $headerData = substr($headerData, 0, $headersPosEnd); + $headerLines = explode("\r\n", $headerData); + unset($headerData); + + $headers = array(); + $currentHeaderName = ''; + + foreach ($headerLines as $headerLine) { + // Line separated + if (ctype_space($headerLines[0]) || false === strpos($headerLine, ':')) { + $headers[$currentHeaderName] .= ' '.trim($headerLine); + continue; + } + + $header = explode(':', $headerLine, 2); + $currentHeaderName = strtolower($header[0]); + $headers[$currentHeaderName] = trim($header[1]); + } + + $messageStream = new Swift_ByteStream_TemporaryFileByteStream(); + $messageStream->addFilter($this->replacementFactory->createFilter("\r\n", "\n"), 'CRLF to LF'); + $messageStream->addFilter($this->replacementFactory->createFilter("\n", "\r\n"), 'LF to CRLF'); + + $messageHeaders = $message->getHeaders(); + + // No need to check for 'application/pkcs7-mime', as this is always base64 + if ('multipart/signed;' === substr($headers['content-type'], 0, 17)) { + if (!preg_match('/boundary=("[^"]+"|(?:[^\s]+|$))/is', $headers['content-type'], $contentTypeData)) { + throw new Swift_SwiftException('Failed to find Boundary parameter'); + } + + $boundary = trim($contentTypeData['1'], '"'); + + // Skip the header and CRLF CRLF + $fromStream->setReadPointer($headersPosEnd + 4); + + while (false !== ($buffer = $fromStream->read($bufferLength))) { + $messageStream->write($buffer); + } + + $messageStream->commit(); + + $messageHeaders->remove('Content-Transfer-Encoding'); + $message->setContentType($headers['content-type']); + $message->setBoundary($boundary); + $message->setBody($messageStream); + } else { + $fromStream->setReadPointer($headersPosEnd + 4); + + if (null === $this->headerFactory) { + $this->headerFactory = Swift_DependencyContainer::getInstance()->lookup('mime.headerfactory'); + } + + $message->setContentType($headers['content-type']); + $messageHeaders->set($this->headerFactory->createTextHeader('Content-Transfer-Encoding', $headers['content-transfer-encoding'])); + $messageHeaders->set($this->headerFactory->createTextHeader('Content-Disposition', $headers['content-disposition'])); + + while (false !== ($buffer = $fromStream->read($bufferLength))) { + $messageStream->write($buffer); + } + + $messageStream->commit(); + $message->setBody($messageStream); + } + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/SmtpTransport.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/SmtpTransport.php new file mode 100644 index 0000000..b97f01e --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/SmtpTransport.php @@ -0,0 +1,58 @@ +createDependenciesFor('transport.smtp') + ); + + $this->setHost($host); + $this->setPort($port); + $this->setEncryption($security); + } + + /** + * Create a new SmtpTransport instance. + * + * @param string $host + * @param int $port + * @param string $security + * + * @return self + */ + public static function newInstance($host = 'localhost', $port = 25, $security = null) + { + return new self($host, $port, $security); + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Spool.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Spool.php new file mode 100644 index 0000000..c16ab4b --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Spool.php @@ -0,0 +1,53 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * Interface for spools. + * + * @author Fabien Potencier + */ +interface Swift_Spool +{ + /** + * Starts this Spool mechanism. + */ + public function start(); + + /** + * Stops this Spool mechanism. + */ + public function stop(); + + /** + * Tests if this Spool mechanism has started. + * + * @return bool + */ + public function isStarted(); + + /** + * Queues a message. + * + * @param Swift_Mime_Message $message The message to store + * + * @return bool Whether the operation has succeeded + */ + public function queueMessage(Swift_Mime_Message $message); + + /** + * Sends messages using the given transport instance. + * + * @param Swift_Transport $transport A transport instance + * @param string[] $failedRecipients An array of failures by-reference + * + * @return int The number of sent emails + */ + public function flushQueue(Swift_Transport $transport, &$failedRecipients = null); +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/SpoolTransport.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/SpoolTransport.php new file mode 100644 index 0000000..79c9b1f --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/SpoolTransport.php @@ -0,0 +1,47 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * Stores Messages in a queue. + * + * @author Fabien Potencier + */ +class Swift_SpoolTransport extends Swift_Transport_SpoolTransport +{ + /** + * Create a new SpoolTransport. + * + * @param Swift_Spool $spool + */ + public function __construct(Swift_Spool $spool) + { + $arguments = Swift_DependencyContainer::getInstance() + ->createDependenciesFor('transport.spool'); + + $arguments[] = $spool; + + call_user_func_array( + array($this, 'Swift_Transport_SpoolTransport::__construct'), + $arguments + ); + } + + /** + * Create a new SpoolTransport instance. + * + * @param Swift_Spool $spool + * + * @return self + */ + public static function newInstance(Swift_Spool $spool) + { + return new self($spool); + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/StreamFilter.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/StreamFilter.php new file mode 100644 index 0000000..362be2e --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/StreamFilter.php @@ -0,0 +1,35 @@ +_search = $search; + $this->_index = array(); + $this->_tree = array(); + $this->_replace = array(); + $this->_repSize = array(); + + $tree = null; + $i = null; + $last_size = $size = 0; + foreach ($search as $i => $search_element) { + if ($tree !== null) { + $tree[-1] = min(count($replace) - 1, $i - 1); + $tree[-2] = $last_size; + } + $tree = &$this->_tree; + if (is_array($search_element)) { + foreach ($search_element as $k => $char) { + $this->_index[$char] = true; + if (!isset($tree[$char])) { + $tree[$char] = array(); + } + $tree = &$tree[$char]; + } + $last_size = $k + 1; + $size = max($size, $last_size); + } else { + $last_size = 1; + if (!isset($tree[$search_element])) { + $tree[$search_element] = array(); + } + $tree = &$tree[$search_element]; + $size = max($last_size, $size); + $this->_index[$search_element] = true; + } + } + if ($i !== null) { + $tree[-1] = min(count($replace) - 1, $i); + $tree[-2] = $last_size; + $this->_treeMaxLen = $size; + } + foreach ($replace as $rep) { + if (!is_array($rep)) { + $rep = array($rep); + } + $this->_replace[] = $rep; + } + for ($i = count($this->_replace) - 1; $i >= 0; --$i) { + $this->_replace[$i] = $rep = $this->filter($this->_replace[$i], $i); + $this->_repSize[$i] = count($rep); + } + } + + /** + * Returns true if based on the buffer passed more bytes should be buffered. + * + * @param array $buffer + * + * @return bool + */ + public function shouldBuffer($buffer) + { + $endOfBuffer = end($buffer); + + return isset($this->_index[$endOfBuffer]); + } + + /** + * Perform the actual replacements on $buffer and return the result. + * + * @param array $buffer + * @param int $_minReplaces + * + * @return array + */ + public function filter($buffer, $_minReplaces = -1) + { + if ($this->_treeMaxLen == 0) { + return $buffer; + } + + $newBuffer = array(); + $buf_size = count($buffer); + $last_size = 0; + for ($i = 0; $i < $buf_size; ++$i) { + $search_pos = $this->_tree; + $last_found = PHP_INT_MAX; + // We try to find if the next byte is part of a search pattern + for ($j = 0; $j <= $this->_treeMaxLen; ++$j) { + // We have a new byte for a search pattern + if (isset($buffer[$p = $i + $j]) && isset($search_pos[$buffer[$p]])) { + $search_pos = $search_pos[$buffer[$p]]; + // We have a complete pattern, save, in case we don't find a better match later + if (isset($search_pos[-1]) && $search_pos[-1] < $last_found + && $search_pos[-1] > $_minReplaces) { + $last_found = $search_pos[-1]; + $last_size = $search_pos[-2]; + } + } + // We got a complete pattern + elseif ($last_found !== PHP_INT_MAX) { + // Adding replacement datas to output buffer + $rep_size = $this->_repSize[$last_found]; + for ($j = 0; $j < $rep_size; ++$j) { + $newBuffer[] = $this->_replace[$last_found][$j]; + } + // We Move cursor forward + $i += $last_size - 1; + // Edge Case, last position in buffer + if ($i >= $buf_size) { + $newBuffer[] = $buffer[$i]; + } + + // We start the next loop + continue 2; + } else { + // this byte is not in a pattern and we haven't found another pattern + break; + } + } + // Normal byte, move it to output buffer + $newBuffer[] = $buffer[$i]; + } + + return $newBuffer; + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/StreamFilters/StringReplacementFilter.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/StreamFilters/StringReplacementFilter.php new file mode 100644 index 0000000..f64144a --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/StreamFilters/StringReplacementFilter.php @@ -0,0 +1,70 @@ +_search = $search; + $this->_replace = $replace; + } + + /** + * Returns true if based on the buffer passed more bytes should be buffered. + * + * @param string $buffer + * + * @return bool + */ + public function shouldBuffer($buffer) + { + if ('' === $buffer) { + return false; + } + + $endOfBuffer = substr($buffer, -1); + foreach ((array) $this->_search as $needle) { + if (false !== strpos($needle, $endOfBuffer)) { + return true; + } + } + + return false; + } + + /** + * Perform the actual replacements on $buffer and return the result. + * + * @param string $buffer + * + * @return string + */ + public function filter($buffer) + { + return str_replace($this->_search, $this->_replace, $buffer); + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/StreamFilters/StringReplacementFilterFactory.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/StreamFilters/StringReplacementFilterFactory.php new file mode 100644 index 0000000..e98240b --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/StreamFilters/StringReplacementFilterFactory.php @@ -0,0 +1,45 @@ +_filters[$search][$replace])) { + if (!isset($this->_filters[$search])) { + $this->_filters[$search] = array(); + } + + if (!isset($this->_filters[$search][$replace])) { + $this->_filters[$search][$replace] = array(); + } + + $this->_filters[$search][$replace] = new Swift_StreamFilters_StringReplacementFilter($search, $replace); + } + + return $this->_filters[$search][$replace]; + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/SwiftException.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/SwiftException.php new file mode 100644 index 0000000..db3d310 --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/SwiftException.php @@ -0,0 +1,29 @@ +_eventDispatcher = $dispatcher; + $this->_buffer = $buf; + $this->_lookupHostname(); + } + + /** + * Set the name of the local domain which Swift will identify itself as. + * + * This should be a fully-qualified domain name and should be truly the domain + * you're using. + * + * If your server doesn't have a domain name, use the IP in square + * brackets (i.e. [127.0.0.1]). + * + * @param string $domain + * + * @return $this + */ + public function setLocalDomain($domain) + { + $this->_domain = $domain; + + return $this; + } + + /** + * Get the name of the domain Swift will identify as. + * + * @return string + */ + public function getLocalDomain() + { + return $this->_domain; + } + + /** + * Sets the source IP. + * + * @param string $source + */ + public function setSourceIp($source) + { + $this->_sourceIp = $source; + } + + /** + * Returns the IP used to connect to the destination. + * + * @return string + */ + public function getSourceIp() + { + return $this->_sourceIp; + } + + /** + * Start the SMTP connection. + */ + public function start() + { + if (!$this->_started) { + if ($evt = $this->_eventDispatcher->createTransportChangeEvent($this)) { + $this->_eventDispatcher->dispatchEvent($evt, 'beforeTransportStarted'); + if ($evt->bubbleCancelled()) { + return; + } + } + + try { + $this->_buffer->initialize($this->_getBufferParams()); + } catch (Swift_TransportException $e) { + $this->_throwException($e); + } + $this->_readGreeting(); + $this->_doHeloCommand(); + + if ($evt) { + $this->_eventDispatcher->dispatchEvent($evt, 'transportStarted'); + } + + $this->_started = true; + } + } + + /** + * Test if an SMTP connection has been established. + * + * @return bool + */ + public function isStarted() + { + return $this->_started; + } + + /** + * Send the given Message. + * + * Recipient/sender data will be retrieved from the Message API. + * The return value is the number of recipients who were accepted for delivery. + * + * @param Swift_Mime_Message $message + * @param string[] $failedRecipients An array of failures by-reference + * + * @return int + */ + public function send(Swift_Mime_Message $message, &$failedRecipients = null) + { + $sent = 0; + $failedRecipients = (array) $failedRecipients; + + if ($evt = $this->_eventDispatcher->createSendEvent($this, $message)) { + $this->_eventDispatcher->dispatchEvent($evt, 'beforeSendPerformed'); + if ($evt->bubbleCancelled()) { + return 0; + } + } + + if (!$reversePath = $this->_getReversePath($message)) { + $this->_throwException(new Swift_TransportException( + 'Cannot send message without a sender address' + ) + ); + } + + $to = (array) $message->getTo(); + $cc = (array) $message->getCc(); + $tos = array_merge($to, $cc); + $bcc = (array) $message->getBcc(); + + $message->setBcc(array()); + + try { + $sent += $this->_sendTo($message, $reversePath, $tos, $failedRecipients); + $sent += $this->_sendBcc($message, $reversePath, $bcc, $failedRecipients); + } catch (Exception $e) { + $message->setBcc($bcc); + throw $e; + } + + $message->setBcc($bcc); + + if ($evt) { + if ($sent == count($to) + count($cc) + count($bcc)) { + $evt->setResult(Swift_Events_SendEvent::RESULT_SUCCESS); + } elseif ($sent > 0) { + $evt->setResult(Swift_Events_SendEvent::RESULT_TENTATIVE); + } else { + $evt->setResult(Swift_Events_SendEvent::RESULT_FAILED); + } + $evt->setFailedRecipients($failedRecipients); + $this->_eventDispatcher->dispatchEvent($evt, 'sendPerformed'); + } + + $message->generateId(); //Make sure a new Message ID is used + + return $sent; + } + + /** + * Stop the SMTP connection. + */ + public function stop() + { + if ($this->_started) { + if ($evt = $this->_eventDispatcher->createTransportChangeEvent($this)) { + $this->_eventDispatcher->dispatchEvent($evt, 'beforeTransportStopped'); + if ($evt->bubbleCancelled()) { + return; + } + } + + try { + $this->executeCommand("QUIT\r\n", array(221)); + } catch (Swift_TransportException $e) { + } + + try { + $this->_buffer->terminate(); + + if ($evt) { + $this->_eventDispatcher->dispatchEvent($evt, 'transportStopped'); + } + } catch (Swift_TransportException $e) { + $this->_throwException($e); + } + } + $this->_started = false; + } + + /** + * Register a plugin. + * + * @param Swift_Events_EventListener $plugin + */ + public function registerPlugin(Swift_Events_EventListener $plugin) + { + $this->_eventDispatcher->bindEventListener($plugin); + } + + /** + * Reset the current mail transaction. + */ + public function reset() + { + $this->executeCommand("RSET\r\n", array(250)); + } + + /** + * Get the IoBuffer where read/writes are occurring. + * + * @return Swift_Transport_IoBuffer + */ + public function getBuffer() + { + return $this->_buffer; + } + + /** + * Run a command against the buffer, expecting the given response codes. + * + * If no response codes are given, the response will not be validated. + * If codes are given, an exception will be thrown on an invalid response. + * + * @param string $command + * @param int[] $codes + * @param string[] $failures An array of failures by-reference + * + * @return string + */ + public function executeCommand($command, $codes = array(), &$failures = null) + { + $failures = (array) $failures; + $seq = $this->_buffer->write($command); + $response = $this->_getFullResponse($seq); + if ($evt = $this->_eventDispatcher->createCommandEvent($this, $command, $codes)) { + $this->_eventDispatcher->dispatchEvent($evt, 'commandSent'); + } + $this->_assertResponseCode($response, $codes); + + return $response; + } + + /** Read the opening SMTP greeting */ + protected function _readGreeting() + { + $this->_assertResponseCode($this->_getFullResponse(0), array(220)); + } + + /** Send the HELO welcome */ + protected function _doHeloCommand() + { + $this->executeCommand( + sprintf("HELO %s\r\n", $this->_domain), array(250) + ); + } + + /** Send the MAIL FROM command */ + protected function _doMailFromCommand($address) + { + $this->executeCommand( + sprintf("MAIL FROM:<%s>\r\n", $address), array(250) + ); + } + + /** Send the RCPT TO command */ + protected function _doRcptToCommand($address) + { + $this->executeCommand( + sprintf("RCPT TO:<%s>\r\n", $address), array(250, 251, 252) + ); + } + + /** Send the DATA command */ + protected function _doDataCommand() + { + $this->executeCommand("DATA\r\n", array(354)); + } + + /** Stream the contents of the message over the buffer */ + protected function _streamMessage(Swift_Mime_Message $message) + { + $this->_buffer->setWriteTranslations(array("\r\n." => "\r\n..")); + try { + $message->toByteStream($this->_buffer); + $this->_buffer->flushBuffers(); + } catch (Swift_TransportException $e) { + $this->_throwException($e); + } + $this->_buffer->setWriteTranslations(array()); + $this->executeCommand("\r\n.\r\n", array(250)); + } + + /** Determine the best-use reverse path for this message */ + protected function _getReversePath(Swift_Mime_Message $message) + { + $return = $message->getReturnPath(); + $sender = $message->getSender(); + $from = $message->getFrom(); + $path = null; + if (!empty($return)) { + $path = $return; + } elseif (!empty($sender)) { + // Don't use array_keys + reset($sender); // Reset Pointer to first pos + $path = key($sender); // Get key + } elseif (!empty($from)) { + reset($from); // Reset Pointer to first pos + $path = key($from); // Get key + } + + return $path; + } + + /** Throw a TransportException, first sending it to any listeners */ + protected function _throwException(Swift_TransportException $e) + { + if ($evt = $this->_eventDispatcher->createTransportExceptionEvent($this, $e)) { + $this->_eventDispatcher->dispatchEvent($evt, 'exceptionThrown'); + if (!$evt->bubbleCancelled()) { + throw $e; + } + } else { + throw $e; + } + } + + /** Throws an Exception if a response code is incorrect */ + protected function _assertResponseCode($response, $wanted) + { + list($code) = sscanf($response, '%3d'); + $valid = (empty($wanted) || in_array($code, $wanted)); + + if ($evt = $this->_eventDispatcher->createResponseEvent($this, $response, + $valid)) { + $this->_eventDispatcher->dispatchEvent($evt, 'responseReceived'); + } + + if (!$valid) { + $this->_throwException( + new Swift_TransportException( + 'Expected response code '.implode('/', $wanted).' but got code '. + '"'.$code.'", with message "'.$response.'"', + $code) + ); + } + } + + /** Get an entire multi-line response using its sequence number */ + protected function _getFullResponse($seq) + { + $response = ''; + try { + do { + $line = $this->_buffer->readLine($seq); + $response .= $line; + } while (null !== $line && false !== $line && ' ' != $line[3]); + } catch (Swift_TransportException $e) { + $this->_throwException($e); + } catch (Swift_IoException $e) { + $this->_throwException( + new Swift_TransportException( + $e->getMessage()) + ); + } + + return $response; + } + + /** Send an email to the given recipients from the given reverse path */ + private function _doMailTransaction($message, $reversePath, array $recipients, array &$failedRecipients) + { + $sent = 0; + $this->_doMailFromCommand($reversePath); + foreach ($recipients as $forwardPath) { + try { + $this->_doRcptToCommand($forwardPath); + ++$sent; + } catch (Swift_TransportException $e) { + $failedRecipients[] = $forwardPath; + } + } + + if ($sent != 0) { + $this->_doDataCommand(); + $this->_streamMessage($message); + } else { + $this->reset(); + } + + return $sent; + } + + /** Send a message to the given To: recipients */ + private function _sendTo(Swift_Mime_Message $message, $reversePath, array $to, array &$failedRecipients) + { + if (empty($to)) { + return 0; + } + + return $this->_doMailTransaction($message, $reversePath, array_keys($to), + $failedRecipients); + } + + /** Send a message to all Bcc: recipients */ + private function _sendBcc(Swift_Mime_Message $message, $reversePath, array $bcc, array &$failedRecipients) + { + $sent = 0; + foreach ($bcc as $forwardPath => $name) { + $message->setBcc(array($forwardPath => $name)); + $sent += $this->_doMailTransaction( + $message, $reversePath, array($forwardPath), $failedRecipients + ); + } + + return $sent; + } + + /** Try to determine the hostname of the server this is run on */ + private function _lookupHostname() + { + if (!empty($_SERVER['SERVER_NAME']) && $this->_isFqdn($_SERVER['SERVER_NAME'])) { + $this->_domain = $_SERVER['SERVER_NAME']; + } elseif (!empty($_SERVER['SERVER_ADDR'])) { + // Set the address literal tag (See RFC 5321, section: 4.1.3) + if (false === strpos($_SERVER['SERVER_ADDR'], ':')) { + $prefix = ''; // IPv4 addresses are not tagged. + } else { + $prefix = 'IPv6:'; // Adding prefix in case of IPv6. + } + + $this->_domain = sprintf('[%s%s]', $prefix, $_SERVER['SERVER_ADDR']); + } + } + + /** Determine is the $hostname is a fully-qualified name */ + private function _isFqdn($hostname) + { + // We could do a really thorough check, but there's really no point + if (false !== $dotPos = strpos($hostname, '.')) { + return ($dotPos > 0) && ($dotPos != strlen($hostname) - 1); + } + + return false; + } + + /** + * Destructor. + */ + public function __destruct() + { + try { + $this->stop(); + } catch (Exception $e) { + } + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/CramMd5Authenticator.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/CramMd5Authenticator.php new file mode 100644 index 0000000..53f721d --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/CramMd5Authenticator.php @@ -0,0 +1,81 @@ +executeCommand("AUTH CRAM-MD5\r\n", array(334)); + $challenge = base64_decode(substr($challenge, 4)); + $message = base64_encode( + $username.' '.$this->_getResponse($password, $challenge) + ); + $agent->executeCommand(sprintf("%s\r\n", $message), array(235)); + + return true; + } catch (Swift_TransportException $e) { + $agent->executeCommand("RSET\r\n", array(250)); + + return false; + } + } + + /** + * Generate a CRAM-MD5 response from a server challenge. + * + * @param string $secret + * @param string $challenge + * + * @return string + */ + private function _getResponse($secret, $challenge) + { + if (strlen($secret) > 64) { + $secret = pack('H32', md5($secret)); + } + + if (strlen($secret) < 64) { + $secret = str_pad($secret, 64, chr(0)); + } + + $k_ipad = substr($secret, 0, 64) ^ str_repeat(chr(0x36), 64); + $k_opad = substr($secret, 0, 64) ^ str_repeat(chr(0x5C), 64); + + $inner = pack('H32', md5($k_ipad.$challenge)); + $digest = md5($k_opad.$inner); + + return $digest; + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/LoginAuthenticator.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/LoginAuthenticator.php new file mode 100644 index 0000000..6ab6e33 --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/LoginAuthenticator.php @@ -0,0 +1,51 @@ +executeCommand("AUTH LOGIN\r\n", array(334)); + $agent->executeCommand(sprintf("%s\r\n", base64_encode($username)), array(334)); + $agent->executeCommand(sprintf("%s\r\n", base64_encode($password)), array(235)); + + return true; + } catch (Swift_TransportException $e) { + $agent->executeCommand("RSET\r\n", array(250)); + + return false; + } + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/NTLMAuthenticator.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/NTLMAuthenticator.php new file mode 100644 index 0000000..8392658 --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/NTLMAuthenticator.php @@ -0,0 +1,725 @@ + + */ +class Swift_Transport_Esmtp_Auth_NTLMAuthenticator implements Swift_Transport_Esmtp_Authenticator +{ + const NTLMSIG = "NTLMSSP\x00"; + const DESCONST = 'KGS!@#$%'; + + /** + * Get the name of the AUTH mechanism this Authenticator handles. + * + * @return string + */ + public function getAuthKeyword() + { + return 'NTLM'; + } + + /** + * Try to authenticate the user with $username and $password. + * + * @param Swift_Transport_SmtpAgent $agent + * @param string $username + * @param string $password + * + * @return bool + */ + public function authenticate(Swift_Transport_SmtpAgent $agent, $username, $password) + { + if (!function_exists('openssl_random_pseudo_bytes') || !function_exists('openssl_encrypt')) { + throw new LogicException('The OpenSSL extension must be enabled to use the NTLM authenticator.'); + } + + if (!function_exists('bcmul')) { + throw new LogicException('The BCMath functions must be enabled to use the NTLM authenticator.'); + } + + try { + // execute AUTH command and filter out the code at the beginning + // AUTH NTLM xxxx + $response = base64_decode(substr(trim($this->sendMessage1($agent)), 4)); + + // extra parameters for our unit cases + $timestamp = func_num_args() > 3 ? func_get_arg(3) : $this->getCorrectTimestamp(bcmul(microtime(true), '1000')); + $client = func_num_args() > 4 ? func_get_arg(4) : $this->getRandomBytes(8); + + // Message 3 response + $this->sendMessage3($response, $username, $password, $timestamp, $client, $agent); + + return true; + } catch (Swift_TransportException $e) { + $agent->executeCommand("RSET\r\n", array(250)); + + return false; + } + } + + protected function si2bin($si, $bits = 32) + { + $bin = null; + if ($si >= -pow(2, $bits - 1) && ($si <= pow(2, $bits - 1))) { + // positive or zero + if ($si >= 0) { + $bin = base_convert($si, 10, 2); + // pad to $bits bit + $bin_length = strlen($bin); + if ($bin_length < $bits) { + $bin = str_repeat('0', $bits - $bin_length).$bin; + } + } else { + // negative + $si = -$si - pow(2, $bits); + $bin = base_convert($si, 10, 2); + $bin_length = strlen($bin); + if ($bin_length > $bits) { + $bin = str_repeat('1', $bits - $bin_length).$bin; + } + } + } + + return $bin; + } + + /** + * Send our auth message and returns the response. + * + * @param Swift_Transport_SmtpAgent $agent + * + * @return string SMTP Response + */ + protected function sendMessage1(Swift_Transport_SmtpAgent $agent) + { + $message = $this->createMessage1(); + + return $agent->executeCommand(sprintf("AUTH %s %s\r\n", $this->getAuthKeyword(), base64_encode($message)), array(334)); + } + + /** + * Fetch all details of our response (message 2). + * + * @param string $response + * + * @return array our response parsed + */ + protected function parseMessage2($response) + { + $responseHex = bin2hex($response); + $length = floor(hexdec(substr($responseHex, 28, 4)) / 256) * 2; + $offset = floor(hexdec(substr($responseHex, 32, 4)) / 256) * 2; + $challenge = $this->hex2bin(substr($responseHex, 48, 16)); + $context = $this->hex2bin(substr($responseHex, 64, 16)); + $targetInfoH = $this->hex2bin(substr($responseHex, 80, 16)); + $targetName = $this->hex2bin(substr($responseHex, $offset, $length)); + $offset = floor(hexdec(substr($responseHex, 88, 4)) / 256) * 2; + $targetInfoBlock = substr($responseHex, $offset); + list($domainName, $serverName, $DNSDomainName, $DNSServerName, $terminatorByte) = $this->readSubBlock($targetInfoBlock); + + return array( + $challenge, + $context, + $targetInfoH, + $targetName, + $domainName, + $serverName, + $DNSDomainName, + $DNSServerName, + $this->hex2bin($targetInfoBlock), + $terminatorByte, + ); + } + + /** + * Read the blob information in from message2. + * + * @param $block + * + * @return array + */ + protected function readSubBlock($block) + { + // remove terminatorByte cause it's always the same + $block = substr($block, 0, -8); + + $length = strlen($block); + $offset = 0; + $data = array(); + while ($offset < $length) { + $blockLength = hexdec(substr(substr($block, $offset, 8), -4)) / 256; + $offset += 8; + $data[] = $this->hex2bin(substr($block, $offset, $blockLength * 2)); + $offset += $blockLength * 2; + } + + if (count($data) == 3) { + $data[] = $data[2]; + $data[2] = ''; + } + + $data[] = $this->createByte('00'); + + return $data; + } + + /** + * Send our final message with all our data. + * + * @param string $response Message 1 response (message 2) + * @param string $username + * @param string $password + * @param string $timestamp + * @param string $client + * @param Swift_Transport_SmtpAgent $agent + * @param bool $v2 Use version2 of the protocol + * + * @return string + */ + protected function sendMessage3($response, $username, $password, $timestamp, $client, Swift_Transport_SmtpAgent $agent, $v2 = true) + { + list($domain, $username) = $this->getDomainAndUsername($username); + //$challenge, $context, $targetInfoH, $targetName, $domainName, $workstation, $DNSDomainName, $DNSServerName, $blob, $ter + list($challenge, , , , , $workstation, , , $blob) = $this->parseMessage2($response); + + if (!$v2) { + // LMv1 + $lmResponse = $this->createLMPassword($password, $challenge); + // NTLMv1 + $ntlmResponse = $this->createNTLMPassword($password, $challenge); + } else { + // LMv2 + $lmResponse = $this->createLMv2Password($password, $username, $domain, $challenge, $client); + // NTLMv2 + $ntlmResponse = $this->createNTLMv2Hash($password, $username, $domain, $challenge, $blob, $timestamp, $client); + } + + $message = $this->createMessage3($domain, $username, $workstation, $lmResponse, $ntlmResponse); + + return $agent->executeCommand(sprintf("%s\r\n", base64_encode($message)), array(235)); + } + + /** + * Create our message 1. + * + * @return string + */ + protected function createMessage1() + { + return self::NTLMSIG + .$this->createByte('01') // Message 1 +.$this->createByte('0702'); // Flags + } + + /** + * Create our message 3. + * + * @param string $domain + * @param string $username + * @param string $workstation + * @param string $lmResponse + * @param string $ntlmResponse + * + * @return string + */ + protected function createMessage3($domain, $username, $workstation, $lmResponse, $ntlmResponse) + { + // Create security buffers + $domainSec = $this->createSecurityBuffer($domain, 64); + $domainInfo = $this->readSecurityBuffer(bin2hex($domainSec)); + $userSec = $this->createSecurityBuffer($username, ($domainInfo[0] + $domainInfo[1]) / 2); + $userInfo = $this->readSecurityBuffer(bin2hex($userSec)); + $workSec = $this->createSecurityBuffer($workstation, ($userInfo[0] + $userInfo[1]) / 2); + $workInfo = $this->readSecurityBuffer(bin2hex($workSec)); + $lmSec = $this->createSecurityBuffer($lmResponse, ($workInfo[0] + $workInfo[1]) / 2, true); + $lmInfo = $this->readSecurityBuffer(bin2hex($lmSec)); + $ntlmSec = $this->createSecurityBuffer($ntlmResponse, ($lmInfo[0] + $lmInfo[1]) / 2, true); + + return self::NTLMSIG + .$this->createByte('03') // TYPE 3 message +.$lmSec // LM response header +.$ntlmSec // NTLM response header +.$domainSec // Domain header +.$userSec // User header +.$workSec // Workstation header +.$this->createByte('000000009a', 8) // session key header (empty) +.$this->createByte('01020000') // FLAGS +.$this->convertTo16bit($domain) // domain name +.$this->convertTo16bit($username) // username +.$this->convertTo16bit($workstation) // workstation +.$lmResponse + .$ntlmResponse; + } + + /** + * @param string $timestamp Epoch timestamp in microseconds + * @param string $client Random bytes + * @param string $targetInfo + * + * @return string + */ + protected function createBlob($timestamp, $client, $targetInfo) + { + return $this->createByte('0101') + .$this->createByte('00') + .$timestamp + .$client + .$this->createByte('00') + .$targetInfo + .$this->createByte('00'); + } + + /** + * Get domain and username from our username. + * + * @example DOMAIN\username + * + * @param string $name + * + * @return array + */ + protected function getDomainAndUsername($name) + { + if (strpos($name, '\\') !== false) { + return explode('\\', $name); + } + + if (false !== strpos($name, '@')) { + list($user, $domain) = explode('@', $name); + + return array($domain, $user); + } + + // no domain passed + return array('', $name); + } + + /** + * Create LMv1 response. + * + * @param string $password + * @param string $challenge + * + * @return string + */ + protected function createLMPassword($password, $challenge) + { + // FIRST PART + $password = $this->createByte(strtoupper($password), 14, false); + list($key1, $key2) = str_split($password, 7); + + $desKey1 = $this->createDesKey($key1); + $desKey2 = $this->createDesKey($key2); + + $constantDecrypt = $this->createByte($this->desEncrypt(self::DESCONST, $desKey1).$this->desEncrypt(self::DESCONST, $desKey2), 21, false); + + // SECOND PART + list($key1, $key2, $key3) = str_split($constantDecrypt, 7); + + $desKey1 = $this->createDesKey($key1); + $desKey2 = $this->createDesKey($key2); + $desKey3 = $this->createDesKey($key3); + + return $this->desEncrypt($challenge, $desKey1).$this->desEncrypt($challenge, $desKey2).$this->desEncrypt($challenge, $desKey3); + } + + /** + * Create NTLMv1 response. + * + * @param string $password + * @param string $challenge + * + * @return string + */ + protected function createNTLMPassword($password, $challenge) + { + // FIRST PART + $ntlmHash = $this->createByte($this->md4Encrypt($password), 21, false); + list($key1, $key2, $key3) = str_split($ntlmHash, 7); + + $desKey1 = $this->createDesKey($key1); + $desKey2 = $this->createDesKey($key2); + $desKey3 = $this->createDesKey($key3); + + return $this->desEncrypt($challenge, $desKey1).$this->desEncrypt($challenge, $desKey2).$this->desEncrypt($challenge, $desKey3); + } + + /** + * Convert a normal timestamp to a tenth of a microtime epoch time. + * + * @param string $time + * + * @return string + */ + protected function getCorrectTimestamp($time) + { + // Get our timestamp (tricky!) + $time = number_format($time, 0, '.', ''); // save microtime to string + $time = bcadd($time, '11644473600000', 0); // add epoch time + $time = bcmul($time, 10000, 0); // tenths of a microsecond. + + $binary = $this->si2bin($time, 64); // create 64 bit binary string + $timestamp = ''; + for ($i = 0; $i < 8; ++$i) { + $timestamp .= chr(bindec(substr($binary, -(($i + 1) * 8), 8))); + } + + return $timestamp; + } + + /** + * Create LMv2 response. + * + * @param string $password + * @param string $username + * @param string $domain + * @param string $challenge NTLM Challenge + * @param string $client Random string + * + * @return string + */ + protected function createLMv2Password($password, $username, $domain, $challenge, $client) + { + $lmPass = '00'; // by default 00 + // if $password > 15 than we can't use this method + if (strlen($password) <= 15) { + $ntlmHash = $this->md4Encrypt($password); + $ntml2Hash = $this->md5Encrypt($ntlmHash, $this->convertTo16bit(strtoupper($username).$domain)); + + $lmPass = bin2hex($this->md5Encrypt($ntml2Hash, $challenge.$client).$client); + } + + return $this->createByte($lmPass, 24); + } + + /** + * Create NTLMv2 response. + * + * @param string $password + * @param string $username + * @param string $domain + * @param string $challenge Hex values + * @param string $targetInfo Hex values + * @param string $timestamp + * @param string $client Random bytes + * + * @return string + * + * @see http://davenport.sourceforge.net/ntlm.html#theNtlmResponse + */ + protected function createNTLMv2Hash($password, $username, $domain, $challenge, $targetInfo, $timestamp, $client) + { + $ntlmHash = $this->md4Encrypt($password); + $ntml2Hash = $this->md5Encrypt($ntlmHash, $this->convertTo16bit(strtoupper($username).$domain)); + + // create blob + $blob = $this->createBlob($timestamp, $client, $targetInfo); + + $ntlmv2Response = $this->md5Encrypt($ntml2Hash, $challenge.$blob); + + return $ntlmv2Response.$blob; + } + + protected function createDesKey($key) + { + $material = array(bin2hex($key[0])); + $len = strlen($key); + for ($i = 1; $i < $len; ++$i) { + list($high, $low) = str_split(bin2hex($key[$i])); + $v = $this->castToByte(ord($key[$i - 1]) << (7 + 1 - $i) | $this->uRShift(hexdec(dechex(hexdec($high) & 0xf).dechex(hexdec($low) & 0xf)), $i)); + $material[] = str_pad(substr(dechex($v), -2), 2, '0', STR_PAD_LEFT); // cast to byte + } + $material[] = str_pad(substr(dechex($this->castToByte(ord($key[6]) << 1)), -2), 2, '0'); + + // odd parity + foreach ($material as $k => $v) { + $b = $this->castToByte(hexdec($v)); + $needsParity = (($this->uRShift($b, 7) ^ $this->uRShift($b, 6) ^ $this->uRShift($b, 5) + ^ $this->uRShift($b, 4) ^ $this->uRShift($b, 3) ^ $this->uRShift($b, 2) + ^ $this->uRShift($b, 1)) & 0x01) == 0; + + list($high, $low) = str_split($v); + if ($needsParity) { + $material[$k] = dechex(hexdec($high) | 0x0).dechex(hexdec($low) | 0x1); + } else { + $material[$k] = dechex(hexdec($high) & 0xf).dechex(hexdec($low) & 0xe); + } + } + + return $this->hex2bin(implode('', $material)); + } + + /** HELPER FUNCTIONS */ + + /** + * Create our security buffer depending on length and offset. + * + * @param string $value Value we want to put in + * @param int $offset start of value + * @param bool $is16 Do we 16bit string or not? + * + * @return string + */ + protected function createSecurityBuffer($value, $offset, $is16 = false) + { + $length = strlen(bin2hex($value)); + $length = $is16 ? $length / 2 : $length; + $length = $this->createByte(str_pad(dechex($length), 2, '0', STR_PAD_LEFT), 2); + + return $length.$length.$this->createByte(dechex($offset), 4); + } + + /** + * Read our security buffer to fetch length and offset of our value. + * + * @param string $value Securitybuffer in hex + * + * @return array array with length and offset + */ + protected function readSecurityBuffer($value) + { + $length = floor(hexdec(substr($value, 0, 4)) / 256) * 2; + $offset = floor(hexdec(substr($value, 8, 4)) / 256) * 2; + + return array($length, $offset); + } + + /** + * Cast to byte java equivalent to (byte). + * + * @param int $v + * + * @return int + */ + protected function castToByte($v) + { + return (($v + 128) % 256) - 128; + } + + /** + * Java unsigned right bitwise + * $a >>> $b. + * + * @param int $a + * @param int $b + * + * @return int + */ + protected function uRShift($a, $b) + { + if ($b == 0) { + return $a; + } + + return ($a >> $b) & ~(1 << (8 * PHP_INT_SIZE - 1) >> ($b - 1)); + } + + /** + * Right padding with 0 to certain length. + * + * @param string $input + * @param int $bytes Length of bytes + * @param bool $isHex Did we provided hex value + * + * @return string + */ + protected function createByte($input, $bytes = 4, $isHex = true) + { + if ($isHex) { + $byte = $this->hex2bin(str_pad($input, $bytes * 2, '00')); + } else { + $byte = str_pad($input, $bytes, "\x00"); + } + + return $byte; + } + + /** + * Create random bytes. + * + * @param $length + * + * @return string + */ + protected function getRandomBytes($length) + { + $bytes = openssl_random_pseudo_bytes($length, $strong); + + if (false !== $bytes && true === $strong) { + return $bytes; + } + + throw new RuntimeException('OpenSSL did not produce a secure random number.'); + } + + /** ENCRYPTION ALGORITHMS */ + + /** + * DES Encryption. + * + * @param string $value An 8-byte string + * @param string $key + * + * @return string + */ + protected function desEncrypt($value, $key) + { + // 1 == OPENSSL_RAW_DATA - but constant is only available as of PHP 5.4. + return substr(openssl_encrypt($value, 'DES-ECB', $key, 1), 0, 8); + } + + /** + * MD5 Encryption. + * + * @param string $key Encryption key + * @param string $msg Message to encrypt + * + * @return string + */ + protected function md5Encrypt($key, $msg) + { + $blocksize = 64; + if (strlen($key) > $blocksize) { + $key = pack('H*', md5($key)); + } + + $key = str_pad($key, $blocksize, "\0"); + $ipadk = $key ^ str_repeat("\x36", $blocksize); + $opadk = $key ^ str_repeat("\x5c", $blocksize); + + return pack('H*', md5($opadk.pack('H*', md5($ipadk.$msg)))); + } + + /** + * MD4 Encryption. + * + * @param string $input + * + * @return string + * + * @see http://php.net/manual/en/ref.hash.php + */ + protected function md4Encrypt($input) + { + $input = $this->convertTo16bit($input); + + return function_exists('hash') ? $this->hex2bin(hash('md4', $input)) : mhash(MHASH_MD4, $input); + } + + /** + * Convert UTF-8 to UTF-16. + * + * @param string $input + * + * @return string + */ + protected function convertTo16bit($input) + { + return iconv('UTF-8', 'UTF-16LE', $input); + } + + /** + * Hex2bin replacement for < PHP 5.4. + * + * @param string $hex + * + * @return string Binary + */ + protected function hex2bin($hex) + { + if (function_exists('hex2bin')) { + return hex2bin($hex); + } else { + return pack('H*', $hex); + } + } + + /** + * @param string $message + */ + protected function debug($message) + { + $message = bin2hex($message); + $messageId = substr($message, 16, 8); + echo substr($message, 0, 16)." NTLMSSP Signature
                                                                      \n"; + echo $messageId." Type Indicator
                                                                      \n"; + + if ($messageId == '02000000') { + $map = array( + 'Challenge', + 'Context', + 'Target Information Security Buffer', + 'Target Name Data', + 'NetBIOS Domain Name', + 'NetBIOS Server Name', + 'DNS Domain Name', + 'DNS Server Name', + 'BLOB', + 'Target Information Terminator', + ); + + $data = $this->parseMessage2($this->hex2bin($message)); + + foreach ($map as $key => $value) { + echo bin2hex($data[$key]).' - '.$data[$key].' ||| '.$value."
                                                                      \n"; + } + } elseif ($messageId == '03000000') { + $i = 0; + $data[$i++] = substr($message, 24, 16); + list($lmLength, $lmOffset) = $this->readSecurityBuffer($data[$i - 1]); + + $data[$i++] = substr($message, 40, 16); + list($ntmlLength, $ntmlOffset) = $this->readSecurityBuffer($data[$i - 1]); + + $data[$i++] = substr($message, 56, 16); + list($targetLength, $targetOffset) = $this->readSecurityBuffer($data[$i - 1]); + + $data[$i++] = substr($message, 72, 16); + list($userLength, $userOffset) = $this->readSecurityBuffer($data[$i - 1]); + + $data[$i++] = substr($message, 88, 16); + list($workLength, $workOffset) = $this->readSecurityBuffer($data[$i - 1]); + + $data[$i++] = substr($message, 104, 16); + $data[$i++] = substr($message, 120, 8); + $data[$i++] = substr($message, $targetOffset, $targetLength); + $data[$i++] = substr($message, $userOffset, $userLength); + $data[$i++] = substr($message, $workOffset, $workLength); + $data[$i++] = substr($message, $lmOffset, $lmLength); + $data[$i] = substr($message, $ntmlOffset, $ntmlLength); + + $map = array( + 'LM Response Security Buffer', + 'NTLM Response Security Buffer', + 'Target Name Security Buffer', + 'User Name Security Buffer', + 'Workstation Name Security Buffer', + 'Session Key Security Buffer', + 'Flags', + 'Target Name Data', + 'User Name Data', + 'Workstation Name Data', + 'LM Response Data', + 'NTLM Response Data', + ); + + foreach ($map as $key => $value) { + echo $data[$key].' - '.$this->hex2bin($data[$key]).' ||| '.$value."
                                                                      \n"; + } + } + + echo '

                                                                      '; + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/PlainAuthenticator.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/PlainAuthenticator.php new file mode 100644 index 0000000..43219f9 --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/PlainAuthenticator.php @@ -0,0 +1,50 @@ +executeCommand(sprintf("AUTH PLAIN %s\r\n", $message), array(235)); + + return true; + } catch (Swift_TransportException $e) { + $agent->executeCommand("RSET\r\n", array(250)); + + return false; + } + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/XOAuth2Authenticator.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/XOAuth2Authenticator.php new file mode 100644 index 0000000..ca35e7b --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/XOAuth2Authenticator.php @@ -0,0 +1,70 @@ + + * $transport = Swift_SmtpTransport::newInstance('smtp.gmail.com', 587, 'tls') + * ->setAuthMode('XOAUTH2') + * ->setUsername('YOUR_EMAIL_ADDRESS') + * ->setPassword('YOUR_ACCESS_TOKEN'); + * + * + * @author xu.li + * + * @see https://developers.google.com/google-apps/gmail/xoauth2_protocol + */ +class Swift_Transport_Esmtp_Auth_XOAuth2Authenticator implements Swift_Transport_Esmtp_Authenticator +{ + /** + * Get the name of the AUTH mechanism this Authenticator handles. + * + * @return string + */ + public function getAuthKeyword() + { + return 'XOAUTH2'; + } + + /** + * Try to authenticate the user with $email and $token. + * + * @param Swift_Transport_SmtpAgent $agent + * @param string $email + * @param string $token + * + * @return bool + */ + public function authenticate(Swift_Transport_SmtpAgent $agent, $email, $token) + { + try { + $param = $this->constructXOAuth2Params($email, $token); + $agent->executeCommand('AUTH XOAUTH2 '.$param."\r\n", array(235)); + + return true; + } catch (Swift_TransportException $e) { + $agent->executeCommand("RSET\r\n", array(250)); + + return false; + } + } + + /** + * Construct the auth parameter. + * + * @see https://developers.google.com/google-apps/gmail/xoauth2_protocol#the_sasl_xoauth2_mechanism + */ + protected function constructXOAuth2Params($email, $token) + { + return base64_encode("user=$email\1auth=Bearer $token\1\1"); + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/AuthHandler.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/AuthHandler.php new file mode 100644 index 0000000..cb36133 --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/AuthHandler.php @@ -0,0 +1,263 @@ +setAuthenticators($authenticators); + } + + /** + * Set the Authenticators which can process a login request. + * + * @param Swift_Transport_Esmtp_Authenticator[] $authenticators + */ + public function setAuthenticators(array $authenticators) + { + $this->_authenticators = $authenticators; + } + + /** + * Get the Authenticators which can process a login request. + * + * @return Swift_Transport_Esmtp_Authenticator[] + */ + public function getAuthenticators() + { + return $this->_authenticators; + } + + /** + * Set the username to authenticate with. + * + * @param string $username + */ + public function setUsername($username) + { + $this->_username = $username; + } + + /** + * Get the username to authenticate with. + * + * @return string + */ + public function getUsername() + { + return $this->_username; + } + + /** + * Set the password to authenticate with. + * + * @param string $password + */ + public function setPassword($password) + { + $this->_password = $password; + } + + /** + * Get the password to authenticate with. + * + * @return string + */ + public function getPassword() + { + return $this->_password; + } + + /** + * Set the auth mode to use to authenticate. + * + * @param string $mode + */ + public function setAuthMode($mode) + { + $this->_auth_mode = $mode; + } + + /** + * Get the auth mode to use to authenticate. + * + * @return string + */ + public function getAuthMode() + { + return $this->_auth_mode; + } + + /** + * Get the name of the ESMTP extension this handles. + * + * @return bool + */ + public function getHandledKeyword() + { + return 'AUTH'; + } + + /** + * Set the parameters which the EHLO greeting indicated. + * + * @param string[] $parameters + */ + public function setKeywordParams(array $parameters) + { + $this->_esmtpParams = $parameters; + } + + /** + * Runs immediately after a EHLO has been issued. + * + * @param Swift_Transport_SmtpAgent $agent to read/write + */ + public function afterEhlo(Swift_Transport_SmtpAgent $agent) + { + if ($this->_username) { + $count = 0; + foreach ($this->_getAuthenticatorsForAgent() as $authenticator) { + if (in_array(strtolower($authenticator->getAuthKeyword()), + array_map('strtolower', $this->_esmtpParams))) { + ++$count; + if ($authenticator->authenticate($agent, $this->_username, $this->_password)) { + return; + } + } + } + throw new Swift_TransportException( + 'Failed to authenticate on SMTP server with username "'. + $this->_username.'" using '.$count.' possible authenticators' + ); + } + } + + /** + * Not used. + */ + public function getMailParams() + { + return array(); + } + + /** + * Not used. + */ + public function getRcptParams() + { + return array(); + } + + /** + * Not used. + */ + public function onCommand(Swift_Transport_SmtpAgent $agent, $command, $codes = array(), &$failedRecipients = null, &$stop = false) + { + } + + /** + * Returns +1, -1 or 0 according to the rules for usort(). + * + * This method is called to ensure extensions can be execute in an appropriate order. + * + * @param string $esmtpKeyword to compare with + * + * @return int + */ + public function getPriorityOver($esmtpKeyword) + { + return 0; + } + + /** + * Returns an array of method names which are exposed to the Esmtp class. + * + * @return string[] + */ + public function exposeMixinMethods() + { + return array('setUsername', 'getUsername', 'setPassword', 'getPassword', 'setAuthMode', 'getAuthMode'); + } + + /** + * Not used. + */ + public function resetState() + { + } + + /** + * Returns the authenticator list for the given agent. + * + * @param Swift_Transport_SmtpAgent $agent + * + * @return array + */ + protected function _getAuthenticatorsForAgent() + { + if (!$mode = strtolower($this->_auth_mode)) { + return $this->_authenticators; + } + + foreach ($this->_authenticators as $authenticator) { + if (strtolower($authenticator->getAuthKeyword()) == $mode) { + return array($authenticator); + } + } + + throw new Swift_TransportException('Auth mode '.$mode.' is invalid'); + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Authenticator.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Authenticator.php new file mode 100644 index 0000000..12a9abf --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Authenticator.php @@ -0,0 +1,35 @@ +. + * + * @return string[] + */ + public function getMailParams(); + + /** + * Get params which are appended to RCPT TO:<>. + * + * @return string[] + */ + public function getRcptParams(); + + /** + * Runs when a command is due to be sent. + * + * @param Swift_Transport_SmtpAgent $agent to read/write + * @param string $command to send + * @param int[] $codes expected in response + * @param string[] $failedRecipients to collect failures + * @param bool $stop to be set true by-reference if the command is now sent + */ + public function onCommand(Swift_Transport_SmtpAgent $agent, $command, $codes = array(), &$failedRecipients = null, &$stop = false); + + /** + * Returns +1, -1 or 0 according to the rules for usort(). + * + * This method is called to ensure extensions can be execute in an appropriate order. + * + * @param string $esmtpKeyword to compare with + * + * @return int + */ + public function getPriorityOver($esmtpKeyword); + + /** + * Returns an array of method names which are exposed to the Esmtp class. + * + * @return string[] + */ + public function exposeMixinMethods(); + + /** + * Tells this handler to clear any buffers and reset its state. + */ + public function resetState(); +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/EsmtpTransport.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/EsmtpTransport.php new file mode 100644 index 0000000..156e2cf --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/EsmtpTransport.php @@ -0,0 +1,411 @@ + 'tcp', + 'host' => 'localhost', + 'port' => 25, + 'timeout' => 30, + 'blocking' => 1, + 'tls' => false, + 'type' => Swift_Transport_IoBuffer::TYPE_SOCKET, + 'stream_context_options' => array(), + ); + + /** + * Creates a new EsmtpTransport using the given I/O buffer. + * + * @param Swift_Transport_IoBuffer $buf + * @param Swift_Transport_EsmtpHandler[] $extensionHandlers + * @param Swift_Events_EventDispatcher $dispatcher + */ + public function __construct(Swift_Transport_IoBuffer $buf, array $extensionHandlers, Swift_Events_EventDispatcher $dispatcher) + { + parent::__construct($buf, $dispatcher); + $this->setExtensionHandlers($extensionHandlers); + } + + /** + * Set the host to connect to. + * + * @param string $host + * + * @return $this + */ + public function setHost($host) + { + $this->_params['host'] = $host; + + return $this; + } + + /** + * Get the host to connect to. + * + * @return string + */ + public function getHost() + { + return $this->_params['host']; + } + + /** + * Set the port to connect to. + * + * @param int $port + * + * @return $this + */ + public function setPort($port) + { + $this->_params['port'] = (int) $port; + + return $this; + } + + /** + * Get the port to connect to. + * + * @return int + */ + public function getPort() + { + return $this->_params['port']; + } + + /** + * Set the connection timeout. + * + * @param int $timeout seconds + * + * @return $this + */ + public function setTimeout($timeout) + { + $this->_params['timeout'] = (int) $timeout; + $this->_buffer->setParam('timeout', (int) $timeout); + + return $this; + } + + /** + * Get the connection timeout. + * + * @return int + */ + public function getTimeout() + { + return $this->_params['timeout']; + } + + /** + * Set the encryption type (tls or ssl). + * + * @param string $encryption + * + * @return $this + */ + public function setEncryption($encryption) + { + $encryption = strtolower($encryption); + if ('tls' == $encryption) { + $this->_params['protocol'] = 'tcp'; + $this->_params['tls'] = true; + } else { + $this->_params['protocol'] = $encryption; + $this->_params['tls'] = false; + } + + return $this; + } + + /** + * Get the encryption type. + * + * @return string + */ + public function getEncryption() + { + return $this->_params['tls'] ? 'tls' : $this->_params['protocol']; + } + + /** + * Sets the stream context options. + * + * @param array $options + * + * @return $this + */ + public function setStreamOptions($options) + { + $this->_params['stream_context_options'] = $options; + + return $this; + } + + /** + * Returns the stream context options. + * + * @return array + */ + public function getStreamOptions() + { + return $this->_params['stream_context_options']; + } + + /** + * Sets the source IP. + * + * @param string $source + * + * @return $this + */ + public function setSourceIp($source) + { + $this->_params['sourceIp'] = $source; + + return $this; + } + + /** + * Returns the IP used to connect to the destination. + * + * @return string + */ + public function getSourceIp() + { + return isset($this->_params['sourceIp']) ? $this->_params['sourceIp'] : null; + } + + /** + * Set ESMTP extension handlers. + * + * @param Swift_Transport_EsmtpHandler[] $handlers + * + * @return $this + */ + public function setExtensionHandlers(array $handlers) + { + $assoc = array(); + foreach ($handlers as $handler) { + $assoc[$handler->getHandledKeyword()] = $handler; + } + + @uasort($assoc, array($this, '_sortHandlers')); + $this->_handlers = $assoc; + $this->_setHandlerParams(); + + return $this; + } + + /** + * Get ESMTP extension handlers. + * + * @return Swift_Transport_EsmtpHandler[] + */ + public function getExtensionHandlers() + { + return array_values($this->_handlers); + } + + /** + * Run a command against the buffer, expecting the given response codes. + * + * If no response codes are given, the response will not be validated. + * If codes are given, an exception will be thrown on an invalid response. + * + * @param string $command + * @param int[] $codes + * @param string[] $failures An array of failures by-reference + * + * @return string + */ + public function executeCommand($command, $codes = array(), &$failures = null) + { + $failures = (array) $failures; + $stopSignal = false; + $response = null; + foreach ($this->_getActiveHandlers() as $handler) { + $response = $handler->onCommand( + $this, $command, $codes, $failures, $stopSignal + ); + if ($stopSignal) { + return $response; + } + } + + return parent::executeCommand($command, $codes, $failures); + } + + /** Mixin handling method for ESMTP handlers */ + public function __call($method, $args) + { + foreach ($this->_handlers as $handler) { + if (in_array(strtolower($method), + array_map('strtolower', (array) $handler->exposeMixinMethods()) + )) { + $return = call_user_func_array(array($handler, $method), $args); + // Allow fluid method calls + if (null === $return && substr($method, 0, 3) == 'set') { + return $this; + } else { + return $return; + } + } + } + trigger_error('Call to undefined method '.$method, E_USER_ERROR); + } + + /** Get the params to initialize the buffer */ + protected function _getBufferParams() + { + return $this->_params; + } + + /** Overridden to perform EHLO instead */ + protected function _doHeloCommand() + { + try { + $response = $this->executeCommand( + sprintf("EHLO %s\r\n", $this->_domain), array(250) + ); + } catch (Swift_TransportException $e) { + return parent::_doHeloCommand(); + } + + if ($this->_params['tls']) { + try { + $this->executeCommand("STARTTLS\r\n", array(220)); + + if (!$this->_buffer->startTLS()) { + throw new Swift_TransportException('Unable to connect with TLS encryption'); + } + + try { + $response = $this->executeCommand( + sprintf("EHLO %s\r\n", $this->_domain), array(250) + ); + } catch (Swift_TransportException $e) { + return parent::_doHeloCommand(); + } + } catch (Swift_TransportException $e) { + $this->_throwException($e); + } + } + + $this->_capabilities = $this->_getCapabilities($response); + $this->_setHandlerParams(); + foreach ($this->_getActiveHandlers() as $handler) { + $handler->afterEhlo($this); + } + } + + /** Overridden to add Extension support */ + protected function _doMailFromCommand($address) + { + $handlers = $this->_getActiveHandlers(); + $params = array(); + foreach ($handlers as $handler) { + $params = array_merge($params, (array) $handler->getMailParams()); + } + $paramStr = !empty($params) ? ' '.implode(' ', $params) : ''; + $this->executeCommand( + sprintf("MAIL FROM:<%s>%s\r\n", $address, $paramStr), array(250) + ); + } + + /** Overridden to add Extension support */ + protected function _doRcptToCommand($address) + { + $handlers = $this->_getActiveHandlers(); + $params = array(); + foreach ($handlers as $handler) { + $params = array_merge($params, (array) $handler->getRcptParams()); + } + $paramStr = !empty($params) ? ' '.implode(' ', $params) : ''; + $this->executeCommand( + sprintf("RCPT TO:<%s>%s\r\n", $address, $paramStr), array(250, 251, 252) + ); + } + + /** Determine ESMTP capabilities by function group */ + private function _getCapabilities($ehloResponse) + { + $capabilities = array(); + $ehloResponse = trim($ehloResponse); + $lines = explode("\r\n", $ehloResponse); + array_shift($lines); + foreach ($lines as $line) { + if (preg_match('/^[0-9]{3}[ -]([A-Z0-9-]+)((?:[ =].*)?)$/Di', $line, $matches)) { + $keyword = strtoupper($matches[1]); + $paramStr = strtoupper(ltrim($matches[2], ' =')); + $params = !empty($paramStr) ? explode(' ', $paramStr) : array(); + $capabilities[$keyword] = $params; + } + } + + return $capabilities; + } + + /** Set parameters which are used by each extension handler */ + private function _setHandlerParams() + { + foreach ($this->_handlers as $keyword => $handler) { + if (array_key_exists($keyword, $this->_capabilities)) { + $handler->setKeywordParams($this->_capabilities[$keyword]); + } + } + } + + /** Get ESMTP handlers which are currently ok to use */ + private function _getActiveHandlers() + { + $handlers = array(); + foreach ($this->_handlers as $keyword => $handler) { + if (array_key_exists($keyword, $this->_capabilities)) { + $handlers[] = $handler; + } + } + + return $handlers; + } + + /** Custom sort for extension handler ordering */ + private function _sortHandlers($a, $b) + { + return $a->getPriorityOver($b->getHandledKeyword()); + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/FailoverTransport.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/FailoverTransport.php new file mode 100644 index 0000000..311a0f2 --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/FailoverTransport.php @@ -0,0 +1,88 @@ +_transports); + $sent = 0; + $this->_lastUsedTransport = null; + + for ($i = 0; $i < $maxTransports + && $transport = $this->_getNextTransport(); ++$i) { + try { + if (!$transport->isStarted()) { + $transport->start(); + } + + if ($sent = $transport->send($message, $failedRecipients)) { + $this->_lastUsedTransport = $transport; + + return $sent; + } + } catch (Swift_TransportException $e) { + $this->_killCurrentTransport(); + } + } + + if (count($this->_transports) == 0) { + throw new Swift_TransportException( + 'All Transports in FailoverTransport failed, or no Transports available' + ); + } + + return $sent; + } + + protected function _getNextTransport() + { + if (!isset($this->_currentTransport)) { + $this->_currentTransport = parent::_getNextTransport(); + } + + return $this->_currentTransport; + } + + protected function _killCurrentTransport() + { + $this->_currentTransport = null; + parent::_killCurrentTransport(); + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/IoBuffer.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/IoBuffer.php new file mode 100644 index 0000000..af97adf --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/IoBuffer.php @@ -0,0 +1,67 @@ +_transports = $transports; + $this->_deadTransports = array(); + } + + /** + * Get $transports to delegate to. + * + * @return Swift_Transport[] + */ + public function getTransports() + { + return array_merge($this->_transports, $this->_deadTransports); + } + + /** + * Get the Transport used in the last successful send operation. + * + * @return Swift_Transport + */ + public function getLastUsedTransport() + { + return $this->_lastUsedTransport; + } + + /** + * Test if this Transport mechanism has started. + * + * @return bool + */ + public function isStarted() + { + return count($this->_transports) > 0; + } + + /** + * Start this Transport mechanism. + */ + public function start() + { + $this->_transports = array_merge($this->_transports, $this->_deadTransports); + } + + /** + * Stop this Transport mechanism. + */ + public function stop() + { + foreach ($this->_transports as $transport) { + $transport->stop(); + } + } + + /** + * Send the given Message. + * + * Recipient/sender data will be retrieved from the Message API. + * The return value is the number of recipients who were accepted for delivery. + * + * @param Swift_Mime_Message $message + * @param string[] $failedRecipients An array of failures by-reference + * + * @return int + */ + public function send(Swift_Mime_Message $message, &$failedRecipients = null) + { + $maxTransports = count($this->_transports); + $sent = 0; + $this->_lastUsedTransport = null; + + for ($i = 0; $i < $maxTransports + && $transport = $this->_getNextTransport(); ++$i) { + try { + if (!$transport->isStarted()) { + $transport->start(); + } + if ($sent = $transport->send($message, $failedRecipients)) { + $this->_lastUsedTransport = $transport; + break; + } + } catch (Swift_TransportException $e) { + $this->_killCurrentTransport(); + } + } + + if (count($this->_transports) == 0) { + throw new Swift_TransportException( + 'All Transports in LoadBalancedTransport failed, or no Transports available' + ); + } + + return $sent; + } + + /** + * Register a plugin. + * + * @param Swift_Events_EventListener $plugin + */ + public function registerPlugin(Swift_Events_EventListener $plugin) + { + foreach ($this->_transports as $transport) { + $transport->registerPlugin($plugin); + } + } + + /** + * Rotates the transport list around and returns the first instance. + * + * @return Swift_Transport + */ + protected function _getNextTransport() + { + if ($next = array_shift($this->_transports)) { + $this->_transports[] = $next; + } + + return $next; + } + + /** + * Tag the currently used (top of stack) transport as dead/useless. + */ + protected function _killCurrentTransport() + { + if ($transport = array_pop($this->_transports)) { + try { + $transport->stop(); + } catch (Exception $e) { + } + $this->_deadTransports[] = $transport; + } + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/MailInvoker.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/MailInvoker.php new file mode 100644 index 0000000..77489ce --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/MailInvoker.php @@ -0,0 +1,32 @@ +_invoker = $invoker; + $this->_eventDispatcher = $eventDispatcher; + } + + /** + * Not used. + */ + public function isStarted() + { + return false; + } + + /** + * Not used. + */ + public function start() + { + } + + /** + * Not used. + */ + public function stop() + { + } + + /** + * Set the additional parameters used on the mail() function. + * + * This string is formatted for sprintf() where %s is the sender address. + * + * @param string $params + * + * @return $this + */ + public function setExtraParams($params) + { + $this->_extraParams = $params; + + return $this; + } + + /** + * Get the additional parameters used on the mail() function. + * + * This string is formatted for sprintf() where %s is the sender address. + * + * @return string + */ + public function getExtraParams() + { + return $this->_extraParams; + } + + /** + * Send the given Message. + * + * Recipient/sender data will be retrieved from the Message API. + * The return value is the number of recipients who were accepted for delivery. + * + * @param Swift_Mime_Message $message + * @param string[] $failedRecipients An array of failures by-reference + * + * @return int + */ + public function send(Swift_Mime_Message $message, &$failedRecipients = null) + { + $failedRecipients = (array) $failedRecipients; + + if ($evt = $this->_eventDispatcher->createSendEvent($this, $message)) { + $this->_eventDispatcher->dispatchEvent($evt, 'beforeSendPerformed'); + if ($evt->bubbleCancelled()) { + return 0; + } + } + + $count = ( + count((array) $message->getTo()) + + count((array) $message->getCc()) + + count((array) $message->getBcc()) + ); + + $toHeader = $message->getHeaders()->get('To'); + $subjectHeader = $message->getHeaders()->get('Subject'); + + if (0 === $count) { + $this->_throwException(new Swift_TransportException('Cannot send message without a recipient')); + } + $to = $toHeader ? $toHeader->getFieldBody() : ''; + $subject = $subjectHeader ? $subjectHeader->getFieldBody() : ''; + + $reversePath = $this->_getReversePath($message); + + // Remove headers that would otherwise be duplicated + $message->getHeaders()->remove('To'); + $message->getHeaders()->remove('Subject'); + + $messageStr = $message->toString(); + + if ($toHeader) { + $message->getHeaders()->set($toHeader); + } + $message->getHeaders()->set($subjectHeader); + + // Separate headers from body + if (false !== $endHeaders = strpos($messageStr, "\r\n\r\n")) { + $headers = substr($messageStr, 0, $endHeaders)."\r\n"; //Keep last EOL + $body = substr($messageStr, $endHeaders + 4); + } else { + $headers = $messageStr."\r\n"; + $body = ''; + } + + unset($messageStr); + + if ("\r\n" != PHP_EOL) { + // Non-windows (not using SMTP) + $headers = str_replace("\r\n", PHP_EOL, $headers); + $subject = str_replace("\r\n", PHP_EOL, $subject); + $body = str_replace("\r\n", PHP_EOL, $body); + $to = str_replace("\r\n", PHP_EOL, $to); + } else { + // Windows, using SMTP + $headers = str_replace("\r\n.", "\r\n..", $headers); + $subject = str_replace("\r\n.", "\r\n..", $subject); + $body = str_replace("\r\n.", "\r\n..", $body); + $to = str_replace("\r\n.", "\r\n..", $to); + } + + if ($this->_invoker->mail($to, $subject, $body, $headers, $this->_formatExtraParams($this->_extraParams, $reversePath))) { + if ($evt) { + $evt->setResult(Swift_Events_SendEvent::RESULT_SUCCESS); + $evt->setFailedRecipients($failedRecipients); + $this->_eventDispatcher->dispatchEvent($evt, 'sendPerformed'); + } + } else { + $failedRecipients = array_merge( + $failedRecipients, + array_keys((array) $message->getTo()), + array_keys((array) $message->getCc()), + array_keys((array) $message->getBcc()) + ); + + if ($evt) { + $evt->setResult(Swift_Events_SendEvent::RESULT_FAILED); + $evt->setFailedRecipients($failedRecipients); + $this->_eventDispatcher->dispatchEvent($evt, 'sendPerformed'); + } + + $message->generateId(); + + $count = 0; + } + + return $count; + } + + /** + * Register a plugin. + * + * @param Swift_Events_EventListener $plugin + */ + public function registerPlugin(Swift_Events_EventListener $plugin) + { + $this->_eventDispatcher->bindEventListener($plugin); + } + + /** Throw a TransportException, first sending it to any listeners */ + protected function _throwException(Swift_TransportException $e) + { + if ($evt = $this->_eventDispatcher->createTransportExceptionEvent($this, $e)) { + $this->_eventDispatcher->dispatchEvent($evt, 'exceptionThrown'); + if (!$evt->bubbleCancelled()) { + throw $e; + } + } else { + throw $e; + } + } + + /** Determine the best-use reverse path for this message */ + private function _getReversePath(Swift_Mime_Message $message) + { + $return = $message->getReturnPath(); + $sender = $message->getSender(); + $from = $message->getFrom(); + $path = null; + if (!empty($return)) { + $path = $return; + } elseif (!empty($sender)) { + $keys = array_keys($sender); + $path = array_shift($keys); + } elseif (!empty($from)) { + $keys = array_keys($from); + $path = array_shift($keys); + } + + return $path; + } + + /** + * Fix CVE-2016-10074 by disallowing potentially unsafe shell characters. + * + * Note that escapeshellarg and escapeshellcmd are inadequate for our purposes, especially on Windows. + * + * @param string $string The string to be validated + * + * @return bool + */ + private function _isShellSafe($string) + { + // Future-proof + if (escapeshellcmd($string) !== $string || !in_array(escapeshellarg($string), array("'$string'", "\"$string\""))) { + return false; + } + + $length = strlen($string); + for ($i = 0; $i < $length; ++$i) { + $c = $string[$i]; + // All other characters have a special meaning in at least one common shell, including = and +. + // Full stop (.) has a special meaning in cmd.exe, but its impact should be negligible here. + // Note that this does permit non-Latin alphanumeric characters based on the current locale. + if (!ctype_alnum($c) && strpos('@_-.', $c) === false) { + return false; + } + } + + return true; + } + + /** + * Return php mail extra params to use for invoker->mail. + * + * @param $extraParams + * @param $reversePath + * + * @return string|null + */ + private function _formatExtraParams($extraParams, $reversePath) + { + if (false !== strpos($extraParams, '-f%s')) { + if (empty($reversePath) || false === $this->_isShellSafe($reversePath)) { + $extraParams = str_replace('-f%s', '', $extraParams); + } else { + $extraParams = sprintf($extraParams, $reversePath); + } + } + + return !empty($extraParams) ? $extraParams : null; + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/NullTransport.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/NullTransport.php new file mode 100644 index 0000000..ad20e0e --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/NullTransport.php @@ -0,0 +1,93 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * Pretends messages have been sent, but just ignores them. + * + * @author Fabien Potencier + */ +class Swift_Transport_NullTransport implements Swift_Transport +{ + /** The event dispatcher from the plugin API */ + private $_eventDispatcher; + + /** + * Constructor. + */ + public function __construct(Swift_Events_EventDispatcher $eventDispatcher) + { + $this->_eventDispatcher = $eventDispatcher; + } + + /** + * Tests if this Transport mechanism has started. + * + * @return bool + */ + public function isStarted() + { + return true; + } + + /** + * Starts this Transport mechanism. + */ + public function start() + { + } + + /** + * Stops this Transport mechanism. + */ + public function stop() + { + } + + /** + * Sends the given message. + * + * @param Swift_Mime_Message $message + * @param string[] $failedRecipients An array of failures by-reference + * + * @return int The number of sent emails + */ + public function send(Swift_Mime_Message $message, &$failedRecipients = null) + { + if ($evt = $this->_eventDispatcher->createSendEvent($this, $message)) { + $this->_eventDispatcher->dispatchEvent($evt, 'beforeSendPerformed'); + if ($evt->bubbleCancelled()) { + return 0; + } + } + + if ($evt) { + $evt->setResult(Swift_Events_SendEvent::RESULT_SUCCESS); + $this->_eventDispatcher->dispatchEvent($evt, 'sendPerformed'); + } + + $count = ( + count((array) $message->getTo()) + + count((array) $message->getCc()) + + count((array) $message->getBcc()) + ); + + return $count; + } + + /** + * Register a plugin. + * + * @param Swift_Events_EventListener $plugin + */ + public function registerPlugin(Swift_Events_EventListener $plugin) + { + $this->_eventDispatcher->bindEventListener($plugin); + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/SendmailTransport.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/SendmailTransport.php new file mode 100644 index 0000000..6430d5f --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/SendmailTransport.php @@ -0,0 +1,160 @@ + 30, + 'blocking' => 1, + 'command' => '/usr/sbin/sendmail -bs', + 'type' => Swift_Transport_IoBuffer::TYPE_PROCESS, + ); + + /** + * Create a new SendmailTransport with $buf for I/O. + * + * @param Swift_Transport_IoBuffer $buf + * @param Swift_Events_EventDispatcher $dispatcher + */ + public function __construct(Swift_Transport_IoBuffer $buf, Swift_Events_EventDispatcher $dispatcher) + { + parent::__construct($buf, $dispatcher); + } + + /** + * Start the standalone SMTP session if running in -bs mode. + */ + public function start() + { + if (false !== strpos($this->getCommand(), ' -bs')) { + parent::start(); + } + } + + /** + * Set the command to invoke. + * + * If using -t mode you are strongly advised to include -oi or -i in the flags. + * For example: /usr/sbin/sendmail -oi -t + * Swift will append a -f flag if one is not present. + * + * The recommended mode is "-bs" since it is interactive and failure notifications + * are hence possible. + * + * @param string $command + * + * @return $this + */ + public function setCommand($command) + { + $this->_params['command'] = $command; + + return $this; + } + + /** + * Get the sendmail command which will be invoked. + * + * @return string + */ + public function getCommand() + { + return $this->_params['command']; + } + + /** + * Send the given Message. + * + * Recipient/sender data will be retrieved from the Message API. + * + * The return value is the number of recipients who were accepted for delivery. + * NOTE: If using 'sendmail -t' you will not be aware of any failures until + * they bounce (i.e. send() will always return 100% success). + * + * @param Swift_Mime_Message $message + * @param string[] $failedRecipients An array of failures by-reference + * + * @return int + */ + public function send(Swift_Mime_Message $message, &$failedRecipients = null) + { + $failedRecipients = (array) $failedRecipients; + $command = $this->getCommand(); + $buffer = $this->getBuffer(); + $count = 0; + + if (false !== strpos($command, ' -t')) { + if ($evt = $this->_eventDispatcher->createSendEvent($this, $message)) { + $this->_eventDispatcher->dispatchEvent($evt, 'beforeSendPerformed'); + if ($evt->bubbleCancelled()) { + return 0; + } + } + + if (false === strpos($command, ' -f')) { + $command .= ' -f'.escapeshellarg($this->_getReversePath($message)); + } + + $buffer->initialize(array_merge($this->_params, array('command' => $command))); + + if (false === strpos($command, ' -i') && false === strpos($command, ' -oi')) { + $buffer->setWriteTranslations(array("\r\n" => "\n", "\n." => "\n..")); + } else { + $buffer->setWriteTranslations(array("\r\n" => "\n")); + } + + $count = count((array) $message->getTo()) + + count((array) $message->getCc()) + + count((array) $message->getBcc()) + ; + $message->toByteStream($buffer); + $buffer->flushBuffers(); + $buffer->setWriteTranslations(array()); + $buffer->terminate(); + + if ($evt) { + $evt->setResult(Swift_Events_SendEvent::RESULT_SUCCESS); + $evt->setFailedRecipients($failedRecipients); + $this->_eventDispatcher->dispatchEvent($evt, 'sendPerformed'); + } + + $message->generateId(); + } elseif (false !== strpos($command, ' -bs')) { + $count = parent::send($message, $failedRecipients); + } else { + $this->_throwException(new Swift_TransportException( + 'Unsupported sendmail command flags ['.$command.']. '. + 'Must be one of "-bs" or "-t" but can include additional flags.' + )); + } + + return $count; + } + + /** Get the params to initialize the buffer */ + protected function _getBufferParams() + { + return $this->_params; + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/SimpleMailInvoker.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/SimpleMailInvoker.php new file mode 100644 index 0000000..4cab66b --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/SimpleMailInvoker.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * Stores Messages in a queue. + * + * @author Fabien Potencier + */ +class Swift_Transport_SpoolTransport implements Swift_Transport +{ + /** The spool instance */ + private $_spool; + + /** The event dispatcher from the plugin API */ + private $_eventDispatcher; + + /** + * Constructor. + */ + public function __construct(Swift_Events_EventDispatcher $eventDispatcher, Swift_Spool $spool = null) + { + $this->_eventDispatcher = $eventDispatcher; + $this->_spool = $spool; + } + + /** + * Sets the spool object. + * + * @param Swift_Spool $spool + * + * @return $this + */ + public function setSpool(Swift_Spool $spool) + { + $this->_spool = $spool; + + return $this; + } + + /** + * Get the spool object. + * + * @return Swift_Spool + */ + public function getSpool() + { + return $this->_spool; + } + + /** + * Tests if this Transport mechanism has started. + * + * @return bool + */ + public function isStarted() + { + return true; + } + + /** + * Starts this Transport mechanism. + */ + public function start() + { + } + + /** + * Stops this Transport mechanism. + */ + public function stop() + { + } + + /** + * Sends the given message. + * + * @param Swift_Mime_Message $message + * @param string[] $failedRecipients An array of failures by-reference + * + * @return int The number of sent e-mail's + */ + public function send(Swift_Mime_Message $message, &$failedRecipients = null) + { + if ($evt = $this->_eventDispatcher->createSendEvent($this, $message)) { + $this->_eventDispatcher->dispatchEvent($evt, 'beforeSendPerformed'); + if ($evt->bubbleCancelled()) { + return 0; + } + } + + $success = $this->_spool->queueMessage($message); + + if ($evt) { + $evt->setResult($success ? Swift_Events_SendEvent::RESULT_SPOOLED : Swift_Events_SendEvent::RESULT_FAILED); + $this->_eventDispatcher->dispatchEvent($evt, 'sendPerformed'); + } + + return 1; + } + + /** + * Register a plugin. + * + * @param Swift_Events_EventListener $plugin + */ + public function registerPlugin(Swift_Events_EventListener $plugin) + { + $this->_eventDispatcher->bindEventListener($plugin); + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/StreamBuffer.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/StreamBuffer.php new file mode 100644 index 0000000..9f2fff4 --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/StreamBuffer.php @@ -0,0 +1,325 @@ +_replacementFactory = $replacementFactory; + } + + /** + * Perform any initialization needed, using the given $params. + * + * Parameters will vary depending upon the type of IoBuffer used. + * + * @param array $params + */ + public function initialize(array $params) + { + $this->_params = $params; + switch ($params['type']) { + case self::TYPE_PROCESS: + $this->_establishProcessConnection(); + break; + case self::TYPE_SOCKET: + default: + $this->_establishSocketConnection(); + break; + } + } + + /** + * Set an individual param on the buffer (e.g. switching to SSL). + * + * @param string $param + * @param mixed $value + */ + public function setParam($param, $value) + { + if (isset($this->_stream)) { + switch ($param) { + case 'timeout': + if ($this->_stream) { + stream_set_timeout($this->_stream, $value); + } + break; + + case 'blocking': + if ($this->_stream) { + stream_set_blocking($this->_stream, 1); + } + } + } + $this->_params[$param] = $value; + } + + public function startTLS() + { + return stream_socket_enable_crypto($this->_stream, true, STREAM_CRYPTO_METHOD_TLS_CLIENT); + } + + /** + * Perform any shutdown logic needed. + */ + public function terminate() + { + if (isset($this->_stream)) { + switch ($this->_params['type']) { + case self::TYPE_PROCESS: + fclose($this->_in); + fclose($this->_out); + proc_close($this->_stream); + break; + case self::TYPE_SOCKET: + default: + fclose($this->_stream); + break; + } + } + $this->_stream = null; + $this->_out = null; + $this->_in = null; + } + + /** + * Set an array of string replacements which should be made on data written + * to the buffer. + * + * This could replace LF with CRLF for example. + * + * @param string[] $replacements + */ + public function setWriteTranslations(array $replacements) + { + foreach ($this->_translations as $search => $replace) { + if (!isset($replacements[$search])) { + $this->removeFilter($search); + unset($this->_translations[$search]); + } + } + + foreach ($replacements as $search => $replace) { + if (!isset($this->_translations[$search])) { + $this->addFilter( + $this->_replacementFactory->createFilter($search, $replace), $search + ); + $this->_translations[$search] = true; + } + } + } + + /** + * Get a line of output (including any CRLF). + * + * The $sequence number comes from any writes and may or may not be used + * depending upon the implementation. + * + * @param int $sequence of last write to scan from + * + * @throws Swift_IoException + * + * @return string + */ + public function readLine($sequence) + { + if (isset($this->_out) && !feof($this->_out)) { + $line = fgets($this->_out); + if (strlen($line) == 0) { + $metas = stream_get_meta_data($this->_out); + if ($metas['timed_out']) { + throw new Swift_IoException( + 'Connection to '. + $this->_getReadConnectionDescription(). + ' Timed Out' + ); + } + } + + return $line; + } + } + + /** + * Reads $length bytes from the stream into a string and moves the pointer + * through the stream by $length. + * + * If less bytes exist than are requested the remaining bytes are given instead. + * If no bytes are remaining at all, boolean false is returned. + * + * @param int $length + * + * @throws Swift_IoException + * + * @return string|bool + */ + public function read($length) + { + if (isset($this->_out) && !feof($this->_out)) { + $ret = fread($this->_out, $length); + if (strlen($ret) == 0) { + $metas = stream_get_meta_data($this->_out); + if ($metas['timed_out']) { + throw new Swift_IoException( + 'Connection to '. + $this->_getReadConnectionDescription(). + ' Timed Out' + ); + } + } + + return $ret; + } + } + + /** Not implemented */ + public function setReadPointer($byteOffset) + { + } + + /** Flush the stream contents */ + protected function _flush() + { + if (isset($this->_in)) { + fflush($this->_in); + } + } + + /** Write this bytes to the stream */ + protected function _commit($bytes) + { + if (isset($this->_in)) { + $bytesToWrite = strlen($bytes); + $totalBytesWritten = 0; + + while ($totalBytesWritten < $bytesToWrite) { + $bytesWritten = fwrite($this->_in, substr($bytes, $totalBytesWritten)); + if (false === $bytesWritten || 0 === $bytesWritten) { + break; + } + + $totalBytesWritten += $bytesWritten; + } + + if ($totalBytesWritten > 0) { + return ++$this->_sequence; + } + } + } + + /** + * Establishes a connection to a remote server. + */ + private function _establishSocketConnection() + { + $host = $this->_params['host']; + if (!empty($this->_params['protocol'])) { + $host = $this->_params['protocol'].'://'.$host; + } + $timeout = 15; + if (!empty($this->_params['timeout'])) { + $timeout = $this->_params['timeout']; + } + $options = array(); + if (!empty($this->_params['sourceIp'])) { + $options['socket']['bindto'] = $this->_params['sourceIp'].':0'; + } + if (isset($this->_params['stream_context_options'])) { + $options = array_merge($options, $this->_params['stream_context_options']); + } + $streamContext = stream_context_create($options); + $this->_stream = @stream_socket_client($host.':'.$this->_params['port'], $errno, $errstr, $timeout, STREAM_CLIENT_CONNECT, $streamContext); + if (false === $this->_stream) { + throw new Swift_TransportException( + 'Connection could not be established with host '.$this->_params['host']. + ' ['.$errstr.' #'.$errno.']' + ); + } + if (!empty($this->_params['blocking'])) { + stream_set_blocking($this->_stream, 1); + } else { + stream_set_blocking($this->_stream, 0); + } + stream_set_timeout($this->_stream, $timeout); + $this->_in = &$this->_stream; + $this->_out = &$this->_stream; + } + + /** + * Opens a process for input/output. + */ + private function _establishProcessConnection() + { + $command = $this->_params['command']; + $descriptorSpec = array( + 0 => array('pipe', 'r'), + 1 => array('pipe', 'w'), + 2 => array('pipe', 'w'), + ); + $pipes = array(); + $this->_stream = proc_open($command, $descriptorSpec, $pipes); + stream_set_blocking($pipes[2], 0); + if ($err = stream_get_contents($pipes[2])) { + throw new Swift_TransportException( + 'Process could not be started ['.$err.']' + ); + } + $this->_in = &$pipes[0]; + $this->_out = &$pipes[1]; + } + + private function _getReadConnectionDescription() + { + switch ($this->_params['type']) { + case self::TYPE_PROCESS: + return 'Process '.$this->_params['command']; + break; + + case self::TYPE_SOCKET: + default: + $host = $this->_params['host']; + if (!empty($this->_params['protocol'])) { + $host = $this->_params['protocol'].'://'.$host; + } + $host .= ':'.$this->_params['port']; + + return $host; + break; + } + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/TransportException.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/TransportException.php new file mode 100644 index 0000000..4ae2412 --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/TransportException.php @@ -0,0 +1,29 @@ + + */ +class Swift_Validate +{ + /** + * Grammar Object. + * + * @var Swift_Mime_Grammar + */ + private static $grammar = null; + + /** + * Checks if an e-mail address matches the current grammars. + * + * @param string $email + * + * @return bool + */ + public static function email($email) + { + if (self::$grammar === null) { + self::$grammar = Swift_DependencyContainer::getInstance() + ->lookup('mime.grammar'); + } + + return (bool) preg_match( + '/^'.self::$grammar->getDefinition('addr-spec').'$/D', + $email + ); + } +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/dependency_maps/cache_deps.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/dependency_maps/cache_deps.php new file mode 100644 index 0000000..6023448 --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/dependency_maps/cache_deps.php @@ -0,0 +1,23 @@ +register('cache') + ->asAliasOf('cache.array') + + ->register('tempdir') + ->asValue('/tmp') + + ->register('cache.null') + ->asSharedInstanceOf('Swift_KeyCache_NullKeyCache') + + ->register('cache.array') + ->asSharedInstanceOf('Swift_KeyCache_ArrayKeyCache') + ->withDependencies(array('cache.inputstream')) + + ->register('cache.disk') + ->asSharedInstanceOf('Swift_KeyCache_DiskKeyCache') + ->withDependencies(array('cache.inputstream', 'tempdir')) + + ->register('cache.inputstream') + ->asNewInstanceOf('Swift_KeyCache_SimpleKeyCacheInputStream') +; diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/dependency_maps/message_deps.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/dependency_maps/message_deps.php new file mode 100644 index 0000000..64d69d2 --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/dependency_maps/message_deps.php @@ -0,0 +1,9 @@ +register('message.message') + ->asNewInstanceOf('Swift_Message') + + ->register('message.mimepart') + ->asNewInstanceOf('Swift_MimePart') +; diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/dependency_maps/mime_deps.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/dependency_maps/mime_deps.php new file mode 100644 index 0000000..d575e4f --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/dependency_maps/mime_deps.php @@ -0,0 +1,123 @@ +register('properties.charset') + ->asValue('utf-8') + + ->register('mime.grammar') + ->asSharedInstanceOf('Swift_Mime_Grammar') + + ->register('mime.message') + ->asNewInstanceOf('Swift_Mime_SimpleMessage') + ->withDependencies(array( + 'mime.headerset', + 'mime.qpcontentencoder', + 'cache', + 'mime.grammar', + 'properties.charset', + )) + + ->register('mime.part') + ->asNewInstanceOf('Swift_Mime_MimePart') + ->withDependencies(array( + 'mime.headerset', + 'mime.qpcontentencoder', + 'cache', + 'mime.grammar', + 'properties.charset', + )) + + ->register('mime.attachment') + ->asNewInstanceOf('Swift_Mime_Attachment') + ->withDependencies(array( + 'mime.headerset', + 'mime.base64contentencoder', + 'cache', + 'mime.grammar', + )) + ->addConstructorValue($swift_mime_types) + + ->register('mime.embeddedfile') + ->asNewInstanceOf('Swift_Mime_EmbeddedFile') + ->withDependencies(array( + 'mime.headerset', + 'mime.base64contentencoder', + 'cache', + 'mime.grammar', + )) + ->addConstructorValue($swift_mime_types) + + ->register('mime.headerfactory') + ->asNewInstanceOf('Swift_Mime_SimpleHeaderFactory') + ->withDependencies(array( + 'mime.qpheaderencoder', + 'mime.rfc2231encoder', + 'mime.grammar', + 'properties.charset', + )) + + ->register('mime.headerset') + ->asNewInstanceOf('Swift_Mime_SimpleHeaderSet') + ->withDependencies(array('mime.headerfactory', 'properties.charset')) + + ->register('mime.qpheaderencoder') + ->asNewInstanceOf('Swift_Mime_HeaderEncoder_QpHeaderEncoder') + ->withDependencies(array('mime.charstream')) + + ->register('mime.base64headerencoder') + ->asNewInstanceOf('Swift_Mime_HeaderEncoder_Base64HeaderEncoder') + ->withDependencies(array('mime.charstream')) + + ->register('mime.charstream') + ->asNewInstanceOf('Swift_CharacterStream_NgCharacterStream') + ->withDependencies(array('mime.characterreaderfactory', 'properties.charset')) + + ->register('mime.bytecanonicalizer') + ->asSharedInstanceOf('Swift_StreamFilters_ByteArrayReplacementFilter') + ->addConstructorValue(array(array(0x0D, 0x0A), array(0x0D), array(0x0A))) + ->addConstructorValue(array(array(0x0A), array(0x0A), array(0x0D, 0x0A))) + + ->register('mime.characterreaderfactory') + ->asSharedInstanceOf('Swift_CharacterReaderFactory_SimpleCharacterReaderFactory') + + ->register('mime.safeqpcontentencoder') + ->asNewInstanceOf('Swift_Mime_ContentEncoder_QpContentEncoder') + ->withDependencies(array('mime.charstream', 'mime.bytecanonicalizer')) + + ->register('mime.rawcontentencoder') + ->asNewInstanceOf('Swift_Mime_ContentEncoder_RawContentEncoder') + + ->register('mime.nativeqpcontentencoder') + ->withDependencies(array('properties.charset')) + ->asNewInstanceOf('Swift_Mime_ContentEncoder_NativeQpContentEncoder') + + ->register('mime.qpcontentencoderproxy') + ->asNewInstanceOf('Swift_Mime_ContentEncoder_QpContentEncoderProxy') + ->withDependencies(array('mime.safeqpcontentencoder', 'mime.nativeqpcontentencoder', 'properties.charset')) + + ->register('mime.7bitcontentencoder') + ->asNewInstanceOf('Swift_Mime_ContentEncoder_PlainContentEncoder') + ->addConstructorValue('7bit') + ->addConstructorValue(true) + + ->register('mime.8bitcontentencoder') + ->asNewInstanceOf('Swift_Mime_ContentEncoder_PlainContentEncoder') + ->addConstructorValue('8bit') + ->addConstructorValue(true) + + ->register('mime.base64contentencoder') + ->asSharedInstanceOf('Swift_Mime_ContentEncoder_Base64ContentEncoder') + + ->register('mime.rfc2231encoder') + ->asNewInstanceOf('Swift_Encoder_Rfc2231Encoder') + ->withDependencies(array('mime.charstream')) + + // As of PHP 5.4.7, the quoted_printable_encode() function behaves correctly. + // see https://github.com/php/php-src/commit/18bb426587d62f93c54c40bf8535eb8416603629 + ->register('mime.qpcontentencoder') + ->asAliasOf(PHP_VERSION_ID >= 50407 ? 'mime.qpcontentencoderproxy' : 'mime.safeqpcontentencoder') +; + +unset($swift_mime_types); diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/dependency_maps/transport_deps.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/dependency_maps/transport_deps.php new file mode 100644 index 0000000..77e432c --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/dependency_maps/transport_deps.php @@ -0,0 +1,76 @@ +register('transport.smtp') + ->asNewInstanceOf('Swift_Transport_EsmtpTransport') + ->withDependencies(array( + 'transport.buffer', + array('transport.authhandler'), + 'transport.eventdispatcher', + )) + + ->register('transport.sendmail') + ->asNewInstanceOf('Swift_Transport_SendmailTransport') + ->withDependencies(array( + 'transport.buffer', + 'transport.eventdispatcher', + )) + + ->register('transport.mail') + ->asNewInstanceOf('Swift_Transport_MailTransport') + ->withDependencies(array('transport.mailinvoker', 'transport.eventdispatcher')) + + ->register('transport.loadbalanced') + ->asNewInstanceOf('Swift_Transport_LoadBalancedTransport') + + ->register('transport.failover') + ->asNewInstanceOf('Swift_Transport_FailoverTransport') + + ->register('transport.spool') + ->asNewInstanceOf('Swift_Transport_SpoolTransport') + ->withDependencies(array('transport.eventdispatcher')) + + ->register('transport.null') + ->asNewInstanceOf('Swift_Transport_NullTransport') + ->withDependencies(array('transport.eventdispatcher')) + + ->register('transport.mailinvoker') + ->asSharedInstanceOf('Swift_Transport_SimpleMailInvoker') + + ->register('transport.buffer') + ->asNewInstanceOf('Swift_Transport_StreamBuffer') + ->withDependencies(array('transport.replacementfactory')) + + ->register('transport.authhandler') + ->asNewInstanceOf('Swift_Transport_Esmtp_AuthHandler') + ->withDependencies(array( + array( + 'transport.crammd5auth', + 'transport.loginauth', + 'transport.plainauth', + 'transport.ntlmauth', + 'transport.xoauth2auth', + ), + )) + + ->register('transport.crammd5auth') + ->asNewInstanceOf('Swift_Transport_Esmtp_Auth_CramMd5Authenticator') + + ->register('transport.loginauth') + ->asNewInstanceOf('Swift_Transport_Esmtp_Auth_LoginAuthenticator') + + ->register('transport.plainauth') + ->asNewInstanceOf('Swift_Transport_Esmtp_Auth_PlainAuthenticator') + + ->register('transport.xoauth2auth') + ->asNewInstanceOf('Swift_Transport_Esmtp_Auth_XOAuth2Authenticator') + + ->register('transport.ntlmauth') + ->asNewInstanceOf('Swift_Transport_Esmtp_Auth_NTLMAuthenticator') + + ->register('transport.eventdispatcher') + ->asNewInstanceOf('Swift_Events_SimpleEventDispatcher') + + ->register('transport.replacementfactory') + ->asSharedInstanceOf('Swift_StreamFilters_StringReplacementFilterFactory') +; diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/mime_types.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/mime_types.php new file mode 100644 index 0000000..2d7b98d --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/mime_types.php @@ -0,0 +1,1007 @@ + 'text/vnd.in3d.3dml', + '3ds' => 'image/x-3ds', + '3g2' => 'video/3gpp2', + '3gp' => 'video/3gpp', + '7z' => 'application/x-7z-compressed', + 'aab' => 'application/x-authorware-bin', + 'aac' => 'audio/x-aac', + 'aam' => 'application/x-authorware-map', + 'aas' => 'application/x-authorware-seg', + 'abw' => 'application/x-abiword', + 'ac' => 'application/pkix-attr-cert', + 'acc' => 'application/vnd.americandynamics.acc', + 'ace' => 'application/x-ace-compressed', + 'acu' => 'application/vnd.acucobol', + 'acutc' => 'application/vnd.acucorp', + 'adp' => 'audio/adpcm', + 'aep' => 'application/vnd.audiograph', + 'afm' => 'application/x-font-type1', + 'afp' => 'application/vnd.ibm.modcap', + 'ahead' => 'application/vnd.ahead.space', + 'ai' => 'application/postscript', + 'aif' => 'audio/x-aiff', + 'aifc' => 'audio/x-aiff', + 'aiff' => 'audio/x-aiff', + 'air' => 'application/vnd.adobe.air-application-installer-package+zip', + 'ait' => 'application/vnd.dvb.ait', + 'ami' => 'application/vnd.amiga.ami', + 'apk' => 'application/vnd.android.package-archive', + 'appcache' => 'text/cache-manifest', + 'apr' => 'application/vnd.lotus-approach', + 'aps' => 'application/postscript', + 'arc' => 'application/x-freearc', + 'asc' => 'application/pgp-signature', + 'asf' => 'video/x-ms-asf', + 'asm' => 'text/x-asm', + 'aso' => 'application/vnd.accpac.simply.aso', + 'asx' => 'video/x-ms-asf', + 'atc' => 'application/vnd.acucorp', + 'atom' => 'application/atom+xml', + 'atomcat' => 'application/atomcat+xml', + 'atomsvc' => 'application/atomsvc+xml', + 'atx' => 'application/vnd.antix.game-component', + 'au' => 'audio/basic', + 'avi' => 'video/x-msvideo', + 'aw' => 'application/applixware', + 'azf' => 'application/vnd.airzip.filesecure.azf', + 'azs' => 'application/vnd.airzip.filesecure.azs', + 'azw' => 'application/vnd.amazon.ebook', + 'bat' => 'application/x-msdownload', + 'bcpio' => 'application/x-bcpio', + 'bdf' => 'application/x-font-bdf', + 'bdm' => 'application/vnd.syncml.dm+wbxml', + 'bed' => 'application/vnd.realvnc.bed', + 'bh2' => 'application/vnd.fujitsu.oasysprs', + 'bin' => 'application/octet-stream', + 'blb' => 'application/x-blorb', + 'blorb' => 'application/x-blorb', + 'bmi' => 'application/vnd.bmi', + 'bmp' => 'image/bmp', + 'book' => 'application/vnd.framemaker', + 'box' => 'application/vnd.previewsystems.box', + 'boz' => 'application/x-bzip2', + 'bpk' => 'application/octet-stream', + 'btif' => 'image/prs.btif', + 'bz' => 'application/x-bzip', + 'bz2' => 'application/x-bzip2', + 'c' => 'text/x-c', + 'c11amc' => 'application/vnd.cluetrust.cartomobile-config', + 'c11amz' => 'application/vnd.cluetrust.cartomobile-config-pkg', + 'c4d' => 'application/vnd.clonk.c4group', + 'c4f' => 'application/vnd.clonk.c4group', + 'c4g' => 'application/vnd.clonk.c4group', + 'c4p' => 'application/vnd.clonk.c4group', + 'c4u' => 'application/vnd.clonk.c4group', + 'cab' => 'application/vnd.ms-cab-compressed', + 'caf' => 'audio/x-caf', + 'cap' => 'application/vnd.tcpdump.pcap', + 'car' => 'application/vnd.curl.car', + 'cat' => 'application/vnd.ms-pki.seccat', + 'cb7' => 'application/x-cbr', + 'cba' => 'application/x-cbr', + 'cbr' => 'application/x-cbr', + 'cbt' => 'application/x-cbr', + 'cbz' => 'application/x-cbr', + 'cc' => 'text/x-c', + 'cct' => 'application/x-director', + 'ccxml' => 'application/ccxml+xml', + 'cdbcmsg' => 'application/vnd.contact.cmsg', + 'cdf' => 'application/x-netcdf', + 'cdkey' => 'application/vnd.mediastation.cdkey', + 'cdmia' => 'application/cdmi-capability', + 'cdmic' => 'application/cdmi-container', + 'cdmid' => 'application/cdmi-domain', + 'cdmio' => 'application/cdmi-object', + 'cdmiq' => 'application/cdmi-queue', + 'cdx' => 'chemical/x-cdx', + 'cdxml' => 'application/vnd.chemdraw+xml', + 'cdy' => 'application/vnd.cinderella', + 'cer' => 'application/pkix-cert', + 'cfs' => 'application/x-cfs-compressed', + 'cgm' => 'image/cgm', + 'chat' => 'application/x-chat', + 'chm' => 'application/vnd.ms-htmlhelp', + 'chrt' => 'application/vnd.kde.kchart', + 'cif' => 'chemical/x-cif', + 'cii' => 'application/vnd.anser-web-certificate-issue-initiation', + 'cil' => 'application/vnd.ms-artgalry', + 'cla' => 'application/vnd.claymore', + 'class' => 'application/java-vm', + 'clkk' => 'application/vnd.crick.clicker.keyboard', + 'clkp' => 'application/vnd.crick.clicker.palette', + 'clkt' => 'application/vnd.crick.clicker.template', + 'clkw' => 'application/vnd.crick.clicker.wordbank', + 'clkx' => 'application/vnd.crick.clicker', + 'clp' => 'application/x-msclip', + 'cmc' => 'application/vnd.cosmocaller', + 'cmdf' => 'chemical/x-cmdf', + 'cml' => 'chemical/x-cml', + 'cmp' => 'application/vnd.yellowriver-custom-menu', + 'cmx' => 'image/x-cmx', + 'cod' => 'application/vnd.rim.cod', + 'com' => 'application/x-msdownload', + 'conf' => 'text/plain', + 'cpio' => 'application/x-cpio', + 'cpp' => 'text/x-c', + 'cpt' => 'application/mac-compactpro', + 'crd' => 'application/x-mscardfile', + 'crl' => 'application/pkix-crl', + 'crt' => 'application/x-x509-ca-cert', + 'csh' => 'application/x-csh', + 'csml' => 'chemical/x-csml', + 'csp' => 'application/vnd.commonspace', + 'css' => 'text/css', + 'cst' => 'application/x-director', + 'csv' => 'text/csv', + 'cu' => 'application/cu-seeme', + 'curl' => 'text/vnd.curl', + 'cww' => 'application/prs.cww', + 'cxt' => 'application/x-director', + 'cxx' => 'text/x-c', + 'dae' => 'model/vnd.collada+xml', + 'daf' => 'application/vnd.mobius.daf', + 'dart' => 'application/vnd.dart', + 'dataless' => 'application/vnd.fdsn.seed', + 'davmount' => 'application/davmount+xml', + 'dbk' => 'application/docbook+xml', + 'dcr' => 'application/x-director', + 'dcurl' => 'text/vnd.curl.dcurl', + 'dd2' => 'application/vnd.oma.dd2+xml', + 'ddd' => 'application/vnd.fujixerox.ddd', + 'deb' => 'application/x-debian-package', + 'def' => 'text/plain', + 'deploy' => 'application/octet-stream', + 'der' => 'application/x-x509-ca-cert', + 'dfac' => 'application/vnd.dreamfactory', + 'dgc' => 'application/x-dgc-compressed', + 'dic' => 'text/x-c', + 'dir' => 'application/x-director', + 'dis' => 'application/vnd.mobius.dis', + 'dist' => 'application/octet-stream', + 'distz' => 'application/octet-stream', + 'djv' => 'image/vnd.djvu', + 'djvu' => 'image/vnd.djvu', + 'dll' => 'application/x-msdownload', + 'dmg' => 'application/x-apple-diskimage', + 'dmp' => 'application/vnd.tcpdump.pcap', + 'dms' => 'application/octet-stream', + 'dna' => 'application/vnd.dna', + 'doc' => 'application/msword', + 'docm' => 'application/vnd.ms-word.document.macroenabled.12', + 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', + 'dot' => 'application/msword', + 'dotm' => 'application/vnd.ms-word.template.macroenabled.12', + 'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template', + 'dp' => 'application/vnd.osgi.dp', + 'dpg' => 'application/vnd.dpgraph', + 'dra' => 'audio/vnd.dra', + 'dsc' => 'text/prs.lines.tag', + 'dssc' => 'application/dssc+der', + 'dtb' => 'application/x-dtbook+xml', + 'dtd' => 'application/xml-dtd', + 'dts' => 'audio/vnd.dts', + 'dtshd' => 'audio/vnd.dts.hd', + 'dump' => 'application/octet-stream', + 'dvb' => 'video/vnd.dvb.file', + 'dvi' => 'application/x-dvi', + 'dwf' => 'model/vnd.dwf', + 'dwg' => 'image/vnd.dwg', + 'dxf' => 'image/vnd.dxf', + 'dxp' => 'application/vnd.spotfire.dxp', + 'dxr' => 'application/x-director', + 'ecelp4800' => 'audio/vnd.nuera.ecelp4800', + 'ecelp7470' => 'audio/vnd.nuera.ecelp7470', + 'ecelp9600' => 'audio/vnd.nuera.ecelp9600', + 'ecma' => 'application/ecmascript', + 'edm' => 'application/vnd.novadigm.edm', + 'edx' => 'application/vnd.novadigm.edx', + 'efif' => 'application/vnd.picsel', + 'ei6' => 'application/vnd.pg.osasli', + 'elc' => 'application/octet-stream', + 'emf' => 'application/x-msmetafile', + 'eml' => 'message/rfc822', + 'emma' => 'application/emma+xml', + 'emz' => 'application/x-msmetafile', + 'eol' => 'audio/vnd.digital-winds', + 'eot' => 'application/vnd.ms-fontobject', + 'eps' => 'application/postscript', + 'epub' => 'application/epub+zip', + 'es3' => 'application/vnd.eszigno3+xml', + 'esa' => 'application/vnd.osgi.subsystem', + 'esf' => 'application/vnd.epson.esf', + 'et3' => 'application/vnd.eszigno3+xml', + 'etx' => 'text/x-setext', + 'eva' => 'application/x-eva', + 'evy' => 'application/x-envoy', + 'exe' => 'application/x-msdownload', + 'exi' => 'application/exi', + 'ext' => 'application/vnd.novadigm.ext', + 'ez' => 'application/andrew-inset', + 'ez2' => 'application/vnd.ezpix-album', + 'ez3' => 'application/vnd.ezpix-package', + 'f' => 'text/x-fortran', + 'f4v' => 'video/x-f4v', + 'f77' => 'text/x-fortran', + 'f90' => 'text/x-fortran', + 'fbs' => 'image/vnd.fastbidsheet', + 'fcdt' => 'application/vnd.adobe.formscentral.fcdt', + 'fcs' => 'application/vnd.isac.fcs', + 'fdf' => 'application/vnd.fdf', + 'fe_launch' => 'application/vnd.denovo.fcselayout-link', + 'fg5' => 'application/vnd.fujitsu.oasysgp', + 'fgd' => 'application/x-director', + 'fh' => 'image/x-freehand', + 'fh4' => 'image/x-freehand', + 'fh5' => 'image/x-freehand', + 'fh7' => 'image/x-freehand', + 'fhc' => 'image/x-freehand', + 'fig' => 'application/x-xfig', + 'flac' => 'audio/x-flac', + 'fli' => 'video/x-fli', + 'flo' => 'application/vnd.micrografx.flo', + 'flv' => 'video/x-flv', + 'flw' => 'application/vnd.kde.kivio', + 'flx' => 'text/vnd.fmi.flexstor', + 'fly' => 'text/vnd.fly', + 'fm' => 'application/vnd.framemaker', + 'fnc' => 'application/vnd.frogans.fnc', + 'for' => 'text/x-fortran', + 'fpx' => 'image/vnd.fpx', + 'frame' => 'application/vnd.framemaker', + 'fsc' => 'application/vnd.fsc.weblaunch', + 'fst' => 'image/vnd.fst', + 'ftc' => 'application/vnd.fluxtime.clip', + 'fti' => 'application/vnd.anser-web-funds-transfer-initiation', + 'fvt' => 'video/vnd.fvt', + 'fxp' => 'application/vnd.adobe.fxp', + 'fxpl' => 'application/vnd.adobe.fxp', + 'fzs' => 'application/vnd.fuzzysheet', + 'g2w' => 'application/vnd.geoplan', + 'g3' => 'image/g3fax', + 'g3w' => 'application/vnd.geospace', + 'gac' => 'application/vnd.groove-account', + 'gam' => 'application/x-tads', + 'gbr' => 'application/rpki-ghostbusters', + 'gca' => 'application/x-gca-compressed', + 'gdl' => 'model/vnd.gdl', + 'geo' => 'application/vnd.dynageo', + 'gex' => 'application/vnd.geometry-explorer', + 'ggb' => 'application/vnd.geogebra.file', + 'ggt' => 'application/vnd.geogebra.tool', + 'ghf' => 'application/vnd.groove-help', + 'gif' => 'image/gif', + 'gim' => 'application/vnd.groove-identity-message', + 'gml' => 'application/gml+xml', + 'gmx' => 'application/vnd.gmx', + 'gnumeric' => 'application/x-gnumeric', + 'gph' => 'application/vnd.flographit', + 'gpx' => 'application/gpx+xml', + 'gqf' => 'application/vnd.grafeq', + 'gqs' => 'application/vnd.grafeq', + 'gram' => 'application/srgs', + 'gramps' => 'application/x-gramps-xml', + 'gre' => 'application/vnd.geometry-explorer', + 'grv' => 'application/vnd.groove-injector', + 'grxml' => 'application/srgs+xml', + 'gsf' => 'application/x-font-ghostscript', + 'gtar' => 'application/x-gtar', + 'gtm' => 'application/vnd.groove-tool-message', + 'gtw' => 'model/vnd.gtw', + 'gv' => 'text/vnd.graphviz', + 'gxf' => 'application/gxf', + 'gxt' => 'application/vnd.geonext', + 'gz' => 'application/x-gzip', + 'h' => 'text/x-c', + 'h261' => 'video/h261', + 'h263' => 'video/h263', + 'h264' => 'video/h264', + 'hal' => 'application/vnd.hal+xml', + 'hbci' => 'application/vnd.hbci', + 'hdf' => 'application/x-hdf', + 'hh' => 'text/x-c', + 'hlp' => 'application/winhlp', + 'hpgl' => 'application/vnd.hp-hpgl', + 'hpid' => 'application/vnd.hp-hpid', + 'hps' => 'application/vnd.hp-hps', + 'hqx' => 'application/mac-binhex40', + 'htke' => 'application/vnd.kenameaapp', + 'htm' => 'text/html', + 'html' => 'text/html', + 'hvd' => 'application/vnd.yamaha.hv-dic', + 'hvp' => 'application/vnd.yamaha.hv-voice', + 'hvs' => 'application/vnd.yamaha.hv-script', + 'i2g' => 'application/vnd.intergeo', + 'icc' => 'application/vnd.iccprofile', + 'ice' => 'x-conference/x-cooltalk', + 'icm' => 'application/vnd.iccprofile', + 'ico' => 'image/x-icon', + 'ics' => 'text/calendar', + 'ief' => 'image/ief', + 'ifb' => 'text/calendar', + 'ifm' => 'application/vnd.shana.informed.formdata', + 'iges' => 'model/iges', + 'igl' => 'application/vnd.igloader', + 'igm' => 'application/vnd.insors.igm', + 'igs' => 'model/iges', + 'igx' => 'application/vnd.micrografx.igx', + 'iif' => 'application/vnd.shana.informed.interchange', + 'imp' => 'application/vnd.accpac.simply.imp', + 'ims' => 'application/vnd.ms-ims', + 'in' => 'text/plain', + 'ink' => 'application/inkml+xml', + 'inkml' => 'application/inkml+xml', + 'install' => 'application/x-install-instructions', + 'iota' => 'application/vnd.astraea-software.iota', + 'ipfix' => 'application/ipfix', + 'ipk' => 'application/vnd.shana.informed.package', + 'irm' => 'application/vnd.ibm.rights-management', + 'irp' => 'application/vnd.irepository.package+xml', + 'iso' => 'application/x-iso9660-image', + 'itp' => 'application/vnd.shana.informed.formtemplate', + 'ivp' => 'application/vnd.immervision-ivp', + 'ivu' => 'application/vnd.immervision-ivu', + 'jad' => 'text/vnd.sun.j2me.app-descriptor', + 'jam' => 'application/vnd.jam', + 'jar' => 'application/java-archive', + 'java' => 'text/x-java-source', + 'jisp' => 'application/vnd.jisp', + 'jlt' => 'application/vnd.hp-jlyt', + 'jnlp' => 'application/x-java-jnlp-file', + 'joda' => 'application/vnd.joost.joda-archive', + 'jpe' => 'image/jpeg', + 'jpeg' => 'image/jpeg', + 'jpg' => 'image/jpeg', + 'jpgm' => 'video/jpm', + 'jpgv' => 'video/jpeg', + 'jpm' => 'video/jpm', + 'js' => 'application/javascript', + 'json' => 'application/json', + 'jsonml' => 'application/jsonml+json', + 'kar' => 'audio/midi', + 'karbon' => 'application/vnd.kde.karbon', + 'kfo' => 'application/vnd.kde.kformula', + 'kia' => 'application/vnd.kidspiration', + 'kml' => 'application/vnd.google-earth.kml+xml', + 'kmz' => 'application/vnd.google-earth.kmz', + 'kne' => 'application/vnd.kinar', + 'knp' => 'application/vnd.kinar', + 'kon' => 'application/vnd.kde.kontour', + 'kpr' => 'application/vnd.kde.kpresenter', + 'kpt' => 'application/vnd.kde.kpresenter', + 'kpxx' => 'application/vnd.ds-keypoint', + 'ksp' => 'application/vnd.kde.kspread', + 'ktr' => 'application/vnd.kahootz', + 'ktx' => 'image/ktx', + 'ktz' => 'application/vnd.kahootz', + 'kwd' => 'application/vnd.kde.kword', + 'kwt' => 'application/vnd.kde.kword', + 'lasxml' => 'application/vnd.las.las+xml', + 'latex' => 'application/x-latex', + 'lbd' => 'application/vnd.llamagraphics.life-balance.desktop', + 'lbe' => 'application/vnd.llamagraphics.life-balance.exchange+xml', + 'les' => 'application/vnd.hhe.lesson-player', + 'lha' => 'application/x-lzh-compressed', + 'link66' => 'application/vnd.route66.link66+xml', + 'list' => 'text/plain', + 'list3820' => 'application/vnd.ibm.modcap', + 'listafp' => 'application/vnd.ibm.modcap', + 'lnk' => 'application/x-ms-shortcut', + 'log' => 'text/plain', + 'lostxml' => 'application/lost+xml', + 'lrf' => 'application/octet-stream', + 'lrm' => 'application/vnd.ms-lrm', + 'ltf' => 'application/vnd.frogans.ltf', + 'lvp' => 'audio/vnd.lucent.voice', + 'lwp' => 'application/vnd.lotus-wordpro', + 'lzh' => 'application/x-lzh-compressed', + 'm13' => 'application/x-msmediaview', + 'm14' => 'application/x-msmediaview', + 'm1v' => 'video/mpeg', + 'm21' => 'application/mp21', + 'm2a' => 'audio/mpeg', + 'm2v' => 'video/mpeg', + 'm3a' => 'audio/mpeg', + 'm3u' => 'audio/x-mpegurl', + 'm3u8' => 'application/vnd.apple.mpegurl', + 'm4a' => 'audio/mp4', + 'm4u' => 'video/vnd.mpegurl', + 'm4v' => 'video/x-m4v', + 'ma' => 'application/mathematica', + 'mads' => 'application/mads+xml', + 'mag' => 'application/vnd.ecowin.chart', + 'maker' => 'application/vnd.framemaker', + 'man' => 'text/troff', + 'mar' => 'application/octet-stream', + 'mathml' => 'application/mathml+xml', + 'mb' => 'application/mathematica', + 'mbk' => 'application/vnd.mobius.mbk', + 'mbox' => 'application/mbox', + 'mc1' => 'application/vnd.medcalcdata', + 'mcd' => 'application/vnd.mcd', + 'mcurl' => 'text/vnd.curl.mcurl', + 'mdb' => 'application/x-msaccess', + 'mdi' => 'image/vnd.ms-modi', + 'me' => 'text/troff', + 'mesh' => 'model/mesh', + 'meta4' => 'application/metalink4+xml', + 'metalink' => 'application/metalink+xml', + 'mets' => 'application/mets+xml', + 'mfm' => 'application/vnd.mfmp', + 'mft' => 'application/rpki-manifest', + 'mgp' => 'application/vnd.osgeo.mapguide.package', + 'mgz' => 'application/vnd.proteus.magazine', + 'mid' => 'audio/midi', + 'midi' => 'audio/midi', + 'mie' => 'application/x-mie', + 'mif' => 'application/vnd.mif', + 'mime' => 'message/rfc822', + 'mj2' => 'video/mj2', + 'mjp2' => 'video/mj2', + 'mk3d' => 'video/x-matroska', + 'mka' => 'audio/x-matroska', + 'mks' => 'video/x-matroska', + 'mkv' => 'video/x-matroska', + 'mlp' => 'application/vnd.dolby.mlp', + 'mmd' => 'application/vnd.chipnuts.karaoke-mmd', + 'mmf' => 'application/vnd.smaf', + 'mmr' => 'image/vnd.fujixerox.edmics-mmr', + 'mng' => 'video/x-mng', + 'mny' => 'application/x-msmoney', + 'mobi' => 'application/x-mobipocket-ebook', + 'mods' => 'application/mods+xml', + 'mov' => 'video/quicktime', + 'movie' => 'video/x-sgi-movie', + 'mp2' => 'audio/mpeg', + 'mp21' => 'application/mp21', + 'mp2a' => 'audio/mpeg', + 'mp3' => 'audio/mpeg', + 'mp4' => 'video/mp4', + 'mp4a' => 'audio/mp4', + 'mp4s' => 'application/mp4', + 'mp4v' => 'video/mp4', + 'mpc' => 'application/vnd.mophun.certificate', + 'mpe' => 'video/mpeg', + 'mpeg' => 'video/mpeg', + 'mpg' => 'video/mpeg', + 'mpg4' => 'video/mp4', + 'mpga' => 'audio/mpeg', + 'mpkg' => 'application/vnd.apple.installer+xml', + 'mpm' => 'application/vnd.blueice.multipass', + 'mpn' => 'application/vnd.mophun.application', + 'mpp' => 'application/vnd.ms-project', + 'mpt' => 'application/vnd.ms-project', + 'mpy' => 'application/vnd.ibm.minipay', + 'mqy' => 'application/vnd.mobius.mqy', + 'mrc' => 'application/marc', + 'mrcx' => 'application/marcxml+xml', + 'ms' => 'text/troff', + 'mscml' => 'application/mediaservercontrol+xml', + 'mseed' => 'application/vnd.fdsn.mseed', + 'mseq' => 'application/vnd.mseq', + 'msf' => 'application/vnd.epson.msf', + 'msh' => 'model/mesh', + 'msi' => 'application/x-msdownload', + 'msl' => 'application/vnd.mobius.msl', + 'msty' => 'application/vnd.muvee.style', + 'mts' => 'model/vnd.mts', + 'mus' => 'application/vnd.musician', + 'musicxml' => 'application/vnd.recordare.musicxml+xml', + 'mvb' => 'application/x-msmediaview', + 'mwf' => 'application/vnd.mfer', + 'mxf' => 'application/mxf', + 'mxl' => 'application/vnd.recordare.musicxml', + 'mxml' => 'application/xv+xml', + 'mxs' => 'application/vnd.triscape.mxs', + 'mxu' => 'video/vnd.mpegurl', + 'n-gage' => 'application/vnd.nokia.n-gage.symbian.install', + 'n3' => 'text/n3', + 'nb' => 'application/mathematica', + 'nbp' => 'application/vnd.wolfram.player', + 'nc' => 'application/x-netcdf', + 'ncx' => 'application/x-dtbncx+xml', + 'nfo' => 'text/x-nfo', + 'ngdat' => 'application/vnd.nokia.n-gage.data', + 'nitf' => 'application/vnd.nitf', + 'nlu' => 'application/vnd.neurolanguage.nlu', + 'nml' => 'application/vnd.enliven', + 'nnd' => 'application/vnd.noblenet-directory', + 'nns' => 'application/vnd.noblenet-sealer', + 'nnw' => 'application/vnd.noblenet-web', + 'npx' => 'image/vnd.net-fpx', + 'nsc' => 'application/x-conference', + 'nsf' => 'application/vnd.lotus-notes', + 'ntf' => 'application/vnd.nitf', + 'nzb' => 'application/x-nzb', + 'oa2' => 'application/vnd.fujitsu.oasys2', + 'oa3' => 'application/vnd.fujitsu.oasys3', + 'oas' => 'application/vnd.fujitsu.oasys', + 'obd' => 'application/x-msbinder', + 'obj' => 'application/x-tgif', + 'oda' => 'application/oda', + 'odb' => 'application/vnd.oasis.opendocument.database', + 'odc' => 'application/vnd.oasis.opendocument.chart', + 'odf' => 'application/vnd.oasis.opendocument.formula', + 'odft' => 'application/vnd.oasis.opendocument.formula-template', + 'odg' => 'application/vnd.oasis.opendocument.graphics', + 'odi' => 'application/vnd.oasis.opendocument.image', + 'odm' => 'application/vnd.oasis.opendocument.text-master', + 'odp' => 'application/vnd.oasis.opendocument.presentation', + 'ods' => 'application/vnd.oasis.opendocument.spreadsheet', + 'odt' => 'application/vnd.oasis.opendocument.text', + 'oga' => 'audio/ogg', + 'ogg' => 'audio/ogg', + 'ogv' => 'video/ogg', + 'ogx' => 'application/ogg', + 'omdoc' => 'application/omdoc+xml', + 'onepkg' => 'application/onenote', + 'onetmp' => 'application/onenote', + 'onetoc' => 'application/onenote', + 'onetoc2' => 'application/onenote', + 'opf' => 'application/oebps-package+xml', + 'opml' => 'text/x-opml', + 'oprc' => 'application/vnd.palm', + 'org' => 'application/vnd.lotus-organizer', + 'osf' => 'application/vnd.yamaha.openscoreformat', + 'osfpvg' => 'application/vnd.yamaha.openscoreformat.osfpvg+xml', + 'otc' => 'application/vnd.oasis.opendocument.chart-template', + 'otf' => 'application/x-font-otf', + 'otg' => 'application/vnd.oasis.opendocument.graphics-template', + 'oth' => 'application/vnd.oasis.opendocument.text-web', + 'oti' => 'application/vnd.oasis.opendocument.image-template', + 'otp' => 'application/vnd.oasis.opendocument.presentation-template', + 'ots' => 'application/vnd.oasis.opendocument.spreadsheet-template', + 'ott' => 'application/vnd.oasis.opendocument.text-template', + 'oxps' => 'application/oxps', + 'oxt' => 'application/vnd.openofficeorg.extension', + 'p' => 'text/x-pascal', + 'p10' => 'application/pkcs10', + 'p12' => 'application/x-pkcs12', + 'p7b' => 'application/x-pkcs7-certificates', + 'p7c' => 'application/pkcs7-mime', + 'p7m' => 'application/pkcs7-mime', + 'p7r' => 'application/x-pkcs7-certreqresp', + 'p7s' => 'application/pkcs7-signature', + 'p8' => 'application/pkcs8', + 'pas' => 'text/x-pascal', + 'paw' => 'application/vnd.pawaafile', + 'pbd' => 'application/vnd.powerbuilder6', + 'pbm' => 'image/x-portable-bitmap', + 'pcap' => 'application/vnd.tcpdump.pcap', + 'pcf' => 'application/x-font-pcf', + 'pcl' => 'application/vnd.hp-pcl', + 'pclxl' => 'application/vnd.hp-pclxl', + 'pct' => 'image/x-pict', + 'pcurl' => 'application/vnd.curl.pcurl', + 'pcx' => 'image/x-pcx', + 'pdb' => 'application/vnd.palm', + 'pdf' => 'application/pdf', + 'pfa' => 'application/x-font-type1', + 'pfb' => 'application/x-font-type1', + 'pfm' => 'application/x-font-type1', + 'pfr' => 'application/font-tdpfr', + 'pfx' => 'application/x-pkcs12', + 'pgm' => 'image/x-portable-graymap', + 'pgn' => 'application/x-chess-pgn', + 'pgp' => 'application/pgp-encrypted', + 'php' => 'application/x-php', + 'php3' => 'application/x-php', + 'php4' => 'application/x-php', + 'php5' => 'application/x-php', + 'pic' => 'image/x-pict', + 'pkg' => 'application/octet-stream', + 'pki' => 'application/pkixcmp', + 'pkipath' => 'application/pkix-pkipath', + 'plb' => 'application/vnd.3gpp.pic-bw-large', + 'plc' => 'application/vnd.mobius.plc', + 'plf' => 'application/vnd.pocketlearn', + 'pls' => 'application/pls+xml', + 'pml' => 'application/vnd.ctc-posml', + 'png' => 'image/png', + 'pnm' => 'image/x-portable-anymap', + 'portpkg' => 'application/vnd.macports.portpkg', + 'pot' => 'application/vnd.ms-powerpoint', + 'potm' => 'application/vnd.ms-powerpoint.template.macroenabled.12', + 'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template', + 'ppam' => 'application/vnd.ms-powerpoint.addin.macroenabled.12', + 'ppd' => 'application/vnd.cups-ppd', + 'ppm' => 'image/x-portable-pixmap', + 'pps' => 'application/vnd.ms-powerpoint', + 'ppsm' => 'application/vnd.ms-powerpoint.slideshow.macroenabled.12', + 'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow', + 'ppt' => 'application/vnd.ms-powerpoint', + 'pptm' => 'application/vnd.ms-powerpoint.presentation.macroenabled.12', + 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation', + 'pqa' => 'application/vnd.palm', + 'prc' => 'application/x-mobipocket-ebook', + 'pre' => 'application/vnd.lotus-freelance', + 'prf' => 'application/pics-rules', + 'ps' => 'application/postscript', + 'psb' => 'application/vnd.3gpp.pic-bw-small', + 'psd' => 'image/vnd.adobe.photoshop', + 'psf' => 'application/x-font-linux-psf', + 'pskcxml' => 'application/pskc+xml', + 'ptid' => 'application/vnd.pvi.ptid1', + 'pub' => 'application/x-mspublisher', + 'pvb' => 'application/vnd.3gpp.pic-bw-var', + 'pwn' => 'application/vnd.3m.post-it-notes', + 'pya' => 'audio/vnd.ms-playready.media.pya', + 'pyv' => 'video/vnd.ms-playready.media.pyv', + 'qam' => 'application/vnd.epson.quickanime', + 'qbo' => 'application/vnd.intu.qbo', + 'qfx' => 'application/vnd.intu.qfx', + 'qps' => 'application/vnd.publishare-delta-tree', + 'qt' => 'video/quicktime', + 'qwd' => 'application/vnd.quark.quarkxpress', + 'qwt' => 'application/vnd.quark.quarkxpress', + 'qxb' => 'application/vnd.quark.quarkxpress', + 'qxd' => 'application/vnd.quark.quarkxpress', + 'qxl' => 'application/vnd.quark.quarkxpress', + 'qxt' => 'application/vnd.quark.quarkxpress', + 'ra' => 'audio/x-pn-realaudio', + 'ram' => 'audio/x-pn-realaudio', + 'rar' => 'application/x-rar-compressed', + 'ras' => 'image/x-cmu-raster', + 'rcprofile' => 'application/vnd.ipunplugged.rcprofile', + 'rdf' => 'application/rdf+xml', + 'rdz' => 'application/vnd.data-vision.rdz', + 'rep' => 'application/vnd.businessobjects', + 'res' => 'application/x-dtbresource+xml', + 'rgb' => 'image/x-rgb', + 'rif' => 'application/reginfo+xml', + 'rip' => 'audio/vnd.rip', + 'ris' => 'application/x-research-info-systems', + 'rl' => 'application/resource-lists+xml', + 'rlc' => 'image/vnd.fujixerox.edmics-rlc', + 'rld' => 'application/resource-lists-diff+xml', + 'rm' => 'application/vnd.rn-realmedia', + 'rmi' => 'audio/midi', + 'rmp' => 'audio/x-pn-realaudio-plugin', + 'rms' => 'application/vnd.jcp.javame.midlet-rms', + 'rmvb' => 'application/vnd.rn-realmedia-vbr', + 'rnc' => 'application/relax-ng-compact-syntax', + 'roa' => 'application/rpki-roa', + 'roff' => 'text/troff', + 'rp9' => 'application/vnd.cloanto.rp9', + 'rpss' => 'application/vnd.nokia.radio-presets', + 'rpst' => 'application/vnd.nokia.radio-preset', + 'rq' => 'application/sparql-query', + 'rs' => 'application/rls-services+xml', + 'rsd' => 'application/rsd+xml', + 'rss' => 'application/rss+xml', + 'rtf' => 'application/rtf', + 'rtx' => 'text/richtext', + 's' => 'text/x-asm', + 's3m' => 'audio/s3m', + 'saf' => 'application/vnd.yamaha.smaf-audio', + 'sbml' => 'application/sbml+xml', + 'sc' => 'application/vnd.ibm.secure-container', + 'scd' => 'application/x-msschedule', + 'scm' => 'application/vnd.lotus-screencam', + 'scq' => 'application/scvp-cv-request', + 'scs' => 'application/scvp-cv-response', + 'scurl' => 'text/vnd.curl.scurl', + 'sda' => 'application/vnd.stardivision.draw', + 'sdc' => 'application/vnd.stardivision.calc', + 'sdd' => 'application/vnd.stardivision.impress', + 'sdkd' => 'application/vnd.solent.sdkm+xml', + 'sdkm' => 'application/vnd.solent.sdkm+xml', + 'sdp' => 'application/sdp', + 'sdw' => 'application/vnd.stardivision.writer', + 'see' => 'application/vnd.seemail', + 'seed' => 'application/vnd.fdsn.seed', + 'sema' => 'application/vnd.sema', + 'semd' => 'application/vnd.semd', + 'semf' => 'application/vnd.semf', + 'ser' => 'application/java-serialized-object', + 'setpay' => 'application/set-payment-initiation', + 'setreg' => 'application/set-registration-initiation', + 'sfd-hdstx' => 'application/vnd.hydrostatix.sof-data', + 'sfs' => 'application/vnd.spotfire.sfs', + 'sfv' => 'text/x-sfv', + 'sgi' => 'image/sgi', + 'sgl' => 'application/vnd.stardivision.writer-global', + 'sgm' => 'text/sgml', + 'sgml' => 'text/sgml', + 'sh' => 'application/x-sh', + 'shar' => 'application/x-shar', + 'shf' => 'application/shf+xml', + 'sid' => 'image/x-mrsid-image', + 'sig' => 'application/pgp-signature', + 'sil' => 'audio/silk', + 'silo' => 'model/mesh', + 'sis' => 'application/vnd.symbian.install', + 'sisx' => 'application/vnd.symbian.install', + 'sit' => 'application/x-stuffit', + 'sitx' => 'application/x-stuffitx', + 'skd' => 'application/vnd.koan', + 'skm' => 'application/vnd.koan', + 'skp' => 'application/vnd.koan', + 'skt' => 'application/vnd.koan', + 'sldm' => 'application/vnd.ms-powerpoint.slide.macroenabled.12', + 'sldx' => 'application/vnd.openxmlformats-officedocument.presentationml.slide', + 'slt' => 'application/vnd.epson.salt', + 'sm' => 'application/vnd.stepmania.stepchart', + 'smf' => 'application/vnd.stardivision.math', + 'smi' => 'application/smil+xml', + 'smil' => 'application/smil+xml', + 'smv' => 'video/x-smv', + 'smzip' => 'application/vnd.stepmania.package', + 'snd' => 'audio/basic', + 'snf' => 'application/x-font-snf', + 'so' => 'application/octet-stream', + 'spc' => 'application/x-pkcs7-certificates', + 'spf' => 'application/vnd.yamaha.smaf-phrase', + 'spl' => 'application/x-futuresplash', + 'spot' => 'text/vnd.in3d.spot', + 'spp' => 'application/scvp-vp-response', + 'spq' => 'application/scvp-vp-request', + 'spx' => 'audio/ogg', + 'sql' => 'application/x-sql', + 'src' => 'application/x-wais-source', + 'srt' => 'application/x-subrip', + 'sru' => 'application/sru+xml', + 'srx' => 'application/sparql-results+xml', + 'ssdl' => 'application/ssdl+xml', + 'sse' => 'application/vnd.kodak-descriptor', + 'ssf' => 'application/vnd.epson.ssf', + 'ssml' => 'application/ssml+xml', + 'st' => 'application/vnd.sailingtracker.track', + 'stc' => 'application/vnd.sun.xml.calc.template', + 'std' => 'application/vnd.sun.xml.draw.template', + 'stf' => 'application/vnd.wt.stf', + 'sti' => 'application/vnd.sun.xml.impress.template', + 'stk' => 'application/hyperstudio', + 'stl' => 'application/vnd.ms-pki.stl', + 'str' => 'application/vnd.pg.format', + 'stw' => 'application/vnd.sun.xml.writer.template', + 'sub' => 'text/vnd.dvb.subtitle', + 'sus' => 'application/vnd.sus-calendar', + 'susp' => 'application/vnd.sus-calendar', + 'sv4cpio' => 'application/x-sv4cpio', + 'sv4crc' => 'application/x-sv4crc', + 'svc' => 'application/vnd.dvb.service', + 'svd' => 'application/vnd.svd', + 'svg' => 'image/svg+xml', + 'svgz' => 'image/svg+xml', + 'swa' => 'application/x-director', + 'swf' => 'application/x-shockwave-flash', + 'swi' => 'application/vnd.aristanetworks.swi', + 'sxc' => 'application/vnd.sun.xml.calc', + 'sxd' => 'application/vnd.sun.xml.draw', + 'sxg' => 'application/vnd.sun.xml.writer.global', + 'sxi' => 'application/vnd.sun.xml.impress', + 'sxm' => 'application/vnd.sun.xml.math', + 'sxw' => 'application/vnd.sun.xml.writer', + 't' => 'text/troff', + 't3' => 'application/x-t3vm-image', + 'taglet' => 'application/vnd.mynfc', + 'tao' => 'application/vnd.tao.intent-module-archive', + 'tar' => 'application/x-tar', + 'tcap' => 'application/vnd.3gpp2.tcap', + 'tcl' => 'application/x-tcl', + 'teacher' => 'application/vnd.smart.teacher', + 'tei' => 'application/tei+xml', + 'teicorpus' => 'application/tei+xml', + 'tex' => 'application/x-tex', + 'texi' => 'application/x-texinfo', + 'texinfo' => 'application/x-texinfo', + 'text' => 'text/plain', + 'tfi' => 'application/thraud+xml', + 'tfm' => 'application/x-tex-tfm', + 'tga' => 'image/x-tga', + 'thmx' => 'application/vnd.ms-officetheme', + 'tif' => 'image/tiff', + 'tiff' => 'image/tiff', + 'tmo' => 'application/vnd.tmobile-livetv', + 'torrent' => 'application/x-bittorrent', + 'tpl' => 'application/vnd.groove-tool-template', + 'tpt' => 'application/vnd.trid.tpt', + 'tr' => 'text/troff', + 'tra' => 'application/vnd.trueapp', + 'trm' => 'application/x-msterminal', + 'tsd' => 'application/timestamped-data', + 'tsv' => 'text/tab-separated-values', + 'ttc' => 'application/x-font-ttf', + 'ttf' => 'application/x-font-ttf', + 'ttl' => 'text/turtle', + 'twd' => 'application/vnd.simtech-mindmapper', + 'twds' => 'application/vnd.simtech-mindmapper', + 'txd' => 'application/vnd.genomatix.tuxedo', + 'txf' => 'application/vnd.mobius.txf', + 'txt' => 'text/plain', + 'u32' => 'application/x-authorware-bin', + 'udeb' => 'application/x-debian-package', + 'ufd' => 'application/vnd.ufdl', + 'ufdl' => 'application/vnd.ufdl', + 'ulx' => 'application/x-glulx', + 'umj' => 'application/vnd.umajin', + 'unityweb' => 'application/vnd.unity', + 'uoml' => 'application/vnd.uoml+xml', + 'uri' => 'text/uri-list', + 'uris' => 'text/uri-list', + 'urls' => 'text/uri-list', + 'ustar' => 'application/x-ustar', + 'utz' => 'application/vnd.uiq.theme', + 'uu' => 'text/x-uuencode', + 'uva' => 'audio/vnd.dece.audio', + 'uvd' => 'application/vnd.dece.data', + 'uvf' => 'application/vnd.dece.data', + 'uvg' => 'image/vnd.dece.graphic', + 'uvh' => 'video/vnd.dece.hd', + 'uvi' => 'image/vnd.dece.graphic', + 'uvm' => 'video/vnd.dece.mobile', + 'uvp' => 'video/vnd.dece.pd', + 'uvs' => 'video/vnd.dece.sd', + 'uvt' => 'application/vnd.dece.ttml+xml', + 'uvu' => 'video/vnd.uvvu.mp4', + 'uvv' => 'video/vnd.dece.video', + 'uvva' => 'audio/vnd.dece.audio', + 'uvvd' => 'application/vnd.dece.data', + 'uvvf' => 'application/vnd.dece.data', + 'uvvg' => 'image/vnd.dece.graphic', + 'uvvh' => 'video/vnd.dece.hd', + 'uvvi' => 'image/vnd.dece.graphic', + 'uvvm' => 'video/vnd.dece.mobile', + 'uvvp' => 'video/vnd.dece.pd', + 'uvvs' => 'video/vnd.dece.sd', + 'uvvt' => 'application/vnd.dece.ttml+xml', + 'uvvu' => 'video/vnd.uvvu.mp4', + 'uvvv' => 'video/vnd.dece.video', + 'uvvx' => 'application/vnd.dece.unspecified', + 'uvvz' => 'application/vnd.dece.zip', + 'uvx' => 'application/vnd.dece.unspecified', + 'uvz' => 'application/vnd.dece.zip', + 'vcard' => 'text/vcard', + 'vcd' => 'application/x-cdlink', + 'vcf' => 'text/x-vcard', + 'vcg' => 'application/vnd.groove-vcard', + 'vcs' => 'text/x-vcalendar', + 'vcx' => 'application/vnd.vcx', + 'vis' => 'application/vnd.visionary', + 'viv' => 'video/vnd.vivo', + 'vob' => 'video/x-ms-vob', + 'vor' => 'application/vnd.stardivision.writer', + 'vox' => 'application/x-authorware-bin', + 'vrml' => 'model/vrml', + 'vsd' => 'application/vnd.visio', + 'vsf' => 'application/vnd.vsf', + 'vss' => 'application/vnd.visio', + 'vst' => 'application/vnd.visio', + 'vsw' => 'application/vnd.visio', + 'vtu' => 'model/vnd.vtu', + 'vxml' => 'application/voicexml+xml', + 'w3d' => 'application/x-director', + 'wad' => 'application/x-doom', + 'wav' => 'audio/x-wav', + 'wax' => 'audio/x-ms-wax', + 'wbmp' => 'image/vnd.wap.wbmp', + 'wbs' => 'application/vnd.criticaltools.wbs+xml', + 'wbxml' => 'application/vnd.wap.wbxml', + 'wcm' => 'application/vnd.ms-works', + 'wdb' => 'application/vnd.ms-works', + 'wdp' => 'image/vnd.ms-photo', + 'weba' => 'audio/webm', + 'webm' => 'video/webm', + 'webp' => 'image/webp', + 'wg' => 'application/vnd.pmi.widget', + 'wgt' => 'application/widget', + 'wks' => 'application/vnd.ms-works', + 'wm' => 'video/x-ms-wm', + 'wma' => 'audio/x-ms-wma', + 'wmd' => 'application/x-ms-wmd', + 'wmf' => 'application/x-msmetafile', + 'wml' => 'text/vnd.wap.wml', + 'wmlc' => 'application/vnd.wap.wmlc', + 'wmls' => 'text/vnd.wap.wmlscript', + 'wmlsc' => 'application/vnd.wap.wmlscriptc', + 'wmv' => 'video/x-ms-wmv', + 'wmx' => 'video/x-ms-wmx', + 'wmz' => 'application/x-msmetafile', + 'woff' => 'application/font-woff', + 'wpd' => 'application/vnd.wordperfect', + 'wpl' => 'application/vnd.ms-wpl', + 'wps' => 'application/vnd.ms-works', + 'wqd' => 'application/vnd.wqd', + 'wri' => 'application/x-mswrite', + 'wrl' => 'model/vrml', + 'wsdl' => 'application/wsdl+xml', + 'wspolicy' => 'application/wspolicy+xml', + 'wtb' => 'application/vnd.webturbo', + 'wvx' => 'video/x-ms-wvx', + 'x32' => 'application/x-authorware-bin', + 'x3d' => 'model/x3d+xml', + 'x3db' => 'model/x3d+binary', + 'x3dbz' => 'model/x3d+binary', + 'x3dv' => 'model/x3d+vrml', + 'x3dvz' => 'model/x3d+vrml', + 'x3dz' => 'model/x3d+xml', + 'xaml' => 'application/xaml+xml', + 'xap' => 'application/x-silverlight-app', + 'xar' => 'application/vnd.xara', + 'xbap' => 'application/x-ms-xbap', + 'xbd' => 'application/vnd.fujixerox.docuworks.binder', + 'xbm' => 'image/x-xbitmap', + 'xdf' => 'application/xcap-diff+xml', + 'xdm' => 'application/vnd.syncml.dm+xml', + 'xdp' => 'application/vnd.adobe.xdp+xml', + 'xdssc' => 'application/dssc+xml', + 'xdw' => 'application/vnd.fujixerox.docuworks', + 'xenc' => 'application/xenc+xml', + 'xer' => 'application/patch-ops-error+xml', + 'xfdf' => 'application/vnd.adobe.xfdf', + 'xfdl' => 'application/vnd.xfdl', + 'xht' => 'application/xhtml+xml', + 'xhtml' => 'application/xhtml+xml', + 'xhvml' => 'application/xv+xml', + 'xif' => 'image/vnd.xiff', + 'xla' => 'application/vnd.ms-excel', + 'xlam' => 'application/vnd.ms-excel.addin.macroenabled.12', + 'xlc' => 'application/vnd.ms-excel', + 'xlf' => 'application/x-xliff+xml', + 'xlm' => 'application/vnd.ms-excel', + 'xls' => 'application/vnd.ms-excel', + 'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroenabled.12', + 'xlsm' => 'application/vnd.ms-excel.sheet.macroenabled.12', + 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + 'xlt' => 'application/vnd.ms-excel', + 'xltm' => 'application/vnd.ms-excel.template.macroenabled.12', + 'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template', + 'xlw' => 'application/vnd.ms-excel', + 'xm' => 'audio/xm', + 'xml' => 'application/xml', + 'xo' => 'application/vnd.olpc-sugar', + 'xop' => 'application/xop+xml', + 'xpi' => 'application/x-xpinstall', + 'xpl' => 'application/xproc+xml', + 'xpm' => 'image/x-xpixmap', + 'xpr' => 'application/vnd.is-xpr', + 'xps' => 'application/vnd.ms-xpsdocument', + 'xpw' => 'application/vnd.intercon.formnet', + 'xpx' => 'application/vnd.intercon.formnet', + 'xsl' => 'application/xml', + 'xslt' => 'application/xslt+xml', + 'xsm' => 'application/vnd.syncml+xml', + 'xspf' => 'application/xspf+xml', + 'xul' => 'application/vnd.mozilla.xul+xml', + 'xvm' => 'application/xv+xml', + 'xvml' => 'application/xv+xml', + 'xwd' => 'image/x-xwindowdump', + 'xyz' => 'chemical/x-xyz', + 'xz' => 'application/x-xz', + 'yang' => 'application/yang', + 'yin' => 'application/yin+xml', + 'z1' => 'application/x-zmachine', + 'z2' => 'application/x-zmachine', + 'z3' => 'application/x-zmachine', + 'z4' => 'application/x-zmachine', + 'z5' => 'application/x-zmachine', + 'z6' => 'application/x-zmachine', + 'z7' => 'application/x-zmachine', + 'z8' => 'application/x-zmachine', + 'zaz' => 'application/vnd.zzazz.deck+xml', + 'zip' => 'application/zip', + 'zir' => 'application/vnd.zul', + 'zirz' => 'application/vnd.zul', + 'zmm' => 'application/vnd.handheld-entertainment+xml', + '123' => 'application/vnd.lotus-1-2-3', +); diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/preferences.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/preferences.php new file mode 100644 index 0000000..0b430e6 --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/preferences.php @@ -0,0 +1,25 @@ +setCharset('utf-8'); + +// Without these lines the default caching mechanism is "array" but this uses a lot of memory. +// If possible, use a disk cache to enable attaching large attachments etc. +// You can override the default temporary directory by setting the TMPDIR environment variable. +if (@is_writable($tmpDir = sys_get_temp_dir())) { + $preferences->setTempDir($tmpDir)->setCacheType('disk'); +} + +// this should only be done when Swiftmailer won't use the native QP content encoder +// see mime_deps.php +if (PHP_VERSION_ID < 50407) { + $preferences->setQPDotEscape(false); +} diff --git a/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/swift_init.php b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/swift_init.php new file mode 100644 index 0000000..ff71963 --- /dev/null +++ b/user/plugins/email/vendor/swiftmailer/swiftmailer/lib/swift_init.php @@ -0,0 +1,28 @@ + 'application/x-php', + 'php3' => 'application/x-php', + 'php4' => 'application/x-php', + 'php5' => 'application/x-php', + 'zip' => 'application/zip', + 'gif' => 'image/gif', + 'png' => 'image/png', + 'css' => 'text/css', + 'js' => 'text/javascript', + 'txt' => 'text/plain', + 'aif' => 'audio/x-aiff', + 'aiff' => 'audio/x-aiff', + 'avi' => 'video/avi', + 'bmp' => 'image/bmp', + 'bz2' => 'application/x-bz2', + 'csv' => 'text/csv', + 'dmg' => 'application/x-apple-diskimage', + 'doc' => 'application/msword', + 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', + 'eml' => 'message/rfc822', + 'aps' => 'application/postscript', + 'exe' => 'application/x-ms-dos-executable', + 'flv' => 'video/x-flv', + 'gz' => 'application/x-gzip', + 'hqx' => 'application/stuffit', + 'htm' => 'text/html', + 'html' => 'text/html', + 'jar' => 'application/x-java-archive', + 'jpeg' => 'image/jpeg', + 'jpg' => 'image/jpeg', + 'm3u' => 'audio/x-mpegurl', + 'm4a' => 'audio/mp4', + 'mdb' => 'application/x-msaccess', + 'mid' => 'audio/midi', + 'midi' => 'audio/midi', + 'mov' => 'video/quicktime', + 'mp3' => 'audio/mpeg', + 'mp4' => 'video/mp4', + 'mpeg' => 'video/mpeg', + 'mpg' => 'video/mpeg', + 'odg' => 'vnd.oasis.opendocument.graphics', + 'odp' => 'vnd.oasis.opendocument.presentation', + 'odt' => 'vnd.oasis.opendocument.text', + 'ods' => 'vnd.oasis.opendocument.spreadsheet', + 'ogg' => 'audio/ogg', + 'pdf' => 'application/pdf', + 'ppt' => 'application/vnd.ms-powerpoint', + 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation', + 'ps' => 'application/postscript', + 'rar' => 'application/x-rar-compressed', + 'rtf' => 'application/rtf', + 'tar' => 'application/x-tar', + 'sit' => 'application/x-stuffit', + 'svg' => 'image/svg+xml', + 'tif' => 'image/tiff', + 'tiff' => 'image/tiff', + 'ttf' => 'application/x-font-truetype', + 'vcf' => 'text/x-vcard', + 'wav' => 'audio/wav', + 'wma' => 'audio/x-ms-wma', + 'wmv' => 'audio/x-ms-wmv', + 'xls' => 'application/excel', + 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + 'xml' => 'application/xml', + ); + + // wrap array for generating file + foreach ($valid_mime_types_preset as $extension => $mime_type) { + // generate array for mimetype to extension resolver (only first match) + $valid_mime_types[$extension] = "'{$extension}' => '{$mime_type}'"; + } + + // collect extensions + $valid_extensions = array(); + + // all extensions from second match + foreach ($matches[2] as $i => $extensions) { + // explode multiple extensions from string + $extensions = explode(' ', strtolower($extensions)); + + // force array for foreach + if (!is_array($extensions)) { + $extensions = array($extensions); + } + + foreach ($extensions as $extension) { + // get mime type + $mime_type = $matches[1][$i]; + + // check if string length lower than 10 + if (strlen($extension) < 10) { + // add extension + $valid_extensions[] = $extension; + + if (!isset($valid_mime_types[$mime_type])) { + // generate array for mimetype to extension resolver (only first match) + $valid_mime_types[$extension] = "'{$extension}' => '{$mime_type}'"; + } + } + } + } + } + + $xml = simplexml_load_string($mime_xml); + + foreach ($xml as $node) { + // check if there is no pattern + if (!isset($node->glob['pattern'])) { + continue; + } + + // get all matching extensions from match + foreach ((array) $node->glob['pattern'] as $extension) { + // skip none glob extensions + if (strpos($extension, '.') === false) { + continue; + } + + // remove get only last part + $extension = explode('.', strtolower($extension)); + $extension = end($extension); + + // maximum length in database column + if (strlen($extension) <= 9) { + $valid_extensions[] = $extension; + } + } + + if (isset($node->glob['pattern'][0])) { + // mime type + $mime_type = strtolower((string) $node['type']); + + // get first extension + $extension = strtolower(trim($node->glob['ddpattern'][0], '*.')); + + // skip none glob extensions and check if string length between 1 and 10 + if (strpos($extension, '.') !== false || strlen($extension) < 1 || strlen($extension) > 9) { + continue; + } + + // check if string length lower than 10 + if (!isset($valid_mime_types[$mime_type])) { + // generate array for mimetype to extension resolver (only first match) + $valid_mime_types[$extension] = "'{$extension}' => '{$mime_type}'"; + } + } + } + + // full list of valid extensions only + $valid_mime_types = array_unique($valid_mime_types); + ksort($valid_mime_types); + + // combine mime types and extensions array + $output = "$preamble\$swift_mime_types = array(\n ".implode($valid_mime_types, ",\n ")."\n);"; + + // write mime_types.php config file + @file_put_contents('./mime_types.php', $output); +} + +generateUpToDateMimeArray(); diff --git a/user/plugins/error/CHANGELOG.md b/user/plugins/error/CHANGELOG.md new file mode 100644 index 0000000..dbb0d78 --- /dev/null +++ b/user/plugins/error/CHANGELOG.md @@ -0,0 +1,54 @@ +# v1.6.0 +## 10/19/2016 + +1. [](#improved) + * Added Croatian translation + * Improved `autoescape: true` support +1. [](#bugfix) + * Fixed issue where template file for `error` page type is only available if page was not found + +# v1.5.1 +## 07/18/2016 + +1. [](#improved) + * Added chinese and german translations +1. [](#bugfix) + * Fixed issue with the Smartypants plugin running before Twig was processed + +# v1.5.0 +## 07/14/2015 + +1. [](#improved) + * Translate some blueprint configuration options + * Allow translating the error message + * Added french, russian, romanian, danish, italian + +# v1.4.1 +## 12/11/2015 + +1. [](#bugfix) + * Fixed CLI command for PHP 5.5 and lower + +# v1.4.0 +## 11/21/2015 + +1. [](#new) + * Implemented CLI commands for the plugin + +# v1.3.0 +## 08/25/2015 + +1. [](#improved) + * Added blueprints for Grav Admin plugin + +# v1.2.2 +## 01/06/2015 + +1. [](#new) + * Added a default `error.json.twig` file + +# v1.2.1 +## 11/30/2014 + +1. [](#new) + * ChangeLog started... diff --git a/user/plugins/error/LICENSE b/user/plugins/error/LICENSE new file mode 100644 index 0000000..484793a --- /dev/null +++ b/user/plugins/error/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/error/README.md b/user/plugins/error/README.md new file mode 100644 index 0000000..16b2a53 --- /dev/null +++ b/user/plugins/error/README.md @@ -0,0 +1,89 @@ +# Grav Error Plugin + +![GPM Installation](assets/readme_1.png) + +`error` is a [Grav](http://github.com/getgrav/grav) Plugin and allows to redirect errors to nice output pages. + +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 Error 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 error + +This will install the Error plugin into your `/user/plugins` directory within Grav. Its files can be found under `/your/site/grav/user/plugins/error`. + +## 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 `error`. You can find these files either on [GitHub](https://github.com/getgrav/grav-plugin-error) or via [GetGrav.org](http://getgrav.org/downloads/plugins#extras). + +You should now have all the plugin files under + + /your/site/grav/user/plugins/error + +>> NOTE: This plugin is a modular component for Grav which requires [Grav](http://github.com/getgrav/grav), the [Problems](https://github.com/getgrav/grav-plugin-problems) plugin, and a theme to be installed in order to operate. + +# Usage + +The `error` plugin doesn't require any configuration. The moment you install it, it is ready to use. + +Something you might want to do is to override the look and feel of the error page, and with Grav it is super easy. + +### Template + +Copy the template file [error.html.twig](templates/error.html.twig) into the `templates` folder of your custom theme and that is it. + +``` +/your/site/grav/user/themes/custom-theme/templates/error.html.twig +``` + +You can now edit the override and tweak it however you prefer. + +### Page + +Copy the page file [error.md](pages/error.md) into the `pages` folder of your user directory and that is it. + +``` +/your/site/grav/user/pages/error/error.md +``` + +You can now edit the override and tweak it however you prefer. + +# CLI Usage +The `error` plugin comes with a CLI command that outputs the `grav.log` in a beautified way, with possibility of limiting the amount of errors displayed, as well as include the trace in the output. + +### Commands + +| `bin/plugin error log` | | +|------------------------|-----------------------------------------------------------------| +| [ --limit N \| -l N ] | The amount of errors to display. Default is 5 | +| [ --trace \| -t ] | When used, it will add the backtrace in the output of the error | + + +# Updating + +As development for the Error plugin continues, new versions may become available that add additional features and functionality, improve compatibility with newer Grav releases, and generally provide a better user experience. Updating Error is easy, and can be done through Grav's GPM system, as well as manually. + +## GPM Update (Preferred) + +The simplest way to update this plugin is via the [Grav Package Manager (GPM)](http://learn.getgrav.org/advanced/grav-gpm). You can do this with this by navigating to the root directory of your Grav install using your system's Terminal (also called command line) and typing the following: + + bin/gpm update error + +This command will check your Grav install to see if your Error plugin is due for an update. If a newer release is found, you will be asked whether or not you wish to update. To continue, type `y` and hit enter. The plugin will automatically update and clear Grav's cache. + +## Manual Update + +Manually updating Error is pretty simple. Here is what you will need to do to get this done: + +* Delete the `your/site/user/plugins/error` directory. +* Download the new version of the Error plugin from either [GitHub](https://github.com/getgrav/grav-plugin-error) or [GetGrav.org](http://getgrav.org/downloads/plugins#extras). +* Unzip the zip file in `your/site/user/plugins` and rename the resulting folder to `error`. +* Clear the Grav cache. The simplest way to do this is by going to the root Grav directory in terminal and typing `bin/grav clear-cache`. + +> Note: Any changes you have made to any of the files listed under this directory will also be removed and replaced by the new set. Any files located elsewhere (for example a YAML settings file placed in `user/config/plugins`) will remain intact. diff --git a/user/plugins/error/assets/readme_1.png b/user/plugins/error/assets/readme_1.png new file mode 100644 index 0000000..930b87b Binary files /dev/null and b/user/plugins/error/assets/readme_1.png differ diff --git a/user/plugins/error/blueprints.yaml b/user/plugins/error/blueprints.yaml new file mode 100644 index 0000000..6ce715f --- /dev/null +++ b/user/plugins/error/blueprints.yaml @@ -0,0 +1,32 @@ +name: Error +version: 1.6.0 +description: Displays the error page. +icon: warning +author: + name: Team Grav + email: devs@getgrav.org + url: http://getgrav.org +homepage: https://github.com/getgrav/grav-plugin-error +keywords: error, plugin, required +bugs: https://github.com/getgrav/grav-plugin-error/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 + + routes.404: + type: text + size: medium + label: 404 Route + default: '/error' diff --git a/user/plugins/error/cli/LogCommand.php b/user/plugins/error/cli/LogCommand.php new file mode 100644 index 0000000..8a6c69a --- /dev/null +++ b/user/plugins/error/cli/LogCommand.php @@ -0,0 +1,130 @@ + 'green', + 'INFO' => 'cyan', + 'NOTICE' => 'yellow', + 'WARNING' => 'yellow', + 'ERROR' => 'red', + 'CRITICAL' => 'red', + 'ALERT' => 'red', + 'EMERGENCY' => 'magenta' + ]; + + /** + * + */ + protected function configure() + { + $this->logfile = LOG_DIR . 'grav.log'; + $this + ->setName("log") + ->setDescription("Outputs the Error Log") + ->addOption( + 'trace', + 't', + InputOption::VALUE_NONE, + 'Include the errors stack trace in the output' + ) + ->addOption( + 'limit', + 'l', + InputArgument::OPTIONAL, + 'Outputs only the last X amount of errors. Use as --limit 10 / -l 10 [default 5]', + 5 + ) + ->setHelp('The log outputs the Errors Log in Console') + ; + } + + /** + * @return int|null|void + */ + protected function serve() + { + $this->options = [ + 'trace' => $this->input->getOption('trace'), + 'limit' => $this->input->getOption('limit') + ]; + + if (!file_exists($this->logfile)) { + $this->output->writeln("\n" . "Log file not found." . "\n"); + exit; + } + + $log = file_get_contents($this->logfile); + $lines = explode("\n", $log); + + if (!is_numeric($this->options['limit'])) { + $this->options['limit'] = 5; + } + + $lines = array_slice($lines, -($this->options['limit'] + 1)); + + foreach ($lines as $line) { + $this->output->writeln($this->parseLine($line)); + } + } + + /** + * @param $line + * + * @return null|string + */ + protected function parseLine($line) + { + $bit = explode(': ', $line); + $line1 = explode('] ', $bit[0]); + + if (!$line1[0]) { + return null; + } + + $line2 = explode(' - ', $bit[1]); + + $date = $line1[0] . ']'; + $type = str_replace('grav.', '', $line1[1]); + $color = $this->colors[$type]; + $error = $line2[0]; + $trace = implode(': ', array_slice($bit, 2)); + + $output = []; + + $output[] = ''; + $output[] = '' . $date . ''; + $output[] = sprintf(' <%s>%s ' . $error . '', $color, $type, $color); + + if ($this->options['trace']) { + $output[] = ' TRACE: '; + $output[] = ' ' . $trace; + } + + $output[] = '' . str_repeat('-', strlen($date)) . ''; + + return implode("\n", $output); + } +} + diff --git a/user/plugins/error/error.php b/user/plugins/error/error.php new file mode 100644 index 0000000..71b7d35 --- /dev/null +++ b/user/plugins/error/error.php @@ -0,0 +1,65 @@ + ['onPageNotFound', 0], + 'onGetPageTemplates' => ['onGetPageTemplates', 0], + 'onTwigTemplatePaths' => ['onTwigTemplatePaths', -10] + ]; + } + + /** + * Display error page if no page was found for the current route. + * + * @param Event $event + */ + public function onPageNotFound(Event $event) + { + /** @var Pages $pages */ + $pages = $this->grav['pages']; + + // Try to load user error page. + $page = $pages->dispatch($this->config->get('plugins.error.routes.404', '/error'), true); + + if (!$page) { + // If none provided use built in error page. + $page = new Page; + $page->init(new \SplFileInfo(__DIR__ . '/pages/error.md')); + } + + $event->page = $page; + $event->stopPropagation(); + } + + /** + * Add page template types. + */ + public function onGetPageTemplates(Event $event) + { + /** @var Types $types */ + $types = $event->types; + $types->register('error'); + } + + /** + * Add current directory to twig lookup paths. + */ + public function onTwigTemplatePaths() + { + $this->grav['twig']->twig_paths[] = __DIR__ . '/templates'; + } +} diff --git a/user/plugins/error/error.yaml b/user/plugins/error/error.yaml new file mode 100644 index 0000000..0a51d4c --- /dev/null +++ b/user/plugins/error/error.yaml @@ -0,0 +1,3 @@ +enabled: true +routes: + 404: '/error' diff --git a/user/plugins/error/languages.yaml b/user/plugins/error/languages.yaml new file mode 100644 index 0000000..fba0c48 --- /dev/null +++ b/user/plugins/error/languages.yaml @@ -0,0 +1,37 @@ +en: + PLUGIN_ERROR: + ERROR: "Error" + ERROR_MESSAGE: "Woops. Looks like this page doesn't exist." +de: + PLUGIN_ERROR: + ERROR: "Fehler" + ERROR_MESSAGE: "Uuups. Sieht aus als ob diese Seite nicht existiert." +hr: + PLUGIN_ERROR: + ERROR: "Greška" + ERROR_MESSAGE: "Uups. Izgleda da ova stranica ne postoji." + +ro: + PLUGIN_ERROR: + ERROR: "Eroare" + ERROR_MESSAGE: "Ooops. Se pare că pagina nu există." +fr: + PLUGIN_ERROR: + ERROR: "Erreur" + ERROR_MESSAGE: "Oups. Il semble que cette page n’existe pas." +it: + PLUGIN_ERROR: + ERROR: "Errore" + ERROR_MESSAGE: "Ooops. A quanto pare, questa pagina non esiste." +ru: + PLUGIN_ERROR: + ERROR: "Ошибка" + ERROR_MESSAGE: "Упс. Похоже, этой страницы не существует." +da: + PLUGIN_ERROR: + ERROR: "Fejl" + ERROR_MESSAGE: "Ups. Det ser ud til at siden ikke eksisterer." +zh: + PLUGIN_ERROR: + ERROR: "错误" + ERROR_MESSAGE: "呃,似乎这个页面不存在。" diff --git a/user/plugins/error/pages/error.md b/user/plugins/error/pages/error.md new file mode 100644 index 0000000..615b50c --- /dev/null +++ b/user/plugins/error/pages/error.md @@ -0,0 +1,13 @@ +--- +title: Page not Found +robots: noindex,nofollow +template: error +routable: false +http_response_code: 404 +twig_first: true +process: + twig: true +--- + +{{ 'PLUGIN_ERROR.ERROR_MESSAGE'|t }} + diff --git a/user/plugins/error/templates/error.html.twig b/user/plugins/error/templates/error.html.twig new file mode 100644 index 0000000..420702b --- /dev/null +++ b/user/plugins/error/templates/error.html.twig @@ -0,0 +1,3 @@ +

                                                                      {{ 'PLUGIN_ERROR.ERROR'|t }} {{ header.http_response_code }}

                                                                      + +

                                                                      {{ page.content|raw }}

                                                                      diff --git a/user/plugins/error/templates/error.json.twig b/user/plugins/error/templates/error.json.twig new file mode 100644 index 0000000..27472f1 --- /dev/null +++ b/user/plugins/error/templates/error.json.twig @@ -0,0 +1 @@ +{{ page.content|json_encode()|raw }} \ No newline at end of file diff --git a/user/plugins/form/.eslintrc b/user/plugins/form/.eslintrc new file mode 100644 index 0000000..1e57de5 --- /dev/null +++ b/user/plugins/form/.eslintrc @@ -0,0 +1,165 @@ +{ + "env": { + "browser": true, + "node": true + }, + + "parserOptions": { + "ecmaVersion": 6, + "sourceType": "module" + }, + + "rules": { + "accessor-pairs": 2, + "array-bracket-spacing": 0, + "block-scoped-var": 0, + "brace-style": [2, "1tbs", { "allowSingleLine": true }], + "camelcase": 0, + "comma-dangle": [2, "never"], + "comma-spacing": [2, { "before": false, "after": true }], + "comma-style": [2, "last"], + "complexity": 0, + "computed-property-spacing": 0, + "consistent-return": 0, + "consistent-this": 0, + "constructor-super": 2, + "curly": [2, "multi-line"], + "default-case": 0, + "dot-location": [2, "property"], + "dot-notation": 0, + "eol-last": 2, + "eqeqeq": [2, "allow-null"], + "func-names": 0, + "func-style": 0, + "generator-star-spacing": [2, { "before": true, "after": true }], + "guard-for-in": 0, + "handle-callback-err": [2, "^(err|error)$" ], + "indent": [2, 4, { "SwitchCase": 1 }], + "key-spacing": [2, { "beforeColon": false, "afterColon": true }], + "linebreak-style": 0, + "lines-around-comment": 0, + "max-nested-callbacks": 0, + "new-cap": [2, { "newIsCap": true, "capIsNew": false }], + "new-parens": 2, + "newline-after-var": 0, + "no-alert": 0, + "no-array-constructor": 2, + "no-caller": 2, + "no-catch-shadow": 0, + "no-cond-assign": 2, + "no-console": 0, + "no-constant-condition": 0, + "no-continue": 0, + "no-control-regex": 2, + "no-debugger": 2, + "no-delete-var": 2, + "no-div-regex": 0, + "no-dupe-args": 2, + "no-dupe-keys": 2, + "no-duplicate-case": 2, + "no-else-return": 0, + "no-empty": 0, + "no-empty-character-class": 2, + "no-eq-null": 0, + "no-eval": 2, + "no-ex-assign": 2, + "no-extend-native": 2, + "no-extra-bind": 2, + "no-extra-boolean-cast": 2, + "no-extra-parens": 0, + "no-extra-semi": 0, + "no-fallthrough": 2, + "no-floating-decimal": 2, + "no-func-assign": 2, + "no-implied-eval": 2, + "no-inline-comments": 0, + "no-inner-declarations": [2, "functions"], + "no-invalid-regexp": 2, + "no-irregular-whitespace": 2, + "no-iterator": 2, + "no-label-var": 2, + "no-labels": 2, + "no-lone-blocks": 2, + "no-lonely-if": 0, + "no-loop-func": 0, + "no-mixed-requires": 0, + "no-mixed-spaces-and-tabs": 2, + "no-multi-spaces": 2, + "no-multi-str": 2, + "no-multiple-empty-lines": [2, { "max": 1 }], + "no-native-reassign": 2, + "no-negated-in-lhs": 2, + "no-nested-ternary": 0, + "no-new": 2, + "no-new-func": 0, + "no-new-object": 2, + "no-new-require": 2, + "no-new-wrappers": 2, + "no-obj-calls": 2, + "no-octal": 2, + "no-octal-escape": 2, + "no-param-reassign": 0, + "no-path-concat": 0, + "no-process-env": 0, + "no-process-exit": 0, + "no-proto": 0, + "no-redeclare": 2, + "no-regex-spaces": 2, + "no-restricted-modules": 0, + "no-return-assign": 2, + "no-script-url": 0, + "no-self-compare": 2, + "no-sequences": 2, + "no-shadow": 0, + "no-shadow-restricted-names": 2, + "no-spaced-func": 2, + "no-sparse-arrays": 2, + "no-sync": 0, + "no-ternary": 0, + "no-this-before-super": 2, + "no-throw-literal": 2, + "no-trailing-spaces": 2, + "no-undef": 2, + "no-undef-init": 2, + "no-undefined": 0, + "no-underscore-dangle": 0, + "no-unexpected-multiline": 2, + "no-unneeded-ternary": 2, + "no-unreachable": 2, + "no-unused-expressions": 0, + "no-unused-vars": [2, { "vars": "all", "args": "none" }], + "no-use-before-define": 0, + "no-var": 0, + "no-void": 0, + "no-warning-comments": 0, + "no-with": 2, + "object-curly-spacing": 0, + "object-shorthand": 0, + "one-var": [2, { "initialized": "never" }], + "operator-assignment": 0, + "operator-linebreak": [2, "after", { "overrides": { "?": "before", ":": "before" } }], + "padded-blocks": 0, + "prefer-const": 0, + "quote-props": 0, + "quotes": [2, "single", "avoid-escape"], + "radix": 2, + "semi": [2, "always"], + "semi-spacing": 0, + "sort-vars": 0, + "keyword-spacing": [2, {"after": true, "overrides": {"throw": { "after": true}, "return": { "before": true }}}], + "space-before-blocks": [2, "always"], + "space-before-function-paren": [2, "never"], + "space-in-parens": [2, "never"], + "space-infix-ops": 2, + "space-unary-ops": [2, { "words": true, "nonwords": false }], + "spaced-comment": [2, "always", { "markers": ["global", "globals", "eslint", "eslint-disable", "*package", "!"] }], + "strict": 0, + "use-isnan": 2, + "valid-jsdoc": 0, + "valid-typeof": 2, + "vars-on-top": 0, + "wrap-iife": [2, "any"], + "wrap-regex": 0, + "yoda": [2, "never"] + } +} diff --git a/user/plugins/form/.gitignore b/user/plugins/form/.gitignore new file mode 100644 index 0000000..1df656a --- /dev/null +++ b/user/plugins/form/.gitignore @@ -0,0 +1,5 @@ +# OS Generated +.DS_Store* +/.idea +node_modules +*.js.map diff --git a/user/plugins/form/CHANGELOG.md b/user/plugins/form/CHANGELOG.md new file mode 100644 index 0000000..6942049 --- /dev/null +++ b/user/plugins/form/CHANGELOG.md @@ -0,0 +1,559 @@ +# v2.11.2 +## 01/22/2018 + +1. [](#new) + * Added support for markdown in all form fields for `label`, `help`, and `description` when `markdown: true` is set on field + +# v2.11.1 +## 12/18/2017 + +1. [](#improved) + * Updated default fields to make them more consistent with class names + +# v2.11.0 +## 12/05/2017 + +1. [](#new) + * Added ability to set `novalidate: true` on form definition to turn off all HTML5 form validation +1. [](#improved) + * Improved logic to handle dynamically added forms to be more reliable + * Added Dutch Translation [#207](https://github.com/getgrav/grav-plugin-form/pull/207) + * Improved both HTML and JSON error output by utilizing `form.status` + * Code Cleanup +1. [](#bugfix) + * Fix AJAX response message and wrong status [#211](https://github.com/getgrav/grav-plugin-form/pull/211) + * Escaped YAML to form save action to prevent parsing errors [#206](https://github.com/getgrav/grav-plugin-form/pull/206) + * Fixed RU translations [#204](https://github.com/getgrav/grav-plugin-form/pull/204) + * Fixed nonce check fail not setting status to `error` [#213](https://github.com/getgrav/grav-plugin-form/issues/213) + * Fixed validation fail not setting status to `error` [#209](https://github.com/getgrav/grav-plugin-form/issues/209) + * Catch ValidationException to avoid potential fatal error + * Fixed regression issue on reset fields + * Removed `required` attribute in individual checkboxes as it forces all to be checked + * Security fix to ensure file uploads are not manipulated mid-post - thnx @FLH! + +# v2.10.0 +## 10/26/2017 + +1. [](#new) + * Added ability to 'remember' field values in cookie between submissions [#200](https://github.com/getgrav/grav-plugin-form/pull/200) +1. [](#improved) + * Added back improved `filesize` option that falls back to PHP file upload limits by default [#202](https://github.com/getgrav/grav-plugin-form/issues/202) + * Added missing file upload options into blueprints and language files + * Added the ability for a form to have an `http_response_code` and use it for `form-messages.html.twig` (requires Grav v1.3.6+) + +# v2.9.3 +## 10/11/2017 + +1. [](#improved) + * Removed `filesize` plugin configuration in favor of `system.media.upload_limit` + * Consolidated `field.classes` and `field.wrapper_classes` in radio/checkbox/checkboxes [#193](https://github.com/getgrav/grav-plugin-form/issues/) + * Remove trailing slash from form action [#195](https://github.com/getgrav/grav-plugin-form/issues/195) + * Improved `honeypot` validation check [#198](https://github.com/getgrav/grav-plugin-form/issues/198) + +# v2.9.2 +## 09/30/2017 + +1. [](#improved) + * Improved Polish translation +1. [](#bugfix) + * Added missing `@input: false` attributes to some non-display fields [#189](https://github.com/getgrav/grav-plugin-form/issues/189) + +# v2.9.1 +## 09/14/2017 + +1. [](#bugfix) + * Fixed backwards compatibility issue with conditional field [#188](https://github.com/getgrav/grav-plugin-form/pull/188) + +# v2.9.0 +## 09/07/2017 + +1. [](#new) + * Added **Refresh Prevention** capabilities (Not enabled by default) [#184](https://github.com/getgrav/grav-plugin-form/issues/184) + * Added support for field `attributes` [#176](https://github.com/getgrav/grav-plugin-form/pull/176) + * Added global variables for setting form classes + * Added support for new `select_optgroup` form field [#165](https://github.com/getgrav/grav-plugin-form/issues/165) +1. [](#improved) + * Moved messages output into partial to allow style overriding + * Logic cleanup + * Updated Italian and Russian translations +1. [](#bugfix) + * Fixed an issue with conditional field not always displaying properly + * Only add Twig form variable if not already set + * Fixed issue with multiple forms on a page failing on Captcha client-side validation [#182](https://github.com/getgrav/grav-plugin-form/issues/182) + * Fixed issue with Ajax forms return full form HTML on error [#163](https://github.com/getgrav/grav-plugin-form/issues/163) + +# v2.8.2 +## 08/18/2017 + +1. [](#new) + * Added new `columns` and `column` fields for controlled form layout + +# v2.8.1 +## 08/15/2017 + +1. [](#improved) + * Added extra class support to the default field for more flexible styling + +# v2.8.0 +## 07/16/2017 + +1. [](#bugfix) + * Fixed a typo in the spanish translation [#167](https://github.com/getgrav/grav-plugin-form/pull/167) + +# v2.8.0-rc.2 +## 06/22/2017 + +1. [](#improved) + * Add default client-side validation for captcha, with error popup [#139](https://github.com/getgrav/grav-plugin-form/issues/139) + * Added key observe for select + * Added Czech translation +1. [](#bugfix) + * Bug fix for radio type form field [#154](https://github.com/getgrav/grav-plugin-form/pull/154) + * Remove double escaping [#155](https://github.com/getgrav/grav-plugin-form/issues/154) + +# v2.8.0-rc.1 +## 05/22/2017 + +1. [](#new) + * Bundled as RC release for Grav/Admin RC releases + +# v2.7.1 +## 05/22/2017 + +1. [](#improved) + * Force modular sub-pages with forms to set `$never_cache_twig = true` to improve form processing reliability [#153](https://github.com/getgrav/grav-plugin-form/issues/153) + * Use new `Utils::getPagePathFromToken()` method + +# v2.7.0 +## 05/16/2017 + +1. [](#bugfix) + * Fix issue with dynamically added forms (Registration, Profile, Comments, etc) not processed [#149](https://github.com/getgrav/grav-plugin-form/issues/149) + * Fixed issue with nested values not being repopulated on form error [#140](https://github.com/getgrav/grav-plugin-form/issues/140) + +# v2.6.0 +## 05/04/2017 + +1. [](#new) + * Allow form item replacement in redirect location [#144](https://github.com/getgrav/grav-plugin-form/issues/144) +1. [](#bugfix) + * Fix regression with file uploads introduced in 2.5.0 + +# v2.5.0 +## 04/24/2017 + +1. [](#new) + * Support proper form handling with nested fields [#141](https://github.com/getgrav/grav-plugin-form/issues/141) +1. [](#bugfix) + * Added check for valid Grav forms before trying to create a form object + +# v2.4.0 +## 04/19/2017 + +1. [](#new) + * Added the ability for front-end forms to use advanced blueprint features such as `data-*@` and `config-*@` + * Added support for dynamically added pages to process forms properly + * Added a new avatar field for displaying account avatar + * Added method to get all `data` from a form + * Support `task` in button types +1. [](#improved) + * Added `step` to range field [#136](https://github.com/getgrav/grav-plugin-form/issues/136) + * Added a new default ajax handler twig template + * Moved twig events to always process even if forms are not defined + * Some code cleanup + * Handle `null` with session-based form + * Added support for append/prepend to number field +1. [](#bugfix) + * Always process form events as long as a `$_POST` exists [login #101](https://github.com/getgrav/grav-plugin-login/issues/101) + * Various fixes for `file` field + * Allow manually added pages to process forms and upload files + * Fixed issue with nested fileds not showing up in `data.*.twig` templates + +# v2.3.1 +## 03/23/2017 + +1. [](#bugfix) + * Only include `outerclasses` DIV if defined [#135](https://github.com/getgrav/grav-plugin-form/issues/135) + +# v2.3.0 +## 03/17/2017 + +1. [](#new) + * Ability to process any form on any page via `action:`. Super useful if you want to handle form processing on some other non-form page (or Ajax) + * Added the ability for the form to set the `template:` to use to render the form processing response. +1. [](#bugfix) + * Fix `number` field so it works with min value `0` [#130](https://github.com/getgrav/grav-plugin-form/issues/130) + +# v2.2.0 +## 03/13/2017 + +1. [](#new) + * Added new `fieldset` form field [#125](https://github.com/getgrav/grav-plugin-form/issues/125) + * Added new `conditional form field` to show fields only if some `condition` is set +1. [](#improved) + * Added the option to have outer-classes on buttons [#124](https://github.com/getgrav/grav-plugin-form/issues/124) + * Added the option to disable fields label if not defined [#126](https://github.com/getgrav/grav-plugin-form/issues/126) + +# v2.1.1 +## 02/17/2017 + +1. [](#improved) + * Better default output for select, checkbox and checkboxes fields in the form destination page and in the emails sent via form submit [#121](https://github.com/getgrav/grav-plugin-form/issues/121) + + +# v2.1.0 +## 02/10/2017 + +1. [](#improved) + * Reworked logic so form caching is based on `Pages::getPagesCacheId()` + * Added `url` option for button field +1. [](#bugfix) + * Fixed issue with `honeypot` field not throwing exception properly + +# v2.0.10 +## 02/08/2017 + +1. [](#improved) + * Optimistically set 'status' to `success` when requesting a form via Ajax. Form processing listeners should take care of setting status to something else +1. [](#bugfix) + * File uploads are now adding a `__form-file-uploader__` POST field to better allow identifying them with Ajax + * Require jQuery when using the File field, as it's needed by the form.min.js file required in the file upload functionality + +# v2.0.9 +## 01/24/2017 + +1. [](#bugfix) + * Translate the labels in data.html.twig [https://github.com/getgrav/grav-plugin-comments/issues/38](https://github.com/getgrav/grav-plugin-comments/issues/38) + * Fixed file input when `System` > `Twig` > `Autoescape` is set to `Yes` + +# v2.0.8 +## 12/13/2016 + +1. [](#new) + * RC released as stable + * Added a new `honeypot` field for form anti-spam protection + +# v2.0.8-rc.1 +## 11/26/2016 + +1. [](#bugfix) + * Fixed Forms 2.0 changes for registration form [#101](https://github.com/getgrav/grav-plugin-form/issues/101) + * Fixed errant reference to Grav DI container in Form#getPagePathFromToken [#105](https://github.com/getgrav/grav-plugin-form/issues/105) + * Fixed issue with spacer fields being displayed first, not in order [#104](https://github.com/getgrav/grav-plugin-form/issues/104) + +# v2.0.7 +## 11/17/2016 + +1. [](#improved) + * Added method to set all data in a form + * Added params to form action URL + * Added ability to add ids to buttons and to set them disabled +1. [](#bugfix) + * Moved Files Upload GC logic to function in front-end only + +# v2.0.6 +## 10/19/2016 + +1. [](#bugfix) + * Fixed translations for `display` field + * Fixed [#95](https://github.com/getgrav/grav-plugin-form/issues/95) multilanguage forms submission + * Fixed duplicate textarea class tag [#98](https://github.com/getgrav/grav-plugin-form/issues/98) + +# v2.0.5 +## 09/15/2016 + +1. [](#bugfix) + * Fix passing updating the header through event, no need for return value + +# v2.0.4 +## 09/15/2016 + +1. [](#improved) + * Allow filling the page header form dynamically (e.g. use case: Comments plugin) + +# v2.0.3 +## 09/12/2016 + +1. [](#improved) + * Use `Page::slug()` for form name if not set in the form itself (better backwards compatibility) + +# v2.0.2 +## 09/08/2016 + +1. [](#improved) + * Added support for Grav's autoescape twig setting + * Allow to add additional markup fields in form and field twig overrides + * Updated the french language translation + +# v2.0.1 +## 09/07/2016 + +1. [](#bugfix) + * Fixed a backwards compatibility issue with Admin forms + +# v2.0.0 +## 09/07/2016 + +1. [](#new) + * Forms now supports multiple forms per page! + * Access forms from any other page within the current page + * Instantiate forms directly in page content with Twig processing enabled + * New Twig function to get forms data from any other page + * Ability to use Twig in saved filename + * Reworked the `file` field. All files get uploaded via Ajax and are stored upon Submit. Fully backward compatible, `file` field now includes also a `limit` and `filesize` option. The former determines how many files are allowed to be uploaded when in combination with `multiple: true` (default: 10), the latter determines the file size limit (in MB) allowed for each file (default: 5MB) +1. [](#improved) + * Added several missing HTML5 form input field types [#87](https://github.com/getgrav/grav-plugin-form/issues/87) + * Added Support for CSS id in form definition + +# v1.3.2 +## 08/10/2016 + +1. [](#improved) + * Added Romanian translation +1. [](#bugfix) + * Fixed an issue with Recaptcha secret throwing errors [#84](https://github.com/getgrav/grav-plugin-form/pull/84) + +# v1.3.1 +## 07/27/2016 + +1. [](#improved) + * Added support for multiple emails in `email` field (add `multiple: true` to enable) +1. [](#bugfix) + * Fixed backward incompatibility with forms submission and data retrieval [getgrav/grav#933](https://github.com/getgrav/grav/issues/933) + +# v1.3.0 +## 07/14/2016 + +1. [](#improved) + * When uploading a file through a form, if the file is already existing prepend the current day and time to the filename instead of overwriting it. + +# v1.3.0-rc.4 +## 06/21/2016 + +1. [](#bugfix) + * Fixed running on Grav 1.0.x + +# v1.3.0-rc.3 +## 06/17/2016 + +1. [](#new) + * Set hints for checkboxes options and allow field descriptions + +# v1.3.0-rc.2 +## 06/08/2016 + +1. [](#new) + * Allow to process Twig in a hidden field, by setting `evaluate: true` + +# v1.3.0-rc.1 +## 06/01/2016 + +1. [](#improved) + * French updated + +# v1.3.0-beta.6 +## 05/23/2016 + +1. [](#new) + * Added support for advanced blueprint functionality in forms + * Added site-wide form options to set Google Captcha site + secret keys [#34](https://github.com/getgrav/grav-plugin-form/pull/34) + * Session-based 'flash' storage of form for redirects [#48](https://github.com/getgrav/grav-plugin-form/issues/48) + * Added ability to **append** to file if you include a `process: save: body:` template attribute [#65](https://github.com/getgrav/grav-plugin-form/issues/65) +1. [](#improved) + * Support `keyname` form format like admin forms + * Added backwards compatibility for Captcha field + * Added 'markdown-notices' style output for better errors + * Added `Forms::getValue()` method to retrieve values programatically + * Changed `datetime` form field to simply extend `text` until implemented + * Updated french language +1. [](#bugfix) + * Refactored the files upload logic + * Missing Language string + * Fixed errors not getting output + +# v1.3.0-beta.5 +## 05/12/2016 + +1. [](#improved) + * Moved form/field.html.twig file to the default folder, to be more easily extended in themes + +# v1.3.0-beta.4 +## 05/04/2016 + +1. [](#new) + * Added support for `prepend` and `append` field attributes for Text input + +# v1.3.0-beta.3 +## 05/03/2016 + +1. [](#bugfix) + * Fix for select field admin translation + +# v1.3.0-beta.2 +## 04/27/2016 + +1. [](#bugfix) + * Fix for autoescape in spacer and display form fields + * Fix issue with form reset action [#66](https://github.com/getgrav/grav-plugin-form/pull/66) + +# v1.3.0-beta.1 +## 04/20/2016 + +1. [](#new) + * Added the HTML5 `range` input field with `min` and `max` parameters +1. [](#improved) + * Allow to override classes in Form definition for the form element + * Add more blocks in the Form twig template, so classes can be overridden more easily in themes + * Reworked some fields to fit the new Admin + * Use `scope` for form fields to allow fields to be excluded from the data by adding `input@: false` to their definition + * Added german translation + * Allow to add inline Twig to the form message definition +1. [](#bugfix) + * Fixed the form action URL for home page forms + * Fix stopping form events propagation, correctly stop when one event is stopped + * Allow to translate the fields placeholders and the form message + * Fix captcha javascript function ordering. Also, render it in the site active language + * Support attribute `for="id"` on label for checkbox + * Fix select fields with the multiple option enabled + * Fixed select options escaping with autoescape on - [#502](https://github.com/getgrav/grav-plugin-admin/issues/502) + +# v1.2.2 +## 02/11/2016 + +1. [](#bugfix) + * Fixed case issue when including form file. + +# v1.2.1 +## 02/11/2016 + +1. [](#new) + * Allow placeholder for **select** field +1. [](#improved) + * Use common language strings in blueprints + * Use `for` attribute in labels + * Improved `README.md` + * Code lint +1. [](#bugfix) + * Moved `nl2br` to correct place or will break for arrays + +# v1.2.0 +## 01/06/2016 + +1. [](#bugfix) + * Correctly merge the file field configuration + * restore full file information save + +# v1.1.0 +## 12/18/2015 + +1. [](#new) + * Croatian translation + * Added id, style, and disabled options to select fields +1. [](#improved) + * Allow adding form labels and help text as lang strings + * Allow translating field content + * Allow translating button and checkbox labels + * Allow adding classes to the form field container with `field.outerclasses` + * Updated French translation +1. [](#bugfix) + * Fixed error message on file upload + * Fixed overriding defaults for the file type in forms + +# v1.0.3 +## 12/11/2015 + +1. [](#improved) + * Updated languages + * Allow an action to stop processing +1. [](#bugfix) + * Fix captcha validation + * Fix issue where Form was unsetting valid page + +# v1.0.2 +## 12/01/2015 + +1. [](#bugfix) + * Fixed merge of defaults settings + * Support for arrays in `data.txt.twig` + * Fixed blueprint for admin + +# v1.0.1 +## 12/01/2015 + +1. [](#new) + * New **file upload** field + * Added modular form template + * Spanish translation + * Hungarian translation + * Italian translation + +# v1.0.0 +## 11/21/2015 + +1. [](#new) + * Server-side validation of forms #11 + * Added french translation + * Added **nonce** form security +1. [](#improved) + * Show a more meaningful error when the display page is not found + * Added links to learn site for form examples + * Label can be omitted + * Allow user to set the CSS class for buttons +1. [](#bugfix) + * Fixed multi-language forms + * Checkbox is translatable + * Minor fixes + +# v0.6.0 +## 10/21/2015 + +1. [](#bugfix) + * Fixed for missing attributes in textarea field + * Fixed checkbox inputs + +# v0.5.0 +## 10/15/2015 + +1. [](#new) + * New `operation` param to allow different file saving strategies + * Ability to add new file saving strategies + * Now calls a `process()` method during form processing +1. [](#improved) + * Added server-side captcha validation and removed front-end validation + * Allow `filename` instead of `prefix`, `format` + `extension` +1. [](#bugfix) + * Fixed radio inputs + +# v0.4.0 +## 9/16/2015 + +1. [](#new) + * PHP server-side form validation + * Added new Google Catpcha field with front-end validation +1. [](#improved) + * Add defaults for forms, moved from the themes to the Form plugin + * Store multi-line fields with line endings converted to HTML + +# v0.3.0 +## 9/11/2015 + +1. [](#improved) + * Refactored all the forms fields + +# v0.2.1 +## 08/24/2015 + +1. [](#improved) + * Translated tooltips + +# 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/form/LICENSE b/user/plugins/form/LICENSE new file mode 100644 index 0000000..484793a --- /dev/null +++ b/user/plugins/form/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/form/README.md b/user/plugins/form/README.md new file mode 100644 index 0000000..fb9e682 --- /dev/null +++ b/user/plugins/form/README.md @@ -0,0 +1,29 @@ +# Grav Form Plugin + +The **form plugin** for [Grav](http://github.com/getgrav/grav) adds the ability to create and use forms. This is currently used extensively by the **admin** and **login** plugins. + +# Installation + +The form plugin is easy to install with GPM. + +``` +$ bin/gpm install form +``` + +# Configuration + +Simply copy the `user/plugins/form/form.yaml` into `user/config/plugins/form.yaml` and make your modifications. + +``` +enabled: true +``` + +# How to use the Form Plugin + +The Learn site has two pages describing how to use the Form Plugin: +- [Forms](http://learn.getgrav.org/advanced/forms) +- [Add a contact form](http://learn.getgrav.org/forms/forms/example-form) + +# Using email + +Note: when using email functionality in your forms, make sure you have configured the Email plugin correctly. In particular, make sure you configured the "Email from" and "Email to" email addresses in the Email plugin with your email address diff --git a/user/plugins/form/app/main.js b/user/plugins/form/app/main.js new file mode 100644 index 0000000..f0f2a6a --- /dev/null +++ b/user/plugins/form/app/main.js @@ -0,0 +1,289 @@ +import $ from 'jquery'; +import Dropzone from 'dropzone'; +import { config, translations } from 'grav-form'; + +let request = {}; + +// translations +const Dictionary = { + dictCancelUpload: translations.PLUGIN_FORM.DROPZONE_CANCEL_UPLOAD, + dictCancelUploadConfirmation: translations.PLUGIN_FORM.DROPZONE_CANCEL_UPLOAD_CONFIRMATION, + dictDefaultMessage: translations.PLUGIN_FORM.DROPZONE_DEFAULT_MESSAGE, + dictFallbackMessage: translations.PLUGIN_FORM.DROPZONE_FALLBACK_MESSAGE, + dictFallbackText: translations.PLUGIN_FORM.DROPZONE_FALLBACK_TEXT, + dictFileTooBig: translations.PLUGIN_FORM.DROPZONE_FILE_TOO_BIG, + dictInvalidFileType: translations.PLUGIN_FORM.DROPZONE_INVALID_FILE_TYPE, + dictMaxFilesExceeded: translations.PLUGIN_FORM.DROPZONE_MAX_FILES_EXCEEDED, + dictRemoveFile: translations.PLUGIN_FORM.DROPZONE_REMOVE_FILE, + dictRemoveFileConfirmation: translations.PLUGIN_FORM.DROPZONE_REMOVE_FILE_CONFIRMATION, + dictResponseError: translations.PLUGIN_FORM.DROPZONE_RESPONSE_ERROR +}; + +Dropzone.autoDiscover = false; + +const DropzoneMediaConfig = { + createImageThumbnails: { thumbnailWidth: 150 }, + addRemoveLinks: false, + dictDefaultMessage: Dictionary.dictDefaultMessage, + dictRemoveFileConfirmation: Dictionary.dictRemoveFileConfirmation, + previewTemplate: ` +
                                                                      +
                                                                      + +
                                                                      +
                                                                      +
                                                                      +
                                                                      +
                                                                      +
                                                                      + + + +
                                                                      + + + + Check + Created with Sketch. + + + + + + +
                                                                      +
                                                                      + + + + error + Created with Sketch. + + + + + + + +
                                                                      +
                                                                      `.trim() +}; + +export default class FilesField { + constructor({ container = '.dropzone.files-upload', options = {} } = {}) { + this.container = $(container); + if (!this.container.length) { return; } + + this.urls = {}; + this.options = Object.assign({}, Dictionary, DropzoneMediaConfig, { + klass: this, + url: this.container.data('file-url-add') || config.current_url, + acceptedFiles: this.container.data('media-types'), + init: this.initDropzone + }, this.container.data('dropzone-options'), options); + + this.dropzone = new Dropzone(container, this.options); + this.dropzone.on('complete', this.onDropzoneComplete.bind(this)); + this.dropzone.on('success', this.onDropzoneSuccess.bind(this)); + this.dropzone.on('removedfile', this.onDropzoneRemovedFile.bind(this)); + this.dropzone.on('sending', this.onDropzoneSending.bind(this)); + this.dropzone.on('error', this.onDropzoneError.bind(this)); + } + + initDropzone() { + let files = this.options.klass.container.find('[data-file]'); + let dropzone = this; + if (!files.length) { return; } + + files.each((index, file) => { + file = $(file); + let data = file.data('file'); + let mock = { + name: data.name, + size: data.size, + type: data.type, + status: Dropzone.ADDED, + accepted: true, + url: this.options.url, + removeUrl: data.remove + }; + + dropzone.files.push(mock); + dropzone.options.addedfile.call(dropzone, mock); + if (mock.type.match(/^image\//)) dropzone.options.thumbnail.call(dropzone, mock, data.path); + + file.remove(); + }); + } + + onDropzoneSending(file, xhr, formData) { + formData.append('__form-name__', this.container.closest('form').find('[name="__form-name__"]').val()); + formData.append('__form-file-uploader__', 1); + formData.append('name', this.options.dotNotation); + formData.append('form-nonce', config.form_nonce); + formData.append('task', 'filesupload'); + } + + onDropzoneSuccess(file, response, xhr) { + if (this.options.reloadPage) { + global.location.reload(); + } + + // store params for removing file from session before it gets saved + if (response.session) { + file.sessionParams = response.session; + file.removeUrl = this.options.url; + + // Touch field value to force a mutation detection + const input = this.container.find('[name][type="hidden"]'); + const value = input.val(); + input.val(value + ' '); + } + + return this.handleError({ + file, + data: response, + mode: 'removeFile', + msg: `

                                                                      ${translations.PLUGIN_FORM.FILE_ERROR_UPLOAD} ${file.name}

                                                                      +
                                                                      ${response.message}
                                                                      ` + }); + } + + onDropzoneComplete(file) { + if (!file.accepted && !file.rejected) { + let data = { + status: 'error', + message: `${translations.PLUGIN_FORM.FILE_UNSUPPORTED}: ${file.name.match(/\..+/).join('')}` + }; + + return this.handleError({ + file, + data, + mode: 'removeFile', + msg: `

                                                                      ${translations.PLUGIN_FORM.FILE_ERROR_ADD} ${file.name}

                                                                      +
                                                                      ${data.message}
                                                                      ` + }); + } + + if (this.options.reloadPage) { + global.location.reload(); + } + } + + onDropzoneRemovedFile(file, ...extra) { + if (!file.accepted || file.rejected) { return; } + let url = file.removeUrl || this.urls.delete; + let path = (url || '').match(/path:(.*)\//); + let body = { filename: file.name }; + + if (file.sessionParams) { + body.task = 'filessessionremove'; + body.session = file.sessionParams; + } + + request(url, { method: 'post', body }, () => { + if (!path) { return; } + + path = global.atob(path[1]); + let input = this.container.find('[name][type="hidden"]'); + let data = JSON.parse(input.val() || '{}'); + delete data[path]; + input.val(JSON.stringify(data)); + }); + } + + onDropzoneError(file, response, xhr) { + let message = xhr && response.error ? response.error.message : response; + $(file.previewElement).find('[data-dz-errormessage]').html(message); + + return this.handleError({ + file, + data: { status: 'error' }, + msg: `
                                                                      ${message}
                                                                      ` + }); + } + + handleError(options) { + return true; + /* let { file, data, mode, msg } = options; + if (data.status !== 'error' && data.status !== 'unauthorized') { return; } + + switch (mode) { + case 'addBack': + if (file instanceof File) { + this.dropzone.addFile.call(this.dropzone, file); + } else { + this.dropzone.files.push(file); + this.dropzone.options.addedfile.call(this.dropzone, file); + this.dropzone.options.thumbnail.call(this.dropzone, file, file.extras.url); + } + + break; + case 'removeFile': + default: + if (~this.dropzone.files.indexOf(file)) { + file.rejected = true; + this.dropzone.removeFile.call(this.dropzone, file, { silent: true }); + } + + break; + } + + let modal = $('[data-remodal-id="generic"]'); + modal.find('.error-content').html(msg); + $.remodal.lookup[modal.data('remodal')].open(); */ + } +} + +export function UriToMarkdown(uri) { + uri = uri.replace(/@3x|@2x|@1x/, ''); + uri = uri.replace(/\(/g, '%28'); + uri = uri.replace(/\)/g, '%29'); + + return uri.match(/\.(jpe?g|png|gif|svg)$/i) ? `![](${uri})` : `[${decodeURI(uri)}](${uri})`; +} + +let instances = []; +let cache = $(); +const onAddedNodes = (event, target/* , record, instance */) => { + let files = $(target).find('.dropzone.files-upload'); + if (!files.length) { return; } + + files.each((index, file) => { + file = $(file); + if (!~cache.index(file)) { + addNode(file); + } + }); +}; + +const addNode = (container) => { + container = $(container); + let input = container.find('input[type="file"]'); + let settings = container.data('grav-file-settings') || {}; + + if (settings.accept && ~settings.accept.indexOf('*')) { + settings.accept = ['']; + } + + let options = { + url: container.data('file-url-add') || (container.closest('form').attr('action') || config.current_url) + '.json', + paramName: settings.paramName || 'file', + dotNotation: settings.name || 'file', + acceptedFiles: settings.accept ? settings.accept.join(',') : input.attr('accept') || container.data('media-types'), + maxFilesize: settings.filesize || 256, + maxFiles: settings.limit || null + }; + + cache = cache.add(container); + container = container[0]; + instances.push(new FilesField({ container, options })); +}; + +export let Instances = (() => { + $('.dropzone.files-upload').each((i, container) => addNode(container)); + $('body').on('mutation._grav', onAddedNodes); + + return instances; +})(); + diff --git a/user/plugins/form/assets/dropzone.min.css b/user/plugins/form/assets/dropzone.min.css new file mode 100644 index 0000000..d04515e --- /dev/null +++ b/user/plugins/form/assets/dropzone.min.css @@ -0,0 +1 @@ +@-webkit-keyframes passing-through{0%{opacity:0;-webkit-transform:translateY(40px);-moz-transform:translateY(40px);-ms-transform:translateY(40px);-o-transform:translateY(40px);transform:translateY(40px)}30%, 70%{opacity:1;-webkit-transform:translateY(0px);-moz-transform:translateY(0px);-ms-transform:translateY(0px);-o-transform:translateY(0px);transform:translateY(0px)}100%{opacity:0;-webkit-transform:translateY(-40px);-moz-transform:translateY(-40px);-ms-transform:translateY(-40px);-o-transform:translateY(-40px);transform:translateY(-40px)}}@-moz-keyframes passing-through{0%{opacity:0;-webkit-transform:translateY(40px);-moz-transform:translateY(40px);-ms-transform:translateY(40px);-o-transform:translateY(40px);transform:translateY(40px)}30%, 70%{opacity:1;-webkit-transform:translateY(0px);-moz-transform:translateY(0px);-ms-transform:translateY(0px);-o-transform:translateY(0px);transform:translateY(0px)}100%{opacity:0;-webkit-transform:translateY(-40px);-moz-transform:translateY(-40px);-ms-transform:translateY(-40px);-o-transform:translateY(-40px);transform:translateY(-40px)}}@keyframes passing-through{0%{opacity:0;-webkit-transform:translateY(40px);-moz-transform:translateY(40px);-ms-transform:translateY(40px);-o-transform:translateY(40px);transform:translateY(40px)}30%, 70%{opacity:1;-webkit-transform:translateY(0px);-moz-transform:translateY(0px);-ms-transform:translateY(0px);-o-transform:translateY(0px);transform:translateY(0px)}100%{opacity:0;-webkit-transform:translateY(-40px);-moz-transform:translateY(-40px);-ms-transform:translateY(-40px);-o-transform:translateY(-40px);transform:translateY(-40px)}}@-webkit-keyframes slide-in{0%{opacity:0;-webkit-transform:translateY(40px);-moz-transform:translateY(40px);-ms-transform:translateY(40px);-o-transform:translateY(40px);transform:translateY(40px)}30%{opacity:1;-webkit-transform:translateY(0px);-moz-transform:translateY(0px);-ms-transform:translateY(0px);-o-transform:translateY(0px);transform:translateY(0px)}}@-moz-keyframes slide-in{0%{opacity:0;-webkit-transform:translateY(40px);-moz-transform:translateY(40px);-ms-transform:translateY(40px);-o-transform:translateY(40px);transform:translateY(40px)}30%{opacity:1;-webkit-transform:translateY(0px);-moz-transform:translateY(0px);-ms-transform:translateY(0px);-o-transform:translateY(0px);transform:translateY(0px)}}@keyframes slide-in{0%{opacity:0;-webkit-transform:translateY(40px);-moz-transform:translateY(40px);-ms-transform:translateY(40px);-o-transform:translateY(40px);transform:translateY(40px)}30%{opacity:1;-webkit-transform:translateY(0px);-moz-transform:translateY(0px);-ms-transform:translateY(0px);-o-transform:translateY(0px);transform:translateY(0px)}}@-webkit-keyframes pulse{0%{-webkit-transform:scale(1);-moz-transform:scale(1);-ms-transform:scale(1);-o-transform:scale(1);transform:scale(1)}10%{-webkit-transform:scale(1.1);-moz-transform:scale(1.1);-ms-transform:scale(1.1);-o-transform:scale(1.1);transform:scale(1.1)}20%{-webkit-transform:scale(1);-moz-transform:scale(1);-ms-transform:scale(1);-o-transform:scale(1);transform:scale(1)}}@-moz-keyframes pulse{0%{-webkit-transform:scale(1);-moz-transform:scale(1);-ms-transform:scale(1);-o-transform:scale(1);transform:scale(1)}10%{-webkit-transform:scale(1.1);-moz-transform:scale(1.1);-ms-transform:scale(1.1);-o-transform:scale(1.1);transform:scale(1.1)}20%{-webkit-transform:scale(1);-moz-transform:scale(1);-ms-transform:scale(1);-o-transform:scale(1);transform:scale(1)}}@keyframes pulse{0%{-webkit-transform:scale(1);-moz-transform:scale(1);-ms-transform:scale(1);-o-transform:scale(1);transform:scale(1)}10%{-webkit-transform:scale(1.1);-moz-transform:scale(1.1);-ms-transform:scale(1.1);-o-transform:scale(1.1);transform:scale(1.1)}20%{-webkit-transform:scale(1);-moz-transform:scale(1);-ms-transform:scale(1);-o-transform:scale(1);transform:scale(1)}}.dropzone,.dropzone *{box-sizing:border-box}.dropzone{min-height:150px;border:2px solid rgba(0,0,0,0.3);background:white;padding:20px 20px}.dropzone.dz-clickable{cursor:pointer}.dropzone.dz-clickable *{cursor:default}.dropzone.dz-clickable .dz-message,.dropzone.dz-clickable .dz-message *{cursor:pointer}.dropzone.dz-started .dz-message{display:none}.dropzone.dz-drag-hover{border-style:solid}.dropzone.dz-drag-hover .dz-message{opacity:0.5}.dropzone .dz-message{text-align:center;margin:2em 0}.dropzone .dz-preview{position:relative;display:inline-block;vertical-align:top;margin:16px;min-height:100px}.dropzone .dz-preview:hover{z-index:1000}.dropzone .dz-preview:hover .dz-details{opacity:1}.dropzone .dz-preview.dz-file-preview .dz-image{border-radius:20px;background:#999;background:linear-gradient(to bottom, #eee, #ddd)}.dropzone .dz-preview.dz-file-preview .dz-details{opacity:1}.dropzone .dz-preview.dz-image-preview{background:white}.dropzone .dz-preview.dz-image-preview .dz-details{-webkit-transition:opacity 0.2s linear;-moz-transition:opacity 0.2s linear;-ms-transition:opacity 0.2s linear;-o-transition:opacity 0.2s linear;transition:opacity 0.2s linear}.dropzone .dz-preview .dz-remove{font-size:14px;text-align:center;display:block;cursor:pointer;border:none}.dropzone .dz-preview .dz-remove:hover{text-decoration:underline}.dropzone .dz-preview:hover .dz-details{opacity:1}.dropzone .dz-preview .dz-details{z-index:20;position:absolute;top:0;left:0;opacity:0;font-size:13px;min-width:100%;max-width:100%;padding:2em 1em;text-align:center;color:rgba(0,0,0,0.9);line-height:150%}.dropzone .dz-preview .dz-details .dz-size{margin-bottom:1em;font-size:16px}.dropzone .dz-preview .dz-details .dz-filename{white-space:nowrap}.dropzone .dz-preview .dz-details .dz-filename:hover span{border:1px solid rgba(200,200,200,0.8);background-color:rgba(255,255,255,0.8)}.dropzone .dz-preview .dz-details .dz-filename:not(:hover){overflow:hidden;text-overflow:ellipsis}.dropzone .dz-preview .dz-details .dz-filename:not(:hover) span{border:1px solid transparent}.dropzone .dz-preview .dz-details .dz-filename span,.dropzone .dz-preview .dz-details .dz-size span{background-color:rgba(255,255,255,0.4);padding:0 0.4em;border-radius:3px}.dropzone .dz-preview:hover .dz-image img{-webkit-transform:scale(1.05, 1.05);-moz-transform:scale(1.05, 1.05);-ms-transform:scale(1.05, 1.05);-o-transform:scale(1.05, 1.05);transform:scale(1.05, 1.05);-webkit-filter:blur(8px);filter:blur(8px)}.dropzone .dz-preview .dz-image{border-radius:20px;overflow:hidden;width:120px;height:120px;position:relative;display:block;z-index:10}.dropzone .dz-preview .dz-image img{display:block}.dropzone .dz-preview.dz-success .dz-success-mark{-webkit-animation:passing-through 3s cubic-bezier(0.77, 0, 0.175, 1);-moz-animation:passing-through 3s cubic-bezier(0.77, 0, 0.175, 1);-ms-animation:passing-through 3s cubic-bezier(0.77, 0, 0.175, 1);-o-animation:passing-through 3s cubic-bezier(0.77, 0, 0.175, 1);animation:passing-through 3s cubic-bezier(0.77, 0, 0.175, 1)}.dropzone .dz-preview.dz-error .dz-error-mark{opacity:1;-webkit-animation:slide-in 3s cubic-bezier(0.77, 0, 0.175, 1);-moz-animation:slide-in 3s cubic-bezier(0.77, 0, 0.175, 1);-ms-animation:slide-in 3s cubic-bezier(0.77, 0, 0.175, 1);-o-animation:slide-in 3s cubic-bezier(0.77, 0, 0.175, 1);animation:slide-in 3s cubic-bezier(0.77, 0, 0.175, 1)}.dropzone .dz-preview .dz-success-mark,.dropzone .dz-preview .dz-error-mark{pointer-events:none;opacity:0;z-index:500;position:absolute;display:block;top:50%;left:50%;margin-left:-27px;margin-top:-27px}.dropzone .dz-preview .dz-success-mark svg,.dropzone .dz-preview .dz-error-mark svg{display:block;width:54px;height:54px}.dropzone .dz-preview.dz-processing .dz-progress{opacity:1;-webkit-transition:all 0.2s linear;-moz-transition:all 0.2s linear;-ms-transition:all 0.2s linear;-o-transition:all 0.2s linear;transition:all 0.2s linear}.dropzone .dz-preview.dz-complete .dz-progress{opacity:0;-webkit-transition:opacity 0.4s ease-in;-moz-transition:opacity 0.4s ease-in;-ms-transition:opacity 0.4s ease-in;-o-transition:opacity 0.4s ease-in;transition:opacity 0.4s ease-in}.dropzone .dz-preview:not(.dz-processing) .dz-progress{-webkit-animation:pulse 6s ease infinite;-moz-animation:pulse 6s ease infinite;-ms-animation:pulse 6s ease infinite;-o-animation:pulse 6s ease infinite;animation:pulse 6s ease infinite}.dropzone .dz-preview .dz-progress{opacity:1;z-index:1000;pointer-events:none;position:absolute;height:16px;left:50%;top:50%;margin-top:-8px;width:80px;margin-left:-40px;background:rgba(255,255,255,0.9);-webkit-transform:scale(1);border-radius:8px;overflow:hidden}.dropzone .dz-preview .dz-progress .dz-upload{background:#333;background:linear-gradient(to bottom, #666, #444);position:absolute;top:0;left:0;bottom:0;width:0;-webkit-transition:width 300ms ease-in-out;-moz-transition:width 300ms ease-in-out;-ms-transition:width 300ms ease-in-out;-o-transition:width 300ms ease-in-out;transition:width 300ms ease-in-out}.dropzone .dz-preview.dz-error .dz-error-message{display:block}.dropzone .dz-preview.dz-error:hover .dz-error-message{opacity:1;pointer-events:auto}.dropzone .dz-preview .dz-error-message{pointer-events:none;z-index:1000;position:absolute;display:block;display:none;opacity:0;-webkit-transition:opacity 0.3s ease;-moz-transition:opacity 0.3s ease;-ms-transition:opacity 0.3s ease;-o-transition:opacity 0.3s ease;transition:opacity 0.3s ease;border-radius:8px;font-size:13px;top:130px;left:-10px;width:140px;background:#be2626;background:linear-gradient(to bottom, #be2626, #a92222);padding:0.5em 1.2em;color:white}.dropzone .dz-preview .dz-error-message:after{content:'';position:absolute;top:-6px;left:64px;width:0;height:0;border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:6px solid #be2626} diff --git a/user/plugins/form/assets/form-styles.css b/user/plugins/form/assets/form-styles.css new file mode 100644 index 0000000..c5709c7 --- /dev/null +++ b/user/plugins/form/assets/form-styles.css @@ -0,0 +1,69 @@ +.form-errors { + background: #fdf7f7; + color: #b52b27; + padding: 0 5px; + border-radius: 3px; + margin-bottom: 10px; +} + +.form-errors p { + margin: 0; + line-height: 2; +} + +.form-field.has-errors .form-errors { + margin-top: -5px; +} + +.form-field.has-errors label { + color: #b52b27; +} + +.form-field.has-errors .form-input-wrapper input, +.form-field.has-errors .form-input-wrapper select, +.form-field.has-errors .form-input-wrapper textarea { + border: 1px solid #d9534f; +} + +.form-input-file.dropzone { + position: relative; + min-height: 70px; + border-radius: 3px; + margin-bottom: .85rem; + border: 2px dashed #ccc; + color: #aaa; + padding: 0.5rem; +} + +.form-input-file input { + display: none; +} + +.form-input-file .dz-default.dz-message { + position: absolute; + text-align: center; + left: 0; + right: 0; + top: 50%; + transform: translateY(-50%); + margin: 0; +} + +.form-input-file.dropzone .dz-preview { + margin: 0.5rem; +} + +.form-input-file.dropzone .dz-preview:hover { + z-index: 2; +} + +.form-input-file.dropzone .dz-preview .dz-error-message { + min-width: 140px; + width: auto; +} + +.form-input-file.dropzone .dz-preview .dz-image, +.form-input-file.dropzone .dz-preview.dz-file-preview .dz-image { + border-radius: 3px; + z-index: 1; +} diff --git a/user/plugins/form/assets/form.min.js b/user/plugins/form/assets/form.min.js new file mode 100644 index 0000000..3bcf31e --- /dev/null +++ b/user/plugins/form/assets/form.min.js @@ -0,0 +1,3 @@ +!function(e){function t(n){if(i[n])return i[n].exports;var o=i[n]={exports:{},id:n,loaded:!1};return e[n].call(o.exports,o,o.exports,t),o.loaded=!0,o.exports}var i={};return t.m=e,t.c=i,t.p="",t(0)}([function(e,t,i){(function(e){"use strict";function n(e){return e&&e.__esModule?e:{default:e}}function o(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function r(e){return e=e.replace(/@3x|@2x|@1x/,""),e=e.replace(/\(/g,"%28"),e=e.replace(/\)/g,"%29"),e.match(/\.(jpe?g|png|gif|svg)$/i)?"![]("+e+")":"["+decodeURI(e)+"]("+e+")"}Object.defineProperty(t,"__esModule",{value:!0}),t.Instances=void 0;var s=function(){function e(e,t){for(var i=0;i\n
                                                                      \n\n
                                                                      \n
                                                                      \n
                                                                      \n
                                                                      \n
                                                                      \n
                                                                      \n\n\n\n
                                                                      \n\n \n \n Check\n Created with Sketch.\n \n \n \n \n \n \n
                                                                      \n
                                                                      \n\n \n \n error\n Created with Sketch.\n \n \n \n \n \n \n \n
                                                                      \n '.trim()},f=function(){function t(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},i=e.container,n=void 0===i?".dropzone.files-upload":i,r=e.options,s=void 0===r?{}:r;o(this,t),this.container=(0,a.default)(n),this.container.length&&(this.urls={},this.options=Object.assign({},h,m,{klass:this,url:this.container.data("file-url-add")||d.config.current_url,acceptedFiles:this.container.data("media-types"),init:this.initDropzone},this.container.data("dropzone-options"),s),this.dropzone=new p.default(n,this.options),this.dropzone.on("complete",this.onDropzoneComplete.bind(this)),this.dropzone.on("success",this.onDropzoneSuccess.bind(this)),this.dropzone.on("removedfile",this.onDropzoneRemovedFile.bind(this)),this.dropzone.on("sending",this.onDropzoneSending.bind(this)),this.dropzone.on("error",this.onDropzoneError.bind(this)))}return s(t,[{key:"initDropzone",value:function(){var e=this,t=this.options.klass.container.find("[data-file]"),i=this;t.length&&t.each(function(t,n){n=(0,a.default)(n);var o=n.data("file"),r={name:o.name,size:o.size,type:o.type,status:p.default.ADDED,accepted:!0,url:e.options.url,removeUrl:o.remove};i.files.push(r),i.options.addedfile.call(i,r),r.type.match(/^image\//)&&i.options.thumbnail.call(i,r,o.path),n.remove()})}},{key:"onDropzoneSending",value:function(e,t,i){i.append("__form-name__",this.container.closest("form").find('[name="__form-name__"]').val()),i.append("__form-file-uploader__",1),i.append("name",this.options.dotNotation),i.append("form-nonce",d.config.form_nonce),i.append("task","filesupload")}},{key:"onDropzoneSuccess",value:function(t,i,n){if(this.options.reloadPage&&e.location.reload(),i.session){t.sessionParams=i.session,t.removeUrl=this.options.url;var o=this.container.find('[name][type="hidden"]'),r=o.val();o.val(r+" ")}return this.handleError({file:t,data:i,mode:"removeFile",msg:"

                                                                      "+d.translations.PLUGIN_FORM.FILE_ERROR_UPLOAD+" "+t.name+"

                                                                      \n
                                                                      "+i.message+"
                                                                      "})}},{key:"onDropzoneComplete",value:function(t){if(!t.accepted&&!t.rejected){var i={status:"error",message:d.translations.PLUGIN_FORM.FILE_UNSUPPORTED+": "+t.name.match(/\..+/).join("")};return this.handleError({file:t,data:i,mode:"removeFile",msg:"

                                                                      "+d.translations.PLUGIN_FORM.FILE_ERROR_ADD+" "+t.name+"

                                                                      \n
                                                                      "+i.message+"
                                                                      "})}this.options.reloadPage&&e.location.reload()}},{key:"onDropzoneRemovedFile",value:function(t){var i=this;if(t.accepted&&!t.rejected){var n=t.removeUrl||this.urls.delete,o=(n||"").match(/path:(.*)\//),r={filename:t.name};t.sessionParams&&(r.task="filessessionremove",r.session=t.sessionParams),c(n,{method:"post",body:r},function(){if(o){o=e.atob(o[1]);var t=i.container.find('[name][type="hidden"]'),n=JSON.parse(t.val()||"{}");delete n[o],t.val(JSON.stringify(n))}})}}},{key:"onDropzoneError",value:function(e,t,i){var n=i&&t.error?t.error.message:t;return(0,a.default)(e.previewElement).find("[data-dz-errormessage]").html(n),this.handleError({file:e,data:{status:"error"},msg:"
                                                                      "+n+"
                                                                      "})}},{key:"handleError",value:function(e){return!0}}]),t}();t.default=f;var g=[],v=(0,a.default)(),F=function(e,t){var i=(0,a.default)(t).find(".dropzone.files-upload");i.length&&i.each(function(e,t){t=(0,a.default)(t),~v.index(t)||y(t)})},y=function(e){e=(0,a.default)(e);var t=e.find('input[type="file"]'),i=e.data("grav-file-settings")||{};i.accept&&~i.accept.indexOf("*")&&(i.accept=[""]);var n={url:e.data("file-url-add")||(e.closest("form").attr("action")||d.config.current_url)+".json",paramName:i.paramName||"file",dotNotation:i.name||"file",acceptedFiles:i.accept?i.accept.join(","):t.attr("accept")||e.data("media-types"),maxFilesize:i.filesize||256,maxFiles:i.limit||null};v=v.add(e),e=e[0],g.push(new f({container:e,options:n}))};t.Instances=function(){return(0,a.default)(".dropzone.files-upload").each(function(e,t){return y(t)}),(0,a.default)("body").on("mutation._grav",F),g}()}).call(t,function(){return this}())},function(e,t){e.exports=jQuery},function(e,t,i){(function(e){(function(){var t,i,n,o,r,s,l,a,u=[].slice,p={}.hasOwnProperty,d=function(e,t){function i(){this.constructor=e}for(var n in t)p.call(t,n)&&(e[n]=t[n]);return i.prototype=t.prototype,e.prototype=new i,e.__super__=t.prototype,e};l=function(){},i=function(){function e(){}return e.prototype.addEventListener=e.prototype.on,e.prototype.on=function(e,t){return this._callbacks=this._callbacks||{},this._callbacks[e]||(this._callbacks[e]=[]),this._callbacks[e].push(t),this},e.prototype.emit=function(){var e,t,i,n,o,r;if(n=arguments[0],e=2<=arguments.length?u.call(arguments,1):[],this._callbacks=this._callbacks||{},i=this._callbacks[n])for(o=0,r=i.length;o'),this.element.appendChild(i)),n=i.getElementsByTagName("span")[0],n&&(null!=n.textContent?n.textContent=this.options.dictFallbackMessage:null!=n.innerText&&(n.innerText=this.options.dictFallbackMessage)),this.element.appendChild(this.getFallbackForm())},resize:function(e){var t,i,n;return t={srcX:0,srcY:0,srcWidth:e.width,srcHeight:e.height},i=e.width/e.height,t.optWidth=this.options.thumbnailWidth,t.optHeight=this.options.thumbnailHeight,null==t.optWidth&&null==t.optHeight?(t.optWidth=t.srcWidth,t.optHeight=t.srcHeight):null==t.optWidth?t.optWidth=i*t.optHeight:null==t.optHeight&&(t.optHeight=1/i*t.optWidth),n=t.optWidth/t.optHeight,e.heightn?(t.srcHeight=e.height,t.srcWidth=t.srcHeight*n):(t.srcWidth=e.width,t.srcHeight=t.srcWidth/n),t.srcX=(e.width-t.srcWidth)/2,t.srcY=(e.height-t.srcHeight)/2,t},drop:function(e){return this.element.classList.remove("dz-drag-hover")},dragstart:l,dragend:function(e){return this.element.classList.remove("dz-drag-hover")},dragenter:function(e){return this.element.classList.add("dz-drag-hover")},dragover:function(e){return this.element.classList.add("dz-drag-hover")},dragleave:function(e){return this.element.classList.remove("dz-drag-hover")},paste:l,reset:function(){return this.element.classList.remove("dz-started")},addedfile:function(e){var i,n,o,r,s,l,a,u,p,d,c,h,m;if(this.element===this.previewsContainer&&this.element.classList.add("dz-started"),this.previewsContainer){for(e.previewElement=t.createElement(this.options.previewTemplate.trim()),e.previewTemplate=e.previewElement,this.previewsContainer.appendChild(e.previewElement),d=e.previewElement.querySelectorAll("[data-dz-name]"),r=0,a=d.length;r'+this.options.dictRemoveFile+""),e.previewElement.appendChild(e._removeLink)),n=function(i){return function(n){return n.preventDefault(),n.stopPropagation(),e.status===t.UPLOADING?t.confirm(i.options.dictCancelUploadConfirmation,function(){return i.removeFile(e)}):i.options.dictRemoveFileConfirmation?t.confirm(i.options.dictRemoveFileConfirmation,function(){return i.removeFile(e)}):i.removeFile(e)}}(this),h=e.previewElement.querySelectorAll("[data-dz-remove]"),m=[],l=0,p=h.length;l\n
                                                                      \n
                                                                      \n
                                                                      \n
                                                                      \n
                                                                      \n
                                                                      \n
                                                                      \n
                                                                      \n \n Check\n \n \n \n \n \n
                                                                      \n
                                                                      \n \n Error\n \n \n \n \n \n \n \n
                                                                      \n'},n=function(){var e,t,i,n,o,r,s;for(n=arguments[0],i=2<=arguments.length?u.call(arguments,1):[],r=0,s=i.length;r'+this.options.dictDefaultMessage+"")),this.clickableElements.length&&(n=function(e){return function(){return e.hiddenFileInput&&e.hiddenFileInput.parentNode.removeChild(e.hiddenFileInput),e.hiddenFileInput=document.createElement("input"),e.hiddenFileInput.setAttribute("type","file"),(null==e.options.maxFiles||e.options.maxFiles>1)&&e.hiddenFileInput.setAttribute("multiple","multiple"),e.hiddenFileInput.className="dz-hidden-input",null!=e.options.acceptedFiles&&e.hiddenFileInput.setAttribute("accept",e.options.acceptedFiles),null!=e.options.capture&&e.hiddenFileInput.setAttribute("capture",e.options.capture),e.hiddenFileInput.style.visibility="hidden",e.hiddenFileInput.style.position="absolute",e.hiddenFileInput.style.top="0",e.hiddenFileInput.style.left="0",e.hiddenFileInput.style.height="0",e.hiddenFileInput.style.width="0",document.querySelector(e.options.hiddenInputContainer).appendChild(e.hiddenFileInput),e.hiddenFileInput.addEventListener("change",function(){var t,i,o,r;if(i=e.hiddenFileInput.files,i.length)for(o=0,r=i.length;o',this.options.dictFallbackText&&(n+="

                                                                      "+this.options.dictFallbackText+"

                                                                      "),n+='',i=t.createElement(n),"FORM"!==this.element.tagName?(o=t.createElement('
                                                                      '),o.appendChild(i)):(this.element.setAttribute("enctype","multipart/form-data"),this.element.setAttribute("method",this.options.method)),null!=o?o:i)},t.prototype.getExistingFallback=function(){var e,t,i,n,o,r;for(t=function(e){var t,i,n;for(i=0,n=e.length;i0){for(s=["TB","GB","MB","KB","b"],i=l=0,a=s.length;l=t){n=e/Math.pow(this.options.filesizeBase,4-i),o=r;break}n=Math.round(10*n)/10}return""+n+" "+o},t.prototype._updateMaxFilesReachedClass=function(){return null!=this.options.maxFiles&&this.getAcceptedFiles().length>=this.options.maxFiles?(this.getAcceptedFiles().length===this.options.maxFiles&&this.emit("maxfilesreached",this.files),this.element.classList.add("dz-max-files-reached")):this.element.classList.remove("dz-max-files-reached")},t.prototype.drop=function(e){var t,i;e.dataTransfer&&(this.emit("drop",e),t=e.dataTransfer.files,this.emit("addedfiles",t),t.length&&(i=e.dataTransfer.items,i&&i.length&&null!=i[0].webkitGetAsEntry?this._addFilesFromItems(i):this.handleFiles(t)))},t.prototype.paste=function(e){var t,i;if(null!=(null!=e&&null!=(i=e.clipboardData)?i.items:void 0))return this.emit("paste",e),t=e.clipboardData.items,t.length?this._addFilesFromItems(t):void 0},t.prototype.handleFiles=function(e){var t,i,n,o;for(o=[],i=0,n=e.length;i0){for(r=0,s=i.length;r1024*this.options.maxFilesize*1024?i(this.options.dictFileTooBig.replace("{{filesize}}",Math.round(e.size/1024/10.24)/100).replace("{{maxFilesize}}",this.options.maxFilesize)):t.isValidFile(e,this.options.acceptedFiles)?null!=this.options.maxFiles&&this.getAcceptedFiles().length>=this.options.maxFiles?(i(this.options.dictMaxFilesExceeded.replace("{{maxFiles}}",this.options.maxFiles)),this.emit("maxfilesexceeded",e)):this.options.accept.call(this,e,i):i(this.options.dictInvalidFileType)},t.prototype.addFile=function(e){return e.upload={progress:0,total:e.size,bytesSent:0},this.files.push(e),e.status=t.ADDED,this.emit("addedfile",e),this._enqueueThumbnail(e),this.accept(e,function(t){return function(i){return i?(e.accepted=!1,t._errorProcessing([e],i)):(e.accepted=!0,t.options.autoQueue&&t.enqueueFile(e)),t._updateMaxFilesReachedClass()}}(this))},t.prototype.enqueueFiles=function(e){var t,i,n;for(i=0,n=e.length;i=t)&&(n=this.getQueuedFiles(),n.length>0)){if(this.options.uploadMultiple)return this.processFiles(n.slice(0,t-i));for(;e=T;p=0<=T?++O:--O)r.append(this._getParamName(p),e[p],this._renameFilename(e[p].name));return this.submitRequest(b,r,e)},t.prototype.submitRequest=function(e,t,i){return e.send(t)},t.prototype._finished=function(e,i,n){var o,r,s;for(r=0,s=e.length;rp;)t=o[4*(a-1)+3],0===t?r=a:p=a,a=r+p>>1;return u=a/s,0===u?1:u},s=function(e,t,i,n,o,s,l,a,u,p){var d;return d=r(t),e.drawImage(t,i,n,o,s,l,a,u,p/d)},o=function(e,t){var i,n,o,r,s,l,a,u,p;if(o=!1,p=!0,n=e.document,u=n.documentElement,i=n.addEventListener?"addEventListener":"attachEvent",a=n.addEventListener?"removeEventListener":"detachEvent",l=n.addEventListener?"":"on",r=function(i){if("readystatechange"!==i.type||"complete"===n.readyState)return("load"===i.type?e:n)[a](l+i.type,r,!1),!o&&(o=!0)?t.call(e,i.type||i):void 0},s=function(){var e;try{u.doScroll("left")}catch(t){return e=t,void setTimeout(s,50)}return r("poll")},"complete"!==n.readyState){if(n.createEventObject&&u.doScroll){try{p=!e.frameElement}catch(e){}p&&s()}return n[i](l+"DOMContentLoaded",r,!1),n[i](l+"readystatechange",r,!1),e[i](l+"load",r,!1)}},t._autoDiscoverFunction=function(){if(t.autoDiscover)return t.discover()},o(window,t._autoDiscoverFunction)}).call(this)}).call(t,i(3)(e))},function(e,t){e.exports=function(e){return e.webpackPolyfill||(e.deprecate=function(){},e.paths=[],e.children=[],e.webpackPolyfill=1),e}},function(e,t){e.exports=GravForm}]); +//# sourceMappingURL=form.min.js.map \ No newline at end of file diff --git a/user/plugins/form/blueprints.yaml b/user/plugins/form/blueprints.yaml new file mode 100644 index 0000000..536ef6d --- /dev/null +++ b/user/plugins/form/blueprints.yaml @@ -0,0 +1,145 @@ +name: Form +version: 2.11.2 +description: Enables the forms handling +icon: check-square +author: + name: Team Grav + email: devs@getgrav.org + url: http://getgrav.org +keywords: plugin, form +homepage: https://github.com/getgrav/grav-plugin-form +bugs: https://github.com/getgrav/grav-plugin-form/issues +license: MIT + +dependencies: + - { name: grav, version: '>=1.3.9' } + +form: + validation: strict + fields: + enabled: + type: hidden + label: PLUGIN_ADMIN.PLUGIN_STATUS + highlight: 1 + default: 0 + options: + 1: PLUGIN_ADMIN.ENABLED + 0: PLUGIN_ADMIN.DISABLED + validate: + type: bool + general: + type: section + title: PLUGIN_FORM.GENERAL + + fields: + built_in_css: + type: toggle + label: PLUGIN_FORM.USE_BUILT_IN_CSS + highlight: 1 + default: 1 + options: + 1: Enabled + 0: Disabled + validate: + type: bool + + refresh_prevention: + type: toggle + label: PLUGIN_FORM.REFRESH_PREVENTION + help: PLUGIN_FORM.REFRESH_PREVENTION_HELP + highlight: 1 + default: 0 + options: + 1: Enabled + 0: Disabled + validate: + type: bool + + files: + type: section + title: PLUGIN_FORM.FILES + + fields: + files.multiple: + type: toggle + label: PLUGIN_FORM.ALLOW_MULTIPLE + help: PLUGIN_FORM.ALLOW_MULTIPLE_HELP + highlight: 1 + default: 0 + options: + 1: PLUGIN_ADMIN.ENABLED + 0: PLUGIN_ADMIN.DISABLED + validate: + type: bool + files.limit: + type: text + size: x-small + label: PLUGIN_FORM.LIMIT + help: PLUGIN_FORM.LIMIT_HELP + default: 10 + validate: + type: number + min: 1 + files.destination: + type: text + size: large + label: PLUGIN_FORM.DESTINATION + help: PLUGIN_FORM.DESTINATION_HELP + default: '@self' + files.accept: + type: selectize + size: large + label: PLUGIN_FORM.ACCEPT + help: PLUGIN_FORM.ACCEPT_HELP + classes: fancy + default: + - image/* + validate: + type: commalist + files.filesize: + type: text + label: PLUGIN_FORM.FILESIZE + help: PLUGIN_FORM.FILESIZE_HELP + size: x-small + default: 5 + validate: + type: number + min: 0 + files.avoid_overwriting: + type: toggle + label: PLUGIN_FORM.AVOID_OVERWRITING + help: PLUGIN_FORM.AVOID_OVERWRITING_HELP + highlight: 0 + default: 0 + options: + 1: PLUGIN_ADMIN.ENABLED + 0: PLUGIN_ADMIN.DISABLED + validate: + type: bool + files.random_name: + type: toggle + label: PLUGIN_FORM.RANDOM_NAME + help: PLUGIN_FORM.RANDOM_NAME_HELP + highlight: 0 + default: 0 + options: + 1: PLUGIN_ADMIN.ENABLED + 0: PLUGIN_ADMIN.DISABLED + validate: + type: bool + + recaptcha: + type: section + title: PLUGIN_FORM.RECAPTCHA + + fields: + recaptcha.site_key: + type: text + label: PLUGIN_FORM.RECAPTCHA_SITE_KEY + help: PLUGIN_FORM.RECAPTCHA_SITE_KEY_HELP + default: '' + recaptcha.secret_key: + type: text + label: PLUGIN_FORM.RECAPTCHA_SECRET_KEY + help: PLUGIN_FORM.RECAPTCHA_SECRET_KEY_HELP + default: '' diff --git a/user/plugins/form/classes/form.php b/user/plugins/form/classes/form.php new file mode 100644 index 0000000..b8d5ee3 --- /dev/null +++ b/user/plugins/form/classes/form.php @@ -0,0 +1,720 @@ +page = $page->route(); + + $header = $page->header(); + $this->rules = isset($header->rules) ? $header->rules : []; + $this->header_data = isset($header->data) ? $header->data : []; + + if ($form) { + $this->items = $form; + } else { + if (isset($header->form)) { + $this->items = $header->form; // for backwards compatibility + } + } + + // Add form specific rules. + if (!empty($this->items['rules']) && is_array($this->items['rules'])) { + $this->rules += $this->items['rules']; + } + + // Set form name if not set. + if ($name && !is_int($name)) { + $this->items['name'] = $name; + } elseif (empty($this->items['name'])) { + $this->items['name'] = $page->slug(); + } + + // Set form id if not set. + if (empty($this->items['id'])) { + $inflector = new Inflector(); + $this->items['id'] = $inflector->hyphenize($this->items['name']); + } + + // Reset and initialize the form + $this->reset(); + } + + /** + * Custom serializer for this complex object + * + * @return string + */ + public function serialize() + { + $data = [ + 'items' => $this->items, + 'message' => $this->message, + 'status' => $this->status, + 'header_data' => $this->header_data, + 'rules' => $this->rules, + 'data' => $this->data->toArray(), + 'values' => $this->values->toArray(), + 'page' => $this->page + ]; + return serialize($data); + } + + /** + * Custom unserializer for this complex object + * + * @param string $data + */ + public function unserialize($data) + { + $data = unserialize($data); + + $this->items = $data['items']; + $this->message = $data['message']; + $this->status = $data['status']; + $this->header_data = $data['header_data']; + $this->rules = $data['rules']; + + $name = $this->items['name']; + $items = $this->items; + $rules = $this->rules; + + $blueprint = function () use ($name, $items, $rules) { + $blueprint = new Blueprint($name, ['form' => $items, 'rules' => $rules]); + return $blueprint->load()->init(); + }; + + $this->data = new Data($data['data'], $blueprint); + $this->values = new Data($data['values']); + $this->page = $data['page']; + } + + /** + * Allow overriding of fields + * + * @param $fields + */ + public function setFields($fields) + { + $this->fields = $fields; + } + + /** + * Get the name of this form + * + * @return String + */ + public function name() + { + return $this->items['name']; + } + + /** + * Reset data. + */ + public function reset() + { + $name = $this->items['name']; + $grav = Grav::instance(); + + // Fix naming for fields (supports nested fields now!) + if (isset($this->items['fields'])) { + $this->items['fields'] = $this->processFields($this->items['fields']); + } + + $items = $this->items; + $rules = $this->rules; + + $blueprint = function() use ($name, $items, $rules) { + $blueprint = new Blueprint($name, ['form' => $items, 'rules' => $rules]); + return $blueprint->load()->init(); + }; + + $this->data = new Data($this->header_data, $blueprint); + $this->values = new Data(); + // Reset fields to null before calling fields() -- Do not remove: + $this->fields = null; + $this->fields = $this->fields(); + + // Fire event + $grav->fireEvent('onFormInitialized', new Event(['form' => $this])); + } + + protected function processFields($fields) + { + $types = Grav::instance()['plugins']->formFieldTypes; + + $return = array(); + foreach ($fields as $key => $value) { + // default to text if not set + if (!isset($value['type'])) { + $value['type'] = 'text'; + } + + // manually merging the field types + if ($types !== null && array_key_exists($value['type'], $types)) { + $value += $types[$value['type']]; + } + + // Fix numeric indexes + if (is_numeric($key) && isset($value['name'])) { + $key = $value['name']; + } + if (isset($value['fields']) && is_array($value['fields'])) { + $value['fields'] = $this->processFields($value['fields']); + } + $return[$key] = $value; + } + return $return; + } + + public function fields() + { + + if (null === $this->fields) { + $blueprint = $this->data->blueprints(); + + if (method_exists($blueprint, 'load')) { + // init the form to process directives + $blueprint->load()->init(); + + // fields set to processed blueprint fields + $this->fields = $blueprint->fields(); + } + } + + return $this->fields; + } + + /** + * Return page object for the form. + * + * @return Page + */ + public function page() + { + return Grav::instance()['pages']->dispatch($this->page); + } + + /** + * Get value of given variable (or all values). + * First look in the $data array, fallback to the $values array + * + * @param string $name + * + * @return mixed + */ + public function value($name = null, $fallback = false) + { + if (!$name) { + return $this->data; + } + + if ($this->data->get($name)) { + return $this->data->get($name); + } + + if ($fallback) { + return $this->values->get($name); + } + + return null; + } + + /** + * Set value of given variable in the values array + * + * @param string $name + */ + public function setValue($name = null, $value = '') + { + if (!$name) { + return; + } + + $this->values->set($name, $value); + } + + /** + * Get a value from the form + * + * @param $name + * @return mixed + */ + public function getValue($name) + { + return $this->values->get($name); + } + + /** + * Get all data + * + * @return Data + */ + public function getData() + { + return $this->data; + } + + /** + * Set value of given variable in the data array + * + * @param string $name + * @param string $value + * + * @return bool + */ + public function setData($name = null, $value = '') + { + if (!$name) { + return false; + } + + $this->data->set($name, $value); + + return true; + } + + public function setAllData($array) + { + $this->data = new Data($array); + } + + /** + * Handles ajax upload for files. + * Stores in a flash object the temporary file and deals with potential file errors. + * + * @return mixed True if the action was performed. + */ + public function uploadFiles() + { + $post = $_POST; + $grav = Grav::instance(); + $uri = $grav['uri']->url; + $config = $grav['config']; + $session = $grav['session']; + + $settings = $this->data->blueprints()->schema()->getProperty($post['name']); + $settings = (object) array_merge( + ['destination' => $config->get('plugins.form.files.destination', 'self@'), + 'avoid_overwriting' => $config->get('plugins.form.files.avoid_overwriting', false), + 'random_name' => $config->get('plugins.form.files.random_name', false), + 'accept' => $config->get('plugins.form.files.accept', ['image/*']), + 'limit' => $config->get('plugins.form.files.limit', 10), + 'filesize' => $this->getMaxFilesize(), + ], + (array) $settings, + ['name' => $post['name']] + ); + + $upload = $this->normalizeFiles($_FILES['data'], $settings->name); + + // Handle errors and breaks without proceeding further + if ($upload->file->error != UPLOAD_ERR_OK) { + // json_response + return [ + 'status' => 'error', + 'message' => sprintf($grav['language']->translate('PLUGIN_FORM.FILEUPLOAD_UNABLE_TO_UPLOAD', null, true), $upload->file->name, $this->upload_errors[$upload->file->error]) + ]; + } + + // Handle bad filenames. + $filename = $upload->file->name; + if (strtr($filename, "\t\n\r\0\x0b", '_____') !== $filename || rtrim($filename, ". ") !== $filename || preg_match('|\.php|', $filename)) { + $this->admin->json_response = [ + 'status' => 'error', + 'message' => sprintf($this->admin->translate('PLUGIN_ADMIN.FILEUPLOAD_UNABLE_TO_UPLOAD', null), + $filename, 'Bad filename') + ]; + + return false; + } + + // Remove the error object to avoid storing it + unset($upload->file->error); + + + // Handle Accepted file types + // Accept can only be mime types (image/png | image/*) or file extensions (.pdf|.jpg) + $accepted = false; + $errors = []; + foreach ((array) $settings->accept as $type) { + // Force acceptance of any file when star notation + if ($type === '*') { + $accepted = true; + break; + } + + $isMime = strstr($type, '/'); + $find = str_replace('*', '.*', $type); + + $match = preg_match('#'. $find .'$#', $isMime ? $upload->file->type : $upload->file->name); + if (!$match) { + $message = $isMime ? 'The MIME type "' . $upload->file->type . '"' : 'The File Extension'; + $errors[] = $message . ' for the file "' . $upload->file->name . '" is not an accepted.'; + $accepted |= false; + } else { + $accepted |= true; + } + } + + if (!$accepted) { + // json_response + return [ + 'status' => 'error', + 'message' => implode('
                                                                      ', $errors) + ]; + } + + + // Handle file size limits + $settings->filesize *= self::BYTES_TO_MB; // 1024 * 1024 [MB in Bytes] + if ($settings->filesize > 0 && $upload->file->size > $settings->filesize) { + // json_response + return [ + 'status' => 'error', + 'message' => $grav['language']->translate('PLUGIN_FORM.EXCEEDED_GRAV_FILESIZE_LIMIT') + ]; + } + + + // we need to move the file at this stage or else + // it won't be available upon save later on + // since php removes it from the upload location + $tmp_dir = $grav['locator']->findResource('tmp://', true, true); + $tmp_file = $upload->file->tmp_name; + $tmp = $tmp_dir . '/uploaded-files/' . basename($tmp_file); + + Folder::create(dirname($tmp)); + if (!move_uploaded_file($tmp_file, $tmp)) { + // json_response + return [ + 'status' => 'error', + 'message' => sprintf($grav['language']->translate('PLUGIN_FORM.FILEUPLOAD_UNABLE_TO_MOVE', null, true), '', $tmp) + ]; + } + + $upload->file->tmp_name = $tmp; + + // Retrieve the current session of the uploaded files for the field + // and initialize it if it doesn't exist + $sessionField = base64_encode($uri); + $flash = $session->getFlashObject('files-upload'); + if (!$flash) { + $flash = []; + } + if (!isset($flash[$sessionField])) { + $flash[$sessionField] = []; + } + if (!isset($flash[$sessionField][$upload->field])) { + $flash[$sessionField][$upload->field] = []; + } + + // Set destination + $destination = Folder::getRelativePath(rtrim($settings->destination, '/')); + $destination = $this->getPagePathFromToken($destination); + + // Create destination if needed + if (!is_dir($destination)) { + Folder::mkdir($destination); + } + + // Generate random name if required + if ($settings->random_name) { + $extension = pathinfo($upload->file->name)['extension']; + $upload->file->name = Utils::generateRandomString(15) . '.' . $extension; + } + + // Handle conflicting name if needed + if ($settings->avoid_overwriting) { + if (file_exists($destination . '/' . $upload->file->name)) { + $upload->file->name = date('YmdHis') . '-' . $upload->file->name; + } + } + + // Prepare object for later save + $path = $destination . '/' . $upload->file->name; + $upload->file->path = $path; + // $upload->file->route = $page ? $path : null; + + // Prepare data to be saved later + $flash[$sessionField][$upload->field][$path] = (array) $upload->file; + + // Finally store the new uploaded file in the field session + $session->setFlashObject('files-upload', $flash); + + + // json_response + return [ + 'status' => 'success', + 'session' => \json_encode([ + 'sessionField' => base64_encode($uri), + 'path' => $upload->file->path, + 'field' => $settings->name + ]) + ]; + } + + /** + * Handle form processing on POST action. + */ + public function post() + { + $grav = Grav::instance(); + $uri = $grav['uri']->url; + $session = $grav['session']; + + if (isset($_POST)) { + $this->values = new Data(isset($_POST) ? (array)$_POST : []); + $data = $this->values->get('data'); + + // Add post data to form dataset + if (!$data) { + $data = $this->values->toArray(); + } + + + if (!$this->values->get('form-nonce') || !Utils::verifyNonce($this->values->get('form-nonce'), 'form')) { + $this->status = 'error'; + $event = new Event(['form' => $this, + 'message' => $grav['language']->translate('PLUGIN_FORM.NONCE_NOT_VALIDATED') + ]); + $grav->fireEvent('onFormValidationError', $event); + + return; + } + + + $i = 0; + foreach ($this->items['fields'] as $key => $field) { + $name = isset($field['name']) ? $field['name'] : $key; + if (!isset($field['name'])) { + if (isset($data[$i])) { //Handle input@ false fields + $data[$name] = $data[$i]; + unset($data[$i]); + } + } + if ($field['type'] === 'checkbox') { + $data[$name] = isset($data[$name]) ? true : false; + } + $i++; + } + + $this->data->merge($data); + } + + // Validate and filter data + try { + $this->data->validate(); + $this->data->filter(); + + $grav->fireEvent('onFormValidationProcessed', new Event(['form' => $this])); + } catch (ValidationException $e) { + $this->status = 'error'; + $event = new Event(['form' => $this, 'message' => $e->getMessage(), 'messages' => $e->getMessages()]); + $grav->fireEvent('onFormValidationError', $event); + if ($event->isPropagationStopped()) { + return; + } + } catch (\RuntimeException $e) { + $this->status = 'error'; + $event = new Event(['form' => $this, 'message' => $e->getMessage(), 'messages' => []]); + $grav->fireEvent('onFormValidationError', $event); + if ($event->isPropagationStopped()) { + return; + } + } + + // Process previously uploaded files for the current URI + // and finally store them. Everything else will get discarded + $queue = $session->getFlashObject('files-upload'); + $queue = $queue[base64_encode($uri)]; + if (is_array($queue)) { + foreach ($queue as $key => $files) { + foreach ($files as $destination => $file) { + if (!rename($file['tmp_name'], $destination)) { + throw new \RuntimeException(sprintf($grav['language']->translate('PLUGIN_FORM.FILEUPLOAD_UNABLE_TO_MOVE', null, true), '"' . $file['tmp_name'] . '"', $destination)); + } + + unset($files[$destination]['tmp_name']); + } + + $this->data->merge([$key => $files]); + } + } + + $process = isset($this->items['process']) ? $this->items['process'] : []; + if (is_array($process)) { + $event = null; + foreach ($process as $action => $data) { + if (is_numeric($action)) { + $action = \key($data); + $data = $data[$action]; + } + + $previousEvent = $event; + $event = new Event(['form' => $this, 'action' => $action, 'params' => $data]); + + if ($previousEvent) { + if (!$previousEvent->isPropagationStopped()) { + $grav->fireEvent('onFormProcessed', $event); + } else { + break; + } + } else { + $grav->fireEvent('onFormProcessed', $event); + } + } + } + } + + public function getPagePathFromToken($path) + { + return Utils::getPagePathFromToken($path, $this->page()); + } + + /** + * Internal method to normalize the $_FILES array + * + * @param array $data $_FILES starting point data + * @param string $key + * @return object a new Object with a normalized list of files + */ + protected function normalizeFiles($data, $key = '') + { + $files = new \stdClass(); + $files->field = $key; + $files->file = new \stdClass(); + + foreach ($data as $fieldName => $fieldValue) { + // Since Files Upload are always happening via Ajax + // we are not interested in handling `multiple="true"` + // because they are always handled one at a time. + // For this reason we normalize the value to string, + // in case it is arriving as an array. + $value = (array) Utils::getDotNotation($fieldValue, $key); + $files->file->{$fieldName} = array_shift($value); + } + + return $files; + } + + /** + * Get the nonce for a form + * + * @return string + */ + public static function getNonce() + { + $action = 'form-plugin'; + return Utils::getNonce($action); + } + + /** + * Get the configured max file size in bytes + * + * @param bool $mbytes return size in MB + * @return int + */ + public static function getMaxFilesize($mbytes = false) + { + $config = Grav::instance()['config']; + + $filesize_mb = (float)$config->get('plugins.form.files.filesize', 0) * static::BYTES_TO_MB; + $system_filesize = $config->get('system.media.upload_limit', 0); + if ($filesize_mb > $system_filesize || $filesize_mb === 0) { + $filesize_mb = $system_filesize; + } + + if ($mbytes) { + return $filesize_mb; + } + + return $filesize_mb / static::BYTES_TO_MB; + } + + public function responseCode($code = null) + { + if ($code) { + $this->response_code = $code; + } + return $this->response_code; + } +} diff --git a/user/plugins/form/form.php b/user/plugins/form/form.php new file mode 100644 index 0000000..2c105d9 --- /dev/null +++ b/user/plugins/form/form.php @@ -0,0 +1,728 @@ + 1000 + ]; + + /** + * @var Form + */ + protected $form; + + protected $forms = []; + + protected $flat_forms = []; + + protected $json_response = []; + + protected $recache_forms = false; + + + /** + * @return array + */ + public static function getSubscribedEvents() + { + return [ + 'onPluginsInitialized' => ['onPluginsInitialized', 0], + 'onTwigTemplatePaths' => ['onTwigTemplatePaths', 0] + ]; + } + + /** + * Initialize forms from cache if possible + */ + public function onPluginsInitialized() + { + require_once(__DIR__ . '/classes/form.php'); + + if ($this->isAdmin()) { + $this->enable([ + 'onPagesInitialized' => ['onPagesInitialized', 0] + ]); + return; + } + + $this->enable([ + 'onPageProcessed' => ['onPageProcessed', 0], + 'onPagesInitialized' => ['onPagesInitialized', 0], + 'onTwigInitialized' => ['onTwigInitialized', 0], + 'onTwigPageVariables' => ['onTwigVariables', 0], + 'onTwigSiteVariables' => ['onTwigVariables', 0], + 'onFormValidationProcessed' => ['onFormValidationProcessed', 0], + ]); + } + + /** + * Process forms after page header processing, but before caching + * + * @param Event $e + */ + public function onPageProcessed(Event $e) + { + /** @var Page $page */ + $page = $e['page']; + $page_route = $page->route(); + + if ($page->home()) { + $page_route = '/'; + } + + $header = $page->header(); + + //call event to allow filling the page header form dynamically (e.g. use case: Comments plugin) + $this->grav->fireEvent('onFormPageHeaderProcessed', new Event(['header' => $header])); + + if ((isset($header->forms) && is_array($header->forms)) || + (isset($header->form) && is_array($header->form))) { + $page_forms = []; + + // Force never_cache_twig if modular form + if ($page->modular()) { + $header->never_cache_twig = true; + } + + // Get the forms from the page headers + if (isset($header->forms)) { + $page_forms = $header->forms; + } elseif (isset($header->form)) { + $page_forms[] = $header->form; + } + + // Store the page forms in the forms instance + foreach ($page_forms as $name => $page_form) { + $form = new Form($page, $name, $page_form); + $this->addForm($page_route, $form); + } + } + } + + /** + * Add a form to the forms plugin + * + * @param $page_route + * @param $form + */ + public function addForm($page_route, $form) + { + + $form_array = [$form['name'] => $form]; + if (array_key_exists($page_route, $this->forms)) { + if (!isset($this->form[$page_route][$form['name']])) { + $this->forms[$page_route] = array_merge($this->forms[$page_route], $form_array); + } + } else { + $this->forms[$page_route] = $form_array; + + } + + $this->flattenForms(); + $this->recache_forms = true; + } + + /** + * Initialize form if the page has one. Also catches form processing if user posts the form. + */ + public function onPagesInitialized() + { + $submitted = false; + $this->json_response = []; + $cache_id = $this->grav['pages']->getPagesCacheId() . '-form-plugin'; + + // Get and set the cache of forms if it exists + list($forms, $flat_forms) = $this->grav['cache']->fetch($cache_id); + + // Only store the forms if they are an array + if (is_array($forms)) { + $this->forms = array_merge($this->forms, $forms); + } + + // Only store the flat_forms if they are an array + if (is_array($flat_forms)) { + $this->flat_forms = array_merge($this->flat_forms, $flat_forms); + } + + // Save the current state of the forms to cache + if ($this->recache_forms) { + $this->grav['cache']->save($cache_id, [$this->forms, $this->flat_forms]); + } + + // Enable form events if there's a POST + if ($this->shouldProcessForm()) { + $this->enable([ + 'onFormProcessed' => ['onFormProcessed', 0], + 'onFormValidationError' => ['onFormValidationError', 0], + 'onFormFieldTypes' => ['onFormFieldTypes', 0], + ]); + + // Post the form + if ($this->form()) { + if ($this->grav['uri']->extension() === 'json' && isset($_POST['__form-file-uploader__'])) { + $this->json_response = $this->form->uploadFiles(); + } else { + $this->form->post(); + $submitted = true; + } + } + + // Clear flash objects for previously uploaded files + // whenever the user switches page / reloads + // ignoring any JSON / extension call + if (null === $this->grav['uri']->extension() && !$submitted) { + // Discard any previously uploaded files session. + // and if there were any uploaded file, remove them from the filesystem + if ($flash = $this->grav['session']->getFlashObject('files-upload')) { + $flash = new \RecursiveIteratorIterator(new \RecursiveArrayIterator($flash)); + foreach ($flash as $key => $value) { + if ($key !== 'tmp_name') { + continue; + } + @unlink($value); + } + } + } + } + } + + /** + * Add simple `forms()` Twig function + */ + public function onTwigInitialized() + { + $this->grav['twig']->twig()->addFunction( + new \Twig_SimpleFunction('forms', [$this, 'getForm']) + ); + + $this->grav['twig']->twig()->getExtension('Twig_Extension_Core')->setEscaper('yaml', function($twig, $string, $charset) { + return Yaml::dump($string); + } + ); + + } + + /** + * Add current directory to twig lookup paths. + */ + public function onTwigTemplatePaths() + { + $this->grav['twig']->twig_paths[] = __DIR__ . '/templates'; + } + + /** + * Make form accessible from twig. + * + * @param Event $event + */ + public function onTwigVariables(Event $event = null) + { + if ($event !== null && isset($event['page'])) { + $page = $event['page']; + } else { + $page = $this->grav['page']; + } + + $twig = $this->grav['twig']; + + if (!isset($twig->twig_vars['form'])) { + $twig->twig_vars['form'] = $this->form($page); + } + + if ($this->config->get('plugins.form.built_in_css')) { + $this->grav['assets']->addCss('plugin://form/assets/form-styles.css'); + } + $twig->twig_vars['form_max_filesize'] = Form::getMaxFilesize(); + $twig->twig_vars['form_json_response'] = $this->json_response; + } + + /** + * Handle form processing instructions. + * + * @param Event $event + * @throws \Exception + */ + public function onFormProcessed(Event $event) + { + $form = $event['form']; + $action = $event['action']; + $params = $event['params']; + + $this->process($form); + + switch ($action) { + case 'captcha': + if (isset($params['recaptcha_secret'])) { + $recaptchaSecret = $params['recaptcha_secret']; + } elseif (isset($params['recatpcha_secret'])) { + // Included for backwards compatibility with typo (issue #51) + $recaptchaSecret = $params['recatpcha_secret']; + } else { + $recaptchaSecret = $this->config->get('plugins.form.recaptcha.secret_key'); + } + + // Validate the captcha + $query = http_build_query([ + 'secret' => $recaptchaSecret, + 'response' => $form->value('g-recaptcha-response', true) + ]); + $url = 'https://www.google.com/recaptcha/api/siteverify?' . $query; + $response = json_decode(file_get_contents($url), true); + + if (!isset($response['success']) || $response['success'] !== true) { + $this->grav->fireEvent('onFormValidationError', new Event([ + 'form' => $form, + 'message' => $this->grav['language']->translate('PLUGIN_FORM.ERROR_VALIDATING_CAPTCHA') + ])); + $event->stopPropagation(); + + return; + } + break; + case 'ip': + $label = isset($params['label']) ? $params['label'] : 'User IP'; + $blueprint = $form->value()->blueprints(); + $blueprint->set('form/fields/ip', ['name'=>'ip', 'label'=> $label]); + $form->setFields($blueprint->fields()); + $form->setData('ip', Uri::ip()); + break; + case 'message': + $translated_string = $this->grav['language']->translate($params); + $vars = array( + 'form' => $form + ); + + /** @var Twig $twig */ + $twig = $this->grav['twig']; + $processed_string = $twig->processString($translated_string, $vars); + + $form->message = $processed_string; + break; + case 'redirect': + $this->grav['session']->setFlashObject('form', $form); + $url = ((string)$params); + $vars = array( + 'form' => $form + ); + /** @var Twig $twig */ + $twig = $this->grav['twig']; + $url = $twig->processString($url, $vars); + $this->grav->redirect($url); + break; + case 'reset': + if (Utils::isPositive($params)) { + $form->reset(); + } + break; + case 'display': + $route = (string)$params; + if (!$route || $route[0] !== '/') { + /** @var Uri $uri */ + $uri = $this->grav['uri']; + $route = rtrim($uri->route(), '/'). '/' . ($route ?: ''); + } + + /** @var Twig $twig */ + $twig = $this->grav['twig']; + $twig->twig_vars['form'] = $form; + + /** @var Pages $pages */ + $pages = $this->grav['pages']; + $page = $pages->dispatch($route, true); + + if (!$page) { + throw new \RuntimeException('Display page not found. Please check the page exists.', 400); + } + + unset($this->grav['page']); + $this->grav['page'] = $page; + break; + case 'remember': + foreach ($params as $remember_field) { + $field_cookie = 'forms-'.$form['name'].'-'.$remember_field; + setcookie($field_cookie, $form->value($remember_field), time()+60*60*24*60); + } + break; + case 'save': + $prefix = !empty($params['fileprefix']) ? $params['fileprefix'] : ''; + $format = !empty($params['dateformat']) ? $params['dateformat'] : 'Ymd-His-u'; + $ext = !empty($params['extension']) ? '.' . trim($params['extension'], '.') : '.txt'; + $filename = !empty($params['filename']) ? $params['filename'] : ''; + $operation = !empty($params['operation']) ? $params['operation'] : 'create'; + + if (!$filename) { + $filename = $prefix . $this->udate($format) . $ext; + } + + /** @var Twig $twig */ + $twig = $this->grav['twig']; + $vars = [ + 'form' => $form + ]; + + // Process with Twig + $filename = $twig->processString($filename, $vars); + + $locator = $this->grav['locator']; + $path = $locator->findResource('user://data', true); + $dir = $path . DS . $form->name(); + $fullFileName = $dir. DS . $filename; + + $file = File::instance($fullFileName); + + if ($operation === 'create') { + $body = $twig->processString(!empty($params['body']) ? $params['body'] : '{% include "forms/data.txt.twig" %}', + $vars); + $file->save($body); + } elseif ($operation === 'add') { + if (!empty($params['body'])) { + // use body similar to 'create' action and append to file as a log + $body = $twig->processString($params['body'], $vars); + + // create folder if it doesn't exist + if (!file_exists($dir)) { + Folder::create($dir); + } + + // append data to existing file + file_put_contents($fullFileName, $body, FILE_APPEND | LOCK_EX); + } else { + // serialize YAML out to file for easier parsing as data sets + $vars = $vars['form']->value()->toArray(); + + foreach ($form->fields as $field) { + if (!empty($field['process']['ignore'])) { + unset($vars[$field['name']]); + } + } + + if (file_exists($fullFileName)) { + $data = Yaml::parse($file->content()); + if (count($data) > 0) { + array_unshift($data, $vars); + } else { + $data[] = $vars; + } + } else { + $data[] = $vars; + } + + $file->save(Yaml::dump($data)); + } + } + break; + } + } + + /** + * Custom field logic can go in here + * + * @param Event $event + */ + public function onFormValidationProcessed(Event $event) + { + // special check for honeypot field + foreach ($event['form']->fields() as $field) { + if ($field['type'] === 'honeypot' && !empty($event['form']->value($field['name']))) { + throw new ValidationException('Are you a bot?'); + } + } + } + + /** + * Handle form validation error + * + * @param Event $event An event object + * @throws \Exception + */ + public function onFormValidationError(Event $event) + { + $form = $event['form']; + if (isset($event['message'])) { + $form->status = 'error'; + $form->message = $event['message']; + $form->messages = $event['messages']; + } + + $uri = $this->grav['uri']; + $route = $uri->route(); + + /** @var Twig $twig */ + $twig = $this->grav['twig']; + $twig->twig_vars['form'] = $form; + + /** @var Pages $pages */ + $pages = $this->grav['pages']; + $page = $pages->dispatch($route, true); + + if ($page) { + unset($this->grav['page']); + $this->grav['page'] = $page; + } + + $event->stopPropagation(); + } + + /** + * Get list of form field types specified in this plugin. Only special types needs to be listed. + * + * @return array + */ + public function getFormFieldTypes() + { + return [ + 'column' => [ + 'input@' => false + ], + 'columns' => [ + 'input@' => false + ], + 'fieldset' => [ + 'input@' => false + ], + 'conditional' => [ + 'input@' => false + ], + 'display' => [ + 'input@' => false + ], + 'spacer' => [ + 'input@' => false + ], + 'captcha' => [ + 'input@' => false + ] + ]; + } + + /** + * Process a form + * + * Currently available processing tasks: + * + * - fillWithCurrentDateTime + * + * @param Form $form + */ + protected function process($form) + { + foreach ($form->fields as $field) { + if (!empty($field['process']['fillWithCurrentDateTime'])) { + $form->setData($field['name'], gmdate('D, d M Y H:i:s', time())); + } + } + } + + /** + * Create unix timestamp for storing the data into the filesystem. + * + * @param string $format + * @param int $utimestamp + * + * @return string + */ + private function udate($format = 'u', $utimestamp = null) + { + if (null === $utimestamp) { + $utimestamp = microtime(true); + } + + $timestamp = floor($utimestamp); + $milliseconds = round(($utimestamp - $timestamp) * 1000000); + + return date(preg_replace('`(?slug(); + } + + return $name; + } + + /** + * function to get a specific form + * + * @param null|array|string $data optional form `name` + * + * @return null|Form + */ + public function getForm($data = null) + { + $page_route = null; + $form_name = null; + + if (is_array($data)) { + if (isset($data['name'])) { + $form_name = $data['name']; + } + if (isset($data['route'])) { + $page_route = $data['route']; + } + } elseif (is_string($data)) { + $form_name = $data; + } + + // if no form name, use the first form found in the page + if (!$form_name) { + // If page route not provided, use the current page + if (!$page_route) { + // Get page route + $page_route = $this->grav['page']->route(); + + // fallback using current URI if page not initialized yet + if (!$page_route) { + $page_route = $this->getCurrentPageRoute(); + } + } + + if (isset($this->forms[$page_route])) { + $forms = $this->forms[$page_route]; + $first_form = array_shift($forms); + $form_name = $first_form['name']; + } else { + //No form on this route. Try looking up in the current page first + return new Form($this->grav['page']); + } + } + + // return the form you are looking for if available + return $this->getFormByName($form_name); + } + + /** + * Get current page's route + * + * @return mixed + */ + protected function getCurrentPageRoute() + { + $path = $this->grav['uri']->route(); + $path = $path ?: '/'; + return $path; + } + + /** + * Retrieve a form based on the form name + * + * @param $form_name + * @return mixed + */ + protected function getFormByName($form_name) + { + if (array_key_exists($form_name, $this->flat_forms)) { + return $this->flat_forms[$form_name]; + } + return null; + } + + /** + * Determine if the page has a form submission that should be processed + * + * @return bool + */ + protected function shouldProcessForm() + { + $status = isset($_POST) && isset($_POST['form-nonce']); + $refresh_prevention = null; + + if ($status && $this->form()) { + // Set page template if passed by form + if (isset($this->form->template)) { + $this->grav['page']->template($this->form->template); + } + + if (!is_null($this->form->refresh_prevention)) { + $refresh_prevention = (bool) $this->form->refresh_prevention; + } else { + $refresh_prevention = $this->config->get('plugins.form.refresh_prevention', false); + } + + $unique_form_id = filter_input(INPUT_POST, '__unique_form_id__', FILTER_SANITIZE_STRING); + + if ($refresh_prevention && $unique_form_id) { + if (($this->grav['session']->unique_form_id != $unique_form_id)) { + $this->grav['session']->unique_form_id = $unique_form_id; + } else { + $status = false; + $this->form->message = $this->grav['language']->translate('PLUGIN_FORM.FORM_ALREADY_SUBMITTED'); + $this->form->status = 'error'; + } + } + } + + return $status; + } + + /** + * Flatten the forms array into something that can be more easily searched + */ + protected function flattenForms() + { + $this->flat_forms = Utils::arrayFlatten($this->forms); + } + + /** + * Get the current form, should already be processed but can get it directly from the page if necessary + * + * @param null $page + * @return Form|mixed + */ + protected function form($page = null) + { + // Regenerate list of flat_forms if not already populated + if (empty($this->flat_forms)) { + $this->flattenForms(); + } + + if (null === $this->form) { + $current_form_name = $this->getFormName($this->grav['page']); + $this->form = $this->getFormByName($current_form_name); + } + + // last attempt using current page's form + if (null == $this->form) { + + // try to get the page if possible + if ($page == null) { + $page = $this->grav['page']; + } + + if ($page) { + $header = $page->header(); + + if (isset($header->form)) { + $this->form = new Form($page); + } + + } + + } + return $this->form; + } +} diff --git a/user/plugins/form/form.yaml b/user/plugins/form/form.yaml new file mode 100644 index 0000000..44c8154 --- /dev/null +++ b/user/plugins/form/form.yaml @@ -0,0 +1,12 @@ +enabled: true +built_in_css: true +refresh_prevention: false +files: + multiple: false # To allow multiple files, default is single + limit: 10 # Number of allowed files per field (multiple required) + destination: 'self@' # Where to upload the files (path and self@, page@, theme@) + avoid_overwriting: false # Prevent files with the same name to be overridden. Date prefix will be added + random_name: false # Generate a random 15 long string name for the uploaded files + filesize: 0 # Maximum file size allowed (in MB) + accept: # List of mime/types or file extensions allowed (ie, image/*,.zip,.mp4) + - image/* diff --git a/user/plugins/form/gulpfile.js b/user/plugins/form/gulpfile.js new file mode 100644 index 0000000..270824c --- /dev/null +++ b/user/plugins/form/gulpfile.js @@ -0,0 +1,53 @@ +'use strict'; + +var gulp = require('gulp'), + util = require('util'), + path = require('path'), + immutable = require('immutable'), + gulpWebpack = require('gulp-webpack'), + webpack = require('webpack'), + sourcemaps = require('gulp-sourcemaps'), + exec = require('child_process').execSync, + pwd = exec('pwd').toString(); + +var plugins = {}, + base = immutable.fromJS(require('./webpack.conf.js')), + options = { + prod: base.mergeDeep({ + devtool: 'source-map', + plugins: [ + new webpack.DefinePlugin({ + 'process.env': { NODE_ENV: '"production"' } + }), + new webpack.optimize.UglifyJsPlugin({ + sourceMap: true, + compress: { + warnings: false + } + }), + new webpack.ProvidePlugin(plugins) + ], + output: { + filename: 'form.min.js' + } + }) + }; + +var compileJS = function(watch) { + var prodOpts = options.prod.set('watch', watch); + + return gulp.src('app/main.js') + .pipe(gulpWebpack(prodOpts.toJS())) + .pipe(gulp.dest('assets/')); +}; + +gulp.task('js', function() { + compileJS(false); +}); + +gulp.task('watch', function() { + compileJS(true); +}); + +gulp.task('all', ['js']); +gulp.task('default', ['all']); \ No newline at end of file diff --git a/user/plugins/form/hebe.json b/user/plugins/form/hebe.json new file mode 100644 index 0000000..861d235 --- /dev/null +++ b/user/plugins/form/hebe.json @@ -0,0 +1,15 @@ +{ + "project":"grav-plugin-form", + "platforms":{ + "grav":{ + "nodes":{ + "plugin":[ + { + "source":"/", + "destination":"/user/plugins/form" + } + ] + } + } + } +} diff --git a/user/plugins/form/languages.yaml b/user/plugins/form/languages.yaml new file mode 100644 index 0000000..565ec8f --- /dev/null +++ b/user/plugins/form/languages.yaml @@ -0,0 +1,374 @@ +en: + PLUGIN_FORM: + NOT_VALIDATED: "Form not validated. One or more required fields are missing." + NONCE_NOT_VALIDATED: "Oops there was a problem, please check your input and submit the form again." + FILES: "Files Upload" + FORM_ALREADY_SUBMITTED: "This form has already been submitted." + ALLOW_MULTIPLE: "Allow More than one file" + ALLOW_MULTIPLE_HELP: "Allows to select more than one file for upload." + DESTINATION: "Destination" + DESTINATION_HELP: "The location where the files should be uploaded to" + ACCEPT: "Allowed MIME Types" + ACCEPT_HELP: "A list of MIME Types that are allowed for upload" + ERROR_VALIDATING_CAPTCHA: "Error validating the Captcha" + DATA_SUMMARY: "Here is the summary of what you wrote to us:" + NO_FORM_DATA: "No form data available" + RECAPTCHA: "ReCaptcha" + RECAPTCHA_SITE_KEY: "Site key" + RECAPTCHA_SITE_KEY_HELP: "For more info visit https://developers.google.com/recaptcha" + RECAPTCHA_SECRET_KEY: "Secret key" + RECAPTCHA_SECRET_KEY_HELP: "For more info visit https://developers.google.com/recaptcha" + GENERAL: "General" + USE_BUILT_IN_CSS: "Use built-in CSS" + FILEUPLOAD_PREVENT_SELF: 'Cannot use "%s" outside of pages.' + FILEUPLOAD_UNABLE_TO_UPLOAD: 'Unable to upload file %s: %s' + FILEUPLOAD_UNABLE_TO_MOVE: 'Unable to move file %s to "%s"' + DROPZONE_CANCEL_UPLOAD: 'Cancel upload' + DROPZONE_CANCEL_UPLOAD_CONFIRMATION: 'Are you sure you want to cancel this upload?' + DROPZONE_DEFAULT_MESSAGE: 'Drop your files here or click in this area' + DROPZONE_FALLBACK_MESSAGE: 'Your browser does not support drag and drop file uploads.' + DROPZONE_FALLBACK_TEXT: 'Please use the fallback form below to upload your files like in the olden days.' + DROPZONE_FILE_TOO_BIG: 'File is too big ({{filesize}}MiB). Max filesize: {{maxFilesize}}MiB.' + DROPZONE_INVALID_FILE_TYPE: "You can't upload files of this type." + DROPZONE_MAX_FILES_EXCEEDED: "You can not upload any more files." + DROPZONE_REMOVE_FILE: "Remove file" + DROPZONE_REMOVE_FILE_CONFIRMATION: 'Are you sure you want to delete this file?' + DROPZONE_RESPONSE_ERROR: "Server responded with {{statusCode}} code." + YES: "Yes" + NO: "No" + REFRESH_PREVENTION: "Refresh prevention" + REFRESH_PREVENTION_HELP: "Use the form's unique ID to ensure the same form is not reprocessed when refreshing the browser" + LIMIT: "Limit" + LIMIT_HELP: "Maximum number of allowed files per field (multiple required)" + FILESIZE: "Max Filesize" + FILESIZE_HELP: "Maximum file size allowed (in MB), 0 = Use system default" + AVOID_OVERWRITING: "Avoid overwriting" + AVOID_OVERWRITING_HELP: "Prevent files with the same name to be overridden. Date prefix will be added" + RANDOM_NAME: "Random name" + RANDOM_NAME_HELP: "Generate a random 15 long string name for the uploaded files" + +de: + PLUGIN_FORM: + NOT_VALIDATED: "Formularwerte nicht gültig. Für ein oder mehrere erforderliche Felder fehlen Werte." + NONCE_NOT_VALIDATED: "Ups, es gibt da ein Problem. Eingabewerte bitte noch mal prüfen und das Formular erneut absenden." + FILES: "Dateien hochladen" + ALLOW_MULTIPLE: "Erlaube mehr als eine Datei" + ALLOW_MULTIPLE_HELP: "Erlaubt es, mehr als eine Datei zum Hochladen auszuwählen." + DESTINATION: "Ziel" + DESTINATION_HELP: "Das Ziel, wohin die Dateien hochgeladen werden sollen." + ACCEPT: "Erlaube MIME-Typen" + ACCEPT_HELP: "Eine Liste von MIME-Typen, die hochgeladen werden dürfen." + ERROR_VALIDATING_CAPTCHA: "Die Überprüfung des Captcha ist fehlgeschlagen." + +es: + PLUGIN_FORM: + NOT_VALIDATED: "Falló la validación del formulario. Uno o más campos obligatorios no fueron cubiertos." + NONCE_NOT_VALIDATED: "Oops, hay un problema, por favor revise la información e intente enviar el formulario otra vez." + FILES: "Subida de Ficheros" + ALLOW_MULTIPLE: "Permitir más de un fichero" + ALLOW_MULTIPLE_HELP: "Permitir seleccionar más de un fichero para subir." + DESTINATION: "Destino" + DESTINATION_HELP: "El lugar de destino al que subir los ficheros" + ACCEPT: "MIME Types permitidos" + ACCEPT_HELP: "Una lista de MIME Types que se permiten subir." + ERROR_VALIDATING_CAPTCHA: "Error al comprobar el Captcha" + RECAPTCHA: "ReCaptcha" + RECAPTCHA_SITE_KEY: "Site key" + RECAPTCHA_SITE_KEY_HELP: "Para más información visita https://developers.google.com/recaptcha" + RECAPTCHA_SECRET_KEY: "Secret key" + RECAPTCHA_SECRET_KEY_HELP: "Para más información visita https://developers.google.com/recaptcha" + +fr: + PLUGIN_FORM: + NOT_VALIDATED: "Formulaire non validé. Un ou plusieurs champs obligatoires sont manquants." + NONCE_NOT_VALIDATED: "Oups, un problème est survenu. Veuillez vérifier votre saisie et soumettre à nouveau le formulaire." + FILES: "Fichiers chargés" + ALLOW_MULTIPLE: "Autoriser plus d'un fichier" + ALLOW_MULTIPLE_HELP: "Permet la sélection de plusieurs fichiers pour chargement." + DESTINATION: "Destination" + DESTINATION_HELP: "L'emplacement où les fichiers doivent être chargés." + ACCEPT: "Autoriser les Types MIME" + ACCEPT_HELP: "Liste des Types MIME autorisés au chargement" + ERROR_VALIDATING_CAPTCHA: "Erreur lors de la validation du Captcha" + DATA_SUMMARY: "Voici le résumé de ce que vous nous avez écrit :" + NO_FORM_DATA: "Aucune donnée de formulaire disponible" + RECAPTCHA: "ReCaptcha" + RECAPTCHA_SITE_KEY: "Clé du site" + RECAPTCHA_SITE_KEY_HELP: "Pour plus d'informations veuillez vous rendre sur https://developers.google.com/recaptcha" + RECAPTCHA_SECRET_KEY: "Clé secrète" + RECAPTCHA_SECRET_KEY_HELP: "Pour plus d'informations veuillez vous rendre sur https://developers.google.com/recaptcha" + GENERAL: "Général" + USE_BUILT_IN_CSS: "Utiliser les CSS natifs" + FILEUPLOAD_PREVENT_SELF: "Impossible d'utiliser '%s' en dehors des pages." + FILEUPLOAD_UNABLE_TO_UPLOAD: "Impossible de charger le fichier %s: %s" + FILEUPLOAD_UNABLE_TO_MOVE: 'Impossible de déplacer le fichier %s vers "%s"' + DROPZONE_CANCEL_UPLOAD: "Annuler le chargement" + DROPZONE_CANCEL_UPLOAD_CONFIRMATION: "Êtes-vous certain de vouloir annuler ce téléchargement ?" + DROPZONE_DEFAULT_MESSAGE: "Glissez vos fichiers ici ou cliquez dans cette zone" + DROPZONE_FALLBACK_MESSAGE: "Votre navigateur ne prend pas en charge les téléchargements par glissé-déposé." + DROPZONE_FALLBACK_TEXT: "Veuillez utiliser le formulaire de secours ci-dessous pour transférer vos fichiers." + DROPZONE_FILE_TOO_BIG: "Le fichier est trop volumineux ({{filesize}}MiB). Taille maximale de fichier : {{maxFilesize}}MiB." + DROPZONE_INVALID_FILE_TYPE: "Vous ne pouvez pas charger des fichiers de ce type." + DROPZONE_MAX_FILES_EXCEEDED: "Vous ne pouvez plus télécharger de fichiers." + DROPZONE_REMOVE_FILE: "Supprimer le fichier" + DROPZONE_REMOVE_FILE_CONFIRMATION: "Êtes-vous sûr de vouloir supprimer ce fichier ?" + DROPZONE_RESPONSE_ERROR: "Le serveur a répondu avec le code {{statusCode}}." + +ru: + PLUGIN_FORM: + NOT_VALIDATED: "Форма не подтверждена. Отсутствует одно или несколько обязательных полей." + NONCE_NOT_VALIDATED: "Упс, у вас возникла проблема, проверьте свои данные и отправьте форму еще раз." + FILES: "Загрузка файлов" + FORM_ALREADY_SUBMITTED: "Эта форма уже была отправлена." + ALLOW_MULTIPLE: "Разрешить несколько файлов" + ALLOW_MULTIPLE_HELP: "Позволяет выбрать более одного файла для загрузки." + DESTINATION: "Место назначения" + DESTINATION_HELP: "Место, куда файлы должны быть загружены в" + ACCEPT: "Разрешенные MIME типы" + ACCEPT_HELP: "Список MIME типов, разрешенных для загрузки" + ERROR_VALIDATING_CAPTCHA: "Ошибка проверки Captcha" + DATA_SUMMARY: "Вот краткое изложение того, что вы нам написали:" + NO_FORM_DATA: "Данные формы отсутствуют" + RECAPTCHA: "ReCaptcha" + RECAPTCHA_SITE_KEY: "Site key" + RECAPTCHA_SITE_KEY_HELP: "Для получения дополнительной информации посетите https://developers.google.com/recaptcha" + RECAPTCHA_SECRET_KEY: "Secret key" + RECAPTCHA_SECRET_KEY_HELP: "Для получения дополнительной информации посетите https://developers.google.com/recaptcha" + GENERAL: "Общие" + USE_BUILT_IN_CSS: "Использовать встроенный CSS" + FILEUPLOAD_PREVENT_SELF: 'Нельзя использовать "%s" за пределами страниц.' + FILEUPLOAD_UNABLE_TO_UPLOAD: 'Не удалось загрузить файл %s: %s' + FILEUPLOAD_UNABLE_TO_MOVE: 'Не удалось переместить файл %s в "%s"' + DROPZONE_CANCEL_UPLOAD: 'Отменить загрузку' + DROPZONE_CANCEL_UPLOAD_CONFIRMATION: 'Вы действительно хотите отменить эту загрузку?' + DROPZONE_DEFAULT_MESSAGE: 'Перетащите свои файлы сюда или щелкните в этой области' + DROPZONE_FALLBACK_MESSAGE: 'Ваш браузер не поддерживает загрузку файлов с перетаскиванием.' + DROPZONE_FALLBACK_TEXT: 'Пожалуйста, используйте приведенную ниже форму для загрузки ваших файлов, как в старые времена.' + DROPZONE_FILE_TOO_BIG: 'Файл слишком большой ({{filesize}}мб). Максимальный размер файла: {{maxFilesize}}мб.' + DROPZONE_INVALID_FILE_TYPE: "Вы не можете загружать файлы этого типа." + DROPZONE_MAX_FILES_EXCEEDED: "Вы не можете загружать больше файлов." + DROPZONE_REMOVE_FILE: "Удалить файл" + DROPZONE_REMOVE_FILE_CONFIRMATION: 'Вы действительно хотите удалить этот файл?' + DROPZONE_RESPONSE_ERROR: "Сервер ответил кодом {{statusCode}}." + YES: "Да" + NO: "Нет" + REFRESH_PREVENTION: "Предотвращение обновления" + REFRESH_PREVENTION_HELP: "Используйте уникальный идентификатор формы, чтобы гарантировать, что одна и та же форма не будет отправляться заново при обновлении страницы браузера" + LIMIT: "Лимит" + LIMIT_HELP: "Максимальное количество разрешенных файлов в поле (требуется несколько)" + FILESIZE: "Максимальный размер файла" + FILESIZE_HELP: "Максимально допустимый размер файла (в МБ), 0 = Использовать системные установки по умолчанию" + AVOID_OVERWRITING: "Избегать перезаписи" + AVOID_OVERWRITING_HELP: "Не допускать перезаписи файлов с тем же именем. Будет добавлен префикс с датой" + RANDOM_NAME: "Случайное имя" + RANDOM_NAME_HELP: "Создавать случайное строковое имя из 15 символов для загруженных файлов" + +hr: + PLUGIN_FORM: + NOT_VALIDATED: "Formular nije validiran. Jedan ili više traženih polja nedostaju." + NONCE_NOT_VALIDATED: "Ups, došlo je do problema, molimo provjerite svoj unos i pokušajte opet." + FILES: "Upload Fajlova" + ALLOW_MULTIPLE: "Dopusti više od jednog fajla" + DESTINATION: "Destinacija" + DESTINATION_HELP: "Lokacija gdje bi fajlovi trebali biti uploadani" + ACCEPT: "Dopušteni MIME Tipovi" + ACCEPT_HELP: "Lista dopuštenih MIME Tipova koji su dozvoljeni za upload" + ERROR_VALIDATING_CAPTCHA: "Greška pri validiranju Captcha" + +hu: + PLUGIN_FORM: + NOT_VALIDATED: "Érvénytelen az űrlap. Egy vagy több kötelező mező nincs kitöltve." + NONCE_NOT_VALIDATED: "Upsz, van egy kis probléma, kérlek nézd át az űrlapot, majd küldd el újra." + FILES: "Fájlok Feltöltése" + ALLOW_MULTIPLE: "Több fájl feltöltése" + ALLOW_MULTIPLE_HELP: "Engedélyezi egyszerre több állomány feltöltését." + DESTINATION: "Feltöltés Helye" + DESTINATION_HELP: "Ide lesznek feltöltve az állományok" + ACCEPT: "Engedélyezett MIME-típusok" + ACCEPT_HELP: "A feltölthető állományok MIME-típusainak listája" + ERROR_VALIDATING_CAPTCHA: "Hiba lépett fel a Captcha validálása során" + +it: + PLUGIN_FORM: + NOT_VALIDATED: "Il Form risulta invalido. Uno o più campi risultano omessi." + NONCE_NOT_VALIDATED: "Oops è stato riscontrato un errore, si prega di ricontrollare i dati inseriti e provare di nuovo." + FILES: "Invio dei Files" + ALLOW_MULTIPLE: "Consenti più di un file" + ALLOW_MULTIPLE_HELP: "Permette la selezione di più di un file per l'upload" + DESTINATION: "Destinazione" + DESTINATION_HELP: "La destinazione dove i files vengono uploadati" + ACCEPT: "Tipi di MIME Concessi" + ACCEPT_HELP: "Una lista di tipi di MIME che sono permessi per l'upload" + ERROR_VALIDATING_CAPTCHA: "Errore durante la validazione del Captcha" + DATA_SUMMARY: "Ecco il riassunto di ciò che ci hai scritto:" + NO_FORM_DATA: "Nessuna informazione disponibile" + RECAPTCHA: "ReCaptcha" + RECAPTCHA_SITE_KEY: "Site key" + RECAPTCHA_SITE_KEY_HELP: "Per maggiori informazioni visita https://developers.google.com/recaptcha" + RECAPTCHA_SECRET_KEY: "Chiave segreta" + RECAPTCHA_SECRET_KEY_HELP: "Per maggiori informazioni visita https://developers.google.com/recaptcha" + GENERAL: "Generale" + USE_BUILT_IN_CSS: "Usa CSS incorporato" + FILEUPLOAD_PREVENT_SELF: 'Non si può usare "%s" fuori dalle pagine.' + FILEUPLOAD_UNABLE_TO_UPLOAD: 'Impossibile caricare il file %s: %s' + FILEUPLOAD_UNABLE_TO_MOVE: 'Impossibile muovere il file %s to "%s"' + DROPZONE_CANCEL_UPLOAD: 'Trasferimento annullato' + DROPZONE_CANCEL_UPLOAD_CONFIRMATION: 'Sei sicuro di voler cancellare questo trasferimento?' + DROPZONE_DEFAULT_MESSAGE: "Trascina qui i tuoi file o clicca su quest'area" + DROPZONE_FALLBACK_MESSAGE: 'Il tuo browser non supporta il trascinamento dei file per il trasferimento.' + DROPZONE_FALLBACK_TEXT: 'Utilizza il modulo di riserva qui sotto per caricare i tuoi file come ai vecchi tempi.' + DROPZONE_FILE_TOO_BIG: 'Il file è troppo grande ({{filesize}}MiB). Dimensione massima consentita: {{maxFilesize}}MiB.' + DROPZONE_INVALID_FILE_TYPE: "Non puoi caricare questo tipo di file" + DROPZONE_MAX_FILES_EXCEEDED: "Non puoi caricare ulteriori file, hai raggiunto il limite consentito." + DROPZONE_REMOVE_FILE: "Rimuovi il file" + DROPZONE_REMOVE_FILE_CONFIRMATION: 'Sei sicuro di voler eliminare questo file??' + DROPZONE_RESPONSE_ERROR: "Il Server ha risposto con il codice {{statusCode}}." + YES: "Si" + NO: "No" + +ro: + PLUGIN_FORM: + NOT_VALIDATED: "Formularul nu a fost validat. Unul sau mai multe câmpuri sunt goale." + NONCE_NOT_VALIDATED: "Oops a apărut o problemă, vă rugăm verificați datele introduse și trimiteți formularul din nou." + FILES: "Încărcare fișiere" + ALLOW_MULTIPLE: "Permiteți mai multe fișiere" + ALLOW_MULTIPLE_HELP: "Vă permite să selectați mai multe fișiere pentru încărcare." + DESTINATION: "Destinație" + DESTINATION_HELP: "Locația unde vor fi încărcate fișierele." + ACCEPT: "Permite tipuri MIME " + ACCEPT_HELP: "O listă cu tipuri MIME care sunt permise la încărcare." + ERROR_VALIDATING_CAPTCHA: "Eroare la validarea Captcha." + DATA_SUMMARY: "Mai jos aveți un rezumat al mesajului pe care ni l-ați trimis:" + NO_FORM_DATA: "Nu e disponibilă nici o dată pentru formular" + RECAPTCHA: "ReCaptcha" + RECAPTCHA_SITE_KEY: "Cheia pentru Site" + RECAPTCHA_SITE_KEY_HELP: "Pentru mai multe detalii vă rugăm vizitați https://developers.google.com/recaptcha" + RECAPTCHA_SECRET_KEY: "Cheia secretă pentru Site" + RECAPTCHA_SECRET_KEY_HELP: "Pentru mai multe detalii vă rugăm vizitați https://developers.google.com/recaptcha" + +cs: + PLUGIN_FORM: + NOT_VALIDATED: "Formulář nebyl ověřen. Chybí jedno nebo více povinných polí." + NONCE_NOT_VALIDATED: "Jejda, došlo k problému, zkontrolujte vstupní stránku a znovu odešlete formulář." + FILES: "Nahrávání souborů" + ALLOW_MULTIPLE: "Povolit více než jeden soubor" + ALLOW_MULTIPLE_HELP: "Umožňuje vybrat více než jeden soubor pro nahrání." + DESTINATION: "Cílové umístění" + DESTINATION_HELP: "Místo, kam mají být soubory nahrány" + ACCEPT: "Povolené MIME typy" + ACCEPT_HELP: "Seznam MIME typů souborů povolených pro upload" + ERROR_VALIDATING_CAPTCHA: "Nepodařilo se ověřit CAPTCHA (kontrola proti spamu)" + DATA_SUMMARY: "Shrnutí toho, co jste nám napsali:" + NO_FORM_DATA: "Formulář neobsahuje žádná data" + RECAPTCHA: "ReCaptcha" + RECAPTCHA_SITE_KEY: "Site key" + RECAPTCHA_SITE_KEY_HELP: "Více informací https://developers.google.com/recaptcha" + RECAPTCHA_SECRET_KEY: "Secret key" + RECAPTCHA_SECRET_KEY_HELP: "Více informací https://developers.google.com/recaptcha" + GENERAL: "Všeobecné" + USE_BUILT_IN_CSS: "Použít built-in CSS" + FILEUPLOAD_PREVENT_SELF: 'Nelze použít "% s" mimo stránky.' + FILEUPLOAD_UNABLE_TO_UPLOAD: 'Nelze nahrát soubor %s: %s' + FILEUPLOAD_UNABLE_TO_MOVE: 'Nelze přesunout soubor %s do "%s"' + DROPZONE_CANCEL_UPLOAD: 'Zrušit upload' + DROPZONE_CANCEL_UPLOAD_CONFIRMATION: 'Opravdu chcete zrušit nahrávání souboru?' + DROPZONE_DEFAULT_MESSAGE: 'Přetáhněte sem soubory nebo klikněte v tomto prostoru' + DROPZONE_FALLBACK_MESSAGE: 'Váš prohlížeč nepodporuje nahrávání souborů táhni a pusť.' + DROPZONE_FALLBACK_TEXT: 'Použijte níže uvedený formulář pro nahrání souborů, jako v minulých dnech.' + DROPZONE_FILE_TOO_BIG: 'Soubor je příliš velký ({{filesize}}MiB). Max. velikost souboru: {{maxFilesize}}MiB.' + DROPZONE_INVALID_FILE_TYPE: "Nelze nahrát soubory tohoto typu." + DROPZONE_MAX_FILES_EXCEEDED: "Nelze nahrát další soubory." + DROPZONE_REMOVE_FILE: "Odstranit soubor" + DROPZONE_REMOVE_FILE_CONFIRMATION: 'Opravdu chcete tento soubor smazat?' + DROPZONE_RESPONSE_ERROR: "Server vrátil chybový kód: {{statusCode}}." + YES: "Ano" + NO: "Ne" +pl: + PLUGIN_FORM: + NOT_VALIDATED: "Formularz został odrzucony. Jedno lub więcej pól wymaga wypełnienia." + NONCE_NOT_VALIDATED: "Ups, pojawił się problem. Proszę sprawdź czy wszystkie pola zostały wypełnione i wyślij formularz ponownie." + FILES: "Plik przesłany." + FORM_ALREADY_SUBMITTED: "Ten formularz został już wysłany." + ALLOW_MULTIPLE: "Zezwól na więcej niż jeden plik." + ALLOW_MULTIPLE_HELP: "Zezwól na przesłanie więcej niż jednego pliku." + DESTINATION: "Przeznaczenie." + DESTINATION_HELP: "Lokalizacja przesłanego pliku." + ACCEPT: "Zezwól na typ MIME." + ACCEPT_HELP: "Lista wspieranych do przesłania typów MIME." + ERROR_VALIDATING_CAPTCHA: "Błąd walidacji Captcha." + DATA_SUMMARY: "Oto podsumowanie informacji, które do nas napisałeś:" + NO_FORM_DATA: "Brak dostępnych danych formularza" + RECAPTCHA: "ReCaptcha" + RECAPTCHA_SITE_KEY: "Klucz strony" + RECAPTCHA_SITE_KEY_HELP: "Aby uzyskać więcej informacji odwiedź https://developers.google.com/recaptcha" + RECAPTCHA_SECRET_KEY: "Tajny klucz" + RECAPTCHA_SECRET_KEY_HELP: "Aby uzyskać więcej informacji odwiedź https://developers.google.com/recaptcha" + GENERAL: "Ogólne" + USE_BUILT_IN_CSS: "Użyj wbudowanych styli CSS" + FILEUPLOAD_PREVENT_SELF: 'Nie można użyć "%s" poza stronami.' + FILEUPLOAD_UNABLE_TO_UPLOAD: 'Nie można przesłać plików %s: %s' + FILEUPLOAD_UNABLE_TO_MOVE: 'Nie można przenieść plików z %s do "%s"' + DROPZONE_CANCEL_UPLOAD: 'Anuluj przesyłanie' + DROPZONE_CANCEL_UPLOAD_CONFIRMATION: 'Czy na pewno chcesz anulować przesyłanie?' + DROPZONE_DEFAULT_MESSAGE: 'Upuść pliki tutaj lub kliknij w tym obszarze' + DROPZONE_FALLBACK_MESSAGE: 'Twoja przelądarka nie obsługują funkcji przeciągnij i upuść.' + DROPZONE_FALLBACK_TEXT: 'Proszę użyć zapasowego formularza do przesyłania plików znajdującego się poniżej.' + DROPZONE_FILE_TOO_BIG: 'Plik jest zbyt duży ({{filesize}}MiB). Maksymalna wielkość pliku to: {{maxFilesize}}MiB.' + DROPZONE_INVALID_FILE_TYPE: "Nie można przesłać pliku. Format nie jest obsługiwany." + DROPZONE_MAX_FILES_EXCEEDED: "Nie można przesłać więcej plików." + DROPZONE_REMOVE_FILE: "Usuń plik" + DROPZONE_REMOVE_FILE_CONFIRMATION: 'Czy na pewno chcesz usunąć plik?' + DROPZONE_RESPONSE_ERROR: "Status serwera {{statusCode}}." + YES: "Tak" + NO: "Nie" + REFRESH_PREVENTION: "Zapobiegaj odświeżaniu" + REFRESH_PREVENTION_HELP: "Użyj unikatowego identyfikatora ID , aby upewnić się, że przeglądarka nie przetworzy formularza ponownie." + +nl: + PLUGIN_FORM: + NOT_VALIDATED: "Formulier niet gevalideerd. Een of meerdere verplichte velden ontbreken." + NONCE_NOT_VALIDATED: "Oeps er was een probleem, controleer je input en stuur het formulier opnieuw." + FILES: "Bestanden geupload" + FORM_ALREADY_SUBMITTED: "Dit formulier is al eerder verstuurd." + ALLOW_MULTIPLE: "Meer dan een bestand toegestaan" + ALLOW_MULTIPLE_HELP: "Staat toe dat meer dan een bestand geselecteerd kan worden voor uploaden." + DESTINATION: "Bestemming" + DESTINATION_HELP: "De lokatie waar de bestanden naartoe moeten worden geupload" + ACCEPT: "Toegestane MIME types" + ACCEPT_HELP: "Een lijst van MIME types welke zijn toegestaan om te uploaden" + ERROR_VALIDATING_CAPTCHA: "Fout bij Captcha validatie" + DATA_SUMMARY: "Hier is de samenvatting van wat u ons heeft gestuurd:" + NO_FORM_DATA: "Geen formdata beschikbaar" + RECAPTCHA: "ReCaptcha" + RECAPTCHA_SITE_KEY: "Site sleutel" + RECAPTCHA_SITE_KEY_HELP: "Voor meer informatie ga naar https://developers.google.com/recaptcha" + RECAPTCHA_SECRET_KEY: "Geheime sleutel" + RECAPTCHA_SECRET_KEY_HELP: "Voor meer informatie ga naar https://developers.google.com/recaptcha" + GENERAL: "Algemeen" + USE_BUILT_IN_CSS: "Gebruik ingebouwde CSS" + FILEUPLOAD_PREVENT_SELF: 'Kan "%s" niet buiten paginas gebruiken.' + FILEUPLOAD_UNABLE_TO_UPLOAD: 'Niet mogelijk om bestand %s: %s te uploaden' + FILEUPLOAD_UNABLE_TO_MOVE: 'Niet mogelijk om bestand %s naar "%s" te verplaatsen' + DROPZONE_CANCEL_UPLOAD: 'Upload annuleren' + DROPZONE_CANCEL_UPLOAD_CONFIRMATION: 'Weet u zeker dat u deze upload wilt annuleren?' + DROPZONE_DEFAULT_MESSAGE: 'Sleep hier uw bestanden heen of klik in dit gebied' + DROPZONE_FALLBACK_MESSAGE: 'Uw browser ondersteund geen drag en drop bestand uploads.' + DROPZONE_FALLBACK_TEXT: 'Gebruik alsublieft het fallback formulier hieronder om uw bestanden te uploaden zoals vroeger.' + DROPZONE_FILE_TOO_BIG: 'Bestand is te groot ({{filesize}}MiB). Maximale bestandsgrootte: {{maxFilesize}}MiB.' + DROPZONE_INVALID_FILE_TYPE: "U kunt geen bestanden uploaden van dit type." + DROPZONE_MAX_FILES_EXCEEDED: "U kunt niet meer bestanden uploaden." + DROPZONE_REMOVE_FILE: "Verwijder bestand" + DROPZONE_REMOVE_FILE_CONFIRMATION: 'Weet u zeker dat u het bestand wilt verwijderen?' + DROPZONE_RESPONSE_ERROR: "Server reageert met {{statusCode}} code." + YES: "Ja" + NO: "Nee" + REFRESH_PREVENTION: "Verversbescherming" + REFRESH_PREVENTION_HELP: "Gebruik het unieke ID van her formulier om zeker te stellen dat hetzelfde formulier niet opnieuw wordt verwerkt als de browser ververst wordt" + LIMIT: "Limiet" + LIMIT_HELP: "Maximum aantal toegestande bestanden per veld (meerdere vereist)" + FILESIZE: "Maximale bestandsgrootte" + FILESIZE_HELP: "Maximale bestandsgrootte toegestaan (in MB), 0 = Gebruik systeem standaard" + AVOID_OVERWRITING: "Vermijd overschrijven" + AVOID_OVERWRITING_HELP: "Voorkom dat bestanden met dezelfde naam worden overschreven. Datum prefix wordt toegevoegd" + RANDOM_NAME: "Willekeurige naam" + RANDOM_NAME_HELP: "Genereer een willekeurige naam van 15 karakters voor de geuploade bestanden" diff --git a/user/plugins/form/package.json b/user/plugins/form/package.json new file mode 100644 index 0000000..74b9c6a --- /dev/null +++ b/user/plugins/form/package.json @@ -0,0 +1,35 @@ +{ + "name": "grav-plugin-form", + "version": "1.0.0", + "description": "Grav Plugin Form", + "repository": "https://github.com/getgrav/grav-plugin-form", + "main": "app/main.js", + "scripts": { + "watch": "webpack --watch --progress --colors --config webpack.conf.js", + "dev": "webpack --progress --colors --config webpack.conf.js", + "prod": "NODE_ENV=production webpack -p --config webpack.conf.js", + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "RocketTheme, LLC", + "license": "MIT", + "dependencies": { + "dropzone": "^4.3.0" + }, + "devDependencies": { + "babel-core": "^6.14.0", + "babel-loader": "^6.2.5", + "babel-polyfill": "^6.13.0", + "babel-preset-es2015": "^6.14.0", + "eslint": "^3.4.0", + "eslint-loader": "^1.5.0", + "exports-loader": "^0.6.3", + "gulp": "^3.9.1", + "gulp-sourcemaps": "^1.6.0", + "gulp-util": "^3.0.7", + "gulp-webpack": "^1.5.0", + "immutable": "^3.8.1", + "imports-loader": "^0.6.5", + "json-loader": "^0.5.4", + "webpack": "^1.13.2" + } +} diff --git a/user/plugins/form/templates/form-messages.html.twig b/user/plugins/form/templates/form-messages.html.twig new file mode 100644 index 0000000..52c438a --- /dev/null +++ b/user/plugins/form/templates/form-messages.html.twig @@ -0,0 +1,2 @@ +{% include 'partials/form-messages.html.twig' %} +{% do http_response_code(form.responseCode) %} diff --git a/user/plugins/form/templates/form-messages.json.twig b/user/plugins/form/templates/form-messages.json.twig new file mode 100644 index 0000000..00b9085 --- /dev/null +++ b/user/plugins/form/templates/form-messages.json.twig @@ -0,0 +1,2 @@ +{% include 'partials/form-messages.json.twig' %} +{% do http_response_code(form.responseCode) %} diff --git a/user/plugins/form/templates/form.html.twig b/user/plugins/form/templates/form.html.twig new file mode 100644 index 0000000..3523d06 --- /dev/null +++ b/user/plugins/form/templates/form.html.twig @@ -0,0 +1,8 @@ +{% extends 'partials/base.html.twig' %} + +{% block content %} + + {{ content|raw }} + {% include "forms/form.html.twig" %} + +{% endblock %} diff --git a/user/plugins/form/templates/form.json.twig b/user/plugins/form/templates/form.json.twig new file mode 100644 index 0000000..f6ba33f --- /dev/null +++ b/user/plugins/form/templates/form.json.twig @@ -0,0 +1 @@ +{% extends 'forms/ajax.json.twig' %} diff --git a/user/plugins/form/templates/formdata.html.twig b/user/plugins/form/templates/formdata.html.twig new file mode 100644 index 0000000..57e8487 --- /dev/null +++ b/user/plugins/form/templates/formdata.html.twig @@ -0,0 +1,20 @@ +{% extends 'partials/base.html.twig' %} + +{% if form is null %} + {% set form = grav.session.getFlashObject('form') %} +{% endif %} + +{% block content %} + {{ content|raw }} + + {% if form %} + {% include 'partials/form-messages.html.twig' %} + +

                                                                      {{ 'PLUGIN_FORM.DATA_SUMMARY'|t }}

                                                                      + + {% include "forms/data.html.twig" %} + {% else %} +

                                                                      {{ 'PLUGIN_FORM.NO_FORM_DATA'|t }}

                                                                      + {% endif %} + +{% endblock %} diff --git a/user/plugins/form/templates/forms/ajax.json.twig b/user/plugins/form/templates/forms/ajax.json.twig new file mode 100644 index 0000000..ccec039 --- /dev/null +++ b/user/plugins/form/templates/forms/ajax.json.twig @@ -0,0 +1,5 @@ +{% if form_json_response %} +{{ form_json_response|json_encode|raw }} +{% else %} +{} +{% endif %} \ No newline at end of file diff --git a/user/plugins/form/templates/forms/data.html.twig b/user/plugins/form/templates/forms/data.html.twig new file mode 100644 index 0000000..9cb16c2 --- /dev/null +++ b/user/plugins/form/templates/forms/data.html.twig @@ -0,0 +1 @@ +{% extends "forms/default/data.html.twig" %} diff --git a/user/plugins/form/templates/forms/data.txt.twig b/user/plugins/form/templates/forms/data.txt.twig new file mode 100644 index 0000000..c647832 --- /dev/null +++ b/user/plugins/form/templates/forms/data.txt.twig @@ -0,0 +1 @@ +{% extends "forms/default/data.txt.twig" %} diff --git a/user/plugins/form/templates/forms/default/data.html.twig b/user/plugins/form/templates/forms/default/data.html.twig new file mode 100644 index 0000000..d11ef3b --- /dev/null +++ b/user/plugins/form/templates/forms/default/data.html.twig @@ -0,0 +1,39 @@ +{% macro render_field(form, fields) %} + {% for index, field in fields %} + {% set input = attribute(field, "input@") %} + {% if input is null or input == true %} + {% if form.value(field.name) %} + {% block field %} +
                                                                      + {% block field_label %} + {{ field.label|t|e }}: + {% endblock %} + + {% block field_value %} + {% if field.type == 'checkboxes' %} +
                                                                        + {% for value in form.value(field.name) %} +
                                                                      • {{ field.options[value]|e }}
                                                                      • + {% endfor %} +
                                                                      + {% elseif field.type == 'checkbox' %} + {{ (form.value(field.name) == 1) ? "PLUGIN_FORM.YES"|t|e : "PLUGIN_FORM.NO"|t|e }} + {% elseif field.type == 'select' %} + {{ field.options[form.value(field.name)]|e }} + {% else %} + {{ string(form.value(field.name))|nl2br }} + {% endif %} + {% endblock %} +
                                                                      + {% endblock %} + {% endif %} + {% else %} + {% if field.fields %} + {{ _self.render_field(form, field.fields) }} + {% endif %} + {% endif %} + {% endfor %} +{% endmacro %} + +{{ _self.render_field(form, form.fields) }} + diff --git a/user/plugins/form/templates/forms/default/data.txt.twig b/user/plugins/form/templates/forms/default/data.txt.twig new file mode 100644 index 0000000..e262444 --- /dev/null +++ b/user/plugins/form/templates/forms/default/data.txt.twig @@ -0,0 +1,16 @@ +{%- macro render_field(form, fields) %} +{%- for index, field in fields %} + {%- set input = attribute(field, "input@") %} + {%- if input is null or input == true %} + {%- set value = form.value(field.name ?? index) %} + {{- field.name ?? index }}: {{ string(value is iterable ? value|json_encode : value|escape('yaml')) ~ "\r\n" }} + {%- else %} + {%- if field.fields %} + {{- _self.render_field(form, field.fields) }} + {%- endif %} + {%- endif %} +{%- endfor %} +{%- endmacro %} +{%- autoescape false %} +{{- _self.render_field(form, form.fields) ~ "\r\n" }} +{%- endautoescape %} \ No newline at end of file diff --git a/user/plugins/form/templates/forms/default/field.html.twig b/user/plugins/form/templates/forms/default/field.html.twig new file mode 100644 index 0000000..8fc0756 --- /dev/null +++ b/user/plugins/form/templates/forms/default/field.html.twig @@ -0,0 +1,98 @@ +{% set originalValue = originalValue is defined ? originalValue : value %} +{% set toggleableChecked = field.toggleable and (originalValue is not null and originalValue is not empty) %} +{% set isDisabledToggleable = field.toggleable and not toggleableChecked %} +{% set value = (is_object(value) or value is null ? field.default : value) %} +{% set cookie_name = 'forms-' ~ form.name ~ '-' ~ field.name %} +{% set value = (is_object(value) or value is null ? (get_cookie(cookie_name) is null ? field.default : get_cookie(cookie_name)) : value) %} +{% set errors = attribute(form.messages, field.name) %} + +{% block field %} +
                                                                      + {% block contents %} + {% if field.label is not same as(false) %} +
                                                                      + +
                                                                      + {% endif %} +
                                                                      + {% block group %} + {% block input %} +
                                                                      + {% block prepend %}{% endblock prepend %} + + {% block append %}{% endblock append %} + {% if form.inline_errors and errors %} +
                                                                      + {% for error in errors %} +

                                                                      {{ error }}

                                                                      + {% endfor %} +
                                                                      + {% endif %} +
                                                                      + {% endblock %} + {% endblock %} + {% if field.description %} +
                                                                      + + {% if field.markdown %} + {{ field.description|tu|markdown(false)|raw }} + {% else %} + {{ field.description|tu|raw }} + {% endif %} + +
                                                                      + {% endif %} + +
                                                                      + {% endblock %} +
                                                                      +{% endblock %} diff --git a/user/plugins/form/templates/forms/default/form.html.twig b/user/plugins/form/templates/forms/default/form.html.twig new file mode 100644 index 0000000..1a9f813 --- /dev/null +++ b/user/plugins/form/templates/forms/default/form.html.twig @@ -0,0 +1,83 @@ +{% if form is null %} + {% set form = grav.session.getFlashObject('form') %} +{% endif %} + +{% include 'partials/form-messages.html.twig' %} + +{% set scope = scope ?: 'data.' %} +{% set multipart = '' %} +{% set method = form.method|upper|default('POST') %} + +{% for field in form.fields %} + {% if (method == 'POST' and field.type == 'file') %} + {% set multipart = ' enctype="multipart/form-data"' %} + {% endif %} +{% endfor %} + +{% set action = form.action ? base_url ~ form.action : base_url ~ page.route ~ uri.params %} + +{% if (action == base_url_relative) %} + {% set action = base_url_relative ~ '/' ~ page.slug %} +{% endif %} + +
                                                                      + + {% block inner_markup_fields_start %}{% endblock %} + + {% for field in form.fields %} + {% if field.type == 'file' %} + {% do assets.addJs('plugin://form/assets/form.min.js') %} + {% endif %} + {% set value = form.value(field.name) %} + {% include "forms/fields/#{field.type}/#{field.type}.html.twig" ignore missing %} + {% endfor %} + + {% include "forms/fields/formname/formname.html.twig" %} + + {% block inner_markup_fields_end %}{% endblock %} + + {% block inner_markup_buttons_start %} +
                                                                      + {% endblock %} + + {% for button in form.buttons %} + {% if button.outerclasses is defined %}
                                                                      {% endif %} + {% if button.url %} + + {% endif %} + + {% if button.url %} + + {% endif %} + {% if button.outerclasses is defined %}
                                                                      {% endif %} + {% endfor %} + + {% block inner_markup_buttons_end %} +
                                                                      + {% endblock %} + + {% include 'forms/fields/uniqueid/uniqueid.html.twig' %} + {{ nonce_field('form', 'form-nonce')|raw }} +
                                                                      diff --git a/user/plugins/form/templates/forms/field.html.twig b/user/plugins/form/templates/forms/field.html.twig new file mode 100644 index 0000000..447d959 --- /dev/null +++ b/user/plugins/form/templates/forms/field.html.twig @@ -0,0 +1 @@ +{% extends "forms/default/field.html.twig" %} diff --git a/user/plugins/form/templates/forms/fields/avatar/avatar.html.twig b/user/plugins/form/templates/forms/fields/avatar/avatar.html.twig new file mode 100644 index 0000000..3386288 --- /dev/null +++ b/user/plugins/form/templates/forms/fields/avatar/avatar.html.twig @@ -0,0 +1,5 @@ +{% if form.data.avatar %} + +{% else %} + +{% endif %} \ No newline at end of file diff --git a/user/plugins/form/templates/forms/fields/captcha/captcha.html.twig b/user/plugins/form/templates/forms/fields/captcha/captcha.html.twig new file mode 100644 index 0000000..5f31820 --- /dev/null +++ b/user/plugins/form/templates/forms/fields/captcha/captcha.html.twig @@ -0,0 +1,32 @@ +{% extends "forms/field.html.twig" %} + +{% block input %} + + +
                                                                      +{% endblock %} diff --git a/user/plugins/form/templates/forms/fields/checkbox/checkbox.html.twig b/user/plugins/form/templates/forms/fields/checkbox/checkbox.html.twig new file mode 100644 index 0000000..3aab536 --- /dev/null +++ b/user/plugins/form/templates/forms/fields/checkbox/checkbox.html.twig @@ -0,0 +1,29 @@ +{% extends "forms/field.html.twig" %} + +{% block label %} +{% endblock %} + +{% block input %} + {% set id = field.id|default(field.name) ~ '-' ~ key %} +
                                                                      + + +
                                                                      +{% endblock %} diff --git a/user/plugins/form/templates/forms/fields/checkboxes/checkboxes.html.twig b/user/plugins/form/templates/forms/fields/checkboxes/checkboxes.html.twig new file mode 100644 index 0000000..d9b6b02 --- /dev/null +++ b/user/plugins/form/templates/forms/fields/checkboxes/checkboxes.html.twig @@ -0,0 +1,43 @@ +{% extends "forms/field.html.twig" %} + +{% set originalValue = value %} +{% set value = (value is null ? field.default : value) %} +{% if field.use == 'keys' and field.default %} + {% set value = field.default|merge(value) %} +{% endif %} + +{% block global_attributes %} + {{ parent() }} + data-grav-keys="{{ field.use == 'keys' ? 'true' : 'false' }}" + data-grav-field-name="{{ (scope ~ field.name)|fieldName }}" +{% endblock %} + +{% block input %} + {% for key, text in field.options %} + + {% set id = field.id|default(field.name) ~ '-' ~ key %} + {% set name = field.use == 'keys' ? key : id %} + {% set val = field.use == 'keys' ? '1' : key %} + {% set checked = (field.use == 'keys' ? value[key] : key in value) %} + {% set help = (key in field.help_options|keys ? field.help_options[key] : false) %} + +
                                                                      + + +
                                                                      + {% endfor %} +{% endblock %} diff --git a/user/plugins/form/templates/forms/fields/color/color.html.twig b/user/plugins/form/templates/forms/fields/color/color.html.twig new file mode 100644 index 0000000..b0c1f60 --- /dev/null +++ b/user/plugins/form/templates/forms/fields/color/color.html.twig @@ -0,0 +1,6 @@ +{% extends "forms/field.html.twig" %} + +{% block input_attributes %} + type="color" + {{ parent() }} +{% endblock %} diff --git a/user/plugins/form/templates/forms/fields/column/column.html.twig b/user/plugins/form/templates/forms/fields/column/column.html.twig new file mode 100644 index 0000000..970bcd0 --- /dev/null +++ b/user/plugins/form/templates/forms/fields/column/column.html.twig @@ -0,0 +1,10 @@ +{% if field.fields %} +
                                                                      + {% for field in field.fields %} + {% if field.type %} + {% set value = form.value(field.name) %} + {% include ["forms/fields/#{field.type}/#{field.type}.html.twig", 'forms/fields/text/text.html.twig'] %} + {% endif %} + {% endfor %} +
                                                                      +{% endif %} diff --git a/user/plugins/form/templates/forms/fields/columns/columns.html.twig b/user/plugins/form/templates/forms/fields/columns/columns.html.twig new file mode 100644 index 0000000..360fea2 --- /dev/null +++ b/user/plugins/form/templates/forms/fields/columns/columns.html.twig @@ -0,0 +1,10 @@ +
                                                                      +{% if field.fields %} + {% set cols = field.fields|length %} + {% for field in field.fields %} + {% set value = form.value(field.name) %} + {% include ["forms/fields/#{field.type}/#{field.type}.html.twig", 'forms/fields/column/column.html.twig'] with {'cols':cols} %} + {% endfor %} +{% endif %} +
                                                                      + diff --git a/user/plugins/form/templates/forms/fields/conditional/conditional.html.twig b/user/plugins/form/templates/forms/fields/conditional/conditional.html.twig new file mode 100644 index 0000000..bd333d0 --- /dev/null +++ b/user/plugins/form/templates/forms/fields/conditional/conditional.html.twig @@ -0,0 +1,22 @@ +{% set value = evaluate(field.condition) %} +{% set value = value == 'true' ? 1 : value %} +{% set value = value == 'false' ? 0 : value %} + +{% if value %} + {% if field.classes %} +
                                                                      + {% endif %} + + {% if field.fields %} + {% for field in field.fields %} + {% if field.type %} + {% set value = data.value(field.name) %} + {% include ["forms/fields/#{field.type}/#{field.type}.html.twig", 'forms/fields/text/text.html.twig'] %} + {% endif %} + {% endfor %} + {% endif %} + + {% if field.classes %} +
                                                                      + {% endif %} +{% endif %} diff --git a/user/plugins/form/templates/forms/fields/date/date.html.twig b/user/plugins/form/templates/forms/fields/date/date.html.twig new file mode 100644 index 0000000..4e42985 --- /dev/null +++ b/user/plugins/form/templates/forms/fields/date/date.html.twig @@ -0,0 +1,8 @@ +{% extends "forms/field.html.twig" %} + +{% block input_attributes %} + type="date" + {% if field.validate.min %}min="{{ field.validate.min }}"{% endif %} + {% if field.validate.max %}max="{{ field.validate.max }}"{% endif %} + {{ parent() }} +{% endblock %} diff --git a/user/plugins/form/templates/forms/fields/datetime/datetime.html.twig b/user/plugins/form/templates/forms/fields/datetime/datetime.html.twig new file mode 100644 index 0000000..dd8e4ce --- /dev/null +++ b/user/plugins/form/templates/forms/fields/datetime/datetime.html.twig @@ -0,0 +1,2 @@ +{# DEPRECATED. Switched to Text field until implemented properly #} +{% extends "forms/fields/text/text.html.twig" %} \ No newline at end of file diff --git a/user/plugins/form/templates/forms/fields/display/display.html.twig b/user/plugins/form/templates/forms/fields/display/display.html.twig new file mode 100644 index 0000000..ab9a5e7 --- /dev/null +++ b/user/plugins/form/templates/forms/fields/display/display.html.twig @@ -0,0 +1,19 @@ +{% extends "forms/field.html.twig" %} + +{% block input %} +
                                                                      + {% if field.markdown %} + {% if grav.twig.twig.filters['tu'] is defined %} + {{ field.content|tu|markdown|raw }} + {% else %} + {{ field.content|t|markdown|raw }} + {% endif %} + {% else %} + {% if grav.twig.twig.filters['tu'] is defined %} + {{ field.content|tu|raw }} + {% else %} + {{ field.content|t|raw }} + {% endif %} + {% endif %} +
                                                                      +{% endblock %} diff --git a/user/plugins/form/templates/forms/fields/email/email.html.twig b/user/plugins/form/templates/forms/fields/email/email.html.twig new file mode 100644 index 0000000..aa33dcf --- /dev/null +++ b/user/plugins/form/templates/forms/fields/email/email.html.twig @@ -0,0 +1,7 @@ +{% extends "forms/field.html.twig" %} + +{% block input_attributes %} + type="email" + {% if field.multiple in ['on', 'true', 1] %}multiple="multiple"{% endif %} + {{ parent() }} +{% endblock %} \ No newline at end of file diff --git a/user/plugins/form/templates/forms/fields/fieldset/fieldset.html.twig b/user/plugins/form/templates/forms/fields/fieldset/fieldset.html.twig new file mode 100644 index 0000000..b934e23 --- /dev/null +++ b/user/plugins/form/templates/forms/fields/fieldset/fieldset.html.twig @@ -0,0 +1,14 @@ +
                                                                      +{% if field.legend %} + {% if grav.twig.twig.filters['tu'] is defined %}{{ field.legend|tu }}{% else %}{{ field.legend|t }}{% endif %} +{% endif %} + +{% if field.fields %} + {% for field in field.fields %} + {% if field.type %} + {% set value = form.value(field.name) %} + {% include ["forms/fields/#{field.type}/#{field.type}.html.twig", 'forms/fields/text/text.html.twig'] %} + {% endif %} + {% endfor %} +{% endif %} +
                                                                      \ No newline at end of file diff --git a/user/plugins/form/templates/forms/fields/file/file.html.twig b/user/plugins/form/templates/forms/fields/file/file.html.twig new file mode 100644 index 0000000..0d91fb4 --- /dev/null +++ b/user/plugins/form/templates/forms/fields/file/file.html.twig @@ -0,0 +1,106 @@ +{% extends "forms/field.html.twig" %} +{% set defaults = config.plugins.form %} +{% set files = defaults.files|merge(field|default([])) %} +{% set limit = not field.multiple ? 1 : files.limit %} + +{% macro bytesToSize(bytes) -%} + {% spaceless %} + {% set kilobyte = 1024 %} + {% set megabyte = kilobyte * 1024 %} + {% set gigabyte = megabyte * 1024 %} + {% set terabyte = gigabyte * 1024 %} + + {% if bytes < kilobyte %} + {{ bytes ~ ' B' }} + {% elseif bytes < megabyte %} + {{ (bytes / kilobyte)|number_format(2, '.') ~ ' KB' }} + {% elseif bytes < gigabyte %} + {{ (bytes / megabyte)|number_format(2, '.') ~ ' MB' }} + {% elseif bytes < terabyte %} + {{ (bytes / gigabyte)|number_format(2, '.') ~ ' GB' }} + {% else %} + {{ (bytes / terabyte)|number_format(2, '.') ~ ' TB' }} + {% endif %} + {% endspaceless %} +{%- endmacro %} + +{% macro preview(path, value, global) %} + {% if value %} + {% set uri = global.grav.uri %} + {% set files = global.files %} + {% set config = global.grav.config %} + {% set route = global.context.route() %} + {% set type = global.context.content() is not null ? 'pages' : global.plugin ? 'plugins' : global.theme ? 'themes' : 'config' %} + {% set blueprint_name = global.blueprints.getFilename %} + {% if type == 'pages' %} + {% set blueprint_name = type ~ '/' ~ blueprint_name %} + {% endif %} + {% set blueprint = base64_encode(blueprint_name) %} + {% set real_path = global.form.getPagePathFromToken(path) %} + {% set remove = uri.addNonce(global.base_url_relative ~ + '/media.json' ~ + '/route' ~ config.system.param_sep ~ base64_encode(global.base_path ~ '/' ~ real_path) ~ + '/task' ~ config.system.param_sep ~ 'removeFileFromBlueprint' ~ + '/proute' ~ config.system.param_sep ~ base64_encode(route) ~ + '/blueprint' ~ config.system.param_sep ~ blueprint ~ + '/type' ~ config.system.param_sep ~ type ~ + '/field' ~ config.system.param_sep ~ files.name ~ + '/path' ~ config.system.param_sep ~ base64_encode(value.path), 'admin-form', 'admin-nonce') %} + + {% set file = value|merge({remove: remove, path: (uri.rootUrl == '/' ? '/' : uri.rootUrl ~ '/' ~ real_path) }) %} + + {% endif %} +{% endmacro %} + +{% block input %} + {% set page_can_upload = exists or (type == 'page' and not exists and not (field.destination starts with '@self' or field.destination starts with 'self@')) %} + + + {% set settings = {name: field.name, paramName: (scope ~ field.name)|fieldName ~ (files.multiple ? '[]' : ''), limit: limit, filesize: form_max_filesize, accept: files.accept} %} +
                                                                      + + + {% for path, file in value %} + {{ _self.preview(path, file, _context) }} + {% endfor %} + {% include 'forms/fields/hidden/hidden.html.twig' with {field: {name: '_json.' ~ field.name}, value:value|json_encode|e('html_attr')} %} +
                                                                      + + {% do assets.addJs('jquery', 101) %} + {% do assets.addJs('plugin://form/assets/form.min.js', { 'group': 'bottom', 'loading': 'defer' }) %} + {% do assets.addCss('plugin://form/assets/dropzone.min.css', { 'group': 'form' }) %} + {{ assets.css('form')|raw }} + {% do assets.addInlineJs(" + window.GravForm = window.GravForm || {}; + window.GravForm.config = { + current_url: '" ~ uri.route(true) ~"', + base_url_relative: '" ~ base_url_relative ~ "', + param_sep: '"~ config.system.param_sep ~ "', + form_nonce: '" ~ form.getNonce ~ "', + }; + window.GravForm.translations = {}; + window.GravForm.translations['PLUGIN_FORM'] = { + 'DROPZONE_CANCEL_UPLOAD': " ~ 'PLUGIN_FORM.DROPZONE_CANCEL_UPLOAD'|t|json_encode ~ ", + 'DROPZONE_CANCEL_UPLOAD_CONFIRMATION': " ~ 'PLUGIN_FORM.DROPZONE_CANCEL_UPLOAD_CONFIRMATION'|t|json_encode ~ ", + 'DROPZONE_DEFAULT_MESSAGE': " ~ 'PLUGIN_FORM.DROPZONE_DEFAULT_MESSAGE'|t|json_encode ~ ", + 'DROPZONE_FALLBACK_MESSAGE': " ~ 'PLUGIN_FORM.DROPZONE_FALLBACK_MESSAGE'|t|json_encode ~ ", + 'DROPZONE_FALLBACK_TEXT': " ~ 'PLUGIN_FORM.DROPZONE_FALLBACK_TEXT'|t|json_encode ~ ", + 'DROPZONE_FILE_TOO_BIG': " ~ 'PLUGIN_FORM.DROPZONE_FILE_TOO_BIG'|t|json_encode ~ ", + 'DROPZONE_INVALID_FILE_TYPE': " ~ 'PLUGIN_FORM.DROPZONE_INVALID_FILE_TYPE'|t|json_encode ~ ", + 'DROPZONE_MAX_FILES_EXCEEDED': " ~ 'PLUGIN_FORM.DROPZONE_MAX_FILES_EXCEEDED'|t|json_encode ~ ", + 'DROPZONE_REMOVE_FILE': " ~ 'PLUGIN_FORM.DROPZONE_REMOVE_FILE'|t|json_encode ~ ", + 'DROPZONE_REMOVE_FILE_CONFIRMATION': " ~ 'PLUGIN_FORM.DROPZONE_REMOVE_FILE_CONFIRMATION'|t|json_encode ~ ", + 'DROPZONE_RESPONSE_ERROR': " ~ 'PLUGIN_FORM.DROPZONE_RESPONSE_ERROR'|t|json_encode ~ " + }; + ", { 'group': 'bottom' }) %} +{% endblock %} diff --git a/user/plugins/form/templates/forms/fields/formname/formname.html.twig b/user/plugins/form/templates/forms/fields/formname/formname.html.twig new file mode 100644 index 0000000..70e2bc0 --- /dev/null +++ b/user/plugins/form/templates/forms/fields/formname/formname.html.twig @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/plugins/form/templates/forms/fields/hidden/hidden.html.twig b/user/plugins/form/templates/forms/fields/hidden/hidden.html.twig new file mode 100644 index 0000000..1c0b481 --- /dev/null +++ b/user/plugins/form/templates/forms/fields/hidden/hidden.html.twig @@ -0,0 +1,3 @@ +{% set value = (value is null ? (field.evaluate ? evaluate(field.default) : field.default) : value) %} + + diff --git a/user/plugins/form/templates/forms/fields/honeypot/honeypot.html.twig b/user/plugins/form/templates/forms/fields/honeypot/honeypot.html.twig new file mode 100644 index 0000000..c1138b1 --- /dev/null +++ b/user/plugins/form/templates/forms/fields/honeypot/honeypot.html.twig @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/user/plugins/form/templates/forms/fields/month/month.html.twig b/user/plugins/form/templates/forms/fields/month/month.html.twig new file mode 100644 index 0000000..36c0fc2 --- /dev/null +++ b/user/plugins/form/templates/forms/fields/month/month.html.twig @@ -0,0 +1,6 @@ +{% extends "forms/field.html.twig" %} + +{% block input_attributes %} + type="month" + {{ parent() }} +{% endblock %} diff --git a/user/plugins/form/templates/forms/fields/number/number.html.twig b/user/plugins/form/templates/forms/fields/number/number.html.twig new file mode 100644 index 0000000..116c7ca --- /dev/null +++ b/user/plugins/form/templates/forms/fields/number/number.html.twig @@ -0,0 +1,9 @@ +{% extends "forms/fields/text/text.html.twig" %} + +{% block input_attributes %} + type="number" + {% if field.validate.min is defined %}min="{{ field.validate.min }}"{% endif %} + {% if field.validate.max is defined %}max="{{ field.validate.max }}"{% endif %} + {% if field.validate.step is defined %}step="{{ field.validate.step }}"{% endif %} + {{ parent() }} +{% endblock %} \ No newline at end of file diff --git a/user/plugins/form/templates/forms/fields/password/password.html.twig b/user/plugins/form/templates/forms/fields/password/password.html.twig new file mode 100644 index 0000000..58047e8 --- /dev/null +++ b/user/plugins/form/templates/forms/fields/password/password.html.twig @@ -0,0 +1,7 @@ +{% extends "forms/field.html.twig" %} + +{% block input_attributes %} + type="password" + class="input" + {{ parent() }} +{% endblock %} diff --git a/user/plugins/form/templates/forms/fields/radio/radio.html.twig b/user/plugins/form/templates/forms/fields/radio/radio.html.twig new file mode 100644 index 0000000..c5af0cd --- /dev/null +++ b/user/plugins/form/templates/forms/fields/radio/radio.html.twig @@ -0,0 +1,23 @@ +{% extends "forms/field.html.twig" %} + +{% set originalValue = value %} +{% set value = (value is null ? field.default : value) %} + +{% block input %} + {% for key, text in field.options %} + {% set id = field.id|default(field.name) ~ '-' ~ key %} + +
                                                                      + + +
                                                                      + {% endfor %} +{% endblock %} diff --git a/user/plugins/form/templates/forms/fields/range/range.html.twig b/user/plugins/form/templates/forms/fields/range/range.html.twig new file mode 100644 index 0000000..3b04284 --- /dev/null +++ b/user/plugins/form/templates/forms/fields/range/range.html.twig @@ -0,0 +1,9 @@ +{% extends "forms/field.html.twig" %} + +{% block input_attributes %} + type="range" + {% if field.validate.min %}min="{{ field.validate.min }}"{% endif %} + {% if field.validate.max %}max="{{ field.validate.max }}"{% endif %} + {% if field.validate.step %}step="{{ field.validate.step }}"{% endif %} + {{ parent() }} +{% endblock %} diff --git a/user/plugins/form/templates/forms/fields/select/select.html.twig b/user/plugins/form/templates/forms/fields/select/select.html.twig new file mode 100644 index 0000000..249e539 --- /dev/null +++ b/user/plugins/form/templates/forms/fields/select/select.html.twig @@ -0,0 +1,34 @@ +{% extends "forms/field.html.twig" %} + +{% block global_attributes %} + data-grav-selectize="{{ (field.selectize is defined ? field.selectize : {})|json_encode()|e('html_attr') }}" + {{ parent() }} +{% endblock %} + +{% block input %} +
                                                                      + +
                                                                      +{% endblock %} diff --git a/user/plugins/form/templates/forms/fields/select_optgroup/select_optgroup.html.twig b/user/plugins/form/templates/forms/fields/select_optgroup/select_optgroup.html.twig new file mode 100644 index 0000000..969c532 --- /dev/null +++ b/user/plugins/form/templates/forms/fields/select_optgroup/select_optgroup.html.twig @@ -0,0 +1,44 @@ +{% extends "forms/field.html.twig" %} + +{% block global_attributes %} + data-grav-selectize="{{ (field.selectize is defined ? field.selectize : {})|json_encode()|e('html_attr') }}" + {{ parent() }} +{% endblock %} + +{% block input %} +
                                                                      + +
                                                                      +{% endblock %} 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 0000000..f0a9593 --- /dev/null +++ b/user/plugins/form/templates/forms/fields/spacer/spacer.html.twig @@ -0,0 +1,33 @@ +
                                                                      + {% if field.title %} +

                                                                      + {% if grav.twig.twig.filters['tu'] is defined %} + {{- field.title|tu|raw -}} + {% else %} + {{- field.title|t|raw -}} + {% endif %} +

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

                                                                      + {% if grav.twig.twig.filters['tu'] is defined %} + {{- field.text|tu|markdown|raw -}} + {% else %} + {{- field.text|t|markdown|raw -}} + {% endif %} +

                                                                      + {% else %} +

                                                                      + {% if grav.twig.twig.filters['tu'] is defined %} + {{- field.text|tu|raw -}} + {% else %} + {{- field.text|t|raw -}} + {% endif %} +

                                                                      + {% endif %} + + {% if field.underline %} +
                                                                      + {% endif %} +
                                                                      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 0000000..f449d8a --- /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/tel/tel.html.twig b/user/plugins/form/templates/forms/fields/tel/tel.html.twig new file mode 100644 index 0000000..6898313 --- /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/text.html.twig b/user/plugins/form/templates/forms/fields/text/text.html.twig new file mode 100644 index 0000000..d6a9af3 --- /dev/null +++ b/user/plugins/form/templates/forms/fields/text/text.html.twig @@ -0,0 +1,37 @@ +{% extends "forms/field.html.twig" %} + +{% block prepend %} +{% if field.prepend %} +
                                                                      + {% if grav.twig.twig.filters['tu'] is defined %} + {{- field.prepend|tu|raw -}} + {% else %} + {{- field.prepend|t|raw -}} + {% endif %} +
                                                                      +{% endif %} +{% endblock %} + +{% block input_attributes %} + type="text" + {{ parent() }} +{% endblock %} + +{% block append %} + {% if field.append %} +
                                                                      + {% if grav.twig.twig.filters['tu'] is defined %} + {{- field.append|tu|raw -}} + {% else %} + {{- field.append|t|raw -}} + {% endif %} +
                                                                      + {% endif %} +{% endblock %} + +{% block input %} +{% if field.prepend or field.append %} + {% set field = field|merge({'wrapper_classes': 'form-input-addon-wrapper'}) %} +{% endif %} +{{ parent() }} +{% endblock %} \ No newline at end of file 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 0000000..003d8bf --- /dev/null +++ b/user/plugins/form/templates/forms/fields/textarea/textarea.html.twig @@ -0,0 +1,27 @@ +{% extends "forms/field.html.twig" %} + +{% block input %} +
                                                                      + +
                                                                      +{% endblock %} 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 0000000..b6bb10e --- /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/uniqueid/uniqueid.html.twig b/user/plugins/form/templates/forms/fields/uniqueid/uniqueid.html.twig new file mode 100644 index 0000000..417f230 --- /dev/null +++ b/user/plugins/form/templates/forms/fields/uniqueid/uniqueid.html.twig @@ -0,0 +1 @@ + \ No newline at end of file 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 0000000..1caae0f --- /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/week/week.html.twig b/user/plugins/form/templates/forms/fields/week/week.html.twig new file mode 100644 index 0000000..c56f871 --- /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 0000000..8f1d467 --- /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/modular/form.html.twig b/user/plugins/form/templates/modular/form.html.twig new file mode 100644 index 0000000..3e06da5 --- /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 0000000..08b5ba5 --- /dev/null +++ b/user/plugins/form/templates/partials/form-messages.html.twig @@ -0,0 +1,5 @@ +{% if form.message %} + {% set status_mapping = {'success':'green', 'error': 'red', 'warning': 'yellow'} %} + {% set message = form.inline_errors and form.messages ? "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 0000000..14e1d18 --- /dev/null +++ b/user/plugins/form/templates/partials/form-messages.json.twig @@ -0,0 +1,2 @@ +{% set message = form.inline_errors and form.messages ? "FORM.VALIDATION_FAIL"|t : form.message %} +{{ {'status':form.status, 'message':message}|json_encode|raw }} diff --git a/user/plugins/form/webpack.conf.js b/user/plugins/form/webpack.conf.js new file mode 100644 index 0000000..879f600 --- /dev/null +++ b/user/plugins/form/webpack.conf.js @@ -0,0 +1,23 @@ +var webpack = require('webpack'), + path = require('path'), + exec = require('child_process').execSync, + pwd = exec('pwd').toString(); + +module.exports = { + entry: { + app: './app/main.js' + }, + externals: { + jquery: 'jQuery', + 'grav-form': 'GravForm' + }, + module: { + preLoaders: [ + { test: /\.json$/, loader: 'json' }, + { test: /\.js$/, loader: 'eslint', exclude: /node_modules/ } + ], + loaders: [ + { test: /\.js$/, loader: 'babel', exclude: /node_modules/, query: { presets: ['es2015'] } } + ] + } +}; diff --git a/user/plugins/form/yarn.lock b/user/plugins/form/yarn.lock new file mode 100644 index 0000000..5776b3a --- /dev/null +++ b/user/plugins/form/yarn.lock @@ -0,0 +1,3243 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +abbrev@1: + version "1.0.9" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.0.9.tgz#91b4792588a7738c25f35dd6f63752a2f8776135" + +acorn-jsx@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b" + dependencies: + acorn "^3.0.4" + +acorn@4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.4.tgz#17a8d6a7a6c4ef538b814ec9abac2779293bf30a" + +acorn@4.X: + version "4.0.8" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.8.tgz#f41e52020ce78118a3c68ed0e9215eb8fc68b5b1" + +acorn@^3.0.0, acorn@^3.0.4: + version "3.3.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" + +ajv-keywords@^1.0.0: + version "1.5.1" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-1.5.1.tgz#314dd0a4b3368fad3dfcdc54ede6171b886daf3c" + +ajv@^4.7.0: + version "4.11.2" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.2.tgz#f166c3c11cbc6cb9dcc102a5bcfe5b72c95287e6" + dependencies: + co "^4.6.0" + json-stable-stringify "^1.0.1" + +align-text@^0.1.1, align-text@^0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117" + dependencies: + kind-of "^3.0.2" + longest "^1.0.1" + repeat-string "^1.5.2" + +amdefine@>=0.0.4: + version "1.0.1" + resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" + +ansi-escapes@^1.1.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" + +ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + +ansi-styles@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" + +anymatch@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.0.tgz#a3e52fa39168c825ff57b0248126ce5a8ff95507" + dependencies: + arrify "^1.0.0" + micromatch "^2.1.5" + +aproba@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.0.4.tgz#2713680775e7614c8ba186c065d4e2e52d1072c0" + +archy@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/archy/-/archy-1.0.0.tgz#f9c8c13757cc1dd7bc379ac77b2c62a5c2868c40" + +are-we-there-yet@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.2.tgz#80e470e95a084794fe1899262c5667c6e88de1b3" + dependencies: + delegates "^1.0.0" + readable-stream "^2.0.0 || ^1.1.13" + +argparse@^1.0.7: + version "1.0.9" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.9.tgz#73d83bc263f86e97f8cc4f6bae1b0e90a7d22c86" + dependencies: + sprintf-js "~1.0.2" + +arr-diff@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" + dependencies: + arr-flatten "^1.0.1" + +arr-flatten@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.0.1.tgz#e5ffe54d45e19f32f216e91eb99c8ce892bb604b" + +array-differ@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/array-differ/-/array-differ-1.0.0.tgz#eff52e3758249d33be402b8bb8e564bb2b5d4031" + +array-union@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" + dependencies: + array-uniq "^1.0.1" + +array-uniq@^1.0.1, array-uniq@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" + +array-unique@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" + +arrify@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" + +asn1@~0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86" + +assert-plus@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234" + +assert-plus@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" + +assert@^1.1.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/assert/-/assert-1.4.1.tgz#99912d591836b5a6f5b345c0f07eefc08fc65d91" + dependencies: + util "0.10.3" + +async-each@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" + +async@^0.9.0: + version "0.9.2" + resolved "https://registry.yarnpkg.com/async/-/async-0.9.2.tgz#aea74d5e61c1f899613bf64bda66d4c78f2fd17d" + +async@^1.3.0: + version "1.5.2" + resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" + +async@~0.2.6: + version "0.2.10" + resolved "https://registry.yarnpkg.com/async/-/async-0.2.10.tgz#b6bbe0b0674b9d719708ca38de8c237cb526c3d1" + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + +atob@~1.1.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/atob/-/atob-1.1.3.tgz#95f13629b12c3a51a5d215abdce2aa9f32f80773" + +aws-sign2@~0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f" + +aws4@^1.2.1: + version "1.5.0" + resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.5.0.tgz#0a29ffb79c31c9e712eeb087e8e7a64b4a56d755" + +babel-code-frame@^6.16.0, babel-code-frame@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.22.0.tgz#027620bee567a88c32561574e7fd0801d33118e4" + dependencies: + chalk "^1.1.0" + esutils "^2.0.2" + js-tokens "^3.0.0" + +babel-core@^6.14.0, babel-core@^6.22.0: + version "6.22.1" + resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.22.1.tgz#9c5fd658ba1772d28d721f6d25d968fc7ae21648" + dependencies: + babel-code-frame "^6.22.0" + babel-generator "^6.22.0" + babel-helpers "^6.22.0" + babel-messages "^6.22.0" + babel-register "^6.22.0" + babel-runtime "^6.22.0" + babel-template "^6.22.0" + babel-traverse "^6.22.1" + babel-types "^6.22.0" + babylon "^6.11.0" + convert-source-map "^1.1.0" + debug "^2.1.1" + json5 "^0.5.0" + lodash "^4.2.0" + minimatch "^3.0.2" + path-is-absolute "^1.0.0" + private "^0.1.6" + slash "^1.0.0" + source-map "^0.5.0" + +babel-generator@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.22.0.tgz#d642bf4961911a8adc7c692b0c9297f325cda805" + dependencies: + babel-messages "^6.22.0" + babel-runtime "^6.22.0" + babel-types "^6.22.0" + detect-indent "^4.0.0" + jsesc "^1.3.0" + lodash "^4.2.0" + source-map "^0.5.0" + +babel-helper-call-delegate@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-helper-call-delegate/-/babel-helper-call-delegate-6.22.0.tgz#119921b56120f17e9dae3f74b4f5cc7bcc1b37ef" + dependencies: + babel-helper-hoist-variables "^6.22.0" + babel-runtime "^6.22.0" + babel-traverse "^6.22.0" + babel-types "^6.22.0" + +babel-helper-define-map@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-helper-define-map/-/babel-helper-define-map-6.22.0.tgz#9544e9502b2d6dfe7d00ff60e82bd5a7a89e95b7" + dependencies: + babel-helper-function-name "^6.22.0" + babel-runtime "^6.22.0" + babel-types "^6.22.0" + lodash "^4.2.0" + +babel-helper-function-name@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-helper-function-name/-/babel-helper-function-name-6.22.0.tgz#51f1bdc4bb89b15f57a9b249f33d742816dcbefc" + dependencies: + babel-helper-get-function-arity "^6.22.0" + babel-runtime "^6.22.0" + babel-template "^6.22.0" + babel-traverse "^6.22.0" + babel-types "^6.22.0" + +babel-helper-get-function-arity@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.22.0.tgz#0beb464ad69dc7347410ac6ade9f03a50634f5ce" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.22.0" + +babel-helper-hoist-variables@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.22.0.tgz#3eacbf731d80705845dd2e9718f600cfb9b4ba72" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.22.0" + +babel-helper-optimise-call-expression@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.22.0.tgz#f8d5d4b40a6e2605a6a7f9d537b581bea3756d15" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.22.0" + +babel-helper-regex@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-helper-regex/-/babel-helper-regex-6.22.0.tgz#79f532be1647b1f0ee3474b5f5c3da58001d247d" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.22.0" + lodash "^4.2.0" + +babel-helper-replace-supers@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-helper-replace-supers/-/babel-helper-replace-supers-6.22.0.tgz#1fcee2270657548908c34db16bcc345f9850cf42" + dependencies: + babel-helper-optimise-call-expression "^6.22.0" + babel-messages "^6.22.0" + babel-runtime "^6.22.0" + babel-template "^6.22.0" + babel-traverse "^6.22.0" + babel-types "^6.22.0" + +babel-helpers@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-helpers/-/babel-helpers-6.22.0.tgz#d275f55f2252b8101bff07bc0c556deda657392c" + dependencies: + babel-runtime "^6.22.0" + babel-template "^6.22.0" + +babel-loader@^6.2.5: + version "6.2.10" + resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-6.2.10.tgz#adefc2b242320cd5d15e65b31cea0e8b1b02d4b0" + dependencies: + find-cache-dir "^0.1.1" + loader-utils "^0.2.11" + mkdirp "^0.5.1" + object-assign "^4.0.1" + +babel-messages@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.22.0.tgz#36066a214f1217e4ed4164867669ecb39e3ea575" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-check-es2015-constants@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz#35157b101426fd2ffd3da3f75c7d1e91835bbf8a" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-arrow-functions@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz#452692cb711d5f79dc7f85e440ce41b9f244d221" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-block-scoped-functions@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz#bbc51b49f964d70cb8d8e0b94e820246ce3a6141" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-block-scoping@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.22.0.tgz#00d6e3a0bebdcfe7536b9d653b44a9141e63e47e" + dependencies: + babel-runtime "^6.22.0" + babel-template "^6.22.0" + babel-traverse "^6.22.0" + babel-types "^6.22.0" + lodash "^4.2.0" + +babel-plugin-transform-es2015-classes@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.22.0.tgz#54d44998fd823d9dca15292324161c331c1b6f14" + dependencies: + babel-helper-define-map "^6.22.0" + babel-helper-function-name "^6.22.0" + babel-helper-optimise-call-expression "^6.22.0" + babel-helper-replace-supers "^6.22.0" + babel-messages "^6.22.0" + babel-runtime "^6.22.0" + babel-template "^6.22.0" + babel-traverse "^6.22.0" + babel-types "^6.22.0" + +babel-plugin-transform-es2015-computed-properties@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.22.0.tgz#7c383e9629bba4820c11b0425bdd6290f7f057e7" + dependencies: + babel-runtime "^6.22.0" + babel-template "^6.22.0" + +babel-plugin-transform-es2015-destructuring@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.22.0.tgz#8e0af2f885a0b2cf999d47c4c1dd23ce88cfa4c6" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-duplicate-keys@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.22.0.tgz#672397031c21610d72dd2bbb0ba9fb6277e1c36b" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.22.0" + +babel-plugin-transform-es2015-for-of@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.22.0.tgz#180467ad63aeea592a1caeee4bf1c8b3e2616265" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-function-name@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.22.0.tgz#f5fcc8b09093f9a23c76ac3d9e392c3ec4b77104" + dependencies: + babel-helper-function-name "^6.22.0" + babel-runtime "^6.22.0" + babel-types "^6.22.0" + +babel-plugin-transform-es2015-literals@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz#4f54a02d6cd66cf915280019a31d31925377ca2e" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-modules-amd@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.22.0.tgz#bf69cd34889a41c33d90dfb740e0091ccff52f21" + dependencies: + babel-plugin-transform-es2015-modules-commonjs "^6.22.0" + babel-runtime "^6.22.0" + babel-template "^6.22.0" + +babel-plugin-transform-es2015-modules-commonjs@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.22.0.tgz#6ca04e22b8e214fb50169730657e7a07dc941145" + dependencies: + babel-plugin-transform-strict-mode "^6.22.0" + babel-runtime "^6.22.0" + babel-template "^6.22.0" + babel-types "^6.22.0" + +babel-plugin-transform-es2015-modules-systemjs@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.22.0.tgz#810cd0cd025a08383b84236b92c6e31f88e644ad" + dependencies: + babel-helper-hoist-variables "^6.22.0" + babel-runtime "^6.22.0" + babel-template "^6.22.0" + +babel-plugin-transform-es2015-modules-umd@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.22.0.tgz#60d0ba3bd23258719c64391d9bf492d648dc0fae" + dependencies: + babel-plugin-transform-es2015-modules-amd "^6.22.0" + babel-runtime "^6.22.0" + babel-template "^6.22.0" + +babel-plugin-transform-es2015-object-super@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.22.0.tgz#daa60e114a042ea769dd53fe528fc82311eb98fc" + dependencies: + babel-helper-replace-supers "^6.22.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-parameters@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.22.0.tgz#57076069232019094f27da8c68bb7162fe208dbb" + dependencies: + babel-helper-call-delegate "^6.22.0" + babel-helper-get-function-arity "^6.22.0" + babel-runtime "^6.22.0" + babel-template "^6.22.0" + babel-traverse "^6.22.0" + babel-types "^6.22.0" + +babel-plugin-transform-es2015-shorthand-properties@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.22.0.tgz#8ba776e0affaa60bff21e921403b8a652a2ff723" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.22.0" + +babel-plugin-transform-es2015-spread@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz#d6d68a99f89aedc4536c81a542e8dd9f1746f8d1" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-sticky-regex@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.22.0.tgz#ab316829e866ee3f4b9eb96939757d19a5bc4593" + dependencies: + babel-helper-regex "^6.22.0" + babel-runtime "^6.22.0" + babel-types "^6.22.0" + +babel-plugin-transform-es2015-template-literals@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz#a84b3450f7e9f8f1f6839d6d687da84bb1236d8d" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-typeof-symbol@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.22.0.tgz#87faf2336d3b6a97f68c4d906b0cd0edeae676e1" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-unicode-regex@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.22.0.tgz#8d9cc27e7ee1decfe65454fb986452a04a613d20" + dependencies: + babel-helper-regex "^6.22.0" + babel-runtime "^6.22.0" + regexpu-core "^2.0.0" + +babel-plugin-transform-regenerator@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.22.0.tgz#65740593a319c44522157538d690b84094617ea6" + dependencies: + regenerator-transform "0.9.8" + +babel-plugin-transform-strict-mode@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.22.0.tgz#e008df01340fdc87e959da65991b7e05970c8c7c" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.22.0" + +babel-polyfill@^6.13.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-polyfill/-/babel-polyfill-6.22.0.tgz#1ac99ebdcc6ba4db1e2618c387b2084a82154a3b" + dependencies: + babel-runtime "^6.22.0" + core-js "^2.4.0" + regenerator-runtime "^0.10.0" + +babel-preset-es2015@^6.14.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-preset-es2015/-/babel-preset-es2015-6.22.0.tgz#af5a98ecb35eb8af764ad8a5a05eb36dc4386835" + dependencies: + babel-plugin-check-es2015-constants "^6.22.0" + babel-plugin-transform-es2015-arrow-functions "^6.22.0" + babel-plugin-transform-es2015-block-scoped-functions "^6.22.0" + babel-plugin-transform-es2015-block-scoping "^6.22.0" + babel-plugin-transform-es2015-classes "^6.22.0" + babel-plugin-transform-es2015-computed-properties "^6.22.0" + babel-plugin-transform-es2015-destructuring "^6.22.0" + babel-plugin-transform-es2015-duplicate-keys "^6.22.0" + babel-plugin-transform-es2015-for-of "^6.22.0" + babel-plugin-transform-es2015-function-name "^6.22.0" + babel-plugin-transform-es2015-literals "^6.22.0" + babel-plugin-transform-es2015-modules-amd "^6.22.0" + babel-plugin-transform-es2015-modules-commonjs "^6.22.0" + babel-plugin-transform-es2015-modules-systemjs "^6.22.0" + babel-plugin-transform-es2015-modules-umd "^6.22.0" + babel-plugin-transform-es2015-object-super "^6.22.0" + babel-plugin-transform-es2015-parameters "^6.22.0" + babel-plugin-transform-es2015-shorthand-properties "^6.22.0" + babel-plugin-transform-es2015-spread "^6.22.0" + babel-plugin-transform-es2015-sticky-regex "^6.22.0" + babel-plugin-transform-es2015-template-literals "^6.22.0" + babel-plugin-transform-es2015-typeof-symbol "^6.22.0" + babel-plugin-transform-es2015-unicode-regex "^6.22.0" + babel-plugin-transform-regenerator "^6.22.0" + +babel-register@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.22.0.tgz#a61dd83975f9ca4a9e7d6eff3059494cd5ea4c63" + dependencies: + babel-core "^6.22.0" + babel-runtime "^6.22.0" + core-js "^2.4.0" + home-or-tmp "^2.0.0" + lodash "^4.2.0" + mkdirp "^0.5.1" + source-map-support "^0.4.2" + +babel-runtime@^6.18.0, babel-runtime@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.22.0.tgz#1cf8b4ac67c77a4ddb0db2ae1f74de52ac4ca611" + dependencies: + core-js "^2.4.0" + regenerator-runtime "^0.10.0" + +babel-template@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.22.0.tgz#403d110905a4626b317a2a1fcb8f3b73204b2edb" + dependencies: + babel-runtime "^6.22.0" + babel-traverse "^6.22.0" + babel-types "^6.22.0" + babylon "^6.11.0" + lodash "^4.2.0" + +babel-traverse@^6.22.0, babel-traverse@^6.22.1: + version "6.22.1" + resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.22.1.tgz#3b95cd6b7427d6f1f757704908f2fc9748a5f59f" + dependencies: + babel-code-frame "^6.22.0" + babel-messages "^6.22.0" + babel-runtime "^6.22.0" + babel-types "^6.22.0" + babylon "^6.15.0" + debug "^2.2.0" + globals "^9.0.0" + invariant "^2.2.0" + lodash "^4.2.0" + +babel-types@^6.19.0, babel-types@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.22.0.tgz#2a447e8d0ea25d2512409e4175479fd78cc8b1db" + dependencies: + babel-runtime "^6.22.0" + esutils "^2.0.2" + lodash "^4.2.0" + to-fast-properties "^1.0.1" + +babylon@^6.11.0, babylon@^6.15.0: + version "6.15.0" + resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.15.0.tgz#ba65cfa1a80e1759b0e89fb562e27dccae70348e" + +balanced-match@^0.4.1: + version "0.4.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838" + +base64-js@^1.0.2: + version "1.2.0" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.2.0.tgz#a39992d723584811982be5e290bb6a53d86700f1" + +bcrypt-pbkdf@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz#63bc5dcb61331b92bc05fd528953c33462a06f8d" + dependencies: + tweetnacl "^0.14.3" + +beeper@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/beeper/-/beeper-1.1.1.tgz#e6d5ea8c5dad001304a70b22638447f69cb2f809" + +big.js@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.1.3.tgz#4cada2193652eb3ca9ec8e55c9015669c9806978" + +binary-extensions@^1.0.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.8.0.tgz#48ec8d16df4377eae5fa5884682480af4d95c774" + +block-stream@*: + version "0.0.9" + resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" + dependencies: + inherits "~2.0.0" + +boom@2.x.x: + version "2.10.1" + resolved "https://registry.yarnpkg.com/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f" + dependencies: + hoek "2.x.x" + +brace-expansion@^1.0.0: + version "1.1.6" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.6.tgz#7197d7eaa9b87e648390ea61fc66c84427420df9" + dependencies: + balanced-match "^0.4.1" + concat-map "0.0.1" + +braces@^1.8.2: + version "1.8.5" + resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7" + dependencies: + expand-range "^1.8.1" + preserve "^0.2.0" + repeat-element "^1.1.2" + +browserify-aes@0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-0.4.0.tgz#067149b668df31c4b58533e02d01e806d8608e2c" + dependencies: + inherits "^2.0.1" + +browserify-zlib@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.1.4.tgz#bb35f8a519f600e0fa6b8485241c979d0141fb2d" + dependencies: + pako "~0.2.0" + +buffer-shims@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/buffer-shims/-/buffer-shims-1.0.0.tgz#9978ce317388c649ad8793028c3477ef044a8b51" + +buffer@^4.9.0: + version "4.9.1" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298" + dependencies: + base64-js "^1.0.2" + ieee754 "^1.1.4" + isarray "^1.0.0" + +builtin-status-codes@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" + +caller-path@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f" + dependencies: + callsites "^0.2.0" + +callsites@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca" + +camelcase@^1.0.2: + version "1.2.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39" + +caseless@~0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.11.0.tgz#715b96ea9841593cc33067923f5ec60ebda4f7d7" + +center-align@^0.1.1: + version "0.1.3" + resolved "https://registry.yarnpkg.com/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad" + dependencies: + align-text "^0.1.3" + lazy-cache "^1.0.3" + +chalk@^1.0.0, chalk@^1.1.0, chalk@^1.1.1, chalk@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" + dependencies: + ansi-styles "^2.2.1" + escape-string-regexp "^1.0.2" + has-ansi "^2.0.0" + strip-ansi "^3.0.0" + supports-color "^2.0.0" + +chokidar@^1.0.0: + version "1.6.1" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.6.1.tgz#2f4447ab5e96e50fb3d789fd90d4c72e0e4c70c2" + dependencies: + anymatch "^1.3.0" + async-each "^1.0.0" + glob-parent "^2.0.0" + inherits "^2.0.1" + is-binary-path "^1.0.0" + is-glob "^2.0.0" + path-is-absolute "^1.0.0" + readdirp "^2.0.0" + optionalDependencies: + fsevents "^1.0.0" + +circular-json@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.1.tgz#be8b36aefccde8b3ca7aa2d6afc07a37242c0d2d" + +cli-cursor@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987" + dependencies: + restore-cursor "^1.0.1" + +cli-width@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.1.0.tgz#b234ca209b29ef66fc518d9b98d5847b00edf00a" + +cliui@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1" + dependencies: + center-align "^0.1.1" + right-align "^0.1.1" + wordwrap "0.0.2" + +clone-stats@^0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/clone-stats/-/clone-stats-0.0.1.tgz#b88f94a82cf38b8791d58046ea4029ad88ca99d1" + +clone@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/clone/-/clone-0.2.0.tgz#c6126a90ad4f72dbf5acdb243cc37724fe93fc1f" + +clone@^1.0.0, clone@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.2.tgz#260b7a99ebb1edfe247538175f783243cb19d149" + +co@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + +code-point-at@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + +combined-stream@^1.0.5, combined-stream@~1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.5.tgz#938370a57b4a51dea2c77c15d5c5fdf895164009" + dependencies: + delayed-stream "~1.0.0" + +commander@^2.9.0: + version "2.9.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4" + dependencies: + graceful-readlink ">= 1.0.0" + +commondir@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + +concat-stream@^1.4.6: + version "1.6.0" + resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.0.tgz#0aac662fd52be78964d5532f694784e70110acf7" + dependencies: + inherits "^2.0.3" + readable-stream "^2.2.2" + typedarray "^0.0.6" + +console-browserify@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10" + dependencies: + date-now "^0.1.4" + +console-control-strings@^1.0.0, console-control-strings@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + +constants-browserify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" + +convert-source-map@1.X, convert-source-map@^1.1.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.3.0.tgz#e9f3e9c6e2728efc2676696a70eb382f73106a67" + +core-js@^2.4.0: + version "2.4.1" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.4.1.tgz#4de911e667b0eae9124e34254b53aea6fc618d3e" + +core-util-is@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + +cryptiles@2.x.x: + version "2.0.5" + resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8" + dependencies: + boom "2.x.x" + +crypto-browserify@3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.3.0.tgz#b9fc75bb4a0ed61dcf1cd5dae96eb30c9c3e506c" + dependencies: + browserify-aes "0.4.0" + pbkdf2-compat "2.0.1" + ripemd160 "0.2.0" + sha.js "2.2.6" + +css@2.X: + version "2.2.1" + resolved "https://registry.yarnpkg.com/css/-/css-2.2.1.tgz#73a4c81de85db664d4ee674f7d47085e3b2d55dc" + dependencies: + inherits "^2.0.1" + source-map "^0.1.38" + source-map-resolve "^0.3.0" + urix "^0.1.0" + +d@^0.1.1, d@~0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/d/-/d-0.1.1.tgz#da184c535d18d8ee7ba2aa229b914009fae11309" + dependencies: + es5-ext "~0.10.2" + +dashdash@^1.12.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" + dependencies: + assert-plus "^1.0.0" + +date-now@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b" + +dateformat@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-2.0.0.tgz#2743e3abb5c3fc2462e527dca445e04e9f4dee17" + +debug-fabulous@0.0.X: + version "0.0.4" + resolved "https://registry.yarnpkg.com/debug-fabulous/-/debug-fabulous-0.0.4.tgz#fa071c5d87484685424807421ca4b16b0b1a0763" + dependencies: + debug "2.X" + lazy-debug-legacy "0.0.X" + object-assign "4.1.0" + +debug@2.X, debug@^2.1.1, debug@^2.2.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.0.tgz#bc596bcabe7617f11d9fa15361eded5608b8499b" + dependencies: + ms "0.7.2" + +debug@~2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.2.0.tgz#f87057e995b1a1f6ae6a4960664137bc56f039da" + dependencies: + ms "0.7.1" + +decamelize@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + +deep-extend@~0.4.0: + version "0.4.1" + resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.1.tgz#efe4113d08085f4e6f9687759810f807469e2253" + +deep-is@~0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" + +defaults@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d" + dependencies: + clone "^1.0.2" + +del@^2.0.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/del/-/del-2.2.2.tgz#c12c981d067846c84bcaf862cff930d907ffd1a8" + dependencies: + globby "^5.0.0" + is-path-cwd "^1.0.0" + is-path-in-cwd "^1.0.0" + object-assign "^4.0.1" + pify "^2.0.0" + pinkie-promise "^2.0.0" + rimraf "^2.2.8" + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + +delegates@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + +deprecated@^0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/deprecated/-/deprecated-0.0.1.tgz#f9c9af5464afa1e7a971458a8bdef2aa94d5bb19" + +detect-file@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/detect-file/-/detect-file-0.1.0.tgz#4935dedfd9488648e006b0129566e9386711ea63" + dependencies: + fs-exists-sync "^0.1.0" + +detect-indent@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208" + dependencies: + repeating "^2.0.0" + +detect-newline@2.X: + version "2.1.0" + resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-2.1.0.tgz#f41f1c10be4b00e87b5f13da680759f2c5bfd3e2" + +doctrine@^1.2.2: + version "1.5.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa" + dependencies: + esutils "^2.0.2" + isarray "^1.0.0" + +domain-browser@^1.1.1: + version "1.1.7" + resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.1.7.tgz#867aa4b093faa05f1de08c06f4d7b21fdf8698bc" + +dropzone@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/dropzone/-/dropzone-4.3.0.tgz#48b0b8f2ad092872e4b535b672a7c3f1a1d67c91" + +duplexer2@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.0.2.tgz#c614dcf67e2fb14995a91711e5a617e8a60a31db" + dependencies: + readable-stream "~1.1.9" + +ecc-jsbn@~0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505" + dependencies: + jsbn "~0.1.0" + +emojis-list@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389" + +end-of-stream@~0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-0.1.5.tgz#8e177206c3c80837d85632e8b9359dfe8b2f6eaf" + dependencies: + once "~1.3.0" + +enhanced-resolve@~0.9.0: + version "0.9.1" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-0.9.1.tgz#4d6e689b3725f86090927ccc86cd9f1635b89e2e" + dependencies: + graceful-fs "^4.1.2" + memory-fs "^0.2.0" + tapable "^0.1.8" + +errno@^0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.4.tgz#b896e23a9e5e8ba33871fc996abd3635fc9a1c7d" + dependencies: + prr "~0.0.0" + +es5-ext@^0.10.7, es5-ext@^0.10.8, es5-ext@~0.10.11, es5-ext@~0.10.2, es5-ext@~0.10.7: + version "0.10.12" + resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.12.tgz#aa84641d4db76b62abba5e45fd805ecbab140047" + dependencies: + es6-iterator "2" + es6-symbol "~3.1" + +es6-iterator@2: + version "2.0.0" + resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.0.tgz#bd968567d61635e33c0b80727613c9cb4b096bac" + dependencies: + d "^0.1.1" + es5-ext "^0.10.7" + es6-symbol "3" + +es6-map@^0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/es6-map/-/es6-map-0.1.4.tgz#a34b147be224773a4d7da8072794cefa3632b897" + dependencies: + d "~0.1.1" + es5-ext "~0.10.11" + es6-iterator "2" + es6-set "~0.1.3" + es6-symbol "~3.1.0" + event-emitter "~0.3.4" + +es6-set@~0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/es6-set/-/es6-set-0.1.4.tgz#9516b6761c2964b92ff479456233a247dc707ce8" + dependencies: + d "~0.1.1" + es5-ext "~0.10.11" + es6-iterator "2" + es6-symbol "3" + event-emitter "~0.3.4" + +es6-symbol@3, es6-symbol@~3.1, es6-symbol@~3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.0.tgz#94481c655e7a7cad82eba832d97d5433496d7ffa" + dependencies: + d "~0.1.1" + es5-ext "~0.10.11" + +es6-weak-map@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/es6-weak-map/-/es6-weak-map-2.0.1.tgz#0d2bbd8827eb5fb4ba8f97fbfea50d43db21ea81" + dependencies: + d "^0.1.1" + es5-ext "^0.10.8" + es6-iterator "2" + es6-symbol "3" + +escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + +escope@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/escope/-/escope-3.6.0.tgz#e01975e812781a163a6dadfdd80398dc64c889c3" + dependencies: + es6-map "^0.1.3" + es6-weak-map "^2.0.1" + esrecurse "^4.1.0" + estraverse "^4.1.1" + +eslint-loader@^1.5.0: + version "1.6.1" + resolved "https://registry.yarnpkg.com/eslint-loader/-/eslint-loader-1.6.1.tgz#96c47c812772eeb077e3a81681818e671a2cabf5" + dependencies: + find-cache-dir "^0.1.1" + loader-utils "^0.2.7" + object-assign "^4.0.1" + object-hash "^1.1.4" + +eslint@^3.4.0: + version "3.14.1" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-3.14.1.tgz#8a62175f2255109494747a1b25128d97b8eb3d97" + dependencies: + babel-code-frame "^6.16.0" + chalk "^1.1.3" + concat-stream "^1.4.6" + debug "^2.1.1" + doctrine "^1.2.2" + escope "^3.6.0" + espree "^3.3.1" + estraverse "^4.2.0" + esutils "^2.0.2" + file-entry-cache "^2.0.0" + glob "^7.0.3" + globals "^9.14.0" + ignore "^3.2.0" + imurmurhash "^0.1.4" + inquirer "^0.12.0" + is-my-json-valid "^2.10.0" + is-resolvable "^1.0.0" + js-yaml "^3.5.1" + json-stable-stringify "^1.0.0" + levn "^0.3.0" + lodash "^4.0.0" + mkdirp "^0.5.0" + natural-compare "^1.4.0" + optionator "^0.8.2" + path-is-inside "^1.0.1" + pluralize "^1.2.1" + progress "^1.1.8" + require-uncached "^1.0.2" + shelljs "^0.7.5" + strip-bom "^3.0.0" + strip-json-comments "~2.0.1" + table "^3.7.8" + text-table "~0.2.0" + user-home "^2.0.0" + +espree@^3.3.1: + version "3.4.0" + resolved "https://registry.yarnpkg.com/espree/-/espree-3.4.0.tgz#41656fa5628e042878025ef467e78f125cb86e1d" + dependencies: + acorn "4.0.4" + acorn-jsx "^3.0.0" + +esprima@^2.6.0: + version "2.7.3" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" + +esrecurse@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.1.0.tgz#4713b6536adf7f2ac4f327d559e7756bff648220" + dependencies: + estraverse "~4.1.0" + object-assign "^4.0.1" + +estraverse@^4.1.1, estraverse@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" + +estraverse@~4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.1.1.tgz#f6caca728933a850ef90661d0e17982ba47111a2" + +esutils@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" + +event-emitter@~0.3.4: + version "0.3.4" + resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.4.tgz#8d63ddfb4cfe1fae3b32ca265c4c720222080bb5" + dependencies: + d "~0.1.1" + es5-ext "~0.10.7" + +events@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" + +exit-hook@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8" + +expand-brackets@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" + dependencies: + is-posix-bracket "^0.1.0" + +expand-range@^1.8.1: + version "1.8.2" + resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" + dependencies: + fill-range "^2.1.0" + +expand-tilde@^1.2.1, expand-tilde@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-1.2.2.tgz#0b81eba897e5a3d31d1c3d102f8f01441e559449" + dependencies: + os-homedir "^1.0.1" + +exports-loader@^0.6.3: + version "0.6.3" + resolved "https://registry.yarnpkg.com/exports-loader/-/exports-loader-0.6.3.tgz#57dc78917f709b96f247fa91e69b554c855013c8" + dependencies: + loader-utils "0.2.x" + source-map "0.1.x" + +extend@^3.0.0, extend@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.0.tgz#5a474353b9f3353ddd8176dfd37b91c83a46f1d4" + +extglob@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" + dependencies: + is-extglob "^1.0.0" + +extsprintf@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.0.2.tgz#e1080e0658e300b06294990cc70e1502235fd550" + +fancy-log@^1.1.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/fancy-log/-/fancy-log-1.3.0.tgz#45be17d02bb9917d60ccffd4995c999e6c8c9948" + dependencies: + chalk "^1.1.1" + time-stamp "^1.0.0" + +fast-levenshtein@~2.0.4: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + +figures@^1.3.5: + version "1.7.0" + resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e" + dependencies: + escape-string-regexp "^1.0.5" + object-assign "^4.1.0" + +file-entry-cache@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-2.0.0.tgz#c392990c3e684783d838b8c84a45d8a048458361" + dependencies: + flat-cache "^1.2.1" + object-assign "^4.0.1" + +filename-regex@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.0.tgz#996e3e80479b98b9897f15a8a58b3d084e926775" + +fill-range@^2.1.0: + version "2.2.3" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.3.tgz#50b77dfd7e469bc7492470963699fe7a8485a723" + dependencies: + is-number "^2.1.0" + isobject "^2.0.0" + randomatic "^1.1.3" + repeat-element "^1.1.2" + repeat-string "^1.5.2" + +find-cache-dir@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-0.1.1.tgz#c8defae57c8a52a8a784f9e31c57c742e993a0b9" + dependencies: + commondir "^1.0.1" + mkdirp "^0.5.1" + pkg-dir "^1.0.0" + +find-index@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/find-index/-/find-index-0.1.1.tgz#675d358b2ca3892d795a1ab47232f8b6e2e0dde4" + +find-up@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" + dependencies: + path-exists "^2.0.0" + pinkie-promise "^2.0.0" + +findup-sync@^0.4.2: + version "0.4.3" + resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-0.4.3.tgz#40043929e7bc60adf0b7f4827c4c6e75a0deca12" + dependencies: + detect-file "^0.1.0" + is-glob "^2.0.1" + micromatch "^2.3.7" + resolve-dir "^0.1.0" + +fined@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/fined/-/fined-1.0.2.tgz#5b28424b760d7598960b7ef8480dff8ad3660e97" + dependencies: + expand-tilde "^1.2.1" + lodash.assignwith "^4.0.7" + lodash.isempty "^4.2.1" + lodash.isplainobject "^4.0.4" + lodash.isstring "^4.0.1" + lodash.pick "^4.2.1" + parse-filepath "^1.0.1" + +first-chunk-stream@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/first-chunk-stream/-/first-chunk-stream-1.0.0.tgz#59bfb50cd905f60d7c394cd3d9acaab4e6ad934e" + +flagged-respawn@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/flagged-respawn/-/flagged-respawn-0.3.2.tgz#ff191eddcd7088a675b2610fffc976be9b8074b5" + +flat-cache@^1.2.1: + version "1.2.2" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-1.2.2.tgz#fa86714e72c21db88601761ecf2f555d1abc6b96" + dependencies: + circular-json "^0.3.1" + del "^2.0.2" + graceful-fs "^4.1.2" + write "^0.2.1" + +for-in@^0.1.5: + version "0.1.6" + resolved "https://registry.yarnpkg.com/for-in/-/for-in-0.1.6.tgz#c9f96e89bfad18a545af5ec3ed352a1d9e5b4dc8" + +for-own@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.4.tgz#0149b41a39088c7515f51ebe1c1386d45f935072" + dependencies: + for-in "^0.1.5" + +forever-agent@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" + +form-data@~2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.2.tgz#89c3534008b97eada4cbb157d58f6f5df025eae4" + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.5" + mime-types "^2.1.12" + +fs-exists-sync@^0.1.0: + version "0.1.0" + resolved "http://registry.npmjs.org/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz#982d6893af918e72d08dec9e8673ff2b5a8d6add" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + +fsevents@^1.0.0: + version "1.0.17" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.0.17.tgz#8537f3f12272678765b4fd6528c0f1f66f8f4558" + dependencies: + nan "^2.3.0" + node-pre-gyp "^0.6.29" + +fstream-ignore@~1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/fstream-ignore/-/fstream-ignore-1.0.5.tgz#9c31dae34767018fe1d249b24dada67d092da105" + dependencies: + fstream "^1.0.0" + inherits "2" + minimatch "^3.0.0" + +fstream@^1.0.0, fstream@^1.0.2, fstream@~1.0.10: + version "1.0.10" + resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.10.tgz#604e8a92fe26ffd9f6fae30399d4984e1ab22822" + dependencies: + graceful-fs "^4.1.2" + inherits "~2.0.0" + mkdirp ">=0.5 0" + rimraf "2" + +gauge@~2.7.1: + version "2.7.2" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.2.tgz#15cecc31b02d05345a5d6b0e171cdb3ad2307774" + dependencies: + aproba "^1.0.3" + console-control-strings "^1.0.0" + has-unicode "^2.0.0" + object-assign "^4.1.0" + signal-exit "^3.0.0" + string-width "^1.0.1" + strip-ansi "^3.0.1" + supports-color "^0.2.0" + wide-align "^1.1.0" + +gaze@^0.5.1: + version "0.5.2" + resolved "https://registry.yarnpkg.com/gaze/-/gaze-0.5.2.tgz#40b709537d24d1d45767db5a908689dfe69ac44f" + dependencies: + globule "~0.1.0" + +generate-function@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/generate-function/-/generate-function-2.0.0.tgz#6858fe7c0969b7d4e9093337647ac79f60dfbe74" + +generate-object-property@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/generate-object-property/-/generate-object-property-1.2.0.tgz#9c0e1c40308ce804f4783618b937fa88f99d50d0" + dependencies: + is-property "^1.0.0" + +getpass@^0.1.1: + version "0.1.6" + resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.6.tgz#283ffd9fc1256840875311c1b60e8c40187110e6" + dependencies: + assert-plus "^1.0.0" + +glob-base@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" + dependencies: + glob-parent "^2.0.0" + is-glob "^2.0.0" + +glob-parent@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28" + dependencies: + is-glob "^2.0.0" + +glob-stream@^3.1.5: + version "3.1.18" + resolved "https://registry.yarnpkg.com/glob-stream/-/glob-stream-3.1.18.tgz#9170a5f12b790306fdfe598f313f8f7954fd143b" + dependencies: + glob "^4.3.1" + glob2base "^0.0.12" + minimatch "^2.0.1" + ordered-read-streams "^0.1.0" + through2 "^0.6.1" + unique-stream "^1.0.0" + +glob-watcher@^0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/glob-watcher/-/glob-watcher-0.0.6.tgz#b95b4a8df74b39c83298b0c05c978b4d9a3b710b" + dependencies: + gaze "^0.5.1" + +glob2base@^0.0.12: + version "0.0.12" + resolved "https://registry.yarnpkg.com/glob2base/-/glob2base-0.0.12.tgz#9d419b3e28f12e83a362164a277055922c9c0d56" + dependencies: + find-index "^0.1.1" + +glob@^4.3.1: + version "4.5.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-4.5.3.tgz#c6cb73d3226c1efef04de3c56d012f03377ee15f" + dependencies: + inflight "^1.0.4" + inherits "2" + minimatch "^2.0.1" + once "^1.3.0" + +glob@^7.0.0, glob@^7.0.3, glob@^7.0.5: + version "7.1.1" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8" + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.2" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@~3.1.21: + version "3.1.21" + resolved "https://registry.yarnpkg.com/glob/-/glob-3.1.21.tgz#d29e0a055dea5138f4d07ed40e8982e83c2066cd" + dependencies: + graceful-fs "~1.2.0" + inherits "1" + minimatch "~0.2.11" + +global-modules@^0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-0.2.3.tgz#ea5a3bed42c6d6ce995a4f8a1269b5dae223828d" + dependencies: + global-prefix "^0.1.4" + is-windows "^0.2.0" + +global-prefix@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-0.1.5.tgz#8d3bc6b8da3ca8112a160d8d496ff0462bfef78f" + dependencies: + homedir-polyfill "^1.0.0" + ini "^1.3.4" + is-windows "^0.2.0" + which "^1.2.12" + +globals@^9.0.0, globals@^9.14.0: + version "9.14.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-9.14.0.tgz#8859936af0038741263053b39d0e76ca241e4034" + +globby@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-5.0.0.tgz#ebd84667ca0dbb330b99bcfc68eac2bc54370e0d" + dependencies: + array-union "^1.0.1" + arrify "^1.0.0" + glob "^7.0.3" + object-assign "^4.0.1" + pify "^2.0.0" + pinkie-promise "^2.0.0" + +globule@~0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/globule/-/globule-0.1.0.tgz#d9c8edde1da79d125a151b79533b978676346ae5" + dependencies: + glob "~3.1.21" + lodash "~1.0.1" + minimatch "~0.2.11" + +glogg@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/glogg/-/glogg-1.0.0.tgz#7fe0f199f57ac906cf512feead8f90ee4a284fc5" + dependencies: + sparkles "^1.0.0" + +graceful-fs@4.X, graceful-fs@^4.1.2: + version "4.1.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" + +graceful-fs@^3.0.0: + version "3.0.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-3.0.11.tgz#7613c778a1afea62f25c630a086d7f3acbbdd818" + dependencies: + natives "^1.1.0" + +graceful-fs@~1.2.0: + version "1.2.3" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-1.2.3.tgz#15a4806a57547cb2d2dbf27f42e89a8c3451b364" + +"graceful-readlink@>= 1.0.0": + version "1.0.1" + resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" + +gulp-sourcemaps@^1.6.0: + version "1.11.0" + resolved "https://registry.yarnpkg.com/gulp-sourcemaps/-/gulp-sourcemaps-1.11.0.tgz#1b249bfe994361c370c168fe2508effc1f1523c9" + dependencies: + acorn "4.X" + convert-source-map "1.X" + css "2.X" + debug-fabulous "0.0.X" + detect-newline "2.X" + graceful-fs "4.X" + source-map "0.X" + strip-bom "2.X" + through2 "2.X" + vinyl "1.X" + +"gulp-util@>=3.0.0 <3.1.0-0", gulp-util@^3.0.0, gulp-util@^3.0.7: + version "3.0.8" + resolved "https://registry.yarnpkg.com/gulp-util/-/gulp-util-3.0.8.tgz#0054e1e744502e27c04c187c3ecc505dd54bbb4f" + dependencies: + array-differ "^1.0.0" + array-uniq "^1.0.2" + beeper "^1.0.0" + chalk "^1.0.0" + dateformat "^2.0.0" + fancy-log "^1.1.0" + gulplog "^1.0.0" + has-gulplog "^0.1.0" + lodash._reescape "^3.0.0" + lodash._reevaluate "^3.0.0" + lodash._reinterpolate "^3.0.0" + lodash.template "^3.0.0" + minimist "^1.1.0" + multipipe "^0.1.2" + object-assign "^3.0.0" + replace-ext "0.0.1" + through2 "^2.0.0" + vinyl "^0.5.0" + +gulp-webpack@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/gulp-webpack/-/gulp-webpack-1.5.0.tgz#7aa683fe88c02d246148e27c7229cb6b62892dba" + dependencies: + gulp-util ">=3.0.0 <3.1.0-0" + memory-fs ">=0.2.0 <0.3.0-0" + through ">=2.3.4 <2.4.0-0" + vinyl ">=0.5.0 <0.6.0-0" + webpack ">=1.9.0 <2.0.0-0" + +gulp@^3.9.1: + version "3.9.1" + resolved "https://registry.yarnpkg.com/gulp/-/gulp-3.9.1.tgz#571ce45928dd40af6514fc4011866016c13845b4" + dependencies: + archy "^1.0.0" + chalk "^1.0.0" + deprecated "^0.0.1" + gulp-util "^3.0.0" + interpret "^1.0.0" + liftoff "^2.1.0" + minimist "^1.1.0" + orchestrator "^0.3.0" + pretty-hrtime "^1.0.0" + semver "^4.1.0" + tildify "^1.0.0" + v8flags "^2.0.2" + vinyl-fs "^0.3.0" + +gulplog@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/gulplog/-/gulplog-1.0.0.tgz#e28c4d45d05ecbbed818363ce8f9c5926229ffe5" + dependencies: + glogg "^1.0.0" + +har-validator@~2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-2.0.6.tgz#cdcbc08188265ad119b6a5a7c8ab70eecfb5d27d" + dependencies: + chalk "^1.1.1" + commander "^2.9.0" + is-my-json-valid "^2.12.4" + pinkie-promise "^2.0.0" + +has-ansi@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" + dependencies: + ansi-regex "^2.0.0" + +has-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa" + +has-gulplog@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/has-gulplog/-/has-gulplog-0.1.0.tgz#6414c82913697da51590397dafb12f22967811ce" + dependencies: + sparkles "^1.0.0" + +has-unicode@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + +hawk@~3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4" + dependencies: + boom "2.x.x" + cryptiles "2.x.x" + hoek "2.x.x" + sntp "1.x.x" + +hoek@2.x.x: + version "2.16.3" + resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed" + +home-or-tmp@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8" + dependencies: + os-homedir "^1.0.0" + os-tmpdir "^1.0.1" + +homedir-polyfill@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz#4c2bbc8a758998feebf5ed68580f76d46768b4bc" + dependencies: + parse-passwd "^1.0.0" + +http-signature@~1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf" + dependencies: + assert-plus "^0.2.0" + jsprim "^1.2.2" + sshpk "^1.7.0" + +https-browserify@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-0.0.1.tgz#3f91365cabe60b77ed0ebba24b454e3e09d95a82" + +ieee754@^1.1.4: + version "1.1.8" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4" + +ignore@^3.2.0: + version "3.2.2" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.2.2.tgz#1c51e1ef53bab6ddc15db4d9ac4ec139eceb3410" + +immutable@^3.8.1: + version "3.8.1" + resolved "https://registry.yarnpkg.com/immutable/-/immutable-3.8.1.tgz#200807f11ab0f72710ea485542de088075f68cd2" + +imports-loader@^0.6.5: + version "0.6.5" + resolved "https://registry.yarnpkg.com/imports-loader/-/imports-loader-0.6.5.tgz#ae74653031d59e37b3c2fb2544ac61aeae3530a6" + dependencies: + loader-utils "0.2.x" + source-map "0.1.x" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + +indexof@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d" + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-1.0.2.tgz#ca4309dadee6b54cc0b8d247e8d7c7a0975bdc9b" + +inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + +inherits@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" + +ini@^1.3.4, ini@~1.3.0: + version "1.3.4" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e" + +inquirer@^0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-0.12.0.tgz#1ef2bfd63504df0bc75785fff8c2c41df12f077e" + dependencies: + ansi-escapes "^1.1.0" + ansi-regex "^2.0.0" + chalk "^1.0.0" + cli-cursor "^1.0.1" + cli-width "^2.0.0" + figures "^1.3.5" + lodash "^4.3.0" + readline2 "^1.0.1" + run-async "^0.1.0" + rx-lite "^3.1.2" + string-width "^1.0.1" + strip-ansi "^3.0.0" + through "^2.3.6" + +interpret@^0.6.4: + version "0.6.6" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-0.6.6.tgz#fecd7a18e7ce5ca6abfb953e1f86213a49f1625b" + +interpret@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.0.1.tgz#d579fb7f693b858004947af39fa0db49f795602c" + +invariant@^2.2.0: + version "2.2.2" + resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.2.tgz#9e1f56ac0acdb6bf303306f338be3b204ae60360" + dependencies: + loose-envify "^1.0.0" + +is-absolute@^0.2.3: + version "0.2.6" + resolved "https://registry.yarnpkg.com/is-absolute/-/is-absolute-0.2.6.tgz#20de69f3db942ef2d87b9c2da36f172235b1b5eb" + dependencies: + is-relative "^0.2.1" + is-windows "^0.2.0" + +is-binary-path@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" + dependencies: + binary-extensions "^1.0.0" + +is-buffer@^1.0.2: + version "1.1.4" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.4.tgz#cfc86ccd5dc5a52fa80489111c6920c457e2d98b" + +is-dotfile@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.2.tgz#2c132383f39199f8edc268ca01b9b007d205cc4d" + +is-equal-shallow@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534" + dependencies: + is-primitive "^2.0.0" + +is-extendable@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" + +is-extglob@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" + +is-finite@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa" + dependencies: + number-is-nan "^1.0.0" + +is-fullwidth-code-point@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + dependencies: + number-is-nan "^1.0.0" + +is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + +is-glob@^2.0.0, is-glob@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" + dependencies: + is-extglob "^1.0.0" + +is-my-json-valid@^2.10.0, is-my-json-valid@^2.12.4: + version "2.15.0" + resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.15.0.tgz#936edda3ca3c211fd98f3b2d3e08da43f7b2915b" + dependencies: + generate-function "^2.0.0" + generate-object-property "^1.1.0" + jsonpointer "^4.0.0" + xtend "^4.0.0" + +is-number@^2.0.2, is-number@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" + dependencies: + kind-of "^3.0.2" + +is-path-cwd@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d" + +is-path-in-cwd@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz#6477582b8214d602346094567003be8a9eac04dc" + dependencies: + is-path-inside "^1.0.0" + +is-path-inside@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.0.tgz#fc06e5a1683fbda13de667aff717bbc10a48f37f" + dependencies: + path-is-inside "^1.0.1" + +is-posix-bracket@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" + +is-primitive@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" + +is-property@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" + +is-relative@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-relative/-/is-relative-0.2.1.tgz#d27f4c7d516d175fb610db84bbeef23c3bc97aa5" + dependencies: + is-unc-path "^0.1.1" + +is-resolvable@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.0.0.tgz#8df57c61ea2e3c501408d100fb013cf8d6e0cc62" + dependencies: + tryit "^1.0.1" + +is-typedarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + +is-unc-path@^0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/is-unc-path/-/is-unc-path-0.1.2.tgz#6ab053a72573c10250ff416a3814c35178af39b9" + dependencies: + unc-path-regex "^0.1.0" + +is-utf8@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" + +is-windows@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-0.2.0.tgz#de1aa6d63ea29dd248737b69f1ff8b8002d2108c" + +isarray@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + +isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + +isexe@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-1.1.2.tgz#36f3e22e60750920f5e7241a476a8c6a42275ad0" + +isobject@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + dependencies: + isarray "1.0.0" + +isstream@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" + +jodid25519@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/jodid25519/-/jodid25519-1.0.2.tgz#06d4912255093419477d425633606e0e90782967" + dependencies: + jsbn "~0.1.0" + +js-tokens@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.1.tgz#08e9f132484a2c45a30907e9dc4d5567b7f114d7" + +js-yaml@^3.5.1: + version "3.7.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.7.0.tgz#5c967ddd837a9bfdca5f2de84253abe8a1c03b80" + dependencies: + argparse "^1.0.7" + esprima "^2.6.0" + +jsbn@~0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.0.tgz#650987da0dd74f4ebf5a11377a2aa2d273e97dfd" + +jsesc@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" + +jsesc@~0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" + +json-loader@^0.5.4: + version "0.5.4" + resolved "https://registry.yarnpkg.com/json-loader/-/json-loader-0.5.4.tgz#8baa1365a632f58a3c46d20175fc6002c96e37de" + +json-schema@0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" + +json-stable-stringify@^1.0.0, json-stable-stringify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" + dependencies: + jsonify "~0.0.0" + +json-stringify-safe@~5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + +json5@^0.5.0: + version "0.5.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" + +jsonify@~0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" + +jsonpointer@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-4.0.1.tgz#4fd92cb34e0e9db3c89c8622ecf51f9b978c6cb9" + +jsprim@^1.2.2: + version "1.3.1" + resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.3.1.tgz#2a7256f70412a29ee3670aaca625994c4dcff252" + dependencies: + extsprintf "1.0.2" + json-schema "0.2.3" + verror "1.3.6" + +kind-of@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.1.0.tgz#475d698a5e49ff5e53d14e3e732429dc8bf4cf47" + dependencies: + is-buffer "^1.0.2" + +lazy-cache@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e" + +lazy-debug-legacy@0.0.X: + version "0.0.1" + resolved "https://registry.yarnpkg.com/lazy-debug-legacy/-/lazy-debug-legacy-0.0.1.tgz#537716c0776e4cf79e3ed1b621f7658c2911b1b1" + +levn@^0.3.0, levn@~0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" + dependencies: + prelude-ls "~1.1.2" + type-check "~0.3.2" + +liftoff@^2.1.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/liftoff/-/liftoff-2.3.0.tgz#a98f2ff67183d8ba7cfaca10548bd7ff0550b385" + dependencies: + extend "^3.0.0" + findup-sync "^0.4.2" + fined "^1.0.1" + flagged-respawn "^0.3.2" + lodash.isplainobject "^4.0.4" + lodash.isstring "^4.0.1" + lodash.mapvalues "^4.4.0" + rechoir "^0.6.2" + resolve "^1.1.7" + +loader-utils@0.2.x, loader-utils@^0.2.11, loader-utils@^0.2.7: + version "0.2.16" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-0.2.16.tgz#f08632066ed8282835dff88dfb52704765adee6d" + dependencies: + big.js "^3.1.3" + emojis-list "^2.0.0" + json5 "^0.5.0" + object-assign "^4.0.1" + +lodash._basecopy@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz#8da0e6a876cf344c0ad8a54882111dd3c5c7ca36" + +lodash._basetostring@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz#d1861d877f824a52f669832dcaf3ee15566a07d5" + +lodash._basevalues@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/lodash._basevalues/-/lodash._basevalues-3.0.0.tgz#5b775762802bde3d3297503e26300820fdf661b7" + +lodash._getnative@^3.0.0: + version "3.9.1" + resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5" + +lodash._isiterateecall@^3.0.0: + version "3.0.9" + resolved "https://registry.yarnpkg.com/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz#5203ad7ba425fae842460e696db9cf3e6aac057c" + +lodash._reescape@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/lodash._reescape/-/lodash._reescape-3.0.0.tgz#2b1d6f5dfe07c8a355753e5f27fac7f1cde1616a" + +lodash._reevaluate@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/lodash._reevaluate/-/lodash._reevaluate-3.0.0.tgz#58bc74c40664953ae0b124d806996daca431e2ed" + +lodash._reinterpolate@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" + +lodash._root@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/lodash._root/-/lodash._root-3.0.1.tgz#fba1c4524c19ee9a5f8136b4609f017cf4ded692" + +lodash.assignwith@^4.0.7: + version "4.2.0" + resolved "https://registry.yarnpkg.com/lodash.assignwith/-/lodash.assignwith-4.2.0.tgz#127a97f02adc41751a954d24b0de17e100e038eb" + +lodash.escape@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/lodash.escape/-/lodash.escape-3.2.0.tgz#995ee0dc18c1b48cc92effae71a10aab5b487698" + dependencies: + lodash._root "^3.0.0" + +lodash.isarguments@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" + +lodash.isarray@^3.0.0: + version "3.0.4" + resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55" + +lodash.isempty@^4.2.1: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.isempty/-/lodash.isempty-4.4.0.tgz#6f86cbedd8be4ec987be9aaf33c9684db1b31e7e" + +lodash.isplainobject@^4.0.4: + version "4.0.6" + resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" + +lodash.isstring@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451" + +lodash.keys@^3.0.0: + version "3.1.2" + resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a" + dependencies: + lodash._getnative "^3.0.0" + lodash.isarguments "^3.0.0" + lodash.isarray "^3.0.0" + +lodash.mapvalues@^4.4.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.mapvalues/-/lodash.mapvalues-4.6.0.tgz#1bafa5005de9dd6f4f26668c30ca37230cc9689c" + +lodash.pick@^4.2.1: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.pick/-/lodash.pick-4.4.0.tgz#52f05610fff9ded422611441ed1fc123a03001b3" + +lodash.restparam@^3.0.0: + version "3.6.1" + resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805" + +lodash.template@^3.0.0: + version "3.6.2" + resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-3.6.2.tgz#f8cdecc6169a255be9098ae8b0c53d378931d14f" + dependencies: + lodash._basecopy "^3.0.0" + lodash._basetostring "^3.0.0" + lodash._basevalues "^3.0.0" + lodash._isiterateecall "^3.0.0" + lodash._reinterpolate "^3.0.0" + lodash.escape "^3.0.0" + lodash.keys "^3.0.0" + lodash.restparam "^3.0.0" + lodash.templatesettings "^3.0.0" + +lodash.templatesettings@^3.0.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-3.1.1.tgz#fb307844753b66b9f1afa54e262c745307dba8e5" + dependencies: + lodash._reinterpolate "^3.0.0" + lodash.escape "^3.0.0" + +lodash@^4.0.0, lodash@^4.2.0, lodash@^4.3.0: + version "4.17.4" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" + +lodash@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-1.0.2.tgz#8f57560c83b59fc270bd3d561b690043430e2551" + +longest@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" + +loose-envify@^1.0.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848" + dependencies: + js-tokens "^3.0.0" + +lru-cache@2: + version "2.7.3" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-2.7.3.tgz#6d4524e8b955f95d4f5b58851ce21dd72fb4e952" + +map-cache@^0.2.0: + version "0.2.2" + resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" + +"memory-fs@>=0.2.0 <0.3.0-0", memory-fs@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.2.0.tgz#f2bb25368bc121e391c2520de92969caee0a0290" + +memory-fs@~0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.3.0.tgz#7bcc6b629e3a43e871d7e29aca6ae8a7f15cbb20" + dependencies: + errno "^0.1.3" + readable-stream "^2.0.1" + +micromatch@^2.1.5, micromatch@^2.3.7: + version "2.3.11" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" + dependencies: + arr-diff "^2.0.0" + array-unique "^0.2.1" + braces "^1.8.2" + expand-brackets "^0.1.4" + extglob "^0.3.1" + filename-regex "^2.0.0" + is-extglob "^1.0.0" + is-glob "^2.0.1" + kind-of "^3.0.2" + normalize-path "^2.0.1" + object.omit "^2.0.0" + parse-glob "^3.0.4" + regex-cache "^0.4.2" + +mime-db@~1.26.0: + version "1.26.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.26.0.tgz#eaffcd0e4fc6935cf8134da246e2e6c35305adff" + +mime-types@^2.1.12, mime-types@~2.1.7: + version "2.1.14" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.14.tgz#f7ef7d97583fcaf3b7d282b6f8b5679dab1e94ee" + dependencies: + mime-db "~1.26.0" + +minimatch@^2.0.1: + version "2.0.10" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-2.0.10.tgz#8d087c39c6b38c001b97fca7ce6d0e1e80afbac7" + dependencies: + brace-expansion "^1.0.0" + +minimatch@^3.0.0, minimatch@^3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.3.tgz#2a4e4090b96b2db06a9d7df01055a62a77c9b774" + dependencies: + brace-expansion "^1.0.0" + +minimatch@~0.2.11: + version "0.2.14" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-0.2.14.tgz#c74e780574f63c6f9a090e90efbe6ef53a6a756a" + dependencies: + lru-cache "2" + sigmund "~1.0.0" + +minimist@0.0.8, minimist@~0.0.1: + version "0.0.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" + +minimist@^1.1.0, minimist@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" + +"mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" + dependencies: + minimist "0.0.8" + +ms@0.7.1: + version "0.7.1" + resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.1.tgz#9cd13c03adbff25b65effde7ce864ee952017098" + +ms@0.7.2: + version "0.7.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.2.tgz#ae25cf2512b3885a1d95d7f037868d8431124765" + +multipipe@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/multipipe/-/multipipe-0.1.2.tgz#2a8f2ddf70eed564dff2d57f1e1a137d9f05078b" + dependencies: + duplexer2 "0.0.2" + +mute-stream@0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.5.tgz#8fbfabb0a98a253d3184331f9e8deb7372fac6c0" + +nan@^2.3.0: + version "2.5.1" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.5.1.tgz#d5b01691253326a97a2bbee9e61c55d8d60351e2" + +natives@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/natives/-/natives-1.1.0.tgz#e9ff841418a6b2ec7a495e939984f78f163e6e31" + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + +node-libs-browser@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-0.7.0.tgz#3e272c0819e308935e26674408d7af0e1491b83b" + dependencies: + assert "^1.1.1" + browserify-zlib "^0.1.4" + buffer "^4.9.0" + console-browserify "^1.1.0" + constants-browserify "^1.0.0" + crypto-browserify "3.3.0" + domain-browser "^1.1.1" + events "^1.0.0" + https-browserify "0.0.1" + os-browserify "^0.2.0" + path-browserify "0.0.0" + process "^0.11.0" + punycode "^1.2.4" + querystring-es3 "^0.2.0" + readable-stream "^2.0.5" + stream-browserify "^2.0.1" + stream-http "^2.3.1" + string_decoder "^0.10.25" + timers-browserify "^2.0.2" + tty-browserify "0.0.0" + url "^0.11.0" + util "^0.10.3" + vm-browserify "0.0.4" + +node-pre-gyp@^0.6.29: + version "0.6.33" + resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.33.tgz#640ac55198f6a925972e0c16c4ac26a034d5ecc9" + dependencies: + mkdirp "~0.5.1" + nopt "~3.0.6" + npmlog "^4.0.1" + rc "~1.1.6" + request "^2.79.0" + rimraf "~2.5.4" + semver "~5.3.0" + tar "~2.2.1" + tar-pack "~3.3.0" + +nopt@~3.0.6: + version "3.0.6" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" + dependencies: + abbrev "1" + +normalize-path@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.0.1.tgz#47886ac1662760d4261b7d979d241709d3ce3f7a" + +npmlog@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.0.2.tgz#d03950e0e78ce1527ba26d2a7592e9348ac3e75f" + dependencies: + are-we-there-yet "~1.1.2" + console-control-strings "~1.1.0" + gauge "~2.7.1" + set-blocking "~2.0.0" + +number-is-nan@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + +oauth-sign@~0.8.1: + version "0.8.2" + resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" + +object-assign@4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.0.tgz#7a3b3d0e98063d43f4c03f2e8ae6cd51a86883a0" + +object-assign@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-3.0.0.tgz#9bedd5ca0897949bca47e7ff408062d549f587f2" + +object-assign@^4.0.1, object-assign@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + +object-hash@^1.1.4: + version "1.1.5" + resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-1.1.5.tgz#bdd844e030d0861b692ca175c6cab6868ec233d7" + +object.omit@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" + dependencies: + for-own "^0.1.4" + is-extendable "^0.1.1" + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + dependencies: + wrappy "1" + +once@~1.3.0, once@~1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/once/-/once-1.3.3.tgz#b2e261557ce4c314ec8304f3fa82663e4297ca20" + dependencies: + wrappy "1" + +onetime@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789" + +optimist@~0.6.0: + version "0.6.1" + resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" + dependencies: + minimist "~0.0.1" + wordwrap "~0.0.2" + +optionator@^0.8.2: + version "0.8.2" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" + dependencies: + deep-is "~0.1.3" + fast-levenshtein "~2.0.4" + levn "~0.3.0" + prelude-ls "~1.1.2" + type-check "~0.3.2" + wordwrap "~1.0.0" + +orchestrator@^0.3.0: + version "0.3.8" + resolved "https://registry.yarnpkg.com/orchestrator/-/orchestrator-0.3.8.tgz#14e7e9e2764f7315fbac184e506c7aa6df94ad7e" + dependencies: + end-of-stream "~0.1.5" + sequencify "~0.0.7" + stream-consume "~0.1.0" + +ordered-read-streams@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/ordered-read-streams/-/ordered-read-streams-0.1.0.tgz#fd565a9af8eb4473ba69b6ed8a34352cb552f126" + +os-browserify@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.2.1.tgz#63fc4ccee5d2d7763d26bbf8601078e6c2e0044f" + +os-homedir@^1.0.0, os-homedir@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" + +os-tmpdir@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + +pako@~0.2.0: + version "0.2.9" + resolved "https://registry.yarnpkg.com/pako/-/pako-0.2.9.tgz#f3f7522f4ef782348da8161bad9ecfd51bf83a75" + +parse-filepath@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parse-filepath/-/parse-filepath-1.0.1.tgz#159d6155d43904d16c10ef698911da1e91969b73" + dependencies: + is-absolute "^0.2.3" + map-cache "^0.2.0" + path-root "^0.1.1" + +parse-glob@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" + dependencies: + glob-base "^0.3.0" + is-dotfile "^1.0.0" + is-extglob "^1.0.0" + is-glob "^2.0.0" + +parse-passwd@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6" + +path-browserify@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.0.tgz#a0b870729aae214005b7d5032ec2cbbb0fb4451a" + +path-exists@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" + dependencies: + pinkie-promise "^2.0.0" + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + +path-is-inside@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" + +path-root-regex@^0.1.0: + version "0.1.2" + resolved "https://registry.yarnpkg.com/path-root-regex/-/path-root-regex-0.1.2.tgz#bfccdc8df5b12dc52c8b43ec38d18d72c04ba96d" + +path-root@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/path-root/-/path-root-0.1.1.tgz#9a4a6814cac1c0cd73360a95f32083c8ea4745b7" + dependencies: + path-root-regex "^0.1.0" + +pbkdf2-compat@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pbkdf2-compat/-/pbkdf2-compat-2.0.1.tgz#b6e0c8fa99494d94e0511575802a59a5c142f288" + +pify@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + +pinkie-promise@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" + dependencies: + pinkie "^2.0.0" + +pinkie@^2.0.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" + +pkg-dir@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-1.0.0.tgz#7a4b508a8d5bb2d629d447056ff4e9c9314cf3d4" + dependencies: + find-up "^1.0.0" + +pluralize@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-1.2.1.tgz#d1a21483fd22bb41e58a12fa3421823140897c45" + +prelude-ls@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" + +preserve@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" + +pretty-hrtime@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz#b7e3ea42435a4c9b2759d99e0f201eb195802ee1" + +private@^0.1.6: + version "0.1.6" + resolved "https://registry.yarnpkg.com/private/-/private-0.1.6.tgz#55c6a976d0f9bafb9924851350fe47b9b5fbb7c1" + +process-nextick-args@~1.0.6: + version "1.0.7" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" + +process@^0.11.0: + version "0.11.9" + resolved "https://registry.yarnpkg.com/process/-/process-0.11.9.tgz#7bd5ad21aa6253e7da8682264f1e11d11c0318c1" + +progress@^1.1.8: + version "1.1.8" + resolved "https://registry.yarnpkg.com/progress/-/progress-1.1.8.tgz#e260c78f6161cdd9b0e56cc3e0a85de17c7a57be" + +prr@~0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/prr/-/prr-0.0.0.tgz#1a84b85908325501411853d0081ee3fa86e2926a" + +punycode@1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" + +punycode@^1.2.4, punycode@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + +qs@~6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.3.0.tgz#f403b264f23bc01228c74131b407f18d5ea5d442" + +querystring-es3@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" + +querystring@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" + +randomatic@^1.1.3: + version "1.1.6" + resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.6.tgz#110dcabff397e9dcff7c0789ccc0a49adf1ec5bb" + dependencies: + is-number "^2.0.2" + kind-of "^3.0.2" + +rc@~1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/rc/-/rc-1.1.6.tgz#43651b76b6ae53b5c802f1151fa3fc3b059969c9" + dependencies: + deep-extend "~0.4.0" + ini "~1.3.0" + minimist "^1.2.0" + strip-json-comments "~1.0.4" + +"readable-stream@>=1.0.33-1 <1.1.0-0": + version "1.0.34" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "0.0.1" + string_decoder "~0.10.x" + +"readable-stream@^2.0.0 || ^1.1.13", readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.1.0, readable-stream@^2.1.5, readable-stream@^2.2.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.2.2.tgz#a9e6fec3c7dda85f8bb1b3ba7028604556fc825e" + dependencies: + buffer-shims "^1.0.0" + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "~1.0.0" + process-nextick-args "~1.0.6" + string_decoder "~0.10.x" + util-deprecate "~1.0.1" + +readable-stream@~1.1.9: + version "1.1.14" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "0.0.1" + string_decoder "~0.10.x" + +readable-stream@~2.1.4: + version "2.1.5" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.1.5.tgz#66fa8b720e1438b364681f2ad1a63c618448c9d0" + dependencies: + buffer-shims "^1.0.0" + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "~1.0.0" + process-nextick-args "~1.0.6" + string_decoder "~0.10.x" + util-deprecate "~1.0.1" + +readdirp@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78" + dependencies: + graceful-fs "^4.1.2" + minimatch "^3.0.2" + readable-stream "^2.0.2" + set-immediate-shim "^1.0.1" + +readline2@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/readline2/-/readline2-1.0.1.tgz#41059608ffc154757b715d9989d199ffbf372e35" + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + mute-stream "0.0.5" + +rechoir@^0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" + dependencies: + resolve "^1.1.6" + +regenerate@^1.2.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.3.2.tgz#d1941c67bad437e1be76433add5b385f95b19260" + +regenerator-runtime@^0.10.0: + version "0.10.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.1.tgz#257f41961ce44558b18f7814af48c17559f9faeb" + +regenerator-transform@0.9.8: + version "0.9.8" + resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.9.8.tgz#0f88bb2bc03932ddb7b6b7312e68078f01026d6c" + dependencies: + babel-runtime "^6.18.0" + babel-types "^6.19.0" + private "^0.1.6" + +regex-cache@^0.4.2: + version "0.4.3" + resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.3.tgz#9b1a6c35d4d0dfcef5711ae651e8e9d3d7114145" + dependencies: + is-equal-shallow "^0.1.3" + is-primitive "^2.0.0" + +regexpu-core@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-2.0.0.tgz#49d038837b8dcf8bfa5b9a42139938e6ea2ae240" + dependencies: + regenerate "^1.2.1" + regjsgen "^0.2.0" + regjsparser "^0.1.4" + +regjsgen@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7" + +regjsparser@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.1.5.tgz#7ee8f84dc6fa792d3fd0ae228d24bd949ead205c" + dependencies: + jsesc "~0.5.0" + +repeat-element@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a" + +repeat-string@^1.5.2: + version "1.6.1" + resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + +repeating@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" + dependencies: + is-finite "^1.0.0" + +replace-ext@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-0.0.1.tgz#29bbd92078a739f0bcce2b4ee41e837953522924" + +request@^2.79.0: + version "2.79.0" + resolved "https://registry.yarnpkg.com/request/-/request-2.79.0.tgz#4dfe5bf6be8b8cdc37fcf93e04b65577722710de" + dependencies: + aws-sign2 "~0.6.0" + aws4 "^1.2.1" + caseless "~0.11.0" + combined-stream "~1.0.5" + extend "~3.0.0" + forever-agent "~0.6.1" + form-data "~2.1.1" + har-validator "~2.0.6" + hawk "~3.1.3" + http-signature "~1.1.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.7" + oauth-sign "~0.8.1" + qs "~6.3.0" + stringstream "~0.0.4" + tough-cookie "~2.3.0" + tunnel-agent "~0.4.1" + uuid "^3.0.0" + +require-uncached@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" + dependencies: + caller-path "^0.1.0" + resolve-from "^1.0.0" + +resolve-dir@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/resolve-dir/-/resolve-dir-0.1.1.tgz#b219259a5602fac5c5c496ad894a6e8cc430261e" + dependencies: + expand-tilde "^1.2.2" + global-modules "^0.2.3" + +resolve-from@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226" + +resolve-url@~0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" + +resolve@^1.1.6, resolve@^1.1.7: + version "1.2.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.2.0.tgz#9589c3f2f6149d1417a40becc1663db6ec6bc26c" + +restore-cursor@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541" + dependencies: + exit-hook "^1.0.0" + onetime "^1.0.0" + +right-align@^0.1.1: + version "0.1.3" + resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef" + dependencies: + align-text "^0.1.1" + +rimraf@2, rimraf@^2.2.8, rimraf@~2.5.1, rimraf@~2.5.4: + version "2.5.4" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.5.4.tgz#96800093cbf1a0c86bd95b4625467535c29dfa04" + dependencies: + glob "^7.0.5" + +ripemd160@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-0.2.0.tgz#2bf198bde167cacfa51c0a928e84b68bbe171fce" + +run-async@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/run-async/-/run-async-0.1.0.tgz#c8ad4a5e110661e402a7d21b530e009f25f8e389" + dependencies: + once "^1.3.0" + +rx-lite@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-3.1.2.tgz#19ce502ca572665f3b647b10939f97fd1615f102" + +semver@^4.1.0: + version "4.3.6" + resolved "https://registry.yarnpkg.com/semver/-/semver-4.3.6.tgz#300bc6e0e86374f7ba61068b5b1ecd57fc6532da" + +semver@~5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" + +sequencify@~0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/sequencify/-/sequencify-0.0.7.tgz#90cff19d02e07027fd767f5ead3e7b95d1e7380c" + +set-blocking@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + +set-immediate-shim@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61" + +setimmediate@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" + +sha.js@2.2.6: + version "2.2.6" + resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.2.6.tgz#17ddeddc5f722fb66501658895461977867315ba" + +shelljs@^0.7.5: + version "0.7.6" + resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.7.6.tgz#379cccfb56b91c8601e4793356eb5382924de9ad" + dependencies: + glob "^7.0.0" + interpret "^1.0.0" + rechoir "^0.6.2" + +sigmund@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/sigmund/-/sigmund-1.0.1.tgz#3ff21f198cad2175f9f3b781853fd94d0d19b590" + +signal-exit@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" + +slash@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" + +slice-ansi@0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35" + +sntp@1.x.x: + version "1.0.9" + resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198" + dependencies: + hoek "2.x.x" + +source-list-map@~0.1.7: + version "0.1.8" + resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-0.1.8.tgz#c550b2ab5427f6b3f21f5afead88c4f5587b2106" + +source-map-resolve@^0.3.0: + version "0.3.1" + resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.3.1.tgz#610f6122a445b8dd51535a2a71b783dfc1248761" + dependencies: + atob "~1.1.0" + resolve-url "~0.2.1" + source-map-url "~0.3.0" + urix "~0.1.0" + +source-map-support@^0.4.2: + version "0.4.11" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.11.tgz#647f939978b38535909530885303daf23279f322" + dependencies: + source-map "^0.5.3" + +source-map-url@~0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.3.0.tgz#7ecaf13b57bcd09da8a40c5d269db33799d4aaf9" + +source-map@0.1.x, source-map@^0.1.38: + version "0.1.43" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.1.43.tgz#c24bc146ca517c1471f5dacbe2571b2b7f9e3346" + dependencies: + amdefine ">=0.0.4" + +source-map@0.X, source-map@^0.5.0, source-map@^0.5.3, source-map@~0.5.1: + version "0.5.6" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412" + +source-map@~0.4.1: + version "0.4.4" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b" + dependencies: + amdefine ">=0.0.4" + +sparkles@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/sparkles/-/sparkles-1.0.0.tgz#1acbbfb592436d10bbe8f785b7cc6f82815012c3" + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + +sshpk@^1.7.0: + version "1.10.2" + resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.10.2.tgz#d5a804ce22695515638e798dbe23273de070a5fa" + dependencies: + asn1 "~0.2.3" + assert-plus "^1.0.0" + dashdash "^1.12.0" + getpass "^0.1.1" + optionalDependencies: + bcrypt-pbkdf "^1.0.0" + ecc-jsbn "~0.1.1" + jodid25519 "^1.0.0" + jsbn "~0.1.0" + tweetnacl "~0.14.0" + +stream-browserify@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.1.tgz#66266ee5f9bdb9940a4e4514cafb43bb71e5c9db" + dependencies: + inherits "~2.0.1" + readable-stream "^2.0.2" + +stream-consume@~0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/stream-consume/-/stream-consume-0.1.0.tgz#a41ead1a6d6081ceb79f65b061901b6d8f3d1d0f" + +stream-http@^2.3.1: + version "2.6.3" + resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.6.3.tgz#4c3ddbf9635968ea2cfd4e48d43de5def2625ac3" + dependencies: + builtin-status-codes "^3.0.0" + inherits "^2.0.1" + readable-stream "^2.1.0" + to-arraybuffer "^1.0.0" + xtend "^4.0.0" + +string-width@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + strip-ansi "^3.0.0" + +string-width@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.0.0.tgz#635c5436cc72a6e0c387ceca278d4e2eec52687e" + dependencies: + is-fullwidth-code-point "^2.0.0" + strip-ansi "^3.0.0" + +string_decoder@^0.10.25, string_decoder@~0.10.x: + version "0.10.31" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" + +stringstream@~0.0.4: + version "0.0.5" + resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878" + +strip-ansi@^3.0.0, strip-ansi@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + dependencies: + ansi-regex "^2.0.0" + +strip-bom@2.X: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" + dependencies: + is-utf8 "^0.2.0" + +strip-bom@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-1.0.0.tgz#85b8862f3844b5a6d5ec8467a93598173a36f794" + dependencies: + first-chunk-stream "^1.0.0" + is-utf8 "^0.2.0" + +strip-bom@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + +strip-json-comments@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-1.0.4.tgz#1e15fbcac97d3ee99bf2d73b4c656b082bbafb91" + +strip-json-comments@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + +supports-color@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-0.2.0.tgz#d92de2694eb3f67323973d7ae3d8b55b4c22190a" + +supports-color@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" + +supports-color@^3.1.0: + version "3.2.3" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6" + dependencies: + has-flag "^1.0.0" + +table@^3.7.8: + version "3.8.3" + resolved "https://registry.yarnpkg.com/table/-/table-3.8.3.tgz#2bbc542f0fda9861a755d3947fefd8b3f513855f" + dependencies: + ajv "^4.7.0" + ajv-keywords "^1.0.0" + chalk "^1.1.1" + lodash "^4.0.0" + slice-ansi "0.0.4" + string-width "^2.0.0" + +tapable@^0.1.8, tapable@~0.1.8: + version "0.1.10" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-0.1.10.tgz#29c35707c2b70e50d07482b5d202e8ed446dafd4" + +tar-pack@~3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/tar-pack/-/tar-pack-3.3.0.tgz#30931816418f55afc4d21775afdd6720cee45dae" + dependencies: + debug "~2.2.0" + fstream "~1.0.10" + fstream-ignore "~1.0.5" + once "~1.3.3" + readable-stream "~2.1.4" + rimraf "~2.5.1" + tar "~2.2.1" + uid-number "~0.0.6" + +tar@~2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1" + dependencies: + block-stream "*" + fstream "^1.0.2" + inherits "2" + +text-table@~0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + +through2@2.X, through2@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.3.tgz#0004569b37c7c74ba39c43f3ced78d1ad94140be" + dependencies: + readable-stream "^2.1.5" + xtend "~4.0.1" + +through2@^0.6.1: + version "0.6.5" + resolved "https://registry.yarnpkg.com/through2/-/through2-0.6.5.tgz#41ab9c67b29d57209071410e1d7a7a968cd3ad48" + dependencies: + readable-stream ">=1.0.33-1 <1.1.0-0" + xtend ">=4.0.0 <4.1.0-0" + +"through@>=2.3.4 <2.4.0-0", through@^2.3.6: + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + +tildify@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/tildify/-/tildify-1.2.0.tgz#dcec03f55dca9b7aa3e5b04f21817eb56e63588a" + dependencies: + os-homedir "^1.0.0" + +time-stamp@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/time-stamp/-/time-stamp-1.0.1.tgz#9f4bd23559c9365966f3302dbba2b07c6b99b151" + +timers-browserify@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.2.tgz#ab4883cf597dcd50af211349a00fbca56ac86b86" + dependencies: + setimmediate "^1.0.4" + +to-arraybuffer@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" + +to-fast-properties@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.2.tgz#f3f5c0c3ba7299a7ef99427e44633257ade43320" + +tough-cookie@~2.3.0: + version "2.3.2" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.2.tgz#f081f76e4c85720e6c37a5faced737150d84072a" + dependencies: + punycode "^1.4.1" + +tryit@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/tryit/-/tryit-1.0.3.tgz#393be730a9446fd1ead6da59a014308f36c289cb" + +tty-browserify@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" + +tunnel-agent@~0.4.1: + version "0.4.3" + resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.4.3.tgz#6373db76909fe570e08d73583365ed828a74eeeb" + +tweetnacl@^0.14.3, tweetnacl@~0.14.0: + version "0.14.5" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" + +type-check@~0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" + dependencies: + prelude-ls "~1.1.2" + +typedarray@^0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" + +uglify-js@~2.7.3: + version "2.7.5" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.7.5.tgz#4612c0c7baaee2ba7c487de4904ae122079f2ca8" + dependencies: + async "~0.2.6" + source-map "~0.5.1" + uglify-to-browserify "~1.0.0" + yargs "~3.10.0" + +uglify-to-browserify@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7" + +uid-number@~0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" + +unc-path-regex@^0.1.0: + version "0.1.2" + resolved "http://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz#e73dd3d7b0d7c5ed86fbac6b0ae7d8c6a69d50fa" + +unique-stream@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unique-stream/-/unique-stream-1.0.0.tgz#d59a4a75427447d9aa6c91e70263f8d26a4b104b" + +urix@^0.1.0, urix@~0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" + +url@^0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" + dependencies: + punycode "1.3.2" + querystring "0.2.0" + +user-home@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/user-home/-/user-home-1.1.1.tgz#2b5be23a32b63a7c9deb8d0f28d485724a3df190" + +user-home@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/user-home/-/user-home-2.0.0.tgz#9c70bfd8169bc1dcbf48604e0f04b8b49cde9e9f" + dependencies: + os-homedir "^1.0.0" + +util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + +util@0.10.3, util@^0.10.3: + version "0.10.3" + resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9" + dependencies: + inherits "2.0.1" + +uuid@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.0.1.tgz#6544bba2dfda8c1cf17e629a3a305e2bb1fee6c1" + +v8flags@^2.0.2: + version "2.0.11" + resolved "https://registry.yarnpkg.com/v8flags/-/v8flags-2.0.11.tgz#bca8f30f0d6d60612cc2c00641e6962d42ae6881" + dependencies: + user-home "^1.1.1" + +verror@1.3.6: + version "1.3.6" + resolved "https://registry.yarnpkg.com/verror/-/verror-1.3.6.tgz#cff5df12946d297d2baaefaa2689e25be01c005c" + dependencies: + extsprintf "1.0.2" + +vinyl-fs@^0.3.0: + version "0.3.14" + resolved "https://registry.yarnpkg.com/vinyl-fs/-/vinyl-fs-0.3.14.tgz#9a6851ce1cac1c1cea5fe86c0931d620c2cfa9e6" + dependencies: + defaults "^1.0.0" + glob-stream "^3.1.5" + glob-watcher "^0.0.6" + graceful-fs "^3.0.0" + mkdirp "^0.5.0" + strip-bom "^1.0.0" + through2 "^0.6.1" + vinyl "^0.4.0" + +vinyl@1.X: + version "1.2.0" + resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-1.2.0.tgz#5c88036cf565e5df05558bfc911f8656df218884" + dependencies: + clone "^1.0.0" + clone-stats "^0.0.1" + replace-ext "0.0.1" + +"vinyl@>=0.5.0 <0.6.0-0", vinyl@^0.5.0: + version "0.5.3" + resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-0.5.3.tgz#b0455b38fc5e0cf30d4325132e461970c2091cde" + dependencies: + clone "^1.0.0" + clone-stats "^0.0.1" + replace-ext "0.0.1" + +vinyl@^0.4.0: + version "0.4.6" + resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-0.4.6.tgz#2f356c87a550a255461f36bbeb2a5ba8bf784847" + dependencies: + clone "^0.2.0" + clone-stats "^0.0.1" + +vm-browserify@0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-0.0.4.tgz#5d7ea45bbef9e4a6ff65f95438e0a87c357d5a73" + dependencies: + indexof "0.0.1" + +watchpack@^0.2.1: + version "0.2.9" + resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-0.2.9.tgz#62eaa4ab5e5ba35fdfc018275626e3c0f5e3fb0b" + dependencies: + async "^0.9.0" + chokidar "^1.0.0" + graceful-fs "^4.1.2" + +webpack-core@~0.6.9: + version "0.6.9" + resolved "https://registry.yarnpkg.com/webpack-core/-/webpack-core-0.6.9.tgz#fc571588c8558da77be9efb6debdc5a3b172bdc2" + dependencies: + source-list-map "~0.1.7" + source-map "~0.4.1" + +"webpack@>=1.9.0 <2.0.0-0", webpack@^1.13.2: + version "1.14.0" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-1.14.0.tgz#54f1ffb92051a328a5b2057d6ae33c289462c823" + dependencies: + acorn "^3.0.0" + async "^1.3.0" + clone "^1.0.2" + enhanced-resolve "~0.9.0" + interpret "^0.6.4" + loader-utils "^0.2.11" + memory-fs "~0.3.0" + mkdirp "~0.5.0" + node-libs-browser "^0.7.0" + optimist "~0.6.0" + supports-color "^3.1.0" + tapable "~0.1.8" + uglify-js "~2.7.3" + watchpack "^0.2.1" + webpack-core "~0.6.9" + +which@^1.2.12: + version "1.2.12" + resolved "https://registry.yarnpkg.com/which/-/which-1.2.12.tgz#de67b5e450269f194909ef23ece4ebe416fa1192" + dependencies: + isexe "^1.1.1" + +wide-align@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.0.tgz#40edde802a71fea1f070da3e62dcda2e7add96ad" + dependencies: + string-width "^1.0.1" + +window-size@0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d" + +wordwrap@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" + +wordwrap@~0.0.2: + version "0.0.3" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" + +wordwrap@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + +write@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757" + dependencies: + mkdirp "^0.5.1" + +"xtend@>=4.0.0 <4.1.0-0", xtend@^4.0.0, xtend@~4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" + +yargs@~3.10.0: + version "3.10.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1" + dependencies: + camelcase "^1.0.2" + cliui "^2.1.0" + decamelize "^1.0.0" + window-size "0.1.0" diff --git a/user/plugins/langswitcher/CHANGELOG.md b/user/plugins/langswitcher/CHANGELOG.md new file mode 100644 index 0000000..1785d5f --- /dev/null +++ b/user/plugins/langswitcher/CHANGELOG.md @@ -0,0 +1,50 @@ +# v1.4.0 +## 06/29/2017 + +1. [](#new) + * Added the `untranslated_pages_behavior` option to determine what to do with a language link when the current page doesn't exist in that language or it exists but it's not published +1. [](#bugfix) + * Fixed generated URLs when `append_url_extension` is set, via PR [#22](https://github.com/getgrav/grav-plugin-langswitcher/pull/22) + +# v1.3.0 +## 02/17/2017 + +1. [](#new) + * Added support for `hreflang` annotations via PR [#19](https://github.com/getgrav/grav-plugin-langswitcher/pull/19) + +# v1.2.1 +## 05/28/2016 + +1. [](#bugfix) + * Display all language names, even those with non supported locales + +# v1.2.0 +## 05/03/2016 + +1. [](#improved) + * Take URI parameters into account when switching languages + * Add `external` class to avoid problems on modular pages when `jquery.singlePageNav` is loaded + +# v1.1.0 +## 10/15/2015 + +1. [](#improved) + * Added active class to language links + +# v1.0.2 +## 07/13/2015 + +1. [](#improved) + * Improved homepage routing + +# v1.0.1 +## 07/08/2015 + +1. [](#improved) + * Updated blueprints with some typo fixes + +# v1.0.0 +## 07/08/2015 + +1. [](#new) + * ChangeLog started... diff --git a/user/plugins/langswitcher/LICENSE b/user/plugins/langswitcher/LICENSE new file mode 100644 index 0000000..0e788c6 --- /dev/null +++ b/user/plugins/langswitcher/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 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/langswitcher/README.md b/user/plugins/langswitcher/README.md new file mode 100644 index 0000000..c2ecea8 --- /dev/null +++ b/user/plugins/langswitcher/README.md @@ -0,0 +1,92 @@ +# Grav LangSwitcher Plugin + +![LangSwitcher](assets/readme_1.png) + +`LangSwitcher` is a [Grav](http://github.com/getgrav/grav) plugin that provides native language text links to switch between [Multiple Languages](http://learn.getgrav.org/content/multi-language) in Grav **0.9.30** or greater. + +# Installation + +Installing the LangSwitcher 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 langswitcher + +This will install the LangSwitcher plugin into your `/user/plugins` directory within Grav. Its files can be found under `/your/site/grav/user/plugins/langswitcher`. + +## 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 `langswitcher`. You can find these files either on [GitHub](https://github.com/getgrav/grav-plugin-langswitcher) or via [GetGrav.org](http://getgrav.org/downloads/plugins#extras). + +You should now have all the plugin files under + + /your/site/grav/user/plugins/langswitcher + +# Usage + +The `langswitcher` plugin doesn't require any configuration. You do however need to add the included Twig partials template into your own theme somewhere you want the available languages to be displayed. + +``` +{% include 'partials/langswitcher.html.twig' %} +``` + +Something you might want to do is to override the look and feel of the langswitcher, and with Grav it is super easy. + +Copy the template file [langswitcher.html.twig](templates/partials/langswitcher.html.twig) into the `templates` folder of your custom theme: + +``` +/your/site/grav/user/themes/custom-theme/templates/partials/langswitcher.html.twig +``` + +You can now edit the override and tweak it however you prefer. + +## Usage of the `hreflang` partial + +A second template is available for `hreflang` annotations in the header of the page. In order to emit language annotations for the available languages of a page you need to add the corrsponding Twig partial template into the `` section of your page, which can typically be found in `base.html.twig`: + +``` +{% include 'partials/langswitcher.hreflang.html.twig' %} +``` + +This will generate something like: + +``` + + + +``` + +# Updating + +As development for the LangSwitcher plugin continues, new versions may become available that add additional features and functionality, improve compatibility with newer Grav releases, and generally provide a better user experience. Updating LangSwitcher is easy, and can be done through Grav's GPM system, as well as manually. + +## GPM Update (Preferred) + +The simplest way to update this plugin is via the [Grav Package Manager (GPM)](http://learn.getgrav.org/advanced/grav-gpm). You can do this with this by navigating to the root directory of your Grav install using your system's Terminal (also called command line) and typing the following: + + bin/gpm update langswitcher + +This command will check your Grav install to see if your LangSwitcher plugin is due for an update. If a newer release is found, you will be asked whether or not you wish to update. To continue, type `y` and hit enter. The plugin will automatically update and clear Grav's cache. + +> Note: Any changes you have made to any of the files listed under this directory will also be removed and replaced by the new set. Any files located elsewhere (for example a YAML settings file placed in `user/config/plugins`) will remain intact. + +## Configuration + +Simply copy the `user/plugins/langswitcher/langswitcher.yaml` into `user/config/plugins/langswitcher.yaml` and make your modifications. + +``` +enabled: true +built_in_css: true +``` + +Options are pretty self explanatory. + +## Redirecting after switching language + +To have Grav redirect to the default page route after switching language, you must add the following configuration to `user/config/system.yaml` +``` +pages: + redirect_default_route: true +``` diff --git a/user/plugins/langswitcher/assets/readme_1.png b/user/plugins/langswitcher/assets/readme_1.png new file mode 100644 index 0000000..8cfb824 Binary files /dev/null and b/user/plugins/langswitcher/assets/readme_1.png differ diff --git a/user/plugins/langswitcher/blueprints.yaml b/user/plugins/langswitcher/blueprints.yaml new file mode 100644 index 0000000..062d2ae --- /dev/null +++ b/user/plugins/langswitcher/blueprints.yaml @@ -0,0 +1,47 @@ +name: LangSwitcher +version: 1.4.0 +description: LangSwitcher is a [Grav](http://github.com/getgrav/grav) plugin that provides native language text links to switch between [multiple languages](http://learn.getgrav.org/content/multi-language) in Grav **v0.9.30** or greater. +icon: globe +author: + name: Team Grav + email: devs@getgrav.org + url: http://getgrav.org +homepage: https://github.com/getgrav/grav-plugin-langswitcher +keywords: mulitlang, multilanguage, translation, switcher +bugs: https://github.com/getgrav/grav-plugin-langswitcher/issues +license: MIT + +form: + validation: strict + fields: + enabled: + type: toggle + label: Plugin status + highlight: 1 + default: 1 + options: + 1: Enabled + 0: Disabled + validate: + type: bool + + built_in_css: + type: toggle + label: Use built in CSS + highlight: 1 + default: 1 + options: + 1: Enabled + 0: Disabled + validate: + type: bool + + untranslated_pages_behavior: + type: select + label: Untranslated pages behavior + help: Determine what to do with a language link when the current page doesn't exist in that language or it exists but it's not published. + default: none + options: + none: Show language (default) + redirect: Show language, link to home route + hide: Hide language diff --git a/user/plugins/langswitcher/css/langswitcher.css b/user/plugins/langswitcher/css/langswitcher.css new file mode 100644 index 0000000..710dee3 --- /dev/null +++ b/user/plugins/langswitcher/css/langswitcher.css @@ -0,0 +1,22 @@ +.langswitcher { + position: relative; + top: 50%; + -webkit-transform: translateY(-50%); + -moz-transform: translateY(-50%); + -o-transform: translateY(-50%); + -ms-transform: translateY(-50%); + transform: translateY(-50%); + margin-left: 1rem !important; + display: inline-block; +} + +.langswitcher li { + display: inline-block; + margin-left: 0.5rem; + line-height: 1rem; +} + +.langswitcher .active { + font-weight: bold; + text-decoration: underline; +} diff --git a/user/plugins/langswitcher/langswitcher.php b/user/plugins/langswitcher/langswitcher.php new file mode 100644 index 0000000..81fd8f8 --- /dev/null +++ b/user/plugins/langswitcher/langswitcher.php @@ -0,0 +1,98 @@ + ['onPluginsInitialized', 0] + ]; + } + + /** + * Initialize configuration + */ + public function onPluginsInitialized() + { + if ($this->isAdmin()) { + $this->active = false; + return; + } + + $this->enable([ + 'onTwigInitialized' => ['onTwigInitialized', 0], + 'onTwigTemplatePaths' => ['onTwigTemplatePaths', 0], + 'onTwigSiteVariables' => ['onTwigSiteVariables', 0] + ]); + } + + /** Add the native_name function */ + public function onTwigInitialized() + { + $this->grav['twig']->twig()->addFunction( + new \Twig_SimpleFunction('native_name', function($key) { + return LanguageCodes::getNativeName($key); + }) + ); + } + + /** + * Add current directory to twig lookup paths. + */ + public function onTwigTemplatePaths() + { + $this->grav['twig']->twig_paths[] = __DIR__ . '/templates'; + } + + /** + * Set needed variables to display Langswitcher. + */ + public function onTwigSiteVariables() + { + $data = new \stdClass; + + $page = $this->grav['page']; + $data->page_route = $page->rawRoute(); + if ($page->home()) { + $data->page_route = '/'; + } + + $languages = $this->grav['language']->getLanguages(); + $data->languages = $languages; + + if ($this->config->get('plugins.langswitcher.untranslated_pages_behavior') !== 'none') { + $translated_pages = []; + foreach ($languages as $language) { + $translated_pages[$language] = null; + $page_name_without_ext = substr($page->name(), 0, -(strlen($page->extension()))); + $translated_page_path = $page->path() . DS . $page_name_without_ext . '.' . $language . '.md'; + if (file_exists($translated_page_path)) { + $translated_page = new Page(); + $translated_page->init(new \SplFileInfo($translated_page_path), $language . '.md'); + $translated_pages[$language] = $translated_page; + } + } + $data->translated_pages = $translated_pages; + } + + $data->current = $this->grav['language']->getLanguage(); + + $this->grav['twig']->twig_vars['langswitcher'] = $data; + + if ($this->config->get('plugins.langswitcher.built_in_css')) { + $this->grav['assets']->add('plugin://langswitcher/css/langswitcher.css'); + } + } + + public function getNativeName($code) { + + } +} diff --git a/user/plugins/langswitcher/langswitcher.yaml b/user/plugins/langswitcher/langswitcher.yaml new file mode 100644 index 0000000..3066a1a --- /dev/null +++ b/user/plugins/langswitcher/langswitcher.yaml @@ -0,0 +1,3 @@ +enabled: true +built_in_css: true +untranslated_pages_behavior: none diff --git a/user/plugins/langswitcher/templates/partials/langswitcher.hreflang.html.twig b/user/plugins/langswitcher/templates/partials/langswitcher.hreflang.html.twig new file mode 100644 index 0000000..a70fd96 --- /dev/null +++ b/user/plugins/langswitcher/templates/partials/langswitcher.hreflang.html.twig @@ -0,0 +1,9 @@ +{% set langobj = grav['language'] %} +{% for key in langswitcher.languages %} +{% if key == langswitcher.current %} + {% set lang_url = page.url %} +{% else %} + {% set lang_url = base_url_simple ~ langobj.getLanguageURLPrefix(key) ~ langswitcher.page_route ~ page.urlExtension ?: '/' %} +{% endif %} + +{% endfor %} diff --git a/user/plugins/langswitcher/templates/partials/langswitcher.html.twig b/user/plugins/langswitcher/templates/partials/langswitcher.html.twig new file mode 100644 index 0000000..040fb25 --- /dev/null +++ b/user/plugins/langswitcher/templates/partials/langswitcher.html.twig @@ -0,0 +1,30 @@ +
                                                                        +{% for language in langswitcher.languages %} + + {% set show_language = true %} + {% if language == langswitcher.current %} + {% set lang_url = page.url %} + {% set active_class = ' active' %} + {% else %} + {% set base_lang_url = base_url_simple ~ grav.language.getLanguageURLPrefix(language) %} + {% set lang_url = base_lang_url ~ langswitcher.page_route ~ page.urlExtension %} + {% set untranslated_pages_behavior = grav.config.plugins.langswitcher.untranslated_pages_behavior %} + {% if untranslated_pages_behavior != 'none' %} + {% set translated_page = langswitcher.translated_pages[language] %} + {% if (not translated_page) or (not translated_page.published) %} + {% if untranslated_pages_behavior == 'redirect' %} + {% set lang_url = base_lang_url ~ '/' %} + {% elseif untranslated_pages_behavior == 'hide' %} + {% set show_language = false %} + {% endif %} + {% endif %} + {% endif %} + {% set active_class = '' %} + {% endif %} + + {% if show_language %} +
                                                                      • {{ native_name(language)|capitalize }}
                                                                      • + {% endif %} + +{% endfor %} +
                                                                      diff --git a/user/plugins/login/.gitignore b/user/plugins/login/.gitignore new file mode 100644 index 0000000..090a1f0 --- /dev/null +++ b/user/plugins/login/.gitignore @@ -0,0 +1,2 @@ +.idea +.DS_Store diff --git a/user/plugins/login/CHANGELOG.md b/user/plugins/login/CHANGELOG.md new file mode 100644 index 0000000..fbfb7ba --- /dev/null +++ b/user/plugins/login/CHANGELOG.md @@ -0,0 +1,475 @@ +# 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 0000000..4bb7092 --- /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 0000000..bf3b5e1 --- /dev/null +++ b/user/plugins/login/README.md @@ -0,0 +1,479 @@ +# 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.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/acounts` 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') +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: 0 # 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: 0 # Number of failed login attempts in a specific time frame (0 = unlimited) +max_login_interval: 2 # Time in minutes to track login attempts +``` + +# 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: true # 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: true # 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 +``` + + + +# 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 0000000..85c054b --- /dev/null +++ b/user/plugins/login/blueprints.yaml @@ -0,0 +1,380 @@ +name: Login +version: 2.5.0 +description: Enables user authentication and login screen. +icon: sign-in +author: + name: Team Grav + email: devs@getgrav.org + url: http://getgrav.org +keywords: admin, plugin, login +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.3.9' } + - { name: form, version: '>=2.4.0' } + - { name: email, version: '~2.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" + + 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 + + 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: 1 + 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.REGISTRATION_FIELD_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: 1 + 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: 1 + 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: 1 + 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: 1 + 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: 1 + options: + 1: PLUGIN_ADMIN.YES + 0: PLUGIN_ADMIN.NO + + 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.SECONDS + 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.SECONDS + 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 0000000..320dd4a --- /dev/null +++ b/user/plugins/login/classes/Controller.php @@ -0,0 +1,452 @@ +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. + if (isset($this->post['_redirect'])) { + $redirect = $this->post['_redirect']; + 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 = call_user_func([$this, $method]); + } catch (\RuntimeException $e) { + $messages->add($e->getMessage(), 'error'); + } + + if (!$this->redirect && isset($redirect)) { + $this->setRedirect($redirect); + } + + return $success; + } + + /** + * Handle login. + * + * @return bool True if the action was performed. + */ + public function taskLogin() + { + /** @var Language $t */ + $t = $this->grav['language']; + + $messages = $this->grav['messages']; + + $userKey = isset($this->post['username']) ? (string)$this->post['username'] : ''; + $ipKey = Uri::ip(); + + $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; + } + + if ($this->authenticate($this->post)) { + $rateLimiter->resetRateLimit($ipKey, 'ip')->resetRateLimit($userKey); + + $messages->add($t->translate('PLUGIN_LOGIN.LOGIN_SUCCESSFUL'), 'info'); + + $redirect = $this->grav['config']->get('plugins.login.redirect_after_login'); + if (!$redirect) { + $redirect = $this->grav['session']->redirect_after_login ?: $this->grav['uri']->referrer('/'); + } + $this->setRedirect($redirect); + } else { + /** @var User $user */ + $user = $this->grav['user']; + if ($user->username) { + $messages->add($t->translate('PLUGIN_LOGIN.ACCESS_DENIED'), 'error'); + $this->setRedirect($this->grav['config']->get('plugins.login.route_unauthorized', '/')); + } else { + $messages->add($t->translate('PLUGIN_LOGIN.LOGIN_FAILED'), 'error'); + } + } + + return true; + } + + /** + * Handle logout. + * + * @return bool True if the action was performed. + */ + public function taskLogout() + { + $this->login->logout(['remember_me' => true]); + + $this->setRedirect('/'); + + 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; + + $email = isset($data['email']) ? $data['email'] : ''; + $user = !empty($email) ? User::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; + } + + $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; + + $reset_link = $this->grav['base_url_absolute'] . $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'])) { + $username = isset($data['username']) ? $data['username'] : null; + $user = !empty($username) ? User::find($username) : null; + $password = isset($data['password']) ? $data['password'] : null; + $token = isset($data['token']) ? $data['token'] : null; + + if ($user && !empty($user->reset) && $user->exists()) { + list($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->redirect($this->grav['config']->get('plugins.login.route_forgot', '/')); + + return true; + } + + unset($user->hashed_password, $user->reset); + $user->password = $password; + + $user->validate(); + $user->filter(); + $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->redirect($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->redirect($this->grav['config']->get('plugins.login.route_forgot')); + + return true; + } + + return true; + } + + /** + * Authenticate user. + * + * @param array $form Form fields. + * + * @return bool + */ + 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; + } + + /** + * Redirects an action + */ + public function redirect() + { + if ($this->redirect) { + $this->grav->redirect($this->redirect, $this->redirectCode); + } + } + + /** + * Set redirect. + * + * @param $path + * @param int $code + */ + public function setRedirect($path, $code = 303) + { + $this->redirect = $path; + $this->redirectCode = $code; + } + + /** + * 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 3.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 User $user + * @param $field + * @param $count + * @param $interval + * @return bool + * @deprecated 3.0 Use $grav['login']->getRateLimiter($context) instead. See Grav\Plugin\Login\RateLimiter class. + */ + protected function isUserRateLimited(User $user, $field, $count, $interval) + { + return $this->login->isUserRateLimited($user, $field, $count, $interval); + } + + /** + * Reset the rate limit counter + * + * @param User $user + * @param $field + * @deprecated 3.0 Use $grav['login']->getRateLimiter($context) instead. See Grav\Plugin\Login\RateLimiter class. + */ + protected function resetRateLimit(User $user, $field) + { + $this->login->resetRateLimit($user, $field); + } +} diff --git a/user/plugins/login/classes/Events/UserLoginEvent.php b/user/plugins/login/classes/Events/UserLoginEvent.php new file mode 100644 index 0000000..c4bf522 --- /dev/null +++ b/user/plugins/login/classes/Events/UserLoginEvent.php @@ -0,0 +1,256 @@ + + (isset($items['credentials']) ? (array)$items['credentials'] : []) + ['username' => '', 'password' => ''], + 'options' => [], + 'authorize' => 'site.login', + 'status' => static::AUTHENTICATION_UNDEFINED, + 'user' => null, + 'message' => '' + ]; + + parent::__construct($items); + + if (!$this->offsetExists('user')) { + $this->offsetSet('user', User::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 isset($this->items['credentials'][$name]) ? $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 isset($this->items['options'][$name]) ? $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 User + */ + public function getUser() + { + return $this->offsetGet('user'); + } + + /** + * @param User $user + * @return $this + */ + public function setUser(User $user) + { + $this->offsetSet('user', $user); + + return $this; + } + + /** + * @return array + */ + public function getAuthorize() + { + return (array)$this->offsetGet('authorize'); + } + + /** + * @param string $message + * @return $this + */ + public function setMessage($message) + { + $this->items['message'] = (string)$message; + + 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 0000000..729bf05 --- /dev/null +++ b/user/plugins/login/classes/Login.php @@ -0,0 +1,499 @@ +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 + * @param array $options + * @param array $extra Example: ['authorize' => 'site.login', 'user' => null], undefined variables gets set. + * @return User + */ + 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 $user; + } + + /** + * Logout user. + * + * @param array $options + * @param User $user + * @return User + */ + public function logout(array $options = [], User $user = null) + { + $grav = Grav::instance(); + + $eventOptions = [ + 'user' => $user ?: $grav['user'], + 'options' => $options + ]; + + $event = new UserLoginEvent($eventOptions); + + // Logout the user. + $grav->fireEvent('onUserLogout', $event); + + $user = $event->getUser(); + $user->authenticated = false; + + return $user; + } + + /** + * Authenticate user. + * + * @param array $credentials Form fields. + * @param array $options + * + * @return bool + */ + public function authenticate($credentials, $options = ['remember_me' => true]) + { + $user = $this->login($credentials, $options); + + if ($user->authenticated) { + $this->grav['messages']->add($this->language->translate('PLUGIN_LOGIN.LOGIN_SUCCESSFUL', + [$user->language]), 'info'); + + $redirect_route = $this->uri->route(); + $this->grav->redirect($redirect_route); + } + + return $user->authenticated; + } + + /** + * Create a new user file + * + * @param array $data + * + * @return User + */ + public function register($data) + { + //Add new user ACL settings + $groups = $this->config->get('plugins.login.user_registration.groups', []); + + if (count($groups) > 0) { + $data['groups'] = $groups; + } + + $access = $this->config->get('plugins.login.user_registration.access.site', []); + if (count($access) > 0) { + $data['access']['site'] = $access; + } + + $username = $data['username']; + $file = CompiledYamlFile::instance($this->grav['locator']->findResource('account://' . $username . YAML_EXT, + true, true)); + + // Create user object and save it + $user = new User($data); + $user->file($file); + $user->save(); + + return $user; + } + + /** + * Handle the email to notify the user account creation to the site admin. + * + * @param User $user + * + * @return bool True if the action was performed. + * @throws \RuntimeException + */ + public function sendNotificationEmail(User $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.from'); + + 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 User $user + * + * @return bool True if the action was performed. + * @throws \RuntimeException + */ + public function sendWelcomeEmail(User $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 User $user + * + * @return bool True if the action was performed. + * @throws \RuntimeException + */ + public function sendActivationEmail(User $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']; + + // Setup storage for RememberMe cookies + $storage = new TokenStorage; + $this->rememberMe = new RememberMe($storage); + $this->rememberMe->setCookieName($config->get('plugins.login.rememberme.name')); + $this->rememberMe->setExpireTime($config->get('plugins.login.rememberme.timeout')); + + // Hardening cookies with user-agent and random salt or + // fallback to use system based cache key + $server_agent = isset($_SERVER['HTTP_USER_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; + } + + /** + * @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', 0); + $interval = $this->grav['config']->get('plugins.login.max_pw_resets_interval', 2); + break; + } + $this->rateLimiters[$context] = new RateLimiter($context, $maxCount, $interval); + } + + return $this->rateLimiters[$context]; + } + + /** + * @param User $user + * @param Page $page + * @param Data|null $config + * @return bool + */ + public function isUserAuthorizedForPage(User $user, Page $page, $config = null) + { + $header = $page->header(); + $rules = isset($header->access) ? (array)$header->access : []; + + if ($config !== null && $config->get('parent_acl')) { + // If page has no ACL rules, use its parent's rules + if (!$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; + } + + // 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) == $nested_value) { + return true; + } + } + } else { + if ($user->authorize($rule) == $value) { + return true; + } + } + } + + return false; + } + + /** + * Check if user may use password reset functionality. + * + * @param User $user + * @param string $field + * @param int $count + * @param int $interval + * @return bool + * @deprecated 3.0 Use $grav['login']->getRateLimiter($context) instead. See Grav\Plugin\Login\RateLimiter class. + */ + public function isUserRateLimited(User $user, $field, $count, $interval) + { + if ($count > 0) { + if (!isset($user->{$field})) { + $user->{$field} = array(); + } + //remove older than 1 hour attempts + $actual_resets = array(); + foreach ($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 User $user + * @param string $field + * @deprecated 3.0 Use $grav['login']->getRateLimiter($context) instead. See Grav\Plugin\Login\RateLimiter class. + */ + public function resetRateLimit(User $user, $field) + { + $user->{$field} = []; + } + + /** + * Get Current logged in user + * + * @return User + * @deprecated 3.0 Use $grav['user'] instead. + */ + public function getUser() + { + /** @var User $user */ + return $this->grav['user']; + } + +} diff --git a/user/plugins/login/classes/LoginCache.php b/user/plugins/login/classes/LoginCache.php new file mode 100644 index 0000000..51d6309 --- /dev/null +++ b/user/plugins/login/classes/LoginCache.php @@ -0,0 +1,103 @@ +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 0000000..aafeb68 --- /dev/null +++ b/user/plugins/login/classes/RateLimiter.php @@ -0,0 +1,108 @@ +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 0000000..27710b0 --- /dev/null +++ b/user/plugins/login/classes/RememberMe/RememberMe.php @@ -0,0 +1,41 @@ + + */ +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 0000000..a3acc14 --- /dev/null +++ b/user/plugins/login/classes/RememberMe/TokenStorage.php @@ -0,0 +1,198 @@ + + */ +class TokenStorage implements StorageInterface +{ + /** + * @var CacheProvider + */ + protected $driver; + + /** + * @var string + */ + protected $cache_dir; + + /** + * Constructor + * + * @param string $path Path to storage directory + * @throws \InvalidArgumentException + */ + public function __construct($path = 'cache://rememberme') + { + /** @var Cache $cache */ + $cache = Grav::instance()['cache']; + + $this->cache_dir = Grav::instance()['locator']->findResource($path, true, true); + + // Setup cache + $this->driver = $cache->getCacheDriver(); + if ($this->driver instanceof FilesystemCache) { + $this->driver = new FilesystemCache($this->cache_dir); + } + + // Set the cache namespace to our unique key + $this->driver->setNamespace($cache->getKey()); + } + + /** + * 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(trim($persistentToken)); + $token = sha1(trim($token)); + + $id = $this->getId($credential); + if (!$this->driver->contains($id)) { + return self::TRIPLET_NOT_FOUND; + } + + list($expire, $tokens) = $this->driver->fetch($id); + if (isset($tokens[$persistentToken]) && $tokens[$persistentToken] === $token) { + return self::TRIPLET_FOUND; + } + + return self::TRIPLET_INVALID; + } + + /** + * 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(trim($persistentToken)); + $token = sha1(trim($token)); + + $e = null; + $tokens = []; + $id = $this->getId($credential); + if ($this->driver->contains($id)) { + list($e, $tokens) = $this->driver->fetch($id); + } + + // Get cache lifetime for tokens + if ($expire === null && $e === null) { + /** @var Cache $cache */ + $cache = Grav::instance()['cache']; + $expire = $cache->getLifetime(); + } elseif ($expire === null) { + $expire = $e; + } + + // Update tokens + $tokens[$persistentToken] = $token; + $this->driver->save($id, [$expire, $tokens], $expire); + + return $this; + } + + /** + * 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->cleanTriplet($credential, $persistentToken); + $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(trim($persistentToken)); + + // Delete token from storage + $id = $this->getId($credential); + if ($this->driver->contains($id)) { + list($expire, $tokens) = $this->driver->fetch($id); + unset($tokens[$persistentToken]); + $this->driver->save($id, [$expire, $tokens], $expire); + } + } + + /** + * Remove all triplets of a user, effectively logging him out on all + * machines + * + * @param mixed $credential + */ + public function cleanAllTriplets($credential) + { + $id = $this->getId($credential); + $this->driver->delete($id); + } + + /** + * Helper method to clear RememberMe cache + */ + public function clearCache() + { + $this->driver->flushAll(); + } + + /** + * Get the cache id + * + * @param string $key A key to compute the cache id for + * @return string The cache id + */ + protected function getId($key) + { + /** @var Cache $cache */ + $cache = Grav::instance()['cache']; + + return 'login' . md5(trim($key) . $cache->getKey()); + } +} diff --git a/user/plugins/login/cli/ChangePasswordCommand.php b/user/plugins/login/cli/ChangePasswordCommand.php new file mode 100644 index 0000000..fc850b5 --- /dev/null +++ b/user/plugins/login/cli/ChangePasswordCommand.php @@ -0,0 +1,202 @@ +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() + { + $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(''); + + if (!$this->options['user']) { + // Get username and validate + $question = new Question('Enter a username: '); + $question->setValidator(function ($value) { + return $this->validate('user', $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']; + } + + // Lowercase the username for the filename + $username = strtolower($username); + + /** @var UniformResourceLocator $locator */ + $locator = Grav::instance()['locator']; + + // Grab the account file and read in the information before setting the file (prevent setting erase) + $oldUserFile = CompiledYamlFile::instance($locator->findResource('account://' . $username . YAML_EXT, true, true)); + $oldData = (array)$oldUserFile->content(); + + //Set the password feild to new password + $oldData['password'] = $data['password']; + + // Create user object and save it using oldData (with updated password) + $user = new User($oldData); + $file = CompiledYamlFile::instance($locator->findResource('account://' . $username . YAML_EXT, true, true)); + $user->file($file); + $user->save(); + + $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 $type + * @param $value + * @param string $extra + * + * @return mixed + */ + protected function validate($type, $value, $extra = '') + { + /** @var Config $config */ + $config = Grav::instance()['config']; + + /** @var UniformResourceLocator $locator */ + $locator = Grav::instance()['locator']; + + $username_regex = '/' . $config->get('system.username_regex') . '/'; + $pwd_regex = '/' . $config->get('system.pwd_regex') . '/'; + + switch ($type) { + case 'user': + if (!preg_match($username_regex, $value)) { + throw new \RuntimeException('Username should be between 3 and 16 characters, including lowercase letters, numbers, underscores, and hyphens. Uppercase letters, spaces, and special characters are not allowed'); + } + if (!$locator->findResource('account://' . $value . YAML_EXT)) { + throw new \RuntimeException('Username "' . $value . '" does not exist, please pick another username'); + } + + break; + + case 'password1': + if (!preg_match($pwd_regex, $value)) { + throw new \RuntimeException('Password must contain at least one number and one uppercase and lowercase letter, and at least 8 or more characters'); + } + + break; + + case 'password2': + if (strcmp($value, $extra)) { + throw new \RuntimeException('Passwords did not match.'); + } + + break; + } + + return $value; + } + + /** + * 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 0000000..a562570 --- /dev/null +++ b/user/plugins/login/cli/ChangeUserStateCommand.php @@ -0,0 +1,175 @@ +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() + { + $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(''); + + if (!$this->options['user']) { + // Get username and validate + $question = new Question('Enter a username: '); + $question->setValidator(function ($value) { + return $this->validate('user', $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'; + } + + // Lowercase the username for the filename + $username = strtolower($username); + + /** @var UniformResourceLocator $locator */ + $locator = Grav::instance()['locator']; + + // Grab the account file and read in the information before setting the file (prevent setting erase) + $oldUserFile = CompiledYamlFile::instance($locator->findResource('account://' . $username . YAML_EXT, true, true)); + $oldData = (array)$oldUserFile->content(); + + //Set the state feild to new state + $oldData['state'] = $data['state']; + + // Create user object and save it using oldData (with updated state) + $user = new User($oldData); + $file = CompiledYamlFile::instance($locator->findResource('account://' . $username . YAML_EXT, true, true)); + $user->file($file); + $user->save(); + + $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 $type + * @param $value + * @param string $extra + * + * @return mixed + */ + protected function validate($type, $value, $extra = '') + { + /** @var Config $config */ + $config = Grav::instance()['config']; + + /** @var UniformResourceLocator $locator */ + $locator = Grav::instance()['locator']; + + $username_regex = '/' . $config->get('system.username_regex') . '/'; + + switch ($type) { + case 'user': + if (!preg_match($username_regex, $value)) { + throw new \RuntimeException('Username should be between 3 and 16 characters, including lowercase letters, numbers, underscores, and hyphens. Uppercase letters, spaces, and special characters are not allowed'); + } + if (!file_exists($locator->findResource('account://' . $value . YAML_EXT))) { + throw new \RuntimeException('Username "' . $value . '" does not exist, please pick another username'); + } + + break; + + case 'state': + if ($value !== 'enabled' && $value !== 'disabled') { + throw new \RuntimeException('State is not valid'); + } + + break; + } + + return $value; + } +} diff --git a/user/plugins/login/cli/NewUserCommand.php b/user/plugins/login/cli/NewUserCommand.php new file mode 100644 index 0000000..4080205 --- /dev/null +++ b/user/plugins/login/cli/NewUserCommand.php @@ -0,0 +1,333 @@ +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() + { + $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(''); + + if (!$this->options['user']) { + // Get username and validate + $question = new Question('Enter a username: ', 'admin'); + $question->setValidator(function ($value) { + return $this->validate('user', $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 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']; + } + + if (!$this->options['email']) { + // Get email and validate + $question = new Question('Enter an email: '); + $question->setValidator(function ($value) { + return $this->validate('email', $value); + }); + + $data['email'] = $helper->ask($this->input, $this->output, $question); + } else { + $data['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': + $data['access']['admin'] = ['login' => true, 'super' => true]; + break; + case 's': + $data['access']['site'] = ['login' => true]; + break; + case 'b': + $data['access']['admin'] = ['login' => true, 'super' => true]; + $data['access']['site'] = ['login' => true]; + } + + if (!$this->options['fullname']) { + // Get fullname + $question = new Question('Enter a fullname: '); + $question->setValidator(function ($value) { + return $this->validate('fullname', $value); + }); + + $data['fullname'] = $helper->ask($this->input, $this->output, $question); + } else { + $data['fullname'] = $this->options['fullname']; + } + + + if (!$this->options['title'] && !count(array_filter($this->options))) { + // Get title + $question = new Question('Enter a title: '); + $data['title'] = $helper->ask($this->input, $this->output, $question); + } else { + $data['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.'); + $data['state'] = $helper->ask($this->input, $this->output, $question); + } else { + $data['state'] = $this->options['state'] ?: 'enabled'; + } + + // Lowercase the username for the filename + $username = strtolower($username); + + /** @var UniformResourceLocator $locator */ + $locator = Grav::instance()['locator']; + + // Create user object and save it + $user = new User($data); + $file = CompiledYamlFile::instance($locator->findResource('account://' . $username . YAML_EXT, true, true)); + $user->file($file); + $user->save(); + + $this->output->writeln(''); + $this->output->writeln('Success! User ' . $username . ' created.'); + } + + /** + * + */ + protected function validateOptions() + { + foreach (array_filter($this->options) as $type => $value) { + $this->validate($type, $value); + } + } + + /** + * @param $type + * @param $value + * @param string $extra + * + * @return mixed + */ + protected function validate($type, $value, $extra = '') + { + /** @var Config $config */ + $config = Grav::instance()['config']; + + /** @var UniformResourceLocator $locator */ + $locator = Grav::instance()['locator']; + + + $username_regex = '/' . $config->get('system.username_regex') . '/'; + $pwd_regex = '/' . $config->get('system.pwd_regex') . '/'; + + switch ($type) { + case 'user': + if (!preg_match($username_regex, $value)) { + throw new \RuntimeException('Username should be between 3 and 16 characters, including lowercase letters, numbers, underscores, and hyphens. Uppercase letters, spaces, and special characters are not allowed'); + } + if (file_exists($locator->findResource('account://' . $value . YAML_EXT))) { + throw new \RuntimeException('Username "' . $value . '" already exists, please pick another username'); + } + + break; + + case 'password1': + if (!preg_match($pwd_regex, $value)) { + throw new \RuntimeException('Password must contain at least one number and one uppercase and lowercase letter, and at least 8 or more characters'); + } + + break; + + case 'password2': + if (strcmp($value, $extra)) { + throw new \RuntimeException('Passwords did not match.'); + } + + break; + + case 'email': + if (!filter_var($value, FILTER_VALIDATE_EMAIL)) { + throw new \RuntimeException('Not a valid email address'); + } + + break; + + case 'permissions': + if (!in_array($value, ['a', 's', 'b'])) { + throw new \RuntimeException('Permissions ' . $value . ' are invalid.'); + } + + break; + + case 'fullname': + if ($value === null || 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; + } + + /** + * 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); + } +} \ No newline at end of file diff --git a/user/plugins/login/composer.json b/user/plugins/login/composer.json new file mode 100644 index 0000000..78751cc --- /dev/null +++ b/user/plugins/login/composer.json @@ -0,0 +1,37 @@ +{ + "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": ">=5.4.0", + "birke/rememberme": "1.*" + }, + "autoload": { + "psr-4": { + "Grav\\Plugin\\Login\\": "classes/" + } + } +} diff --git a/user/plugins/login/composer.lock b/user/plugins/login/composer.lock new file mode 100644 index 0000000..8d1fb6d --- /dev/null +++ b/user/plugins/login/composer.lock @@ -0,0 +1,113 @@ +{ + "_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": "540c2e320c9819de1b7c90b59f17263d", + "packages": [ + { + "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.2", + "source": { + "type": "git", + "url": "https://github.com/paragonie/random_compat.git", + "reference": "965cdeb01fdcab7653253aa81d40441d261f1e66" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/paragonie/random_compat/zipball/965cdeb01fdcab7653253aa81d40441d261f1e66", + "reference": "965cdeb01fdcab7653253aa81d40441d261f1e66", + "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": "2017-03-13T16:22:52+00:00" + } + ], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "php": ">=5.4.0" + }, + "platform-dev": [] +} diff --git a/user/plugins/login/css/login.css b/user/plugins/login/css/login.css new file mode 100644 index 0000000..3b470c4 --- /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/hebe.json b/user/plugins/login/hebe.json new file mode 100644 index 0000000..d1f65ae --- /dev/null +++ b/user/plugins/login/hebe.json @@ -0,0 +1,15 @@ +{ + "project":"grav-plugin-login", + "platforms":{ + "grav":{ + "nodes":{ + "plugin":[ + { + "source":"/", + "destination":"/user/plugins/login" + } + ] + } + } + } +} diff --git a/user/plugins/login/languages/de.yaml b/user/plugins/login/languages/de.yaml new file mode 100644 index 0000000..cb65837 --- /dev/null +++ b/user/plugins/login/languages/de.yaml @@ -0,0 +1,47 @@ +PLUGIN_LOGIN: + USERNAME: "Benutzername" + EMAIL: "Email" + USERNAME_EMAIL: "Benutzername/Email" + PASSWORD: "Passwort" + ACCESS_DENIED: "Zugang verweigert" + LOGIN_FAILED: "Login fehlgeschlagen..." + LOGIN_SUCCESSFUL: "Du wurdest erfolgreich eingeloggt." + BTN_LOGIN: "Anmelden" + BTN_LOGOUT: "Abmelden" + BTN_FORGOT: "Vergessen" + BTN_REGISTER: "Registrieren" + REMEMBER_ME: "Angemeldet bleiben" + REMEMBER_ME_HELP: "Speichert einen Cookie im Browser, welcher eine fortwährende Anmeldung sicherstellt." + BUILTIN_CSS: "Nutze das integrierte CSS" + BUILTIN_CSS_HELP: "Nutze das CSS, welches vom Admin Plugin bereitgestellt werden" + ROUTE: "Anmeldepfad" + ROUTE_REGISTER: "Registrierungspfad" + USERNAME_NOT_AVAILABLE: "Der Nutzername %s existiert bereits, bitte wähle einen Anderen" + USER_NEEDS_EMAIL_FIELD: "Der Nutzer benötigt ein E-Mail Feld" + EMAIL_SENDING_FAILURE: "Ein Fehler ist beim senden der E-Mail aufgetreten" + ACTIVATION_EMAIL_SUBJECT: "Aktiviere dein Account auf %s" + ACTIVATION_EMAIL_BODY: "Hi %s, click %s to activate your account on %s" + WELCOME_EMAIL_SUBJECT: "Willkommen zu %s" + WELCOME_EMAIL_BODY: "Hi %s, willkommen zu %s!" + NOTIFICATION_EMAIL_SUBJECT: "Neuer Nutzer auf %s" + NOTIFICATION_EMAIL_BODY: "Hi, ein neuer Nutzer hat sich auf %s registriert. Nutzername: %s, E-Mail: %s" + EMAIL_FOOTER: "GetGrav.org" + ACTIVATION_LINK_EXPIRED: "Aktivierungslink ist abgelaufen" + USER_ACTIVATED_SUCCESSFULLY: "Nutzer erfolgreich aktiviert" + INVALID_REQUEST: "Ungültige Anfrage" + USER_REGISTRATION: "Nutzer Registrierung" + USER_REGISTRATION_ENABLED_HELP: "Aktiviere die Nutzer Registrierung" + VALIDATE_PASSWORD1_AND_PASSWORD2: "Überprüfe das doppelt eingegebene Passwort" + SEND_ACTIVATION_EMAIL: "Aktivierungs E-Mail senden" + SEND_NOTIFICATION_EMAIL: "Benachtichtigungs E-Mail senden" + SEND_WELCOME_EMAIL: "Sende eine Willkommens E-Mail" + DEFAULT_VALUES: "Standard Werte" + ADDITIONAL_PARAM_KEY: "Parameter" + ADDITIONAL_PARAM_VALUE: "Wert" + REGISTRATION_FIELDS: "Registrierungsfelder" + REGISTRATION_FIELD_KEY: "Feldname" + REDIRECT_AFTER_LOGIN: "Umleitung nach Login" + REDIRECT_AFTER_REGISTRATION: "Umleitung nach Registrierung" + OPTIONS: "Optionen" + EMAIL_VALIDATION_MESSAGE: "Muss eine gültige E-Mail Adresse sein" + WELCOME: "Willkommen" \ No newline at end of file diff --git a/user/plugins/login/languages/en.yaml b/user/plugins/login/languages/en.yaml new file mode 100644 index 0000000..14edd62 --- /dev/null +++ b/user/plugins/login/languages/en.yaml @@ -0,0 +1,115 @@ +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_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 activated successfully" + 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_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" + 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" \ No newline at end of file diff --git a/user/plugins/login/languages/fr.yaml b/user/plugins/login/languages/fr.yaml new file mode 100644 index 0000000..028af85 --- /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 0000000..3090885 --- /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 0000000..ac9c7f8 --- /dev/null +++ b/user/plugins/login/languages/hu.yaml @@ -0,0 +1,21 @@ +PLUGIN_LOGIN: + ACCESS_DENIED: "Hozzáférés megtagadva..." + LOGIN_FAILED: "Sikertelen belépés..." + LOGIN_SUCCESSFUL: "Sikeresen belé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ő" \ No newline at end of file diff --git a/user/plugins/login/languages/ro.yaml b/user/plugins/login/languages/ro.yaml new file mode 100644 index 0000000..307e590 --- /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 0000000..06781c5 --- /dev/null +++ b/user/plugins/login/languages/ru.yaml @@ -0,0 +1,108 @@ +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_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 уже существует, выберите другое имя пользователя" + PASSWORD_NOT_VALID: "Пароль должен содержать как минимум одно число, одну прописную и строчную букву, и быть не менее 8 символов" + PASSWORDS_DO_NOT_MATCH: "Пароли не совпадают. Дважды проверьте, что вы дважды ввели тот же пароль" + USER_NEEDS_EMAIL_FIELD: "Пользователю требуется поле электронной почты" + EMAIL_SENDING_FAILURE: "Произошла ошибка при отправке письма" + ACTIVATION_EMAIL_SUBJECT: "Активируйте свою учетную запись %s" + ACTIVATION_EMAIL_BODY: "Привет %s, перейдите сюда для активации вашей учетной записи %s" + WELCOME_EMAIL_SUBJECT: "Добро пожаловать в %s" + WELCOME_EMAIL_BODY: "Привет %s, добро пожаловать в %s!" + NOTIFICATION_EMAIL_SUBJECT: "Новый пользователь %s" + NOTIFICATION_EMAIL_BODY: "Привет, новый пользователь, зарегистрированный на %s. Имя пользователя: %s, email: %s" + EMAIL_FOOTER: "GetGrav.org" + ACTIVATION_LINK_EXPIRED: "Время ссылки для активации истекло" + USER_ACTIVATED_SUCCESSFULLY: "Пользователь успешно активирован" + 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_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: "секунд" + RESETS: "сбросов" + ATTEMPTS: "попыток" + ROUTES: "Маршруты" + ROUTE_FORGOT: "Забыли пароль" + ROUTE_RESET: "Сброса пароля" + ROUTE_PROFILE: "Профиля пользователя" + ROUTE_ACTIVATE: "Активации пользователя" \ No newline at end of file diff --git a/user/plugins/login/login.php b/user/plugins/login/login.php new file mode 100644 index 0000000..b7040e6 --- /dev/null +++ b/user/plugins/login/login.php @@ -0,0 +1,936 @@ + [['initializeSession', 10000], ['initializeLogin', 1000]], + 'onTask.login.login' => ['loginController', 0], + 'onTask.login.forgot' => ['loginController', 0], + 'onTask.login.logout' => ['loginController', 0], + 'onTask.login.reset' => ['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] 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'); + } + + // Autoload classes + $autoload = __DIR__ . '/vendor/autoload.php'; + if (!is_file($autoload)) { + throw new \RuntimeException('Login Plugin failed to load. Composer dependencies not met.'); + } + require_once $autoload; + + // 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->login['visibility_requires_access'])) { + $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(); + + if (!in_array($current_route, $invalid_redirect_routes, true)) { + $allowed = true; + + /** @var Page $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()) { + $this->grav['session']->redirect_after_login = $page->route() . ($uri->params() ?: ''); + } + } + } + } + + /** + * 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->template('form'); + $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']; + + $username = $uri->param('username'); + + $token = $uri->param('token'); + $user = User::load($username); + + 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 { + $user['state'] = 'enabled'; + unset($user['activation_token']); + $user->save(); + + $message = $this->grav['language']->translate('PLUGIN_LOGIN.USER_ACTIVATED_SUCCESSFULLY'); + $messages->add($message, 'info'); + + 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)) { + $this->login->login(['username' => $username], ['after_registration' => true]); + } + } + } else { + $message = $this->grav['language']->translate('PLUGIN_LOGIN.INVALID_REQUEST'); + $messages->add($message, 'error'); + } + } + + $redirect_route = $this->config->get('plugins.login.user_registration.redirect_after_activation', '/'); + $this->grav->redirect($redirect_route); + } + + /** + * 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->template('default'); + $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 User $user */ + $user = $this->grav['user']; + + /** @var Page $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; + } + + // User is not logged in; redirect to login page. + if ($this->redirect_to_login && $this->route && !$user->authenticated) { + $this->grav->redirect($this->route, 302); + } + + /** @var Twig $twig */ + $twig = $this->grav['twig']; + + // Reset page with login page. + if (empty($user->authenticated)) { + + 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)); + } + + $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') ?: (isset($_POST['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'] = isset($_POST['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')); + } + + // Check for existing username + $username = $form->value('username'); + $existing_username = User::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->value('email'); + $existing_email = User::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->value('password1') !== $form->value('password2')) { + $this->grav->fireEvent('onFormValidationError', new Event([ + 'form' => $form, + 'message' => $language->translate('PLUGIN_LOGIN.PASSWORDS_DO_NOT_MATCH') + ])); + $event->stopPropagation(); + + return; + } + $data['password'] = $form->value('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->value($field)) { + $data[$field] = $form->value($field); + } + } + + if ($this->config->get('plugins.login.user_registration.options.set_user_disabled', false)) { + $data['state'] = 'disabled'; + } else { + $data['state'] = 'enabled'; + } + + $this->grav->fireEvent('onUserLoginRegisterData', new Event(['data' => &$data])); + $user = $this->login->register($data); + + $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])); + + if (isset($data['state']) && $data['state'] === 'enabled' && $this->config->get('plugins.login.user_registration.options.login_after_registration', false)) { + $this->login->login(['username' => $username], ['after_registration' => true], ['user' => $user]); + } + + $redirect = $this->config->get('plugins.login.user_registration.redirect_after_registration', false); + if ($redirect) { + $this->grav->redirect($redirect); + } + } + + /** + * Save user profile information + * + * @param Form $form + * @return bool + */ + private function processUserProfile($form) + { + $user = $this->grav['user']; + $user->merge($form->getData()->toArray()); + + try { + $user->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); + 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 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. + 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. + $event->setStatus($event::AUTHENTICATION_FAILURE); + $event->stopPropagation(); + + return; + } + + // Allow remember me to work with different login methods. + $event->setCredential('username', $username); + $event->setUser(User::load($username, false)); + } + } + + public function userLoginAuthenticateByEmail(UserLoginEvent $event) + { + if (($username = $event->getCredential('username')) && !$event->getUser()->exists()) { + $event->setUser(User::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; + } + } + } + + public function userLoginFailure(UserLoginEvent $event) + { + $this->grav['session']->user = User::load('', false); + } + + 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); + } else { + $login->rememberMe()->getStorage()->cleanAllTriplets($username); + $login->rememberMe()->clearCookie(); + } + } + } + + 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(); + $this->grav['session']->setFlashCookieObject(self::TMP_COOKIE_NAME, ['message' => $this->grav['language']->translate('PLUGIN_LOGIN.LOGGED_OUT'), + 'status' => 'info']); + } +} diff --git a/user/plugins/login/login.yaml b/user/plugins/login/login.yaml new file mode 100644 index 0000000..b035cbe --- /dev/null +++ b/user/plugins/login/login.yaml @@ -0,0 +1,53 @@ +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') +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: 0 # 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: 0 # Number of failed login attempts in a specific time frame (0 = unlimited) +max_login_interval: 2 # Time in minutes to track login attempts + +user_registration: + enabled: true # 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: true # 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` diff --git a/user/plugins/login/pages/forgot.md b/user/plugins/login/pages/forgot.md new file mode 100644 index 0000000..6f46df6 --- /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 0000000..3e20ac3 --- /dev/null +++ b/user/plugins/login/pages/login.md @@ -0,0 +1,27 @@ +--- +title: Login + +login_redirect_here: false + +form: + name: login + action: + method: post + + fields: + - name: username + type: text + id: username + placeholder: Username + label: PLUGIN_LOGIN.USERNAME_EMAIL + autofocus: true + + - name: password + type: password + id: password + placeholder: Password + label: PLUGIN_LOGIN.PASSWORD +--- + +# User Login + diff --git a/user/plugins/login/pages/profile.md b/user/plugins/login/pages/profile.md new file mode 100644 index 0000000..b3e59ba --- /dev/null +++ b/user/plugins/login/pages/profile.md @@ -0,0 +1,50 @@ +--- +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 + + + 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 0000000..36bdaff --- /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 0000000..1c3048a --- /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 0000000..6b9aa13 --- /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 0000000..9ca0001 --- /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/login.html.twig b/user/plugins/login/templates/login.html.twig new file mode 100644 index 0000000..7ac282f --- /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 0000000..14dbf95 --- /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 0000000..8435540 --- /dev/null +++ b/user/plugins/login/templates/partials/forgot-form.html.twig @@ -0,0 +1,18 @@ +
                                                                      + {{ 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 0000000..63b8c38 --- /dev/null +++ b/user/plugins/login/templates/partials/login-form.html.twig @@ -0,0 +1,51 @@ +
                                                                      + + {% if page.template == 'login' or show_login_form %} + + {% if grav.user.authenticated %} +

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

                                                                      +
                                                                      + {{ 'PLUGIN_LOGIN.BTN_LOGOUT'|t }} + + {% else %} + {{ content|raw }} + +
                                                                      + {% if grav.twig.plugins_hooked_loginPage %} + {% for label in grav.twig.plugins_hooked_loginPage %} + {% include label %} + {% endfor %} + {% endif %} + + {% for field in form.fields %} + {% set value = field.name == 'username' ? username : '' %} + {% if field.type %} + {% include ["forms/fields/#{field.type}/#{field.type}.html.twig", 'forms/fields/text/text.html.twig'] %} + {% endif %} + {% endfor %} + +
                                                                      + {% if config.plugins.login.rememberme.enabled and page.header.form.login.rememberme ?? true %} +
                                                                      +
                                                                      + + +
                                                                      +
                                                                      + {% endif %} + + {% if page.header.form.login.forgot_button ?? true %} + {{ 'PLUGIN_LOGIN.BTN_FORGOT'|t }} + {% endif %} + + +
                                                                      + + {{ nonce_field('login-form', 'login-form-nonce')|raw }} +
                                                                      + + {% 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 0000000..7c06016 --- /dev/null +++ b/user/plugins/login/templates/partials/login-status.html.twig @@ -0,0 +1,5 @@ + 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 0000000..079a607 --- /dev/null +++ b/user/plugins/login/templates/partials/reset-form.html.twig @@ -0,0 +1,24 @@ +{% if uri.param('token') and uri.param('task') %} +
                                                                      + {{ 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 0000000..e35b743 --- /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 0000000..da0d023 --- /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/reset.html.twig b/user/plugins/login/templates/reset.html.twig new file mode 100644 index 0000000..f459784 --- /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/vendor/autoload.php b/user/plugins/login/vendor/autoload.php new file mode 100644 index 0000000..c13a8a3 --- /dev/null +++ b/user/plugins/login/vendor/autoload.php @@ -0,0 +1,7 @@ + + +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 0000000..4769e1f --- /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 0000000..d05a6d5 --- /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 0000000..0a7ea94 --- /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 0000000..ded8371 --- /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 0000000..b79a829 --- /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 0000000..7f2c699 --- /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 0000000..0d516d7 --- /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 0000000..edda89a --- /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/phpunit.xml b/user/plugins/login/vendor/birke/rememberme/phpunit.xml new file mode 100644 index 0000000..c5304c6 --- /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 0000000..5a2b4b4 --- /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 0000000..a1031e9 --- /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 0000000..d8f9dab --- /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 0000000..23c5cb5 --- /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 0000000..e494513 --- /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 0000000..94163b0 --- /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 0000000..5ec58a7 --- /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 0000000..462bf2f --- /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 0000000..a581ee7 --- /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 0000000..c53f2ef --- /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])) { + foreach ($this->prefixDirsPsr4[$search] as $dir) { + $length = $this->prefixLengthsPsr4[$first][$search]; + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) { + 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 0000000..f27399a --- /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 0000000..7a91153 --- /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 0000000..b7fc012 --- /dev/null +++ b/user/plugins/login/vendor/composer/autoload_namespaces.php @@ -0,0 +1,9 @@ + 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 0000000..6a282d7 --- /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 0000000..49fb9e3 --- /dev/null +++ b/user/plugins/login/vendor/composer/autoload_static.php @@ -0,0 +1,43 @@ + __DIR__ . '/..' . '/paragonie/random_compat/lib/random.php', + ); + + public static $prefixLengthsPsr4 = array ( + 'G' => + array ( + 'Grav\\Plugin\\Login\\' => 18, + ), + 'B' => + array ( + 'Birke\\' => 6, + ), + ); + + public static $prefixDirsPsr4 = array ( + 'Grav\\Plugin\\Login\\' => + array ( + 0 => __DIR__ . '/../..' . '/classes', + ), + 'Birke\\' => + array ( + 0 => __DIR__ . '/..' . '/birke/rememberme/src', + ), + ); + + public static function getInitializer(ClassLoader $loader) + { + return \Closure::bind(function () use ($loader) { + $loader->prefixLengthsPsr4 = ComposerStaticIniteed5e5cf0aa1e2139f2db7445511e366::$prefixLengthsPsr4; + $loader->prefixDirsPsr4 = ComposerStaticIniteed5e5cf0aa1e2139f2db7445511e366::$prefixDirsPsr4; + + }, 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 0000000..0e840cf --- /dev/null +++ b/user/plugins/login/vendor/composer/installed.json @@ -0,0 +1,99 @@ +[ + { + "name": "paragonie/random_compat", + "version": "v1.4.2", + "version_normalized": "1.4.2.0", + "source": { + "type": "git", + "url": "https://github.com/paragonie/random_compat.git", + "reference": "965cdeb01fdcab7653253aa81d40441d261f1e66" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/paragonie/random_compat/zipball/965cdeb01fdcab7653253aa81d40441d261f1e66", + "reference": "965cdeb01fdcab7653253aa81d40441d261f1e66", + "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": "2017-03-13T16:22:52+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": "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" + ] + } +] diff --git a/user/plugins/login/vendor/paragonie/random_compat/CHANGELOG.md b/user/plugins/login/vendor/paragonie/random_compat/CHANGELOG.md new file mode 100644 index 0000000..f8f01b7 --- /dev/null +++ b/user/plugins/login/vendor/paragonie/random_compat/CHANGELOG.md @@ -0,0 +1,282 @@ +### Version 1.4.2 - 2017-03-13 + +* Backport changes from version 2: + * Version 2.0.9 - 2017-03-03 + * More Psalm integration fixes. + * Version 2.0.8 - 2017-03-03 + * Prevent function already declared error for `random_int()` caused by misusing + the library (really you should only ever include `lib/random.php` and never any + of the other files). See [#125](https://github.com/paragonie/random_compat/issues/125). + * Version 2.0.6, 2.0.7 - 2017-02-27 + * Just updates to psalm.xml to silence false positives. + * Version 2.0.5 - 2017-02-27 + * Run random_compat through the static analysis tool, [psalm](https://github.com/vimeo/psalm), + as part of our continuous integration process. + * Minor readability enhancements ([#122](https://github.com/paragonie/random_compat/issues/122) + and several docblock changes). + * Version 2.0.4 - 2016-11-07 + * Don't unnecessarily prevent `mcrypt_create_iv()` from being used. + See [#111](https://github.com/paragonie/random_compat/issues/111). + * Version 2.0.3 - 2016-10-17 + * Updated `lib/error_polyfill.php` [to resolve corner cases](https://github.com/paragonie/random_compat/issues/104). + * The README was updated to help users troubleshoot and fix insecure environments. + * Tags will now be signed by [the GnuPG key used by the security team at Paragon Initiative Enterprises, LLC](https://paragonie.com/static/gpg-public-key.txt). + * Version 2.0.2 - 2016-04-03 + * Added a consistency check (discovered by Taylor Hornby in his + [PHP encryption library](https://github.com/defuse/php-encryption)). It + wasn't likely causing any trouble for us. + +### Version 1.4.1 - 2016-03-18 + +Update comment in random.php + +### Version 1.4.0 - 2016-03-18 + +Restored OpenSSL in the version 1 branch in preparation to remove +OpenSSL in version 2. + +### Version 1.3.1/1.2.3 - 2016-03-18 + +* Add more possible values to `open_baseir` check. + +### Version 1.3.0 - 2016-03-17 + +* Removed `openssl_random_pseudo_bytes()` entirely. If you are using + random_compat in PHP on a Unix-like OS but cannot access + `/dev/urandom`, version 1.3+ will throw an `Exception`. If you want to + trust OpenSSL, feel free to write your own fallback code. e.g. + + ```php + try { + $bytes = random_bytes(32); + } catch (Exception $ex) { + $strong = false; + $bytes = openssl_random_pseudo_bytes(32, $strong); + if (!$strong) { + throw $ex; + } + } + ``` + +### Version 1.2.2 - 2016-03-11 + +* To prevent applications from hanging, if `/dev/urandom` is not + accessible to PHP, skip mcrypt (which just fails before giving OpenSSL + a chance and was morally equivalent to not offering OpenSSL at all). + +### Version 1.2.1 - 2016-02-29 + +* PHP 5.6.10 - 5.6.12 will hang when mcrypt is used on Unix-based operating + systems ([PHP bug 69833](https://bugs.php.net/bug.php?id=69833)). If you are + running one of these versions, please upgrade (or make sure `/dev/urandom` is + readable) otherwise you're relying on OpenSSL. + +### Version 1.2.0 - 2016-02-05 + +* Whitespace and other cosmetic changes +* Added a changelog. +* We now ship with a command line utility to build a PHP Archive from the + command line. + + Every time we publish a new release, we will also upload a .phar + to Github. Our public key is signed by our GPG key. + +### Version 1.1.6 - 2016-01-29 + +* Eliminate `open_basedir` warnings by detecting this configuration setting. + (Thanks [@oucil](https://github.com/oucil) for reporting this.) +* Added install instructions to the README. +* Documentation cleanup (there is, in fact, no `MCRYPT_CREATE_IV` constant, I + meant to write `MCRYPT_DEV_URANDOM`) + +### Version 1.1.5 - 2016-01-06 + +Prevent fatal errors on platforms with older versions of libsodium. + +### Version 1.1.4 - 2015-12-10 + +Thanks [@narfbg](https://github.com/narfbg) for [critiquing the previous patch](https://github.com/paragonie/random_compat/issues/79#issuecomment-163590589) +and suggesting a fix. + +### Version 1.1.3 - 2015-12-09 + +The test for COM in disabled_classes is now case-insensitive. + +### Version 1.1.2 - 2015-12-09 + +Don't instantiate COM if it's a disabled class. Removes the E_WARNING on Windows. + +### Version 1.1.1 - 2015-11-30 + +Fix a performance issue with `/dev/urandom` buffering. + +### Version 1.1.0 - 2015-11-09 + +Fix performance issues with ancient versions of PHP on Windows, but dropped +support for PHP < 5.4.1 without mcrypt on Windows 7+ in the process. Since this + is a BC break, semver dictates a minor version bump. + +### Version 1.0.10 - 2015-10-23 + +* Avoid a performance killer with OpenSSL on Windows PHP 5.3.0 - 5.3.3 that was + affecting [WordPress users](https://core.trac.wordpress.org/ticket/34409). +* Use `$var = null` instead of `unset($var)` to avoid triggering the garbage + collector and slowing things down. + +### Version 1.0.9 - 2015-10-20 + +There is an outstanding issue `mcrypt_create_iv()` and PHP 7's `random_bytes()` +on Windows reported by [@nicolas-grekas](https://github.com/nicolas-grekas) caused by `proc_open()` and environment +variable handling (discovered by Appveyor when developing Symfony). + +Since the break is consistent, it's not our responsibility to fix it, but we +should fail the same way PHP 7 will (i.e. throw an `Exception` rather than raise +an error and then throw an `Exception`). + +### Version 1.0.8 - 2015-10-18 + +* Fix usability issues with Windows (`new COM('CAPICOM.Utilities.1')` is not + always available). +* You can now test all the possible drivers by running `phpunit.sh each` in the + `tests` directory. + +### Version 1.0.7 - 2015-10-16 + +Several large integer handling bugfixes were contributed by [@oittaa](https://github.com/oittaa). + +### Version 1.0.6 - 2015-10-15 + +Don't let the version number fool you, this was a pretty significant change. + +1. Added support for ext-libsodium, if it exists on the system. This is morally + equivalent to adding `getrandom(2)` support without having to expose the + syscall interface in PHP-land. +2. Relaxed open_basedir restrictions. In previous versions, if open_basedir was + set, PHP wouldn't even try to read from `/dev/urandom`. Now it will still do + so if you can. +3. Fixed integer casting inconsistencies between random_compat and PHP 7. +4. Handle edge cases where an integer overflow turns one of the parameters into + a float. + +One change that we discussed was making `random_bytes()` and `random_int()` +strict typed; meaning you could *only* pass integers to either function. While +most veteran programmers are probably only doing this already (we strongly +encourage it), it wouldn't be consistent with how these functions behave in PHP +7. Please use these functions responsibly. + +We've had even more of the PHP community involved in this release; the +contributors list has been updated. If I forgot anybody, I promise you it's not +because your contributions (either code or ideas) aren't valued, it's because +I'm a bit overloaded with information at the moment. Please let me know +immediately and I will correct my oversight. + +Thanks everyone for helping make random_compat better. + +### Version 1.0.5 - 2015-10-08 + +Got rid of the methods in the `Throwable` interface, which was causing problems +on PHP 5.2. While we would normally not care about 5.2 (since [5.4 and earlier are EOL'd](https://secure.php.net/supported-versions.php)), +we do want to encourage widespread adoption (e.g. [Wordpress](https://core.trac.wordpress.org/ticket/28633)). + +### Version 1.0.4 - 2015-10-02 + +Removed redundant `if()` checks, since `lib/random.php` is the entrypoint people +should use. + +### Version 1.0.3 - 2015-10-02 + +This release contains bug fixes contributed by the community. + +* Avoid a PHP Notice when PHP is running without the mbstring extension +* Use a compatible version of PHPUnit for testing on older versions of PHP + +Although none of these bugs were outright security-affecting, updating ASAP is +still strongly encouraged. + +### Version 1.0.2 - 2015-09-23 + +Less strict input validation on `random_int()` parameters. PHP 7's `random_int()` +accepts strings and floats that look like numbers, so we should too. + +Thanks [@dd32](https://github.com/@dd32) for correcting this oversight. + +### Version 1.0.1 - 2015-09-10 + +Instead of throwing an Exception immediately on insecure platforms, only do so +when `random_bytes()` is invoked. + +### Version 1.0.0 - 2015-09-07 + +Our API is now stable and forward-compatible with the CSPRNG features in PHP 7 +(as of 7.0.0 RC3). + +A lot of great people have contributed their time and expertise to make this +compatibility library possible. That this library has reached a stable release +is more a reflection on the community than it is on PIE. + +We are confident that random_compat will serve as the simplest and most secure +CSPRNG interface available for PHP5 projects. + +### Version 0.9.7 (pre-release) - 2015-09-01 + +An attempt to achieve compatibility with Error/TypeError in the RFC. + +This should be identical to 1.0.0 sans any last-minute changes or performance enhancements. + +### Version 0.9.6 (pre-release) - 2015-08-06 + +* Split the implementations into their own file (for ease of auditing) +* Corrected the file type check after `/dev/urandom` has been opened (thanks + [@narfbg](https://github.com/narfbg) and [@jedisct1](https://github.com/jedisct1)) + +### Version 0.9.5 (pre-release) - 2015-07-31 + +* Validate that `/dev/urandom` is a character device + * Reported by [@lokdnet](https://twitter.com/lokdnet) + * Investigated by [@narfbg](https://github.com/narfbg) and [frymaster](http://stackoverflow.com/users/1226810/frymaster) on [StackOverflow](http://stackoverflow.com/q/31631066/2224584) +* Remove support for `/dev/arandom` which is an old OpenBSD feature, thanks [@jedisct1](https://github.com/jedisct1) +* Prevent race conditions on the `filetype()` check, thanks [@jedisct1](https://github.com/jedisct1) +* Buffer file reads to 8 bytes (performance optimization; PHP defaults to 8192 bytes) + +### Version 0.9.4 (pre-release) - 2015-07-27 + +* Add logic to verify that `/dev/arandom` and `/dev/urandom` are actually devices. +* Some clean-up in the comments + +### Version 0.9.3 (pre-release) - 2015-07-22 + +Unless the Exceptions change to PHP 7 fails, this should be the last pre-release +version. If need be, we'll make one more pre-release version with compatible +behavior. + +Changes since 0.9.2: + +* Prioritize `/dev/arandom` and `/dev/urandom` over mcrypt. +[@oittaa](https://github.com/oittaa) removed the -1 and +1 juggling on `$range` calculations for `random_int()` +* Whitespace and comment clean-up, plus better variable names +* Actually put a description in the composer.json file... + +### Version 0.9.2 (pre-release) - 2015-07-16 + +* Consolidated `$range > 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 0000000..45c7017 --- /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 0000000..a6e7307 --- /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 0000000..63c6d71 --- /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 0000000..8f731b3 --- /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 0000000..b4a5ba3 --- /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 0000000..d363f4c --- /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 0000000..eb50ebf --- /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 0000000..6a1d7f3 --- /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 0000000..6de294f --- /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 0000000..dc4048c --- /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 0000000..17ece7b --- /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 0000000..28cc56a --- /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 0000000..8bf7034 --- /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 0000000..7d32b21 --- /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 0000000..ba93c40 --- /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 0000000..3bce91a --- /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 0000000..70ef4b2 --- /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 0000000..4ba4bb3 --- /dev/null +++ b/user/plugins/login/vendor/paragonie/random_compat/other/ide_stubs/COM.php @@ -0,0 +1,20 @@ + + + + + + + + + + + diff --git a/user/plugins/markdown-notices/CHANGELOG.md b/user/plugins/markdown-notices/CHANGELOG.md new file mode 100644 index 0000000..b3b685c --- /dev/null +++ b/user/plugins/markdown-notices/CHANGELOG.md @@ -0,0 +1,5 @@ +# 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 0000000..4bb7092 --- /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 0000000..397d6db --- /dev/null +++ b/user/plugins/markdown-notices/README.md @@ -0,0 +1,61 @@ +# 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 +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 `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 0000000..93c3a85 --- /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 0000000..cf27677 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 0000000..2d3d49b --- /dev/null +++ b/user/plugins/markdown-notices/blueprints.yaml @@ -0,0 +1,44 @@ +name: Markdown Notices +version: 1.0.0 +description: "Adds the ability to render notices blocks in Markdown" +icon: asterisk +author: + name: Team Grav + email: devs@getgrav.org + url: http://getgrav.org +license: MIT + +form: + validation: strict + fields: + enabled: + type: toggle + label: Plugin status + highlight: 1 + default: 0 + options: + 1: Enabled + 0: Disabled + validate: + type: bool + + built_in_css: + type: toggle + label: Use built in CSS + highlight: 1 + default: 1 + options: + 1: Enabled + 0: Disabled + validate: + type: bool + + level_classes: + type: selectize + size: large + placeholder: "e.g. yellow, red, blue, green" + label: Level classes + help: The classes to use for each level of notices depth + classes: fancy + validate: + type: commalist diff --git a/user/plugins/markdown-notices/markdown-notices.php b/user/plugins/markdown-notices/markdown-notices.php new file mode 100644 index 0000000..6930481 --- /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'); + + 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]; + + $Block = array( + 'element' => array( + 'name' => 'div', + 'handler' => 'lines', + 'attributes' => array( + 'class' => 'notices '. $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'); + } + } + +} \ No newline at end of file diff --git a/user/plugins/markdown-notices/markdown-notices.yaml b/user/plugins/markdown-notices/markdown-notices.yaml new file mode 100644 index 0000000..35ce5a6 --- /dev/null +++ b/user/plugins/markdown-notices/markdown-notices.yaml @@ -0,0 +1,3 @@ +enabled: true +built_in_css: true +level_classes: [yellow, red, blue, green] \ No newline at end of file diff --git a/user/plugins/mediaembed/.gitignore b/user/plugins/mediaembed/.gitignore new file mode 100644 index 0000000..9509a05 --- /dev/null +++ b/user/plugins/mediaembed/.gitignore @@ -0,0 +1,3 @@ +assets/logo.svg +*.xcf +.idea diff --git a/user/plugins/mediaembed/CHANGELOG.md b/user/plugins/mediaembed/CHANGELOG.md new file mode 100644 index 0000000..8cef24a --- /dev/null +++ b/user/plugins/mediaembed/CHANGELOG.md @@ -0,0 +1,50 @@ +# v1.3.0 +## 02/05/2017 + +1. [](#new) + * Added support image or link for not embed media (Thanks to [@magikcypres](https://github.com/magikcypress)) + * Added support for **Twitter.com** (Thanks to [@magikcypres](https://github.com/magikcypress)) +2. [](#bugfix) + * Fixed support for **Github** (Thanks to [@magikcypres](https://github.com/magikcypress)) + * Fixed partial bug [#9](https://github.com/Sommerregen/grav-plugin-mediaembed/issues/9) (Mediaembed converts images into images) + * Fixed [#15](https://github.com/Sommerregen/grav-plugin-mediaembed/pull/15) (Fixed `media.responsive`) + * Fixed [#25](https://github.com/Sommerregen/grav-plugin-mediaembed/pull/25) (Fix Admin Panel issues [#13](https://github.com/Sommerregen/grav-plugin-mediaembed/issues/13), [#17](https://github.com/Sommerregen/grav-plugin-mediaembed/issues/17), and [#24](https://github.com/Sommerregen/grav-plugin-mediaembed/issues/24)) + +# v1.2.0 +## 08/08/2015 + +1. [](#new) + * Added admin configurations **(requires Grav 0.9.34+)** +2. [](#improved) + * Updated `README.md` + +# v1.1.0 +## 05/17/2015 + +1. [](#new) + * Added support for **Slides.com SlideDesk** as requested in issue [#4](https://github.com/Sommerregen/grav-plugin-mediaembed/issues/4) +2. [](#improved) + * Assets checks (in rare cases it was possible that MediaEmbed throws an error) + +# v1.0.2 +## 05/10/2015 + +1. [](#new) + * Added plugin roadmap + * Added support for modular pages +2. [](#improved) + * Prevent potential division by zero error [#2](https://github.com/Sommerregen/grav-plugin-mediaembed/pull/2) +3. [](#bugfix) + * Fixed link generation in case no MediaEmbed service is found + +# v1.0.1 +## 04/28/2015 + +3. [](#bugfix) + * Fixed issue [#1](https://github.com/Sommerregen/grav-plugin-mediaembed/issues/1) with broken MediaEmbed functionality (i.e. removed test code) + +# v1.0.0 +## 04/26/2015 + +1. [](#new) + * ChangeLog started... diff --git a/user/plugins/mediaembed/LICENSE b/user/plugins/mediaembed/LICENSE new file mode 100644 index 0000000..cf14dd9 --- /dev/null +++ b/user/plugins/mediaembed/LICENSE @@ -0,0 +1,727 @@ +Grav MediaEmbed Plugin License +================================== + +Grav MediaEmbed Plugin is meant to be a free and open source for all now +and in future. + +For ease of distribution, Grav MediaEmbed Plugin is licensed under a dual +license and is based on the principle of Give-and-Take. + +Unless otherwise noted Grav MediaEmbed Plugin is licensed under the terms +of GPLv3 (or see license text below). + +However it is licensed under the terms of MIT + + + +(or see license text below) when the following conditions are met: + + - Grav MediaEmbed Plugin is used, copied, merged, published for or + distributed with Grav (http://getgrav.org) + +and can be understood as a Free and Open Source Software ("FOSS") License +Exception especially for all plugins, themes, extensions available for Grav +using Grav MediaEmbed Plugin in any way. + + +MIT LICENSE +----------- + +Copyright (c) 2017 Benjamin Regler, https://github.com/sommerregen/grav-plugin-mediaembed + +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. + + +GPL VERSION 3 +------------- + +GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + {one line to give the program's name and a brief idea of what it does.} + Copyright (C) {year} {name of author} + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + {project} Copyright (C) {year} {fullname} + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/user/plugins/mediaembed/README.md b/user/plugins/mediaembed/README.md new file mode 100644 index 0000000..3747183 --- /dev/null +++ b/user/plugins/mediaembed/README.md @@ -0,0 +1,144 @@ +# [![Grav MediaEmbed Plugin](assets/logo.png)][project] + +[![Release](https://img.shields.io/github/release/sommerregen/grav-plugin-mediaembed.svg)][project] [![Issues](https://img.shields.io/github/issues/sommerregen/grav-plugin-mediaembed.svg)][issues] [![Dual license](https://img.shields.io/badge/dual%20license-MIT%2FGPL-blue.svg)](LICENSE "License") [![Flattr](https://api.flattr.com/button/flattr-badge-large.png)][flattr] [![PayPal](https://www.paypal.com/en_US/i/btn/btn_donate_SM.gif)][paypal] + +> This plugin embeds several media sites (e.g. YouTube, Vimeo, Soundcloud) by only providing the URL to the medium. + +##### Table of Contents: + +* [About](#about) +* [Installation and Updates](#installation-and-updates) +* [Usage](#usage) +* [Contributing](#contributing) +* [Licencse](#license) + +## About + +Grav MediaEmbed plugin is the official successor of [Grav VideoEmbed plugin](https://github.com/sommerregen/grav-plugin-videoembed/), allows to embed several media sites by only providing the URL to the medium and supports lazy loading techniques for videos and other media. Currently it supports + +- YouTube +- Vimeo +- DailyMotion +- SoundCloud +- Spotify +- Flickr +- Imgur +- Instagram +- GitHub +- Twitter + +but more services are coming soon! In principle it supports any service, which provides the [oEmbed format](http://www.oembed.com/). Media are embedded using the Markdown syntax for images (`![Alt](URL "Title")`), e.g. the below screenshot was created with the following code: + +``` +![](https://www.flickr.com/photos/chris_gin/6585842063) +``` + +![Screenshot MediaEmbed Plugin](assets/screenshot.png "MediaEmbed Preview") + +### The Roadmap + +Grav MediaEmbed plugin is neat and a powerful tool to embed other media types. However at the moment only a few services are supported. Further the configuration for the services may differ under certain circumstances; some may be more configurable than others. In future releases I intend to implement: + + - [ ] a unified interface for accessing [OEmbed](http://oembed.com "An overview about OEmbed services") services + - [ ] a cache mechanism for requests, data and images + - [ ] support more than 200+ OEmbed services + - [ ] and a more powerful API + +If you have any ideas to extend the list, then please don't hesitate to open an issue and spread your idea with the community! + +So far I'm happy that Grav MediaEmbed plugin becomes one of the most popular a d used plugins in a few days. Thank you! I try to give my best to provide you a fast, easy to use and extensible plugin. I have already spent a lot of time and will spend a lot of time even more. The plan is to extend Grav MediaEmbed plugin even more to embed arbitrary websites and embed media as cards (e.g. Wordpress, Twitter, Facebook, GitHub). This will however mean a many hour work and thus I plan to support such features in a paid version of Grav MediaEmbed plugin called "MediaEmbed Pro", which will coming soon. From then on, Grav MediaEmbed plugin will come in two flavors: a free version supporting all OEmbed services and a paid version with better embedding support of media and enabling the use of embed media cards. + +## Installation and Updates + +Installing or updating the `MediaEmbed` plugin can be done in one of two ways. Using the GPM (Grav Package Manager) installation update method (i.e. `bin/gpm install mediaembed`) or manual install by downloading [this plugin](https://github.com/sommerregen/grav-plugin-mediaembed) and extracting all plugin files to + + user/plugins/mediaembed + +For more informations, please check the [Installation and update guide](docs/INSTALL.md). + +## Usage + +The `MediaEmbed` plugin comes with some sensible default configuration, that are pretty self explanatory: + +### Config Defaults + +```yaml +# Global plugin configurations + +enabled: true # Set to false to disable this plugin completely +built_in_css: true # Use built-in CSS of the plugin +built_in_js: true # Use built-in JS of the plugin + +# Default options for MediaEmbed configuration. + +# -- Media -- +media: + width: 640 # Default media width + height: 390 # Default media height including controls + adjust: true # Adjust media or keep default dimensions? + + preview: true # Show or hide media preview + responsive: false # Allow media to be responsive + protocol: "http://" # Default protocol for remote media resources + +services: + : + enabled: true # Set to false to disable this service completely + type: # Type of the media service + + # URL of media service used for embedding + url: "www.domain.com/embed/{:id}" + + # Canonical URL of media service (used in endpoint calls) + canonical: "http://www.domain.com/{:id}" + + # Endpoint to grab media informations + endpoint: "http://www.domain.com/oembed?url={:canonical}&format=json" + + # Regex filters ("~REGEX~i") to grab media id + schemes: + - "domain.com/*" + + # Custom service-related media option overrides + params: + : +``` + +If you need to change any value, then the best process is to copy the [mediaembed.yaml](mediaembed.yaml) file into your `users/config/plugins/` folder (create it if it doesn't exist), and then modify there. This will override the default settings. + +## Contributing + +You can contribute at any time! Before opening any issue, please search for existing issues and review the [guidelines for contributing](docs/CONTRIBUTING.md). + +After that please note: + +* If you find a bug, would like to make a feature request or suggest an improvement, [please open a new issue][issues]. If you have any interesting ideas for additions to the syntax please do suggest them as well! +* Feature requests are more likely to get attention if you include a clearly described use case. +* If you wish to submit a pull request, please make again sure that your request match the [guidelines for contributing](docs/CONTRIBUTING.md) and that you keep track of adding unit tests for any new or changed functionality. + +### Support and donations + +If you like my project, feel free to support me via [![Flattr](https://api.flattr.com/button/flattr-badge-large.png)][flattr] or by sending me some bitcoins to [**1HQdy5aBzNKNvqspiLvcmzigCq7doGfLM4**][bitcoin]. + +Thanks! + +## License + +Copyright (c) 2017 [Benjamin Regler][github]. See also the list of [contributors] who participated in this project. + +[Dual-licensed](LICENSE) for use under the terms of the [MIT][mit-license] or [GPLv3][gpl-license] licenses. + +![GNU license - Some rights reserved][gnu] + +[github]: https://github.com/sommerregen/ "GitHub account from Benjamin Regler" +[gpl-license]: http://opensource.org/licenses/GPL-3.0 "GPLv3 license" +[mit-license]: http://www.opensource.org/licenses/mit-license.php "MIT license" + +[flattr]: https://flattr.com/submit/auto?user_id=Sommerregen&url=https://github.com/sommerregen/grav-plugin-mediaembed "Flatter my GitHub project" +[paypal]: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=SYFNP82USG3RN "Donate for my GitHub project using PayPal" +[bitcoin]: bitcoin:1HQdy5aBzNKNvqspiLvcmzigCq7doGfLM4?label=GitHub%20project "Donate for my GitHub project using BitCoin" +[gnu]: https://upload.wikimedia.org/wikipedia/commons/thumb/3/33/License_icon-gpl-88x31.svg/88px-License_icon-gpl-88x31.svg.png "GNU license - Some rights reserved" + +[project]: https://github.com/sommerregen/grav-plugin-mediaembed +[issues]: https://github.com/sommerregen/grav-plugin-mediaembed/issues "GitHub Issues for Grav MediaEmbed Plugin" +[contributors]: https://github.com/sommerregen/grav-plugin-mediaembed/graphs/contributors "List of contributors of the project" diff --git a/user/plugins/mediaembed/assets/css/mediaembed.css b/user/plugins/mediaembed/assets/css/mediaembed.css new file mode 100644 index 0000000..7951909 --- /dev/null +++ b/user/plugins/mediaembed/assets/css/mediaembed.css @@ -0,0 +1,330 @@ +/* MediaEmbed */ +.mediaembed, +.mediaembed-responsive { + margin: 0 auto; + overflow: hidden; + + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; +} + +.mediaembed-media .mediaembed-media, +.mediaembed-media embed, +.mediaembed-media iframe, +.mediaembed-media object, +.mediaembed-media video, +.mediaembed-embed img { + top: 0; + left: 0; + width: 100%; + height: 100%; + position: absolute; + z-index: 1; +} + +/* Media screen of death */ +.mediaembed-msod { + background-color: #000; + color: white; + display: block; + font-size: 80%; + overflow: hidden; + padding: 1em; + position: relative; + text-align: center; + vertical-align: middle; + z-index: 1; +} +.mediaembed-msod:before { + content: ""; + display: block; + + position: absolute; + z-index: -1; + + /* We make the element extra-large so we can shuffle it around without exposing the edges */ + height: 300%; + left: -100%; + top: -100%; + width: 300%; + + -webkit-animation: grain 5s steps(10) infinite; + -moz-animation: grain 5s steps(10) infinite; + -ms-animation: grain 5s steps(10) infinite; + animation: grain 5s steps(10) infinite; + + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAMAAAAp4XiDAAAAUVBMVEWFhYWDg4N3d3dtbW17e3t1dXWBgYGHh4d5eXlzc3OLi4ubm5uVlZWPj4+NjY19fX2JiYl/f39ra2uRkZGZmZlpaWmXl5dvb29xcXGTk5NnZ2c8TV1mAAAAG3RSTlNAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAvEOwtAAAFVklEQVR4XpWWB67c2BUFb3g557T/hRo9/WUMZHlgr4Bg8Z4qQgQJlHI4A8SzFVrapvmTF9O7dmYRFZ60YiBhJRCgh1FYhiLAmdvX0CzTOpNE77ME0Zty/nWWzchDtiqrmQDeuv3powQ5ta2eN0FY0InkqDD73lT9c9lEzwUNqgFHs9VQce3TVClFCQrSTfOiYkVJQBmpbq2L6iZavPnAPcoU0dSw0SUTqz/GtrGuXfbyyBniKykOWQWGqwwMA7QiYAxi+IlPdqo+hYHnUt5ZPfnsHJyNiDtnpJyayNBkF6cWoYGAMY92U2hXHF/C1M8uP/ZtYdiuj26UdAdQQSXQErwSOMzt/XWRWAz5GuSBIkwG1H3FabJ2OsUOUhGC6tK4EMtJO0ttC6IBD3kM0ve0tJwMdSfjZo+EEISaeTr9P3wYrGjXqyC1krcKdhMpxEnt5JetoulscpyzhXN5FRpuPHvbeQaKxFAEB6EN+cYN6xD7RYGpXpNndMmZgM5Dcs3YSNFDHUo2LGfZuukSWyUYirJAdYbF3MfqEKmjM+I2EfhA94iG3L7uKrR+GdWD73ydlIB+6hgref1QTlmgmbM3/LeX5GI1Ux1RWpgxpLuZ2+I+IjzZ8wqE4nilvQdkUdfhzI5QDWy+kw5Wgg2pGpeEVeCCA7b85BO3F9DzxB3cdqvBzWcmzbyMiqhzuYqtHRVG2y4x+KOlnyqla8AoWWpuBoYRxzXrfKuILl6SfiWCbjxoZJUaCBj1CjH7GIaDbc9kqBY3W/Rgjda1iqQcOJu2WW+76pZC9QG7M00dffe9hNnseupFL53r8F7YHSwJWUKP2q+k7RdsxyOB11n0xtOvnW4irMMFNV4H0uqwS5ExsmP9AxbDTc9JwgneAT5vTiUSm1E7BSflSt3bfa1tv8Di3R8n3Af7MNWzs49hmauE2wP+ttrq+AsWpFG2awvsuOqbipWHgtuvuaAE+A1Z/7gC9hesnr+7wqCwG8c5yAg3AL1fm8T9AZtp/bbJGwl1pNrE7RuOX7PeMRUERVaPpEs+yqeoSmuOlokqw49pgomjLeh7icHNlG19yjs6XXOMedYm5xH2YxpV2tc0Ro2jJfxC50ApuxGob7lMsxfTbeUv07TyYxpeLucEH1gNd4IKH2LAg5TdVhlCafZvpskfncCfx8pOhJzd76bJWeYFnFciwcYfubRc12Ip/ppIhA1/mSZ/RxjFDrJC5xifFjJpY2Xl5zXdguFqYyTR1zSp1Y9p+tktDYYSNflcxI0iyO4TPBdlRcpeqjK/piF5bklq77VSEaA+z8qmJTFzIWiitbnzR794USKBUaT0NTEsVjZqLaFVqJoPN9ODG70IPbfBHKK+/q/AWR0tJzYHRULOa4MP+W/HfGadZUbfw177G7j/OGbIs8TahLyynl4X4RinF793Oz+BU0saXtUHrVBFT/DnA3ctNPoGbs4hRIjTok8i+algT1lTHi4SxFvONKNrgQFAq2/gFnWMXgwffgYMJpiKYkmW3tTg3ZQ9Jq+f8XN+A5eeUKHWvJWJ2sgJ1Sop+wwhqFVijqWaJhwtD8MNlSBeWNNWTa5Z5kPZw5+LbVT99wqTdx29lMUH4OIG/D86ruKEauBjvH5xy6um/Sfj7ei6UUVk4AIl3MyD4MSSTOFgSwsH/QJWaQ5as7ZcmgBZkzjjU1UrQ74ci1gWBCSGHtuV1H2mhSnO3Wp/3fEV5a+4wz//6qy8JxjZsmxxy5+4w9CDNJY09T072iKG0EnOS0arEYgXqYnXcYHwjTtUNAcMelOd4xpkoqiTYICWFq0JSiPfPDQdnt+4/wuqcXY47QILbgAAAABJRU5ErkJggg==); +} +.mediaembed-msod .mediaembed-icon { + font-size: 7em; + line-height: 1em; + margin: 0.25em auto 0; +} +.mediaembed-msod p b { + display: block; + font-weight: bold; + text-align: center; +} +.mediaembed-msod .mediaembed-error-message { + margin: 0 3em 1em; + text-align: justify; +} +.mediaembed-msod .mediaembed-error-message b { + color: #f00; + text-transform: uppercase; +} + +/* MediaEmbed media */ + +.mediaembed-container { + position: relative; +} + +/* MediaEmbed Play button */ +.mediaembed-play { + margin: auto; + position: absolute; + + top: 0; + right: 0; + bottom: 0; + left: 10px; + + width: 1em; + height: 1em; + + color: #fff; + display: block; + font-size: 6em; + line-height: 1; + text-align: center; + text-shadow: 0 0 2px #ccc; + + visibility: visible; + opacity: 1; + z-index: 2; +} +.mediaembed-play:before { + box-shadow: 0 0 2px 0 #ccc inset, 0 0 2px 0 #ccc; + border: medium solid; + border-radius: 100%; + content: ""; + display: block; + height: 120%; + left: calc(-10% - 10px); + position: absolute; + top: calc(-5% - 5px); + width: 120%; +} +.mediaembed-play::after { + bottom: -1000%; + content: ""; + display: block; + left: -1000%; + position: absolute; + right: -1000%; + top: -1000%; +} +.mediaembed-play:hover { + color: #ccc; +} +.mediaembed-media iframe ~ .mediaembed-play, +.mediaembed-media input:checked ~ .mediaembed-play { + visibility: hidden; + opacity: 0; + z-index: 1; + + -webkit-transition: opacity 1.5s ease-in-out 0s, visibility 1.5s linear 0s, z-index 1.5s linear 0s; + -moz-transition: opacity 1.5s ease-in-out 0s, visibility 1.5s linear 0s, z-index 1.5s linear 0s; + -ms-transition: opacity 1.5s ease-in-out 0s, visibility 1.5s linear 0s, z-index 1.5s linear 0s; + -o-transition: opacity 1.5s ease-in-out 0s, visibility 1.5s linear 0s, z-index 1.5s linear 0s; + transition: opacity 1.5s ease-in-out 0s, visibility 1.5s linear 0s, z-index 1.5s linear 0s; +} +.mediaembed-media iframe ~ .mediaembed-play, +.mediaembed-media input:checked ~ .mediaembed-play:before { + -webkit-animation: ring 1.5s ease-in-out 1; + -moz-animation: ring 1.5s ease-in-out 1; + -ms-animation: ring 1.5s ease-in-out 1; + -o-animation: ring 1.5s ease-in-out 1; + animation: ring 1.5s ease-in-out 1; +} + +.mediaembed-media input:checked ~ noscript iframe { + display: block !important; +} +.mediaembed-media .mediaembed-input { + display: none; +} +.mediaembed-thumbnail { + margin: auto; + position: absolute; + + top: -50%; + right: 0; + bottom: -50%; + left: 0; + + width: 100%; + z-index: 0; +} + +/* GitHub adjustments */ +.mediaembed-github { + overflow: auto; +} +.mediaembed-github .gist .line-numbers { + width: 4em; +} +.mediaembed-github .gist-file { + padding: 1em; +} + +/* + * Animations + */ + +/* -- Grain -- */ +@-webkit-keyframes grain { + 0%, 100% { + -webkit-transform: translate(0, 0); + } + 10% { + -webkit-transform: translate(-5%, -10%); + } + 20% { + -webkit-transform: translate(-15%, 5%); + } + 30% { + -webkit-transform: translate(7%, -25%); + } + 40% { + -webkit-transform: translate(-5%, 25%); + } + 50% { + -webkit-transform: translate(-15%, 10%); + } + 60% { + -webkit-transform: translate(15%, 0%); + } + 70% { + -webkit-transform: translate(0%, 15%); + } + 80% { + -webkit-transform: translate(3%, 20%); + } + 90% { + -webkit-transform: translate(-10%, 10%); + } +} +@-moz-keyframes grain { + 0%, 100% { + -moz-transform: translate(0, 0); + } + 10% { + -moz-transform: translate(-5%, -10%); + } + 20% { + -moz-transform: translate(-15%, 5%); + } + 30% { + -moz-transform: translate(7%, -25%); + } + 40% { + -moz-transform: translate(-5%, 25%); + } + 50% { + -moz-transform: translate(-15%, 10%); + } + 60% { + -moz-transform: translate(15%, 0%); + } + 70% { + -moz-transform: translate(0%, 15%); + } + 80% { + -moz-transform: translate(3%, 20%); + } + 90% { + -moz-transform: translate(-10%, 10%); + } +} +@-ms-keyframes grain { + 0%, 100% { + -ms-transform: translate(0, 0); + } + 10% { + -ms-transform: translate(-5%, -10%); + } + 20% { + -ms-transform: translate(-15%, 5%); + } + 30% { + -ms-transform: translate(7%, -25%); + } + 40% { + -ms-transform: translate(-5%, 25%); + } + 50% { + -ms-transform: translate(-15%, 10%); + } + 60% { + -ms-transform: translate(15%, 0%); + } + 70% { + -ms-transform: translate(0%, 15%); + } + 80% { + -ms-transform: translate(3%, 20%); + } + 90% { + -ms-transform: translate(-10%, 10%); + } +} +@keyframes grain { + 0%, 100% { + transform: translate(0, 0); + } + 10% { + transform: translate(-5%, -10%); + } + 20% { + transform: translate(-15%, 5%); + } + 30% { + transform: translate(7%, -25%); + } + 40% { + transform: translate(-5%, 25%); + } + 50% { + transform: translate(-15%, 10%); + } + 60% { + transform: translate(15%, 0%); + } + 70% { + transform: translate(0%, 15%); + } + 80% { + transform: translate(3%, 20%); + } + 90% { + transform: translate(-10%, 10%); + } +} + +/* -- Ring -- */ +@keyframes ring { + 0% { + transform: scale(1); + opacity: 1; + border-width: medium; + } + /* hidden */ + 100% { + transform: scale(3); + opacity: 0; + border-width: thin; + } +} diff --git a/user/plugins/mediaembed/assets/js/mediaembed.js b/user/plugins/mediaembed/assets/js/mediaembed.js new file mode 100644 index 0000000..aba16ef --- /dev/null +++ b/user/plugins/mediaembed/assets/js/mediaembed.js @@ -0,0 +1,18 @@ +function lazyload(anchor) { + setTimeout(function () { + // Strip comment tags around innerHTML + anchor.innerHTML = anchor.innerHTML.replace('', ''); + }, 1000); + + // Remove