, e.g.
+ // Soccer -> Soc cer for regex = /soc/i
+ if (node.nodeType === 3) {
+ var pos = node.data.search(regex);
+ if (pos >= 0 && node.data.length > 0) {
+ var match = node.data.match(regex);
+ var spannode = document.createElement('span');
+ spannode.className = 'highlight';
+ var middlebit = node.splitText(pos);
+ var endbit = middlebit.splitText(match[0].length);
+ var middleclone = middlebit.cloneNode(true);
+ spannode.appendChild(middleclone);
+ middlebit.parentNode.replaceChild(spannode, middlebit);
+ skip = 1;
+ }
+ }
+ // Recurse element node, looking for child text nodes to highlight, unless element
+ // is childless,
+{% endblock %}
diff --git a/config/www/user/plugins/admin/themes/grav/templates/partials/backups-button.html.twig b/config/www/user/plugins/admin/themes/grav/templates/partials/backups-button.html.twig
new file mode 100644
index 0000000..970d816
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/partials/backups-button.html.twig
@@ -0,0 +1,21 @@
+
+ {% set profiles = grav.backups.getBackupProfiles() %}
+ {% set backup_url = uri.addNonce(base_url_relative ~ "/backup.json/id" ~ config.system.param_sep ~ "%BACKUP_ID/task" ~ config.system.param_sep ~ "backup", 'admin-form', 'admin-nonce') %}
+
+
+ {{ "PLUGIN_ADMIN.BACKUP_NOW"|t }}
+
+
+
+
+
+
diff --git a/config/www/user/plugins/admin/themes/grav/templates/partials/base-root.html.twig b/config/www/user/plugins/admin/themes/grav/templates/partials/base-root.html.twig
new file mode 100644
index 0000000..9a0c7aa
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/partials/base-root.html.twig
@@ -0,0 +1,154 @@
+{% if uri.extension() == 'json' %}{% include 'default.json.twig' %}{% else %}
+
+
+
+ {% block head %}
+
+ {% if title %}{{ title|striptags|raw }} | {% else %}{% if header.title %}{{ header.title }} | {% endif %}{% endif %}{{ site.title }}
+ {% if header.description %}
+
+ {% else %}
+
+ {% endif %}
+ {% if header.robots %}
+
+ {% else %}
+
+ {% endif %}
+
+
+
+ {% block stylesheets %}
+ {% include 'partials/stylesheets.html.twig' %}
+ {% endblock %}
+
+ {% include 'partials/javascript-config.html.twig' %}
+ {% block javascripts %}
+ {% include 'partials/javascripts.html.twig' %}
+ {% endblock %}
+ {% endblock %}
+
+ {% block assets deferred %}
+ {{ assets.css()|raw }}
+ {{ assets.js()|raw }}
+ {% endblock %}
+
+
+
+
+ {% block body %}
+ {% set sidebarStatus = get_cookie('grav-admin-sidebar') %}
+ {% set sidebarStatus = (sidebarStatus is not null and sidebarStatus == 'false') or config.plugins.admin.sidebar.size == 'small' ? 'sidebar-closed' : '' %}
+
+
+ {% if not authorize(['admin.login']) %}
+ {% include 'partials/messages.html.twig' %}
+ {% else %}
+ {% block page %}
+
+
+ {% block navigation %}
+ {% include 'partials/nav.html.twig' %}
+ {% endblock %}
+
+
+ {% include 'partials/nav-toggle.html.twig' %}
+
+ {% block titlebar %}{% endblock %}
+
+
+ {% block content_wrapper %}
+
+
+ {% block messages %}
+ {% include 'partials/messages.html.twig' %}
+ {% endblock %}
+
+ {% block widgets %}{% endblock %}
+
+ {% block content_top %}{% endblock %}
+
+ {%- block content %}{% endblock -%}
+
+ {% if config.plugins.admin.show_github_msg %}
+
+ {% endif %}
+ {% block content_bottom %}{% endblock %}
+
+ {% block footer %}
+
+ {% endblock %}
+
+
+ {% endblock %}
+
+ {% block modals %}
+
+
+
+
+ {% endblock %}
+
+
+
+
+ {% endblock page %}
+
+ {% endif %}
+
+ {% block bottom %}
+ {{ assets.js('bottom')|raw }}
+ {% endblock %}
+
+ {% endblock body %}
+
+{% endif %}
diff --git a/config/www/user/plugins/admin/themes/grav/templates/partials/base.html.twig b/config/www/user/plugins/admin/themes/grav/templates/partials/base.html.twig
new file mode 100644
index 0000000..4b40cd5
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/partials/base.html.twig
@@ -0,0 +1 @@
+{% extends 'partials/base-root.html.twig' %}
diff --git a/config/www/user/plugins/admin/themes/grav/templates/partials/blueprints-copy.html.twig b/config/www/user/plugins/admin/themes/grav/templates/partials/blueprints-copy.html.twig
new file mode 100644
index 0000000..0c84761
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/partials/blueprints-copy.html.twig
@@ -0,0 +1,19 @@
+{% set form_id = form_id ? form_id : 'blueprints' %}
+{% set scope = scope ?: 'data.' %}
+{% set field_layout = 'admin' %}
+
+
diff --git a/config/www/user/plugins/admin/themes/grav/templates/partials/blueprints-new-folder.html.twig b/config/www/user/plugins/admin/themes/grav/templates/partials/blueprints-new-folder.html.twig
new file mode 100644
index 0000000..128eb49
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/partials/blueprints-new-folder.html.twig
@@ -0,0 +1,18 @@
+{% set form_id = form_id ? form_id : 'blueprints' %}
+{% set scope = scope ?: 'data.' %}
+{% set field_layout = 'admin' %}
+
+
diff --git a/config/www/user/plugins/admin/themes/grav/templates/partials/blueprints-new.html.twig b/config/www/user/plugins/admin/themes/grav/templates/partials/blueprints-new.html.twig
new file mode 100644
index 0000000..b8d244c
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/partials/blueprints-new.html.twig
@@ -0,0 +1,19 @@
+{% set form_id = form_id ? form_id : 'blueprints' %}
+{% set scope = scope ?: 'data.' %}
+{% set field_layout = 'admin' %}
+
+
diff --git a/config/www/user/plugins/admin/themes/grav/templates/partials/blueprints-raw.html.twig b/config/www/user/plugins/admin/themes/grav/templates/partials/blueprints-raw.html.twig
new file mode 100644
index 0000000..7ab3a6e
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/partials/blueprints-raw.html.twig
@@ -0,0 +1,22 @@
+{% set form_id = form_id ? form_id : 'blueprints' %}
+{% set scope = scope ?: 'data.' %}
+{% set field_layout = 'admin' %}
+
+{% if admin.findFormFields('file', blueprints.fields) %}
+ {% set multipart = ' enctype="multipart/form-data"' %}
+{% endif %}
+
+
diff --git a/config/www/user/plugins/admin/themes/grav/templates/partials/blueprints.html.twig b/config/www/user/plugins/admin/themes/grav/templates/partials/blueprints.html.twig
new file mode 100644
index 0000000..f4ab5e7
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/partials/blueprints.html.twig
@@ -0,0 +1,34 @@
+{% set blueprints = blueprints ?? form.blueprint %}
+{% set data = data ?? form.data %}
+{% set form_id = form_id ?? 'blueprints' %}
+{% set scope = scope ?: 'data.' %}
+{% set field_layout = 'admin' %}
+
+{% if admin.findFormFields('file', blueprints.fields) %}
+ {% set multipart = ' enctype="multipart/form-data"' %}
+{% endif %}
+
+
diff --git a/config/www/user/plugins/admin/themes/grav/templates/partials/dashboard-feed.html.twig b/config/www/user/plugins/admin/themes/grav/templates/partials/dashboard-feed.html.twig
new file mode 100644
index 0000000..343bdf7
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/partials/dashboard-feed.html.twig
@@ -0,0 +1,14 @@
+
+
+ {{ "PLUGIN_ADMIN.NEWS_FEED"|t }}
+
+
+
+
+
+
+
+
diff --git a/config/www/user/plugins/admin/themes/grav/templates/partials/dashboard-maintenance.html.twig b/config/www/user/plugins/admin/themes/grav/templates/partials/dashboard-maintenance.html.twig
new file mode 100644
index 0000000..d6e334d
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/partials/dashboard-maintenance.html.twig
@@ -0,0 +1,33 @@
+{% if authorize(['admin.maintenance', 'admin.super']) %}
+ {% set backup = admin.lastBackup() %}
+
+
+
+
{{ "PLUGIN_ADMIN.MAINTENANCE"|t }}
+
+
+
+
+
- {{ "PLUGIN_ADMIN.UPDATED"|t|lower }}
+
+
+
+
+
+
+
{{ backup.days|raw }}{{ "PLUGIN_ADMIN.DAYS"|t|lower }}
+
+
{{ "PLUGIN_ADMIN.LAST_BACKUP"|t }}
+
+
+
+
+
+
+
+ {% include 'partials/modal-update-packages.html.twig' with { type: 'plugin' } %}
+
+{% endif %}
diff --git a/config/www/user/plugins/admin/themes/grav/templates/partials/dashboard-notifications.html.twig b/config/www/user/plugins/admin/themes/grav/templates/partials/dashboard-notifications.html.twig
new file mode 100644
index 0000000..5a96cda
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/partials/dashboard-notifications.html.twig
@@ -0,0 +1,13 @@
+
+
+ {{ "PLUGIN_ADMIN.NOTIFICATIONS"|t }}
+
+
+
+
+
+
+
diff --git a/config/www/user/plugins/admin/themes/grav/templates/partials/dashboard-pages.html.twig b/config/www/user/plugins/admin/themes/grav/templates/partials/dashboard-pages.html.twig
new file mode 100644
index 0000000..501e211
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/partials/dashboard-pages.html.twig
@@ -0,0 +1,18 @@
+{% if authorize(['admin.pages.list', 'admin.pages', 'admin.super']) %}
+
+
+
{{ "PLUGIN_ADMIN.LATEST_PAGE_UPDATES"|t }}
+
+ {% for latest in admin.latestPages if admin.latestPages %}
+ {% set route = latest.rawRoute %}
+
+
+ {{ latest.title }}
+ {{ route }} {{ latest.modified|adminNicetime }}
+
+ {% endfor %}
+
+
+{% endif %}
diff --git a/config/www/user/plugins/admin/themes/grav/templates/partials/dashboard-problems.html.twig b/config/www/user/plugins/admin/themes/grav/templates/partials/dashboard-problems.html.twig
new file mode 100644
index 0000000..beeb7c4
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/partials/dashboard-problems.html.twig
@@ -0,0 +1,11 @@
+{% if authorize(['admin.plugins', 'admin.super']) and grav['flex_objects'] is null %}
+
+
+{% endif %}
diff --git a/config/www/user/plugins/admin/themes/grav/templates/partials/dashboard-statistics.html.twig b/config/www/user/plugins/admin/themes/grav/templates/partials/dashboard-statistics.html.twig
new file mode 100644
index 0000000..0ba390d
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/partials/dashboard-statistics.html.twig
@@ -0,0 +1,24 @@
+{% if authorize(['admin.statistics', 'admin.super']) %}
+
+
+
{{ "PLUGIN_ADMIN.VIEWS_STATISTICS"|t }}
+
+
+
+
+ {{ popularity.getDailyTotal }}
+ {{ "PLUGIN_ADMIN.TODAY"|t }}
+
+
+ {{ popularity.getWeeklyTotal }}
+ {{ "PLUGIN_ADMIN.WEEK"|t }}
+
+
+ {{ popularity.getMonthlyTotal }}
+ {{ "PLUGIN_ADMIN.MONTH"|t }}
+
+
+
+
+
+{% endif %}
diff --git a/config/www/user/plugins/admin/themes/grav/templates/partials/feed-block.html.twig b/config/www/user/plugins/admin/themes/grav/templates/partials/feed-block.html.twig
new file mode 100644
index 0000000..52bd2c9
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/partials/feed-block.html.twig
@@ -0,0 +1,3 @@
+{% for entry in feed %}
+{{ entry.nicetime }} {{ entry.title }}
+{% endfor %}
diff --git a/config/www/user/plugins/admin/themes/grav/templates/partials/footer.html.twig b/config/www/user/plugins/admin/themes/grav/templates/partials/footer.html.twig
new file mode 100644
index 0000000..19f5aa8
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/partials/footer.html.twig
@@ -0,0 +1,5 @@
+{% if custom_admin_footer %}
+ {{ custom_admin_footer|raw }}
+{% else %}
+ Grav v{{ constant('GRAV_VERSION') }} - Admin v{{ admin_version }} - {{ "PLUGIN_ADMIN.WAS_MADE_WITH"|t|lower }} {{ "PLUGIN_ADMIN.BY"|t|lower }} Trilby Media .
+{% endif %}
diff --git a/config/www/user/plugins/admin/themes/grav/templates/partials/header.html.twig b/config/www/user/plugins/admin/themes/grav/templates/partials/header.html.twig
new file mode 100644
index 0000000..d52349b
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/partials/header.html.twig
@@ -0,0 +1,11 @@
+
+
+ {% for page in pages %}
+ {% if page.visible %}
+
+ {{ page.menu }}
+
+ {% endif %}
+ {% endfor %}
+
+
diff --git a/config/www/user/plugins/admin/themes/grav/templates/partials/javascript-config.html.twig b/config/www/user/plugins/admin/themes/grav/templates/partials/javascript-config.html.twig
new file mode 100644
index 0000000..c0c1542
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/partials/javascript-config.html.twig
@@ -0,0 +1,48 @@
+{% if user.authorized and authorize(['admin.login', 'admin.super']) %}
+{% set feed_enabled = config.plugins.admin.notifications.feed is same as(true) or config.plugins.admin.notifications.feed == 'true' %}
+{% set dashboard_enabled = config.plugins.admin.notifications.dashboard is same as(true) or config.plugins.admin.notifications.dashboard == 'true' %}
+{% set plugins_enabled = config.plugins.admin.notifications.plugins is same as(true) or config.plugins.admin.notifications.plugins == 'true' %}
+{% set themes_enabled = config.plugins.admin.notifications.themes is same as(true) or config.plugins.admin.notifications.themes == 'true' %}
+{% set notifications = (feed_enabled or dashboard_enabled or plugins_enabled or themes_enabled) ? 1 : 0 %}
+
+{% switch template_route %}
+ {% case 'dashboard' %}
+ {% set notifications_filters = "['feed', 'dashboard', 'top']" %}
+ {% case 'plugins' %}
+ {% set notifications_filters = "['plugins', 'top']" %}
+ {% case 'themes' %}
+ {% set notifications_filters = "['themes', 'top']" %}
+ {% default %}
+ {% set notifications_filters = "['top']" %}
+{% endswitch %}
+
+{% endif %}
diff --git a/config/www/user/plugins/admin/themes/grav/templates/partials/javascripts.html.twig b/config/www/user/plugins/admin/themes/grav/templates/partials/javascripts.html.twig
new file mode 100644
index 0000000..15bfec7
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/partials/javascripts.html.twig
@@ -0,0 +1,11 @@
+{% 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 %}
diff --git a/config/www/user/plugins/admin/themes/grav/templates/partials/list-sort.html.twig b/config/www/user/plugins/admin/themes/grav/templates/partials/list-sort.html.twig
new file mode 100644
index 0000000..ba1c128
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/partials/list-sort.html.twig
@@ -0,0 +1,13 @@
+
diff --git a/config/www/user/plugins/admin/themes/grav/templates/partials/login-form.html.twig b/config/www/user/plugins/admin/themes/grav/templates/partials/login-form.html.twig
new file mode 100755
index 0000000..7f24d1e
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/partials/login-form.html.twig
@@ -0,0 +1,25 @@
+{% embed 'partials/login.html.twig' with {title: 'Grav Admin Login'} %}
+
+{% block integration %}
+
+ {# NEW WAY OF INCLUDING 3RD PARTY LOGIN OPTIONS #}
+ {% for template in grav.login.getProviderLoginTemplates %}
+ {% include template %}
+ {% endfor %}
+
+{% endblock %}
+
+{% block form %}
+ {% embed 'forms/default/fields.html.twig' with {name: null, fields: form.fields} %}
+ {% block inner_markup_field_open %}{% endblock %}
+ {% block inner_markup_field_close %}
{% endblock %}
+ {% endembed %}
+
+
+
+{% endblock %}
+
+{% endembed %}
diff --git a/config/www/user/plugins/admin/themes/grav/templates/partials/login-logo.html.twig b/config/www/user/plugins/admin/themes/grav/templates/partials/login-logo.html.twig
new file mode 100644
index 0000000..39fdec1
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/partials/login-logo.html.twig
@@ -0,0 +1,14 @@
+{% if config.plugins.admin.logo_text %}
+
+ {{ config.plugins.admin.logo_text }}
+
+{% else %}
+
+ {{ title }}
+ {% if custom_login_logo %}
+
+ {% else %}
+ {% include('@admin-images/logo.svg') %}
+ {% endif %}
+
+{% endif %}
diff --git a/config/www/user/plugins/admin/themes/grav/templates/partials/login-logout.html.twig b/config/www/user/plugins/admin/themes/grav/templates/partials/login-logout.html.twig
new file mode 100644
index 0000000..082f827
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/partials/login-logout.html.twig
@@ -0,0 +1,15 @@
+{% embed 'partials/login.html.twig' with {title:'Grav Admin Logout'} %}
+
+{% block integration %}
+{% endblock %}
+
+{% block form %}
+
+
+
+{% endblock %}
+
+{% endembed %}
diff --git a/config/www/user/plugins/admin/themes/grav/templates/partials/login-twofa.html.twig b/config/www/user/plugins/admin/themes/grav/templates/partials/login-twofa.html.twig
new file mode 100644
index 0000000..06fbcaf
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/partials/login-twofa.html.twig
@@ -0,0 +1,20 @@
+{% embed 'partials/login.html.twig' with {title:'Grav 2-Factor Authentication', redirect: admin.session.redirect} %}
+
+{% block integration %}
+{% endblock %}
+
+{% block form %}
+ {% embed 'forms/default/fields.html.twig' with {name: null, fields: form.fields} %}
+ {% block inner_markup_field_open %}{% endblock %}
+ {% block inner_markup_field_close %}
{% endblock %}
+ {% endembed %}
+
+
+
+{% endblock %}
+
+{% endembed %}
diff --git a/config/www/user/plugins/admin/themes/grav/templates/partials/login.html.twig b/config/www/user/plugins/admin/themes/grav/templates/partials/login.html.twig
new file mode 100644
index 0000000..e554a81
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/partials/login.html.twig
@@ -0,0 +1,33 @@
+{% extends 'partials/base.html.twig' %}
+{% set scope = form.scope %}
+{% set field_layout = 'admin' %}
+
+{% block messages %}{% endblock %}
+
+{% block body %}
+
+
+
+ {% include 'partials/login-logo.html.twig' %}
+
+ {% include 'partials/messages.html.twig' %}
+
+ {% block instructions %}{% endblock %}
+
+ {% block integration %}{% endblock %}
+
+
+
+
+
+
+{% endblock %}
diff --git a/config/www/user/plugins/admin/themes/grav/templates/partials/logo.html.twig b/config/www/user/plugins/admin/themes/grav/templates/partials/logo.html.twig
new file mode 100644
index 0000000..2f8c303
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/partials/logo.html.twig
@@ -0,0 +1,20 @@
+{% if config.plugins.admin.logo_text %}
+
+{% else %}
+
+{% endif %}
diff --git a/config/www/user/plugins/admin/themes/grav/templates/partials/media-list-wrapper.html.twig b/config/www/user/plugins/admin/themes/grav/templates/partials/media-list-wrapper.html.twig
new file mode 100644
index 0000000..24deafd
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/partials/media-list-wrapper.html.twig
@@ -0,0 +1,32 @@
+
\ No newline at end of file
diff --git a/config/www/user/plugins/admin/themes/grav/templates/partials/media-list-wrapper__list.html.twig b/config/www/user/plugins/admin/themes/grav/templates/partials/media-list-wrapper__list.html.twig
new file mode 100644
index 0000000..5f354c2
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/partials/media-list-wrapper__list.html.twig
@@ -0,0 +1,23 @@
+
+
+{% include 'partials/spinning-wheel.html.twig' %}
diff --git a/config/www/user/plugins/admin/themes/grav/templates/partials/media-list-wrapper__list__filters.html.twig b/config/www/user/plugins/admin/themes/grav/templates/partials/media-list-wrapper__list__filters.html.twig
new file mode 100644
index 0000000..05057d2
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/partials/media-list-wrapper__list__filters.html.twig
@@ -0,0 +1,28 @@
+
+
+
+ All Files
+ Images
+ Videos
+ Audio
+ Files
+
+
+
+
+
+ All Dates
+ {% set theDate = date() %}
+ {% for year, months in admin.filesDates %}
+
+ {% for month, number in months %}
+
+ {{theDate.setDate(theDate.format('Y'), month, theDate.format('d'))|date('M')}}
+ ({{number}})
+ {% endfor %}
+
+ {% endfor %}
+
+
+
+
\ No newline at end of file
diff --git a/config/www/user/plugins/admin/themes/grav/templates/partials/media-list-wrapper__sidebar.html.twig b/config/www/user/plugins/admin/themes/grav/templates/partials/media-list-wrapper__sidebar.html.twig
new file mode 100644
index 0000000..fd33ecf
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/partials/media-list-wrapper__sidebar.html.twig
@@ -0,0 +1,36 @@
+{% macro loop(page, depth, twig_vars) %}
+ {% import _self as self %}
+
+ {% for p in page.children() %}
+
+
+
0 ? 'data-toggle="children"' : ''}} class="hint--bottom">
+
+
+
+
+ {{ p.title }}
+
+
+
{{ p.home ? ' ' }}
+
+ {% if p.children().count > 0 %}
+
+
+ {{ self.loop(p, depth + 1, twig_vars) }}
+
+ {% endif %}
+
+ {% endfor %}
+{% endmacro %}
+
+{% import _self as macro %}
+
+
+
{{ "PLUGIN_ADMIN.PAGES"|t }}
+
+
diff --git a/config/www/user/plugins/admin/themes/grav/templates/partials/messages.html.twig b/config/www/user/plugins/admin/themes/grav/templates/partials/messages.html.twig
new file mode 100644
index 0000000..3d89c43
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/partials/messages.html.twig
@@ -0,0 +1,14 @@
+{% set admin_messages = admin.messages|merge(admin.getTempMessages()) %}
+{% set form_message = form.message %}
+
diff --git a/config/www/user/plugins/admin/themes/grav/templates/partials/modal-add-package.html.twig b/config/www/user/plugins/admin/themes/grav/templates/partials/modal-add-package.html.twig
new file mode 100644
index 0000000..07e9792
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/partials/modal-add-package.html.twig
@@ -0,0 +1,89 @@
+
diff --git a/config/www/user/plugins/admin/themes/grav/templates/partials/modal-changelog.html.twig b/config/www/user/plugins/admin/themes/grav/templates/partials/modal-changelog.html.twig
new file mode 100644
index 0000000..95754e5
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/partials/modal-changelog.html.twig
@@ -0,0 +1 @@
+
diff --git a/config/www/user/plugins/admin/themes/grav/templates/partials/modal-changes-detected.html.twig b/config/www/user/plugins/admin/themes/grav/templates/partials/modal-changes-detected.html.twig
new file mode 100644
index 0000000..dd0c4d6
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/partials/modal-changes-detected.html.twig
@@ -0,0 +1,13 @@
+
diff --git a/config/www/user/plugins/admin/themes/grav/templates/partials/modal-reinstall-package.html.twig b/config/www/user/plugins/admin/themes/grav/templates/partials/modal-reinstall-package.html.twig
new file mode 100644
index 0000000..30712fc
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/partials/modal-reinstall-package.html.twig
@@ -0,0 +1,38 @@
+
diff --git a/config/www/user/plugins/admin/themes/grav/templates/partials/modal-remove-package.html.twig b/config/www/user/plugins/admin/themes/grav/templates/partials/modal-remove-package.html.twig
new file mode 100644
index 0000000..7107c01
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/partials/modal-remove-package.html.twig
@@ -0,0 +1,44 @@
+
diff --git a/config/www/user/plugins/admin/themes/grav/templates/partials/modal-switch-theme.html.twig b/config/www/user/plugins/admin/themes/grav/templates/partials/modal-switch-theme.html.twig
new file mode 100644
index 0000000..923deaf
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/partials/modal-switch-theme.html.twig
@@ -0,0 +1,16 @@
+
diff --git a/config/www/user/plugins/admin/themes/grav/templates/partials/modal-update-packages.html.twig b/config/www/user/plugins/admin/themes/grav/templates/partials/modal-update-packages.html.twig
new file mode 100644
index 0000000..cc28558
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/partials/modal-update-packages.html.twig
@@ -0,0 +1,89 @@
+
diff --git a/config/www/user/plugins/admin/themes/grav/templates/partials/nav-quick-tray.html.twig b/config/www/user/plugins/admin/themes/grav/templates/partials/nav-quick-tray.html.twig
new file mode 100644
index 0000000..d78e3b4
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/partials/nav-quick-tray.html.twig
@@ -0,0 +1,47 @@
+{% set clear_cache_url = base_url_relative ~ '/cache.json/task' ~ config.system.param_sep ~ 'clearCache'|e('html_attr') %}
+
+ {% if authorize(['admin.maintenance', 'admin.super', 'admin.cache']) %}
+
+
+
+
+
+ {% endif %}
+ {% if authorize(['admin.super']) and config.plugins.admin.whitelabel.quicktray_recompile %}
+
+
+
+
+
+ {% endif %}
+ {% if grav.twig.plugins_quick_tray %}
+ {% for label, item in grav.twig.plugins_quick_tray %}
+ {% if authorize((item.authorize is defined and item.authorize is iterable) ? item.authorize : [item.authorize ?: ('admin.' ~ (item.location ?: item.route)), 'admin.super']) %}
+ {% set data_tags = '' %}
+ {% if (item.data) %}
+ {% for key, value in item.data %}
+ {% set data_tags = data_tags ~ ' data-' ~ key ~ '="' ~ value ~ '"' %}
+ {% endfor %}
+ {% endif %}
+
+ {% if item.route %}
+
+
+
+ {% else %}
+
+ {% endif %}
+
+ {% endif %}
+ {% endfor %}
+ {% else %}
+ {% if authorize(['admin.maintenance', 'admin.super']) %}
+
+
+
+
+
+ {% endif %}
+ {% endif %}
+
+
diff --git a/config/www/user/plugins/admin/themes/grav/templates/partials/nav-toggle.html.twig b/config/www/user/plugins/admin/themes/grav/templates/partials/nav-toggle.html.twig
new file mode 100644
index 0000000..b041d3a
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/partials/nav-toggle.html.twig
@@ -0,0 +1,3 @@
+
+
+
diff --git a/config/www/user/plugins/admin/themes/grav/templates/partials/nav-user-avatar.html.twig b/config/www/user/plugins/admin/themes/grav/templates/partials/nav-user-avatar.html.twig
new file mode 100644
index 0000000..3350a05
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/partials/nav-user-avatar.html.twig
@@ -0,0 +1,2 @@
+{% set user_avatar = admin.user.getAvatarUrl() %}
+
diff --git a/config/www/user/plugins/admin/themes/grav/templates/partials/nav-user-details.html.twig b/config/www/user/plugins/admin/themes/grav/templates/partials/nav-user-details.html.twig
new file mode 100644
index 0000000..cfeefb7
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/partials/nav-user-details.html.twig
@@ -0,0 +1,21 @@
+
+ You are offline
+
+{% set flex = grav['flex_objects'] ?? null %}
+{% set user = admin.user %}
+{% if flex and user.hasFlexFeature('user') %}
+ {% set route = flex.adminRoute(user) %}
+{% else %}
+ {% set route = '/user/' ~ user.username %}
+{% endif %}
+
+
diff --git a/config/www/user/plugins/admin/themes/grav/templates/partials/nav.html.twig b/config/www/user/plugins/admin/themes/grav/templates/partials/nav.html.twig
new file mode 100644
index 0000000..bb5c785
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/partials/nav.html.twig
@@ -0,0 +1,47 @@
+{% set nav_hover = config.plugins.admin.sidebar.activate == 'hover' %}
+{% if authorize(['admin.login', 'admin.super']) %}
+
+{% endif %}
diff --git a/config/www/user/plugins/admin/themes/grav/templates/partials/notification-dashboard-block.html.twig b/config/www/user/plugins/admin/themes/grav/templates/partials/notification-dashboard-block.html.twig
new file mode 100644
index 0000000..9bd8f45
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/partials/notification-dashboard-block.html.twig
@@ -0,0 +1,6 @@
+{% for entry_id, entry in notifications %}
+
+
+ {{ entry.message|raw }}
+
+{% endfor %}
diff --git a/config/www/user/plugins/admin/themes/grav/templates/partials/notification-feed-block.html.twig b/config/www/user/plugins/admin/themes/grav/templates/partials/notification-feed-block.html.twig
new file mode 100644
index 0000000..44cf157
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/partials/notification-feed-block.html.twig
@@ -0,0 +1,3 @@
+{% for entry in notifications %}
+{{ entry.type|capitalize }} {{ entry.message|raw }}
+{% endfor %}
diff --git a/config/www/user/plugins/admin/themes/grav/templates/partials/notification-plugins-block.html.twig b/config/www/user/plugins/admin/themes/grav/templates/partials/notification-plugins-block.html.twig
new file mode 100644
index 0000000..d821b50
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/partials/notification-plugins-block.html.twig
@@ -0,0 +1,6 @@
+{% for entry_id, entry in notifications %}
+
+
+ {{ entry.message|raw }}
+
+{% endfor %}
diff --git a/config/www/user/plugins/admin/themes/grav/templates/partials/notification-themes-block.html.twig b/config/www/user/plugins/admin/themes/grav/templates/partials/notification-themes-block.html.twig
new file mode 100644
index 0000000..44532df
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/partials/notification-themes-block.html.twig
@@ -0,0 +1,6 @@
+{% for entry_id, entry in notifications %}
+
+
+ {{ entry.message|raw }}
+
+{% endfor %}
diff --git a/config/www/user/plugins/admin/themes/grav/templates/partials/notification-top-block.html.twig b/config/www/user/plugins/admin/themes/grav/templates/partials/notification-top-block.html.twig
new file mode 100644
index 0000000..2a7fcd4
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/partials/notification-top-block.html.twig
@@ -0,0 +1,6 @@
+{% for entry_id, entry in notifications %}
+
+
+ {{ entry.message|raw }}
+
+{% endfor %}
diff --git a/config/www/user/plugins/admin/themes/grav/templates/partials/page-children.html.twig b/config/www/user/plugins/admin/themes/grav/templates/partials/page-children.html.twig
new file mode 100644
index 0000000..d6f2709
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/partials/page-children.html.twig
@@ -0,0 +1,11 @@
+
+
diff --git a/config/www/user/plugins/admin/themes/grav/templates/partials/page-legend.html.twig b/config/www/user/plugins/admin/themes/grav/templates/partials/page-legend.html.twig
new file mode 100644
index 0000000..04944e7
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/partials/page-legend.html.twig
@@ -0,0 +1,11 @@
+{% set legend = {'VISIBLE':'', 'NON_ROUTABLE':'not-routable', 'NON_VISIBLE':'not-visible', 'MODULE':'module'} %}
+
+
{{ 'PLUGIN_ADMIN.LEGEND'|t }}:
+
+ {% for key, class in legend %}
+ {{ ('PLUGIN_ADMIN.'~key)|t }}
+ {% endfor %}
+
+
+
+
diff --git a/config/www/user/plugins/admin/themes/grav/templates/partials/page-move.html.twig b/config/www/user/plugins/admin/themes/grav/templates/partials/page-move.html.twig
new file mode 100644
index 0000000..ff6347c
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/partials/page-move.html.twig
@@ -0,0 +1,21 @@
+{% set form_id = form_id ? form_id : 'page-move' %}
+{% set scope = scope ?: 'data.' %}
+{% set field_layout = 'admin' %}
+
+
diff --git a/config/www/user/plugins/admin/themes/grav/templates/partials/plugin-data.html.twig b/config/www/user/plugins/admin/themes/grav/templates/partials/plugin-data.html.twig
new file mode 100644
index 0000000..435b067
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/partials/plugin-data.html.twig
@@ -0,0 +1,74 @@
+
+ {% if plugin.author %}
+
+ {{ "PLUGIN_ADMIN.AUTHOR"|t }}:
+
+ {% if plugin.author.url %}
+ {{ plugin.author.name }}
+ {% else %}
+ {{ plugin.author.name }}
+ {% endif %}
+ {% if plugin.author.email %}
+ - {{ plugin.author.email }}
+ {% endif %}
+
+
+ {% endif %}
+ {% if plugin.homepage %}
+
+ {{ "PLUGIN_ADMIN.HOMEPAGE"|t }}:
+ {{ plugin.homepage }}
+
+ {% endif %}
+ {% if plugin.demo %}
+
+ {{ "PLUGIN_ADMIN.DEMO"|t }}:
+ {{ plugin.demo }}
+
+ {% endif %}
+ {% if plugin.bugs %}
+
+ {{ "PLUGIN_ADMIN.BUG_TRACKER"|t }}:
+ {{ plugin.bugs }}
+
+ {% endif %}
+ {% if plugin.keywords %}
+
+ {{ "PLUGIN_ADMIN.KEYWORDS"|t }}:
+ {{ plugin.keywords|join(', ') }}
+
+ {% endif %}
+ {% if plugin.license %}
+
+ {{ "PLUGIN_ADMIN.LICENSE"|t }}:
+ {% if plugin.license|starts_with('http') %}
+ {{ plugin.license }}
+ {% else %}
+ {{ plugin.license }}
+ {% endif %}
+
+ {% endif %}
+
+ {% if plugin.description %}
+
+ {{ "PLUGIN_ADMIN.DESCRIPTION"|t }}:
+ {{ plugin.description_html|raw }}
+
+ {% endif %}
+
+ {% if plugin.readme or plugin.homepage %}
+ {% set readme_link = plugin.readme ?: plugin.docs|default(plugin.homepage ~ '/blob/master/README.md') %}
+
+ {{ plugin.readme ? "PLUGIN_ADMIN.README"|t : "PLUGIN_ADMIN.DOCS"|t }}:
+ {{ readme_link }}
+
+ {% endif %}
+
+ {% if admin.gpm.findPackage(plugin.slug, true).changelog %}
+
+ {{ "PLUGIN_ADMIN.CHANGELOG"|t }}:
+ View Changelog
+
+ {% endif %}
+
+
diff --git a/config/www/user/plugins/admin/themes/grav/templates/partials/plugins-details.html.twig b/config/www/user/plugins/admin/themes/grav/templates/partials/plugins-details.html.twig
new file mode 100644
index 0000000..46ea88e
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/partials/plugins-details.html.twig
@@ -0,0 +1,76 @@
+{% set gpm = admin.gpm() %}
+{% set installed = gpm.isPluginInstalled(admin.route) %}
+{% set isTestingRelease = gpm.isTestingRelease(plugin.slug) %}
+{% set gumroad_loaded = false %}
+
+
+
+
+
+ {{ plugin.name }}
+ {% if admin.isTeamGrav(plugin) %}
+
+ {% endif %}
+ {% if admin.isPremiumProduct(plugin) %}
+ {{ "PLUGIN_ADMIN.PREMIUM_PRODUCT"|t }}
+ {% endif %}
+ {% if plugin.symlink %}
+
+
+
+ {% endif %}
+ {{ plugin.version ? 'v' ~ plugin.version }}
+ {% if isTestingRelease %}test release {% endif %}
+
+
+
+ {% include 'partials/plugin-data.html.twig' with { plugin: plugin } %}
+
+
+{% if (installed) %}
+ {% set data = admin.data('plugins/' ~ admin.route) %}
+ {% if data.get('enabled') %}
+ {% include 'partials/blueprints.html.twig' with { data: data, blueprints: data.blueprints } %}
+ {% else %}
+
+ {% endif %}
+ {% if (plugin.form.fields.enabled.type != 'hidden' and plugin.form.fields.tabs.fields.login.fields.enabled.type != 'hidden') %}
+
+ {% endif %}
+{% else %}
+
+{% 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 } %}
+{% include 'partials/modal-changelog.html.twig' with { package: plugin} %}
diff --git a/config/www/user/plugins/admin/themes/grav/templates/partials/plugins-list.html.twig b/config/www/user/plugins/admin/themes/grav/templates/partials/plugins-list.html.twig
new file mode 100644
index 0000000..f17782c
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/partials/plugins-list.html.twig
@@ -0,0 +1,76 @@
+{% 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"|t : "PLUGIN_ADMIN.INSTALLED_PLUGINS"|t }}
+
+
+
+
+ {% for slug, plugin in admin.plugins(not installing).toArray|ksort %}
+ {% set data = admin.data('plugins/' ~ slug) %}
+ {% set isTestingRelease = admin.gpm.isTestingRelease(slug) %}
+ {% set isPremium = admin.isPremiumProduct(plugin) %}
+ {% set releaseDate = plugin.date ?: admin.gpm.findPackage(slug, true).date %}
+
+
+
+
+ {{ plugin.name }}
+ {% if admin.isTeamGrav(plugin) %}
+
+ {% endif %}
+ {% if isPremium %}
+ {% if not gumroad_loaded %}
+ {% set gumroad_loaded = true %}
+
+ {% endif %}
+ {{ "PLUGIN_ADMIN.PREMIUM_PRODUCT"|t }}
+ {% 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.options.fields.enabled.type != 'hidden')) %}
+
+
+
+ {% elseif (installing) %}
+ {% if (plugin.premium and not admin.license(plugin.slug)) %}
+ {% if not gumroad_loaded %}
+ {% set gumroad_loaded = true %}
+
+ {% endif %}
+ {{ plugin.premium.button|default('Purchase') }}
+ {% else %}
+ {{ "PLUGIN_ADMIN.INSTALL"|t }}
+ {% endif %}
+ {% endif %}
+
+
+
+
+ {% include 'partials/plugin-data.html.twig' with { plugin: plugin } %}
+
+
+
+ {% else %}
+ {{ "PLUGIN_ADMIN.OFFLINE_WARNING"|t }}
+ {% endfor %}
+
+
+{% include 'partials/modal-add-package.html.twig' with { type: 'plugin' } %}
+{% include 'partials/modal-update-packages.html.twig' with { type: 'plugin' } %}
+{% include 'partials/modal-changelog.html.twig' with { package: plugin} %}
diff --git a/config/www/user/plugins/admin/themes/grav/templates/partials/register.html.twig b/config/www/user/plugins/admin/themes/grav/templates/partials/register.html.twig
new file mode 100644
index 0000000..da9173c
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/partials/register.html.twig
@@ -0,0 +1,24 @@
+{% extends 'partials/base.html.twig' %}
+{% set scope = form.scope %}
+{% set field_layout = 'admin' %}
+
+{% block body %}
+
+
+ {% include 'partials/login-logo.html.twig' %}
+
+ {% include 'partials/messages.html.twig' %}
+
+ {% block instructions %}{% endblock %}
+
+
+
+
+{% endblock %}
diff --git a/config/www/user/plugins/admin/themes/grav/templates/partials/release-toggle.html.twig b/config/www/user/plugins/admin/themes/grav/templates/partials/release-toggle.html.twig
new file mode 100644
index 0000000..2f3c300
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/partials/release-toggle.html.twig
@@ -0,0 +1,11 @@
+{% if authorize(['admin.super']) %}
+
+{% endif %}
diff --git a/config/www/user/plugins/admin/themes/grav/templates/partials/spinning-wheel.html.twig b/config/www/user/plugins/admin/themes/grav/templates/partials/spinning-wheel.html.twig
new file mode 100644
index 0000000..d622905
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/partials/spinning-wheel.html.twig
@@ -0,0 +1,3 @@
+
+ {{ "PLUGIN_ADMIN.LOADING"|t }}
+
diff --git a/config/www/user/plugins/admin/themes/grav/templates/partials/stylesheets.html.twig b/config/www/user/plugins/admin/themes/grav/templates/partials/stylesheets.html.twig
new file mode 100644
index 0000000..c155faf
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/partials/stylesheets.html.twig
@@ -0,0 +1,17 @@
+{% do assets.addCss(theme_url~'/css-compiled/nucleus.css', {priority: 20}) %}
+{% do assets.addCss(theme_url~'/css-compiled/template.css', {priority: 20}) %}
+{% do assets.addCss('asset://admin-preset.css', {priority: 5}) %}
+{% do assets.addCss(theme_url~'/css-compiled/simple-fonts.css') %}
+{% do assets.addCss(theme_url~'/css/fontawesome7.min.css') %}
+{% do assets.addCss(theme_url~'/css/fork-awesome-shim.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 %}
+{% if language_codes.rtl(grav.user.language) %}
+ {% do assets.addCss(theme_url~'/css/rtl.css') %}
+{% endif %}
diff --git a/config/www/user/plugins/admin/themes/grav/templates/partials/theme.html.twig b/config/www/user/plugins/admin/themes/grav/templates/partials/theme.html.twig
new file mode 100644
index 0000000..f298c87
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/partials/theme.html.twig
@@ -0,0 +1,13 @@
+{% set theme = admin.themes[admin.route] %}
+{% set blueprints = theme.blueprints() %}
+
+
+ {{ blueprints.get('name') }}
+ {{ blueprints.get('version') ? 'v' ~ blueprints.get('version') }}
+
+
+{% include 'partials/messages.html.twig' %}
+
+{{ blueprints.get('description') }}
+
+{% include 'partials/blueprints.html.twig' with { data: theme } %}
diff --git a/config/www/user/plugins/admin/themes/grav/templates/partials/themes-details.html.twig b/config/www/user/plugins/admin/themes/grav/templates/partials/themes-details.html.twig
new file mode 100644
index 0000000..afd9d56
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/partials/themes-details.html.twig
@@ -0,0 +1,161 @@
+{% set gpm = admin.gpm() %}
+{% set installed = gpm.isThemeInstalled(admin.route) %}
+{% set isTestingRelease = gpm.isTestingRelease(theme.slug) %}
+{% set gumroad_loaded = false %}
+
+{% set state = 'inactive' %}
+{% if (config.get('system.pages.theme') == theme.slug) %}{% set state = 'active' %}{% endif %}
+
+
+
+
+
+ {{ theme.name }}
+ {% if admin.isTeamGrav(theme) %}
+
+ {% endif %}
+ {% if admin.isPremiumProduct(theme) %}
+ {{ "PLUGIN_ADMIN.PREMIUM_PRODUCT"|t }}
+ {% endif %}
+ {% if theme.symlink %}
+
+
+
+ {% endif %}
+ {{ theme.version ? 'v' ~ theme.version }}
+ {% if isTestingRelease %}test release {% endif %}
+
+
+
+
+ {% if theme.version %}
+
+ {{ "PLUGIN_ADMIN.VERSION"|t }}:
+ {{ theme.version }}
+
+ {% endif %}
+ {% if theme.author %}
+
+ {{ "PLUGIN_ADMIN.AUTHOR"|t }}:
+
+ {% if theme.author.url %}
+ {{ theme.author.name }}
+ {% else %}
+ {{ theme.author.name }}
+ {% endif %}
+ {% if theme.author.email %}
+ - {{ theme.author.email }}
+ {% endif %}
+
+
+ {% endif %}
+ {% if theme.homepage %}
+
+ {{ "PLUGIN_ADMIN.HOMEPAGE"|t }}:
+ {{ theme.homepage }}
+
+ {% endif %}
+ {% if theme.demo %}
+
+ {{ "PLUGIN_ADMIN.DEMO"|t }}:
+ {{ theme.demo }}
+
+ {% endif %}
+ {% if theme.bugs %}
+
+ {{ "PLUGIN_ADMIN.BUG_TRACKER"|t }}:
+ {{ theme.bugs }}
+
+ {% endif %}
+ {% if theme.keywords %}
+
+ {{ "PLUGIN_ADMIN.KEYWORDS"|t }}:
+
+ {{ theme.keywords|join(', ') }}
+
+
+ {% endif %}
+ {% if theme.license %}
+
+ {{ "PLUGIN_ADMIN.LICENSE"|t }}:
+ {% if theme.license|starts_with('http') %}
+ {{ theme.license }}
+ {% else %}
+ {{ theme.license }}
+ {% endif %}
+
+ {% endif %}
+ {% if theme.description %}
+
+ {{ "PLUGIN_ADMIN.DESCRIPTION"|t }}:
+ {{ theme.description_html|raw }}
+
+ {% endif %}
+
+ {% if theme.readme or theme.homepage %}
+ {% set readme_link = theme.readme ?: theme.docs|default(theme.homepage ~ '/blob/master/README.md') %}
+
+ {{ theme.readme ? "PLUGIN_ADMIN.README"|t : "PLUGIN_ADMIN.DOCS"|t }}:
+ {{ readme_link }}
+
+ {% endif %}
+
+ {% if admin.gpm.findPackage(theme.slug, true).changelog %}
+
+ {{ "PLUGIN_ADMIN.CHANGELOG"|t }}:
+ View Changelog
+
+ {% endif %}
+
+
+
+{% if installed %}
+ {% if state == 'active' %}
+ {% set data = admin.data('themes/' ~ admin.route) %}
+ {% include 'partials/blueprints.html.twig' with { data: data, blueprints: data.blueprints } %}
+ {% else %}
+
+
+
+ {% endif %}
+{% else %}
+
+{% endif %}
+
+{% include 'partials/modal-switch-theme.html.twig' with {theme_name: theme.name} %}
+{% include 'partials/modal-changes-detected.html.twig' %}
+{% include 'partials/modal-add-package.html.twig' with { type: 'theme' } %}
+{% include 'partials/modal-update-packages.html.twig' with { type: 'theme' } %}
+{% include 'partials/modal-remove-package.html.twig' with { type: 'theme', package: theme } %}
+{% include 'partials/modal-reinstall-package.html.twig' with { type: 'theme', package: theme } %}
+{% include 'partials/modal-changelog.html.twig' with { package: theme} %}
diff --git a/config/www/user/plugins/admin/themes/grav/templates/partials/themes-list.html.twig b/config/www/user/plugins/admin/themes/grav/templates/partials/themes-list.html.twig
new file mode 100644
index 0000000..ea1b3c8
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/partials/themes-list.html.twig
@@ -0,0 +1,81 @@
+{% set gumroad_loaded = false %}
+
+{% if installing %}
+ {% include 'partials/release-toggle.html.twig' %}
+{% endif %}
+{% include 'partials/list-sort.html.twig' with { list_view: 'themes' } %}
+
+ {{ installing ? "PLUGIN_ADMIN.AVAILABLE_THEMES"|t : "PLUGIN_ADMIN.INSTALLED_THEMES"|t }}
+
+
+
+
+ {% 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 isPremium = admin.isPremiumProduct(theme) %}
+ {% set releaseDate = theme.date ?: admin.gpm.findPackage(slug, true).date %}
+
+
+
+
+
{{ theme.name }}
+ {% if admin.isTeamGrav(theme) %}
+
+ {% endif %}
+ {% if isPremium %}
+ {% if not gumroad_loaded %}
+ {% set gumroad_loaded = true %}
+
+ {% endif %}
+
{{ "PLUGIN_ADMIN.PREMIUM_PRODUCT"|t }}
+ {% 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"|t }}
+
+ {% else %}
+
+ {{ "PLUGIN_ADMIN.ACTIVATE"|t }}
+
+ {% endif %}
+
+ {% else %}
+
{{ "PLUGIN_ADMIN.OFFLINE_WARNING"|t }}
+ {% endfor %}
+
+
+{% include 'partials/modal-switch-theme.html.twig' %}
+{% include 'partials/modal-add-package.html.twig' with { type: 'theme' } %}
+{% include 'partials/modal-update-packages.html.twig' with { type: 'theme' } %}
diff --git a/config/www/user/plugins/admin/themes/grav/templates/partials/tools-backups-titlebar.html.twig b/config/www/user/plugins/admin/themes/grav/templates/partials/tools-backups-titlebar.html.twig
new file mode 100644
index 0000000..1c218e6
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/partials/tools-backups-titlebar.html.twig
@@ -0,0 +1,7 @@
+
+ {{ "PLUGIN_ADMIN.TOOLS"|t }} - {{ "PLUGIN_ADMIN.BACKUPS"|t }}
+
diff --git a/config/www/user/plugins/admin/themes/grav/templates/partials/tools-backups.html.twig b/config/www/user/plugins/admin/themes/grav/templates/partials/tools-backups.html.twig
new file mode 100644
index 0000000..06eb459
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/partials/tools-backups.html.twig
@@ -0,0 +1,81 @@
+
+
+ {% set data = admin.data('config/backups') %}
+ {% set backups = grav.backups.getAvailableBackups() %}
+ {% set profiles = grav.backups.getBackupProfiles() %}
+ {% set purge_config = grav.backups.getPurgeConfig() %}
+ {% set newest_date = (backups|first).date %}
+ {% set newest_backup = newest_date ? newest_date|nicetime(false, false) : 'none' %}
+ {% set oldest_date = (backups|last).date %}
+ {% set oldest_backup = oldest_date ? oldest_date|nicetime(false, false) : 'none' %}
+
+ {% switch purge_config.trigger %}
+ {% case 'number' %}
+ {% set count = backups|count %}
+ {% set max_backups = purge_config.max_backups_count %}
+ {% if max_backups > 0 %}
+ {% set percent_used = count == 0 ? 0 : 100 - (count / max_backups * 100) %}
+ {% else %}
+ {% set percent_used = 100 %}
+ {% endif %}
+ {% set bar_msg = "PLUGIN_ADMIN.BACKUPS_PURGE_NUMBER"|t(count, purge_config.max_backups_count) %}
+ {% case 'time' %}
+ {% set last = backups|last %}
+ {% set days = last == null ? 0 : (date('now')).diff(last.time).days %}
+ {% set percent_used = days == 0 ? 0 : 100 - (days / purge_config.max_backups_time * 100) %}
+ {% set bar_msg = "PLUGIN_ADMIN.BACKUPS_PURGE_TIME"|t(purge_config.max_backups_time - days) %}
+ {% default %}
+ {% set space_used = grav.backups.getTotalBackupsSize() %}
+ {% set space_available = purge_config.max_backups_space * 1024 * 1024 * 1024 %}
+ {% set percent_used = space_used == 0 ? 0 : 100 - (space_used / space_available * 100) %}
+ {% set bar_msg = "PLUGIN_ADMIN.BACKUPS_PURGE_SPACE"|t(space_used|nicefilesize, space_available|nicefilesize) %}
+ {% endswitch %}
+
+
+
+
+
{{ "PLUGIN_ADMIN.BACKUPS_STATS"|t }}
+
+
+
+
+
+ {% if percent_used >= 100 %}
+
+ {% else %}
+
+ {% endif %}
+
+
{{ bar_msg }}
+
+
+
+
+
+ {{ backups|length }}
+ {{ "PLUGIN_ADMIN.BACKUPS_COUNT"|t }}
+
+
+ {{ profiles|count }}
+ {{ "PLUGIN_ADMIN.BACKUPS_PROFILES_COUNT"|t }}
+
+
+ {{ newest_backup }}
+ {{ "PLUGIN_ADMIN.BACKUPS_NEWEST"|t }}
+
+
+ {{ oldest_backup }}
+ {{ "PLUGIN_ADMIN.BACKUPS_OLDEST"|t }}
+
+
+
+
+
+
+
+ {% include 'partials/blueprints.html.twig' with { blueprints: data.blueprints, data: data } %}
+
+ {% include 'partials/modal-changes-detected.html.twig' %}
+
+
+
diff --git a/config/www/user/plugins/admin/themes/grav/templates/partials/tools-direct-install.html.twig b/config/www/user/plugins/admin/themes/grav/templates/partials/tools-direct-install.html.twig
new file mode 100644
index 0000000..9b2f8df
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/partials/tools-direct-install.html.twig
@@ -0,0 +1,29 @@
+{{ "PLUGIN_ADMIN.TOOLS_DIRECT_INSTALL_TITLE"|t }}
+
+
+
+
{{ "PLUGIN_ADMIN.TOOLS_DIRECT_INSTALL_UPLOAD_TITLE"|t }}
+
{{ "PLUGIN_ADMIN.TOOLS_DIRECT_INSTALL_UPLOAD_DESC"|t|raw }}
+
+
+
+
+
{{ "PLUGIN_ADMIN.TOOLS_DIRECT_INSTALL_URL_TITLE"|t }}
+
{{ "PLUGIN_ADMIN.TOOLS_DIRECT_INSTALL_URL_DESC"|t|raw }}
+
+
+
+
+
diff --git a/config/www/user/plugins/admin/themes/grav/templates/partials/tools-logs.html.twig b/config/www/user/plugins/admin/themes/grav/templates/partials/tools-logs.html.twig
new file mode 100644
index 0000000..70b9f98
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/partials/tools-logs.html.twig
@@ -0,0 +1,80 @@
+
+
+ {% macro render_select(name, options, selected, autokey=false) %}
+
+
+ {% for key,option in options %}
+ {% if autokey %}
+ {% set key = key|of_type('int') ? option|lower : key %}
+ {% endif %}
+ {{ option|titleize }}
+ {% endfor %}
+
+
+ {% endmacro %}
+
+ {% import _self as macro %}
+
+ {% set file = grav.uri.query('log') ?: 'grav.log' %}
+ {% set verbose = grav.uri.query('verbose') == 'true' ? true : false %}
+ {% set lines = grav.uri.query('lines') ?: 20 %}
+ {% set logfile = grav.locator.findResource("log://" ~ file) %}
+ {% set logs = logfile ? logviewer.objectTail(logfile, lines|int, false) : [] %}
+ {% set log_files = admin.getLogFiles() %}
+ {% set title = log_files[file] %}
+
+
+
+
+
+
{{ title }} Output
+
Display the {{ lines }} most recent entries...
+
+
+
+ Date
+ Level
+ Message
+
+
+
+ {% for log in logs %}
+
+ {{ log.date|date }}
+ {{ log.level }}
+ {{ log.message }}
+ {% if verbose %}
+
+
+
+
+
+
+ {% for tracerow in log.trace %}
+ {{ tracerow }}
+ {% endfor %}
+
+
+
+ {% endif %}
+
+ {% endfor %}
+
+
+
+
+
+
diff --git a/config/www/user/plugins/admin/themes/grav/templates/partials/tools-reports.html.twig b/config/www/user/plugins/admin/themes/grav/templates/partials/tools-reports.html.twig
new file mode 100644
index 0000000..32f9cc8
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/partials/tools-reports.html.twig
@@ -0,0 +1,15 @@
+
+
+ {% set reports = admin.generateReports() %}
+
+
+ {% for title, report in reports %}
+
{{ title }}
+ {{ report|raw }}
+ {% endfor %}
+
+
+ {% include 'partials/modal-changes-detected.html.twig' %}
+
+
+
diff --git a/config/www/user/plugins/admin/themes/grav/templates/partials/tools-scheduler-titlebar.html.twig b/config/www/user/plugins/admin/themes/grav/templates/partials/tools-scheduler-titlebar.html.twig
new file mode 100644
index 0000000..9741da4
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/partials/tools-scheduler-titlebar.html.twig
@@ -0,0 +1,6 @@
+
+ {{ "PLUGIN_ADMIN.TOOLS"|t }} - {{ "PLUGIN_ADMIN.SCHEDULER"|t }}
+
diff --git a/config/www/user/plugins/admin/themes/grav/templates/partials/tools-scheduler.html.twig b/config/www/user/plugins/admin/themes/grav/templates/partials/tools-scheduler.html.twig
new file mode 100644
index 0000000..0034383
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/partials/tools-scheduler.html.twig
@@ -0,0 +1,82 @@
+
+
+
+ {% set data = admin.data('config/scheduler') %}
+ {% set cron_status = grav.scheduler.isCrontabSetup() %}
+ {% set user = grav.scheduler.whoami() %}
+ {% set webhook_enabled = grav.scheduler.isWebhookEnabled() %}
+ {% set active_triggers = grav.scheduler.getActiveTriggers() %}
+
+ {% if active_triggers|length > 0 %}
+ {# We have at least one active trigger method #}
+ {% if 'webhook' in active_triggers and 'cron' not in active_triggers %}
+ {# Webhook only mode #}
+
+
{{ "PLUGIN_ADMIN.SCHEDULER_INSTALL_INSTRUCTIONS"|t }}
+
Webhook Active - Scheduler is ready to receive webhook triggers
+
+ {% elseif 'cron' in active_triggers and 'webhook' in active_triggers %}
+ {# Both cron and webhook #}
+
+
{{ "PLUGIN_ADMIN.SCHEDULER_INSTALL_INSTRUCTIONS"|t }}
+
Cron & Webhook Active - Scheduler is running via cron and accepts webhook triggers
+
+ {% elseif 'cron' in active_triggers %}
+ {# Cron only #}
+
+
{{ "PLUGIN_ADMIN.SCHEDULER_INSTALL_INSTRUCTIONS"|t }}
+
{{ "PLUGIN_ADMIN.SCHEDULER_INSTALLED_READY"|t }}
+
+ {% endif %}
+ {% elseif cron_status == 2 %}
+
{{ "PLUGIN_ADMIN.SCHEDULER_CRON_NA"|t([user])|raw }}
+ {% else %}
+
{{ "PLUGIN_ADMIN.SCHEDULER_NOT_ENABLED"|t([user])|raw }}
+ {% endif %}
+
+
{{ "PLUGIN_ADMIN.SCHEDULER_WARNING"|t([user]) }}
+
+
+
+ {% include 'partials/blueprints.html.twig' with { blueprints: data.blueprints, data: data } %}
+
+ {% include 'partials/modal-changes-detected.html.twig' %}
+
+
+
+
diff --git a/config/www/user/plugins/admin/themes/grav/templates/partials/userinfo-avatar-credit.html.twig b/config/www/user/plugins/admin/themes/grav/templates/partials/userinfo-avatar-credit.html.twig
new file mode 100644
index 0000000..f3a944c
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/partials/userinfo-avatar-credit.html.twig
@@ -0,0 +1,10 @@
+
+{{ "PLUGIN_ADMIN.AVATAR_BY"|t }}
+
+{% if config.system.accounts.avatar == 'gravatar' %}
+gravatar.com .
+{% else %}
+Multiavatar .
+{% endif %}
+
+{{ "PLUGIN_ADMIN.AVATAR_UPLOAD_OWN"|t }}
diff --git a/config/www/user/plugins/admin/themes/grav/templates/partials/userinfo-avatar.html.twig b/config/www/user/plugins/admin/themes/grav/templates/partials/userinfo-avatar.html.twig
new file mode 100644
index 0000000..b9d5d9f
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/partials/userinfo-avatar.html.twig
@@ -0,0 +1,2 @@
+{% set user_avatar = data.getAvatarUrl() %}
+
diff --git a/config/www/user/plugins/admin/themes/grav/templates/plugins.html.twig b/config/www/user/plugins/admin/themes/grav/templates/plugins.html.twig
new file mode 100644
index 0000000..468b02f
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/plugins.html.twig
@@ -0,0 +1,94 @@
+{% extends 'partials/base.html.twig' %}
+
+{% set plugin_slug = admin.route %}
+{% set enabled = true %}
+
+{% if plugin_slug %}
+ {% set installing = plugin_slug starts with 'install' %}
+
+ {% if installing %}
+ {% set title = "PLUGIN_ADMIN.PLUGINS"|t %}
+ {% 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"|t ~ ": " ~ plugin.name %}
+ {% set data = admin.data('plugins/' ~ admin.route) %}
+ {% set enabled = data.get('enabled') %}
+ {% endif %}
+{% else %}
+ {% set title = "PLUGIN_ADMIN.PLUGINS"|t %}
+{% 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 %}
+
+ {{ "PLUGIN_ADMIN.PLUGINS"|t }}
+ {% else %}
+ {% if (installed) %}
+
+ {% else %}
+
+ {% endif %}
+
+ {{ "PLUGIN_ADMIN.PLUGIN"|t }}: {{ plugin.name }}
+ {% 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 %}
diff --git a/config/www/user/plugins/admin/themes/grav/templates/plugins/admin-buttons.html.twig b/config/www/user/plugins/admin/themes/grav/templates/plugins/admin-buttons.html.twig
new file mode 100644
index 0000000..e1ff549
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/plugins/admin-buttons.html.twig
@@ -0,0 +1,3 @@
+ {{ "PLUGIN_ADMIN.PREVIEW"|t }}
+ {{ "PLUGIN_ADMIN.RECOMPILE"|t }}
+ {{ "PLUGIN_ADMIN.EXPORT"|t }}
diff --git a/config/www/user/plugins/admin/themes/grav/templates/preview.html.twig b/config/www/user/plugins/admin/themes/grav/templates/preview.html.twig
new file mode 100644
index 0000000..da89144
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/preview.html.twig
@@ -0,0 +1,24 @@
+{% extends 'partials/base.html.twig' %}
+
+{% set route = admin.route == '' ? '/' : '/' ~ admin.route %}
+{% set preview_link = base_url_relative_frontend|rtrim('/') ~ route %}
+{% set preview_html = (base_url|rtrim('/') ~ '/preview' ~ (context.home ? '' : context.route)) ?: '/' %}
+{% set admin_route = '/' ~ admin.route %}
+{% set back_link = base_url|rtrim('/') ~ '/pages' ~ page.find(admin_route).rawRoute() %}
+
+{% block titlebar %}
+
+ {{ "PLUGIN_ADMIN.PREVIEW"|t }}: /{{ admin.route }}
+{% endblock %}
+
+{% block content_wrapper %}
+
+
+{% endblock %}
diff --git a/config/www/user/plugins/admin/themes/grav/templates/register.html.twig b/config/www/user/plugins/admin/themes/grav/templates/register.html.twig
new file mode 100644
index 0000000..ef9ce1a
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/register.html.twig
@@ -0,0 +1,24 @@
+{% embed 'partials/register.html.twig' with {title:'Grav Register Admin User', classes:'wide'} %}
+
+ {% block instructions %}
+
+ {{ page.content|raw }}
+
+ {% endblock %}
+
+ {% block form %}
+ {% embed 'forms/default/fields.html.twig' with {name: null, fields: form.fields} %}
+ {% block inner_markup_field_open %}{% endblock %}
+ {% block inner_markup_field_close %}
{% endblock %}
+ {% endembed %}
+
+
+
+ {{ 'PLUGIN_ADMIN.LOGIN_BTN_CLEAR'|t }}
+ {{ 'PLUGIN_ADMIN.LOGIN_BTN_CREATE_USER'|t }}
+
+
+
+ {% endblock %}
+
+{% endembed %}
diff --git a/config/www/user/plugins/admin/themes/grav/templates/reports/security.html.twig b/config/www/user/plugins/admin/themes/grav/templates/reports/security.html.twig
new file mode 100644
index 0000000..ed75e30
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/reports/security.html.twig
@@ -0,0 +1,20 @@
+{% if result %}
+ Security Scan complete: {{ result|length }} potential XSS issues found...
+
+ {% for route, results in result %}
+
+ {{ route }}
+ {% set results_string = [] %}
+ {% for key, value in results %}
+ {% set results_string = results_string|merge(['' ~ key ~ ' : ' ~ value|titleize ~ ' ']) %}
+ {% endfor %}
+
+ {{ results_string|join(', ')|raw }}
+
+ {% endfor %}
+
+
+{% else %}
+ Security Scan complete: No issues found...
+{% endif %}
+
diff --git a/config/www/user/plugins/admin/themes/grav/templates/reports/yamllinter.html.twig b/config/www/user/plugins/admin/themes/grav/templates/reports/yamllinter.html.twig
new file mode 100644
index 0000000..920db04
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/reports/yamllinter.html.twig
@@ -0,0 +1,31 @@
+{% if result %}
+ YAML Linting: Found {{ result|length }} linting errors
+
+ {% for path, error in result %}
+ {% set page_url = base_url_simple ~ '/' ~ admin_route %}
+ {% set bits = path|pathinfo %}
+ {% if admin.multilang %}
+ {% set lang = (bits.filename|pathinfo).extension %}
+ {% set page_url = base_url_simple ~ '/' ~ lang ~ '/' ~ admin_route %}
+ {% endif %}
+ {% set page_path = base_path ~ bits.dirname %}
+ {% set page = grav.pages.get(page_path) %}
+
+
+ {% if page.url %}
+ {{ page.route }}
+ {% else %}
+ {{ path }}
+ {% endif %}
+ {% if lang %}
+ {{ lang }}
+ {% endif %}
+
+ {{ error }}
+
+ {% endfor %}
+
+{% else %}
+ YAML Linting: No errors found.
+{% endif %}
+
diff --git a/config/www/user/plugins/admin/themes/grav/templates/reset.html.twig b/config/www/user/plugins/admin/themes/grav/templates/reset.html.twig
new file mode 100644
index 0000000..88a067e
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/reset.html.twig
@@ -0,0 +1,14 @@
+{% embed 'partials/login.html.twig' with {title:'Grav Reset Password'} %}
+
+ {% block form %}
+ {% embed 'forms/default/fields.html.twig' with {name: null, fields: form.fields} %}
+ {% block inner_markup_field_open %}{% endblock %}
+ {% block inner_markup_field_close %}
{% endblock %}
+ {% endembed %}
+
+ {{ 'PLUGIN_ADMIN.LOGIN_BTN_RESET'|t }}
+
+ {% endblock %}
+
+{% endembed %}
+
diff --git a/config/www/user/plugins/admin/themes/grav/templates/statistics.html.twig b/config/www/user/plugins/admin/themes/grav/templates/statistics.html.twig
new file mode 100644
index 0000000..20504d0
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/statistics.html.twig
@@ -0,0 +1,15 @@
+{% extends 'partials/base.html.twig' %}
+
+{% block messages %}{% endblock %}
+
+{% block content %}
+
+
+
+ {{ "PLUGIN_ADMIN.VIEWS_STATISTICS"|t }}
+
+
+ {% include 'partials/messages.html.twig' %}
+
+{% endblock %}
+
diff --git a/config/www/user/plugins/admin/themes/grav/templates/themes.html.twig b/config/www/user/plugins/admin/themes/grav/templates/themes.html.twig
new file mode 100644
index 0000000..74b1ce8
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/themes.html.twig
@@ -0,0 +1,87 @@
+{% extends 'partials/base.html.twig' %}
+
+{% if admin.route %}
+ {% set installing = admin.route starts with 'install' %}
+
+ {% if installing %}
+ {% set title = "PLUGIN_ADMIN.THEMES"|t %}
+ {% 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 state = config.get('system.pages.theme') == theme.slug ? 'active' : 'inactive' %}
+
+ {% set title = "PLUGIN_ADMIN.THEME"|t ~ ": " ~ theme.name %}
+ {% endif %}
+{% else %}
+ {% set title = "PLUGIN_ADMIN.THEMES"|t %}
+{% 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 %}
+
+ {{ "PLUGIN_ADMIN.THEMES"|t }}
+ {% else %}
+ {% if (installed) %}
+
+ {% else %}
+
+ {% endif %}
+ {{ "PLUGIN_ADMIN.THEME"|t }}: {{ theme.name }}
+ {% 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 %}
diff --git a/config/www/user/plugins/admin/themes/grav/templates/tools.html.twig b/config/www/user/plugins/admin/themes/grav/templates/tools.html.twig
new file mode 100644
index 0000000..7706707
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/tools.html.twig
@@ -0,0 +1,50 @@
+{% extends 'partials/base.html.twig' %}
+
+{% set tools_slug = uri.basename %}
+{% if tools_slug == 'tools' %}{% set tools_slug = 'backups' %}{% endif %}
+{% set title = "PLUGIN_ADMIN.TOOLS"|t ~ ": " ~ ("PLUGIN_ADMIN." ~ tools_slug|underscorize|upper)|t %}
+{% set tools = admin.tools() %}
+
+{% set titlebar -%}
+ {% include 'partials/tools-' ~ tools_slug ~ '-titlebar.html.twig' ignore missing %}
+{%- endset %}
+
+{% block titlebar %}
+ {% if titlebar %}
+ {{ titlebar }}
+ {% else %}
+
+ {{ "PLUGIN_ADMIN.TOOLS"|t }} - {{ ("PLUGIN_ADMIN." ~ tools_slug|underscorize|upper)|t }}
+ {% endif %}
+{% endblock %}
+
+{% block content_top %}
+ {% if tools|length > 1 %}
+
+ {% endif %}
+{% endblock %}
+
+{% block content %}
+ {% set perms = tools[tools_slug]|first %}
+
+ {% if authorize(perms) %}
+ {% include 'partials/tools-' ~ tools_slug ~ '.html.twig' ignore missing %}
+ {% else %}
+ Unauthorized
+ {% endif %}
+{% endblock %}
+
diff --git a/config/www/user/plugins/admin/themes/grav/templates/unauthorized.html.twig b/config/www/user/plugins/admin/themes/grav/templates/unauthorized.html.twig
new file mode 100644
index 0000000..0867b99
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/unauthorized.html.twig
@@ -0,0 +1 @@
+{% extends 'partials/base.html.twig' %}
\ No newline at end of file
diff --git a/config/www/user/plugins/admin/themes/grav/templates/user.html.twig b/config/www/user/plugins/admin/themes/grav/templates/user.html.twig
new file mode 100644
index 0000000..7cb5aae
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/templates/user.html.twig
@@ -0,0 +1,63 @@
+{% extends 'partials/base.html.twig' %}
+
+{% if admin.route %}
+ {% set user = admin.data('users/' ~ admin.route) %}
+ {% set title = "PLUGIN_ADMIN.USER"|t ~ ": " ~ admin.route|e %}
+{% else %}
+ {% set title = "PLUGIN_ADMIN_PRO.USERS"|t %}
+{% endif %}
+
+{% block titlebar %}
+ {% if not admin.route %}
+ {% if authorize(['admin.users', 'admin.super']) %}
+
+ {{ "PLUGIN_ADMIN.USERS"|t }}
+ {% else %}
+ {{ "PLUGIN_ADMIN.ACCESS_DENIED"|t }}
+ {% endif %}
+ {% else %}
+ {% if authorize(['admin.users', 'admin.super']) or grav.user.username == user.username %}
+
+ {{ "PLUGIN_ADMIN.USER"|t }}: {{ user.username }}
+ {% else %}
+ {{ "PLUGIN_ADMIN.ACCESS_DENIED"|t }}
+ {% 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 %}
+
+
+
+ {% endif %}
+{% endblock %}
diff --git a/config/www/user/plugins/admin/themes/grav/test-icons.html b/config/www/user/plugins/admin/themes/grav/test-icons.html
new file mode 100644
index 0000000..4f64ad4
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/test-icons.html
@@ -0,0 +1,40 @@
+
+
+
+
+ Icon Test
+
+
+
+
+
+ FontAwesome 7 Icon Test
+
+
+
Testing fa-sign-out with ForkAwesome shim:
+ - Should show logout icon
+
+
+
+
Testing fa-list-ol with ForkAwesome shim:
+ - Should show ordered list icon
+
+
+
+
Testing native FontAwesome 7 classes:
+ - Native FA7 logout icon (solid)
+ - Native FA7 list icon (solid)
+ - Alternative logout icon
+
+
+
+
Testing with different font weights:
+ - Force 900 weight
+ - Force 400 weight
+
+
+
\ No newline at end of file
diff --git a/user/accounts/.gitkeep b/config/www/user/plugins/admin/themes/grav/theme.yaml
similarity index 100%
rename from user/accounts/.gitkeep
rename to config/www/user/plugins/admin/themes/grav/theme.yaml
diff --git a/config/www/user/plugins/admin/themes/grav/watch.sh b/config/www/user/plugins/admin/themes/grav/watch.sh
new file mode 100755
index 0000000..de3654d
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/watch.sh
@@ -0,0 +1,27 @@
+#!/bin/sh
+
+#
+# Configuration
+#
+
+# sass source
+
+SASS_SOURCE_PATH="scss"
+
+# sass options
+SASS_OPTIONS="--source-map=true --style=nested"
+
+# css target
+CSS_TARGET_PATH="css-compiled"
+
+#
+# Check prerequisites
+#
+wtfile=$(command -v wt) || { echo "install wellington with 'brew install wellington"; exit 1; }
+
+#
+# Watch folder for changes
+#
+cd -P `pwd`
+$wtfile compile "$SASS_SOURCE_PATH" -b "$CSS_TARGET_PATH" $SASS_OPTIONS
+$wtfile watch "$SASS_SOURCE_PATH" -b "$CSS_TARGET_PATH" $SASS_OPTIONS
diff --git a/config/www/user/plugins/admin/themes/grav/webfonts/fa-brands-400.woff2 b/config/www/user/plugins/admin/themes/grav/webfonts/fa-brands-400.woff2
new file mode 100644
index 0000000..4bb9e62
Binary files /dev/null and b/config/www/user/plugins/admin/themes/grav/webfonts/fa-brands-400.woff2 differ
diff --git a/config/www/user/plugins/admin/themes/grav/webfonts/fa-regular-400.woff2 b/config/www/user/plugins/admin/themes/grav/webfonts/fa-regular-400.woff2
new file mode 100644
index 0000000..644a834
Binary files /dev/null and b/config/www/user/plugins/admin/themes/grav/webfonts/fa-regular-400.woff2 differ
diff --git a/config/www/user/plugins/admin/themes/grav/webfonts/fa-solid-900.woff2 b/config/www/user/plugins/admin/themes/grav/webfonts/fa-solid-900.woff2
new file mode 100644
index 0000000..6b79def
Binary files /dev/null and b/config/www/user/plugins/admin/themes/grav/webfonts/fa-solid-900.woff2 differ
diff --git a/config/www/user/plugins/admin/themes/grav/webfonts/fa-v4compatibility.woff2 b/config/www/user/plugins/admin/themes/grav/webfonts/fa-v4compatibility.woff2
new file mode 100644
index 0000000..c5eb335
Binary files /dev/null and b/config/www/user/plugins/admin/themes/grav/webfonts/fa-v4compatibility.woff2 differ
diff --git a/config/www/user/plugins/admin/themes/grav/webpack.conf.js b/config/www/user/plugins/admin/themes/grav/webpack.conf.js
new file mode 100644
index 0000000..cae4d26
--- /dev/null
+++ b/config/www/user/plugins/admin/themes/grav/webpack.conf.js
@@ -0,0 +1,58 @@
+const path = require('path');
+const TerserPlugin = require('terser-webpack-plugin');
+const ESLintPlugin = require('eslint-webpack-plugin');
+
+module.exports = (env, argv) => ({
+ entry: {
+ admin: './app/main.js'
+ },
+ devtool: argv.mode === 'production' ? false : 'eval-source-map',
+ target: 'web',
+ output: {
+ path: path.resolve(__dirname, 'js'),
+ filename: '[name].min.js',
+ chunkFilename: 'vendor.min,js',
+ library: 'Grav'
+ },
+ optimization: {
+ minimize: argv.mode === 'disabled-production',
+ minimizer: [new TerserPlugin()],
+ splitChunks: {
+ cacheGroups: {
+ vendors: {
+ test: /[\\/]node_modules[\\/]/,
+ priority: 1,
+ name: 'vendor',
+ enforce: true,
+ chunks: 'all'
+ }
+ }
+ }
+ },
+ externals: {
+ jquery: 'jQuery',
+ 'grav-config': 'GravAdmin'
+ },
+ plugins: [new ESLintPlugin({
+ extensions: ['js', 'jsx'],
+ exclude: ['/node_modules/']
+ })],
+ module: {
+ rules: [
+ { enforce: 'pre', test: /\.json$/, loader: 'json-loader' },
+ {
+ test: /\.css$/,
+ use: ['style-loader', 'css-loader']
+ },
+ {
+ test: /\.js$/,
+ loader: 'babel-loader',
+ exclude: /node_modules/,
+ options: {
+ presets: ['@babel/preset-env'],
+ plugins: ['@babel/plugin-proposal-object-rest-spread']
+ }
+ }
+ ]
+ }
+});
diff --git a/config/www/user/plugins/admin/twig/AdminTwigExtension.php b/config/www/user/plugins/admin/twig/AdminTwigExtension.php
new file mode 100644
index 0000000..cfa99f5
--- /dev/null
+++ b/config/www/user/plugins/admin/twig/AdminTwigExtension.php
@@ -0,0 +1,7 @@
+realpath = realpath($opened_path) ?: $opened_path;
+ $opened_path = $this->realpath;
+ $this->handle = fopen($this->realpath, $mode);
+ $this->position = 0;
+
+ return (bool) $this->handle;
+ }
+
+ public function stream_read($count)
+ {
+ $data = fread($this->handle, $count);
+
+ if ($this->position === 0) {
+ $data = preg_replace('{^#!.*\r?\n}', '', $data);
+ }
+
+ $this->position += strlen($data);
+
+ return $data;
+ }
+
+ public function stream_cast($castAs)
+ {
+ return $this->handle;
+ }
+
+ public function stream_close()
+ {
+ fclose($this->handle);
+ }
+
+ public function stream_lock($operation)
+ {
+ return $operation ? flock($this->handle, $operation) : true;
+ }
+
+ public function stream_seek($offset, $whence)
+ {
+ if (0 === fseek($this->handle, $offset, $whence)) {
+ $this->position = ftell($this->handle);
+ return true;
+ }
+
+ return false;
+ }
+
+ public function stream_tell()
+ {
+ return $this->position;
+ }
+
+ public function stream_eof()
+ {
+ return feof($this->handle);
+ }
+
+ public function stream_stat()
+ {
+ return array();
+ }
+
+ public function stream_set_option($option, $arg1, $arg2)
+ {
+ return true;
+ }
+
+ public function url_stat($path, $flags)
+ {
+ $path = substr($path, 17);
+ if (file_exists($path)) {
+ return stat($path);
+ }
+
+ return false;
+ }
+ }
+ }
+
+ if (
+ (function_exists('stream_get_wrappers') && in_array('phpvfscomposer', stream_get_wrappers(), true))
+ || (function_exists('stream_wrapper_register') && stream_wrapper_register('phpvfscomposer', 'Composer\BinProxyWrapper'))
+ ) {
+ include("phpvfscomposer://" . __DIR__ . '/..'.'/p3k/picofeed/picofeed');
+ exit(0);
+ }
+}
+
+include __DIR__ . '/..'.'/p3k/picofeed/picofeed';
diff --git a/config/www/user/plugins/admin/vendor/bin/pscss b/config/www/user/plugins/admin/vendor/bin/pscss
new file mode 100755
index 0000000..e57bed8
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/bin/pscss
@@ -0,0 +1,119 @@
+#!/usr/bin/env php
+realpath = realpath($opened_path) ?: $opened_path;
+ $opened_path = $this->realpath;
+ $this->handle = fopen($this->realpath, $mode);
+ $this->position = 0;
+
+ return (bool) $this->handle;
+ }
+
+ public function stream_read($count)
+ {
+ $data = fread($this->handle, $count);
+
+ if ($this->position === 0) {
+ $data = preg_replace('{^#!.*\r?\n}', '', $data);
+ }
+
+ $this->position += strlen($data);
+
+ return $data;
+ }
+
+ public function stream_cast($castAs)
+ {
+ return $this->handle;
+ }
+
+ public function stream_close()
+ {
+ fclose($this->handle);
+ }
+
+ public function stream_lock($operation)
+ {
+ return $operation ? flock($this->handle, $operation) : true;
+ }
+
+ public function stream_seek($offset, $whence)
+ {
+ if (0 === fseek($this->handle, $offset, $whence)) {
+ $this->position = ftell($this->handle);
+ return true;
+ }
+
+ return false;
+ }
+
+ public function stream_tell()
+ {
+ return $this->position;
+ }
+
+ public function stream_eof()
+ {
+ return feof($this->handle);
+ }
+
+ public function stream_stat()
+ {
+ return array();
+ }
+
+ public function stream_set_option($option, $arg1, $arg2)
+ {
+ return true;
+ }
+
+ public function url_stat($path, $flags)
+ {
+ $path = substr($path, 17);
+ if (file_exists($path)) {
+ return stat($path);
+ }
+
+ return false;
+ }
+ }
+ }
+
+ if (
+ (function_exists('stream_get_wrappers') && in_array('phpvfscomposer', stream_get_wrappers(), true))
+ || (function_exists('stream_wrapper_register') && stream_wrapper_register('phpvfscomposer', 'Composer\BinProxyWrapper'))
+ ) {
+ return include("phpvfscomposer://" . __DIR__ . '/..'.'/scssphp/scssphp/bin/pscss');
+ }
+}
+
+return include __DIR__ . '/..'.'/scssphp/scssphp/bin/pscss';
diff --git a/config/www/user/plugins/admin/vendor/composer/ClassLoader.php b/config/www/user/plugins/admin/vendor/composer/ClassLoader.php
new file mode 100644
index 0000000..7824d8f
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/composer/ClassLoader.php
@@ -0,0 +1,579 @@
+
+ * 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 https://www.php-fig.org/psr/psr-0/
+ * @see https://www.php-fig.org/psr/psr-4/
+ */
+class ClassLoader
+{
+ /** @var \Closure(string):void */
+ private static $includeFile;
+
+ /** @var string|null */
+ private $vendorDir;
+
+ // PSR-4
+ /**
+ * @var array>
+ */
+ private $prefixLengthsPsr4 = array();
+ /**
+ * @var array>
+ */
+ private $prefixDirsPsr4 = array();
+ /**
+ * @var list
+ */
+ private $fallbackDirsPsr4 = array();
+
+ // PSR-0
+ /**
+ * List of PSR-0 prefixes
+ *
+ * Structured as array('F (first letter)' => array('Foo\Bar (full prefix)' => array('path', 'path2')))
+ *
+ * @var array>>
+ */
+ private $prefixesPsr0 = array();
+ /**
+ * @var list
+ */
+ private $fallbackDirsPsr0 = array();
+
+ /** @var bool */
+ private $useIncludePath = false;
+
+ /**
+ * @var array
+ */
+ private $classMap = array();
+
+ /** @var bool */
+ private $classMapAuthoritative = false;
+
+ /**
+ * @var array
+ */
+ private $missingClasses = array();
+
+ /** @var string|null */
+ private $apcuPrefix;
+
+ /**
+ * @var array
+ */
+ private static $registeredLoaders = array();
+
+ /**
+ * @param string|null $vendorDir
+ */
+ public function __construct($vendorDir = null)
+ {
+ $this->vendorDir = $vendorDir;
+ self::initializeIncludeClosure();
+ }
+
+ /**
+ * @return array>
+ */
+ public function getPrefixes()
+ {
+ if (!empty($this->prefixesPsr0)) {
+ return call_user_func_array('array_merge', array_values($this->prefixesPsr0));
+ }
+
+ return array();
+ }
+
+ /**
+ * @return array>
+ */
+ public function getPrefixesPsr4()
+ {
+ return $this->prefixDirsPsr4;
+ }
+
+ /**
+ * @return list
+ */
+ public function getFallbackDirs()
+ {
+ return $this->fallbackDirsPsr0;
+ }
+
+ /**
+ * @return list
+ */
+ public function getFallbackDirsPsr4()
+ {
+ return $this->fallbackDirsPsr4;
+ }
+
+ /**
+ * @return array Array of classname => path
+ */
+ public function getClassMap()
+ {
+ return $this->classMap;
+ }
+
+ /**
+ * @param array $classMap Class to filename map
+ *
+ * @return void
+ */
+ 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 list|string $paths The PSR-0 root directories
+ * @param bool $prepend Whether to prepend the directories
+ *
+ * @return void
+ */
+ public function add($prefix, $paths, $prepend = false)
+ {
+ $paths = (array) $paths;
+ if (!$prefix) {
+ if ($prepend) {
+ $this->fallbackDirsPsr0 = array_merge(
+ $paths,
+ $this->fallbackDirsPsr0
+ );
+ } else {
+ $this->fallbackDirsPsr0 = array_merge(
+ $this->fallbackDirsPsr0,
+ $paths
+ );
+ }
+
+ return;
+ }
+
+ $first = $prefix[0];
+ if (!isset($this->prefixesPsr0[$first][$prefix])) {
+ $this->prefixesPsr0[$first][$prefix] = $paths;
+
+ return;
+ }
+ if ($prepend) {
+ $this->prefixesPsr0[$first][$prefix] = array_merge(
+ $paths,
+ $this->prefixesPsr0[$first][$prefix]
+ );
+ } else {
+ $this->prefixesPsr0[$first][$prefix] = array_merge(
+ $this->prefixesPsr0[$first][$prefix],
+ $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 list|string $paths The PSR-4 base directories
+ * @param bool $prepend Whether to prepend the directories
+ *
+ * @throws \InvalidArgumentException
+ *
+ * @return void
+ */
+ public function addPsr4($prefix, $paths, $prepend = false)
+ {
+ $paths = (array) $paths;
+ if (!$prefix) {
+ // Register directories for the root namespace.
+ if ($prepend) {
+ $this->fallbackDirsPsr4 = array_merge(
+ $paths,
+ $this->fallbackDirsPsr4
+ );
+ } else {
+ $this->fallbackDirsPsr4 = array_merge(
+ $this->fallbackDirsPsr4,
+ $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] = $paths;
+ } elseif ($prepend) {
+ // Prepend directories for an already registered namespace.
+ $this->prefixDirsPsr4[$prefix] = array_merge(
+ $paths,
+ $this->prefixDirsPsr4[$prefix]
+ );
+ } else {
+ // Append directories for an already registered namespace.
+ $this->prefixDirsPsr4[$prefix] = array_merge(
+ $this->prefixDirsPsr4[$prefix],
+ $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 list|string $paths The PSR-0 base directories
+ *
+ * @return void
+ */
+ 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 list|string $paths The PSR-4 base directories
+ *
+ * @throws \InvalidArgumentException
+ *
+ * @return void
+ */
+ 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
+ *
+ * @return void
+ */
+ 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
+ *
+ * @return void
+ */
+ 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
+ *
+ * @return void
+ */
+ public function setApcuPrefix($apcuPrefix)
+ {
+ $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
+ }
+
+ /**
+ * The APCu prefix in use, or null if APCu caching is not enabled.
+ *
+ * @return string|null
+ */
+ public function getApcuPrefix()
+ {
+ return $this->apcuPrefix;
+ }
+
+ /**
+ * Registers this instance as an autoloader.
+ *
+ * @param bool $prepend Whether to prepend the autoloader or not
+ *
+ * @return void
+ */
+ public function register($prepend = false)
+ {
+ spl_autoload_register(array($this, 'loadClass'), true, $prepend);
+
+ if (null === $this->vendorDir) {
+ return;
+ }
+
+ if ($prepend) {
+ self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders;
+ } else {
+ unset(self::$registeredLoaders[$this->vendorDir]);
+ self::$registeredLoaders[$this->vendorDir] = $this;
+ }
+ }
+
+ /**
+ * Unregisters this instance as an autoloader.
+ *
+ * @return void
+ */
+ public function unregister()
+ {
+ spl_autoload_unregister(array($this, 'loadClass'));
+
+ if (null !== $this->vendorDir) {
+ unset(self::$registeredLoaders[$this->vendorDir]);
+ }
+ }
+
+ /**
+ * Loads the given class or interface.
+ *
+ * @param string $class The name of the class
+ * @return true|null True if loaded, null otherwise
+ */
+ public function loadClass($class)
+ {
+ if ($file = $this->findFile($class)) {
+ $includeFile = self::$includeFile;
+ $includeFile($file);
+
+ return true;
+ }
+
+ return null;
+ }
+
+ /**
+ * 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;
+ }
+
+ /**
+ * Returns the currently registered loaders keyed by their corresponding vendor directories.
+ *
+ * @return array
+ */
+ public static function getRegisteredLoaders()
+ {
+ return self::$registeredLoaders;
+ }
+
+ /**
+ * @param string $class
+ * @param string $ext
+ * @return string|false
+ */
+ private function findFileWithExtension($class, $ext)
+ {
+ // PSR-4 lookup
+ $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
+
+ $first = $class[0];
+ if (isset($this->prefixLengthsPsr4[$first])) {
+ $subPath = $class;
+ while (false !== $lastPos = strrpos($subPath, '\\')) {
+ $subPath = substr($subPath, 0, $lastPos);
+ $search = $subPath . '\\';
+ if (isset($this->prefixDirsPsr4[$search])) {
+ $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
+ foreach ($this->prefixDirsPsr4[$search] as $dir) {
+ if (file_exists($file = $dir . $pathEnd)) {
+ return $file;
+ }
+ }
+ }
+ }
+ }
+
+ // PSR-4 fallback dirs
+ foreach ($this->fallbackDirsPsr4 as $dir) {
+ if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
+ return $file;
+ }
+ }
+
+ // PSR-0 lookup
+ if (false !== $pos = strrpos($class, '\\')) {
+ // namespaced class name
+ $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
+ . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
+ } else {
+ // PEAR-like class name
+ $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
+ }
+
+ if (isset($this->prefixesPsr0[$first])) {
+ foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
+ if (0 === strpos($class, $prefix)) {
+ foreach ($dirs as $dir) {
+ if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
+ return $file;
+ }
+ }
+ }
+ }
+ }
+
+ // PSR-0 fallback dirs
+ foreach ($this->fallbackDirsPsr0 as $dir) {
+ if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
+ return $file;
+ }
+ }
+
+ // PSR-0 include paths.
+ if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
+ return $file;
+ }
+
+ return false;
+ }
+
+ /**
+ * @return void
+ */
+ private static function initializeIncludeClosure()
+ {
+ if (self::$includeFile !== null) {
+ return;
+ }
+
+ /**
+ * Scope isolated include.
+ *
+ * Prevents access to $this/self from included files.
+ *
+ * @param string $file
+ * @return void
+ */
+ self::$includeFile = \Closure::bind(static function($file) {
+ include $file;
+ }, null, null);
+ }
+}
diff --git a/config/www/user/plugins/admin/vendor/composer/InstalledVersions.php b/config/www/user/plugins/admin/vendor/composer/InstalledVersions.php
new file mode 100644
index 0000000..51e734a
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/composer/InstalledVersions.php
@@ -0,0 +1,359 @@
+
+ * Jordi Boggiano
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Composer;
+
+use Composer\Autoload\ClassLoader;
+use Composer\Semver\VersionParser;
+
+/**
+ * This class is copied in every Composer installed project and available to all
+ *
+ * See also https://getcomposer.org/doc/07-runtime.md#installed-versions
+ *
+ * To require its presence, you can require `composer-runtime-api ^2.0`
+ *
+ * @final
+ */
+class InstalledVersions
+{
+ /**
+ * @var mixed[]|null
+ * @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array}|array{}|null
+ */
+ private static $installed;
+
+ /**
+ * @var bool|null
+ */
+ private static $canGetVendors;
+
+ /**
+ * @var array[]
+ * @psalm-var array}>
+ */
+ private static $installedByVendor = array();
+
+ /**
+ * Returns a list of all package names which are present, either by being installed, replaced or provided
+ *
+ * @return string[]
+ * @psalm-return list
+ */
+ public static function getInstalledPackages()
+ {
+ $packages = array();
+ foreach (self::getInstalled() as $installed) {
+ $packages[] = array_keys($installed['versions']);
+ }
+
+ if (1 === \count($packages)) {
+ return $packages[0];
+ }
+
+ return array_keys(array_flip(\call_user_func_array('array_merge', $packages)));
+ }
+
+ /**
+ * Returns a list of all package names with a specific type e.g. 'library'
+ *
+ * @param string $type
+ * @return string[]
+ * @psalm-return list
+ */
+ public static function getInstalledPackagesByType($type)
+ {
+ $packagesByType = array();
+
+ foreach (self::getInstalled() as $installed) {
+ foreach ($installed['versions'] as $name => $package) {
+ if (isset($package['type']) && $package['type'] === $type) {
+ $packagesByType[] = $name;
+ }
+ }
+ }
+
+ return $packagesByType;
+ }
+
+ /**
+ * Checks whether the given package is installed
+ *
+ * This also returns true if the package name is provided or replaced by another package
+ *
+ * @param string $packageName
+ * @param bool $includeDevRequirements
+ * @return bool
+ */
+ public static function isInstalled($packageName, $includeDevRequirements = true)
+ {
+ foreach (self::getInstalled() as $installed) {
+ if (isset($installed['versions'][$packageName])) {
+ return $includeDevRequirements || !isset($installed['versions'][$packageName]['dev_requirement']) || $installed['versions'][$packageName]['dev_requirement'] === false;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Checks whether the given package satisfies a version constraint
+ *
+ * e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call:
+ *
+ * Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3')
+ *
+ * @param VersionParser $parser Install composer/semver to have access to this class and functionality
+ * @param string $packageName
+ * @param string|null $constraint A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package
+ * @return bool
+ */
+ public static function satisfies(VersionParser $parser, $packageName, $constraint)
+ {
+ $constraint = $parser->parseConstraints((string) $constraint);
+ $provided = $parser->parseConstraints(self::getVersionRanges($packageName));
+
+ return $provided->matches($constraint);
+ }
+
+ /**
+ * Returns a version constraint representing all the range(s) which are installed for a given package
+ *
+ * It is easier to use this via isInstalled() with the $constraint argument if you need to check
+ * whether a given version of a package is installed, and not just whether it exists
+ *
+ * @param string $packageName
+ * @return string Version constraint usable with composer/semver
+ */
+ public static function getVersionRanges($packageName)
+ {
+ foreach (self::getInstalled() as $installed) {
+ if (!isset($installed['versions'][$packageName])) {
+ continue;
+ }
+
+ $ranges = array();
+ if (isset($installed['versions'][$packageName]['pretty_version'])) {
+ $ranges[] = $installed['versions'][$packageName]['pretty_version'];
+ }
+ if (array_key_exists('aliases', $installed['versions'][$packageName])) {
+ $ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']);
+ }
+ if (array_key_exists('replaced', $installed['versions'][$packageName])) {
+ $ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']);
+ }
+ if (array_key_exists('provided', $installed['versions'][$packageName])) {
+ $ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']);
+ }
+
+ return implode(' || ', $ranges);
+ }
+
+ throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
+ }
+
+ /**
+ * @param string $packageName
+ * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
+ */
+ public static function getVersion($packageName)
+ {
+ foreach (self::getInstalled() as $installed) {
+ if (!isset($installed['versions'][$packageName])) {
+ continue;
+ }
+
+ if (!isset($installed['versions'][$packageName]['version'])) {
+ return null;
+ }
+
+ return $installed['versions'][$packageName]['version'];
+ }
+
+ throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
+ }
+
+ /**
+ * @param string $packageName
+ * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
+ */
+ public static function getPrettyVersion($packageName)
+ {
+ foreach (self::getInstalled() as $installed) {
+ if (!isset($installed['versions'][$packageName])) {
+ continue;
+ }
+
+ if (!isset($installed['versions'][$packageName]['pretty_version'])) {
+ return null;
+ }
+
+ return $installed['versions'][$packageName]['pretty_version'];
+ }
+
+ throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
+ }
+
+ /**
+ * @param string $packageName
+ * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference
+ */
+ public static function getReference($packageName)
+ {
+ foreach (self::getInstalled() as $installed) {
+ if (!isset($installed['versions'][$packageName])) {
+ continue;
+ }
+
+ if (!isset($installed['versions'][$packageName]['reference'])) {
+ return null;
+ }
+
+ return $installed['versions'][$packageName]['reference'];
+ }
+
+ throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
+ }
+
+ /**
+ * @param string $packageName
+ * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path.
+ */
+ public static function getInstallPath($packageName)
+ {
+ foreach (self::getInstalled() as $installed) {
+ if (!isset($installed['versions'][$packageName])) {
+ continue;
+ }
+
+ return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null;
+ }
+
+ throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
+ }
+
+ /**
+ * @return array
+ * @psalm-return array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}
+ */
+ public static function getRootPackage()
+ {
+ $installed = self::getInstalled();
+
+ return $installed[0]['root'];
+ }
+
+ /**
+ * Returns the raw installed.php data for custom implementations
+ *
+ * @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect.
+ * @return array[]
+ * @psalm-return array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array}
+ */
+ public static function getRawData()
+ {
+ @trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED);
+
+ if (null === self::$installed) {
+ // only require the installed.php file if this file is loaded from its dumped location,
+ // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
+ if (substr(__DIR__, -8, 1) !== 'C') {
+ self::$installed = include __DIR__ . '/installed.php';
+ } else {
+ self::$installed = array();
+ }
+ }
+
+ return self::$installed;
+ }
+
+ /**
+ * Returns the raw data of all installed.php which are currently loaded for custom implementations
+ *
+ * @return array[]
+ * @psalm-return list}>
+ */
+ public static function getAllRawData()
+ {
+ return self::getInstalled();
+ }
+
+ /**
+ * Lets you reload the static array from another file
+ *
+ * This is only useful for complex integrations in which a project needs to use
+ * this class but then also needs to execute another project's autoloader in process,
+ * and wants to ensure both projects have access to their version of installed.php.
+ *
+ * A typical case would be PHPUnit, where it would need to make sure it reads all
+ * the data it needs from this class, then call reload() with
+ * `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure
+ * the project in which it runs can then also use this class safely, without
+ * interference between PHPUnit's dependencies and the project's dependencies.
+ *
+ * @param array[] $data A vendor/composer/installed.php data set
+ * @return void
+ *
+ * @psalm-param array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} $data
+ */
+ public static function reload($data)
+ {
+ self::$installed = $data;
+ self::$installedByVendor = array();
+ }
+
+ /**
+ * @return array[]
+ * @psalm-return list}>
+ */
+ private static function getInstalled()
+ {
+ if (null === self::$canGetVendors) {
+ self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders');
+ }
+
+ $installed = array();
+
+ if (self::$canGetVendors) {
+ foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
+ if (isset(self::$installedByVendor[$vendorDir])) {
+ $installed[] = self::$installedByVendor[$vendorDir];
+ } elseif (is_file($vendorDir.'/composer/installed.php')) {
+ /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} $required */
+ $required = require $vendorDir.'/composer/installed.php';
+ $installed[] = self::$installedByVendor[$vendorDir] = $required;
+ if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) {
+ self::$installed = $installed[count($installed) - 1];
+ }
+ }
+ }
+ }
+
+ if (null === self::$installed) {
+ // only require the installed.php file if this file is loaded from its dumped location,
+ // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
+ if (substr(__DIR__, -8, 1) !== 'C') {
+ /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} $required */
+ $required = require __DIR__ . '/installed.php';
+ self::$installed = $required;
+ } else {
+ self::$installed = array();
+ }
+ }
+
+ if (self::$installed !== array()) {
+ $installed[] = self::$installed;
+ }
+
+ return $installed;
+ }
+}
diff --git a/config/www/user/plugins/admin/vendor/composer/LICENSE b/config/www/user/plugins/admin/vendor/composer/LICENSE
new file mode 100644
index 0000000..f27399a
--- /dev/null
+++ b/config/www/user/plugins/admin/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/config/www/user/plugins/admin/vendor/composer/autoload_classmap.php b/config/www/user/plugins/admin/vendor/composer/autoload_classmap.php
new file mode 100644
index 0000000..11af3cb
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/composer/autoload_classmap.php
@@ -0,0 +1,11 @@
+ $vendorDir . '/composer/InstalledVersions.php',
+ 'Grav\\Plugin\\AdminPlugin' => $baseDir . '/admin.php',
+);
diff --git a/config/www/user/plugins/admin/vendor/composer/autoload_namespaces.php b/config/www/user/plugins/admin/vendor/composer/autoload_namespaces.php
new file mode 100644
index 0000000..24d7952
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/composer/autoload_namespaces.php
@@ -0,0 +1,10 @@
+ array($vendorDir . '/p3k/picofeed/lib'),
+);
diff --git a/config/www/user/plugins/admin/vendor/composer/autoload_psr4.php b/config/www/user/plugins/admin/vendor/composer/autoload_psr4.php
new file mode 100644
index 0000000..e20c171
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/composer/autoload_psr4.php
@@ -0,0 +1,12 @@
+ array($vendorDir . '/scssphp/scssphp/src'),
+ 'Laminas\\Xml\\' => array($vendorDir . '/laminas/laminas-xml/src'),
+ 'Grav\\Plugin\\Admin\\' => array($baseDir . '/classes/plugin'),
+);
diff --git a/config/www/user/plugins/admin/vendor/composer/autoload_real.php b/config/www/user/plugins/admin/vendor/composer/autoload_real.php
new file mode 100644
index 0000000..cb2d2b8
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/composer/autoload_real.php
@@ -0,0 +1,38 @@
+register(true);
+
+ return $loader;
+ }
+}
diff --git a/config/www/user/plugins/admin/vendor/composer/autoload_static.php b/config/www/user/plugins/admin/vendor/composer/autoload_static.php
new file mode 100644
index 0000000..aefc3b2
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/composer/autoload_static.php
@@ -0,0 +1,64 @@
+
+ array (
+ 'ScssPhp\\ScssPhp\\' => 16,
+ ),
+ 'L' =>
+ array (
+ 'Laminas\\Xml\\' => 12,
+ ),
+ 'G' =>
+ array (
+ 'Grav\\Plugin\\Admin\\' => 18,
+ ),
+ );
+
+ public static $prefixDirsPsr4 = array (
+ 'ScssPhp\\ScssPhp\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/scssphp/scssphp/src',
+ ),
+ 'Laminas\\Xml\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/laminas/laminas-xml/src',
+ ),
+ 'Grav\\Plugin\\Admin\\' =>
+ array (
+ 0 => __DIR__ . '/../..' . '/classes/plugin',
+ ),
+ );
+
+ public static $prefixesPsr0 = array (
+ 'P' =>
+ array (
+ 'PicoFeed' =>
+ array (
+ 0 => __DIR__ . '/..' . '/p3k/picofeed/lib',
+ ),
+ ),
+ );
+
+ public static $classMap = array (
+ 'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
+ 'Grav\\Plugin\\AdminPlugin' => __DIR__ . '/../..' . '/admin.php',
+ );
+
+ public static function getInitializer(ClassLoader $loader)
+ {
+ return \Closure::bind(function () use ($loader) {
+ $loader->prefixLengthsPsr4 = ComposerStaticInit98c98c1c3d67f21a128f935fe4a74897::$prefixLengthsPsr4;
+ $loader->prefixDirsPsr4 = ComposerStaticInit98c98c1c3d67f21a128f935fe4a74897::$prefixDirsPsr4;
+ $loader->prefixesPsr0 = ComposerStaticInit98c98c1c3d67f21a128f935fe4a74897::$prefixesPsr0;
+ $loader->classMap = ComposerStaticInit98c98c1c3d67f21a128f935fe4a74897::$classMap;
+
+ }, null, ClassLoader::class);
+ }
+}
diff --git a/config/www/user/plugins/admin/vendor/composer/installed.json b/config/www/user/plugins/admin/vendor/composer/installed.json
new file mode 100644
index 0000000..f2700fa
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/composer/installed.json
@@ -0,0 +1,213 @@
+{
+ "packages": [
+ {
+ "name": "laminas/laminas-xml",
+ "version": "1.4.0",
+ "version_normalized": "1.4.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/laminas/laminas-xml.git",
+ "reference": "dcadeefdb6d7ed6b39d772b47e3845003d6ea60f"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/laminas/laminas-xml/zipball/dcadeefdb6d7ed6b39d772b47e3845003d6ea60f",
+ "reference": "dcadeefdb6d7ed6b39d772b47e3845003d6ea60f",
+ "shasum": ""
+ },
+ "require": {
+ "ext-dom": "*",
+ "ext-simplexml": "*",
+ "php": "^7.3 || ~8.0.0 || ~8.1.0"
+ },
+ "conflict": {
+ "zendframework/zendxml": "*"
+ },
+ "require-dev": {
+ "ext-iconv": "*",
+ "laminas/laminas-coding-standard": "~1.0.0",
+ "phpunit/phpunit": "^9.5.8",
+ "squizlabs/php_codesniffer": "3.6.1 as 2.9999999.9999999"
+ },
+ "time": "2021-11-30T02:16:35+00:00",
+ "type": "library",
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "Laminas\\Xml\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "description": "Utility library for XML usage, best practices, and security in PHP",
+ "homepage": "https://laminas.dev",
+ "keywords": [
+ "laminas",
+ "security",
+ "xml"
+ ],
+ "support": {
+ "chat": "https://laminas.dev/chat",
+ "forum": "https://discourse.laminas.dev",
+ "issues": "https://github.com/laminas/laminas-xml/issues",
+ "rss": "https://github.com/laminas/laminas-xml/releases.atom",
+ "source": "https://github.com/laminas/laminas-xml"
+ },
+ "funding": [
+ {
+ "url": "https://funding.communitybridge.org/projects/laminas-project",
+ "type": "community_bridge"
+ }
+ ],
+ "install-path": "../laminas/laminas-xml"
+ },
+ {
+ "name": "p3k/picofeed",
+ "version": "1.0.0",
+ "version_normalized": "1.0.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/rhukster/picofeed.git",
+ "reference": "8eacaa62f50a0935e26ca33f8d30d283344ca397"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/rhukster/picofeed/zipball/8eacaa62f50a0935e26ca33f8d30d283344ca397",
+ "reference": "8eacaa62f50a0935e26ca33f8d30d283344ca397",
+ "shasum": ""
+ },
+ "require": {
+ "ext-dom": "*",
+ "ext-iconv": "*",
+ "ext-libxml": "*",
+ "ext-simplexml": "*",
+ "ext-xml": "*",
+ "laminas/laminas-xml": "^1.2",
+ "php": ">=5.3.0"
+ },
+ "replace": {
+ "miniflux/picofeed": "0.1.35"
+ },
+ "require-dev": {
+ "phpdocumentor/reflection-docblock": "2.0.4",
+ "phpunit/phpunit": "4.8.26",
+ "symfony/yaml": "2.8.7"
+ },
+ "suggest": {
+ "ext-curl": "PicoFeed will use cURL if present"
+ },
+ "time": "2023-02-19T19:58:09+00:00",
+ "bin": [
+ "picofeed"
+ ],
+ "type": "library",
+ "installation-source": "dist",
+ "autoload": {
+ "psr-0": {
+ "PicoFeed": "lib/"
+ }
+ },
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Frédéric Guillot"
+ }
+ ],
+ "description": "Modern library to handle RSS/Atom feeds",
+ "homepage": "https://github.com/aaronpk/picoFeed",
+ "support": {
+ "source": "https://github.com/rhukster/picofeed/tree/1.0.0"
+ },
+ "install-path": "../p3k/picofeed"
+ },
+ {
+ "name": "scssphp/scssphp",
+ "version": "v1.13.0",
+ "version_normalized": "1.13.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/scssphp/scssphp.git",
+ "reference": "63d1157457e5554edf00b0c1fabab4c1511d2520"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/scssphp/scssphp/zipball/63d1157457e5554edf00b0c1fabab4c1511d2520",
+ "reference": "63d1157457e5554edf00b0c1fabab4c1511d2520",
+ "shasum": ""
+ },
+ "require": {
+ "ext-ctype": "*",
+ "ext-json": "*",
+ "php": ">=5.6.0"
+ },
+ "require-dev": {
+ "bamarni/composer-bin-plugin": "^1.4",
+ "phpunit/phpunit": "^5.7 || ^6.5 || ^7.5 || ^8.3 || ^9.4",
+ "sass/sass-spec": "*",
+ "squizlabs/php_codesniffer": "~3.5",
+ "symfony/phpunit-bridge": "^5.1",
+ "thoughtbot/bourbon": "^7.0",
+ "twbs/bootstrap": "~5.0",
+ "twbs/bootstrap4": "4.6.1",
+ "zurb/foundation": "~6.7.0"
+ },
+ "suggest": {
+ "ext-iconv": "Can be used as fallback when ext-mbstring is not available",
+ "ext-mbstring": "For best performance, mbstring should be installed as it is faster than ext-iconv"
+ },
+ "time": "2024-08-17T21:02:11+00:00",
+ "bin": [
+ "bin/pscss"
+ ],
+ "type": "library",
+ "extra": {
+ "bamarni-bin": {
+ "bin-links": false,
+ "forward-command": false
+ }
+ },
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "ScssPhp\\ScssPhp\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Anthon Pang",
+ "email": "apang@softwaredevelopment.ca",
+ "homepage": "https://github.com/robocoder"
+ },
+ {
+ "name": "Cédric Morin",
+ "email": "cedric@yterium.com",
+ "homepage": "https://github.com/Cerdic"
+ }
+ ],
+ "description": "scssphp is a compiler for SCSS written in PHP.",
+ "homepage": "http://scssphp.github.io/scssphp/",
+ "keywords": [
+ "css",
+ "less",
+ "sass",
+ "scss",
+ "stylesheet"
+ ],
+ "support": {
+ "issues": "https://github.com/scssphp/scssphp/issues",
+ "source": "https://github.com/scssphp/scssphp/tree/v1.13.0"
+ },
+ "install-path": "../scssphp/scssphp"
+ }
+ ],
+ "dev": false,
+ "dev-package-names": []
+}
diff --git a/config/www/user/plugins/admin/vendor/composer/installed.php b/config/www/user/plugins/admin/vendor/composer/installed.php
new file mode 100644
index 0000000..5ffa5c4
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/composer/installed.php
@@ -0,0 +1,62 @@
+ array(
+ 'name' => 'getgrav/grav-plugin-admin',
+ 'pretty_version' => 'dev-develop',
+ 'version' => 'dev-develop',
+ 'reference' => '12bdb5af4bd10e30e24d191b7ea1a78602a583fb',
+ 'type' => 'grav-plugin',
+ 'install_path' => __DIR__ . '/../../',
+ 'aliases' => array(),
+ 'dev' => false,
+ ),
+ 'versions' => array(
+ 'getgrav/grav-plugin-admin' => array(
+ 'pretty_version' => 'dev-develop',
+ 'version' => 'dev-develop',
+ 'reference' => '12bdb5af4bd10e30e24d191b7ea1a78602a583fb',
+ 'type' => 'grav-plugin',
+ 'install_path' => __DIR__ . '/../../',
+ 'aliases' => array(),
+ 'dev_requirement' => false,
+ ),
+ 'laminas/laminas-xml' => array(
+ 'pretty_version' => '1.4.0',
+ 'version' => '1.4.0.0',
+ 'reference' => 'dcadeefdb6d7ed6b39d772b47e3845003d6ea60f',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../laminas/laminas-xml',
+ 'aliases' => array(),
+ 'dev_requirement' => false,
+ ),
+ 'miniflux/picofeed' => array(
+ 'dev_requirement' => false,
+ 'replaced' => array(
+ 0 => '0.1.35',
+ ),
+ ),
+ 'p3k/picofeed' => array(
+ 'pretty_version' => '1.0.0',
+ 'version' => '1.0.0.0',
+ 'reference' => '8eacaa62f50a0935e26ca33f8d30d283344ca397',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../p3k/picofeed',
+ 'aliases' => array(),
+ 'dev_requirement' => false,
+ ),
+ 'scssphp/scssphp' => array(
+ 'pretty_version' => 'v1.13.0',
+ 'version' => '1.13.0.0',
+ 'reference' => '63d1157457e5554edf00b0c1fabab4c1511d2520',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../scssphp/scssphp',
+ 'aliases' => array(),
+ 'dev_requirement' => false,
+ ),
+ 'symfony/polyfill-php73' => array(
+ 'dev_requirement' => false,
+ 'replaced' => array(
+ 0 => '*',
+ ),
+ ),
+ ),
+);
diff --git a/config/www/user/plugins/admin/vendor/composer/platform_check.php b/config/www/user/plugins/admin/vendor/composer/platform_check.php
new file mode 100644
index 0000000..0109125
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/composer/platform_check.php
@@ -0,0 +1,26 @@
+= 70306)) {
+ $issues[] = 'Your Composer dependencies require a PHP version ">= 7.3.6". You are running ' . PHP_VERSION . '.';
+}
+
+if ($issues) {
+ if (!headers_sent()) {
+ header('HTTP/1.1 500 Internal Server Error');
+ }
+ if (!ini_get('display_errors')) {
+ if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
+ fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL);
+ } elseif (!headers_sent()) {
+ echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL;
+ }
+ }
+ trigger_error(
+ 'Composer detected issues in your platform: ' . implode(' ', $issues),
+ E_USER_ERROR
+ );
+}
diff --git a/config/www/user/plugins/admin/vendor/laminas/laminas-xml/COPYRIGHT.md b/config/www/user/plugins/admin/vendor/laminas/laminas-xml/COPYRIGHT.md
new file mode 100644
index 0000000..0a8cccc
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/laminas/laminas-xml/COPYRIGHT.md
@@ -0,0 +1 @@
+Copyright (c) 2020 Laminas Project a Series of LF Projects, LLC. (https://getlaminas.org/)
diff --git a/config/www/user/plugins/admin/vendor/laminas/laminas-xml/LICENSE.md b/config/www/user/plugins/admin/vendor/laminas/laminas-xml/LICENSE.md
new file mode 100644
index 0000000..10b40f1
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/laminas/laminas-xml/LICENSE.md
@@ -0,0 +1,26 @@
+Copyright (c) 2020 Laminas Project a Series of LF Projects, LLC.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+- Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+- Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+- Neither the name of Laminas Foundation nor the names of its contributors may
+ be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/config/www/user/plugins/admin/vendor/laminas/laminas-xml/README.md b/config/www/user/plugins/admin/vendor/laminas/laminas-xml/README.md
new file mode 100644
index 0000000..3826780
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/laminas/laminas-xml/README.md
@@ -0,0 +1,51 @@
+# laminas-xml
+
+> This package is considered feature-complete, and is now in **security-only** maintenance mode, following a [decision by the Technical Steering Committee](https://github.com/laminas/technical-steering-committee/blob/2b55453e172a1b8c9c4c212be7cf7e7a58b9352c/meetings/minutes/2020-08-03-TSC-Minutes.md#vote-on-components-to-mark-as-security-only).
+> If you have a security issue, please [follow our security reporting guidelines](https://getlaminas.org/security/).
+> If you wish to take on the role of maintainer, please [nominate yourself](https://github.com/laminas/technical-steering-committee/issues/new?assignees=&labels=Nomination&template=Maintainer_Nomination.md&title=%5BNOMINATION%5D%5BMAINTAINER%5D%3A+%7Bname+of+person+being+nominated%7D)
+
+
+[](https://github.com/laminas/laminas-xml/actions?query=workflow%3A"Continuous+Integration")
+
+An utility component for XML usage and best practices in PHP
+
+## Installation
+
+You can install using:
+
+```bash
+$ curl -s https://getcomposer.org/installer | php
+$ php composer.phar install
+```
+
+Notice that this library doesn't have any external dependencies, the usage of composer is for autoloading and standard purpose.
+
+## Laminas\Xml\Security
+
+This is a security component to prevent [XML eXternal Entity](https://www.owasp.org/index.php/XML_External_Entity_%28XXE%29_Processing) (XXE) and [XML Entity Expansion](http://projects.webappsec.org/w/page/13247002/XML%20Entity%20Expansion) (XEE) attacks on XML documents.
+
+The XXE attack is prevented disabling the load of external entities in the libxml library used by PHP, using the function [libxml_disable_entity_loader](http://www.php.net/manual/en/function.libxml-disable-entity-loader.php).
+
+The XEE attack is prevented looking inside the XML document for ENTITY usage. If the XML document uses ENTITY the library throw an Exception.
+
+We have two static methods to scan and load XML document from a string (scan) and from a file (scanFile). You can decide to get a SimpleXMLElement or DOMDocument as result, using the following use cases:
+
+```php
+use Laminas\Xml\Security as XmlSecurity;
+
+$xml = <<
+
+ 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/config/www/user/plugins/admin/vendor/laminas/laminas-xml/composer.json b/config/www/user/plugins/admin/vendor/laminas/laminas-xml/composer.json
new file mode 100644
index 0000000..e7f0e1b
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/laminas/laminas-xml/composer.json
@@ -0,0 +1,55 @@
+{
+ "name": "laminas/laminas-xml",
+ "description": "Utility library for XML usage, best practices, and security in PHP",
+ "license": "BSD-3-Clause",
+ "keywords": [
+ "laminas",
+ "xml",
+ "security"
+ ],
+ "homepage": "https://laminas.dev",
+ "support": {
+ "issues": "https://github.com/laminas/laminas-xml/issues",
+ "source": "https://github.com/laminas/laminas-xml",
+ "rss": "https://github.com/laminas/laminas-xml/releases.atom",
+ "chat": "https://laminas.dev/chat",
+ "forum": "https://discourse.laminas.dev"
+ },
+ "config": {
+ "sort-packages": true
+ },
+ "require": {
+ "php": "^7.3 || ~8.0.0 || ~8.1.0",
+ "ext-dom": "*",
+ "ext-simplexml": "*"
+ },
+ "require-dev": {
+ "laminas/laminas-coding-standard": "~1.0.0",
+ "squizlabs/php_codesniffer": "3.6.1 as 2.9999999.9999999",
+ "phpunit/phpunit": "^9.5.8",
+ "ext-iconv": "*"
+ },
+ "autoload": {
+ "psr-4": {
+ "Laminas\\Xml\\": "src/"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "LaminasTest\\Xml\\": "test/"
+ }
+ },
+ "scripts": {
+ "check": [
+ "@cs-check",
+ "@test"
+ ],
+ "cs-check": "phpcs",
+ "cs-fix": "phpcbf",
+ "test": "phpunit --colors=always",
+ "test-coverage": "phpunit --colors=always --coverage-clover clover.xml"
+ },
+ "conflict": {
+ "zendframework/zendxml": "*"
+ }
+}
diff --git a/config/www/user/plugins/admin/vendor/laminas/laminas-xml/composer.lock b/config/www/user/plugins/admin/vendor/laminas/laminas-xml/composer.lock
new file mode 100644
index 0000000..f90f3ff
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/laminas/laminas-xml/composer.lock
@@ -0,0 +1,2285 @@
+{
+ "_readme": [
+ "This file locks the dependencies of your project to a known state",
+ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
+ "This file is @generated automatically"
+ ],
+ "content-hash": "7bd20d466bd034077f9a403d2468ed89",
+ "packages": [],
+ "packages-dev": [
+ {
+ "name": "doctrine/instantiator",
+ "version": "1.4.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/doctrine/instantiator.git",
+ "reference": "d56bf6102915de5702778fe20f2de3b2fe570b5b"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/doctrine/instantiator/zipball/d56bf6102915de5702778fe20f2de3b2fe570b5b",
+ "reference": "d56bf6102915de5702778fe20f2de3b2fe570b5b",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.1 || ^8.0"
+ },
+ "require-dev": {
+ "doctrine/coding-standard": "^8.0",
+ "ext-pdo": "*",
+ "ext-phar": "*",
+ "phpbench/phpbench": "^0.13 || 1.0.0-alpha2",
+ "phpstan/phpstan": "^0.12",
+ "phpstan/phpstan-phpunit": "^0.12",
+ "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0"
+ },
+ "type": "library",
+ "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": "https://ocramius.github.io/"
+ }
+ ],
+ "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors",
+ "homepage": "https://www.doctrine-project.org/projects/instantiator.html",
+ "keywords": [
+ "constructor",
+ "instantiate"
+ ],
+ "support": {
+ "issues": "https://github.com/doctrine/instantiator/issues",
+ "source": "https://github.com/doctrine/instantiator/tree/1.4.0"
+ },
+ "funding": [
+ {
+ "url": "https://www.doctrine-project.org/sponsorship.html",
+ "type": "custom"
+ },
+ {
+ "url": "https://www.patreon.com/phpdoctrine",
+ "type": "patreon"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finstantiator",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2020-11-10T18:47:58+00:00"
+ },
+ {
+ "name": "laminas/laminas-coding-standard",
+ "version": "1.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/laminas/laminas-coding-standard.git",
+ "reference": "08880ce2fbfe62d471cd3cb766a91da630b32539"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/laminas/laminas-coding-standard/zipball/08880ce2fbfe62d471cd3cb766a91da630b32539",
+ "reference": "08880ce2fbfe62d471cd3cb766a91da630b32539",
+ "shasum": ""
+ },
+ "require": {
+ "laminas/laminas-zendframework-bridge": "^1.0",
+ "squizlabs/php_codesniffer": "^2.7"
+ },
+ "replace": {
+ "zendframework/zend-coding-standard": "self.version"
+ },
+ "type": "library",
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "description": "Laminas coding standard",
+ "homepage": "https://laminas.dev",
+ "keywords": [
+ "Coding Standard",
+ "laminas"
+ ],
+ "support": {
+ "chat": "https://laminas.dev/chat",
+ "docs": "https://docs.laminas.dev/laminas-coding-standard/",
+ "forum": "https://discourse.laminas.dev",
+ "issues": "https://github.com/laminas/laminas-coding-standard/issues",
+ "rss": "https://github.com/laminas/laminas-coding-standard/releases.atom",
+ "source": "https://github.com/laminas/laminas-coding-standard"
+ },
+ "time": "2019-12-31T16:28:26+00:00"
+ },
+ {
+ "name": "laminas/laminas-zendframework-bridge",
+ "version": "1.4.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/laminas/laminas-zendframework-bridge.git",
+ "reference": "bf180a382393e7db5c1e8d0f2ec0c4af9c724baf"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/laminas/laminas-zendframework-bridge/zipball/bf180a382393e7db5c1e8d0f2ec0c4af9c724baf",
+ "reference": "bf180a382393e7db5c1e8d0f2ec0c4af9c724baf",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.3 || ~8.0.0 || ~8.1.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.3",
+ "psalm/plugin-phpunit": "^0.15.1",
+ "squizlabs/php_codesniffer": "^3.5",
+ "vimeo/psalm": "^4.6"
+ },
+ "type": "library",
+ "extra": {
+ "laminas": {
+ "module": "Laminas\\ZendFrameworkBridge"
+ }
+ },
+ "autoload": {
+ "files": [
+ "src/autoload.php"
+ ],
+ "psr-4": {
+ "Laminas\\ZendFrameworkBridge\\": "src//"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "description": "Alias legacy ZF class names to Laminas Project equivalents.",
+ "keywords": [
+ "ZendFramework",
+ "autoloading",
+ "laminas",
+ "zf"
+ ],
+ "support": {
+ "forum": "https://discourse.laminas.dev/",
+ "issues": "https://github.com/laminas/laminas-zendframework-bridge/issues",
+ "rss": "https://github.com/laminas/laminas-zendframework-bridge/releases.atom",
+ "source": "https://github.com/laminas/laminas-zendframework-bridge"
+ },
+ "funding": [
+ {
+ "url": "https://funding.communitybridge.org/projects/laminas-project",
+ "type": "community_bridge"
+ }
+ ],
+ "time": "2021-09-03T17:53:30+00:00"
+ },
+ {
+ "name": "myclabs/deep-copy",
+ "version": "1.10.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/myclabs/DeepCopy.git",
+ "reference": "776f831124e9c62e1a2c601ecc52e776d8bb7220"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/776f831124e9c62e1a2c601ecc52e776d8bb7220",
+ "reference": "776f831124e9c62e1a2c601ecc52e776d8bb7220",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.1 || ^8.0"
+ },
+ "replace": {
+ "myclabs/deep-copy": "self.version"
+ },
+ "require-dev": {
+ "doctrine/collections": "^1.0",
+ "doctrine/common": "^2.6",
+ "phpunit/phpunit": "^7.1"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "DeepCopy\\": "src/DeepCopy/"
+ },
+ "files": [
+ "src/DeepCopy/deep_copy.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "description": "Create deep copies (clones) of your objects",
+ "keywords": [
+ "clone",
+ "copy",
+ "duplicate",
+ "object",
+ "object graph"
+ ],
+ "support": {
+ "issues": "https://github.com/myclabs/DeepCopy/issues",
+ "source": "https://github.com/myclabs/DeepCopy/tree/1.10.2"
+ },
+ "funding": [
+ {
+ "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2020-11-13T09:40:50+00:00"
+ },
+ {
+ "name": "nikic/php-parser",
+ "version": "v4.13.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/nikic/PHP-Parser.git",
+ "reference": "63a79e8daa781cac14e5195e63ed8ae231dd10fd"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/63a79e8daa781cac14e5195e63ed8ae231dd10fd",
+ "reference": "63a79e8daa781cac14e5195e63ed8ae231dd10fd",
+ "shasum": ""
+ },
+ "require": {
+ "ext-tokenizer": "*",
+ "php": ">=7.0"
+ },
+ "require-dev": {
+ "ircmaxell/php-yacc": "^0.0.7",
+ "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0"
+ },
+ "bin": [
+ "bin/php-parse"
+ ],
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "4.9-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "PhpParser\\": "lib/PhpParser"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Nikita Popov"
+ }
+ ],
+ "description": "A PHP parser written in PHP",
+ "keywords": [
+ "parser",
+ "php"
+ ],
+ "support": {
+ "issues": "https://github.com/nikic/PHP-Parser/issues",
+ "source": "https://github.com/nikic/PHP-Parser/tree/v4.13.1"
+ },
+ "time": "2021-11-03T20:52:16+00:00"
+ },
+ {
+ "name": "phar-io/manifest",
+ "version": "2.0.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/phar-io/manifest.git",
+ "reference": "97803eca37d319dfa7826cc2437fc020857acb53"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/phar-io/manifest/zipball/97803eca37d319dfa7826cc2437fc020857acb53",
+ "reference": "97803eca37d319dfa7826cc2437fc020857acb53",
+ "shasum": ""
+ },
+ "require": {
+ "ext-dom": "*",
+ "ext-phar": "*",
+ "ext-xmlwriter": "*",
+ "phar-io/version": "^3.0.1",
+ "php": "^7.2 || ^8.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.0.x-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Arne Blankerts",
+ "email": "arne@blankerts.de",
+ "role": "Developer"
+ },
+ {
+ "name": "Sebastian Heuer",
+ "email": "sebastian@phpeople.de",
+ "role": "Developer"
+ },
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "Developer"
+ }
+ ],
+ "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)",
+ "support": {
+ "issues": "https://github.com/phar-io/manifest/issues",
+ "source": "https://github.com/phar-io/manifest/tree/2.0.3"
+ },
+ "time": "2021-07-20T11:28:43+00:00"
+ },
+ {
+ "name": "phar-io/version",
+ "version": "3.1.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/phar-io/version.git",
+ "reference": "bae7c545bef187884426f042434e561ab1ddb182"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/phar-io/version/zipball/bae7c545bef187884426f042434e561ab1ddb182",
+ "reference": "bae7c545bef187884426f042434e561ab1ddb182",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.2 || ^8.0"
+ },
+ "type": "library",
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Arne Blankerts",
+ "email": "arne@blankerts.de",
+ "role": "Developer"
+ },
+ {
+ "name": "Sebastian Heuer",
+ "email": "sebastian@phpeople.de",
+ "role": "Developer"
+ },
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "Developer"
+ }
+ ],
+ "description": "Library for handling version information and constraints",
+ "support": {
+ "issues": "https://github.com/phar-io/version/issues",
+ "source": "https://github.com/phar-io/version/tree/3.1.0"
+ },
+ "time": "2021-02-23T14:00:09+00:00"
+ },
+ {
+ "name": "phpdocumentor/reflection-common",
+ "version": "2.2.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/phpDocumentor/ReflectionCommon.git",
+ "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/1d01c49d4ed62f25aa84a747ad35d5a16924662b",
+ "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.2 || ^8.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-2.x": "2.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"
+ ],
+ "support": {
+ "issues": "https://github.com/phpDocumentor/ReflectionCommon/issues",
+ "source": "https://github.com/phpDocumentor/ReflectionCommon/tree/2.x"
+ },
+ "time": "2020-06-27T09:03:43+00:00"
+ },
+ {
+ "name": "phpdocumentor/reflection-docblock",
+ "version": "5.3.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
+ "reference": "622548b623e81ca6d78b721c5e029f4ce664f170"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/622548b623e81ca6d78b721c5e029f4ce664f170",
+ "reference": "622548b623e81ca6d78b721c5e029f4ce664f170",
+ "shasum": ""
+ },
+ "require": {
+ "ext-filter": "*",
+ "php": "^7.2 || ^8.0",
+ "phpdocumentor/reflection-common": "^2.2",
+ "phpdocumentor/type-resolver": "^1.3",
+ "webmozart/assert": "^1.9.1"
+ },
+ "require-dev": {
+ "mockery/mockery": "~1.3.2",
+ "psalm/phar": "^4.8"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "5.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"
+ },
+ {
+ "name": "Jaap van Otterdijk",
+ "email": "account@ijaap.nl"
+ }
+ ],
+ "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
+ "support": {
+ "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues",
+ "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.3.0"
+ },
+ "time": "2021-10-19T17:43:47+00:00"
+ },
+ {
+ "name": "phpdocumentor/type-resolver",
+ "version": "1.5.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/phpDocumentor/TypeResolver.git",
+ "reference": "a12f7e301eb7258bb68acd89d4aefa05c2906cae"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/a12f7e301eb7258bb68acd89d4aefa05c2906cae",
+ "reference": "a12f7e301eb7258bb68acd89d4aefa05c2906cae",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.2 || ^8.0",
+ "phpdocumentor/reflection-common": "^2.0"
+ },
+ "require-dev": {
+ "ext-tokenizer": "*",
+ "psalm/phar": "^4.8"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-1.x": "1.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "phpDocumentor\\Reflection\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Mike van Riel",
+ "email": "me@mikevanriel.com"
+ }
+ ],
+ "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names",
+ "support": {
+ "issues": "https://github.com/phpDocumentor/TypeResolver/issues",
+ "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.5.1"
+ },
+ "time": "2021-10-02T14:08:47+00:00"
+ },
+ {
+ "name": "phpspec/prophecy",
+ "version": "1.14.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/phpspec/prophecy.git",
+ "reference": "d86dfc2e2a3cd366cee475e52c6bb3bbc371aa0e"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/phpspec/prophecy/zipball/d86dfc2e2a3cd366cee475e52c6bb3bbc371aa0e",
+ "reference": "d86dfc2e2a3cd366cee475e52c6bb3bbc371aa0e",
+ "shasum": ""
+ },
+ "require": {
+ "doctrine/instantiator": "^1.2",
+ "php": "^7.2 || ~8.0, <8.2",
+ "phpdocumentor/reflection-docblock": "^5.2",
+ "sebastian/comparator": "^3.0 || ^4.0",
+ "sebastian/recursion-context": "^3.0 || ^4.0"
+ },
+ "require-dev": {
+ "phpspec/phpspec": "^6.0 || ^7.0",
+ "phpunit/phpunit": "^8.0 || ^9.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Prophecy\\": "src/Prophecy"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Konstantin Kudryashov",
+ "email": "ever.zet@gmail.com",
+ "homepage": "http://everzet.com"
+ },
+ {
+ "name": "Marcello Duarte",
+ "email": "marcello.duarte@gmail.com"
+ }
+ ],
+ "description": "Highly opinionated mocking framework for PHP 5.3+",
+ "homepage": "https://github.com/phpspec/prophecy",
+ "keywords": [
+ "Double",
+ "Dummy",
+ "fake",
+ "mock",
+ "spy",
+ "stub"
+ ],
+ "support": {
+ "issues": "https://github.com/phpspec/prophecy/issues",
+ "source": "https://github.com/phpspec/prophecy/tree/1.14.0"
+ },
+ "time": "2021-09-10T09:02:12+00:00"
+ },
+ {
+ "name": "phpunit/php-code-coverage",
+ "version": "9.2.9",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
+ "reference": "f301eb1453c9e7a1bc912ee8b0ea9db22c60223b"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/f301eb1453c9e7a1bc912ee8b0ea9db22c60223b",
+ "reference": "f301eb1453c9e7a1bc912ee8b0ea9db22c60223b",
+ "shasum": ""
+ },
+ "require": {
+ "ext-dom": "*",
+ "ext-libxml": "*",
+ "ext-xmlwriter": "*",
+ "nikic/php-parser": "^4.13.0",
+ "php": ">=7.3",
+ "phpunit/php-file-iterator": "^3.0.3",
+ "phpunit/php-text-template": "^2.0.2",
+ "sebastian/code-unit-reverse-lookup": "^2.0.2",
+ "sebastian/complexity": "^2.0",
+ "sebastian/environment": "^5.1.2",
+ "sebastian/lines-of-code": "^1.0.3",
+ "sebastian/version": "^3.0.1",
+ "theseer/tokenizer": "^1.2.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.3"
+ },
+ "suggest": {
+ "ext-pcov": "*",
+ "ext-xdebug": "*"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "9.2-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": "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"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
+ "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.9"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2021-11-19T15:21:02+00:00"
+ },
+ {
+ "name": "phpunit/php-file-iterator",
+ "version": "3.0.5",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/php-file-iterator.git",
+ "reference": "aa4be8575f26070b100fccb67faabb28f21f66f8"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/aa4be8575f26070b100fccb67faabb28f21f66f8",
+ "reference": "aa4be8575f26070b100fccb67faabb28f21f66f8",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.3"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.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"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues",
+ "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/3.0.5"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2020-09-28T05:57:25+00:00"
+ },
+ {
+ "name": "phpunit/php-invoker",
+ "version": "3.1.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/php-invoker.git",
+ "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/5a10147d0aaf65b58940a0b72f71c9ac0423cc67",
+ "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.3"
+ },
+ "require-dev": {
+ "ext-pcntl": "*",
+ "phpunit/phpunit": "^9.3"
+ },
+ "suggest": {
+ "ext-pcntl": "*"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.1-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Invoke callables with a timeout",
+ "homepage": "https://github.com/sebastianbergmann/php-invoker/",
+ "keywords": [
+ "process"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/php-invoker/issues",
+ "source": "https://github.com/sebastianbergmann/php-invoker/tree/3.1.1"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2020-09-28T05:58:55+00:00"
+ },
+ {
+ "name": "phpunit/php-text-template",
+ "version": "2.0.4",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/php-text-template.git",
+ "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28",
+ "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.3"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Simple template engine.",
+ "homepage": "https://github.com/sebastianbergmann/php-text-template/",
+ "keywords": [
+ "template"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/php-text-template/issues",
+ "source": "https://github.com/sebastianbergmann/php-text-template/tree/2.0.4"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2020-10-26T05:33:50+00:00"
+ },
+ {
+ "name": "phpunit/php-timer",
+ "version": "5.0.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/php-timer.git",
+ "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2",
+ "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.3"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "5.0-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": "Utility class for timing",
+ "homepage": "https://github.com/sebastianbergmann/php-timer/",
+ "keywords": [
+ "timer"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/php-timer/issues",
+ "source": "https://github.com/sebastianbergmann/php-timer/tree/5.0.3"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2020-10-26T13:16:10+00:00"
+ },
+ {
+ "name": "phpunit/phpunit",
+ "version": "9.5.10",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/phpunit.git",
+ "reference": "c814a05837f2edb0d1471d6e3f4ab3501ca3899a"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/c814a05837f2edb0d1471d6e3f4ab3501ca3899a",
+ "reference": "c814a05837f2edb0d1471d6e3f4ab3501ca3899a",
+ "shasum": ""
+ },
+ "require": {
+ "doctrine/instantiator": "^1.3.1",
+ "ext-dom": "*",
+ "ext-json": "*",
+ "ext-libxml": "*",
+ "ext-mbstring": "*",
+ "ext-xml": "*",
+ "ext-xmlwriter": "*",
+ "myclabs/deep-copy": "^1.10.1",
+ "phar-io/manifest": "^2.0.3",
+ "phar-io/version": "^3.0.2",
+ "php": ">=7.3",
+ "phpspec/prophecy": "^1.12.1",
+ "phpunit/php-code-coverage": "^9.2.7",
+ "phpunit/php-file-iterator": "^3.0.5",
+ "phpunit/php-invoker": "^3.1.1",
+ "phpunit/php-text-template": "^2.0.3",
+ "phpunit/php-timer": "^5.0.2",
+ "sebastian/cli-parser": "^1.0.1",
+ "sebastian/code-unit": "^1.0.6",
+ "sebastian/comparator": "^4.0.5",
+ "sebastian/diff": "^4.0.3",
+ "sebastian/environment": "^5.1.3",
+ "sebastian/exporter": "^4.0.3",
+ "sebastian/global-state": "^5.0.1",
+ "sebastian/object-enumerator": "^4.0.3",
+ "sebastian/resource-operations": "^3.0.3",
+ "sebastian/type": "^2.3.4",
+ "sebastian/version": "^3.0.2"
+ },
+ "require-dev": {
+ "ext-pdo": "*",
+ "phpspec/prophecy-phpunit": "^2.0.1"
+ },
+ "suggest": {
+ "ext-soap": "*",
+ "ext-xdebug": "*"
+ },
+ "bin": [
+ "phpunit"
+ ],
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "9.5-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ],
+ "files": [
+ "src/Framework/Assert/Functions.php"
+ ]
+ },
+ "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"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/phpunit/issues",
+ "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.10"
+ },
+ "funding": [
+ {
+ "url": "https://phpunit.de/donate.html",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2021-09-25T07:38:51+00:00"
+ },
+ {
+ "name": "sebastian/cli-parser",
+ "version": "1.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/cli-parser.git",
+ "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/442e7c7e687e42adc03470c7b668bc4b2402c0b2",
+ "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.3"
+ },
+ "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",
+ "role": "lead"
+ }
+ ],
+ "description": "Library for parsing CLI options",
+ "homepage": "https://github.com/sebastianbergmann/cli-parser",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/cli-parser/issues",
+ "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.1"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2020-09-28T06:08:49+00:00"
+ },
+ {
+ "name": "sebastian/code-unit",
+ "version": "1.0.8",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/code-unit.git",
+ "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/1fc9f64c0927627ef78ba436c9b17d967e68e120",
+ "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.3"
+ },
+ "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",
+ "role": "lead"
+ }
+ ],
+ "description": "Collection of value objects that represent the PHP code units",
+ "homepage": "https://github.com/sebastianbergmann/code-unit",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/code-unit/issues",
+ "source": "https://github.com/sebastianbergmann/code-unit/tree/1.0.8"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2020-10-26T13:08:54+00:00"
+ },
+ {
+ "name": "sebastian/code-unit-reverse-lookup",
+ "version": "2.0.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git",
+ "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5",
+ "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.3"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Looks up which function or method a line of code belongs to",
+ "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues",
+ "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/2.0.3"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2020-09-28T05:30:19+00:00"
+ },
+ {
+ "name": "sebastian/comparator",
+ "version": "4.0.6",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/comparator.git",
+ "reference": "55f4261989e546dc112258c7a75935a81a7ce382"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/55f4261989e546dc112258c7a75935a81a7ce382",
+ "reference": "55f4261989e546dc112258c7a75935a81a7ce382",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.3",
+ "sebastian/diff": "^4.0",
+ "sebastian/exporter": "^4.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.3"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "4.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ },
+ {
+ "name": "Jeff Welch",
+ "email": "whatthejeff@gmail.com"
+ },
+ {
+ "name": "Volker Dusch",
+ "email": "github@wallbash.com"
+ },
+ {
+ "name": "Bernhard Schussek",
+ "email": "bschussek@2bepublished.at"
+ }
+ ],
+ "description": "Provides the functionality to compare PHP values for equality",
+ "homepage": "https://github.com/sebastianbergmann/comparator",
+ "keywords": [
+ "comparator",
+ "compare",
+ "equality"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/comparator/issues",
+ "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.6"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2020-10-26T15:49:45+00:00"
+ },
+ {
+ "name": "sebastian/complexity",
+ "version": "2.0.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/complexity.git",
+ "reference": "739b35e53379900cc9ac327b2147867b8b6efd88"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/739b35e53379900cc9ac327b2147867b8b6efd88",
+ "reference": "739b35e53379900cc9ac327b2147867b8b6efd88",
+ "shasum": ""
+ },
+ "require": {
+ "nikic/php-parser": "^4.7",
+ "php": ">=7.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.3"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Library for calculating the complexity of PHP code units",
+ "homepage": "https://github.com/sebastianbergmann/complexity",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/complexity/issues",
+ "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.2"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2020-10-26T15:52:27+00:00"
+ },
+ {
+ "name": "sebastian/diff",
+ "version": "4.0.4",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/diff.git",
+ "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/3461e3fccc7cfdfc2720be910d3bd73c69be590d",
+ "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.3",
+ "symfony/process": "^4.2 || ^5"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "4.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ },
+ {
+ "name": "Kore Nordmann",
+ "email": "mail@kore-nordmann.de"
+ }
+ ],
+ "description": "Diff implementation",
+ "homepage": "https://github.com/sebastianbergmann/diff",
+ "keywords": [
+ "diff",
+ "udiff",
+ "unidiff",
+ "unified diff"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/diff/issues",
+ "source": "https://github.com/sebastianbergmann/diff/tree/4.0.4"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2020-10-26T13:10:38+00:00"
+ },
+ {
+ "name": "sebastian/environment",
+ "version": "5.1.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/environment.git",
+ "reference": "388b6ced16caa751030f6a69e588299fa09200ac"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/388b6ced16caa751030f6a69e588299fa09200ac",
+ "reference": "388b6ced16caa751030f6a69e588299fa09200ac",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.3"
+ },
+ "suggest": {
+ "ext-posix": "*"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "5.1-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"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/environment/issues",
+ "source": "https://github.com/sebastianbergmann/environment/tree/5.1.3"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2020-09-28T05:52:38+00:00"
+ },
+ {
+ "name": "sebastian/exporter",
+ "version": "4.0.4",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/exporter.git",
+ "reference": "65e8b7db476c5dd267e65eea9cab77584d3cfff9"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/65e8b7db476c5dd267e65eea9cab77584d3cfff9",
+ "reference": "65e8b7db476c5dd267e65eea9cab77584d3cfff9",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.3",
+ "sebastian/recursion-context": "^4.0"
+ },
+ "require-dev": {
+ "ext-mbstring": "*",
+ "phpunit/phpunit": "^9.3"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "4.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ },
+ {
+ "name": "Jeff Welch",
+ "email": "whatthejeff@gmail.com"
+ },
+ {
+ "name": "Volker Dusch",
+ "email": "github@wallbash.com"
+ },
+ {
+ "name": "Adam Harvey",
+ "email": "aharvey@php.net"
+ },
+ {
+ "name": "Bernhard Schussek",
+ "email": "bschussek@gmail.com"
+ }
+ ],
+ "description": "Provides the functionality to export PHP variables for visualization",
+ "homepage": "https://www.github.com/sebastianbergmann/exporter",
+ "keywords": [
+ "export",
+ "exporter"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/exporter/issues",
+ "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.4"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2021-11-11T14:18:36+00:00"
+ },
+ {
+ "name": "sebastian/global-state",
+ "version": "5.0.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/global-state.git",
+ "reference": "23bd5951f7ff26f12d4e3242864df3e08dec4e49"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/23bd5951f7ff26f12d4e3242864df3e08dec4e49",
+ "reference": "23bd5951f7ff26f12d4e3242864df3e08dec4e49",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.3",
+ "sebastian/object-reflector": "^2.0",
+ "sebastian/recursion-context": "^4.0"
+ },
+ "require-dev": {
+ "ext-dom": "*",
+ "phpunit/phpunit": "^9.3"
+ },
+ "suggest": {
+ "ext-uopz": "*"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "5.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"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/global-state/issues",
+ "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.3"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2021-06-11T13:31:12+00:00"
+ },
+ {
+ "name": "sebastian/lines-of-code",
+ "version": "1.0.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/lines-of-code.git",
+ "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/c1c2e997aa3146983ed888ad08b15470a2e22ecc",
+ "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc",
+ "shasum": ""
+ },
+ "require": {
+ "nikic/php-parser": "^4.6",
+ "php": ">=7.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.3"
+ },
+ "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",
+ "role": "lead"
+ }
+ ],
+ "description": "Library for counting the lines of code in PHP source code",
+ "homepage": "https://github.com/sebastianbergmann/lines-of-code",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/lines-of-code/issues",
+ "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.3"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2020-11-28T06:42:11+00:00"
+ },
+ {
+ "name": "sebastian/object-enumerator",
+ "version": "4.0.4",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/object-enumerator.git",
+ "reference": "5c9eeac41b290a3712d88851518825ad78f45c71"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/5c9eeac41b290a3712d88851518825ad78f45c71",
+ "reference": "5c9eeac41b290a3712d88851518825ad78f45c71",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.3",
+ "sebastian/object-reflector": "^2.0",
+ "sebastian/recursion-context": "^4.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.3"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "4.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Traverses array structures and object graphs to enumerate all referenced objects",
+ "homepage": "https://github.com/sebastianbergmann/object-enumerator/",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/object-enumerator/issues",
+ "source": "https://github.com/sebastianbergmann/object-enumerator/tree/4.0.4"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2020-10-26T13:12:34+00:00"
+ },
+ {
+ "name": "sebastian/object-reflector",
+ "version": "2.0.4",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/object-reflector.git",
+ "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/b4f479ebdbf63ac605d183ece17d8d7fe49c15c7",
+ "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.3"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Allows reflection of object attributes, including inherited and non-public ones",
+ "homepage": "https://github.com/sebastianbergmann/object-reflector/",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/object-reflector/issues",
+ "source": "https://github.com/sebastianbergmann/object-reflector/tree/2.0.4"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2020-10-26T13:14:26+00:00"
+ },
+ {
+ "name": "sebastian/recursion-context",
+ "version": "4.0.4",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/recursion-context.git",
+ "reference": "cd9d8cf3c5804de4341c283ed787f099f5506172"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/cd9d8cf3c5804de4341c283ed787f099f5506172",
+ "reference": "cd9d8cf3c5804de4341c283ed787f099f5506172",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.3"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "4.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ },
+ {
+ "name": "Jeff Welch",
+ "email": "whatthejeff@gmail.com"
+ },
+ {
+ "name": "Adam Harvey",
+ "email": "aharvey@php.net"
+ }
+ ],
+ "description": "Provides functionality to recursively process PHP variables",
+ "homepage": "http://www.github.com/sebastianbergmann/recursion-context",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/recursion-context/issues",
+ "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.4"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2020-10-26T13:17:30+00:00"
+ },
+ {
+ "name": "sebastian/resource-operations",
+ "version": "3.0.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/resource-operations.git",
+ "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8",
+ "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Provides a list of PHP built-in functions that operate on resources",
+ "homepage": "https://www.github.com/sebastianbergmann/resource-operations",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/resource-operations/issues",
+ "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.3"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2020-09-28T06:45:17+00:00"
+ },
+ {
+ "name": "sebastian/type",
+ "version": "2.3.4",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/type.git",
+ "reference": "b8cd8a1c753c90bc1a0f5372170e3e489136f914"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/b8cd8a1c753c90bc1a0f5372170e3e489136f914",
+ "reference": "b8cd8a1c753c90bc1a0f5372170e3e489136f914",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.3"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.3-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": "Collection of value objects that represent the types of the PHP type system",
+ "homepage": "https://github.com/sebastianbergmann/type",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/type/issues",
+ "source": "https://github.com/sebastianbergmann/type/tree/2.3.4"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2021-06-15T12:49:02+00:00"
+ },
+ {
+ "name": "sebastian/version",
+ "version": "3.0.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/version.git",
+ "reference": "c6c1022351a901512170118436c764e473f6de8c"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c6c1022351a901512170118436c764e473f6de8c",
+ "reference": "c6c1022351a901512170118436c764e473f6de8c",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.3"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "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",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/version/issues",
+ "source": "https://github.com/sebastianbergmann/version/tree/3.0.2"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2020-09-28T06:39:44+00:00"
+ },
+ {
+ "name": "squizlabs/php_codesniffer",
+ "version": "3.6.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/squizlabs/PHP_CodeSniffer.git",
+ "reference": "f268ca40d54617c6e06757f83f699775c9b3ff2e"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/f268ca40d54617c6e06757f83f699775c9b3ff2e",
+ "reference": "f268ca40d54617c6e06757f83f699775c9b3ff2e",
+ "shasum": ""
+ },
+ "require": {
+ "ext-simplexml": "*",
+ "ext-tokenizer": "*",
+ "ext-xmlwriter": "*",
+ "php": ">=5.4.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0"
+ },
+ "bin": [
+ "bin/phpcs",
+ "bin/phpcbf"
+ ],
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.x-dev"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Greg Sherwood",
+ "role": "lead"
+ }
+ ],
+ "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.",
+ "homepage": "https://github.com/squizlabs/PHP_CodeSniffer",
+ "keywords": [
+ "phpcs",
+ "standards"
+ ],
+ "support": {
+ "issues": "https://github.com/squizlabs/PHP_CodeSniffer/issues",
+ "source": "https://github.com/squizlabs/PHP_CodeSniffer",
+ "wiki": "https://github.com/squizlabs/PHP_CodeSniffer/wiki"
+ },
+ "time": "2021-10-11T04:00:11+00:00"
+ },
+ {
+ "name": "symfony/polyfill-ctype",
+ "version": "v1.23.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-ctype.git",
+ "reference": "46cd95797e9df938fdd2b03693b5fca5e64b01ce"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/46cd95797e9df938fdd2b03693b5fca5e64b01ce",
+ "reference": "46cd95797e9df938fdd2b03693b5fca5e64b01ce",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.1"
+ },
+ "suggest": {
+ "ext-ctype": "For best performance"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "1.23-dev"
+ },
+ "thanks": {
+ "name": "symfony/polyfill",
+ "url": "https://github.com/symfony/polyfill"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Polyfill\\Ctype\\": ""
+ },
+ "files": [
+ "bootstrap.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Gert de Pagter",
+ "email": "BackEndTea@gmail.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony polyfill for ctype functions",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "ctype",
+ "polyfill",
+ "portable"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/polyfill-ctype/tree/v1.23.0"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2021-02-19T12:13:01+00:00"
+ },
+ {
+ "name": "theseer/tokenizer",
+ "version": "1.2.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/theseer/tokenizer.git",
+ "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/theseer/tokenizer/zipball/34a41e998c2183e22995f158c581e7b5e755ab9e",
+ "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e",
+ "shasum": ""
+ },
+ "require": {
+ "ext-dom": "*",
+ "ext-tokenizer": "*",
+ "ext-xmlwriter": "*",
+ "php": "^7.2 || ^8.0"
+ },
+ "type": "library",
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Arne Blankerts",
+ "email": "arne@blankerts.de",
+ "role": "Developer"
+ }
+ ],
+ "description": "A small library for converting tokenized PHP source code into XML and potentially other formats",
+ "support": {
+ "issues": "https://github.com/theseer/tokenizer/issues",
+ "source": "https://github.com/theseer/tokenizer/tree/1.2.1"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/theseer",
+ "type": "github"
+ }
+ ],
+ "time": "2021-07-28T10:34:58+00:00"
+ },
+ {
+ "name": "webmozart/assert",
+ "version": "1.10.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/webmozarts/assert.git",
+ "reference": "6964c76c7804814a842473e0c8fd15bab0f18e25"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/webmozarts/assert/zipball/6964c76c7804814a842473e0c8fd15bab0f18e25",
+ "reference": "6964c76c7804814a842473e0c8fd15bab0f18e25",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.2 || ^8.0",
+ "symfony/polyfill-ctype": "^1.8"
+ },
+ "conflict": {
+ "phpstan/phpstan": "<0.12.20",
+ "vimeo/psalm": "<4.6.1 || 4.6.2"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^8.5.13"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.10-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"
+ ],
+ "support": {
+ "issues": "https://github.com/webmozarts/assert/issues",
+ "source": "https://github.com/webmozarts/assert/tree/1.10.0"
+ },
+ "time": "2021-03-09T10:59:23+00:00"
+ }
+ ],
+ "aliases": [
+ {
+ "package": "squizlabs/php_codesniffer",
+ "version": "3.6.1.0",
+ "alias": "2.9999999.9999999",
+ "alias_normalized": "2.9999999.9999999.0"
+ }
+ ],
+ "minimum-stability": "stable",
+ "stability-flags": [],
+ "prefer-stable": false,
+ "prefer-lowest": false,
+ "platform": {
+ "php": "^7.3 || ~8.0.0 || ~8.1.0",
+ "ext-dom": "*",
+ "ext-simplexml": "*"
+ },
+ "platform-dev": {
+ "ext-iconv": "*"
+ },
+ "plugin-api-version": "2.1.0"
+}
diff --git a/config/www/user/plugins/admin/vendor/laminas/laminas-xml/src/Exception/ExceptionInterface.php b/config/www/user/plugins/admin/vendor/laminas/laminas-xml/src/Exception/ExceptionInterface.php
new file mode 100644
index 0000000..8856393
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/laminas/laminas-xml/src/Exception/ExceptionInterface.php
@@ -0,0 +1,7 @@
+ 0) {
+ return true;
+ }
+ return false;
+ }, E_WARNING);
+
+ $result = $callback($xml, $dom, LIBXML_NONET | $libXmlConstants);
+
+ restore_error_handler();
+
+ if (! $result) {
+ // Entity load to previous setting
+ if (! self::isPhpFpm()) {
+ if (\PHP_VERSION_ID < 80000) {
+ 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()) {
+ if (\PHP_VERSION_ID < 80000) {
+ 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 string for potential XXE and XEE attacks
+ *
+ * @param string $xml
+ * @param DomDocument $dom
+ * @param int $libXmlConstants additional libxml constants to pass in
+ * @throws Exception\RuntimeException
+ * @return SimpleXMLElement|DomDocument|boolean
+ */
+ public static function scan($xml, DOMDocument $dom = null, $libXmlConstants = 0)
+ {
+ $callback = function ($xml, $dom, $constants) {
+ return $dom->loadXml($xml, $constants);
+ };
+ return self::scanString($xml, $dom, $libXmlConstants, $callback);
+ }
+
+ /**
+ * Scan HTML string for potential XXE and XEE attacks
+ *
+ * @param string $xml
+ * @param DomDocument $dom
+ * @param int $libXmlConstants additional libxml constants to pass in
+ * @throws Exception\RuntimeException
+ * @return SimpleXMLElement|DomDocument|boolean
+ */
+ public static function scanHtml($html, DOMDocument $dom = null, $libXmlConstants = 0)
+ {
+ $callback = function ($html, $dom, $constants) {
+ return $dom->loadHtml($html, $constants);
+ };
+ return self::scanString($html, $dom, $libXmlConstants, $callback);
+ }
+
+ /**
+ * 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.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.6', 'ge')
+ && version_compare(PHP_VERSION, '5.6.6', 'lt');
+
+ if (0 === strpos(php_sapi_name(), '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 [$fileEncoding];
+ }
+
+ $encPos = strpos($xml, $encAttr);
+ if (false === $encPos
+ || $encPos > $closePos
+ ) {
+ return [$fileEncoding];
+ }
+
+ $encPos += strlen($encAttr);
+ $quotePos = strpos($xml, $quote, $encPos);
+ if (false === $quotePos) {
+ return [$fileEncoding];
+ }
+
+ $encoding = self::substr($xml, $encPos, $quotePos);
+ return [
+ // 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 [
+ [
+ 'encoding' => 'UTF-32BE',
+ 'bom' => pack('CCCC', 0x00, 0x00, 0xfe, 0xff),
+ 'length' => 4,
+ ],
+ [
+ 'encoding' => 'UTF-32LE',
+ 'bom' => pack('CCCC', 0xff, 0xfe, 0x00, 0x00),
+ 'length' => 4,
+ ],
+ [
+ 'encoding' => 'GB-18030',
+ 'bom' => pack('CCCC', 0x84, 0x31, 0x95, 0x33),
+ 'length' => 4,
+ ],
+ [
+ 'encoding' => 'UTF-16BE',
+ 'bom' => pack('CC', 0xfe, 0xff),
+ 'length' => 2,
+ ],
+ [
+ 'encoding' => 'UTF-16LE',
+ 'bom' => pack('CC', 0xff, 0xfe),
+ 'length' => 2,
+ ],
+ [
+ '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 [
+ '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/config/www/user/plugins/admin/vendor/p3k/picofeed/LICENSE b/config/www/user/plugins/admin/vendor/p3k/picofeed/LICENSE
new file mode 100644
index 0000000..6a362bc
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/picofeed/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2015 Frederic Guillot
+
+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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Base.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Base.php
new file mode 100644
index 0000000..41a6f8f
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Base.php
@@ -0,0 +1,38 @@
+config = $config ?: new Config();
+ Logger::setTimezone($this->config->getTimezone());
+ }
+
+ public function setConfig(Config $config) {
+ $this->config = $config;
+ }
+}
diff --git a/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Client/Client.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Client/Client.php
new file mode 100644
index 0000000..333eee6
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Client/Client.php
@@ -0,0 +1,712 @@
+request_headers = $headers;
+ }
+
+ /**
+ * Perform the HTTP request.
+ *
+ * @param string $url URL
+ *
+ * @return Client
+ */
+ public function execute($url = '')
+ {
+ if ($url !== '') {
+ $this->url = $url;
+ }
+
+ Logger::setMessage(get_called_class().' Fetch URL: '.$this->url);
+ Logger::setMessage(get_called_class().' Etag provided: '.$this->etag);
+ Logger::setMessage(get_called_class().' Last-Modified provided: '.$this->last_modified);
+
+ $response = $this->doRequest();
+
+ $this->status_code = $response['status'];
+ $this->handleNotModifiedResponse($response);
+ $this->handleErrorResponse($response);
+ $this->handleNormalResponse($response);
+
+ $this->expiration = $this->parseExpiration($response['headers']);
+ Logger::setMessage(get_called_class().' Expiration: '.$this->expiration->format(DATE_ISO8601));
+
+ return $this;
+ }
+
+ /**
+ * Handle not modified response.
+ *
+ * @param array $response Client response
+ */
+ protected function handleNotModifiedResponse(array $response)
+ {
+ if ($response['status'] == 304) {
+ $this->is_modified = false;
+ } elseif ($response['status'] == 200) {
+ $this->is_modified = $this->hasBeenModified($response, $this->etag, $this->last_modified);
+ $this->etag = $this->getHeader($response, 'ETag');
+ $this->last_modified = $this->getHeader($response, 'Last-Modified');
+ }
+
+ if ($this->is_modified === false) {
+ Logger::setMessage(get_called_class().' Resource not modified');
+ }
+ }
+
+ /**
+ * Handle Http Error codes
+ *
+ * @param array $response Client response
+ * @throws ForbiddenException
+ * @throws InvalidUrlException
+ * @throws UnauthorizedException
+ */
+ protected function handleErrorResponse(array $response)
+ {
+ $status = $response['status'];
+ if ($status == 401) {
+ throw new UnauthorizedException('Wrong or missing credentials');
+ } else if ($status == 403) {
+ throw new ForbiddenException('Not allowed to access resource');
+ } else if ($status == 404) {
+ throw new InvalidUrlException('Resource not found');
+ }
+ }
+
+ /**
+ * Handle normal response.
+ *
+ * @param array $response Client response
+ */
+ protected function handleNormalResponse(array $response)
+ {
+ if ($response['status'] == 200) {
+ $this->content = $response['body'];
+ $this->content_type = $this->findContentType($response);
+ $this->encoding = $this->findCharset();
+ }
+ }
+
+ /**
+ * Check if a request has been modified according to the parameters.
+ *
+ * @param array $response
+ * @param string $etag
+ * @param string $lastModified
+ *
+ * @return bool
+ */
+ private function hasBeenModified($response, $etag, $lastModified)
+ {
+ $headers = array(
+ 'Etag' => $etag,
+ 'Last-Modified' => $lastModified,
+ );
+
+ // Compare the values for each header that is present
+ $presentCacheHeaderCount = 0;
+ foreach ($headers as $key => $value) {
+ if (isset($response['headers'][$key])) {
+ if ($response['headers'][$key] !== $value) {
+ return true;
+ }
+ ++$presentCacheHeaderCount;
+ }
+ }
+
+ // If at least one header is present and the values match, the response
+ // was not modified
+ if ($presentCacheHeaderCount > 0) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Find content type from response headers.
+ *
+ * @param array $response Client response
+ * @return string
+ */
+ public function findContentType(array $response)
+ {
+ return strtolower($this->getHeader($response, 'Content-Type'));
+ }
+
+ /**
+ * Find charset from response headers.
+ *
+ * @return string
+ */
+ public function findCharset()
+ {
+ $result = explode('charset=', $this->content_type);
+ return isset($result[1]) ? $result[1] : '';
+ }
+
+ /**
+ * Get header value from a client response.
+ *
+ * @param array $response Client response
+ * @param string $header Header name
+ * @return string
+ */
+ public function getHeader(array $response, $header)
+ {
+ return isset($response['headers'][$header]) ? $response['headers'][$header] : '';
+ }
+
+ /**
+ * Set the Last-Modified HTTP header.
+ *
+ * @param string $last_modified Header value
+ * @return $this
+ */
+ public function setLastModified($last_modified)
+ {
+ $this->last_modified = $last_modified;
+ return $this;
+ }
+
+ /**
+ * Get the value of the Last-Modified HTTP header.
+ *
+ * @return string
+ */
+ public function getLastModified()
+ {
+ return $this->last_modified;
+ }
+
+ /**
+ * Set the value of the Etag HTTP header.
+ *
+ * @param string $etag Etag HTTP header value
+ * @return $this
+ */
+ public function setEtag($etag)
+ {
+ $this->etag = $etag;
+ return $this;
+ }
+
+ /**
+ * Get the Etag HTTP header value.
+ *
+ * @return string
+ */
+ public function getEtag()
+ {
+ return $this->etag;
+ }
+
+ /**
+ * Get the final url value.
+ *
+ * @return string
+ */
+ public function getUrl()
+ {
+ return $this->url;
+ }
+
+ /**
+ * Set the url.
+ *
+ * @param $url
+ * @return string
+ */
+ public function setUrl($url)
+ {
+ $this->url = $url;
+ return $this;
+ }
+
+ /**
+ * Get the HTTP response status code.
+ *
+ * @return int
+ */
+ public function getStatusCode()
+ {
+ return $this->status_code;
+ }
+
+ /**
+ * Get the body of the HTTP response.
+ *
+ * @return string
+ */
+ public function getContent()
+ {
+ return $this->content;
+ }
+
+ /**
+ * Get the content type value from HTTP headers.
+ *
+ * @return string
+ */
+ public function getContentType()
+ {
+ return $this->content_type;
+ }
+
+ /**
+ * Get the encoding value from HTTP headers.
+ *
+ * @return string
+ */
+ public function getEncoding()
+ {
+ return $this->encoding;
+ }
+
+ /**
+ * Return true if the remote resource has changed.
+ *
+ * @return bool
+ */
+ public function isModified()
+ {
+ return $this->is_modified;
+ }
+
+ /**
+ * return true if passthrough mode is enabled.
+ *
+ * @return bool
+ */
+ public function isPassthroughEnabled()
+ {
+ return $this->passthrough;
+ }
+
+ /**
+ * Set connection timeout.
+ *
+ * @param int $timeout Connection timeout
+ * @return $this
+ */
+ public function setTimeout($timeout)
+ {
+ $this->timeout = $timeout ?: $this->timeout;
+ return $this;
+ }
+
+ /**
+ * Set a custom user agent.
+ *
+ * @param string $user_agent User Agent
+ * @return $this
+ */
+ public function setUserAgent($user_agent)
+ {
+ $this->user_agent = $user_agent ?: $this->user_agent;
+ return $this;
+ }
+
+ /**
+ * Set the maximum number of HTTP redirections.
+ *
+ * @param int $max Maximum
+ * @return $this
+ */
+ public function setMaxRedirections($max)
+ {
+ $this->max_redirects = $max ?: $this->max_redirects;
+ return $this;
+ }
+
+ /**
+ * Set the maximum size of the HTTP body.
+ *
+ * @param int $max Maximum
+ * @return $this
+ */
+ public function setMaxBodySize($max)
+ {
+ $this->max_body_size = $max ?: $this->max_body_size;
+ return $this;
+ }
+
+ /**
+ * Set the proxy hostname.
+ *
+ * @param string $hostname Proxy hostname
+ * @return $this
+ */
+ public function setProxyHostname($hostname)
+ {
+ $this->proxy_hostname = $hostname ?: $this->proxy_hostname;
+ return $this;
+ }
+
+ /**
+ * Set the proxy port.
+ *
+ * @param int $port Proxy port
+ * @return $this
+ */
+ public function setProxyPort($port)
+ {
+ $this->proxy_port = $port ?: $this->proxy_port;
+ return $this;
+ }
+
+ /**
+ * Set the proxy username.
+ *
+ * @param string $username Proxy username
+ * @return $this
+ */
+ public function setProxyUsername($username)
+ {
+ $this->proxy_username = $username ?: $this->proxy_username;
+ return $this;
+ }
+
+ /**
+ * Set the proxy password.
+ *
+ * @param string $password Password
+ * @return $this
+ */
+ public function setProxyPassword($password)
+ {
+ $this->proxy_password = $password ?: $this->proxy_password;
+ return $this;
+ }
+
+ /**
+ * Set the username.
+ *
+ * @param string $username Basic Auth username
+ *
+ * @return $this
+ */
+ public function setUsername($username)
+ {
+ $this->username = $username ?: $this->username;
+ return $this;
+ }
+
+ /**
+ * Set the password.
+ *
+ * @param string $password Basic Auth Password
+ *
+ * @return $this
+ */
+ public function setPassword($password)
+ {
+ $this->password = $password ?: $this->password;
+ return $this;
+ }
+
+ /**
+ * Set the CURL options.
+ *
+ * @param array $options
+ * @return $this
+ */
+ public function setAdditionalCurlOptions(array $options)
+ {
+ $this->additional_curl_options = $options ?: $this->additional_curl_options;
+ return $this;
+ }
+
+
+ /**
+ * Enable the passthrough mode.
+ *
+ * @return $this
+ */
+ public function enablePassthroughMode()
+ {
+ $this->passthrough = true;
+ return $this;
+ }
+
+ /**
+ * Disable the passthrough mode.
+ *
+ * @return $this
+ */
+ public function disablePassthroughMode()
+ {
+ $this->passthrough = false;
+ return $this;
+ }
+
+ /**
+ * Set config object.
+ *
+ * @param \PicoFeed\Config\Config $config Config instance
+ * @return $this
+ */
+ public function setConfig(Config $config)
+ {
+ if ($config !== null) {
+ $this->setTimeout($config->getClientTimeout());
+ $this->setUserAgent($config->getClientUserAgent());
+ $this->setMaxRedirections($config->getMaxRedirections());
+ $this->setMaxBodySize($config->getMaxBodySize());
+ $this->setProxyHostname($config->getProxyHostname());
+ $this->setProxyPort($config->getProxyPort());
+ $this->setProxyUsername($config->getProxyUsername());
+ $this->setProxyPassword($config->getProxyPassword());
+ $this->setAdditionalCurlOptions($config->getAdditionalCurlOptions() ?: array());
+ }
+
+ return $this;
+ }
+
+ /**
+ * Return true if the HTTP status code is a redirection
+ *
+ * @access protected
+ * @param integer $code
+ * @return boolean
+ */
+ public function isRedirection($code)
+ {
+ return $code == 301 || $code == 302 || $code == 303 || $code == 307;
+ }
+
+ public function parseExpiration(HttpHeaders $headers)
+ {
+ try {
+
+ if (isset($headers['Cache-Control'])) {
+ if (preg_match('/s-maxage=(\d+)/', $headers['Cache-Control'], $matches)) {
+ return new DateTime('+' . $matches[1] . ' seconds');
+ } else if (preg_match('/max-age=(\d+)/', $headers['Cache-Control'], $matches)) {
+ return new DateTime('+' . $matches[1] . ' seconds');
+ }
+ }
+
+ if (! empty($headers['Expires'])) {
+ return new DateTime($headers['Expires']);
+ }
+ } catch (Exception $e) {
+ Logger::setMessage('Unable to parse expiration date: '.$e->getMessage());
+ }
+
+ return new DateTime();
+ }
+
+ /**
+ * Get expiration date time from "Expires" or "Cache-Control" headers
+ *
+ * @return DateTime
+ */
+ public function getExpiration()
+ {
+ return $this->expiration ?: new DateTime();
+ }
+}
diff --git a/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Client/ClientException.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Client/ClientException.php
new file mode 100644
index 0000000..b3a95c9
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Client/ClientException.php
@@ -0,0 +1,14 @@
+body_length += $length;
+
+ if ($this->body_length > $this->max_body_size) {
+ return -1;
+ }
+
+ $this->body .= $buffer;
+
+ return $length;
+ }
+
+ /**
+ * cURL callback to read HTTP headers.
+ *
+ * @param resource $ch cURL handler
+ * @param string $buffer Header line
+ *
+ * @return int Length of the buffer
+ */
+ public function readHeaders($ch, $buffer)
+ {
+ $length = strlen($buffer);
+
+ if ($buffer === "\r\n" || $buffer === "\n") {
+ ++$this->response_headers_count;
+ } else {
+ if (!isset($this->response_headers[$this->response_headers_count])) {
+ $this->response_headers[$this->response_headers_count] = '';
+ }
+
+ $this->response_headers[$this->response_headers_count] .= $buffer;
+ }
+
+ return $length;
+ }
+
+ /**
+ * cURL callback to passthrough the HTTP body to the client.
+ *
+ * If the function return -1, curl stop to read the HTTP response
+ *
+ * @param resource $ch cURL handler
+ * @param string $buffer Chunk of data
+ *
+ * @return int Length of the buffer
+ */
+ public function passthroughBody($ch, $buffer)
+ {
+ // do it only at the beginning of a transmission
+ if ($this->body_length === 0) {
+ list($status, $headers) = HttpHeaders::parse(explode("\n", $this->response_headers[$this->response_headers_count - 1]));
+
+ if ($this->isRedirection($status)) {
+ return $this->handleRedirection($headers['Location']);
+ }
+
+ if (isset($headers['Content-Type'])) {
+ header('Content-Type:' .$headers['Content-Type']);
+ }
+ }
+
+ $length = strlen($buffer);
+ $this->body_length += $length;
+
+ echo $buffer;
+
+ return $length;
+ }
+
+ /**
+ * Prepare HTTP headers.
+ *
+ * @return string[]
+ */
+ private function prepareHeaders()
+ {
+ $headers = array(
+ 'Connection: close',
+ );
+
+ if ($this->etag) {
+ $headers[] = 'If-None-Match: '.$this->etag;
+ $headers[] = 'A-IM: feed';
+ }
+
+ if ($this->last_modified) {
+ $headers[] = 'If-Modified-Since: '.$this->last_modified;
+ }
+
+ $headers = array_merge($headers, $this->request_headers);
+
+ return $headers;
+ }
+
+ /**
+ * Prepare curl proxy context.
+ *
+ * @param resource $ch
+ *
+ * @return resource $ch
+ */
+ private function prepareProxyContext($ch)
+ {
+ if ($this->proxy_hostname) {
+ Logger::setMessage(get_called_class().' Proxy: '.$this->proxy_hostname.':'.$this->proxy_port);
+
+ curl_setopt($ch, CURLOPT_PROXYPORT, $this->proxy_port);
+ curl_setopt($ch, CURLOPT_PROXYTYPE, 'HTTP');
+ curl_setopt($ch, CURLOPT_PROXY, $this->proxy_hostname);
+
+ if ($this->proxy_username) {
+ Logger::setMessage(get_called_class().' Proxy credentials: Yes');
+ curl_setopt($ch, CURLOPT_PROXYUSERPWD, $this->proxy_username.':'.$this->proxy_password);
+ } else {
+ Logger::setMessage(get_called_class().' Proxy credentials: No');
+ }
+ }
+
+ return $ch;
+ }
+
+ /**
+ * Prepare curl auth context.
+ *
+ * @param resource $ch
+ *
+ * @return resource $ch
+ */
+ private function prepareAuthContext($ch)
+ {
+ if ($this->username && $this->password) {
+ curl_setopt($ch, CURLOPT_USERPWD, $this->username.':'.$this->password);
+ }
+
+ return $ch;
+ }
+
+ /**
+ * Set write/header functions.
+ *
+ * @param resource $ch
+ *
+ * @return resource $ch
+ */
+ private function prepareDownloadMode($ch)
+ {
+ $this->body = '';
+ $this->response_headers = array();
+ $this->response_headers_count = 0;
+ $write_function = 'readBody';
+ $header_function = 'readHeaders';
+
+ if ($this->isPassthroughEnabled()) {
+ $write_function = 'passthroughBody';
+ }
+
+ curl_setopt($ch, CURLOPT_WRITEFUNCTION, array($this, $write_function));
+ curl_setopt($ch, CURLOPT_HEADERFUNCTION, array($this, $header_function));
+
+ return $ch;
+ }
+
+ /**
+ * Set additional CURL options.
+ *
+ * @param resource $ch
+ *
+ * @return resource $ch
+ */
+ private function prepareAdditionalCurlOptions($ch){
+ foreach( $this->additional_curl_options as $c_op => $c_val ){
+ curl_setopt($ch, $c_op, $c_val);
+ }
+ return $ch;
+ }
+
+ /**
+ * Prepare curl context.
+ *
+ * @return resource
+ */
+ private function prepareContext()
+ {
+ $ch = curl_init();
+
+ curl_setopt($ch, CURLOPT_URL, $this->url);
+ curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+ curl_setopt($ch, CURLOPT_TIMEOUT, $this->timeout);
+ curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $this->timeout);
+ curl_setopt($ch, CURLOPT_USERAGENT, $this->user_agent);
+ curl_setopt($ch, CURLOPT_HTTPHEADER, $this->prepareHeaders());
+ curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false);
+ curl_setopt($ch, CURLOPT_ENCODING, '');
+ curl_setopt($ch, CURLOPT_COOKIEJAR, 'php://memory');
+ curl_setopt($ch, CURLOPT_COOKIEFILE, 'php://memory');
+
+ // Disable SSLv3 by enforcing TLSv1.x for curl >= 7.34.0 and < 7.39.0.
+ // Versions prior to 7.34 and at least when compiled against openssl
+ // interpret this parameter as "limit to TLSv1.0" which fails for sites
+ // which enforce TLS 1.1+.
+ // Starting with curl 7.39.0 SSLv3 is disabled by default.
+ $version = curl_version();
+ if ($version['version_number'] >= 467456 && $version['version_number'] < 468736) {
+ curl_setopt($ch, CURLOPT_SSLVERSION, 1);
+ }
+
+ $ch = $this->prepareDownloadMode($ch);
+ $ch = $this->prepareProxyContext($ch);
+ $ch = $this->prepareAuthContext($ch);
+ $ch = $this->prepareAdditionalCurlOptions($ch);
+
+ return $ch;
+ }
+
+ /**
+ * Execute curl context.
+ */
+ private function executeContext()
+ {
+ $ch = $this->prepareContext();
+ curl_exec($ch);
+
+ Logger::setMessage(get_called_class().' cURL total time: '.curl_getinfo($ch, CURLINFO_TOTAL_TIME));
+ Logger::setMessage(get_called_class().' cURL dns lookup time: '.curl_getinfo($ch, CURLINFO_NAMELOOKUP_TIME));
+ Logger::setMessage(get_called_class().' cURL connect time: '.curl_getinfo($ch, CURLINFO_CONNECT_TIME));
+ Logger::setMessage(get_called_class().' cURL speed download: '.curl_getinfo($ch, CURLINFO_SPEED_DOWNLOAD));
+ Logger::setMessage(get_called_class().' cURL effective url: '.curl_getinfo($ch, CURLINFO_EFFECTIVE_URL));
+
+ $curl_errno = curl_errno($ch);
+
+ if ($curl_errno) {
+ Logger::setMessage(get_called_class().' cURL error: '.curl_error($ch));
+ curl_close($ch);
+
+ $this->handleError($curl_errno);
+ }
+
+ // Update the url if there where redirects
+ $this->url = curl_getinfo($ch, CURLINFO_EFFECTIVE_URL);
+
+ curl_close($ch);
+ }
+
+ /**
+ * Do the HTTP request.
+ *
+ * @return array HTTP response ['body' => ..., 'status' => ..., 'headers' => ...]
+ */
+ public function doRequest()
+ {
+ $this->executeContext();
+
+ list($status, $headers) = HttpHeaders::parse(explode("\n", $this->response_headers[$this->response_headers_count - 1]));
+
+ if ($this->isRedirection($status)) {
+ if (empty($headers['Location'])) {
+ $status = 200;
+ } else {
+ return $this->handleRedirection($headers['Location']);
+ }
+ }
+
+ return array(
+ 'status' => $status,
+ 'body' => $this->body,
+ 'headers' => $headers,
+ );
+ }
+
+ /**
+ * Handle HTTP redirects
+ *
+ * @param string $location Redirected URL
+ * @return array
+ * @throws MaxRedirectException
+ */
+ private function handleRedirection($location)
+ {
+ $result = array();
+ $this->url = Url::resolve($location, $this->url);
+ $this->body = '';
+ $this->body_length = 0;
+ $this->response_headers = array();
+ $this->response_headers_count = 0;
+
+ while (true) {
+ $this->nbRedirects++;
+
+ if ($this->nbRedirects >= $this->max_redirects) {
+ throw new MaxRedirectException('Maximum number of redirections reached');
+ }
+
+ $result = $this->doRequest();
+
+ if ($this->isRedirection($result['status'])) {
+ $this->url = Url::resolve($result['headers']['Location'], $this->url);
+ $this->body = '';
+ $this->body_length = 0;
+ $this->response_headers = array();
+ $this->response_headers_count = 0;
+ } else {
+ break;
+ }
+ }
+
+ return $result;
+ }
+
+ /**
+ * Handle cURL errors (throw individual exceptions).
+ *
+ * We don't use constants because they are not necessary always available
+ * (depends of the version of libcurl linked to php)
+ *
+ * @see http://curl.haxx.se/libcurl/c/libcurl-errors.html
+ *
+ * @param int $errno cURL error code
+ * @throws InvalidCertificateException
+ * @throws InvalidUrlException
+ * @throws MaxRedirectException
+ * @throws MaxSizeException
+ * @throws TimeoutException
+ */
+ private function handleError($errno)
+ {
+ switch ($errno) {
+ case 78: // CURLE_REMOTE_FILE_NOT_FOUND
+ throw new InvalidUrlException('Resource not found', $errno);
+ case 6: // CURLE_COULDNT_RESOLVE_HOST
+ throw new InvalidUrlException('Unable to resolve hostname', $errno);
+ case 7: // CURLE_COULDNT_CONNECT
+ throw new InvalidUrlException('Unable to connect to the remote host', $errno);
+ case 23: // CURLE_WRITE_ERROR
+ throw new MaxSizeException('Maximum response size exceeded', $errno);
+ case 28: // CURLE_OPERATION_TIMEDOUT
+ throw new TimeoutException('Operation timeout', $errno);
+ case 35: // CURLE_SSL_CONNECT_ERROR
+ case 51: // CURLE_PEER_FAILED_VERIFICATION
+ case 58: // CURLE_SSL_CERTPROBLEM
+ case 60: // CURLE_SSL_CACERT
+ case 59: // CURLE_SSL_CIPHER
+ case 64: // CURLE_USE_SSL_FAILED
+ case 66: // CURLE_SSL_ENGINE_INITFAILED
+ case 77: // CURLE_SSL_CACERT_BADFILE
+ case 83: // CURLE_SSL_ISSUER_ERROR
+ $msg = 'Invalid SSL certificate caused by CURL error number ' . $errno;
+ throw new InvalidCertificateException($msg, $errno);
+ case 47: // CURLE_TOO_MANY_REDIRECTS
+ throw new MaxRedirectException('Maximum number of redirections reached', $errno);
+ case 63: // CURLE_FILESIZE_EXCEEDED
+ throw new MaxSizeException('Maximum response size exceeded', $errno);
+ default:
+ throw new InvalidUrlException('Unable to fetch the URL', $errno);
+ }
+ }
+}
diff --git a/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Client/ForbiddenException.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Client/ForbiddenException.php
new file mode 100644
index 0000000..c226e95
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Client/ForbiddenException.php
@@ -0,0 +1,10 @@
+ $value) {
+ $this->headers[strtolower($key)] = $value;
+ }
+ }
+
+ public function offsetGet($offset)
+ {
+ return $this->offsetExists($offset) ? $this->headers[strtolower($offset)] : '';
+ }
+
+ public function offsetSet($offset, $value)
+ {
+ $this->headers[strtolower($offset)] = $value;
+ }
+
+ public function offsetExists($offset)
+ {
+ return isset($this->headers[strtolower($offset)]);
+ }
+
+ public function offsetUnset($offset)
+ {
+ unset($this->headers[strtolower($offset)]);
+ }
+
+ /**
+ * Parse HTTP headers.
+ *
+ * @static
+ *
+ * @param array $lines List of headers
+ *
+ * @return array
+ */
+ public static function parse(array $lines)
+ {
+ $status = 0;
+ $headers = array();
+
+ foreach ($lines as $line) {
+ if (strpos($line, 'HTTP/1') === 0) {
+ $headers = array();
+ $status = (int) substr($line, 9, 3);
+ } elseif (strpos($line, ': ') !== false) {
+ list($name, $value) = explode(': ', $line);
+ if ($value) {
+ $headers[trim($name)] = trim($value);
+ }
+ }
+ }
+
+ Logger::setMessage(get_called_class().' HTTP status code: '.$status);
+
+ foreach ($headers as $name => $value) {
+ Logger::setMessage(get_called_class().' HTTP header: '.$name.' => '.$value);
+ }
+
+ return array($status, new self($headers));
+ }
+}
diff --git a/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Client/InvalidCertificateException.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Client/InvalidCertificateException.php
new file mode 100644
index 0000000..8d25d7e
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Client/InvalidCertificateException.php
@@ -0,0 +1,12 @@
+user_agent,
+ );
+
+ // disable compression in passthrough mode. It could result in double
+ // compressed content which isn't decodeable by browsers
+ if (function_exists('gzdecode') && !$this->isPassthroughEnabled()) {
+ $headers[] = 'Accept-Encoding: gzip';
+ }
+
+ if ($this->etag) {
+ $headers[] = 'If-None-Match: '.$this->etag;
+ $headers[] = 'A-IM: feed';
+ }
+
+ if ($this->last_modified) {
+ $headers[] = 'If-Modified-Since: '.$this->last_modified;
+ }
+
+ if ($this->proxy_username) {
+ $headers[] = 'Proxy-Authorization: Basic '.base64_encode($this->proxy_username.':'.$this->proxy_password);
+ }
+
+ if ($this->username && $this->password) {
+ $headers[] = 'Authorization: Basic '.base64_encode($this->username.':'.$this->password);
+ }
+
+ $headers = array_merge($headers, $this->request_headers);
+
+ return $headers;
+ }
+
+ /**
+ * Construct the final URL from location headers.
+ *
+ * @param array $headers List of HTTP response header
+ */
+ private function setEffectiveUrl($headers)
+ {
+ foreach ($headers as $header) {
+ if (stripos($header, 'Location') === 0) {
+ list(, $value) = explode(': ', $header);
+
+ $this->url = Url::resolve($value, $this->url);
+ }
+ }
+ }
+
+ /**
+ * Prepare stream context.
+ *
+ * @return array
+ */
+ private function prepareContext()
+ {
+ $context = array(
+ 'http' => array(
+ 'method' => 'GET',
+ 'protocol_version' => 1.1,
+ 'timeout' => $this->timeout,
+ 'max_redirects' => $this->max_redirects,
+ ),
+ );
+
+ if ($this->proxy_hostname) {
+ Logger::setMessage(get_called_class().' Proxy: '.$this->proxy_hostname.':'.$this->proxy_port);
+
+ $context['http']['proxy'] = 'tcp://'.$this->proxy_hostname.':'.$this->proxy_port;
+ $context['http']['request_fulluri'] = true;
+
+ if ($this->proxy_username) {
+ Logger::setMessage(get_called_class().' Proxy credentials: Yes');
+ } else {
+ Logger::setMessage(get_called_class().' Proxy credentials: No');
+ }
+ }
+
+ $context['http']['header'] = implode("\r\n", $this->prepareHeaders());
+
+ return $context;
+ }
+
+ /**
+ * Do the HTTP request.
+ *
+ * @return array HTTP response ['body' => ..., 'status' => ..., 'headers' => ...]
+ * @throws InvalidUrlException
+ * @throws MaxSizeException
+ * @throws TimeoutException
+ */
+ public function doRequest()
+ {
+ $body = '';
+
+ // Create context
+ $context = stream_context_create($this->prepareContext());
+
+ // Make HTTP request
+ $stream = @fopen($this->url, 'r', false, $context);
+ if (!is_resource($stream)) {
+ throw new InvalidUrlException('Unable to establish a connection');
+ }
+
+ // Get HTTP headers response
+ $metadata = stream_get_meta_data($stream);
+ list($status, $headers) = HttpHeaders::parse($metadata['wrapper_data']);
+
+ if ($this->isPassthroughEnabled()) {
+ header(':', true, $status);
+
+ if (isset($headers['Content-Type'])) {
+ header('Content-Type: '.$headers['Content-Type']);
+ }
+
+ fpassthru($stream);
+ } else {
+ // Get the entire body until the max size
+ $body = stream_get_contents($stream, $this->max_body_size + 1);
+
+ // If the body size is too large abort everything
+ if (strlen($body) > $this->max_body_size) {
+ throw new MaxSizeException('Content size too large');
+ }
+
+ if ($metadata['timed_out']) {
+ throw new TimeoutException('Operation timeout');
+ }
+ }
+
+ fclose($stream);
+
+ $this->setEffectiveUrl($metadata['wrapper_data']);
+
+ return array(
+ 'status' => $status,
+ 'body' => $this->decodeBody($body, $headers),
+ 'headers' => $headers,
+ );
+ }
+
+ /**
+ * Decode body response according to the HTTP headers.
+ *
+ * @param string $body Raw body
+ * @param HttpHeaders $headers HTTP headers
+ *
+ * @return string
+ */
+ public function decodeBody($body, HttpHeaders $headers)
+ {
+ if (isset($headers['Transfer-Encoding']) && $headers['Transfer-Encoding'] === 'chunked') {
+ $body = $this->decodeChunked($body);
+ }
+
+ if (isset($headers['Content-Encoding']) && $headers['Content-Encoding'] === 'gzip') {
+ $body = gzdecode($body);
+ }
+
+ return $body;
+ }
+
+ /**
+ * Decode a chunked body.
+ *
+ * @param string $str Raw body
+ *
+ * @return string Decoded body
+ */
+ public function decodeChunked($str)
+ {
+ for ($result = ''; !empty($str); $str = trim($str)) {
+
+ // Get the chunk length
+ $pos = strpos($str, "\r\n");
+ $len = hexdec(substr($str, 0, $pos));
+
+ // Append the chunk to the result
+ $result .= substr($str, $pos + 2, $len);
+ $str = substr($str, $pos + 2 + $len);
+ }
+
+ return $result;
+ }
+}
diff --git a/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Client/TimeoutException.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Client/TimeoutException.php
new file mode 100644
index 0000000..da98da1
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Client/TimeoutException.php
@@ -0,0 +1,12 @@
+url = $url;
+ $this->components = parse_url($url) ?: array();
+
+ // Issue with PHP < 5.4.7 and protocol relative url
+ if (version_compare(PHP_VERSION, '5.4.7', '<') && $this->isProtocolRelative()) {
+ $pos = strpos($this->components['path'], '/', 2);
+
+ if ($pos === false) {
+ $pos = strlen($this->components['path']);
+ }
+
+ $this->components['host'] = substr($this->components['path'], 2, $pos - 2);
+ $this->components['path'] = substr($this->components['path'], $pos);
+ }
+ }
+
+ /**
+ * Shortcut method to get an absolute url from relative url.
+ *
+ * @static
+ * @param mixed $item_url Unknown url (can be relative or not)
+ * @param mixed $website_url Website url
+ * @return string
+ */
+ public static function resolve($item_url, $website_url)
+ {
+ $link = is_string($item_url) ? new self($item_url) : $item_url;
+ $website = is_string($website_url) ? new self($website_url) : $website_url;
+
+ if ($link->isRelativeUrl()) {
+ if ($link->isRelativePath()) {
+ return $link->getAbsoluteUrl($website->getBaseUrl($website->getBasePath()));
+ }
+
+ return $link->getAbsoluteUrl($website->getBaseUrl());
+ } elseif ($link->isProtocolRelative()) {
+ $link->setScheme($website->getScheme());
+ }
+
+ return $link->getAbsoluteUrl();
+ }
+
+ /**
+ * Shortcut method to get a base url.
+ *
+ * @static
+ * @param string $url
+ * @return string
+ */
+ public static function base($url)
+ {
+ $link = new self($url);
+
+ return $link->getBaseUrl();
+ }
+
+ /**
+ * Get the base URL.
+ *
+ * @param string $suffix Add a suffix to the url
+ * @return string
+ */
+ public function getBaseUrl($suffix = '')
+ {
+ return $this->hasHost() ? $this->getScheme('://').$this->getHost().$this->getPort(':').$suffix : '';
+ }
+
+ /**
+ * Get the absolute URL.
+ *
+ * @param string $base_url Use this url as base url
+ * @return string
+ */
+ public function getAbsoluteUrl($base_url = '')
+ {
+ if ($base_url) {
+ $base = new self($base_url);
+ $url = $base->getAbsoluteUrl().substr($this->getFullPath(), 1);
+ } else {
+ $url = $this->hasHost() ? $this->getBaseUrl().$this->getFullPath() : '';
+ }
+
+ return $url;
+ }
+
+ /**
+ * Return true if the url is relative.
+ *
+ * @return bool
+ */
+ public function isRelativeUrl()
+ {
+ return !$this->hasScheme() && !$this->isProtocolRelative();
+ }
+
+ /**
+ * Return true if the path is relative.
+ *
+ * @return bool
+ */
+ public function isRelativePath()
+ {
+ $path = $this->getPath();
+
+ return empty($path) || $path[0]
+ !== '/';
+ }
+
+ /**
+ * Filters the path of a URI.
+ *
+ * Imported from Guzzle library: https://github.com/guzzle/psr7/blob/master/src/Uri.php#L568-L582
+ *
+ * @param $path
+ * @param string $charUnreserved
+ * @param string $charSubDelims
+ * @return string
+ */
+ public function filterPath($path, $charUnreserved = 'a-zA-Z0-9_\-\.~', $charSubDelims = '!\$&\'\(\)\*\+,;=')
+ {
+ return preg_replace_callback(
+ '/(?:[^'.$charUnreserved.$charSubDelims.':@\/%]+|%(?![A-Fa-f0-9]{2}))/',
+ function (array $matches) { return rawurlencode($matches[0]); },
+ $path
+ );
+ }
+
+ /**
+ * Get the path.
+ *
+ * @return string
+ */
+ public function getPath()
+ {
+ return $this->filterPath(empty($this->components['path']) ? '' : $this->components['path']);
+ }
+
+ /**
+ * Get the base path.
+ *
+ * @return string
+ */
+ public function getBasePath()
+ {
+ $current_path = $this->getPath();
+
+ $path = $this->isRelativePath() ? '/' : '';
+ $path .= substr($current_path, -1) === '/' ? $current_path : dirname($current_path);
+
+ return preg_replace('/\\\\\/|\/\//', '/', $path.'/');
+ }
+
+ /**
+ * Get the full path (path + querystring + fragment).
+ *
+ * @return string
+ */
+ public function getFullPath()
+ {
+ $path = $this->isRelativePath() ? '/' : '';
+ $path .= $this->getPath();
+ $path .= empty($this->components['query']) ? '' : '?'.$this->components['query'];
+ $path .= empty($this->components['fragment']) ? '' : '#'.$this->components['fragment'];
+
+ return $path;
+ }
+
+ /**
+ * Get the hostname.
+ *
+ * @return string
+ */
+ public function getHost()
+ {
+ return empty($this->components['host']) ? '' : $this->components['host'];
+ }
+
+ /**
+ * Return true if the url has a hostname.
+ *
+ * @return bool
+ */
+ public function hasHost()
+ {
+ return !empty($this->components['host']);
+ }
+
+ /**
+ * Get the scheme.
+ *
+ * @param string $suffix Suffix to add when there is a scheme
+ * @return string
+ */
+ public function getScheme($suffix = '')
+ {
+ return ($this->hasScheme() ? $this->components['scheme'] : 'http').$suffix;
+ }
+
+ /**
+ * Set the scheme.
+ *
+ * @param string $scheme Set a scheme
+ * @return $this
+ */
+ public function setScheme($scheme)
+ {
+ $this->components['scheme'] = $scheme;
+ return $this;
+ }
+
+ /**
+ * Return true if the url has a scheme.
+ *
+ * @return bool
+ */
+ public function hasScheme()
+ {
+ return !empty($this->components['scheme']);
+ }
+
+ /**
+ * Get the port.
+ *
+ * @param string $prefix Prefix to add when there is a port
+ * @return string
+ */
+ public function getPort($prefix = '')
+ {
+ return $this->hasPort() ? $prefix.$this->components['port'] : '';
+ }
+
+ /**
+ * Return true if the url has a port.
+ *
+ * @return bool
+ */
+ public function hasPort()
+ {
+ return !empty($this->components['port']);
+ }
+
+ /**
+ * Return true if the url is protocol relative (start with //).
+ *
+ * @return bool
+ */
+ public function isProtocolRelative()
+ {
+ return strpos($this->url, '//') === 0;
+ }
+}
diff --git a/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Config/Config.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Config/Config.php
new file mode 100644
index 0000000..1452d55
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Config/Config.php
@@ -0,0 +1,102 @@
+container[$parameter] = $arguments[0];
+
+ return $this;
+ } elseif ($prefix === 'get') {
+ $default_value = isset($arguments[0]) ? $arguments[0] : null;
+
+ return isset($this->container[$parameter]) ? $this->container[$parameter] : $default_value;
+ }
+
+ return null;
+ }
+}
diff --git a/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Encoding/Encoding.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Encoding/Encoding.php
new file mode 100644
index 0000000..fa0917e
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Encoding/Encoding.php
@@ -0,0 +1,33 @@
+ array('controls', 'src'),
+ 'video' => array('poster', 'controls', 'height', 'width', 'src'),
+ 'source' => array('src', 'type'),
+ 'dt' => array(),
+ 'dd' => array(),
+ 'dl' => array(),
+ 'table' => array(),
+ 'caption' => array(),
+ 'tr' => array(),
+ 'th' => array(),
+ 'td' => array(),
+ 'tbody' => array(),
+ 'thead' => array(),
+ 'h1' => array(),
+ 'h2' => array(),
+ 'h3' => array(),
+ 'h4' => array(),
+ 'h5' => array(),
+ 'h6' => array(),
+ 'strong' => array(),
+ 'em' => array(),
+ 'code' => array(),
+ 'pre' => array(),
+ 'blockquote' => array(),
+ 'p' => array(),
+ 'ul' => array(),
+ 'li' => array(),
+ 'ol' => array(),
+ 'br' => array(),
+ 'del' => array(),
+ 'a' => array('href'),
+ 'img' => array('src', 'title', 'alt'),
+ 'figure' => array(),
+ 'figcaption' => array(),
+ 'cite' => array(),
+ 'time' => array('datetime'),
+ 'abbr' => array('title'),
+ 'iframe' => array('width', 'height', 'frameborder', 'src', 'allowfullscreen'),
+ 'q' => array('cite'),
+ );
+
+ /**
+ * Scheme whitelist.
+ *
+ * For a complete list go to http://en.wikipedia.org/wiki/URI_scheme
+ *
+ * @var array
+ */
+ private $scheme_whitelist = array(
+ 'bitcoin:',
+ 'callto:',
+ 'ed2k://',
+ 'facetime://',
+ 'feed:',
+ 'ftp://',
+ 'geo:',
+ 'git://',
+ 'http://',
+ 'https://',
+ 'irc://',
+ 'irc6://',
+ 'ircs://',
+ 'jabber:',
+ 'magnet:',
+ 'mailto:',
+ 'nntp://',
+ 'rtmp://',
+ 'sftp://',
+ 'sip:',
+ 'sips:',
+ 'skype:',
+ 'smb://',
+ 'sms:',
+ 'spotify:',
+ 'ssh:',
+ 'steam:',
+ 'svn://',
+ 'tel:',
+ );
+
+ /**
+ * Iframe source whitelist, everything else is ignored.
+ *
+ * @var array
+ */
+ private $iframe_whitelist = array(
+ 'http://www.youtube.com',
+ 'https://www.youtube.com',
+ 'http://player.vimeo.com',
+ 'https://player.vimeo.com',
+ 'http://www.dailymotion.com',
+ 'https://www.dailymotion.com',
+ 'http://vk.com',
+ 'https://vk.com',
+ );
+
+ /**
+ * Blacklisted resources.
+ *
+ * @var array
+ */
+ private $media_blacklist = array(
+ 'api.flattr.com',
+ 'feeds.feedburner.com',
+ 'share.feedsportal.com',
+ 'da.feedsportal.com',
+ 'rc.feedsportal.com',
+ 'rss.feedsportal.com',
+ 'res.feedsportal.com',
+ 'res1.feedsportal.com',
+ 'res2.feedsportal.com',
+ 'res3.feedsportal.com',
+ 'pi.feedsportal.com',
+ 'rss.nytimes.com',
+ 'feeds.wordpress.com',
+ 'stats.wordpress.com',
+ 'rss.cnn.com',
+ 'twitter.com/home?status=',
+ 'twitter.com/share',
+ 'twitter_icon_large.png',
+ 'www.facebook.com/sharer.php',
+ 'facebook_icon_large.png',
+ 'plus.google.com/share',
+ 'www.gstatic.com/images/icons/gplus-16.png',
+ 'www.gstatic.com/images/icons/gplus-32.png',
+ 'www.gstatic.com/images/icons/gplus-64.png',
+ );
+
+ /**
+ * Attributes used for external resources.
+ *
+ * @var array
+ */
+ private $media_attributes = array(
+ 'src',
+ 'href',
+ 'poster',
+ );
+
+ /**
+ * Attributes that must be integer.
+ *
+ * @var array
+ */
+ private $integer_attributes = array(
+ 'width',
+ 'height',
+ 'frameborder',
+ );
+
+ /**
+ * Mandatory attributes for specified tags.
+ *
+ * @var array
+ */
+ private $required_attributes = array(
+ 'a' => array('href'),
+ 'img' => array('src'),
+ 'iframe' => array('src'),
+ 'audio' => array('src'),
+ 'source' => array('src'),
+ );
+
+ /**
+ * Add attributes to specified tags.
+ *
+ * @var array
+ */
+ private $add_attributes = array(
+ 'a' => array('rel' => 'noreferrer', 'target' => '_blank'),
+ 'video' => array('controls' => 'true'),
+ );
+
+ /**
+ * List of filters to apply.
+ *
+ * @var array
+ */
+ private $filters = array(
+ 'filterAllowedAttribute',
+ 'filterIntegerAttribute',
+ 'rewriteAbsoluteUrl',
+ 'filterIframeAttribute',
+ 'filterBlacklistResourceAttribute',
+ 'filterProtocolUrlAttribute',
+ 'rewriteImageProxyUrl',
+ 'secureIframeSrc',
+ 'removeYouTubeAutoplay',
+ );
+
+ /**
+ * Add attributes to specified tags.
+ *
+ * @var \PicoFeed\Client\Url
+ */
+ private $website;
+
+ /**
+ * Constructor.
+ *
+ * @param \PicoFeed\Client\Url $website Website url instance
+ */
+ public function __construct(Url $website)
+ {
+ $this->website = $website;
+ }
+
+ /**
+ * Apply filters to the attributes list.
+ *
+ * @param string $tag Tag name
+ * @param array $attributes Attributes dictionary
+ *
+ * @return array Filtered attributes
+ */
+ public function filter($tag, array $attributes)
+ {
+ foreach ($attributes as $attribute => &$value) {
+ foreach ($this->filters as $filter) {
+ if (!$this->$filter($tag, $attribute, $value)) {
+ unset($attributes[$attribute]);
+ break;
+ }
+ }
+ }
+
+ return $attributes;
+ }
+
+ /**
+ * Return true if the value is allowed (remove not allowed attributes).
+ *
+ * @param string $tag Tag name
+ * @param string $attribute Attribute name
+ * @param string $value Attribute value
+ *
+ * @return bool
+ */
+ public function filterAllowedAttribute($tag, $attribute, $value)
+ {
+ return isset($this->attribute_whitelist[$tag]) && in_array($attribute, $this->attribute_whitelist[$tag]);
+ }
+
+ /**
+ * Return true if the value is not integer (remove attributes that should have an integer value).
+ *
+ * @param string $tag Tag name
+ * @param string $attribute Attribute name
+ * @param string $value Attribute value
+ *
+ * @return bool
+ */
+ public function filterIntegerAttribute($tag, $attribute, $value)
+ {
+ if (in_array($attribute, $this->integer_attributes)) {
+ return ctype_digit($value);
+ }
+
+ return true;
+ }
+
+ /**
+ * Return true if the iframe source is allowed (remove not allowed iframe).
+ *
+ * @param string $tag Tag name
+ * @param string $attribute Attribute name
+ * @param string $value Attribute value
+ *
+ * @return bool
+ */
+ public function filterIframeAttribute($tag, $attribute, $value)
+ {
+ if ($tag === 'iframe' && $attribute === 'src') {
+ foreach ($this->iframe_whitelist as $url) {
+ if (strpos($value, $url) === 0) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Return true if the resource is not blacklisted (remove blacklisted resource attributes).
+ *
+ * @param string $tag Tag name
+ * @param string $attribute Attribute name
+ * @param string $value Attribute value
+ *
+ * @return bool
+ */
+ public function filterBlacklistResourceAttribute($tag, $attribute, $value)
+ {
+ if ($this->isResource($attribute) && $this->isBlacklistedMedia($value)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Convert all relative links to absolute url.
+ *
+ * @param string $tag Tag name
+ * @param string $attribute Attribute name
+ * @param string $value Attribute value
+ *
+ * @return bool
+ */
+ public function rewriteAbsoluteUrl($tag, $attribute, &$value)
+ {
+ if ($this->isResource($attribute)) {
+ $value = Url::resolve($value, $this->website);
+ }
+
+ return true;
+ }
+
+ /**
+ * Turns iframes' src attribute from http to https to prevent
+ * mixed active content.
+ *
+ * @param string $tag Tag name
+ * @param array $attribute Atttributes name
+ * @param string $value Attribute value
+ *
+ * @return bool
+ */
+ public function secureIframeSrc($tag, $attribute, &$value)
+ {
+ if ($tag === 'iframe' && $attribute === 'src' && strpos($value, 'http://') === 0) {
+ $value = substr_replace($value, 's', 4, 0);
+ }
+
+ return true;
+ }
+
+ /**
+ * Removes YouTube autoplay from iframes.
+ *
+ * @param string $tag Tag name
+ * @param array $attribute Atttributes name
+ * @param string $value Attribute value
+ *
+ * @return bool
+ */
+ public function removeYouTubeAutoplay($tag, $attribute, &$value)
+ {
+ $regex = '%^(https://(?:www\.)?youtube.com/.*\?.*autoplay=)(1)(.*)%i';
+ if ($tag === 'iframe' && $attribute === 'src' && preg_match($regex, $value)) {
+ $value = preg_replace($regex, '${1}0$3', $value);
+ }
+
+ return true;
+ }
+
+ /**
+ * Rewrite image url to use with a proxy.
+ *
+ * @param string $tag Tag name
+ * @param string $attribute Attribute name
+ * @param string $value Attribute value
+ *
+ * @return bool
+ */
+ public function rewriteImageProxyUrl($tag, $attribute, &$value)
+ {
+ if ($tag === 'img' && $attribute === 'src'
+ && !($this->image_proxy_limit_protocol !== '' && stripos($value, $this->image_proxy_limit_protocol.':') !== 0)) {
+ if ($this->image_proxy_url) {
+ $value = sprintf($this->image_proxy_url, rawurlencode($value));
+ } elseif (is_callable($this->image_proxy_callback)) {
+ $value = call_user_func($this->image_proxy_callback, $value);
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Return true if the scheme is authorized.
+ *
+ * @param string $tag Tag name
+ * @param string $attribute Attribute name
+ * @param string $value Attribute value
+ *
+ * @return bool
+ */
+ public function filterProtocolUrlAttribute($tag, $attribute, $value)
+ {
+ if ($this->isResource($attribute) && !$this->isAllowedProtocol($value)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Automatically add/override some attributes for specific tags.
+ *
+ * @param string $tag Tag name
+ * @param array $attributes Attributes list
+ *
+ * @return array
+ */
+ public function addAttributes($tag, array $attributes)
+ {
+ if (isset($this->add_attributes[$tag])) {
+ $attributes += $this->add_attributes[$tag];
+ }
+
+ return $attributes;
+ }
+
+ /**
+ * Return true if all required attributes are present.
+ *
+ * @param string $tag Tag name
+ * @param array $attributes Attributes list
+ *
+ * @return bool
+ */
+ public function hasRequiredAttributes($tag, array $attributes)
+ {
+ if (isset($this->required_attributes[$tag])) {
+ foreach ($this->required_attributes[$tag] as $attribute) {
+ if (!isset($attributes[$attribute])) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Check if an attribute name is an external resource.
+ *
+ * @param string $attribute Attribute name
+ *
+ * @return bool
+ */
+ public function isResource($attribute)
+ {
+ return in_array($attribute, $this->media_attributes);
+ }
+
+ /**
+ * Detect if the protocol is allowed or not.
+ *
+ * @param string $value Attribute value
+ *
+ * @return bool
+ */
+ public function isAllowedProtocol($value)
+ {
+ foreach ($this->scheme_whitelist as $protocol) {
+ if (strpos($value, $protocol) === 0) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Detect if an url is blacklisted.
+ *
+ * @param string $resource Attribute value (URL)
+ *
+ * @return bool
+ */
+ public function isBlacklistedMedia($resource)
+ {
+ foreach ($this->media_blacklist as $name) {
+ if (strpos($resource, $name) !== false) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Convert the attribute list to html.
+ *
+ * @param array $attributes Attributes
+ *
+ * @return string
+ */
+ public function toHtml(array $attributes)
+ {
+ $html = array();
+
+ foreach ($attributes as $attribute => $value) {
+ $html[] = sprintf('%s="%s"', $attribute, Filter::escape($value));
+ }
+
+ return implode(' ', $html);
+ }
+
+ /**
+ * Set whitelisted tags and attributes for each tag.
+ *
+ * @param array $values List of tags: ['video' => ['src', 'cover'], 'img' => ['src']]
+ *
+ * @return Attribute
+ */
+ public function setWhitelistedAttributes(array $values)
+ {
+ $this->attribute_whitelist = $values ?: $this->attribute_whitelist;
+
+ return $this;
+ }
+
+ /**
+ * Set scheme whitelist.
+ *
+ * @param array $values List of scheme: ['http://', 'ftp://']
+ *
+ * @return Attribute
+ */
+ public function setSchemeWhitelist(array $values)
+ {
+ $this->scheme_whitelist = $values ?: $this->scheme_whitelist;
+
+ return $this;
+ }
+
+ /**
+ * Set media attributes (used to load external resources).
+ *
+ * @param array $values List of values: ['src', 'href']
+ *
+ * @return Attribute
+ */
+ public function setMediaAttributes(array $values)
+ {
+ $this->media_attributes = $values ?: $this->media_attributes;
+
+ return $this;
+ }
+
+ /**
+ * Set blacklisted external resources.
+ *
+ * @param array $values List of tags: ['http://google.com/', '...']
+ *
+ * @return Attribute
+ */
+ public function setMediaBlacklist(array $values)
+ {
+ $this->media_blacklist = $values ?: $this->media_blacklist;
+
+ return $this;
+ }
+
+ /**
+ * Set mandatory attributes for whitelisted tags.
+ *
+ * @param array $values List of tags: ['img' => 'src']
+ *
+ * @return Attribute
+ */
+ public function setRequiredAttributes(array $values)
+ {
+ $this->required_attributes = $values ?: $this->required_attributes;
+
+ return $this;
+ }
+
+ /**
+ * Set attributes to automatically to specific tags.
+ *
+ * @param array $values List of tags: ['a' => 'target="_blank"']
+ *
+ * @return Attribute
+ */
+ public function setAttributeOverrides(array $values)
+ {
+ $this->add_attributes = $values ?: $this->add_attributes;
+
+ return $this;
+ }
+
+ /**
+ * Set attributes that must be an integer.
+ *
+ * @param array $values List of tags: ['width', 'height']
+ *
+ * @return Attribute
+ */
+ public function setIntegerAttributes(array $values)
+ {
+ $this->integer_attributes = $values ?: $this->integer_attributes;
+
+ return $this;
+ }
+
+ /**
+ * Set allowed iframe resources.
+ *
+ * @param array $values List of tags: ['http://www.youtube.com']
+ *
+ * @return Attribute
+ */
+ public function setIframeWhitelist(array $values)
+ {
+ $this->iframe_whitelist = $values ?: $this->iframe_whitelist;
+
+ return $this;
+ }
+
+ /**
+ * Set image proxy URL.
+ *
+ * The original image url will be urlencoded
+ *
+ * @param string $url Proxy URL
+ *
+ * @return Attribute
+ */
+ public function setImageProxyUrl($url)
+ {
+ $this->image_proxy_url = $url ?: $this->image_proxy_url;
+
+ return $this;
+ }
+
+ /**
+ * Set image proxy callback.
+ *
+ * @param \Closure $callback
+ *
+ * @return Attribute
+ */
+ public function setImageProxyCallback($callback)
+ {
+ $this->image_proxy_callback = $callback ?: $this->image_proxy_callback;
+
+ return $this;
+ }
+
+ /**
+ * Set image proxy protocol restriction.
+ *
+ * @param string $value
+ *
+ * @return Attribute
+ */
+ public function setImageProxyProtocol($value)
+ {
+ $this->image_proxy_limit_protocol = $value ?: $this->image_proxy_limit_protocol;
+
+ return $this;
+ }
+}
diff --git a/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Filter/Filter.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Filter/Filter.php
new file mode 100644
index 0000000..03a05ba
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Filter/Filter.php
@@ -0,0 +1,144 @@
+]*>\s*~i', '', $data);
+ }
+
+ /**
+ * Remove the XML tag from a document.
+ *
+ * @static
+ * @param string $data Input data
+ * @return string
+ */
+ public static function stripXmlTag($data)
+ {
+ if (strpos($data, '') + 2));
+ }
+
+ do {
+ $pos = strpos($data, '') + 2));
+ }
+ } while ($pos !== false && $pos < 200);
+
+ return $data;
+ }
+
+ /**
+ * Strip head tag from the HTML content.
+ *
+ * @static
+ * @param string $data Input data
+ * @return string
+ */
+ public static function stripHeadTags($data)
+ {
+ return preg_replace('@]*?>.*?@siu', '', $data);
+ }
+
+ /**
+ * Trim whitespace from the begining, the end and inside a string and don't break utf-8 string.
+ *
+ * @static
+ * @param string $value Raw data
+ * @return string Normalized data
+ */
+ public static function stripWhiteSpace($value)
+ {
+ $value = str_replace("\r", ' ', $value);
+ $value = str_replace("\t", ' ', $value);
+ $value = str_replace("\n", ' ', $value);
+ // $value = preg_replace('/\s+/', ' ', $value); <= break utf-8
+ return trim($value);
+ }
+
+ /**
+ * Fixes before XML parsing.
+ *
+ * @static
+ * @param string $data Raw data
+ * @return string Normalized data
+ */
+ public static function normalizeData($data)
+ {
+ $entities = array(
+ '/()(\d+);/m', // decimal encoded
+ '/()([a-f0-9]+);/mi', // hex encoded
+ );
+
+ // strip invalid XML 1.0 characters which are encoded as entities
+ $data = preg_replace_callback($entities, function ($matches) {
+ $code_point = $matches[2];
+
+ // convert hex entity to decimal
+ if (strtolower($matches[1]) === '') {
+ $code_point = hexdec($code_point);
+ }
+
+ $code_point = (int) $code_point;
+
+ // replace invalid characters
+ if ($code_point < 9
+ || ($code_point > 10 && $code_point < 13)
+ || ($code_point > 13 && $code_point < 32)
+ || ($code_point > 55295 && $code_point < 57344)
+ || ($code_point > 65533 && $code_point < 65536)
+ || $code_point > 1114111
+ ) {
+ return '';
+ };
+
+ return $matches[0];
+ }, $data);
+
+ // strip every utf-8 character than isn't in the range of valid XML 1.0 characters
+ return (string) preg_replace('/[^\x{0009}\x{000A}\x{000D}\x{0020}-\x{D7FF}\x{E000}-\x{FFFD}\x{10000}-\x{10FFFF}]/u', '', $data);
+ }
+}
diff --git a/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Filter/Html.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Filter/Html.php
new file mode 100644
index 0000000..3f37482
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Filter/Html.php
@@ -0,0 +1,243 @@
+config = new Config();
+ $this->input = XmlParser::htmlToXml($html);
+ $this->output = '';
+ $this->tag = new Tag($this->config);
+ $this->website = $website;
+ $this->attribute = new Attribute(new Url($website));
+ }
+
+ /**
+ * Set config object.
+ *
+ * @param \PicoFeed\Config\Config $config Config instance
+ * @return \PicoFeed\Filter\Html
+ */
+ public function setConfig($config)
+ {
+ $this->config = $config;
+
+ if ($this->config !== null) {
+ $this->attribute->setImageProxyCallback($this->config->getFilterImageProxyCallback());
+ $this->attribute->setImageProxyUrl($this->config->getFilterImageProxyUrl());
+ $this->attribute->setImageProxyProtocol($this->config->getFilterImageProxyProtocol());
+ $this->attribute->setIframeWhitelist($this->config->getFilterIframeWhitelist(array()));
+ $this->attribute->setIntegerAttributes($this->config->getFilterIntegerAttributes(array()));
+ $this->attribute->setAttributeOverrides($this->config->getFilterAttributeOverrides(array()));
+ $this->attribute->setRequiredAttributes($this->config->getFilterRequiredAttributes(array()));
+ $this->attribute->setMediaBlacklist($this->config->getFilterMediaBlacklist(array()));
+ $this->attribute->setMediaAttributes($this->config->getFilterMediaAttributes(array()));
+ $this->attribute->setSchemeWhitelist($this->config->getFilterSchemeWhitelist(array()));
+ $this->attribute->setWhitelistedAttributes($this->config->getFilterWhitelistedTags(array()));
+ $this->tag->setWhitelistedTags(array_keys($this->config->getFilterWhitelistedTags(array())));
+ }
+
+ return $this;
+ }
+
+ /**
+ * Run tags/attributes filtering.
+ *
+ * @return string
+ */
+ public function execute()
+ {
+ $this->preFilter();
+
+ $parser = xml_parser_create();
+
+ xml_set_object($parser, $this);
+ xml_set_element_handler($parser, 'startTag', 'endTag');
+ xml_set_character_data_handler($parser, 'dataTag');
+ xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, false);
+ xml_parse($parser, $this->input, true);
+ xml_parser_free($parser);
+
+ $this->postFilter();
+
+ return $this->output;
+ }
+
+ /**
+ * Called before XML parsing.
+ */
+ public function preFilter()
+ {
+ $this->input = $this->tag->removeBlacklistedTags($this->input);
+ }
+
+ /**
+ * Called after XML parsing.
+ */
+ public function postFilter()
+ {
+ $this->output = $this->tag->removeEmptyTags($this->output);
+ $this->output = $this->filterRules($this->output);
+ $this->output = $this->tag->removeMultipleBreakTags($this->output);
+ $this->output = trim($this->output);
+ }
+
+ /**
+ * Called after XML parsing.
+ *
+ * @param string $content
+ * @return string
+ */
+ public function filterRules($content)
+ {
+ // the constructor should require a config, then this if can be removed
+ if ($this->config === null) {
+ $config = new Config();
+ } else {
+ $config = $this->config;
+ }
+
+ $loader = new RuleLoader($config);
+ $rules = $loader->getRules($this->website);
+
+ $url = new Url($this->website);
+ $sub_url = $url->getFullPath();
+
+ if (isset($rules['filter'])) {
+ foreach ($rules['filter'] as $pattern => $rule) {
+ if (preg_match($pattern, $sub_url)) {
+ foreach ($rule as $search => $replace) {
+ $content = preg_replace($search, $replace, $content);
+ }
+ }
+ }
+ }
+
+ return $content;
+ }
+
+ /**
+ * Parse opening tag.
+ *
+ * @param resource $parser XML parser
+ * @param string $tag Tag name
+ * @param array $attributes Tag attributes
+ */
+ public function startTag($parser, $tag, array $attributes)
+ {
+ $this->empty = true;
+
+ if ($this->tag->isAllowed($tag, $attributes)) {
+ $attributes = $this->attribute->filter($tag, $attributes);
+
+ if ($this->attribute->hasRequiredAttributes($tag, $attributes)) {
+ $attributes = $this->attribute->addAttributes($tag, $attributes);
+
+ $this->output .= $this->tag->openHtmlTag($tag, $this->attribute->toHtml($attributes));
+ $this->empty = false;
+ }
+ }
+
+ $this->empty_tags[] = $this->empty;
+ }
+
+ /**
+ * Parse closing tag.
+ *
+ * @param resource $parser XML parser
+ * @param string $tag Tag name
+ */
+ public function endTag($parser, $tag)
+ {
+ if (!array_pop($this->empty_tags) && $this->tag->isAllowedTag($tag)) {
+ $this->output .= $this->tag->closeHtmlTag($tag);
+ }
+ }
+
+ /**
+ * Parse tag content.
+ *
+ * @param resource $parser XML parser
+ * @param string $content Tag content
+ */
+ public function dataTag($parser, $content)
+ {
+ // Replace with normal space
+ $content = str_replace("\xc2\xa0", ' ', $content);
+ $this->output .= Filter::escape($content);
+ }
+}
diff --git a/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Filter/Tag.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Filter/Tag.php
new file mode 100644
index 0000000..3cb011c
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Filter/Tag.php
@@ -0,0 +1,208 @@
+isAllowedTag($tag) && !$this->isPixelTracker($tag, $attributes);
+ }
+
+ /**
+ * Return the HTML opening tag.
+ *
+ * @param string $tag Tag name
+ * @param string $attributes Attributes converted in html
+ * @return string
+ */
+ public function openHtmlTag($tag, $attributes = '')
+ {
+ return '<'.$tag.(empty($attributes) ? '' : ' '.$attributes).($this->isSelfClosingTag($tag) ? '/>' : '>');
+ }
+
+ /**
+ * Return the HTML closing tag.
+ *
+ * @param string $tag Tag name
+ * @return string
+ */
+ public function closeHtmlTag($tag)
+ {
+ return $this->isSelfClosingTag($tag) ? '' : ''.$tag.'>';
+ }
+
+ /**
+ * Return true is the tag is self-closing.
+ *
+ * @param string $tag Tag name
+ * @return bool
+ */
+ public function isSelfClosingTag($tag)
+ {
+ return $tag === 'br' || $tag === 'img';
+ }
+
+ /**
+ * Check if a tag is on the whitelist.
+ *
+ * @param string $tag Tag name
+ * @return bool
+ */
+ public function isAllowedTag($tag)
+ {
+ return in_array($tag, array_merge(
+ $this->tag_whitelist,
+ array_keys($this->config->getFilterWhitelistedTags(array()))
+ ));
+ }
+
+ /**
+ * Detect if an image tag is a pixel tracker.
+ *
+ * @param string $tag Tag name
+ * @param array $attributes Tag attributes
+ * @return bool
+ */
+ public function isPixelTracker($tag, array $attributes)
+ {
+ return $tag === 'img' &&
+ isset($attributes['height']) && isset($attributes['width']) &&
+ $attributes['height'] == 1 && $attributes['width'] == 1;
+ }
+
+ /**
+ * Remove script tags.
+ *
+ * @param string $data Input data
+ * @return string
+ */
+ public function removeBlacklistedTags($data)
+ {
+ $dom = XmlParser::getDomDocument($data);
+
+ if ($dom === false) {
+ return '';
+ }
+
+ $xpath = new DOMXpath($dom);
+
+ $nodes = $xpath->query(implode(' | ', $this->tag_blacklist));
+
+ foreach ($nodes as $node) {
+ $node->parentNode->removeChild($node);
+ }
+
+ return $dom->saveXML();
+ }
+
+ /**
+ * Remove empty tags.
+ *
+ * @param string $data Input data
+ * @return string
+ */
+ public function removeEmptyTags($data)
+ {
+ return preg_replace('/<([^<\/>]*)>([\s]*?|(?R))<\/\1>/imsU', '', $data);
+ }
+
+ /**
+ * Replace by only one.
+ *
+ * @param string $data Input data
+ * @return string
+ */
+ public function removeMultipleBreakTags($data)
+ {
+ return preg_replace("/( \s*)+/", ' ', $data);
+ }
+
+ /**
+ * Set whitelisted tags adn attributes for each tag.
+ *
+ * @param array $values List of tags: ['video' => ['src', 'cover'], 'img' => ['src']]
+ * @return Tag
+ */
+ public function setWhitelistedTags(array $values)
+ {
+ $this->tag_whitelist = $values ?: $this->tag_whitelist;
+
+ return $this;
+ }
+}
diff --git a/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Generator/ContentGeneratorInterface.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Generator/ContentGeneratorInterface.php
new file mode 100644
index 0000000..5c2f205
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Generator/ContentGeneratorInterface.php
@@ -0,0 +1,23 @@
+extensions as $extension) {
+ if (substr($item->getUrl(), - strlen($extension)) === $extension) {
+ $item->setContent(''.$item->getUrl().' ');
+ return true;
+ }
+ }
+
+ return false;
+ }
+}
diff --git a/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Generator/YoutubeContentGenerator.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Generator/YoutubeContentGenerator.php
new file mode 100644
index 0000000..198090d
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Generator/YoutubeContentGenerator.php
@@ -0,0 +1,67 @@
+hasNamespace('yt')) {
+ return $this->generateHtmlFromXml($item);
+ }
+
+ return $this->generateHtmlFromUrl($item);
+ }
+
+ /**
+ * Generate HTML
+ *
+ * @access public
+ * @param Item $item
+ * @return boolean
+ */
+ private function generateHtmlFromXml(Item $item)
+ {
+ $videoId = $item->getTag('yt:videoId');
+
+ if (! empty($videoId)) {
+ $item->setContent('');
+ 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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Logging/Logger.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Logging/Logger.php
new file mode 100644
index 0000000..caec463
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/Atom.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/Atom.php
new file mode 100644
index 0000000..0496869
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/Atom.php
@@ -0,0 +1,395 @@
+ '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 author URL.
+ *
+ * @param SimpleXMLElement $xml Feed
+ * @param SimpleXMLElement $entry Feed item
+ * @param \PicoFeed\Parser\Item $item Item object
+ */
+ public function findItemAuthorUrl(SimpleXMLElement $xml, SimpleXMLElement $entry, Item $item)
+ {
+ $authorUrl = XmlParser::getXPathResult($entry, 'atom:author/atom:uri', $this->namespaces)
+ ?: XmlParser::getXPathResult($entry, 'author/uri')
+ ?: XmlParser::getXPathResult($xml, 'atom:author/atom:uri', $this->namespaces)
+ ?: XmlParser::getXPathResult($xml, 'author/uri');
+
+ $item->setAuthorUrl(XmlParser::getValue($authorUrl));
+ }
+
+ /**
+ * 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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/DateParser.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/DateParser.php
new file mode 100644
index 0000000..b7a015d
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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 === false || ($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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/Feed.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/Feed.php
new file mode 100644
index 0000000..a56e71c
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/Item.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/Item.php
new file mode 100644
index 0000000..98214b8
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/Item.php
@@ -0,0 +1,562 @@
+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;
+ }
+
+ /**
+ * Get author URL.
+ *
+ * @return string
+ */
+ public function getAuthorUrl()
+ {
+ return $this->authorUrl;
+ }
+
+ /**
+ * 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 author URL.
+ *
+ * @param string $authorUrl
+ * @return Item
+ */
+ public function setAuthorUrl($authorUrl)
+ {
+ $this->authorUrl = $authorUrl;
+ 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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/MalformedXmlException.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/MalformedXmlException.php
new file mode 100644
index 0000000..efaf0ff
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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->findItemAuthorUrl($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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/ParserException.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/ParserException.php
new file mode 100644
index 0000000..b5fbb69
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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 author URL.
+ *
+ * @param SimpleXMLElement $xml Feed
+ * @param SimpleXMLElement $entry Feed item
+ * @param \PicoFeed\Parser\Item $item Item object
+ */
+ public function findItemAuthorUrl(SimpleXMLElement $xml, SimpleXMLElement $entry, Item $item)
+ {
+ // There appears to be no support for author URL in the dc: terms
+ $item->setAuthorUrl('');
+ }
+
+ /**
+ * 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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/Rss20.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/Rss20.php
new file mode 100644
index 0000000..da9c0d5
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/Rss20.php
@@ -0,0 +1,330 @@
+ '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 author URL.
+ *
+ * @param SimpleXMLElement $xml Feed
+ * @param SimpleXMLElement $entry Feed item
+ * @param \PicoFeed\Parser\Item $item Item object
+ */
+ public function findItemAuthorUrl(SimpleXMLElement $xml, SimpleXMLElement $entry, Item $item)
+ {
+ // There appears to be no support for author URL in the dc: terms or author element
+ $item->setAuthorUrl('');
+ }
+
+ /**
+ * 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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/Rss91.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/Rss91.php
new file mode 100644
index 0000000..058fca1
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/Rss91.php
@@ -0,0 +1,13 @@
+childNodes->length === 0) {
+ return false;
+ }
+
+ return $dom;
+ }
+
+ /**
+ * Small wrapper around Laminas Xml 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);
+ }
+
+ self::$errors = [];
+ foreach (libxml_get_errors() as $error) {
+ self::$errors[] = sprintf('XML error: %s (Line: %d - Column: %d - Code: %d)',
+ $error->message,
+ $error->line,
+ $error->column,
+ $error->code
+ );
+ }
+
+ libxml_use_internal_errors(false);
+
+ 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()
+ {
+ return implode(', ', self::$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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/PicoFeedException.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/PicoFeedException.php
new file mode 100644
index 0000000..2de9e4b
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Processor/ContentGeneratorProcessor.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Processor/ContentGeneratorProcessor.php
new file mode 100644
index 0000000..49adf9c
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Processor/ItemPostProcessor.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Processor/ItemPostProcessor.php
new file mode 100644
index 0000000..7b092b5
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Processor/ItemProcessorInterface.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Processor/ItemProcessorInterface.php
new file mode 100644
index 0000000..5d53226
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Reader/Favicon.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Reader/Favicon.php
new file mode 100644
index 0000000..d4ca07d
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Reader/Reader.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Reader/Reader.php
new file mode 100644
index 0000000..596b02d
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Reader/ReaderException.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Reader/ReaderException.php
new file mode 100644
index 0000000..4f03dbe
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.blogs.nytimes.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.blogs.nytimes.com.php
new file mode 100644
index 0000000..ee641b0
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.igen.fr.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.igen.fr.php
new file mode 100644
index 0000000..f2028f4
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.nytimes.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.nytimes.com.php
new file mode 100644
index 0000000..8ff921c
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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(
+ '//p[contains(@class, "story-content")] | //div[@class="image"]',
+ ),
+ )
+ )
+);
diff --git a/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.over-blog.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.over-blog.com.php
new file mode 100644
index 0000000..cc5d83c
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.phoronix.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.phoronix.com.php
new file mode 100644
index 0000000..66713f7
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.slate.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.slate.com.php
new file mode 100644
index 0000000..a795bca
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.theguardian.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.theguardian.com.php
new file mode 100644
index 0000000..e0d6f3f
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.wikipedia.org.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.wikipedia.org.php
new file mode 100644
index 0000000..7b8f76e
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.wired.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.wired.com.php
new file mode 100644
index 0000000..952b09a
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.wsj.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.wsj.com.php
new file mode 100644
index 0000000..f6e6cc1
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/01net.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/01net.com.php
new file mode 100644
index 0000000..6d144f0
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/24.hu.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/24.hu.php
new file mode 100644
index 0000000..6c269db
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/24.hu.php
@@ -0,0 +1,16 @@
+ array(
+ '%.*%' => array(
+ 'test_url' => 'http://24.hu/belfold/2017/10/20/millios-lehuzasok-miatt-razziaztak-egy-budapesti-barban-videoval/',
+ 'body' => array(
+ '//div[@class="post-title-wrapper"]/h1',
+ '//div[@class="post-header-wrapper has-img"]/img',
+ '//div[@class="post-body"]'
+
+ ),
+ 'strip' => array(
+ )
+ ),
+ ),
+);
diff --git a/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/444.hu.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/444.hu.php
new file mode 100644
index 0000000..e65bad1
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/444.hu.php
@@ -0,0 +1,19 @@
+ array(
+ '%.*%' => array(
+ 'test_url' => 'https://444.hu/2017/10/20/tulszamlazo-helyen-utottek-rajta-budapest-belvarosaban',
+ 'body' => array(
+ '//div[@id="headline"]/h1',
+ '//article'
+ ),
+ 'strip' => array(
+ '//article/footer',
+ '//article/div[@class="jeti-roadblock ad"]',
+ '//figcaption',
+ '//noscript',
+ '//ul[@class="widget-stream-items"]'
+ )
+ ),
+ ),
+);
diff --git a/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/888.hu.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/888.hu.php
new file mode 100644
index 0000000..68cfe05
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/888.hu.php
@@ -0,0 +1,16 @@
+ array(
+ '%.*%' => array(
+ 'test_url' => 'https://888.hu/article-a-budapesti-szocik-nem-szeretik-a-videki-szocikat',
+ 'body' => array(
+ '//div[@id="cikkholder"]/h1',
+ '//div[@class="maincontent8"]'
+ ),
+ 'strip' => array(
+ '//div[@class="AdW"]',
+ '//h1[@class="olvastadmar"]'
+ )
+ ),
+ ),
+);
diff --git a/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/abstrusegoose.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/abstrusegoose.com.php
new file mode 100644
index 0000000..752d041
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/abstrusegoose.com.php
@@ -0,0 +1,8 @@
+ array(
+ '%.*%' => array(
+ '%alt="(.+)" title="(.+)" */>%' => '/> $1 $2',
+ ),
+ ),
+);
diff --git a/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/achgut.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/achgut.com.php
new file mode 100644
index 0000000..1e61fe6
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/achgut.com.php
@@ -0,0 +1,16 @@
+ array(
+ '%.*%' => array(
+ 'test_url' => 'http://www.achgut.com/artikel/deutscher_herbst_wg_reichsstrasse_106',
+ 'body' => array(
+ '//div[@class="headerpict_half"]/div/img',
+ '//div[@class="beitrag"]/div[@class="teaser_blog_text"]'
+ ),
+ 'strip' => array(
+ '//div[@class="footer_blog_text"]',
+ '//div[@class="beitrag"]/div[@class="teaser_blog_text"]/h2[1]'
+ )
+ ),
+ ),
+);
diff --git a/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/adventuregamers.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/adventuregamers.com.php
new file mode 100644
index 0000000..98d384e
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/alainonline.net.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/alainonline.net.php
new file mode 100644
index 0000000..f440b23
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/aljazeera.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/aljazeera.com.php
new file mode 100644
index 0000000..c02eb21
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/allafrica.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/allafrica.com.php
new file mode 100644
index 0000000..e8a506d
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/allgemeine-zeitung.de.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/allgemeine-zeitung.de.php
new file mode 100644
index 0000000..8ede99b
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/amazingsuperpowers.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/amazingsuperpowers.com.php
new file mode 100644
index 0000000..3214c62
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/amazingsuperpowers.com.php
@@ -0,0 +1,8 @@
+ array(
+ '%.*%' => array(
+ '%title="(.+)" */>%' => '/> $1',
+ ),
+ ),
+);
diff --git a/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/anythingcomic.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/anythingcomic.com.php
new file mode 100644
index 0000000..51247f7
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/ap.org.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/ap.org.php
new file mode 100644
index 0000000..5bb2bb6
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/areadvd.de.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/areadvd.de.php
new file mode 100644
index 0000000..fc56922
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/arstechnica.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/arstechnica.com.php
new file mode 100644
index 0000000..55e01ce
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/atv.hu.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/atv.hu.php
new file mode 100644
index 0000000..170ec4d
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/atv.hu.php
@@ -0,0 +1,18 @@
+ array(
+ '%.*%' => array(
+ 'test_url' => 'http://www.atv.hu/belfold/20171020-tobb-millio-forintot-csalt-ki-egy-idos-ferfitol-a-budapesti-no',
+ 'body' => array(
+ '//article'
+ ),
+ 'strip' => array(
+ '//span[@class="date"]',
+ '//div[@class="fb-like db_iframe_widget"]',
+ '//div[@class="ad-wrapper dashed-border"]',
+ '//div[@class="footer-meta-wrapper"]',
+ '//div[@class="image-wrapper "]'
+ )
+ ),
+ ),
+);
diff --git a/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/awkwardzombie.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/awkwardzombie.com.php
new file mode 100644
index 0000000..5ab7051
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/backchannel.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/backchannel.com.php
new file mode 100644
index 0000000..bc5932a
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/bangkokpost.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/bangkokpost.com.php
new file mode 100644
index 0000000..165515b
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/bauerwilli.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/bauerwilli.com.php
new file mode 100644
index 0000000..b191a6e
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/bauerwilli.com.php
@@ -0,0 +1,17 @@
+ array(
+ '%.*%' => array(
+ 'test_url' => 'http://www.bauerwilli.com/intuitive-eating/',
+ 'body' => array(
+ '//div[@class="entry-thumbnail"]',
+ '//div[@class="entry-content"]',
+ ),
+ 'strip' => array(
+ '//div[@class="tptn_counter"]',
+ '//div[contains(@class, "sharedaddy")]'
+ ),
+ ),
+ ),
+);
+
diff --git a/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/bgr.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/bgr.com.php
new file mode 100644
index 0000000..7507a2f
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/bigfootjustice.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/bigfootjustice.com.php
new file mode 100644
index 0000000..d06ed12
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/bigfootjustice.com.php
@@ -0,0 +1,8 @@
+ array(
+ '%.*%' => array(
+ '%-150x150%' => '',
+ ),
+ ),
+);
diff --git a/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/bigpicture.ru.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/bigpicture.ru.php
new file mode 100644
index 0000000..55c4089
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/bizjournals.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/bizjournals.com.php
new file mode 100644
index 0000000..d1cc3da
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/biztimes.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/biztimes.com.php
new file mode 100644
index 0000000..d21aa98
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/bleepingcomputer.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/bleepingcomputer.com.php
new file mode 100644
index 0000000..7b74060
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/blog.fefe.de.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/blog.fefe.de.php
new file mode 100644
index 0000000..39c88ae
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/blog.mapillary.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/blog.mapillary.com.php
new file mode 100644
index 0000000..ce01651
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/brewers.mlb.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/brewers.mlb.com.php
new file mode 100644
index 0000000..be406fa
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/buenosairesherald.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/buenosairesherald.com.php
new file mode 100644
index 0000000..4e73e79
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/bunicomic.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/bunicomic.com.php
new file mode 100644
index 0000000..ad83e43
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/buttersafe.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/buttersafe.com.php
new file mode 100644
index 0000000..1f313cd
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/cad-comic.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/cad-comic.com.php
new file mode 100644
index 0000000..a631c97
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/chaoslife.findchaos.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/chaoslife.findchaos.com.php
new file mode 100644
index 0000000..ea6191e
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/chinafile.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/chinafile.com.php
new file mode 100644
index 0000000..450117b
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/cicero.de.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/cicero.de.php
new file mode 100644
index 0000000..2cd1b70
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/cicero.de.php
@@ -0,0 +1,17 @@
+ array(
+ '%.*%' => array(
+ 'test_url' => 'https://cicero.de/innenpolitik/plaene-der-eu-kommission-der-ganz-normale-terror',
+ 'body' => array(
+ '//p[@class="lead"]',
+ '//article/div[2]/div[contains(@class, "field--name-field-cc-image")]',
+ '//article/div[2]/div[contains(@class, "image-description")]',
+ '//div[@class="field field-name-field-cc-body"]',
+ ),
+ 'strip' => array(
+ '//*[contains(@class, "urban-ad-sign")]'
+ )
+ ),
+ ),
+);
diff --git a/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/cliquerefresh.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/cliquerefresh.com.php
new file mode 100644
index 0000000..9dcc7e5
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/cnet.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/cnet.com.php
new file mode 100644
index 0000000..60767a5
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/coinwelt.de.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/coinwelt.de.php
new file mode 100644
index 0000000..28a8bba
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/coinwelt.de.php
@@ -0,0 +1,14 @@
+ array(
+ '%.*%' => array(
+ 'test_url' => 'http://coinwelt.de/2017/08/bitcache-kreierer-kim-dotcom-bietet-arbeitsplaetze-fuer-blockchain-goetter/',
+ 'body' => array(
+ '//div[@class="post-inner"]//div[@class="entry"]',
+ ),
+ 'strip' => array(
+ '//div[contains(@class, "shariff")]',
+ ),
+ ),
+ ),
+);
diff --git a/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/consomac.fr.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/consomac.fr.php
new file mode 100644
index 0000000..9209f9c
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/cowbirdsinlove.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/cowbirdsinlove.com.php
new file mode 100644
index 0000000..3214c62
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/cowbirdsinlove.com.php
@@ -0,0 +1,8 @@
+ array(
+ '%.*%' => array(
+ '%title="(.+)" */>%' => '/> $1',
+ ),
+ ),
+);
diff --git a/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/crash.net.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/crash.net.php
new file mode 100644
index 0000000..88cef14
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/crash.net.php
@@ -0,0 +1,18 @@
+ array(
+ '%.*%' => array(
+ 'test_url' => 'http://www.crash.net/motogp/news/885102/1/dovizioso-mugello-win-was-catalyst-for-title-challenge',
+ 'body' => array(
+ '//*[@id="block-system-main"]',
+ ),
+ 'strip' => array(
+ '//script',
+ '//style',
+ '//*[@class="social-bar"]',
+ '//*[@id="below-headline-image-ad"]',
+ '//*[@class="advert-"]',
+ ),
+ ),
+ ),
+);
diff --git a/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/csmonitor.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/csmonitor.com.php
new file mode 100644
index 0000000..481e4b0
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/dailyjs.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/dailyjs.com.php
new file mode 100644
index 0000000..20eb1d7
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/dailyreporter.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/dailyreporter.com.php
new file mode 100644
index 0000000..db3fc0e
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/dailytech.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/dailytech.com.php
new file mode 100644
index 0000000..5d1df4a
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/degroupnews.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/degroupnews.com.php
new file mode 100644
index 0000000..91f5c56
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/derstandard.at.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/derstandard.at.php
new file mode 100644
index 0000000..7e95a51
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/dilbert.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/dilbert.com.php
new file mode 100644
index 0000000..b8e9b3d
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/discovermagazine.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/discovermagazine.com.php
new file mode 100644
index 0000000..ae0dfe7
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/distrowatch.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/distrowatch.com.php
new file mode 100644
index 0000000..aefc8f8
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/dozodomo.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/dozodomo.com.php
new file mode 100644
index 0000000..e116695
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/drawingboardcomic.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/drawingboardcomic.com.php
new file mode 100644
index 0000000..cd30f2e
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/e-w-e.ru.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/e-w-e.ru.php
new file mode 100644
index 0000000..8139cc9
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/economist.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/economist.com.php
new file mode 100644
index 0000000..522032f
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/encyclopedie.naheulbeuk.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/encyclopedie.naheulbeuk.com.php
new file mode 100644
index 0000000..19bcbde
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/endlessorigami.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/endlessorigami.com.php
new file mode 100644
index 0000000..d06ed12
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/endlessorigami.com.php
@@ -0,0 +1,8 @@
+ array(
+ '%.*%' => array(
+ '%-150x150%' => '',
+ ),
+ ),
+);
diff --git a/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/engadget.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/engadget.com.php
new file mode 100644
index 0000000..cf9e448
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/escapistmagazine.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/escapistmagazine.com.php
new file mode 100644
index 0000000..e86b59c
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/espn.go.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/espn.go.com.php
new file mode 100644
index 0000000..76a20f7
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/exocomics.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/exocomics.com.php
new file mode 100644
index 0000000..5adc59f
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/explosm.net.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/explosm.net.php
new file mode 100644
index 0000000..3fdf02c
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/extrafabulouscomics.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/extrafabulouscomics.com.php
new file mode 100644
index 0000000..12697cc
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/extrafabulouscomics.com.php
@@ -0,0 +1,8 @@
+ array(
+ '%.*%' => array(
+ '%-150x150%' => '',
+ ),
+ ),
+);
diff --git a/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/factroom.ru.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/factroom.ru.php
new file mode 100644
index 0000000..a572061
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/fastcodesign.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/fastcodesign.com.php
new file mode 100644
index 0000000..74e70a8
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/fastcoexist.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/fastcoexist.com.php
new file mode 100644
index 0000000..6916f28
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/fastcompany.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/fastcompany.com.php
new file mode 100644
index 0000000..e0869a2
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/ffworld.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/ffworld.com.php
new file mode 100644
index 0000000..20a47b2
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/foreignpolicy.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/foreignpolicy.com.php
new file mode 100644
index 0000000..3cbcddc
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/fossbytes.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/fossbytes.com.php
new file mode 100644
index 0000000..6ce4725
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/fototelegraf.ru.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/fototelegraf.ru.php
new file mode 100644
index 0000000..ca2f85a
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/fowllanguagecomics.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/fowllanguagecomics.com.php
new file mode 100644
index 0000000..3f62f07
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/gamechannel.hu.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/gamechannel.hu.php
new file mode 100644
index 0000000..8ab9c5c
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/gamechannel.hu.php
@@ -0,0 +1,15 @@
+ array(
+ '%.*%' => array(
+ 'test_url' => 'http://www.gamechannel.hu/cikk/hirblock/a-legacy-of-kain-feltamasztasara-keszul-a-crystal-dynamics',
+ 'body' => array(
+ '//div[@class="post"]/div[@class="entry"]'
+ ),
+ 'strip' => array(
+ '//div[@class="valaszto"]',
+ '//center/blockquote' // as we can't grab iframe here
+ )
+ ),
+ ),
+);
diff --git a/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/gamestar.hu.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/gamestar.hu.php
new file mode 100644
index 0000000..56a4c72
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/gamestar.hu.php
@@ -0,0 +1,17 @@
+ array(
+ '%.*%' => array(
+ 'test_url' => 'https://www.gamestar.hu/hir/horizon-zero-dawn-the-frozen-wilds-vedjegy-239019.html',
+ 'body' => array(
+ '//article/header/h1',
+ '//div[@class="section section-2-3"]/div[@class="image"]/img',
+ '//article/p[@class="lead"]',
+ '//article/div[@class="content"]'
+ ),
+ 'strip' => array(
+ '//div[@class="ad ad-article-inside"]'
+ )
+ ),
+ ),
+);
diff --git a/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/geek.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/geek.com.php
new file mode 100644
index 0000000..d9ccecc
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/geektimes.ru.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/geektimes.ru.php
new file mode 100644
index 0000000..1954138
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/gerbilwithajetpack.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/gerbilwithajetpack.com.php
new file mode 100644
index 0000000..44013b3
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/giantitp.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/giantitp.com.php
new file mode 100644
index 0000000..d9c3ae5
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/github.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/github.com.php
new file mode 100644
index 0000000..726634f
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/gocomics.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/gocomics.com.php
new file mode 100644
index 0000000..32960f0
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/golem.de.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/golem.de.php
new file mode 100644
index 0000000..8731285
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/golem.de.php
@@ -0,0 +1,21 @@
+ 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',
+ '//header[@class="cluster-header"]/h1',
+ '//div[@id="iqadtile4"]',
+ ),
+ ),
+ ),
+);
diff --git a/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/gondola.hu.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/gondola.hu.php
new file mode 100644
index 0000000..62b1e3c
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/gondola.hu.php
@@ -0,0 +1,22 @@
+ array(
+ '%.*%' => array(
+ 'test_url' => 'https://gondola.hu/hirek/213754-A_budapesti_fejlesztesek_kerdese_mar_nem_zsakbamacska.html',
+ 'body' => array(
+ '//div[@id="cikk"]/div[@class="cim"]',
+ '//br[1]',
+ '//div[@class="alcim"]',
+ '//div[@class="lead"]',
+ '//div[@class="szoveg"]'
+ ),
+ 'strip' => array(
+ '//div[@class="ikonok"]',
+ '//div[@class="linkekblokk"]',
+ '//div[@id="billboardbanner"]',
+ '//div[@class="szerzo"]',
+ '//div[@class="kulcsszavak"]'
+ )
+ ),
+ ),
+);
diff --git a/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/gorabbit.ru.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/gorabbit.ru.php
new file mode 100644
index 0000000..4e43248
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/habrahabr.ru.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/habrahabr.ru.php
new file mode 100644
index 0000000..3f1ec16
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/happletea.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/happletea.com.php
new file mode 100644
index 0000000..75b0b83
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/hardware.fr.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/hardware.fr.php
new file mode 100644
index 0000000..56aec4f
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/heise.de.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/heise.de.php
new file mode 100644
index 0000000..0ee6915
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/heise.de.php
@@ -0,0 +1,79 @@
+ array(
+ '%^/tp.*%' => array(
+ 'test_url' => 'https://www.heise.de/tp/features/Macrons-Vermoegenssteuer-Der-Staat-verzichtet-auf-3-2-Milliarden-3863931.html',
+ 'body' => array(
+ '//main/article'
+ ),
+ 'strip' => array(
+ '//header',
+ '//aside',
+ '//nav[@class="pre-akwa-toc"]',
+ '//*[@class="seite_zurueck"]',
+ '//*[@class="pagination"]',
+ '//a[@class="kommentare_lesen_link"]',
+ '//div[contains(@class, "shariff")]',
+ '//a[@class="beitragsfooter_permalink"]',
+ '//a[@class="beitragsfooter_fehlermelden"]',
+ '//a[@class="beitragsfooter_printversion"]'
+ ),
+ 'next_page' => array(
+ '//a[@class="seite_weiter"]'
+ ),
+ ),
+ '%^/newsticker/meldung.*%' => array(
+ 'test_url' => 'https://www.heise.de/newsticker/meldung/DragonFly-BSD-5-0-mit-experimentellem-HAMMER2-veroeffentlicht-3864731.html',
+ 'body' => array(
+ '//div[@class="article-content"]',
+ ),
+ 'strip' => array(
+ '//*[contains(@class, "gallery")]',
+ '//*[contains(@class, "video")]',
+ ),
+ ),
+ '%^/autos/artikel.*%' => array(
+ 'test_url' => 'https://www.heise.de/autos/artikel/Bericht-Mazda-baut-Range-Extender-mit-Wankelmotor-3864760.html',
+ 'body' => array(
+ '//section[@id="artikel_text"]'
+ ),
+ 'strip' => array(
+ '//p[@id="content_foren"]',
+ '//div[contains(@class, "shariff")]',
+ '//p[@class="permalink"]',
+ '//p[@class="printversion"]'
+ ),
+ ),
+ '%^/foto/meldung.*%' => array(
+ 'test_url' => 'https://www.heise.de/foto/meldung/Wildlife-Fotograf-des-Jahres-Gewinnerbild-zeigt-getoetetes-Nashorn-3864311.html',
+ 'body' => array(
+ '//div[@class="article-content"]'
+ ),
+ ),
+ '%^/ct.*%' => array(
+ 'test_url' => 'https://www.heise.de/ct/artikel/Google-Pixel-2-und-Pixel-2-XL-im-Test-3863842.html',
+ 'body' => array(
+ '//main/div[1]/div[1]/section'
+ ),
+ 'strip' => array(
+ '//header'
+ )
+ ),
+ '%^/developer.*%' => array(
+ 'test_url' => 'https://www.heise.de/developer/meldung/Container-Docker-unterstuetzt-Kubernetes-3863625.html',
+ 'body' => array(
+ '//div[@class="article-content"]'
+ )
+ ),
+ '%.*%' => array(
+ 'test_url' => 'https://www.heise.de/mac-and-i/meldung/iOS-App-Nude-findet-mittels-ML-Nacktbilder-und-versteckt-sie-3864217.html',
+ 'body' => array(
+ '//article/div[@class="meldung_wrapper"]',
+ ),
+ 'strip' => array(
+ '//*[contains(@class, "gallery")]',
+ '//*[contains(@class, "video")]',
+ ),
+ ),
+ ),
+);
diff --git a/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/hirek.prim.hu.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/hirek.prim.hu.php
new file mode 100644
index 0000000..1a38809
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/hirek.prim.hu.php
@@ -0,0 +1,14 @@
+ array(
+ '%.*%' => array(
+ 'test_url' => 'http://hirek.prim.hu/cikk/2017/10/02/atadtak_a_6_fenntarthatosagi_sajtodijat',
+ 'body' => array(
+ '//div[@class="boxbody article_box"]/h2',
+ '//div[@class="text_body"]'
+ ),
+ 'strip' => array(
+ )
+ ),
+ ),
+);
diff --git a/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/hotshowlife.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/hotshowlife.com.php
new file mode 100644
index 0000000..faf01f3
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/huffingtonpost.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/huffingtonpost.com.php
new file mode 100644
index 0000000..b52b07b
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/hvg.hu.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/hvg.hu.php
new file mode 100644
index 0000000..efc9371
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/hvg.hu.php
@@ -0,0 +1,17 @@
+ array(
+ '%.*%' => array(
+ 'test_url' => 'http://hvg.hu/brandchannel/mastercardbch_20171006_Egyetlen_mobillal_erintettuk_Budapest_legjobb_gasztrohelyeit',
+ 'body' => array(
+ '//div[@class="article-title article-title"]',
+ '//div[@class="article-cover-img"]',
+ '//div[@class="article-main"]'
+ ),
+ 'strip' => array(
+ '//figcaption',
+ '//div[@class="article-info byline"]'
+ )
+ ),
+ ),
+);
diff --git a/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/idokep.hu.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/idokep.hu.php
new file mode 100644
index 0000000..06cae09
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/idokep.hu.php
@@ -0,0 +1,18 @@
+ array(
+ '%.*%' => array(
+ 'test_url' => 'https://www.idokep.hu/hirek/4-es-erossegu-tajfun-tart-japan-fele',
+ 'body' => array(
+ '//div[@class="cikk-title"]/h3',
+ '//div[@class="lead"]',
+ '//div[@class="atvett_tartalom"]',
+ '//div[@class="cikk-tartalom"]'
+ ),
+ 'strip' => array(
+ '//div[@class="cimkes-doboz"]',
+ '//div[@class="komment-wrap"]'
+ )
+ ),
+ ),
+);
diff --git a/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/imogenquest.net.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/imogenquest.net.php
new file mode 100644
index 0000000..3214c62
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/imogenquest.net.php
@@ -0,0 +1,8 @@
+ array(
+ '%.*%' => array(
+ '%title="(.+)" */>%' => '/> $1',
+ ),
+ ),
+);
diff --git a/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/index.hu.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/index.hu.php
new file mode 100644
index 0000000..727d7b7
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/index.hu.php
@@ -0,0 +1,29 @@
+ array(
+ '%.*%' => array(
+ 'test_url' => 'http://index.hu/mindekozben/poszt/2017/10/20/art_deco_budapest_varosnezo_zsebkonyv_bolla_zoltan/',
+ 'body' => array(
+ '//div[@class="mindenkozben_post_content content"]',
+ '//div[@id="content"]'
+ ),
+ 'strip' => array(
+ '//div[@class="topszponzor_wrapper"]',
+ '//ul[@class="cikk-cimkek"]',
+ '//div[@class="author-share-date-container"]',
+ '//div[@class="pp-list"]',
+ '//div[@class="social-stripe cikk-bottom-box"]',
+ '//div[@class="cikk-bottom-text-ad"]',
+ '//a[@name="hozzaszolasok"]',
+ '//div[@class="cikk-vegi-ajanlo-reklamok-container"]',
+ '//div[@id="comments"]',
+ '//div[@class="comments"]',
+ '//div[@class="linkpreview-box bekezdes_utan"]',
+ '//div[@class="lapozo"]',
+ '//div[@class="szelso-jobb"]',
+ '//div[@class="social cikk-bottom-box"]',
+ '//input'
+ )
+ ),
+ ),
+);
diff --git a/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/indiehaven.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/indiehaven.com.php
new file mode 100644
index 0000000..a40ce69
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/inforadio.hu.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/inforadio.hu.php
new file mode 100644
index 0000000..569013d
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/inforadio.hu.php
@@ -0,0 +1,25 @@
+ array(
+ '%.*%' => array(
+ 'test_url' => 'http://inforadio.hu/belfold/2017/10/20/fontos_valtozas_vegleg_lezarnak_tobb_villamosatjarot_budapesten/',
+ 'body' => array(
+ '//div[@class="content-title"]',
+ '//div[@class="szelso-jobb-lead_container"]',
+ '//div[@class="cikk-torzs"]'
+ ),
+ 'strip' => array(
+ '//div[@id="microsite_microsite"]',
+ '//div[@class="cikk-bottom-text-ad"]',
+ '//div[@class="social-stripe_container"]',
+ '//div[@class="facebook-like-box"]',
+ '//div[@class="rovat sargabg rovatdobozcim"]',
+ '//div[@class="m-okosradio_magazin arenaMagazineItem"]',
+ '//header[@class="m-okosradio_header"]',
+ '//div[@class="m-okosradio_elo"]',
+ '//div[@class="m-okosradio_container"]',
+ '//form'
+ )
+ ),
+ ),
+);
diff --git a/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/ing.dk.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/ing.dk.php
new file mode 100644
index 0000000..5a021a0
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/invisiblebread.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/invisiblebread.com.php
new file mode 100644
index 0000000..90f8759
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/invisiblebread.com.php
@@ -0,0 +1,8 @@
+ array(
+ '%.*%' => array(
+ '%( )%' => '$1 ',
+ ),
+ ),
+);
diff --git a/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/ir.amd.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/ir.amd.com.php
new file mode 100644
index 0000000..af99fe9
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/japantimes.co.jp.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/japantimes.co.jp.php
new file mode 100644
index 0000000..9959441
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/japantoday.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/japantoday.com.php
new file mode 100644
index 0000000..22485d6
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/journaldugeek.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/journaldugeek.com.php
new file mode 100644
index 0000000..876b269
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/jsonline.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/jsonline.com.php
new file mode 100644
index 0000000..5895256
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/justcoolidea.ru.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/justcoolidea.ru.php
new file mode 100644
index 0000000..089ff29
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/kanpai.fr.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/kanpai.fr.php
new file mode 100644
index 0000000..c3a1abc
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/karriere.jobfinder.dk.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/karriere.jobfinder.dk.php
new file mode 100644
index 0000000..25d6dfa
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/kisalfold.hu.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/kisalfold.hu.php
new file mode 100644
index 0000000..7568901
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/kisalfold.hu.php
@@ -0,0 +1,17 @@
+ array(
+ '%.*%' => array(
+ 'test_url' => 'http://www.kisalfold.hu/szorakozas/egy_15_eves_srac_szuntetheti_meg_a_wc-parat_budapesten/2536699/',
+ 'body' => array(
+ '//header[@class="single-article__header"]/h1',
+ '//header[@class="single-article__header"]/h2',
+ '//figure[@class="single-article__image"]/img',
+ '//div[@class="single-article__content"]/div[@id="single-article__lead"]',
+ '//div[@id="article_text"]'
+ ),
+ 'strip' => array(
+ )
+ ),
+ ),
+);
diff --git a/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/kiszamolo.hu.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/kiszamolo.hu.php
new file mode 100644
index 0000000..c44a08f
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/kiszamolo.hu.php
@@ -0,0 +1,14 @@
+ array(
+ '%.*%' => array(
+ 'test_url' => 'https://kiszamolo.hu/30-eve-volt-a-fekete-hetfo/',
+ 'body' => array(
+ '//article/h2',
+ '//article/div[@class="entry clearfix"]/p'
+ ),
+ 'strip' => array(
+ )
+ ),
+ ),
+);
diff --git a/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/kodi.tv.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/kodi.tv.php
new file mode 100644
index 0000000..439fc90
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/koreaherald.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/koreaherald.com.php
new file mode 100644
index 0000000..9651056
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/koreatimes.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/koreatimes.php
new file mode 100644
index 0000000..f274b4a
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/lastplacecomics.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/lastplacecomics.com.php
new file mode 100644
index 0000000..12697cc
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/lastplacecomics.com.php
@@ -0,0 +1,8 @@
+ array(
+ '%.*%' => array(
+ '%-150x150%' => '',
+ ),
+ ),
+);
diff --git a/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/legorafi.fr.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/legorafi.fr.php
new file mode 100644
index 0000000..e6aae46
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/lejapon.fr.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/lejapon.fr.php
new file mode 100644
index 0000000..8f2b293
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/lesjoiesducode.fr.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/lesjoiesducode.fr.php
new file mode 100644
index 0000000..369206a
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/lfg.co.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/lfg.co.php
new file mode 100644
index 0000000..d978a5f
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/lifehacker.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/lifehacker.com.php
new file mode 100644
index 0000000..b9a6933
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/lifehacker.ru.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/lifehacker.ru.php
new file mode 100644
index 0000000..bc140f6
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/linux-magazin.de.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/linux-magazin.de.php
new file mode 100644
index 0000000..f4bc07d
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/linux-magazin.de.php
@@ -0,0 +1,16 @@
+ array(
+ '%.*%' => array(
+ 'test_url' => 'http://www.linux-magazin.de/Ausgaben/2017/09/AWS-Alternativen',
+ 'body' => array(
+ '//div[@class="attribute-content"]/div[@class="attribute-intro"]',
+ '(//div[@class="attribute-image"])[1]',
+ '//div[@itemprop="articleBody"]',
+ ),
+ 'strip' => array(
+ '//p[@class="attribute-advice"]',
+ )
+ )
+ )
+);
diff --git a/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/linux.org.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/linux.org.php
new file mode 100644
index 0000000..2520d0d
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/linux.org.ru.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/linux.org.ru.php
new file mode 100644
index 0000000..7fa0249
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/linuxinsider.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/linuxinsider.com.php
new file mode 100644
index 0000000..4e0a4cc
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/lists.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/lists.php
new file mode 100644
index 0000000..c7051a2
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/loadingartist.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/loadingartist.com.php
new file mode 100644
index 0000000..d06ed12
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/loadingartist.com.php
@@ -0,0 +1,8 @@
+ array(
+ '%.*%' => array(
+ '%-150x150%' => '',
+ ),
+ ),
+);
diff --git a/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/loldwell.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/loldwell.com.php
new file mode 100644
index 0000000..d358e15
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/lukesurl.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/lukesurl.com.php
new file mode 100644
index 0000000..816233d
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/macg.co.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/macg.co.php
new file mode 100644
index 0000000..bbe6dbc
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/maclife.de.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/maclife.de.php
new file mode 100644
index 0000000..bca347e
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/maclife.de.php
@@ -0,0 +1,11 @@
+ array(
+ '%.*%' => array(
+ 'test_url' => 'http://www.maclife.de/news/neue-farbe-iphone-8-kommt-blush-gold-10094817.html',
+ 'body' => array(
+ '//div[contains(@class, "article_wrapper")]/p | //div[contains(@class, "article_wrapper")]/h2 | //div[@class="gallery"]//figure | //div[contains(@class, "gallery_single")]//figure',
+ )
+ )
+ )
+);
diff --git a/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/magyarkurir.hu.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/magyarkurir.hu.php
new file mode 100644
index 0000000..32d78bc
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/magyarkurir.hu.php
@@ -0,0 +1,21 @@
+ array(
+ '%.*%' => array(
+ 'test_url' => 'http://www.magyarkurir.hu/hirek/a-vilagszerte-ismert-dicsoito-csapat-hillsong-young-free-lep-fel-budapesten',
+ 'body' => array(
+ '//div[@class="behuzas"]'
+ ),
+ 'strip' => array(
+ '//div[@class="ikonsav"]',
+ '//p[@class="copyright"]',
+ '//div[@class="cimkek"]',
+ '//div[@id="footerbanner"]',
+ '//div[@class="rovat sargabg rovatdobozcim"]',
+ '//div[@class="rovatdoboz"]',
+ '//a[contains(., "Own")]',
+ '//a[@class="fblink"]'
+ )
+ ),
+ ),
+);
diff --git a/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/marc.info.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/marc.info.php
new file mode 100644
index 0000000..5f582a6
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/marriedtothesea.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/marriedtothesea.com.php
new file mode 100644
index 0000000..469640d
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/marycagle.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/marycagle.com.php
new file mode 100644
index 0000000..b8665e3
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/maximumble.thebookofbiff.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/maximumble.thebookofbiff.com.php
new file mode 100644
index 0000000..8880054
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/medium.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/medium.com.php
new file mode 100644
index 0000000..e20860e
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/mercworks.net.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/mercworks.net.php
new file mode 100644
index 0000000..c7a27de
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/metronieuws.nl.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/metronieuws.nl.php
new file mode 100644
index 0000000..5011169
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/milwaukeenns.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/milwaukeenns.php
new file mode 100644
index 0000000..ddb29a5
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/mno.hu.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/mno.hu.php
new file mode 100644
index 0000000..a2799b8
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/mno.hu.php
@@ -0,0 +1,14 @@
+ array(
+ '%.*%' => array(
+ 'test_url' => 'https://mno.hu/kulfold/elnokot-valasztanak-szloveniaban-2422840',
+ 'body' => array(
+ '//div[@class="header"]/h1',
+ '//div[@class="content hircikk clearfix"]/p'
+ ),
+ 'strip' => array(
+ )
+ ),
+ ),
+);
diff --git a/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/mokepon.smackjeeves.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/mokepon.smackjeeves.com.php
new file mode 100644
index 0000000..1ddcd40
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/monandroid.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/monandroid.com.php
new file mode 100644
index 0000000..f87560e
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/monwindows.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/monwindows.com.php
new file mode 100644
index 0000000..b2b24d7
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/moya-planeta.ru.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/moya-planeta.ru.php
new file mode 100644
index 0000000..dd84284
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/mrlovenstein.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/mrlovenstein.com.php
new file mode 100644
index 0000000..b971091
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/mrlovenstein.com.php
@@ -0,0 +1,9 @@
+ array(
+ '%.*%' => array(
+ '%alt="(.+)" */>%' => '/> $1',
+ '%\.png%' => '_rollover.png',
+ ),
+ ),
+);
diff --git a/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/muckrock.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/muckrock.com.php
new file mode 100644
index 0000000..9e354a3
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/mynorthshorenow.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/mynorthshorenow.com.php
new file mode 100644
index 0000000..b630915
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nakedCapitalism.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nakedCapitalism.php
new file mode 100644
index 0000000..ec2d5fd
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nasa.gov.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nasa.gov.php
new file mode 100644
index 0000000..c6692d0
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nat-geo.ru.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nat-geo.ru.php
new file mode 100644
index 0000000..1a42d99
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nationaljournal.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nationaljournal.com.php
new file mode 100644
index 0000000..5e612be
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nature.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nature.com.php
new file mode 100644
index 0000000..6b9e87f
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nba.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nba.com.php
new file mode 100644
index 0000000..c8ea926
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nedroid.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nedroid.com.php
new file mode 100644
index 0000000..3214c62
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nedroid.com.php
@@ -0,0 +1,8 @@
+ array(
+ '%.*%' => array(
+ '%title="(.+)" */>%' => '/> $1',
+ ),
+ ),
+);
diff --git a/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/networkworld.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/networkworld.com.php
new file mode 100644
index 0000000..1852435
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/neustadt-ticker.de.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/neustadt-ticker.de.php
new file mode 100644
index 0000000..e0c0d19
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nextinpact.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nextinpact.com.php
new file mode 100644
index 0000000..29dd9d6
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/niceteethcomic.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/niceteethcomic.com.php
new file mode 100644
index 0000000..f41e443
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nichtlustig.de.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nichtlustig.de.php
new file mode 100644
index 0000000..4d083f9
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nichtlustig.de.php
@@ -0,0 +1,8 @@
+ array(
+ '%.*%' => array(
+ '%.*static.nichtlustig.de/comics/full/(\\d+).*%s' => ' ',
+ ),
+ ),
+);
diff --git a/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nlcafe.hu.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nlcafe.hu.php
new file mode 100644
index 0000000..b85e6b2
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nlcafe.hu.php
@@ -0,0 +1,18 @@
+ array(
+ '%.*%' => array(
+ 'test_url' => 'http://www.nlcafe.hu/ezvan/20171021/nyugdijas-drogdilert-fogtak-a-ferencvarosi-rendorok/',
+ 'body' => array(
+ '//div[@class="single-title"]',
+ '//div[@class="single-excerpt"]',
+ '//div[@class="single-post-container-content"]/p',
+ '//div[@class="single-post-container-content"]/div'
+ ),
+ 'strip' => array(
+ '//div[@class="widget-container related-articles bigdata-widget related-full"]',
+ '//div[@class="banner-container clear-banner-row clearfix"]'
+ )
+ ),
+ ),
+);
diff --git a/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/novo-argumente.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/novo-argumente.com.php
new file mode 100644
index 0000000..cef3595
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/novo-argumente.com.php
@@ -0,0 +1,16 @@
+ array(
+ '%.*%' => array(
+ 'test_url' => 'https://www.novo-argumente.com/artikel/der_kampf_gegen_die_schlafkrankheit',
+ 'body' => array(
+ '//main/div/article',
+ ),
+ 'strip' => array(
+ '//*[@class="artikel-datum"]',
+ '//*[@class="artikel-titel"]',
+ '//*[@class="artikel-autor"]',
+ ),
+ ),
+ ),
+);
diff --git a/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/oglaf.com.php b/config/www/user/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/oglaf.com.php
new file mode 100644
index 0000000..8b2b5b6
--- /dev/null
+++ b/config/www/user/plugins/admin/vendor/p3k/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 ',
+ '%