diff --git a/Dockerfile b/Dockerfile
index 2ec3eb1..e7cdddd 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,4 +1,4 @@
-FROM matomo:5.4.0
+FROM matomo:5.5.1
# checkov:skip=CKV_DOCKER_2:Skipping HEALTHCHECK configuration for now
# checkov:skip=CKV_DOCKER_3:The container actually runs as www-data user
@@ -9,16 +9,16 @@ COPY ./files/plugin-EnvironmentVariables-5.0.3/ /var/www/html/plugins/Environmen
COPY ./files/plugin-CustomVariables-5.0.4/ /var/www/html/plugins/CustomVariables
# Add the HeatmapSessionRecording plugin
-COPY ./files/plugin-HeatmapSessionRecording-5.2.4/ /var/www/html/plugins/HeatmapSessionRecording
+COPY ./files/plugin-HeatmapSessionRecording-5.3.1/ /var/www/html/plugins/HeatmapSessionRecording
# Add the UsersFlow plugin
-COPY ./files/plugin-UsersFlow-5.0.5/ /var/www/html/plugins/UsersFlow
+COPY ./files/plugin-UsersFlow-5.0.6/ /var/www/html/plugins/UsersFlow
# Add the SearchEngineKeywordsPerformance plugin
-COPY ./files/plugin-SearchEngineKeywordsPerformance-5.0.22/ /var/www/html/plugins/SearchEngineKeywordsPerformance
+COPY ./files/plugin-SearchEngineKeywordsPerformance-5.0.23/ /var/www/html/plugins/SearchEngineKeywordsPerformance
# Add the CustomReports plugin
-COPY ./files/plugin-CustomReports-5.4.3/ /var/www/html/plugins/CustomReports
+COPY ./files/plugin-CustomReports-5.4.5/ /var/www/html/plugins/CustomReports
# Our custom configuration settings.
COPY ./files/config.ini.php /var/www/html/config/config.ini.php
diff --git a/Makefile b/Makefile
index 0111936..045dd33 100644
--- a/Makefile
+++ b/Makefile
@@ -24,29 +24,3 @@ publish-dev: dist-dev ## Build, tag and push (intended for developer-based manua
docker login -u AWS -p $$(aws ecr get-login-password --region us-east-1) $(ECR_URL_DEV)
docker push $(ECR_URL_DEV):latest
docker push $(ECR_URL_DEV):`git describe --always`
-
-### If this is a Lambda repo, uncomment the two lines below ###
-# update-lambda-dev: ## Updates the lambda with whatever is the most recent image in the ecr (intended for developer-based manual update)
-# aws lambda update-function-code --function-name $(FUNCTION_DEV) --image-uri $(ECR_URL_DEV):latest
-
-
-### Terraform-generated manual shortcuts for deploying to Stage. This requires ###
-### that ECR_NAME_STAGE, ECR_URL_STAGE, and FUNCTION_STAGE environment ###
-### variables are set locally by the developer and that the developer has ###
-### authenticated to the correct AWS Account. The values for the environment ###
-### variables can be found in the stage_build.yml caller workflow. ###
-dist-stage: ## Only use in an emergency
- docker build \
- --platform linux/amd64 \
- -t $(ECR_URL_STAGE):latest \
- -t $(ECR_URL_STAGE):`git describe --always` \
- -t $(ECR_NAME_STAGE):latest .
-
-publish-stage: ## Only use in an emergency
- docker login -u AWS -p $$(aws ecr get-login-password --region us-east-1) $(ECR_URL_STAGE)
- docker push $(ECR_URL_STAGE):latest
- docker push $(ECR_URL_STAGE):`git describe --always`
-
-### If this is a Lambda repo, uncomment the two lines below ###
-# update-lambda-stage: ## Updates the lambda with whatever is the most recent image in the ecr (intended for developer-based manual update)
-# aws lambda update-function-code --function-name $(FUNCTION_STAGE) --image-uri $(ECR_URL_STAGE):latest
diff --git a/docs/HowTos/HOWTO-premium-plugins.md b/docs/HowTos/HOWTO-premium-plugins.md
index 5ea4d58..de577c6 100644
--- a/docs/HowTos/HOWTO-premium-plugins.md
+++ b/docs/HowTos/HOWTO-premium-plugins.md
@@ -36,7 +36,7 @@ Before installing the license key, the *Marketplace* plugin must be activated. T
According to the support team at Matomo, the premium license key can be installed in two instances of Matomo, "stage" and "prod." So, we can do some initial validation of a license key in Dev1, but the key cannot remain installed in the Dev1 instance. The license key installation can either be done by a user with "superuser" privileges in the Matomo web UI or it can be done by a member of InfraEng who has ssh access to the running container task/service. The CLI command is
```bash
-./console marketplace:set-license-key --license-key=LICENSE-KEY ""
+./console marketplace:set-license-key --license-key=
```
This needs to be done once on each of the stage & prod instances of Matomo.
diff --git a/files/plugin-CustomReports-5.4.3/API.php b/files/plugin-CustomReports-5.4.3/API.php
deleted file mode 100644
index 059fc2a..0000000
--- a/files/plugin-CustomReports-5.4.3/API.php
+++ /dev/null
@@ -1,852 +0,0 @@
-Custom Reports API lets you 1) create custom
- * reports within Matomo and 2) view the created reports in the Matomo Reporting UI or consume them via the API.
- *
- * You can choose between different visualizations (eg table or evolution graph) and combine hundreds of dimensions
- * and metrics to get the data you need.
- *
- * @method static \Piwik\Plugins\CustomReports\API getInstance()
- */
-class API extends \Piwik\Plugin\API
-{
- /**
- * @var MetricsList
- */
- private $metricsList;
-
- /**
- * @var DimensionsProvider
- */
- private $columnsProvider;
-
- /**
- * @var CustomReportsModel
- */
- private $model;
-
- /**
- * @var Validator
- */
- private $validator;
-
- /**
- * @var LogTablesProvider
- */
- private $logTablesProvider;
-
- /**
- * @var Configuration
- */
- private $configuration;
-
- /**
- * @var ArchiveInvalidator
- */
- private $archiveInvalidator;
-
- public function __construct(
- CustomReportsModel $model,
- Validator $validator,
- DimensionsProvider $columnsProvider,
- LogTablesProvider $logTablesProvider,
- Configuration $configuration,
- ArchiveInvalidator $archiveInvalidator
- ) {
- $this->metricsList = MetricsList::get();
- $this->columnsProvider = $columnsProvider;
- $this->model = $model;
- $this->validator = $validator;
- $this->logTablesProvider = $logTablesProvider;
- $this->configuration = $configuration;
- $this->archiveInvalidator = $archiveInvalidator;
- }
-
- /**
- * Adds a new custom report
- * @param int $idSite
- * @param string $name The name of the report.
- * @param string $reportType The type of report you want to create, for example 'table' or 'evolution'.
- * For a list of available reports call 'CustomReports.getAvailableReportTypes'
- * @param string[] $metricIds A list of metric IDs. For a list of available metrics call 'CustomReports.getAvailableMetrics'
- * @param string $categoryId By default, the report will be put into a custom report category unless a specific
- * categoryId is provided. For a list of available categories call 'CustomReports.getAvailableCategories'.
- * @param string[] $dimensionIds A list of dimension IDs. For a list of available metrics call 'CustomReports.getAvailableDimensions'
- * @param bool|string $subcategoryId By default, a new reporting page will be created for this report unless you
- * specifiy a specific name or subcategoryID. For a list of available subcategories
- * call 'CustomReports.getAvailableCategories'.
- * @param string $description An optional description for the report, will be shown in the title help icon of the report.
- * @param string $segmentFilter An optional segment to filter the report data. Needs to be sent urlencoded.
- * @param string[] $multipleIdSites An optional list of idsites for which we need to execute the report
- * @return int
- */
- public function addCustomReport($idSite, $name, $reportType, $metricIds, $categoryId = false, $dimensionIds = array(), $subcategoryId = false, $description = '', $segmentFilter = '', $multipleIdSites = [])
- {
- if (!empty($multipleIdSites) && $idSite != 'all' && $idSite != '0') {
- $multipleIdSites = array_unique($multipleIdSites);
- foreach ($multipleIdSites as $multipleIdSite) {
- $this->validator->checkWritePermission($multipleIdSite);
- }
- if (!in_array($idSite, $multipleIdSites)) {
- throw new \Exception(Piwik::translate('CustomReports_ErrorInvalidMultipleIdSite', [$idSite]));
- }
- } else {
- $this->validator->checkWritePermission($idSite);
- // prevent creating reports for sites that do not yet exist but might in the future
- $this->validator->checkSiteExists($idSite);
- }
-
- if (empty($categoryId)) {
- $categoryId = CustomReportsDao::DEFAULT_CATEGORY;
- }
-
- $createdDate = Date::now()->getDatetime();
- if (!empty($segmentFilter)) {
- $segmentFilter = Common::unsanitizeInputValue($segmentFilter);
- $segmentFilter = urldecode($segmentFilter);
- }
-
- // If there's a Product Revenue metric without a Product Quantity metric, throw an exception
- if (
- (in_array('sum_product_revenue', $metricIds) || in_array('avg_product_revenue', $metricIds))
- && !in_array('sum_ecommerce_productquantity', $metricIds)
- && !in_array('avg_ecommerce_productquantity', $metricIds)
- ) {
- throw new \Exception(Piwik::translate('CustomReports_ErrorProductRevenueMetricDependency'));
- }
-
- $idReport = $this->model->createCustomReport($idSite, $name, $description, $reportType, $dimensionIds, $metricIds, $segmentFilter, $categoryId, $subcategoryId, $createdDate, $multipleIdSites);
- $report = $this->model->getCustomReportById($idReport, $idSite);
-
- $config = StaticContainer::get(Configuration::class);
- $startDate = null;
- $subMonth = $config->getReArchiveReportsInPastLastNMonths();
- if (!empty($subMonth)) {
- $startDate = Date::yesterday()->subMonth($subMonth)->setDay(1);
- }
-
- $this->archiveInvalidator->scheduleReArchiving(
- $idSite === 0 || $idSite === '0' || $idSite == 'all' ? 'all' : (!empty($multipleIdSites) ? $multipleIdSites : [$idSite]),
- 'CustomReports',
- Archiver::makeRecordName($idReport, $report['revision'] ?? '0'),
- $startDate
- );
-
- $this->clearCache();
- return $idReport;
- }
-
- private function clearCache()
- {
- // we need to delete possibly cached values. especially ReportsProvider
- try {
- Cache::getLazyCache()->flushAll();
- } catch (\Exception $e) {
- }
- // we need to delete possibly cached values. especially ReportsProvider
- try {
- Cache::getEagerCache()->flushAll();
- } catch (\Exception $e) {
- }
- // we need to delete possibly cached values. especially ReportsProvider
- try {
- Cache::getTransientCache()->flushAll();
- } catch (\Exception $e) {
- }
- }
-
- /**
- * Updates an existing custom report. Be aware that if you change metrics, dimensions, the report type or the segment filter,
- * previously processed/archived reports may become unavailable and would need to be re-processed.
- *
- * @param int $idSite
- * @param int $idCustomReport
- * @param string $name The name of the report.
- * @param string $reportType The type of report you want to create, for example 'table' or 'evolution'.
- * For a list of available reports call 'CustomReports.getAvailableReportTypes'
- * @param string[] $metricIds A list of metric IDs. For a list of available metrics call 'CustomReports.getAvailableMetrics'
- * @param string $categoryId By default, the report will be put into a custom report category unless a specific
- * categoryId is provided. For a list of available categories call 'CustomReports.getAvailableCategories'.
- * @param string[] $dimensionIds A list of dimension IDs. For a list of available metrics call 'CustomReports.getAvailableDimensions'
- * @param bool|string $subcategoryId By default, a new reporting page will be created for this report unless you
- * specifiy a specific name or subcategoryID. For a list of available subcategories
- * call 'CustomReports.getAvailableCategories'.
- * @param string $description An optional description for the report, will be shown in the title help icon of the report.
- * @param string $segmentFilter An optional segment to filter the report data. Needs to be sent urlencoded.
- * @param int[] $subCategoryReportIds List of sub report ids mapped to this report
- * @param string[] $multipleIdSites An optional list of idsites for which we need to execute the report
- */
- public function updateCustomReport(
- $idSite,
- $idCustomReport,
- $name,
- $reportType,
- $metricIds,
- $categoryId = false,
- $dimensionIds = array(),
- $subcategoryId = false,
- $description = '',
- $segmentFilter = '',
- $subCategoryReportIds = [],
- $multipleIdSites = []
- ) {
- if (!empty($multipleIdSites) && $idSite != 'all' && $idSite != '0') {
- $multipleIdSites = array_unique($multipleIdSites);
- foreach ($multipleIdSites as $multipleIdSite) {
- $this->validator->checkWritePermission($multipleIdSite);
- }
- if (!in_array($idSite, $multipleIdSites)) {
- throw new \Exception(Piwik::translate('CustomReports_ErrorInvalidMultipleIdSite', [$idSite]));
- }
- } else {
- $this->validator->checkWritePermission($idSite);
- // prevent creating reports for sites that do not yet exist but might in the future
- $this->validator->checkSiteExists($idSite);
- }
-
- // we cannot get report by idSite, idCustomReport since the idSite may change!
- $report = $this->model->getCustomReportById($idCustomReport, $idSite);
-
- if (empty($report)) {
- throw new \Exception(Piwik::translate('CustomReports_ErrorReportDoesNotExist'));
- }
-
- if ($report['idsite'] != $idSite && empty($multipleIdSites)) {
- // if the site changes for a report, make sure the user write permission for the old and the new site
- $this->validator->checkWritePermission($report['idsite']);
- }
-
- if (empty($categoryId)) {
- $categoryId = CustomReportsDao::DEFAULT_CATEGORY;
- }
-
- if (!empty($segmentFilter)) {
- $segmentFilter = Common::unsanitizeInputValue($segmentFilter);
- $segmentFilter = urldecode($segmentFilter);
- }
-
- $updatedDate = Date::now()->getDatetime();
-
- $shouldReArchive = false;
- if (
- (
- isset($report['report_type']) &&
- $report['report_type'] != $reportType
- ) ||
- (
- isset($report['dimensions']) &&
- $report['dimensions'] != $dimensionIds
- ) ||
- (
- isset($report['metrics']) &&
- $report['metrics'] != $metricIds
- ) ||
- (
- isset($report['segment_filter']) &&
- $report['segment_filter'] != $segmentFilter
- )
- ) {
- $shouldReArchive = true;
- }
-
- // If there's a Product Revenue metric without a Product Quantity metric, throw an exception
- if (
- (in_array('sum_product_revenue', $metricIds) || in_array('avg_product_revenue', $metricIds))
- && !in_array('sum_ecommerce_productquantity', $metricIds)
- && !in_array('avg_ecommerce_productquantity', $metricIds)
- ) {
- throw new \Exception(Piwik::translate('CustomReports_ErrorProductRevenueMetricDependency'));
- }
-
- $this->model->updateCustomReport($idSite, $idCustomReport, $name, $description, $reportType, $dimensionIds, $metricIds, $segmentFilter, $categoryId, $subcategoryId, $updatedDate, $subCategoryReportIds, $multipleIdSites);
-
- if ($shouldReArchive) {
- $updatedReport = $this->model->getCustomReportById($idCustomReport, $idSite);
- $config = StaticContainer::get(Configuration::class);
- $startDate = null;
- $subMonth = $config->getReArchiveReportsInPastLastNMonths();
- if (!empty($subMonth)) {
- $startDate = Date::yesterday()->subMonth($subMonth)->setDay(1);
- }
-
- $this->archiveInvalidator->scheduleReArchiving(
- $idSite === 0 || $idSite === '0' || $idSite == 'all' ? 'all' : (!empty($multipleIdSites) ? $multipleIdSites : [$idSite]),
- 'CustomReports',
- Archiver::makeRecordName($idCustomReport, $updatedReport['revision']),
- $startDate
- );
- }
-
- $this->clearCache();
- }
-
- /**
- * Get all custom report configurations for a specific site.
- *
- * @param int $idSite
- * @param bool $skipCategoryMetadata
- * @return array
- */
- public function getConfiguredReports($idSite, $skipCategoryMetadata = false)
- {
- $this->validator->checkReportViewPermission($idSite);
- $this->validator->checkSiteExists($idSite);
-
- if ($idSite === 'all') {
- $idSite = 0;
- }
-
- $reports = $this->model->getAllCustomReportsForSite($idSite, $skipCategoryMetadata == '1');
- usort($reports, function ($a, $b) {
- if ($a['idcustomreport'] > $b['idcustomreport']) {
- return 1; // no need to check for === because two reports won't have same ID
- }
- return -1;
- });
-
- foreach ($reports as &$report) {
- $this->addAllowedToEditStatus($report);
- }
-
- return $reports;
- }
-
- /**
- * Get a specific custom report configuration.
- *
- * @param int $idSite
- * @param int $idCustomReport
- * @return array
- */
- public function getConfiguredReport($idSite, $idCustomReport)
- {
- $this->validator->checkReportViewPermission($idSite);
- $this->validator->checkSiteExists($idSite);
-
- if ($idSite === 'all') {
- $idSite = 0;
- }
-
- $this->model->checkReportExists($idSite, $idCustomReport);
-
- $report = $this->model->getCustomReport($idSite, $idCustomReport);
- $this->addAllowedToEditStatus($report);
-
- return $report;
- }
-
- /**
- * Deletes the given custom report.
- *
- * When a custom report is deleted, its report will be no longer available in the API and tracked data for this
- * report might be removed at some point by the system.
- *
- * @param int $idSite
- * @param int $idForm
- */
- public function deleteCustomReport($idSite, $idCustomReport)
- {
- $this->validator->checkWritePermission($idSite);
-
- if ($idSite === 'all') {
- $idSite = 0;
- }
-
- $report = $this->getCustomReportInfo($idSite, $idCustomReport, 'Delete');
-
- $multipleIDSites = $report['multiple_idsites'] ? explode(',', $report['multiple_idsites']) : [];
- if ($multipleIDSites) {
- foreach ($multipleIDSites as $multipleIdSite) {
- $this->validator->checkWritePermission($multipleIdSite);
- }
- }
- $this->archiveInvalidator->removeInvalidationsSafely(
- $multipleIDSites ? $multipleIDSites : [$idSite],
- 'CustomReports',
- Archiver::makeRecordName($idCustomReport, $report['revision'])
- );
-
- $this->model->deactivateReport($multipleIDSites ? -1 : $idSite, $idCustomReport, $report['name']);
- Piwik::postEvent('CustomReports.deleteCustomReport.end', array($idSite, $idCustomReport));
- $this->clearCache();
- }
-
- /**
- * Pauses the given custom report.
- *
- * When a custom report is paused, its report will be no longer be archived
- *
- * @param int $idSite
- * @param int $idForm
- */
- public function pauseCustomReport($idSite, $idCustomReport)
- {
- $this->validator->checkWritePermission($idSite);
-
- if ($idSite === 'all') {
- $idSite = 0;
- }
-
- $report = $this->getCustomReportInfo($idSite, $idCustomReport, 'Pause');
-
- $multipleIDSites = $report['multiple_idsites'] ? explode(',', $report['multiple_idsites']) : [];
- if ($multipleIDSites) {
- foreach ($multipleIDSites as $multipleIdSite) {
- $this->validator->checkWritePermission($multipleIdSite);
- }
- }
- $this->archiveInvalidator->removeInvalidationsSafely(
- $multipleIDSites ? $multipleIDSites : [$idSite],
- 'CustomReports',
- Archiver::makeRecordName($idCustomReport, $report['revision'])
- );
-
- $this->model->pauseReport($multipleIDSites ? -1 : $idSite, $idCustomReport, $report['name']);
- $this->clearCache();
- }
-
- /**
- * Resumes the given custom report.
- *
- * When a custom report is resumed, its report will start archiving again
- *
- * @param int $idSite
- * @param int $idForm
- */
- public function resumeCustomReport($idSite, $idCustomReport)
- {
- $this->validator->checkWritePermission($idSite);
-
- if ($idSite === 'all') {
- $idSite = 0;
- }
-
- $report = $this->getCustomReportInfo($idSite, $idCustomReport, 'Resume');
-
- $multipleIDSites = $report['multiple_idsites'] ? explode(',', $report['multiple_idsites']) : [];
- if ($multipleIDSites) {
- foreach ($multipleIDSites as $multipleIdSite) {
- $this->validator->checkWritePermission($multipleIdSite);
- }
- }
-
- $this->model->resumeReport($multipleIDSites ? -1 : $idSite, $idCustomReport, $report['name']);
- $this->clearCache();
- }
-
- /**
- * Get a list of available categories that can be used in custom reports.
- *
- * @param int $idSite
- * @return array
- */
- public function getAvailableCategories($idSite)
- {
- $this->validator->checkReportViewPermission($idSite);
-
- $reportPages = Request::processRequest('API.getReportPagesMetadata', array('idSite' => $idSite, 'filter_limit' => -1));
-
- $categories = array();
- foreach ($reportPages as $reportPage) {
- if (!empty($reportPage['category']['id'])) {
- $categoryId = $reportPage['category']['id'];
-
- if ($categoryId === 'Dashboard_Dashboard') {
- continue;
- }
-
- $subcategoryId = $reportPage['subcategory']['id'];
- if (strpos($subcategoryId, '_Manage') !== false) {
- continue; // we do not want to be able to add reports to manage pages
- }
-
- if (isset($categories[$categoryId])) {
- $categories[$categoryId]['subcategories'][] = array(
- 'uniqueId' => $reportPage['subcategory']['id'],
- 'name' => $reportPage['subcategory']['name']
- );
- } else {
- $categories[$categoryId] = array(
- 'uniqueId' => $categoryId,
- 'name' => $reportPage['category']['name'],
- 'subcategories' => array(
- array(
- 'uniqueId' => $reportPage['subcategory']['id'],
- 'name' => $reportPage['subcategory']['name']
- )
- ),
- );
- }
- }
- }
-
- if (!isset($categories['CustomReports_CustomReports'])) {
- $categories['CustomReports_CustomReports'] = array(
- 'uniqueId' => 'CustomReports_CustomReports',
- 'name' => Piwik::translate('CustomReports_CustomReports'),
- 'subcategories' => array()
- );
- }
-
- return array_values($categories);
- }
-
- /**
- * Get a list of available reporty types that can be used in custom reports.
- *
- * @param int $idSite
- * @return array
- */
- public function getAvailableReportTypes()
- {
- $this->validator->checkHasSomeWritePermission();
-
- $rows = array();
- foreach (ReportType::getAll() as $reportType) {
- $rows[] = array('key' => $reportType::ID, 'value' => $reportType->getName());
- }
-
- return $rows;
- }
-
- private function isTableJoinable($tableName)
- {
- $logTable = $this->logTablesProvider->getLogTable($tableName);
- if ($logTable && ($logTable->getColumnToJoinOnIdAction() || $logTable->getColumnToJoinOnIdVisit())) {
- if ($logTable->getPrimaryKey()) {
- // without primary key we would not group the data correctly
- return true;
- }
- } elseif ($logTable && $logTable->getWaysToJoinToOtherLogTables()) {
- $tables = new JoinTables($this->logTablesProvider, [$tableName]);
- return $tables->isTableJoinableOnVisit($tableName) || $tables->isTableJoinableOnAction($tableName);
- }
-
- return false;
- }
-
- /**
- * Get a list of available dimensions that can be used in custom reports.
- *
- * @param int $idSite
- * @return array
- */
- public function getAvailableDimensions($idSite)
- {
- Piwik::checkUserIsNotAnonymous();
- Piwik::checkUserHasSomeViewAccess();
-
- $dimensions = $this->columnsProvider->getAllDimensions();
-
- $rows = array();
-
- $dimensionsToIgnore = array(
- 'Actions.IdPageview', 'CoreHome.VisitId',
- 'DevicesDetection.OsVersion', // only makes sense in combination with Os Family
- 'CoreHome.LinkVisitActionId', 'CoreHome.LinkVisitActionIdPages', 'UserCountry.Provider'
- );
-
- $dimensionsToRename = [
- 'CoreHome.IdSite' => Piwik::translate('CustomReports_WebsiteName')
- ];
-
- $config = StaticContainer::get(Configuration::class);
- foreach ($config->getDisabledDimensions() as $dimensionDisabled) {
- $dimensionsToIgnore[] = $dimensionDisabled;
- }
-
- /**
- * Adds the possibility to other plugins to ignore more dimensions
- */
- Piwik::postEvent('CustomReports.addDimensionsToIgnore', array(&$dimensionsToIgnore));
-
- $categoryList = CategoryList::get();
-
- foreach ($dimensions as $dimension) {
- $categoryId = $dimension->getCategoryId();
- $dimensionName = $dimension->getName();
- $table = $dimension->getDbTableName();
- $dimensionId = $dimension->getId();
-
- if (!$table) {
- // without table we cannot join it
- continue;
- }
-
- if (!$this->isTableJoinable($table)) {
- // archiving this dimension would not work
- continue;
- }
-
- if (in_array($dimensionId, $dimensionsToIgnore)) {
- continue;
- }
-
- if (key_exists($dimensionId, $dimensionsToRename)) {
- $dimensionName = $dimensionsToRename[$dimensionId];
- }
-
- if ($dimension->getColumnName() && $dimensionName) {
- if (!isset($rows[$categoryId])) {
- $category = $categoryList->getCategory($categoryId);
- $orderId = 999;
- if (!empty($category)) {
- $orderId = $category->getOrder();
- }
-
- $categoryName = Piwik::translate($categoryId);
- if (!is_null($category) && method_exists($category, 'getDisplayName')) {
- $categoryName = $category->getDisplayName();
- }
-
- $rows[$categoryId] = array(
- 'category' => $categoryName,
- 'dimensions' => array(),
- 'orderId' => $orderId
- );
- }
- $rows[$categoryId]['dimensions'][] = array(
- 'uniqueId' => $dimension->getId(),
- 'name' => ucwords($dimensionName),
- 'sqlSegment' => $dimension->getSqlSegment(),
- );
- }
- }
-
- usort($rows, function ($rowA, $rowB) {
- if ((int)$rowA['orderId'] > (int)$rowB['orderId']) {
- return 1;
- }
- if ((int)$rowA['orderId'] === (int)$rowB['orderId']) {
- return 0;
- }
- return -1;
- });
-
- foreach ($rows as $categoryId => $row) {
- $dimensions = $row['dimensions'];
- usort($dimensions, function ($dimA, $dimB) {
- return strcmp($dimA['name'], $dimB['name']);
- });
- $rows[$categoryId]['dimensions'] = $dimensions;
- }
-
- return array_values($rows);
- }
-
- /**
- * Get a list of available metrics that can be used in custom reports.
- *
- * @param int $idSite
- * @return array
- */
- public function getAvailableMetrics($idSite)
- {
- Piwik::checkUserIsNotAnonymous();
- Piwik::checkUserHasSomeViewAccess();
-
- $metrics = MetricsList::get();
- $categoryList = CategoryList::get();
-
- $rows = array();
- $period = Common::getRequestVar('period', '', 'string');
- foreach ($metrics->getMetrics() as $metric) {
- if (!$metric) {
- continue;
- }
- if ($metric instanceof ProcessedMetric && !$this->canGenerateMetricAutomatically($metric)) {
- // we do not have all the dependent metrics to generate this processed metric automatically
- continue;
- }
-
- $categoryId = $metric->getCategoryId();
- $name = $metric->getName();
- $translatedName = $metric->getTranslatedName();
-
- if (($metric instanceof ProcessedMetric || $metric instanceof ArchivedMetric) && $name && $translatedName) {
- if (method_exists($metric, 'getQuery') && !$metric->getQuery()) {
- // archiving this metric would not work!
- continue;
- }
-
- if (method_exists($metric, 'getDbTableName') && $metric->getDbTableName() && !$this->isTableJoinable($metric->getDbTableName())) {
- // archiving this metric would not work!
- continue;
- }
-
- if (method_exists($metric, 'getDimension') && $metric->getDimension()) {
- $dimension = $metric->getDimension();
- $dbDiscriminator = $dimension->getDbDiscriminator();
- if ($dbDiscriminator) {
- $dbDiscriminatorValue = $dbDiscriminator->getValue();
- if (!isset($dbDiscriminatorValue) || !is_numeric($dbDiscriminatorValue)) {
- continue;
- }
- }
- }
-
- if (!isset($rows[$categoryId])) {
- $category = $categoryList->getCategory($categoryId);
- $orderId = 999;
- if (!empty($category)) {
- $orderId = $category->getOrder();
- }
-
- $categoryName = Piwik::translate($categoryId);
- if (!is_null($category) && method_exists($category, 'getDisplayName')) {
- $categoryName = $category->getDisplayName();
- }
-
- $rows[$categoryId] = array(
- 'category' => $categoryName,
- 'metrics' => array(),
- 'orderId' => $orderId
- );
- }
-
- $description = $metric->getDocumentation();
- if (stripos($translatedName, 'unique') === 0) {
- $description = Piwik::translate('CustomReports_CommonUniqueMetricDescription', array($description, ucwords($translatedName), str_replace('Unique ', '', ucwords($translatedName))));
- }
-
- $rows[$categoryId]['metrics'][] = array(
- 'uniqueId' => $name, 'name' => ucwords($translatedName), 'description' => $description
- );
- }
- }
-
- usort($rows, function ($rowA, $rowB) {
- if ((int)$rowA['orderId'] > (int)$rowB['orderId']) {
- return 1;
- }
- if ((int)$rowA['orderId'] === (int)$rowB['orderId']) {
- return 0;
- }
- return -1;
- });
-
- foreach ($rows as $category => $row) {
- $dimensions = $row['metrics'];
- usort($dimensions, function ($dimA, $dimB) {
- return strcasecmp($dimA['name'], $dimB['name']);
- });
- $rows[$category]['metrics'] = $dimensions;
- }
-
- return array_values($rows);
- }
-
- private function canGenerateMetricAutomatically(ProcessedMetric $metric)
- {
- foreach ($metric->getDependentMetrics() as $dependentMetric) {
- $depMetric = $this->metricsList->getMetric($dependentMetric);
- if (!$depMetric) {
- // we cannot generate this metric directly
- return false;
- }
-
- if ($depMetric instanceof ProcessedMetric && !$this->canGenerateMetricAutomatically($depMetric)) {
- return false;
- }
- }
-
- return true;
- }
-
- /**
- * Get report data for a previously created custom report.
- *
- * @param int $idSite
- * @param string $period
- * @param string $date
- * @param int $idCustomReport
- * @param bool|string $segment
- * @param bool $expanded
- * @param bool $flat
- * @param int|bool $idSubtable
- * @param string|bool $columns
- * @return DataTable\DataTableInterface
- */
- public function getCustomReport($idSite, $period, $date, $idCustomReport, $segment = false, $expanded = false, $flat = false, $idSubtable = false, $columns = false)
- {
- $this->validator->checkReportViewPermission($idSite);
- $this->validator->checkSiteExists($idSite); // lets not return any reports from eg deleted sites if for some reason report still exists
- $this->model->checkReportExists($idSite, $idCustomReport);
-
- $report = $this->model->getCustomReport($idSite, $idCustomReport);
-
- $reportType = ReportType::factory($report['report_type']);
-
- $table = $reportType->fetchApi($idSite, $idCustomReport, $period, $date, $segment, $expanded, $flat, $idSubtable, $columns);
-
- return $table;
- }
-
- private function addAllowedToEditStatus(&$report)
- {
- $idSite = $report['idsite'];
- $multipleIdSites = $report['multiple_idsites'] ? explode(',', $report['multiple_idsites']) : array();
- if (Piwik::hasUserSuperUserAccess()) {
- $allowedToEdit = true;
- } elseif ($idSite == 'all' || $idSite == '0') {
- $allowedToEdit = false;
- } else {
- $allowedToEdit = $multipleIdSites ? Piwik::isUserHasWriteAccess($multipleIdSites) : Piwik::isUserHasWriteAccess($idSite);
- }
-
- $report['allowedToEdit'] = $allowedToEdit;
- }
-
- private function getCustomReportInfo($idSite, $idCustomReport, $action)
- {
- $report = $this->model->getCustomReport($idSite, $idCustomReport);
-
- if (empty($report)) {
- throw new \Exception(Piwik::translate('CustomReports_ErrorCustomReportDoesNotExist'));
- } elseif ($report['idsite'] != $idSite) {
- // prevent a possible hack that someone passes a different site than the report has and then we accidentally
- // still delete the report because we match with `idsite = 0 or idsite = ?`. We don't do this here right now
- // and wouldn't need this code but it is to prevent any possible future security bugs.
- throw new \Exception(Piwik::translate('CustomReports_' . $action . 'ExceptionMessage'));
- }
-
- return $report;
- }
-}
diff --git a/files/plugin-CustomReports-5.4.3/vue/dist/CustomReports.umd.min.js b/files/plugin-CustomReports-5.4.3/vue/dist/CustomReports.umd.min.js
deleted file mode 100644
index 9bbc062..0000000
--- a/files/plugin-CustomReports-5.4.3/vue/dist/CustomReports.umd.min.js
+++ /dev/null
@@ -1,44 +0,0 @@
-(function(e,t){"object"===typeof exports&&"object"===typeof module?module.exports=t(require("CoreHome"),require("vue"),require("CorePluginsAdmin"),require("SegmentEditor")):"function"===typeof define&&define.amd?define(["CoreHome",,"CorePluginsAdmin","SegmentEditor"],t):"object"===typeof exports?exports["CustomReports"]=t(require("CoreHome"),require("vue"),require("CorePluginsAdmin"),require("SegmentEditor")):e["CustomReports"]=t(e["CoreHome"],e["Vue"],e["CorePluginsAdmin"],e["SegmentEditor"])})("undefined"!==typeof self?self:this,(function(e,t,o,r){return function(e){var t={};function o(r){if(t[r])return t[r].exports;var i=t[r]={i:r,l:!1,exports:{}};return e[r].call(i.exports,i,i.exports,o),i.l=!0,i.exports}return o.m=e,o.c=t,o.d=function(e,t,r){o.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},o.r=function(e){"undefined"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},o.t=function(e,t){if(1&t&&(e=o(e)),8&t)return e;if(4&t&&"object"===typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(o.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var i in e)o.d(r,i,function(t){return e[t]}.bind(null,i));return r},o.n=function(e){var t=e&&e.__esModule?function(){return e["default"]}:function(){return e};return o.d(t,"a",t),t},o.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},o.p="plugins/CustomReports/vue/dist/",o(o.s="fae3")}({"19dc":function(t,o){t.exports=e},"8bbf":function(e,o){e.exports=t},a5a2:function(e,t){e.exports=o},f06f:function(e,t){e.exports=r},fae3:function(e,t,o){"use strict";if(o.r(t),o.d(t,"ReportEdit",(function(){return Mt})),o.d(t,"ReportsList",(function(){return Vo})),o.d(t,"ReportsManage",(function(){return Io})),"undefined"!==typeof window){var r=window.document.currentScript,i=r&&r.src.match(/(.+\/)[^/]+\.js(\?.*)?$/);i&&(o.p=i[1])}var n=o("8bbf"),s={class:"loadingPiwik"},a=Object(n["createElementVNode"])("img",{src:"plugins/Morpheus/images/loading-blue.gif"},null,-1),l={class:"loadingPiwik"},c=Object(n["createElementVNode"])("img",{src:"plugins/Morpheus/images/loading-blue.gif"},null,-1),d={class:"alert alert-warning"},u={key:0},p={key:1},m={key:0,class:"alert alert-warning"},h=["innerHTML"],b={key:1},f={name:"name"},v={name:"description"},g={class:"form-group row"},j={class:"col s12"},O={class:"col s12 m6"},y={for:"all_websites",class:"siteSelectorLabel"},R={class:"sites_autocomplete"},S={class:"col s12 m6"},C={class:"form-help"},N={key:0,class:"inline-help"},E={key:1,class:"inline-help"},k={key:0,class:"col s12 m6"},V={key:0},w={for:"websitecontains"},_=Object(n["createElementVNode"])("br",null,null,-1),M=["placeholder"],D=["disabled","value"],A={key:1},I=Object(n["createElementVNode"])("br",null,null,-1),U={class:"entityTable"},B={class:"siteId"},T={class:"siteName"},L={key:0,class:"siteAction"},x={colspan:"3"},P={key:0,class:"siteAction"},H=["onClick"],G={class:"form-group row"},q={class:"col s12"},F={class:"unlockAlert alert alert-info"},W={key:0},Y={key:1},z=Object(n["createElementVNode"])("br",null,null,-1),Q=Object(n["createElementVNode"])("br",null,null,-1),X=["value"],J={class:"alertUnlocked alert alert-warning"},K={key:0},Z={key:1},ee={name:"reportType"},te={class:"form-group row"},oe={class:"col s12 m6 dimensionsGroup"},re=Object(n["createElementVNode"])("br",null,null,-1),ie={class:"groupValueSelect",name:"dimensions"},ne=["title","onClick"],se={class:"groupValueSelect addDimension",name:"dimensions"},ae={class:"col s12 m6"},le={class:"form-help"},ce=["innerHTML"],de={class:"form-group row"},ue={class:"col s12 m6 metricsGroup"},pe=Object(n["createElementVNode"])("br",null,null,-1),me={class:"groupValueSelect",name:"metrics"},he=["title","onClick"],be={class:"groupValueSelect addMetric",name:"metrics"},fe={class:"col s12 m6"},ve={class:"form-help"},ge={class:"inline-help"},je=["innerHTML"],Oe={class:"form-group row segmentFilterGroup"},ye={class:"col s12"},Re={style:{margin:"8px 0",display:"inline-block"}},Se={class:"form-group row"},Ce={class:"col s12"},Ne=Object(n["createElementVNode"])("br",null,null,-1),Ee=Object(n["createElementVNode"])("br",null,null,-1),ke={name:"reportCategories"},Ve={name:"reportSubcategories"},we={class:"alert alert-warning"},_e={key:0},Me={key:1},De={class:"alert alert-warning"},Ae={key:0},Ie={key:1},Ue={key:0,class:"form-group row"},Be=["textContent"],Te={class:"col s12 m6"},Le={id:"childReports",class:"col s12 m6"},xe=["data-id"],Pe=Object(n["createElementVNode"])("span",{class:"ui-icon ui-icon-arrowthick-2-n-s"},null,-1),He={class:"col s12 m6"},Ge={class:"form-help"},qe=["textContent"],Fe={class:"entityCancel"},We={class:"ui-confirm",id:"confirmUnlockReport",ref:"confirmUnlockReport"},$e={key:0},Ye={key:1},ze=["value"],Qe=["value"],Xe={class:"ui-confirm",id:"infoReportIsLocked",ref:"infoReportIsLocked"},Je={key:0},Ke={key:1},Ze=["value"],et=["value"];function tt(e,t,o,r,i,$){var tt=Object(n["resolveComponent"])("Field"),ot=Object(n["resolveComponent"])("SiteSelector"),rt=Object(n["resolveComponent"])("SegmentGenerator"),it=Object(n["resolveComponent"])("SaveButton"),nt=Object(n["resolveComponent"])("ContentBlock");return Object(n["openBlock"])(),Object(n["createBlock"])(nt,{class:"editReport","content-title":e.contentTitle},{default:Object(n["withCtx"])((function(){var o,r,i;return[Object(n["withDirectives"])(Object(n["createElementVNode"])("p",null,[Object(n["createElementVNode"])("span",s,[a,Object(n["createTextVNode"])(" "+Object(n["toDisplayString"])(e.translate("General_LoadingData")),1)])],512),[[n["vShow"],e.isLoading]]),Object(n["withDirectives"])(Object(n["createElementVNode"])("p",null,[Object(n["createElementVNode"])("span",l,[c,Object(n["createTextVNode"])(" "+Object(n["toDisplayString"])(e.translate("CustomReports_UpdatingData")),1)])],512),[[n["vShow"],e.isUpdating]]),Object(n["withDirectives"])(Object(n["createElementVNode"])("div",d,[e.multipleSites.length&&!e.report.allowedToEdit?(Object(n["openBlock"])(),Object(n["createElementBlock"])("span",u,Object(n["toDisplayString"])(e.translate("CustomReports_ReportEditNotAllowedMultipleWebsitesAccessIssue")),1)):(Object(n["openBlock"])(),Object(n["createElementBlock"])("span",p,Object(n["toDisplayString"])(e.translate("CustomReports_ReportEditNotAllowedAllWebsitesUpdated")),1))],512),[[n["vShow"],!e.canEdit]]),"paused"===e.report.status?(Object(n["openBlock"])(),Object(n["createElementBlock"])("div",m,[e.report.allowedToEdit?(Object(n["openBlock"])(),Object(n["createElementBlock"])("span",{key:0,innerHTML:e.getPausedStateAdminMessage},null,8,h)):(Object(n["openBlock"])(),Object(n["createElementBlock"])("span",b,Object(n["toDisplayString"])(e.translate("CustomReports_NoDataMessagePausedStateNonAdminUser")),1))])):Object(n["createCommentVNode"])("",!0),Object(n["createElementVNode"])("form",{onSubmit:t[15]||(t[15]=function(t){return e.edit?e.updateReport():e.createReport()})},[Object(n["createElementVNode"])("div",null,[Object(n["createElementVNode"])("div",f,[Object(n["createVNode"])(tt,{uicontrol:"text",name:"name","model-value":e.report.name,"onUpdate:modelValue":t[0]||(t[0]=function(t){e.report.name=t,e.setValueHasChanged()}),title:e.translate("General_Name"),maxlength:50,disabled:!e.canEdit,placeholder:e.translate("CustomReports_FieldNamePlaceholder"),"inline-help":e.translate("CustomReports_ReportNameHelp")},null,8,["model-value","title","disabled","placeholder","inline-help"])]),Object(n["createElementVNode"])("div",v,[Object(n["createVNode"])(tt,{uicontrol:"textarea",name:"description","model-value":e.report.description,"onUpdate:modelValue":t[1]||(t[1]=function(t){e.report.description=t,e.setValueHasChanged()}),title:"".concat(e.translate("General_Description")," (optional)"),maxlength:1e3,disabled:!e.canEdit,rows:3,placeholder:e.translate("CustomReports_FieldDescriptionPlaceholder"),"inline-help":e.translate("CustomReports_ReportDescriptionHelp")},null,8,["model-value","title","disabled","placeholder","inline-help"])]),Object(n["createElementVNode"])("div",g,[Object(n["createElementVNode"])("h3",j,Object(n["toDisplayString"])(e.translate("CustomReports_ApplyTo")),1),Object(n["createElementVNode"])("div",O,[Object(n["createElementVNode"])("div",null,[Object(n["createElementVNode"])("label",y,Object(n["toDisplayString"])(e.translate("General_Website")),1),Object(n["createElementVNode"])("div",R,[Object(n["createVNode"])(ot,{id:"all_websites","model-value":e.report.site,"onUpdate:modelValue":t[2]||(t[2]=function(t){e.report.site=t,e.setWebsiteChanged(t)}),"show-all-sites-item":e.isSuperUser,"switch-site-on-select":!1,"show-selected-site":!0},null,8,["model-value","show-all-sites-item"])])])]),Object(n["createElementVNode"])("div",S,[Object(n["createElementVNode"])("div",C,[e.isSuperUser?(Object(n["openBlock"])(),Object(n["createElementBlock"])("span",N,Object(n["toDisplayString"])(e.translate("CustomReports_ReportAllWebsitesHelp")),1)):(Object(n["openBlock"])(),Object(n["createElementBlock"])("span",E,Object(n["toDisplayString"])(e.translate("CustomReports_ReportAllWebsitesNonSuperUserHelp")),1))])]),"all"!==e.report.site.id&&"0"!==e.report.site.id&&0!==e.report.site.id?(Object(n["openBlock"])(),Object(n["createElementBlock"])("div",k,[e.report.allowedToEdit?(Object(n["openBlock"])(),Object(n["createElementBlock"])("div",V,[Object(n["createElementVNode"])("span",w,Object(n["toDisplayString"])(e.translate("CustomReports_SelectMeasurablesMatchingSearch")),1),_,Object(n["withDirectives"])(Object(n["createElementVNode"])("input",{class:"control_text customReportSearchMeasurablesField",type:"text",id:"websitecontains","onUpdate:modelValue":t[3]||(t[3]=function(t){return e.containsText=t}),placeholder:e.translate("General_Search")},null,8,M),[[n["vModelText"],e.containsText]]),Object(n["createElementVNode"])("input",{style:{"margin-left":"3.5px"},disabled:!e.containsText,class:"btn customReportSearchFindMeasurables",type:"button",onClick:t[4]||(t[4]=function(t){return e.addSitesContaining(e.containsText)}),value:e.translate("CustomReports_FindMeasurables")},null,8,D)])):Object(n["createCommentVNode"])("",!0),e.report.allowedToEdit||e.multipleSites.length?(Object(n["openBlock"])(),Object(n["createElementBlock"])("div",A,[I,Object(n["createElementVNode"])("table",U,[Object(n["createElementVNode"])("thead",null,[Object(n["createElementVNode"])("tr",null,[Object(n["createElementVNode"])("th",B,Object(n["toDisplayString"])(e.translate("General_Id")),1),Object(n["createElementVNode"])("th",T,Object(n["toDisplayString"])(e.translate("General_Name")),1),e.report.allowedToEdit?(Object(n["openBlock"])(),Object(n["createElementBlock"])("th",L,Object(n["toDisplayString"])(e.translate("General_Remove")),1)):Object(n["createCommentVNode"])("",!0)])]),Object(n["createElementVNode"])("tbody",null,[Object(n["withDirectives"])(Object(n["createElementVNode"])("tr",null,[Object(n["createElementVNode"])("td",x,Object(n["toDisplayString"])(e.translate("CustomReports_NoMeasurableAssignedYet")),1)],512),[[n["vShow"],!e.multipleSites.length]]),(Object(n["openBlock"])(!0),Object(n["createElementBlock"])(n["Fragment"],null,Object(n["renderList"])(e.multipleSites,(function(t,o){return Object(n["withDirectives"])((Object(n["openBlock"])(),Object(n["createElementBlock"])("tr",{key:o},[Object(n["createElementVNode"])("td",null,Object(n["toDisplayString"])(t.idsite),1),Object(n["createElementVNode"])("td",null,Object(n["toDisplayString"])(t.name),1),e.report.allowedToEdit?(Object(n["openBlock"])(),Object(n["createElementBlock"])("td",P,[Object(n["createElementVNode"])("span",{class:"icon-minus table-action",onClick:function(o){return e.removeSite(t)}},null,8,H)])):Object(n["createCommentVNode"])("",!0)],512)),[[n["vShow"],e.multipleSites.length>0]])})),128))])])])):Object(n["createCommentVNode"])("",!0)])):Object(n["createCommentVNode"])("",!0)]),Object(n["createElementVNode"])("div",G,[Object(n["createElementVNode"])("h3",q,Object(n["toDisplayString"])(e.translate("CustomReports_ReportContent")),1)]),Object(n["withDirectives"])(Object(n["createElementVNode"])("div",F,[e.browserArchivingDisabled&&e.reArchiveLastN?(Object(n["openBlock"])(),Object(n["createElementBlock"])("span",W,Object(n["toDisplayString"])(e.translate("CustomReports_WarningRequiresUnlockBrowserArchivingDisabled",e.reArchiveLastN)),1)):Object(n["createCommentVNode"])("",!0),e.browserArchivingDisabled&&e.reArchiveLastN?Object(n["createCommentVNode"])("",!0):(Object(n["openBlock"])(),Object(n["createElementBlock"])("span",Y,Object(n["toDisplayString"])(e.translate("CustomReports_WarningRequiresUnlock")),1)),z,Q,Object(n["createElementVNode"])("input",{type:"button",class:"btn unlockReport",onClick:t[5]||(t[5]=function(t){return e.unlockReport()}),value:e.translate("CustomReports_Unlock")},null,8,X)],512),[[n["vShow"],e.isLocked]]),Object(n["withDirectives"])(Object(n["createElementVNode"])("div",J,[e.browserArchivingDisabled&&e.reArchiveLastN?(Object(n["openBlock"])(),Object(n["createElementBlock"])("span",K,Object(n["toDisplayString"])(e.translate("CustomReports_WarningOnUpdateReportMightGetLostBrowserArchivingDisabled",e.reArchiveLastN)),1)):Object(n["createCommentVNode"])("",!0),e.browserArchivingDisabled&&e.reArchiveLastN?Object(n["createCommentVNode"])("",!0):(Object(n["openBlock"])(),Object(n["createElementBlock"])("span",Z,Object(n["toDisplayString"])(e.translate("CustomReports_WarningOnUpdateReportMightGetLost")),1))],512),[[n["vShow"],e.isUnlocked]]),Object(n["createElementVNode"])("div",ee,[Object(n["createVNode"])(tt,{uicontrol:"radio",name:"reportType","model-value":e.report.report_type,"onUpdate:modelValue":t[6]||(t[6]=function(t){return e.setReportTypeHasChanged(t)}),title:e.translate("CustomReports_ReportType"),disabled:!e.canEdit,options:e.reportTypes},null,8,["model-value","title","disabled","options"])]),Object(n["withDirectives"])(Object(n["createElementVNode"])("div",te,[Object(n["createElementVNode"])("div",oe,[Object(n["createElementVNode"])("label",null,Object(n["toDisplayString"])(e.translate("CustomReports_Dimensions")),1),re,Object(n["createElementVNode"])("div",null,[(Object(n["openBlock"])(!0),Object(n["createElementBlock"])(n["Fragment"],null,Object(n["renderList"])(e.report.dimensions,(function(t,o){return Object(n["openBlock"])(),Object(n["createElementBlock"])("div",{class:Object(n["normalizeClass"])("selectedDimension selectedDimension".concat(o)),key:o},[Object(n["createElementVNode"])("div",ie,[Object(n["createVNode"])(tt,{uicontrol:"expandable-select",name:"dimensions","model-value":t,"onUpdate:modelValue":function(t){return e.changeDimension(t,o)},title:e.dimensionsReadable[t]||t,"full-width":!0,options:e.dimensions},null,8,["model-value","onUpdate:modelValue","title","options"])]),Object(n["createElementVNode"])("span",{class:"icon-minus",title:e.translate("CustomReports_RemoveDimension"),onClick:function(t){return e.removeDimension(o)}},null,8,ne)],2)})),128)),Object(n["withDirectives"])(Object(n["createElementVNode"])("div",se,[Object(n["createVNode"])(tt,{uicontrol:"expandable-select",name:"dimensions","model-value":"","onUpdate:modelValue":t[7]||(t[7]=function(t){e.addDimension(t)}),title:e.translate("CustomReports_AddDimension"),"full-width":!0,options:e.dimensions},null,8,["title","options"])],512),[[n["vShow"],e.report.dimensions.lengthe.length)&&(t=e.length);for(var o=0,r=new Array(t);oe.length)&&(t=e.length);for(var o=0,r=new Array(t);o2&&void 0!==arguments[2]?arguments[2]:null,r=ot["NotificationsStore"].show({message:e,context:t,id:Et,type:null!==o&&void 0!==o?o:"transient",prepend:!0});setTimeout((function(){ot["NotificationsStore"].scrollToNotification(r)}),100)},showProductMetricNotification:function(e,t){var o=ot["NotificationsStore"].show({message:e,context:"warning",id:kt,type:"transient"});t&&setTimeout((function(){ot["NotificationsStore"].scrollToNotification(o)}),100)},showErrorFieldNotProvidedNotification:function(e){var t=Object(ot["translate"])("CustomReports_ErrorXNotProvided",[e]);this.showNotification(t,"error")},init:function(){var e=this,t=this.idCustomReport;this.canEdit=!0,this.report=wt(),ot["Matomo"].helper.lazyScrollToContent(),this.edit&&t?jt.findReport(t,!0).then((function(t){var o;if(t){e.report=Object(ot["clone"])(t),e.isLocked=!0,e.isUnlocked=!1,e.canEdit=!0,e.childReports=null!==(o=e.report.child_reports)&&void 0!==o?o:[],e.report.multipleIdSites&&e.report.multipleIdSites.length&&"all"!==e.report.site.id&&"0"!==e.report.site.id&&0!==e.report.site.id&&(e.multipleSites=e.report.multipleIdSites,e.report.allowedToEdit||(e.canEdit=!1,e.isLocked=!1)),e.childReports.length&&Object.values(e.childReports).forEach((function(t){e.childReportIds.push(t.idcustomreport)})),$(document).ready((function(){$("#childReports").sortable({connectWith:"#childReports",update:function(){e.isDirty=!0;var t=$("#childReports li");e.childReportIds=[],t.each((function(t,o){o.dataset.id&&e.childReportIds.push(o.dataset.id)}))}})}));var r=e.report.idsite;0!==r&&"0"!==r&&"all"!==r||(r="all",e.isSuperUser||(e.canEdit=!1,e.isLocked=!1)),e.report.site={id:r,name:e.report.site.name},e.isDirty=!1,e.initReportOptions()}})):this.create&&(this.report={idsite:ot["Matomo"].idSite,site:{id:ot["Matomo"].idSite,name:ot["Matomo"].currentSiteName||ot["Matomo"].siteName},name:"",description:"",dimensions:[],metrics:["nb_visits"],report_type:"table",category:{id:"CustomReports_CustomReports"},subcategory:null,segment_filter:"",child_reports:[],allowedToEdit:!0},this.isLocked=!1,this.canEdit=!0,this.isDirty=!1,this.initReportOptions())},cancel:function(){var e=Object.assign({},ot["MatomoUrl"].hashParsed.value);delete e.idCustomReport,ot["MatomoUrl"].updateHash(e)},unlockReport:function(){var e=this;this.report&&this.isLocked&&ot["Matomo"].helper.modalConfirm(this.$refs.confirmUnlockReport,{yes:function(){e.doUnlock()}})},createReport:function(){var e=this,t="CustomReports.addCustomReport";this.removeAnyReportNotification(),this.checkRequiredFieldsAreSet()&&(this.multipleIdSites=[],this.multipleSites&&this.multipleSites.length&&"all"!==this.report.site.id&&"0"!==this.report.site.id&&0!==this.report.site.id&&(this.multipleIdSites.push(ot["Matomo"].idSite),this.multipleSites.forEach((function(t){var o=t.idsite;e.multipleIdSites.includes(o)||e.multipleIdSites.push(o)}))),this.multipleIdSites&&this.multipleIdSites.length&&(this.report.site.id=ot["Matomo"].idSite),jt.createOrUpdateReport(this.report,t,this.childReportIds,this.multipleIdSites).then((function(t){if(t&&"error"!==t.type&&t.response){e.isDirty=!1;var o=t.response.value;if(e.report.site){var r=e.report.site.id;if(r&&"all"!==r&&"".concat(r)!=="".concat(ot["Matomo"].idSite))return void ot["MatomoUrl"].updateUrl(Object.assign(Object.assign({},ot["MatomoUrl"].urlParsed.value),{},{idSite:r}),Object.assign(Object.assign({},ot["MatomoUrl"].hashParsed.value),{},{idCustomReport:o}))}jt.reload().then((function(){ot["Matomo"].helper.isReportingPage()&&ot["Matomo"].postEvent("updateReportingMenu"),ot["MatomoUrl"].updateHash(Object.assign(Object.assign({},ot["MatomoUrl"].hashParsed.value),{},{idCustomReport:o})),setTimeout((function(){e.showNotification(Object(ot["translate"])("CustomReports_ReportCreated"),t.type)}),200)}))}else{var i,n;e.showApiErrorMessage(null!==(i=t.message)&&void 0!==i?i:"",null!==(n=t.type)&&void 0!==n?n:"error")}})))},showPreview:function(){var e,t,o;if(this.isProductRevenueDependencyMet(!0)){var r=null!==(e=this.report.site)&&void 0!==e&&e.id&&"all"!==this.report.site.id?this.report.site.id:ot["Matomo"].idSite,i=(null===(t=this.report.dimensions)||void 0===t?void 0:t.length)&&this.report.report_type&&"evolution"!==this.report.report_type,n=i?this.report.dimensions.join(","):void 0,s=!(null===(o=this.report.metrics)||void 0===o||!o.length),a=s?this.report.metrics.join(","):void 0,l=ot["MatomoUrl"].stringify({module:"CustomReports",action:"previewReport",period:"day",date:"today",idSite:r,report_type:this.report.report_type,dimensions:n,metrics:a,segment:this.report.segment_filter||void 0}),c=Object(ot["translate"])("CustomReports_Preview");window.Piwik_Popover.createPopupAndLoadUrl(l,c,"customReportPreview")}},setValueHasChanged:function(){this.isDirty=!0},addDimension:function(e){var t=this;this.report&&e&&(this.isLocked?this.confirmReportIsLocked((function(){t.addDimension(e)})):(this.report.dimensions||(this.report.dimensions=[]),this.report.dimensions=[].concat(Ot(this.report.dimensions),[e]),this.setValueHasChanged()))},changeDimension:function(e,t){var o,r=this;this.report&&e&&(this.isLocked?this.confirmReportIsLocked((function(){r.changeDimension(e,t)})):null!==(o=this.report.dimensions)&&void 0!==o&&o[t]&&(this.report.dimensions=Ot(this.report.dimensions),this.report.dimensions[t]=e,this.setValueHasChanged()))},changeMetric:function(e,t){var o,r=this;this.dependencyAdded=!1,this.report&&e&&(this.isLocked?this.confirmReportIsLocked((function(){r.changeMetric(e,t)})):null!==(o=this.report.metrics)&&void 0!==o&&o[t]&&(this.report.metrics=Ot(this.report.metrics),this.report.metrics[t]=e,this.setValueHasChanged(),this.addMetricIfMissingDependency(e)))},setWebsiteChanged:function(e){this.setValueHasChanged(),this.initReportOptions(),"all"===this.report.site.id||"0"===this.report.site.id||0===this.report.site.id?this.multipleSites=[]:this.report.allowedToEdit&&!this.isSiteIncludedAlready("".concat(e.id))&&this.multipleSites&&this.multipleSites.push({idsite:e.id,name:e.name})},removeDimension:function(e){var t=this;this.isLocked?this.confirmReportIsLocked((function(){t.removeDimension(e)})):(window.$('div.ui-tooltip[role="tooltip"]:not([style*="display: none"])').remove(),e>-1&&(this.report.dimensions=Ot(this.report.dimensions),this.report.dimensions.splice(e,1),this.setValueHasChanged()))},addMetric:function(e){var t=this;this.dependencyAdded=!1,this.report&&e&&(this.report.metrics||(this.report.metrics=[]),this.isLocked?this.confirmReportIsLocked((function(){t.addMetric(e)})):(this.report.metrics=[].concat(Ot(this.report.metrics),[e]),this.setValueHasChanged(),this.addMetricIfMissingDependency(e)))},addMetricIfMissingDependency:function(e){if(["sum_product_revenue","avg_product_revenue"].includes(e)&&!this.doesReportIncludeProductQuantityMetric()){var t="avg_product_revenue"===e?"avg_ecommerce_productquantity":"sum_ecommerce_productquantity";this.addMetric(t),this.dependencyAdded=!0}},removeMetric:function(e){var t=this;this.dependencyAdded=!1,this.isLocked?this.confirmReportIsLocked((function(){t.removeMetric(e)})):(window.$('div.ui-tooltip[role="tooltip"]:not([style*="display: none"])').remove(),e>-1&&(this.report.metrics=Ot(this.report.metrics),this.report.metrics.splice(e,1),this.setValueHasChanged()))},setReportTypeHasChanged:function(e){var t=this;this.report&&this.isLocked?e!==this.report.report_type&&this.confirmReportIsLocked((function(){t.report.report_type=e,t.setValueHasChanged()})):(this.report.report_type=e,this.setValueHasChanged())},setSegmentFilterHasChanged:function(e){var t=this;this.report&&this.isLocked?e!==this.report.segment_filter&&this.confirmReportIsLocked((function(){t.report.segment_filter=e,t.setValueHasChanged()})):(this.report.segment_filter=e,this.setValueHasChanged())},updateReport:function(){var e=this;if(this.removeAnyReportNotification(),this.checkRequiredFieldsAreSet()){this.multipleIdSites=[],this.multipleSites&&this.multipleSites.length&&"all"!==this.report.site.id&&"0"!==this.report.site.id&&0!==this.report.site.id&&(this.multipleIdSites.push(ot["Matomo"].idSite),this.multipleSites.forEach((function(t){var o=t.idsite;e.multipleIdSites.includes(o)||e.multipleIdSites.push(o)})));var t="CustomReports.updateCustomReport";this.multipleIdSites&&this.multipleIdSites.length&&(this.report.site.id=ot["Matomo"].idSite),jt.createOrUpdateReport(this.report,t,this.childReportIds,this.multipleIdSites).then((function(t){if(t&&"error"!==t.type){var o=e.report.site.id;e.isDirty=!1,e.canEdit=!0,o&&"all"!==o&&"".concat(o)!=="".concat(ot["Matomo"].idSite)?ot["MatomoUrl"].updateUrl(Object.assign(Object.assign({},ot["MatomoUrl"].urlParsed.value),{},{idSite:o}),Object.assign({},ot["MatomoUrl"].hashParsed.value)):(jt.reload().then((function(){e.init()})),e.showNotification(Object(ot["translate"])("CustomReports_ReportUpdated"),t.type))}else{var r,i;e.showApiErrorMessage(null!==(r=t.message)&&void 0!==r?r:"",null!==(i=t.type)&&void 0!==i?i:"error")}}))}},checkRequiredFieldsAreSet:function(){var e,t;if(!this.report.name){var o=Object(ot["translate"])("General_Name");return this.showErrorFieldNotProvidedNotification(o),!1}if("evolution"!==this.report.report_type&&(null===(t=this.report.dimensions)||void 0===t||!t.length||!Vt(this.report.dimensions).length)){var r=Object(ot["translate"])("CustomReports_ErrorMissingDimension");return this.showNotification(r,"error"),!1}if(null===(e=this.report.metrics)||void 0===e||!e.length||!Vt(this.report.metrics).length){var i=Object(ot["translate"])("CustomReports_ErrorMissingMetric");return this.showNotification(i,"error"),!1}return this.isProductRevenueDependencyMet(!1),!0},setSubcategory:function(e){this.report.subcategory=this.report.subcategory||{id:""},this.report.subcategory.id=e},isProductRevenueDependencyMet:function(e){var t=Object(ot["externalLink"])("https://matomo.org/faq/custom-reports/why-is-there-an-error-when-i-try-to-run-a-custom-report-with-the-product-revenue-metric/"),o=Object(ot["translate"])("CustomReports_WarningProductRevenueMetricDependency",t,"");return this.report.metrics.includes("sum_product_revenue")&&!this.doesReportIncludeProductQuantityMetric()?(this.addMetric("sum_ecommerce_productquantity"),this.showProductMetricNotification(o,e),!1):!(this.report.metrics.includes("avg_product_revenue")&&!this.doesReportIncludeProductQuantityMetric())||(this.addMetric("avg_ecommerce_productquantity"),this.showProductMetricNotification(o,e),!1)},doesReportIncludeProductQuantityMetric:function(){return this.report.metrics.includes("sum_ecommerce_productquantity")||this.report.metrics.includes("avg_ecommerce_productquantity")},isSiteIncludedAlready:function(e){return!(!this.multipleSites||!this.multipleSites.length)&&this.multipleSites.some((function(t){return"".concat(t.idsite)==="".concat(e)}))},removeSite:function(e){this.multipleSites&&(this.isDirty=!0,this.multipleSites=this.multipleSites.filter((function(t){return t.idsite!==e.idsite})))},addSitesContaining:function(e){var t=this;if(e){var o='"'.concat(ot["Matomo"].helper.escape(ot["Matomo"].helper.htmlEntities(e)),'"');ot["AjaxHelper"].fetch({method:"SitesManager.getSitesWithAdminAccess",pattern:e,filter_limit:-1}).then((function(e){if(e&&e.length){var r=[],i=[];e.forEach((function(e){var o=window.vueSanitize(ot["Matomo"].helper.htmlEntities(e.name)),n="".concat(o," (id ").concat(parseInt("".concat(e.idsite),10),") ");t.isSiteIncludedAlready("".concat(e.idsite))?i.push(n):r.push(n)}));var n=Object(ot["translate"])("CustomReports_MatchingSearchConfirmTitle",r.length);if(i.length){var s=Object(ot["translate"])("CustomReports_MatchingSearchConfirmTitleAlreadyAdded",i.length);n+=" (".concat(s,")")}var a="
").concat(t):e},getDimensionsHelpTextExtended:function(){if(this.isCloud)return"";var e=Object(ot["externalLink"])("https://matomo.org/faq/custom-reports/faq_25655/");return Object(ot["translate"])("CustomReports_ReportDimensionsHelpExtended",e,"")}}});_t.render=tt;var Mt=_t,Dt={class:"reportSearchFilter"},At={class:"index"},It={class:"name"},Ut={class:"description"},Bt={class:"reportType"},Tt={class:"reportCategory"},Lt={class:"action"},xt={colspan:"7"},Pt={class:"loadingPiwik"},Ht=Object(n["createElementVNode"])("img",{src:"plugins/Morpheus/images/loading-blue.gif"},null,-1),Gt={colspan:"7"},qt=["id"],Ft={class:"index"},Wt={class:"name"},$t=["title"],Yt=["title"],zt=["title"],Qt=["title"],Xt=["title"],Jt={class:"reportType"},Kt=["title"],Zt={key:0},eo={class:"action"},to=["title","onClick"],oo=["title","onClick"],ro=["title","onClick"],io=["title","href"],no=["title","onClick"],so={class:"tableActionBar"},ao=Object(n["createElementVNode"])("span",{class:"icon-add"},null,-1),lo={class:"ui-confirm",ref:"confirmDeleteReport"},co=["value"],uo=["value"],po={class:"ui-confirm",ref:"confirmPauseReport"},mo=["value"],ho=["value"],bo={class:"ui-confirm",ref:"confirmResumeReport"},fo=["value"],vo=["value"];function go(e,t,o,r,i,s){var a=Object(n["resolveComponent"])("Field"),l=Object(n["resolveComponent"])("ContentBlock"),c=Object(n["resolveDirective"])("content-table");return Object(n["openBlock"])(),Object(n["createElementBlock"])("div",null,[Object(n["createVNode"])(l,{"content-title":e.translate("CustomReports_ManageReports"),feature:e.translate("CustomReports_ManageReports")},{default:Object(n["withCtx"])((function(){return[Object(n["createElementVNode"])("p",null,Object(n["toDisplayString"])(e.translate("CustomReports_CustomReportIntroduction")),1),Object(n["createElementVNode"])("div",Dt,[Object(n["withDirectives"])(Object(n["createVNode"])(a,{uicontrol:"text",name:"reportSearch",title:e.translate("General_Search"),modelValue:e.searchFilter,"onUpdate:modelValue":t[0]||(t[0]=function(t){return e.searchFilter=t})},null,8,["title","modelValue"]),[[n["vShow"],e.reports.length>0]])]),Object(n["withDirectives"])(Object(n["createElementVNode"])("table",null,[Object(n["createElementVNode"])("thead",null,[Object(n["createElementVNode"])("tr",null,[Object(n["createElementVNode"])("th",At,Object(n["toDisplayString"])(e.translate("General_Id")),1),Object(n["createElementVNode"])("th",It,Object(n["toDisplayString"])(e.translate("General_Name")),1),Object(n["createElementVNode"])("th",Ut,Object(n["toDisplayString"])(e.translate("General_Description")),1),Object(n["createElementVNode"])("th",Bt,Object(n["toDisplayString"])(e.translate("CustomReports_Type")),1),Object(n["createElementVNode"])("th",Tt,Object(n["toDisplayString"])(e.translate("CustomReports_Category")),1),Object(n["createElementVNode"])("th",Lt,Object(n["toDisplayString"])(e.translate("General_Actions")),1)])]),Object(n["createElementVNode"])("tbody",null,[Object(n["withDirectives"])(Object(n["createElementVNode"])("tr",null,[Object(n["createElementVNode"])("td",xt,[Object(n["createElementVNode"])("span",Pt,[Ht,Object(n["createTextVNode"])(" "+Object(n["toDisplayString"])(e.translate("General_LoadingData")),1)])])],512),[[n["vShow"],e.isLoading||e.isUpdating]]),Object(n["withDirectives"])(Object(n["createElementVNode"])("tr",null,[Object(n["createElementVNode"])("td",Gt,Object(n["toDisplayString"])(e.translate("CustomReports_NoCustomReportsFound")),1)],512),[[n["vShow"],!e.isLoading&&0==e.reports.length]]),(Object(n["openBlock"])(!0),Object(n["createElementBlock"])(n["Fragment"],null,Object(n["renderList"])(e.sortedReports,(function(t){var o;return Object(n["openBlock"])(),Object(n["createElementBlock"])("tr",{id:"report".concat(t.idcustomreport),class:"customReports",key:t.idcustomreport},[Object(n["createElementVNode"])("td",Ft,Object(n["toDisplayString"])(t.idcustomreport),1),Object(n["createElementVNode"])("td",Wt,[Object(n["createTextVNode"])(Object(n["toDisplayString"])(t.name)+" ",1),Object(n["withDirectives"])(Object(n["createElementVNode"])("span",{class:"icon-locked",title:e.translate("CustomReports_ReportEditNotAllowedAllWebsitesUpdated")},null,8,$t),[[n["vShow"],!t.idsite&&!e.isSuperUser]]),Object(n["withDirectives"])(Object(n["createElementVNode"])("span",{class:"icon-info2",title:e.translate("CustomReports_ReportAvailableToAllWebsites")},null,8,Yt),[[n["vShow"],!t.idsite&&e.isSuperUser]]),Object(n["withDirectives"])(Object(n["createElementVNode"])("span",{class:"icon-locked",title:e.translate("CustomReports_ReportEditNotAllowedMultipleWebsitesAccessIssue")},null,8,zt),[[n["vShow"],!t.allowedToEdit&&e.isMultiSiteReport(t)]]),Object(n["withDirectives"])(Object(n["createElementVNode"])("span",{class:"icon-info2",title:e.translate("CustomReports_ReportAvailableToMultipleWebsites")},null,8,Qt),[[n["vShow"],t.allowedToEdit&&e.isMultiSiteReport(t)]])]),Object(n["createElementVNode"])("td",{class:"description",title:e.htmlEntities(t.description)},Object(n["toDisplayString"])(e.truncate(t.description.trim(),60)),9,Xt),Object(n["createElementVNode"])("td",Jt,Object(n["toDisplayString"])(e.reportTypesReadable[t.report_type]),1),Object(n["createElementVNode"])("td",{class:"reportCategory",title:e.htmlEntities(t.category.name)},[Object(n["createTextVNode"])(Object(n["toDisplayString"])(e.truncate(t.category.name.trim(),60))+" ",1),null!==(o=t.subcategory)&&void 0!==o&&o.name?(Object(n["openBlock"])(),Object(n["createElementBlock"])("span",Zt," - "+Object(n["toDisplayString"])(e.truncate(t.subcategory.name.trim(),60)),1)):Object(n["createCommentVNode"])("",!0)],8,Kt),Object(n["createElementVNode"])("td",eo,[Object(n["withDirectives"])(Object(n["createElementVNode"])("a",{class:"table-action icon-pause",title:e.translate("CustomReports_PauseReportInfo"),onClick:function(o){return e.pauseReport(t)}},null,8,to),[[n["vShow"],(t.idsite&&!e.isMultiSiteReport(t)||t.allowedToEdit)&&"active"===t.status]]),Object(n["withDirectives"])(Object(n["createElementVNode"])("a",{class:"table-action icon-play",title:e.translate("CustomReports_ResumeReportInfo"),onClick:function(o){return e.resumeReport(t)}},null,8,oo),[[n["vShow"],(t.idsite&&!e.isMultiSiteReport(t)||t.allowedToEdit)&&"paused"===t.status]]),Object(n["createElementVNode"])("a",{class:"table-action icon-edit",title:e.translate("CustomReports_EditReport"),onClick:function(o){return e.editReport(t.idcustomreport)}},null,8,ro),Object(n["createElementVNode"])("a",{target:"_blank",class:"table-action icon-show",title:e.translate("CustomReports_ViewReportInfo"),href:e.getViewReportLink(t)},null,8,io),Object(n["withDirectives"])(Object(n["createElementVNode"])("a",{class:"table-action icon-delete",title:e.translate("CustomReports_DeleteReportInfo"),onClick:function(o){return e.deleteReport(t)}},null,8,no),[[n["vShow"],t.idsite&&!e.isMultiSiteReport(t)||t.allowedToEdit]])])],8,qt)})),128))])],512),[[c]]),Object(n["createElementVNode"])("div",so,[Object(n["createElementVNode"])("a",{class:"createNewReport",onClick:t[1]||(t[1]=function(t){return e.createReport()})},[ao,Object(n["createTextVNode"])(" "+Object(n["toDisplayString"])(e.translate("CustomReports_CreateNewReport")),1)])])]})),_:1},8,["content-title","feature"]),Object(n["createElementVNode"])("div",lo,[Object(n["createElementVNode"])("h2",null,Object(n["toDisplayString"])(e.translate("CustomReports_DeleteReportConfirm")),1),Object(n["createElementVNode"])("input",{role:"yes",type:"button",value:e.translate("General_Yes")},null,8,co),Object(n["createElementVNode"])("input",{role:"no",type:"button",value:e.translate("General_No")},null,8,uo)],512),Object(n["createElementVNode"])("div",po,[Object(n["createElementVNode"])("h2",null,Object(n["toDisplayString"])(e.translate("CustomReports_PauseReportConfirm")),1),Object(n["createElementVNode"])("input",{role:"yes",type:"button",value:e.translate("General_Yes")},null,8,mo),Object(n["createElementVNode"])("input",{role:"no",type:"button",value:e.translate("General_No")},null,8,ho)],512),Object(n["createElementVNode"])("div",bo,[Object(n["createElementVNode"])("h2",null,Object(n["toDisplayString"])(e.translate("CustomReports_ResumeReportConfirm")),1),Object(n["createElementVNode"])("input",{role:"yes",type:"button",value:e.translate("General_Yes")},null,8,fo),Object(n["createElementVNode"])("input",{role:"no",type:"button",value:e.translate("General_No")},null,8,vo)],512)])}
-/**
- * Copyright (C) InnoCraft Ltd - All rights reserved.
- *
- * NOTICE: All information contained herein is, and remains the property of InnoCraft Ltd.
- * The intellectual and technical concepts contained herein are protected by trade secret
- * or copyright law. Redistribution of this information or reproduction of this material is
- * strictly forbidden unless prior written permission is obtained from InnoCraft Ltd.
- *
- * You shall use this code only in accordance with the license agreement obtained from
- * InnoCraft Ltd.
- *
- * @link https://www.innocraft.com/
- * @license For license details see https://www.innocraft.com/license
- */function jo(e,t){return e&&e.length>t?"".concat(e.substr(0,t-3),"..."):e}function Oo(e){return Co(e)||So(e)||Ro(e)||yo()}function yo(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function Ro(e,t){if(e){if("string"===typeof e)return No(e,t);var o=Object.prototype.toString.call(e).slice(8,-1);return"Object"===o&&e.constructor&&(o=e.constructor.name),"Map"===o||"Set"===o?Array.from(e):"Arguments"===o||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(o)?No(e,t):void 0}}function So(e){if("undefined"!==typeof Symbol&&null!=e[Symbol.iterator]||null!=e["@@iterator"])return Array.from(e)}function Co(e){if(Array.isArray(e))return No(e)}function No(e,t){(null==t||t>e.length)&&(t=e.length);for(var o=0,r=new Array(t);o2&&void 0!==arguments[2]?arguments[2]:null,r=ot["NotificationsStore"].show({message:e,context:t,id:Eo,type:null!==o?o:"toast"});setTimeout((function(){ot["NotificationsStore"].scrollToNotification(r)}),200)},deleteReport:function(e){ot["Matomo"].helper.modalConfirm(this.$refs.confirmDeleteReport,{yes:function(){jt.deleteReport(e.idcustomreport,e.idsite).then((function(){jt.reload(),ot["Matomo"].postEvent("updateReportingMenu")}))}})},getViewReportLink:function(e){return"?".concat(ot["MatomoUrl"].stringify({module:"CoreHome",action:"index",idSite:e.linkIdSite,period:"day",date:"yesterday"}),"#?").concat(ot["MatomoUrl"].stringify({category:e.category.id,idSite:e.linkIdSite,date:ot["MatomoUrl"].parsed.value.date,period:ot["MatomoUrl"].parsed.value.period,segment:ot["MatomoUrl"].parsed.value.segment,subcategory:e.subcategoryLink}))},truncate:jo,htmlEntities:function(e){return ot["Matomo"].helper.htmlEntities(e)},isMultiSiteReport:function(e){return e.multiple_idsites&&e.multiple_idsites.split(",")}},computed:{isSuperUser:function(){return ot["Matomo"].hasSuperUserAccess},reports:function(){return jt.state.value.reports},sortedReports:function(){var e=this.searchFilter.toLowerCase(),t=Oo(this.reports).filter((function(t){return Object.keys(t).some((function(o){var r=t;return"string"===typeof r[o]&&-1!==r[o].toLowerCase().indexOf(e)}))}));return t.sort((function(e,t){var o=parseInt("".concat(e.idcustomreport),10),r=parseInt("".concat(t.idcustomreport),10);return o-r})),t},isLoading:function(){return jt.state.value.isLoading},isUpdating:function(){return jt.state.value.isUpdating},reportTypesReadable:function(){return jt.state.value.reportTypesReadable}}});ko.render=go;var Vo=ko,wo={class:"manageReports"},_o={key:0},Mo={key:1};function Do(e,t,o,r,i,s){var a=Object(n["resolveComponent"])("CustomReportsList"),l=Object(n["resolveComponent"])("CustomReportsEdit");return Object(n["openBlock"])(),Object(n["createElementBlock"])("div",wo,[e.editMode?Object(n["createCommentVNode"])("",!0):(Object(n["openBlock"])(),Object(n["createElementBlock"])("div",_o,[Object(n["createVNode"])(a)])),e.editMode?(Object(n["openBlock"])(),Object(n["createElementBlock"])("div",Mo,[Object(n["createVNode"])(l,{"id-custom-report":e.idCustomReport,"browser-archiving-disabled":e.browserArchivingDisabled,"re-archive-last-n":e.reArchiveLastN,"max-dimensions":e.maxDimensions,"is-cloud":e.isCloud},null,8,["id-custom-report","browser-archiving-disabled","re-archive-last-n","max-dimensions","is-cloud"])])):Object(n["createCommentVNode"])("",!0)])}var Ao=Object(n["defineComponent"])({props:{browserArchivingDisabled:Boolean,reArchiveLastN:Number,maxDimensions:Number,isCloud:Boolean},components:{CustomReportsList:Vo,CustomReportsEdit:Mt},data:function(){return{editMode:!1,idCustomReport:null}},watch:{editMode:function(){$(".ui-tooltip").remove()}},created:function(){var e=this;Object(n["watch"])((function(){return ot["MatomoUrl"].hashParsed.value.idCustomReport}),(function(t){e.initState(t)})),this.initState(ot["MatomoUrl"].hashParsed.value.idCustomReport)},methods:{removeAnyReportNotification:function(){var e=!(arguments.length>0&&void 0!==arguments[0])||arguments[0];ot["NotificationsStore"].remove("reportsmanagement"),e&&ot["NotificationsStore"].remove("reportsmanagementProductMetric")},initState:function(e){if(e){if("0"===e){var t={isAllowed:!0};if(ot["Matomo"].postEvent("CustomReports.initAddReport",t),t&&!t.isAllowed)return this.editMode=!1,void(this.idCustomReport=null)}this.editMode=!0,this.idCustomReport=parseInt(e,10)}else this.editMode=!1,this.idCustomReport=null;this.removeAnyReportNotification(!e)}}});Ao.render=Do;var Io=Ao;
-/**
- * Copyright (C) InnoCraft Ltd - All rights reserved.
- *
- * NOTICE: All information contained herein is, and remains the property of InnoCraft Ltd.
- * The intellectual and technical concepts contained herein are protected by trade secret
- * or copyright law. Redistribution of this information or reproduction of this material is
- * strictly forbidden unless prior written permission is obtained from InnoCraft Ltd.
- *
- * You shall use this code only in accordance with the license agreement obtained from
- * InnoCraft Ltd.
- *
- * @link https://www.innocraft.com/
- * @license For license details see https://www.innocraft.com/license
- */}})}));
-//# sourceMappingURL=CustomReports.umd.min.js.map
\ No newline at end of file
diff --git a/files/plugin-CustomReports-5.4.5/API.php b/files/plugin-CustomReports-5.4.5/API.php
new file mode 100644
index 0000000..a5dc7e7
--- /dev/null
+++ b/files/plugin-CustomReports-5.4.5/API.php
@@ -0,0 +1,2033 @@
+Custom Reports API lets you 1) create custom
+ * reports within Matomo and 2) view the created reports in the Matomo Reporting UI or consume them via the API.
+ *
+ * You can choose between different visualizations (eg table or evolution graph) and combine hundreds of dimensions
+ * and metrics to get the data you need.
+ *
+ * @method static \Piwik\Plugins\CustomReports\API getInstance()
+ *
+ * @OA\Tag(name="CustomReports")
+ */
+class API extends \Piwik\Plugin\API
+{
+ /**
+ * @var MetricsList
+ */
+ private $metricsList;
+
+ /**
+ * @var DimensionsProvider
+ */
+ private $columnsProvider;
+
+ /**
+ * @var CustomReportsModel
+ */
+ private $model;
+
+ /**
+ * @var Validator
+ */
+ private $validator;
+
+ /**
+ * @var LogTablesProvider
+ */
+ private $logTablesProvider;
+
+ /**
+ * @var Configuration
+ */
+ private $configuration;
+
+ /**
+ * @var ArchiveInvalidator
+ */
+ private $archiveInvalidator;
+
+ public function __construct(
+ CustomReportsModel $model,
+ Validator $validator,
+ DimensionsProvider $columnsProvider,
+ LogTablesProvider $logTablesProvider,
+ Configuration $configuration,
+ ArchiveInvalidator $archiveInvalidator
+ ) {
+ $this->metricsList = MetricsList::get();
+ $this->columnsProvider = $columnsProvider;
+ $this->model = $model;
+ $this->validator = $validator;
+ $this->logTablesProvider = $logTablesProvider;
+ $this->configuration = $configuration;
+ $this->archiveInvalidator = $archiveInvalidator;
+ }
+
+ /**
+ * Copies a specified custom report to one or more sites. If a custom report with the same name already exists, the new custom report
+ * will have an automatically adjusted name to make it unique to the assigned site.
+ *
+ * @param int $idSite
+ * @param int $idCustomReport The ID of the custom report to duplicate.
+ * @param int[] $idDestinationSites Optional array of IDs identifying which site(s) the new custom report is to be
+ * assigned to. The default is [idSite] when nothing is provided.
+ *
+ * @return array Response indicating success and containing the ID of the newly created report.
+ * @throws Exception
+ *
+ * @OA\Get(
+ * path="/index.php?module=API&method=CustomReports.duplicateCustomReport",
+ * operationId="CustomReports.duplicateCustomReport",
+ * tags={"CustomReports"},
+ * @OA\Parameter(ref="#/components/parameters/formatOptional"),
+ * @OA\Parameter(ref="#/components/parameters/idSiteRequired"),
+ * @OA\Parameter(
+ * name="idCustomReport",
+ * in="query",
+ * required=true,
+ * description="The ID of the custom report to duplicate.",
+ * @OA\Schema(
+ * type="integer"
+ * )
+ * ),
+ * @OA\Parameter(
+ * name="idDestinationSites",
+ * in="query",
+ * required=false,
+ * description="Optional array of IDs identifying which site(s) the new custom report is to be assigned to. The default is [idSite] when nothing is provided.",
+ * @OA\Schema(
+ * type="array",
+ * @OA\Items(type="integer"),
+ * default={}
+ * )
+ * ),
+ * @OA\Response(
+ * response=200,
+ * description="Response indicating success and containing the ID of the newly created report.",
+ * @OA\MediaType(
+ * mediaType="text/xml",
+ * example={"success":"1","message":"The custom report has been successfully copied.","additionalData":{"idSite":"1","idDestinationSites":"","idCustomReport":"1","newIds":"9"}},
+ * @OA\Schema(
+ * type="object",
+ * @OA\Xml(name="result"),
+ * @OA\Property(
+ * property="additionalData",
+ * type="object"
+ * )
+ * )
+ * ),
+ * @OA\MediaType(
+ * mediaType="application/json",
+ * example={"success":true,"message":"The custom report has been successfully copied.","additionalData":{"idSite":1,"idDestinationSites":{},"idCustomReport":1,"newIds":9}},
+ * @OA\Schema(
+ * type="object",
+ * @OA\Property(property="success", type="boolean"),
+ * @OA\Property(property="message", type="string"),
+ * @OA\Property(
+ * property="additionalData",
+ * type="object",
+ * @OA\Property(property="idSite", type="integer"),
+ * @OA\Property(
+ * property="idDestinationSites",
+ * type="array",
+ * @OA\Items()
+ * ),
+ * @OA\Property(property="idCustomReport", type="integer"),
+ * @OA\Property(property="newIds", type="integer")
+ * )
+ * )
+ * )
+ * ),
+ * @OA\Response(response=400, ref="#/components/responses/BadRequest"),
+ * @OA\Response(response=401, ref="#/components/responses/Unauthorized"),
+ * @OA\Response(response=403, ref="#/components/responses/Forbidden"),
+ * @OA\Response(response=404, ref="#/components/responses/NotFound"),
+ * @OA\Response(response=500, ref="#/components/responses/ServerError"),
+ * @OA\Response(response="default", ref="#/components/responses/DefaultError")
+ * )
+ */
+ public function duplicateCustomReport(int $idSite, int $idCustomReport, array $idDestinationSites = []): array
+ {
+ if (!class_exists('\Piwik\Plugins\CoreHome\EntityDuplicator\DuplicateRequestResponse')) {
+ throw new BadRequestException('This endpoint is not available until Matomo 5.4.0');
+ }
+
+ // Define data array before any alterations to the variables
+ $additionalData = [
+ 'idSite' => $idSite,
+ 'idDestinationSites' => $idDestinationSites,
+ 'idCustomReport' => $idCustomReport,
+ ];
+
+ $idDestinationSites = count($idDestinationSites) > 0 ? $idDestinationSites : [$idSite];
+ $idSitesToCheck = array_unique(array_merge([$idSite], $idDestinationSites));
+ $this->validator->checkSitesDuplicationPermission($idSitesToCheck);
+
+ // Initialise the common response values
+ $duplicateRequestResponse = new DuplicateRequestResponse();
+
+ $customReport = null;
+ try {
+ $customReport = $this->getConfiguredReport($idSite, $idCustomReport);
+ } catch (\Throwable $e) {
+ // Log the error, but continue for the proper response to be built later
+ $this->logError('Uncaught exception looking up custom report to duplicate: {exception}', $e);
+ }
+ // Name and atleast 1 dimension and 1 metric is needed to create a custom report
+ if (empty($customReport['name'])) {
+ $duplicateRequestResponse->setSuccess(false);
+ $duplicateRequestResponse->setMessage(Piwik::translate('CustomReports_SourceCustomReportLookupError'));
+ $duplicateRequestResponse->setAdditionalData($additionalData);
+
+ return $duplicateRequestResponse->getResponseArray();
+ }
+
+ $newName = $customReport['name'];
+ $customReportNames = [];
+ foreach ($idDestinationSites as $idDestinationSite) {
+ $customReports = $this->model->getAllCustomReportsForSite($idDestinationSite, true, true);
+ // It can only be a duplicate name if some custom reports were found for the site.
+ if (is_array($customReports) && count($customReports) > 0) {
+ $customReportNames = array_merge($customReportNames, array_column($customReports, 'name'));
+ }
+ }
+ // It can only be a duplicate name if some custom reports were found for the site.
+ if (count($customReportNames) > 0) {
+ $newName = EntityDuplicatorHelper::getUniqueNameComparedToList($newName, $customReportNames, 50);
+ }
+ $category = '';
+ $subCategory = '';
+ if ($idDestinationSites[0] === $idSite) {
+ $category = !empty($customReport['category']['id']) ? $customReport['category']['id'] : '';
+ $subCategory = !empty($customReport['subcategory']['id']) ? $customReport['subcategory']['id'] : '';
+ }
+ try {
+ $response = $this->addCustomReport(
+ $idDestinationSites[0],
+ $newName,
+ $customReport['report_type'],
+ $customReport['metrics'],
+ $category,
+ $customReport['dimensions'],
+ $subCategory,
+ $customReport['description'],
+ $customReport['segment_filter'],
+ (count($idDestinationSites) > 1 ? $idDestinationSites : []) // Add only if more than 1 destination site is passed
+ );
+ } catch (\Exception $e) {
+ $response = false;
+ $this->logError('Uncaught exception duplicating custom report: {exception}', $e);
+ }
+
+ if (!is_int($response) || $response < 1) {
+ $duplicateRequestResponse->setSuccess(false);
+ $duplicateRequestResponse->setMessage(Piwik::translate('CustomReports_CustomReportDuplicationError'));
+ } else {
+ // Set the values for success response
+ $duplicateRequestResponse->setSuccess(true);
+ $duplicateRequestResponse->setMessage(Piwik::translate('CustomReports_CustomReportCopied'));
+ $additionalData['newIds'] = $response;
+ $duplicateRequestResponse->setAdditionalData($additionalData);
+ }
+
+ // Make sure to record the activity for the report being copied
+ if (class_exists('\Piwik\Plugins\ActivityLog\ActivityParamObject\EntityDuplicatedData')) {
+ // TODO - Remove this if/else and always use the setRequestDataForActivity method for Matomo 6.x
+ if (method_exists($duplicateRequestResponse, 'setRequestDataForEvent')) {
+ $duplicateRequestResponse->setRequestDataForEvent(
+ 'CustomReports_CustomReport',
+ $customReport['name'],
+ $idCustomReport,
+ $idSite,
+ $idDestinationSites,
+ $additionalData
+ );
+ } else {
+ (
+ new \Piwik\Plugins\ActivityLog\ActivityParamObject\EntityDuplicatedData(
+ 'CustomReports_CustomReport',
+ $customReport['name'],
+ $idCustomReport,
+ $idSite,
+ $idDestinationSites,
+ $additionalData
+ )
+ )->postActivityEvent();
+ }
+ }
+
+ return $duplicateRequestResponse->getResponseArray();
+ }
+
+ private function logError(string $message, \Throwable $e): void
+ {
+ StaticContainer::get(\Piwik\Log\LoggerInterface::class)->error(
+ $message,
+ [
+ 'exception' => $e,
+ 'ignoreInScreenWriter' => true,
+ ]
+ );
+ }
+
+ /**
+ * Adds a new custom report
+ *
+ * @param int $idSite
+ * @param string $name The name of the report.
+ * @param string $reportType The type of report you want to create, for example 'table' or 'evolution'.
+ * For a list of available reports call 'CustomReports.getAvailableReportTypes'
+ * @param string[] $metricIds A list of metric IDs. For a list of available metrics call 'CustomReports.getAvailableMetrics'
+ * @param string $categoryId By default, the report will be put into a custom report category unless a specific
+ * categoryId is provided. For a list of available categories call 'CustomReports.getAvailableCategories'.
+ * @param string[] $dimensionIds A list of dimension IDs. For a list of available metrics call 'CustomReports.getAvailableDimensions'
+ * @param string $subcategoryId By default, a new reporting page will be created for this report unless you
+ * specifiy a specific name or subcategoryID. For a list of available subcategories
+ * call 'CustomReports.getAvailableCategories'.
+ * @param string $description An optional description for the report, will be shown in the title help icon of the report.
+ * @param string $segmentFilter An optional segment to filter the report data. Needs to be sent urlencoded.
+ * @param string[] $multipleIdSites An optional list of idsites for which we need to execute the report
+ *
+ * @return int
+ *
+ * @OA\Get(
+ * path="/index.php?module=API&method=CustomReports.addCustomReport",
+ * operationId="CustomReports.addCustomReport",
+ * tags={"CustomReports"},
+ * @OA\Parameter(ref="#/components/parameters/formatOptional"),
+ * @OA\Parameter(ref="#/components/parameters/idSiteRequired"),
+ * @OA\Parameter(
+ * name="name",
+ * in="query",
+ * required=true,
+ * description="The name of the report.",
+ * @OA\Schema(
+ * type="string"
+ * )
+ * ),
+ * @OA\Parameter(
+ * name="reportType",
+ * in="query",
+ * required=true,
+ * description="The type of report you want to create, for example 'table' or 'evolution'. For a list of available reports call 'CustomReports.getAvailableReportTypes'",
+ * @OA\Schema(
+ * type="string"
+ * )
+ * ),
+ * @OA\Parameter(
+ * name="metricIds",
+ * in="query",
+ * required=true,
+ * description="A list of metric IDs. For a list of available metrics call 'CustomReports.getAvailableMetrics'",
+ * @OA\Schema(
+ * type="array",
+ * @OA\Items(type="string")
+ * )
+ * ),
+ * @OA\Parameter(
+ * name="categoryId",
+ * in="query",
+ * required=false,
+ * description="By default, the report will be put into a custom report category unless a specific categoryId is provided. For a list of available categories call 'CustomReports.getAvailableCategories'.",
+ * @OA\Schema(
+ * type="string"
+ * )
+ * ),
+ * @OA\Parameter(
+ * name="dimensionIds",
+ * in="query",
+ * required=false,
+ * description="A list of dimension IDs. For a list of available metrics call 'CustomReports.getAvailableDimensions'",
+ * @OA\Schema(
+ * type="array",
+ * @OA\Items(type="string"),
+ * default={}
+ * )
+ * ),
+ * @OA\Parameter(
+ * name="subcategoryId",
+ * in="query",
+ * required=false,
+ * description="By default, a new reporting page will be created for this report unless you specifiy a specific name or subcategoryID. For a list of available subcategories call 'CustomReports.getAvailableCategories'.",
+ * @OA\Schema(
+ * type="string"
+ * )
+ * ),
+ * @OA\Parameter(
+ * name="description",
+ * in="query",
+ * required=false,
+ * description="An optional description for the report, will be shown in the title help icon of the report.",
+ * @OA\Schema(
+ * type="string",
+ * default=""
+ * )
+ * ),
+ * @OA\Parameter(
+ * name="segmentFilter",
+ * in="query",
+ * required=false,
+ * description="An optional segment to filter the report data. Needs to be sent urlencoded.",
+ * @OA\Schema(
+ * type="string",
+ * default=""
+ * )
+ * ),
+ * @OA\Parameter(
+ * name="multipleIdSites",
+ * in="query",
+ * required=false,
+ * description="An optional list of idsites for which we need to execute the report",
+ * @OA\Schema(
+ * type="array",
+ * @OA\Items(type="string"),
+ * default={}
+ * )
+ * ),
+ * @OA\Response(response=200, ref="#/components/responses/GenericInteger"),
+ * @OA\Response(response=400, ref="#/components/responses/BadRequest"),
+ * @OA\Response(response=401, ref="#/components/responses/Unauthorized"),
+ * @OA\Response(response=403, ref="#/components/responses/Forbidden"),
+ * @OA\Response(response=404, ref="#/components/responses/NotFound"),
+ * @OA\Response(response=500, ref="#/components/responses/ServerError"),
+ * @OA\Response(response="default", ref="#/components/responses/DefaultError")
+ * )
+ */
+ public function addCustomReport($idSite, $name, $reportType, $metricIds, $categoryId = false, $dimensionIds = array(), $subcategoryId = false, $description = '', $segmentFilter = '', $multipleIdSites = [])
+ {
+ if (!empty($multipleIdSites) && $idSite != 'all' && $idSite != '0') {
+ $multipleIdSites = array_unique($multipleIdSites);
+ foreach ($multipleIdSites as $multipleIdSite) {
+ $this->validator->checkWritePermission($multipleIdSite);
+ }
+ if (!in_array($idSite, $multipleIdSites)) {
+ throw new \Exception(Piwik::translate('CustomReports_ErrorInvalidMultipleIdSite', [$idSite]));
+ }
+ } else {
+ $this->validator->checkWritePermission($idSite);
+ // prevent creating reports for sites that do not yet exist but might in the future
+ $this->validator->checkSiteExists($idSite);
+ }
+
+ if (empty($categoryId)) {
+ $categoryId = CustomReportsDao::DEFAULT_CATEGORY;
+ }
+
+ $createdDate = Date::now()->getDatetime();
+ if (!empty($segmentFilter)) {
+ $segmentFilter = Common::unsanitizeInputValue($segmentFilter);
+ $segmentFilter = urldecode($segmentFilter);
+ }
+
+ // If there's a Product Revenue metric without a Product Quantity metric, throw an exception
+ if (
+ (in_array('sum_product_revenue', $metricIds) || in_array('avg_product_revenue', $metricIds))
+ && !in_array('sum_ecommerce_productquantity', $metricIds)
+ && !in_array('avg_ecommerce_productquantity', $metricIds)
+ ) {
+ throw new \Exception(Piwik::translate('CustomReports_ErrorProductRevenueMetricDependency'));
+ }
+
+ $idReport = $this->model->createCustomReport($idSite, $name, $description, $reportType, $dimensionIds, $metricIds, $segmentFilter, $categoryId, $subcategoryId, $createdDate, $multipleIdSites);
+ $report = $this->model->getCustomReportById($idReport, $idSite);
+
+ $config = StaticContainer::get(Configuration::class);
+ $startDate = null;
+ $subMonth = $config->getReArchiveReportsInPastLastNMonths();
+ if (!empty($subMonth)) {
+ $startDate = Date::yesterday()->subMonth($subMonth)->setDay(1);
+ }
+
+ $this->scheduleReArchiving($idSite, $multipleIdSites, $report, $startDate);
+
+ $this->clearCache();
+ return $idReport;
+ }
+
+ private function clearCache()
+ {
+ // we need to delete possibly cached values. especially ReportsProvider
+ try {
+ Cache::getLazyCache()->flushAll();
+ } catch (\Exception $e) {
+ }
+ // we need to delete possibly cached values. especially ReportsProvider
+ try {
+ Cache::getEagerCache()->flushAll();
+ } catch (\Exception $e) {
+ }
+ // we need to delete possibly cached values. especially ReportsProvider
+ try {
+ Cache::getTransientCache()->flushAll();
+ } catch (\Exception $e) {
+ }
+ }
+
+ /**
+ * Updates an existing custom report. Be aware that if you change metrics, dimensions, the report type or the segment filter,
+ * previously processed/archived reports may become unavailable and would need to be re-processed.
+ *
+ * @param int $idSite
+ * @param int $idCustomReport The ID of the custom report to update.
+ * @param string $name The name of the report.
+ * @param string $reportType The type of report you want to create, for example 'table' or 'evolution'.
+ * For a list of available reports call 'CustomReports.getAvailableReportTypes'
+ * @param string[] $metricIds A list of metric IDs. For a list of available metrics call 'CustomReports.getAvailableMetrics'
+ * @param string $categoryId By default, the report will be put into a custom report category unless a specific
+ * categoryId is provided. For a list of available categories call 'CustomReports.getAvailableCategories'.
+ * @param string[] $dimensionIds A list of dimension IDs. For a list of available metrics call 'CustomReports.getAvailableDimensions'
+ * @param string $subcategoryId By default, a new reporting page will be created for this report unless you
+ * specify a specific name or subcategoryID. For a list of available subcategories
+ * call 'CustomReports.getAvailableCategories'.
+ * @param string $description An optional description for the report, will be shown in the title help icon of the report.
+ * @param string $segmentFilter An optional segment to filter the report data. Needs to be sent urlencoded.
+ * @param int[] $subCategoryReportIds List of sub report ids mapped to this report
+ * @param string[] $multipleIdSites An optional list of idSites for which we need to execute the report
+ *
+ * @OA\Get(
+ * path="/index.php?module=API&method=CustomReports.updateCustomReport",
+ * operationId="CustomReports.updateCustomReport",
+ * tags={"CustomReports"},
+ * @OA\Parameter(ref="#/components/parameters/formatOptional"),
+ * @OA\Parameter(ref="#/components/parameters/idSiteRequired"),
+ * @OA\Parameter(
+ * name="idCustomReport",
+ * in="query",
+ * required=true,
+ * description="The ID of the custom report to update.",
+ * @OA\Schema(
+ * type="integer"
+ * )
+ * ),
+ * @OA\Parameter(
+ * name="name",
+ * in="query",
+ * required=true,
+ * description="The name of the report.",
+ * @OA\Schema(
+ * type="string"
+ * )
+ * ),
+ * @OA\Parameter(
+ * name="reportType",
+ * in="query",
+ * required=true,
+ * description="The type of report you want to create, for example 'table' or 'evolution'. For a list of available reports call 'CustomReports.getAvailableReportTypes'",
+ * @OA\Schema(
+ * type="string"
+ * )
+ * ),
+ * @OA\Parameter(
+ * name="metricIds",
+ * in="query",
+ * required=true,
+ * description="A list of metric IDs. For a list of available metrics call 'CustomReports.getAvailableMetrics'",
+ * @OA\Schema(
+ * type="array",
+ * @OA\Items(type="string")
+ * )
+ * ),
+ * @OA\Parameter(
+ * name="categoryId",
+ * in="query",
+ * required=false,
+ * description="By default, the report will be put into a custom report category unless a specific categoryId is provided. For a list of available categories call 'CustomReports.getAvailableCategories'.",
+ * @OA\Schema(
+ * type="string"
+ * )
+ * ),
+ * @OA\Parameter(
+ * name="dimensionIds",
+ * in="query",
+ * required=false,
+ * description="A list of dimension IDs. For a list of available metrics call 'CustomReports.getAvailableDimensions'",
+ * @OA\Schema(
+ * type="array",
+ * @OA\Items(type="string"),
+ * default={}
+ * )
+ * ),
+ * @OA\Parameter(
+ * name="subcategoryId",
+ * in="query",
+ * required=false,
+ * description="By default, a new reporting page will be created for this report unless you specifiy a specific name or subcategoryID. For a list of available subcategories call 'CustomReports.getAvailableCategories'.",
+ * @OA\Schema(
+ * type="string"
+ * )
+ * ),
+ * @OA\Parameter(
+ * name="description",
+ * in="query",
+ * required=false,
+ * description="An optional description for the report, will be shown in the title help icon of the report.",
+ * @OA\Schema(
+ * type="string",
+ * default=""
+ * )
+ * ),
+ * @OA\Parameter(
+ * name="segmentFilter",
+ * in="query",
+ * required=false,
+ * description="An optional segment to filter the report data. Needs to be sent urlencoded.",
+ * @OA\Schema(
+ * type="string",
+ * default=""
+ * )
+ * ),
+ * @OA\Parameter(
+ * name="subCategoryReportIds",
+ * in="query",
+ * required=false,
+ * description="List of sub report ids mapped to this report",
+ * @OA\Schema(
+ * type="array",
+ * @OA\Items(type="integer"),
+ * default={}
+ * )
+ * ),
+ * @OA\Parameter(
+ * name="multipleIdSites",
+ * in="query",
+ * required=false,
+ * description="An optional list of idsites for which we need to execute the report",
+ * @OA\Schema(
+ * type="array",
+ * @OA\Items(type="string"),
+ * default={}
+ * )
+ * ),
+ * @OA\Response(response=200, ref="#/components/responses/GenericSuccess"),
+ * @OA\Response(response=400, ref="#/components/responses/BadRequest"),
+ * @OA\Response(response=401, ref="#/components/responses/Unauthorized"),
+ * @OA\Response(response=403, ref="#/components/responses/Forbidden"),
+ * @OA\Response(response=404, ref="#/components/responses/NotFound"),
+ * @OA\Response(response=500, ref="#/components/responses/ServerError"),
+ * @OA\Response(response="default", ref="#/components/responses/DefaultError")
+ * )
+ */
+ public function updateCustomReport(
+ $idSite,
+ $idCustomReport,
+ $name,
+ $reportType,
+ $metricIds,
+ $categoryId = false,
+ $dimensionIds = array(),
+ $subcategoryId = false,
+ $description = '',
+ $segmentFilter = '',
+ $subCategoryReportIds = [],
+ $multipleIdSites = []
+ ): void {
+ if (!empty($multipleIdSites) && $idSite != 'all' && $idSite != '0') {
+ $multipleIdSites = array_unique($multipleIdSites);
+ foreach ($multipleIdSites as $multipleIdSite) {
+ $this->validator->checkWritePermission($multipleIdSite);
+ }
+ if (!in_array($idSite, $multipleIdSites)) {
+ throw new \Exception(Piwik::translate('CustomReports_ErrorInvalidMultipleIdSite', [$idSite]));
+ }
+ } else {
+ $this->validator->checkWritePermission($idSite);
+ // prevent creating reports for sites that do not yet exist but might in the future
+ $this->validator->checkSiteExists($idSite);
+ }
+
+ // we cannot get report by idSite, idCustomReport since the idSite may change!
+ $report = $this->model->getCustomReportById($idCustomReport, $idSite);
+
+ if (empty($report)) {
+ throw new \Exception(Piwik::translate('CustomReports_ErrorReportDoesNotExist'));
+ }
+
+ if ($report['idsite'] != $idSite && empty($multipleIdSites)) {
+ // if the site changes for a report, make sure the user write permission for the old and the new site
+ $this->validator->checkWritePermission($report['idsite']);
+ }
+
+ if (empty($categoryId)) {
+ $categoryId = CustomReportsDao::DEFAULT_CATEGORY;
+ }
+
+ if (!empty($segmentFilter)) {
+ $segmentFilter = Common::unsanitizeInputValue($segmentFilter);
+ $segmentFilter = urldecode($segmentFilter);
+ }
+
+ $updatedDate = Date::now()->getDatetime();
+
+ $shouldReArchive = false;
+ if (
+ (
+ isset($report['report_type']) &&
+ $report['report_type'] != $reportType
+ ) ||
+ (
+ isset($report['dimensions']) &&
+ $report['dimensions'] != $dimensionIds
+ ) ||
+ (
+ isset($report['metrics']) &&
+ $report['metrics'] != $metricIds
+ ) ||
+ (
+ isset($report['segment_filter']) &&
+ $report['segment_filter'] != $segmentFilter
+ )
+ ) {
+ $shouldReArchive = true;
+ }
+
+ // If there's a Product Revenue metric without a Product Quantity metric, throw an exception
+ if (
+ (in_array('sum_product_revenue', $metricIds) || in_array('avg_product_revenue', $metricIds))
+ && !in_array('sum_ecommerce_productquantity', $metricIds)
+ && !in_array('avg_ecommerce_productquantity', $metricIds)
+ ) {
+ throw new \Exception(Piwik::translate('CustomReports_ErrorProductRevenueMetricDependency'));
+ }
+
+ $this->model->updateCustomReport($idSite, $idCustomReport, $name, $description, $reportType, $dimensionIds, $metricIds, $segmentFilter, $categoryId, $subcategoryId, $updatedDate, $subCategoryReportIds, $multipleIdSites);
+
+ if ($shouldReArchive) {
+ $updatedReport = $this->model->getCustomReportById($idCustomReport, $idSite);
+ $config = StaticContainer::get(Configuration::class);
+ $startDate = null;
+ $subMonth = $config->getReArchiveReportsInPastLastNMonths();
+ if (!empty($subMonth)) {
+ $startDate = Date::yesterday()->subMonth($subMonth)->setDay(1);
+ }
+
+ $this->scheduleReArchiving($idSite, $multipleIdSites, $updatedReport, $startDate);
+ }
+
+ $this->clearCache();
+ }
+
+ private function scheduleReArchiving($idSite, $multipleIdSites, array $report, ?Date $startDate): void
+ {
+ $idSites = $idSite === 0 || $idSite === '0' || $idSite == 'all' ? 'all' : (!empty($multipleIdSites) ? $multipleIdSites : [$idSite]);
+
+ $this->archiveInvalidator->scheduleReArchiving(
+ $idSites,
+ 'CustomReports',
+ Archiver::makeRecordName($report['idcustomreport'], $report['revision'] ?? 0),
+ $startDate
+ );
+
+ if ($report['report_type'] === Evolution::ID) {
+ foreach ($this->model->getArchivableMetricsInReport($report) as $metric) {
+ $this->archiveInvalidator->scheduleReArchiving(
+ $idSites,
+ 'CustomReports',
+ Archiver::makeEvolutionRecordName($report['idcustomreport'], $report['revision'], $metric->getName()),
+ $startDate
+ );
+ }
+ }
+ }
+
+ // phpcs:disable Generic.Files.LineLength
+ /**
+ * Get all custom report configurations for a specific site.
+ *
+ * @param int $idSite
+ * @param bool $skipCategoryMetadata Optional flag indicating whether to omit metadata for the category.
+ * @return array The list of configured custom reports.
+ *
+ * @OA\Get(
+ * path="/index.php?module=API&method=CustomReports.getConfiguredReports",
+ * operationId="CustomReports.getConfiguredReports",
+ * tags={"CustomReports"},
+ * @OA\Parameter(ref="#/components/parameters/formatOptional"),
+ * @OA\Parameter(ref="#/components/parameters/idSiteRequired"),
+ * @OA\Parameter(
+ * name="skipCategoryMetadata",
+ * in="query",
+ * required=false,
+ * @OA\Schema(
+ * type="boolean",
+ * default=false
+ * )
+ * ),
+ * @OA\Response(
+ * response=200,
+ * description="Example links: [XML](https://demo.matomo.cloud/?module=API&method=CustomReports.getConfiguredReports&idSite=1&format=xml&token_auth=anonymous), [JSON](https://demo.matomo.cloud/?module=API&method=CustomReports.getConfiguredReports&idSite=1&format=JSON&token_auth=anonymous), TSV (N/A)",
+ * @OA\MediaType(
+ * mediaType="text/xml",
+ * example={"row":{{"idcustomreport":"1","idsite":"1","revision":"0","report_type":"table","name":"Pages by New\/Returning visitor","description":"","category":{"id":"CustomReports_CustomReports","name":"Custom Reports","order":"65","icon":"icon-business"},"subcategory":"","subcategory_order":"9999999","dimensions":{"row":{"CoreHome.VisitorReturning","Actions.PageTitle"}},"metrics":{"row":{"nb_uniq_visitors","nb_visits","pageviews"}},"segment_filter":"","created_date":"2017-10-20 02:31:50","updated_date":"2017-10-20 02:31:50","status":"active","multiple_idsites":"","site":{"id":"1","name":"Demo Site"},"allowedToEdit":"0"},{"idcustomreport":"2","idsite":"1","revision":"0","report_type":"table","name":"Bali pages, breakdown new\/returning","description":"","category":{"id":"CustomReports_CustomReports","name":"Custom Reports","order":"65","icon":"icon-business"},"subcategory":"","subcategory_order":"9999999","dimensions":{"row":{"Actions.PageTitle","CoreHome.VisitorReturning"}},"metrics":{"row":{"nb_uniq_visitors","pageviews","nb_visits"}},"segment_filter":"pageTitle=@bali","created_date":"2017-10-20 02:41:08","updated_date":"2017-10-20 02:41:08","status":"active","multiple_idsites":"","site":{"id":"1","name":"Demo Site"},"allowedToEdit":"0"},{"idcustomreport":"5","idsite":"1","revision":"0","report_type":"table","name":"Country by New\/returning with a filter","description":"","category":{"id":"CustomReports_CustomReports","name":"Custom Reports","order":"65","icon":"icon-business"},"subcategory":"","subcategory_order":"9999999","dimensions":{"row":{"UserCountry.Country","CoreHome.VisitorReturning"}},"metrics":{"row":{"nb_uniq_visitors","goal_7_conversion","goal_7_conversion_uniq_visitors_rate"}},"segment_filter":"countryCode!=pl","created_date":"2018-01-26 03:51:11","updated_date":"2018-01-26 03:51:11","status":"active","multiple_idsites":"","site":{"id":"1","name":"Demo Site"},"allowedToEdit":"0"},{"idcustomreport":"8","idsite":"1","revision":"0","report_type":"evolution","name":"Evolution KPIs","description":"","category":{"id":"CustomReports_CustomReports","name":"Custom Reports","order":"65","icon":"icon-business"},"subcategory":"","subcategory_order":"9999999","dimensions":"","metrics":{"row":{"nb_uniq_visitors","goal_7_conversion","goal_7_conversion_uniq_visitors_rate","goal_4_conversion"}},"segment_filter":"","created_date":"2018-04-03 02:55:32","updated_date":"2018-04-03 02:55:32","status":"active","multiple_idsites":"","site":{"id":"1","name":"Demo Site"},"allowedToEdit":"0"}}},
+ * @OA\Schema(
+ * type="object",
+ * @OA\Xml(name="result"),
+ * @OA\Property(
+ * property="row",
+ * type="array",
+ * @OA\Items(
+ * type="object",
+ * @OA\Xml(name="row"),
+ * additionalProperties=true,
+ * @OA\Property(
+ * property="category",
+ * type="object"
+ * ),
+ * @OA\Property(
+ * property="dimensions",
+ * type="object",
+ * @OA\Property(
+ * property="row",
+ * type="array",
+ * @OA\Items(
+ * type="string"
+ * )
+ * )
+ * ),
+ * @OA\Property(
+ * property="metrics",
+ * type="object",
+ * @OA\Property(
+ * property="row",
+ * type="array",
+ * @OA\Items(
+ * type="string"
+ * )
+ * )
+ * ),
+ * @OA\Property(
+ * property="site",
+ * type="object"
+ * )
+ * )
+ * )
+ * )
+ * ),
+ * @OA\MediaType(
+ * mediaType="application/json",
+ * example={{"idcustomreport":1,"idsite":1,"revision":0,"report_type":"table","name":"Pages by New\/Returning visitor","description":"","category":{"id":"CustomReports_CustomReports","name":"Custom Reports","order":65,"icon":"icon-business"},"subcategory":null,"subcategory_order":9999999,"dimensions":{"CoreHome.VisitorReturning","Actions.PageTitle"},"metrics":{"nb_uniq_visitors","nb_visits","pageviews"},"segment_filter":"","created_date":"2017-10-20 02:31:50","updated_date":"2017-10-20 02:31:50","status":"active","multiple_idsites":null,"site":{"id":1,"name":"Demo Site"},"allowedToEdit":false},{"idcustomreport":2,"idsite":1,"revision":0,"report_type":"table","name":"Bali pages, breakdown new\/returning","description":"","category":{"id":"CustomReports_CustomReports","name":"Custom Reports","order":65,"icon":"icon-business"},"subcategory":null,"subcategory_order":9999999,"dimensions":{"Actions.PageTitle","CoreHome.VisitorReturning"},"metrics":{"nb_uniq_visitors","pageviews","nb_visits"},"segment_filter":"pageTitle=@bali","created_date":"2017-10-20 02:41:08","updated_date":"2017-10-20 02:41:08","status":"active","multiple_idsites":null,"site":{"id":1,"name":"Demo Site"},"allowedToEdit":false},{"idcustomreport":5,"idsite":1,"revision":0,"report_type":"table","name":"Country by New\/returning with a filter","description":"","category":{"id":"CustomReports_CustomReports","name":"Custom Reports","order":65,"icon":"icon-business"},"subcategory":null,"subcategory_order":9999999,"dimensions":{"UserCountry.Country","CoreHome.VisitorReturning"},"metrics":{"nb_uniq_visitors","goal_7_conversion","goal_7_conversion_uniq_visitors_rate"},"segment_filter":"countryCode!=pl","created_date":"2018-01-26 03:51:11","updated_date":"2018-01-26 03:51:11","status":"active","multiple_idsites":null,"site":{"id":1,"name":"Demo Site"},"allowedToEdit":false},{"idcustomreport":8,"idsite":1,"revision":0,"report_type":"evolution","name":"Evolution KPIs","description":"","category":{"id":"CustomReports_CustomReports","name":"Custom Reports","order":65,"icon":"icon-business"},"subcategory":null,"subcategory_order":9999999,"dimensions":{},"metrics":{"nb_uniq_visitors","goal_7_conversion","goal_7_conversion_uniq_visitors_rate","goal_4_conversion"},"segment_filter":"","created_date":"2018-04-03 02:55:32","updated_date":"2018-04-03 02:55:32","status":"active","multiple_idsites":null,"site":{"id":1,"name":"Demo Site"},"allowedToEdit":false}},
+ * @OA\Schema(
+ * type="array",
+ * @OA\Items(
+ * type="object",
+ * additionalProperties=true,
+ * @OA\Property(
+ * type="object",
+ * @OA\Property(property="idcustomreport", type="integer"),
+ * @OA\Property(property="idsite", type="integer"),
+ * @OA\Property(property="revision", type="integer"),
+ * @OA\Property(property="report_type", type="string"),
+ * @OA\Property(property="name", type="string"),
+ * @OA\Property(property="description", type="string"),
+ * @OA\Property(
+ * property="site",
+ * type="object",
+ * @OA\Property(property="id", type="integer"),
+ * @OA\Property(property="name", type="string")
+ * ),
+ * @OA\Property(property="subcategory", type={"string", "number", "integer", "boolean", "array", "object", "null"}),
+ * @OA\Property(property="subcategory_order", type="integer"),
+ * @OA\Property(property="segment_filter", type="string"),
+ * @OA\Property(property="created_date", type="string"),
+ * @OA\Property(property="updated_date", type="string"),
+ * @OA\Property(property="status", type="string"),
+ * @OA\Property(property="multiple_idsites", type={"string", "number", "integer", "boolean", "array", "object", "null"}),
+ * @OA\Property(property="allowedToEdit", type="boolean")
+ * )
+ * )
+ * )
+ * )
+ * ),
+ * @OA\Response(response=400, ref="#/components/responses/BadRequest"),
+ * @OA\Response(response=401, ref="#/components/responses/Unauthorized"),
+ * @OA\Response(response=403, ref="#/components/responses/Forbidden"),
+ * @OA\Response(response=404, ref="#/components/responses/NotFound"),
+ * @OA\Response(response=500, ref="#/components/responses/ServerError"),
+ * @OA\Response(response="default", ref="#/components/responses/DefaultError")
+ * )
+ */
+ // phpcs:enable Generic.Files.LineLength
+ public function getConfiguredReports($idSite, $skipCategoryMetadata = false)
+ {
+ $this->validator->checkReportViewPermission($idSite);
+ $this->validator->checkSiteExists($idSite);
+
+ if ($idSite === 'all') {
+ $idSite = 0;
+ }
+
+ $reports = $this->model->getAllCustomReportsForSite($idSite, $skipCategoryMetadata == '1');
+ usort($reports, function ($a, $b) {
+ if ($a['idcustomreport'] > $b['idcustomreport']) {
+ return 1; // no need to check for === because two reports won't have same ID
+ }
+ return -1;
+ });
+
+ foreach ($reports as &$report) {
+ $this->addAllowedToEditStatus($report);
+ }
+
+ return $reports;
+ }
+
+ // phpcs:disable Generic.Files.LineLength
+ /**
+ * Get a specific custom report configuration.
+ *
+ * @param int $idSite
+ * @param int $idCustomReport The ID of the custom report. [@example=1]
+ * @return array The details of the configured custom report.
+ *
+ * @OA\Get(
+ * path="/index.php?module=API&method=CustomReports.getConfiguredReport",
+ * operationId="CustomReports.getConfiguredReport",
+ * tags={"CustomReports"},
+ * @OA\Parameter(ref="#/components/parameters/formatOptional"),
+ * @OA\Parameter(ref="#/components/parameters/idSiteRequired"),
+ * @OA\Parameter(
+ * name="idCustomReport",
+ * in="query",
+ * required=true,
+ * description="The ID of the custom report.",
+ * @OA\Schema(
+ * type="integer",
+ * example=1
+ * )
+ * ),
+ * @OA\Response(
+ * response=200,
+ * description="Example links: [XML](https://demo.matomo.cloud/?module=API&method=CustomReports.getConfiguredReport&idSite=1&idCustomReport=1&format=xml&token_auth=anonymous), [JSON](https://demo.matomo.cloud/?module=API&method=CustomReports.getConfiguredReport&idSite=1&idCustomReport=1&format=JSON&token_auth=anonymous), TSV (N/A)",
+ * @OA\MediaType(
+ * mediaType="text/xml",
+ * example={"idcustomreport":"1","idsite":"1","revision":"0","report_type":"table","name":"Pages by New\/Returning visitor","description":"","category":{"id":"CustomReports_CustomReports","name":"Custom Reports","order":"65","icon":"icon-business"},"subcategory":"","subcategory_order":"9999999","dimensions":{"row":{"CoreHome.VisitorReturning","Actions.PageTitle"}},"metrics":{"row":{"nb_uniq_visitors","nb_visits","pageviews"}},"segment_filter":"","created_date":"2017-10-20 02:31:50","updated_date":"2017-10-20 02:31:50","status":"active","multiple_idsites":"","site":{"id":"1","name":"Demo Site"},"child_reports":"","multipleIdSites":"","allowedToEdit":"0"},
+ * @OA\Schema(
+ * type="object",
+ * @OA\Xml(name="result"),
+ * @OA\Property(
+ * property="category",
+ * type="object"
+ * ),
+ * @OA\Property(
+ * property="dimensions",
+ * type="object",
+ * @OA\Property(
+ * property="row",
+ * type="array",
+ * @OA\Items(
+ * type="object",
+ * @OA\Xml(name="row"),
+ * additionalProperties=true
+ * )
+ * )
+ * ),
+ * @OA\Property(
+ * property="metrics",
+ * type="object",
+ * @OA\Property(
+ * property="row",
+ * type="array",
+ * @OA\Items(
+ * type="object",
+ * @OA\Xml(name="row"),
+ * additionalProperties=true
+ * )
+ * )
+ * ),
+ * @OA\Property(
+ * property="site",
+ * type="object"
+ * )
+ * )
+ * ),
+ * @OA\MediaType(
+ * mediaType="application/json",
+ * example={"idcustomreport":1,"idsite":1,"revision":0,"report_type":"table","name":"Pages by New\/Returning visitor","description":"","category":{"id":"CustomReports_CustomReports","name":"Custom Reports","order":65,"icon":"icon-business"},"subcategory":null,"subcategory_order":9999999,"dimensions":{"CoreHome.VisitorReturning","Actions.PageTitle"},"metrics":{"nb_uniq_visitors","nb_visits","pageviews"},"segment_filter":"","created_date":"2017-10-20 02:31:50","updated_date":"2017-10-20 02:31:50","status":"active","multiple_idsites":null,"site":{"id":1,"name":"Demo Site"},"child_reports":{},"multipleIdSites":{},"allowedToEdit":false},
+ * @OA\Schema(
+ * type="object",
+ * @OA\Property(property="idcustomreport", type="integer"),
+ * @OA\Property(property="idsite", type="integer"),
+ * @OA\Property(property="revision", type="integer"),
+ * @OA\Property(property="report_type", type="string"),
+ * @OA\Property(property="name", type="string"),
+ * @OA\Property(property="description", type="string"),
+ * @OA\Property(
+ * property="multipleIdSites",
+ * type="array",
+ * @OA\Items()
+ * ),
+ * @OA\Property(property="subcategory", type={"string", "number", "integer", "boolean", "array", "object", "null"}),
+ * @OA\Property(property="subcategory_order", type="integer"),
+ * @OA\Property(property="segment_filter", type="string"),
+ * @OA\Property(property="created_date", type="string"),
+ * @OA\Property(property="updated_date", type="string"),
+ * @OA\Property(property="status", type="string"),
+ * @OA\Property(property="multiple_idsites", type={"string", "number", "integer", "boolean", "array", "object", "null"}),
+ * @OA\Property(property="allowedToEdit", type="boolean")
+ * )
+ * )
+ * ),
+ * @OA\Response(response=400, ref="#/components/responses/BadRequest"),
+ * @OA\Response(response=401, ref="#/components/responses/Unauthorized"),
+ * @OA\Response(response=403, ref="#/components/responses/Forbidden"),
+ * @OA\Response(response=404, ref="#/components/responses/NotFound"),
+ * @OA\Response(response=500, ref="#/components/responses/ServerError"),
+ * @OA\Response(response="default", ref="#/components/responses/DefaultError")
+ * )
+ */
+ // phpcs:enable Generic.Files.LineLength
+ public function getConfiguredReport($idSite, $idCustomReport)
+ {
+ $this->validator->checkReportViewPermission($idSite);
+ $this->validator->checkSiteExists($idSite);
+
+ if ($idSite === 'all') {
+ $idSite = 0;
+ }
+
+ $this->model->checkReportExists($idSite, $idCustomReport);
+
+ $report = $this->model->getCustomReport($idSite, $idCustomReport);
+ $this->addAllowedToEditStatus($report);
+
+ return $report;
+ }
+
+ /**
+ * Deletes the given custom report.
+ *
+ * When a custom report is deleted, its report will be no longer available in the API and tracked data for this
+ * report might be removed at some point by the system.
+ *
+ * @param int $idSite
+ * @param int $idCustomReport The ID of the custom report to duplicate.
+ *
+ * @OA\Get(
+ * path="/index.php?module=API&method=CustomReports.deleteCustomReport",
+ * operationId="CustomReports.deleteCustomReport",
+ * tags={"CustomReports"},
+ * @OA\Parameter(ref="#/components/parameters/formatOptional"),
+ * @OA\Parameter(ref="#/components/parameters/idSiteRequired"),
+ * @OA\Parameter(
+ * name="idCustomReport",
+ * in="query",
+ * required=true,
+ * description="The ID of the custom report to duplicate.",
+ * @OA\Schema(
+ * type="string"
+ * )
+ * ),
+ * @OA\Response(
+ * response=200,
+ * description="",
+ * @OA\MediaType(
+ * mediaType="text/xml",
+ * example={"success":""},
+ * @OA\Schema(
+ * type="object",
+ * @OA\Xml(name="result")
+ * )
+ * ),
+ * @OA\MediaType(
+ * mediaType="application/json",
+ * example={"result":"success","message":"ok"},
+ * @OA\Schema(
+ * type="object",
+ * @OA\Property(property="result", type="string"),
+ * @OA\Property(property="message", type="string")
+ * )
+ * )
+ * ),
+ * @OA\Response(response=400, ref="#/components/responses/BadRequest"),
+ * @OA\Response(response=401, ref="#/components/responses/Unauthorized"),
+ * @OA\Response(response=403, ref="#/components/responses/Forbidden"),
+ * @OA\Response(response=404, ref="#/components/responses/NotFound"),
+ * @OA\Response(response=500, ref="#/components/responses/ServerError"),
+ * @OA\Response(response="default", ref="#/components/responses/DefaultError")
+ * )
+ */
+ public function deleteCustomReport($idSite, $idCustomReport): void
+ {
+ $this->validator->checkWritePermission($idSite);
+
+ if ($idSite === 'all') {
+ $idSite = 0;
+ }
+
+ $report = $this->getCustomReportInfo($idSite, $idCustomReport, 'Delete');
+
+ $multipleIDSites = $report['multiple_idsites'] ? explode(',', $report['multiple_idsites']) : [];
+ if ($multipleIDSites) {
+ foreach ($multipleIDSites as $multipleIdSite) {
+ $this->validator->checkWritePermission($multipleIdSite);
+ }
+ }
+ $this->archiveInvalidator->removeInvalidationsSafely(
+ $multipleIDSites ? $multipleIDSites : [$idSite],
+ 'CustomReports',
+ Archiver::makeRecordName($idCustomReport, $report['revision'])
+ );
+
+ $this->model->deactivateReport($multipleIDSites ? -1 : $idSite, $idCustomReport, $report['name']);
+ Piwik::postEvent('CustomReports.deleteCustomReport.end', array($idSite, $idCustomReport));
+ $this->clearCache();
+ }
+
+ /**
+ * Pauses the given custom report.
+ *
+ * When a custom report is paused, its report will be no longer be archived
+ *
+ * @param int $idSite
+ * @param int $idCustomReport The ID of the custom report to pause.
+ *
+ * @OA\Get(
+ * path="/index.php?module=API&method=CustomReports.pauseCustomReport",
+ * operationId="CustomReports.pauseCustomReport",
+ * tags={"CustomReports"},
+ * @OA\Parameter(ref="#/components/parameters/formatOptional"),
+ * @OA\Parameter(ref="#/components/parameters/idSiteRequired"),
+ * @OA\Parameter(
+ * name="idCustomReport",
+ * in="query",
+ * required=true,
+ * description="The ID of the custom report to pause.",
+ * @OA\Schema(
+ * type="integer"
+ * )
+ * ),
+ * @OA\Response(response=200, ref="#/components/responses/GenericSuccess"),
+ * @OA\Response(response=400, ref="#/components/responses/BadRequest"),
+ * @OA\Response(response=401, ref="#/components/responses/Unauthorized"),
+ * @OA\Response(response=403, ref="#/components/responses/Forbidden"),
+ * @OA\Response(response=404, ref="#/components/responses/NotFound"),
+ * @OA\Response(response=500, ref="#/components/responses/ServerError"),
+ * @OA\Response(response="default", ref="#/components/responses/DefaultError")
+ * )
+ */
+ public function pauseCustomReport($idSite, $idCustomReport): void
+ {
+ $this->validator->checkWritePermission($idSite);
+
+ if ($idSite === 'all') {
+ $idSite = 0;
+ }
+
+ $report = $this->getCustomReportInfo($idSite, $idCustomReport, 'Pause');
+
+ $multipleIDSites = $report['multiple_idsites'] ? explode(',', $report['multiple_idsites']) : [];
+ if ($multipleIDSites) {
+ foreach ($multipleIDSites as $multipleIdSite) {
+ $this->validator->checkWritePermission($multipleIdSite);
+ }
+ }
+ $this->archiveInvalidator->removeInvalidationsSafely(
+ $multipleIDSites ? $multipleIDSites : [$idSite],
+ 'CustomReports',
+ Archiver::makeRecordName($idCustomReport, $report['revision'])
+ );
+
+ $this->model->pauseReport($multipleIDSites ? -1 : $idSite, $idCustomReport, $report['name']);
+ $this->clearCache();
+ }
+
+ /**
+ * Resumes the given custom report.
+ *
+ * When a custom report is resumed, its report will start archiving again
+ *
+ * @param int $idSite
+ * @param int $idCustomReport The ID of the custom report to resume.
+ *
+ * @OA\Get(
+ * path="/index.php?module=API&method=CustomReports.resumeCustomReport",
+ * operationId="CustomReports.resumeCustomReport",
+ * tags={"CustomReports"},
+ * @OA\Parameter(ref="#/components/parameters/formatOptional"),
+ * @OA\Parameter(ref="#/components/parameters/idSiteRequired"),
+ * @OA\Parameter(
+ * name="idCustomReport",
+ * in="query",
+ * required=true,
+ * description="The ID of the custom report to resume.",
+ * @OA\Schema(
+ * type="integer"
+ * )
+ * ),
+ * @OA\Response(response=200, ref="#/components/responses/GenericSuccess"),
+ * @OA\Response(response=400, ref="#/components/responses/BadRequest"),
+ * @OA\Response(response=401, ref="#/components/responses/Unauthorized"),
+ * @OA\Response(response=403, ref="#/components/responses/Forbidden"),
+ * @OA\Response(response=404, ref="#/components/responses/NotFound"),
+ * @OA\Response(response=500, ref="#/components/responses/ServerError"),
+ * @OA\Response(response="default", ref="#/components/responses/DefaultError")
+ * )
+ */
+ public function resumeCustomReport($idSite, $idCustomReport): void
+ {
+ $this->validator->checkWritePermission($idSite);
+
+ if ($idSite === 'all') {
+ $idSite = 0;
+ }
+
+ $report = $this->getCustomReportInfo($idSite, $idCustomReport, 'Resume');
+
+ $multipleIDSites = $report['multiple_idsites'] ? explode(',', $report['multiple_idsites']) : [];
+ if ($multipleIDSites) {
+ foreach ($multipleIDSites as $multipleIdSite) {
+ $this->validator->checkWritePermission($multipleIdSite);
+ }
+ }
+
+ $this->model->resumeReport($multipleIDSites ? -1 : $idSite, $idCustomReport, $report['name']);
+ $this->clearCache();
+ }
+
+ // phpcs:disable Generic.Files.LineLength
+ /**
+ * Get a list of available categories that can be used in custom reports.
+ *
+ * @param int $idSite
+ * @return array
+ *
+ * @OA\Get(
+ * path="/index.php?module=API&method=CustomReports.getAvailableCategories",
+ * operationId="CustomReports.getAvailableCategories",
+ * tags={"CustomReports"},
+ * @OA\Parameter(ref="#/components/parameters/formatOptional"),
+ * @OA\Parameter(ref="#/components/parameters/idSiteRequired"),
+ * @OA\Response(
+ * response=200,
+ * description="Example links: [XML](https://demo.matomo.cloud/?module=API&method=CustomReports.getAvailableCategories&idSite=1&format=xml&token_auth=anonymous), [JSON](https://demo.matomo.cloud/?module=API&method=CustomReports.getAvailableCategories&idSite=1&format=JSON&token_auth=anonymous), TSV (N/A)",
+ * @OA\MediaType(
+ * mediaType="text/xml",
+ * example={"row":{{"uniqueId":"General_Actions","name":"Behaviour","subcategories":{"row":{{"uniqueId":"customdimension2","name":"Page Author"},{"uniqueId":"customdimension4","name":"Page Location"},{"uniqueId":"customdimension5","name":"Page Type"},{"uniqueId":"VisitorInterest_Engagement","name":"Engagement"},{"uniqueId":"Transitions_Transitions","name":"Transitions"},{"uniqueId":"General_Downloads","name":"Downloads"},{"uniqueId":"Actions_SubmenuPagesEntry","name":"Entry pages"},{"uniqueId":"Actions_SubmenuPagesExit","name":"Exit pages"},{"uniqueId":"General_Outlinks","name":"Outlinks"},{"uniqueId":"Actions_SubmenuPageTitles","name":"Page titles"},{"uniqueId":"General_Pages","name":"Pages"},{"uniqueId":"Actions_SubmenuSitesearch","name":"Site Search"},{"uniqueId":"Events_Events","name":"Events"},{"uniqueId":"Contents_Contents","name":"Contents"},{"uniqueId":"PagePerformance_Performance","name":"Performance"},{"uniqueId":"UsersFlow_TopPaths","name":"Top Paths"},{"uniqueId":"UsersFlow_UsersFlow","name":"Users Flow"},{"uniqueId":"SearchEngineKeywordsPerformance_CrawlingErrors","name":"Crawling errors"}}}},{"uniqueId":"General_Visitors","name":"Visitors","subcategories":{"row":{{"uniqueId":"customdimension1","name":"User Type"},{"uniqueId":"DevicesDetection_Devices","name":"Devices"},{"uniqueId":"DevicesDetection_Software","name":"Software"},{"uniqueId":"General_Overview","name":"Overview"},{"uniqueId":"UserCountry_SubmenuLocations","name":"Locations"},{"uniqueId":"VisitTime_SubmenuTimes","name":"Times"},{"uniqueId":"UserCountryMap_RealTimeMap","name":"Real-time Map"},{"uniqueId":"General_RealTime","name":"Real-time"},{"uniqueId":"Live_VisitorLog","name":"Visits Log"},{"uniqueId":"UserId_UserReportTitle","name":"User IDs"},{"uniqueId":"CustomVariables_CustomVariables","name":"Custom Variables"}}}},{"uniqueId":"Referrers_Referrers","name":"Acquisition","subcategories":{"row":{{"uniqueId":"Referrers_AIAssistants","name":"AI Assistants"},{"uniqueId":"Referrers_WidgetGetAll","name":"All Channels"},{"uniqueId":"Referrers_URLCampaignBuilder","name":"Campaign URL Builder"},{"uniqueId":"Referrers_Campaigns","name":"Campaigns"},{"uniqueId":"General_Overview","name":"Overview"},{"uniqueId":"Referrers_SubmenuSearchEngines","name":"Search Engines & Keywords"},{"uniqueId":"Referrers_Socials","name":"Social Networks"},{"uniqueId":"Referrers_SubmenuWebsitesOnly","name":"Websites"},{"uniqueId":"SearchEngineKeywordsPerformance_CrawlingStats","name":"Crawling overview"}}}},{"uniqueId":"Goals_Goals","name":"Goals","subcategories":{"row":{{"uniqueId":"8","name":"Agoda click"},{"uniqueId":"7","name":"Liveaboard.com click"},{"uniqueId":"4","name":"New Job Application"},{"uniqueId":"6","name":"New Resume"},{"uniqueId":"10","name":"Newsletter Signup"},{"uniqueId":"9","name":"User Comments"},{"uniqueId":"5","name":"View Submit Job"},{"uniqueId":"General_Overview","name":"Overview"},{"uniqueId":"MultiChannelConversionAttribution_MultiAttribution","name":"Multi Attribution"}}}}}},
+ * @OA\Schema(
+ * type="object",
+ * @OA\Xml(name="result"),
+ * @OA\Property(
+ * property="row",
+ * type="array",
+ * @OA\Items(
+ * type="object",
+ * @OA\Xml(name="row"),
+ * additionalProperties=true,
+ * @OA\Property(
+ * property="subcategories",
+ * type="object",
+ * @OA\Property(
+ * property="row",
+ * type="array",
+ * @OA\Items(
+ * type="object",
+ * @OA\Xml(name="row"),
+ * additionalProperties=true
+ * )
+ * )
+ * )
+ * )
+ * )
+ * )
+ * ),
+ * @OA\MediaType(
+ * mediaType="application/json",
+ * example={{"uniqueId":"General_Actions","name":"Behaviour","subcategories":{{"uniqueId":"customdimension2","name":"Page Author"},{"uniqueId":"customdimension4","name":"Page Location"},{"uniqueId":"customdimension5","name":"Page Type"},{"uniqueId":"VisitorInterest_Engagement","name":"Engagement"},{"uniqueId":"Transitions_Transitions","name":"Transitions"},{"uniqueId":"General_Downloads","name":"Downloads"},{"uniqueId":"Actions_SubmenuPagesEntry","name":"Entry pages"},{"uniqueId":"Actions_SubmenuPagesExit","name":"Exit pages"},{"uniqueId":"General_Outlinks","name":"Outlinks"},{"uniqueId":"Actions_SubmenuPageTitles","name":"Page titles"},{"uniqueId":"General_Pages","name":"Pages"},{"uniqueId":"Actions_SubmenuSitesearch","name":"Site Search"},{"uniqueId":"Events_Events","name":"Events"},{"uniqueId":"Contents_Contents","name":"Contents"},{"uniqueId":"PagePerformance_Performance","name":"Performance"},{"uniqueId":"UsersFlow_TopPaths","name":"Top Paths"},{"uniqueId":"UsersFlow_UsersFlow","name":"Users Flow"},{"uniqueId":"SearchEngineKeywordsPerformance_CrawlingErrors","name":"Crawling errors"}}},{"uniqueId":"General_Visitors","name":"Visitors","subcategories":{{"uniqueId":"customdimension1","name":"User Type"},{"uniqueId":"DevicesDetection_Devices","name":"Devices"},{"uniqueId":"DevicesDetection_Software","name":"Software"},{"uniqueId":"General_Overview","name":"Overview"},{"uniqueId":"UserCountry_SubmenuLocations","name":"Locations"},{"uniqueId":"VisitTime_SubmenuTimes","name":"Times"},{"uniqueId":"UserCountryMap_RealTimeMap","name":"Real-time Map"},{"uniqueId":"General_RealTime","name":"Real-time"},{"uniqueId":"Live_VisitorLog","name":"Visits Log"},{"uniqueId":"UserId_UserReportTitle","name":"User IDs"},{"uniqueId":"CustomVariables_CustomVariables","name":"Custom Variables"}}},{"uniqueId":"Referrers_Referrers","name":"Acquisition","subcategories":{{"uniqueId":"Referrers_AIAssistants","name":"AI Assistants"},{"uniqueId":"Referrers_WidgetGetAll","name":"All Channels"},{"uniqueId":"Referrers_URLCampaignBuilder","name":"Campaign URL Builder"},{"uniqueId":"Referrers_Campaigns","name":"Campaigns"},{"uniqueId":"General_Overview","name":"Overview"},{"uniqueId":"Referrers_SubmenuSearchEngines","name":"Search Engines & Keywords"},{"uniqueId":"Referrers_Socials","name":"Social Networks"},{"uniqueId":"Referrers_SubmenuWebsitesOnly","name":"Websites"},{"uniqueId":"SearchEngineKeywordsPerformance_CrawlingStats","name":"Crawling overview"}}},{"uniqueId":"Goals_Goals","name":"Goals","subcategories":{{"uniqueId":"8","name":"Agoda click"},{"uniqueId":"7","name":"Liveaboard.com click"},{"uniqueId":"4","name":"New Job Application"},{"uniqueId":"6","name":"New Resume"},{"uniqueId":"10","name":"Newsletter Signup"},{"uniqueId":"9","name":"User Comments"},{"uniqueId":"5","name":"View Submit Job"},{"uniqueId":"General_Overview","name":"Overview"},{"uniqueId":"MultiChannelConversionAttribution_MultiAttribution","name":"Multi Attribution"}}}},
+ * @OA\Schema(
+ * type="array",
+ * @OA\Items(
+ * type="object",
+ * additionalProperties=true,
+ * @OA\Property(
+ * type="object",
+ * @OA\Property(property="uniqueId", type="string"),
+ * @OA\Property(property="name", type="string"),
+ * @OA\Property(
+ * property="subcategories",
+ * type="array",
+ * @OA\Items(
+ * type="object",
+ * additionalProperties=true,
+ * @OA\Property(
+ * type="object",
+ * @OA\Property(property="uniqueId", type="string"),
+ * @OA\Property(property="name", type="string")
+ * )
+ * )
+ * )
+ * )
+ * )
+ * )
+ * )
+ * ),
+ * @OA\Response(response=400, ref="#/components/responses/BadRequest"),
+ * @OA\Response(response=401, ref="#/components/responses/Unauthorized"),
+ * @OA\Response(response=403, ref="#/components/responses/Forbidden"),
+ * @OA\Response(response=404, ref="#/components/responses/NotFound"),
+ * @OA\Response(response=500, ref="#/components/responses/ServerError"),
+ * @OA\Response(response="default", ref="#/components/responses/DefaultError")
+ * )
+ */
+ // phpcs:enable Generic.Files.LineLength
+ public function getAvailableCategories($idSite)
+ {
+ $this->validator->checkReportViewPermission($idSite);
+
+ $reportPages = Request::processRequest('API.getReportPagesMetadata', array('idSite' => $idSite, 'filter_limit' => -1));
+
+ $categories = array();
+ foreach ($reportPages as $reportPage) {
+ if (!empty($reportPage['category']['id'])) {
+ $categoryId = $reportPage['category']['id'];
+
+ if ($categoryId === 'Dashboard_Dashboard') {
+ continue;
+ }
+
+ $subcategoryId = $reportPage['subcategory']['id'];
+ if (strpos($subcategoryId, '_Manage') !== false) {
+ continue; // we do not want to be able to add reports to manage pages
+ }
+
+ if (isset($categories[$categoryId])) {
+ $categories[$categoryId]['subcategories'][] = array(
+ 'uniqueId' => $reportPage['subcategory']['id'],
+ 'name' => $reportPage['subcategory']['name']
+ );
+ } else {
+ $categories[$categoryId] = array(
+ 'uniqueId' => $categoryId,
+ 'name' => $reportPage['category']['name'],
+ 'subcategories' => array(
+ array(
+ 'uniqueId' => $reportPage['subcategory']['id'],
+ 'name' => $reportPage['subcategory']['name']
+ )
+ ),
+ );
+ }
+ }
+ }
+
+ if (!isset($categories['CustomReports_CustomReports'])) {
+ $categories['CustomReports_CustomReports'] = array(
+ 'uniqueId' => 'CustomReports_CustomReports',
+ 'name' => Piwik::translate('CustomReports_CustomReports'),
+ 'subcategories' => array()
+ );
+ }
+
+ return array_values($categories);
+ }
+
+ // phpcs:disable Generic.Files.LineLength
+ /**
+ * Get a list of available report types that can be used in custom reports.
+ *
+ * @return array
+ *
+ * @OA\Get(
+ * path="/index.php?module=API&method=CustomReports.getAvailableReportTypes",
+ * operationId="CustomReports.getAvailableReportTypes",
+ * tags={"CustomReports"},
+ * @OA\Parameter(ref="#/components/parameters/formatOptional"),
+ * @OA\Response(
+ * response=200,
+ * description="Example links: [XML](https://demo.matomo.cloud/?module=API&method=CustomReports.getAvailableReportTypes&format=xml&token_auth=anonymous), [JSON](https://demo.matomo.cloud/?module=API&method=CustomReports.getAvailableReportTypes&format=JSON&token_auth=anonymous), [TSV (Excel)](https://demo.matomo.cloud/?module=API&method=CustomReports.getAvailableReportTypes&format=Tsv&token_auth=anonymous)",
+ * @OA\MediaType(
+ * mediaType="text/xml",
+ * example={"row":{{"key":"table","value":"Table"},{"key":"evolution","value":"Evolution"}}},
+ * @OA\Schema(
+ * type="object",
+ * @OA\Xml(name="result"),
+ * @OA\Property(
+ * property="row",
+ * type="array",
+ * @OA\Items(
+ * type="object",
+ * @OA\Xml(name="row"),
+ * additionalProperties=true
+ * )
+ * )
+ * )
+ * ),
+ * @OA\MediaType(
+ * mediaType="application/json",
+ * example={{"key":"table","value":"Table"},{"key":"evolution","value":"Evolution"}},
+ * @OA\Schema(
+ * type="array",
+ * @OA\Items(
+ * type="object",
+ * additionalProperties=true,
+ * @OA\Property(
+ * type="object",
+ * @OA\Property(property="key", type="string"),
+ * @OA\Property(property="value", type="string")
+ * )
+ * )
+ * )
+ * ),
+ * @OA\MediaType(
+ * mediaType="application/vnd.ms-excel",
+ * example="key value
+ * table Table
+ * evolution Evolution"
+ * )
+ * ),
+ * @OA\Response(response=400, ref="#/components/responses/BadRequest"),
+ * @OA\Response(response=401, ref="#/components/responses/Unauthorized"),
+ * @OA\Response(response=403, ref="#/components/responses/Forbidden"),
+ * @OA\Response(response=404, ref="#/components/responses/NotFound"),
+ * @OA\Response(response=500, ref="#/components/responses/ServerError"),
+ * @OA\Response(response="default", ref="#/components/responses/DefaultError")
+ * )
+ */
+ // phpcs:enable Generic.Files.LineLength
+ public function getAvailableReportTypes()
+ {
+ $this->validator->checkHasSomeWritePermission();
+
+ $rows = array();
+ foreach (ReportType::getAll() as $reportType) {
+ $rows[] = array('key' => $reportType::ID, 'value' => $reportType->getName());
+ }
+
+ return $rows;
+ }
+
+ private function isTableJoinable($tableName)
+ {
+ $logTable = $this->logTablesProvider->getLogTable($tableName);
+ if ($logTable && ($logTable->getColumnToJoinOnIdAction() || $logTable->getColumnToJoinOnIdVisit())) {
+ if ($logTable->getPrimaryKey()) {
+ // without primary key we would not group the data correctly
+ return true;
+ }
+ } elseif ($logTable && $logTable->getWaysToJoinToOtherLogTables()) {
+ $tables = new JoinTables($this->logTablesProvider, [$tableName]);
+ return $tables->isTableJoinableOnVisit($tableName) || $tables->isTableJoinableOnAction($tableName);
+ }
+
+ return false;
+ }
+
+ // phpcs:disable Generic.Files.LineLength
+ /**
+ * Get a list of available dimensions that can be used in custom reports.
+ *
+ * @param int $idSite
+ * @return array
+ *
+ * @OA\Get(
+ * path="/index.php?module=API&method=CustomReports.getAvailableDimensions",
+ * operationId="CustomReports.getAvailableDimensions",
+ * tags={"CustomReports"},
+ * @OA\Parameter(ref="#/components/parameters/formatOptional"),
+ * @OA\Parameter(ref="#/components/parameters/idSiteRequired"),
+ * @OA\Response(
+ * response=200,
+ * description="Example links: [XML](https://demo.matomo.cloud/?module=API&method=CustomReports.getAvailableDimensions&idSite=1&format=xml&token_auth=anonymous), [JSON](https://demo.matomo.cloud/?module=API&method=CustomReports.getAvailableDimensions&idSite=1&format=JSON&token_auth=anonymous), TSV (N/A)",
+ * @OA\MediaType(
+ * mediaType="text/xml",
+ * example={"row":{{"category":"Visitor location","dimensions":{"row":{{"uniqueId":"UserCountry.City","name":"City","sqlSegment":"log_visit.location_city"},{"uniqueId":"UserCountry.Continent","name":"Continent","sqlSegment":"log_visit.location_country"},{"uniqueId":"UserCountry.Country","name":"Country","sqlSegment":"log_visit.location_country"},{"uniqueId":"UserLanguage.Language","name":"Language","sqlSegment":"log_visit.location_browser_lang"},{"uniqueId":"UserCountry.Latitude","name":"Latitude","sqlSegment":"log_visit.location_latitude"},{"uniqueId":"UserCountry.Longitude","name":"Longitude","sqlSegment":"log_visit.location_longitude"},{"uniqueId":"UserCountry.Region","name":"Region","sqlSegment":"log_visit.location_region"}}},"orderId":"7"},{"category":"Events","dimensions":{"row":{{"uniqueId":"Events.EventAction","name":"Event Action","sqlSegment":"log_link_visit_action.idaction_event_action"},{"uniqueId":"Events.EventCategory","name":"Event Category","sqlSegment":"log_link_visit_action.idaction_event_category"},{"uniqueId":"Events.EventName","name":"Event Name","sqlSegment":"log_link_visit_action.idaction_name"},{"uniqueId":"Events.EventUrl","name":"Event URL","sqlSegment":"log_link_visit_action.idaction_url"},{"uniqueId":"Events.EventValue","name":"Event Value","sqlSegment":"log_link_visit_action.custom_float"}}},"orderId":"12"},{"category":"Acquisition","dimensions":{"row":{{"uniqueId":"AdvertisingConversionExport.AdClickId","name":"Ad Click ID","sqlSegment":"log_clickid.adclickid"},{"uniqueId":"AdvertisingConversionExport.AdProvider","name":"Ad Provider","sqlSegment":"log_clickid.adprovider"},{"uniqueId":"MarketingCampaignsReporting.CampaignContent","name":"Campaign Content","sqlSegment":"log_visit.campaign_content"},{"uniqueId":"MarketingCampaignsReporting.CampaignGroup","name":"Campaign Group","sqlSegment":"log_visit.campaign_group"},{"uniqueId":"MarketingCampaignsReporting.CampaignId","name":"Campaign Id","sqlSegment":"log_visit.campaign_id"},{"uniqueId":"MarketingCampaignsReporting.CampaignKeyword","name":"Campaign Keyword","sqlSegment":"log_visit.campaign_keyword"},{"uniqueId":"MarketingCampaignsReporting.CampaignMedium","name":"Campaign Medium","sqlSegment":"log_visit.campaign_medium"},{"uniqueId":"MarketingCampaignsReporting.CampaignName","name":"Campaign Name","sqlSegment":"log_visit.campaign_name"},{"uniqueId":"MarketingCampaignsReporting.CampaignPlacement","name":"Campaign Placement","sqlSegment":"log_visit.campaign_placement"},{"uniqueId":"MarketingCampaignsReporting.CampaignSource","name":"Campaign Source","sqlSegment":"log_visit.campaign_source"},{"uniqueId":"Referrers.ReferrerType","name":"Channel Type","sqlSegment":"log_visit.referer_type"},{"uniqueId":"Referrers.Keyword","name":"Keyword","sqlSegment":"log_visit.referer_keyword"},{"uniqueId":"Referrers.ReferrerName","name":"Referrer Name","sqlSegment":"log_visit.referer_name"},{"uniqueId":"Referrers.ReferrerUrl","name":"Referrer URL","sqlSegment":"log_visit.referer_url"}}},"orderId":"15"}}},
+ * @OA\Schema(
+ * type="object",
+ * @OA\Xml(name="result"),
+ * @OA\Property(
+ * property="row",
+ * type="array",
+ * @OA\Items(
+ * type="object",
+ * @OA\Xml(name="row"),
+ * additionalProperties=true,
+ * @OA\Property(
+ * property="dimensions",
+ * type="object",
+ * @OA\Property(
+ * property="row",
+ * type="array",
+ * @OA\Items(
+ * type="object",
+ * @OA\Xml(name="row"),
+ * additionalProperties=true
+ * )
+ * )
+ * )
+ * )
+ * )
+ * )
+ * ),
+ * @OA\MediaType(
+ * mediaType="application/json",
+ * example={{"category":"Visitor location","dimensions":{{"uniqueId":"UserCountry.City","name":"City","sqlSegment":"log_visit.location_city"},{"uniqueId":"UserCountry.Continent","name":"Continent","sqlSegment":"log_visit.location_country"},{"uniqueId":"UserCountry.Country","name":"Country","sqlSegment":"log_visit.location_country"},{"uniqueId":"UserLanguage.Language","name":"Language","sqlSegment":"log_visit.location_browser_lang"},{"uniqueId":"UserCountry.Latitude","name":"Latitude","sqlSegment":"log_visit.location_latitude"},{"uniqueId":"UserCountry.Longitude","name":"Longitude","sqlSegment":"log_visit.location_longitude"},{"uniqueId":"UserCountry.Region","name":"Region","sqlSegment":"log_visit.location_region"}},"orderId":7},{"category":"Events","dimensions":{{"uniqueId":"Events.EventAction","name":"Event Action","sqlSegment":"log_link_visit_action.idaction_event_action"},{"uniqueId":"Events.EventCategory","name":"Event Category","sqlSegment":"log_link_visit_action.idaction_event_category"},{"uniqueId":"Events.EventName","name":"Event Name","sqlSegment":"log_link_visit_action.idaction_name"},{"uniqueId":"Events.EventUrl","name":"Event URL","sqlSegment":"log_link_visit_action.idaction_url"},{"uniqueId":"Events.EventValue","name":"Event Value","sqlSegment":"log_link_visit_action.custom_float"}},"orderId":12},{"category":"Acquisition","dimensions":{{"uniqueId":"AdvertisingConversionExport.AdClickId","name":"Ad Click ID","sqlSegment":"log_clickid.adclickid"},{"uniqueId":"AdvertisingConversionExport.AdProvider","name":"Ad Provider","sqlSegment":"log_clickid.adprovider"},{"uniqueId":"MarketingCampaignsReporting.CampaignContent","name":"Campaign Content","sqlSegment":"log_visit.campaign_content"},{"uniqueId":"MarketingCampaignsReporting.CampaignGroup","name":"Campaign Group","sqlSegment":"log_visit.campaign_group"},{"uniqueId":"MarketingCampaignsReporting.CampaignId","name":"Campaign Id","sqlSegment":"log_visit.campaign_id"},{"uniqueId":"MarketingCampaignsReporting.CampaignKeyword","name":"Campaign Keyword","sqlSegment":"log_visit.campaign_keyword"},{"uniqueId":"MarketingCampaignsReporting.CampaignMedium","name":"Campaign Medium","sqlSegment":"log_visit.campaign_medium"},{"uniqueId":"MarketingCampaignsReporting.CampaignName","name":"Campaign Name","sqlSegment":"log_visit.campaign_name"},{"uniqueId":"MarketingCampaignsReporting.CampaignPlacement","name":"Campaign Placement","sqlSegment":"log_visit.campaign_placement"},{"uniqueId":"MarketingCampaignsReporting.CampaignSource","name":"Campaign Source","sqlSegment":"log_visit.campaign_source"},{"uniqueId":"Referrers.ReferrerType","name":"Channel Type","sqlSegment":"log_visit.referer_type"},{"uniqueId":"Referrers.Keyword","name":"Keyword","sqlSegment":"log_visit.referer_keyword"},{"uniqueId":"Referrers.ReferrerName","name":"Referrer Name","sqlSegment":"log_visit.referer_name"},{"uniqueId":"Referrers.ReferrerUrl","name":"Referrer URL","sqlSegment":"log_visit.referer_url"}},"orderId":15}},
+ * @OA\Schema(
+ * type="array",
+ * @OA\Items(
+ * type="object",
+ * additionalProperties=true,
+ * @OA\Property(
+ * type="object",
+ * @OA\Property(property="category", type="string"),
+ * @OA\Property(
+ * property="dimensions",
+ * type="array",
+ * @OA\Items(
+ * type="object",
+ * additionalProperties=true,
+ * @OA\Property(
+ * type="object",
+ * @OA\Property(property="uniqueId", type="string"),
+ * @OA\Property(property="name", type="string"),
+ * @OA\Property(property="sqlSegment", type="string")
+ * )
+ * )
+ * ),
+ * @OA\Property(property="orderId", type="integer")
+ * )
+ * )
+ * )
+ * )
+ * ),
+ * @OA\Response(response=400, ref="#/components/responses/BadRequest"),
+ * @OA\Response(response=401, ref="#/components/responses/Unauthorized"),
+ * @OA\Response(response=403, ref="#/components/responses/Forbidden"),
+ * @OA\Response(response=404, ref="#/components/responses/NotFound"),
+ * @OA\Response(response=500, ref="#/components/responses/ServerError"),
+ * @OA\Response(response="default", ref="#/components/responses/DefaultError")
+ * )
+ */
+ // phpcs:enable Generic.Files.LineLength
+ public function getAvailableDimensions($idSite)
+ {
+ Piwik::checkUserIsNotAnonymous();
+ Piwik::checkUserHasSomeViewAccess();
+
+ $dimensions = $this->columnsProvider->getAllDimensions();
+
+ $rows = array();
+
+ $dimensionsToIgnore = array(
+ 'Actions.IdPageview', 'CoreHome.VisitId',
+ 'DevicesDetection.OsVersion', // only makes sense in combination with Os Family
+ 'CoreHome.LinkVisitActionId', 'CoreHome.LinkVisitActionIdPages', 'UserCountry.Provider'
+ );
+
+ $dimensionsToRename = [
+ 'CoreHome.IdSite' => Piwik::translate('CustomReports_WebsiteName')
+ ];
+
+ $config = StaticContainer::get(Configuration::class);
+ foreach ($config->getDisabledDimensions() as $dimensionDisabled) {
+ $dimensionsToIgnore[] = $dimensionDisabled;
+ }
+
+ /**
+ * Adds the possibility to other plugins to ignore more dimensions
+ */
+ Piwik::postEvent('CustomReports.addDimensionsToIgnore', array(&$dimensionsToIgnore));
+
+ $categoryList = CategoryList::get();
+
+ foreach ($dimensions as $dimension) {
+ $categoryId = $dimension->getCategoryId();
+ $dimensionName = $dimension->getName();
+ $table = $dimension->getDbTableName();
+ $dimensionId = $dimension->getId();
+
+ if (!$table) {
+ // without table we cannot join it
+ continue;
+ }
+
+ if (!$this->isTableJoinable($table)) {
+ // archiving this dimension would not work
+ continue;
+ }
+
+ if (in_array($dimensionId, $dimensionsToIgnore)) {
+ continue;
+ }
+
+ if (key_exists($dimensionId, $dimensionsToRename)) {
+ $dimensionName = $dimensionsToRename[$dimensionId];
+ }
+
+ if ($dimension->getColumnName() && $dimensionName) {
+ if (!isset($rows[$categoryId])) {
+ $category = $categoryList->getCategory($categoryId);
+ $orderId = 999;
+ if (!empty($category)) {
+ $orderId = $category->getOrder();
+ }
+
+ $categoryName = Piwik::translate($categoryId);
+ if (!is_null($category) && method_exists($category, 'getDisplayName')) {
+ $categoryName = $category->getDisplayName();
+ }
+
+ $rows[$categoryId] = array(
+ 'category' => $categoryName,
+ 'dimensions' => array(),
+ 'orderId' => $orderId
+ );
+ }
+ $rows[$categoryId]['dimensions'][] = array(
+ 'uniqueId' => $dimension->getId(),
+ 'name' => ucwords($dimensionName),
+ 'sqlSegment' => $dimension->getSqlSegment(),
+ );
+ }
+ }
+
+ usort($rows, function ($rowA, $rowB) {
+ if ((int)$rowA['orderId'] > (int)$rowB['orderId']) {
+ return 1;
+ }
+ if ((int)$rowA['orderId'] === (int)$rowB['orderId']) {
+ return 0;
+ }
+ return -1;
+ });
+
+ foreach ($rows as $categoryId => $row) {
+ $dimensions = $row['dimensions'];
+ usort($dimensions, function ($dimA, $dimB) {
+ return strcmp($dimA['name'], $dimB['name']);
+ });
+ $rows[$categoryId]['dimensions'] = $dimensions;
+ }
+
+ return array_values($rows);
+ }
+
+ // phpcs:disable Generic.Files.LineLength
+ /**
+ * Get a list of available metrics that can be used in custom reports.
+ *
+ * @param int $idSite
+ * @return array
+ *
+ * @OA\Get(
+ * path="/index.php?module=API&method=CustomReports.getAvailableMetrics",
+ * operationId="CustomReports.getAvailableMetrics",
+ * tags={"CustomReports"},
+ * @OA\Parameter(ref="#/components/parameters/formatOptional"),
+ * @OA\Parameter(ref="#/components/parameters/idSiteRequired"),
+ * @OA\Response(
+ * response=200,
+ * description="Example links: [XML](https://demo.matomo.cloud/?module=API&method=CustomReports.getAvailableMetrics&idSite=1&format=xml&token_auth=anonymous), [JSON](https://demo.matomo.cloud/?module=API&method=CustomReports.getAvailableMetrics&idSite=1&format=JSON&token_auth=anonymous), TSV (N/A)",
+ * @OA\MediaType(
+ * mediaType="text/xml",
+ * example={"row":{{"category":"Visitor location","metrics":{"row":{{"uniqueId":"nb_uniq_usercountry_city","name":"Unique Cities","description":"The unique number of Cities. When viewing a period that is not day, then this metric will become ""Sum of Unique Cities"". In such case, if the same Cities appear in 2 or more days within the selected period, then it will be counted as 2 or the total number of days it has appeared and not 1."},{"uniqueId":"nb_uniq_usercountry_continent","name":"Unique Continents","description":"The unique number of Continents. When viewing a period that is not day, then this metric will become ""Sum of Unique Continents"". In such case, if the same Continents appear in 2 or more days within the selected period, then it will be counted as 2 or the total number of days it has appeared and not 1."},{"uniqueId":"nb_uniq_usercountry_country","name":"Unique Countries","description":"The unique number of Countries. When viewing a period that is not day, then this metric will become ""Sum of Unique Countries"". In such case, if the same Countries appear in 2 or more days within the selected period, then it will be counted as 2 or the total number of days it has appeared and not 1."},{"uniqueId":"nb_uniq_userlanguage_language","name":"Unique Languages","description":"The unique number of Languages. When viewing a period that is not day, then this metric will become ""Sum of Unique Languages"". In such case, if the same Languages appear in 2 or more days within the selected period, then it will be counted as 2 or the total number of days it has appeared and not 1."},{"uniqueId":"nb_uniq_usercountry_latitude","name":"Unique Latitudes","description":"The unique number of Latitudes. When viewing a period that is not day, then this metric will become ""Sum of Unique Latitudes"". In such case, if the same Latitudes appear in 2 or more days within the selected period, then it will be counted as 2 or the total number of days it has appeared and not 1."},{"uniqueId":"nb_uniq_usercountry_longitude","name":"Unique Longitudes","description":"The unique number of Longitudes. When viewing a period that is not day, then this metric will become ""Sum of Unique Longitudes"". In such case, if the same Longitudes appear in 2 or more days within the selected period, then it will be counted as 2 or the total number of days it has appeared and not 1."},{"uniqueId":"nb_uniq_usercountry_region","name":"Unique Regions","description":"The unique number of Regions. When viewing a period that is not day, then this metric will become ""Sum of Unique Regions"". In such case, if the same Regions appear in 2 or more days within the selected period, then it will be counted as 2 or the total number of days it has appeared and not 1."}}},"orderId":"7"}}},
+ * @OA\Schema(
+ * type="object",
+ * @OA\Xml(name="result"),
+ * @OA\Property(
+ * property="row",
+ * type="array",
+ * @OA\Items(
+ * type="object",
+ * @OA\Xml(name="row"),
+ * additionalProperties=true,
+ * @OA\Property(
+ * property="metrics",
+ * type="object",
+ * @OA\Property(
+ * property="row",
+ * type="array",
+ * @OA\Items(
+ * type="object",
+ * @OA\Xml(name="row"),
+ * additionalProperties=true
+ * )
+ * )
+ * )
+ * )
+ * )
+ * )
+ * ),
+ * @OA\MediaType(
+ * mediaType="application/json",
+ * example={{"category":"Visitor location","metrics":{{"uniqueId":"nb_uniq_usercountry_city","name":"Unique Cities","description":"The unique number of Cities. When viewing a period that is not day, then this metric will become ""Sum of Unique Cities"". In such case, if the same Cities appear in 2 or more days within the selected period, then it will be counted as 2 or the total number of days it has appeared and not 1."},{"uniqueId":"nb_uniq_usercountry_continent","name":"Unique Continents","description":"The unique number of Continents. When viewing a period that is not day, then this metric will become ""Sum of Unique Continents"". In such case, if the same Continents appear in 2 or more days within the selected period, then it will be counted as 2 or the total number of days it has appeared and not 1."},{"uniqueId":"nb_uniq_usercountry_country","name":"Unique Countries","description":"The unique number of Countries. When viewing a period that is not day, then this metric will become ""Sum of Unique Countries"". In such case, if the same Countries appear in 2 or more days within the selected period, then it will be counted as 2 or the total number of days it has appeared and not 1."},{"uniqueId":"nb_uniq_userlanguage_language","name":"Unique Languages","description":"The unique number of Languages. When viewing a period that is not day, then this metric will become ""Sum of Unique Languages"". In such case, if the same Languages appear in 2 or more days within the selected period, then it will be counted as 2 or the total number of days it has appeared and not 1."},{"uniqueId":"nb_uniq_usercountry_latitude","name":"Unique Latitudes","description":"The unique number of Latitudes. When viewing a period that is not day, then this metric will become ""Sum of Unique Latitudes"". In such case, if the same Latitudes appear in 2 or more days within the selected period, then it will be counted as 2 or the total number of days it has appeared and not 1."},{"uniqueId":"nb_uniq_usercountry_longitude","name":"Unique Longitudes","description":"The unique number of Longitudes. When viewing a period that is not day, then this metric will become ""Sum of Unique Longitudes"". In such case, if the same Longitudes appear in 2 or more days within the selected period, then it will be counted as 2 or the total number of days it has appeared and not 1."},{"uniqueId":"nb_uniq_usercountry_region","name":"Unique Regions","description":"The unique number of Regions. When viewing a period that is not day, then this metric will become ""Sum of Unique Regions"". In such case, if the same Regions appear in 2 or more days within the selected period, then it will be counted as 2 or the total number of days it has appeared and not 1."}},"orderId":7}},
+ * @OA\Schema(
+ * type="array",
+ * @OA\Items(
+ * type="object",
+ * additionalProperties=true,
+ * @OA\Property(
+ * type="object",
+ * @OA\Property(property="category", type="string"),
+ * @OA\Property(
+ * property="metrics",
+ * type="array",
+ * @OA\Items(
+ * type="object",
+ * additionalProperties=true,
+ * @OA\Property(
+ * type="object",
+ * @OA\Property(property="uniqueId", type="string"),
+ * @OA\Property(property="name", type="string"),
+ * @OA\Property(property="description", type="string")
+ * )
+ * )
+ * ),
+ * @OA\Property(property="orderId", type="integer")
+ * )
+ * )
+ * )
+ * )
+ * ),
+ * @OA\Response(response=400, ref="#/components/responses/BadRequest"),
+ * @OA\Response(response=401, ref="#/components/responses/Unauthorized"),
+ * @OA\Response(response=403, ref="#/components/responses/Forbidden"),
+ * @OA\Response(response=404, ref="#/components/responses/NotFound"),
+ * @OA\Response(response=500, ref="#/components/responses/ServerError"),
+ * @OA\Response(response="default", ref="#/components/responses/DefaultError")
+ * )
+ */
+ // phpcs:enable Generic.Files.LineLength
+ public function getAvailableMetrics($idSite)
+ {
+ Piwik::checkUserIsNotAnonymous();
+ Piwik::checkUserHasSomeViewAccess();
+
+ $metrics = MetricsList::get();
+ $categoryList = CategoryList::get();
+
+ $rows = array();
+ $period = Common::getRequestVar('period', '', 'string');
+ foreach ($metrics->getMetrics() as $metric) {
+ if (!$metric) {
+ continue;
+ }
+ if ($metric instanceof ProcessedMetric && !$this->canGenerateMetricAutomatically($metric)) {
+ // we do not have all the dependent metrics to generate this processed metric automatically
+ continue;
+ }
+
+ $categoryId = $metric->getCategoryId();
+ $name = $metric->getName();
+ $translatedName = $metric->getTranslatedName();
+
+ if (($metric instanceof ProcessedMetric || $metric instanceof ArchivedMetric) && $name && $translatedName) {
+ if (method_exists($metric, 'getQuery') && !$metric->getQuery()) {
+ // archiving this metric would not work!
+ continue;
+ }
+
+ if (method_exists($metric, 'getDbTableName') && $metric->getDbTableName() && !$this->isTableJoinable($metric->getDbTableName())) {
+ // archiving this metric would not work!
+ continue;
+ }
+
+ if (method_exists($metric, 'getDimension') && $metric->getDimension()) {
+ $dimension = $metric->getDimension();
+ $dbDiscriminator = $dimension->getDbDiscriminator();
+ if ($dbDiscriminator) {
+ $dbDiscriminatorValue = $dbDiscriminator->getValue();
+ if (!isset($dbDiscriminatorValue) || !is_numeric($dbDiscriminatorValue)) {
+ continue;
+ }
+ }
+ }
+
+ if (!isset($rows[$categoryId])) {
+ $category = $categoryList->getCategory($categoryId);
+ $orderId = 999;
+ if (!empty($category)) {
+ $orderId = $category->getOrder();
+ }
+
+ $categoryName = Piwik::translate($categoryId);
+ if (!is_null($category) && method_exists($category, 'getDisplayName')) {
+ $categoryName = $category->getDisplayName();
+ }
+
+ $rows[$categoryId] = array(
+ 'category' => $categoryName,
+ 'metrics' => array(),
+ 'orderId' => $orderId
+ );
+ }
+
+ $description = $metric->getDocumentation();
+ if (stripos($translatedName, 'unique') === 0) {
+ $description = Piwik::translate('CustomReports_CommonUniqueMetricDescription', array($description, ucwords($translatedName), str_replace('Unique ', '', ucwords($translatedName))));
+ }
+
+ $rows[$categoryId]['metrics'][] = array(
+ 'uniqueId' => $name, 'name' => ucwords($translatedName), 'description' => $description
+ );
+ }
+ }
+
+ usort($rows, function ($rowA, $rowB) {
+ if ((int)$rowA['orderId'] > (int)$rowB['orderId']) {
+ return 1;
+ }
+ if ((int)$rowA['orderId'] === (int)$rowB['orderId']) {
+ return 0;
+ }
+ return -1;
+ });
+
+ foreach ($rows as $category => $row) {
+ $dimensions = $row['metrics'];
+ usort($dimensions, function ($dimA, $dimB) {
+ return strcasecmp($dimA['name'], $dimB['name']);
+ });
+ $rows[$category]['metrics'] = $dimensions;
+ }
+
+ return array_values($rows);
+ }
+
+ private function canGenerateMetricAutomatically(ProcessedMetric $metric)
+ {
+ foreach ($metric->getDependentMetrics() as $dependentMetric) {
+ $depMetric = $this->metricsList->getMetric($dependentMetric);
+ if (!$depMetric) {
+ // we cannot generate this metric directly
+ return false;
+ }
+
+ if ($depMetric instanceof ProcessedMetric && !$this->canGenerateMetricAutomatically($depMetric)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ // phpcs:disable Generic.Files.LineLength
+ /**
+ * Get report data for a previously created custom report.
+ *
+ * @param int $idSite
+ * @param string $period
+ * @param string $date
+ * @param int $idCustomReport The ID of the custom report to look up data for.
+ * @param string $segment
+ * @param bool $expanded
+ * @param bool $flat
+ * @param int $idSubtable
+ * @param string $columns
+ *
+ * @return DataTable\DataTableInterface
+ *
+ * @OA\Get(
+ * path="/index.php?module=API&method=CustomReports.getCustomReport",
+ * operationId="CustomReports.getCustomReport",
+ * tags={"CustomReports"},
+ * @OA\Parameter(ref="#/components/parameters/formatOptional"),
+ * @OA\Parameter(ref="#/components/parameters/idSiteRequired"),
+ * @OA\Parameter(
+ * name="period",
+ * in="query",
+ * required=true,
+ * description="The ID of the custom report to look up data for.",
+ * @OA\Schema(
+ * type="string"
+ * )
+ * ),
+ * @OA\Parameter(
+ * name="date",
+ * in="query",
+ * required=true,
+ * @OA\Schema(
+ * type="string"
+ * )
+ * ),
+ * @OA\Parameter(
+ * name="idCustomReport",
+ * in="query",
+ * required=true,
+ * @OA\Schema(
+ * type="integer"
+ * )
+ * ),
+ * @OA\Parameter(
+ * name="segment",
+ * in="query",
+ * required=false,
+ * @OA\Schema(
+ * type="string"
+ * )
+ * ),
+ * @OA\Parameter(
+ * name="expanded",
+ * in="query",
+ * required=false,
+ * @OA\Schema(
+ * type="boolean",
+ * default=false
+ * )
+ * ),
+ * @OA\Parameter(
+ * name="flat",
+ * in="query",
+ * required=false,
+ * @OA\Schema(
+ * type="boolean",
+ * default=false
+ * )
+ * ),
+ * @OA\Parameter(
+ * name="idSubtable",
+ * in="query",
+ * required=false,
+ * @OA\Schema(
+ * type="integer"
+ * )
+ * ),
+ * @OA\Parameter(
+ * name="columns",
+ * in="query",
+ * required=false,
+ * @OA\Schema(
+ * type="string"
+ * )
+ * ),
+ * @OA\Response(
+ * response=200,
+ * description="Example links: [XML](https://demo.matomo.cloud/index.php?module=API&method=CustomReports.getCustomReport&idSite=1&idCustomReport=5&period=day&date=today&format=xml&token_auth=anonymous), [JSON](https://demo.matomo.cloud/index.php?module=API&method=CustomReports.getCustomReport&idSite=1&idCustomReport=5&period=day&date=today&format=JSON&token_auth=anonymous), [TSV (Excel)](https://demo.matomo.cloud/index.php?module=API&method=CustomReports.getCustomReport&idSite=1&idCustomReport=5&period=day&date=today&format=Tsv&token_auth=anonymous)",
+ * @OA\MediaType(
+ * mediaType="text/xml",
+ * example={"row":{{"label":"Australia","nb_uniq_visitors":"1","goal_7_conversion":"0","level":"1","goal_7_conversion_uniq_visitors_rate":"0","segment":"countryCode==au;countryCode!=pl"},{"label":"United States","nb_uniq_visitors":"1","goal_7_conversion":"0","level":"1","goal_7_conversion_uniq_visitors_rate":"0","segment":"countryCode==us;countryCode!=pl"}}},
+ * @OA\Schema(
+ * type="object",
+ * @OA\Xml(name="result"),
+ * @OA\Property(
+ * property="row",
+ * type="array",
+ * @OA\Items(
+ * type="object",
+ * @OA\Xml(name="row"),
+ * additionalProperties=true
+ * )
+ * )
+ * )
+ * ),
+ * @OA\MediaType(
+ * mediaType="application/json",
+ * example={{"label":"Australia","nb_uniq_visitors":1,"goal_7_conversion":0,"level":1,"goal_7_conversion_uniq_visitors_rate":0,"segment":"countryCode==au;countryCode!=pl"},{"label":"United States","nb_uniq_visitors":1,"goal_7_conversion":0,"level":1,"goal_7_conversion_uniq_visitors_rate":0,"segment":"countryCode==us;countryCode!=pl"}},
+ * @OA\Schema(
+ * type="array",
+ * @OA\Items(
+ * type="object",
+ * additionalProperties=true,
+ * @OA\Property(
+ * type="object",
+ * @OA\Property(property="label", type="string"),
+ * @OA\Property(property="nb_uniq_visitors", type="integer"),
+ * @OA\Property(property="goal_7_conversion", type="integer"),
+ * @OA\Property(property="level", type="integer"),
+ * @OA\Property(property="goal_7_conversion_uniq_visitors_rate", type="integer"),
+ * @OA\Property(property="segment", type="string")
+ * )
+ * )
+ * )
+ * ),
+ * @OA\MediaType(
+ * mediaType="application/vnd.ms-excel",
+ * example="label nb_uniq_visitors goal_7_conversion level goal_7_conversion_uniq_visitors_rate metadata_segment
+ * Australia 1 0 1 0 ""countryCode==au;countryCode!=pl""
+ * United States 1 0 1 0 ""countryCode==us;countryCode!=pl"""
+ * )
+ * ),
+ * @OA\Response(response=400, ref="#/components/responses/BadRequest"),
+ * @OA\Response(response=401, ref="#/components/responses/Unauthorized"),
+ * @OA\Response(response=403, ref="#/components/responses/Forbidden"),
+ * @OA\Response(response=404, ref="#/components/responses/NotFound"),
+ * @OA\Response(response=500, ref="#/components/responses/ServerError"),
+ * @OA\Response(response="default", ref="#/components/responses/DefaultError")
+ * )
+ */
+ // phpcs:enable Generic.Files.LineLength
+ public function getCustomReport($idSite, $period, $date, $idCustomReport, $segment = false, $expanded = false, $flat = false, $idSubtable = false, $columns = false)
+ {
+ $this->validator->checkReportViewPermission($idSite);
+ $this->validator->checkSiteExists($idSite); // lets not return any reports from eg deleted sites if for some reason report still exists
+ $this->model->checkReportExists($idSite, $idCustomReport);
+
+ $report = $this->model->getCustomReport($idSite, $idCustomReport);
+
+ $reportType = ReportType::factory($report['report_type']);
+
+ $table = $reportType->fetchApi($idSite, $idCustomReport, $period, $date, $segment, $expanded, $flat, $idSubtable, $columns);
+
+ return $table;
+ }
+
+ private function addAllowedToEditStatus(&$report)
+ {
+ $idSite = $report['idsite'];
+ $multipleIdSites = $report['multiple_idsites'] ? explode(',', $report['multiple_idsites']) : array();
+ if (Piwik::hasUserSuperUserAccess()) {
+ $allowedToEdit = true;
+ } elseif ($idSite == 'all' || $idSite == '0') {
+ $allowedToEdit = false;
+ } else {
+ $allowedToEdit = $multipleIdSites ? Piwik::isUserHasWriteAccess($multipleIdSites) : Piwik::isUserHasWriteAccess($idSite);
+ }
+
+ $report['allowedToEdit'] = $allowedToEdit;
+ }
+
+ private function getCustomReportInfo($idSite, $idCustomReport, $action)
+ {
+ $report = $this->model->getCustomReport($idSite, $idCustomReport);
+
+ if (empty($report)) {
+ throw new \Exception(Piwik::translate('CustomReports_ErrorCustomReportDoesNotExist'));
+ } elseif ($report['idsite'] != $idSite) {
+ // prevent a possible hack that someone passes a different site than the report has and then we accidentally
+ // still delete the report because we match with `idsite = 0 or idsite = ?`. We don't do this here right now
+ // and wouldn't need this code but it is to prevent any possible future security bugs.
+ throw new \Exception(Piwik::translate('CustomReports_' . $action . 'ExceptionMessage'));
+ }
+
+ return $report;
+ }
+}
diff --git a/files/plugin-CustomReports-5.4.3/Activity/BaseActivity.php b/files/plugin-CustomReports-5.4.5/Activity/BaseActivity.php
similarity index 100%
rename from files/plugin-CustomReports-5.4.3/Activity/BaseActivity.php
rename to files/plugin-CustomReports-5.4.5/Activity/BaseActivity.php
diff --git a/files/plugin-CustomReports-5.4.3/Activity/ReportAdded.php b/files/plugin-CustomReports-5.4.5/Activity/ReportAdded.php
similarity index 100%
rename from files/plugin-CustomReports-5.4.3/Activity/ReportAdded.php
rename to files/plugin-CustomReports-5.4.5/Activity/ReportAdded.php
diff --git a/files/plugin-CustomReports-5.4.3/Activity/ReportDeleted.php b/files/plugin-CustomReports-5.4.5/Activity/ReportDeleted.php
similarity index 100%
rename from files/plugin-CustomReports-5.4.3/Activity/ReportDeleted.php
rename to files/plugin-CustomReports-5.4.5/Activity/ReportDeleted.php
diff --git a/files/plugin-CustomReports-5.4.3/Activity/ReportPaused.php b/files/plugin-CustomReports-5.4.5/Activity/ReportPaused.php
similarity index 100%
rename from files/plugin-CustomReports-5.4.3/Activity/ReportPaused.php
rename to files/plugin-CustomReports-5.4.5/Activity/ReportPaused.php
diff --git a/files/plugin-CustomReports-5.4.3/Activity/ReportResumed.php b/files/plugin-CustomReports-5.4.5/Activity/ReportResumed.php
similarity index 100%
rename from files/plugin-CustomReports-5.4.3/Activity/ReportResumed.php
rename to files/plugin-CustomReports-5.4.5/Activity/ReportResumed.php
diff --git a/files/plugin-CustomReports-5.4.3/Activity/ReportUpdated.php b/files/plugin-CustomReports-5.4.5/Activity/ReportUpdated.php
similarity index 100%
rename from files/plugin-CustomReports-5.4.3/Activity/ReportUpdated.php
rename to files/plugin-CustomReports-5.4.5/Activity/ReportUpdated.php
diff --git a/files/plugin-CustomReports-5.4.3/Archiver.php b/files/plugin-CustomReports-5.4.5/Archiver.php
similarity index 100%
rename from files/plugin-CustomReports-5.4.3/Archiver.php
rename to files/plugin-CustomReports-5.4.5/Archiver.php
diff --git a/files/plugin-CustomReports-5.4.3/Archiver/ExecutionPlan.php b/files/plugin-CustomReports-5.4.5/Archiver/ExecutionPlan.php
similarity index 100%
rename from files/plugin-CustomReports-5.4.3/Archiver/ExecutionPlan.php
rename to files/plugin-CustomReports-5.4.5/Archiver/ExecutionPlan.php
diff --git a/files/plugin-CustomReports-5.4.3/Archiver/NotJoinableException.php b/files/plugin-CustomReports-5.4.5/Archiver/NotJoinableException.php
similarity index 100%
rename from files/plugin-CustomReports-5.4.3/Archiver/NotJoinableException.php
rename to files/plugin-CustomReports-5.4.5/Archiver/NotJoinableException.php
diff --git a/files/plugin-CustomReports-5.4.3/Archiver/QueryBuilder.php b/files/plugin-CustomReports-5.4.5/Archiver/QueryBuilder.php
similarity index 100%
rename from files/plugin-CustomReports-5.4.3/Archiver/QueryBuilder.php
rename to files/plugin-CustomReports-5.4.5/Archiver/QueryBuilder.php
diff --git a/files/plugin-CustomReports-5.4.3/Archiver/ReportQuery.php b/files/plugin-CustomReports-5.4.5/Archiver/ReportQuery.php
similarity index 100%
rename from files/plugin-CustomReports-5.4.3/Archiver/ReportQuery.php
rename to files/plugin-CustomReports-5.4.5/Archiver/ReportQuery.php
diff --git a/files/plugin-CustomReports-5.4.3/CHANGELOG.md b/files/plugin-CustomReports-5.4.5/CHANGELOG.md
similarity index 96%
rename from files/plugin-CustomReports-5.4.3/CHANGELOG.md
rename to files/plugin-CustomReports-5.4.5/CHANGELOG.md
index c88875b..428795f 100644
--- a/files/plugin-CustomReports-5.4.3/CHANGELOG.md
+++ b/files/plugin-CustomReports-5.4.5/CHANGELOG.md
@@ -1,5 +1,12 @@
## Changelog
+5.4.5 - 2025-10-13
+- Added triggering of event when reports are copied
+
+5.4.4 - 2025-09-15
+- Added ability to copy a custom report when Matomo 5.4.0-b4 or later is installed
+- Fixed bug when creating an evolution report which prevented historical archiving of weekly/monthly/yearly data
+
5.4.3 - 2025-07-21
- Stopped filtering empty values for regionCode dimension
diff --git a/files/plugin-CustomReports-5.4.3/Categories/CustomReportsCategory.php b/files/plugin-CustomReports-5.4.5/Categories/CustomReportsCategory.php
similarity index 100%
rename from files/plugin-CustomReports-5.4.3/Categories/CustomReportsCategory.php
rename to files/plugin-CustomReports-5.4.5/Categories/CustomReportsCategory.php
diff --git a/files/plugin-CustomReports-5.4.3/Categories/ManageReportsSubcategory.php b/files/plugin-CustomReports-5.4.5/Categories/ManageReportsSubcategory.php
similarity index 100%
rename from files/plugin-CustomReports-5.4.3/Categories/ManageReportsSubcategory.php
rename to files/plugin-CustomReports-5.4.5/Categories/ManageReportsSubcategory.php
diff --git a/files/plugin-CustomReports-5.4.3/Columns/CustomMetricHelper.php b/files/plugin-CustomReports-5.4.5/Columns/CustomMetricHelper.php
similarity index 100%
rename from files/plugin-CustomReports-5.4.3/Columns/CustomMetricHelper.php
rename to files/plugin-CustomReports-5.4.5/Columns/CustomMetricHelper.php
diff --git a/files/plugin-CustomReports-5.4.3/Columns/ProductCategory.php b/files/plugin-CustomReports-5.4.5/Columns/ProductCategory.php
similarity index 100%
rename from files/plugin-CustomReports-5.4.3/Columns/ProductCategory.php
rename to files/plugin-CustomReports-5.4.5/Columns/ProductCategory.php
diff --git a/files/plugin-CustomReports-5.4.3/Commands/ArchiveReports.php b/files/plugin-CustomReports-5.4.5/Commands/ArchiveReports.php
similarity index 100%
rename from files/plugin-CustomReports-5.4.3/Commands/ArchiveReports.php
rename to files/plugin-CustomReports-5.4.5/Commands/ArchiveReports.php
diff --git a/files/plugin-CustomReports-5.4.3/Commands/GenerateReports.php b/files/plugin-CustomReports-5.4.5/Commands/GenerateReports.php
similarity index 100%
rename from files/plugin-CustomReports-5.4.3/Commands/GenerateReports.php
rename to files/plugin-CustomReports-5.4.5/Commands/GenerateReports.php
diff --git a/files/plugin-CustomReports-5.4.3/Configuration.php b/files/plugin-CustomReports-5.4.5/Configuration.php
similarity index 100%
rename from files/plugin-CustomReports-5.4.3/Configuration.php
rename to files/plugin-CustomReports-5.4.5/Configuration.php
diff --git a/files/plugin-CustomReports-5.4.3/Controller.php b/files/plugin-CustomReports-5.4.5/Controller.php
similarity index 100%
rename from files/plugin-CustomReports-5.4.3/Controller.php
rename to files/plugin-CustomReports-5.4.5/Controller.php
diff --git a/files/plugin-CustomReports-5.4.3/CustomLogAggregator.php b/files/plugin-CustomReports-5.4.5/CustomLogAggregator.php
similarity index 100%
rename from files/plugin-CustomReports-5.4.3/CustomLogAggregator.php
rename to files/plugin-CustomReports-5.4.5/CustomLogAggregator.php
diff --git a/files/plugin-CustomReports-5.4.3/CustomReports.php b/files/plugin-CustomReports-5.4.5/CustomReports.php
similarity index 99%
rename from files/plugin-CustomReports-5.4.3/CustomReports.php
rename to files/plugin-CustomReports-5.4.5/CustomReports.php
index 84aa45d..52c4467 100644
--- a/files/plugin-CustomReports-5.4.3/CustomReports.php
+++ b/files/plugin-CustomReports-5.4.5/CustomReports.php
@@ -5,7 +5,7 @@
* Description: Pull out the information you need in order to be successful. Develop your custom strategy to meet your individualized goals while saving money & time.
* Author: InnoCraft
* Author URI: https://www.innocraft.com
- * Version: 5.4.3
+ * Version: 5.4.5
*/
?> 0) {
+ throw new \Exception(Piwik::translate(
+ 'CustomReports_CustomReportDuplicationSiteTypeError',
+ ['\'' . implode('\', \'', $rollupSiteNames) . '\'']
+ ));
+ }
+ }
+
public static function isAllWebsitesRequest($idSite)
{
return $idSite === 0 || $idSite === '0' || $idSite === 'all' || $idSite === false;
diff --git a/files/plugin-CustomReports-5.4.3/LICENSE b/files/plugin-CustomReports-5.4.5/LICENSE
similarity index 100%
rename from files/plugin-CustomReports-5.4.3/LICENSE
rename to files/plugin-CustomReports-5.4.5/LICENSE
diff --git a/files/plugin-CustomReports-5.4.3/Menu.php b/files/plugin-CustomReports-5.4.5/Menu.php
similarity index 100%
rename from files/plugin-CustomReports-5.4.3/Menu.php
rename to files/plugin-CustomReports-5.4.5/Menu.php
diff --git a/files/plugin-CustomReports-5.4.3/Model/CustomReportsModel.php b/files/plugin-CustomReports-5.4.5/Model/CustomReportsModel.php
similarity index 93%
rename from files/plugin-CustomReports-5.4.3/Model/CustomReportsModel.php
rename to files/plugin-CustomReports-5.4.5/Model/CustomReportsModel.php
index 2b12c39..a2dd827 100644
--- a/files/plugin-CustomReports-5.4.3/Model/CustomReportsModel.php
+++ b/files/plugin-CustomReports-5.4.5/Model/CustomReportsModel.php
@@ -19,12 +19,16 @@
use Piwik\API\Request;
use Piwik\ArchiveProcessor;
use Piwik\Category\CategoryList;
+use Piwik\Columns\MetricsList;
use Piwik\Container\StaticContainer;
use Piwik\DataAccess\ArchiveWriter;
use Piwik\DataAccess\LogAggregator;
use Piwik\Date;
use Piwik\Period;
use Piwik\Piwik;
+use Piwik\Plugin\ArchivedMetric;
+use Piwik\Plugin\Metric;
+use Piwik\Plugin\ProcessedMetric;
use Piwik\Plugins\CustomReports\Configuration;
use Piwik\Plugins\CustomReports\Dao\CustomReportsDao;
use Piwik\Plugins\CustomReports\Input\Category;
@@ -176,9 +180,13 @@ public function getCustomReportById($idCustomReport, $idSite)
/**
* @return array
*/
- public function getAllCustomReportsForSite($idSite, $skipCategoryMetadata = false)
+ public function getAllCustomReportsForSite($idSite, $skipCategoryMetadata = false, $skipEnrich = false)
{
$reports = $this->dao->getCustomReports($idSite);
+ if ($skipEnrich) {
+ return $reports;
+ }
+
return $this->enrichReports($reports, $skipCategoryMetadata);
}
@@ -488,4 +496,42 @@ private function makeArchiveProcessor($idSite, $date = 'today', $period = 'day',
return $processor;
}
+
+ /**
+ * @return Metric[]
+ */
+ public function getArchivableMetricsInReport(array $report): array
+ {
+ $metrics = array();
+
+ if (!empty($report['metrics'])) {
+ foreach ($report['metrics'] as $metric) {
+ $metrics = $this->getMetrics($metrics, $metric);
+ }
+ }
+
+ return $metrics;
+ }
+
+ /**
+ * @return Metric[]
+ */
+ private function getMetrics(array $metricInstances, string $metricName): array
+ {
+ $metricsList = MetricsList::get();
+ $metricInstance = $metricsList->getMetric($metricName);
+
+ if ($metricInstance instanceof ArchivedMetric) {
+ if (!in_array($metricInstance, $metricInstances, $strict = true)) {
+ $metricInstances[] = $metricInstance;
+ }
+ } elseif ($metricInstance instanceof ProcessedMetric) {
+ $depMetrics = $metricInstance->getDependentMetrics();
+ foreach ($depMetrics as $depMetric) {
+ $metricInstances = $this->getMetrics($metricInstances, $depMetric);
+ }
+ }
+
+ return $metricInstances;
+ }
}
diff --git a/files/plugin-CustomReports-5.4.3/README.md b/files/plugin-CustomReports-5.4.5/README.md
similarity index 100%
rename from files/plugin-CustomReports-5.4.3/README.md
rename to files/plugin-CustomReports-5.4.5/README.md
diff --git a/files/plugin-CustomReports-5.4.3/RecordBuilders/CustomReport.php b/files/plugin-CustomReports-5.4.5/RecordBuilders/CustomReport.php
similarity index 95%
rename from files/plugin-CustomReports-5.4.3/RecordBuilders/CustomReport.php
rename to files/plugin-CustomReports-5.4.5/RecordBuilders/CustomReport.php
index 1ce71e2..2f8032f 100644
--- a/files/plugin-CustomReports-5.4.3/RecordBuilders/CustomReport.php
+++ b/files/plugin-CustomReports-5.4.5/RecordBuilders/CustomReport.php
@@ -28,7 +28,6 @@
use Piwik\Log;
use Piwik\Piwik;
use Piwik\Plugin\ArchivedMetric;
-use Piwik\Plugin\ProcessedMetric;
use Piwik\Plugins\CustomDimensions\CustomDimension;
use Piwik\Plugins\CustomReports\Configuration;
use Piwik\Plugins\CustomReports\Archiver;
@@ -384,38 +383,13 @@ private function findNotFoundCustomDimensionManually(string $dimensionId, int $i
}
/**
+ * @deprecated Moved to the model
* @return ArchivedMetric[]
*/
public function getArchivableMetricsInReport(): array
{
- $metrics = array();
-
- $report = $this->report;
- if (!empty($report['metrics'])) {
- foreach ($report['metrics'] as $metric) {
- $metrics = $this->getMetrics($metrics, $metric);
- }
- }
-
- return $metrics;
- }
-
- private function getMetrics(array $metricInstances, string $metricName): array
- {
- $metricInstance = $this->metricsList->getMetric($metricName);
-
- if ($metricInstance && $metricInstance instanceof ArchivedMetric) {
- if (!in_array($metricInstance, $metricInstances, $strict = true)) {
- $metricInstances[] = $metricInstance;
- }
- } elseif ($metricInstance && $metricInstance instanceof ProcessedMetric) {
- $depMetrics = $metricInstance->getDependentMetrics();
- foreach ($depMetrics as $depMetric) {
- $metricInstances = $this->getMetrics($metricInstances, $depMetric);
- }
- }
-
- return $metricInstances;
+ $customReportsModel = StaticContainer::get('Piwik\Plugins\CustomReports\Model\CustomReportsModel');
+ return $customReportsModel->getArchivableMetricsInReport($this->report);
}
private function usesSqlFunction(string $function, string $select): bool
diff --git a/files/plugin-CustomReports-5.4.3/ReportType/Evolution.php b/files/plugin-CustomReports-5.4.5/ReportType/Evolution.php
similarity index 100%
rename from files/plugin-CustomReports-5.4.3/ReportType/Evolution.php
rename to files/plugin-CustomReports-5.4.5/ReportType/Evolution.php
diff --git a/files/plugin-CustomReports-5.4.3/ReportType/ReportType.php b/files/plugin-CustomReports-5.4.5/ReportType/ReportType.php
similarity index 100%
rename from files/plugin-CustomReports-5.4.3/ReportType/ReportType.php
rename to files/plugin-CustomReports-5.4.5/ReportType/ReportType.php
diff --git a/files/plugin-CustomReports-5.4.3/ReportType/Table.php b/files/plugin-CustomReports-5.4.5/ReportType/Table.php
similarity index 100%
rename from files/plugin-CustomReports-5.4.3/ReportType/Table.php
rename to files/plugin-CustomReports-5.4.5/ReportType/Table.php
diff --git a/files/plugin-CustomReports-5.4.3/Updates/5.0.18.php b/files/plugin-CustomReports-5.4.5/Updates/5.0.18.php
similarity index 100%
rename from files/plugin-CustomReports-5.4.3/Updates/5.0.18.php
rename to files/plugin-CustomReports-5.4.5/Updates/5.0.18.php
diff --git a/files/plugin-CustomReports-5.4.3/Updates/5.1.0.php b/files/plugin-CustomReports-5.4.5/Updates/5.1.0.php
similarity index 100%
rename from files/plugin-CustomReports-5.4.3/Updates/5.1.0.php
rename to files/plugin-CustomReports-5.4.5/Updates/5.1.0.php
diff --git a/files/plugin-CustomReports-5.4.3/Updates/5.2.0.php b/files/plugin-CustomReports-5.4.5/Updates/5.2.0.php
similarity index 100%
rename from files/plugin-CustomReports-5.4.3/Updates/5.2.0.php
rename to files/plugin-CustomReports-5.4.5/Updates/5.2.0.php
diff --git a/files/plugin-CustomReports-5.4.3/Updates/5.4.0.php b/files/plugin-CustomReports-5.4.5/Updates/5.4.0.php
similarity index 100%
rename from files/plugin-CustomReports-5.4.3/Updates/5.4.0.php
rename to files/plugin-CustomReports-5.4.5/Updates/5.4.0.php
diff --git a/files/plugin-CustomReports-5.4.3/Updates/5.4.2.php b/files/plugin-CustomReports-5.4.5/Updates/5.4.2.php
similarity index 100%
rename from files/plugin-CustomReports-5.4.3/Updates/5.4.2.php
rename to files/plugin-CustomReports-5.4.5/Updates/5.4.2.php
diff --git a/files/plugin-CustomReports-5.4.3/Widgets/BaseWidget.php b/files/plugin-CustomReports-5.4.5/Widgets/BaseWidget.php
similarity index 100%
rename from files/plugin-CustomReports-5.4.3/Widgets/BaseWidget.php
rename to files/plugin-CustomReports-5.4.5/Widgets/BaseWidget.php
diff --git a/files/plugin-CustomReports-5.4.3/Widgets/GetManageReports.php b/files/plugin-CustomReports-5.4.5/Widgets/GetManageReports.php
similarity index 100%
rename from files/plugin-CustomReports-5.4.3/Widgets/GetManageReports.php
rename to files/plugin-CustomReports-5.4.5/Widgets/GetManageReports.php
diff --git a/files/plugin-CustomReports-5.4.3/config/config.php b/files/plugin-CustomReports-5.4.5/config/config.php
similarity index 100%
rename from files/plugin-CustomReports-5.4.3/config/config.php
rename to files/plugin-CustomReports-5.4.5/config/config.php
diff --git a/files/plugin-CustomReports-5.4.3/docs/index.md b/files/plugin-CustomReports-5.4.5/docs/index.md
similarity index 100%
rename from files/plugin-CustomReports-5.4.3/docs/index.md
rename to files/plugin-CustomReports-5.4.5/docs/index.md
diff --git a/files/plugin-CustomReports-5.4.3/lang/da.json b/files/plugin-CustomReports-5.4.5/lang/am.json
similarity index 100%
rename from files/plugin-CustomReports-5.4.3/lang/da.json
rename to files/plugin-CustomReports-5.4.5/lang/am.json
diff --git a/files/plugin-CustomReports-5.4.3/lang/fi.json b/files/plugin-CustomReports-5.4.5/lang/ar.json
similarity index 100%
rename from files/plugin-CustomReports-5.4.3/lang/fi.json
rename to files/plugin-CustomReports-5.4.5/lang/ar.json
diff --git a/files/plugin-CustomReports-5.4.3/lang/hi.json b/files/plugin-CustomReports-5.4.5/lang/az.json
similarity index 100%
rename from files/plugin-CustomReports-5.4.3/lang/hi.json
rename to files/plugin-CustomReports-5.4.5/lang/az.json
diff --git a/files/plugin-CustomReports-5.4.3/lang/ja.json b/files/plugin-CustomReports-5.4.5/lang/be.json
similarity index 100%
rename from files/plugin-CustomReports-5.4.3/lang/ja.json
rename to files/plugin-CustomReports-5.4.5/lang/be.json
diff --git a/files/plugin-CustomReports-5.4.3/lang/bg.json b/files/plugin-CustomReports-5.4.5/lang/bg.json
similarity index 100%
rename from files/plugin-CustomReports-5.4.3/lang/bg.json
rename to files/plugin-CustomReports-5.4.5/lang/bg.json
diff --git a/files/plugin-CustomReports-5.4.3/lang/nb.json b/files/plugin-CustomReports-5.4.5/lang/bn.json
similarity index 100%
rename from files/plugin-CustomReports-5.4.3/lang/nb.json
rename to files/plugin-CustomReports-5.4.5/lang/bn.json
diff --git a/files/plugin-CustomReports-5.4.3/lang/ru.json b/files/plugin-CustomReports-5.4.5/lang/bs.json
similarity index 100%
rename from files/plugin-CustomReports-5.4.3/lang/ru.json
rename to files/plugin-CustomReports-5.4.5/lang/bs.json
diff --git a/files/plugin-CustomReports-5.4.3/lang/zh-cn.json b/files/plugin-CustomReports-5.4.5/lang/ca.json
similarity index 100%
rename from files/plugin-CustomReports-5.4.3/lang/zh-cn.json
rename to files/plugin-CustomReports-5.4.5/lang/ca.json
diff --git a/files/plugin-CustomReports-5.4.3/lang/cs.json b/files/plugin-CustomReports-5.4.5/lang/cs.json
similarity index 100%
rename from files/plugin-CustomReports-5.4.3/lang/cs.json
rename to files/plugin-CustomReports-5.4.5/lang/cs.json
diff --git a/files/plugin-HeatmapSessionRecording-5.2.4/lang/da.json b/files/plugin-CustomReports-5.4.5/lang/cy.json
similarity index 100%
rename from files/plugin-HeatmapSessionRecording-5.2.4/lang/da.json
rename to files/plugin-CustomReports-5.4.5/lang/cy.json
diff --git a/files/plugin-HeatmapSessionRecording-5.2.6/lang/da.json b/files/plugin-CustomReports-5.4.5/lang/da.json
similarity index 100%
rename from files/plugin-HeatmapSessionRecording-5.2.6/lang/da.json
rename to files/plugin-CustomReports-5.4.5/lang/da.json
diff --git a/files/plugin-CustomReports-5.4.3/lang/de.json b/files/plugin-CustomReports-5.4.5/lang/de.json
similarity index 100%
rename from files/plugin-CustomReports-5.4.3/lang/de.json
rename to files/plugin-CustomReports-5.4.5/lang/de.json
diff --git a/files/plugin-HeatmapSessionRecording-5.2.4/lang/fi.json b/files/plugin-CustomReports-5.4.5/lang/dv.json
similarity index 100%
rename from files/plugin-HeatmapSessionRecording-5.2.4/lang/fi.json
rename to files/plugin-CustomReports-5.4.5/lang/dv.json
diff --git a/files/plugin-HeatmapSessionRecording-5.2.4/lang/hi.json b/files/plugin-CustomReports-5.4.5/lang/el.json
similarity index 100%
rename from files/plugin-HeatmapSessionRecording-5.2.4/lang/hi.json
rename to files/plugin-CustomReports-5.4.5/lang/el.json
diff --git a/files/plugin-CustomReports-5.4.3/lang/en.json b/files/plugin-CustomReports-5.4.5/lang/en.json
similarity index 94%
rename from files/plugin-CustomReports-5.4.3/lang/en.json
rename to files/plugin-CustomReports-5.4.5/lang/en.json
index 431c2a4..05e6e1f 100644
--- a/files/plugin-CustomReports-5.4.3/lang/en.json
+++ b/files/plugin-CustomReports-5.4.5/lang/en.json
@@ -118,6 +118,11 @@
"NoDataMessagePausedStateAdminUser": "This report is paused, no new data will be available until the report is resumed. To resume the report, go to %1$sManage Reports%2$s and click Play for the selected report.",
"NoSegmentationJoinExceptionMessage": "The current order or combination of dimensions is not compatible. %1$sLearn more%2$s.",
"PreviewReportInvalidTimeFrameValues": "Invalid timeframe values set for preview report, allowed values are seconds, minutes, hours and days.",
- "PreviewReportExceedsMaximumTimeFrameValueAllowed": "The maximum time frame for preview report cannot be > 24 hours."
+ "PreviewReportExceedsMaximumTimeFrameValueAllowed": "The maximum time frame for preview report cannot be > 24 hours.",
+ "QuotaReachedForX": "You’ve reached your quota limit. Unable to copy the %1$s due to exceeded usage. Consider deleting unused or less critical %2$s to manage your quota.",
+ "SourceCustomReportLookupError": "There was an unexpected error looking up the source custom report. Please try again. Contact your administrator or support if the problem persists.",
+ "CustomReportDuplicationError": "Process incomplete. The custom report could not be copied to all selected sites.",
+ "CustomReportCopied": "The custom report has been successfully copied.",
+ "CustomReportDuplicationSiteTypeError": "Copy feature is not supported for sites: %1$s."
}
}
diff --git a/files/plugin-HeatmapSessionRecording-5.2.4/lang/ja.json b/files/plugin-CustomReports-5.4.5/lang/eo.json
similarity index 100%
rename from files/plugin-HeatmapSessionRecording-5.2.4/lang/ja.json
rename to files/plugin-CustomReports-5.4.5/lang/eo.json
diff --git a/files/plugin-HeatmapSessionRecording-5.2.4/lang/ru.json b/files/plugin-CustomReports-5.4.5/lang/es-ar.json
similarity index 100%
rename from files/plugin-HeatmapSessionRecording-5.2.4/lang/ru.json
rename to files/plugin-CustomReports-5.4.5/lang/es-ar.json
diff --git a/files/plugin-CustomReports-5.4.3/lang/es.json b/files/plugin-CustomReports-5.4.5/lang/es.json
similarity index 100%
rename from files/plugin-CustomReports-5.4.3/lang/es.json
rename to files/plugin-CustomReports-5.4.5/lang/es.json
diff --git a/files/plugin-HeatmapSessionRecording-5.2.4/lang/zh-cn.json b/files/plugin-CustomReports-5.4.5/lang/et.json
similarity index 100%
rename from files/plugin-HeatmapSessionRecording-5.2.4/lang/zh-cn.json
rename to files/plugin-CustomReports-5.4.5/lang/et.json
diff --git a/files/plugin-HeatmapSessionRecording-5.2.6/lang/fi.json b/files/plugin-CustomReports-5.4.5/lang/eu.json
similarity index 100%
rename from files/plugin-HeatmapSessionRecording-5.2.6/lang/fi.json
rename to files/plugin-CustomReports-5.4.5/lang/eu.json
diff --git a/files/plugin-HeatmapSessionRecording-5.2.6/lang/hi.json b/files/plugin-CustomReports-5.4.5/lang/fa.json
similarity index 100%
rename from files/plugin-HeatmapSessionRecording-5.2.6/lang/hi.json
rename to files/plugin-CustomReports-5.4.5/lang/fa.json
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/lang/fi.json b/files/plugin-CustomReports-5.4.5/lang/fi.json
similarity index 100%
rename from files/plugin-SearchEngineKeywordsPerformance-5.0.22/lang/fi.json
rename to files/plugin-CustomReports-5.4.5/lang/fi.json
diff --git a/files/plugin-CustomReports-5.4.3/lang/fr.json b/files/plugin-CustomReports-5.4.5/lang/fr.json
similarity index 100%
rename from files/plugin-CustomReports-5.4.3/lang/fr.json
rename to files/plugin-CustomReports-5.4.5/lang/fr.json
diff --git a/files/plugin-HeatmapSessionRecording-5.2.6/lang/ja.json b/files/plugin-CustomReports-5.4.5/lang/ga.json
similarity index 100%
rename from files/plugin-HeatmapSessionRecording-5.2.6/lang/ja.json
rename to files/plugin-CustomReports-5.4.5/lang/ga.json
diff --git a/files/plugin-HeatmapSessionRecording-5.2.6/lang/ru.json b/files/plugin-CustomReports-5.4.5/lang/gl.json
similarity index 100%
rename from files/plugin-HeatmapSessionRecording-5.2.6/lang/ru.json
rename to files/plugin-CustomReports-5.4.5/lang/gl.json
diff --git a/files/plugin-HeatmapSessionRecording-5.2.6/lang/zh-cn.json b/files/plugin-CustomReports-5.4.5/lang/gu.json
similarity index 100%
rename from files/plugin-HeatmapSessionRecording-5.2.6/lang/zh-cn.json
rename to files/plugin-CustomReports-5.4.5/lang/gu.json
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/lang/cs.json b/files/plugin-CustomReports-5.4.5/lang/he.json
similarity index 100%
rename from files/plugin-SearchEngineKeywordsPerformance-5.0.22/lang/cs.json
rename to files/plugin-CustomReports-5.4.5/lang/he.json
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/lang/hi.json b/files/plugin-CustomReports-5.4.5/lang/hi.json
similarity index 100%
rename from files/plugin-SearchEngineKeywordsPerformance-5.0.22/lang/hi.json
rename to files/plugin-CustomReports-5.4.5/lang/hi.json
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/lang/da.json b/files/plugin-CustomReports-5.4.5/lang/hr.json
similarity index 100%
rename from files/plugin-SearchEngineKeywordsPerformance-5.0.22/lang/da.json
rename to files/plugin-CustomReports-5.4.5/lang/hr.json
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/lang/ja.json b/files/plugin-CustomReports-5.4.5/lang/hu.json
similarity index 100%
rename from files/plugin-SearchEngineKeywordsPerformance-5.0.22/lang/ja.json
rename to files/plugin-CustomReports-5.4.5/lang/hu.json
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/lang/nb.json b/files/plugin-CustomReports-5.4.5/lang/hy.json
similarity index 100%
rename from files/plugin-SearchEngineKeywordsPerformance-5.0.22/lang/nb.json
rename to files/plugin-CustomReports-5.4.5/lang/hy.json
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/lang/ro.json b/files/plugin-CustomReports-5.4.5/lang/id.json
similarity index 100%
rename from files/plugin-SearchEngineKeywordsPerformance-5.0.22/lang/ro.json
rename to files/plugin-CustomReports-5.4.5/lang/id.json
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/lang/uk.json b/files/plugin-CustomReports-5.4.5/lang/is.json
similarity index 100%
rename from files/plugin-SearchEngineKeywordsPerformance-5.0.22/lang/uk.json
rename to files/plugin-CustomReports-5.4.5/lang/is.json
diff --git a/files/plugin-CustomReports-5.4.3/lang/it.json b/files/plugin-CustomReports-5.4.5/lang/it.json
similarity index 100%
rename from files/plugin-CustomReports-5.4.3/lang/it.json
rename to files/plugin-CustomReports-5.4.5/lang/it.json
diff --git a/files/plugin-UsersFlow-5.0.5/lang/ja.json b/files/plugin-CustomReports-5.4.5/lang/ja.json
similarity index 100%
rename from files/plugin-UsersFlow-5.0.5/lang/ja.json
rename to files/plugin-CustomReports-5.4.5/lang/ja.json
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/lang/zh-cn.json b/files/plugin-CustomReports-5.4.5/lang/ka.json
similarity index 100%
rename from files/plugin-SearchEngineKeywordsPerformance-5.0.22/lang/zh-cn.json
rename to files/plugin-CustomReports-5.4.5/lang/ka.json
diff --git a/files/plugin-UsersFlow-5.0.5/lang/da.json b/files/plugin-CustomReports-5.4.5/lang/ko.json
similarity index 100%
rename from files/plugin-UsersFlow-5.0.5/lang/da.json
rename to files/plugin-CustomReports-5.4.5/lang/ko.json
diff --git a/files/plugin-UsersFlow-5.0.5/lang/fi.json b/files/plugin-CustomReports-5.4.5/lang/ku.json
similarity index 100%
rename from files/plugin-UsersFlow-5.0.5/lang/fi.json
rename to files/plugin-CustomReports-5.4.5/lang/ku.json
diff --git a/files/plugin-UsersFlow-5.0.5/lang/hi.json b/files/plugin-CustomReports-5.4.5/lang/lb.json
similarity index 100%
rename from files/plugin-UsersFlow-5.0.5/lang/hi.json
rename to files/plugin-CustomReports-5.4.5/lang/lb.json
diff --git a/files/plugin-UsersFlow-5.0.5/lang/nb.json b/files/plugin-CustomReports-5.4.5/lang/lt.json
similarity index 100%
rename from files/plugin-UsersFlow-5.0.5/lang/nb.json
rename to files/plugin-CustomReports-5.4.5/lang/lt.json
diff --git a/files/plugin-UsersFlow-5.0.5/lang/ru.json b/files/plugin-CustomReports-5.4.5/lang/lv.json
similarity index 100%
rename from files/plugin-UsersFlow-5.0.5/lang/ru.json
rename to files/plugin-CustomReports-5.4.5/lang/lv.json
diff --git a/files/plugin-UsersFlow-5.0.5/lang/zh-cn.json b/files/plugin-CustomReports-5.4.5/lang/ms.json
similarity index 100%
rename from files/plugin-UsersFlow-5.0.5/lang/zh-cn.json
rename to files/plugin-CustomReports-5.4.5/lang/ms.json
diff --git a/files/plugin-CustomReports-5.4.5/lang/nb.json b/files/plugin-CustomReports-5.4.5/lang/nb.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/files/plugin-CustomReports-5.4.5/lang/nb.json
@@ -0,0 +1 @@
+{}
diff --git a/files/plugin-CustomReports-5.4.3/lang/nl.json b/files/plugin-CustomReports-5.4.5/lang/nl.json
similarity index 100%
rename from files/plugin-CustomReports-5.4.3/lang/nl.json
rename to files/plugin-CustomReports-5.4.5/lang/nl.json
diff --git a/files/plugin-CustomReports-5.4.5/lang/nn.json b/files/plugin-CustomReports-5.4.5/lang/nn.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/files/plugin-CustomReports-5.4.5/lang/nn.json
@@ -0,0 +1 @@
+{}
diff --git a/files/plugin-CustomReports-5.4.3/lang/pl.json b/files/plugin-CustomReports-5.4.5/lang/pl.json
similarity index 100%
rename from files/plugin-CustomReports-5.4.3/lang/pl.json
rename to files/plugin-CustomReports-5.4.5/lang/pl.json
diff --git a/files/plugin-CustomReports-5.4.5/lang/pt-br.json b/files/plugin-CustomReports-5.4.5/lang/pt-br.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/files/plugin-CustomReports-5.4.5/lang/pt-br.json
@@ -0,0 +1 @@
+{}
diff --git a/files/plugin-CustomReports-5.4.3/lang/pt.json b/files/plugin-CustomReports-5.4.5/lang/pt.json
similarity index 100%
rename from files/plugin-CustomReports-5.4.3/lang/pt.json
rename to files/plugin-CustomReports-5.4.5/lang/pt.json
diff --git a/files/plugin-CustomReports-5.4.3/lang/ro.json b/files/plugin-CustomReports-5.4.5/lang/ro.json
similarity index 100%
rename from files/plugin-CustomReports-5.4.3/lang/ro.json
rename to files/plugin-CustomReports-5.4.5/lang/ro.json
diff --git a/files/plugin-CustomReports-5.4.5/lang/ru.json b/files/plugin-CustomReports-5.4.5/lang/ru.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/files/plugin-CustomReports-5.4.5/lang/ru.json
@@ -0,0 +1 @@
+{}
diff --git a/files/plugin-CustomReports-5.4.5/lang/si.json b/files/plugin-CustomReports-5.4.5/lang/si.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/files/plugin-CustomReports-5.4.5/lang/si.json
@@ -0,0 +1 @@
+{}
diff --git a/files/plugin-CustomReports-5.4.5/lang/sk.json b/files/plugin-CustomReports-5.4.5/lang/sk.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/files/plugin-CustomReports-5.4.5/lang/sk.json
@@ -0,0 +1 @@
+{}
diff --git a/files/plugin-CustomReports-5.4.5/lang/sl.json b/files/plugin-CustomReports-5.4.5/lang/sl.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/files/plugin-CustomReports-5.4.5/lang/sl.json
@@ -0,0 +1 @@
+{}
diff --git a/files/plugin-CustomReports-5.4.3/lang/sq.json b/files/plugin-CustomReports-5.4.5/lang/sq.json
similarity index 95%
rename from files/plugin-CustomReports-5.4.3/lang/sq.json
rename to files/plugin-CustomReports-5.4.5/lang/sq.json
index aa65248..d732b34 100644
--- a/files/plugin-CustomReports-5.4.3/lang/sq.json
+++ b/files/plugin-CustomReports-5.4.5/lang/sq.json
@@ -17,6 +17,9 @@
"ContentImpressions": "Përshtypje Nga Lënda",
"CreateNewReport": "Krijoni raport të ri",
"CustomReport": "Raport Vetjak",
+ "CustomReportCopied": "Raporti vetjak u kopjua me sukses.",
+ "CustomReportDuplicationError": "Proces i paplotësuar. Raporti vetjak s’u kopjua dot te krejt sajtet e përzgjedhur.",
+ "CustomReportDuplicationSiteTypeError": "Veçoria e kopjimit nuk mbulohet për sajtet: %1$s.",
"CustomReportIntroduction": "Raportet Vetjakë ju lejojnë të krijoni raporte të rinj për të ndjekur prirje të reja që s’janë të mundshme me raportet standarde. Përmasat (të tilla si, “Lloj Pajisjeje” dhe “Shfletues”), matjet (të tilla si, “Numër Vizitorësh” dhe “Nivel Kthimesh”) dhe se si duhet të shfaqen për të pasur të dhënat unike të përdorshme dhe të dobishme që ju nevojiten, i zgjidhni ju.",
"CustomReports": "Raporte Vetjakë",
"DeleteExceptionMessage": "S’fshihet dot raporti, sajti s’përputhet",
@@ -77,6 +80,7 @@
"PreviewReportInvalidTimeFrameValues": "Për paraparje raporti janë vënë vlera të pavlefshme intervalesh kohorë, vlerat e lejuara janë sekonda, minuta, orë dhe ditë.",
"PreviewSupportsDimension": "Hëpërhë paraparja mbulon deri në %s përmasa.",
"ProductsWithX": "Produkte me %s",
+ "QuotaReachedForX": "Keni mbërritur në kufirin e kuotës tuaj. S’arrihet të kopjohet %1$s, për shkak tejkalimi përdorimi. Që të administroni kuotën tuaj, shihni mundësinë e fshirjes së %2$s të papërdorur, ose më pak kritike.",
"RemoveDimension": "Hiqe përmasën",
"RemoveMetric": "Hiqe matjen",
"RemovedMetrics": "Këto vlera u hoqën, ngaqë s’mund të përllogariten saktë për këtë periudhë: %s.",
@@ -108,7 +112,7 @@
"ResumeReportConfirm": "Kur rinisni këtë raport, arkivimi do të rinisë nga sot. Jeni i sigurt se doni të riniset ky raport vetjak?",
"ResumeReportInfo": "Kur rinisni këtë raport, arkivimi do të rifillojë nga sot.",
"ResumedReport": "Raporti u rinis me sukses.",
- "SelectMeasurablesMatchingSearch": "ose shtoni krejt gjërat e matshme që përmbajnë termin vijues të kërkimit",
+ "SourceCustomReportLookupError": "Pati një gabim të papritur me kërkimin e raportit vetjak burim. Ju lutemi, riprovoni. Nëse problemi vazhdon, lidhuni me përgjegjësin tuaj, ose me asistencën.",
"Type": "Lloj",
"Unlock": "Shkyçe",
"UpdatingData": "Po përditësohen të dhëna…",
diff --git a/files/plugin-CustomReports-5.4.5/lang/sr.json b/files/plugin-CustomReports-5.4.5/lang/sr.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/files/plugin-CustomReports-5.4.5/lang/sr.json
@@ -0,0 +1 @@
+{}
diff --git a/files/plugin-CustomReports-5.4.3/lang/sv.json b/files/plugin-CustomReports-5.4.5/lang/sv.json
similarity index 100%
rename from files/plugin-CustomReports-5.4.3/lang/sv.json
rename to files/plugin-CustomReports-5.4.5/lang/sv.json
diff --git a/files/plugin-CustomReports-5.4.5/lang/ta.json b/files/plugin-CustomReports-5.4.5/lang/ta.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/files/plugin-CustomReports-5.4.5/lang/ta.json
@@ -0,0 +1 @@
+{}
diff --git a/files/plugin-CustomReports-5.4.5/lang/te.json b/files/plugin-CustomReports-5.4.5/lang/te.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/files/plugin-CustomReports-5.4.5/lang/te.json
@@ -0,0 +1 @@
+{}
diff --git a/files/plugin-CustomReports-5.4.5/lang/th.json b/files/plugin-CustomReports-5.4.5/lang/th.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/files/plugin-CustomReports-5.4.5/lang/th.json
@@ -0,0 +1 @@
+{}
diff --git a/files/plugin-CustomReports-5.4.5/lang/tl.json b/files/plugin-CustomReports-5.4.5/lang/tl.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/files/plugin-CustomReports-5.4.5/lang/tl.json
@@ -0,0 +1 @@
+{}
diff --git a/files/plugin-CustomReports-5.4.3/lang/tr.json b/files/plugin-CustomReports-5.4.5/lang/tr.json
similarity index 95%
rename from files/plugin-CustomReports-5.4.3/lang/tr.json
rename to files/plugin-CustomReports-5.4.5/lang/tr.json
index bd40f4b..2a7b952 100644
--- a/files/plugin-CustomReports-5.4.3/lang/tr.json
+++ b/files/plugin-CustomReports-5.4.5/lang/tr.json
@@ -17,6 +17,9 @@
"ContentImpressions": "İçerik gösterimleri",
"CreateNewReport": "Yeni rapor ekle",
"CustomReport": "Özel rapor",
+ "CustomReportCopied": "Özel rapor kopyalandı.",
+ "CustomReportDuplicationError": "İşlem tamamlanmadı. Özel rapor seçilmiş tüm sitelere kopyalanamadı.",
+ "CustomReportDuplicationSiteTypeError": "Kopyalama özelliği sitelerde desteklenmiyor: %1$s.",
"CustomReportIntroduction": "Özel raporlar, standart raporlarda bulunmayan yeni bakış açıları oluşturmanızı sağlar. Boyutları (\"Aygıt türü\" ve \"Tarayıcı\" gibi) ve ölçümleri (\"Ziyaretçi sayısı\" ve \"Geri dönüş oranı\" gibi) ve nasıl görüneceğini seçerek eşsiz ve işinize yarayacak veriler elde edebilirsiniz.",
"CustomReports": "Özel raporlar",
"DeleteExceptionMessage": "Rapor silinemedi. Site eşleşmiyor",
@@ -77,6 +80,7 @@
"PreviewReportInvalidTimeFrameValues": "Rapor ön izlemesi için ayarlanmış zaman aralığı değerleri geçersiz. Saniye, dakika, saat ve gün değerlerine izin verilir.",
"PreviewSupportsDimension": "Ön izlemede en çok %s boyut görüntülenebilir.",
"ProductsWithX": "%s ile ürünler",
+ "QuotaReachedForX": "Kota sınırınıza ulaştınız. Kullanım aşımı nedeniyle %1$s kopyalanamıyor. Kotanızı yönetmek için kullanılmayan veya daha az önemli %2$s ögesini silmeyi değerlendirin.",
"RemoveDimension": "Boyutu kaldır",
"RemoveMetric": "Ölçümü kaldır",
"RemovedMetrics": "%s aralığı için doğru hesaplanamadığından bu ölçümler çıkarıldı.",
@@ -109,6 +113,7 @@
"ResumeReportInfo": "Bu raporu sürdürdüğünüzde, arşivleme bugünden itibaren yeniden başlar.",
"ResumedReport": "Rapor sürdürüldü.",
"SelectMeasurablesMatchingSearch": "ya da şu ifadeyi içeren tüm ölçülebilirleri ekleyin",
+ "SourceCustomReportLookupError": "Kaynak özel raporuna bakılırken beklenmeyen bir sorun çıktı. Lütfen yeniden deneyin. Sorun sürerse yöneticinizle veya destek ekibinizle görüşün.",
"Type": "Tür",
"Unlock": "Kilidi aç",
"UpdatingData": "Veriler güncelleniyor…",
diff --git a/files/plugin-CustomReports-5.4.5/lang/tzm.json b/files/plugin-CustomReports-5.4.5/lang/tzm.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/files/plugin-CustomReports-5.4.5/lang/tzm.json
@@ -0,0 +1 @@
+{}
diff --git a/files/plugin-CustomReports-5.4.3/lang/uk.json b/files/plugin-CustomReports-5.4.5/lang/uk.json
similarity index 100%
rename from files/plugin-CustomReports-5.4.3/lang/uk.json
rename to files/plugin-CustomReports-5.4.5/lang/uk.json
diff --git a/files/plugin-CustomReports-5.4.5/lang/ur.json b/files/plugin-CustomReports-5.4.5/lang/ur.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/files/plugin-CustomReports-5.4.5/lang/ur.json
@@ -0,0 +1 @@
+{}
diff --git a/files/plugin-CustomReports-5.4.5/lang/vi.json b/files/plugin-CustomReports-5.4.5/lang/vi.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/files/plugin-CustomReports-5.4.5/lang/vi.json
@@ -0,0 +1 @@
+{}
diff --git a/files/plugin-CustomReports-5.4.5/lang/zh-cn.json b/files/plugin-CustomReports-5.4.5/lang/zh-cn.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/files/plugin-CustomReports-5.4.5/lang/zh-cn.json
@@ -0,0 +1 @@
+{}
diff --git a/files/plugin-CustomReports-5.4.3/lang/zh-tw.json b/files/plugin-CustomReports-5.4.5/lang/zh-tw.json
similarity index 100%
rename from files/plugin-CustomReports-5.4.3/lang/zh-tw.json
rename to files/plugin-CustomReports-5.4.5/lang/zh-tw.json
diff --git a/files/plugin-CustomReports-5.4.3/phpcs.xml b/files/plugin-CustomReports-5.4.5/phpcs.xml
similarity index 100%
rename from files/plugin-CustomReports-5.4.3/phpcs.xml
rename to files/plugin-CustomReports-5.4.5/phpcs.xml
diff --git a/files/plugin-CustomReports-5.4.3/phpstan.neon b/files/plugin-CustomReports-5.4.5/phpstan.neon
similarity index 54%
rename from files/plugin-CustomReports-5.4.3/phpstan.neon
rename to files/plugin-CustomReports-5.4.5/phpstan.neon
index c3fa656..8ec3d36 100644
--- a/files/plugin-CustomReports-5.4.3/phpstan.neon
+++ b/files/plugin-CustomReports-5.4.5/phpstan.neon
@@ -1,6 +1,7 @@
parameters:
level: 0
phpVersion: 70200
+ tmpDir: /tmp/phpstan/CustomReports/main
paths:
- .
excludePaths:
@@ -12,4 +13,7 @@ parameters:
- Piwik\View
- Piwik\ViewDataTable\Config
scanDirectories:
- - ../../plugins/
+ # ../../ does not actually seem to give us anything
+ # that ../plugins/ does not, but including it for
+ # completeness. It does not seem to slow down performance.
+ - ../../
diff --git a/files/plugin-CustomReports-5.4.5/phpstan/phpstan.created.neon b/files/plugin-CustomReports-5.4.5/phpstan/phpstan.created.neon
new file mode 100644
index 0000000..084eb8d
--- /dev/null
+++ b/files/plugin-CustomReports-5.4.5/phpstan/phpstan.created.neon
@@ -0,0 +1,5 @@
+includes:
+ - ../phpstan.neon
+parameters:
+ level: 9
+ tmpDir: /tmp/phpstan/CustomReports/created
diff --git a/files/plugin-CustomReports-5.4.5/phpstan/phpstan.modified.neon b/files/plugin-CustomReports-5.4.5/phpstan/phpstan.modified.neon
new file mode 100644
index 0000000..ac4783d
--- /dev/null
+++ b/files/plugin-CustomReports-5.4.5/phpstan/phpstan.modified.neon
@@ -0,0 +1,5 @@
+includes:
+ - ../phpstan.neon
+parameters:
+ level: 1
+ tmpDir: /tmp/phpstan/CustomReports/modified
diff --git a/files/plugin-CustomReports-5.4.3/plugin.json b/files/plugin-CustomReports-5.4.5/plugin.json
similarity index 97%
rename from files/plugin-CustomReports-5.4.3/plugin.json
rename to files/plugin-CustomReports-5.4.5/plugin.json
index 910ca83..1383377 100644
--- a/files/plugin-CustomReports-5.4.3/plugin.json
+++ b/files/plugin-CustomReports-5.4.5/plugin.json
@@ -1,7 +1,7 @@
{
"name": "CustomReports",
"description": "Pull out the information you need in order to be successful. Develop your custom strategy to meet your individualized goals while saving money & time.",
- "version": "5.4.3",
+ "version": "5.4.5",
"theme": false,
"require": {
"matomo": ">=5.0.0-rc5,<6.0.0-b1"
diff --git a/files/plugin-CustomReports-5.4.3/pull_request_template.md b/files/plugin-CustomReports-5.4.5/pull_request_template.md
similarity index 100%
rename from files/plugin-CustomReports-5.4.3/pull_request_template.md
rename to files/plugin-CustomReports-5.4.5/pull_request_template.md
diff --git a/files/plugin-CustomReports-5.4.3/templates/manage.twig b/files/plugin-CustomReports-5.4.5/templates/manage.twig
similarity index 100%
rename from files/plugin-CustomReports-5.4.3/templates/manage.twig
rename to files/plugin-CustomReports-5.4.5/templates/manage.twig
diff --git a/files/plugin-CustomReports-5.4.3/vue/dist/CustomReports.umd.js b/files/plugin-CustomReports-5.4.5/vue/dist/CustomReports.umd.js
similarity index 56%
rename from files/plugin-CustomReports-5.4.3/vue/dist/CustomReports.umd.js
rename to files/plugin-CustomReports-5.4.5/vue/dist/CustomReports.umd.js
index 04a71bb..640ceae 100644
--- a/files/plugin-CustomReports-5.4.3/vue/dist/CustomReports.umd.js
+++ b/files/plugin-CustomReports-5.4.5/vue/dist/CustomReports.umd.js
@@ -155,338 +155,309 @@ if (typeof window !== 'undefined') {
// EXTERNAL MODULE: external {"commonjs":"vue","commonjs2":"vue","root":"Vue"}
var external_commonjs_vue_commonjs2_vue_root_Vue_ = __webpack_require__("8bbf");
-// CONCATENATED MODULE: ./node_modules/@vue/cli-plugin-babel/node_modules/cache-loader/dist/cjs.js??ref--12-0!./node_modules/@vue/cli-plugin-babel/node_modules/thread-loader/dist/cjs.js!./node_modules/babel-loader/lib!./node_modules/@vue/cli-service/node_modules/vue-loader-v16/dist/templateLoader.js??ref--6!./node_modules/@vue/cli-service/node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/@vue/cli-service/node_modules/vue-loader-v16/dist??ref--0-1!./plugins/CustomReports/vue/src/Reports/Edit.vue?vue&type=template&id=769922f2
+// CONCATENATED MODULE: ./node_modules/@vue/cli-plugin-babel/node_modules/cache-loader/dist/cjs.js??ref--13-0!./node_modules/@vue/cli-plugin-babel/node_modules/thread-loader/dist/cjs.js!./node_modules/babel-loader/lib!./node_modules/@vue/cli-service/node_modules/vue-loader-v16/dist/templateLoader.js??ref--6!./node_modules/@vue/cli-service/node_modules/cache-loader/dist/cjs.js??ref--1-0!./node_modules/@vue/cli-service/node_modules/vue-loader-v16/dist??ref--1-1!./plugins/CustomReports/vue/src/Reports/Edit.vue?vue&type=template&id=769922f2
-var _hoisted_1 = {
+const _hoisted_1 = {
class: "loadingPiwik"
};
-
-var _hoisted_2 = /*#__PURE__*/Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("img", {
+const _hoisted_2 = /*#__PURE__*/Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("img", {
src: "plugins/Morpheus/images/loading-blue.gif"
}, null, -1);
-
-var _hoisted_3 = {
+const _hoisted_3 = {
class: "loadingPiwik"
};
-
-var _hoisted_4 = /*#__PURE__*/Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("img", {
+const _hoisted_4 = /*#__PURE__*/Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("img", {
src: "plugins/Morpheus/images/loading-blue.gif"
}, null, -1);
-
-var _hoisted_5 = {
+const _hoisted_5 = {
class: "alert alert-warning"
};
-var _hoisted_6 = {
+const _hoisted_6 = {
key: 0
};
-var _hoisted_7 = {
+const _hoisted_7 = {
key: 1
};
-var _hoisted_8 = {
+const _hoisted_8 = {
key: 0,
class: "alert alert-warning"
};
-var _hoisted_9 = ["innerHTML"];
-var _hoisted_10 = {
+const _hoisted_9 = ["innerHTML"];
+const _hoisted_10 = {
key: 1
};
-var _hoisted_11 = {
+const _hoisted_11 = {
name: "name"
};
-var _hoisted_12 = {
+const _hoisted_12 = {
name: "description"
};
-var _hoisted_13 = {
+const _hoisted_13 = {
class: "form-group row"
};
-var _hoisted_14 = {
+const _hoisted_14 = {
class: "col s12"
};
-var _hoisted_15 = {
+const _hoisted_15 = {
class: "col s12 m6"
};
-var _hoisted_16 = {
+const _hoisted_16 = {
for: "all_websites",
class: "siteSelectorLabel"
};
-var _hoisted_17 = {
+const _hoisted_17 = {
class: "sites_autocomplete"
};
-var _hoisted_18 = {
+const _hoisted_18 = {
class: "col s12 m6"
};
-var _hoisted_19 = {
+const _hoisted_19 = {
class: "form-help"
};
-var _hoisted_20 = {
+const _hoisted_20 = {
key: 0,
class: "inline-help"
};
-var _hoisted_21 = {
+const _hoisted_21 = {
key: 1,
class: "inline-help"
};
-var _hoisted_22 = {
+const _hoisted_22 = {
key: 0,
class: "col s12 m6"
};
-var _hoisted_23 = {
+const _hoisted_23 = {
key: 0
};
-var _hoisted_24 = {
+const _hoisted_24 = {
for: "websitecontains"
};
-
-var _hoisted_25 = /*#__PURE__*/Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("br", null, null, -1);
-
-var _hoisted_26 = ["placeholder"];
-var _hoisted_27 = ["disabled", "value"];
-var _hoisted_28 = {
+const _hoisted_25 = /*#__PURE__*/Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("br", null, null, -1);
+const _hoisted_26 = ["placeholder"];
+const _hoisted_27 = ["disabled", "value"];
+const _hoisted_28 = {
key: 1
};
-
-var _hoisted_29 = /*#__PURE__*/Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("br", null, null, -1);
-
-var _hoisted_30 = {
+const _hoisted_29 = /*#__PURE__*/Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("br", null, null, -1);
+const _hoisted_30 = {
class: "entityTable"
};
-var _hoisted_31 = {
+const _hoisted_31 = {
class: "siteId"
};
-var _hoisted_32 = {
+const _hoisted_32 = {
class: "siteName"
};
-var _hoisted_33 = {
+const _hoisted_33 = {
key: 0,
class: "siteAction"
};
-var _hoisted_34 = {
+const _hoisted_34 = {
colspan: "3"
};
-var _hoisted_35 = {
+const _hoisted_35 = {
key: 0,
class: "siteAction"
};
-var _hoisted_36 = ["onClick"];
-var _hoisted_37 = {
+const _hoisted_36 = ["onClick"];
+const _hoisted_37 = {
class: "form-group row"
};
-var _hoisted_38 = {
+const _hoisted_38 = {
class: "col s12"
};
-var _hoisted_39 = {
+const _hoisted_39 = {
class: "unlockAlert alert alert-info"
};
-var _hoisted_40 = {
+const _hoisted_40 = {
key: 0
};
-var _hoisted_41 = {
+const _hoisted_41 = {
key: 1
};
-
-var _hoisted_42 = /*#__PURE__*/Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("br", null, null, -1);
-
-var _hoisted_43 = /*#__PURE__*/Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("br", null, null, -1);
-
-var _hoisted_44 = ["value"];
-var _hoisted_45 = {
+const _hoisted_42 = /*#__PURE__*/Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("br", null, null, -1);
+const _hoisted_43 = /*#__PURE__*/Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("br", null, null, -1);
+const _hoisted_44 = ["value"];
+const _hoisted_45 = {
class: "alertUnlocked alert alert-warning"
};
-var _hoisted_46 = {
+const _hoisted_46 = {
key: 0
};
-var _hoisted_47 = {
+const _hoisted_47 = {
key: 1
};
-var _hoisted_48 = {
+const _hoisted_48 = {
name: "reportType"
};
-var _hoisted_49 = {
+const _hoisted_49 = {
class: "form-group row"
};
-var _hoisted_50 = {
+const _hoisted_50 = {
class: "col s12 m6 dimensionsGroup"
};
-
-var _hoisted_51 = /*#__PURE__*/Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("br", null, null, -1);
-
-var _hoisted_52 = {
+const _hoisted_51 = /*#__PURE__*/Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("br", null, null, -1);
+const _hoisted_52 = {
class: "groupValueSelect",
name: "dimensions"
};
-var _hoisted_53 = ["title", "onClick"];
-var _hoisted_54 = {
+const _hoisted_53 = ["title", "onClick"];
+const _hoisted_54 = {
class: "groupValueSelect addDimension",
name: "dimensions"
};
-var _hoisted_55 = {
+const _hoisted_55 = {
class: "col s12 m6"
};
-var _hoisted_56 = {
+const _hoisted_56 = {
class: "form-help"
};
-var _hoisted_57 = ["innerHTML"];
-var _hoisted_58 = {
+const _hoisted_57 = ["innerHTML"];
+const _hoisted_58 = {
class: "form-group row"
};
-var _hoisted_59 = {
+const _hoisted_59 = {
class: "col s12 m6 metricsGroup"
};
-
-var _hoisted_60 = /*#__PURE__*/Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("br", null, null, -1);
-
-var _hoisted_61 = {
+const _hoisted_60 = /*#__PURE__*/Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("br", null, null, -1);
+const _hoisted_61 = {
class: "groupValueSelect",
name: "metrics"
};
-var _hoisted_62 = ["title", "onClick"];
-var _hoisted_63 = {
+const _hoisted_62 = ["title", "onClick"];
+const _hoisted_63 = {
class: "groupValueSelect addMetric",
name: "metrics"
};
-var _hoisted_64 = {
+const _hoisted_64 = {
class: "col s12 m6"
};
-var _hoisted_65 = {
+const _hoisted_65 = {
class: "form-help"
};
-var _hoisted_66 = {
+const _hoisted_66 = {
class: "inline-help"
};
-var _hoisted_67 = ["innerHTML"];
-var _hoisted_68 = {
+const _hoisted_67 = ["innerHTML"];
+const _hoisted_68 = {
class: "form-group row segmentFilterGroup"
};
-var _hoisted_69 = {
+const _hoisted_69 = {
class: "col s12"
};
-var _hoisted_70 = {
+const _hoisted_70 = {
style: {
"margin": "8px 0",
"display": "inline-block"
}
};
-var _hoisted_71 = {
+const _hoisted_71 = {
class: "form-group row"
};
-var _hoisted_72 = {
+const _hoisted_72 = {
class: "col s12"
};
-
-var _hoisted_73 = /*#__PURE__*/Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("br", null, null, -1);
-
-var _hoisted_74 = /*#__PURE__*/Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("br", null, null, -1);
-
-var _hoisted_75 = {
+const _hoisted_73 = /*#__PURE__*/Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("br", null, null, -1);
+const _hoisted_74 = /*#__PURE__*/Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("br", null, null, -1);
+const _hoisted_75 = {
name: "reportCategories"
};
-var _hoisted_76 = {
+const _hoisted_76 = {
name: "reportSubcategories"
};
-var _hoisted_77 = {
+const _hoisted_77 = {
class: "alert alert-warning"
};
-var _hoisted_78 = {
+const _hoisted_78 = {
key: 0
};
-var _hoisted_79 = {
+const _hoisted_79 = {
key: 1
};
-var _hoisted_80 = {
+const _hoisted_80 = {
class: "alert alert-warning"
};
-var _hoisted_81 = {
+const _hoisted_81 = {
key: 0
};
-var _hoisted_82 = {
+const _hoisted_82 = {
key: 1
};
-var _hoisted_83 = {
+const _hoisted_83 = {
key: 0,
class: "form-group row"
};
-var _hoisted_84 = ["textContent"];
-var _hoisted_85 = {
+const _hoisted_84 = ["textContent"];
+const _hoisted_85 = {
class: "col s12 m6"
};
-var _hoisted_86 = {
+const _hoisted_86 = {
id: "childReports",
class: "col s12 m6"
};
-var _hoisted_87 = ["data-id"];
-
-var _hoisted_88 = /*#__PURE__*/Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("span", {
+const _hoisted_87 = ["data-id"];
+const _hoisted_88 = /*#__PURE__*/Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("span", {
class: "ui-icon ui-icon-arrowthick-2-n-s"
}, null, -1);
-
-var _hoisted_89 = {
+const _hoisted_89 = {
class: "col s12 m6"
};
-var _hoisted_90 = {
+const _hoisted_90 = {
class: "form-help"
};
-var _hoisted_91 = ["textContent"];
-var _hoisted_92 = {
+const _hoisted_91 = ["textContent"];
+const _hoisted_92 = {
class: "entityCancel"
};
-var _hoisted_93 = {
+const _hoisted_93 = {
class: "ui-confirm",
id: "confirmUnlockReport",
ref: "confirmUnlockReport"
};
-var _hoisted_94 = {
+const _hoisted_94 = {
key: 0
};
-var _hoisted_95 = {
+const _hoisted_95 = {
key: 1
};
-var _hoisted_96 = ["value"];
-var _hoisted_97 = ["value"];
-var _hoisted_98 = {
+const _hoisted_96 = ["value"];
+const _hoisted_97 = ["value"];
+const _hoisted_98 = {
class: "ui-confirm",
id: "infoReportIsLocked",
ref: "infoReportIsLocked"
};
-var _hoisted_99 = {
+const _hoisted_99 = {
key: 0
};
-var _hoisted_100 = {
+const _hoisted_100 = {
key: 1
};
-var _hoisted_101 = ["value"];
-var _hoisted_102 = ["value"];
+const _hoisted_101 = ["value"];
+const _hoisted_102 = ["value"];
function render(_ctx, _cache, $props, $setup, $data, $options) {
- var _component_Field = Object(external_commonjs_vue_commonjs2_vue_root_Vue_["resolveComponent"])("Field");
-
- var _component_SiteSelector = Object(external_commonjs_vue_commonjs2_vue_root_Vue_["resolveComponent"])("SiteSelector");
-
- var _component_SegmentGenerator = Object(external_commonjs_vue_commonjs2_vue_root_Vue_["resolveComponent"])("SegmentGenerator");
-
- var _component_SaveButton = Object(external_commonjs_vue_commonjs2_vue_root_Vue_["resolveComponent"])("SaveButton");
-
- var _component_ContentBlock = Object(external_commonjs_vue_commonjs2_vue_root_Vue_["resolveComponent"])("ContentBlock");
-
+ const _component_Field = Object(external_commonjs_vue_commonjs2_vue_root_Vue_["resolveComponent"])("Field");
+ const _component_SiteSelector = Object(external_commonjs_vue_commonjs2_vue_root_Vue_["resolveComponent"])("SiteSelector");
+ const _component_SegmentGenerator = Object(external_commonjs_vue_commonjs2_vue_root_Vue_["resolveComponent"])("SegmentGenerator");
+ const _component_SaveButton = Object(external_commonjs_vue_commonjs2_vue_root_Vue_["resolveComponent"])("SaveButton");
+ const _component_ContentBlock = Object(external_commonjs_vue_commonjs2_vue_root_Vue_["resolveComponent"])("ContentBlock");
return Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createBlock"])(_component_ContentBlock, {
class: "editReport",
"content-title": _ctx.contentTitle
}, {
- default: Object(external_commonjs_vue_commonjs2_vue_root_Vue_["withCtx"])(function () {
+ default: Object(external_commonjs_vue_commonjs2_vue_root_Vue_["withCtx"])(() => {
var _ctx$report$metrics, _ctx$report$dimension, _ctx$report$subcatego;
-
return [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["withDirectives"])(Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("p", null, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("span", _hoisted_1, [_hoisted_2, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createTextVNode"])(" " + Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.translate('General_LoadingData')), 1)])], 512), [[external_commonjs_vue_commonjs2_vue_root_Vue_["vShow"], _ctx.isLoading]]), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["withDirectives"])(Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("p", null, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("span", _hoisted_3, [_hoisted_4, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createTextVNode"])(" " + Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.translate('CustomReports_UpdatingData')), 1)])], 512), [[external_commonjs_vue_commonjs2_vue_root_Vue_["vShow"], _ctx.isUpdating]]), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["withDirectives"])(Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", _hoisted_5, [_ctx.multipleSites.length && !_ctx.report.allowedToEdit ? (Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("span", _hoisted_6, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.translate('CustomReports_ReportEditNotAllowedMultipleWebsitesAccessIssue')), 1)) : (Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("span", _hoisted_7, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.translate('CustomReports_ReportEditNotAllowedAllWebsitesUpdated')), 1))], 512), [[external_commonjs_vue_commonjs2_vue_root_Vue_["vShow"], !_ctx.canEdit]]), _ctx.report.status === 'paused' ? (Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("div", _hoisted_8, [_ctx.report.allowedToEdit ? (Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("span", {
key: 0,
innerHTML: _ctx.getPausedStateAdminMessage
}, null, 8, _hoisted_9)) : (Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("span", _hoisted_10, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.translate('CustomReports_NoDataMessagePausedStateNonAdminUser')), 1))])) : Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createCommentVNode"])("", true), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("form", {
- onSubmit: _cache[15] || (_cache[15] = function ($event) {
- return _ctx.edit ? _ctx.updateReport() : _ctx.createReport();
- })
+ onSubmit: _cache[15] || (_cache[15] = $event => _ctx.edit ? _ctx.updateReport() : _ctx.createReport())
}, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", null, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", _hoisted_11, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createVNode"])(_component_Field, {
uicontrol: "text",
name: "name",
"model-value": _ctx.report.name,
- "onUpdate:modelValue": _cache[0] || (_cache[0] = function ($event) {
+ "onUpdate:modelValue": _cache[0] || (_cache[0] = $event => {
_ctx.report.name = $event;
-
_ctx.setValueHasChanged();
}),
title: _ctx.translate('General_Name'),
@@ -498,12 +469,11 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
uicontrol: "textarea",
name: "description",
"model-value": _ctx.report.description,
- "onUpdate:modelValue": _cache[1] || (_cache[1] = function ($event) {
+ "onUpdate:modelValue": _cache[1] || (_cache[1] = $event => {
_ctx.report.description = $event;
-
_ctx.setValueHasChanged();
}),
- title: "".concat(_ctx.translate('General_Description'), " (optional)"),
+ title: `${_ctx.translate('General_Description')} (optional)`,
maxlength: 1000,
disabled: !_ctx.canEdit,
rows: 3,
@@ -512,9 +482,8 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
}, null, 8, ["model-value", "title", "disabled", "placeholder", "inline-help"])]), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", _hoisted_13, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("h3", _hoisted_14, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.translate('CustomReports_ApplyTo')), 1), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", _hoisted_15, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", null, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("label", _hoisted_16, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.translate('General_Website')), 1), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", _hoisted_17, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createVNode"])(_component_SiteSelector, {
id: "all_websites",
"model-value": _ctx.report.site,
- "onUpdate:modelValue": _cache[2] || (_cache[2] = function ($event) {
+ "onUpdate:modelValue": _cache[2] || (_cache[2] = $event => {
_ctx.report.site = $event;
-
_ctx.setWebsiteChanged($event);
}),
"show-all-sites-item": _ctx.isSuperUser,
@@ -524,9 +493,7 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
class: "control_text customReportSearchMeasurablesField",
type: "text",
id: "websitecontains",
- "onUpdate:modelValue": _cache[3] || (_cache[3] = function ($event) {
- return _ctx.containsText = $event;
- }),
+ "onUpdate:modelValue": _cache[3] || (_cache[3] = $event => _ctx.containsText = $event),
placeholder: _ctx.translate('General_Search')
}, null, 8, _hoisted_26), [[external_commonjs_vue_commonjs2_vue_root_Vue_["vModelText"], _ctx.containsText]]), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("input", {
style: {
@@ -535,62 +502,50 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
disabled: !_ctx.containsText,
class: "btn customReportSearchFindMeasurables",
type: "button",
- onClick: _cache[4] || (_cache[4] = function ($event) {
- return _ctx.addSitesContaining(_ctx.containsText);
- }),
+ onClick: _cache[4] || (_cache[4] = $event => _ctx.addSitesContaining(_ctx.containsText)),
value: _ctx.translate('CustomReports_FindMeasurables')
- }, null, 8, _hoisted_27)])) : Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createCommentVNode"])("", true), _ctx.report.allowedToEdit || _ctx.multipleSites.length ? (Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("div", _hoisted_28, [_hoisted_29, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("table", _hoisted_30, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("thead", null, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("tr", null, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("th", _hoisted_31, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.translate('General_Id')), 1), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("th", _hoisted_32, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.translate('General_Name')), 1), _ctx.report.allowedToEdit ? (Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("th", _hoisted_33, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.translate('General_Remove')), 1)) : Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createCommentVNode"])("", true)])]), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("tbody", null, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["withDirectives"])(Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("tr", null, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("td", _hoisted_34, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.translate('CustomReports_NoMeasurableAssignedYet')), 1)], 512), [[external_commonjs_vue_commonjs2_vue_root_Vue_["vShow"], !_ctx.multipleSites.length]]), (Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(true), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])(external_commonjs_vue_commonjs2_vue_root_Vue_["Fragment"], null, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["renderList"])(_ctx.multipleSites, function (site, index) {
+ }, null, 8, _hoisted_27)])) : Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createCommentVNode"])("", true), _ctx.report.allowedToEdit || _ctx.multipleSites.length ? (Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("div", _hoisted_28, [_hoisted_29, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("table", _hoisted_30, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("thead", null, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("tr", null, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("th", _hoisted_31, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.translate('General_Id')), 1), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("th", _hoisted_32, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.translate('General_Name')), 1), _ctx.report.allowedToEdit ? (Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("th", _hoisted_33, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.translate('General_Remove')), 1)) : Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createCommentVNode"])("", true)])]), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("tbody", null, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["withDirectives"])(Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("tr", null, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("td", _hoisted_34, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.translate('CustomReports_NoMeasurableAssignedYet')), 1)], 512), [[external_commonjs_vue_commonjs2_vue_root_Vue_["vShow"], !_ctx.multipleSites.length]]), (Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(true), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])(external_commonjs_vue_commonjs2_vue_root_Vue_["Fragment"], null, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["renderList"])(_ctx.multipleSites, (site, index) => {
return Object(external_commonjs_vue_commonjs2_vue_root_Vue_["withDirectives"])((Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("tr", {
key: index
}, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("td", null, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(site.idsite), 1), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("td", null, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(site.name), 1), _ctx.report.allowedToEdit ? (Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("td", _hoisted_35, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("span", {
class: "icon-minus table-action",
- onClick: function onClick($event) {
- return _ctx.removeSite(site);
- }
- }, null, 8, _hoisted_36)])) : Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createCommentVNode"])("", true)], 512)), [[external_commonjs_vue_commonjs2_vue_root_Vue_["vShow"], _ctx.multipleSites.length > 0]]);
+ onClick: $event => _ctx.removeSite(site)
+ }, null, 8, _hoisted_36)])) : Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createCommentVNode"])("", true)])), [[external_commonjs_vue_commonjs2_vue_root_Vue_["vShow"], _ctx.multipleSites.length > 0]]);
}), 128))])])])) : Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createCommentVNode"])("", true)])) : Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createCommentVNode"])("", true)]), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", _hoisted_37, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("h3", _hoisted_38, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.translate('CustomReports_ReportContent')), 1)]), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["withDirectives"])(Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", _hoisted_39, [_ctx.browserArchivingDisabled && _ctx.reArchiveLastN ? (Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("span", _hoisted_40, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.translate('CustomReports_WarningRequiresUnlockBrowserArchivingDisabled', _ctx.reArchiveLastN)), 1)) : Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createCommentVNode"])("", true), !_ctx.browserArchivingDisabled || !_ctx.reArchiveLastN ? (Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("span", _hoisted_41, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.translate('CustomReports_WarningRequiresUnlock')), 1)) : Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createCommentVNode"])("", true), _hoisted_42, _hoisted_43, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("input", {
type: "button",
class: "btn unlockReport",
- onClick: _cache[5] || (_cache[5] = function ($event) {
- return _ctx.unlockReport();
- }),
+ onClick: _cache[5] || (_cache[5] = $event => _ctx.unlockReport()),
value: _ctx.translate('CustomReports_Unlock')
}, null, 8, _hoisted_44)], 512), [[external_commonjs_vue_commonjs2_vue_root_Vue_["vShow"], _ctx.isLocked]]), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["withDirectives"])(Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", _hoisted_45, [_ctx.browserArchivingDisabled && _ctx.reArchiveLastN ? (Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("span", _hoisted_46, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.translate('CustomReports_WarningOnUpdateReportMightGetLostBrowserArchivingDisabled', _ctx.reArchiveLastN)), 1)) : Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createCommentVNode"])("", true), !_ctx.browserArchivingDisabled || !_ctx.reArchiveLastN ? (Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("span", _hoisted_47, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.translate('CustomReports_WarningOnUpdateReportMightGetLost')), 1)) : Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createCommentVNode"])("", true)], 512), [[external_commonjs_vue_commonjs2_vue_root_Vue_["vShow"], _ctx.isUnlocked]]), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", _hoisted_48, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createVNode"])(_component_Field, {
uicontrol: "radio",
name: "reportType",
"model-value": _ctx.report.report_type,
- "onUpdate:modelValue": _cache[6] || (_cache[6] = function ($event) {
- return _ctx.setReportTypeHasChanged($event);
- }),
+ "onUpdate:modelValue": _cache[6] || (_cache[6] = $event => _ctx.setReportTypeHasChanged($event)),
title: _ctx.translate('CustomReports_ReportType'),
disabled: !_ctx.canEdit,
options: _ctx.reportTypes
- }, null, 8, ["model-value", "title", "disabled", "options"])]), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["withDirectives"])(Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", _hoisted_49, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", _hoisted_50, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("label", null, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.translate('CustomReports_Dimensions')), 1), _hoisted_51, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", null, [(Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(true), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])(external_commonjs_vue_commonjs2_vue_root_Vue_["Fragment"], null, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["renderList"])(_ctx.report.dimensions, function (dimension, dimIndex) {
+ }, null, 8, ["model-value", "title", "disabled", "options"])]), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["withDirectives"])(Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", _hoisted_49, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", _hoisted_50, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("label", null, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.translate('CustomReports_Dimensions')), 1), _hoisted_51, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", null, [(Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(true), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])(external_commonjs_vue_commonjs2_vue_root_Vue_["Fragment"], null, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["renderList"])(_ctx.report.dimensions, (dimension, dimIndex) => {
return Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("div", {
- class: Object(external_commonjs_vue_commonjs2_vue_root_Vue_["normalizeClass"])("selectedDimension selectedDimension".concat(dimIndex)),
+ class: Object(external_commonjs_vue_commonjs2_vue_root_Vue_["normalizeClass"])(`selectedDimension selectedDimension${dimIndex}`),
key: dimIndex
}, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", _hoisted_52, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createVNode"])(_component_Field, {
uicontrol: "expandable-select",
name: "dimensions",
"model-value": dimension,
- "onUpdate:modelValue": function onUpdateModelValue($event) {
- return _ctx.changeDimension($event, dimIndex);
- },
+ "onUpdate:modelValue": $event => _ctx.changeDimension($event, dimIndex),
title: _ctx.dimensionsReadable[dimension] || dimension,
"full-width": true,
options: _ctx.dimensions
}, null, 8, ["model-value", "onUpdate:modelValue", "title", "options"])]), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("span", {
class: "icon-minus",
title: _ctx.translate('CustomReports_RemoveDimension'),
- onClick: function onClick($event) {
- return _ctx.removeDimension(dimIndex);
- }
+ onClick: $event => _ctx.removeDimension(dimIndex)
}, null, 8, _hoisted_53)], 2);
}), 128)), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["withDirectives"])(Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", _hoisted_54, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createVNode"])(_component_Field, {
uicontrol: "expandable-select",
name: "dimensions",
"model-value": '',
- "onUpdate:modelValue": _cache[7] || (_cache[7] = function ($event) {
+ "onUpdate:modelValue": _cache[7] || (_cache[7] = $event => {
_ctx.addDimension($event);
}),
title: _ctx.translate('CustomReports_AddDimension'),
@@ -599,32 +554,28 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
}, null, 8, ["title", "options"])], 512), [[external_commonjs_vue_commonjs2_vue_root_Vue_["vShow"], _ctx.report.dimensions.length < _ctx.maxDimensions]])])]), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", _hoisted_55, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", _hoisted_56, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("span", {
class: "inline-help",
innerHTML: _ctx.$sanitize(_ctx.getDimensionsHelpText)
- }, null, 8, _hoisted_57)])])], 512), [[external_commonjs_vue_commonjs2_vue_root_Vue_["vShow"], _ctx.report.report_type !== 'evolution']]), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", _hoisted_58, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", _hoisted_59, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("label", null, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.translate('General_Metrics')), 1), _hoisted_60, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", null, [(Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(true), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])(external_commonjs_vue_commonjs2_vue_root_Vue_["Fragment"], null, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["renderList"])(_ctx.report.metrics, function (metric, metricIndex) {
+ }, null, 8, _hoisted_57)])])], 512), [[external_commonjs_vue_commonjs2_vue_root_Vue_["vShow"], _ctx.report.report_type !== 'evolution']]), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", _hoisted_58, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", _hoisted_59, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("label", null, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.translate('General_Metrics')), 1), _hoisted_60, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", null, [(Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(true), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])(external_commonjs_vue_commonjs2_vue_root_Vue_["Fragment"], null, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["renderList"])(_ctx.report.metrics, (metric, metricIndex) => {
return Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("div", {
- class: Object(external_commonjs_vue_commonjs2_vue_root_Vue_["normalizeClass"])("selectedMetric selectedMetric".concat(metricIndex)),
+ class: Object(external_commonjs_vue_commonjs2_vue_root_Vue_["normalizeClass"])(`selectedMetric selectedMetric${metricIndex}`),
key: metricIndex
}, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", _hoisted_61, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createVNode"])(_component_Field, {
uicontrol: "expandable-select",
name: "metrics",
"model-value": metric,
- "onUpdate:modelValue": function onUpdateModelValue($event) {
- return _ctx.changeMetric($event, metricIndex);
- },
+ "onUpdate:modelValue": $event => _ctx.changeMetric($event, metricIndex),
title: _ctx.metricsReadable[metric] || metric,
"full-width": true,
options: _ctx.metrics
}, null, 8, ["model-value", "onUpdate:modelValue", "title", "options"])]), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("span", {
class: "icon-minus",
title: _ctx.translate('CustomReports_RemoveMetric'),
- onClick: function onClick($event) {
- return _ctx.removeMetric(metricIndex);
- }
+ onClick: $event => _ctx.removeMetric(metricIndex)
}, null, 8, _hoisted_62)], 2);
}), 128)), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", _hoisted_63, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createVNode"])(_component_Field, {
uicontrol: "expandable-select",
name: "metrics",
"model-value": '',
- "onUpdate:modelValue": _cache[8] || (_cache[8] = function ($event) {
+ "onUpdate:modelValue": _cache[8] || (_cache[8] = $event => {
_ctx.addMetric($event);
}),
title: _ctx.translate('CustomReports_AddMetric'),
@@ -635,24 +586,19 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
innerHTML: _ctx.getProductRevenueDependencyMessage
}, null, 8, _hoisted_67), [[external_commonjs_vue_commonjs2_vue_root_Vue_["vShow"], _ctx.dependencyAdded]]), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", _hoisted_68, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", _hoisted_69, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", null, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("label", _hoisted_70, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.translate('CustomReports_Filter')), 1), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("p", null, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.translate('CustomReports_ReportSegmentHelp')), 1), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", null, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createVNode"])(_component_SegmentGenerator, {
"model-value": _ctx.report.segment_filter,
- "onUpdate:modelValue": _cache[9] || (_cache[9] = function ($event) {
- return _ctx.setSegmentFilterHasChanged($event);
- }),
+ "onUpdate:modelValue": _cache[9] || (_cache[9] = $event => _ctx.setSegmentFilterHasChanged($event)),
idsite: _ctx.report.site.id
}, null, 8, ["model-value", "idsite"])])])])]), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["withDirectives"])(Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", _hoisted_71, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", _hoisted_72, [_hoisted_73, _hoisted_74, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createVNode"])(_component_SaveButton, {
class: "showPreviewButton",
disabled: !((_ctx$report$metrics = _ctx.report.metrics) !== null && _ctx$report$metrics !== void 0 && _ctx$report$metrics.length) || !((_ctx$report$dimension = _ctx.report.dimensions) !== null && _ctx$report$dimension !== void 0 && _ctx$report$dimension.length),
- onConfirm: _cache[10] || (_cache[10] = function ($event) {
- return _ctx.showPreview();
- }),
+ onConfirm: _cache[10] || (_cache[10] = $event => _ctx.showPreview()),
value: _ctx.translate('CustomReports_PreviewReport')
}, null, 8, ["disabled", "value"])])], 512), [[external_commonjs_vue_commonjs2_vue_root_Vue_["vShow"], _ctx.report.report_type === 'table']]), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", _hoisted_75, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createVNode"])(_component_Field, {
uicontrol: "select",
name: "reportCategories",
"model-value": _ctx.report.category.id,
- "onUpdate:modelValue": _cache[11] || (_cache[11] = function ($event) {
+ "onUpdate:modelValue": _cache[11] || (_cache[11] = $event => {
_ctx.report.category.id = $event;
-
_ctx.setValueHasChanged();
}),
title: _ctx.translate('CustomReports_ReportCategory'),
@@ -664,9 +610,8 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
uicontrol: "select",
name: "reportSubcategories",
"model-value": (_ctx$report$subcatego = _ctx.report.subcategory) === null || _ctx$report$subcatego === void 0 ? void 0 : _ctx$report$subcatego.id,
- "onUpdate:modelValue": _cache[12] || (_cache[12] = function ($event) {
+ "onUpdate:modelValue": _cache[12] || (_cache[12] = $event => {
_ctx.setSubcategory($event);
-
_ctx.setValueHasChanged();
}),
title: _ctx.translate('CustomReports_ReportSubcategory'),
@@ -676,7 +621,7 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
}, null, 8, ["model-value", "title", "disabled", "options", "inline-help"])]), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["withDirectives"])(Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", _hoisted_77, [_ctx.browserArchivingDisabled && _ctx.reArchiveLastN ? (Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("span", _hoisted_78, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.translate('CustomReports_WarningOnUpdateReportMightGetLostBrowserArchivingDisabled', _ctx.reArchiveLastN)), 1)) : Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createCommentVNode"])("", true), !_ctx.browserArchivingDisabled || !_ctx.reArchiveLastN ? (Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("span", _hoisted_79, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.translate('CustomReports_WarningOnUpdateReportMightGetLost')), 1)) : Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createCommentVNode"])("", true)], 512), [[external_commonjs_vue_commonjs2_vue_root_Vue_["vShow"], _ctx.isUnlocked]]), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["withDirectives"])(Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", _hoisted_80, [_ctx.multipleSites.length && !_ctx.report.allowedToEdit ? (Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("span", _hoisted_81, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.translate('CustomReports_ReportEditNotAllowedMultipleWebsitesAccessIssue')), 1)) : (Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("span", _hoisted_82, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.translate('CustomReports_ReportEditNotAllowedAllWebsitesUpdated')), 1))], 512), [[external_commonjs_vue_commonjs2_vue_root_Vue_["vShow"], !_ctx.canEdit]]), _ctx.childReports.length ? (Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("div", _hoisted_83, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("h3", {
class: "col s12",
textContent: Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.translate('CustomReports_OrderSubCategoryReports'))
- }, null, 8, _hoisted_84), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", _hoisted_85, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("ul", _hoisted_86, [(Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(true), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])(external_commonjs_vue_commonjs2_vue_root_Vue_["Fragment"], null, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["renderList"])(_ctx.childReports, function (childReport) {
+ }, null, 8, _hoisted_84), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", _hoisted_85, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("ul", _hoisted_86, [(Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(true), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])(external_commonjs_vue_commonjs2_vue_root_Vue_["Fragment"], null, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["renderList"])(_ctx.childReports, childReport => {
return Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("li", {
key: childReport.idcustomreport,
"data-id": childReport.idcustomreport
@@ -686,16 +631,12 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
textContent: Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.translate('CustomReports_OrderSubCategoryReportsDescription'))
}, null, 8, _hoisted_91)])])])) : Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createCommentVNode"])("", true), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["withDirectives"])(Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createVNode"])(_component_SaveButton, {
class: "createButton",
- onConfirm: _cache[13] || (_cache[13] = function ($event) {
- return _ctx.edit ? _ctx.updateReport() : _ctx.createReport();
- }),
+ onConfirm: _cache[13] || (_cache[13] = $event => _ctx.edit ? _ctx.updateReport() : _ctx.createReport()),
disabled: _ctx.isUpdating || !_ctx.isDirty,
saving: _ctx.isUpdating,
value: _ctx.saveButtonText
}, null, 8, ["disabled", "saving", "value"]), [[external_commonjs_vue_commonjs2_vue_root_Vue_["vShow"], _ctx.canEdit]]), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", _hoisted_92, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("a", {
- onClick: _cache[14] || (_cache[14] = function ($event) {
- return _ctx.cancel();
- })
+ onClick: _cache[14] || (_cache[14] = $event => _ctx.cancel())
}, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.translate('General_Cancel')), 1)])])], 32), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", _hoisted_93, [_ctx.browserArchivingDisabled && _ctx.reArchiveLastN ? (Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("h2", _hoisted_94, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.translate('CustomReports_ConfirmUnlockReportBrowserArchivingDisabled', _ctx.reArchiveLastN)), 1)) : Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createCommentVNode"])("", true), !_ctx.browserArchivingDisabled || !_ctx.reArchiveLastN ? (Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("h2", _hoisted_95, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.translate('CustomReports_ConfirmUnlockReport')), 1)) : Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createCommentVNode"])("", true), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("input", {
role: "yes",
type: "button",
@@ -729,26 +670,7 @@ var external_CorePluginsAdmin_ = __webpack_require__("a5a2");
var external_SegmentEditor_ = __webpack_require__("f06f");
// CONCATENATED MODULE: ./plugins/CustomReports/vue/src/CustomReports.store.ts
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
-
-function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
-
-function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
-
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
-
-function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
-
-function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
-
-function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
-
-function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); }
-
-function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
-
-function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
-
/**
* Copyright (C) InnoCraft Ltd - All rights reserved.
*
@@ -765,39 +687,31 @@ function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len
*/
-
function arrayFilterAndRemoveDuplicates(values) {
- return _toConsumableArray(new Set(values)).filter(function (v) {
- return !!v;
- });
+ return [...new Set(values)].filter(v => !!v);
}
-
function formatExpandableList(listByCategories, subcategoryField, extraField) {
- var list = [];
- listByCategories.forEach(function (category) {
- category[subcategoryField].forEach(function (value) {
+ const list = [];
+ listByCategories.forEach(category => {
+ category[subcategoryField].forEach(value => {
list.push(Object.assign({
group: category.category,
key: value.uniqueId,
value: value.name,
tooltip: value.description || undefined
- }, extraField ? _defineProperty({}, extraField, value[extraField]) : {}));
+ }, extraField ? {
+ [extraField]: value[extraField]
+ } : {}));
});
});
return list;
}
-
-var EMPTY_CAT = {
+const EMPTY_CAT = {
key: '',
value: ''
};
-
-var CustomReports_store_CustomReportsStore = /*#__PURE__*/function () {
- function CustomReportsStore() {
- var _this = this;
-
- _classCallCheck(this, CustomReportsStore);
-
+class CustomReports_store_CustomReportsStore {
+ constructor() {
_defineProperty(this, "privateState", Object(external_commonjs_vue_commonjs2_vue_root_Vue_["reactive"])({
reports: [],
reportTypesReadable: {},
@@ -810,366 +724,254 @@ var CustomReports_store_CustomReportsStore = /*#__PURE__*/function () {
allMetrics: [],
allDimensions: []
}));
-
- _defineProperty(this, "state", Object(external_commonjs_vue_commonjs2_vue_root_Vue_["computed"])(function () {
- return Object(external_commonjs_vue_commonjs2_vue_root_Vue_["readonly"])(_this.privateState);
- }));
-
+ _defineProperty(this, "state", Object(external_commonjs_vue_commonjs2_vue_root_Vue_["computed"])(() => Object(external_commonjs_vue_commonjs2_vue_root_Vue_["readonly"])(this.privateState)));
_defineProperty(this, "fetchPromise", null);
-
_defineProperty(this, "availableReportTypesPromise", null);
-
_defineProperty(this, "dimensionsPromise", null);
-
_defineProperty(this, "dimensionsIdsiteLoaded", 0);
-
_defineProperty(this, "metricsPromise", null);
-
_defineProperty(this, "metricsIdsiteLoaded", 0);
-
_defineProperty(this, "categoriesPromise", null);
-
_defineProperty(this, "categoriesIdsiteLoaded", null);
}
-
- _createClass(CustomReportsStore, [{
- key: "reload",
- value: function reload() {
- this.privateState.reports = [];
- this.fetchPromise = null;
- return this.fetchReports();
- }
- }, {
- key: "cleanupSegmentDefinition",
- value: function cleanupSegmentDefinition(definition) {
- var result = definition;
- result = result.replace('\'', '%27');
- result = result.replace('&', '%26');
- return result;
- }
- }, {
- key: "getAvailableReportTypes",
- value: function getAvailableReportTypes() {
- var _this2 = this;
-
- if (!this.availableReportTypesPromise) {
- this.availableReportTypesPromise = external_CoreHome_["AjaxHelper"].fetch({
- method: 'CustomReports.getAvailableReportTypes',
- filter_limit: '-1'
- }).then(function (reportTypes) {
- var reportTypeMap = {};
- reportTypes.forEach(function (rt) {
- reportTypeMap[rt.key] = rt.value;
- });
- _this2.privateState.reportTypesReadable = reportTypeMap;
+ reload() {
+ this.privateState.reports = [];
+ this.fetchPromise = null;
+ return this.fetchReports();
+ }
+ cleanupSegmentDefinition(definition) {
+ let result = definition;
+ result = result.replace('\'', '%27');
+ result = result.replace('&', '%26');
+ return result;
+ }
+ getAvailableReportTypes() {
+ if (!this.availableReportTypesPromise) {
+ this.availableReportTypesPromise = external_CoreHome_["AjaxHelper"].fetch({
+ method: 'CustomReports.getAvailableReportTypes',
+ filter_limit: '-1'
+ }).then(reportTypes => {
+ const reportTypeMap = {};
+ reportTypes.forEach(rt => {
+ reportTypeMap[rt.key] = rt.value;
});
- }
-
- return this.availableReportTypesPromise.then(function () {
- return _this2.state.value.reportTypesReadable;
+ this.privateState.reportTypesReadable = reportTypeMap;
});
}
- }, {
- key: "getAvailableDimensions",
- value: function getAvailableDimensions(idSite) {
- var _this3 = this;
-
- if (!this.dimensionsPromise || this.dimensionsIdsiteLoaded !== idSite) {
- this.dimensionsIdsiteLoaded = idSite;
- this.dimensionsPromise = external_CoreHome_["AjaxHelper"].fetch({
- method: 'CustomReports.getAvailableDimensions',
- filter_limit: '-1',
- idSite: idSite
- }).then(function (dimensions) {
- var dimensionMap = {};
- dimensions.forEach(function (category) {
- category.dimensions.forEach(function (dimension) {
- dimensionMap[dimension.uniqueId] = dimension.name;
- });
+ return this.availableReportTypesPromise.then(() => this.state.value.reportTypesReadable);
+ }
+ getAvailableDimensions(idSite) {
+ if (!this.dimensionsPromise || this.dimensionsIdsiteLoaded !== idSite) {
+ this.dimensionsIdsiteLoaded = idSite;
+ this.dimensionsPromise = external_CoreHome_["AjaxHelper"].fetch({
+ method: 'CustomReports.getAvailableDimensions',
+ filter_limit: '-1',
+ idSite
+ }).then(dimensions => {
+ const dimensionMap = {};
+ dimensions.forEach(category => {
+ category.dimensions.forEach(dimension => {
+ dimensionMap[dimension.uniqueId] = dimension.name;
});
- _this3.privateState.dimensionsReadable = dimensionMap;
- _this3.privateState.allDimensions = formatExpandableList(dimensions, 'dimensions', 'sqlSegment');
});
- }
-
- return this.dimensionsPromise.then(function () {
- return _this3.state.value.dimensionsReadable;
+ this.privateState.dimensionsReadable = dimensionMap;
+ this.privateState.allDimensions = formatExpandableList(dimensions, 'dimensions', 'sqlSegment');
});
}
- }, {
- key: "getAvailableMetrics",
- value: function getAvailableMetrics(idSite) {
- var _this4 = this;
-
- if (!this.metricsPromise || this.metricsIdsiteLoaded !== idSite) {
- this.metricsIdsiteLoaded = idSite;
- this.metricsPromise = external_CoreHome_["AjaxHelper"].fetch({
- method: 'CustomReports.getAvailableMetrics',
- filter_limit: '-1',
- idSite: idSite
- }).then(function (metrics) {
- var metricsMap = {};
- metrics.forEach(function (metricsCategory) {
- metricsCategory.metrics.forEach(function (metric) {
- metricsMap[metric.uniqueId] = metric.name;
- });
+ return this.dimensionsPromise.then(() => this.state.value.dimensionsReadable);
+ }
+ getAvailableMetrics(idSite) {
+ if (!this.metricsPromise || this.metricsIdsiteLoaded !== idSite) {
+ this.metricsIdsiteLoaded = idSite;
+ this.metricsPromise = external_CoreHome_["AjaxHelper"].fetch({
+ method: 'CustomReports.getAvailableMetrics',
+ filter_limit: '-1',
+ idSite
+ }).then(metrics => {
+ const metricsMap = {};
+ metrics.forEach(metricsCategory => {
+ metricsCategory.metrics.forEach(metric => {
+ metricsMap[metric.uniqueId] = metric.name;
});
- _this4.privateState.metricsReadable = metricsMap;
- _this4.privateState.allMetrics = formatExpandableList(metrics, 'metrics');
});
- }
-
- return this.metricsPromise.then(function () {
- return _this4.state.value.metricsReadable;
+ this.privateState.metricsReadable = metricsMap;
+ this.privateState.allMetrics = formatExpandableList(metrics, 'metrics');
});
}
- }, {
- key: "getAvailableCategories",
- value: function getAvailableCategories(idSite) {
- var _this5 = this;
-
- var idSiteToUse = !idSite || idSite === 'all' ? external_CoreHome_["Matomo"].idSite : idSite;
-
- if (!this.categoriesPromise || this.categoriesIdsiteLoaded !== idSite) {
- this.categoriesPromise = external_CoreHome_["AjaxHelper"].fetch({
- method: 'CustomReports.getAvailableCategories',
- filter_limit: '-1',
- idSite: idSiteToUse
- }).then(function (response) {
- var categories = [];
- var subcategories = {};
- response.forEach(function (category) {
- categories.push({
- key: category.uniqueId,
- value: category.name
- });
- category.subcategories.forEach(function (subcat) {
- subcategories[category.uniqueId] = subcategories[category.uniqueId] || [EMPTY_CAT];
- subcategories[category.uniqueId].push({
- key: subcat.uniqueId,
- value: subcat.name
- });
- });
+ return this.metricsPromise.then(() => this.state.value.metricsReadable);
+ }
+ getAvailableCategories(idSite) {
+ const idSiteToUse = !idSite || idSite === 'all' ? external_CoreHome_["Matomo"].idSite : idSite;
+ if (!this.categoriesPromise || this.categoriesIdsiteLoaded !== idSite) {
+ this.categoriesPromise = external_CoreHome_["AjaxHelper"].fetch({
+ method: 'CustomReports.getAvailableCategories',
+ filter_limit: '-1',
+ idSite: idSiteToUse
+ }).then(response => {
+ const categories = [];
+ const subcategories = {};
+ response.forEach(category => {
+ categories.push({
+ key: category.uniqueId,
+ value: category.name
});
- _this5.privateState.categories = categories;
- _this5.privateState.subcategories = subcategories;
- });
- }
-
- return this.categoriesPromise;
- }
- }, {
- key: "fetchReports",
- value: function fetchReports() {
- var _this6 = this;
-
- if (!this.fetchPromise) {
- this.fetchPromise = external_CoreHome_["AjaxHelper"].fetch({
- method: 'CustomReports.getConfiguredReports',
- filter_limit: '-1'
- });
- }
-
- this.privateState.isLoading = true;
- this.privateState.reports = [];
- return this.fetchPromise.then(function (reports) {
- _this6.privateState.reports = reports.map(function (report) {
- var _report$subcategory, _report$category;
-
- var subcategoryLink = undefined;
-
- if (report !== null && report !== void 0 && (_report$subcategory = report.subcategory) !== null && _report$subcategory !== void 0 && _report$subcategory.id) {
- subcategoryLink = report.subcategory.id;
- } else if ((report === null || report === void 0 ? void 0 : (_report$category = report.category) === null || _report$category === void 0 ? void 0 : _report$category.id) === 'CustomReports_CustomReports') {
- subcategoryLink = report.idcustomreport;
- } else {
- subcategoryLink = report.name;
- }
-
- return Object.assign(Object.assign({}, report), {}, {
- // report.idsite is falsey when report is set for all sites
- linkIdSite: report.idsite ? report.idsite : external_CoreHome_["Matomo"].idSite,
- subcategoryLink: subcategoryLink
+ category.subcategories.forEach(subcat => {
+ subcategories[category.uniqueId] = subcategories[category.uniqueId] || [EMPTY_CAT];
+ subcategories[category.uniqueId].push({
+ key: subcat.uniqueId,
+ value: subcat.name
+ });
});
});
- return _this6.state.value.reports;
- }).finally(function () {
- _this6.privateState.isLoading = false;
+ this.privateState.categories = categories;
+ this.privateState.subcategories = subcategories;
});
}
- }, {
- key: "findReport",
- value: function findReport(idCustomReport, isReload) {
- var _this7 = this;
-
- // before going through an API request we first try to find it in loaded reports
- var found = this.state.value.reports.find(function (r) {
- return parseInt("".concat(r.idcustomreport), 10) === idCustomReport;
- });
-
- if (found && !isReload) {
- return Promise.resolve(found);
- } // otherwise we fetch it via API
-
-
- this.privateState.isLoading = true;
- return external_CoreHome_["AjaxHelper"].fetch({
- idCustomReport: idCustomReport,
- method: 'CustomReports.getConfiguredReport'
- }).finally(function () {
- _this7.privateState.isLoading = false;
- });
- }
- }, {
- key: "deleteReport",
- value: function deleteReport(idCustomReport, idSite) {
- var _this8 = this;
-
- this.privateState.isUpdating = true;
- this.privateState.reports = [];
- return external_CoreHome_["AjaxHelper"].fetch({
- idCustomReport: idCustomReport,
- idSite: "".concat(idSite),
- method: 'CustomReports.deleteCustomReport'
- }, {
- withTokenInUrl: true
- }).then(function () {
- return {
- type: 'success'
- };
- }).catch(function (e) {
- return {
- type: 'error',
- message: e.message || e
- };
- }).finally(function () {
- _this8.privateState.isUpdating = false;
- });
- }
- }, {
- key: "pauseReport",
- value: function pauseReport(idCustomReport, idSite) {
- var _this9 = this;
-
- this.privateState.isUpdating = true;
- this.privateState.reports = [];
- return external_CoreHome_["AjaxHelper"].fetch({
- idCustomReport: idCustomReport,
- idSite: "".concat(idSite),
- method: 'CustomReports.pauseCustomReport'
- }, {
- withTokenInUrl: true
- }).then(function () {
- return {
- type: 'success'
- };
- }).catch(function (e) {
- return {
- type: 'error',
- message: e.message || e
- };
- }).finally(function () {
- _this9.privateState.isUpdating = false;
- });
- }
- }, {
- key: "resumeReport",
- value: function resumeReport(idCustomReport, idSite) {
- var _this10 = this;
-
- this.privateState.isUpdating = true;
- this.privateState.reports = [];
- return external_CoreHome_["AjaxHelper"].fetch({
- idCustomReport: idCustomReport,
- idSite: "".concat(idSite),
- method: 'CustomReports.resumeCustomReport'
- }, {
- withTokenInUrl: true
- }).then(function () {
- return {
- type: 'success'
- };
- }).catch(function (e) {
- return {
- type: 'error',
- message: e.message || e
- };
- }).finally(function () {
- _this10.privateState.isUpdating = false;
+ return this.categoriesPromise;
+ }
+ fetchReports() {
+ if (!this.fetchPromise) {
+ this.fetchPromise = external_CoreHome_["AjaxHelper"].fetch({
+ method: 'CustomReports.getConfiguredReports',
+ filter_limit: '-1'
});
}
- }, {
- key: "createOrUpdateReport",
- value: function createOrUpdateReport(report, method, childReportIds, multipleIdSites) {
- var _report$category2,
- _report$subcategory2,
- _this11 = this;
-
- this.privateState.isUpdating = true;
- return external_CoreHome_["AjaxHelper"].post({
- method: method,
- idCustomReport: report.idcustomreport,
- reportType: report.report_type,
- name: report.name.trim(),
- description: report.description.trim(),
- segmentFilter: encodeURIComponent(report.segment_filter),
- categoryId: (_report$category2 = report.category) === null || _report$category2 === void 0 ? void 0 : _report$category2.id,
- subcategoryId: (_report$subcategory2 = report.subcategory) === null || _report$subcategory2 === void 0 ? void 0 : _report$subcategory2.id,
- idSite: report.site.id,
- subCategoryReportIds: childReportIds,
- multipleIdSites: multipleIdSites
- }, {
- dimensionIds: arrayFilterAndRemoveDuplicates(report.dimensions),
- metricIds: arrayFilterAndRemoveDuplicates(report.metrics)
- }, {
- withTokenInUrl: true
- }).then(function (response) {
- return {
- type: 'success',
- response: response
- };
- }).catch(function (error) {
- return {
- type: 'error',
- message: error.message || error
- };
- }).finally(function () {
- _this11.privateState.isUpdating = false;
+ this.privateState.isLoading = true;
+ this.privateState.reports = [];
+ return this.fetchPromise.then(reports => {
+ this.privateState.reports = reports.map(report => {
+ var _report$subcategory, _report$category;
+ let subcategoryLink = undefined;
+ if (report !== null && report !== void 0 && (_report$subcategory = report.subcategory) !== null && _report$subcategory !== void 0 && _report$subcategory.id) {
+ subcategoryLink = report.subcategory.id;
+ } else if ((report === null || report === void 0 || (_report$category = report.category) === null || _report$category === void 0 ? void 0 : _report$category.id) === 'CustomReports_CustomReports') {
+ subcategoryLink = report.idcustomreport;
+ } else {
+ subcategoryLink = report.name;
+ }
+ return Object.assign(Object.assign({}, report), {}, {
+ // report.idsite is falsey when report is set for all sites
+ linkIdSite: report.idsite ? report.idsite : external_CoreHome_["Matomo"].idSite,
+ subcategoryLink
+ });
});
+ return this.state.value.reports;
+ }).finally(() => {
+ this.privateState.isLoading = false;
+ });
+ }
+ findReport(idCustomReport, isReload) {
+ // before going through an API request we first try to find it in loaded reports
+ const found = this.state.value.reports.find(r => parseInt(`${r.idcustomreport}`, 10) === idCustomReport);
+ if (found && !isReload) {
+ return Promise.resolve(found);
}
- }]);
-
- return CustomReportsStore;
-}();
-
+ // otherwise we fetch it via API
+ this.privateState.isLoading = true;
+ return external_CoreHome_["AjaxHelper"].fetch({
+ idCustomReport,
+ method: 'CustomReports.getConfiguredReport'
+ }).finally(() => {
+ this.privateState.isLoading = false;
+ });
+ }
+ deleteReport(idCustomReport, idSite) {
+ this.privateState.isUpdating = true;
+ this.privateState.reports = [];
+ return external_CoreHome_["AjaxHelper"].fetch({
+ idCustomReport,
+ idSite: `${idSite}`,
+ method: 'CustomReports.deleteCustomReport'
+ }, {
+ withTokenInUrl: true
+ }).then(() => ({
+ type: 'success'
+ })).catch(e => ({
+ type: 'error',
+ message: e.message || e
+ })).finally(() => {
+ this.privateState.isUpdating = false;
+ });
+ }
+ pauseReport(idCustomReport, idSite) {
+ this.privateState.isUpdating = true;
+ this.privateState.reports = [];
+ return external_CoreHome_["AjaxHelper"].fetch({
+ idCustomReport,
+ idSite: `${idSite}`,
+ method: 'CustomReports.pauseCustomReport'
+ }, {
+ withTokenInUrl: true
+ }).then(() => ({
+ type: 'success'
+ })).catch(e => ({
+ type: 'error',
+ message: e.message || e
+ })).finally(() => {
+ this.privateState.isUpdating = false;
+ });
+ }
+ resumeReport(idCustomReport, idSite) {
+ this.privateState.isUpdating = true;
+ this.privateState.reports = [];
+ return external_CoreHome_["AjaxHelper"].fetch({
+ idCustomReport,
+ idSite: `${idSite}`,
+ method: 'CustomReports.resumeCustomReport'
+ }, {
+ withTokenInUrl: true
+ }).then(() => ({
+ type: 'success'
+ })).catch(e => ({
+ type: 'error',
+ message: e.message || e
+ })).finally(() => {
+ this.privateState.isUpdating = false;
+ });
+ }
+ createOrUpdateReport(report, method, childReportIds, multipleIdSites) {
+ var _report$category2, _report$subcategory2;
+ this.privateState.isUpdating = true;
+ return external_CoreHome_["AjaxHelper"].post({
+ method,
+ idCustomReport: report.idcustomreport,
+ reportType: report.report_type,
+ name: report.name.trim(),
+ description: report.description.trim(),
+ segmentFilter: encodeURIComponent(report.segment_filter),
+ categoryId: (_report$category2 = report.category) === null || _report$category2 === void 0 ? void 0 : _report$category2.id,
+ subcategoryId: (_report$subcategory2 = report.subcategory) === null || _report$subcategory2 === void 0 ? void 0 : _report$subcategory2.id,
+ idSite: report.site.id,
+ subCategoryReportIds: childReportIds,
+ multipleIdSites
+ }, {
+ dimensionIds: arrayFilterAndRemoveDuplicates(report.dimensions),
+ metricIds: arrayFilterAndRemoveDuplicates(report.metrics)
+ }, {
+ withTokenInUrl: true
+ }).then(response => ({
+ type: 'success',
+ response
+ })).catch(error => ({
+ type: 'error',
+ message: error.message || error
+ })).finally(() => {
+ this.privateState.isUpdating = false;
+ });
+ }
+}
/* harmony default export */ var CustomReports_store = (new CustomReports_store_CustomReportsStore());
-// CONCATENATED MODULE: ./node_modules/@vue/cli-plugin-typescript/node_modules/cache-loader/dist/cjs.js??ref--14-0!./node_modules/babel-loader/lib!./node_modules/@vue/cli-plugin-typescript/node_modules/ts-loader??ref--14-2!./node_modules/@vue/cli-service/node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/@vue/cli-service/node_modules/vue-loader-v16/dist??ref--0-1!./plugins/CustomReports/vue/src/Reports/Edit.vue?vue&type=script&lang=ts
-function Editvue_type_script_lang_ts_toConsumableArray(arr) { return Editvue_type_script_lang_ts_arrayWithoutHoles(arr) || Editvue_type_script_lang_ts_iterableToArray(arr) || Editvue_type_script_lang_ts_unsupportedIterableToArray(arr) || Editvue_type_script_lang_ts_nonIterableSpread(); }
-
-function Editvue_type_script_lang_ts_nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
-
-function Editvue_type_script_lang_ts_unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return Editvue_type_script_lang_ts_arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return Editvue_type_script_lang_ts_arrayLikeToArray(o, minLen); }
-
-function Editvue_type_script_lang_ts_iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); }
-
-function Editvue_type_script_lang_ts_arrayWithoutHoles(arr) { if (Array.isArray(arr)) return Editvue_type_script_lang_ts_arrayLikeToArray(arr); }
-
-function Editvue_type_script_lang_ts_arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
-
-
+// CONCATENATED MODULE: ./node_modules/@vue/cli-plugin-typescript/node_modules/cache-loader/dist/cjs.js??ref--15-0!./node_modules/babel-loader/lib!./node_modules/@vue/cli-plugin-typescript/node_modules/ts-loader??ref--15-2!./node_modules/@vue/cli-service/node_modules/cache-loader/dist/cjs.js??ref--1-0!./node_modules/@vue/cli-service/node_modules/vue-loader-v16/dist??ref--1-1!./plugins/CustomReports/vue/src/Reports/Edit.vue?vue&type=script&lang=ts
-var notificationId = 'reportsmanagement';
-var productMetricNotificationId = 'reportsmanagementProductMetric';
+const notificationId = 'reportsmanagement';
+const productMetricNotificationId = 'reportsmanagementProductMetric';
function Editvue_type_script_lang_ts_arrayFilterAndRemoveDuplicates(values) {
- return Editvue_type_script_lang_ts_toConsumableArray(new Set(values)).filter(function (v) {
- return !!v;
- });
+ return [...new Set(values)].filter(v => !!v);
}
-
function makeDefaultReport() {
return {
dimensions: [],
@@ -1180,7 +982,6 @@ function makeDefaultReport() {
category: {}
};
}
-
/* harmony default export */ var Editvue_type_script_lang_ts = (Object(external_commonjs_vue_commonjs2_vue_root_Vue_["defineComponent"])({
props: {
idCustomReport: Number,
@@ -1196,7 +997,7 @@ function makeDefaultReport() {
SegmentGenerator: external_SegmentEditor_["SegmentGenerator"],
SaveButton: external_CorePluginsAdmin_["SaveButton"]
},
- data: function data() {
+ data() {
return {
isDirty: false,
report: makeDefaultReport(),
@@ -1211,168 +1012,149 @@ function makeDefaultReport() {
multipleIdSites: []
};
},
- created: function created() {
+ created() {
CustomReports_store.getAvailableReportTypes();
this.init();
},
watch: {
- idCustomReport: function idCustomReport(newValue) {
+ idCustomReport(newValue) {
if (newValue === null) {
return;
}
-
this.init();
}
},
methods: {
- initReportOptions: function initReportOptions() {
- var idsite = parseInt("".concat(this.report.site.id), 10) || 'all';
+ initReportOptions() {
+ const idsite = parseInt(`${this.report.site.id}`, 10) || 'all';
CustomReports_store.getAvailableDimensions(idsite);
CustomReports_store.getAvailableMetrics(idsite);
CustomReports_store.getAvailableCategories(idsite);
},
- doUnlock: function doUnlock() {
+ doUnlock() {
this.isLocked = false;
this.isUnlocked = true;
},
- confirmReportIsLocked: function confirmReportIsLocked(callback) {
- var _this = this;
-
+ confirmReportIsLocked(callback) {
external_CoreHome_["Matomo"].helper.modalConfirm(this.$refs.infoReportIsLocked, {
- unlock: function unlock() {
- _this.doUnlock();
-
+ unlock: () => {
+ this.doUnlock();
if (callback) {
callback();
}
}
});
},
- removeAnyReportNotification: function removeAnyReportNotification() {
+ removeAnyReportNotification() {
external_CoreHome_["NotificationsStore"].remove(notificationId);
external_CoreHome_["NotificationsStore"].remove(productMetricNotificationId);
external_CoreHome_["NotificationsStore"].remove('ajaxHelper');
},
- showApiErrorMessage: function showApiErrorMessage(errorMessage, responseType) {
+ showApiErrorMessage(errorMessage, responseType) {
if (errorMessage && responseType) {
this.removeAnyReportNotification();
- var elem = document.createElement('textarea');
+ const elem = document.createElement('textarea');
elem.innerHTML = errorMessage;
this.showNotification(elem.value, responseType, 'toast');
}
},
- showNotification: function showNotification(message, context) {
- var type = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
- var instanceId = external_CoreHome_["NotificationsStore"].show({
- message: message,
- context: context,
+ showNotification(message, context, type = null) {
+ const instanceId = external_CoreHome_["NotificationsStore"].show({
+ message,
+ context,
id: notificationId,
type: type !== null && type !== void 0 ? type : 'transient',
prepend: true
});
- setTimeout(function () {
+ setTimeout(() => {
external_CoreHome_["NotificationsStore"].scrollToNotification(instanceId);
}, 100);
},
- showProductMetricNotification: function showProductMetricNotification(message, shouldScrollToNotification) {
- var instanceId = external_CoreHome_["NotificationsStore"].show({
- message: message,
+ showProductMetricNotification(message, shouldScrollToNotification) {
+ const instanceId = external_CoreHome_["NotificationsStore"].show({
+ message,
context: 'warning',
id: productMetricNotificationId,
type: 'transient'
});
-
if (!shouldScrollToNotification) {
return;
}
-
- setTimeout(function () {
+ setTimeout(() => {
external_CoreHome_["NotificationsStore"].scrollToNotification(instanceId);
}, 100);
},
- showErrorFieldNotProvidedNotification: function showErrorFieldNotProvidedNotification(title) {
- var message = Object(external_CoreHome_["translate"])('CustomReports_ErrorXNotProvided', [title]);
+ showErrorFieldNotProvidedNotification(title) {
+ const message = Object(external_CoreHome_["translate"])('CustomReports_ErrorXNotProvided', [title]);
this.showNotification(message, 'error');
},
- init: function init() {
- var _this2 = this;
-
- var idCustomReport = this.idCustomReport;
+ init() {
+ const {
+ idCustomReport
+ } = this;
this.canEdit = true;
this.report = makeDefaultReport();
external_CoreHome_["Matomo"].helper.lazyScrollToContent();
-
if (this.edit && idCustomReport) {
- CustomReports_store.findReport(idCustomReport, true).then(function (report) {
- var _this2$report$child_r;
-
+ CustomReports_store.findReport(idCustomReport, true).then(report => {
+ var _this$report$child_re;
if (!report) {
return;
}
-
- _this2.report = Object(external_CoreHome_["clone"])(report);
- _this2.isLocked = true;
- _this2.isUnlocked = false;
- _this2.canEdit = true;
- _this2.childReports = (_this2$report$child_r = _this2.report.child_reports) !== null && _this2$report$child_r !== void 0 ? _this2$report$child_r : [];
-
- if (_this2.report.multipleIdSites && _this2.report.multipleIdSites.length && _this2.report.site.id !== 'all' && _this2.report.site.id !== '0' && _this2.report.site.id !== 0) {
- _this2.multipleSites = _this2.report.multipleIdSites;
-
- if (!_this2.report.allowedToEdit) {
- _this2.canEdit = false;
- _this2.isLocked = false;
+ this.report = Object(external_CoreHome_["clone"])(report);
+ this.isLocked = true;
+ this.isUnlocked = false;
+ this.canEdit = true;
+ this.childReports = (_this$report$child_re = this.report.child_reports) !== null && _this$report$child_re !== void 0 ? _this$report$child_re : [];
+ if (this.report.multipleIdSites && this.report.multipleIdSites.length && this.report.site.id !== 'all' && this.report.site.id !== '0' && this.report.site.id !== 0) {
+ this.multipleSites = this.report.multipleIdSites;
+ if (!this.report.allowedToEdit) {
+ this.canEdit = false;
+ this.isLocked = false;
}
}
-
- if (_this2.childReports.length) {
- Object.values(_this2.childReports).forEach(function (value) {
- _this2.childReportIds.push(value.idcustomreport);
+ if (this.childReports.length) {
+ Object.values(this.childReports).forEach(value => {
+ this.childReportIds.push(value.idcustomreport);
});
}
-
- $(document).ready(function () {
+ $(document).ready(() => {
$('#childReports').sortable({
connectWith: '#childReports',
- update: function update() {
- _this2.isDirty = true;
- var childReportsListItems = $('#childReports li');
- _this2.childReportIds = [];
- childReportsListItems.each(function (idx, li) {
+ update: () => {
+ this.isDirty = true;
+ const childReportsListItems = $('#childReports li');
+ this.childReportIds = [];
+ childReportsListItems.each((idx, li) => {
if (li.dataset.id) {
- _this2.childReportIds.push(li.dataset.id);
+ this.childReportIds.push(li.dataset.id);
}
});
}
});
});
- var idSite = _this2.report.idsite;
-
+ let idSite = this.report.idsite;
if (idSite === 0 || idSite === '0' || idSite === 'all') {
// we need to make sure to send 'all' and not '0' as otherwise piwikApi would
// consider 0 as no value set and replace it with the current idsite. Also the
// site selector expects us to set 'all' instead of 0
idSite = 'all';
-
- if (!_this2.isSuperUser) {
+ if (!this.isSuperUser) {
// a lock does not make sense because report cannot be changed anyway. we do not want
// to show a warning related to this in such a case
- _this2.canEdit = false;
- _this2.isLocked = false;
+ this.canEdit = false;
+ this.isLocked = false;
}
}
-
- _this2.report.site = {
+ this.report.site = {
id: idSite,
- name: _this2.report.site.name
+ name: this.report.site.name
};
- _this2.isDirty = false;
-
- _this2.initReportOptions();
+ this.isDirty = false;
+ this.initReportOptions();
});
return;
}
-
if (this.create) {
this.report = {
idsite: external_CoreHome_["Matomo"].idSite,
@@ -1399,289 +1181,233 @@ function makeDefaultReport() {
this.initReportOptions();
}
},
- cancel: function cancel() {
- var newParams = Object.assign({}, external_CoreHome_["MatomoUrl"].hashParsed.value);
+ cancel() {
+ const newParams = Object.assign({}, external_CoreHome_["MatomoUrl"].hashParsed.value);
delete newParams.idCustomReport;
external_CoreHome_["MatomoUrl"].updateHash(newParams);
},
- unlockReport: function unlockReport() {
- var _this3 = this;
-
+ unlockReport() {
if (!this.report) {
return;
}
-
if (this.isLocked) {
external_CoreHome_["Matomo"].helper.modalConfirm(this.$refs.confirmUnlockReport, {
- yes: function yes() {
- _this3.doUnlock();
+ yes: () => {
+ this.doUnlock();
}
});
}
},
- createReport: function createReport() {
- var _this4 = this;
-
- var method = 'CustomReports.addCustomReport';
+ createReport() {
+ const method = 'CustomReports.addCustomReport';
this.removeAnyReportNotification();
-
if (!this.checkRequiredFieldsAreSet()) {
return;
}
-
this.multipleIdSites = [];
-
if (this.multipleSites && this.multipleSites.length && this.report.site.id !== 'all' && this.report.site.id !== '0' && this.report.site.id !== 0) {
this.multipleIdSites.push(external_CoreHome_["Matomo"].idSite);
- this.multipleSites.forEach(function (item) {
- var idSite = item.idsite;
-
- if (!_this4.multipleIdSites.includes(idSite)) {
- _this4.multipleIdSites.push(idSite);
+ this.multipleSites.forEach(item => {
+ const idSite = item.idsite;
+ if (!this.multipleIdSites.includes(idSite)) {
+ this.multipleIdSites.push(idSite);
}
});
}
-
if (this.multipleIdSites && this.multipleIdSites.length) {
// need to update this else this creates an issue after save
this.report.site.id = external_CoreHome_["Matomo"].idSite;
}
-
- CustomReports_store.createOrUpdateReport(this.report, method, this.childReportIds, this.multipleIdSites).then(function (response) {
+ CustomReports_store.createOrUpdateReport(this.report, method, this.childReportIds, this.multipleIdSites).then(response => {
if (!response || response.type === 'error' || !response.response) {
var _response$message, _response$type;
-
- _this4.showApiErrorMessage((_response$message = response.message) !== null && _response$message !== void 0 ? _response$message : '', (_response$type = response.type) !== null && _response$type !== void 0 ? _response$type : 'error');
-
+ this.showApiErrorMessage((_response$message = response.message) !== null && _response$message !== void 0 ? _response$message : '', (_response$type = response.type) !== null && _response$type !== void 0 ? _response$type : 'error');
return;
}
-
- _this4.isDirty = false;
- var idCustomReport = response.response.value;
-
- if (_this4.report.site) {
- var idSite = _this4.report.site.id;
-
- if (idSite && idSite !== 'all' && "".concat(idSite) !== "".concat(external_CoreHome_["Matomo"].idSite)) {
+ this.isDirty = false;
+ const idCustomReport = response.response.value;
+ if (this.report.site) {
+ const idSite = this.report.site.id;
+ if (idSite && idSite !== 'all' && `${idSite}` !== `${external_CoreHome_["Matomo"].idSite}`) {
// when creating a report for a different site...
// we need to reload this page for a different idsite, otherwise the report won't
// be found
external_CoreHome_["MatomoUrl"].updateUrl(Object.assign(Object.assign({}, external_CoreHome_["MatomoUrl"].urlParsed.value), {}, {
- idSite: idSite
+ idSite
}), Object.assign(Object.assign({}, external_CoreHome_["MatomoUrl"].hashParsed.value), {}, {
- idCustomReport: idCustomReport
+ idCustomReport
}));
return;
}
}
-
- CustomReports_store.reload().then(function () {
+ CustomReports_store.reload().then(() => {
if (external_CoreHome_["Matomo"].helper.isReportingPage()) {
external_CoreHome_["Matomo"].postEvent('updateReportingMenu');
}
-
external_CoreHome_["MatomoUrl"].updateHash(Object.assign(Object.assign({}, external_CoreHome_["MatomoUrl"].hashParsed.value), {}, {
- idCustomReport: idCustomReport
+ idCustomReport
}));
- setTimeout(function () {
- _this4.showNotification(Object(external_CoreHome_["translate"])('CustomReports_ReportCreated'), response.type);
+ setTimeout(() => {
+ this.showNotification(Object(external_CoreHome_["translate"])('CustomReports_ReportCreated'), response.type);
}, 200);
});
});
},
- showPreview: function showPreview() {
+ showPreview() {
var _this$report$site, _this$report$dimensio, _this$report$metrics;
-
if (!this.isProductRevenueDependencyMet(true)) {
return;
}
-
- var idSite = (_this$report$site = this.report.site) !== null && _this$report$site !== void 0 && _this$report$site.id && this.report.site.id !== 'all' ? this.report.site.id : external_CoreHome_["Matomo"].idSite;
- var hasDimensions = ((_this$report$dimensio = this.report.dimensions) === null || _this$report$dimensio === void 0 ? void 0 : _this$report$dimensio.length) && this.report.report_type && this.report.report_type !== 'evolution';
- var dimensions = hasDimensions ? this.report.dimensions.join(',') : undefined;
- var hasMetrics = !!((_this$report$metrics = this.report.metrics) !== null && _this$report$metrics !== void 0 && _this$report$metrics.length);
- var metrics = hasMetrics ? this.report.metrics.join(',') : undefined;
- var url = external_CoreHome_["MatomoUrl"].stringify({
+ const idSite = (_this$report$site = this.report.site) !== null && _this$report$site !== void 0 && _this$report$site.id && this.report.site.id !== 'all' ? this.report.site.id : external_CoreHome_["Matomo"].idSite;
+ const hasDimensions = ((_this$report$dimensio = this.report.dimensions) === null || _this$report$dimensio === void 0 ? void 0 : _this$report$dimensio.length) && this.report.report_type && this.report.report_type !== 'evolution';
+ const dimensions = hasDimensions ? this.report.dimensions.join(',') : undefined;
+ const hasMetrics = !!((_this$report$metrics = this.report.metrics) !== null && _this$report$metrics !== void 0 && _this$report$metrics.length);
+ const metrics = hasMetrics ? this.report.metrics.join(',') : undefined;
+ const url = external_CoreHome_["MatomoUrl"].stringify({
module: 'CustomReports',
action: 'previewReport',
period: 'day',
date: 'today',
- idSite: idSite,
+ idSite,
report_type: this.report.report_type,
- dimensions: dimensions,
- metrics: metrics,
+ dimensions,
+ metrics,
segment: this.report.segment_filter || undefined
});
- var title = Object(external_CoreHome_["translate"])('CustomReports_Preview');
+ const title = Object(external_CoreHome_["translate"])('CustomReports_Preview');
window.Piwik_Popover.createPopupAndLoadUrl(url, title, 'customReportPreview');
},
- setValueHasChanged: function setValueHasChanged() {
+ setValueHasChanged() {
this.isDirty = true;
},
- addDimension: function addDimension(dimension) {
- var _this5 = this;
-
+ addDimension(dimension) {
if (!this.report || !dimension) {
return;
}
-
if (this.isLocked) {
- this.confirmReportIsLocked(function () {
- _this5.addDimension(dimension);
+ this.confirmReportIsLocked(() => {
+ this.addDimension(dimension);
});
return;
}
-
if (!this.report.dimensions) {
this.report.dimensions = [];
}
-
- this.report.dimensions = [].concat(Editvue_type_script_lang_ts_toConsumableArray(this.report.dimensions), [dimension]);
+ this.report.dimensions = [...this.report.dimensions, dimension];
this.setValueHasChanged();
},
- changeDimension: function changeDimension(dimension, index) {
- var _this6 = this,
- _this$report$dimensio2;
-
+ changeDimension(dimension, index) {
+ var _this$report$dimensio2;
if (!this.report || !dimension) {
return;
}
-
if (this.isLocked) {
- this.confirmReportIsLocked(function () {
- _this6.changeDimension(dimension, index);
+ this.confirmReportIsLocked(() => {
+ this.changeDimension(dimension, index);
});
return;
}
-
if (!((_this$report$dimensio2 = this.report.dimensions) !== null && _this$report$dimensio2 !== void 0 && _this$report$dimensio2[index])) {
return;
}
-
- this.report.dimensions = Editvue_type_script_lang_ts_toConsumableArray(this.report.dimensions);
+ this.report.dimensions = [...this.report.dimensions];
this.report.dimensions[index] = dimension;
this.setValueHasChanged();
},
- changeMetric: function changeMetric(metric, index) {
- var _this7 = this,
- _this$report$metrics2;
-
+ changeMetric(metric, index) {
+ var _this$report$metrics2;
this.dependencyAdded = false;
-
if (!this.report || !metric) {
return;
}
-
if (this.isLocked) {
- this.confirmReportIsLocked(function () {
- _this7.changeMetric(metric, index);
+ this.confirmReportIsLocked(() => {
+ this.changeMetric(metric, index);
});
return;
}
-
if (!((_this$report$metrics2 = this.report.metrics) !== null && _this$report$metrics2 !== void 0 && _this$report$metrics2[index])) {
return;
}
-
- this.report.metrics = Editvue_type_script_lang_ts_toConsumableArray(this.report.metrics);
+ this.report.metrics = [...this.report.metrics];
this.report.metrics[index] = metric;
this.setValueHasChanged();
this.addMetricIfMissingDependency(metric);
},
- setWebsiteChanged: function setWebsiteChanged(newValue) {
+ setWebsiteChanged(newValue) {
this.setValueHasChanged();
this.initReportOptions();
-
if (this.report.site.id === 'all' || this.report.site.id === '0' || this.report.site.id === 0) {
this.multipleSites = [];
- } else if (this.report.allowedToEdit && !this.isSiteIncludedAlready("".concat(newValue.id)) && this.multipleSites) {
+ } else if (this.report.allowedToEdit && !this.isSiteIncludedAlready(`${newValue.id}`) && this.multipleSites) {
this.multipleSites.push({
idsite: newValue.id,
name: newValue.name
});
}
},
- removeDimension: function removeDimension(index) {
- var _this8 = this;
-
+ removeDimension(index) {
if (this.isLocked) {
- this.confirmReportIsLocked(function () {
- _this8.removeDimension(index);
+ this.confirmReportIsLocked(() => {
+ this.removeDimension(index);
});
return;
}
-
window.$('div.ui-tooltip[role="tooltip"]:not([style*="display: none"])').remove();
-
if (index > -1) {
- this.report.dimensions = Editvue_type_script_lang_ts_toConsumableArray(this.report.dimensions);
+ this.report.dimensions = [...this.report.dimensions];
this.report.dimensions.splice(index, 1);
this.setValueHasChanged();
}
},
- addMetric: function addMetric(metric) {
- var _this9 = this;
-
+ addMetric(metric) {
this.dependencyAdded = false;
-
if (!this.report || !metric) {
return;
}
-
if (!this.report.metrics) {
this.report.metrics = [];
}
-
if (this.isLocked) {
- this.confirmReportIsLocked(function () {
- _this9.addMetric(metric);
+ this.confirmReportIsLocked(() => {
+ this.addMetric(metric);
});
return;
}
-
- this.report.metrics = [].concat(Editvue_type_script_lang_ts_toConsumableArray(this.report.metrics), [metric]);
+ this.report.metrics = [...this.report.metrics, metric];
this.setValueHasChanged();
this.addMetricIfMissingDependency(metric);
},
- addMetricIfMissingDependency: function addMetricIfMissingDependency(metric) {
+ addMetricIfMissingDependency(metric) {
// If the metric isn't Product Revenue or the dependency is already met, return
if (!['sum_product_revenue', 'avg_product_revenue'].includes(metric) || this.doesReportIncludeProductQuantityMetric()) {
return;
}
-
- var dependency = metric === 'avg_product_revenue' ? 'avg_ecommerce_productquantity' : 'sum_ecommerce_productquantity';
+ const dependency = metric === 'avg_product_revenue' ? 'avg_ecommerce_productquantity' : 'sum_ecommerce_productquantity';
this.addMetric(dependency);
this.dependencyAdded = true;
},
- removeMetric: function removeMetric(index) {
- var _this10 = this;
-
+ removeMetric(index) {
this.dependencyAdded = false;
-
if (this.isLocked) {
- this.confirmReportIsLocked(function () {
- _this10.removeMetric(index);
+ this.confirmReportIsLocked(() => {
+ this.removeMetric(index);
});
return;
}
-
window.$('div.ui-tooltip[role="tooltip"]:not([style*="display: none"])').remove();
-
if (index > -1) {
- this.report.metrics = Editvue_type_script_lang_ts_toConsumableArray(this.report.metrics);
+ this.report.metrics = [...this.report.metrics];
this.report.metrics.splice(index, 1);
this.setValueHasChanged();
}
},
- setReportTypeHasChanged: function setReportTypeHasChanged(newReportType) {
- var _this11 = this;
-
+ setReportTypeHasChanged(newReportType) {
if (this.report && this.isLocked) {
if (newReportType !== this.report.report_type) {
- this.confirmReportIsLocked(function () {
- _this11.report.report_type = newReportType;
-
- _this11.setValueHasChanged();
+ this.confirmReportIsLocked(() => {
+ this.report.report_type = newReportType;
+ this.setValueHasChanged();
});
}
} else {
@@ -1689,15 +1415,12 @@ function makeDefaultReport() {
this.setValueHasChanged();
}
},
- setSegmentFilterHasChanged: function setSegmentFilterHasChanged(newSegmentFilter) {
- var _this12 = this;
-
+ setSegmentFilterHasChanged(newSegmentFilter) {
if (this.report && this.isLocked) {
if (newSegmentFilter !== this.report.segment_filter) {
- this.confirmReportIsLocked(function () {
- _this12.report.segment_filter = newSegmentFilter;
-
- _this12.setValueHasChanged();
+ this.confirmReportIsLocked(() => {
+ this.report.segment_filter = newSegmentFilter;
+ this.setValueHasChanged();
});
}
} else {
@@ -1705,293 +1428,243 @@ function makeDefaultReport() {
this.setValueHasChanged();
}
},
- updateReport: function updateReport() {
- var _this13 = this;
-
+ updateReport() {
this.removeAnyReportNotification();
-
if (!this.checkRequiredFieldsAreSet()) {
return;
}
-
this.multipleIdSites = [];
-
if (this.multipleSites && this.multipleSites.length && this.report.site.id !== 'all' && this.report.site.id !== '0' && this.report.site.id !== 0) {
this.multipleIdSites.push(external_CoreHome_["Matomo"].idSite);
- this.multipleSites.forEach(function (item) {
- var idSite = item.idsite;
-
- if (!_this13.multipleIdSites.includes(idSite)) {
- _this13.multipleIdSites.push(idSite);
+ this.multipleSites.forEach(item => {
+ const idSite = item.idsite;
+ if (!this.multipleIdSites.includes(idSite)) {
+ this.multipleIdSites.push(idSite);
}
});
}
-
- var method = 'CustomReports.updateCustomReport';
-
+ const method = 'CustomReports.updateCustomReport';
if (this.multipleIdSites && this.multipleIdSites.length) {
// need to update this else this creates an issue after save
this.report.site.id = external_CoreHome_["Matomo"].idSite;
}
-
- CustomReports_store.createOrUpdateReport(this.report, method, this.childReportIds, this.multipleIdSites).then(function (response) {
+ CustomReports_store.createOrUpdateReport(this.report, method, this.childReportIds, this.multipleIdSites).then(response => {
if (!response || response.type === 'error') {
var _response$message2, _response$type2;
-
- _this13.showApiErrorMessage((_response$message2 = response.message) !== null && _response$message2 !== void 0 ? _response$message2 : '', (_response$type2 = response.type) !== null && _response$type2 !== void 0 ? _response$type2 : 'error');
-
+ this.showApiErrorMessage((_response$message2 = response.message) !== null && _response$message2 !== void 0 ? _response$message2 : '', (_response$type2 = response.type) !== null && _response$type2 !== void 0 ? _response$type2 : 'error');
return;
}
-
- var idSite = _this13.report.site.id;
- _this13.isDirty = false;
- _this13.canEdit = true;
-
- if (idSite && idSite !== 'all' && "".concat(idSite) !== "".concat(external_CoreHome_["Matomo"].idSite)) {
+ const idSite = this.report.site.id;
+ this.isDirty = false;
+ this.canEdit = true;
+ if (idSite && idSite !== 'all' && `${idSite}` !== `${external_CoreHome_["Matomo"].idSite}`) {
// when moving a report from one site to another...
// we need to reload this page for a different idsite, otherwise the report won't be found
external_CoreHome_["MatomoUrl"].updateUrl(Object.assign(Object.assign({}, external_CoreHome_["MatomoUrl"].urlParsed.value), {}, {
- idSite: idSite
+ idSite
}), Object.assign({}, external_CoreHome_["MatomoUrl"].hashParsed.value));
return;
}
-
- CustomReports_store.reload().then(function () {
- _this13.init();
+ CustomReports_store.reload().then(() => {
+ this.init();
});
-
- _this13.showNotification(Object(external_CoreHome_["translate"])('CustomReports_ReportUpdated'), response.type);
+ this.showNotification(Object(external_CoreHome_["translate"])('CustomReports_ReportUpdated'), response.type);
});
},
- checkRequiredFieldsAreSet: function checkRequiredFieldsAreSet() {
+ checkRequiredFieldsAreSet() {
var _this$report$metrics3;
-
if (!this.report.name) {
- var title = Object(external_CoreHome_["translate"])('General_Name');
+ const title = Object(external_CoreHome_["translate"])('General_Name');
this.showErrorFieldNotProvidedNotification(title);
return false;
}
-
if (this.report.report_type !== 'evolution') {
var _this$report$dimensio3;
-
if (!((_this$report$dimensio3 = this.report.dimensions) !== null && _this$report$dimensio3 !== void 0 && _this$report$dimensio3.length) || !Editvue_type_script_lang_ts_arrayFilterAndRemoveDuplicates(this.report.dimensions).length) {
- var _title = Object(external_CoreHome_["translate"])('CustomReports_ErrorMissingDimension');
-
- this.showNotification(_title, 'error');
+ const title = Object(external_CoreHome_["translate"])('CustomReports_ErrorMissingDimension');
+ this.showNotification(title, 'error');
return false;
}
}
-
if (!((_this$report$metrics3 = this.report.metrics) !== null && _this$report$metrics3 !== void 0 && _this$report$metrics3.length) || !Editvue_type_script_lang_ts_arrayFilterAndRemoveDuplicates(this.report.metrics).length) {
- var _title2 = Object(external_CoreHome_["translate"])('CustomReports_ErrorMissingMetric');
-
- this.showNotification(_title2, 'error');
+ const title = Object(external_CoreHome_["translate"])('CustomReports_ErrorMissingMetric');
+ this.showNotification(title, 'error');
return false;
- } // Don't fail validation since we automatically add the dependency
-
-
+ }
+ // Don't fail validation since we automatically add the dependency
this.isProductRevenueDependencyMet(false);
return true;
},
- setSubcategory: function setSubcategory(subcategoryId) {
+ setSubcategory(subcategoryId) {
this.report.subcategory = this.report.subcategory || {
id: ''
};
this.report.subcategory.id = subcategoryId;
},
- isProductRevenueDependencyMet: function isProductRevenueDependencyMet(shouldScrollToNotification) {
- var linkString = Object(external_CoreHome_["externalLink"])('https://matomo.org/faq/custom-reports/why-is-there-an-error-when-i-try-to-run-a-custom-report-with-the-product-revenue-metric/');
- var notificationText = Object(external_CoreHome_["translate"])('CustomReports_WarningProductRevenueMetricDependency', linkString, '');
-
+ isProductRevenueDependencyMet(shouldScrollToNotification) {
+ const linkString = Object(external_CoreHome_["externalLink"])('https://matomo.org/faq/custom-reports/why-is-there-an-error-when-i-try-to-run-a-custom-report-with-the-product-revenue-metric/');
+ const notificationText = Object(external_CoreHome_["translate"])('CustomReports_WarningProductRevenueMetricDependency', linkString, '');
if (this.report.metrics.includes('sum_product_revenue') && !this.doesReportIncludeProductQuantityMetric()) {
this.addMetric('sum_ecommerce_productquantity');
this.showProductMetricNotification(notificationText, shouldScrollToNotification);
return false;
}
-
if (this.report.metrics.includes('avg_product_revenue') && !this.doesReportIncludeProductQuantityMetric()) {
this.addMetric('avg_ecommerce_productquantity');
this.showProductMetricNotification(notificationText, shouldScrollToNotification);
return false;
}
-
return true;
},
- doesReportIncludeProductQuantityMetric: function doesReportIncludeProductQuantityMetric() {
+ doesReportIncludeProductQuantityMetric() {
return this.report.metrics.includes('sum_ecommerce_productquantity') || this.report.metrics.includes('avg_ecommerce_productquantity');
},
- isSiteIncludedAlready: function isSiteIncludedAlready(idSite) {
+ isSiteIncludedAlready(idSite) {
if (this.multipleSites && this.multipleSites.length) {
- return this.multipleSites.some(function (item) {
- return "".concat(item.idsite) === "".concat(idSite);
- });
+ return this.multipleSites.some(item => `${item.idsite}` === `${idSite}`);
}
-
return false;
},
- removeSite: function removeSite(site) {
+ removeSite(site) {
if (this.multipleSites) {
this.isDirty = true;
- this.multipleSites = this.multipleSites.filter(function (item) {
- return item.idsite !== site.idsite;
- });
+ this.multipleSites = this.multipleSites.filter(item => item.idsite !== site.idsite);
}
},
- addSitesContaining: function addSitesContaining(searchTerm) {
- var _this14 = this;
-
+ addSitesContaining(searchTerm) {
if (!searchTerm) {
return;
}
-
- var displaySearchTerm = "\"".concat(external_CoreHome_["Matomo"].helper.escape(external_CoreHome_["Matomo"].helper.htmlEntities(searchTerm)), "\"");
+ const displaySearchTerm = `"${external_CoreHome_["Matomo"].helper.escape(external_CoreHome_["Matomo"].helper.htmlEntities(searchTerm))}"`;
external_CoreHome_["AjaxHelper"].fetch({
method: 'SitesManager.getSitesWithAdminAccess',
pattern: searchTerm,
filter_limit: -1
- }).then(function (sites) {
+ }).then(sites => {
if (!sites || !sites.length) {
- var _sitesToAdd = "
${t}`:e},getDimensionsHelpTextExtended(){if(this.isCloud)return"";const e=Object(ot["externalLink"])("https://matomo.org/faq/custom-reports/faq_25655/");return Object(ot["translate"])("CustomReports_ReportDimensionsHelpExtended",e,"")}}});bt.render=tt;var vt=bt;const Ot={class:"reportSearchFilter"},jt={class:"index"},gt={class:"name"},Rt={class:"description"},yt={class:"reportType"},Ct={class:"reportCategory"},ft={class:"action"},St={colspan:"7"},Et={class:"loadingPiwik"},Nt=Object(s["createElementVNode"])("img",{src:"plugins/Morpheus/images/loading-blue.gif"},null,-1),kt={colspan:"7"},Vt=["id"],wt={class:"index"},Dt={class:"name"},_t=["title"],Mt=["title"],At=["title"],Bt=["title"],Ut=["title"],It={class:"reportType"},Lt=["title"],Tt={key:0},xt=["title","onClick"],Pt=["title","onClick"],Ht=["title","onClick"],Gt=["title","href"],Ft={key:0},qt=["title","onClick"],$t={class:"tableActionBar"},Wt=Object(s["createElementVNode"])("span",{class:"icon-add"},null,-1),zt={class:"ui-confirm",ref:"confirmDeleteReport"},Yt=["value"],Qt=["value"],Xt={class:"ui-confirm",ref:"confirmPauseReport"},Jt=["value"],Kt=["value"],Zt={class:"ui-confirm",ref:"confirmResumeReport"},eo=["value"],to=["value"];function oo(e,t,o,i,r,n){const a=Object(s["resolveComponent"])("Field"),l=Object(s["resolveComponent"])("EntityDuplicatorAction"),c=Object(s["resolveComponent"])("ContentBlock"),d=Object(s["resolveComponent"])("EntityDuplicatorModal"),p=Object(s["resolveDirective"])("content-table");return Object(s["openBlock"])(),Object(s["createElementBlock"])(s["Fragment"],null,[Object(s["createElementVNode"])("div",null,[Object(s["createVNode"])(c,{"content-title":e.translate("CustomReports_ManageReports"),feature:e.translate("CustomReports_ManageReports")},{default:Object(s["withCtx"])(()=>[Object(s["createElementVNode"])("p",null,Object(s["toDisplayString"])(e.translate("CustomReports_CustomReportIntroduction")),1),Object(s["createElementVNode"])("div",Ot,[Object(s["withDirectives"])(Object(s["createVNode"])(a,{uicontrol:"text",name:"reportSearch",title:e.translate("General_Search"),modelValue:e.searchFilter,"onUpdate:modelValue":t[0]||(t[0]=t=>e.searchFilter=t)},null,8,["title","modelValue"]),[[s["vShow"],e.reports.length>0]])]),Object(s["withDirectives"])((Object(s["openBlock"])(),Object(s["createElementBlock"])("table",null,[Object(s["createElementVNode"])("thead",null,[Object(s["createElementVNode"])("tr",null,[Object(s["createElementVNode"])("th",jt,Object(s["toDisplayString"])(e.translate("General_Id")),1),Object(s["createElementVNode"])("th",gt,Object(s["toDisplayString"])(e.translate("General_Name")),1),Object(s["createElementVNode"])("th",Rt,Object(s["toDisplayString"])(e.translate("General_Description")),1),Object(s["createElementVNode"])("th",yt,Object(s["toDisplayString"])(e.translate("CustomReports_Type")),1),Object(s["createElementVNode"])("th",Ct,Object(s["toDisplayString"])(e.translate("CustomReports_Category")),1),Object(s["createElementVNode"])("th",ft,Object(s["toDisplayString"])(e.translate("General_Actions")),1)])]),Object(s["createElementVNode"])("tbody",null,[Object(s["withDirectives"])(Object(s["createElementVNode"])("tr",null,[Object(s["createElementVNode"])("td",St,[Object(s["createElementVNode"])("span",Et,[Nt,Object(s["createTextVNode"])(" "+Object(s["toDisplayString"])(e.translate("General_LoadingData")),1)])])],512),[[s["vShow"],e.isLoading||e.isUpdating]]),Object(s["withDirectives"])(Object(s["createElementVNode"])("tr",null,[Object(s["createElementVNode"])("td",kt,Object(s["toDisplayString"])(e.translate("CustomReports_NoCustomReportsFound")),1)],512),[[s["vShow"],!e.isLoading&&0==e.reports.length]]),(Object(s["openBlock"])(!0),Object(s["createElementBlock"])(s["Fragment"],null,Object(s["renderList"])(e.sortedReports,t=>{var o;return Object(s["openBlock"])(),Object(s["createElementBlock"])("tr",{id:"report"+t.idcustomreport,class:"customReports",key:t.idcustomreport},[Object(s["createElementVNode"])("td",wt,Object(s["toDisplayString"])(t.idcustomreport),1),Object(s["createElementVNode"])("td",Dt,[Object(s["createTextVNode"])(Object(s["toDisplayString"])(t.name)+" ",1),Object(s["withDirectives"])(Object(s["createElementVNode"])("span",{class:"icon-locked",title:e.translate("CustomReports_ReportEditNotAllowedAllWebsitesUpdated")},null,8,_t),[[s["vShow"],!t.idsite&&!e.isSuperUser]]),Object(s["withDirectives"])(Object(s["createElementVNode"])("span",{class:"icon-info2",title:e.translate("CustomReports_ReportAvailableToAllWebsites")},null,8,Mt),[[s["vShow"],!t.idsite&&e.isSuperUser]]),Object(s["withDirectives"])(Object(s["createElementVNode"])("span",{class:"icon-locked",title:e.translate("CustomReports_ReportEditNotAllowedMultipleWebsitesAccessIssue")},null,8,At),[[s["vShow"],!t.allowedToEdit&&e.isMultiSiteReport(t)]]),Object(s["withDirectives"])(Object(s["createElementVNode"])("span",{class:"icon-info2",title:e.translate("CustomReports_ReportAvailableToMultipleWebsites")},null,8,Bt),[[s["vShow"],t.allowedToEdit&&e.isMultiSiteReport(t)]])]),Object(s["createElementVNode"])("td",{class:"description",title:e.htmlEntities(t.description)},Object(s["toDisplayString"])(e.truncate(t.description.trim(),60)),9,Ut),Object(s["createElementVNode"])("td",It,Object(s["toDisplayString"])(e.reportTypesReadable[t.report_type]),1),Object(s["createElementVNode"])("td",{class:"reportCategory",title:e.htmlEntities(t.category.name)},[Object(s["createTextVNode"])(Object(s["toDisplayString"])(e.truncate(t.category.name.trim(),60))+" ",1),null!==(o=t.subcategory)&&void 0!==o&&o.name?(Object(s["openBlock"])(),Object(s["createElementBlock"])("span",Tt," - "+Object(s["toDisplayString"])(e.truncate(t.subcategory.name.trim(),60)),1)):Object(s["createCommentVNode"])("",!0)],8,Lt),Object(s["createElementVNode"])("td",{class:Object(s["normalizeClass"])({action:!0,"duplicate-available":e.isEntityDuplicatorAvailable})},[Object(s["withDirectives"])(Object(s["createElementVNode"])("a",{class:"table-action icon-pause",title:e.translate("CustomReports_PauseReportInfo"),onClick:o=>e.pauseReport(t)},null,8,xt),[[s["vShow"],(t.idsite&&!e.isMultiSiteReport(t)||t.allowedToEdit)&&"active"===t.status]]),Object(s["withDirectives"])(Object(s["createElementVNode"])("a",{class:"table-action icon-play",title:e.translate("CustomReports_ResumeReportInfo"),onClick:o=>e.resumeReport(t)},null,8,Pt),[[s["vShow"],(t.idsite&&!e.isMultiSiteReport(t)||t.allowedToEdit)&&"paused"===t.status]]),Object(s["createElementVNode"])("a",{class:"table-action icon-edit",title:e.translate("CustomReports_EditReport"),onClick:o=>e.editReport(t.idcustomreport)},null,8,Ht),Object(s["createElementVNode"])("a",{target:"_blank",class:"table-action icon-show",title:e.translate("CustomReports_ViewReportInfo"),href:e.getViewReportLink(t)},null,8,Gt),e.isEntityDuplicatorAvailable&&(t.idsite&&!e.isMultiSiteReport(t)||t.allowedToEdit)?(Object(s["openBlock"])(),Object(s["createElementBlock"])("span",Ft,[Object(s["createVNode"])(l,{actionFormData:{idCustomReport:t.idcustomreport},modalStore:e.entityDuplicatorStore,isActionVisible:e.showDuplicatorAction,isActionEnabled:e.enableDuplicatorAction,tooltipTextOverrideDisabled:e.translate("CustomReports_QuotaReachedForX",e.translate("CustomReports_CustomReport"),e.translate("CustomReports_CustomReports")),extraClasses:["customreport-duplicate-action","customreport-"+t.idcustomreport]},null,8,["actionFormData","modalStore","isActionVisible","isActionEnabled","tooltipTextOverrideDisabled","extraClasses"])])):Object(s["createCommentVNode"])("",!0),Object(s["withDirectives"])(Object(s["createElementVNode"])("a",{class:"table-action icon-delete",title:e.translate("CustomReports_DeleteReportInfo"),onClick:o=>e.deleteReport(t)},null,8,qt),[[s["vShow"],t.idsite&&!e.isMultiSiteReport(t)||t.allowedToEdit]])],2)],8,Vt)}),128))])])),[[p]]),Object(s["createElementVNode"])("div",$t,[Object(s["createElementVNode"])("a",{class:"createNewReport",onClick:t[1]||(t[1]=t=>e.createReport())},[Wt,Object(s["createTextVNode"])(" "+Object(s["toDisplayString"])(e.translate("CustomReports_CreateNewReport")),1)])])]),_:1},8,["content-title","feature"]),Object(s["createElementVNode"])("div",zt,[Object(s["createElementVNode"])("h2",null,Object(s["toDisplayString"])(e.translate("CustomReports_DeleteReportConfirm")),1),Object(s["createElementVNode"])("input",{role:"yes",type:"button",value:e.translate("General_Yes")},null,8,Yt),Object(s["createElementVNode"])("input",{role:"no",type:"button",value:e.translate("General_No")},null,8,Qt)],512),Object(s["createElementVNode"])("div",Xt,[Object(s["createElementVNode"])("h2",null,Object(s["toDisplayString"])(e.translate("CustomReports_PauseReportConfirm")),1),Object(s["createElementVNode"])("input",{role:"yes",type:"button",value:e.translate("General_Yes")},null,8,Jt),Object(s["createElementVNode"])("input",{role:"no",type:"button",value:e.translate("General_No")},null,8,Kt)],512),Object(s["createElementVNode"])("div",Zt,[Object(s["createElementVNode"])("h2",null,Object(s["toDisplayString"])(e.translate("CustomReports_ResumeReportConfirm")),1),Object(s["createElementVNode"])("input",{role:"yes",type:"button",value:e.translate("General_Yes")},null,8,eo),Object(s["createElementVNode"])("input",{role:"no",type:"button",value:e.translate("General_No")},null,8,to)],512)]),Object(s["createVNode"])(d,{modalStore:e.entityDuplicatorStore},null,8,["modalStore"])],64)}
+/**
+ * Copyright (C) InnoCraft Ltd - All rights reserved.
+ *
+ * NOTICE: All information contained herein is, and remains the property of InnoCraft Ltd.
+ * The intellectual and technical concepts contained herein are protected by trade secret
+ * or copyright law. Redistribution of this information or reproduction of this material is
+ * strictly forbidden unless prior written permission is obtained from InnoCraft Ltd.
+ *
+ * You shall use this code only in accordance with the license agreement obtained from
+ * InnoCraft Ltd.
+ *
+ * @link https://www.innocraft.com/
+ * @license For license details see https://www.innocraft.com/license
+ */function io(e,t){return e&&e.length>t?e.substr(0,t-3)+"...":e}const ro=Object(ot["useExternalPluginComponent"])("CoreHome","EntityDuplicatorModal"),so=Object(ot["useExternalPluginComponent"])("CoreHome","EntityDuplicatorAction");let no=void 0;Object(ot["importPluginUmd"])("CoreHome").then(e=>{no=null===e||void 0===e?void 0:e.EntityDuplicatorStore});const ao="customreportmanagementlist";var lo=Object(s["defineComponent"])({props:{},components:{ContentBlock:ot["ContentBlock"],Field:it["Field"],EntityDuplicatorModal:ro,EntityDuplicatorAction:so},directives:{ContentTable:ot["ContentTable"]},data(){return{searchFilter:"",showDuplicatorAction:!0,enableDuplicatorAction:!1,entityDuplicatorStore:"undefined"!==typeof no?no.buildStoreInstance("CustomReports_CustomReport",{method:"CustomReports.duplicateCustomReport",requiredFields:["idSite","idDestinationSites","idCustomReport"]}):void 0}},created(){dt.getAvailableReportTypes(),dt.fetchReports()},mounted(){if(this.checkIsAddingCustomReportsAllowed(),this.entityDuplicatorStore){const e=this.entityDuplicatorStore.adapter;e.onSuccessCallback=e=>new Promise(t=>{var o,i,r;const s=null===(o=e.additionalData)||void 0===o?void 0:o.idSite;return null!==(i=e.additionalData)&&void 0!==i&&i.idSite&&Array.isArray(null===(r=e.additionalData)||void 0===r?void 0:r.idDestinationSites)&&!e.additionalData.idDestinationSites.some(e=>+e===+s)?t():dt.reload().then(()=>t())})}},methods:{createReport(){this.editReport(0)},checkIsAddingCustomReportsAllowed(){const e={isAllowed:!0};return ot["Matomo"].postEvent("CustomReports.initAddCustomReport",e),this.enableDuplicatorAction=e&&!0===e.isAllowed,!this.enableDuplicatorAction},editReport(e){ot["MatomoUrl"].updateHash(Object.assign(Object.assign({},ot["MatomoUrl"].hashParsed.value),{},{idCustomReport:e}))},pauseReport(e){ot["Matomo"].helper.modalConfirm(this.$refs.confirmPauseReport,{yes:()=>{dt.pauseReport(e.idcustomreport,e.idsite).then(e=>{e&&"error"!==e.type?(dt.reload().then(()=>{this.showNotification(this.translate("CustomReports_PausedReport"),"success")}),ot["Matomo"].postEvent("updateReportingMenu")):dt.reload()})}})},resumeReport(e){ot["Matomo"].helper.modalConfirm(this.$refs.confirmResumeReport,{yes:()=>{dt.resumeReport(e.idcustomreport,e.idsite).then(e=>{e&&"error"!==e.type?(dt.reload().then(()=>{this.showNotification(this.translate("CustomReports_ResumedReport"),"success")}),ot["Matomo"].postEvent("updateReportingMenu")):dt.reload()})}})},showNotification(e,t,o=null){const i=ot["NotificationsStore"].show({message:e,context:t,id:ao,type:null!==o?o:"toast"});setTimeout(()=>{ot["NotificationsStore"].scrollToNotification(i)},200)},deleteReport(e){ot["Matomo"].helper.modalConfirm(this.$refs.confirmDeleteReport,{yes:()=>{dt.deleteReport(e.idcustomreport,e.idsite).then(()=>{dt.reload(),ot["Matomo"].postEvent("updateReportingMenu")})}})},getViewReportLink(e){return`?${ot["MatomoUrl"].stringify({module:"CoreHome",action:"index",idSite:e.linkIdSite,period:"day",date:"yesterday"})}#?${ot["MatomoUrl"].stringify({category:e.category.id,idSite:e.linkIdSite,date:ot["MatomoUrl"].parsed.value.date,period:ot["MatomoUrl"].parsed.value.period,segment:ot["MatomoUrl"].parsed.value.segment,subcategory:e.subcategoryLink})}`},truncate:io,htmlEntities(e){return ot["Matomo"].helper.htmlEntities(e)},isMultiSiteReport(e){return e.multiple_idsites&&e.multiple_idsites.split(",")}},computed:{isSuperUser(){return ot["Matomo"].hasSuperUserAccess},reports(){return dt.state.value.reports},sortedReports(){const e=this.searchFilter.toLowerCase(),t=[...this.reports].filter(t=>Object.keys(t).some(o=>{const i=t;return"string"===typeof i[o]&&-1!==i[o].toLowerCase().indexOf(e)}));return t.sort((e,t)=>{const o=parseInt(""+e.idcustomreport,10),i=parseInt(""+t.idcustomreport,10);return o-i}),t},isLoading(){return dt.state.value.isLoading},isUpdating(){return dt.state.value.isUpdating},reportTypesReadable(){return dt.state.value.reportTypesReadable},isEntityDuplicatorAvailable(){return"undefined"!==typeof no}}});lo.render=oo;var co=lo;const po={class:"manageReports"},mo={key:0},uo={key:1};function ho(e,t,o,i,r,n){const a=Object(s["resolveComponent"])("CustomReportsList"),l=Object(s["resolveComponent"])("CustomReportsEdit");return Object(s["openBlock"])(),Object(s["createElementBlock"])("div",po,[e.editMode?Object(s["createCommentVNode"])("",!0):(Object(s["openBlock"])(),Object(s["createElementBlock"])("div",mo,[Object(s["createVNode"])(a)])),e.editMode?(Object(s["openBlock"])(),Object(s["createElementBlock"])("div",uo,[Object(s["createVNode"])(l,{"id-custom-report":e.idCustomReport,"browser-archiving-disabled":e.browserArchivingDisabled,"re-archive-last-n":e.reArchiveLastN,"max-dimensions":e.maxDimensions,"is-cloud":e.isCloud},null,8,["id-custom-report","browser-archiving-disabled","re-archive-last-n","max-dimensions","is-cloud"])])):Object(s["createCommentVNode"])("",!0)])}var bo=Object(s["defineComponent"])({props:{browserArchivingDisabled:Boolean,reArchiveLastN:Number,maxDimensions:Number,isCloud:Boolean},components:{CustomReportsList:co,CustomReportsEdit:vt},data(){return{editMode:!1,idCustomReport:null}},watch:{editMode(){$(".ui-tooltip").remove()}},created(){Object(s["watch"])(()=>ot["MatomoUrl"].hashParsed.value.idCustomReport,e=>{this.initState(e)}),this.initState(ot["MatomoUrl"].hashParsed.value.idCustomReport)},methods:{removeAnyReportNotification(e=!0){ot["NotificationsStore"].remove("reportsmanagement"),e&&ot["NotificationsStore"].remove("reportsmanagementProductMetric")},initState(e){if(e){if("0"===e){const e={isAllowed:!0};if(ot["Matomo"].postEvent("CustomReports.initAddReport",e),e&&!e.isAllowed)return this.editMode=!1,void(this.idCustomReport=null)}this.editMode=!0,this.idCustomReport=parseInt(e,10)}else this.editMode=!1,this.idCustomReport=null;this.removeAnyReportNotification(!e)}}});bo.render=ho;var vo=bo;
+/**
+ * Copyright (C) InnoCraft Ltd - All rights reserved.
+ *
+ * NOTICE: All information contained herein is, and remains the property of InnoCraft Ltd.
+ * The intellectual and technical concepts contained herein are protected by trade secret
+ * or copyright law. Redistribution of this information or reproduction of this material is
+ * strictly forbidden unless prior written permission is obtained from InnoCraft Ltd.
+ *
+ * You shall use this code only in accordance with the license agreement obtained from
+ * InnoCraft Ltd.
+ *
+ * @link https://www.innocraft.com/
+ * @license For license details see https://www.innocraft.com/license
+ */}})}));
+//# sourceMappingURL=CustomReports.umd.min.js.map
\ No newline at end of file
diff --git a/files/plugin-CustomReports-5.4.3/vue/dist/umd.metadata.json b/files/plugin-CustomReports-5.4.5/vue/dist/umd.metadata.json
similarity index 100%
rename from files/plugin-CustomReports-5.4.3/vue/dist/umd.metadata.json
rename to files/plugin-CustomReports-5.4.5/vue/dist/umd.metadata.json
diff --git a/files/plugin-CustomReports-5.4.3/vue/src/CustomReports.store.ts b/files/plugin-CustomReports-5.4.5/vue/src/CustomReports.store.ts
similarity index 100%
rename from files/plugin-CustomReports-5.4.3/vue/src/CustomReports.store.ts
rename to files/plugin-CustomReports-5.4.5/vue/src/CustomReports.store.ts
diff --git a/files/plugin-CustomReports-5.4.3/vue/src/Reports/Edit.less b/files/plugin-CustomReports-5.4.5/vue/src/Reports/Edit.less
similarity index 100%
rename from files/plugin-CustomReports-5.4.3/vue/src/Reports/Edit.less
rename to files/plugin-CustomReports-5.4.5/vue/src/Reports/Edit.less
diff --git a/files/plugin-CustomReports-5.4.3/vue/src/Reports/Edit.vue b/files/plugin-CustomReports-5.4.5/vue/src/Reports/Edit.vue
similarity index 100%
rename from files/plugin-CustomReports-5.4.3/vue/src/Reports/Edit.vue
rename to files/plugin-CustomReports-5.4.5/vue/src/Reports/Edit.vue
diff --git a/files/plugin-CustomReports-5.4.3/vue/src/Reports/List.less b/files/plugin-CustomReports-5.4.5/vue/src/Reports/List.less
similarity index 90%
rename from files/plugin-CustomReports-5.4.3/vue/src/Reports/List.less
rename to files/plugin-CustomReports-5.4.5/vue/src/Reports/List.less
index f32f753..0b28ef0 100644
--- a/files/plugin-CustomReports-5.4.3/vue/src/Reports/List.less
+++ b/files/plugin-CustomReports-5.4.5/vue/src/Reports/List.less
@@ -37,6 +37,10 @@
}
}
+ th.action.duplicate-available, td.action.duplicate-available {
+ width: 280px;
+ }
+
.index {
width: 60px;
}
diff --git a/files/plugin-CustomReports-5.4.3/vue/src/Reports/List.vue b/files/plugin-CustomReports-5.4.5/vue/src/Reports/List.vue
similarity index 73%
rename from files/plugin-CustomReports-5.4.3/vue/src/Reports/List.vue
rename to files/plugin-CustomReports-5.4.5/vue/src/Reports/List.vue
index 61cacf4..910c7a9 100644
--- a/files/plugin-CustomReports-5.4.3/vue/src/Reports/List.vue
+++ b/files/plugin-CustomReports-5.4.5/vue/src/Reports/List.vue
@@ -93,7 +93,10 @@
- {{ truncate(report.subcategory.name.trim(), 60) }}
-
+
+
+
+
+
+
diff --git a/files/plugin-CustomReports-5.4.3/vue/src/Reports/Manage.vue b/files/plugin-CustomReports-5.4.5/vue/src/Reports/Manage.vue
similarity index 100%
rename from files/plugin-CustomReports-5.4.3/vue/src/Reports/Manage.vue
rename to files/plugin-CustomReports-5.4.5/vue/src/Reports/Manage.vue
diff --git a/files/plugin-CustomReports-5.4.3/vue/src/index.ts b/files/plugin-CustomReports-5.4.5/vue/src/index.ts
similarity index 100%
rename from files/plugin-CustomReports-5.4.3/vue/src/index.ts
rename to files/plugin-CustomReports-5.4.5/vue/src/index.ts
diff --git a/files/plugin-CustomReports-5.4.3/vue/src/truncateText2.ts b/files/plugin-CustomReports-5.4.5/vue/src/truncateText2.ts
similarity index 100%
rename from files/plugin-CustomReports-5.4.3/vue/src/truncateText2.ts
rename to files/plugin-CustomReports-5.4.5/vue/src/truncateText2.ts
diff --git a/files/plugin-CustomReports-5.4.3/vue/src/types.ts b/files/plugin-CustomReports-5.4.5/vue/src/types.ts
similarity index 100%
rename from files/plugin-CustomReports-5.4.3/vue/src/types.ts
rename to files/plugin-CustomReports-5.4.5/vue/src/types.ts
diff --git a/files/plugin-HeatmapSessionRecording-5.2.4/API.php b/files/plugin-HeatmapSessionRecording-5.2.4/API.php
deleted file mode 100644
index 8dd9ecc..0000000
--- a/files/plugin-HeatmapSessionRecording-5.2.4/API.php
+++ /dev/null
@@ -1,999 +0,0 @@
-validator = $validator;
- $this->aggregator = $aggregator;
- $this->siteHsr = $siteHsr;
- $this->logHsr = $logHsr;
- $this->logEvent = $logEvent;
- $this->logHsrSite = $logHsrSite;
- $this->systemSettings = $settings;
- $this->configuration = $configuration;
-
- $dir = Plugin\Manager::getPluginDirectory('UserCountry');
- require_once $dir . '/functions.php';
- }
-
- /**
- * Adds a new heatmap.
- *
- * Once added, the system will start recording activities for this heatmap.
- *
- * @param int $idSite
- * @param string $name The name of heatmap which will be visible in the reporting UI.
- * @param array $matchPageRules Eg. array(array('attribute' => 'url', 'type' => 'equals_simple', 'inverted' => 0, 'value' => 'http://example.com/directory'))
- * For a list of available attribute and type values call {@link getAvailableTargetPageRules()}.
- * "inverted" should be "0" or "1".
- * @param int $sampleLimit The number of page views you want to record. Once the sample limit has been reached, the heatmap will be ended automatically.
- * @param float $sampleRate Needs to be between 0 and 100 where 100 means => 100%, 10 => 10%, 0.1 => 0.1%.
- * Defines how often a visitor will be actually recorded when they match the page rules, also known as "traffic". Currently max one decimal is supported.
- * @param string $excludedElements Optional, a comma separated list of CSS selectors to exclude elements from being shown in the heatmap. For example to disable popups etc.
- * @param string $screenshotUrl Optional, a URL to define on which page a screenshot should be taken.
- * @param int $breakpointMobile If the device type cannot be detected, we will put any device having a lower width than this value into the mobile category. Useful if your website is responsive.
- * @param int $breakpointTablet If the device type cannot be detected, we will put any device having a lower width than this value into the tablet category. Useful if your website is responsive.
- * @return int
- */
- public function addHeatmap($idSite, $name, $matchPageRules, $sampleLimit = 1000, $sampleRate = 5, $excludedElements = false, $screenshotUrl = false, $breakpointMobile = false, $breakpointTablet = false, $captureDomManually = false)
- {
- $this->validator->checkHeatmapReportWritePermission($idSite);
-
- if ($breakpointMobile === false || $breakpointMobile === null) {
- $breakpointMobile = $this->systemSettings->breakpointMobile->getValue();
- }
-
- if ($breakpointTablet === false || $breakpointTablet === null) {
- $breakpointTablet = $this->systemSettings->breakpointTablet->getValue();
- }
-
- $createdDate = Date::now()->getDatetime();
-
- $matchPageRules = $this->unsanitizePageRules($matchPageRules);
- $screenshotUrl = $this->unsanitizeScreenshotUrl($screenshotUrl);
-
- return $this->siteHsr->addHeatmap($idSite, $name, $matchPageRules, $sampleLimit, $sampleRate, $excludedElements, $screenshotUrl, $breakpointMobile, $breakpointTablet, $captureDomManually, $createdDate);
- }
-
- private function unsanitizeScreenshotUrl($screenshotUrl)
- {
- if (!empty($screenshotUrl) && is_string($screenshotUrl)) {
- $screenshotUrl = Common::unsanitizeInputValue($screenshotUrl);
- }
-
- return $screenshotUrl;
- }
-
- private function unsanitizePageRules($matchPageRules)
- {
- if (!empty($matchPageRules) && is_array($matchPageRules)) {
- foreach ($matchPageRules as $index => $matchPageRule) {
- if (is_array($matchPageRule) && !empty($matchPageRule['value'])) {
- $matchPageRules[$index]['value'] = Common::unsanitizeInputValue($matchPageRule['value']);
- }
- }
- }
- return $matchPageRules;
- }
-
- /**
- * Updates an existing heatmap.
- *
- * All fields need to be set in order to update a heatmap. Easiest way is to get all values for a heatmap via
- * "HeatmapSessionRecording.getHeatmap", make the needed changes on the heatmap, and send all values back to
- * "HeatmapSessionRecording.updateHeatmap".
- *
- * @param int $idSite
- * @param int $idSiteHsr The id of the heatmap you want to update.
- * @param string $name The name of heatmap which will be visible in the reporting UI.
- * @param array $matchPageRules Eg. array(array('attribute' => 'url', 'type' => 'equals_simple', 'inverted' => 0, 'value' => 'http://example.com/directory'))
- * For a list of available attribute and type values call {@link getAvailableTargetPageRules()}.
- * "inverted" should be "0" or "1".
- * @param int $sampleLimit The number of page views you want to record. Once the sample limit has been reached, the heatmap will be ended automatically.
- * @param float $sampleRate Needs to be between 0 and 100 where 100 means => 100%, 10 => 10%, 0.1 => 0.1%.
- * Defines how often a visitor will be actually recorded when they match the page rules, also known as "traffic". Currently max one decimal is supported.
- * @param string $excludedElements Optional, a comma separated list of CSS selectors to exclude elements from being shown in the heatmap. For example to disable popups etc.
- * @param string $screenshotUrl Optional, a URL to define on which page a screenshot should be taken.
- * @param int $breakpointMobile If the device type cannot be detected, we will put any device having a lower width than this value into the mobile category. Useful if your website is responsive.
- * @param int $breakpointTablet If the device type cannot be detected, we will put any device having a lower width than this value into the tablet category. Useful if your website is responsive.
- */
- public function updateHeatmap($idSite, $idSiteHsr, $name, $matchPageRules, $sampleLimit = 1000, $sampleRate = 5, $excludedElements = false, $screenshotUrl = false, $breakpointMobile = false, $breakpointTablet = false, $captureDomManually = false)
- {
- $this->validator->checkHeatmapReportWritePermission($idSite);
- $this->siteHsr->checkHeatmapExists($idSite, $idSiteHsr);
-
- if ($breakpointMobile === false || $breakpointMobile === null) {
- $breakpointMobile = $this->systemSettings->breakpointMobile->getValue();
- }
-
- if ($breakpointTablet === false || $breakpointTablet === null) {
- $breakpointTablet = $this->systemSettings->breakpointTablet->getValue();
- }
-
- $updatedDate = Date::now()->getDatetime();
-
- $matchPageRules = $this->unsanitizePageRules($matchPageRules);
- $screenshotUrl = $this->unsanitizeScreenshotUrl($screenshotUrl);
-
- $this->siteHsr->updateHeatmap($idSite, $idSiteHsr, $name, $matchPageRules, $sampleLimit, $sampleRate, $excludedElements, $screenshotUrl, $breakpointMobile, $breakpointTablet, $captureDomManually, $updatedDate);
- }
-
- /**
- * Deletes / removes the screenshot from a heatmap
- * @param int $idSite
- * @param int $idSiteHsr
- * @return bool
- * @throws Exception
- */
- public function deleteHeatmapScreenshot($idSite, $idSiteHsr)
- {
- $this->validator->checkHeatmapReportWritePermission($idSite);
- $this->siteHsr->checkHeatmapExists($idSite, $idSiteHsr);
-
- $heatmap = $this->siteHsr->getHeatmap($idSite, $idSiteHsr);
- if (!empty($heatmap['status']) && $heatmap['status'] === SiteHsrDao::STATUS_ACTIVE) {
- $this->siteHsr->setPageTreeMirror($idSite, $idSiteHsr, null, null);
-
- if (!empty($heatmap['page_treemirror'])) {
- // only needed when a screenshot existed before that
- Cache::deleteCacheWebsiteAttributes($idSite);
- }
- return true;
- } elseif (!empty($heatmap['status'])) {
- throw new Exception('The screenshot can be only removed from active heatmaps');
- }
- }
-
- /**
- * Adds a new session recording.
- *
- * Once added, the system will start recording sessions.
- *
- * @param int $idSite
- * @param string $name The name of session recording which will be visible in the reporting UI.
- * @param array $matchPageRules Eg. array(array('attribute' => 'url', 'type' => 'equals_simple', 'inverted' => 0, 'value' => 'http://example.com/directory'))
- * For a list of available attribute and type values call {@link getAvailableTargetPageRules()}.
- * "inverted" should be "0" or "1". Leave it empty to record any page.
- * If page rules are set, a session will be only recorded as soon as a visitor has reached a page that matches these rules.
- * @param int $sampleLimit The number of sessions you want to record. Once the sample limit has been reached, the session recording will be ended automatically.
- * @param float $sampleRate Needs to be between 0 and 100 where 100 means => 100%, 10 => 10%, 0.1 => 0.1%.
- * Defines how often a visitor will be actually recorded when they match the page rules, also known as "traffic". Currently max one decimal is supported.
- * @param int $minSessionTime If defined, will only record sessions when the visitor has spent more than this many seconds on the current page.
- * @param int $requiresActivity If enabled (default), the session will be only recorded if the visitor has at least scrolled and clicked once.
- * @param int $captureKeystrokes If enabled (default), any text that a user enters into text form elements will be recorded.
- * Password fields will be automatically masked and you can mask other elements with sensitive data using a data-matomo-mask attribute.
- * @return int
- */
- public function addSessionRecording($idSite, $name, $matchPageRules = array(), $sampleLimit = 1000, $sampleRate = 10, $minSessionTime = 0, $requiresActivity = true, $captureKeystrokes = true)
- {
- $this->validator->checkSessionReportWritePermission($idSite);
-
- $createdDate = Date::now()->getDatetime();
-
- $matchPageRules = $this->unsanitizePageRules($matchPageRules);
-
- return $this->siteHsr->addSessionRecording($idSite, $name, $matchPageRules, $sampleLimit, $sampleRate, $minSessionTime, $requiresActivity, $captureKeystrokes, $createdDate);
- }
-
- /**
- * Updates an existing session recording.
- *
- * All fields need to be set in order to update a session recording. Easiest way is to get all values for a
- * session recording via "HeatmapSessionRecording.getSessionRecording", make the needed changes on the recording,
- * and send all values back to "HeatmapSessionRecording.updateSessionRecording".
- *
- * @param int $idSite
- * @param int $idSiteHsr The id of the session recording you want to update.
- * @param string $name The name of session recording which will be visible in the reporting UI.
- * @param array $matchPageRules Eg. array(array('attribute' => 'url', 'type' => 'equals_simple', 'inverted' => 0, 'value' => 'http://example.com/directory'))
- * For a list of available attribute and type values call {@link getAvailableTargetPageRules()}.
- * "inverted" should be "0" or "1". Leave it empty to record any page.
- * If page rules are set, a session will be only recorded as soon as a visitor has reached a page that matches these rules.
- * @param int $sampleLimit The number of sessions you want to record. Once the sample limit has been reached, the session recording will be ended automatically.
- * @param float $sampleRate Needs to be between 0 and 100 where 100 means => 100%, 10 => 10%, 0.1 => 0.1%.
- * Defines how often a visitor will be actually recorded when they match the page rules, also known as "traffic". Currently max one decimal is supported.
- * @param int $minSessionTime If defined, will only record sessions when the visitor has spent more than this many seconds on the current page.
- * @param int $requiresActivity If enabled (default), the session will be only recorded if the visitor has at least scrolled and clicked once.
- * @param int $captureKeystrokes If enabled (default), any text that a user enters into text form elements will be recorded.
- * Password fields will be automatically masked and you can mask other elements with sensitive data using a data-matomo-mask attribute.
- */
- public function updateSessionRecording($idSite, $idSiteHsr, $name, $matchPageRules = array(), $sampleLimit = 1000, $sampleRate = 10, $minSessionTime = 0, $requiresActivity = true, $captureKeystrokes = true)
- {
- $this->validator->checkSessionReportWritePermission($idSite);
- $this->siteHsr->checkSessionRecordingExists($idSite, $idSiteHsr);
-
- $updatedDate = Date::now()->getDatetime();
-
- $matchPageRules = $this->unsanitizePageRules($matchPageRules);
-
- $this->siteHsr->updateSessionRecording($idSite, $idSiteHsr, $name, $matchPageRules, $sampleLimit, $sampleRate, $minSessionTime, $requiresActivity, $captureKeystrokes, $updatedDate);
- }
-
- /**
- * Get a specific heatmap by its ID.
- *
- * @param int $idSite
- * @param int $idSiteHsr The id of the heatmap.
- * @return array|false
- */
- public function getHeatmap($idSite, $idSiteHsr)
- {
- $this->validator->checkHeatmapReportViewPermission($idSite);
- $this->siteHsr->checkHeatmapExists($idSite, $idSiteHsr);
-
- $heatmap = $this->siteHsr->getHeatmap($idSite, $idSiteHsr);
-
- return $heatmap;
- }
-
- /**
- * Get a specific session recording by its ID.
- *
- * @param int $idSite
- * @param int $idSiteHsr The id of the heatmap.
- * @return array|false
- */
- public function getSessionRecording($idSite, $idSiteHsr)
- {
- $this->validator->checkSessionReportViewPermission($idSite);
- $this->siteHsr->checkSessionRecordingExists($idSite, $idSiteHsr);
-
- return $this->siteHsr->getSessionRecording($idSite, $idSiteHsr);
- }
-
- /**
- * Pauses the given heatmap.
- *
- * When a heatmap is paused, all the tracking will be paused until its resumed again.
- *
- * @param int $idSite
- * @param int $idSiteHsr The id of the heatmap
- */
- public function pauseHeatmap($idSite, $idSiteHsr)
- {
- $this->validator->checkHeatmapReportWritePermission($idSite);
- $this->siteHsr->checkHeatmapExists($idSite, $idSiteHsr);
-
- $this->siteHsr->pauseHeatmap($idSite, $idSiteHsr);
-
- Cache::deleteCacheWebsiteAttributes($idSite);
- }
-
- /**
- * Resumes the given heatmap.
- *
- * When a heatmap is resumed, all the tracking will be enabled.
- *
- * @param int $idSite
- * @param int $idSiteHsr The id of the heatmap
- */
- public function resumeHeatmap($idSite, $idSiteHsr)
- {
- $this->validator->checkHeatmapReportWritePermission($idSite);
- $this->siteHsr->checkHeatmapExists($idSite, $idSiteHsr);
-
- $this->siteHsr->resumeHeatmap($idSite, $idSiteHsr);
-
- Cache::deleteCacheWebsiteAttributes($idSite);
- }
-
- /**
- * Deletes the given heatmap.
- *
- * When a heatmap is deleted, the report will be no longer available in the API and tracked data for this
- * heatmap might be removed.
- *
- * @param int $idSite
- * @param int $idSiteHsr The id of the heatmap
- */
- public function deleteHeatmap($idSite, $idSiteHsr)
- {
- $this->validator->checkHeatmapReportWritePermission($idSite);
-
- $this->siteHsr->deactivateHeatmap($idSite, $idSiteHsr);
- }
-
- /**
- * Ends / finishes the given heatmap.
- *
- * When you end a heatmap, the heatmap reports will be still available via API and UI but no new heatmap activity
- * will be recorded for this heatmap.
- *
- * @param int $idSite
- * @param int $idSiteHsr The id of the heatmap.
- */
- public function endHeatmap($idSite, $idSiteHsr)
- {
- $this->validator->checkHeatmapReportWritePermission($idSite);
- $this->siteHsr->checkHeatmapExists($idSite, $idSiteHsr);
-
- $this->siteHsr->endHeatmap($idSite, $idSiteHsr);
- }
-
- /**
- * Pauses the given session recording.
- *
- * When a session recording is paused, all the tracking will be paused until its resumed again.
- *
- * @param int $idSite
- * @param int $idSiteHsr The id of the heatmap
- */
- public function pauseSessionRecording($idSite, $idSiteHsr)
- {
- $this->validator->checkSessionReportWritePermission($idSite);
- $this->siteHsr->checkSessionRecordingExists($idSite, $idSiteHsr);
-
- $this->siteHsr->pauseSessionRecording($idSite, $idSiteHsr);
-
- Cache::deleteCacheWebsiteAttributes($idSite);
- }
-
- /**
- * Resumes the given session recording.
- *
- * When a session recording is resumed, all the tracking will be enabled.
- *
- * @param int $idSite
- * @param int $idSiteHsr The id of the heatmap
- */
- public function resumeSessionRecording($idSite, $idSiteHsr)
- {
- $this->validator->checkSessionReportWritePermission($idSite);
- $this->siteHsr->checkSessionRecordingExists($idSite, $idSiteHsr);
-
- $this->siteHsr->resumeSessionRecording($idSite, $idSiteHsr);
-
- Cache::deleteCacheWebsiteAttributes($idSite);
- }
-
- /**
- * Deletes the given session recording.
- *
- * When a session recording is deleted, any related recordings be no longer available in the API and tracked data
- * for this session recording might be removed.
- *
- * @param int $idSite
- * @param int $idSiteHsr The id of the session recording.
- */
- public function deleteSessionRecording($idSite, $idSiteHsr)
- {
-
- $this->validator->checkSessionReportWritePermission($idSite);
-
- $this->siteHsr->deactivateSessionRecording($idSite, $idSiteHsr);
- }
-
- /**
- * Ends / finishes the given session recording.
- *
- * When you end a session recording, the session recording reports will be still available via API and UI but no new
- * session will be recorded anymore.
- *
- * @param int $idSite
- * @param int $idSiteHsr The id of the session recording.
- */
- public function endSessionRecording($idSite, $idSiteHsr)
- {
- $this->validator->checkSessionReportWritePermission($idSite);
- $this->siteHsr->checkSessionRecordingExists($idSite, $idSiteHsr);
-
- $this->siteHsr->endSessionRecording($idSite, $idSiteHsr);
- }
-
- /**
- * Get all available heatmaps for a specific website or app.
- *
- * It will return active as well as ended heatmaps but not any deleted heatmaps.
- *
- * @param int $idSite
- * @param bool|int $includePageTreeMirror set to 0 if you don't need the page tree mirror for heatmaps (improves performance)
- * @return array
- */
- public function getHeatmaps($idSite, $includePageTreeMirror = true)
- {
- $this->validator->checkHeatmapReportViewPermission($idSite);
-
- return $this->siteHsr->getHeatmaps($idSite, !empty($includePageTreeMirror));
- }
-
- /**
- * Get all available session recordings for a specific website or app.
- *
- * It will return active as well as ended session recordings but not any deleted session recordings.
- *
- * @param int $idSite
- * @return array
- */
- public function getSessionRecordings($idSite)
- {
- $this->validator->checkSessionReportViewPermission($idSite);
-
- return $this->siteHsr->getSessionRecordings($idSite);
- }
-
- /**
- * Returns all page views that were recorded during a particular session / visit. We do not apply segments as it is
- * used for video player when replaying sessions etc.
- *
- * @param int $idSite
- * @param int $idSiteHsr The id of a session recording
- * @param int $idVisit The visit / session id
- * @return array
- */
- private function getRecordedPageViewsInSession($idSite, $idSiteHsr, $idVisit, $period, $date)
- {
- $timezone = Site::getTimezoneFor($idSite);
-
- // ideally we would also check if idSiteHsr is actually linked to idLogHsr but not really needed for security reasons
- $pageviews = $this->aggregator->getRecordedPageViewsInSession($idSite, $idSiteHsr, $idVisit, $period, $date, $segment = false);
-
- $isAnonymous = Piwik::isUserIsAnonymous();
-
- foreach ($pageviews as &$pageview) {
- $pageview['server_time_pretty'] = Date::factory($pageview['server_time'], $timezone)->getLocalized(DateTimeFormatProvider::DATETIME_FORMAT_SHORT);
-
- if ($isAnonymous) {
- unset($pageview['idvisitor']);
- } else {
- $pageview['idvisitor'] = bin2hex($pageview['idvisitor']);
- }
-
- $formatter = new Formatter();
- $pageview['time_on_page_pretty'] = $formatter->getPrettyTimeFromSeconds(intval($pageview['time_on_page'] / 1000), $asSentence = true);
- }
-
- return $pageviews;
- }
-
- /**
- * Returns all recorded sessions for a specific session recording.
- *
- * To get the actual recorded data for any of the recorded sessions, call {@link getRecordedSession()}.
- *
- * @param int $idSite
- * @param string $period
- * @param string $date
- * @param int $idSiteHsr The id of the session recording you want to retrieve all the recorded sessions for.
- * @param bool $segment
- * @param int $idSubtable Optional visit id if you want to get all recorded pageviews of a specific visitor
- * @return DataTable
- */
- public function getRecordedSessions($idSite, $period, $date, $idSiteHsr, $segment = false, $idSubtable = false)
- {
- $this->validator->checkSessionReportViewPermission($idSite);
- $this->siteHsr->checkSessionRecordingExists($idSite, $idSiteHsr);
-
- $idVisit = $idSubtable;
-
- try {
- PeriodFactory::checkPeriodIsEnabled($period);
- } catch (\Exception $e) {
- throw new Exception(Piwik::translate('HeatmapSessionRecording_PeriodDisabledErrorMessage', $period));
- }
-
- if (!empty($idVisit)) {
- $recordings = $this->aggregator->getRecordedPageViewsInSession($idSite, $idSiteHsr, $idVisit, $period, $date, $segment);
- } else {
- $recordings = $this->aggregator->getRecordedSessions($idSite, $idSiteHsr, $period, $date, $segment);
- }
-
- $table = new DataTable();
- $table->disableFilter('AddColumnsProcessedMetrics');
- $table->setMetadata('idSiteHsr', $idSiteHsr);
-
- if (!empty($recordings)) {
- $table->addRowsFromSimpleArray($recordings);
- }
-
- if (empty($idVisit)) {
- $table->queueFilter(function (DataTable $table) {
- foreach ($table->getRowsWithoutSummaryRow() as $row) {
- if ($idVisit = $row->getColumn('idvisit')) {
- $row->setNonLoadedSubtableId($idVisit);
- }
- }
- });
- } else {
- $table->disableFilter('Sort');
- }
-
- if (!method_exists(SettingsServer::class, 'isMatomoForWordPress') || !SettingsServer::isMatomoForWordPress()) {
- $table->queueFilter(function (DataTable $table) use ($idSite, $idSiteHsr, $period, $date) {
- foreach ($table->getRowsWithoutSummaryRow() as $row) {
- $idLogHsr = $row->getColumn('idloghsr');
- $row->setMetadata('sessionReplayUrl', SiteHsrModel::completeWidgetUrl('replayRecording', 'idSiteHsr=' . (int) $idSiteHsr . '&idLogHsr=' . (int) $idLogHsr, $idSite, $period, $date));
- }
- });
- }
-
- $table->filter('Piwik\Plugins\HeatmapSessionRecording\DataTable\Filter\EnrichRecordedSessions');
-
- return $table;
- }
-
- /**
- * Get all activities of a specific recorded session.
- *
- * This includes events such as clicks, mouse moves, scrolls, resizes, page / HTML DOM changes, form changed.
- * It is recommended to call this API method with filter_limit = -1 to retrieve all results. It also returns
- * metadata like the viewport size the user had when it was recorded, the browser, operating system, and more.
- *
- * To see what each event type in the events property means, call {@link getEventTypes()}.
- *
- * @param int $idSite
- * @param int $idSiteHsr The id of the session recording you want to retrieve the data for.
- * @param int $idLogHsr The id of the recorded session you want to retrieve the data for.
- * @return array
- * @throws Exception
- */
- public function getRecordedSession($idSite, $idSiteHsr, $idLogHsr)
- {
- $this->validator->checkSessionReportViewPermission($idSite);
- $this->siteHsr->checkSessionRecordingExists($idSite, $idSiteHsr);
-
- // ideally we would also check if idSiteHsr is actually linked to idLogHsr but not really needed for security reasons
- $session = $this->aggregator->getRecordedSession($idLogHsr);
-
- if (empty($session['idsite']) || empty($idSite)) {
- throw new Exception(Piwik::translate('HeatmapSessionRecording_ErrorSessionRecordingDoesNotExist'));
- }
-
- if ($session['idsite'] != $idSite) {
- // important otherwise can fetch any log entry!
- throw new Exception(Piwik::translate('HeatmapSessionRecording_ErrorSessionRecordingDoesNotExist'));
- }
-
- $session['idvisitor'] = !empty($session['idvisitor']) ? bin2hex($session['idvisitor']) : '';
-
- if (Piwik::isUserIsAnonymous()) {
- foreach (EnrichRecordedSessions::getBlockedFields() as $blockedField) {
- if (isset($session[$blockedField])) {
- $session[$blockedField] = null;
- }
- }
- }
-
-
- $configBrowserName = !empty($session['config_browser_name']) ? $session['config_browser_name'] : '';
- $session['browser_name'] = \Piwik\Plugins\DevicesDetection\getBrowserName($configBrowserName);
- $session['browser_logo'] = \Piwik\Plugins\DevicesDetection\getBrowserLogo($configBrowserName);
- $configOs = !empty($session['config_os']) ? $session['config_os'] : '';
- $session['os_name'] = \Piwik\Plugins\DevicesDetection\getOsFullName($configOs);
- $session['os_logo'] = \Piwik\Plugins\DevicesDetection\getOsLogo($configOs);
- $session['device_name'] = \Piwik\Plugins\DevicesDetection\getDeviceTypeLabel($session['config_device_type']);
- $session['device_logo'] = \Piwik\Plugins\DevicesDetection\getDeviceTypeLogo($session['config_device_type']);
-
- if (!empty($session['config_device_model'])) {
- $session['device_name'] .= ', ' . $session['config_device_model'];
- }
-
- $session['location_name'] = '';
- $session['location_logo'] = '';
-
- if (!empty($session['location_country'])) {
- $session['location_name'] = \Piwik\Plugins\UserCountry\countryTranslate($session['location_country']);
- $session['location_logo'] = \Piwik\Plugins\UserCountry\getFlagFromCode($session['location_country']);
-
- if (!empty($session['location_region']) && $session['location_region'] != Visit::UNKNOWN_CODE) {
- $session['location_name'] .= ', ' . \Piwik\Plugins\UserCountry\getRegionNameFromCodes($session['location_country'], $session['location_region']);
- }
-
- if (!empty($session['location_city'])) {
- $session['location_name'] .= ', ' . $session['location_city'];
- }
- }
-
- $timezone = Site::getTimezoneFor($idSite);
- $session['server_time_pretty'] = Date::factory($session['server_time'], $timezone)->getLocalized(DateTimeFormatProvider::DATETIME_FORMAT_SHORT);
-
- $formatter = new Formatter();
- $session['time_on_page_pretty'] = $formatter->getPrettyTimeFromSeconds(intval($session['time_on_page'] / 1000), $asSentence = true);
-
- // we make sure to get all recorded pageviews in this session
- $serverTime = Date::factory($session['server_time']);
- $from = $serverTime->subDay(1)->toString();
- $to = $serverTime->addDay(1)->toString();
-
- $period = 'range';
- $dateRange = $from . ',' . $to;
-
- $session['events'] = $this->logEvent->getEventsForPageview($idLogHsr);
- $session['pageviews'] = $this->getRecordedPageViewsInSession($idSite, $idSiteHsr, $session['idvisit'], $period, $dateRange);
- $session['numPageviews'] = count($session['pageviews']);
-
- return $session;
- }
-
- /**
- * Deletes all recorded page views within a recorded session.
- *
- * Once a recorded session has been deleted, the replay video will no longer be available in the UI and no data
- * can be retrieved anymore via the API.
- *
- * @param int $idSite
- * @param int $idSiteHsr The id of the session recording you want to delete the data.
- * @param int $idVisit The visitId of the recorded session you want to delete.
- */
- public function deleteRecordedSession($idSite, $idSiteHsr, $idVisit)
- {
- $this->validator->checkSessionReportWritePermission($idSite);
- // make sure the recording actually belongs to that site, otherwise could delete any recording for any other site
- $this->siteHsr->checkSessionRecordingExists($idSite, $idSiteHsr);
-
- // we also need to make sure the visit actually belongs to that site
- $idLogHsrs = $this->logHsr->findLogHsrIdsInVisit($idSite, $idVisit);
-
- foreach ($idLogHsrs as $idLogHsr) {
- $this->logHsrSite->unlinkRecord($idLogHsr, $idSiteHsr);
- }
- }
-
- /**
- * Deletes an individual page view within a recorded session.
- *
- * It only deletes one recorded session of one page view, not all recorded sessions.
- * Once a recorded page view has been deleted, the replay video will no longer be available in the UI and no data
- * can be retrieved anymore via the API for this page view.
- *
- * @param int $idSite
- * @param int $idSiteHsr The id of the session recording you want to delete the data.
- * @param int $idLogHsr The id of the recorded session you want to delete.
- */
- public function deleteRecordedPageview($idSite, $idSiteHsr, $idLogHsr)
- {
- $this->validator->checkWritePermission($idSite);
- // make sure the recording actually belongs to that site, otherwise could delete any recording for any other site
- $this->siteHsr->checkSessionRecordingExists($idSite, $idSiteHsr);
-
- $this->logHsrSite->unlinkRecord($idLogHsr, $idSiteHsr);
- }
-
- /**
- * Get metadata for a specific heatmap like the number of samples / pageviews that were recorded or the
- * average above the fold per device type.
- *
- * @param int $idSite
- * @param string $period
- * @param string $date
- * @param int $idSiteHsr The id of the heatmap you want to retrieve the meta data for.
- * @param bool|string $segment
- * @return array
- */
- public function getRecordedHeatmapMetadata($idSite, $period, $date, $idSiteHsr, $segment = false)
- {
- $this->validator->checkHeatmapReportViewPermission($idSite);
- $this->siteHsr->checkHeatmapExists($idSite, $idSiteHsr);
-
- $samples = $this->aggregator->getRecordedHeatmapMetadata($idSiteHsr, $idSite, $period, $date, $segment);
-
- $result = array('nb_samples_device_all' => 0);
-
- foreach ($samples as $sample) {
- $result['nb_samples_device_' . $sample['device_type']] = $sample['value'];
- $result['avg_fold_device_' . $sample['device_type']] = round(($sample['avg_fold'] / LogHsr::SCROLL_ACCURACY) * 100, 1);
- $result['nb_samples_device_all'] += $sample['value'];
- }
-
- return $result;
- }
-
- /**
- * Get all activities of a heatmap.
- *
- * For example retrieve all mouse movements made by desktop visitors, or all clicks made my tablet visitors, or
- * all scrolls by mobile users. It is recommended to call this method with filter_limit = -1 to retrieve all
- * results. As there can be many results, you may want to call this method several times using filter_limit and
- * filter_offset.
- *
- * @param int $idSite
- * @param string $period
- * @param string $date
- * @param int $idSiteHsr The id of the heatmap you want to retrieve the data for.
- * @param int $heatmapType To see which heatmap types can be used, call {@link getAvailableHeatmapTypes()}
- * @param int $deviceType To see which device types can be used, call {@link getAvailableDeviceTypes()}
- * @param bool|string $segment
- * @return array
- */
- public function getRecordedHeatmap($idSite, $period, $date, $idSiteHsr, $heatmapType, $deviceType, $segment = false)
- {
- $this->validator->checkHeatmapReportViewPermission($idSite);
- $this->siteHsr->checkHeatmapExists($idSite, $idSiteHsr);
-
- if ($heatmapType == RequestProcessor::EVENT_TYPE_SCROLL) {
- $heatmap = $this->aggregator->aggregateScrollHeatmap($idSiteHsr, $deviceType, $idSite, $period, $date, $segment);
- } else {
- $heatmap = $this->aggregator->aggregateHeatmap($idSiteHsr, $heatmapType, $deviceType, $idSite, $period, $date, $segment);
- }
-
- // we do not return dataTable here as it doubles the time it takes to call this method (eg 4s vs 7s when heaps of data)
- // datatable is not really needed here as we don't want to sort it or so
- return $heatmap;
- }
-
- /**
- * @param $idSite
- * @param $idSiteHsr
- * @param $idLogHsr
- * @return array
- * @hide
- */
- public function getEmbedSessionInfo($idSite, $idSiteHsr, $idLogHsr)
- {
- $this->validator->checkSessionReportViewPermission($idSite);
-
- $aggregator = new Aggregator();
- return $aggregator->getEmbedSessionInfo($idSite, $idSiteHsr, $idLogHsr);
- }
-
- /**
- * Tests, checks whether the given URL matches the given page rules.
- *
- * This can be used before configuring a heatmap or session recording to make sure the configured target page(s)
- * will match a specific URL.
- *
- * @param string $url
- * @param array $matchPageRules
- * @return array
- * @throws Exception
- */
- public function testUrlMatchPages($url, $matchPageRules = array())
- {
- $this->validator->checkHasSomeWritePermission();
-
- if ($url === '' || $url === false || $url === null) {
- return array('url' => '', 'matches' => false);
- }
-
- if (!empty($matchPageRules) && !is_array($matchPageRules)) {
- throw new Exception(Piwik::translate('HeatmapSessionRecording_ErrorNotAnArray', 'matchPageRules'));
- }
-
- $url = Common::unsanitizeInputValue($url);
-
- if (!empty($matchPageRules)) {
- $pageRules = new PageRules($matchPageRules, '', $needsOneEntry = false);
- $pageRules->check();
- }
-
- $matchPageRules = $this->unsanitizePageRules($matchPageRules);
-
- $allMatch = HsrMatcher::matchesAllPageRules($matchPageRules, $url);
-
- return array('url' => $url, 'matches' => $allMatch);
- }
-
- /**
- * Get a list of valid heatmap and session recording statuses (eg "active", "ended")
- *
- * @return array
- */
- public function getAvailableStatuses()
- {
- $this->validator->checkHasSomeWritePermission();
-
- return array(
- array('value' => SiteHsrDao::STATUS_ACTIVE, 'name' => Piwik::translate('HeatmapSessionRecording_StatusActive')),
- array('value' => SiteHsrDao::STATUS_ENDED, 'name' => Piwik::translate('HeatmapSessionRecording_StatusEnded')),
- );
- }
-
- /**
- * Get a list of all available target attributes and target types for "pageTargets" / "page rules".
- *
- * For example URL, URL Parameter, Path, simple comparison, contains, starts with, and more.
- *
- * @return array
- */
- public function getAvailableTargetPageRules()
- {
- $this->validator->checkHasSomeWritePermission();
-
- return PageRuleMatcher::getAvailableTargetTypes();
- }
-
- /**
- * Get a list of available device types that can be used when fetching a heatmap report.
- *
- * For example desktop, tablet, mobile.
- *
- * @return array
- */
- public function getAvailableDeviceTypes()
- {
- Piwik::checkUserHasSomeViewAccess();
-
- return array(
- array('name' => Piwik::translate('General_Desktop'),
- 'key' => LogHsr::DEVICE_TYPE_DESKTOP,
- 'logo' => 'plugins/Morpheus/icons/dist/devices/desktop.png'),
- array('name' => Piwik::translate('DevicesDetection_Tablet'),
- 'key' => LogHsr::DEVICE_TYPE_TABLET,
- 'logo' => 'plugins/Morpheus/icons/dist/devices/tablet.png'),
- array('name' => Piwik::translate('General_Mobile'),
- 'key' => LogHsr::DEVICE_TYPE_MOBILE,
- 'logo' => 'plugins/Morpheus/icons/dist/devices/smartphone.png'),
- );
- }
-
- /**
- * Get a list of available heatmap types that can be used when fetching a heatmap report.
- *
- * For example click, mouse move, scroll.
- *
- * @return array
- */
- public function getAvailableHeatmapTypes()
- {
- Piwik::checkUserHasSomeViewAccess();
-
- return array(
- array(
- 'name' => Piwik::translate('HeatmapSessionRecording_ActivityClick'),
- 'key' => RequestProcessor::EVENT_TYPE_CLICK),
- array(
- 'name' => Piwik::translate('HeatmapSessionRecording_ActivityMove'),
- 'key' => RequestProcessor::EVENT_TYPE_MOVEMENT),
- array(
- 'name' => Piwik::translate('HeatmapSessionRecording_ActivityScroll'),
- 'key' => RequestProcessor::EVENT_TYPE_SCROLL),
- );
- }
-
- /**
- * Get a list of available session recording sample limits.
- *
- * Note: This is only a suggested list of sample limits that should be shown in the UI when creating or editing a
- * session recording. When you configure a session recording via the API directly, any limit can be used.
- *
- * For example 50, 100, 200, 500
- *
- * @return array
- */
- public function getAvailableSessionRecordingSampleLimits()
- {
- $this->validator->checkHasSomeWritePermission();
- $this->validator->checkSessionRecordingEnabled();
-
- return $this->configuration->getSessionRecordingSampleLimits();
- }
-
- /**
- * Get a list of available event types that may be returned eg when fetching a recorded session.
- *
- * @return array
- */
- public function getEventTypes()
- {
- Piwik::checkUserHasSomeViewAccess();
-
- return array(
- array(
- 'name' => Piwik::translate('HeatmapSessionRecording_ActivityMove'),
- 'key' => RequestProcessor::EVENT_TYPE_MOVEMENT),
- array(
- 'name' => Piwik::translate('HeatmapSessionRecording_ActivityClick'),
- 'key' => RequestProcessor::EVENT_TYPE_CLICK),
- array(
- 'name' => Piwik::translate('HeatmapSessionRecording_ActivityScroll'),
- 'key' => RequestProcessor::EVENT_TYPE_SCROLL),
- array(
- 'name' => Piwik::translate('HeatmapSessionRecording_ActivityResize'),
- 'key' => RequestProcessor::EVENT_TYPE_RESIZE),
- array(
- 'name' => Piwik::translate('HeatmapSessionRecording_ActivityInitialDom'),
- 'key' => RequestProcessor::EVENT_TYPE_INITIAL_DOM),
- array(
- 'name' => Piwik::translate('HeatmapSessionRecording_ActivityPageChange'),
- 'key' => RequestProcessor::EVENT_TYPE_MUTATION),
- array(
- 'name' => Piwik::translate('HeatmapSessionRecording_ActivityFormText'),
- 'key' => RequestProcessor::EVENT_TYPE_FORM_TEXT),
- array(
- 'name' => Piwik::translate('HeatmapSessionRecording_ActivityFormValue'),
- 'key' => RequestProcessor::EVENT_TYPE_FORM_VALUE),
- array(
- 'name' => Piwik::translate('HeatmapSessionRecording_ActivityScrollElement'),
- 'key' => RequestProcessor::EVENT_TYPE_SCROLL_ELEMENT),
- );
- }
-}
diff --git a/files/plugin-HeatmapSessionRecording-5.2.4/CHANGELOG.md b/files/plugin-HeatmapSessionRecording-5.2.4/CHANGELOG.md
deleted file mode 100644
index a32f012..0000000
--- a/files/plugin-HeatmapSessionRecording-5.2.4/CHANGELOG.md
+++ /dev/null
@@ -1,452 +0,0 @@
-## Changelog
-
-5.2.4 - 2025-06-09
-- Started showing the troubleshooting link even when no heatmap sample has been recorded
-- Do not crash when displaying a heatmap for a page with invalid HTML
-
-5.2.3 - 2025-01-20
-- Added an activity for pause and resume action
-- Added a troubleshooting FAQ link for heatmaps
-
-5.2.2 - 2024-12-16
-- Fixes PHP deprecation warnings
-
-5.2.1 - 2024-12-02
-- Added activities to track deleting recorded sessions and page views
-
-5.2.0 - 2024-11-04
-- Implemented a tooltip which displays click count and rate
-
-5.1.8 - 2024-10-17
-- Fixes excluded_elements not working for escaped values for a heatmap
-
-5.1.7 - 2024-10-11
-- Fixes classes with word script being removed due to xss filtering
-
-5.1.6 - 2024-08-26
-- Pricing updated
-
-5.1.5
-- Added cover image for marketplace
-
-5.1.4
-- Fixes captureInitialDom not working for single heatmap
-
-5.1.3
-- Added code to disable matomo.js file writable check code for Matomo Cloud
-
-5.1.2
-- Added code to alert if matomo.js is not writable
-
-5.1.1
-- Fixed applying segment returns error for SessionRecording
-
-5.1.0
-- Added an option to capture Heatmap DOM on demand
-
-5.0.10
-- Added total actions column in Session Recording listing page
-
-5.0.9
-- Added code to keep playing on resize event
-- Added code to update Translation keys via event
-
-5.0.8
-- Changes for README.md
-- Fixed an error that occurs when viewing posts that have heatmaps associated in WordPress.
-
-5.0.7
-- Fixed issue where form fields that were supposed to be unmasked weren't
-- Added code to pause/resume heatmap for Matomo Cloud
-
-5.0.6
-- Fixed input[type="button"] background being ignored
-- Added code to display AdBlocker banner when detected
-
-5.0.5
-- Fixed regression where good configs were disabled
-
-5.0.4
-- Fixed location provider not loading for cloud customers
-
-5.0.3
-- Fixed error when location provider is null
-
-5.0.2
-- Added option to fire heatmap/session recording only for certain geographies
-
-5.0.1
-- Compatibility with Matomo 5.0.0-b4
-
-5.0.0
-- Compatibility with Matomo 5
-
-4.5.10
-- Started skipping deletion of heatmap and session recordings for proxysite
-
-4.5.9
-- Started hiding period selector when viewing heatmaps
-
-4.5.8
-- Fixed scroll data not displaying correctly due to sort missing
-
-4.5.7
-- Fixed deprecation warnings for PHP 8.1
-
-4.5.6
-- Changed time_on_page column to BIGINT for new installation for log_hsr and log_hsr_event table
-
-4.5.5
-- Fixed session recording not masking image with `data-matomo-mask` attribute set on parent node
-
-4.5.4
-- Fixed unmasking issue for text-node elements
-- Fixed recording to not end on tabs switch
-
-4.5.3
-- Added support to pass media attribute if present for external stylesheets
-
-4.5.2
-- Made regex to work consistently, #PG-373
-- Added examples of possible xss from portswigger.net
-
-4.5.1
-- Fixed mutation id bug to load css from DB
-
-4.5.0
-- Starting migrating AngularJS to Vue.
-- Migrated view code to VueJs
-- Updated code to respect max execution time during Archiving
-
-4.4.3
-- Added code to remove attributes with possible XSS values
-
-4.4.2
-- Added support for lazy loaded images
-
-4.4.1
-- Fixed masking issue for dynamically added DOM elements
-
-4.4.0
-- Added option to disable heatmap independently
-- Stopped showing visitor profile icon in session recording when visitor profile is disabled
-
-4.3.1
-- Fixed recorded session link not working for segmented logs in visit action
-
-4.3.0
-- Started storing CSS content in DB
-- Fixed range error when range is disabled
-
-4.2.1
-- Fixed double encoded segments
-
-4.2.0
-- Fixed heatmap not triggering when tracker configured directly.
-- Added masking for images with height and width
-- Added masking for [input type="image"]
-- Fixed non-masking bug for child elements with data-matomo-unmask
-
-4.1.2
-- Fix to record inputs with data-matomo-unmask
-
-4.1.1
-- Removed masking for input type button, submit and reset
-
-4.1.0
-- Added option to disable session recording independently
-
-4.0.14
-- Support Matomo's new content security policy header
-
-4.0.13
-- Fix sharing a session might not work anymore with latest Matomo version
-
-4.0.12
-- Ensure configs.php is loaded correctly with multiple trackers
-- Translation updates
-
-4.0.11
-- Improve handling of attribute changes
-- Add translations for Czech, Dutch & Portuguese
-
-4.0.10
-- Further improvements for loading for iframes
-
-4.0.9
-- Improve loading for iframes
-
-4.0.8
-- Improve tracking react pages
-
-4.0.7
-- Add category help texts
-- Increase possible sample limit
-- jQuery 3 compatibility for WP
-
-4.0.6
-- Performance improvements
-
-4.0.4
-- Compatibility with Matomo 4.X
-
-4.0.3
-- Compatibility with Matomo 4.X
-
-4.0.2
-- Compatibility with Matomo 4.X
-
-4.0.1
-- Handle base URLs better
-
-4.0.0
-- Compatibility with Matomo 4.X
-
-3.2.39
-- Better handling for base URL
-
-3.2.38
-- Improve SPA tracking
-
-3.2.37
-- Improve sorting of server time
-
-3.2.36
-- Fix number of recorded pages may be wrong when a segment is applied
-
-3.2.35
-- Improve widgetize feature when embedded as iframe
-
-3.2.34
-- Further improvements for WordPress
-
-3.2.33
-- Improve compatibilty with WordPress
-
-3.2.32
-- Improve checking for number of previously recorded sessions
-
-3.2.31
-- Matomo for WordPress support
-
-3.2.30
-- Send less tracking requests by queueing more requests together
-
-3.2.29
-- Use DB reader in Aggregator for better compatibility with Matomo 3.12
-
-3.2.28
-- Improvements for Matomo 3.12 to support faster segment archiving
-- Better support for single page applications
-
-3.2.27
- - Show search box for entities
- - Support usage of a reader DB when configured
-
-3.2.26
- - Tracker improvements
-
-3.2.25
- - Tracker improvements
-
-3.2.24
- - Generate correct session recording link when a visitor matches multiple recordings in the visitor log
-
-3.2.23
- - Internal tracker performance improvements
-
-3.2.22
- - Add more translations
- - Tracker improvements
- - Internal changes
-
-3.2.21
- - title-text of JavaScript Tracking option help box shows HTML
- - Add primary key to log_event table for new installs (existing users should receive the update with Matomo 4)
-
-3.2.20
- - Fix tracker may under circumstances not enable tracking after disabling it manually
-
-3.2.19
- - Add possibility to delete an already taken heatmap screenshot so it can be re-taken
-
-3.2.18
- - Performance improvements for high traffic websites
-
-3.2.17
- - Add possibility to define alternative CSS file through `data-matomo-href`
- - Added new API method `HeatmapSessionRecording.deleteHeatmapScreenshot` to delete an already taken heatmap screenshot
- - Add possibility to delete an already taken heatmap screenshot so it can be re-taken
-
-3.2.16
- - Add useDateUrl=0 to default Heatmap export URL so it can be used easier
-
-3.2.15
- - Support a URL parameter &useDateUrl=1 in exported heatmaps to fetch heatmaps only for a specific date range
-
-3.2.14
- - Improve compatibility with tag manager
- - Fix possible notice when matching url array parameters
- - Add command to remove a stored heatmap
-
-3.2.13
- - Fix some coordinate cannot be calculated for SVG elements
- - Added more languages
- - Use new brand colors
- - If time on page is too high, abort the tracking request
-
-3.2.12
- - Update tracker file
-
-3.2.11
- - Add possibility to mask images
-
-3.2.10
- - Make sure to replay scrolling in element correctly
-
-3.2.9
- - Change min height of heatmaps to 400 pixels.
-
-3.2.8
- - When widgetizing the session player it bursts out of the iframe
- - Log more debug information in tracker
- - Use API calls instead of model
-
-3.2.7
- - Support new "Write" role
-
-3.2.6
- - Improve compatibility with styled-components and similar projects
- - Add possibility to not record mouse and touch movements.
-
-3.2.5
- - Compatibility with SiteUrlTrackingID plugin
- - Ensure selectors are generated correctly
-
-3.2.4
- - Allow users to pass sample limit of zero for unlimited recordings
- - Show which page view within a session is currently being replayed
-
-3.2.3
- - In configs.php return a 403 if Matomo is not installed yet
-
-3.2.2
- - Validate an entered regular expression when configuring a heatmap or session recording
- - Improve heatmap rendering of sharepoint sites
-
-3.2.1
- - Improve the rendering of heatmaps and session recordings
-
-3.2.0
- - Optimize tracker cache file
- - Prevent recording injected CSS resources that only work on a visitors' computer such as Kaspersky Antivirus CSS.
- - For better GDPR compliance disable capture keystroke in sessions by default.
- - Added logic to support Matomo GDPR features
- - Only specifically whitelisted form fields can now be recorded in plain text
- - Some form fields that could potentially include personal information such as an address will be always masked and anonymized
- - Trim any whitespace when configuring target pages
-
-3.1.9
- - Support new attribute `data-matomo-mask` which works similar to `data-piwik-mask` but additionally allows to mask content of elements.
-
-3.1.8
- - Support new CSS rendering classes matomoHsr, matomoHeatmap and matomoSessionRecording
- - For input text fields prefer a set value on the element directly
- - Differentiate between scrolling of the window and scrolling within an element (part of the window)
- - Replay in the recorded session when a user is scrolling within an element
-
-3.1.7
- - Make sure validating URL works correctly with HTML entities
- - Prevent possible fatal error when opening manage screen for all websites
-
-3.1.6
- - Renamed Piwik to Matomo
-
-3.1.5
- - Fix requested stylesheet URLs were requested lowercase when using a relative base href in the recorded page
- - Show more accurate time on page and record pageviews for a longer period in case a user is not active right away.
-
-3.1.4
- - Prevent target rules in heatmap or session recording to visually disappear under circumstances when not using the cancel or back button.
- - Respect URL prefix (eg www.) when replaying a session recording, may fix some displaying issues if website does not work without www.
- - Improved look of widgetized session recording
-
-3.1.3
- - Make Heatmap & Session Recording compatible with canvas and webgl libraries like threejs and earcut
- - Better detected of the embedded heatmap height
- - Fix scroll heatmap did not paint the last scroll section correctly
- - It is now possible to configure the sample limits in the config via `[HeatmapSessionRecording] session_recording_sample_limits = 50,100,...`
-
-3.1.2
- - Added URL to view heatmap and to replay a session recording to the API response
- - Fix widgetized URL for heatmaps and sessions redirected to another page when authenticated via token_auth
-
-3.1.1
- - Better error code when a site does not exist
- - Fix configs.php may fail if plugins directory is a symlink
- - Available sessions are now also displayed in the visitor profile
-
-3.1.0
- - Added autoplay feature for page views within a visit
- - Added possibility to change replay speed
- - Added possibility to skip long pauses in a session recording automatically
- - Better base URL detection in case a relative base URL is used
-
-3.0.15
- - Fix only max 100 heatmaps or session recordings were shown when managing them for a specific site.
- - Mask closing body in embedded page so it won't be replaced by some server logic
-
-3.0.14
- - Make sure to find all matches for a root folder when "equals simple" is used
-
-3.0.13
- - Fix a custom set based URL was ignored.
-
-3.0.12
- - Fix session recording stops when a user changes a file form field because form value is not allowed to be changed.
-
-3.0.11
- - Improve the performance of a DB query of a daily task when cleaning up blob entries.
-
-3.0.10
- - Improve the performance of a DB query of a daily task
- - Respect the new config setting `enable_internet_features` in the system check
-
-3.0.9
- - Make sure page rules work fine when using HTML entities
-
-3.0.8
- - Fix possible notice when tracking
- - Avoid some logs in chrome when viewing a heatmaps or session recordings
- - Always prefer same protocol when replaying sessions as currently used
-
-3.0.7
- - When using an "equals exactly" comparison, ignore a trailing slash when there is no path set
- - Let users customize if the tracking code should be included only when active records are configured
-
-3.0.6
- - Fix link to replay session in visitor log may not work under circumstances
-
-3.0.5
- - More detailed "no data message" when nothing has been recorded yet
- - Fix select fields were not recorded
-
-3.0.4
- - Only add tracker code when heatmap or sessions are actually active in any site
- - Added index on site_hsr table
- - Add custom stylesheets for custom styling
-
-3.0.3
- - Add system check for configs.php
- - On install, if .htaccess was not created, create the file manually
-
-3.0.2
- - Enrich system summary widget
- - Show an arrow instead of a dash between entry and exit url
- - Added some German translations
-
-3.0.1
- - Updated translations
-
-3.0.0
- - Heatmap & Session Recording for Piwik 3
diff --git a/files/plugin-HeatmapSessionRecording-5.2.4/HeatmapSessionRecording.php b/files/plugin-HeatmapSessionRecording-5.2.4/HeatmapSessionRecording.php
deleted file mode 100644
index f9f7059..0000000
--- a/files/plugin-HeatmapSessionRecording-5.2.4/HeatmapSessionRecording.php
+++ /dev/null
@@ -1,886 +0,0 @@
-register_route('HeatmapSessionRecording', 'getHeatmap');
- $api->register_route('HeatmapSessionRecording', 'getHeatmaps');
- $api->register_route('HeatmapSessionRecording', 'getRecordedHeatmapMetadata');
- $api->register_route('HeatmapSessionRecording', 'getRecordedHeatmap');
-
- $api->register_route('HeatmapSessionRecording', 'getSessionRecording');
- $api->register_route('HeatmapSessionRecording', 'getSessionRecordings');
- $api->register_route('HeatmapSessionRecording', 'getRecordedSessions');
- $api->register_route('HeatmapSessionRecording', 'getRecordedSession');
- });
-
- /**
- * @param array $actions
- * @param \WP_Post $post
- *
- * @return mixed
- */
- function add_new_heat_map_link($actions, $post)
- {
- if (
- !$post
- || !is_plugin_active('matomo/matomo.php')
- || !current_user_can('write_matomo')
- ) {
- return $actions;
- }
-
- if ($post->post_status !== 'publish') {
- // the permalink url wouldn't be correct yet for unpublished post
- return $actions;
- }
-
- $postUrl = get_permalink($post);
- $rules = array(array(
- 'attribute' => 'url',
- 'type' => 'equals_simple',
- 'inverted' => 0,
- 'value' => $postUrl
- ));
-
- $hsrParams = array(
- 'idSite' => 1,
- 'idSiteHsr' => 0,
- 'name' => $post->post_title,
- // Encoded to avoid pitfalls of decoding multi-dimensional array URL params in JavaScript
- 'matchPageRules' => json_encode($rules)
- );
-
- $url = Menu::get_matomo_reporting_url(
- 'HeatmapSessionRecording_Heatmaps',
- 'HeatmapSessionRecording_ManageHeatmaps',
- $hsrParams
- );
-
- $actions['create_heatmap'] = 'Create Heatmap';
- return $actions;
- }
-
- function get_matomo_heatmaps()
- {
- static $heatmaps_cached;
-
- global $wpdb;
-
- if (!isset($heatmaps_cached)) {
- $site = new Site();
- $idsite = $site->get_current_matomo_site_id();
-
- if (!$idsite) {
- $heatmaps_cached = array(); // prevent it not being executed again
- } else {
- $wpDbSettings = new \WpMatomo\Db\Settings();
- $tableName = $wpDbSettings->prefix_table_name('site_hsr');
- $idsite = (int) $idsite;// needed cause we don't bind parameters below
-
- $heatmaps_cached = $wpdb->get_results(
- "select * from $tableName WHERE record_type = 1 AND idsite = $idsite AND status != 'deleted'",
- ARRAY_A
- );
- }
- }
- return $heatmaps_cached;
- }
-
- /**
- * @param array $actions
- * @param \WP_Post $post
- *
- * @return mixed
- */
- function add_view_heat_map_link($actions, $post)
- {
- if (
- !$post
- || !is_plugin_active('matomo/matomo.php')
- || !current_user_can('write_matomo')
- ) {
- return $actions;
- }
-
- $heatmaps = get_matomo_heatmaps();
-
- if (empty($heatmaps)) {
- return $actions;
- }
-
- $postUrl = get_permalink($post);
-
- if (!$postUrl) {
- return $actions;
- }
-
- if (class_exists(Bootstrap::class)) {
- Bootstrap::do_bootstrap();
- }
-
- require_once('Tracker/PageRuleMatcher.php');
- require_once('Tracker/HsrMatcher.php');
-
- $heatmaps = array_values(array_filter($heatmaps, function ($heatmap) use ($postUrl) {
- $systemSettings = StaticContainer::get(SystemSettings::class);
- $includedCountries = $systemSettings->getIncludedCountries();
- return HsrMatcher::matchesAllPageRules(json_decode($heatmap['match_page_rules'], true), $postUrl) && HsrMatcher::isIncludedCountry($includedCountries);
- }));
-
- $numMatches = count($heatmaps);
- foreach ($heatmaps as $i => $heatmap) {
- $url = Menu::get_matomo_reporting_url(
- 'HeatmapSessionRecording_Heatmaps',
- $heatmap['idsitehsr'],
- array()
- );
- $linkText = 'View Heatmap';
- if ($numMatches > 1) {
- $linkText .= ' #' . ($i + 1);
- }
- $actions['view_heatmap_' . $i] =
- '' . esc_html($linkText) . '';
- }
-
- return $actions;
- }
-}
-
-class HeatmapSessionRecording extends \Piwik\Plugin
-{
- public const EMBED_SESSION_TIME = 43200; // half day in seconds
- public const ULR_PARAM_FORCE_SAMPLE = 'pk_hsr_forcesample';
- public const ULR_PARAM_FORCE_CAPTURE_SCREEN = 'pk_hsr_capturescreen';
- public const EMBED_SESSION_NAME = 'HSR_EMBED_SESSID';
-
- public const TRACKER_READY_HOOK_NAME = '/*!! hsrTrackerReadyHook */';
- public const TRACKER_READY_HOOK_NAME_WHEN_MINIFIED = '/*!!! hsrTrackerReadyHook */';
-
- public function registerEvents()
- {
- return array(
- 'Db.getActionReferenceColumnsByTable' => 'addActionReferenceColumnsByTable',
- 'Tracker.Cache.getSiteAttributes' => 'addSiteTrackerCache',
- 'AssetManager.getStylesheetFiles' => 'getStylesheetFiles',
- 'AssetManager.getJavaScriptFiles' => 'getJsFiles',
- 'Translate.getClientSideTranslationKeys' => 'getClientSideTranslationKeys',
- 'Template.jsGlobalVariables' => 'addJsGlobalVariables',
- 'Category.addSubcategories' => 'addSubcategories',
- 'SitesManager.deleteSite.end' => 'onDeleteSite',
- 'Tracker.PageUrl.getQueryParametersToExclude' => 'getQueryParametersToExclude',
- 'Widget.addWidgetConfigs' => 'addWidgetConfigs',
- 'System.addSystemSummaryItems' => 'addSystemSummaryItems',
- 'API.HeatmapSessionRecording.addHeatmap.end' => 'updatePiwikTracker',
- 'API.HeatmapSessionRecording.addSessionRecording.end' => 'updatePiwikTracker',
- 'CustomJsTracker.shouldAddTrackerFile' => 'shouldAddTrackerFile',
- 'Updater.componentUpdated' => 'installHtAccess',
- 'Live.visitorLogViewBeforeActionsInfo' => 'visitorLogViewBeforeActionsInfo',
- 'Widgetize.shouldEmbedIframeEmpty' => 'shouldEmbedIframeEmpty',
- 'Session.beforeSessionStart' => 'changeSessionLengthIfEmbedPage',
- 'TwoFactorAuth.requiresTwoFactorAuthentication' => 'requiresTwoFactorAuthentication',
- 'API.getPagesComparisonsDisabledFor' => 'getPagesComparisonsDisabledFor',
- 'CustomJsTracker.manipulateJsTracker' => 'disableHeatmapsDefaultIfNeeded',
- 'AssetManager.addStylesheets' => [
- 'function' => 'addStylesheets',
- 'after' => true,
- ],
- 'Db.getTablesInstalled' => 'getTablesInstalled'
- );
- }
-
- public function disableHeatmapsDefaultIfNeeded(&$content)
- {
- $settings = StaticContainer::get(SystemSettings::class);
- if ($settings->disableTrackingByDefault->getValue()) {
- $replace = 'Matomo.HeatmapSessionRecording._setDisabled();';
- } else {
- $replace = '';
- }
-
- $content = str_replace(array(self::TRACKER_READY_HOOK_NAME_WHEN_MINIFIED, self::TRACKER_READY_HOOK_NAME), $replace, $content);
- }
-
- /**
- * Register the new tables, so Matomo knows about them.
- *
- * @param array $allTablesInstalled
- */
- public function getTablesInstalled(&$allTablesInstalled)
- {
- $allTablesInstalled[] = Common::prefixTable('log_hsr');
- $allTablesInstalled[] = Common::prefixTable('log_hsr_blob');
- $allTablesInstalled[] = Common::prefixTable('log_hsr_event');
- $allTablesInstalled[] = Common::prefixTable('log_hsr_site');
- $allTablesInstalled[] = Common::prefixTable('site_hsr');
- }
-
- public static function getPathPrefix()
- {
- $webRootDirs = Manager::getInstance()->getWebRootDirectoriesForCustomPluginDirs();
- if (!empty($webRootDirs['HeatmapSessionRecording'])) {
- $baseUrl = trim($webRootDirs['HeatmapSessionRecording'], '/');
- } else {
- $baseUrl = 'plugins';
- }
- return $baseUrl;
- }
-
- public static function isMatomoForWordPress()
- {
- return defined('ABSPATH') && function_exists('add_action');
- }
-
- public function addStylesheets(&$mergedContent)
- {
- if (self::isMatomoForWordPress()) {
- // we hide this icon since it uses the widgetize feature which is disabled in WordPress
- $mergedContent .= '.manageHsr .action .icon-show { display: none; }';
- }
- }
- public function getPagesComparisonsDisabledFor(&$pages)
- {
- $pages[] = 'HeatmapSessionRecording_Heatmaps.*';
- $pages[] = 'HeatmapSessionRecording_SessionRecordings.*';
- }
-
- public function addJsGlobalVariables()
- {
- $idSite = Common::getRequestVar('idSite', 0, 'int');
-
- if ($idSite > 0 && Piwik::isUserHasWriteAccess($idSite)) {
- echo 'piwik.heatmapWriteAccess = true;';
- } else {
- echo 'piwik.heatmapWriteAccess = false;';
- }
- }
-
- public function requiresTwoFactorAuthentication(&$requiresAuth, $module, $action, $parameters)
- {
- if ($module == 'HeatmapSessionRecording' && $action === 'embedPage') {
- $requiresAuth = false;
- }
- }
-
- public function shouldEmbedIframeEmpty(&$shouldEmbedEmpty, $controllerName, $actionName)
- {
- if ($controllerName == 'HeatmapSessionRecording' && ($actionName == 'replayRecording' || $actionName == 'embedPage')) {
- $shouldEmbedEmpty = true;
- }
- }
-
- /**
- * Fallback to add play session link for Matomo < 3.1.0
- *
- * NOTE: TO BE REMOVED EG FROM FEBRUARY OR MARCH 2018
- *
- * @param string $out
- * @param Row $visitor
- */
- public function visitorLogViewBeforeActionsInfo(&$out, $visitor)
- {
- if (class_exists('\\Piwik\\Plugins\\Live\\VisitorDetailsAbstract')) {
- return;
- }
-
- $idVisit = $visitor->getColumn('idVisit');
- $idSite = (int) $visitor->getColumn('idSite');
-
- if (empty($idSite) || empty($idVisit) || !$this->getValidator()->canViewSessionReport($idSite)) {
- return;
- }
-
- $aggregator = new Aggregator();
- $recording = $aggregator->findRecording($idVisit);
- if (!empty($recording['idsitehsr'])) {
- $title = Piwik::translate('HeatmapSessionRecording_ReplayRecordedSession');
- $out .= ' ' . $title . ' ';
- }
- }
-
- public function shouldAddTrackerFile(&$shouldAdd, $pluginName)
- {
- if ($pluginName === 'HeatmapSessionRecording') {
- $config = new Configuration();
-
- $siteHsrDao = $this->getSiteHsrDao();
- if ($config->shouldOptimizeTrackingCode() && !$siteHsrDao->hasActiveRecordsAcrossSites()) {
- // saves requests to configs.php while no heatmap or session recording configured.
- $shouldAdd = false;
- }
- }
- }
-
- public function updatePiwikTracker()
- {
- if (Plugin\Manager::getInstance()->isPluginActivated('CustomJsTracker')) {
- $trackerUpdater = StaticContainer::get('Piwik\Plugins\CustomJsTracker\TrackerUpdater');
- if (!empty($trackerUpdater)) {
- $trackerUpdater->update();
- }
- }
- }
-
- public function addSystemSummaryItems(&$systemSummary)
- {
- $dao = $this->getSiteHsrDao();
- $numHeatmaps = $dao->getNumRecordsTotal(SiteHsrDao::RECORD_TYPE_HEATMAP);
- $numSessions = $dao->getNumRecordsTotal(SiteHsrDao::RECORD_TYPE_SESSION);
-
- $systemSummary[] = new SystemSummary\Item(
- $key = 'heatmaps',
- Piwik::translate('HeatmapSessionRecording_NHeatmaps', $numHeatmaps),
- $value = null,
- array('module' => 'HeatmapSessionRecording', 'action' => 'manageHeatmap'),
- $icon = 'icon-drop',
- $order = 6
- );
- $systemSummary[] = new SystemSummary\Item(
- $key = 'sessionrecordings',
- Piwik::translate('HeatmapSessionRecording_NSessionRecordings', $numSessions),
- $value = null,
- array('module' => 'HeatmapSessionRecording', 'action' => 'manageSessions'),
- $icon = 'icon-play',
- $order = 7
- );
- }
-
- public function getQueryParametersToExclude(&$parametersToExclude)
- {
- // these are used by the tracker
- $parametersToExclude[] = self::ULR_PARAM_FORCE_CAPTURE_SCREEN;
- $parametersToExclude[] = self::ULR_PARAM_FORCE_SAMPLE;
- }
-
- public function onDeleteSite($idSite)
- {
- $model = $this->getSiteHsrModel();
- $model->deactivateRecordsForSite($idSite);
- }
-
- private function getSiteHsrModel()
- {
- return StaticContainer::get('Piwik\Plugins\HeatmapSessionRecording\Model\SiteHsrModel');
- }
-
- private function getValidator()
- {
- return StaticContainer::get('Piwik\Plugins\HeatmapSessionRecording\Input\Validator');
- }
-
- public function addWidgetConfigs(&$configs)
- {
- $idSite = Common::getRequestVar('idSite', 0, 'int');
-
- if (!$this->getValidator()->canViewHeatmapReport($idSite)) {
- return;
- }
-
- $heatmaps = $this->getHeatmaps($idSite);
-
- foreach ($heatmaps as $heatmap) {
- $widget = new WidgetConfig();
- $widget->setCategoryId('HeatmapSessionRecording_Heatmaps');
- $widget->setSubcategoryId($heatmap['idsitehsr']);
- $widget->setModule('HeatmapSessionRecording');
- $widget->setAction('showHeatmap');
- $widget->setParameters(array('idSiteHsr' => $heatmap['idsitehsr']));
- $widget->setIsNotWidgetizable();
- $configs[] = $widget;
- }
- }
-
- public function addSubcategories(&$subcategories)
- {
- $idSite = Common::getRequestVar('idSite', 0, 'int');
-
- if (empty($idSite)) {
- // fallback for eg API.getReportMetadata which uses idSites
- $idSite = Common::getRequestVar('idSites', 0, 'int');
-
- if (empty($idSite)) {
- return;
- }
- }
-
- if ($this->getValidator()->canViewHeatmapReport($idSite)) {
- $heatmaps = $this->getHeatmaps($idSite);
-
- // we list recently created heatmaps first
- $order = 20;
- foreach ($heatmaps as $heatmap) {
- $subcategory = new Subcategory();
- $subcategory->setName($heatmap['name']);
- $subcategory->setCategoryId('HeatmapSessionRecording_Heatmaps');
- $subcategory->setId($heatmap['idsitehsr']);
- $subcategory->setOrder($order++);
- $subcategories[] = $subcategory;
- }
- }
-
- if ($this->getValidator()->canViewSessionReport($idSite)) {
- $recordings = $this->getSessionRecordings($idSite);
-
- // we list recently created recordings first
- $order = 20;
- foreach ($recordings as $recording) {
- $subcategory = new Subcategory();
- $subcategory->setName($recording['name']);
- $subcategory->setCategoryId('HeatmapSessionRecording_SessionRecordings');
- $subcategory->setId($recording['idsitehsr']);
- $subcategory->setOrder($order++);
- $subcategories[] = $subcategory;
- }
- }
- }
-
- public function getClientSideTranslationKeys(&$result)
- {
- $result[] = 'General_Save';
- $result[] = 'General_Done';
- $result[] = 'General_Actions';
- $result[] = 'General_Yes';
- $result[] = 'General_No';
- $result[] = 'General_Add';
- $result[] = 'General_Remove';
- $result[] = 'General_Id';
- $result[] = 'General_Ok';
- $result[] = 'General_Cancel';
- $result[] = 'General_Name';
- $result[] = 'General_Loading';
- $result[] = 'General_LoadingData';
- $result[] = 'General_Mobile';
- $result[] = 'General_All';
- $result[] = 'General_Search';
- $result[] = 'CorePluginsAdmin_Status';
- $result[] = 'DevicesDetection_Tablet';
- $result[] = 'CoreUpdater_UpdateTitle';
- $result[] = 'DevicesDetection_Device';
- $result[] = 'Installation_Legend';
- $result[] = 'HeatmapSessionRecording_DeleteScreenshot';
- $result[] = 'HeatmapSessionRecording_DeleteHeatmapScreenshotConfirm';
- $result[] = 'HeatmapSessionRecording_enable';
- $result[] = 'HeatmapSessionRecording_disable';
- $result[] = 'HeatmapSessionRecording_ChangeReplaySpeed';
- $result[] = 'HeatmapSessionRecording_ClickToSkipPauses';
- $result[] = 'HeatmapSessionRecording_AutoPlayNextPageview';
- $result[] = 'HeatmapSessionRecording_XSamples';
- $result[] = 'HeatmapSessionRecording_StatusActive';
- $result[] = 'HeatmapSessionRecording_StatusEnded';
- $result[] = 'HeatmapSessionRecording_StatusPaused';
- $result[] = 'HeatmapSessionRecording_RequiresActivity';
- $result[] = 'HeatmapSessionRecording_RequiresActivityHelp';
- $result[] = 'HeatmapSessionRecording_CaptureKeystrokes';
- $result[] = 'HeatmapSessionRecording_CaptureKeystrokesHelp';
- $result[] = 'HeatmapSessionRecording_SessionRecording';
- $result[] = 'HeatmapSessionRecording_Heatmap';
- $result[] = 'HeatmapSessionRecording_ActivityClick';
- $result[] = 'HeatmapSessionRecording_ActivityMove';
- $result[] = 'HeatmapSessionRecording_ActivityScroll';
- $result[] = 'HeatmapSessionRecording_ActivityResize';
- $result[] = 'HeatmapSessionRecording_ActivityFormChange';
- $result[] = 'HeatmapSessionRecording_ActivityPageChange';
- $result[] = 'HeatmapSessionRecording_HeatmapWidth';
- $result[] = 'HeatmapSessionRecording_Width';
- $result[] = 'HeatmapSessionRecording_Action';
- $result[] = 'HeatmapSessionRecording_DeviceType';
- $result[] = 'HeatmapSessionRecording_PlayerDurationXofY';
- $result[] = 'HeatmapSessionRecording_PlayerPlay';
- $result[] = 'HeatmapSessionRecording_PlayerPause';
- $result[] = 'HeatmapSessionRecording_PlayerRewindFast';
- $result[] = 'HeatmapSessionRecording_PlayerForwardFast';
- $result[] = 'HeatmapSessionRecording_PlayerReplay';
- $result[] = 'HeatmapSessionRecording_PlayerPageViewPrevious';
- $result[] = 'HeatmapSessionRecording_PlayerPageViewNext';
- $result[] = 'HeatmapSessionRecording_SessionRecordingsUsageBenefits';
- $result[] = 'HeatmapSessionRecording_ManageSessionRecordings';
- $result[] = 'HeatmapSessionRecording_ManageHeatmaps';
- $result[] = 'HeatmapSessionRecording_NoSessionRecordingsFound';
- $result[] = 'HeatmapSessionRecording_FieldIncludedTargetsHelpSessions';
- $result[] = 'HeatmapSessionRecording_NoHeatmapsFound';
- $result[] = 'HeatmapSessionRecording_AvgAboveFoldTitle';
- $result[] = 'HeatmapSessionRecording_AvgAboveFoldDescription';
- $result[] = 'HeatmapSessionRecording_TargetPage';
- $result[] = 'HeatmapSessionRecording_TargetPages';
- $result[] = 'HeatmapSessionRecording_ViewReport';
- $result[] = 'HeatmapSessionRecording_SampleLimit';
- $result[] = 'HeatmapSessionRecording_SessionNameHelp';
- $result[] = 'HeatmapSessionRecording_HeatmapSampleLimit';
- $result[] = 'HeatmapSessionRecording_SessionSampleLimit';
- $result[] = 'HeatmapSessionRecording_HeatmapSampleLimitHelp';
- $result[] = 'HeatmapSessionRecording_SessionSampleLimitHelp';
- $result[] = 'HeatmapSessionRecording_MinSessionTime';
- $result[] = 'HeatmapSessionRecording_MinSessionTimeHelp';
- $result[] = 'HeatmapSessionRecording_EditX';
- $result[] = 'HeatmapSessionRecording_StopX';
- $result[] = 'HeatmapSessionRecording_HeatmapUsageBenefits';
- $result[] = 'HeatmapSessionRecording_AdvancedOptions';
- $result[] = 'HeatmapSessionRecording_SampleRate';
- $result[] = 'HeatmapSessionRecording_HeatmapSampleRateHelp';
- $result[] = 'HeatmapSessionRecording_SessionSampleRateHelp';
- $result[] = 'HeatmapSessionRecording_ExcludedElements';
- $result[] = 'HeatmapSessionRecording_ExcludedElementsHelp';
- $result[] = 'HeatmapSessionRecording_ScreenshotUrl';
- $result[] = 'HeatmapSessionRecording_ScreenshotUrlHelp';
- $result[] = 'HeatmapSessionRecording_BreakpointX';
- $result[] = 'HeatmapSessionRecording_BreakpointGeneralHelp';
- $result[] = 'HeatmapSessionRecording_Rule';
- $result[] = 'HeatmapSessionRecording_UrlParameterValueToMatchPlaceholder';
- $result[] = 'HeatmapSessionRecording_EditHeatmapX';
- $result[] = 'HeatmapSessionRecording_TargetTypeIsAny';
- $result[] = 'HeatmapSessionRecording_TargetTypeIsNot';
- $result[] = 'HeatmapSessionRecording_PersonalInformationNote';
- $result[] = 'HeatmapSessionRecording_UpdatingData';
- $result[] = 'HeatmapSessionRecording_FieldIncludedTargetsHelp';
- $result[] = 'HeatmapSessionRecording_DeleteX';
- $result[] = 'HeatmapSessionRecording_DeleteHeatmapConfirm';
- $result[] = 'HeatmapSessionRecording_BreakpointGeneralHelpManage';
- $result[] = 'HeatmapSessionRecording_TargetPageTestTitle';
- $result[] = 'HeatmapSessionRecording_TargetPageTestErrorInvalidUrl';
- $result[] = 'HeatmapSessionRecording_TargetPageTestUrlMatches';
- $result[] = 'HeatmapSessionRecording_TargetPageTestUrlNotMatches';
- $result[] = 'HeatmapSessionRecording_TargetPageTestLabel';
- $result[] = 'HeatmapSessionRecording_ErrorXNotProvided';
- $result[] = 'HeatmapSessionRecording_ErrorPageRuleRequired';
- $result[] = 'HeatmapSessionRecording_CreationDate';
- $result[] = 'HeatmapSessionRecording_HeatmapCreated';
- $result[] = 'HeatmapSessionRecording_HeatmapUpdated';
- $result[] = 'HeatmapSessionRecording_FieldNamePlaceholder';
- $result[] = 'HeatmapSessionRecording_HeatmapNameHelp';
- $result[] = 'HeatmapSessionRecording_CreateNewHeatmap';
- $result[] = 'HeatmapSessionRecording_CreateNewSessionRecording';
- $result[] = 'HeatmapSessionRecording_EditSessionRecordingX';
- $result[] = 'HeatmapSessionRecording_DeleteSessionRecordingConfirm';
- $result[] = 'HeatmapSessionRecording_EndHeatmapConfirm';
- $result[] = 'HeatmapSessionRecording_EndSessionRecordingConfirm';
- $result[] = 'HeatmapSessionRecording_SessionRecordingCreated';
- $result[] = 'HeatmapSessionRecording_SessionRecordingUpdated';
- $result[] = 'HeatmapSessionRecording_Filter';
- $result[] = 'HeatmapSessionRecording_PlayRecordedSession';
- $result[] = 'HeatmapSessionRecording_DeleteRecordedSession';
- $result[] = 'HeatmapSessionRecording_DeleteRecordedPageview';
- $result[] = 'Live_ViewVisitorProfile';
- $result[] = 'HeatmapSessionRecording_HeatmapXRecordedSamplesSince';
- $result[] = 'HeatmapSessionRecording_PageviewsInVisit';
- $result[] = 'HeatmapSessionRecording_ColumnTime';
- $result[] = 'General_TimeOnPage';
- $result[] = 'Goals_URL';
- $result[] = 'General_Close';
- $result[] = 'HeatmapSessionRecording_HeatmapX';
- $result[] = 'HeatmapSessionRecording_NoHeatmapSamplesRecordedYet';
- $result[] = 'HeatmapSessionRecording_NoHeatmapScreenshotRecordedYet';
- $result[] = 'HeatmapSessionRecording_NoHeatmapSamplesRecordedYetWithoutSystemConfiguration';
- $result[] = 'HeatmapSessionRecording_NoHeatmapScreenshotRecordedYetWithoutSystemConfiguration';
- $result[] = 'HeatmapSessionRecording_HeatmapInfoTrackVisitsFromCountries';
- $result[] = 'HeatmapSessionRecording_SessionRecordingInfoTrackVisitsFromCountries';
- $result[] = 'HeatmapSessionRecording_AdBlockerDetected';
- $result[] = 'HeatmapSessionRecording_CaptureDomTitle';
- $result[] = 'HeatmapSessionRecording_CaptureDomInlineHelp';
- $result[] = 'HeatmapSessionRecording_MatomoJSNotWritableErrorMessage';
- $result[] = 'HeatmapSessionRecording_SessionRecordings';
- $result[] = 'HeatmapSessionRecording_Heatmaps';
- $result[] = 'HeatmapSessionRecording_Clicks';
- $result[] = 'HeatmapSessionRecording_ClickRate';
- $result[] = 'HeatmapSessionRecording_Moves';
- $result[] = 'HeatmapSessionRecording_MoveRate';
- $result[] = 'HeatmapSessionRecording_HeatmapTroubleshoot';
- }
-
- public function getJsFiles(&$jsFiles)
- {
- $jsFiles[] = "plugins/HeatmapSessionRecording/javascripts/rowaction.js";
- }
-
- public function getStylesheetFiles(&$stylesheets)
- {
- $stylesheets[] = "plugins/HeatmapSessionRecording/stylesheets/list-entities.less";
- $stylesheets[] = "plugins/HeatmapSessionRecording/stylesheets/edit-entities.less";
- $stylesheets[] = "plugins/HeatmapSessionRecording/vue/src/HsrTargetTest/HsrTargetTest.less";
- $stylesheets[] = "plugins/HeatmapSessionRecording/vue/src/HsrUrlTarget/HsrUrlTarget.less";
- $stylesheets[] = "plugins/HeatmapSessionRecording/stylesheets/recordings.less";
- $stylesheets[] = "plugins/HeatmapSessionRecording/vue/src/SessionRecordingVis/SessionRecordingVis.less";
- $stylesheets[] = "plugins/HeatmapSessionRecording/vue/src/HeatmapVis/HeatmapVis.less";
- $stylesheets[] = "plugins/HeatmapSessionRecording/vue/src/Tooltip/Tooltip.less";
- }
-
- public function activate()
- {
- $this->installHtAccess();
- }
-
- public function install()
- {
- $siteHsr = new SiteHsrDao();
- $siteHsr->install();
-
- $hsrSite = new LogHsrSite();
- $hsrSite->install();
-
- $hsr = new LogHsr($hsrSite);
- $hsr->install();
-
- $blobHsr = new LogHsrBlob();
- $blobHsr->install();
-
- $event = new LogHsrEvent($blobHsr);
- $event->install();
-
- $this->installHtAccess();
-
- $configuration = new Configuration();
- $configuration->install();
- }
-
- public function installHtAccess()
- {
- $htaccess = new HtAccess();
- $htaccess->install();
- }
-
- public function uninstall()
- {
- $siteHsr = new SiteHsrDao();
- $siteHsr->uninstall();
-
- $hsrSite = new LogHsrSite();
- $hsrSite->uninstall();
-
- $hsr = new LogHsr($hsrSite);
- $hsr->uninstall();
-
- $blobHsr = new LogHsrBlob();
- $blobHsr->uninstall();
-
- $event = new LogHsrEvent($blobHsr);
- $event->uninstall();
-
- $configuration = new Configuration();
- $configuration->uninstall();
- }
-
- public function isTrackerPlugin()
- {
- return true;
- }
-
- private function getSiteHsrDao()
- {
- return StaticContainer::get('Piwik\Plugins\HeatmapSessionRecording\Dao\SiteHsrDao');
- }
-
- public function addSiteTrackerCache(&$content, $idSite)
- {
- $hsr = $this->getSiteHsrDao();
- $hsrs = $hsr->getActiveRecords($idSite);
-
- foreach ($hsrs as $index => $hsr) {
- // we make sure to keep the cache file small as this is not needed in the cache
- $hsrs[$index]['page_treemirror'] = !empty($hsr['page_treemirror']) ? '1' : null;
- }
-
- $content['hsr'] = $hsrs;
- }
-
- public function addActionReferenceColumnsByTable(&$result)
- {
- $result['log_hsr'] = array('idaction_url');
- $result['log_hsr_event'] = array('idselector');
- }
-
- public function changeSessionLengthIfEmbedPage()
- {
- if (
- SettingsServer::isTrackerApiRequest()
- || Common::isPhpCliMode()
- ) {
- return;
- }
-
- // if there's no token_auth=... in the URL and there's no existing HSR session, then
- // we don't change the session options and try to use the normal matomo session.
- if (
- Common::getRequestVar('token_auth', false) === false
- && empty($_COOKIE[self::EMBED_SESSION_NAME])
- ) {
- return;
- }
-
- $module = Common::getRequestVar('module', '', 'string');
- $action = Common::getRequestVar('action', '', 'string');
- if (
- $module == 'HeatmapSessionRecording'
- && $action == 'embedPage'
- ) {
- Config::getInstance()->General['login_cookie_expire'] = self::EMBED_SESSION_TIME;
-
- Session::$sessionName = self::EMBED_SESSION_NAME;
- Session::rememberMe(Config::getInstance()->General['login_cookie_expire']);
- }
- }
-
- public static function getTranslationKey($type)
- {
- $key = '';
- switch ($type) {
- case 'pause':
- $key = 'HeatmapSessionRecording_PauseReason';
- break;
- case 'noDataSession':
- $key = 'HeatmapSessionRecording_NoSessionRecordedYetWithoutSystemConfiguration';
- break;
- case 'noDataHeatmap':
- $key = 'HeatmapSessionRecording_NoHeatmapSamplesRecordedYetWithoutSystemConfiguration';
- break;
- }
-
- if (!$key) {
- return null;
- }
-
- Piwik::postEvent('HeatmapSessionRecording.updateTranslationKey', [&$key]);
- return $key;
- }
-
- public static function isMatomoJsWritable($checkSpecificFile = '')
- {
- if (Manager::getInstance()->isPluginActivated('Cloud')) {
- return true;
- }
-
- $updater = StaticContainer::get('Piwik\Plugins\CustomJsTracker\TrackerUpdater');
- $filePath = $updater->getToFile()->getPath();
- $filesToCheck = array($filePath);
- $jsCodeGenerator = new TrackerCodeGenerator();
- if (SettingsPiwik::isMatomoInstalled() && $jsCodeGenerator->shouldPreferPiwikEndpoint()) {
- // if matomo is not installed yet, we definitely prefer matomo.js... check for isMatomoInstalled is needed
- // cause otherwise it would perform a db query before matomo DB is configured
- $filesToCheck[] = str_replace('matomo.js', 'piwik.js', $filePath);
- }
-
- if (!empty($checkSpecificFile)) {
- $filesToCheck = [$checkSpecificFile]; // mostly used for testing isMatomoJsWritable functionality
- }
-
- if (!Manager::getInstance()->isPluginActivated('CustomJsTracker')) {
- return false;
- }
-
- foreach ($filesToCheck as $fileToCheck) {
- $file = new File($fileToCheck);
-
- if (!$file->hasWriteAccess()) {
- return false;
- }
- }
-
- return true;
- }
-
- private function getHeatmaps($idSite)
- {
- return Request::processRequest('HeatmapSessionRecording.getHeatmaps', [
- 'idSite' => $idSite, 'filter_limit' => -1,
- 'includePageTreeMirror' => 0 // IMPORTANT for performance and IO. If you need page tree mirror please add another method and don't remove this parameter
- ], $default = []);
- }
-
- private function getSessionRecordings($idSite)
- {
- return Request::processRequest('HeatmapSessionRecording.getSessionRecordings', [
- 'idSite' => $idSite, 'filter_limit' => -1
- ], $default = []);
- }
-}
diff --git a/files/plugin-HeatmapSessionRecording-5.2.4/Input/Validator.php b/files/plugin-HeatmapSessionRecording-5.2.4/Input/Validator.php
deleted file mode 100644
index e1b99c3..0000000
--- a/files/plugin-HeatmapSessionRecording-5.2.4/Input/Validator.php
+++ /dev/null
@@ -1,176 +0,0 @@
-configuration = new Configuration();
- $this->systemSettings = $systemSettings;
- }
-
- private function supportsMethod($method)
- {
- return method_exists('Piwik\Piwik', $method);
- }
-
- public function checkHasSomeWritePermission()
- {
- if ($this->supportsMethod('checkUserHasSomeWriteAccess')) {
- // since Matomo 3.6.0
- Piwik::checkUserHasSomeWriteAccess();
- return;
- }
-
- Piwik::checkUserHasSomeAdminAccess();
- }
-
- public function checkWritePermission($idSite)
- {
- $this->checkSiteExists($idSite);
- Piwik::checkUserIsNotAnonymous();
-
- if ($this->supportsMethod('checkUserHasWriteAccess')) {
- // since Matomo 3.6.0
- Piwik::checkUserHasWriteAccess($idSite);
- return;
- }
-
- Piwik::checkUserHasAdminAccess($idSite);
- }
-
- public function checkHeatmapReportViewPermission($idSite)
- {
- $this->checkSiteExists($idSite);
- Piwik::checkUserHasViewAccess($idSite);
- $this->checkHeatmapRecordingEnabled();
- }
-
- public function checkSessionReportViewPermission($idSite)
- {
- $this->checkSiteExists($idSite);
- $this->checkUserIsNotAnonymousForView($idSite);
- Piwik::checkUserHasViewAccess($idSite);
- $this->checkSessionRecordingEnabled();
- }
-
- public function checkSessionReportWritePermission($idSite)
- {
- $this->checkWritePermission($idSite);
- $this->checkSessionRecordingEnabled();
- }
-
- public function checkHeatmapReportWritePermission($idSite)
- {
- $this->checkWritePermission($idSite);
- $this->checkHeatmapRecordingEnabled();
- }
-
- public function checkSessionRecordingEnabled()
- {
- if ($this->isSessionRecordingDisabled()) {
- throw new \Exception(Piwik::translate('HeatmapSessionRecording_ErrorSessionRecordingDisabled'));
- }
- }
-
- public function checkHeatmapRecordingEnabled()
- {
- if ($this->isHeatmapRecordingDisabled()) {
- throw new \Exception(Piwik::translate('HeatmapSessionRecording_ErrorHeatmapRecordingDisabled'));
- }
- }
-
- private function checkUserIsNotAnonymousForView($idSite)
- {
- if ($this->configuration->isAnonymousSessionRecordingAccessEnabled($idSite)) {
- Piwik::checkUserHasViewAccess($idSite);
- return;
- }
-
- Piwik::checkUserIsNotAnonymous();
- }
-
- private function checkSiteExists($idSite)
- {
- new Site($idSite);
- }
-
- public function canViewSessionReport($idSite)
- {
- if (empty($idSite) || $this->isSessionRecordingDisabled()) {
- return false;
- }
-
- if (
- !$this->configuration->isAnonymousSessionRecordingAccessEnabled($idSite)
- && Piwik::isUserIsAnonymous()
- ) {
- return false;
- }
-
- return Piwik::isUserHasViewAccess($idSite);
- }
-
- public function canViewHeatmapReport($idSite)
- {
- if (empty($idSite) || $this->isHeatmapRecordingDisabled()) {
- return false;
- }
-
- return Piwik::isUserHasViewAccess($idSite);
- }
-
- public function canWrite($idSite)
- {
- if (empty($idSite)) {
- return false;
- }
-
- if ($this->supportsMethod('isUserHasWriteAccess')) {
- // since Matomo 3.6.0
- return Piwik::isUserHasWriteAccess($idSite);
- }
-
- return Piwik::isUserHasAdminAccess($idSite);
- }
-
- public function isSessionRecordingDisabled()
- {
- return $this->systemSettings->disableSessionRecording->getValue();
- }
-
- public function isHeatmapRecordingDisabled()
- {
- return $this->systemSettings->disableHeatmapRecording->getValue();
- }
-}
diff --git a/files/plugin-HeatmapSessionRecording-5.2.4/Model/SiteHsrModel.php b/files/plugin-HeatmapSessionRecording-5.2.4/Model/SiteHsrModel.php
deleted file mode 100644
index f95767c..0000000
--- a/files/plugin-HeatmapSessionRecording-5.2.4/Model/SiteHsrModel.php
+++ /dev/null
@@ -1,489 +0,0 @@
-dao = $dao;
- $this->logHsrSite = $logHsrSite;
- }
-
- public function addHeatmap($idSite, $name, $matchPageRules, $sampleLimit, $sampleRate, $excludedElements, $screenshotUrl, $breakpointMobile, $breakpointTablet, $captureDomManually, $createdDate)
- {
- $this->checkHeatmap($name, $matchPageRules, $sampleLimit, $sampleRate, $excludedElements, $screenshotUrl, $breakpointMobile, $breakpointTablet);
-
- $status = SiteHsrDao::STATUS_ACTIVE;
-
- $idSiteHsr = $this->dao->createHeatmapRecord($idSite, $name, $sampleLimit, $sampleRate, $matchPageRules, $excludedElements, $screenshotUrl, $breakpointMobile, $breakpointTablet, $status, $captureDomManually, $createdDate);
- $this->clearTrackerCache($idSite);
-
- return (int) $idSiteHsr;
- }
-
- public function updateHeatmap($idSite, $idSiteHsr, $name, $matchPageRules, $sampleLimit, $sampleRate, $excludedElements, $screenshotUrl, $breakpointMobile, $breakpointTablet, $captureDomManually, $updatedDate)
- {
- $this->checkHeatmap($name, $matchPageRules, $sampleLimit, $sampleRate, $excludedElements, $screenshotUrl, $breakpointMobile, $breakpointTablet);
-
- $columns = array(
- 'name' => $name,
- 'sample_limit' => $sampleLimit,
- 'match_page_rules' => $matchPageRules,
- 'sample_rate' => $sampleRate,
- 'excluded_elements' => $excludedElements,
- 'screenshot_url' => $screenshotUrl,
- 'breakpoint_mobile' => $breakpointMobile,
- 'breakpoint_tablet' => $breakpointTablet,
- 'updated_date' => $updatedDate,
- );
-
- if (!empty($captureDomManually)) {
- $columns['capture_manually'] = 1;
- $columns['page_treemirror'] = null;
- } else {
- $columns['capture_manually'] = 0;
- }
-
- $this->updateHsrColumns($idSite, $idSiteHsr, $columns);
- $this->clearTrackerCache($idSite);
- }
-
- private function checkHeatmap($name, $matchPageRules, $sampleLimit, $sampleRate, $excludedElements, $screenshotUrl, $breakpointMobile, $breakpointTablet)
- {
- $name = new Name($name);
- $name->check();
-
- $pageRules = new PageRules($matchPageRules, 'matchPageRules', $needsOneEntry = true);
- $pageRules->check();
-
- $sampleLimit = new SampleLimit($sampleLimit);
- $sampleLimit->check();
-
- $sampleRate = new SampleRate($sampleRate);
- $sampleRate->check();
-
- $screenshotUrl = new ScreenshotUrl($screenshotUrl);
- $screenshotUrl->check();
-
- $excludedElements = new ExcludedElements($excludedElements);
- $excludedElements->check();
-
- $breakpointMobile = new Breakpoint($breakpointMobile, 'Mobile');
- $breakpointMobile->check();
-
- $breakpointTablet = new Breakpoint($breakpointTablet, 'Tablet');
- $breakpointTablet->check();
- }
-
- public function addSessionRecording($idSite, $name, $matchPageRules, $sampleLimit, $sampleRate, $minSessionTime, $requiresActivity, $captureKeystrokes, $createdDate)
- {
- $this->checkSession($name, $matchPageRules, $sampleLimit, $sampleRate, $minSessionTime, $requiresActivity, $captureKeystrokes);
- $status = SiteHsrDao::STATUS_ACTIVE;
-
- $idSiteHsr = $this->dao->createSessionRecord($idSite, $name, $sampleLimit, $sampleRate, $matchPageRules, $minSessionTime, $requiresActivity, $captureKeystrokes, $status, $createdDate);
-
- $this->clearTrackerCache($idSite);
- return (int) $idSiteHsr;
- }
-
- public function updateSessionRecording($idSite, $idSiteHsr, $name, $matchPageRules, $sampleLimit, $sampleRate, $minSessionTime, $requiresActivity, $captureKeystrokes, $updatedDate)
- {
- $this->checkSession($name, $matchPageRules, $sampleLimit, $sampleRate, $minSessionTime, $requiresActivity, $captureKeystrokes);
-
- $columns = array(
- 'name' => $name,
- 'sample_limit' => $sampleLimit,
- 'match_page_rules' => $matchPageRules,
- 'sample_rate' => $sampleRate,
- 'min_session_time' => $minSessionTime,
- 'requires_activity' => $requiresActivity,
- 'capture_keystrokes' => $captureKeystrokes,
- 'updated_date' => $updatedDate,
- );
-
- $this->updateHsrColumns($idSite, $idSiteHsr, $columns);
- $this->clearTrackerCache($idSite);
- }
-
- private function checkSession($name, $matchPageRules, $sampleLimit, $sampleRate, $minSessionTime, $requiresActivity, $captureKeystrokes)
- {
- $name = new Name($name);
- $name->check();
-
- $pageRules = new PageRules($matchPageRules, 'matchPageRules', $needsOneEntry = false);
- $pageRules->check();
-
- $sampleLimit = new SampleLimit($sampleLimit);
- $sampleLimit->check();
-
- $sampleRate = new SampleRate($sampleRate);
- $sampleRate->check();
-
- $minSessionTime = new MinSessionTime($minSessionTime);
- $minSessionTime->check();
-
- $requiresActivity = new RequiresActivity($requiresActivity);
- $requiresActivity->check();
-
- $captureKeystrokes = new CaptureKeystrokes($captureKeystrokes);
- $captureKeystrokes->check();
- }
-
- public function getHeatmap($idSite, $idSiteHsr)
- {
- $record = $this->dao->getRecord($idSite, $idSiteHsr, SiteHsrDao::RECORD_TYPE_HEATMAP);
-
- return $this->enrichHeatmap($record);
- }
-
- public function getSessionRecording($idSite, $idSiteHsr)
- {
- $record = $this->dao->getRecord($idSite, $idSiteHsr, SiteHsrDao::RECORD_TYPE_SESSION);
- return $this->enrichSessionRecording($record);
- }
-
- public function pauseHeatmap($idSite, $idSiteHsr)
- {
- $this->updateHsrColumns($idSite, $idSiteHsr, array('status' => SiteHsrDao::STATUS_PAUSED));
- }
-
- public function resumeHeatmap($idSite, $idSiteHsr)
- {
- $this->updateHsrColumns($idSite, $idSiteHsr, array('status' => SiteHsrDao::STATUS_ACTIVE));
- }
-
- public function deactivateHeatmap($idSite, $idSiteHsr)
- {
- $heatmap = $this->getHeatmap($idSite, $idSiteHsr);
-
- if (!empty($heatmap)) {
- $this->updateHsrColumns($idSite, $idSiteHsr, array('status' => SiteHsrDao::STATUS_DELETED));
-
- // the actual recorded heatmap data will still exist but we remove the "links" which is quick. a task will later remove all entries
- $this->logHsrSite->unlinkSiteRecords($idSiteHsr);
- }
- }
-
- public function checkHeatmapExists($idSite, $idSiteHsr)
- {
- $hsr = $this->dao->getRecord($idSite, $idSiteHsr, SiteHsrDao::RECORD_TYPE_HEATMAP);
-
- if (empty($hsr)) {
- throw new Exception(Piwik::translate('HeatmapSessionRecording_ErrorHeatmapDoesNotExist'));
- }
- }
-
- public function checkSessionRecordingExists($idSite, $idSiteHsr)
- {
- $hsr = $this->dao->getRecord($idSite, $idSiteHsr, SiteHsrDao::RECORD_TYPE_SESSION);
-
- if (empty($hsr)) {
- throw new Exception(Piwik::translate('HeatmapSessionRecording_ErrorSessionRecordingDoesNotExist'));
- }
- }
-
- public function pauseSessionRecording($idSite, $idSiteHsr)
- {
- $this->updateHsrColumns($idSite, $idSiteHsr, array('status' => SiteHsrDao::STATUS_PAUSED));
- }
-
- public function resumeSessionRecording($idSite, $idSiteHsr)
- {
- $this->updateHsrColumns($idSite, $idSiteHsr, array('status' => SiteHsrDao::STATUS_ACTIVE));
- }
-
- public function deactivateSessionRecording($idSite, $idSiteHsr)
- {
- $session = $this->getSessionRecording($idSite, $idSiteHsr);
-
- if (!empty($session)) {
- $this->updateHsrColumns($idSite, $idSiteHsr, array('status' => SiteHsrDao::STATUS_DELETED));
-
- // the actual recording will still exist but we remove the "links" which is quick. a task will later remove all entries
- $this->logHsrSite->unlinkSiteRecords($idSiteHsr);
- }
- }
-
- public function deactivateRecordsForSite($idSite)
- {
- foreach ($this->dao->getRecords($idSite, SiteHsrDao::RECORD_TYPE_HEATMAP, false) as $heatmap) {
- $this->deactivateHeatmap($idSite, $heatmap['idsitehsr']);
- }
-
- foreach ($this->dao->getRecords($idSite, SiteHsrDao::RECORD_TYPE_SESSION, false) as $session) {
- $this->deactivateSessionRecording($idSite, $session['idsitehsr']);
- }
- }
-
- public function pauseRecordsForSite($idSite)
- {
- foreach ($this->dao->getRecords($idSite, SiteHsrDao::RECORD_TYPE_HEATMAP, false) as $heatmap) {
- $this->pauseHeatmap($idSite, $heatmap['idsitehsr']);
- }
-
- foreach ($this->dao->getRecords($idSite, SiteHsrDao::RECORD_TYPE_SESSION, false) as $session) {
- $this->pauseSessionRecording($idSite, $session['idsitehsr']);
- }
- }
-
- public function resumeRecordsForSite($idSite)
- {
- foreach ($this->dao->getRecords($idSite, SiteHsrDao::RECORD_TYPE_HEATMAP, false) as $heatmap) {
- $this->resumeHeatmap($idSite, $heatmap['idsitehsr']);
- }
-
- foreach ($this->dao->getRecords($idSite, SiteHsrDao::RECORD_TYPE_SESSION, false) as $session) {
- $this->resumeSessionRecording($idSite, $session['idsitehsr']);
- }
- }
-
- public function endHeatmap($idSite, $idSiteHsr)
- {
- $heatmap = $this->getHeatmap($idSite, $idSiteHsr);
- if (!empty($heatmap)) {
- $this->updateHsrColumns($idSite, $idSiteHsr, array('status' => SiteHsrDao::STATUS_ENDED));
-
- Piwik::postEvent('HeatmapSessionRecording.endHeatmap', array($idSite, $idSiteHsr));
- }
- }
-
- public function endSessionRecording($idSite, $idSiteHsr)
- {
- $session = $this->getSessionRecording($idSite, $idSiteHsr);
- if (!empty($session)) {
- $this->updateHsrColumns($idSite, $idSiteHsr, array('status' => SiteHsrDao::STATUS_ENDED));
-
- Piwik::postEvent('HeatmapSessionRecording.endSessionRecording', array($idSite, $idSiteHsr));
- }
- }
-
- /**
- * @param $idSite
- * @param bool $includePageTreeMirror performance and IO tweak has some heatmaps might have a 16MB or more treemirror and it would be loaded on every request causing a lot of IO etc.
- * @return array
- */
- public function getHeatmaps($idSite, $includePageTreeMirror)
- {
- $heatmaps = $this->dao->getRecords($idSite, SiteHsrDao::RECORD_TYPE_HEATMAP, $includePageTreeMirror);
-
- return $this->enrichHeatmaps($heatmaps);
- }
-
- public function getSessionRecordings($idSite)
- {
- $sessionRecordings = $this->dao->getRecords($idSite, SiteHsrDao::RECORD_TYPE_SESSION, $includePageTreeMirror = false);
-
- return $this->enrichSessionRecordings($sessionRecordings);
- }
-
- public function hasSessionRecordings($idSite)
- {
- $hasSession = $this->dao->hasRecords($idSite, SiteHsrDao::RECORD_TYPE_SESSION);
-
- return !empty($hasSession);
- }
-
- public function hasHeatmaps($idSite)
- {
- $hasHeatmap = $this->dao->hasRecords($idSite, SiteHsrDao::RECORD_TYPE_HEATMAP);
-
- return !empty($hasHeatmap);
- }
-
- public function setPageTreeMirror($idSite, $idSiteHsr, $treeMirror, $screenshotUrl)
- {
- $heatmap = $this->getHeatmap($idSite, $idSiteHsr);
- if (!empty($heatmap)) {
- // only supported by heatmaps
- $columns = array(
- 'page_treemirror' => $treeMirror,
- 'screenshot_url' => $screenshotUrl
- );
- if (!empty($heatmap['capture_manually']) && !empty($treeMirror)) {
- $columns['capture_manually'] = 0;
- }
- $this->updateHsrColumns($idSite, $idSiteHsr, $columns);
- }
- }
-
- public function getPiwikRequestDate($hsr)
- {
- // we sub one day to make sure to include them all
- $from = Date::factory($hsr['created_date'])->subDay(1)->toString();
- $to = Date::now()->addDay(1)->toString();
-
- if ($from === $to) {
- $dateRange = $from;
- $period = 'year';
- } else {
- $period = 'range';
- $dateRange = $from . ',' . $to;
- }
-
- return array('period' => $period, 'date' => $dateRange);
- }
-
- private function enrichHeatmaps($heatmaps)
- {
- if (empty($heatmaps)) {
- return array();
- }
-
- foreach ($heatmaps as $index => $heatmap) {
- $heatmaps[$index] = $this->enrichHeatmap($heatmap);
- }
-
- return $heatmaps;
- }
-
- private function enrichHeatmap($heatmap)
- {
- if (empty($heatmap)) {
- return $heatmap;
- }
-
- unset($heatmap['record_type']);
- unset($heatmap['min_session_time']);
- unset($heatmap['requires_activity']);
- unset($heatmap['capture_keystrokes']);
- $heatmap['created_date_pretty'] = Date::factory($heatmap['created_date'])->getLocalized(DateTimeFormatProvider::DATE_FORMAT_SHORT);
-
- if ((!method_exists(SettingsServer::class, 'isMatomoForWordPress') || !SettingsServer::isMatomoForWordPress()) && !SettingsServer::isTrackerApiRequest()) {
- $heatmap['heatmapViewUrl'] = self::completeWidgetUrl('showHeatmap', 'idSiteHsr=' . (int) $heatmap['idsitehsr'] . '&useDateUrl=0', (int) $heatmap['idsite']);
- }
-
- return $heatmap;
- }
-
- public static function completeWidgetUrl($action, $params, $idSite, $period = null, $date = null)
- {
- if (!isset($date)) {
- if (empty(self::$defaultDate)) {
- $userPreferences = new UserPreferences();
- self::$defaultDate = $userPreferences->getDefaultDate();
- if (empty(self::$defaultDate)) {
- self:: $defaultDate = 'today';
- }
- }
- $date = self::$defaultDate;
- }
-
- if (!isset($period)) {
- if (!isset(self::$defaultPeriod)) {
- $userPreferences = new UserPreferences();
- self::$defaultPeriod = $userPreferences->getDefaultPeriod(false);
- if (empty(self::$defaultPeriod)) {
- self::$defaultPeriod = 'day';
- }
- }
- $period = self::$defaultPeriod;
- }
-
- $token = Access::getInstance()->getTokenAuth();
-
- $url = 'index.php?module=Widgetize&action=iframe&moduleToWidgetize=HeatmapSessionRecording&actionToWidgetize=' . urlencode($action) . '&' . $params . '&idSite=' . (int) $idSite . '&period=' . urlencode($period) . '&date=' . urlencode($date);
- if (!empty($token)) {
- $url .= '&token_auth=' . urlencode($token);
- }
- return $url;
- }
-
- private function enrichSessionRecordings($sessionRecordings)
- {
- if (empty($sessionRecordings)) {
- return array();
- }
-
- foreach ($sessionRecordings as $index => $sessionRecording) {
- $sessionRecordings[$index] = $this->enrichSessionRecording($sessionRecording);
- }
-
- return $sessionRecordings;
- }
-
- private function enrichSessionRecording($session)
- {
- if (empty($session)) {
- return $session;
- }
-
- unset($session['record_type']);
- unset($session['screenshot_url']);
- unset($session['page_treemirror']);
- unset($session['excluded_elements']);
- unset($session['breakpoint_mobile']);
- unset($session['breakpoint_tablet']);
- $session['created_date_pretty'] = Date::factory($session['created_date'])->getLocalized(DateTimeFormatProvider::DATE_FORMAT_SHORT);
-
- return $session;
- }
-
- protected function getCurrentDateTime()
- {
- return Date::now()->getDatetime();
- }
-
- private function updateHsrColumns($idSite, $idSiteHsr, $columns)
- {
- if (!isset($columns['updated_date'])) {
- $columns['updated_date'] = $this->getCurrentDateTime();
- }
-
- $this->dao->updateHsrColumns($idSite, $idSiteHsr, $columns);
- $this->clearTrackerCache($idSite);
- }
-
- private function clearTrackerCache($idSite)
- {
- Tracker\Cache::deleteCacheWebsiteAttributes($idSite);
- }
-}
diff --git a/files/plugin-HeatmapSessionRecording-5.2.4/SystemSettings.php b/files/plugin-HeatmapSessionRecording-5.2.4/SystemSettings.php
deleted file mode 100644
index 3c16e9c..0000000
--- a/files/plugin-HeatmapSessionRecording-5.2.4/SystemSettings.php
+++ /dev/null
@@ -1,296 +0,0 @@
-breakpointMobile = $this->createBreakpointMobileSetting();
- $this->breakpointTablet = $this->createBreakpointTabletSetting();
- $this->disableTrackingByDefault = $this->createDisableTrackingByDefaultSetting();
- $this->disableSessionRecording = $this->createDisableSessionRecordingSetting();
- $this->disableHeatmapRecording = $this->createDisableHeatmapRecordingSetting();
- $this->includeCountries = $this->createIncludeCountriesSetting();
-
- if (Plugin\Manager::getInstance()->isPluginActivated('CustomJsTracker')) {
- $trackerUpdater = StaticContainer::get(TrackerUpdater::class);
- if (!$trackerUpdater || !$trackerUpdater->getToFile() || !$trackerUpdater->getToFile()->hasWriteAccess()) {
- // only works if matomo file can be updated
- $this->disableTrackingByDefault->setIsWritableByCurrentUser(false);
- }
- } else {
- $this->disableTrackingByDefault->setIsWritableByCurrentUser(false);
- }
- }
-
- private function createDisableTrackingByDefaultSetting()
- {
- $setting = new TrackingDisableDefault('trackingDisabledDefault', false, FieldConfig::TYPE_BOOL, $this->pluginName);
- $setting->setConfigureCallback(function (FieldConfig $field) {
- $field->title = Piwik::translate('HeatmapSessionRecording_TrackingDisabledDefaultSettingTitle');
- $field->uiControl = FieldConfig::UI_CONTROL_CHECKBOX;
- $field->description = Piwik::translate('HeatmapSessionRecording_TrackingDisabledDefaultSettingDescription');
- });
- $this->addSetting($setting);
- return $setting;
- }
-
- private function createBreakpointMobileSetting()
- {
- return $this->makeSetting('breakpointMobile', Breakpoint::DEFAULT_MOBILE, FieldConfig::TYPE_INT, function (FieldConfig $field) {
- $field->title = Piwik::translate('HeatmapSessionRecording_BreakpointX', Piwik::translate('General_Mobile'));
- $field->uiControl = FieldConfig::UI_CONTROL_TEXT;
- $field->description = Piwik::translate('HeatmapSessionRecording_BreakpointGeneralHelp');
- $field->validate = function ($value) {
- $breakpoint = new Breakpoint($value, Piwik::translate('General_Mobile'));
- $breakpoint->check();
- };
- });
- }
-
- private function createBreakpointTabletSetting()
- {
- return $this->makeSetting('breakpointTablet', Breakpoint::DEFAULT_TABLET, FieldConfig::TYPE_INT, function (FieldConfig $field) {
- $field->title = Piwik::translate('HeatmapSessionRecording_BreakpointX', Piwik::translate('DevicesDetection_Tablet'));
- $field->uiControl = FieldConfig::UI_CONTROL_TEXT;
- $field->description = Piwik::translate('HeatmapSessionRecording_BreakpointGeneralHelp');
- $field->validate = function ($value) {
- $breakpoint = new Breakpoint($value, Piwik::translate('DevicesDetection_Tablet'));
- $breakpoint->check();
- };
- });
- }
-
- private function createDisableSessionRecordingSetting()
- {
- $setting = new TrackingDisableDefault('disableSessionRecording', false, FieldConfig::TYPE_BOOL, $this->pluginName);
- $setting->setConfigureCallback(function (FieldConfig $field) {
- $field->title = Piwik::translate('HeatmapSessionRecording_DisableSessionRecordingTitle', Piwik::translate('General_Mobile'));
- $field->description = Piwik::translate('HeatmapSessionRecording_DisableSessionRecordingDescription');
- $field->inlineHelp = Piwik::translate('HeatmapSessionRecording_DisableSessionRecordingInlineHelp', array('',''));
- });
- $this->addSetting($setting);
-
- return $setting;
- }
-
- private function createDisableHeatmapRecordingSetting()
- {
- $setting = new TrackingDisableDefault('disableHeatmapRecording', false, FieldConfig::TYPE_BOOL, $this->pluginName);
- $setting->setConfigureCallback(function (FieldConfig $field) {
- $field->title = Piwik::translate('HeatmapSessionRecording_DisableHeatmapRecordingTitle', Piwik::translate('General_Mobile'));
- $field->description = Piwik::translate('HeatmapSessionRecording_DisableHeatmapRecordingDescription');
- $field->inlineHelp = Piwik::translate('HeatmapSessionRecording_DisableHeatmapRecordingInlineHelp', array('',''));
- });
- $this->addSetting($setting);
-
- return $setting;
- }
-
- public function createIncludeCountriesSetting()
- {
- return $this->makeSetting('included_countries', [], FieldConfig::TYPE_ARRAY, function (FieldConfig $field) {
- $field->title = Piwik::translate('HeatmapSessionRecording_EnableIncludeCountriesTitle');
- $field->description = Piwik::translate('HeatmapSessionRecording_EnableIncludeCountriesDescription');
- $field->uiControl = FieldConfig::UI_CONTROL_MULTI_TUPLE;
- $field1 = new FieldConfig\MultiPair(Piwik::translate('HeatmapSessionRecording_Country'), 'country', FieldConfig::UI_CONTROL_SINGLE_SELECT);
- $field1->availableValues = $this->getAvailableCountries();
- $field->uiControlAttributes['field1'] = $field1->toArray();
-
- $self = $this;
- $field->transform = function ($value) use ($self) {
- return $self->transformCountryList($value);
- };
- $field->validate = function ($value) use ($field1) {
- foreach ($value as $country) {
- if (empty($country['country'])) {
- continue;
- }
- if ($country['country'] === 'xx') {
- continue; // valid, country not detected
- }
- if (!isset($field1->availableValues[$country['country']])) {
- throw new \Exception('Invalid country code');
- }
- }
- };
- });
- }
-
- public function transformCountryList($value)
- {
- if (!empty($value) && is_array($value)) {
- $newVal = [];
- foreach ($value as $index => $val) {
- if (empty($val['country'])) {
- continue;
- }
- $newVal[] = ['country' => $val['country']];
- }
- return $newVal;
- }
- return $value;
- }
-
- public function save()
- {
- $this->endSessionRecordings();
- $this->endHeatmapRecordings();
- parent::save();
-
- if (!empty($this->disableTrackingByDefault)) {
- $oldValue = $this->disableTrackingByDefault->getOldValue();
- $newValue = $this->disableTrackingByDefault->getValue();
- if ($oldValue != $newValue) {
- $plugin = Plugin\Manager::getInstance()->getLoadedPlugin($this->pluginName);
- if (!empty($plugin) && $plugin instanceof HeatmapSessionRecording) {
- $plugin->updatePiwikTracker();
- }
- }
- }
- }
-
- public function getIncludedCountries($applyTransformation = true)
- {
- $includedCountries = $this->includeCountries->getValue();
- $transformedList = [];
-
- if (!empty($includedCountries)) {
- foreach ($includedCountries as $value) {
- $transformedList[] = $value['country'];
- }
- }
-
- if (!empty($transformedList) && $applyTransformation) {
- $transformedList = $this->getAvailableCountries($transformedList);
- }
-
- return $transformedList;
- }
-
- private function getAvailableCountries($countryCodesToFilter = [])
- {
- $regionDataProvider = StaticContainer::get(RegionDataProvider::class);
- $countryList = $regionDataProvider->getCountryList();
- array_walk($countryList, function (&$item, $key) {
- $item = Piwik::translate('Intl_Country_' . strtoupper($key));
- });
- asort($countryList); //order by localized name
-
- if (!empty($countryCodesToFilter)) {
- $filteredList = [];
- foreach ($countryList as $countryCode => $countryName) {
- if (in_array($countryCode, $countryCodesToFilter)) {
- $filteredList[$countryCode] = $countryName;
- }
- }
-
- return $filteredList;
- }
-
- return $countryList;
- }
-
- private function endSessionRecordings()
- {
- if (
- !empty($this->disableSessionRecording->getValue()) &&
- $this->disableSessionRecording->getOldValue() != $this->disableSessionRecording->getValue()
- ) {
- $sites = SitesManagerAPI::getInstance()->getAllSitesId();
- $this->disableSessionRecording->setValue(false); //added this to fetch results, else it throws an exception
- foreach ($sites as $idSite) {
- if (Site::getTypeFor($idSite) === 'proxysite') {
- continue; //do not delete session recording for proxySite as it will throw an exception due to read only behaviour
- }
- $recordings = Request::processRequest('HeatmapSessionRecording.getSessionRecordings', [
- 'idSite' => $idSite, 'filter_limit' => -1
- ]);
- foreach ($recordings as $recording) {
- Request::processRequest('HeatmapSessionRecording.deleteSessionRecording', [
- 'idSite' => $idSite,
- 'idSiteHsr' => $recording['idsitehsr']
- ]);
- }
- }
-
- $this->disableSessionRecording->setValue(true);
- Cache::deleteTrackerCache();
- }
- }
-
- private function endHeatmapRecordings()
- {
- if (
- !empty($this->disableHeatmapRecording->getValue()) &&
- $this->disableHeatmapRecording->getOldValue() != $this->disableHeatmapRecording->getValue()
- ) {
- $sites = SitesManagerAPI::getInstance()->getAllSitesId();
- $this->disableHeatmapRecording->setValue(false); //added this to fetch results, else it throws an exception
- foreach ($sites as $idSite) {
- if (Site::getTypeFor($idSite) === 'proxysite') {
- continue; //do not delete heatmap for proxySite as it will throw an exception due to read only behaviour
- }
- $recordings = Request::processRequest('HeatmapSessionRecording.getHeatmaps', [
- 'idSite' => $idSite, 'filter_limit' => -1
- ]);
- foreach ($recordings as $recording) {
- Request::processRequest('HeatmapSessionRecording.deleteHeatmap', [
- 'idSite' => $idSite,
- 'idSiteHsr' => $recording['idsitehsr']
- ]);
- }
- }
-
- $this->disableHeatmapRecording->setValue(true);
- Cache::deleteTrackerCache();
- }
- }
-}
diff --git a/files/plugin-HeatmapSessionRecording-5.2.4/lang/en.json b/files/plugin-HeatmapSessionRecording-5.2.4/lang/en.json
deleted file mode 100644
index 9f39115..0000000
--- a/files/plugin-HeatmapSessionRecording-5.2.4/lang/en.json
+++ /dev/null
@@ -1,237 +0,0 @@
-{
- "HeatmapSessionRecording": {
- "Recordings": "Recordings",
- "Heatmaps": "Heatmaps",
- "Heatmap": "Heatmap",
- "HeatmapX": "Heatmap %s",
- "NHeatmaps": "%s heatmaps",
- "NSessionRecordings": "%s session recordings",
- "NoHeatmapsFound": "No heatmaps found",
- "NoSessionRecordingsFound": "No session recordings found",
- "HeatmapUsageBenefits": "Heatmaps let you record all clicks, mouse moves, and scroll activities of your visitors on a certain page. This helps you to find out where users think something is clickable but is not, whether there are parts of the page that are being barely viewed or interacted with, what your visitors are looking for, how much of the page is visible when users view your page, and more.",
- "HeatmapXRecordedSamplesSince": "%1$s samples have been recorded since %2$s.",
- "HeatmapTroubleshoot": "Having issues? %1$sLearn more%2$s.",
- "SessionRecordingsUsageBenefits": "Session recordings let you record all activities of a real visitor during their session (visit) such as clicks, mouse movements, scrolls, window resizes, page changes, and form interactions. You can then replay these interactions to see exactly how a visitor interacted with your website. This way you understand their expectations, problems they may have, usage patterns, and more.",
- "SessionRecordings": "Session Recordings",
- "SessionRecording": "Session Recording",
- "AutoPlayNextPageview": "Click to %1$s autoplay next page view (shortcut %2$s)",
- "ClickToSkipPauses": "Click to %1$s skip pauses (shortcut %2$s)",
- "ChangeReplaySpeed": "Change replay speed (shortcut %s)",
- "PageviewXofY": "Pageview %1$s of %2$s",
- "enable": "enable",
- "disable": "disable",
- "ReplayX": "Replay %s",
- "DeleteScreenshot": "Delete Screenshot",
- "CreationDate": "Creation Date",
- "SessionRecordingX": "Session Recording %s",
- "ReplayRecordedSession": "Replay recorded session",
- "RecordedSessions": "Recorded Sessions",
- "RecordedSessionsDocStatusActive": "This session recording is active. Up to %1$d sessions will be recorded with a sample rate of %2$s.",
- "RecordedSessionsDocStatusEnded": "This session recording has ended and no new sessions will be recorded.",
- "RecordedHeatmapDocStatusActive": "This heatmap is active. Up to %1$d page views will be recorded with a sample rate of %2$s.",
- "RecordedHeatmapDocStatusEnded": "This heatmap has ended. No new activity will be recorded.",
- "TrackingDisabledDefaultSettingTitle": "Disable tracking by default",
- "TrackingDisabledDefaultSettingDescription": "This feature can be useful if your Matomo has multiple sites and you want to use the feature only in a few specific sites. When disabling tracking by default, the Heatmap and Session Recording feature won't execute on any site unless you specifically enable it as part of your tracking code for example by calling '_paq.push(['HeatmapSessionRecording::enable']);'. This avoids unnecessary network requests to the 'configs.php' file to determine if a heatmap or session recording is configured for the current site. It can also be useful for privacy reasons if you want to make sure the feature will be only used on some sites.",
- "StatusActive": "Active",
- "StatusEnded": "Ended",
- "StatusPaused": "Paused",
- "ExcludedElements": "Excluded Elements",
- "ExcludedElementsHelp": "You can optionally define CSS selectors to exclude certain elements that should not be visible in the heatmap preview. For example a popup that is shown when the target page is opened. You can separate multiple selectors with a comma.",
- "Rule": "Rule",
- "Manage": "Manage",
- "ViewReport": "View report",
- "ErrorXNotANumber": "\"%1$s\" has to be a number.",
- "SampleLimit": "Sample Limit",
- "TimeOnSite": "Time on website",
- "HeatmapSampleLimit": "Number of page views",
- "SessionSampleLimit": "Number of sessions",
- "HeatmapSampleLimitHelp": "Defines the amount of page views you want to record in total.",
- "SessionSampleLimitHelp": "Defines the amount of sessions you want to record in total.",
- "PageviewsInVisit": "Recorded pageviews in this session",
- "PlayRecordedSession": "Play this recorded session",
- "DeleteRecordedSession": "Delete this recorded session (no confirmation asked)",
- "DeleteRecordedPageview": "Delete this recorded page view (no confirmation asked)",
- "ViewportResolution": "Viewport Resolution (width x height)",
- "OnePageview": "1 pageview",
- "TargetPage": "Target Page",
- "TargetPages": "Entry Pages",
- "ActivityClick": "Click",
- "ActivityMove": "Move",
- "ActivityScroll": "Scroll",
- "ActivityScrollElement": "Scroll Element",
- "ActivityResize": "Resize",
- "ActivityFormChange": "Form Change",
- "ActivityFormText": "Form Text Change",
- "ActivityFormValue": "Form Value Change",
- "ActivityInitialDom": "Initial Page",
- "ActivityPageChange": "Change Within Page",
- "PlayerRewindFast": "Rewind %1$s seconds (shortcut %2$s)",
- "PlayerForwardFast": "Skip %1$s seconds (shortcut %2$s)",
- "PlayerPageViewPrevious": "Play previous pageview of this visitor %1$s (shortcut %2$s)",
- "PlayerPageViewNext": "Play next pageview of this visitor (%1$s) (shortcut %2$s)",
- "PlayerPlay": "Play (shortcut %s or space)",
- "PlayerPause": "Pause (shortcut %s or space)",
- "PlayerReplay": "Replay (shortcut %s or space)",
- "PlayerDurationXofY": "%1$s of %2$s",
- "AdvancedOptions": "Advanced options",
- "AvgAboveFoldTitle": "Avg. Above Fold %spx",
- "XSamples": "%s samples",
- "AvgAboveFoldDescription": "On average visitors see the content above this line without scrolling",
- "NoSessionRecordedYet": "No session has been recorded yet. If there are supposed to be recorded sessions by now, maybe the configured entry page does not match any page on your website. It is also recommended to check the \"System Check\" under \"Administration\" (only Super Users) to see if your system is configured to automatically recorded sessions.",
- "NoHeatmapSamplesRecordedYet": "No page view has been recorded yet for this heatmap. If there are supposed to be recordings by now, maybe the page targets configured for this heatmap do not match any page on your website. It is also recommended to check the \"System Check\" under \"Administration\" (only Super Users) to see if your system is configured to automatically track Heatmaps.",
- "NoSessionRecordedYetWithoutSystemConfiguration": "No session has been recorded yet. If there are supposed to be recorded sessions by now, maybe the configured entry page does not match any page on your website.",
- "NoHeatmapSamplesRecordedYetWithoutSystemConfiguration": "No page view has been recorded yet for this heatmap. If there are supposed to be recordings by now, maybe the page targets configured for this heatmap do not match any page on your website.",
- "NoHeatmapScreenshotRecordedYet": "There have been %1$s samples recorded so far. However, no screenshot has been taken yet. If there is a \"%2$s\" for this heatmap, it may take a while for the screenshot to become available as a user first needs to open this screenshot URL. Depending on the sample rate this may take a while.",
- "ColumnPageviewsDocumentation": "The number of page views that were recorded during this session.",
- "ColumnBrowserDocumentation": "The browser the visitor was using when this session was recorded.",
- "ColumnDeviceDocumentation": "The device the visitor was using when this session was recorded.",
- "ColumnLocationDocumentation": "The location of the visitor when this session was recorded.",
- "ColumnOperatingSystem": "OS",
- "ColumnTime": "Time",
- "ColumnLabelRecordedSessions": "Entry URL → Exit URL",
- "ColumnOperatingSystemDocumentation": "The operating system the visitor was using when this session was recorded.",
- "ColumnActionsDocumentation": "Play the recorded session or remove the recording permanently.",
- "ColumnTimeDocumentation": "The time the recording started in the timezone of the website.",
- "ColumnTimeOnSiteDocumentation": "How much time the visitor spent in total while the session was recorded",
- "ColumnTimeOnPageDocumentation": "How much time the visitor spent on this page while the session was recorded",
- "ColumnResolutionDocumentation": "The number of pixels of the visible viewport in the browser window when the user opened this page.",
- "UrlXDoesNotLookLikeUrl": "The %s does not look like a URL. Make sure it contains a protocol like http:\/\/ or that it starts with \/\/",
- "ReportRecordedSessionsDocumentation": "A list of all sessions that have been recorded. You can replay any recorded session.",
- "NoHeatmapsConfiguredInfo": "There are currently no active heatmaps. To view heatmaps, please ask a user with at least admin access to create a new heatmap.",
- "NoSessionRecordingsConfiguredInfo": "There are currently no active session recordings. To record new sessions, please ask a user with at least admin access to create a new recording.",
- "NotSupportedBrowser": "This browser is not supported, please use a later version or try a different browser.",
- "HeatmapWidth": "Heatmap width",
- "Width": "Width",
- "Action": "Action",
- "DeviceType": "Device Type",
- "BreakpointX": "Breakpoint %s",
- "BreakpointGeneralHelp": "The device type is automatically detected when a visitor views your website. However, sometimes it might not be possible to detect the device type. If your website is responsive and your layout breaks at a certain point, we will put desktop users with a small resolution into this device type for more accurate heatmaps. Any width lower than this value will be put into this device type. Set it to zero if your website is not responsive.",
- "BreakpointGeneralHelpManage": "A user with Super User access can change the default values for these breakpoints in Administration => General Settings.",
- "CaptureKeystrokes": "Capture keystrokes",
- "CaptureKeystrokesHelp": "If enabled, any text that is entered into text form fields are recorded. While the text is recorded, any character a user enters is replaced with a star ('*'). You may whitelist certain fields to be recorded in plain text by specifying a 'data-matomo-unmask' attribute on a form field. However, password fields and many other fields which could potentially include personal information (address, email, credit card information, username, phone number, …) will be always automatically masked if detected by us as such (%1$slearn more%2$s). Please note that when you enable this feature, you may record personal data which may affect GDPR.",
- "PersonalInformationNote": "Please note a %1$s may record personal or sensitive information. If you wish to hide certain content on your website or app, you may tag this content by adding a %2$sdata-matomo-mask%3$s attribute to the HTML markup. %4$sLearn more%5$s",
- "RequiresActivity": "Requires activity",
- "RequiresActivityHelp": "If enabled, only sessions that have a scroll and a click activity in one page view will be recorded. This prevents the recording of sessions with not much activity.",
- "SampleRate": "Sample Rate",
- "HeatmapSampleRateHelp": "Also known as 'traffic'. When you select 100%%, all visitors that visit the selected target page will be recorded. When you select for example 10%%, only every 10th visitor will be recorded. The lower the percentage you select, the longer it will take to reach the selected sample limit.",
- "SessionSampleRateHelp": "Also known as 'traffic'. When you select 100%%, all sessions will be recorded as soon as they have reached the target page. When you select for example 10%%, only every 10th session will be recorded. The lower the percentage you select, the longer it will take to reach the selected sample limit.",
- "MinSessionTime": "Min Session Time",
- "MinSessionTimeHelp": "A session will be only recorded when a visitor has spent at least the specified time on a page.",
- "ScreenshotUrl": "Screenshot URL",
- "ScreenshotUrlHelp": "By default, a screenshot is taken when the first visitor views the target page. If different page URLs match your target page, you can specify a specific URL that should be used to capture the screenshot. The heatmap visualization will be only available once at least one visitor has visited this URL whose activities are recorded. If defined, the URL has to match exactly. To ignore the protocol, start the URL with two double slashes (\/\/example.com). Please note that this URL cannot be changed as soon as a screenshot has been taken.",
- "GettingStarted": "Getting Started",
- "TargetPageTestTitle": "URL validator",
- "TargetPageTestLabel": "Enter a full URL including the protocol to check if activities will be recorded on this URL:",
- "TargetPageTestErrorInvalidUrl": "Enter a URL including a protocol.",
- "TargetPageTestUrlMatches": "Activities will be recorded on this URL",
- "TargetPageTestUrlNotMatches": "Activities will not be recorded on this URL",
- "UrlParameterValueToMatchPlaceholder": "Value to match for URL parameter name",
- "TargetTypeIsAny": "is any",
- "TargetTypeIsNot": "not %s",
- "TargetTypeEqualsExactly": "equals exactly",
- "TargetTypeEqualsExactlyInfo": "The value has to match exactly, including the URL protocol, search query and hash.",
- "TargetTypeEqualsSimple": "equals simple",
- "TargetTypeEqualsSimpleInfo": "The URL will match any protocol (eg http and https) with or without \"www.\" subdomain. Any trailing slash in the path as well as the search query and hash part of the URL will be ignored when matching the URL.",
- "TargetTypeContains": "contains",
- "TargetTypeExists": "exists",
- "TargetTypeStartsWith": "starts with",
- "TargetTypeRegExp": "matches the regular expression",
- "TargetTypeRegExpInfo": "Any regular expression, for example \"^(.*)test(.*)$\".",
- "UpdatingData": "Updating data…",
- "FieldIncludedTargetsHelp": "Targets allow you to define on which pages the user activities should be recorded. You can define one or more conditions. For example, you can define to record activities whenever the URL or path equals a certain value and only if a certain URL parameter is present in the URL. Activities will be recorded only when all conditions are met, not if only one of them is met. All conditions will be evaluated case-insensitive. When you select 'equals simple', the URL protocol, search parameters and a trailing slash will be ignored.",
- "FieldIncludedTargetsHelpSessions": "Targets allow you to configure to only start the recording of a session as soon as a visitor has reached a certain page. This lets you for example only record sessions that go through the check out process. You can define one or more conditions. For example, you can define to record a session only when the URL or path equals a certain value and only if a certain URL parameter is present in the URL. Sessions will be only recorded when all conditions are met on a page view, not if only one of them is met. All conditions will be evaluated case-insensitive. When you select 'equals simple', the URL protocol, search parameters and a trailing slash will be ignored.",
- "DeleteHeatmapScreenshotConfirm": "Are you sure you want to delete this screenshot? It may take a while for the screenshot to be re-taken.",
- "DeleteHeatmapConfirm": "Are you sure you want to delete this heatmap? Reports previously generated heatmaps will no longer be available in the reporting UI.",
- "DeleteSessionRecordingConfirm": "Are you sure you want to delete this session recording? Recordings previously generated will no longer be available in the reporting UI.",
- "EndSessionRecordingConfirm": "Are you sure you want to stop recording any new sessions?",
- "EndHeatmapConfirm": "Are you sure you want to stop capturing any activities for this heatmap?",
- "ErrorInvalidRegExp": "The regular expression \"%1$s\" does not have a valid format.",
- "ErrorHeatmapNameDuplicate": "The heatmap name is already in use by another heatmap.",
- "ErrorHeatmapDoesNotExist": "The requested heatmap does not exist",
- "ErrorSessionRecordingDoesNotExist": "The requested session recording does not exist",
- "ErrorSessionRecordingDisabled": "The session recording feature is disabled. To use this feature it needs to be enabled by a Matomo super user in the general settings.",
- "ErrorHeatmapRecordingDisabled": "The heatmap recording feature is disabled. To use this feature it needs to be enabled by a Matomo super user in the general settings.",
- "ErrorXNotProvided": "Please provide a value for \"%1$s\".",
- "ErrorXTooLow": "\"%1$s\" is too low, minimum allowed value is %2$s.",
- "ErrorXTooHigh": "\"%1$s\" is too high, maximum allowed value is %2$s.",
- "ErrorXTooLong": "\"%1$s\" is too long, max %2$s characters are allowed.",
- "ErrorNotAnArray": "\"%1$s\" has to be an array.",
- "ErrorInnerIsNotAnArray": "Each \"%1$s\" within \"%2$s\" has to be an array.",
- "ErrorArrayMissingKey": "Missing array key \"%1$s\" in \"%2$s\" at position \"%3$s\".",
- "ErrorArrayMissingValue": "Missing value for array key \"%1$s\" in \"%2$s\" at position \"%3$s\".",
- "ErrorXNotWhitelisted": "The value for \"%1$s\" is not allowed, use one of: %2$s.",
- "ErrorXContainsWhitespace": "The \"%1$s\" is not allowed to contain any white space.",
- "ErrorPageRuleRequired": "At least one page rule has to be set.",
- "HeatmapCreated": "The heatmap has been successfully created.",
- "HeatmapUpdated": "The heatmap has been successfully updated.",
- "SessionRecordingCreated": "The session recording has been successfully created.",
- "SessionRecordingUpdated": "The session recording has been successfully updated.",
- "FieldNamePlaceholder": "eg 'Sign Up Page'",
- "PageRule": "Page Rule",
- "HeatmapNameHelp": "Defines the name under which the report for this heatmap will be available.",
- "SessionNameHelp": "Defines the name under which the session recordings will be available.",
- "CreateNewHeatmap": "Create new heatmap",
- "StopX": "Stop recording any new activities for this %s.",
- "EditX": "Edit %s",
- "DeleteX": "Delete %s",
- "EditHeatmapX": "Edit Heatmap %s",
- "Filter": "Filter",
- "EditSessionRecordingX": "Edit Session Recording %s",
- "CreateNewSessionRecording": "Create new session recording",
- "TargetAttributeUrl": "URL",
- "TargetAttributePath": "Path",
- "FilesystemDirectory": "directory",
- "TargetAttributeUrlParameter": "URL Parameter",
- "TargetAttributeUrlParameterExample": "nameOfUrlParameter",
- "ManageSessionRecordings": "Manage Session Recordings",
- "ManageHeatmaps": "Manage Heatmaps",
- "ConfigsPhpSuccess": "'%s' is accessible",
- "ConfigsPhpNotAccessible": "The URL '%s' seems to be not accessible from the Internet or Intranet.",
- "ConfigsPhpErrorResult": "As a result, tracking Heatmaps and Session Recordings may not work. You may need to change your webserver configuration to allow access to this file via the Internet or Intranet.",
- "ConfigsPhpSelfSignedError": "Requesting '%s' resulted in an SSL error. Maybe you are using a self signed certificate?",
- "ConfigsInternetDisabled": "We couldn't check if '%s' is accessible because the internet connection is disabled on this Matomo.",
- "ConfigsPhpUnknown": "We couldn't check if '%s' is accessible over the Internet or Intranet.",
- "ConfigsPhpManualCheck": "Please open the URL manually in a browser to see if the response contains 'Piwik.HeatmapSessionRecording'. If not, you might need to modify your server configuration as this file needs to be accessible via a browser from the Internet or Intranet.",
- "ConfigsPhpUnknownError": "Requesting '%1$s' resulted in an error: %2$s.",
- "ManageHeatmapSubcategoryHelp": "Heatmaps let you record all clicks, mouse moves, and scroll activities of your visitors on a specific page. This section enables you to create and manage Heatmap tracking for your website.",
- "ManageSessionRecordingSubcategoryHelp": "Session recordings let you record all activities of a real visitor during their session (visit) such as clicks, mouse movements, scrolls, window resizes, page changes, and form interactions. This section enables you to create and manage Session Recordings for your site.",
- "DisableSessionRecordingTitle": "Disable Session Recording",
- "DisableSessionRecordingDescription": "By disabling this feature no session recordings can be configured or tracked anymore.",
- "DisableSessionRecordingInlineHelp": "%1$sNote: Disabling this feature will delete all session recordings including previously tracked session recordings. There will be no changes for heatmaps if you enable or disable this feature.%2$s",
- "PeriodDisabledErrorMessage": "The \"%1$s\" period is disabled but required for this feature to work. Select a different period or ask a system administrator to change Matomo's config file 'config\/config.ini.php' to allow the \"%1$s\" period in the \"enabled_periods_API\" setting.",
- "DisableHeatmapRecordingTitle": "Disable Heatmaps",
- "DisableHeatmapRecordingDescription": "By disabling this feature no heatmap can be configured or recorded anymore.",
- "DisableHeatmapRecordingInlineHelp": "%1$sNote: Disabling this feature will delete all heatmaps including previously tracked heatmaps. There will be no changes for session recording if you enable or disable this feature.%2$s",
- "EnableIncludeCountriesTitle": "Only track visitors from specific countries",
- "EnableIncludeCountriesDescription": "By default, all visits are recorded. Enable this section when you want to track visits from specific countries.",
- "Country": "Country",
- "HeatmapInfoTrackVisitsFromCountries": "The heatmap is configured to only track visits from %1$s.",
- "SessionRecordingInfoTrackVisitsFromCountries": "The session recording is configured to only track visits from %1$s.",
- "AdBlockerDetected": "%1$s might not be visible when using an ad blocker. Please disable your ad blocker on this site to make sure Matomo works without any issues.",
- "PauseReason": "The %1$s was paused due to exhaustion of your quota, please contact support for further details.",
- "TotalEvents": "Events",
- "ColumnTotalEventsDocumentation": "The number of events that were recorded during this session. For example: click, move, scroll, resize, page changes and form interaction events.",
- "CaptureDomTitle": "Capture Heatmap Snapshot Manually",
- "CaptureDomInlineHelp": "By default, heatmap snapshots are automatically taken on page load. If your page dynamically loads elements (such as with lazy loading) your snapshot could be incomplete. You can manually capture a complete snapshot by enabling this option and executing the following Javascript code in your browser: %1$s %2$sNote:%3$s This option resets automatically after capturing the snapshot.",
- "MatomoJSNotWritableErrorMessage": "HeatmapSessionRecording: %1$s are currently unable to track visits, because the matomo.js file is read-only. Please see the %2$sdocumentation%3$s about how to make the file writable.",
- "Clicks": "Clicks:",
- "ClickRate": "Click rate:",
- "Moves": "Moves:",
- "MoveRate": "Move rate:",
- "HeatmapAddedActivity": "added a heatmap \"%1$s\" for site \"%2$s\"",
- "HeatmapDeletedActivity": "deleted the heatmap \"%1$s\" for site \"%2$s\"",
- "HeatmapPausedActivity": "paused the heatmap \"%1$s\" for site \"%2$s\"",
- "HeatmapResumedActivity": "resumed the heatmap \"%1$s\" for site \"%2$s\"",
- "HeatmapEndedActivity": "ended the heatmap \"%1$s\" for site \"%2$s\"",
- "HeatmapScreenshotDeletedActivity": "deleted the heatmap screenshot \"%1$s\" for site \"%2$s\"",
- "HeatmapUpdatedActivity": "updated the heatmap \"%1$s\" for site \"%2$s\"",
- "SessionRecordingAddedActivity": "added a session recording \"%1$s\" for site \"%2$s\"",
- "SessionRecordingDeletedActivity": "deleted the session recording \"%1$s\" for site \"%2$s\"",
- "SessionRecordingEndedActivity": "ended the session recording \"%1$s\" for site \"%2$s\"",
- "SessionRecordingUpdatedActivity": "updated the session recording \"%1$s\" for site \"%2$s\"",
- "SessionRecordingPausedActivity": "paused the session recording \"%1$s\" for site \"%2$s\"",
- "SessionRecordingResumedActivity": "resumed the session recording \"%1$s\" for site \"%2$s\"",
- "RecordedSessionDeletedActivity": "deleted a recorded session for session recording \"%1$s\" for site \"%2$s\"",
- "RecordedPageviewDeletedActivity": "deleted a recorded page view for session recording \"%1$s\" for site \"%2$s\""
- }
-}
diff --git a/files/plugin-HeatmapSessionRecording-5.2.4/stylesheets/list-entities.less b/files/plugin-HeatmapSessionRecording-5.2.4/stylesheets/list-entities.less
deleted file mode 100644
index c7c1189..0000000
--- a/files/plugin-HeatmapSessionRecording-5.2.4/stylesheets/list-entities.less
+++ /dev/null
@@ -1,35 +0,0 @@
-.manageHsr {
- .filterStatus, .hsrSearchFilter {
- display: inline-block;
- width:200px;
- }
-
- div.filterStatus {
- margin: 0 -0.75em;
- display: inline-block;
-
- .theWidgetContent & {
- margin: 0;
- }
- }
-
- th.action, td.action {
- width: 250px;
-
- a {
- color: black;
- }
- }
-
- .index {
- width: 60px;
- }
-
- a.table-action {
- margin-right: 3.5px;
- }
-
- a.table-action:last-child {
- margin-right: 0;
- }
-}
\ No newline at end of file
diff --git a/files/plugin-HeatmapSessionRecording-5.2.4/tracker.min.js b/files/plugin-HeatmapSessionRecording-5.2.4/tracker.min.js
deleted file mode 100644
index 91383a4..0000000
--- a/files/plugin-HeatmapSessionRecording-5.2.4/tracker.min.js
+++ /dev/null
@@ -1,125 +0,0 @@
-(function(){var N=1;var aH=9;var o=10;var P=8;var w=3;var ax=["button","submit","reset"];
-/*!!
- * Copyright (C) 2015 Pavel Savshenko
- * Copyright (C) 2011 Google Inc. All rights reserved.
- * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
- * Copyright (C) 2008 Matt Lilek
- * Copyright (C) 2009 Joseph Pecoraro
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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.
- */
-;
-var i={};i.cssPath=function(aT,aR){if(aT.nodeType!==N){return""}var aQ=[];var aP=aT;while(aP){var aS=i._cssPathStep(aP,!!aR,aP===aT);if(!aS){break}aQ.push(aS);if(aS.optimized){break}aP=aP.parentNode}aQ.reverse();return aQ.join(" > ")};i._cssPathStep=function(a4,aW,a3){if(a4.nodeType!==N){return null}var a2=a4.getAttribute("id");if(aW){if(a2){return new i.DOMNodePathStep(ba(a2),true)}var aQ=a4.nodeName.toLowerCase();if(aQ==="body"||aQ==="head"||aQ==="html"){return new i.DOMNodePathStep(a4.nodeName.toLowerCase(),true)}}var aP=a4.nodeName.toLowerCase();if(a2){return new i.DOMNodePathStep(aP.toLowerCase()+ba(a2),true)}var aX=a4.parentNode;if(!aX||aX.nodeType===aH){return new i.DOMNodePathStep(aP.toLowerCase(),true)}function bg(bi){var bj=bi.getAttribute("class");if(!bj){return[]}return bj.split(/\s+/g).filter(Boolean).map(function(bk){return"$"+bk})}function ba(bi){return"#"+bf(bi)}function bf(bj){if(bb(bj)){return bj}var bi=/^(?:[0-9]|-[0-9-]?)/.test(bj);var bk=bj.length-1;return bj.replace(/./g,function(bm,bl){return((bi&&bl===0)||!aR(bm))?aT(bm,bl===bk):bm
-})}function aT(bj,bi){return"\\"+a1(bj)+(bi?"":" ")}function a1(bj){var bi=bj.charCodeAt(0).toString(16);if(bi.length===1){bi="0"+bi}return bi}function aR(bi){if(/[a-zA-Z0-9_\-]/.test(bi)){return true}return bi.charCodeAt(0)>=160}function bb(bi){return/^-?[a-zA-Z_][a-zA-Z0-9_\-]*$/.test(bi)}function a6(bi){var bk={},bj;for(bj=0;bj>>0};aP.prototype.nodeId=function(aQ){var aR=aQ[aP.ID_PROP];if(!aR){aR=aQ[aP.ID_PROP]=aP.nextId_++}return aR};aP.prototype.set=function(aQ,aR){var aS=this.nodeId(aQ);this.nodes[aS]=aQ;this.values[aS]=aR};aP.prototype.get=function(aQ){var aR=this.nodeId(aQ);return this.values[aR]};aP.prototype.has=function(aQ){return this.nodeId(aQ) in this.nodes};aP.prototype["delete"]=function(aQ){var aR=this.nodeId(aQ);delete this.nodes[aR];this.values[aR]=undefined};aP.prototype.keys=function(){var aQ=[];for(var aR in this.nodes){if(!this.isIndex(aR)){continue}aQ.push(this.nodes[aR])}return aQ};aP.ID_PROP="__mutation_summary_node_map_id__";aP.nextId_=1;return aP})();var aC;
-(function(aP){aP[aP.STAYED_OUT=0]="STAYED_OUT";aP[aP.ENTERED=1]="ENTERED";aP[aP.STAYED_IN=2]="STAYED_IN";aP[aP.REPARENTED=3]="REPARENTED";aP[aP.REORDERED=4]="REORDERED";aP[aP.EXITED=5]="EXITED"})(aC||(aC={}));function B(aP){return aP===aC.ENTERED||aP===aC.EXITED}var ab=(function(){function aP(aW,aV,aR,aT,aS,aU,aQ,aX){if(aV===void 0){aV=false}if(aR===void 0){aR=false}if(aT===void 0){aT=false}if(aS===void 0){aS=null}if(aU===void 0){aU=false}if(aQ===void 0){aQ=null}if(aX===void 0){aX=null}this.node=aW;this.childList=aV;this.attributes=aR;this.characterData=aT;this.oldParentNode=aS;this.added=aU;this.attributeOldValues=aQ;this.characterDataOldValue=aX;this.isCaseInsensitive=this.node.nodeType===N&&this.node instanceof HTMLElement&&this.node.ownerDocument instanceof HTMLDocument}aP.prototype.getAttributeOldValue=function(aQ){if(!this.attributeOldValues){return undefined}if(this.isCaseInsensitive){aQ=aQ.toLowerCase()}return this.attributeOldValues[aQ]};aP.prototype.getAttributeNamesMutated=function(){var aR=[];
-if(!this.attributeOldValues){return aR}for(var aQ in this.attributeOldValues){aR.push(aQ)}return aR};aP.prototype.attributeMutated=function(aR,aQ){this.attributes=true;this.attributeOldValues=this.attributeOldValues||{};if(aR in this.attributeOldValues){return}this.attributeOldValues[aR]=aQ};aP.prototype.characterDataMutated=function(aQ){if(this.characterData){return}this.characterData=true;this.characterDataOldValue=aQ};aP.prototype.removedFromParent=function(aQ){this.childList=true;if(this.added||this.oldParentNode){this.added=false}else{this.oldParentNode=aQ}};aP.prototype.insertedIntoParent=function(){this.childList=true;this.added=true};aP.prototype.getOldParent=function(){if(this.childList){if(this.oldParentNode){return this.oldParentNode}if(this.added){return null}}return this.node.parentNode};return aP})();var ao=(function(){function aP(){this.added=new J();this.removed=new J();this.maybeMoved=new J();this.oldPrevious=new J();this.moved=undefined}return aP})();var W=(function(aQ){b(aP,aQ);
-function aP(aU,aS){aQ.call(this);this.rootNode=aU;this.reachableCache=undefined;this.wasReachableCache=undefined;this.anyParentsChanged=false;this.anyAttributesChanged=false;this.anyCharacterDataChanged=false;for(var aR=0;aR1){throw Error("Invalid request option. all has no options.")}aU.queries.push({all:true});continue}if("attribute" in aT){var aV={attribute:j(aT.attribute)};aV.elementFilter=aG.parseSelectors("*["+aV.attribute+"]");if(Object.keys(aT).length>1){throw Error("Invalid request option. attribute has no options.")}aU.queries.push(aV);continue}if("element" in aT){var aS=Object.keys(aT).length;var aV={element:aT.element,elementFilter:aG.parseSelectors(aT.element)};if(aT.hasOwnProperty("elementAttributes")){aV.attributeList=az(aT.elementAttributes);aS--}if(aS>1){throw Error("Invalid request option. element only allows elementAttributes option.")}aU.queries.push(aV);continue}if(aT.characterData){if(Object.keys(aT).length>1){throw Error("Invalid request option. characterData has no options.")
-}aU.queries.push({characterData:true});continue}throw Error("Invalid request option. Unknown query request.")}return aU};aP.prototype.createSummaries=function(aR){if(!aR||!aR.length){return[]}var aQ=new K(this.root,aR,this.elementFilter,this.calcReordered,this.options.oldPreviousSibling);var aT=[];for(var aS=0;aS=0){aV={}}else{if(aU.attributes.name){var a3=String(aU.attributes.name.value).toLowerCase();if(a3.indexOf("twitter:")>=0||a3.indexOf("description")>=0||a3.indexOf("keywords")>=0){aV={}}}}}else{if("LINK"===aU.tagName){if(aU.attributes.rel){var a2=String(aU.attributes.rel.value).toLowerCase();
-var a1=["icon","preload","preconnect","dns-prefetch","next","prev","alternate","search"];if(a1.indexOf(a2)>=0){aV={}}}if(aU.attributes.href){var aT=String(aU.attributes.href.value).toLowerCase().indexOf(".scr.kaspersky-labs.com");if(aT>5&&aT<=20){aV={}}}if(aU.href){if(typeof I.URL==="function"){var aS=ak.onCssLoaded(aU.href);var aQ=3;if(!aS){aR(aU.href);function aR(a5){if(aQ>0){setTimeout(function(){aQ--;aS=ak.onCssLoaded(aU.href);if(!aS){aR(aU.href)}},300)}}}}aV.url=aU.href}}}}return aV};aP.prototype.serializeAddedAndMoved=function(aT,aQ,aU){var aW=this;var aS=aT.concat(aQ).concat(aU);var aV=new d.NodeMap();aS.forEach(function(aZ){var aY=aZ.parentNode;var aX=aV.get(aY);if(!aX){aX=new d.NodeMap();aV.set(aY,aX)}aX.set(aZ,true)});var aR=[];aV.keys().forEach(function(aY){var aX=aV.get(aY);var a0=aX.keys();while(a0.length){var aZ=a0[0];while(aZ.previousSibling&&aX.has(aZ.previousSibling)){aZ=aZ.previousSibling}while(aZ&&aX.has(aZ)){var a1=aW.serializeNode(aZ);a1.previousSibling=aW.serializeNode(aZ.previousSibling);
-a1.parentNode=aW.serializeNode(aZ.parentNode);aR.push(a1);aX["delete"](aZ);aZ=aZ.nextSibling}var a0=aX.keys()}});return aR};aP.prototype.serializeAttributeChanges=function(aQ){var aS=this;var aR=new d.NodeMap();Object.keys(aQ).forEach(function(aT){aQ[aT].forEach(function(aW){var aU=aR.get(aW);if(!aU){aU=aS.serializeNode(aW);aU.attributes={};aR.set(aW,aU)}var aV=aN.shouldMaskElementRecursive(aW);var aX=aS.getAttributesFromNode(aW,aV.isIgnoredField,aV.isIgnoredContent);aU.attributes[aT]=aT in aX?aX[aT]:null})});return aR.keys().map(function(aT){return aR.get(aT)})};aP.prototype.applyChanged=function(aT){var aW=this;var aR=aT[0];var aU=aR.removed.map(function(aX){return aW.serializeNode(aX)});var aS=this.serializeAddedAndMoved(aR.added,aR.reparented,aR.reordered);var aQ=this.serializeAttributeChanges(aR.attributeChanged);var aV=aR.characterDataChanged.map(function(aY){var aZ=aW.serializeNode(aY);if(aY.nodeType===w&&aY.parentNode){aY=aY.parentNode}var aX=aN.shouldMaskElementRecursive(aY,false,false);
-aZ.textContent=aN.getMaskedTextContent(aY,aX.isIgnoredField,aX.isIgnoredContent);return aZ});this.mirror.applyChanged(aU,aS,aQ,aV);aR.removed.forEach(function(aX){aW.forgetNode(aX)})};return aP})()}
-/*!!
- * Copyright (C) InnoCraft Ltd - All rights reserved.
- *
- * All information contained herein is, and remains the property of InnoCraft Ltd.
- *
- * @link https://www.innocraft.com/
- * @license For license details see https://www.innocraft.com/license
- */
-;var O=document;var I=window;var F=0;var l=false;var L=!u();var am=true;var n=null;var at=false;var ad="";var T=false;var g=15*60*1000;var aa=30*60*1000;var S=10;var av=(5*60*1000);var aA=2000;var C=1000;var H=100;var Y=500;var G=false;function u(){if("object"!==typeof JSON){return true}if("function"!==typeof Array.prototype.map||"function"!==typeof Array.prototype.filter||"function"!==typeof Array.prototype.indexOf){return true}if("function"!==typeof Element.prototype.getBoundingClientRect){return true}var aP=["cc.bingj.com"];
-if(aP.indexOf(O.domain)!==-1||String(O.domain).indexOf(".googleusercontent.com")!==-1){return true}var aR=/alexa|baidu|bing|bot|crawler|curl|crawling|duckduckgo|facebookexternalhit|feedburner|googlebot|google web preview|linkdex|nagios|postrank|pingdom|robot|slurp|spider|yahoo!|yandex|wget/i.test(navigator.userAgent);if(aR){return true}var aQ=String(O.referrer);if(aQ&&aQ.indexOf("module=Overlay&action=startOverlaySession")>=0){return true}return false}function U(){if(l&&"object"===typeof console){if(typeof console.debug==="function"){console.debug.apply(console,arguments)}else{if(typeof console.log==="function"){console.log.apply(console,arguments)}}}}var D=function(){return true};var s=1;var aJ=2;var h=3;var V=4;var aK=5;var ag=6;var a=7;var k=8;var e=9;var ar=10;var p=11;var ay=12;var aF=13;var aD=0;var af=1;var c=2;var aI=true;var Q=false;var an=false;var aO=true;var M=null;var A=false;var ae={};if("object"===typeof JSON){ae=JSON}var aj=false;var al=[];var aL={hasObserver:function(){if(typeof WebKitMutationObserver!=="undefined"){return true
-}else{if(typeof MutationObserver!=="undefined"){return true}}return false}};var ai=aL.hasObserver();var r={getScrollLeft:function(){return I.document.body.scrollLeft||I.document.documentElement.scrollLeft},getScrollTop:function(){return I.document.body.scrollTop||I.document.documentElement.scrollTop},getDocumentHeight:function(){return au.safeMathMax([O.body.offsetHeight,O.body.scrollHeight,O.documentElement.offsetHeight,O.documentElement.clientHeight,O.documentElement.scrollHeight,1])},getDocumentWidth:function(){return au.safeMathMax([O.body.offsetWidth,O.body.scrollWidth,O.documentElement.offsetWidth,O.documentElement.clientWidth,O.documentElement.scrollWidth,1])},getWindowSize:function(){var aP=I.innerHeight||O.documentElement.clientHeight||O.body.clientHeight;var aQ=I.innerWidth||O.documentElement.clientWidth||O.body.clientWidth;return{width:aQ,height:aP}}};var t={namespace:"hsr",set:function(aR,aV,aT){aV=parseInt(aV,10);aT=parseInt(aT,10);var aU="";var aQ=t.getHsrConfigs(aR);var aS=false;
-for(var aP=0;aP2){return true}}}if(aY){var aX=aP.parentNode?aP.parentNode:null;var aQ=false;while(aX){if(aN.hasAttribute(aX,"data-piwik-mask")||aN.hasAttribute(aX,"data-matomo-mask")){return true}else{if(!aQ&&aX&&aN.hasAttribute(aX,"data-matomo-unmask")){aQ=true}aX=aX.parentNode?aX.parentNode:null}}if(aQ){return false}}if(aN.hasAttribute(aP,"data-matomo-unmask")){return false}if(aT){return false}return true},shouldMaskContent:function(aR,aQ){if(!aR){return false}if(aR.tagName&&aR.tagName!=="FORM"&&aN.hasAttribute(aR,"data-matomo-mask")){return true}if(aR.tagName&&aR.tagName!=="FORM"&&aN.hasAttribute(aR,"data-matomo-unmask")){return false
-}if(aQ){var aP=aR.parentNode?aR.parentNode:null;while(aP){if(aR.nodeName==="#text"&&aN.hasAttribute(aP,"data-matomo-unmask")){return false}else{if(aP.tagName!=="FORM"&&aN.hasAttribute(aP,"data-matomo-mask")){return true}else{aP=aP.parentNode?aP.parentNode:null}}}}return false},isAllowedInputType:function(aP){return(aP.type&&ax.indexOf(aP.type)!==-1&&!aN.hasAttribute(aP,"data-piwik-mask")&&!aN.hasAttribute(aP,"data-matomo-mask"))}};var au={safeMathMax:function(aP){var aQ=[];var aR;for(aR=0;aR0}function x(){return f("pk_hsr_forcesample=1")||f("pk_hsr_capturescreen=1")}function v(){return f("pk_hsr_forcesample=0")}function Z(aP){if(x()){return true}if(v()){return false}if(aP>=100){return true}if(aP<=0){return false}if(aP>=1){return aP>=au.getRandomInt(1,H)}return(aP*10)>=au.getRandomInt(1,H*10)}function q(aP){if("undefined"!==typeof aP.HeatmapSessionRecording){return}aP.HeatmapSessionRecording={myId:au.generateUniqueId(),hasReceivedConfig:false,hasRequestedConfig:false,hasTrackedData:false,hasSentStopTrackingEvent:false,enabled:true,hsrIdsToGetDOM:[],disable:function(){this.enabled=false},enable:function(){this.enabled=true
-},isEnabled:function(){return L&&this.enabled},numSentTrackingRequests:0,Heatmap:{data:[],hsrids:[],configs:[],addConfig:function(aQ){if("object"!==typeof aQ||!aQ.id){return}aQ.id=parseInt(aQ.id,10);this.configs.push(aQ);if("undefined"===typeof aQ.sample_rate){aQ.sample_rate=H}else{aQ.sample_rate=Math.min(parseFloat(aQ.sample_rate),H)}if(aQ.id&&Z(aQ.sample_rate)&&D(aQ)){this.addHsrId(aQ.id);if((aQ.getdom&&!aQ.capture_manually)||f("pk_hsr_capturescreen=1")){aP.HeatmapSessionRecording.hsrIdsToGetDOM.push(aQ.id)}}},addHsrId:function(aQ){this.hsrids.push(aQ);if(aP.HeatmapSessionRecording.hasTrackedData){z.recordData(af,{ty:a,id:aQ})}}},Both:{data:[]},Session:{data:[],hsrids:[],configs:[],addConfig:function(aS){if("object"!==typeof aS||!aS.id){return}aS.id=parseInt(aS.id,10);if("undefined"===typeof aS.sample_rate){aS.sample_rate=H}else{aS.sample_rate=Math.min(parseFloat(aS.sample_rate),H)}aS.conditionsMet=false;this.configs.push(aS);var aR=parseInt(aP.getSiteId(),10);var aT=t.get(aP,aS.id);if(1===aT&&!v()){aS.sample_rate=H;
-aS.activity=false;aS.min_time=0}else{if(x()){}else{if(0===aT||!Z(aS.sample_rate)){t.set(aP,aS.id,0);return}}}this.checkConditionsMet();if(aS.min_time){var aQ=this;Piwik.DOM.onReady(function(){var aU=(aS.min_time*1000)-au.getTimeSincePageReady()+120;if(aU>=0){setTimeout(function(){aQ.checkConditionsMet()},aU)}else{aQ.checkConditionsMet()}})}},checkConditionsMet:function(){var aR;for(var aS=0;aS=au.roundTimeToSeconds(au.getTimeSincePageReady())){aQ=false}if(aR.activity&&!an){an=r.getDocumentHeight()<=r.getWindowSize().height}if(aR.activity&&(!Q||!an)){aQ=false}if(aQ){aR.conditionsMet=true;if(D(aR)){if("undefined"===typeof aR.keystrokes||!aR.keystrokes||aR.keystrokes==="0"){aI=false}this.addHsrId(aR.id)}}}}},addHsrId:function(aQ){this.hsrids.push(aQ);if(aP.HeatmapSessionRecording.hasTrackedData){z.recordData(c,{ty:a,id:aQ})}var aR=parseInt(aP.getSiteId(),10);t.set(aP,aQ,1)}},addConfig:function(aQ){this.hasRequestedConfig=true;
-this.hasReceivedConfig=true;if("undefined"===typeof aQ||!aQ){aM.checkAllConfigsReceived();return}if("object"===typeof aQ.heatmap){this.Heatmap.addConfig(aQ.heatmap)}var aR;if(aQ.heatmaps&&au.isArray(aQ.heatmaps)&&aQ.heatmaps.length){for(aR=0;aR=0;aR--){if(aQ[aR]&&aQ[aR].ty&&aQ[aR].ty===e){aQ.splice(aR,1)}}}}}if(aP.length&&aT.Both.data.length){aQ=aQ.concat(aT.Both.data);aT.Both.data=[]}if("undefined"===typeof aX){aX=this.shouldEndRecording(aW)}if(aX&&aT.hasTrackedData&&!aT.hasSentStopTrackingEvent&&aV){aQ.push({ty:p});aT.hasSentStopTrackingEvent=true}if(!aP||!aP.length||!aQ||!aQ.length){return}if(aW.HeatmapSessionRecording.hsrIdsToGetDOM&&aW.HeatmapSessionRecording.hsrIdsToGetDOM.length){if(!ak.initialDOM&&ai){var aU=new y(O,{initialize:function(aY,aZ){ak.initialDOM=ae.stringify({rootId:aY,children:aZ})}});aU.disconnect()}if(ak.initialDOM&&ai){for(var aS=0;aSM)&&aQ.ty&&aQ.ty!==ag){M=aQ.ti}if(aD===aP){aS.HeatmapSessionRecording.Both.data.push(aQ)}else{if(af===aP){aS.HeatmapSessionRecording.Heatmap.data.push(aQ)}else{if(c===aP){aS.HeatmapSessionRecording.Session.data.push(aQ)}}}}});if(l){U("recorddata",ae.stringify(aQ))}},stopSendingData:function(){var aP=z.getPiwikTrackers();aP.forEach(function(aQ){if(aQ.HeatmapSessionRecording){var aR=aQ.HeatmapSessionRecording;
-if("undefined"!==typeof aR.trackingInterval){clearInterval(aR.trackingInterval);delete aR.trackingInterval}}})},startSendingData:function(){var aP=z.getPiwikTrackers();aP.forEach(function(aQ){if(aQ.HeatmapSessionRecording&&"undefined"===typeof aQ.HeatmapSessionRecording.trackingInterval){var aR=au.getRandomInt(10250,11250);aQ.HeatmapSessionRecording.trackingInterval=setInterval(function(){z.sendQueuedData(aQ)},aR);z.sendQueuedData(aQ)}})}};function aE(){
-/*!!! hsrTrackerReadyHook */
-;if(typeof window==="object"&&"function"===typeof I.piwikHeatmapSessionRecordingAsyncInit){I.piwikHeatmapSessionRecordingAsyncInit()}if(typeof window==="object"&&"function"===typeof I.matomoHeatmapSessionRecordingAsyncInit){I.matomoHeatmapSessionRecordingAsyncInit()}var aQ=al;al=[];aj=true;for(var aP=0;aPY){aY=aY.substr(0,Y)}if(aN.shouldMaskField(aS,!aN.hasAttribute(aS,"data-matomo-unmask"))){aY=aN.maskFormField(aY,aN.getAttribute(aS,"type")==="password")}}else{if(aP===ar&&"undefined"!==typeof aS.value){aY=String(aS.value)}}}var aV={ti:aR,ty:aP,s:aU,te:aY};if(aU){z.recordData(c,aV)}else{U("No selector found for text input ",aX)
-}},onScroll:function(aP){if(!an){an=true;ak.checkTrackersIfConditionsMet()}var aT=au.getTimeSincePageReady();if(aP&&aP.type&&aP.type==="scroll"&&aP.target&&aP.target!==O){var aZ=aP.target;if("undefined"===typeof aZ.scrollTop){return}var aR=aZ.scrollTop;var aU=aZ.scrollLeft;var aS=aN.getWidth(aZ);var aQ=aN.getHeight(aZ);if(aS<=0||aQ<=0||!aS||!aQ){return}var aV=aN.getSelector(aZ);ak.lastElementScroll={time:aT,selector:aV,scrollY:parseInt((C*aR)/aQ,10),scrollX:parseInt((C*aU)/aS,10)};return}var aX=parseInt(r.getScrollTop(),10);var aW=parseInt(r.getScrollLeft(),10);var a1=r.getDocumentHeight();var aY=r.getDocumentWidth();ak.lastScroll={time:aT,scrollY:parseInt((C*aX)/a1,10),scrollX:parseInt((C*aW)/aY,10)};var a0=parseInt((C*(aX+r.getWindowSize().height))/a1,10);if(a0>ak.scrollMaxPercentage){ak.scrollMaxPercentage=a0}},checkTrackersIfConditionsMet:function(){var aQ=z.getPiwikTrackers();for(var aP=0;aPaa){g=aa}},setMaxTextInputLength:function(aQ){Y=aQ},disableCaptureKeystrokes:function(){aI=false},enableCaptureKeystrokes:function(){aI=true},setMatomoTrackers:function(aQ){this.setPiwikTrackers(aQ)},setPiwikTrackers:function(aQ){if(aQ===null){n=null;return}if(!au.isArray(aQ)){aQ=[aQ]
-}n=aQ;n.forEach(q);if(aj){if(A){this.enable()}else{if(L){aM.fetch()}}}},enableDebugMode:function(){l=true}};Piwik.DOM.onReady(function(){F=new Date().getTime()});Piwik.addPlugin("HeatmapSessionRecording",{log:function(aQ){if(aO){if(aQ.tracker&&aQ.tracker.getNumTrackedPageViews&&aQ.tracker.getNumTrackedPageViews()>1){setTimeout(function(){Piwik.HeatmapSessionRecording.setNewPageView(true)},10)}}return""},unload:function(){if(!u()){var aQ=z.getPiwikTrackers();z.stopSendingData();aQ.forEach(function(aS){var aR=false;z.sendQueuedData(aS,aR)})}}});if(I.Piwik.initialized){var aP=Piwik.getAsyncTrackers();aP.forEach(q);Piwik.on("TrackerSetup",q);Piwik.retryMissedPluginCalls();aE();aM.fetch();Piwik.on("TrackerAdded",function(){if(A){Piwik.HeatmapSessionRecording.enable()}else{aM.fetch()}})}else{Piwik.on("TrackerSetup",q);Piwik.on("MatomoInitialized",function(){aE();if(L||A){aM.fetch()}Piwik.on("TrackerAdded",function(){if(L){aM.fetch()}else{if(A){Piwik.HeatmapSessionRecording.enable()}}})})}}ad=au.generateUniqueId();
-if("object"===typeof I.Piwik){ah()}else{if("object"!==typeof I.matomoPluginAsyncInit){I.matomoPluginAsyncInit=[]}I.matomoPluginAsyncInit.push(ah)}})();
\ No newline at end of file
diff --git a/files/plugin-HeatmapSessionRecording-5.2.4/vue/dist/HeatmapSessionRecording.umd.js b/files/plugin-HeatmapSessionRecording-5.2.4/vue/dist/HeatmapSessionRecording.umd.js
deleted file mode 100644
index 5468f48..0000000
--- a/files/plugin-HeatmapSessionRecording-5.2.4/vue/dist/HeatmapSessionRecording.umd.js
+++ /dev/null
@@ -1,5480 +0,0 @@
-(function webpackUniversalModuleDefinition(root, factory) {
- if(typeof exports === 'object' && typeof module === 'object')
- module.exports = factory(require("CoreHome"), require("vue"), require("CorePluginsAdmin"));
- else if(typeof define === 'function' && define.amd)
- define(["CoreHome", , "CorePluginsAdmin"], factory);
- else if(typeof exports === 'object')
- exports["HeatmapSessionRecording"] = factory(require("CoreHome"), require("vue"), require("CorePluginsAdmin"));
- else
- root["HeatmapSessionRecording"] = factory(root["CoreHome"], root["Vue"], root["CorePluginsAdmin"]);
-})((typeof self !== 'undefined' ? self : this), function(__WEBPACK_EXTERNAL_MODULE__19dc__, __WEBPACK_EXTERNAL_MODULE__8bbf__, __WEBPACK_EXTERNAL_MODULE_a5a2__) {
-return /******/ (function(modules) { // webpackBootstrap
-/******/ // The module cache
-/******/ var installedModules = {};
-/******/
-/******/ // The require function
-/******/ function __webpack_require__(moduleId) {
-/******/
-/******/ // Check if module is in cache
-/******/ if(installedModules[moduleId]) {
-/******/ return installedModules[moduleId].exports;
-/******/ }
-/******/ // Create a new module (and put it into the cache)
-/******/ var module = installedModules[moduleId] = {
-/******/ i: moduleId,
-/******/ l: false,
-/******/ exports: {}
-/******/ };
-/******/
-/******/ // Execute the module function
-/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
-/******/
-/******/ // Flag the module as loaded
-/******/ module.l = true;
-/******/
-/******/ // Return the exports of the module
-/******/ return module.exports;
-/******/ }
-/******/
-/******/
-/******/ // expose the modules object (__webpack_modules__)
-/******/ __webpack_require__.m = modules;
-/******/
-/******/ // expose the module cache
-/******/ __webpack_require__.c = installedModules;
-/******/
-/******/ // define getter function for harmony exports
-/******/ __webpack_require__.d = function(exports, name, getter) {
-/******/ if(!__webpack_require__.o(exports, name)) {
-/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter });
-/******/ }
-/******/ };
-/******/
-/******/ // define __esModule on exports
-/******/ __webpack_require__.r = function(exports) {
-/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
-/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
-/******/ }
-/******/ Object.defineProperty(exports, '__esModule', { value: true });
-/******/ };
-/******/
-/******/ // create a fake namespace object
-/******/ // mode & 1: value is a module id, require it
-/******/ // mode & 2: merge all properties of value into the ns
-/******/ // mode & 4: return value when already ns object
-/******/ // mode & 8|1: behave like require
-/******/ __webpack_require__.t = function(value, mode) {
-/******/ if(mode & 1) value = __webpack_require__(value);
-/******/ if(mode & 8) return value;
-/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
-/******/ var ns = Object.create(null);
-/******/ __webpack_require__.r(ns);
-/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value });
-/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
-/******/ return ns;
-/******/ };
-/******/
-/******/ // getDefaultExport function for compatibility with non-harmony modules
-/******/ __webpack_require__.n = function(module) {
-/******/ var getter = module && module.__esModule ?
-/******/ function getDefault() { return module['default']; } :
-/******/ function getModuleExports() { return module; };
-/******/ __webpack_require__.d(getter, 'a', getter);
-/******/ return getter;
-/******/ };
-/******/
-/******/ // Object.prototype.hasOwnProperty.call
-/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
-/******/
-/******/ // __webpack_public_path__
-/******/ __webpack_require__.p = "plugins/HeatmapSessionRecording/vue/dist/";
-/******/
-/******/
-/******/ // Load entry module and return exports
-/******/ return __webpack_require__(__webpack_require__.s = "fae3");
-/******/ })
-/************************************************************************/
-/******/ ({
-
-/***/ "19dc":
-/***/ (function(module, exports) {
-
-module.exports = __WEBPACK_EXTERNAL_MODULE__19dc__;
-
-/***/ }),
-
-/***/ "246e":
-/***/ (function(module, exports, __webpack_require__) {
-
-var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_RESULT__;/*
- * heatmap.js v2.0.5 | JavaScript Heatmap Library
- *
- * Copyright 2008-2016 Patrick Wied - All rights reserved.
- * Dual licensed under MIT and Beerware license
- *
- * :: 2016-09-05 01:16
- */
-;(function (name, context, factory) {
-
- // Supports UMD. AMD, CommonJS/Node.js and browser context
- if ( true && module.exports) {
- module.exports = factory();
- } else if (true) {
- !(__WEBPACK_AMD_DEFINE_FACTORY__ = (factory),
- __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ?
- (__WEBPACK_AMD_DEFINE_FACTORY__.call(exports, __webpack_require__, exports, module)) :
- __WEBPACK_AMD_DEFINE_FACTORY__),
- __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
- } else {}
-
-})("h337", this, function () {
-
-// Heatmap Config stores default values and will be merged with instance config
-var HeatmapConfig = {
- defaultRadius: 40,
- defaultRenderer: 'canvas2d',
- defaultGradient: { 0.25: "rgb(0,0,255)", 0.55: "rgb(0,255,0)", 0.85: "yellow", 1.0: "rgb(255,0,0)"},
- defaultMaxOpacity: 1,
- defaultMinOpacity: 0,
- defaultBlur: .85,
- defaultXField: 'x',
- defaultYField: 'y',
- defaultValueField: 'value',
- plugins: {}
-};
-var Store = (function StoreClosure() {
-
- var Store = function Store(config) {
- this._coordinator = {};
- this._data = [];
- this._radi = [];
- this._min = 10;
- this._max = 1;
- this._xField = config['xField'] || config.defaultXField;
- this._yField = config['yField'] || config.defaultYField;
- this._valueField = config['valueField'] || config.defaultValueField;
-
- if (config["radius"]) {
- this._cfgRadius = config["radius"];
- }
- };
-
- var defaultRadius = HeatmapConfig.defaultRadius;
-
- Store.prototype = {
- // when forceRender = false -> called from setData, omits renderall event
- _organiseData: function(dataPoint, forceRender) {
- var x = dataPoint[this._xField];
- var y = dataPoint[this._yField];
- var radi = this._radi;
- var store = this._data;
- var max = this._max;
- var min = this._min;
- var value = dataPoint[this._valueField] || 1;
- var radius = dataPoint.radius || this._cfgRadius || defaultRadius;
-
- if (!store[x]) {
- store[x] = [];
- radi[x] = [];
- }
-
- if (!store[x][y]) {
- store[x][y] = value;
- radi[x][y] = radius;
- } else {
- store[x][y] += value;
- }
- var storedVal = store[x][y];
-
- if (storedVal > max) {
- if (!forceRender) {
- this._max = storedVal;
- } else {
- this.setDataMax(storedVal);
- }
- return false;
- } else if (storedVal < min) {
- if (!forceRender) {
- this._min = storedVal;
- } else {
- this.setDataMin(storedVal);
- }
- return false;
- } else {
- return {
- x: x,
- y: y,
- value: value,
- radius: radius,
- min: min,
- max: max
- };
- }
- },
- _unOrganizeData: function() {
- var unorganizedData = [];
- var data = this._data;
- var radi = this._radi;
-
- for (var x in data) {
- for (var y in data[x]) {
-
- unorganizedData.push({
- x: x,
- y: y,
- radius: radi[x][y],
- value: data[x][y]
- });
-
- }
- }
- return {
- min: this._min,
- max: this._max,
- data: unorganizedData
- };
- },
- _onExtremaChange: function() {
- this._coordinator.emit('extremachange', {
- min: this._min,
- max: this._max
- });
- },
- addData: function() {
- if (arguments[0].length > 0) {
- var dataArr = arguments[0];
- var dataLen = dataArr.length;
- while (dataLen--) {
- this.addData.call(this, dataArr[dataLen]);
- }
- } else {
- // add to store
- var organisedEntry = this._organiseData(arguments[0], true);
- if (organisedEntry) {
- // if it's the first datapoint initialize the extremas with it
- if (this._data.length === 0) {
- this._min = this._max = organisedEntry.value;
- }
- this._coordinator.emit('renderpartial', {
- min: this._min,
- max: this._max,
- data: [organisedEntry]
- });
- }
- }
- return this;
- },
- setData: function(data) {
- var dataPoints = data.data;
- var pointsLen = dataPoints.length;
-
-
- // reset data arrays
- this._data = [];
- this._radi = [];
-
- for(var i = 0; i < pointsLen; i++) {
- this._organiseData(dataPoints[i], false);
- }
- this._max = data.max;
- this._min = data.min || 0;
-
- this._onExtremaChange();
- this._coordinator.emit('renderall', this._getInternalData());
- return this;
- },
- removeData: function() {
- // TODO: implement
- },
- setDataMax: function(max) {
- this._max = max;
- this._onExtremaChange();
- this._coordinator.emit('renderall', this._getInternalData());
- return this;
- },
- setDataMin: function(min) {
- this._min = min;
- this._onExtremaChange();
- this._coordinator.emit('renderall', this._getInternalData());
- return this;
- },
- setCoordinator: function(coordinator) {
- this._coordinator = coordinator;
- },
- _getInternalData: function() {
- return {
- max: this._max,
- min: this._min,
- data: this._data,
- radi: this._radi
- };
- },
- getData: function() {
- return this._unOrganizeData();
- }/*,
-
- TODO: rethink.
-
- getValueAt: function(point) {
- var value;
- var radius = 100;
- var x = point.x;
- var y = point.y;
- var data = this._data;
-
- if (data[x] && data[x][y]) {
- return data[x][y];
- } else {
- var values = [];
- // radial search for datapoints based on default radius
- for(var distance = 1; distance < radius; distance++) {
- var neighbors = distance * 2 +1;
- var startX = x - distance;
- var startY = y - distance;
-
- for(var i = 0; i < neighbors; i++) {
- for (var o = 0; o < neighbors; o++) {
- if ((i == 0 || i == neighbors-1) || (o == 0 || o == neighbors-1)) {
- if (data[startY+i] && data[startY+i][startX+o]) {
- values.push(data[startY+i][startX+o]);
- }
- } else {
- continue;
- }
- }
- }
- }
- if (values.length > 0) {
- return Math.max.apply(Math, values);
- }
- }
- return false;
- }*/
- };
-
-
- return Store;
-})();
-
-var Canvas2dRenderer = (function Canvas2dRendererClosure() {
-
- var _getColorPalette = function(config) {
- var gradientConfig = config.gradient || config.defaultGradient;
- var paletteCanvas = document.createElement('canvas');
- var paletteCtx = paletteCanvas.getContext('2d');
-
- paletteCanvas.width = 256;
- paletteCanvas.height = 1;
-
- var gradient = paletteCtx.createLinearGradient(0, 0, 256, 1);
- for (var key in gradientConfig) {
- gradient.addColorStop(key, gradientConfig[key]);
- }
-
- paletteCtx.fillStyle = gradient;
- paletteCtx.fillRect(0, 0, 256, 1);
-
- return paletteCtx.getImageData(0, 0, 256, 1).data;
- };
-
- var _getPointTemplate = function(radius, blurFactor) {
- var tplCanvas = document.createElement('canvas');
- var tplCtx = tplCanvas.getContext('2d');
- var x = radius;
- var y = radius;
- tplCanvas.width = tplCanvas.height = radius*2;
-
- if (blurFactor == 1) {
- tplCtx.beginPath();
- tplCtx.arc(x, y, radius, 0, 2 * Math.PI, false);
- tplCtx.fillStyle = 'rgba(0,0,0,1)';
- tplCtx.fill();
- } else {
- var gradient = tplCtx.createRadialGradient(x, y, radius*blurFactor, x, y, radius);
- gradient.addColorStop(0, 'rgba(0,0,0,1)');
- gradient.addColorStop(1, 'rgba(0,0,0,0)');
- tplCtx.fillStyle = gradient;
- tplCtx.fillRect(0, 0, 2*radius, 2*radius);
- }
-
-
-
- return tplCanvas;
- };
-
- var _prepareData = function(data) {
- var renderData = [];
- var min = data.min;
- var max = data.max;
- var radi = data.radi;
- var data = data.data;
-
- var xValues = Object.keys(data);
- var xValuesLen = xValues.length;
-
- while(xValuesLen--) {
- var xValue = xValues[xValuesLen];
- var yValues = Object.keys(data[xValue]);
- var yValuesLen = yValues.length;
- while(yValuesLen--) {
- var yValue = yValues[yValuesLen];
- var value = data[xValue][yValue];
- var radius = radi[xValue][yValue];
- renderData.push({
- x: xValue,
- y: yValue,
- value: value,
- radius: radius
- });
- }
- }
-
- return {
- min: min,
- max: max,
- data: renderData
- };
- };
-
-
- function Canvas2dRenderer(config) {
- var container = config.container;
- var shadowCanvas = this.shadowCanvas = document.createElement('canvas');
- var canvas = this.canvas = config.canvas || document.createElement('canvas');
- var renderBoundaries = this._renderBoundaries = [10000, 10000, 0, 0];
-
- var computed = getComputedStyle(config.container) || {};
-
- canvas.className = 'heatmap-canvas';
-
- this._width = canvas.width = shadowCanvas.width = config.width || +(computed.width.replace(/px/,''));
- this._height = canvas.height = shadowCanvas.height = config.height || +(computed.height.replace(/px/,''));
-
- this.shadowCtx = shadowCanvas.getContext('2d');
- this.ctx = canvas.getContext('2d');
-
- // @TODO:
- // conditional wrapper
-
- canvas.style.cssText = shadowCanvas.style.cssText = 'position:absolute;left:0;top:0;';
-
- container.style.position = 'relative';
- container.appendChild(canvas);
-
- this._palette = _getColorPalette(config);
- this._templates = {};
-
- this._setStyles(config);
- };
-
- Canvas2dRenderer.prototype = {
- renderPartial: function(data) {
- if (data.data.length > 0) {
- this._drawAlpha(data);
- this._colorize();
- }
- },
- renderAll: function(data) {
- // reset render boundaries
- this._clear();
- if (data.data.length > 0) {
- this._drawAlpha(_prepareData(data));
- this._colorize();
- }
- },
- _updateGradient: function(config) {
- this._palette = _getColorPalette(config);
- },
- updateConfig: function(config) {
- if (config['gradient']) {
- this._updateGradient(config);
- }
- this._setStyles(config);
- },
- setDimensions: function(width, height) {
- this._width = width;
- this._height = height;
- this.canvas.width = this.shadowCanvas.width = width;
- this.canvas.height = this.shadowCanvas.height = height;
- },
- _clear: function() {
- this.shadowCtx.clearRect(0, 0, this._width, this._height);
- this.ctx.clearRect(0, 0, this._width, this._height);
- },
- _setStyles: function(config) {
- this._blur = (config.blur == 0)?0:(config.blur || config.defaultBlur);
-
- if (config.backgroundColor) {
- this.canvas.style.backgroundColor = config.backgroundColor;
- }
-
- this._width = this.canvas.width = this.shadowCanvas.width = config.width || this._width;
- this._height = this.canvas.height = this.shadowCanvas.height = config.height || this._height;
-
-
- this._opacity = (config.opacity || 0) * 255;
- this._maxOpacity = (config.maxOpacity || config.defaultMaxOpacity) * 255;
- this._minOpacity = (config.minOpacity || config.defaultMinOpacity) * 255;
- this._useGradientOpacity = !!config.useGradientOpacity;
- },
- _drawAlpha: function(data) {
- var min = this._min = data.min;
- var max = this._max = data.max;
- var data = data.data || [];
- var dataLen = data.length;
- // on a point basis?
- var blur = 1 - this._blur;
-
- while(dataLen--) {
-
- var point = data[dataLen];
-
- var x = point.x;
- var y = point.y;
- var radius = point.radius;
- // if value is bigger than max
- // use max as value
- var value = Math.min(point.value, max);
- var rectX = x - radius;
- var rectY = y - radius;
- var shadowCtx = this.shadowCtx;
-
-
-
-
- var tpl;
- if (!this._templates[radius]) {
- this._templates[radius] = tpl = _getPointTemplate(radius, blur);
- } else {
- tpl = this._templates[radius];
- }
- // value from minimum / value range
- // => [0, 1]
- var templateAlpha = (value-min)/(max-min);
- // this fixes #176: small values are not visible because globalAlpha < .01 cannot be read from imageData
- shadowCtx.globalAlpha = templateAlpha < .01 ? .01 : templateAlpha;
-
- shadowCtx.drawImage(tpl, rectX, rectY);
-
- // update renderBoundaries
- if (rectX < this._renderBoundaries[0]) {
- this._renderBoundaries[0] = rectX;
- }
- if (rectY < this._renderBoundaries[1]) {
- this._renderBoundaries[1] = rectY;
- }
- if (rectX + 2*radius > this._renderBoundaries[2]) {
- this._renderBoundaries[2] = rectX + 2*radius;
- }
- if (rectY + 2*radius > this._renderBoundaries[3]) {
- this._renderBoundaries[3] = rectY + 2*radius;
- }
-
- }
- },
- _colorize: function() {
- var x = this._renderBoundaries[0];
- var y = this._renderBoundaries[1];
- var width = this._renderBoundaries[2] - x;
- var height = this._renderBoundaries[3] - y;
- var maxWidth = this._width;
- var maxHeight = this._height;
- var opacity = this._opacity;
- var maxOpacity = this._maxOpacity;
- var minOpacity = this._minOpacity;
- var useGradientOpacity = this._useGradientOpacity;
-
- if (x < 0) {
- x = 0;
- }
- if (y < 0) {
- y = 0;
- }
- if (x + width > maxWidth) {
- width = maxWidth - x;
- }
- if (y + height > maxHeight) {
- height = maxHeight - y;
- }
-
- var img = this.shadowCtx.getImageData(x, y, width, height);
- var imgData = img.data;
- var len = imgData.length;
- var palette = this._palette;
-
-
- for (var i = 3; i < len; i+= 4) {
- var alpha = imgData[i];
- var offset = alpha * 4;
-
-
- if (!offset) {
- continue;
- }
-
- var finalAlpha;
- if (opacity > 0) {
- finalAlpha = opacity;
- } else {
- if (alpha < maxOpacity) {
- if (alpha < minOpacity) {
- finalAlpha = minOpacity;
- } else {
- finalAlpha = alpha;
- }
- } else {
- finalAlpha = maxOpacity;
- }
- }
-
- imgData[i-3] = palette[offset];
- imgData[i-2] = palette[offset + 1];
- imgData[i-1] = palette[offset + 2];
- imgData[i] = useGradientOpacity ? palette[offset + 3] : finalAlpha;
-
- }
-
- img.data = imgData;
- this.ctx.putImageData(img, x, y);
-
- this._renderBoundaries = [1000, 1000, 0, 0];
-
- },
- getValueAt: function(point) {
- var value;
- var shadowCtx = this.shadowCtx;
- var img = shadowCtx.getImageData(point.x, point.y, 1, 1);
- var data = img.data[3];
- var max = this._max;
- var min = this._min;
-
- value = (Math.abs(max-min) * (data/255)) >> 0;
-
- return value;
- },
- getDataURL: function() {
- return this.canvas.toDataURL();
- }
- };
-
-
- return Canvas2dRenderer;
-})();
-
-
-var Renderer = (function RendererClosure() {
-
- var rendererFn = false;
-
- if (HeatmapConfig['defaultRenderer'] === 'canvas2d') {
- rendererFn = Canvas2dRenderer;
- }
-
- return rendererFn;
-})();
-
-
-var Util = {
- merge: function() {
- var merged = {};
- var argsLen = arguments.length;
- for (var i = 0; i < argsLen; i++) {
- var obj = arguments[i]
- for (var key in obj) {
- merged[key] = obj[key];
- }
- }
- return merged;
- }
-};
-// Heatmap Constructor
-var Heatmap = (function HeatmapClosure() {
-
- var Coordinator = (function CoordinatorClosure() {
-
- function Coordinator() {
- this.cStore = {};
- };
-
- Coordinator.prototype = {
- on: function(evtName, callback, scope) {
- var cStore = this.cStore;
-
- if (!cStore[evtName]) {
- cStore[evtName] = [];
- }
- cStore[evtName].push((function(data) {
- return callback.call(scope, data);
- }));
- },
- emit: function(evtName, data) {
- var cStore = this.cStore;
- if (cStore[evtName]) {
- var len = cStore[evtName].length;
- for (var i=0; i {
- return Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("span", {
- class: Object(external_commonjs_vue_commonjs2_vue_root_Vue_["normalizeClass"])(["btn-flat", {
- 'visActive': theHeatmapType.key === _ctx.heatmapType,
- [`heatmapType${theHeatmapType.key}`]: true
- }]),
- onClick: $event => _ctx.changeHeatmapType(theHeatmapType.key),
- key: theHeatmapType.key
- }, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(theHeatmapType.name), 11, _hoisted_5);
- }), 128)), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("h4", _hoisted_6, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.translate('HeatmapSessionRecording_DeviceType')), 1), (Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(true), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])(external_commonjs_vue_commonjs2_vue_root_Vue_["Fragment"], null, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["renderList"])(_ctx.deviceTypesWithSamples, theDeviceType => {
- return Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("span", {
- class: Object(external_commonjs_vue_commonjs2_vue_root_Vue_["normalizeClass"])(["btn-flat", {
- 'visActive': theDeviceType.key === _ctx.deviceType,
- [`deviceType${theDeviceType.key}`]: true
- }]),
- title: theDeviceType.tooltip,
- onClick: $event => _ctx.changeDeviceType(theDeviceType.key),
- key: theDeviceType.key
- }, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("img", {
- height: "15",
- src: theDeviceType.logo,
- alt: `${_ctx.translate('DevicesDetection_Device')} ${theDeviceType.name}`
- }, null, 8, _hoisted_8), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createTextVNode"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("span", _hoisted_9, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(theDeviceType.numSamples), 1)], 10, _hoisted_7);
- }), 128)), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", _hoisted_10, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("h4", null, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.translate('Installation_Legend')), 1), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", _hoisted_11, [_hoisted_12, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("img", {
- class: "gradient",
- alt: "gradient",
- src: _ctx.gradientImgData
- }, null, 8, _hoisted_13), _hoisted_14])]), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", _hoisted_15, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("span", {
- style: {
- "margin-left": "2.5rem",
- "margin-right": "13.5px"
- },
- textContent: Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.translate('HeatmapSessionRecording_Width'))
- }, null, 8, _hoisted_16), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createVNode"])(_component_Field, {
- uicontrol: "select",
- name: "iframewidth",
- "model-value": _ctx.customIframeWidth,
- "onUpdate:modelValue": _cache[0] || (_cache[0] = $event => {
- _ctx.customIframeWidth = $event;
- _ctx.changeIframeWidth(_ctx.customIframeWidth, true);
- }),
- options: _ctx.iframeWidthOptions
- }, null, 8, ["model-value", "options"])])]), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", _hoisted_17, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", _hoisted_18, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", _hoisted_19, null, 512), _hoisted_20]), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["withDirectives"])(Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", {
- class: "hsrLoadingOuter",
- style: Object(external_commonjs_vue_commonjs2_vue_root_Vue_["normalizeStyle"])([{
- "height": "400px"
- }, {
- width: _ctx.iframeWidth + 'px'
- }])
- }, [_hoisted_21, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", _hoisted_22, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", _hoisted_23, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.translate('General_Loading')), 1)])], 4), [[external_commonjs_vue_commonjs2_vue_root_Vue_["vShow"], _ctx.isLoading]]), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["withDirectives"])(Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", {
- class: "aboveFoldLine",
- title: _ctx.translate('HeatmapSessionRecording_AvgAboveFoldDescription'),
- style: Object(external_commonjs_vue_commonjs2_vue_root_Vue_["normalizeStyle"])({
- width: _ctx.iframeWidth + 'px',
- top: _ctx.avgFold + 'px'
- })
- }, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", null, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.translate('HeatmapSessionRecording_AvgAboveFoldTitle', _ctx.avgFold)), 1)], 12, _hoisted_24), [[external_commonjs_vue_commonjs2_vue_root_Vue_["vShow"], _ctx.avgFold]]), _ctx.embedUrl ? (Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("iframe", {
- key: 0,
- id: "recordingPlayer",
- ref: "recordingPlayer",
- sandbox: "allow-scripts allow-same-origin",
- referrerpolicy: "no-referrer",
- onLoad: _cache[1] || (_cache[1] = $event => _ctx.onLoaded()),
- height: "400",
- src: _ctx.embedUrl,
- width: _ctx.iframeWidth
- }, null, 40, _hoisted_25)) : Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createCommentVNode"])("", true)], 512), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["withDirectives"])(Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", _hoisted_26, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createVNode"])(_component_SaveButton, {
- style: {
- "display": "block !important"
- },
- loading: _ctx.isLoading,
- onClick: _cache[2] || (_cache[2] = $event => _ctx.deleteScreenshot()),
- value: _ctx.translate('HeatmapSessionRecording_DeleteScreenshot')
- }, null, 8, ["loading", "value"])], 512), [[external_commonjs_vue_commonjs2_vue_root_Vue_["vShow"], _ctx.showDeleteScreenshot]]), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", _hoisted_27, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("h2", null, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.translate('HeatmapSessionRecording_DeleteHeatmapScreenshotConfirm')), 1), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("input", {
- role: "yes",
- type: "button",
- value: _ctx.translate('General_Yes')
- }, null, 8, _hoisted_28), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("input", {
- role: "no",
- type: "button",
- value: _ctx.translate('General_No')
- }, null, 8, _hoisted_29)], 512), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createVNode"])(_component_Tooltip, {
- ref: "tooltip",
- "click-count": _ctx.clickCount,
- "click-rate": _ctx.clickRate,
- "is-moves": _ctx.heatmapType === 1
- }, null, 8, ["click-count", "click-rate", "is-moves"])]);
-}
-// CONCATENATED MODULE: ./plugins/HeatmapSessionRecording/vue/src/HeatmapVis/HeatmapVis.vue?vue&type=template&id=d1a5d966
-
-// EXTERNAL MODULE: ./plugins/HeatmapSessionRecording/node_modules/heatmap.js/build/heatmap.js
-var heatmap = __webpack_require__("246e");
-var heatmap_default = /*#__PURE__*/__webpack_require__.n(heatmap);
-
-// EXTERNAL MODULE: external "CoreHome"
-var external_CoreHome_ = __webpack_require__("19dc");
-
-// EXTERNAL MODULE: external "CorePluginsAdmin"
-var external_CorePluginsAdmin_ = __webpack_require__("a5a2");
-
-// CONCATENATED MODULE: ./plugins/HeatmapSessionRecording/vue/src/getIframeWindow.ts
-/**
- * Copyright (C) InnoCraft Ltd - All rights reserved.
- *
- * NOTICE: All information contained herein is, and remains the property of InnoCraft Ltd.
- * The intellectual and technical concepts contained herein are protected by trade secret
- * or copyright law. Redistribution of this information or reproduction of this material is
- * strictly forbidden unless prior written permission is obtained from InnoCraft Ltd.
- *
- * You shall use this code only in accordance with the license agreement obtained from
- * InnoCraft Ltd.
- *
- * @link https://www.innocraft.com/
- * @license For license details see https://www.innocraft.com/license
- */
-// eslint-disable-next-line @typescript-eslint/no-explicit-any
-function getIframeWindow(iframeElement) {
- if (iframeElement && iframeElement.contentWindow) {
- return iframeElement.contentWindow;
- }
- if (iframeElement && iframeElement.contentDocument && iframeElement.contentDocument.defaultView) {
- return iframeElement.contentDocument.defaultView;
- }
- return undefined;
-}
-// CONCATENATED MODULE: ./plugins/HeatmapSessionRecording/vue/src/oneAtATime.ts
-/**
- * Copyright (C) InnoCraft Ltd - All rights reserved.
- *
- * NOTICE: All information contained herein is, and remains the property of InnoCraft Ltd.
- * The intellectual and technical concepts contained herein are protected by trade secret
- * or copyright law. Redistribution of this information or reproduction of this material is
- * strictly forbidden unless prior written permission is obtained from InnoCraft Ltd.
- *
- * You shall use this code only in accordance with the license agreement obtained from
- * InnoCraft Ltd.
- *
- * @link https://www.innocraft.com/
- * @license For license details see https://www.innocraft.com/license
- */
-
-// eslint-disable-next-line @typescript-eslint/no-explicit-any
-function oneAtATime(method, options) {
- let abortController = null;
- return (params, postParams) => {
- if (abortController) {
- abortController.abort();
- abortController = null;
- }
- abortController = new AbortController();
- return external_CoreHome_["AjaxHelper"].post(Object.assign(Object.assign({}, params), {}, {
- method
- }), postParams, Object.assign(Object.assign({}, options), {}, {
- abortController
- })).finally(() => {
- abortController = null;
- });
- };
-}
-// CONCATENATED MODULE: ./node_modules/@vue/cli-plugin-babel/node_modules/cache-loader/dist/cjs.js??ref--13-0!./node_modules/@vue/cli-plugin-babel/node_modules/thread-loader/dist/cjs.js!./node_modules/babel-loader/lib!./node_modules/@vue/cli-service/node_modules/vue-loader-v16/dist/templateLoader.js??ref--6!./node_modules/@vue/cli-service/node_modules/cache-loader/dist/cjs.js??ref--1-0!./node_modules/@vue/cli-service/node_modules/vue-loader-v16/dist??ref--1-1!./plugins/HeatmapSessionRecording/vue/src/Tooltip/Tooltip.vue?vue&type=template&id=6a6ace20
-
-const Tooltipvue_type_template_id_6a6ace20_hoisted_1 = {
- class: "tooltip-item"
-};
-const Tooltipvue_type_template_id_6a6ace20_hoisted_2 = {
- class: "tooltip-label"
-};
-const Tooltipvue_type_template_id_6a6ace20_hoisted_3 = {
- class: "tooltip-value"
-};
-const Tooltipvue_type_template_id_6a6ace20_hoisted_4 = {
- class: "tooltip-item"
-};
-const Tooltipvue_type_template_id_6a6ace20_hoisted_5 = {
- class: "tooltip-label"
-};
-const Tooltipvue_type_template_id_6a6ace20_hoisted_6 = {
- class: "tooltip-value"
-};
-function Tooltipvue_type_template_id_6a6ace20_render(_ctx, _cache, $props, $setup, $data, $options) {
- return Object(external_commonjs_vue_commonjs2_vue_root_Vue_["withDirectives"])((Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("div", {
- ref: "tooltipRef",
- class: "tooltip",
- style: Object(external_commonjs_vue_commonjs2_vue_root_Vue_["normalizeStyle"])(_ctx.tooltipStyle)
- }, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", Tooltipvue_type_template_id_6a6ace20_hoisted_1, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("span", Tooltipvue_type_template_id_6a6ace20_hoisted_2, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.getClickCountTranslation), 1), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("span", Tooltipvue_type_template_id_6a6ace20_hoisted_3, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.getClickCount), 1)]), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", Tooltipvue_type_template_id_6a6ace20_hoisted_4, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("span", Tooltipvue_type_template_id_6a6ace20_hoisted_5, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.getClickRateTranslation), 1), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("span", Tooltipvue_type_template_id_6a6ace20_hoisted_6, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.getClickRate), 1)])], 4)), [[external_commonjs_vue_commonjs2_vue_root_Vue_["vShow"], _ctx.visible]]);
-}
-// CONCATENATED MODULE: ./plugins/HeatmapSessionRecording/vue/src/Tooltip/Tooltip.vue?vue&type=template&id=6a6ace20
-
-// CONCATENATED MODULE: ./node_modules/@vue/cli-plugin-typescript/node_modules/cache-loader/dist/cjs.js??ref--15-0!./node_modules/babel-loader/lib!./node_modules/@vue/cli-plugin-typescript/node_modules/ts-loader??ref--15-2!./node_modules/@vue/cli-service/node_modules/cache-loader/dist/cjs.js??ref--1-0!./node_modules/@vue/cli-service/node_modules/vue-loader-v16/dist??ref--1-1!./plugins/HeatmapSessionRecording/vue/src/Tooltip/Tooltip.vue?vue&type=script&lang=ts
-
-
-/* harmony default export */ var Tooltipvue_type_script_lang_ts = (Object(external_commonjs_vue_commonjs2_vue_root_Vue_["defineComponent"])({
- props: {
- clickCount: {
- type: Number,
- required: true
- },
- clickRate: {
- type: Number,
- required: true
- },
- isMoves: {
- type: Boolean,
- required: false,
- default: false
- }
- },
- setup() {
- const state = Object(external_commonjs_vue_commonjs2_vue_root_Vue_["reactive"])({
- visible: false,
- position: {
- top: 0,
- left: 0
- }
- });
- const tooltipRef = Object(external_commonjs_vue_commonjs2_vue_root_Vue_["ref"])(null);
- const tooltipStyle = Object(external_commonjs_vue_commonjs2_vue_root_Vue_["computed"])(() => ({
- top: `${state.position.top}px`,
- left: `${state.position.left}px`,
- position: 'absolute',
- zIndex: 1000
- }));
- function show(event) {
- const scrollTop = window.scrollY || document.documentElement.scrollTop;
- const scrollLeft = window.scrollX || document.documentElement.scrollLeft;
- state.position.top = event.clientY + scrollTop + 10;
- state.position.left = event.clientX + scrollLeft + 10;
- state.visible = true;
- Object(external_commonjs_vue_commonjs2_vue_root_Vue_["nextTick"])(() => {
- const tooltipElement = tooltipRef.value;
- if (tooltipElement) {
- const {
- innerWidth,
- innerHeight
- } = window;
- const tooltipRect = tooltipElement.getBoundingClientRect();
- if (tooltipRect.right > innerWidth) {
- state.position.left = event.clientX + scrollLeft - tooltipRect.width - 10;
- }
- if (tooltipRect.bottom > innerHeight) {
- state.position.top = event.clientY + scrollTop - tooltipRect.height - 10;
- }
- const adjustedTooltipRect = tooltipElement.getBoundingClientRect();
- if (adjustedTooltipRect.left < 0) {
- state.position.left = scrollLeft + 10;
- }
- if (adjustedTooltipRect.top < 0) {
- state.position.top = scrollTop + 10;
- }
- }
- });
- }
- function hide() {
- state.visible = false;
- }
- return Object.assign(Object.assign({}, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toRefs"])(state)), {}, {
- tooltipRef,
- show,
- hide,
- tooltipStyle,
- translate: external_CoreHome_["translate"]
- });
- },
- computed: {
- getClickCount() {
- return external_CoreHome_["NumberFormatter"].formatNumber(this.clickCount);
- },
- getClickRate() {
- return external_CoreHome_["NumberFormatter"].formatPercent(this.clickRate);
- },
- getClickCountTranslation() {
- const translation = this.isMoves ? 'HeatmapSessionRecording_Moves' : 'HeatmapSessionRecording_Clicks';
- return Object(external_CoreHome_["translate"])(translation);
- },
- getClickRateTranslation() {
- const translation = this.isMoves ? 'HeatmapSessionRecording_MoveRate' : 'HeatmapSessionRecording_ClickRate';
- return Object(external_CoreHome_["translate"])(translation);
- }
- }
-}));
-// CONCATENATED MODULE: ./plugins/HeatmapSessionRecording/vue/src/Tooltip/Tooltip.vue?vue&type=script&lang=ts
-
-// CONCATENATED MODULE: ./plugins/HeatmapSessionRecording/vue/src/Tooltip/Tooltip.vue
-
-
-
-Tooltipvue_type_script_lang_ts.render = Tooltipvue_type_template_id_6a6ace20_render
-
-/* harmony default export */ var Tooltip = (Tooltipvue_type_script_lang_ts);
-// CONCATENATED MODULE: ./node_modules/@vue/cli-plugin-typescript/node_modules/cache-loader/dist/cjs.js??ref--15-0!./node_modules/babel-loader/lib!./node_modules/@vue/cli-plugin-typescript/node_modules/ts-loader??ref--15-2!./node_modules/@vue/cli-service/node_modules/cache-loader/dist/cjs.js??ref--1-0!./node_modules/@vue/cli-service/node_modules/vue-loader-v16/dist??ref--1-1!./plugins/HeatmapSessionRecording/vue/src/HeatmapVis/HeatmapVis.vue?vue&type=script&lang=ts
-
-
-
-
-
-
-
-const {
- $
-} = window;
-const deviceDesktop = 1;
-const deviceTablet = 2;
-const deviceMobile = 3;
-let heightPerHeatmap = 32000;
-const userAgent = String(window.navigator.userAgent).toLowerCase();
-if (userAgent.match(/(iPod|iPhone|iPad|Android|IEMobile|Windows Phone)/i)) {
- heightPerHeatmap = 2000;
-} else if (userAgent.indexOf('msie ') > 0 || userAgent.indexOf('trident/') > 0 || userAgent.indexOf('edge') > 0) {
- heightPerHeatmap = 8000;
-}
-function initHeatmap(recordingPlayer, heatmapContainer,
-// eslint-disable-next-line @typescript-eslint/no-explicit-any
-recordingIframe) {
- const $iframe = $(recordingPlayer);
- // we first set the iframe to the initial 400px again so we can for sure detect the current
- // height of the inner iframe body correctly
- $iframe.css('height', '400px');
- const documentHeight = recordingIframe.getIframeHeight();
- $iframe.css('height', `${documentHeight}px`);
- $(heatmapContainer).css('height', `${documentHeight}px`).css('width', `${$iframe.width()}px`).empty();
- const numHeatmaps = Math.ceil(documentHeight / heightPerHeatmap);
- for (let i = 1; i <= numHeatmaps; i += 1) {
- let height = heightPerHeatmap;
- if (i === numHeatmaps) {
- height = documentHeight % heightPerHeatmap;
- }
- $(heatmapContainer).append(``);
- $(heatmapContainer).find(`#heatmap${i}`).css({
- height: `${height}px`
- });
- }
- return numHeatmaps;
-}
-function scrollHeatmap(iframeRecordingContainer, recordingPlayer,
-// eslint-disable-next-line @typescript-eslint/no-explicit-any
-recordingIframe, scrollReaches) {
- const $iframe = $(recordingPlayer);
- // we first set the iframe to the initial 400px again so we can for sure detect the current
- // height of the inner iframe body correctly
- $iframe.css('height', '400px');
- const documentHeight = recordingIframe.getIframeHeight();
- $iframe.css('height', `${documentHeight}px`);
- const numIntervals = 1000;
- const heightToIntervalRatio = documentHeight / numIntervals;
- const numViewersTotal = scrollReaches.reduce((pv, cv) => pv + parseInt(cv.value, 10), 0);
- const buckets = [];
- let num_viewers = 0;
- let lastBucket = null;
- let percentage = 100;
- let reachScrolledFromPosition = 0;
- // reachScrolledFromPosition we start from 0, and then always paint to the next bucket. eg when
- // scrollReach is 27 and scrollDepth is 35, then we know that 27 people have scrolled down to
- // 3.5% of the page.
- scrollReaches.forEach(scrollReachObj => {
- // the number of people that reached this point
- const scrollReach = parseInt(scrollReachObj.value, 10);
- // how far down they scrolled
- const scrollDepth = parseInt(scrollReachObj.label, 10);
- const reachScrolledToPosition = Math.round(scrollDepth * heightToIntervalRatio);
- if (lastBucket && lastBucket.position === reachScrolledToPosition) {
- // when page is < 1000 we need to aggregate buckets
- num_viewers += scrollReach;
- } else {
- if (numViewersTotal !== 0) {
- percentage = (numViewersTotal - num_viewers) / numViewersTotal * 100;
- }
- num_viewers += scrollReach;
- // percentage.toFixed(1) * 10 => convert eg 99.8 => 998
- lastBucket = {
- percentageValue: parseFloat(percentage.toFixed(1)) * 10,
- position: reachScrolledFromPosition,
- percent: percentage.toFixed(1)
- };
- buckets.push(lastBucket);
- }
- reachScrolledFromPosition = reachScrolledToPosition;
- });
- function map(value, istart, istop, ostart, ostop) {
- return ostart + (ostop - ostart) * ((value - istart) / (istop - istart));
- }
- function mapColorIntensity(intensity, min, max) {
- if (min === max || !min && !max) {
- return [255, 255, 0];
- }
- const cint = map(intensity, min, max, 0, 255);
- const step = (max - min) / 5;
- if (cint > 204) {
- return [255, map(intensity, max - step, max, 255, 0), 0];
- }
- if (cint > 153) {
- return [map(intensity, max - 2 * step, max - step, 0, 255), 255, 0];
- }
- if (cint > 102) {
- return [0, 255, map(intensity, max - 3 * step, max - 2 * step, 255, 0)];
- }
- if (cint > 51) {
- return [0, map(intensity, max - 4 * step, max - 3 * step, 0, 255), 255];
- }
- return [map(intensity, min, max - 4 * step, 255, 0), 0, 255];
- }
- if (buckets.length) {
- // we need to make sure to draw scroll heatmap over full page
- const found = buckets.some(b => b.position === 0);
- if (!found) {
- buckets.unshift({
- percent: '100.0',
- percentageValue: 1000,
- position: 0
- });
- }
- } else {
- // we'll show full page as not scrolled
- buckets.push({
- percent: '0',
- percentageValue: 0,
- position: 0
- });
- }
- let minValue = 0;
- const maxValue = 1000; // max value is always 1000 (=100%)
- if (buckets && buckets.length && buckets[0]) {
- minValue = buckets[buckets.length - 1].percentageValue;
- }
- const iframeWidth = $iframe.width();
- let nextBucket = null;
- for (let index = 0; index < buckets.length; index += 1) {
- const bucket = buckets[index];
- if (buckets[index + 1]) {
- nextBucket = buckets[index + 1];
- } else {
- nextBucket = {
- position: documentHeight
- };
- }
- const top = bucket.position;
- let height = nextBucket.position - bucket.position;
- if (height === 0) {
- height = 1; // make sure to draw at least one px
- }
- const percent = `${bucket.percent} percent reached this point`;
- const colorValues = mapColorIntensity(bucket.percentageValue, minValue, maxValue);
- const color = `rgb(${colorValues.join(',')})`;
- $(iframeRecordingContainer).append(``);
- }
- $('.scrollHeatmapLeaf', iframeRecordingContainer).tooltip({
- track: true,
- items: '*',
- tooltipClass: 'heatmapTooltip',
- show: false,
- hide: false
- });
- $('.legend-area .min').text(`${(minValue / 10).toFixed(1)}%`);
- $('.legend-area .max').text(`${(maxValue / 10).toFixed(1)}%`);
-}
-function actualRenderHeatmap(recordingPlayer, heatmapContainer,
-// eslint-disable-next-line @typescript-eslint/no-explicit-any
-recordingIframe, dataPoints) {
- const numHeatmaps = initHeatmap(recordingPlayer, heatmapContainer, recordingIframe);
- const legendCanvas = document.createElement('canvas');
- legendCanvas.width = 100;
- legendCanvas.height = 10;
- const min = document.querySelector('.legend-area .min');
- const max = document.querySelector('.legend-area .max');
- const gradientImg = document.querySelector('.legend-area .gradient');
- const legendCtx = legendCanvas.getContext('2d');
- let gradientCfg = {};
- function updateLegend(data) {
- // the onExtremaChange callback gives us min, max, and the gradientConfig
- // so we can update the legend
- min.innerHTML = `${data.min}`;
- max.innerHTML = `${data.max}`;
- // regenerate gradient image
- if (data.gradient && data.gradient !== gradientCfg) {
- gradientCfg = data.gradient;
- const gradient = legendCtx.createLinearGradient(0, 0, 100, 1);
- Object.keys(gradientCfg).forEach(key => {
- gradient.addColorStop(parseFloat(key), gradientCfg[key]);
- });
- legendCtx.fillStyle = gradient;
- legendCtx.fillRect(0, 0, 100, 10);
- gradientImg.src = legendCanvas.toDataURL();
- }
- }
- const heatmapInstances = [];
- for (let i = 1; i <= numHeatmaps; i += 1) {
- const dpoints = {
- min: dataPoints.min,
- max: dataPoints.max,
- data: []
- };
- const config = {
- container: document.getElementById(`heatmap${i}`),
- radius: 10,
- maxOpacity: 0.5,
- minOpacity: 0,
- blur: 0.75
- };
- if (i === 1) {
- config.onExtremaChange = updateLegend; // typing is wrong here
- }
- if (dataPoints && dataPoints.data && dataPoints.data.length >= 20000) {
- config.radius = 8;
- } else if (dataPoints && dataPoints.data && dataPoints.data.length >= 2000) {
- config.radius = 9;
- }
- if (numHeatmaps === 1) {
- dpoints.data = dataPoints.data;
- } else {
- const lowerLimit = (i - 1) * heightPerHeatmap;
- const upperLimit = lowerLimit + heightPerHeatmap - 1;
- dataPoints.data.forEach(dp => {
- if (dp.y >= lowerLimit && dp.y <= upperLimit) {
- const thePoint = Object.assign(Object.assign({}, dp), {}, {
- y: dp.y - lowerLimit
- });
- dpoints.data.push(thePoint);
- }
- });
- }
- const heatmapInstance = heatmap_default.a.create(config);
- // heatmap type requires value to be number, but matomo sets it as string
- heatmapInstance.setData(dpoints);
- heatmapInstances.push(heatmapInstance);
- }
- return heatmapInstances;
-}
-/* harmony default export */ var HeatmapVisvue_type_script_lang_ts = (Object(external_commonjs_vue_commonjs2_vue_root_Vue_["defineComponent"])({
- props: {
- idSiteHsr: {
- type: Number,
- required: true
- },
- deviceTypes: {
- type: Array,
- required: true
- },
- heatmapTypes: {
- type: Array,
- required: true
- },
- breakpointMobile: {
- type: Number,
- required: true
- },
- breakpointTablet: {
- type: Number,
- required: true
- },
- offsetAccuracy: {
- type: Number,
- required: true
- },
- heatmapPeriod: {
- type: String,
- required: true
- },
- heatmapDate: {
- type: String,
- required: true
- },
- url: {
- type: String,
- required: true
- },
- isActive: Boolean,
- numSamples: {
- type: Object,
- required: true
- },
- excludedElements: {
- type: String,
- required: true
- },
- createdDate: {
- type: String,
- required: true
- },
- desktopPreviewSize: {
- type: Number,
- required: true
- },
- iframeResolutionsValues: {
- type: Object,
- required: true
- }
- },
- components: {
- Field: external_CorePluginsAdmin_["Field"],
- SaveButton: external_CorePluginsAdmin_["SaveButton"],
- Tooltip: Tooltip
- },
- data() {
- return {
- isLoading: false,
- iframeWidth: this.desktopPreviewSize,
- customIframeWidth: this.desktopPreviewSize,
- avgFold: 0,
- heatmapType: this.heatmapTypes[0].key,
- deviceType: this.deviceTypes[0].key,
- iframeResolutions: this.iframeResolutionsValues,
- actualNumSamples: this.numSamples,
- dataCoordinates: [],
- currentElement: null,
- totalClicks: 0,
- tooltipShowTimeoutId: null,
- clickCount: 0,
- clickRate: 0
- };
- },
- setup(props) {
- const tooltip = Object(external_commonjs_vue_commonjs2_vue_root_Vue_["ref"])(null);
- let iframeLoadedResolve = null;
- const iframeLoadedPromise = new Promise(resolve => {
- iframeLoadedResolve = resolve;
- });
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- let recordingIframe = null;
- const getRecordingIframe = recordingPlayer => {
- if (!recordingIframe) {
- recordingIframe = getIframeWindow(recordingPlayer).recordingFrame;
- recordingIframe.excludeElements(props.excludedElements);
- recordingIframe.addClass('html', 'piwikHeatmap');
- recordingIframe.addClass('html', 'matomoHeatmap');
- recordingIframe.addWorkaroundForSharepointHeatmaps();
- }
- return recordingIframe;
- };
- const heatmapInstances = Object(external_commonjs_vue_commonjs2_vue_root_Vue_["ref"])(null);
- const renderHeatmap = (recordingPlayer, heatmapContainer,
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- theRecordingIframe, dataPoints) => {
- heatmapInstances.value = actualRenderHeatmap(recordingPlayer, heatmapContainer, theRecordingIframe, dataPoints);
- };
- return {
- iframeLoadedPromise,
- onLoaded: iframeLoadedResolve,
- getRecordedHeatmap: oneAtATime('HeatmapSessionRecording.getRecordedHeatmap'),
- getRecordedHeatmapMetadata: oneAtATime('HeatmapSessionRecording.getRecordedHeatmapMetadata'),
- getRecordingIframe,
- heatmapInstances,
- renderHeatmap,
- tooltip
- };
- },
- created() {
- if (this.iframeResolutions.indexOf(this.breakpointMobile) === -1) {
- this.iframeResolutions.push(this.breakpointMobile);
- }
- if (this.iframeResolutions.indexOf(this.breakpointTablet) === -1) {
- this.iframeResolutions.push(this.breakpointTablet);
- }
- this.iframeResolutions = this.iframeResolutions.sort((a, b) => a - b);
- this.fetchHeatmap();
- // Hide the period selector since we don't filter the heatmap by period
- external_CoreHome_["Matomo"].postEvent('hidePeriodSelector');
- },
- watch: {
- isLoading() {
- if (this.isLoading === true) {
- return;
- }
- const heatmapContainer = window.document.getElementById('heatmapContainer');
- if (!heatmapContainer) {
- return;
- }
- heatmapContainer.addEventListener('mouseleave', event => {
- // Stop processing tooltip when moving mouse out of parent element
- if (this.tooltipShowTimeoutId) {
- clearTimeout(this.tooltipShowTimeoutId);
- this.tooltipShowTimeoutId = null;
- }
- // Reset the highlight and tooltip when leaving the container
- this.currentElement = null;
- this.handleTooltip(event, 0, 0, 'hide');
- const highlightDiv = window.document.getElementById('highlightDiv');
- if (!highlightDiv) {
- return;
- }
- highlightDiv.hidden = true;
- });
- heatmapContainer.addEventListener('mousemove', e => {
- this.handleMouseMove(e);
- });
- }
- },
- beforeUnmount() {
- this.removeScrollHeatmap();
- },
- methods: {
- removeScrollHeatmap() {
- const element = this.$refs.iframeRecordingContainer;
- $(element).find('.scrollHeatmapLeaf').remove();
- },
- deleteScreenshot() {
- external_CoreHome_["Matomo"].helper.modalConfirm(this.$refs.confirmDeleteHeatmapScreenshot, {
- yes: () => {
- this.isLoading = true;
- external_CoreHome_["AjaxHelper"].fetch({
- method: 'HeatmapSessionRecording.deleteHeatmapScreenshot',
- idSiteHsr: this.idSiteHsr
- }).then(() => {
- this.isLoading = false;
- window.location.reload();
- });
- }
- });
- },
- fetchHeatmap() {
- this.removeScrollHeatmap();
- if (this.heatmapInstances) {
- const instances = this.heatmapInstances;
- instances.forEach(heatmapInstance => {
- heatmapInstance.setData({
- max: 1,
- min: 0,
- data: []
- });
- });
- }
- this.isLoading = true;
- this.avgFold = 0;
- const segment = external_CoreHome_["MatomoUrl"].parsed.value.segment ? decodeURIComponent(external_CoreHome_["MatomoUrl"].parsed.value.segment) : undefined;
- const requestParams = {
- idSiteHsr: this.idSiteHsr,
- heatmapType: this.heatmapType,
- deviceType: this.deviceType,
- period: this.heatmapPeriod,
- date: this.heatmapDate,
- filter_limit: -1,
- segment
- };
- const heatmapDataPromise = this.getRecordedHeatmap(requestParams);
- const heatmapMetaDataPromise = this.getRecordedHeatmapMetadata(requestParams);
- Promise.all([heatmapDataPromise, heatmapMetaDataPromise, this.iframeLoadedPromise]).then(response => {
- const iframeElement = this.$refs.recordingPlayer;
- const recordingIframe = this.getRecordingIframe(iframeElement);
- initHeatmap(this.$refs.recordingPlayer, this.$refs.heatmapContainer, recordingIframe);
- this.removeScrollHeatmap();
- const rows = response[0];
- const numSamples = response[1];
- if (Array.isArray(numSamples) && numSamples[0]) {
- [this.actualNumSamples] = numSamples;
- } else {
- this.actualNumSamples = numSamples;
- }
- this.isLoading = false;
- if (this.isScrollHeatmapType) {
- scrollHeatmap(this.$refs.iframeRecordingContainer, iframeElement, recordingIframe, rows);
- } else {
- var _this$actualNumSample;
- const dataPoints = {
- min: 0,
- max: 0,
- data: []
- };
- for (let i = 0; i < rows.length; i += 1) {
- const row = rows[i];
- if (row.selector) {
- const dataPoint = recordingIframe.getCoordinatesInFrame(row.selector, row.offset_x, row.offset_y, this.offsetAccuracy, true);
- if (dataPoint) {
- dataPoint.value = row.value;
- dataPoints.data.push(dataPoint);
- this.dataCoordinates.push(dataPoint);
- this.totalClicks += parseInt(row.value, 10);
- }
- }
- }
- if (this.heatmapType === 2) {
- // click
- let numEntriesHigherThan1 = 0;
- dataPoints.data.forEach(dp => {
- if (dp !== null && dp !== void 0 && dp.value && parseInt(dp.value, 10) > 1) {
- numEntriesHigherThan1 += 1;
- }
- });
- if (numEntriesHigherThan1 / dataPoints.data.length >= 0.10 && dataPoints.data.length > 120) {
- // if at least 10% have .value >= 2, then we set max to 2 to differntiate better
- // between 1 and 2 clicks but only if we also have more than 80 data points
- // ("randomly" chosen that threshold)
- dataPoints.max = 2;
- } else {
- dataPoints.max = 1;
- }
- } else {
- const LIMIT_MAX_DATA_POINT = 10;
- const values = {};
- dataPoints.data.forEach(dp => {
- if (!dp || !dp.value) {
- return;
- }
- let value = parseInt(dp.value, 10);
- if (value > dataPoints.max) {
- dataPoints.max = value;
- }
- if (value > LIMIT_MAX_DATA_POINT) {
- value = LIMIT_MAX_DATA_POINT;
- }
- const valueStr = `${value}`;
- if (valueStr in values) {
- values[valueStr] += 1;
- } else {
- values[valueStr] = 0;
- }
- });
- if (dataPoints.max > LIMIT_MAX_DATA_POINT) {
- // we limit it to 10 otherwise many single points are not visible etc
- // if there is no single entry having value 10, we set it to 9, 8 or 7
- // to make sure there is actually a dataPoint for this max value.
- let sumValuesAboveThreshold = 0;
- for (let k = LIMIT_MAX_DATA_POINT; k > 1; k -= 1) {
- const kStr = `${k}`;
- if (kStr in values) {
- // we need to aggregate the value
- sumValuesAboveThreshold += values[kStr];
- }
- if (sumValuesAboveThreshold / dataPoints.data.length >= 0.2) {
- // we make sure to have at least 20% of entries in that max value
- dataPoints.max = k;
- break;
- }
- // todo ideally in this case also require that akk 2 - (k-1) have a distribution
- // of 0.2 to make sure we have enough values in between, and if not select k-1 or
- // so. Otherwise we have maybe 75% with value 1, 20% with value 10, and only 5% in
- // between... which would be barely visible those 75% maybe
- }
- if (dataPoints.max > LIMIT_MAX_DATA_POINT) {
- // when no entry has more than 15% distribution, we set a default of 5
- dataPoints.max = 5;
- for (let k = 5; k > 0; k -= 1) {
- const kStr = `${k}`;
- if (kStr in values) {
- // we limit it to 10 otherwise many single points are not visible etc
- // also if there is no single entry having value 10, we set it to 9, 8 or 7
- // to make sure there is actually a dataPoint for this max value.
- dataPoints.max = k;
- break;
- }
- }
- }
- }
- }
- this.renderHeatmap(this.$refs.recordingPlayer, this.$refs.heatmapContainer, recordingIframe, dataPoints);
- if ((_this$actualNumSample = this.actualNumSamples) !== null && _this$actualNumSample !== void 0 && _this$actualNumSample[`avg_fold_device_${this.deviceType}`]) {
- const avgFoldPercent = this.actualNumSamples[`avg_fold_device_${this.deviceType}`];
- const height = recordingIframe.getIframeHeight();
- if (height) {
- this.avgFold = parseInt(`${avgFoldPercent / 100 * height}`, 10);
- }
- }
- }
- }).finally(() => {
- this.isLoading = false;
- });
- },
- changeDeviceType(deviceType) {
- this.deviceType = deviceType;
- if (this.deviceType === deviceDesktop) {
- this.changeIframeWidth(this.desktopPreviewSize, false);
- } else if (this.deviceType === deviceTablet) {
- this.changeIframeWidth(this.breakpointTablet || 960, false);
- } else if (this.deviceType === deviceMobile) {
- this.changeIframeWidth(this.breakpointMobile || 600, false);
- }
- },
- changeIframeWidth(iframeWidth, scrollToTop) {
- this.iframeWidth = iframeWidth;
- this.customIframeWidth = this.iframeWidth;
- this.totalClicks = 0;
- this.dataCoordinates = [];
- this.fetchHeatmap();
- if (scrollToTop) {
- external_CoreHome_["Matomo"].helper.lazyScrollToContent();
- }
- },
- changeHeatmapType(heatmapType) {
- this.heatmapType = heatmapType;
- this.totalClicks = 0;
- this.clickCount = 0;
- this.clickRate = 0;
- this.dataCoordinates = [];
- this.fetchHeatmap();
- },
- handleMouseMove(event) {
- const highlightDiv = window.document.getElementById('highlightDiv');
- if (!highlightDiv) {
- return;
- }
- // Keep the tooltip from showing until the cursor has stopped moving
- if (this.tooltipShowTimeoutId) {
- clearTimeout(this.tooltipShowTimeoutId);
- this.tooltipShowTimeoutId = null;
- this.currentElement = null;
- }
- // If the highlight is visible, move the tooltip around with the cursor
- if (!highlightDiv.hidden) {
- this.handleTooltip(event, 0, 0, 'move');
- }
- const element = this.lookUpRecordedElementAtEventLocation(event);
- // If there's no element, don't do anything else
- // If the element hasn't changed, there's no need to do anything else
- if (!element || element === this.currentElement) {
- return;
- }
- this.handleTooltip(event, 0, 0, 'hide');
- highlightDiv.hidden = true;
- const elementRect = element.getBoundingClientRect();
- let elementClicks = 0;
- this.dataCoordinates.forEach(dataPoint => {
- // Return if the dataPoint isn't within the element
- if (dataPoint.y < elementRect.top || dataPoint.y > elementRect.bottom || dataPoint.x < elementRect.left || dataPoint.x > elementRect.right) {
- return;
- }
- elementClicks += parseInt(dataPoint.value, 10);
- });
- // Have a slight delay so that it's not jarring when it displays
- this.tooltipShowTimeoutId = setTimeout(() => {
- this.currentElement = element;
- highlightDiv.hidden = false;
- // Multiplying by 10000 and then dividing by 100 to get 2 decimal points of precision
- const clickRate = this.totalClicks ? Math.round(elementClicks / this.totalClicks * 10000) / 100 : 0;
- const rect = element.getBoundingClientRect();
- highlightDiv.style.top = `${rect.top}px`;
- highlightDiv.style.left = `${rect.left}px`;
- highlightDiv.style.width = `${rect.width}px`;
- highlightDiv.style.height = `${rect.height}px`;
- this.handleTooltip(event, elementClicks, clickRate, 'show');
- this.tooltipShowTimeoutId = null;
- }, 100);
- },
- lookUpRecordedElementAtEventLocation(event) {
- const targetElement = event.target;
- if (!targetElement) {
- return null;
- }
- const frameElement = window.document.getElementById('recordingPlayer');
- if (!frameElement) {
- return null;
- }
- const frameRef = frameElement.contentWindow ? frameElement.contentWindow.document : frameElement.contentDocument;
- if (!frameRef) {
- return null;
- }
- const rect = targetElement.getBoundingClientRect();
- return frameRef.elementFromPoint(event.clientX - rect.left, event.clientY - rect.top);
- },
- handleTooltip(event, clickCount, clickRate, action) {
- if (this.tooltip) {
- if (action === 'show') {
- this.clickCount = clickCount;
- this.clickRate = clickRate;
- this.tooltip.show(event);
- } else if (action === 'move') {
- this.tooltip.show(event);
- } else {
- this.tooltip.hide();
- }
- }
- }
- },
- computed: {
- isScrollHeatmapType() {
- return this.heatmapType === 3;
- },
- tokenAuth() {
- return external_CoreHome_["MatomoUrl"].parsed.value.token_auth;
- },
- embedUrl() {
- return `?${external_CoreHome_["MatomoUrl"].stringify({
- module: 'HeatmapSessionRecording',
- action: 'embedPage',
- idSite: external_CoreHome_["Matomo"].idSite,
- idSiteHsr: this.idSiteHsr,
- token_auth: this.tokenAuth || undefined
- })}`;
- },
- iframeWidthOptions() {
- return this.iframeResolutions.map(width => ({
- key: width,
- value: `${width}px`
- }));
- },
- recordedSamplesSince() {
- const string1 = Object(external_CoreHome_["translate"])('HeatmapSessionRecording_HeatmapXRecordedSamplesSince', `${this.actualNumSamples.nb_samples_device_all}`, this.createdDate);
- const linkString = Object(external_CoreHome_["externalLink"])('https://matomo.org/faq/heatmap-session-recording/troubleshooting-heatmaps/');
- const string2 = Object(external_CoreHome_["translate"])('HeatmapSessionRecording_HeatmapTroubleshoot', linkString, '');
- return `${string1} ${string2}`;
- },
- deviceTypesWithSamples() {
- return this.deviceTypes.map(deviceType => {
- let numSamples;
- if (this.actualNumSamples[`nb_samples_device_${deviceType.key}`]) {
- numSamples = this.actualNumSamples[`nb_samples_device_${deviceType.key}`];
- } else {
- numSamples = 0;
- }
- const tooltip = Object(external_CoreHome_["translate"])('HeatmapSessionRecording_XSamples', `${deviceType.name} - ${numSamples}`);
- return Object.assign(Object.assign({}, deviceType), {}, {
- numSamples,
- tooltip
- });
- });
- },
- hasWriteAccess() {
- return !!(external_CoreHome_["Matomo"] !== null && external_CoreHome_["Matomo"] !== void 0 && external_CoreHome_["Matomo"].heatmapWriteAccess);
- },
- showDeleteScreenshot() {
- return this.isActive && this.hasWriteAccess;
- },
- gradientImgData() {
- return 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAAAKCAYAAABCHPt+AAAAnklEQVRYR+2WQQq' + 'DQBAES5wB/f8/Y05RcMWwSu6JIT0Dm4WlH1DUdHew7/z6WYFhhnGRpnlhAEaQpi/ADbh/np0MiBhGhW+2ymFU+DZ' + 'fg1EhaoB4jCFuMYYcQKZrXwPEVvm5Og0pcYakBvI35G1jNIZ4jCHexxjSpz9ZFUjAynLbpOvqteaODkm9sloz5JF' + '+ZTVmSAWSu9Qb65AvgDwBQoLgVDlWfAQAAAAASUVORK5CYII=';
- }
- }
-}));
-// CONCATENATED MODULE: ./plugins/HeatmapSessionRecording/vue/src/HeatmapVis/HeatmapVis.vue?vue&type=script&lang=ts
-
-// CONCATENATED MODULE: ./plugins/HeatmapSessionRecording/vue/src/HeatmapVis/HeatmapVis.vue
-
-
-
-HeatmapVisvue_type_script_lang_ts.render = render
-
-/* harmony default export */ var HeatmapVis = (HeatmapVisvue_type_script_lang_ts);
-// CONCATENATED MODULE: ./node_modules/@vue/cli-plugin-babel/node_modules/cache-loader/dist/cjs.js??ref--13-0!./node_modules/@vue/cli-plugin-babel/node_modules/thread-loader/dist/cjs.js!./node_modules/babel-loader/lib!./node_modules/@vue/cli-service/node_modules/vue-loader-v16/dist/templateLoader.js??ref--6!./node_modules/@vue/cli-service/node_modules/cache-loader/dist/cjs.js??ref--1-0!./node_modules/@vue/cli-service/node_modules/vue-loader-v16/dist??ref--1-1!./plugins/HeatmapSessionRecording/vue/src/SessionRecordingVis/SessionRecordingVis.vue?vue&type=template&id=6f77b61e
-
-const SessionRecordingVisvue_type_template_id_6f77b61e_hoisted_1 = {
- class: "sessionRecordingPlayer"
-};
-const SessionRecordingVisvue_type_template_id_6f77b61e_hoisted_2 = {
- class: "controls"
-};
-const SessionRecordingVisvue_type_template_id_6f77b61e_hoisted_3 = {
- class: "playerActions"
-};
-const SessionRecordingVisvue_type_template_id_6f77b61e_hoisted_4 = ["title"];
-const SessionRecordingVisvue_type_template_id_6f77b61e_hoisted_5 = ["title"];
-const SessionRecordingVisvue_type_template_id_6f77b61e_hoisted_6 = ["title"];
-const SessionRecordingVisvue_type_template_id_6f77b61e_hoisted_7 = ["title"];
-const SessionRecordingVisvue_type_template_id_6f77b61e_hoisted_8 = ["title"];
-const SessionRecordingVisvue_type_template_id_6f77b61e_hoisted_9 = ["title"];
-const SessionRecordingVisvue_type_template_id_6f77b61e_hoisted_10 = ["title"];
-const SessionRecordingVisvue_type_template_id_6f77b61e_hoisted_11 = ["title"];
-const SessionRecordingVisvue_type_template_id_6f77b61e_hoisted_12 = {
- version: "1.1",
- xmlns: "http://www.w3.org/2000/svg",
- width: "20",
- height: "20",
- viewBox: "0 0 768 768"
-};
-const SessionRecordingVisvue_type_template_id_6f77b61e_hoisted_13 = /*#__PURE__*/Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("path", {
- d: "M480 576.5v-321h-64.5v129h-63v-129h-64.5v192h127.5v129h64.5zM607.5 127.999c34.5 0\n 64.5 30 64.5 64.5v447c0 34.5-30 64.5-64.5 64.5h-447c-34.5\n 0-64.5-30-64.5-64.5v-447c0-34.5 30-64.5 64.5-64.5h447z"
-}, null, -1);
-const SessionRecordingVisvue_type_template_id_6f77b61e_hoisted_14 = [SessionRecordingVisvue_type_template_id_6f77b61e_hoisted_13];
-const SessionRecordingVisvue_type_template_id_6f77b61e_hoisted_15 = {
- version: "1.1",
- xmlns: "http://www.w3.org/2000/svg",
- width: "20",
- height: "20",
- viewBox: "0 0 768 768"
-};
-const SessionRecordingVisvue_type_template_id_6f77b61e_hoisted_16 = /*#__PURE__*/Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("path", {
- d: "M448.5 576.5v-321h-129v64.5h64.5v256.5h64.5zM607.5 127.999c34.5 0 64.5 30 64.5\n 64.5v447c0 34.5-30 64.5-64.5 64.5h-447c-34.5 0-64.5-30-64.5-64.5v-447c0-34.5\n 30-64.5 64.5-64.5h447z"
-}, null, -1);
-const SessionRecordingVisvue_type_template_id_6f77b61e_hoisted_17 = [SessionRecordingVisvue_type_template_id_6f77b61e_hoisted_16];
-const SessionRecordingVisvue_type_template_id_6f77b61e_hoisted_18 = {
- version: "1.1",
- xmlns: "http://www.w3.org/2000/svg",
- width: "20",
- height: "20",
- viewBox: "0 0 768 768"
-};
-const SessionRecordingVisvue_type_template_id_6f77b61e_hoisted_19 = /*#__PURE__*/Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("path", {
- d: "M480 384.5v-64.5c0-36-30-64.5-64.5-64.5h-127.5v64.5h127.5v64.5h-63c-34.5 0-64.5\n 27-64.5 63v129h192v-64.5h-127.5v-64.5h63c34.5 0 64.5-27 64.5-63zM607.5 127.999c34.5\n 0 64.5 30 64.5 64.5v447c0 34.5-30 64.5-64.5 64.5h-447c-34.5\n 0-64.5-30-64.5-64.5v-447c0-34.5 30-64.5 64.5-64.5h447z"
-}, null, -1);
-const SessionRecordingVisvue_type_template_id_6f77b61e_hoisted_20 = [SessionRecordingVisvue_type_template_id_6f77b61e_hoisted_19];
-const SessionRecordingVisvue_type_template_id_6f77b61e_hoisted_21 = {
- version: "1.1",
- xmlns: "http://www.w3.org/2000/svg",
- width: "20",
- height: "20",
- viewBox: "0 0 768 768"
-};
-const SessionRecordingVisvue_type_template_id_6f77b61e_hoisted_22 = /*#__PURE__*/Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("path", {
- d: "M480 320v-64.5h-127.5c-34.5 0-64.5 28.5-64.5 64.5v192c0 36 30 64.5 64.5\n 64.5h63c34.5 0 64.5-28.5 64.5-64.5v-64.5c0-36-30-63-64.5-63h-63v-64.5h127.5zM607.5\n 127.999c34.5 0 64.5 30 64.5 64.5v447c0 34.5-30 64.5-64.5 64.5h-447c-34.5\n 0-64.5-30-64.5-64.5v-447c0-34.5 30-64.5 64.5-64.5h447zM352.5 512v-64.5h63v64.5h-63z"
-}, null, -1);
-const SessionRecordingVisvue_type_template_id_6f77b61e_hoisted_23 = [SessionRecordingVisvue_type_template_id_6f77b61e_hoisted_22];
-const SessionRecordingVisvue_type_template_id_6f77b61e_hoisted_24 = ["title"];
-const SessionRecordingVisvue_type_template_id_6f77b61e_hoisted_25 = /*#__PURE__*/Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("svg", {
- version: "1.1",
- xmlns: "http://www.w3.org/2000/svg",
- width: "20",
- height: "20",
- viewBox: "0 0 768 768"
-}, [/*#__PURE__*/Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("path", {
- d: "M223.5 415.5h111l-64.5-63h-46.5v63zM72 72l624 624-42 40.5-88.5-90c-51 36-114\n 57-181.5 57-177 0-319.5-142.5-319.5-319.5 0-67.5 21-130.5 57-181.5l-90-88.5zM544.5\n 352.5h-111l-231-231c51-36 114-57 181.5-57 177 0 319.5 142.5 319.5 319.5 0 67.5-21\n 130.5-57 181.5l-148.5-150h46.5v-63z"
-})], -1);
-const SessionRecordingVisvue_type_template_id_6f77b61e_hoisted_26 = [SessionRecordingVisvue_type_template_id_6f77b61e_hoisted_25];
-const SessionRecordingVisvue_type_template_id_6f77b61e_hoisted_27 = ["title"];
-const SessionRecordingVisvue_type_template_id_6f77b61e_hoisted_28 = /*#__PURE__*/Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("svg", {
- version: "1.1",
- xmlns: "http://www.w3.org/2000/svg",
- width: "22",
- height: "22",
- viewBox: "0 0 768 768"
-}, [/*#__PURE__*/Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("path", {
- d: "M544.5 609v-129h63v192h-384v96l-127.5-127.5 127.5-127.5v96h321zM223.5\n 288v129h-63v-192h384v-96l127.5 127.5-127.5 127.5v-96h-321z"
-})], -1);
-const SessionRecordingVisvue_type_template_id_6f77b61e_hoisted_29 = [SessionRecordingVisvue_type_template_id_6f77b61e_hoisted_28];
-const _hoisted_30 = {
- class: "duration"
-};
-const _hoisted_31 = {
- class: "playerHelp"
-};
-const _hoisted_32 = /*#__PURE__*/Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("span", {
- class: "clickEvent"
-}, null, -1);
-const _hoisted_33 = /*#__PURE__*/Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("span", {
- class: "moveEvent"
-}, null, -1);
-const _hoisted_34 = /*#__PURE__*/Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("span", {
- class: "scrollEvent"
-}, null, -1);
-const _hoisted_35 = /*#__PURE__*/Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("span", {
- class: "resizeEvent"
-}, null, -1);
-const _hoisted_36 = /*#__PURE__*/Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("span", {
- class: "formChange"
-}, null, -1);
-const _hoisted_37 = /*#__PURE__*/Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("span", {
- class: "mutationEvent"
-}, null, -1);
-const _hoisted_38 = /*#__PURE__*/Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("br", {
- style: {
- "clear": "right"
- }
-}, null, -1);
-const _hoisted_39 = ["title"];
-const _hoisted_40 = /*#__PURE__*/Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("br", null, null, -1);
-const _hoisted_41 = /*#__PURE__*/Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", {
- class: "loadingUnderlay"
-}, null, -1);
-const _hoisted_42 = {
- class: "valign-wrapper loadingInner"
-};
-const _hoisted_43 = {
- class: "loadingContent"
-};
-const _hoisted_44 = ["src", "width", "height"];
-function SessionRecordingVisvue_type_template_id_6f77b61e_render(_ctx, _cache, $props, $setup, $data, $options) {
- return Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("div", SessionRecordingVisvue_type_template_id_6f77b61e_hoisted_1, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", SessionRecordingVisvue_type_template_id_6f77b61e_hoisted_2, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("span", SessionRecordingVisvue_type_template_id_6f77b61e_hoisted_3, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["withDirectives"])(Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("span", {
- class: "playerAction icon-skip-previous",
- title: _ctx.skipPreviousButtonTitle,
- onClick: _cache[0] || (_cache[0] = $event => _ctx.loadNewRecording(_ctx.previousRecordingId))
- }, null, 8, SessionRecordingVisvue_type_template_id_6f77b61e_hoisted_4), [[external_commonjs_vue_commonjs2_vue_root_Vue_["vShow"], _ctx.previousRecordingId]]), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("span", {
- class: "playerAction icon-fast-rewind",
- title: _ctx.translate('HeatmapSessionRecording_PlayerRewindFast', 10, 'J'),
- onClick: _cache[1] || (_cache[1] = $event => _ctx.jumpRelative(10, false))
- }, null, 8, SessionRecordingVisvue_type_template_id_6f77b61e_hoisted_5), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["withDirectives"])(Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("span", {
- class: "playerAction icon-play",
- title: _ctx.translate('HeatmapSessionRecording_PlayerPlay', 'K'),
- onClick: _cache[2] || (_cache[2] = $event => _ctx.play())
- }, null, 8, SessionRecordingVisvue_type_template_id_6f77b61e_hoisted_6), [[external_commonjs_vue_commonjs2_vue_root_Vue_["vShow"], !_ctx.isPlaying && !_ctx.isFinished]]), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["withDirectives"])(Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("span", {
- class: "playerAction icon-replay",
- title: _ctx.translate('HeatmapSessionRecording_PlayerReplay', 'K'),
- onClick: _cache[3] || (_cache[3] = $event => _ctx.replay())
- }, null, 8, SessionRecordingVisvue_type_template_id_6f77b61e_hoisted_7), [[external_commonjs_vue_commonjs2_vue_root_Vue_["vShow"], !_ctx.isPlaying && _ctx.isFinished]]), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["withDirectives"])(Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("span", {
- class: "playerAction icon-pause",
- title: _ctx.translate('HeatmapSessionRecording_PlayerPause', 'K'),
- onClick: _cache[4] || (_cache[4] = $event => _ctx.pause())
- }, null, 8, SessionRecordingVisvue_type_template_id_6f77b61e_hoisted_8), [[external_commonjs_vue_commonjs2_vue_root_Vue_["vShow"], _ctx.isPlaying]]), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("span", {
- class: "playerAction icon-fast-forward",
- title: _ctx.translate('HeatmapSessionRecording_PlayerForwardFast', 10, 'L'),
- onClick: _cache[5] || (_cache[5] = $event => _ctx.jumpRelative(10, true))
- }, null, 8, SessionRecordingVisvue_type_template_id_6f77b61e_hoisted_9), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["withDirectives"])(Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("span", {
- class: "playerAction icon-skip-next",
- title: _ctx.translate('HeatmapSessionRecording_PlayerPageViewNext', _ctx.nextRecordingInfo, 'N'),
- onClick: _cache[6] || (_cache[6] = $event => _ctx.loadNewRecording(_ctx.nextRecordingId))
- }, null, 8, SessionRecordingVisvue_type_template_id_6f77b61e_hoisted_10), [[external_commonjs_vue_commonjs2_vue_root_Vue_["vShow"], _ctx.nextRecordingId]]), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("span", {
- class: "changeReplaySpeed",
- title: _ctx.translate('HeatmapSessionRecording_ChangeReplaySpeed', 'S'),
- onClick: _cache[7] || (_cache[7] = $event => _ctx.increaseReplaySpeed())
- }, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["withDirectives"])((Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("svg", SessionRecordingVisvue_type_template_id_6f77b61e_hoisted_12, SessionRecordingVisvue_type_template_id_6f77b61e_hoisted_14, 512)), [[external_commonjs_vue_commonjs2_vue_root_Vue_["vShow"], _ctx.actualReplaySpeed === 4]]), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["withDirectives"])((Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("svg", SessionRecordingVisvue_type_template_id_6f77b61e_hoisted_15, SessionRecordingVisvue_type_template_id_6f77b61e_hoisted_17, 512)), [[external_commonjs_vue_commonjs2_vue_root_Vue_["vShow"], _ctx.actualReplaySpeed === 1]]), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["withDirectives"])((Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("svg", SessionRecordingVisvue_type_template_id_6f77b61e_hoisted_18, SessionRecordingVisvue_type_template_id_6f77b61e_hoisted_20, 512)), [[external_commonjs_vue_commonjs2_vue_root_Vue_["vShow"], _ctx.actualReplaySpeed === 2]]), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["withDirectives"])((Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("svg", SessionRecordingVisvue_type_template_id_6f77b61e_hoisted_21, SessionRecordingVisvue_type_template_id_6f77b61e_hoisted_23, 512)), [[external_commonjs_vue_commonjs2_vue_root_Vue_["vShow"], _ctx.actualReplaySpeed === 6]])], 8, SessionRecordingVisvue_type_template_id_6f77b61e_hoisted_11), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("span", {
- class: Object(external_commonjs_vue_commonjs2_vue_root_Vue_["normalizeClass"])(["toggleSkipPause", {
- 'active': _ctx.actualSkipPausesEnabled
- }]),
- title: _ctx.translate('HeatmapSessionRecording_ClickToSkipPauses', _ctx.skipPausesEnabledText, 'B'),
- onClick: _cache[8] || (_cache[8] = $event => _ctx.toggleSkipPauses())
- }, SessionRecordingVisvue_type_template_id_6f77b61e_hoisted_26, 10, SessionRecordingVisvue_type_template_id_6f77b61e_hoisted_24), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("span", {
- class: Object(external_commonjs_vue_commonjs2_vue_root_Vue_["normalizeClass"])(["toggleAutoPlay", {
- 'active': _ctx.actualAutoPlayEnabled
- }]),
- title: _ctx.translate('HeatmapSessionRecording_AutoPlayNextPageview', _ctx.autoplayEnabledText, 'A'),
- onClick: _cache[9] || (_cache[9] = $event => _ctx.toggleAutoPlay())
- }, SessionRecordingVisvue_type_template_id_6f77b61e_hoisted_29, 10, SessionRecordingVisvue_type_template_id_6f77b61e_hoisted_27), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("span", _hoisted_30, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.translate('HeatmapSessionRecording_PlayerDurationXofY', _ctx.positionPretty, _ctx.durationPretty)), 1)]), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", _hoisted_31, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("ul", null, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("li", null, [_hoisted_32, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createTextVNode"])(" " + Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.translate('HeatmapSessionRecording_ActivityClick')), 1)]), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("li", null, [_hoisted_33, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createTextVNode"])(" " + Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.translate('HeatmapSessionRecording_ActivityMove')), 1)]), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("li", null, [_hoisted_34, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createTextVNode"])(" " + Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.translate('HeatmapSessionRecording_ActivityScroll')), 1)]), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("li", null, [_hoisted_35, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createTextVNode"])(" " + Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.translate('HeatmapSessionRecording_ActivityResize')), 1)]), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("li", null, [_hoisted_36, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createTextVNode"])(" " + Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.translate('HeatmapSessionRecording_ActivityFormChange')), 1)]), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("li", null, [_hoisted_37, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createTextVNode"])(" " + Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.translate('HeatmapSessionRecording_ActivityPageChange')), 1)])])]), _hoisted_38]), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", {
- class: "timelineOuter",
- onClick: _cache[10] || (_cache[10] = $event => _ctx.seekEvent($event)),
- style: Object(external_commonjs_vue_commonjs2_vue_root_Vue_["normalizeStyle"])({
- width: `${_ctx.replayWidth}px`
- })
- }, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", {
- class: "timelineInner",
- style: Object(external_commonjs_vue_commonjs2_vue_root_Vue_["normalizeStyle"])({
- width: `${_ctx.progress}%`
- })
- }, null, 4), (Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(true), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])(external_commonjs_vue_commonjs2_vue_root_Vue_["Fragment"], null, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["renderList"])(_ctx.clues, (clue, index) => {
- return Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("div", {
- title: clue.title,
- class: Object(external_commonjs_vue_commonjs2_vue_root_Vue_["normalizeClass"])(clue.type),
- style: Object(external_commonjs_vue_commonjs2_vue_root_Vue_["normalizeStyle"])({
- left: `${clue.left}%`
- }),
- key: index
- }, null, 14, _hoisted_39);
- }), 128))], 4), _hoisted_40, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["withDirectives"])(Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", {
- class: "hsrLoadingOuter",
- style: Object(external_commonjs_vue_commonjs2_vue_root_Vue_["normalizeStyle"])({
- width: `${_ctx.replayWidth}px`,
- height: `${_ctx.replayHeight}px`
- })
- }, [_hoisted_41, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", _hoisted_42, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", _hoisted_43, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.translate('General_Loading')), 1)])], 4), [[external_commonjs_vue_commonjs2_vue_root_Vue_["vShow"], _ctx.isLoading]]), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", {
- class: "replayContainerOuter",
- onClick: _cache[12] || (_cache[12] = $event => _ctx.togglePlay()),
- style: Object(external_commonjs_vue_commonjs2_vue_root_Vue_["normalizeStyle"])({
- height: `${_ctx.replayHeight}px`,
- width: `${_ctx.replayWidth}px`
- })
- }, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", {
- class: "replayContainerInner",
- style: Object(external_commonjs_vue_commonjs2_vue_root_Vue_["normalizeStyle"])([{
- "transform-origin": "0 0"
- }, {
- transform: `scale(${_ctx.replayScale})`,
- 'margin-left': `${_ctx.replayMarginLeft}px`
- }])
- }, [_ctx.embedUrl ? (Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("iframe", {
- key: 0,
- id: "recordingPlayer",
- ref: "recordingPlayer",
- onLoad: _cache[11] || (_cache[11] = $event => _ctx.onLoaded()),
- scrolling: "no",
- sandbox: "allow-scripts allow-same-origin",
- referrerpolicy: "no-referrer",
- src: _ctx.embedUrl,
- width: _ctx.recording.viewport_w_px,
- height: _ctx.recording.viewport_h_px
- }, null, 40, _hoisted_44)) : Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createCommentVNode"])("", true)], 4)], 4)]);
-}
-// CONCATENATED MODULE: ./plugins/HeatmapSessionRecording/vue/src/SessionRecordingVis/SessionRecordingVis.vue?vue&type=template&id=6f77b61e
-
-// CONCATENATED MODULE: ./node_modules/@vue/cli-plugin-typescript/node_modules/cache-loader/dist/cjs.js??ref--15-0!./node_modules/babel-loader/lib!./node_modules/@vue/cli-plugin-typescript/node_modules/ts-loader??ref--15-2!./node_modules/@vue/cli-service/node_modules/cache-loader/dist/cjs.js??ref--1-0!./node_modules/@vue/cli-service/node_modules/vue-loader-v16/dist??ref--1-1!./plugins/HeatmapSessionRecording/vue/src/SessionRecordingVis/SessionRecordingVis.vue?vue&type=script&lang=ts
-
-
-
-const FRAME_STEP = 20;
-const EVENT_TYPE_MOVEMENT = 1;
-const EVENT_TYPE_CLICK = 2;
-const EVENT_TYPE_SCROLL = 3;
-const EVENT_TYPE_RESIZE = 4;
-const EVENT_TYPE_INITIAL_DOM = 5;
-const EVENT_TYPE_MUTATION = 6;
-const EVENT_TYPE_FORM_TEXT = 9;
-const EVENT_TYPE_FORM_VALUE = 10;
-const EVENT_TYPE_SCROLL_ELEMENT = 12;
-const EVENT_TYPE_TO_NAME = {
- [EVENT_TYPE_CLICK]: 'clickEvent',
- [EVENT_TYPE_MOVEMENT]: 'moveEvent',
- [EVENT_TYPE_SCROLL]: 'scrollEvent',
- [EVENT_TYPE_SCROLL_ELEMENT]: 'scrollEvent',
- [EVENT_TYPE_RESIZE]: 'resizeEvent',
- [EVENT_TYPE_FORM_TEXT]: 'formChange',
- [EVENT_TYPE_FORM_VALUE]: 'formChange',
- [EVENT_TYPE_INITIAL_DOM]: 'mutationEvent',
- [EVENT_TYPE_MUTATION]: 'mutationEvent'
-};
-const EVENT_TYPE_TO_TITLE = {
- [EVENT_TYPE_CLICK]: Object(external_CoreHome_["translate"])('HeatmapSessionRecording_ActivityClick'),
- [EVENT_TYPE_MOVEMENT]: Object(external_CoreHome_["translate"])('HeatmapSessionRecording_ActivityMove'),
- [EVENT_TYPE_SCROLL]: Object(external_CoreHome_["translate"])('HeatmapSessionRecording_ActivityScroll'),
- [EVENT_TYPE_SCROLL_ELEMENT]: Object(external_CoreHome_["translate"])('HeatmapSessionRecording_ActivityScroll'),
- [EVENT_TYPE_RESIZE]: Object(external_CoreHome_["translate"])('HeatmapSessionRecording_ActivityResize'),
- [EVENT_TYPE_FORM_TEXT]: Object(external_CoreHome_["translate"])('HeatmapSessionRecording_ActivityFormChange'),
- [EVENT_TYPE_FORM_VALUE]: Object(external_CoreHome_["translate"])('HeatmapSessionRecording_ActivityFormChange'),
- [EVENT_TYPE_INITIAL_DOM]: Object(external_CoreHome_["translate"])('HeatmapSessionRecording_ActivityPageChange'),
- [EVENT_TYPE_MUTATION]: Object(external_CoreHome_["translate"])('HeatmapSessionRecording_ActivityPageChange')
-};
-const MOUSE_POINTER_HTML = `
-
-
-
-
diff --git a/files/plugin-HeatmapSessionRecording-5.2.6/API.php b/files/plugin-HeatmapSessionRecording-5.2.6/API.php
deleted file mode 100644
index 84acc11..0000000
--- a/files/plugin-HeatmapSessionRecording-5.2.6/API.php
+++ /dev/null
@@ -1,1113 +0,0 @@
-validator = $validator;
- $this->aggregator = $aggregator;
- $this->siteHsr = $siteHsr;
- $this->logHsr = $logHsr;
- $this->logEvent = $logEvent;
- $this->logHsrSite = $logHsrSite;
- $this->systemSettings = $settings;
- $this->configuration = $configuration;
-
- $dir = Plugin\Manager::getPluginDirectory('UserCountry');
- require_once $dir . '/functions.php';
- }
-
- /**
- * Adds a new heatmap.
- *
- * Once added, the system will start recording activities for this heatmap.
- *
- * @param int $idSite
- * @param string $name The name of heatmap which will be visible in the reporting UI.
- * @param array $matchPageRules Eg. array(array('attribute' => 'url', 'type' => 'equals_simple', 'inverted' => 0, 'value' => 'http://example.com/directory'))
- * For a list of available attribute and type values call {@link getAvailableTargetPageRules()}.
- * "inverted" should be "0" or "1".
- * @param int $sampleLimit The number of page views you want to record. Once the sample limit has been reached, the heatmap will be ended automatically.
- * @param float $sampleRate Needs to be between 0 and 100 where 100 means => 100%, 10 => 10%, 0.1 => 0.1%.
- * Defines how often a visitor will be actually recorded when they match the page rules, also known as "traffic". Currently max one decimal is supported.
- * @param string $excludedElements Optional, a comma separated list of CSS selectors to exclude elements from being shown in the heatmap. For example to disable popups etc.
- * @param string $screenshotUrl Optional, a URL to define on which page a screenshot should be taken.
- * @param int $breakpointMobile If the device type cannot be detected, we will put any device having a lower width than this value into the mobile category. Useful if your website is responsive.
- * @param int $breakpointTablet If the device type cannot be detected, we will put any device having a lower width than this value into the tablet category. Useful if your website is responsive.
- * @return int
- */
- public function addHeatmap($idSite, $name, $matchPageRules, $sampleLimit = 1000, $sampleRate = 5, $excludedElements = false, $screenshotUrl = false, $breakpointMobile = false, $breakpointTablet = false, $captureDomManually = false)
- {
- $this->validator->checkHeatmapReportWritePermission($idSite);
-
- if ($breakpointMobile === false || $breakpointMobile === null) {
- $breakpointMobile = $this->systemSettings->breakpointMobile->getValue();
- }
-
- if ($breakpointTablet === false || $breakpointTablet === null) {
- $breakpointTablet = $this->systemSettings->breakpointTablet->getValue();
- }
-
- $createdDate = Date::now()->getDatetime();
-
- $matchPageRules = $this->unsanitizePageRules($matchPageRules);
- $screenshotUrl = $this->unsanitizeScreenshotUrl($screenshotUrl);
-
- return $this->siteHsr->addHeatmap($idSite, $name, $matchPageRules, $sampleLimit, $sampleRate, $excludedElements, $screenshotUrl, $breakpointMobile, $breakpointTablet, $captureDomManually, $createdDate);
- }
-
- /**
- * Copies a specified heatmap to one or more sites. If a heatmap with the same name already exists, the new heatmap
- * will have an automatically adjusted name to make it unique to the assigned site.
- *
- * @param int $idSite
- * @param int $idSiteHsr ID of the heatmap to duplicate.
- * @param int[] $idDestinationSites Optional array of IDs identifying which site(s) the new heatmap is to be
- * assigned to. The default is [idSite] when nothing is provided.
- * @return array
- * @throws Exception
- */
- public function duplicateHeatmap(int $idSite, int $idSiteHsr, array $idDestinationSites = []): array
- {
- // Define data array before any alterations to the variables
- $additionalData = [
- 'idSite' => $idSite,
- 'idDestinationSites' => $idDestinationSites,
- 'idSiteHsr' => $idSiteHsr,
- ];
-
- $idDestinationSites = count($idDestinationSites) > 0 ? $idDestinationSites : [$idSite];
- $idSitesToCheck = array_unique(array_merge([$idSite], $idDestinationSites));
- $this->validator->checkSitesDuplicationPermission($idSitesToCheck);
-
- // Initialise the common response values
- $duplicateRequestResponse = new DuplicateRequestResponse();
-
- $heatmap = null;
- try {
- $heatmap = $this->getHeatmap($idSite, $idSiteHsr);
- } catch (\Throwable $e) {
- // Log the error, but continue for the proper response to be built later
- $this->logError('Uncaught exception looking up heatmap to duplicate: {exception}', $e);
- }
- if (empty($heatmap['name']) || empty($heatmap['match_page_rules'])) {
- $duplicateRequestResponse->setSuccess(false);
- $duplicateRequestResponse->setMessage(Piwik::translate('HeatmapSessionRecording_SourceHeatmapLookupError'));
- $duplicateRequestResponse->setAdditionalData($additionalData);
-
- return $duplicateRequestResponse->getResponseArray();
- }
-
- $idSitesFailed = $idHrsNew = [];
- foreach ($idDestinationSites as $idDestinationSite) {
- try {
- // Make sure that the new name is unique.
- $newName = $heatmap['name'];
- $heatmaps = $this->siteHsr->getHeatmaps($idDestinationSite, false, true);
- // It can only be a duplicate name if some heatmaps were found for the site.
- if (is_array($heatmaps) && count($heatmaps) > 0) {
- $heatmapNames = array_column($heatmaps, 'name');
- $newName = EntityDuplicatorHelper::getUniqueNameComparedToList($newName, $heatmapNames, 50);
- }
-
- $response = $this->addHeatmap(
- $idDestinationSite,
- $newName,
- $heatmap['match_page_rules'],
- $heatmap['sample_limit'] ?? 1000,
- $heatmap['sample_rate'] ?? 5,
- $heatmap['excluded_elements'] ?? false,
- $heatmap['screenshot_url'] ?? false,
- $heatmap['breakpoint_mobile'] ?? false,
- $heatmap['breakpoint_tablet'] ?? false,
- $heatmap['capture_manually'] ?? false
- );
-
- // Check response for success or failure. The only return is the new ID, so make sure it's a valid int
- if (!is_int($response) || $response < 1) {
- $idSitesFailed[] = $idDestinationSite;
- continue;
- }
-
- $idHrsNew[] = $response;
- } catch (\Throwable $e) {
- $idSitesFailed[] = $idDestinationSite;
-
- // Log the error, but continue in case there are other sites to copy to
- $this->logError('Uncaught exception duplicating heatmap: {exception}', $e);
- }
- }
-
- // Set the values for success response
- $duplicateRequestResponse->setSuccess(true);
- $duplicateRequestResponse->setMessage(Piwik::translate('HeatmapSessionRecording_HeatmapCopied'));
- $additionalData['newIds'] = $idHrsNew;
- $duplicateRequestResponse->setAdditionalData($additionalData);
-
- // If any of the sites failed, update to error response
- if (count($idSitesFailed) > 0) {
- $successSites = array_diff($idDestinationSites, $idSitesFailed);
- $sitesString = count($successSites) ? implode(',', $successSites) : Piwik::translate('HeatmapSessionRecording_None');
- $message = Piwik::translate('HeatmapSessionRecording_HeatmapDuplicationError', [implode(',', $idSitesFailed), $sitesString]);
- $duplicateRequestResponse->setSuccess(false);
- $duplicateRequestResponse->setMessage($message);
- }
-
- return $duplicateRequestResponse->getResponseArray();
- }
-
- private function logError(string $message, \Throwable $e): void
- {
- StaticContainer::get(\Piwik\Log\LoggerInterface::class)->error(
- $message,
- [
- 'exception' => $e,
- 'ignoreInScreenWriter' => true,
- ]
- );
- }
-
- private function unsanitizeScreenshotUrl($screenshotUrl)
- {
- if (!empty($screenshotUrl) && is_string($screenshotUrl)) {
- $screenshotUrl = Common::unsanitizeInputValue($screenshotUrl);
- }
-
- return $screenshotUrl;
- }
-
- private function unsanitizePageRules($matchPageRules)
- {
- if (!empty($matchPageRules) && is_array($matchPageRules)) {
- foreach ($matchPageRules as $index => $matchPageRule) {
- if (is_array($matchPageRule) && !empty($matchPageRule['value'])) {
- $matchPageRules[$index]['value'] = Common::unsanitizeInputValue($matchPageRule['value']);
- }
- }
- }
- return $matchPageRules;
- }
-
- /**
- * Updates an existing heatmap.
- *
- * All fields need to be set in order to update a heatmap. Easiest way is to get all values for a heatmap via
- * "HeatmapSessionRecording.getHeatmap", make the needed changes on the heatmap, and send all values back to
- * "HeatmapSessionRecording.updateHeatmap".
- *
- * @param int $idSite
- * @param int $idSiteHsr The id of the heatmap you want to update.
- * @param string $name The name of heatmap which will be visible in the reporting UI.
- * @param array $matchPageRules Eg. array(array('attribute' => 'url', 'type' => 'equals_simple', 'inverted' => 0, 'value' => 'http://example.com/directory'))
- * For a list of available attribute and type values call {@link getAvailableTargetPageRules()}.
- * "inverted" should be "0" or "1".
- * @param int $sampleLimit The number of page views you want to record. Once the sample limit has been reached, the heatmap will be ended automatically.
- * @param float $sampleRate Needs to be between 0 and 100 where 100 means => 100%, 10 => 10%, 0.1 => 0.1%.
- * Defines how often a visitor will be actually recorded when they match the page rules, also known as "traffic". Currently max one decimal is supported.
- * @param string $excludedElements Optional, a comma separated list of CSS selectors to exclude elements from being shown in the heatmap. For example to disable popups etc.
- * @param string $screenshotUrl Optional, a URL to define on which page a screenshot should be taken.
- * @param int $breakpointMobile If the device type cannot be detected, we will put any device having a lower width than this value into the mobile category. Useful if your website is responsive.
- * @param int $breakpointTablet If the device type cannot be detected, we will put any device having a lower width than this value into the tablet category. Useful if your website is responsive.
- */
- public function updateHeatmap($idSite, $idSiteHsr, $name, $matchPageRules, $sampleLimit = 1000, $sampleRate = 5, $excludedElements = false, $screenshotUrl = false, $breakpointMobile = false, $breakpointTablet = false, $captureDomManually = false)
- {
- $this->validator->checkHeatmapReportWritePermission($idSite);
- $this->siteHsr->checkHeatmapExists($idSite, $idSiteHsr);
-
- if ($breakpointMobile === false || $breakpointMobile === null) {
- $breakpointMobile = $this->systemSettings->breakpointMobile->getValue();
- }
-
- if ($breakpointTablet === false || $breakpointTablet === null) {
- $breakpointTablet = $this->systemSettings->breakpointTablet->getValue();
- }
-
- $updatedDate = Date::now()->getDatetime();
-
- $matchPageRules = $this->unsanitizePageRules($matchPageRules);
- $screenshotUrl = $this->unsanitizeScreenshotUrl($screenshotUrl);
-
- $this->siteHsr->updateHeatmap($idSite, $idSiteHsr, $name, $matchPageRules, $sampleLimit, $sampleRate, $excludedElements, $screenshotUrl, $breakpointMobile, $breakpointTablet, $captureDomManually, $updatedDate);
- }
-
- /**
- * Deletes / removes the screenshot from a heatmap
- * @param int $idSite
- * @param int $idSiteHsr
- * @return bool
- * @throws Exception
- */
- public function deleteHeatmapScreenshot($idSite, $idSiteHsr)
- {
- $this->validator->checkHeatmapReportWritePermission($idSite);
- $this->siteHsr->checkHeatmapExists($idSite, $idSiteHsr);
-
- $heatmap = $this->siteHsr->getHeatmap($idSite, $idSiteHsr);
- if (!empty($heatmap['status']) && $heatmap['status'] === SiteHsrDao::STATUS_ACTIVE) {
- $this->siteHsr->setPageTreeMirror($idSite, $idSiteHsr, null, null);
-
- if (!empty($heatmap['page_treemirror'])) {
- // only needed when a screenshot existed before that
- Cache::deleteCacheWebsiteAttributes($idSite);
- }
- return true;
- } elseif (!empty($heatmap['status'])) {
- throw new Exception('The screenshot can be only removed from active heatmaps');
- }
- }
-
- /**
- * Adds a new session recording.
- *
- * Once added, the system will start recording sessions.
- *
- * @param int $idSite
- * @param string $name The name of session recording which will be visible in the reporting UI.
- * @param array $matchPageRules Eg. array(array('attribute' => 'url', 'type' => 'equals_simple', 'inverted' => 0, 'value' => 'http://example.com/directory'))
- * For a list of available attribute and type values call {@link getAvailableTargetPageRules()}.
- * "inverted" should be "0" or "1". Leave it empty to record any page.
- * If page rules are set, a session will be only recorded as soon as a visitor has reached a page that matches these rules.
- * @param int $sampleLimit The number of sessions you want to record. Once the sample limit has been reached, the session recording will be ended automatically.
- * @param float $sampleRate Needs to be between 0 and 100 where 100 means => 100%, 10 => 10%, 0.1 => 0.1%.
- * Defines how often a visitor will be actually recorded when they match the page rules, also known as "traffic". Currently max one decimal is supported.
- * @param int $minSessionTime If defined, will only record sessions when the visitor has spent more than this many seconds on the current page.
- * @param int $requiresActivity If enabled (default), the session will be only recorded if the visitor has at least scrolled and clicked once.
- * @param int $captureKeystrokes If enabled (default), any text that a user enters into text form elements will be recorded.
- * Password fields will be automatically masked and you can mask other elements with sensitive data using a data-matomo-mask attribute.
- * @return int
- */
- public function addSessionRecording($idSite, $name, $matchPageRules = array(), $sampleLimit = 1000, $sampleRate = 10, $minSessionTime = 0, $requiresActivity = true, $captureKeystrokes = true)
- {
- $this->validator->checkSessionReportWritePermission($idSite);
-
- $createdDate = Date::now()->getDatetime();
-
- $matchPageRules = $this->unsanitizePageRules($matchPageRules);
-
- return $this->siteHsr->addSessionRecording($idSite, $name, $matchPageRules, $sampleLimit, $sampleRate, $minSessionTime, $requiresActivity, $captureKeystrokes, $createdDate);
- }
-
- /**
- * Updates an existing session recording.
- *
- * All fields need to be set in order to update a session recording. Easiest way is to get all values for a
- * session recording via "HeatmapSessionRecording.getSessionRecording", make the needed changes on the recording,
- * and send all values back to "HeatmapSessionRecording.updateSessionRecording".
- *
- * @param int $idSite
- * @param int $idSiteHsr The id of the session recording you want to update.
- * @param string $name The name of session recording which will be visible in the reporting UI.
- * @param array $matchPageRules Eg. array(array('attribute' => 'url', 'type' => 'equals_simple', 'inverted' => 0, 'value' => 'http://example.com/directory'))
- * For a list of available attribute and type values call {@link getAvailableTargetPageRules()}.
- * "inverted" should be "0" or "1". Leave it empty to record any page.
- * If page rules are set, a session will be only recorded as soon as a visitor has reached a page that matches these rules.
- * @param int $sampleLimit The number of sessions you want to record. Once the sample limit has been reached, the session recording will be ended automatically.
- * @param float $sampleRate Needs to be between 0 and 100 where 100 means => 100%, 10 => 10%, 0.1 => 0.1%.
- * Defines how often a visitor will be actually recorded when they match the page rules, also known as "traffic". Currently max one decimal is supported.
- * @param int $minSessionTime If defined, will only record sessions when the visitor has spent more than this many seconds on the current page.
- * @param int $requiresActivity If enabled (default), the session will be only recorded if the visitor has at least scrolled and clicked once.
- * @param int $captureKeystrokes If enabled (default), any text that a user enters into text form elements will be recorded.
- * Password fields will be automatically masked and you can mask other elements with sensitive data using a data-matomo-mask attribute.
- */
- public function updateSessionRecording($idSite, $idSiteHsr, $name, $matchPageRules = array(), $sampleLimit = 1000, $sampleRate = 10, $minSessionTime = 0, $requiresActivity = true, $captureKeystrokes = true)
- {
- $this->validator->checkSessionReportWritePermission($idSite);
- $this->siteHsr->checkSessionRecordingExists($idSite, $idSiteHsr);
-
- $updatedDate = Date::now()->getDatetime();
-
- $matchPageRules = $this->unsanitizePageRules($matchPageRules);
-
- $this->siteHsr->updateSessionRecording($idSite, $idSiteHsr, $name, $matchPageRules, $sampleLimit, $sampleRate, $minSessionTime, $requiresActivity, $captureKeystrokes, $updatedDate);
- }
-
- /**
- * Get a specific heatmap by its ID.
- *
- * @param int $idSite
- * @param int $idSiteHsr The id of the heatmap.
- * @return array|false
- */
- public function getHeatmap($idSite, $idSiteHsr)
- {
- $this->validator->checkHeatmapReportViewPermission($idSite);
- $this->siteHsr->checkHeatmapExists($idSite, $idSiteHsr);
-
- $heatmap = $this->siteHsr->getHeatmap($idSite, $idSiteHsr);
-
- return $heatmap;
- }
-
- /**
- * Get a specific session recording by its ID.
- *
- * @param int $idSite
- * @param int $idSiteHsr The id of the heatmap.
- * @return array|false
- */
- public function getSessionRecording($idSite, $idSiteHsr)
- {
- $this->validator->checkSessionReportViewPermission($idSite);
- $this->siteHsr->checkSessionRecordingExists($idSite, $idSiteHsr);
-
- return $this->siteHsr->getSessionRecording($idSite, $idSiteHsr);
- }
-
- /**
- * Pauses the given heatmap.
- *
- * When a heatmap is paused, all the tracking will be paused until its resumed again.
- *
- * @param int $idSite
- * @param int $idSiteHsr The id of the heatmap
- */
- public function pauseHeatmap($idSite, $idSiteHsr)
- {
- $this->validator->checkHeatmapReportWritePermission($idSite);
- $this->siteHsr->checkHeatmapExists($idSite, $idSiteHsr);
-
- $this->siteHsr->pauseHeatmap($idSite, $idSiteHsr);
-
- Cache::deleteCacheWebsiteAttributes($idSite);
- }
-
- /**
- * Resumes the given heatmap.
- *
- * When a heatmap is resumed, all the tracking will be enabled.
- *
- * @param int $idSite
- * @param int $idSiteHsr The id of the heatmap
- */
- public function resumeHeatmap($idSite, $idSiteHsr)
- {
- $this->validator->checkHeatmapReportWritePermission($idSite);
- $this->siteHsr->checkHeatmapExists($idSite, $idSiteHsr);
-
- $this->siteHsr->resumeHeatmap($idSite, $idSiteHsr);
-
- Cache::deleteCacheWebsiteAttributes($idSite);
- }
-
- /**
- * Deletes the given heatmap.
- *
- * When a heatmap is deleted, the report will be no longer available in the API and tracked data for this
- * heatmap might be removed.
- *
- * @param int $idSite
- * @param int $idSiteHsr The id of the heatmap
- */
- public function deleteHeatmap($idSite, $idSiteHsr)
- {
- $this->validator->checkHeatmapReportWritePermission($idSite);
-
- $this->siteHsr->deactivateHeatmap($idSite, $idSiteHsr);
- }
-
- /**
- * Ends / finishes the given heatmap.
- *
- * When you end a heatmap, the heatmap reports will be still available via API and UI but no new heatmap activity
- * will be recorded for this heatmap.
- *
- * @param int $idSite
- * @param int $idSiteHsr The id of the heatmap.
- */
- public function endHeatmap($idSite, $idSiteHsr)
- {
- $this->validator->checkHeatmapReportWritePermission($idSite);
- $this->siteHsr->checkHeatmapExists($idSite, $idSiteHsr);
-
- $this->siteHsr->endHeatmap($idSite, $idSiteHsr);
- }
-
- /**
- * Pauses the given session recording.
- *
- * When a session recording is paused, all the tracking will be paused until its resumed again.
- *
- * @param int $idSite
- * @param int $idSiteHsr The id of the heatmap
- */
- public function pauseSessionRecording($idSite, $idSiteHsr)
- {
- $this->validator->checkSessionReportWritePermission($idSite);
- $this->siteHsr->checkSessionRecordingExists($idSite, $idSiteHsr);
-
- $this->siteHsr->pauseSessionRecording($idSite, $idSiteHsr);
-
- Cache::deleteCacheWebsiteAttributes($idSite);
- }
-
- /**
- * Resumes the given session recording.
- *
- * When a session recording is resumed, all the tracking will be enabled.
- *
- * @param int $idSite
- * @param int $idSiteHsr The id of the heatmap
- */
- public function resumeSessionRecording($idSite, $idSiteHsr)
- {
- $this->validator->checkSessionReportWritePermission($idSite);
- $this->siteHsr->checkSessionRecordingExists($idSite, $idSiteHsr);
-
- $this->siteHsr->resumeSessionRecording($idSite, $idSiteHsr);
-
- Cache::deleteCacheWebsiteAttributes($idSite);
- }
-
- /**
- * Deletes the given session recording.
- *
- * When a session recording is deleted, any related recordings be no longer available in the API and tracked data
- * for this session recording might be removed.
- *
- * @param int $idSite
- * @param int $idSiteHsr The id of the session recording.
- */
- public function deleteSessionRecording($idSite, $idSiteHsr)
- {
-
- $this->validator->checkSessionReportWritePermission($idSite);
-
- $this->siteHsr->deactivateSessionRecording($idSite, $idSiteHsr);
- }
-
- /**
- * Ends / finishes the given session recording.
- *
- * When you end a session recording, the session recording reports will be still available via API and UI but no new
- * session will be recorded anymore.
- *
- * @param int $idSite
- * @param int $idSiteHsr The id of the session recording.
- */
- public function endSessionRecording($idSite, $idSiteHsr)
- {
- $this->validator->checkSessionReportWritePermission($idSite);
- $this->siteHsr->checkSessionRecordingExists($idSite, $idSiteHsr);
-
- $this->siteHsr->endSessionRecording($idSite, $idSiteHsr);
- }
-
- /**
- * Get all available heatmaps for a specific website or app.
- *
- * It will return active as well as ended heatmaps but not any deleted heatmaps.
- *
- * @param int $idSite
- * @param bool|int $includePageTreeMirror set to 0 if you don't need the page tree mirror for heatmaps (improves performance)
- * @return array
- */
- public function getHeatmaps($idSite, $includePageTreeMirror = true)
- {
- $this->validator->checkHeatmapReportViewPermission($idSite);
-
- return $this->siteHsr->getHeatmaps($idSite, !empty($includePageTreeMirror));
- }
-
- /**
- * Get all available session recordings for a specific website or app.
- *
- * It will return active as well as ended session recordings but not any deleted session recordings.
- *
- * @param int $idSite
- * @return array
- */
- public function getSessionRecordings($idSite)
- {
- $this->validator->checkSessionReportViewPermission($idSite);
-
- return $this->siteHsr->getSessionRecordings($idSite);
- }
-
- /**
- * Returns all page views that were recorded during a particular session / visit. We do not apply segments as it is
- * used for video player when replaying sessions etc.
- *
- * @param int $idSite
- * @param int $idSiteHsr The id of a session recording
- * @param int $idVisit The visit / session id
- * @return array
- */
- private function getRecordedPageViewsInSession($idSite, $idSiteHsr, $idVisit, $period, $date)
- {
- $timezone = Site::getTimezoneFor($idSite);
-
- // ideally we would also check if idSiteHsr is actually linked to idLogHsr but not really needed for security reasons
- $pageviews = $this->aggregator->getRecordedPageViewsInSession($idSite, $idSiteHsr, $idVisit, $period, $date, $segment = false);
-
- $isAnonymous = Piwik::isUserIsAnonymous();
-
- foreach ($pageviews as &$pageview) {
- $pageview['server_time_pretty'] = Date::factory($pageview['server_time'], $timezone)->getLocalized(DateTimeFormatProvider::DATETIME_FORMAT_SHORT);
-
- if ($isAnonymous) {
- unset($pageview['idvisitor']);
- } else {
- $pageview['idvisitor'] = bin2hex($pageview['idvisitor']);
- }
-
- $formatter = new Formatter();
- $pageview['time_on_page_pretty'] = $formatter->getPrettyTimeFromSeconds(intval($pageview['time_on_page'] / 1000), $asSentence = true);
- }
-
- return $pageviews;
- }
-
- /**
- * Returns all recorded sessions for a specific session recording.
- *
- * To get the actual recorded data for any of the recorded sessions, call {@link getRecordedSession()}.
- *
- * @param int $idSite
- * @param string $period
- * @param string $date
- * @param int $idSiteHsr The id of the session recording you want to retrieve all the recorded sessions for.
- * @param bool $segment
- * @param int $idSubtable Optional visit id if you want to get all recorded pageviews of a specific visitor
- * @return DataTable
- */
- public function getRecordedSessions($idSite, $period, $date, $idSiteHsr, $segment = false, $idSubtable = false)
- {
- $this->validator->checkSessionReportViewPermission($idSite);
- $this->siteHsr->checkSessionRecordingExists($idSite, $idSiteHsr);
-
- $idVisit = $idSubtable;
-
- try {
- PeriodFactory::checkPeriodIsEnabled($period);
- } catch (\Exception $e) {
- throw new Exception(Piwik::translate('HeatmapSessionRecording_PeriodDisabledErrorMessage', $period));
- }
-
- if (!empty($idVisit)) {
- $recordings = $this->aggregator->getRecordedPageViewsInSession($idSite, $idSiteHsr, $idVisit, $period, $date, $segment);
- } else {
- $recordings = $this->aggregator->getRecordedSessions($idSite, $idSiteHsr, $period, $date, $segment);
- }
-
- $table = new DataTable();
- $table->disableFilter('AddColumnsProcessedMetrics');
- $table->setMetadata('idSiteHsr', $idSiteHsr);
-
- if (!empty($recordings)) {
- $table->addRowsFromSimpleArray($recordings);
- }
-
- if (empty($idVisit)) {
- $table->queueFilter(function (DataTable $table) {
- foreach ($table->getRowsWithoutSummaryRow() as $row) {
- if ($idVisit = $row->getColumn('idvisit')) {
- $row->setNonLoadedSubtableId($idVisit);
- }
- }
- });
- } else {
- $table->disableFilter('Sort');
- }
-
- if (!method_exists(SettingsServer::class, 'isMatomoForWordPress') || !SettingsServer::isMatomoForWordPress()) {
- $table->queueFilter(function (DataTable $table) use ($idSite, $idSiteHsr, $period, $date) {
- foreach ($table->getRowsWithoutSummaryRow() as $row) {
- $idLogHsr = $row->getColumn('idloghsr');
- $row->setMetadata('sessionReplayUrl', SiteHsrModel::completeWidgetUrl('replayRecording', 'idSiteHsr=' . (int) $idSiteHsr . '&idLogHsr=' . (int) $idLogHsr, $idSite, $period, $date));
- }
- });
- }
-
- $table->filter('Piwik\Plugins\HeatmapSessionRecording\DataTable\Filter\EnrichRecordedSessions');
-
- return $table;
- }
-
- /**
- * Get all activities of a specific recorded session.
- *
- * This includes events such as clicks, mouse moves, scrolls, resizes, page / HTML DOM changes, form changed.
- * It is recommended to call this API method with filter_limit = -1 to retrieve all results. It also returns
- * metadata like the viewport size the user had when it was recorded, the browser, operating system, and more.
- *
- * To see what each event type in the events property means, call {@link getEventTypes()}.
- *
- * @param int $idSite
- * @param int $idSiteHsr The id of the session recording you want to retrieve the data for.
- * @param int $idLogHsr The id of the recorded session you want to retrieve the data for.
- * @return array
- * @throws Exception
- */
- public function getRecordedSession($idSite, $idSiteHsr, $idLogHsr)
- {
- $this->validator->checkSessionReportViewPermission($idSite);
- $this->siteHsr->checkSessionRecordingExists($idSite, $idSiteHsr);
-
- // ideally we would also check if idSiteHsr is actually linked to idLogHsr but not really needed for security reasons
- $session = $this->aggregator->getRecordedSession($idLogHsr);
-
- if (empty($session['idsite']) || empty($idSite)) {
- throw new Exception(Piwik::translate('HeatmapSessionRecording_ErrorSessionRecordingDoesNotExist'));
- }
-
- if ($session['idsite'] != $idSite) {
- // important otherwise can fetch any log entry!
- throw new Exception(Piwik::translate('HeatmapSessionRecording_ErrorSessionRecordingDoesNotExist'));
- }
-
- $session['idvisitor'] = !empty($session['idvisitor']) ? bin2hex($session['idvisitor']) : '';
-
- if (Piwik::isUserIsAnonymous()) {
- foreach (EnrichRecordedSessions::getBlockedFields() as $blockedField) {
- if (isset($session[$blockedField])) {
- $session[$blockedField] = null;
- }
- }
- }
-
-
- $configBrowserName = !empty($session['config_browser_name']) ? $session['config_browser_name'] : '';
- $session['browser_name'] = \Piwik\Plugins\DevicesDetection\getBrowserName($configBrowserName);
- $session['browser_logo'] = \Piwik\Plugins\DevicesDetection\getBrowserLogo($configBrowserName);
- $configOs = !empty($session['config_os']) ? $session['config_os'] : '';
- $session['os_name'] = \Piwik\Plugins\DevicesDetection\getOsFullName($configOs);
- $session['os_logo'] = \Piwik\Plugins\DevicesDetection\getOsLogo($configOs);
- $session['device_name'] = \Piwik\Plugins\DevicesDetection\getDeviceTypeLabel($session['config_device_type']);
- $session['device_logo'] = \Piwik\Plugins\DevicesDetection\getDeviceTypeLogo($session['config_device_type']);
-
- if (!empty($session['config_device_model'])) {
- $session['device_name'] .= ', ' . $session['config_device_model'];
- }
-
- $session['location_name'] = '';
- $session['location_logo'] = '';
-
- if (!empty($session['location_country'])) {
- $session['location_name'] = \Piwik\Plugins\UserCountry\countryTranslate($session['location_country']);
- $session['location_logo'] = \Piwik\Plugins\UserCountry\getFlagFromCode($session['location_country']);
-
- if (!empty($session['location_region']) && $session['location_region'] != Visit::UNKNOWN_CODE) {
- $session['location_name'] .= ', ' . \Piwik\Plugins\UserCountry\getRegionNameFromCodes($session['location_country'], $session['location_region']);
- }
-
- if (!empty($session['location_city'])) {
- $session['location_name'] .= ', ' . $session['location_city'];
- }
- }
-
- $timezone = Site::getTimezoneFor($idSite);
- $session['server_time_pretty'] = Date::factory($session['server_time'], $timezone)->getLocalized(DateTimeFormatProvider::DATETIME_FORMAT_SHORT);
-
- $formatter = new Formatter();
- $session['time_on_page_pretty'] = $formatter->getPrettyTimeFromSeconds(intval($session['time_on_page'] / 1000), $asSentence = true);
-
- // we make sure to get all recorded pageviews in this session
- $serverTime = Date::factory($session['server_time']);
- $from = $serverTime->subDay(1)->toString();
- $to = $serverTime->addDay(1)->toString();
-
- $period = 'range';
- $dateRange = $from . ',' . $to;
-
- $session['events'] = $this->logEvent->getEventsForPageview($idLogHsr);
- $session['pageviews'] = $this->getRecordedPageViewsInSession($idSite, $idSiteHsr, $session['idvisit'], $period, $dateRange);
- $session['numPageviews'] = count($session['pageviews']);
-
- return $session;
- }
-
- /**
- * Deletes all recorded page views within a recorded session.
- *
- * Once a recorded session has been deleted, the replay video will no longer be available in the UI and no data
- * can be retrieved anymore via the API.
- *
- * @param int $idSite
- * @param int $idSiteHsr The id of the session recording you want to delete the data.
- * @param int $idVisit The visitId of the recorded session you want to delete.
- */
- public function deleteRecordedSession($idSite, $idSiteHsr, $idVisit)
- {
- $this->validator->checkSessionReportWritePermission($idSite);
- // make sure the recording actually belongs to that site, otherwise could delete any recording for any other site
- $this->siteHsr->checkSessionRecordingExists($idSite, $idSiteHsr);
-
- // we also need to make sure the visit actually belongs to that site
- $idLogHsrs = $this->logHsr->findLogHsrIdsInVisit($idSite, $idVisit);
-
- foreach ($idLogHsrs as $idLogHsr) {
- $this->logHsrSite->unlinkRecord($idLogHsr, $idSiteHsr);
- }
- }
-
- /**
- * Deletes an individual page view within a recorded session.
- *
- * It only deletes one recorded session of one page view, not all recorded sessions.
- * Once a recorded page view has been deleted, the replay video will no longer be available in the UI and no data
- * can be retrieved anymore via the API for this page view.
- *
- * @param int $idSite
- * @param int $idSiteHsr The id of the session recording you want to delete the data.
- * @param int $idLogHsr The id of the recorded session you want to delete.
- */
- public function deleteRecordedPageview($idSite, $idSiteHsr, $idLogHsr)
- {
- $this->validator->checkWritePermission($idSite);
- // make sure the recording actually belongs to that site, otherwise could delete any recording for any other site
- $this->siteHsr->checkSessionRecordingExists($idSite, $idSiteHsr);
-
- $this->logHsrSite->unlinkRecord($idLogHsr, $idSiteHsr);
- }
-
- /**
- * Get metadata for a specific heatmap like the number of samples / pageviews that were recorded or the
- * average above the fold per device type.
- *
- * @param int $idSite
- * @param string $period
- * @param string $date
- * @param int $idSiteHsr The id of the heatmap you want to retrieve the meta data for.
- * @param bool|string $segment
- * @return array
- */
- public function getRecordedHeatmapMetadata($idSite, $period, $date, $idSiteHsr, $segment = false)
- {
- $this->validator->checkHeatmapReportViewPermission($idSite);
- $this->siteHsr->checkHeatmapExists($idSite, $idSiteHsr);
-
- $samples = $this->aggregator->getRecordedHeatmapMetadata($idSiteHsr, $idSite, $period, $date, $segment);
-
- $result = array('nb_samples_device_all' => 0);
-
- foreach ($samples as $sample) {
- $result['nb_samples_device_' . $sample['device_type']] = $sample['value'];
- $result['avg_fold_device_' . $sample['device_type']] = round(($sample['avg_fold'] / LogHsr::SCROLL_ACCURACY) * 100, 1);
- $result['nb_samples_device_all'] += $sample['value'];
- }
-
- return $result;
- }
-
- /**
- * Get all activities of a heatmap.
- *
- * For example retrieve all mouse movements made by desktop visitors, or all clicks made my tablet visitors, or
- * all scrolls by mobile users. It is recommended to call this method with filter_limit = -1 to retrieve all
- * results. As there can be many results, you may want to call this method several times using filter_limit and
- * filter_offset.
- *
- * @param int $idSite
- * @param string $period
- * @param string $date
- * @param int $idSiteHsr The id of the heatmap you want to retrieve the data for.
- * @param int $heatmapType To see which heatmap types can be used, call {@link getAvailableHeatmapTypes()}
- * @param int $deviceType To see which device types can be used, call {@link getAvailableDeviceTypes()}
- * @param bool|string $segment
- * @return array
- */
- public function getRecordedHeatmap($idSite, $period, $date, $idSiteHsr, $heatmapType, $deviceType, $segment = false)
- {
- $this->validator->checkHeatmapReportViewPermission($idSite);
- $this->siteHsr->checkHeatmapExists($idSite, $idSiteHsr);
-
- if ($heatmapType == RequestProcessor::EVENT_TYPE_SCROLL) {
- $heatmap = $this->aggregator->aggregateScrollHeatmap($idSiteHsr, $deviceType, $idSite, $period, $date, $segment);
- } else {
- $heatmap = $this->aggregator->aggregateHeatmap($idSiteHsr, $heatmapType, $deviceType, $idSite, $period, $date, $segment);
- }
-
- // we do not return dataTable here as it doubles the time it takes to call this method (eg 4s vs 7s when heaps of data)
- // datatable is not really needed here as we don't want to sort it or so
- return $heatmap;
- }
-
- /**
- * @param $idSite
- * @param $idSiteHsr
- * @param $idLogHsr
- * @return array
- * @hide
- */
- public function getEmbedSessionInfo($idSite, $idSiteHsr, $idLogHsr)
- {
- $this->validator->checkSessionReportViewPermission($idSite);
-
- $aggregator = new Aggregator();
- return $aggregator->getEmbedSessionInfo($idSite, $idSiteHsr, $idLogHsr);
- }
-
- /**
- * Tests, checks whether the given URL matches the given page rules.
- *
- * This can be used before configuring a heatmap or session recording to make sure the configured target page(s)
- * will match a specific URL.
- *
- * @param string $url
- * @param array $matchPageRules
- * @return array
- * @throws Exception
- */
- public function testUrlMatchPages($url, $matchPageRules = array())
- {
- $this->validator->checkHasSomeWritePermission();
-
- if ($url === '' || $url === false || $url === null) {
- return array('url' => '', 'matches' => false);
- }
-
- if (!empty($matchPageRules) && !is_array($matchPageRules)) {
- throw new Exception(Piwik::translate('HeatmapSessionRecording_ErrorNotAnArray', 'matchPageRules'));
- }
-
- $url = Common::unsanitizeInputValue($url);
-
- if (!empty($matchPageRules)) {
- $pageRules = new PageRules($matchPageRules, '', $needsOneEntry = false);
- $pageRules->check();
- }
-
- $matchPageRules = $this->unsanitizePageRules($matchPageRules);
-
- $allMatch = HsrMatcher::matchesAllPageRules($matchPageRules, $url);
-
- return array('url' => $url, 'matches' => $allMatch);
- }
-
- /**
- * Get a list of valid heatmap and session recording statuses (eg "active", "ended")
- *
- * @return array
- */
- public function getAvailableStatuses()
- {
- $this->validator->checkHasSomeWritePermission();
-
- return array(
- array('value' => SiteHsrDao::STATUS_ACTIVE, 'name' => Piwik::translate('HeatmapSessionRecording_StatusActive')),
- array('value' => SiteHsrDao::STATUS_ENDED, 'name' => Piwik::translate('HeatmapSessionRecording_StatusEnded')),
- );
- }
-
- /**
- * Get a list of all available target attributes and target types for "pageTargets" / "page rules".
- *
- * For example URL, URL Parameter, Path, simple comparison, contains, starts with, and more.
- *
- * @return array
- */
- public function getAvailableTargetPageRules()
- {
- $this->validator->checkHasSomeWritePermission();
-
- return PageRuleMatcher::getAvailableTargetTypes();
- }
-
- /**
- * Get a list of available device types that can be used when fetching a heatmap report.
- *
- * For example desktop, tablet, mobile.
- *
- * @return array
- */
- public function getAvailableDeviceTypes()
- {
- Piwik::checkUserHasSomeViewAccess();
-
- return array(
- array('name' => Piwik::translate('General_Desktop'),
- 'key' => LogHsr::DEVICE_TYPE_DESKTOP,
- 'logo' => 'plugins/Morpheus/icons/dist/devices/desktop.png'),
- array('name' => Piwik::translate('DevicesDetection_Tablet'),
- 'key' => LogHsr::DEVICE_TYPE_TABLET,
- 'logo' => 'plugins/Morpheus/icons/dist/devices/tablet.png'),
- array('name' => Piwik::translate('General_Mobile'),
- 'key' => LogHsr::DEVICE_TYPE_MOBILE,
- 'logo' => 'plugins/Morpheus/icons/dist/devices/smartphone.png'),
- );
- }
-
- /**
- * Get a list of available heatmap types that can be used when fetching a heatmap report.
- *
- * For example click, mouse move, scroll.
- *
- * @return array
- */
- public function getAvailableHeatmapTypes()
- {
- Piwik::checkUserHasSomeViewAccess();
-
- return array(
- array(
- 'name' => Piwik::translate('HeatmapSessionRecording_ActivityClick'),
- 'key' => RequestProcessor::EVENT_TYPE_CLICK),
- array(
- 'name' => Piwik::translate('HeatmapSessionRecording_ActivityMove'),
- 'key' => RequestProcessor::EVENT_TYPE_MOVEMENT),
- array(
- 'name' => Piwik::translate('HeatmapSessionRecording_ActivityScroll'),
- 'key' => RequestProcessor::EVENT_TYPE_SCROLL),
- );
- }
-
- /**
- * Get a list of available session recording sample limits.
- *
- * Note: This is only a suggested list of sample limits that should be shown in the UI when creating or editing a
- * session recording. When you configure a session recording via the API directly, any limit can be used.
- *
- * For example 50, 100, 200, 500
- *
- * @return array
- */
- public function getAvailableSessionRecordingSampleLimits()
- {
- $this->validator->checkHasSomeWritePermission();
- $this->validator->checkSessionRecordingEnabled();
-
- return $this->configuration->getSessionRecordingSampleLimits();
- }
-
- /**
- * Get a list of available event types that may be returned eg when fetching a recorded session.
- *
- * @return array
- */
- public function getEventTypes()
- {
- Piwik::checkUserHasSomeViewAccess();
-
- return array(
- array(
- 'name' => Piwik::translate('HeatmapSessionRecording_ActivityMove'),
- 'key' => RequestProcessor::EVENT_TYPE_MOVEMENT),
- array(
- 'name' => Piwik::translate('HeatmapSessionRecording_ActivityClick'),
- 'key' => RequestProcessor::EVENT_TYPE_CLICK),
- array(
- 'name' => Piwik::translate('HeatmapSessionRecording_ActivityScroll'),
- 'key' => RequestProcessor::EVENT_TYPE_SCROLL),
- array(
- 'name' => Piwik::translate('HeatmapSessionRecording_ActivityResize'),
- 'key' => RequestProcessor::EVENT_TYPE_RESIZE),
- array(
- 'name' => Piwik::translate('HeatmapSessionRecording_ActivityInitialDom'),
- 'key' => RequestProcessor::EVENT_TYPE_INITIAL_DOM),
- array(
- 'name' => Piwik::translate('HeatmapSessionRecording_ActivityPageChange'),
- 'key' => RequestProcessor::EVENT_TYPE_MUTATION),
- array(
- 'name' => Piwik::translate('HeatmapSessionRecording_ActivityFormText'),
- 'key' => RequestProcessor::EVENT_TYPE_FORM_TEXT),
- array(
- 'name' => Piwik::translate('HeatmapSessionRecording_ActivityFormValue'),
- 'key' => RequestProcessor::EVENT_TYPE_FORM_VALUE),
- array(
- 'name' => Piwik::translate('HeatmapSessionRecording_ActivityScrollElement'),
- 'key' => RequestProcessor::EVENT_TYPE_SCROLL_ELEMENT),
- );
- }
-}
diff --git a/files/plugin-HeatmapSessionRecording-5.2.6/Actions/ActionHsr.php b/files/plugin-HeatmapSessionRecording-5.2.6/Actions/ActionHsr.php
deleted file mode 100644
index 8eb7998..0000000
--- a/files/plugin-HeatmapSessionRecording-5.2.6/Actions/ActionHsr.php
+++ /dev/null
@@ -1,61 +0,0 @@
-getParam('url');
-
- $this->setActionUrl($url);
- }
-
- public static function shouldHandle(Request $request)
- {
- $params = $request->getParams();
- $isHsrRequest = Common::getRequestVar(RequestProcessor::TRACKING_PARAM_HSR_ID_VIEW, '', 'string', $params);
-
- return !empty($isHsrRequest);
- }
-
- protected function getActionsToLookup()
- {
- return array();
- }
-
- // Do not track this Event URL as Entry/Exit Page URL (leave the existing entry/exit)
- public function getIdActionUrlForEntryAndExitIds()
- {
- return false;
- }
-
- // Do not track this Event Name as Entry/Exit Page Title (leave the existing entry/exit)
- public function getIdActionNameForEntryAndExitIds()
- {
- return false;
- }
-}
diff --git a/files/plugin-HeatmapSessionRecording-5.2.6/Activity/BaseActivity.php b/files/plugin-HeatmapSessionRecording-5.2.6/Activity/BaseActivity.php
deleted file mode 100644
index daac776..0000000
--- a/files/plugin-HeatmapSessionRecording-5.2.6/Activity/BaseActivity.php
+++ /dev/null
@@ -1,114 +0,0 @@
- $this->getSiteData($idSite),
- 'version' => 'v1',
- 'hsr' => $this->getHsrData($idSiteHsr, $idSite),
- );
- }
-
- private function getSiteData($idSite)
- {
- return array(
- 'site_id' => $idSite,
- 'site_name' => Site::getNameFor($idSite)
- );
- }
-
- private function getHsrData($idSiteHsr, $idSite)
- {
- $dao = $this->getDao();
- $hsr = $dao->getRecord($idSite, $idSiteHsr, SiteHsrDao::RECORD_TYPE_HEATMAP);
- if (empty($hsr)) {
- // maybe it is a session? we could make this faster by adding a new method to DAO that returns hsr independent of type
- $hsr = $dao->getRecord($idSite, $idSiteHsr, SiteHsrDao::RECORD_TYPE_SESSION);
- }
-
- $hsrName = '';
- if (!empty($hsr['name'])) {
- // hsr name might not be set when we are handling deleteExperiment activity
- $hsrName = $hsr['name'];
- }
-
- return array(
- 'id' => $idSiteHsr,
- 'name' => $hsrName
- );
- }
-
- public function getPerformingUser($eventData = null)
- {
- $login = Piwik::getCurrentUserLogin();
-
- if ($login === self::USER_ANONYMOUS || empty($login)) {
- // anonymous cannot change an experiment, in this case the system changed it, eg during tracking it started
- // an experiment
- return self::USER_SYSTEM;
- }
-
- return $login;
- }
-
- private function getDao()
- {
- // we do not get it via DI as it would slow down creation of all activities on all requests. Instead only
- // create instance when needed
- return StaticContainer::get('Piwik\Plugins\HeatmapSessionRecording\Dao\SiteHsrDao');
- }
-}
diff --git a/files/plugin-HeatmapSessionRecording-5.2.6/Activity/HeatmapAdded.php b/files/plugin-HeatmapSessionRecording-5.2.6/Activity/HeatmapAdded.php
deleted file mode 100644
index ad04966..0000000
--- a/files/plugin-HeatmapSessionRecording-5.2.6/Activity/HeatmapAdded.php
+++ /dev/null
@@ -1,41 +0,0 @@
-formatActivityData($idSiteHsr, $idSite);
- }
-
- public function getTranslatedDescription($activityData, $performingUser)
- {
- $siteName = $this->getSiteNameFromActivityData($activityData);
- $hsrName = $this->getHsrNameFromActivityData($activityData);
-
- return Piwik::translate('HeatmapSessionRecording_HeatmapAddedActivity', [$hsrName, $siteName]);
- }
-}
diff --git a/files/plugin-HeatmapSessionRecording-5.2.6/Activity/HeatmapDeleted.php b/files/plugin-HeatmapSessionRecording-5.2.6/Activity/HeatmapDeleted.php
deleted file mode 100644
index fae6d25..0000000
--- a/files/plugin-HeatmapSessionRecording-5.2.6/Activity/HeatmapDeleted.php
+++ /dev/null
@@ -1,46 +0,0 @@
-formatActivityData($idSiteHsr, $idSite);
- }
-
- public function getTranslatedDescription($activityData, $performingUser)
- {
- $siteName = $this->getSiteNameFromActivityData($activityData);
- $hsrName = $this->getHsrNameFromActivityData($activityData);
-
- return Piwik::translate('HeatmapSessionRecording_HeatmapDeletedActivity', [$hsrName, $siteName]);
- }
-}
diff --git a/files/plugin-HeatmapSessionRecording-5.2.6/Activity/HeatmapEnded.php b/files/plugin-HeatmapSessionRecording-5.2.6/Activity/HeatmapEnded.php
deleted file mode 100644
index 28afe54..0000000
--- a/files/plugin-HeatmapSessionRecording-5.2.6/Activity/HeatmapEnded.php
+++ /dev/null
@@ -1,44 +0,0 @@
-formatActivityData($idSiteHsr, $idSite);
- }
-
- public function getTranslatedDescription($activityData, $performingUser)
- {
- $siteName = $this->getSiteNameFromActivityData($activityData);
- $hsrName = $this->getHsrNameFromActivityData($activityData);
-
- return Piwik::translate('HeatmapSessionRecording_HeatmapEndedActivity', [$hsrName, $siteName]);
- }
-}
diff --git a/files/plugin-HeatmapSessionRecording-5.2.6/Activity/HeatmapPaused.php b/files/plugin-HeatmapSessionRecording-5.2.6/Activity/HeatmapPaused.php
deleted file mode 100644
index ddacfb5..0000000
--- a/files/plugin-HeatmapSessionRecording-5.2.6/Activity/HeatmapPaused.php
+++ /dev/null
@@ -1,46 +0,0 @@
-formatActivityData($idSiteHsr, $idSite);
- }
-
- public function getTranslatedDescription($activityData, $performingUser)
- {
- $siteName = $this->getSiteNameFromActivityData($activityData);
- $hsrName = $this->getHsrNameFromActivityData($activityData);
-
- return Piwik::translate('HeatmapSessionRecording_HeatmapPausedActivity', [$hsrName, $siteName]);
- }
-}
diff --git a/files/plugin-HeatmapSessionRecording-5.2.6/Activity/HeatmapResumed.php b/files/plugin-HeatmapSessionRecording-5.2.6/Activity/HeatmapResumed.php
deleted file mode 100644
index 9062306..0000000
--- a/files/plugin-HeatmapSessionRecording-5.2.6/Activity/HeatmapResumed.php
+++ /dev/null
@@ -1,46 +0,0 @@
-formatActivityData($idSiteHsr, $idSite);
- }
-
- public function getTranslatedDescription($activityData, $performingUser)
- {
- $siteName = $this->getSiteNameFromActivityData($activityData);
- $hsrName = $this->getHsrNameFromActivityData($activityData);
-
- return Piwik::translate('HeatmapSessionRecording_HeatmapResumedActivity', [$hsrName, $siteName]);
- }
-}
diff --git a/files/plugin-HeatmapSessionRecording-5.2.6/Activity/HeatmapScreenshotDeleted.php b/files/plugin-HeatmapSessionRecording-5.2.6/Activity/HeatmapScreenshotDeleted.php
deleted file mode 100644
index 4275d16..0000000
--- a/files/plugin-HeatmapSessionRecording-5.2.6/Activity/HeatmapScreenshotDeleted.php
+++ /dev/null
@@ -1,46 +0,0 @@
-formatActivityData($idSiteHsr, $idSite);
- }
-
- public function getTranslatedDescription($activityData, $performingUser)
- {
- $siteName = $this->getSiteNameFromActivityData($activityData);
- $hsrName = $this->getHsrNameFromActivityData($activityData);
-
- return Piwik::translate('HeatmapSessionRecording_HeatmapScreenshotDeletedActivity', [$hsrName, $siteName]);
- }
-}
diff --git a/files/plugin-HeatmapSessionRecording-5.2.6/Activity/HeatmapUpdated.php b/files/plugin-HeatmapSessionRecording-5.2.6/Activity/HeatmapUpdated.php
deleted file mode 100644
index 16b0636..0000000
--- a/files/plugin-HeatmapSessionRecording-5.2.6/Activity/HeatmapUpdated.php
+++ /dev/null
@@ -1,42 +0,0 @@
-formatActivityData($idSiteHsr, $idSite);
- }
-
- public function getTranslatedDescription($activityData, $performingUser)
- {
- $siteName = $this->getSiteNameFromActivityData($activityData);
- $hsrName = $this->getHsrNameFromActivityData($activityData);
-
- return Piwik::translate('HeatmapSessionRecording_HeatmapUpdatedActivity', [$hsrName, $siteName]);
- }
-}
diff --git a/files/plugin-HeatmapSessionRecording-5.2.6/Activity/RecordedPageviewDeleted.php b/files/plugin-HeatmapSessionRecording-5.2.6/Activity/RecordedPageviewDeleted.php
deleted file mode 100644
index 0c608b3..0000000
--- a/files/plugin-HeatmapSessionRecording-5.2.6/Activity/RecordedPageviewDeleted.php
+++ /dev/null
@@ -1,46 +0,0 @@
-formatActivityData($idSiteHsr, $idSite);
- }
-
- public function getTranslatedDescription($activityData, $performingUser)
- {
- $siteName = $this->getSiteNameFromActivityData($activityData);
- $hsrName = $this->getHsrNameFromActivityData($activityData);
-
- return Piwik::translate('HeatmapSessionRecording_RecordedPageviewDeletedActivity', [$hsrName, $siteName]);
- }
-}
diff --git a/files/plugin-HeatmapSessionRecording-5.2.6/Activity/RecordedSessionDeleted.php b/files/plugin-HeatmapSessionRecording-5.2.6/Activity/RecordedSessionDeleted.php
deleted file mode 100644
index 0eb581a..0000000
--- a/files/plugin-HeatmapSessionRecording-5.2.6/Activity/RecordedSessionDeleted.php
+++ /dev/null
@@ -1,46 +0,0 @@
-formatActivityData($idSiteHsr, $idSite);
- }
-
- public function getTranslatedDescription($activityData, $performingUser)
- {
- $siteName = $this->getSiteNameFromActivityData($activityData);
- $hsrName = $this->getHsrNameFromActivityData($activityData);
-
- return Piwik::translate('HeatmapSessionRecording_RecordedSessionDeletedActivity', [$hsrName, $siteName]);
- }
-}
diff --git a/files/plugin-HeatmapSessionRecording-5.2.6/Activity/SessionRecordingAdded.php b/files/plugin-HeatmapSessionRecording-5.2.6/Activity/SessionRecordingAdded.php
deleted file mode 100644
index 6178a0e..0000000
--- a/files/plugin-HeatmapSessionRecording-5.2.6/Activity/SessionRecordingAdded.php
+++ /dev/null
@@ -1,41 +0,0 @@
-formatActivityData($idSiteHsr, $idSite);
- }
-
- public function getTranslatedDescription($activityData, $performingUser)
- {
- $siteName = $this->getSiteNameFromActivityData($activityData);
- $hsrName = $this->getHsrNameFromActivityData($activityData);
-
- return Piwik::translate('HeatmapSessionRecording_SessionRecordingAddedActivity', [$hsrName, $siteName]);
- }
-}
diff --git a/files/plugin-HeatmapSessionRecording-5.2.6/Activity/SessionRecordingDeleted.php b/files/plugin-HeatmapSessionRecording-5.2.6/Activity/SessionRecordingDeleted.php
deleted file mode 100644
index 2f35f7f..0000000
--- a/files/plugin-HeatmapSessionRecording-5.2.6/Activity/SessionRecordingDeleted.php
+++ /dev/null
@@ -1,46 +0,0 @@
-formatActivityData($idSiteHsr, $idSite);
- }
-
- public function getTranslatedDescription($activityData, $performingUser)
- {
- $siteName = $this->getSiteNameFromActivityData($activityData);
- $hsrName = $this->getHsrNameFromActivityData($activityData);
-
- return Piwik::translate('HeatmapSessionRecording_SessionRecordingDeletedActivity', [$hsrName, $siteName]);
- }
-}
diff --git a/files/plugin-HeatmapSessionRecording-5.2.6/Activity/SessionRecordingEnded.php b/files/plugin-HeatmapSessionRecording-5.2.6/Activity/SessionRecordingEnded.php
deleted file mode 100644
index dfd0df0..0000000
--- a/files/plugin-HeatmapSessionRecording-5.2.6/Activity/SessionRecordingEnded.php
+++ /dev/null
@@ -1,44 +0,0 @@
-formatActivityData($idSiteHsr, $idSite);
- }
-
- public function getTranslatedDescription($activityData, $performingUser)
- {
- $siteName = $this->getSiteNameFromActivityData($activityData);
- $hsrName = $this->getHsrNameFromActivityData($activityData);
-
- return Piwik::translate('HeatmapSessionRecording_SessionRecordingEndedActivity', [$hsrName, $siteName]);
- }
-}
diff --git a/files/plugin-HeatmapSessionRecording-5.2.6/Activity/SessionRecordingPaused.php b/files/plugin-HeatmapSessionRecording-5.2.6/Activity/SessionRecordingPaused.php
deleted file mode 100644
index 7b376fd..0000000
--- a/files/plugin-HeatmapSessionRecording-5.2.6/Activity/SessionRecordingPaused.php
+++ /dev/null
@@ -1,46 +0,0 @@
-formatActivityData($idSiteHsr, $idSite);
- }
-
- public function getTranslatedDescription($activityData, $performingUser)
- {
- $siteName = $this->getSiteNameFromActivityData($activityData);
- $hsrName = $this->getHsrNameFromActivityData($activityData);
-
- return Piwik::translate('HeatmapSessionRecording_SessionRecordingPausedActivity', [$hsrName, $siteName]);
- }
-}
diff --git a/files/plugin-HeatmapSessionRecording-5.2.6/Activity/SessionRecordingResumed.php b/files/plugin-HeatmapSessionRecording-5.2.6/Activity/SessionRecordingResumed.php
deleted file mode 100644
index b89500d..0000000
--- a/files/plugin-HeatmapSessionRecording-5.2.6/Activity/SessionRecordingResumed.php
+++ /dev/null
@@ -1,46 +0,0 @@
-formatActivityData($idSiteHsr, $idSite);
- }
-
- public function getTranslatedDescription($activityData, $performingUser)
- {
- $siteName = $this->getSiteNameFromActivityData($activityData);
- $hsrName = $this->getHsrNameFromActivityData($activityData);
-
- return Piwik::translate('HeatmapSessionRecording_SessionRecordingResumedActivity', [$hsrName, $siteName]);
- }
-}
diff --git a/files/plugin-HeatmapSessionRecording-5.2.6/Activity/SessionRecordingUpdated.php b/files/plugin-HeatmapSessionRecording-5.2.6/Activity/SessionRecordingUpdated.php
deleted file mode 100644
index fd35fa1..0000000
--- a/files/plugin-HeatmapSessionRecording-5.2.6/Activity/SessionRecordingUpdated.php
+++ /dev/null
@@ -1,42 +0,0 @@
-formatActivityData($idSiteHsr, $idSite);
- }
-
- public function getTranslatedDescription($activityData, $performingUser)
- {
- $siteName = $this->getSiteNameFromActivityData($activityData);
- $hsrName = $this->getHsrNameFromActivityData($activityData);
-
- return Piwik::translate('HeatmapSessionRecording_SessionRecordingUpdatedActivity', [$hsrName, $siteName]);
- }
-}
diff --git a/files/plugin-HeatmapSessionRecording-5.2.6/Archiver/Aggregator.php b/files/plugin-HeatmapSessionRecording-5.2.6/Archiver/Aggregator.php
deleted file mode 100644
index bc15cef..0000000
--- a/files/plugin-HeatmapSessionRecording-5.2.6/Archiver/Aggregator.php
+++ /dev/null
@@ -1,476 +0,0 @@
-forceSleepInQuery) {
- $extraWhere = 'SLEEP(1) AND';
- }
-
- $query = sprintf(
- 'SELECT /* HeatmapSessionRecording.findRecording */ hsrsite.idsitehsr,
- min(hsr.idloghsr) as idloghsr
- FROM %s hsr
- LEFT JOIN %s hsrsite ON hsr.idloghsr = hsrsite.idloghsr
- LEFT JOIN %s hsrevent ON hsrevent.idloghsr = hsr.idloghsr and hsrevent.event_type = %s
- LEFT JOIN %s sitehsr ON hsrsite.idsitehsr = sitehsr.idsitehsr
- WHERE %s hsr.idvisit = ? and sitehsr.record_type = ? and hsrevent.idhsrblob is not null and hsrsite.idsitehsr is not null
- GROUP BY hsrsite.idsitehsr
- LIMIT 1',
- Common::prefixTable('log_hsr'),
- Common::prefixTable('log_hsr_site'),
- Common::prefixTable('log_hsr_event'),
- RequestProcessor::EVENT_TYPE_INITIAL_DOM,
- Common::prefixTable('site_hsr'),
- $extraWhere
- );
-
- $readerDb = $this->getDbReader();
- $query = DbHelper::addMaxExecutionTimeHintToQuery($query, $this->getLiveQueryMaxExecutionTime());
-
- try {
- return $readerDb->fetchRow($query, array($idVisit, SiteHsrDao::RECORD_TYPE_SESSION));
- } catch (\Exception $e) {
- Model::handleMaxExecutionTimeError($readerDb, $e, '', Date::now(), Date::now(), null, 0, ['sql' => $query]);
- throw $e;
- }
- }
-
- private function getDbReader()
- {
- if (method_exists(Db::class, 'getReader')) {
- return Db::getReader();
- } else {
- return Db::get();
- }
- }
-
- public function findRecordings($visitIds)
- {
- if (empty($visitIds)) {
- return array();
- }
-
- $visitIds = array_map('intval', $visitIds);
-
- $extraWhere = '';
- if ($this->forceSleepInQuery) {
- $extraWhere = 'SLEEP(1) AND';
- }
-
- $query = sprintf(
- 'SELECT /* HeatmapSessionRecording.findRecordings */ hsrsite.idsitehsr,
- min(hsr.idloghsr) as idloghsr,
- hsr.idvisit
- FROM %s hsr
- LEFT JOIN %s hsrsite ON hsr.idloghsr = hsrsite.idloghsr
- LEFT JOIN %s hsrevent ON hsrevent.idloghsr = hsr.idloghsr and hsrevent.event_type = %s
- LEFT JOIN %s sitehsr ON hsrsite.idsitehsr = sitehsr.idsitehsr
- WHERE %s hsr.idvisit IN ("%s") and sitehsr.record_type = ? and hsrevent.idhsrblob is not null and hsrsite.idsitehsr is not null
- GROUP BY hsr.idvisit, hsrsite.idsitehsr',
- Common::prefixTable('log_hsr'),
- Common::prefixTable('log_hsr_site'),
- Common::prefixTable('log_hsr_event'),
- RequestProcessor::EVENT_TYPE_INITIAL_DOM,
- Common::prefixTable('site_hsr'),
- $extraWhere,
- implode('","', $visitIds)
- );
-
- $readerDb = $this->getDbReader();
- $query = DbHelper::addMaxExecutionTimeHintToQuery($query, $this->getLiveQueryMaxExecutionTime());
-
- try {
- return $readerDb->fetchAll($query, array(SiteHsrDao::RECORD_TYPE_SESSION));
- } catch (\Exception $e) {
- Model::handleMaxExecutionTimeError($readerDb, $e, '', Date::now(), Date::now(), null, 0, ['sql' => $query]);
- throw $e;
- }
- }
-
- private function getLiveQueryMaxExecutionTime()
- {
- return Config::getInstance()->General['live_query_max_execution_time'];
- }
-
- public function getEmbedSessionInfo($idSite, $idSiteHsr, $idLogHsr)
- {
- $logHsr = Common::prefixTable('log_hsr');
- $logHsrSite = Common::prefixTable('log_hsr_site');
- $logAction = Common::prefixTable('log_action');
- $logEvent = Common::prefixTable('log_hsr_event');
- $logBlob = Common::prefixTable('log_hsr_blob');
-
- $query = sprintf(
- 'SELECT laction.name as base_url,
- laction.url_prefix, hsrblob.`value` as initial_mutation, hsrblob.compressed
- FROM %s hsr
- LEFT JOIN %s laction ON laction.idaction = hsr.idaction_url
- LEFT JOIN %s hsr_site ON hsr_site.idloghsr = hsr.idloghsr
- LEFT JOIN %s hsrevent ON hsrevent.idloghsr = hsr.idloghsr and hsrevent.event_type = %s
- LEFT JOIN %s hsrblob ON hsrevent.idhsrblob = hsrblob.idhsrblob
- WHERE hsr.idloghsr = ? and hsr.idsite = ? and hsr_site.idsitehsr = ?
- and hsrevent.idhsrblob is not null and `hsrblob`.`value` is not null
- LIMIT 1',
- $logHsr,
- $logAction,
- $logHsrSite,
- $logEvent,
- RequestProcessor::EVENT_TYPE_INITIAL_DOM,
- $logBlob
- );
-
- $row = $this->getDbReader()->fetchRow($query, array($idLogHsr, $idSite, $idSiteHsr));
-
- if (!empty($row['compressed'])) {
- $row['initial_mutation'] = gzuncompress($row['initial_mutation']);
- }
-
- return $row;
- }
-
- public function getRecordedSession($idLogHsr)
- {
- $select = 'log_action.name as url,
- log_visit.idvisit,
- log_visit.idvisitor,
- log_hsr.idsite,
- log_visit.location_country,
- log_visit.location_region,
- log_visit.location_city,
- log_visit.config_os,
- log_visit.config_device_type,
- log_visit.config_device_model,
- log_visit.config_browser_name,
- log_hsr.time_on_page,
- log_hsr.server_time,
- log_hsr.viewport_w_px,
- log_hsr.viewport_h_px,
- log_hsr.scroll_y_max_relative,
- log_hsr.fold_y_relative';
-
- $logHsr = Common::prefixTable('log_hsr');
- $logVisit = Common::prefixTable('log_visit');
- $logAction = Common::prefixTable('log_action');
-
- $query = sprintf('SELECT %s
- FROM %s log_hsr
- LEFT JOIN %s log_visit ON log_hsr.idvisit = log_visit.idvisit
- LEFT JOIN %s log_action ON log_action.idaction = log_hsr.idaction_url
- WHERE log_hsr.idloghsr = ?', $select, $logHsr, $logVisit, $logAction);
-
- return $this->getDbReader()->fetchRow($query, array($idLogHsr));
- }
-
- public function getRecordedSessions($idSite, $idSiteHsr, $period, $date, $segment)
- {
- $period = Period\Factory::build($period, $date);
- $segment = new Segment($segment, array($idSite));
- $site = new Site($idSite);
-
- $from = array(
- 'log_hsr',
- array(
- 'table' => 'log_hsr_site',
- 'joinOn' => 'log_hsr_site.idloghsr = log_hsr.idloghsr'
- ),
- array(
- 'table' => 'log_visit',
- 'joinOn' => 'log_visit.idvisit = log_hsr.idvisit'
- ),
- array(
- 'table' => 'log_action',
- 'joinOn' => 'log_action.idaction = log_hsr.idaction_url'
- ),
- array(
- 'table' => 'log_hsr_event',
- 'joinOn' => 'log_hsr_event.idloghsr = log_hsr.idloghsr and log_hsr_event.event_type = ' . RequestProcessor::EVENT_TYPE_INITIAL_DOM
- )
- );
-
- // we need to make sure to show only sessions that have an initial mutation with time_since_load = 0, otherwise
- // the recording won't work.
- $logHsrEventTable = Common::prefixTable('log_hsr_event');
-
- $actionQuery = sprintf('SELECT count(*) FROM %1$s as hsr_ev
- WHERE hsr_ev.idloghsr = log_hsr_site.idloghsr and hsr_ev.event_type not in (%2$s, %3$s)', $logHsrEventTable, RequestProcessor::EVENT_TYPE_CSS, RequestProcessor::EVENT_TYPE_INITIAL_DOM);
-
- $select = 'log_hsr.idvisit as label,
- count(*) as nb_pageviews,
- log_hsr.idvisit,
- SUBSTRING_INDEX(GROUP_CONCAT(CAST(log_action.name AS CHAR) ORDER BY log_hsr.server_time ASC SEPARATOR \'##\'), \'##\', 1) as first_url,
- SUBSTRING_INDEX(GROUP_CONCAT(CAST(log_action.name AS CHAR) ORDER BY log_hsr.server_time DESC SEPARATOR \'##\'), \'##\', 1) as last_url,
- sum(log_hsr.time_on_page) as time_on_site,
- (' . $actionQuery . ') as total_events,
- min(log_hsr_site.idloghsr) as idloghsr,
- log_visit.idvisitor,
- log_visit.location_country,
- log_visit.location_region,
- log_visit.location_city,
- log_visit.config_os,
- log_visit.config_device_type,
- log_visit.config_device_model,
- log_visit.config_browser_name,
- min(log_hsr.server_time) as server_time';
-
- $params = new ArchiveProcessor\Parameters($site, $period, $segment);
- $logAggregator = new LogAggregator($params);
-
- $where = $logAggregator->getWhereStatement('log_hsr', 'server_time');
- $where .= sprintf(" and log_hsr_site.idsitehsr = %d and log_hsr_event.idhsrblob is not null", (int) $idSiteHsr);
- $groupBy = 'log_hsr.idvisit';
- $orderBy = 'log_hsr.server_time DESC';
-
- $revertSubselect = $this->applyForceSubselect($segment, 'log_hsr.idvisit,log_hsr_site.idloghsr');
-
- $query = $logAggregator->generateQuery($select, $from, $where, $groupBy, $orderBy);
-
- if (!empty($revertSubselect) && is_callable($revertSubselect)) {
- call_user_func($revertSubselect);
- }
-
- $dbReader = $this->getDbReader();
- $query['sql'] = DbHelper::addMaxExecutionTimeHintToQuery($query['sql'], $this->getLiveQueryMaxExecutionTime());
-
- try {
- return $dbReader->fetchAll($query['sql'], $query['bind']);
- } catch (\Exception $e) {
- Model::handleMaxExecutionTimeError($dbReader, $e, '', Date::now(), Date::now(), null, 0, $query);
- throw $e;
- }
- }
-
- private function applyForceSubselect($segment, $subselectForced)
- {
- // for performance reasons we use this and not `LogAggregator->allowUsageSegmentCache()`
- // That's because this is a LIVE query and not archived... and HSR tables usually have few entries < 5000
- // so segmentation should be fairly fast using this method compared to allowUsageSegmentCache
- // which would query the entire log_visit over several days with the applied query and then create the temp table
- // and only then apply the log_hsr query.
- // it should be a lot faster this way
- if (class_exists('Piwik\DataAccess\LogQueryBuilder') && !$segment->isEmpty()) {
- $logQueryBuilder = StaticContainer::get('Piwik\DataAccess\LogQueryBuilder');
- if (
- method_exists($logQueryBuilder, 'getForcedInnerGroupBySubselect') &&
- method_exists($logQueryBuilder, 'forceInnerGroupBySubselect')
- ) {
- $forceGroupByBackup = $logQueryBuilder->getForcedInnerGroupBySubselect();
- $logQueryBuilder->forceInnerGroupBySubselect($subselectForced);
-
- return function () use ($forceGroupByBackup, $logQueryBuilder) {
- $logQueryBuilder->forceInnerGroupBySubselect($forceGroupByBackup);
- };
- }
- }
- }
-
- public function getRecordedPageViewsInSession($idSite, $idSiteHsr, $idVisit, $period, $date, $segment)
- {
- $period = Period\Factory::build($period, $date);
- $segment = new Segment($segment, array($idSite));
- $site = new Site($idSite);
-
- $from = array(
- 'log_hsr',
- array(
- 'table' => 'log_hsr_site',
- 'joinOn' => 'log_hsr_site.idloghsr = log_hsr.idloghsr'
- ),
- array(
- 'table' => 'log_visit',
- 'joinOn' => 'log_visit.idvisit = log_hsr.idvisit'
- ),
- array(
- 'table' => 'log_action',
- 'joinOn' => 'log_action.idaction = log_hsr.idaction_url'
- ),
- array(
- 'table' => 'log_hsr_event',
- 'joinOn' => 'log_hsr_event.idloghsr = log_hsr.idloghsr and log_hsr_event.event_type = ' . RequestProcessor::EVENT_TYPE_INITIAL_DOM
- )
- );
-
- // we need to make sure to show only sessions that have an initial mutation with time_since_load = 0, otherwise
- // the recording won't work. If this happens often, we might "end / finish" a configured session recording
- // earlier since we have eg recorded 1000 sessions, but user sees only 950 which will be confusing but we can
- // for now not take this into consideration during tracking when we get number of available samples only using
- // log_hsr_site to detect if the number of configured sessions have been reached. ideally we would at some point
- // also make sure to include this check there but will be slower.
-
- $select = 'log_action.name as label,
- log_visit.idvisitor,
- log_hsr_site.idloghsr,
- log_hsr.time_on_page as time_on_page,
- CONCAT(log_hsr.viewport_w_px, "x", log_hsr.viewport_h_px) as resolution,
- log_hsr.server_time,
- log_hsr.scroll_y_max_relative,
- log_hsr.fold_y_relative';
-
- $params = new ArchiveProcessor\Parameters($site, $period, $segment);
- $logAggregator = new LogAggregator($params);
-
- $where = $logAggregator->getWhereStatement('log_hsr', 'server_time');
- $where .= sprintf(" and log_hsr_site.idsitehsr = %d and log_hsr.idvisit = %d and log_hsr_event.idhsrblob is not null ", (int) $idSiteHsr, (int) $idVisit);
- $groupBy = '';
- $orderBy = 'log_hsr.server_time ASC';
-
- $revertSubselect = $this->applyForceSubselect($segment, 'log_hsr.idvisit,log_hsr_site.idloghsr');
-
- $query = $logAggregator->generateQuery($select, $from, $where, $groupBy, $orderBy);
-
- if (!empty($revertSubselect) && is_callable($revertSubselect)) {
- call_user_func($revertSubselect);
- }
-
- return $this->getDbReader()->fetchAll($query['sql'], $query['bind']);
- }
-
- public function aggregateHeatmap($idSiteHsr, $heatmapType, $deviceType, $idSite, $period, $date, $segment)
- {
- $heatmapTypeWhere = '';
- if ($heatmapType == RequestProcessor::EVENT_TYPE_CLICK) {
- $heatmapTypeWhere .= 'log_hsr_event.event_type = ' . (int) $heatmapType;
- } elseif ($heatmapType == RequestProcessor::EVENT_TYPE_MOVEMENT) {
- $heatmapTypeWhere .= 'log_hsr_event.event_type IN(' . (int) RequestProcessor::EVENT_TYPE_MOVEMENT . ',' . (int) RequestProcessor::EVENT_TYPE_CLICK . ')';
- } else {
- throw new \Exception('Heatmap type not supported');
- }
-
- $period = Period\Factory::build($period, $date);
- $segment = new Segment($segment, array($idSite));
- $site = new Site($idSite);
-
- $from = array(
- 'log_hsr',
- array(
- 'table' => 'log_hsr_site',
- 'joinOn' => 'log_hsr_site.idloghsr = log_hsr.idloghsr'
- ),
- array(
- 'table' => 'log_hsr_event',
- 'joinOn' => 'log_hsr_site.idloghsr = log_hsr_event.idloghsr'
- ),
- array(
- 'table' => 'log_action',
- 'joinOn' => 'log_action.idaction = log_hsr_event.idselector'
- )
- );
-
- $select = 'log_action.name as selector,
- log_hsr_event.x as offset_x,
- log_hsr_event.y as offset_y,
- count(*) as value';
-
- $params = new ArchiveProcessor\Parameters($site, $period, $segment);
- $logAggregator = new LogAggregator($params);
-
- $where = $logAggregator->getWhereStatement('log_hsr', 'server_time');
- $where .= ' and log_hsr_site.idsitehsr = ' . (int) $idSiteHsr . ' and log_hsr_event.idselector is not null and ' . $heatmapTypeWhere;
- $where .= ' and log_hsr.device_type = ' . (int) $deviceType;
-
- $groupBy = 'log_hsr_event.idselector, log_hsr_event.x, log_hsr_event.y';
- $orderBy = '';
-
- $query = $logAggregator->generateQuery($select, $from, $where, $groupBy, $orderBy);
-
- return $this->getDbReader()->fetchAll($query['sql'], $query['bind']);
- }
-
- public function getRecordedHeatmapMetadata($idSiteHsr, $idSite, $period, $date, $segment)
- {
- $period = Period\Factory::build($period, $date);
- $segment = new Segment($segment, array($idSite));
- $site = new Site($idSite);
-
- $from = array(
- 'log_hsr',
- array(
- 'table' => 'log_hsr_site',
- 'joinOn' => 'log_hsr_site.idloghsr = log_hsr.idloghsr'
- )
- );
-
- $select = 'log_hsr.device_type, count(*) as value, avg(log_hsr.fold_y_relative) as avg_fold';
-
- $params = new ArchiveProcessor\Parameters($site, $period, $segment);
- $logAggregator = new LogAggregator($params);
-
- $where = $logAggregator->getWhereStatement('log_hsr', 'server_time');
- $where .= ' and log_hsr_site.idsitehsr = ' . (int) $idSiteHsr;
- $groupBy = 'log_hsr.device_type';
- $orderBy = '';
-
- $query = $logAggregator->generateQuery($select, $from, $where, $groupBy, $orderBy);
-
- return $this->getDbReader()->fetchAll($query['sql'], $query['bind']);
- }
-
- public function aggregateScrollHeatmap($idSiteHsr, $deviceType, $idSite, $period, $date, $segment)
- {
- $period = Period\Factory::build($period, $date);
- $segment = new Segment($segment, array($idSite));
- $site = new Site($idSite);
-
- $from = array('log_hsr',
- array(
- 'table' => 'log_hsr_site',
- 'joinOn' => 'log_hsr_site.idloghsr = log_hsr.idloghsr'
- ),
- );
-
- $select = 'log_hsr.scroll_y_max_relative as label,
- count(*) as value';
-
- $params = new ArchiveProcessor\Parameters($site, $period, $segment);
- $logAggregator = new LogAggregator($params);
- $where = $logAggregator->getWhereStatement('log_hsr', 'server_time');
- $where .= ' and log_hsr_site.idsitehsr = ' . (int) $idSiteHsr;
- $where .= ' and log_hsr.device_type = ' . (int) $deviceType;
-
- $groupBy = 'log_hsr.scroll_y_max_relative';
- $orderBy = 'label ASC'; // labels are no from 0-1000 i.e page from top to bottom, so top label should always come first 0..100..500..1000
-
- $query = $logAggregator->generateQuery($select, $from, $where, $groupBy, $orderBy);
-
- return $this->getDbReader()->fetchAll($query['sql'], $query['bind']);
- }
-}
diff --git a/files/plugin-HeatmapSessionRecording-5.2.6/Categories/HeatmapCategory.php b/files/plugin-HeatmapSessionRecording-5.2.6/Categories/HeatmapCategory.php
deleted file mode 100644
index 946c2ea..0000000
--- a/files/plugin-HeatmapSessionRecording-5.2.6/Categories/HeatmapCategory.php
+++ /dev/null
@@ -1,26 +0,0 @@
-' . Piwik::translate('HeatmapSessionRecording_ManageHeatmapSubcategoryHelp') . '';
- }
-}
diff --git a/files/plugin-HeatmapSessionRecording-5.2.6/Categories/ManageSessionRecordingSubcategory.php b/files/plugin-HeatmapSessionRecording-5.2.6/Categories/ManageSessionRecordingSubcategory.php
deleted file mode 100644
index fa5c615..0000000
--- a/files/plugin-HeatmapSessionRecording-5.2.6/Categories/ManageSessionRecordingSubcategory.php
+++ /dev/null
@@ -1,32 +0,0 @@
-' . Piwik::translate('HeatmapSessionRecording_ManageSessionRecordingSubcategoryHelp') . '';
- }
-}
diff --git a/files/plugin-HeatmapSessionRecording-5.2.6/Categories/SessionRecordingsCategory.php b/files/plugin-HeatmapSessionRecording-5.2.6/Categories/SessionRecordingsCategory.php
deleted file mode 100644
index f376af1..0000000
--- a/files/plugin-HeatmapSessionRecording-5.2.6/Categories/SessionRecordingsCategory.php
+++ /dev/null
@@ -1,26 +0,0 @@
-getMetric($row, 'config_browser_name');
- }
-
- public function getDependentMetrics()
- {
- return array(
- 'config_browser_name',
- );
- }
-
- public function showsHtml()
- {
- return true;
- }
-
- public function format($value, Formatter $formatter)
- {
- if (empty($value) || $value === 'UNK') {
- return false;
- }
-
- $title = \Piwik\Plugins\DevicesDetection\getBrowserName($value);
-
- return '';
- }
-}
diff --git a/files/plugin-HeatmapSessionRecording-5.2.6/Columns/Metrics/Device.php b/files/plugin-HeatmapSessionRecording-5.2.6/Columns/Metrics/Device.php
deleted file mode 100644
index c0c0c6b..0000000
--- a/files/plugin-HeatmapSessionRecording-5.2.6/Columns/Metrics/Device.php
+++ /dev/null
@@ -1,78 +0,0 @@
- $this->getMetric($row, 'config_device_type'),
- 'model' => $this->getMetric($row, 'config_device_model')
- );
- }
-
- public function getDependentMetrics()
- {
- return array(
- 'config_device_type',
- 'config_device_model',
- );
- }
-
- public function showsHtml()
- {
- return true;
- }
-
- public function format($value, Formatter $formatter)
- {
- if (empty($value['type']) && $value['type'] !== 0 && $value['type'] !== '0') {
- return false;
- }
-
- $title = \Piwik\Plugins\DevicesDetection\getDeviceTypeLabel($value['type']);
-
- if (!empty($value['model'])) {
- $title .= ', ' . SafeDecodeLabel::decodeLabelSafe($value['model']);
- }
-
- return '';
- }
-}
diff --git a/files/plugin-HeatmapSessionRecording-5.2.6/Columns/Metrics/Location.php b/files/plugin-HeatmapSessionRecording-5.2.6/Columns/Metrics/Location.php
deleted file mode 100644
index 671a658..0000000
--- a/files/plugin-HeatmapSessionRecording-5.2.6/Columns/Metrics/Location.php
+++ /dev/null
@@ -1,86 +0,0 @@
- $this->getMetric($row, 'location_country'),
- 'region' => $this->getMetric($row, 'location_region'),
- 'city' => $this->getMetric($row, 'location_city'),
- );
- }
-
- public function getDependentMetrics()
- {
- return array(
- 'location_country',
- 'location_region',
- 'location_city'
- );
- }
-
- public function showsHtml()
- {
- return true;
- }
-
- public function format($value, Formatter $formatter)
- {
- if (empty($value['country']) || $value['country'] === Visit::UNKNOWN_CODE) {
- return false;
- }
-
- $title = \Piwik\Plugins\UserCountry\countryTranslate($value['country']);
-
- if (!empty($value['region']) && $value['region'] !== Visit::UNKNOWN_CODE) {
- $title .= ', ' . \Piwik\Plugins\UserCountry\getRegionNameFromCodes($value['country'], $value['region']);
- }
-
- if (!empty($value['city'])) {
- $title .= ', ' . SafeDecodeLabel::decodeLabelSafe($value['city']);
- }
-
- return '';
- }
-}
diff --git a/files/plugin-HeatmapSessionRecording-5.2.6/Columns/Metrics/OperatingSystem.php b/files/plugin-HeatmapSessionRecording-5.2.6/Columns/Metrics/OperatingSystem.php
deleted file mode 100644
index d78691b..0000000
--- a/files/plugin-HeatmapSessionRecording-5.2.6/Columns/Metrics/OperatingSystem.php
+++ /dev/null
@@ -1,67 +0,0 @@
-getMetric($row, 'config_os');
- }
-
- public function getDependentMetrics()
- {
- return array(
- 'config_os',
- );
- }
-
- public function showsHtml()
- {
- return true;
- }
-
- public function format($value, Formatter $formatter)
- {
- if (empty($value) || $value === 'UNK') {
- return false;
- }
-
- $title = \Piwik\Plugins\DevicesDetection\getOsFullName($value);
-
- return '';
- }
-}
diff --git a/files/plugin-HeatmapSessionRecording-5.2.6/Columns/Metrics/SessionTime.php b/files/plugin-HeatmapSessionRecording-5.2.6/Columns/Metrics/SessionTime.php
deleted file mode 100644
index 0de98a4..0000000
--- a/files/plugin-HeatmapSessionRecording-5.2.6/Columns/Metrics/SessionTime.php
+++ /dev/null
@@ -1,97 +0,0 @@
-dateFormat = $dateFormat;
- }
-
- public function getName()
- {
- return 'server_time';
- }
-
- public function getTranslatedName()
- {
- return Piwik::translate('HeatmapSessionRecording_ColumnTime');
- }
-
- public function getDocumentation()
- {
- return Piwik::translate('HeatmapSessionRecording_ColumnTimeDocumentation');
- }
-
- public function compute(Row $row)
- {
- return $this->getMetric($row, 'server_time');
- }
-
- public function getDependentMetrics()
- {
- return array($this->getName());
- }
-
- public function format($value, Formatter $formatter)
- {
- $date = Date::factory($value, $this->timezone);
-
- $dateTimeFormatProvider = StaticContainer::get('Piwik\Intl\Data\Provider\DateTimeFormatProvider');
-
- $template = $dateTimeFormatProvider->getFormatPattern($this->dateFormat);
- $template = str_replace(array(' y ', '.y '), ' ', $template);
-
- return $date->getLocalized($template);
- }
-
- public function beforeFormat($report, DataTable $table)
- {
- $this->idSite = DataTableFactory::getSiteIdFromMetadata($table);
- if (empty($this->idSite)) {
- $this->idSite = Common::getRequestVar('idSite', 0, 'int');
- }
- if (!empty($this->idSite)) {
- $this->timezone = Site::getTimezoneFor($this->idSite);
- return true;
- }
- return false; // skip formatting if there is no site to get currency info from
- }
-}
diff --git a/files/plugin-HeatmapSessionRecording-5.2.6/Columns/Metrics/TimeOnPage.php b/files/plugin-HeatmapSessionRecording-5.2.6/Columns/Metrics/TimeOnPage.php
deleted file mode 100644
index 506472d..0000000
--- a/files/plugin-HeatmapSessionRecording-5.2.6/Columns/Metrics/TimeOnPage.php
+++ /dev/null
@@ -1,65 +0,0 @@
-getMetric($row, $this->getName());
- }
-
- public function getDependentMetrics()
- {
- return array($this->getName());
- }
-
- public function format($value, Formatter $formatter)
- {
- if (!empty($value)) {
- $value = round($value / 1000, 1); // convert ms to seconds
- $value = (int) round($value);
- }
-
- $time = $formatter->getPrettyTimeFromSeconds($value, $asSentence = false);
-
- if (strpos($time, '00:') === 0) {
- $time = substr($time, 3);
- }
-
- return $time;
- }
-}
diff --git a/files/plugin-HeatmapSessionRecording-5.2.6/Columns/Metrics/TimeOnSite.php b/files/plugin-HeatmapSessionRecording-5.2.6/Columns/Metrics/TimeOnSite.php
deleted file mode 100644
index 2ba27d2..0000000
--- a/files/plugin-HeatmapSessionRecording-5.2.6/Columns/Metrics/TimeOnSite.php
+++ /dev/null
@@ -1,37 +0,0 @@
-getMetric($row, 'total_events');
- }
-
- public function getDependentMetrics()
- {
- return [];
- }
-}
diff --git a/files/plugin-HeatmapSessionRecording-5.2.6/Commands/RemoveHeatmapScreenshot.php b/files/plugin-HeatmapSessionRecording-5.2.6/Commands/RemoveHeatmapScreenshot.php
deleted file mode 100644
index 86783de..0000000
--- a/files/plugin-HeatmapSessionRecording-5.2.6/Commands/RemoveHeatmapScreenshot.php
+++ /dev/null
@@ -1,101 +0,0 @@
-setName('heatmapsessionrecording:remove-heatmap-screenshot');
- $this->setDescription('Removes a saved heatmap screenshot which can be useful if you want Matomo to re-take this screenshot. If the heatmap is currently ended, it will automatically restart it.');
- $this->addRequiredValueOption('idsite', null, 'The ID of the site the heatmap belongs to');
- $this->addRequiredValueOption('idheatmap', null, 'The ID of the heatamp');
- }
-
- /**
- * @return int
- */
- protected function doExecute(): int
- {
- $this->checkAllRequiredOptionsAreNotEmpty();
- $input = $this->getInput();
- $output = $this->getOutput();
- $idSite = $input->getOption('idsite');
- $idHeatmap = $input->getOption('idheatmap');
-
- $heatmap = Request::processRequest('HeatmapSessionRecording.getHeatmap', array(
- 'idSite' => $idSite,
- 'idSiteHsr' => $idHeatmap
- ));
-
- if ($heatmap['status'] === SiteHsrDao::STATUS_ENDED) {
- $logHsrSite = new LogHsrSite();
- $numSamplesTakenSoFar = $logHsrSite->getNumPageViews($idHeatmap);
-
- $currentSampleLimit = $heatmap['sample_limit'];
- $newSampleLimit = $numSamplesTakenSoFar + 50; // 50 heatmaps should be enough to collect at least once the dom.
-
- $update = array('status' => SiteHsrDao::STATUS_ACTIVE);
- if ($currentSampleLimit >= $newSampleLimit) {
- $output->writeln('Sample limit remains unchanged at ' . $currentSampleLimit);
- if ($currentSampleLimit - $numSamplesTakenSoFar > 75) {
- $output->writeln('make sure to end the heatmap again as soon as a screenshot has been taken!');
- }
- } else {
- $output->writeln('Going to increase sample limit from ' . $currentSampleLimit . ' to ' . $newSampleLimit . ' so a screenshot can be retaken. The heatmap will be automatically ended after about 50 new recordings have been recorded.');
- $output->writeln('Note: This means when you manage this heatmap the selected sample wont be shown correctly in the select field');
- $update['sample_limit'] = $newSampleLimit;
- }
-
- $output->writeln('Going to change status of heatmap from ended to active');
-
- $siteHsr = StaticContainer::get(SiteHsrDao::class);
- $siteHsr->updateHsrColumns($idSite, $idHeatmap, array(
- 'status' => SiteHsrDao::STATUS_ACTIVE,
- 'sample_limit' => $newSampleLimit
- ));
- $output->writeln('Done');
- }
-
- $success = Request::processRequest('HeatmapSessionRecording.deleteHeatmapScreenshot', array(
- 'idSite' => $idSite,
- 'idSiteHsr' => $idHeatmap
- ));
-
- if ($success) {
- Filesystem::deleteAllCacheOnUpdate();
- /** @var HeatmapSessionRecording $hsr */
- $hsr = Plugin\Manager::getInstance()->getLoadedPlugin('HeatmapSessionRecording');
- $hsr->updatePiwikTracker();
- $output->writeln('Screenhot removed');
-
- return self::SUCCESS;
- }
-
- $output->writeln('Heatmap not found');
- return self::FAILURE;
- }
-}
diff --git a/files/plugin-HeatmapSessionRecording-5.2.6/Configuration.php b/files/plugin-HeatmapSessionRecording-5.2.6/Configuration.php
deleted file mode 100644
index b8dd31a..0000000
--- a/files/plugin-HeatmapSessionRecording-5.2.6/Configuration.php
+++ /dev/null
@@ -1,145 +0,0 @@
-getConfig();
- $config->HeatmapSessionRecording = array(
- self::KEY_OPTIMIZE_TRACKING_CODE => self::DEFAULT_OPTIMIZE_TRACKING_CODE,
- self::KEY_SESSION_RECORDING_SAMPLE_LIMITS => self::DEFAULT_SESSION_RECORDING_SAMPLE_LIMITS,
- self::KEY_ENABLE_LOAD_CSS_FROM_DB => self::DEFAULT_ENABLE_LOAD_CSS_FROM_DB,
- self::MAX_ALLOWED_TIME_ON_PAGE_COLUMN_LIMIT => pow(2, 63),
- self::KEY_DEFAULT_HEATMAP_WIDTH => self::DEFAULT_HEATMAP_WIDTH
-
- );
- $config->forceSave();
- }
-
- public function uninstall()
- {
- $config = $this->getConfig();
- $config->HeatmapSessionRecording = array();
- $config->forceSave();
- }
-
- public function shouldOptimizeTrackingCode()
- {
- $value = $this->getConfigValue(self::KEY_OPTIMIZE_TRACKING_CODE, self::DEFAULT_OPTIMIZE_TRACKING_CODE);
-
- return !empty($value);
- }
-
- public function isAnonymousSessionRecordingAccessEnabled($idSite)
- {
- $value = $this->getDiValue(self::KEY_ENABLE_ANONYMOUS_SESSION_RECORDING_ACCESS, self::DEFAULT_ENABLE_ANONYMOUS_SESSION_RECORDING_ACCESS);
- $idSites = explode(',', $value);
- $idSites = array_map('trim', $idSites);
- $idSites = array_filter($idSites);
- return in_array($idSite, $idSites);
- }
-
- public function getSessionRecordingSampleLimits()
- {
- $value = $this->getConfigValue(self::KEY_SESSION_RECORDING_SAMPLE_LIMITS, self::DEFAULT_SESSION_RECORDING_SAMPLE_LIMITS);
-
- if (empty($value)) {
- $value = self::DEFAULT_SESSION_RECORDING_SAMPLE_LIMITS;
- }
-
- $value = explode(',', $value);
- $value = array_filter($value, function ($val) {
- return !empty($val);
- });
- $value = array_map(function ($val) {
- return intval(trim($val));
- }, $value);
- natsort($value);
-
- if (empty($value)) {
- // just a fallback in case config is completely misconfigured
- $value = explode(',', self::DEFAULT_SESSION_RECORDING_SAMPLE_LIMITS);
- }
-
- return array_values($value);
- }
-
- public function isLoadCSSFromDBEnabled()
- {
- return $this->getConfigValue(self::KEY_ENABLE_LOAD_CSS_FROM_DB, self::DEFAULT_ENABLE_LOAD_CSS_FROM_DB);
- }
-
- public function getMaximumAllowedPageTime()
- {
- return $this->getConfigValue(self::MAX_ALLOWED_TIME_ON_PAGE_COLUMN_LIMIT, '');
- }
-
- public function getDefaultHeatmapWidth()
- {
- $width = $this->getConfigValue(self::KEY_DEFAULT_HEATMAP_WIDTH, 1280);
- if (!in_array($width, self::HEATMAP_ALLOWED_WIDTHS)) {
- $width = self::DEFAULT_HEATMAP_WIDTH;
- }
-
- return $width;
- }
-
- private function getConfig()
- {
- return Config::getInstance();
- }
-
- private function getConfigValue($name, $default)
- {
- $config = $this->getConfig();
- $values = $config->HeatmapSessionRecording;
- if (isset($values[$name])) {
- return $values[$name];
- }
- return $default;
- }
-
- private function getDiValue($name, $default)
- {
- $value = $default;
- try {
- $value = StaticContainer::get('HeatmapSessionRecording.' . $name);
- } catch (NotFoundException $ex) {
- // ignore
- }
- return $value;
- }
-}
diff --git a/files/plugin-HeatmapSessionRecording-5.2.6/Controller.php b/files/plugin-HeatmapSessionRecording-5.2.6/Controller.php
deleted file mode 100644
index 2fd7c93..0000000
--- a/files/plugin-HeatmapSessionRecording-5.2.6/Controller.php
+++ /dev/null
@@ -1,463 +0,0 @@
-validator = $validator;
- $this->siteHsrModel = $model;
- $this->systemSettings = $settings;
- $this->mutationManipulator = $mutationManipulator;
- $this->mutationManipulator->generateNonce();
- $this->configuration = $configuration;
- }
-
- public function manageHeatmap()
- {
- $idSite = Common::getRequestVar('idSite');
-
- if (strtolower($idSite) === 'all') {
- // prevent fatal error... redirect to a specific site as it is not possible to manage for all sites
- $this->validator->checkHasSomeWritePermission();
- $this->redirectToIndex('HeatmapSessionRecording', 'manageHeatmap');
- exit;
- }
-
- $this->checkSitePermission();
- $this->validator->checkHeatmapReportWritePermission($this->idSite);
-
- return $this->renderTemplate('manageHeatmap', array(
- 'breakpointMobile' => (int) $this->systemSettings->breakpointMobile->getValue(),
- 'breakpointTablet' => (int) $this->systemSettings->breakpointTablet->getValue(),
- 'pauseReason' => Piwik::translate(HeatmapSessionRecording::getTranslationKey('pause'), [Piwik::translate('HeatmapSessionRecording_Heatmap')]),
- 'isMatomoJsWritable' => HeatmapSessionRecording::isMatomoJsWritable()
- ));
- }
-
- public function manageSessions()
- {
- $idSite = Common::getRequestVar('idSite');
-
- if (strtolower($idSite) === 'all') {
- // prevent fatal error... redirect to a specific site as it is not possible to manage for all sites
- $this->validator->checkHasSomeWritePermission();
- $this->redirectToIndex('HeatmapSessionRecording', 'manageSessions');
- exit;
- }
-
- $this->checkSitePermission();
- $this->validator->checkSessionReportWritePermission($this->idSite);
-
- return $this->renderTemplate('manageSessions', array(
- 'pauseReason' => Piwik::translate(HeatmapSessionRecording::getTranslationKey('pause'), [Piwik::translate('HeatmapSessionRecording_SessionRecording')]),
- 'isMatomoJsWritable' => HeatmapSessionRecording::isMatomoJsWritable()
- ));
- }
-
- private function checkNotInternetExplorerWhenUsingToken()
- {
- if (Common::getRequestVar('token_auth', '', 'string') && !empty($_SERVER['HTTP_USER_AGENT'])) {
- // we want to detect device type only once for faster performance
- $ddFactory = StaticContainer::get(\Piwik\DeviceDetector\DeviceDetectorFactory::class);
- $deviceDetector = $ddFactory->makeInstance($_SERVER['HTTP_USER_AGENT']);
- $client = $deviceDetector->getClient();
-
- if (
- (!empty($client['short_name']) && $client['short_name'] === 'IE')
- || (!empty($client['name']) && $client['name'] === 'Internet Explorer')
- || (!empty($client['name']) && $client['name'] === 'Opera Mini')
- ) {
- // see https://caniuse.com/?search=noreferrer
- // and https://caniuse.com/?search=referrerpolicy
- throw new \Exception('For security reasons this feature doesn\'t work in this browser when using authentication using token_auth. Please try a different browser or log in to view this.');
- }
- }
- }
-
- public function replayRecording()
- {
- $this->validator->checkSessionReportViewPermission($this->idSite);
- $this->checkNotInternetExplorerWhenUsingToken();
-
- $idLogHsr = Common::getRequestVar('idLogHsr', null, 'int');
- $idSiteHsr = Common::getRequestVar('idSiteHsr', null, 'int');
-
- $_GET['period'] = 'year'; // setting it randomly to not having to pass it in the URL
- $_GET['date'] = 'today'; // date is ignored anyway
-
- $recording = Request::processRequest('HeatmapSessionRecording.getRecordedSession', array(
- 'idSite' => $this->idSite,
- 'idLogHsr' => $idLogHsr,
- 'idSiteHsr' => $idSiteHsr,
- 'filter_limit' => '-1'
- ), $default = []);
-
- $currentPage = null;
- if (!empty($recording['pageviews']) && is_array($recording['pageviews'])) {
- $allPageviews = array_values($recording['pageviews']);
- foreach ($allPageviews as $index => $pageview) {
- if (!empty($pageview['idloghsr']) && $idLogHsr == $pageview['idloghsr']) {
- $currentPage = $index + 1;
- break;
- }
- }
- }
-
- $settings = $this->getPluginSettings();
- $settings = $settings->load();
- $skipPauses = !empty($settings['skip_pauses']);
- $autoPlayEnabled = !empty($settings['autoplay_pageviews']);
- $replaySpeed = !empty($settings['replay_speed']) ? (int) $settings['replay_speed'] : 1;
- $isVisitorProfileEnabled = Manager::getInstance()->isPluginActivated('Live') && Live::isVisitorProfileEnabled();
-
- if (!empty($recording['events'])) {
- foreach ($recording['events'] as $recordingEventIndex => $recordingEventValue) {
- if (
- !empty($recordingEventValue['event_type']) &&
- (
- $recordingEventValue['event_type'] == RequestProcessor::EVENT_TYPE_INITIAL_DOM ||
- $recordingEventValue['event_type'] == RequestProcessor::EVENT_TYPE_MUTATION
- ) &&
- !empty(
- $recordingEventValue['text']
- )
- ) {
- $recording['events'][$recordingEventIndex]['text'] = $this->mutationManipulator->manipulate($recordingEventValue['text'], $idSiteHsr, $idLogHsr);
- break;
- }
- }
- }
-
- return $this->renderTemplate('replayRecording', array(
- 'idLogHsr' => $idLogHsr,
- 'idSiteHsr' => $idSiteHsr,
- 'recording' => $recording,
- 'scrollAccuracy' => LogHsr::SCROLL_ACCURACY,
- 'offsetAccuracy' => LogHsrEvent::OFFSET_ACCURACY,
- 'autoPlayEnabled' => $autoPlayEnabled,
- 'visitorProfileEnabled' => $isVisitorProfileEnabled,
- 'skipPausesEnabled' => $skipPauses,
- 'replaySpeed' => $replaySpeed,
- 'currentPage' => $currentPage
- ));
- }
-
- protected function setBasicVariablesView($view)
- {
- parent::setBasicVariablesView($view);
-
- if (
- Common::getRequestVar('module', '', 'string') === 'Widgetize'
- && Common::getRequestVar('action', '', 'string') === 'iframe'
- && Common::getRequestVar('moduleToWidgetize', '', 'string') === 'HeatmapSessionRecording'
- ) {
- $action = Common::getRequestVar('actionToWidgetize', '', 'string');
- if (in_array($action, array('replayRecording', 'showHeatmap'), true)) {
- $view->enableFrames = true;
- }
- }
- }
-
- private function getPluginSettings()
- {
- $login = Piwik::getCurrentUserLogin();
-
- $settings = new PluginSettingsTable('HeatmapSessionRecording', $login);
- return $settings;
- }
-
- public function saveSessionRecordingSettings()
- {
- Piwik::checkUserHasSomeViewAccess();
- $this->validator->checkSessionRecordingEnabled();
- // there is no nonce for this action but that should also not be needed here. as it is just replay settings
-
- $autoPlay = Common::getRequestVar('autoplay', '0', 'int');
- $replaySpeed = Common::getRequestVar('replayspeed', '1', 'int');
- $skipPauses = Common::getRequestVar('skippauses', '0', 'int');
-
- $settings = $this->getPluginSettings();
- $settings->save(array('autoplay_pageviews' => $autoPlay, 'replay_speed' => $replaySpeed, 'skip_pauses' => $skipPauses));
- }
-
- private function initHeatmapAuth()
- {
- // todo remove in Matomo 5 when we hopefully no longer support IE 11.
- // This is mostly there to prevent forwarding tokens through referrer to third parties
- // most browsers support this except IE11
- // we said we're technically OK with IE11 forwarding a view token in worst case but we still have this here for now
- $token_auth = Common::getRequestVar('token_auth', '', 'string');
-
- if (!empty($token_auth)) {
- $auth = StaticContainer::get('Piwik\Auth');
- $auth->setTokenAuth($token_auth);
- $auth->setPassword(null);
- $auth->setPasswordHash(null);
- $auth->setLogin(null);
-
- Session::start();
- $sessionInitializer = new SessionInitializer();
- $sessionInitializer->initSession($auth);
-
- $url = preg_replace('/&token_auth=[^&]{20,38}|$/i', '', Url::getCurrentUrl());
- if ($url) {
- Url::redirectToUrl($url);
- return;
- }
- }
-
- // if no token_auth, we just rely on an existing session auth check
- }
-
- protected function setBasicVariablesNoneAdminView($view)
- {
- parent::setBasicVariablesNoneAdminView($view);
- if (Piwik::getAction() === 'embedPage' && Piwik::getModule() === 'HeatmapSessionRecording') {
- $view->setXFrameOptions('allow');
- }
- }
-
- public function embedPage()
- {
- $this->checkNotInternetExplorerWhenUsingToken();
- $this->initHeatmapAuth();
- $nonceRandom = '';
-
- if (
- property_exists($this, 'securityPolicy') &&
- method_exists($this->securityPolicy, 'allowEmbedPage')
- ) {
- $toSearch = array("'unsafe-inline' ", "'unsafe-eval' ", "'unsafe-inline'", "'unsafe-eval'");
- $nonceRandom = $this->mutationManipulator->getNonce();
- $this->securityPolicy->overridePolicy('default-src', $this->securityPolicy::RULE_EMBEDDED_FRAME);
- $this->securityPolicy->overridePolicy('img-src', $this->securityPolicy::RULE_EMBEDDED_FRAME);
- $this->securityPolicy->addPolicy('script-src', str_replace($toSearch, '', $this->securityPolicy::RULE_DEFAULT) . "'nonce-$nonceRandom'");
- }
-
- $pathPrefix = HeatmapSessionRecording::getPathPrefix();
- $jQueryPath = 'node_modules/jquery/dist/jquery.min.js';
- if (HeatmapSessionRecording::isMatomoForWordPress()) {
- $jQueryPath = includes_url('js/jquery/jquery.js');
- }
-
- $idLogHsr = Common::getRequestVar('idLogHsr', 0, 'int');
- $idSiteHsr = Common::getRequestVar('idSiteHsr', null, 'int');
-
- $_GET['period'] = 'year'; // setting it randomly to not having to pass it in the URL
- $_GET['date'] = 'today'; // date is ignored anyway
-
- if (empty($idLogHsr)) {
- $this->validator->checkHeatmapReportViewPermission($this->idSite);
-
- $heatmap = $this->getHeatmap($this->idSite, $idSiteHsr);
-
- if (isset($heatmap[0])) {
- $heatmap = $heatmap[0];
- }
-
- $baseUrl = $heatmap['screenshot_url'];
- $initialMutation = $heatmap['page_treemirror'];
- } else {
- $this->validator->checkSessionReportViewPermission($this->idSite);
- $this->checkSessionRecordingExists($this->idSite, $idSiteHsr);
-
- $recording = Request::processRequest('HeatmapSessionRecording.getEmbedSessionInfo', [
- 'idSite' => $this->idSite,
- 'idSiteHsr' => $idSiteHsr,
- 'idLogHsr' => $idLogHsr,
- ], $default = []);
-
- if (empty($recording)) {
- throw new \Exception(Piwik::translate('HeatmapSessionRecording_ErrorSessionRecordingDoesNotExist'));
- }
-
- $baseUrl = $recording['base_url'];
- $map = array_flip(PageUrl::$urlPrefixMap);
-
- if (isset($recording['url_prefix']) !== null && isset($map[$recording['url_prefix']])) {
- $baseUrl = $map[$recording['url_prefix']] . $baseUrl;
- }
-
- if (!empty($recording['initial_mutation'])) {
- $initialMutation = $recording['initial_mutation'];
- } else {
- $initialMutation = '';
- }
- }
-
- $initialMutation = $this->mutationManipulator->manipulate($initialMutation, $idSiteHsr, $idLogHsr);
-
- return $this->renderTemplate('embedPage', array(
- 'idLogHsr' => $idLogHsr,
- 'idSiteHsr' => $idSiteHsr,
- 'initialMutation' => $initialMutation,
- 'baseUrl' => $baseUrl,
- 'pathPrefix' => $pathPrefix,
- 'jQueryPath' => $jQueryPath,
- 'nonceRandom' => $nonceRandom
- ));
- }
-
- public function showHeatmap()
- {
- $this->validator->checkHeatmapReportViewPermission($this->idSite);
- $this->checkNotInternetExplorerWhenUsingToken();
-
- $idSiteHsr = Common::getRequestVar('idSiteHsr', null, 'int');
- $heatmapType = Common::getRequestVar('heatmapType', RequestProcessor::EVENT_TYPE_CLICK, 'int');
- $deviceType = Common::getRequestVar('deviceType', LogHsr::DEVICE_TYPE_DESKTOP, 'int');
-
- $heatmap = Request::processRequest('HeatmapSessionRecording.getHeatmap', array(
- 'idSite' => $this->idSite,
- 'idSiteHsr' => $idSiteHsr
- ), $default = []);
-
- if (isset($heatmap[0])) {
- $heatmap = $heatmap[0];
- }
-
- $requestDate = $this->siteHsrModel->getPiwikRequestDate($heatmap);
- $period = $requestDate['period'];
- $dateRange = $requestDate['date'];
-
- if (
- !PeriodFactory::isPeriodEnabledForAPI($period) ||
- Common::getRequestVar('useDateUrl', 0, 'int')
- ) {
- $period = Common::getRequestVar('period', null, 'string');
- $dateRange = Common::getRequestVar('date', null, 'string');
- }
-
- try {
- PeriodFactory::checkPeriodIsEnabled($period);
- } catch (\Exception $e) {
- $periodEscaped = Common::sanitizeInputValue(Piwik::translate('HeatmapSessionRecording_PeriodDisabledErrorMessage', $period));
- return '
' . $periodEscaped . '
';
- }
-
- $metadata = Request::processRequest('HeatmapSessionRecording.getRecordedHeatmapMetadata', array(
- 'idSite' => $this->idSite,
- 'idSiteHsr' => $idSiteHsr,
- 'period' => $period,
- 'date' => $dateRange
- ), $default = []);
-
- if (isset($metadata[0])) {
- $metadata = $metadata[0];
- }
-
- $editUrl = 'index.php' . Url::getCurrentQueryStringWithParametersModified(array(
- 'module' => 'HeatmapSessionRecording',
- 'action' => 'manageHeatmap'
- )) . '#?idSiteHsr=' . (int)$idSiteHsr;
-
- $reportDocumentation = '';
- if ($heatmap['status'] == SiteHsrDao::STATUS_ACTIVE) {
- $reportDocumentation = Piwik::translate('HeatmapSessionRecording_RecordedHeatmapDocStatusActive', array($heatmap['sample_limit'], $heatmap['sample_rate'] . '%'));
- } elseif ($heatmap['status'] == SiteHsrDao::STATUS_ENDED) {
- $reportDocumentation = Piwik::translate('HeatmapSessionRecording_RecordedHeatmapDocStatusEnded');
- }
-
- $includedCountries = $this->systemSettings->getIncludedCountries();
-
- return $this->renderTemplate('showHeatmap', array(
- 'idSiteHsr' => $idSiteHsr,
- 'editUrl' => $editUrl,
- 'heatmapType' => $heatmapType,
- 'deviceType' => $deviceType,
- 'heatmapPeriod' => $period,
- 'heatmapDate' => $dateRange,
- 'heatmap' => $heatmap,
- 'isActive' => $heatmap['status'] == SiteHsrDao::STATUS_ACTIVE,
- 'heatmapMetadata' => $metadata,
- 'reportDocumentation' => $reportDocumentation,
- 'isScroll' => $heatmapType == RequestProcessor::EVENT_TYPE_SCROLL,
- 'offsetAccuracy' => LogHsrEvent::OFFSET_ACCURACY,
- 'heatmapTypes' => API::getInstance()->getAvailableHeatmapTypes(),
- 'deviceTypes' => API::getInstance()->getAvailableDeviceTypes(),
- 'includedCountries' => !empty($includedCountries) ? implode(', ', $includedCountries) : '',
- 'desktopPreviewSize' => $this->configuration->getDefaultHeatmapWidth(),
- 'allowedWidth' => Configuration::HEATMAP_ALLOWED_WIDTHS,
- 'noDataMessageKey' => HeatmapSessionRecording::getTranslationKey('noDataHeatmap'),
- 'isMatomoJsWritable' => HeatmapSessionRecording::isMatomoJsWritable(),
- ));
- }
-
- private function getHeatmap($idSite, $idSiteHsr)
- {
- $heatmap = Request::processRequest('HeatmapSessionRecording.getHeatmap', [
- 'idSite' => $idSite,
- 'idSiteHsr' => $idSiteHsr,
- ], $default = []);
- if (empty($heatmap)) {
- throw new \Exception(Piwik::translate('HeatmapSessionRecording_ErrorHeatmapDoesNotExist'));
- }
- return $heatmap;
- }
-
- private function checkSessionRecordingExists($idSite, $idSiteHsr)
- {
- $sessionRecording = Request::processRequest('HeatmapSessionRecording.getSessionRecording', [
- 'idSite' => $idSite,
- 'idSiteHsr' => $idSiteHsr,
- ], $default = []);
- if (empty($sessionRecording)) {
- throw new \Exception(Piwik::translate('HeatmapSessionRecording_ErrorSessionRecordingDoesNotExist'));
- }
- }
-}
diff --git a/files/plugin-HeatmapSessionRecording-5.2.6/Dao/LogHsr.php b/files/plugin-HeatmapSessionRecording-5.2.6/Dao/LogHsr.php
deleted file mode 100644
index 8851782..0000000
--- a/files/plugin-HeatmapSessionRecording-5.2.6/Dao/LogHsr.php
+++ /dev/null
@@ -1,375 +0,0 @@
-tablePrefixed = Common::prefixTable($this->table);
- $this->logHsrSite = $logHsrSite;
- }
-
- private function getDb()
- {
- if (!isset($this->db)) {
- $this->db = Db::get();
- }
- return $this->db;
- }
-
- public function install()
- {
- DbHelper::createTable($this->table, "
- `idloghsr` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
- `idsite` INT UNSIGNED NOT NULL,
- `idvisit` BIGINT UNSIGNED NOT NULL,
- `idhsrview` CHAR(6) NOT NULL,
- `idpageview` CHAR(6) NULL,
- `idaction_url` INT(10) UNSIGNED NOT NULL DEFAULT 0,
- `device_type` TINYINT(1) NOT NULL DEFAULT 1,
- `server_time` DATETIME NOT NULL,
- `time_on_page` BIGINT(8) UNSIGNED NOT NULL,
- `viewport_w_px` SMALLINT(5) UNSIGNED DEFAULT 0,
- `viewport_h_px` SMALLINT(5) UNSIGNED DEFAULT 0,
- `scroll_y_max_relative` SMALLINT(5) UNSIGNED DEFAULT 0,
- `fold_y_relative` SMALLINT(5) UNSIGNED DEFAULT 0,
- PRIMARY KEY(`idloghsr`),
- UNIQUE KEY idvisit_idhsrview (`idvisit`,`idhsrview`),
- KEY idsite_servertime (`idsite`,`server_time`)");
-
- // idpageview is only there so we can add it to visitor log later. Please note that idpageview is only set on
- // the first tracking request. As the user may track a new pageview during the recording, the pageview may
- // change over time. This is why we need the idhsrview.
-
- // we need the idhsrview as there can be many recordings during one visit and this way we can control when
- // to trigger a new recording / heatmap in the tracker by changing this id
- }
-
- public function uninstall()
- {
- Db::query(sprintf('DROP TABLE IF EXISTS `%s`', $this->tablePrefixed));
- }
-
- protected function getDeviceWidth($resolution)
- {
- if (!empty($resolution)) {
- $parts = explode('x', $resolution);
- if (count($parts) === 2 && $parts[0] > 1 && $parts[1] > 1) {
- $width = $parts[0];
- return (int) $width;
- }
- }
-
- return 1280; // default desktop
- }
-
- protected function getDeviceType($hsrSiteIds, $idSite, $userAgent, $deviceWidth)
- {
- $deviceType = null;
-
- // we want to detect device type only once for faster performance
- $ddFactory = StaticContainer::get(\Piwik\DeviceDetector\DeviceDetectorFactory::class);
- $deviceDetector = $ddFactory->makeInstance($userAgent);
- $device = $deviceDetector->getDevice();
-
- $checkWidth = false;
- if (
- in_array(
- $device,
- array(
- AbstractDeviceParser::DEVICE_TYPE_FEATURE_PHONE,
- AbstractDeviceParser::DEVICE_TYPE_PHABLET,
- AbstractDeviceParser::DEVICE_TYPE_SMARTPHONE,
- AbstractDeviceParser::DEVICE_TYPE_CAMERA,
- AbstractDeviceParser::DEVICE_TYPE_CAR_BROWSER
- ),
- $strict = true
- )
- ) {
- $deviceType = self::DEVICE_TYPE_MOBILE;
- } elseif (in_array($device, array(AbstractDeviceParser::DEVICE_TYPE_TABLET), $strict = true)) {
- $deviceType = self::DEVICE_TYPE_TABLET;
- } elseif ($deviceType === AbstractDeviceParser::DEVICE_TYPE_DESKTOP) {
- $deviceType = LogHsr::DEVICE_TYPE_DESKTOP;
- $checkWidth = true;
- } else {
- $checkWidth = true;
- }
-
- if ($checkWidth && !empty($deviceWidth)) {
- $hsrs = $this->getCachedHsrs($idSite);
-
- foreach ($hsrs as $hsr) {
- // the device type is only relevant for heatmaps so we only look for breakpoints in heatmaps
- if (
- $hsr['record_type'] == SiteHsrDao::RECORD_TYPE_HEATMAP
- && in_array($hsr['idsitehsr'], $hsrSiteIds)
- ) {
- if ($deviceWidth < $hsr['breakpoint_mobile']) {
- // resolution has to be lower than this
- $deviceType = self::DEVICE_TYPE_MOBILE;
- } elseif ($deviceWidth < $hsr['breakpoint_tablet']) {
- $deviceType = self::DEVICE_TYPE_TABLET;
- } else {
- $deviceType = self::DEVICE_TYPE_DESKTOP;
- }
-
- break;
- }
- }
- }
-
- if (empty($deviceType)) {
- $deviceType = LogHsr::DEVICE_TYPE_DESKTOP;
- }
-
- return $deviceType;
- }
-
- protected function getCachedHsrs($idSite)
- {
- $cache = Tracker\Cache::getCacheWebsiteAttributes($idSite);
-
- if (!empty($cache['hsr'])) {
- return $cache['hsr'];
- }
-
- return array();
- }
-
- public function findIdLogHsr($idVisit, $idHsrView)
- {
- $query = sprintf('SELECT idloghsr FROM %s WHERE idvisit = ? and idhsrview = ? LIMIT 1', $this->tablePrefixed);
-
- return $this->getDb()->fetchOne($query, array($idVisit, $idHsrView));
- }
-
- public function hasRecordedIdVisit($idVisit, $idSiteHsr)
- {
- $siteTable = Common::prefixTable('log_hsr_site');
- $query = sprintf('SELECT lhsr.idvisit
- FROM %s lhsr
- LEFT JOIN %s lhsrsite ON lhsr.idloghsr=lhsrsite.idloghsr
- WHERE lhsr.idvisit = ? and lhsrsite.idsitehsr = ?
- LIMIT 1', $this->tablePrefixed, $siteTable);
- $id = $this->getDb()->fetchOne($query, array($idVisit, $idSiteHsr));
- return !empty($id);
- }
-
- // $hsrSiteIds => one recording may be long to several actual recordings.
- public function record($hsrSiteIds, $idSite, $idVisit, $idHsrView, $idPageview, $url, $serverTime, $userAgent, $resolution, $timeOnPage, $viewportW, $viewportH, $scrollYMaxRelative, $foldYRelative)
- {
- if ($foldYRelative > self::SCROLL_ACCURACY) {
- $foldYRelative = self::SCROLL_ACCURACY;
- }
-
- if ($scrollYMaxRelative > self::SCROLL_ACCURACY) {
- $scrollYMaxRelative = self::SCROLL_ACCURACY;
- }
-
- $idLogHsr = $this->findIdLogHsr($idVisit, $idHsrView);
-
- if (empty($idLogHsr)) {
- // to prevent race conditions we use atomic insert. It may lead to more gaps in auto increment but there is
- // no way around it
-
- Piwik::postEvent('HeatmapSessionRecording.trackNewHsrSiteIds', array(&$hsrSiteIds, array('idSite' => $idSite, 'serverTime' => $serverTime, 'idVisit' => $idVisit)));
-
- if (empty($hsrSiteIds)) {
- throw new \Exception('No hsrSiteIds');
- }
-
- $values = array(
- 'idvisit' => $idVisit,
- 'idsite' => $idSite,
- 'idhsrview' => $idHsrView,
- 'idpageview' => $idPageview,
- 'server_time' => $serverTime,
- 'time_on_page' => $timeOnPage,
- 'viewport_w_px' => $viewportW,
- 'viewport_h_px' => $viewportH,
- 'scroll_y_max_relative' => (int)$scrollYMaxRelative,
- 'fold_y_relative' => (int) $foldYRelative,
- );
-
- $columns = implode('`,`', array_keys($values));
- $bind = array_values($values);
- $sql = sprintf('INSERT INTO %s (`%s`) VALUES(?,?,?,?,?,?,?,?,?,?)', $this->tablePrefixed, $columns);
-
- try {
- $result = $this->getDb()->query($sql, $bind);
- } catch (\Exception $e) {
- if (Db::get()->isErrNo($e, \Piwik\Updater\Migration\Db::ERROR_CODE_DUPLICATE_ENTRY)) {
- // race condition where two tried to insert at same time... we need to update instead
-
- $idLogHsr = $this->findIdLogHsr($idVisit, $idHsrView);
- $this->updateRecord($idLogHsr, $timeOnPage, $scrollYMaxRelative);
- return $idLogHsr;
- }
- throw $e;
- }
-
- $all = $this->getDb()->rowCount($result);
-
- $idLogHsr = $this->getDb()->lastInsertId();
-
- if ($all === 1 || $all === '1') {
- // was inserted, resolve idaction! would be 2 or 0 on update
- // to be efficient we want to resolve idaction only once
- $url = PageUrl::normalizeUrl($url);
- $ids = TableLogAction::loadIdsAction(array('idaction_url' => array($url['url'], Action::TYPE_PAGE_URL, $url['prefixId'])));
-
- if (!empty($viewportW)) {
- $deviceWidth = (int) $viewportW;
- } else {
- $deviceWidth = $this->getDeviceWidth($resolution);
- }
- $deviceType = $this->getDeviceType($hsrSiteIds, $idSite, $userAgent, $deviceWidth);
-
- $idaction = $ids['idaction_url'];
- $this->getDb()->query(
- sprintf('UPDATE %s set idaction_url = ?, device_type = ? where idloghsr = ?', $this->tablePrefixed),
- array($idaction, $deviceType, $idLogHsr)
- );
-
- foreach ($hsrSiteIds as $hsrId) {
- // for performance reasons we check the limit only on hsr start and we make this way sure to still
- // accept all following requests to that hsr
- $this->logHsrSite->linkRecord($idLogHsr, $hsrId);
- }
- }
- } else {
- $this->updateRecord($idLogHsr, $timeOnPage, $scrollYMaxRelative);
- }
-
- return $idLogHsr;
- }
-
- public function updateRecord($idLogHsr, $timeOnPage, $scrollYMaxRelative)
- {
- $sql = sprintf(
- 'UPDATE %s SET
- time_on_page = if(? > time_on_page, ?, time_on_page),
- scroll_y_max_relative = if(? > scroll_y_max_relative, ?, scroll_y_max_relative)
- WHERE idloghsr = ?',
- $this->tablePrefixed
- );
-
- $bind = array();
- $bind[] = $timeOnPage;
- $bind[] = $timeOnPage;
- $bind[] = $scrollYMaxRelative;
- $bind[] = $scrollYMaxRelative;
- $bind[] = $idLogHsr;
-
- $this->getDb()->query($sql, $bind);
- }
-
- public function getAllRecords()
- {
- return $this->getDb()->fetchAll('SELECT * FROM ' . $this->tablePrefixed);
- }
-
- public function findLogHsrIdsInVisit($idSite, $idVisit)
- {
- $rows = Db::fetchAll(sprintf('SELECT idloghsr FROM %s WHERE idvisit = ? and idsite = ?', $this->tablePrefixed), array($idVisit, $idSite));
-
- $idLogHsrs = array();
- foreach ($rows as $row) {
- $idLogHsrs[] = (int) $row['idloghsr'];
- }
-
- return $idLogHsrs;
- }
-
- public function findDeletedLogHsrIds()
- {
- // DELETE ALL LOG ENTRIES WHOSE IDSITEHSR DOES NO LONGER EXIST
- $rows = Db::fetchAll(sprintf(
- 'SELECT DISTINCT log_hsr.idloghsr FROM %s log_hsr LEFT OUTER JOIN %s log_hsr_site ON log_hsr.idloghsr = log_hsr_site.idloghsr WHERE log_hsr_site.idsitehsr IS NULL',
- $this->tablePrefixed,
- Common::prefixTable('log_hsr_site')
- ));
-
- $idLogHsrsToDelete = array();
- foreach ($rows as $row) {
- $idLogHsrsToDelete[] = (int) $row['idloghsr'];
- }
-
- return $idLogHsrsToDelete;
- }
-
- public function deleteIdLogHsrsFromAllTables($idLogHsrsToDelete)
- {
- if (!is_array($idLogHsrsToDelete)) {
- throw new \Exception('idLogHsrsToDelete is not an array');
- }
-
- if (empty($idLogHsrsToDelete)) {
- return;
- }
-
- // we delete them in chunks of 2500
- $idLogHsrsToDelete = array_chunk($idLogHsrsToDelete, 2500);
-
- $tablesToDelete = array(
- Common::prefixTable('log_hsr_event'),
- Common::prefixTable('log_hsr_site'),
- Common::prefixTable('log_hsr'),
- );
- foreach ($idLogHsrsToDelete as $idsToDelete) {
- $idsToDelete = array_map('intval', $idsToDelete);
- $idsToDelete = implode(',', $idsToDelete);
- foreach ($tablesToDelete as $tableToDelete) {
- $sql = sprintf('DELETE FROM %s WHERE idloghsr IN(%s)', $tableToDelete, $idsToDelete);
- Db::query($sql);
- }
- }
- }
-}
diff --git a/files/plugin-HeatmapSessionRecording-5.2.6/Dao/LogHsrBlob.php b/files/plugin-HeatmapSessionRecording-5.2.6/Dao/LogHsrBlob.php
deleted file mode 100644
index 9945d50..0000000
--- a/files/plugin-HeatmapSessionRecording-5.2.6/Dao/LogHsrBlob.php
+++ /dev/null
@@ -1,180 +0,0 @@
-tablePrefixed = Common::prefixTable($this->table);
- }
-
- private function getDb()
- {
- if (!isset($this->db)) {
- $this->db = Db::get();
- }
- return $this->db;
- }
-
- public function install()
- {
- DbHelper::createTable($this->table, "
- `idhsrblob` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
- `hash` INT(10) UNSIGNED NOT NULL,
- `compressed` TINYINT(1) UNSIGNED NOT NULL DEFAULT 0,
- `value` MEDIUMBLOB NULL DEFAULT NULL,
- PRIMARY KEY (`idhsrblob`),
- INDEX (`hash`)");
-
- // we always build the hash on the raw text for simplicity
- }
-
- public function uninstall()
- {
- Db::query(sprintf('DROP TABLE IF EXISTS `%s`', $this->tablePrefixed));
- }
-
- public function findEntry($textHash, $text, $textCompressed)
- {
- $sql = sprintf('SELECT idhsrblob FROM %s WHERE `hash` = ? and (`value` = ? or `value` = ?) LIMIT 1', $this->tablePrefixed);
- $id = $this->getDb()->fetchOne($sql, array($textHash, $text, $textCompressed));
-
- return $id;
- }
-
- public function createEntry($textHash, $text, $isCompressed)
- {
- $sql = sprintf('INSERT INTO %s (`hash`, `compressed`, `value`) VALUES(?,?,?) ', $this->tablePrefixed);
- $this->getDb()->query($sql, array($textHash, (int) $isCompressed, $text));
-
- return $this->getDb()->lastInsertId();
- }
-
- public function record($text)
- {
- if ($text === null || $text === false) {
- return null;
- }
-
- $textHash = abs(crc32($text));
- $textCompressed = $this->compress($text);
-
- $id = $this->findEntry($textHash, $text, $textCompressed);
-
- if (!empty($id)) {
- return $id;
- }
-
- $isCompressed = 0;
- if ($text !== $textCompressed && strlen($textCompressed) < strlen($text)) {
- // detect if it is more efficient to store compressed or raw text
- $text = $textCompressed;
- $isCompressed = 1;
- }
-
- return $this->createEntry($textHash, $text, $isCompressed);
- }
-
- public function deleteUnusedBlobEntries()
- {
- $eventTable = Common::prefixTable('log_hsr_event');
- $blobTable = Common::prefixTable('log_hsr_blob');
-
- $blobEntries = Db::fetchAll('SELECT distinct idhsrblob FROM ' . $eventTable . ' LIMIT 2');
- $blobEntries = array_filter($blobEntries, function ($val) {
- return $val['idhsrblob'] !== null;
- }); // remove null values.
-
- if (empty($blobEntries)) {
- // no longer any blobs in use... delete all blobs
- $sql = 'DELETE FROM ' . $blobTable;
- Db::query($sql);
- return $sql;
- }
-
- $indexes = Db::fetchAll('SHOW INDEX FROM ' . $eventTable);
- $indexSql = '';
- foreach ($indexes as $index) {
- if (
- (!empty($index['Column_name']) && !empty($index['Key_name']) && $index['Column_name'] === 'idhsrblob')
- || (!empty($index['Key_name']) && $index['Key_name'] === 'idhsrblob')
- || (!empty($index['Key_name']) && $index['Key_name'] === 'index_idhsrblob')
- ) {
- $indexSql = 'FORCE INDEX FOR JOIN (' . $index['Key_name'] . ')';
- break;
- }
- }
-
- $sql = sprintf('DELETE hsrblob
- FROM %s hsrblob
- LEFT JOIN %s hsrevent %s on hsrblob.idhsrblob = hsrevent.idhsrblob
- WHERE hsrevent.idloghsr is null', $blobTable, $eventTable, $indexSql);
-
- Db::query($sql);
- return $sql;
- }
-
- public function getAllRecords()
- {
- $blobs = $this->getDb()->fetchAll('SELECT * FROM ' . $this->tablePrefixed);
- return $this->enrichRecords($blobs);
- }
-
- private function enrichRecords($blobs)
- {
- if (!empty($blobs)) {
- foreach ($blobs as $index => &$blob) {
- if (!empty($blob['compressed'])) {
- $blob['value'] = $this->uncompress($blob['value']);
- }
- }
- }
-
- return $blobs;
- }
-
- private function compress($data)
- {
- if (!empty($data)) {
- return gzcompress($data);
- }
-
- return $data;
- }
-
- private function uncompress($data)
- {
- if (!empty($data)) {
- return gzuncompress($data);
- }
-
- return $data;
- }
-}
diff --git a/files/plugin-HeatmapSessionRecording-5.2.6/Dao/LogHsrEvent.php b/files/plugin-HeatmapSessionRecording-5.2.6/Dao/LogHsrEvent.php
deleted file mode 100644
index 6a64065..0000000
--- a/files/plugin-HeatmapSessionRecording-5.2.6/Dao/LogHsrEvent.php
+++ /dev/null
@@ -1,166 +0,0 @@
-tablePrefixed = Common::prefixTable($this->table);
- $this->logBlobHsr = $logBlobHsr;
- }
-
- private function getDb()
- {
- if (!isset($this->db)) {
- $this->db = Db::get();
- }
- return $this->db;
- }
-
- public function install()
- {
- DbHelper::createTable($this->table, "
- `idhsrevent` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
- `idloghsr` INT(10) UNSIGNED NOT NULL,
- `time_since_load` BIGINT(8) UNSIGNED NOT NULL DEFAULT 0,
- `event_type` TINYINT UNSIGNED NOT NULL DEFAULT 0,
- `idselector` INT(10) UNSIGNED NULL DEFAULT NULL,
- `x` SMALLINT(5) NOT NULL DEFAULT 0,
- `y` SMALLINT(5) NOT NULL DEFAULT 0,
- `idhsrblob` INT(10) UNSIGNED DEFAULT NULL,
- PRIMARY KEY(`idhsrevent`),
- INDEX idloghsr (`idloghsr`),
- INDEX idhsrblob (`idhsrblob`)");
- // x and y is not unsigned on purpose as it may hold rarely a negative value
- }
-
- public function uninstall()
- {
- Db::query(sprintf('DROP TABLE IF EXISTS `%s`', $this->tablePrefixed));
- }
-
- public function record($idloghsr, $timeSinceLoad, $eventType, $idSelector, $x, $y, $text)
- {
- if ($x > self::MAX_SIZE) {
- $x = self::MAX_SIZE;
- }
-
- if ($y > self::MAX_SIZE) {
- $y = self::MAX_SIZE;
- }
-
- if ($x === null || $x === false) {
- $x = 0;
- }
-
- if ($y === null || $y === false) {
- $y = 0;
- }
-
- $idHsrBlob = $this->logBlobHsr->record($text);
-
- $values = array(
- 'idloghsr' => $idloghsr,
- 'time_since_load' => $timeSinceLoad,
- 'event_type' => $eventType,
- 'idselector' => $idSelector,
- 'x' => $x,
- 'y' => $y,
- 'idhsrblob' => $idHsrBlob,
- );
-
- $columns = implode('`,`', array_keys($values));
-
- $sql = sprintf('INSERT INTO %s (`%s`) VALUES(?,?,?,?,?,?,?) ', $this->tablePrefixed, $columns);
-
- $bind = array_values($values);
-
- $this->getDb()->query($sql, $bind);
- }
-
- public function getEventsForPageview($idLogHsr)
- {
- $sql = sprintf('SELECT %1$s.time_since_load, %1$s.event_type, %1$s.x, %1$s.y, %2$s.name as selector, %3$s.value as text, %3$s.compressed
- FROM %1$s
- LEFT JOIN %2$s ON %1$s.idselector = %2$s.idaction
- LEFT JOIN %3$s ON %1$s.idhsrblob = %3$s.idhsrblob
- WHERE %1$s.idloghsr = ? and %1$s.event_type != ?
- ORDER BY time_since_load ASC', $this->tablePrefixed, Common::prefixTable('log_action'), Common::prefixTable('log_hsr_blob'));
-
- $rows = $this->getDb()->fetchAll($sql, array($idLogHsr, RequestProcessor::EVENT_TYPE_CSS));
- foreach ($rows as $index => $row) {
- if (!empty($row['compressed'])) {
- $rows[$index]['text'] = gzuncompress($row['text']);
- }
- unset($rows[$index]['compressed']);
- }
- return $rows;
- }
-
- public function getCssEvents($idSiteHsr, $idLoghsr = '')
- {
- //idLogHsr will be empty in case of heatmaps, we cannot use it in where clause to resolve that, when its heatmap the where condition is `AND 1=1` and for session recording its `AND x.idloghsr=$idLoghsr`
- $idLogHsrLhs = '1';
- $idLogHsrRhs = '1';
- if (!empty($idLoghsr)) {
- $idLogHsrLhs = 'x.idloghsr';
- $idLogHsrRhs = $idLoghsr;
- }
- $sql = sprintf('SELECT distinct z.idhsrblob,a.name as url, z.value as text, z.compressed
- FROM %2$s x,%3$s y,%4$s z,%5$s a
- WHERE x.idsitehsr=? AND %1$s=? and y.event_type=? and x.idloghsr=y.idloghsr and y.idhsrblob = z.idhsrblob and a.idaction=y.idselector
- order by z.idhsrblob ASC', $idLogHsrLhs, Common::prefixTable('log_hsr_site'), Common::prefixTable('log_hsr_event'), Common::prefixTable('log_hsr_blob'), Common::prefixTable('log_action'));
-
- $rows = $this->getDb()->fetchAll($sql, array($idSiteHsr, $idLogHsrRhs, RequestProcessor::EVENT_TYPE_CSS));
- foreach ($rows as $index => $row) {
- if (!empty($row['compressed'])) {
- $rows[$index]['text'] = gzuncompress($row['text']);
- }
- unset($rows[$index]['compressed']);
- }
- return $rows;
- }
-
- public function getAllRecords()
- {
- return $this->getDb()->fetchAll('SELECT * FROM ' . $this->tablePrefixed);
- }
-}
diff --git a/files/plugin-HeatmapSessionRecording-5.2.6/Dao/LogHsrSite.php b/files/plugin-HeatmapSessionRecording-5.2.6/Dao/LogHsrSite.php
deleted file mode 100644
index 708aba3..0000000
--- a/files/plugin-HeatmapSessionRecording-5.2.6/Dao/LogHsrSite.php
+++ /dev/null
@@ -1,141 +0,0 @@
-tablePrefixed = Common::prefixTable($this->table);
- }
-
- private function getDb()
- {
- if (!isset($this->db)) {
- $this->db = Db::get();
- }
- return $this->db;
- }
-
- public function install()
- {
- // it actually also has the advantage that removing an entry will be fast because when a user clicks on
- // "delete heatmap" we could only remove this entry, and then have a daily cronjob to delete all entries that are
- // no longer linked. instead of having to directly delete all data. Also it is more efficient to track when eg
- // a session and a heatmap is being recording at the same time or when several heatmaps are being recorded at once
- DbHelper::createTable($this->table, "
- `idsitehsr` INT(10) UNSIGNED NOT NULL,
- `idloghsr` INT(10) UNSIGNED NOT NULL,
- PRIMARY KEY(`idsitehsr`, `idloghsr`),
- INDEX index_idloghsr (`idloghsr`)");
- }
-
- public function uninstall()
- {
- Db::query(sprintf('DROP TABLE IF EXISTS `%s`', $this->tablePrefixed));
- }
-
- public function linkRecord($idLogHsr, $idSiteHsr)
- {
- $bind = array($idLogHsr,$idSiteHsr);
- $sql = sprintf('INSERT INTO %s (`idloghsr`, `idsitehsr`) VALUES(?,?)', $this->tablePrefixed);
-
- try {
- $this->getDb()->query($sql, $bind);
- } catch (\Exception $e) {
- if (Db::get()->isErrNo($e, \Piwik\Updater\Migration\Db::ERROR_CODE_DUPLICATE_ENTRY)) {
- return;
- }
- throw $e;
- }
- }
-
- // should be fast as covered index
- public function getNumPageViews($idSiteHsr)
- {
- $sql = sprintf('SELECT count(*) as numsamples FROM %s WHERE idsitehsr = ?', $this->tablePrefixed);
-
- return (int) $this->getDb()->fetchOne($sql, array($idSiteHsr));
- }
-
- // should be fast as covered index
- public function getNumSessions($idSiteHsr)
- {
- $sql = sprintf(
- 'SELECT count(distinct idvisit)
- FROM %s loghsrsite
- left join %s loghsr on loghsr.idloghsr = loghsrsite.idloghsr
- left join %s loghsrevent on loghsr.idloghsr = loghsrevent.idloghsr and loghsrevent.event_type = %s
- WHERE loghsrsite.idsitehsr = ? and loghsrevent.idhsrblob is not null',
- $this->tablePrefixed,
- Common::prefixTable('log_hsr'),
- Common::prefixTable('log_hsr_event'),
- RequestProcessor::EVENT_TYPE_INITIAL_DOM
- );
-
- return (int) $this->getDb()->fetchOne($sql, array($idSiteHsr));
- }
-
- public function unlinkRecord($idLogHsr, $idSiteHsr)
- {
- $sql = sprintf('DELETE FROM %s WHERE idsitehsr = ? and idloghsr = ?', $this->tablePrefixed);
-
- return $this->getDb()->query($sql, array($idSiteHsr, $idLogHsr));
- }
-
- public function unlinkSiteRecords($idSiteHsr)
- {
- $sql = sprintf('DELETE FROM %s WHERE idsitehsr = ?', $this->tablePrefixed);
-
- return $this->getDb()->query($sql, array($idSiteHsr));
- }
-
- public function getAllRecords()
- {
- return $this->getDb()->fetchAll('SELECT * FROM ' . $this->tablePrefixed);
- }
-
- public function deleteNoLongerNeededRecords()
- {
- // DELETE ALL linked LOG ENTRIES WHOSE idsite does no longer exist or was removed
- // we delete links for removed site_hsr entries, and for site_hsr entries with status deleted
- // this query should only delete entries when they were deleted manually in the database basically.
- // otherwise the application takes already care of removing the needed links
- $sql = sprintf(
- 'DELETE FROM %1$s WHERE %1$s.idsitehsr NOT IN (select site_hsr.idsitehsr from %2$s site_hsr where site_hsr.status = "%3$s" or site_hsr.status = "%4$s")',
- Common::prefixTable('log_hsr_site'),
- Common::prefixTable('site_hsr'),
- SiteHsrDao::STATUS_ACTIVE,
- SiteHsrDao::STATUS_ENDED
- );
-
- Db::query($sql);
- }
-}
diff --git a/files/plugin-HeatmapSessionRecording-5.2.6/Dao/SiteHsrDao.php b/files/plugin-HeatmapSessionRecording-5.2.6/Dao/SiteHsrDao.php
deleted file mode 100644
index 037d00c..0000000
--- a/files/plugin-HeatmapSessionRecording-5.2.6/Dao/SiteHsrDao.php
+++ /dev/null
@@ -1,422 +0,0 @@
-tablePrefixed = Common::prefixTable($this->table);
- }
-
- private function getDb()
- {
- if (!isset($this->db)) {
- $this->db = Db::get();
- }
- return $this->db;
- }
-
- public function install()
- {
- DbHelper::createTable($this->table, "
- `idsitehsr` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
- `idsite` INT(10) UNSIGNED NOT NULL,
- `name` VARCHAR(" . Name::MAX_LENGTH . ") NOT NULL,
- `sample_rate` DECIMAL(4,1) UNSIGNED NOT NULL DEFAULT " . SampleRate::MAX_RATE . ",
- `sample_limit` MEDIUMINT(8) UNSIGNED NOT NULL DEFAULT 1000,
- `match_page_rules` TEXT DEFAULT '',
- `excluded_elements` TEXT DEFAULT '',
- `record_type` TINYINT(1) UNSIGNED DEFAULT 0,
- `page_treemirror` MEDIUMBLOB NULL DEFAULT NULL,
- `screenshot_url` VARCHAR(300) NULL DEFAULT NULL,
- `breakpoint_mobile` SMALLINT(5) UNSIGNED NOT NULL DEFAULT 0,
- `breakpoint_tablet` SMALLINT(5) UNSIGNED NOT NULL DEFAULT 0,
- `min_session_time` SMALLINT(5) UNSIGNED NOT NULL DEFAULT 0,
- `requires_activity` TINYINT(1) UNSIGNED NOT NULL DEFAULT 0,
- `capture_keystrokes` TINYINT(1) UNSIGNED NOT NULL DEFAULT 0,
- `created_date` DATETIME NOT NULL,
- `updated_date` DATETIME NOT NULL,
- `status` VARCHAR(10) NOT NULL DEFAULT '" . self::STATUS_ACTIVE . "',
- `capture_manually` TINYINT(1) UNSIGNED NOT NULL DEFAULT 0,
- PRIMARY KEY(`idsitehsr`),
- INDEX index_status_idsite (`status`, `idsite`),
- INDEX index_idsite_record_type (`idsite`, `record_type`)");
- }
-
- public function createHeatmapRecord($idSite, $name, $sampleLimit, $sampleRate, $matchPageRules, $excludedElements, $screenshotUrl, $breakpointMobile, $breakpointTablet, $status, $captureDomManually, $createdDate)
- {
- $columns = array(
- 'idsite' => $idSite,
- 'name' => $name,
- 'sample_limit' => $sampleLimit,
- 'match_page_rules' => $matchPageRules,
- 'sample_rate' => $sampleRate,
- 'status' => $status,
- 'record_type' => self::RECORD_TYPE_HEATMAP,
- 'created_date' => $createdDate,
- 'updated_date' => $createdDate,
- 'capture_manually' => !empty($captureDomManually) ? 1 : 0,
- );
-
- if (!empty($excludedElements)) {
- $columns['excluded_elements'] = $excludedElements;
- }
-
- if (!empty($screenshotUrl)) {
- $columns['screenshot_url'] = $screenshotUrl;
- }
- if ($breakpointMobile !== false && $breakpointMobile !== null) {
- $columns['breakpoint_mobile'] = $breakpointMobile;
- }
-
- if ($breakpointTablet !== false && $breakpointTablet !== null) {
- $columns['breakpoint_tablet'] = $breakpointTablet;
- }
-
- return $this->insertColumns($columns);
- }
-
- public function createSessionRecord($idSite, $name, $sampleLimit, $sampleRate, $matchPageRules, $minSessionTime, $requiresActivity, $captureKeystrokes, $status, $createdDate)
- {
- $columns = array(
- 'idsite' => $idSite,
- 'name' => $name,
- 'sample_limit' => $sampleLimit,
- 'match_page_rules' => $matchPageRules,
- 'sample_rate' => $sampleRate,
- 'status' => $status,
- 'record_type' => self::RECORD_TYPE_SESSION,
- 'min_session_time' => !empty($minSessionTime) ? $minSessionTime : 0,
- 'requires_activity' => !empty($requiresActivity) ? 1 : 0,
- 'capture_keystrokes' => !empty($captureKeystrokes) ? 1 : 0,
- 'created_date' => $createdDate,
- 'updated_date' => $createdDate,
- );
-
- return $this->insertColumns($columns);
- }
-
- private function insertColumns($columns)
- {
- $columns = $this->encodeFieldsWhereNeeded($columns);
-
- $bind = array_values($columns);
- $placeholder = Common::getSqlStringFieldsArray($columns);
-
- $sql = sprintf(
- 'INSERT INTO %s (`%s`) VALUES(%s)',
- $this->tablePrefixed,
- implode('`,`', array_keys($columns)),
- $placeholder
- );
-
- $this->getDb()->query($sql, $bind);
-
- $idSiteHsr = $this->getDb()->lastInsertId();
-
- return (int) $idSiteHsr;
- }
-
- protected function getCurrentTime()
- {
- return Date::now()->getDatetime();
- }
-
- public function updateHsrColumns($idSite, $idSiteHsr, $columns)
- {
- $columns = $this->encodeFieldsWhereNeeded($columns);
-
- if (!empty($columns)) {
- if (!isset($columns['updated_date'])) {
- $columns['updated_date'] = $this->getCurrentTime();
- }
-
- if (!empty($columns['page_treemirror'])) {
- $columns['capture_manually'] = 0;
- } elseif (!empty($columns['capture_manually'])) {
- $columns['page_treemirror'] = null;
- }
-
- $fields = array();
- $bind = array();
- foreach ($columns as $key => $value) {
- $fields[] = ' ' . $key . ' = ?';
- $bind[] = $value;
- }
- $fields = implode(',', $fields);
-
- $query = sprintf('UPDATE %s SET %s WHERE idsitehsr = ? AND idsite = ?', $this->tablePrefixed, $fields);
- $bind[] = (int) $idSiteHsr;
- $bind[] = (int) $idSite;
-
- // we do not use $db->update() here as this method is as well used in Tracker mode and the tracker DB does not
- // support "->update()". Therefore we use the query method where we know it works with tracker and regular DB
- $this->getDb()->query($query, $bind);
- }
- }
-
- public function hasRecords($idSite, $recordType)
- {
- $sql = sprintf('SELECT idsite FROM %s WHERE record_type = ? and `status` IN(?,?) and idsite = ? LIMIT 1', $this->tablePrefixed);
- $records = $this->getDb()->fetchRow($sql, array($recordType, self::STATUS_ENDED, self::STATUS_ACTIVE, $idSite));
-
- return !empty($records);
- }
-
- public function deleteRecord($idSite, $idSiteHsr)
- {
- // now we delete the heatmap manually and it should notice all log entries for that heatmap are no longer needed
- $sql = sprintf('DELETE FROM %s WHERE idsitehsr = ? and idsite = ?', $this->tablePrefixed);
- Db::query($sql, array($idSiteHsr, $idSite));
- }
-
- private function getAllFieldNames($includePageTreeMirror)
- {
- $fields = '`idsitehsr`,`idsite`,`name`, `sample_rate`, `sample_limit`, `match_page_rules`, `excluded_elements`, `record_type`, ';
- if (!empty($includePageTreeMirror)) {
- $fields .= '`page_treemirror`,';
- }
- $fields .= '`screenshot_url`, `breakpoint_mobile`, `breakpoint_tablet`, `min_session_time` , `requires_activity`, `capture_keystrokes`, `created_date`, `updated_date`, `status`, `capture_manually`';
- return $fields;
- }
-
- public function getRecords($idSite, $recordType, $includePageTreeMirror)
- {
- $fields = $this->getAllFieldNames($includePageTreeMirror);
- $sql = sprintf('SELECT ' . $fields . ' FROM %s WHERE record_type = ? and `status` IN(?,?,?) and idsite = ? order by created_date desc', $this->tablePrefixed);
- $records = $this->getDb()->fetchAll($sql, array($recordType, self::STATUS_ENDED, self::STATUS_ACTIVE, self::STATUS_PAUSED, $idSite));
-
- return $this->enrichRecords($records);
- }
-
- public function getRecord($idSite, $idSiteHsr, $recordType)
- {
- $sql = sprintf('SELECT * FROM %s WHERE record_type = ? and `status` IN(?,?,?) and idsite = ? and idsitehsr = ? LIMIT 1', $this->tablePrefixed);
- $record = $this->getDb()->fetchRow($sql, array($recordType, self::STATUS_ENDED, self::STATUS_ACTIVE, self::STATUS_PAUSED, $idSite, $idSiteHsr));
-
- return $this->enrichRecord($record);
- }
-
- public function getNumRecordsTotal($recordType)
- {
- $sql = sprintf('SELECT count(*) as total FROM %s WHERE record_type = ? and `status` IN(?,?,?)', $this->tablePrefixed);
- return $this->getDb()->fetchOne($sql, array($recordType, self::STATUS_ENDED, self::STATUS_ACTIVE, self::STATUS_PAUSED));
- }
-
- public function hasActiveRecordsAcrossSites()
- {
- $query = $this->getQueryActiveRequests();
-
- $sql = sprintf("SELECT count(*) as numrecords FROM %s WHERE %s LIMIT 1", $this->tablePrefixed, $query['where']);
- $numRecords = $this->getDb()->fetchOne($sql, $query['bind']);
-
- return !empty($numRecords);
- }
-
- private function getQueryActiveRequests()
- {
- // for sessions we also need to return ended sessions to make sure to record all page views once a user takes part in
- // a session recording. Otherwise as soon as the limit of sessions has reached, it would stop recording any further page views in already started session recordings
-
- // we only fetch recorded sessions with status ended for the last 24 hours to not expose any potential config and for faster processing etc
- $oneDayAgo = Date::now()->subDay(1)->getDatetime();
-
- return array(
- 'where' => '(status = ? or (record_type = ? and status = ? and updated_date > ?))',
- 'bind' => array(self::STATUS_ACTIVE, self::RECORD_TYPE_SESSION, self::STATUS_ENDED, $oneDayAgo)
- );
- }
-
- /**
- * For performance reasons the page_treemirror will be read only partially!
- * @param $idSite
- * @return mixed
- * @throws \Piwik\Tracker\Db\DbException
- */
- public function getActiveRecords($idSite)
- {
- $query = $this->getQueryActiveRequests();
-
- $bind = $query['bind'];
- $bind[] = $idSite;
-
- $fields = $this->getAllFieldNames(false);
- // we want to avoid needing to read all the entire treemirror every time the tracking cache will be updated
- // as in worst case every treemirror can be 16MB or in rare cases even more. Most of the time it's only like 50KB or so
- // but we want to avoid fetching heaps of unneeded data
- $fields .= ', SUBSTRING(page_treemirror, 1, 10) as page_treemirror';
-
- // NOTE: If you adjust this query, you might also
- $sql = sprintf("SELECT " . $fields . " FROM %s WHERE %s and idsite = ? ORDER BY idsitehsr asc", $this->tablePrefixed, $query['where']);
- $records = $this->getDb()->fetchAll($sql, $bind);
-
- foreach ($records as $index => $record) {
- if (!empty($record['page_treemirror'])) {
- // avoids an error when it tries to uncompress
- $records[$index]['page_treemirror'] = $this->compress($record['page_treemirror']);
- }
- }
-
- return $this->enrichRecords($records);
- }
-
- private function enrichRecords($records)
- {
- if (empty($records)) {
- return $records;
- }
-
- foreach ($records as $index => $record) {
- $records[$index] = $this->enrichRecord($record);
- }
-
- return $records;
- }
-
- private function enrichRecord($record)
- {
- if (empty($record)) {
- return $record;
- }
-
- $record['idsitehsr'] = (int) $record['idsitehsr'];
- $record['idsite'] = (int) $record['idsite'];
- $record['sample_rate'] = number_format($record['sample_rate'], 1, '.', '');
- $record['record_type'] = (int) $record['record_type'];
- $record['sample_limit'] = (int) $record['sample_limit'];
- $record['min_session_time'] = (int) $record['min_session_time'];
- $record['breakpoint_mobile'] = (int) $record['breakpoint_mobile'];
- $record['breakpoint_tablet'] = (int) $record['breakpoint_tablet'];
- $record['match_page_rules'] = $this->decodeField($record['match_page_rules']);
- $record['requires_activity'] = !empty($record['requires_activity']);
- $record['capture_keystrokes'] = !empty($record['capture_keystrokes']);
- $record['capture_manually'] = !empty($record['capture_manually']) ? 1 : 0;
-
- if (!empty($record['page_treemirror'])) {
- $record['page_treemirror'] = $this->uncompress($record['page_treemirror']);
- } else {
- $record['page_treemirror'] = '';
- }
-
- return $record;
- }
-
- public function uninstall()
- {
- Db::query(sprintf('DROP TABLE IF EXISTS `%s`', $this->tablePrefixed));
- }
-
- public function getAllEntities()
- {
- $records = $this->getDb()->fetchAll('SELECT * FROM ' . $this->tablePrefixed);
-
- return $this->enrichRecords($records);
- }
-
- private function encodeFieldsWhereNeeded($columns)
- {
- foreach ($columns as $column => $value) {
- if ($column === 'match_page_rules') {
- $columns[$column] = $this->encodeField($value);
- } elseif ($column === 'page_treemirror') {
- if (!empty($value)) {
- $columns[$column] = $this->compress($value);
- } else {
- $columns[$column] = null;
- }
- } elseif (in_array($column, array('breakpoint_mobile', 'breakpoint_tablet', 'min_session_time', 'sample_rate'), $strict = true)) {
- if ($value > self::MAX_SMALLINT) {
- $columns[$column] = self::MAX_SMALLINT;
- }
- } elseif (in_array($column, array('requires_activity', 'capture_keystrokes'), $strict = true)) {
- if (!empty($value)) {
- $columns[$column] = 1;
- } else {
- $columns[$column] = 0;
- }
- }
- }
-
- return $columns;
- }
-
- private function compress($data)
- {
- if (!empty($data)) {
- return gzcompress($data);
- }
-
- return $data;
- }
-
- private function uncompress($data)
- {
- if (!empty($data)) {
- return gzuncompress($data);
- }
-
- return $data;
- }
-
- private function encodeField($field)
- {
- if (empty($field) || !is_array($field)) {
- $field = array();
- }
-
- return json_encode($field);
- }
-
- private function decodeField($field)
- {
- if (!empty($field)) {
- $field = @json_decode($field, true);
- }
-
- if (empty($field) || !is_array($field)) {
- $field = array();
- }
-
- return $field;
- }
-}
diff --git a/files/plugin-HeatmapSessionRecording-5.2.6/DataTable/Filter/EnrichRecordedSessions.php b/files/plugin-HeatmapSessionRecording-5.2.6/DataTable/Filter/EnrichRecordedSessions.php
deleted file mode 100644
index 0a306e7..0000000
--- a/files/plugin-HeatmapSessionRecording-5.2.6/DataTable/Filter/EnrichRecordedSessions.php
+++ /dev/null
@@ -1,73 +0,0 @@
-getRowsWithoutSummaryRow() as $row) {
- if ($isAnonymous) {
- foreach (self::getBlockedFields() as $blockedField) {
- if ($row->getColumn($blockedField) !== false) {
- $row->setColumn($blockedField, false);
- }
- }
- } else {
- $row->setColumn('idvisitor', bin2hex($row->getColumn('idvisitor')));
- }
- }
- }
-}
diff --git a/files/plugin-HeatmapSessionRecording-5.2.6/Diagnostic/ConfigsPhpCheck.php b/files/plugin-HeatmapSessionRecording-5.2.6/Diagnostic/ConfigsPhpCheck.php
deleted file mode 100644
index c436154..0000000
--- a/files/plugin-HeatmapSessionRecording-5.2.6/Diagnostic/ConfigsPhpCheck.php
+++ /dev/null
@@ -1,112 +0,0 @@
-translator = $translator;
- }
-
- public function execute()
- {
- $label = $this->translator->translate('Heatmap & Session Recording Tracking');
-
- $site = new Model();
- $idSites = $site->getSitesId();
- $idSite = array_shift($idSites);
-
- $baseUrl = SettingsPiwik::getPiwikUrl();
- if (!Common::stringEndsWith($baseUrl, '/')) {
- $baseUrl .= '/';
- }
-
- $baseUrl .= HeatmapSessionRecording::getPathPrefix() . '/';
- $baseUrl .= 'HeatmapSessionRecording/configs.php';
- $testUrl = $baseUrl . '?idsite=' . (int) $idSite . '&trackerid=5lX6EM&url=http%3A%2F%2Ftest.test%2F';
-
- $error = null;
- $response = null;
-
- $errorResult = $this->translator->translate('HeatmapSessionRecording_ConfigsPhpErrorResult');
- $manualCheck = $this->translator->translate('HeatmapSessionRecording_ConfigsPhpManualCheck');
-
- if (method_exists('\Piwik\SettingsPiwik', 'isInternetEnabled')) {
- $isInternetEnabled = SettingsPiwik::isInternetEnabled();
- if (!$isInternetEnabled) {
- $unknown = $this->translator->translate('HeatmapSessionRecording_ConfigsInternetDisabled', $testUrl) . ' ' . $manualCheck;
- return array(DiagnosticResult::singleResult($label, DiagnosticResult::STATUS_WARNING, $unknown));
- }
- }
-
- try {
- $response = Http::sendHttpRequest($testUrl, $timeout = 2);
- } catch (\Exception $e) {
- $error = $e->getMessage();
- }
-
- if (!empty($response)) {
- $response = Common::mb_strtolower($response);
- if (strpos($response, 'piwik.heatmapsessionrecording') !== false) {
- $message = $this->translator->translate('HeatmapSessionRecording_ConfigsPhpSuccess', $baseUrl);
- return array(DiagnosticResult::singleResult($label, DiagnosticResult::STATUS_OK, $message));
- } elseif (strpos($response, 'forbidden') !== false || strpos($response, ' forbidden') !== false || strpos($response, ' denied ') !== false || strpos($response, '403 ') !== false || strpos($response, '404 ') !== false) {
- // Likely the server returned eg a 403 HTML
- $message = $this->translator->translate('HeatmapSessionRecording_ConfigsPhpNotAccessible', array($testUrl)) . ' ' . $errorResult;
- return array(DiagnosticResult::singleResult($label, DiagnosticResult::STATUS_ERROR, $message));
- }
- }
-
- if (!empty($error)) {
- $error = Common::mb_strtolower($error);
-
- if (strpos($error, 'forbidden ') !== false || strpos($error, ' forbidden') !== false || strpos($error, 'denied ') !== false || strpos($error, '403 ') !== false || strpos($error, '404 ') !== false) {
- $message = $this->translator->translate('HeatmapSessionRecording_ConfigsPhpNotAccessible', array($testUrl)) . ' ' . $errorResult;
- return array(DiagnosticResult::singleResult($label, DiagnosticResult::STATUS_ERROR, $message));
- }
-
- if (strpos($error, 'ssl ') !== false || strpos($error, ' ssl') !== false || strpos($error, 'self signed') !== false || strpos($error, 'certificate ') !== false) {
- $message = $this->translator->translate('HeatmapSessionRecording_ConfigsPhpSelfSignedError', array($testUrl)) . ' ' . $manualCheck;
- return array(DiagnosticResult::singleResult($label, DiagnosticResult::STATUS_WARNING, $message));
- }
-
- $unknownError = $this->translator->translate('HeatmapSessionRecording_ConfigsPhpUnknownError', array($testUrl, $error)) . ' ' . $errorResult;
- return array(DiagnosticResult::singleResult($label, DiagnosticResult::STATUS_WARNING, $unknownError));
- }
-
- $unknown = $this->translator->translate('HeatmapSessionRecording_ConfigsPhpUnknown', $testUrl) . $manualCheck;
- return array(DiagnosticResult::singleResult($label, DiagnosticResult::STATUS_WARNING, $unknown));
- }
-}
diff --git a/files/plugin-HeatmapSessionRecording-5.2.6/Input/Breakpoint.php b/files/plugin-HeatmapSessionRecording-5.2.6/Input/Breakpoint.php
deleted file mode 100644
index bb0eb6a..0000000
--- a/files/plugin-HeatmapSessionRecording-5.2.6/Input/Breakpoint.php
+++ /dev/null
@@ -1,66 +0,0 @@
-breakpoint = $breakpoint;
- $this->name = $name;
- }
-
- public function check()
- {
- $title = Piwik::translate('HeatmapSessionRecording_BreakpointX', array($this->name));
-
- // zero is a valid value!
- if ($this->breakpoint === false || $this->breakpoint === null || $this->breakpoint === '') {
- throw new Exception(Piwik::translate('HeatmapSessionRecording_ErrorXNotProvided', $title));
- }
-
- if (!is_numeric($this->breakpoint)) {
- throw new Exception(Piwik::translate('HeatmapSessionRecording_ErrorXNotANumber', array($title)));
- }
-
- if ($this->breakpoint < 0) {
- throw new Exception(Piwik::translate('HeatmapSessionRecording_ErrorXTooLow', array($title, 0)));
- }
-
- if ($this->breakpoint > self::MAX_LIMIT) {
- throw new Exception(Piwik::translate('HeatmapSessionRecording_ErrorXTooHigh', array($title, self::MAX_LIMIT)));
- }
- }
-}
diff --git a/files/plugin-HeatmapSessionRecording-5.2.6/Input/CaptureKeystrokes.php b/files/plugin-HeatmapSessionRecording-5.2.6/Input/CaptureKeystrokes.php
deleted file mode 100644
index b6004f9..0000000
--- a/files/plugin-HeatmapSessionRecording-5.2.6/Input/CaptureKeystrokes.php
+++ /dev/null
@@ -1,40 +0,0 @@
-value = $value;
- }
-
- public function check()
- {
- $allowedValues = array('0', '1', 0, 1, true, false);
-
- if (!in_array($this->value, $allowedValues, $strict = true)) {
- $message = Piwik::translate('HeatmapSessionRecording_ErrorXNotWhitelisted', array('captureKeystrokes', '"1", "0"'));
- throw new Exception($message);
- }
- }
-}
diff --git a/files/plugin-HeatmapSessionRecording-5.2.6/Input/ExcludedElements.php b/files/plugin-HeatmapSessionRecording-5.2.6/Input/ExcludedElements.php
deleted file mode 100644
index 2395013..0000000
--- a/files/plugin-HeatmapSessionRecording-5.2.6/Input/ExcludedElements.php
+++ /dev/null
@@ -1,50 +0,0 @@
-selector = $name;
- }
-
- public function check()
- {
- if ($this->selector === null || $this->selector === false || $this->selector === '') {
- // selecto may not be set
- return;
- }
-
- $title = Piwik::translate('HeatmapSessionRecording_ExcludedElements');
-
- if (Common::mb_strlen($this->selector) > static::MAX_LENGTH) {
- throw new Exception(Piwik::translate('HeatmapSessionRecording_ErrorXTooLong', array($title, static::MAX_LENGTH)));
- }
- }
-}
diff --git a/files/plugin-HeatmapSessionRecording-5.2.6/Input/MinSessionTime.php b/files/plugin-HeatmapSessionRecording-5.2.6/Input/MinSessionTime.php
deleted file mode 100644
index 22dd6d4..0000000
--- a/files/plugin-HeatmapSessionRecording-5.2.6/Input/MinSessionTime.php
+++ /dev/null
@@ -1,57 +0,0 @@
-minSessionTime = $minSessionTime;
- }
-
- public function check()
- {
- $title = 'HeatmapSessionRecording_MinSessionTime';
-
- if ($this->minSessionTime === false || $this->minSessionTime === null || $this->minSessionTime === '') {
- $title = Piwik::translate($title);
- throw new Exception(Piwik::translate('HeatmapSessionRecording_ErrorXNotProvided', $title));
- }
-
- if (!is_numeric($this->minSessionTime)) {
- $title = Piwik::translate($title);
- throw new Exception(Piwik::translate('HeatmapSessionRecording_ErrorXNotANumber', array($title)));
- }
-
- if ($this->minSessionTime < 0) {
- $title = Piwik::translate($title);
- throw new Exception(Piwik::translate('HeatmapSessionRecording_ErrorXTooLow', array($title, 0)));
- }
-
- if ($this->minSessionTime > self::MAX_LIMIT) {
- $title = Piwik::translate($title);
- throw new Exception(Piwik::translate('HeatmapSessionRecording_ErrorXTooHigh', array($title, self::MAX_LIMIT)));
- }
- }
-}
diff --git a/files/plugin-HeatmapSessionRecording-5.2.6/Input/Name.php b/files/plugin-HeatmapSessionRecording-5.2.6/Input/Name.php
deleted file mode 100644
index f03692d..0000000
--- a/files/plugin-HeatmapSessionRecording-5.2.6/Input/Name.php
+++ /dev/null
@@ -1,51 +0,0 @@
-name = $name;
- }
-
- public function check()
- {
- $title = 'General_Name';
-
- if (empty($this->name)) {
- $title = Piwik::translate($title);
- throw new Exception(Piwik::translate('HeatmapSessionRecording_ErrorXNotProvided', $title));
- }
-
- if (Common::mb_strlen($this->name) > static::MAX_LENGTH) {
- $title = Piwik::translate($title);
- throw new Exception(Piwik::translate('HeatmapSessionRecording_ErrorXTooLong', array($title, static::MAX_LENGTH)));
- }
- }
-}
diff --git a/files/plugin-HeatmapSessionRecording-5.2.6/Input/PageRule.php b/files/plugin-HeatmapSessionRecording-5.2.6/Input/PageRule.php
deleted file mode 100644
index 3c09d15..0000000
--- a/files/plugin-HeatmapSessionRecording-5.2.6/Input/PageRule.php
+++ /dev/null
@@ -1,80 +0,0 @@
-target = $targets;
- $this->parameterName = $parameterName;
- $this->index = $index;
- }
-
- public function check()
- {
- $titleSingular = 'HeatmapSessionRecording_PageRule';
-
- if (!is_array($this->target)) {
- $titleSingular = Piwik::translate($titleSingular);
- throw new Exception(Piwik::translate('HeatmapSessionRecording_ErrorInnerIsNotAnArray', array($titleSingular, $this->parameterName)));
- }
-
- if (empty($this->target['attribute'])) {
- throw new Exception(Piwik::translate('HeatmapSessionRecording_ErrorArrayMissingKey', array('attribute', $this->parameterName, $this->index)));
- }
-
- if (empty($this->target['type'])) {
- throw new Exception(Piwik::translate('HeatmapSessionRecording_ErrorArrayMissingKey', array('type', $this->parameterName, $this->index)));
- }
-
- if (!array_key_exists('inverted', $this->target)) {
- throw new Exception(Piwik::translate('HeatmapSessionRecording_ErrorArrayMissingKey', array('inverted', $this->parameterName, $this->index)));
- }
-
- if (empty($this->target['value']) && Tracker\PageRuleMatcher::doesTargetTypeRequireValue($this->target['type'])) {
- // any is the only target type that may have an empty value
- throw new Exception(Piwik::translate('HeatmapSessionRecording_ErrorArrayMissingValue', array('value', $this->parameterName, $this->index)));
- }
-
- if ($this->target['type'] === Tracker\PageRuleMatcher::TYPE_REGEXP && isset($this->target['value'])) {
- $pattern = Tracker\PageRuleMatcher::completeRegexpPattern($this->target['value']);
- if (@preg_match($pattern, '') === false) {
- throw new Exception(Piwik::translate('HeatmapSessionRecording_ErrorInvalidRegExp', array($this->target['value'])));
- }
- }
- }
-}
diff --git a/files/plugin-HeatmapSessionRecording-5.2.6/Input/PageRules.php b/files/plugin-HeatmapSessionRecording-5.2.6/Input/PageRules.php
deleted file mode 100644
index 562c871..0000000
--- a/files/plugin-HeatmapSessionRecording-5.2.6/Input/PageRules.php
+++ /dev/null
@@ -1,61 +0,0 @@
-targets = $targets;
- $this->parameterName = $parameterName;
- $this->needsAtLeastOneEntry = $needsAtLeastOneEntry;
- }
-
- public function check()
- {
- if ($this->needsAtLeastOneEntry && empty($this->targets)) {
- throw new Exception(Piwik::translate('HeatmapSessionRecording_ErrorXNotProvided', $this->parameterName));
- }
-
- if (!is_array($this->targets)) {
- throw new Exception(Piwik::translate('HeatmapSessionRecording_ErrorNotAnArray', $this->parameterName));
- }
-
- foreach ($this->targets as $index => $target) {
- $target = new PageRule($target, $this->parameterName, $index);
- $target->check();
- }
- }
-}
diff --git a/files/plugin-HeatmapSessionRecording-5.2.6/Input/RequiresActivity.php b/files/plugin-HeatmapSessionRecording-5.2.6/Input/RequiresActivity.php
deleted file mode 100644
index 61ff6a6..0000000
--- a/files/plugin-HeatmapSessionRecording-5.2.6/Input/RequiresActivity.php
+++ /dev/null
@@ -1,40 +0,0 @@
-value = $value;
- }
-
- public function check()
- {
- $allowedValues = array('0', '1', 0, 1, true, false);
-
- if (!in_array($this->value, $allowedValues, $strict = true)) {
- $message = Piwik::translate('HeatmapSessionRecording_ErrorXNotWhitelisted', array('activated', '"1", "0"'));
- throw new Exception($message);
- }
- }
-}
diff --git a/files/plugin-HeatmapSessionRecording-5.2.6/Input/SampleLimit.php b/files/plugin-HeatmapSessionRecording-5.2.6/Input/SampleLimit.php
deleted file mode 100644
index daa8686..0000000
--- a/files/plugin-HeatmapSessionRecording-5.2.6/Input/SampleLimit.php
+++ /dev/null
@@ -1,57 +0,0 @@
-sampleLimit = $sampleLimit;
- }
-
- public function check()
- {
- $title = 'HeatmapSessionRecording_SampleLimit';
-
- if ($this->sampleLimit === false || $this->sampleLimit === null || $this->sampleLimit === '') {
- $title = Piwik::translate($title);
- throw new Exception(Piwik::translate('HeatmapSessionRecording_ErrorXNotProvided', $title));
- }
-
- if (!is_numeric($this->sampleLimit)) {
- $title = Piwik::translate($title);
- throw new Exception(Piwik::translate('HeatmapSessionRecording_ErrorXNotANumber', array($title)));
- }
-
- if ($this->sampleLimit < 0) {
- $title = Piwik::translate($title);
- throw new Exception(Piwik::translate('HeatmapSessionRecording_ErrorXTooLow', array($title, 0)));
- }
-
- if ($this->sampleLimit > self::MAX_LIMIT) {
- $title = Piwik::translate($title);
- throw new Exception(Piwik::translate('HeatmapSessionRecording_ErrorXTooHigh', array($title, self::MAX_LIMIT)));
- }
- }
-}
diff --git a/files/plugin-HeatmapSessionRecording-5.2.6/Input/SampleRate.php b/files/plugin-HeatmapSessionRecording-5.2.6/Input/SampleRate.php
deleted file mode 100644
index b0f6261..0000000
--- a/files/plugin-HeatmapSessionRecording-5.2.6/Input/SampleRate.php
+++ /dev/null
@@ -1,62 +0,0 @@
-sampleRate = $sampleRate;
- }
-
- public function check()
- {
- $title = 'HeatmapSessionRecording_SampleRate';
-
- if ($this->sampleRate === false || $this->sampleRate === null || $this->sampleRate === '') {
- $title = Piwik::translate($title);
- throw new Exception(Piwik::translate('HeatmapSessionRecording_ErrorXNotProvided', $title));
- }
-
- if (!is_numeric($this->sampleRate)) {
- $title = Piwik::translate($title);
- throw new Exception(Piwik::translate('HeatmapSessionRecording_ErrorXNotANumber', array($title)));
- }
-
- if ($this->sampleRate < 0) {
- $title = Piwik::translate($title);
- throw new Exception(Piwik::translate('HeatmapSessionRecording_ErrorXTooLow', array($title, 0)));
- }
-
- if ($this->sampleRate > self::MAX_RATE) {
- $title = Piwik::translate($title);
- throw new Exception(Piwik::translate('HeatmapSessionRecording_ErrorXTooHigh', array($title, self::MAX_RATE)));
- }
-
- if (!preg_match('/^\d{1,3}\.?\d?$/', (string) $this->sampleRate)) {
- $title = Piwik::translate($title);
- throw new Exception(Piwik::translate('HeatmapSessionRecording_ErrorXNotANumber', array($title)));
- }
- }
-}
diff --git a/files/plugin-HeatmapSessionRecording-5.2.6/Input/ScreenshotUrl.php b/files/plugin-HeatmapSessionRecording-5.2.6/Input/ScreenshotUrl.php
deleted file mode 100644
index 2b40332..0000000
--- a/files/plugin-HeatmapSessionRecording-5.2.6/Input/ScreenshotUrl.php
+++ /dev/null
@@ -1,58 +0,0 @@
-url = $name;
- }
-
- public function check()
- {
- if ($this->url === null || $this->url === false || $this->url === '') {
- // url may not be set
- return;
- }
-
- $title = Piwik::translate('HeatmapSessionRecording_ScreenshotUrl');
-
- if (preg_match('/\s/', $this->url)) {
- throw new Exception(Piwik::translate('HeatmapSessionRecording_ErrorXContainsWhitespace', $title));
- }
-
- if (strpos($this->url, '//') === false) {
- throw new Exception(Piwik::translate('HeatmapSessionRecording_UrlXDoesNotLookLikeUrl', array($title, static::MAX_LENGTH)));
- }
-
- if (Common::mb_strlen($this->url) > static::MAX_LENGTH) {
- throw new Exception(Piwik::translate('HeatmapSessionRecording_ErrorXTooLong', array($title, static::MAX_LENGTH)));
- }
- }
-}
diff --git a/files/plugin-HeatmapSessionRecording-5.2.6/Install/HtAccess.php b/files/plugin-HeatmapSessionRecording-5.2.6/Install/HtAccess.php
deleted file mode 100644
index dc7017d..0000000
--- a/files/plugin-HeatmapSessionRecording-5.2.6/Install/HtAccess.php
+++ /dev/null
@@ -1,66 +0,0 @@
-getPluginDir() . '/.htaccess';
- }
-
- private function getSourcePath()
- {
- return $this->getPluginDir() . '/Install/htaccessTemplate';
- }
-
- private function exists()
- {
- $path = $this->getTargetPath();
- return file_exists($path);
- }
-
- private function canCreate()
- {
- return is_writable($this->getPluginDir());
- }
-
- private function isContentDifferent()
- {
- $templateContent = trim(file_get_contents($this->getSourcePath()));
- $fileContent = trim(file_get_contents($this->getTargetPath()));
-
- return $templateContent !== $fileContent;
- }
-
- public function install()
- {
- if (
- $this->canCreate() && (!$this->exists() || (is_readable($this->getTargetPath()) && $this->isContentDifferent()))
- ) {
- Filesystem::copy($this->getSourcePath(), $this->getTargetPath());
- }
- }
-}
diff --git a/files/plugin-HeatmapSessionRecording-5.2.6/Install/htaccessTemplate b/files/plugin-HeatmapSessionRecording-5.2.6/Install/htaccessTemplate
deleted file mode 100644
index c302274..0000000
--- a/files/plugin-HeatmapSessionRecording-5.2.6/Install/htaccessTemplate
+++ /dev/null
@@ -1,23 +0,0 @@
-# This file is generated by InnoCraft - Piwik, do not edit directly
-# Please report any issue or improvement directly to the InnoCraft team.
-# Allow to serve configs.php which is safe
-
-
-
- Order Allow,Deny
- Allow from All
-
- = 2.4>
- Require all granted
-
-
-
-
- Order Allow,Deny
- Allow from All
-
-
- Require all granted
-
-
-
\ No newline at end of file
diff --git a/files/plugin-HeatmapSessionRecording-5.2.6/LEGALNOTICE b/files/plugin-HeatmapSessionRecording-5.2.6/LEGALNOTICE
deleted file mode 100644
index b8a6bb2..0000000
--- a/files/plugin-HeatmapSessionRecording-5.2.6/LEGALNOTICE
+++ /dev/null
@@ -1,46 +0,0 @@
-COPYRIGHT
-
- The software package is:
-
- Copyright (C) 2017 InnoCraft Ltd (NZBN 6106769)
-
-
-SOFTWARE LICENSE
-
- This software is licensed under the InnoCraft EULA and the license has been included in this
- software package in the file LICENSE.
-
-
-THIRD-PARTY COMPONENTS AND LIBRARIES
-
- The following components/libraries are redistributed in this package,
- and subject to their respective licenses.
-
- Name: heatmap.js
- Link: https://www.patrick-wied.at/static/heatmapjs/
- License: MIT
- License File: ibs/heatmap.js/LICENSE
-
- Name: mutation-summary
- Link: https://github.com/rafaelw/mutation-summary/
- License: Apache 2.0
- License File: libs/mutation-summary/COPYING
-
- Name: MutationObserver.js
- Link: https://github.com/megawac/MutationObserver.js/tree/master
- License: WTFPL, Version 2
- License File: libs/MutationObserver.js/license
-
- Name: svg.js
- Link: http://tkyk.github.com/jquery-history-plugin/
- License: http://svgjs.com/
- License File: libs/svg.js/LICENSE.txt
-
- Name: Get Element CSS Selector
- Link: https://gist.github.com/asfaltboy/8aea7435b888164e8563
- License: MIT
- License File: included in tracker.min.js
-
- Name: Material icons ("repeat", "looks_one", "looks_two", "looks_four", "looks_six") in angularjs/sessionvis/sessionvis.directive.html
- Link: https://design.google.com/icons/
- License: Apache License Version 2.0
diff --git a/files/plugin-HeatmapSessionRecording-5.2.6/LICENSE b/files/plugin-HeatmapSessionRecording-5.2.6/LICENSE
deleted file mode 100644
index 4686f35..0000000
--- a/files/plugin-HeatmapSessionRecording-5.2.6/LICENSE
+++ /dev/null
@@ -1,49 +0,0 @@
-InnoCraft License
-
-This InnoCraft End User License Agreement (the "InnoCraft EULA") is between you and InnoCraft Ltd (NZBN 6106769) ("InnoCraft"). If you are agreeing to this Agreement not as an individual but on behalf of your company, then "Customer" or "you" means your company, and you are binding your company to this Agreement. InnoCraft may modify this Agreement from time to time, subject to the terms in Section (xii) below.
-
-By clicking on the "I’ve read and accept the terms & conditions (https://shop.matomo.org/terms-conditions/)" (or similar button) that is presented to you at the time of your Order, or by using or accessing InnoCraft products, you indicate your assent to be bound by this Agreement.
-
-
-InnoCraft EULA
-
-(i) InnoCraft is the licensor of the Plugin for Matomo Analytics (the "Software").
-
-(ii) Subject to the terms and conditions of this Agreement, InnoCraft grants you a limited, worldwide, non-exclusive, non-transferable and non-sublicensable license to install and use the Software only on hardware systems owned, leased or controlled by you, during the applicable License Term. The term of each Software license ("License Term") will be specified in your Order. Your License Term will end upon any breach of this Agreement.
-
-(iii) Unless otherwise specified in your Order, for each Software license that you purchase, you may install one production instance of the Software in a Matomo Analytics instance owned or operated by you, and accessible via one URL ("Matomo instance"). Additional licenses must be purchased in order to deploy the Software in multiple Matomo instances, including when these multiple Matomo instances are hosted on a single hardware system.
-
-(iv) Licenses granted by InnoCraft are granted subject to the condition that you must ensure the maximum number of Authorized Users and Authorized Sites that are able to access and use the Software is equal to the number of User and Site Licenses for which the necessary fees have been paid to InnoCraft for the Subscription period. You may upgrade your license at any time on payment of the appropriate fees to InnoCraft in order to increase the maximum number of authorized users or sites. The number of User and Site Licenses granted to you is dependent on the fees paid by you. “User License” means a license granted under this EULA to you to permit an Authorized User to use the Software. “Authorized User” means a person who has an account in the Matomo instance and for which the necessary fees (“Subscription fees”) have been paid to InnoCraft for the current license term. "Site License" means a license granted under this EULA to you to permit an Authorized Site to use the Matomo Marketplace Plugin. “Authorized Sites” means a website or a measurable within Matomo instance and for which the necessary fees (“Subscription fees”) have been paid to InnoCraft for the current license term. These restrictions also apply if you install the Matomo Analytics Platform as part of your WordPress.
-
-(v) Piwik Analytics was renamed to Matomo Analytics in January 2018. The same terms and conditions as well as any restrictions or grants apply if you are using any version of Piwik.
-
-(vi) The Software requires a license key in order to operate, which will be delivered to the email addresses specified in your Order when we have received payment of the applicable fees.
-
-(vii) Any information that InnoCraft may collect from you or your device will be subject to InnoCraft Privacy Policy (https://www.innocraft.com/privacy).
-
-(viii) You are bound by the Matomo Marketplace Terms and Conditions (https://shop.matomo.org/terms-conditions/).
-
-(ix) You may not reverse engineer or disassemble or re-distribute the Software in whole or in part, or create any derivative works from or sublicense any rights in the Software, unless otherwise expressly authorized in writing by InnoCraft.
-
-(x) The Software is protected by copyright and other intellectual property laws and treaties. InnoCraft own all title, copyright and other intellectual property rights in the Software, and the Software is licensed to you directly by InnoCraft, not sold.
-
-(xi) The Software is provided under an "as is" basis and without any support or maintenance. Nothing in this Agreement shall require InnoCraft to provide you with support or fixes to any bug, failure, mis-performance or other defect in The Software. InnoCraft may provide you, from time to time, according to his sole discretion, with updates of the Software. You hereby warrant to keep the Software up-to-date and install all relevant updates. InnoCraft shall provide any update free of charge.
-
-(xii) The Software is provided "as is", and InnoCraft hereby disclaim all warranties, including but not limited to any implied warranties of title, non-infringement, merchantability or fitness for a particular purpose. InnoCraft shall not be liable or responsible in any way for any losses or damage of any kind, including lost profits or other indirect or consequential damages, relating to your use of or reliance upon the Software.
-
-(xiii) We may update or modify this Agreement from time to time, including the referenced Privacy Policy and the Matomo Marketplace Terms and Conditions. If a revision meaningfully reduces your rights, we will use reasonable efforts to notify you (by, for example, sending an email to the billing or technical contact you designate in the applicable Order). If we modify the Agreement during your License Term or Subscription Term, the modified version will be effective upon your next renewal of a License Term.
-
-
-About InnoCraft Ltd
-
-At InnoCraft Ltd, we create innovating quality products to grow your business and to maximize your success.
-
-Our software products are built on top of Matomo Analytics: the leading open digital analytics platform used by more than one million websites worldwide. We are the creators and makers of the Matomo Analytics platform.
-
-
-Contact
-
-Email: contact@innocraft.com
-Contact form: https://www.innocraft.com/#contact
-Website: https://www.innocraft.com/
-Buy our products: Premium Features for Matomo Analytics https://plugins.matomo.org/premium
diff --git a/files/plugin-HeatmapSessionRecording-5.2.6/Menu.php b/files/plugin-HeatmapSessionRecording-5.2.6/Menu.php
deleted file mode 100644
index 9ec1075..0000000
--- a/files/plugin-HeatmapSessionRecording-5.2.6/Menu.php
+++ /dev/null
@@ -1,50 +0,0 @@
-validator = $validator;
- }
-
- public function configureAdminMenu(MenuAdmin $menu)
- {
- $idSite = Common::getRequestVar('idSite', 0, 'int');
-
- if (!empty($idSite) && !Piwik::isUserIsAnonymous() && $this->validator->canWrite($idSite)) {
- if (!$this->validator->isHeatmapRecordingDisabled()) {
- $menu->addMeasurableItem('HeatmapSessionRecording_Heatmaps', $this->urlForAction('manageHeatmap'), $orderId = 30);
- }
- if (!$this->validator->isSessionRecordingDisabled()) {
- $menu->addMeasurableItem('HeatmapSessionRecording_SessionRecordings', $this->urlForAction('manageSessions'), $orderId = 30);
- }
- }
- }
-}
diff --git a/files/plugin-HeatmapSessionRecording-5.2.6/MutationManipulator.php b/files/plugin-HeatmapSessionRecording-5.2.6/MutationManipulator.php
deleted file mode 100644
index 5878e4f..0000000
--- a/files/plugin-HeatmapSessionRecording-5.2.6/MutationManipulator.php
+++ /dev/null
@@ -1,226 +0,0 @@
-configuration = $configuration;
- $this->generateNonce();
- }
-
- public function manipulate($initialMutation, $idSiteHsr, $idLogHsr)
- {
- $parseAndSanitizeCssLinks = $this->updateCssLinks($initialMutation, $idSiteHsr, $idLogHsr);
-
- return $this->sanitizeNodeAttributes($parseAndSanitizeCssLinks);
- }
-
- public function updateCssLinks($initialMutation, $idSiteHsr, $idLogHsr)
- {
- if ($this->configuration->isLoadCSSFromDBEnabled()) {
- $blob = new LogHsrBlob();
- $dao = new LogHsrEvent($blob);
- $cssEvents = $dao->getCssEvents($idSiteHsr, $idLogHsr);
- if (!empty($cssEvents) && !empty($initialMutation)) {
- $initialMutation = $this->updateInitialMutationWithInlineCss($initialMutation, $cssEvents);
- }
- }
-
- return $initialMutation;
- }
-
- public function getNonce()
- {
- if (!$this->nonce) {
- $this->generateNonce();
- }
-
-
- return $this->nonce;
- }
-
- public function generateNonce()
- {
- $this->nonce = $this->generateRandomString();
- }
-
- private function generateRandomString($length = 10)
- {
- $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
- $charactersLength = strlen($characters);
- $randomString = '';
- for ($i = 0; $i < $length; $i++) {
- $randomString .= $characters[rand(0, $charactersLength - 1)];
- }
- return $randomString;
- }
-
- public function sanitizeNodeAttributes($initialMutation)
- {
- $initialMutationArray = json_decode($initialMutation, true);
- if (!empty($initialMutationArray['children'])) {
- $this->parseMutationArrayRecursivelyToSanitizeNodes($initialMutationArray['children']);
- $initialMutation = json_encode($initialMutationArray);
- }
-
- return $initialMutation;
- }
-
- public function updateInitialMutationWithInlineCss($initialMutation, $cssEvents)
- {
- $formattedCssEvents = $this->formatCssEvents($cssEvents);
- $initialMutationArray = json_decode($initialMutation, true);
- if (!empty($initialMutationArray['children']) && !empty($formattedCssEvents)) {
- $this->parseMutationArrayRecursivelyForCssLinks($initialMutationArray['children'], $formattedCssEvents);
-
- $initialMutation = json_encode($initialMutationArray);
- }
-
- return $initialMutation;
- }
-
- public function formatCssEvents($cssEvents)
- {
- $formatted = array();
- foreach ($cssEvents as $cssEvent) {
- if (!isset($formatted[md5(trim($cssEvent['url']))])) { //Only use the first one since the o/p is sorted by ID in ascending order
- $formatted[md5(trim($cssEvent['url']))] = $cssEvent;
- }
- }
-
- return $formatted;
- }
-
- private function parseMutationArrayRecursivelyForCssLinks(&$nodes, $cssEvents, &$id = 900000000)
- {
- foreach ($nodes as &$node) {
- $parseChildNodes = true;
- if (isset($node['tagName']) && $node['tagName'] == 'LINK' && !empty($node['attributes']['url']) && !empty($cssEvents) && !empty($cssEvents[md5(trim($node['attributes']['url']))]['text'])) {
- $parseChildNodes = false;
- $content = $cssEvents[md5(trim($node['attributes']['url']))]['text'];
- if (!empty($content)) {
- $node['tagName'] = 'STYLE';
- $media = $node['attributes']['media'] ?? '';
- if (isset($node['attributes'])) {
- $node['attributes'] = [];
- }
- $node['attributes']['nonce'] = $this->getNonce();
- if ($media) {
- $node['attributes']['media'] = $media;
- }
- $node['childNodes'] = [
- [
- 'nodeType' => 3,
- 'id' => $id++,
- 'textContent' => $content
- ]
- ];
- }
- }
-
- if ($parseChildNodes && !empty($node['childNodes'])) {
- $this->parseMutationArrayRecursivelyForCssLinks($node['childNodes'], $cssEvents, $id);
- }
- }
- }
-
- private function parseMutationArrayRecursivelyToSanitizeNodes(&$nodes)
- {
- foreach ($nodes as &$node) {
- if (!empty($node['attributes'])) {
- // empty all the attributes with base64 and contains javascript/script/"("
- // Eg: OR
- foreach ($node['attributes'] as $nodeAttributeKey => &$nodeAttributeValue) {
- // had to double encode `\x09` as `\\\\x09` in MutationManipulatorTest.php to make json_decode work, else it was giving "syntax error" via json_last_error_msg()
- // Due to double encoding had to add entry for both "\\x09" and "\x09"
- $nodeAttributeValue = str_replace(["\\x09", "\\x0a", "\\x0d", "\\0", "\x09", "\x0a", "\x0d", "\0"], "", $nodeAttributeValue);
- $htmlDecodedAttributeValue = html_entity_decode($nodeAttributeValue, ENT_COMPAT, 'UTF-8');
- if (
- $htmlDecodedAttributeValue &&
- (
- stripos($htmlDecodedAttributeValue, 'ecmascript') !== false ||
- stripos($htmlDecodedAttributeValue, 'javascript') !== false ||
- stripos($htmlDecodedAttributeValue, 'script:') !== false ||
- stripos($htmlDecodedAttributeValue, 'jscript') !== false ||
- stripos($htmlDecodedAttributeValue, 'vbscript') !== false
- )
- ) {
- $nodeAttributeValue = '';
- } elseif (stripos($nodeAttributeValue, 'base64') !== false) {
- $base64KeywordMadeLowerCase = str_ireplace('base64', 'base64', $nodeAttributeValue);
- //For values like data:text/javascript;base64,YWxlcnQoMSk= we split the value into 2 parts
- // part1: data:text/javascript;base64
- // part2: ,YWxlcnQoMSk= we split the value into 2 parts
- // we determine the position of first comma from second part and try to decode the base64 string and check fo possible XSS
- // cannot assume the position of firstComma to be `0` since there can be string with spaces in beginning
- $attributeExploded = explode('base64', $base64KeywordMadeLowerCase);
- array_shift($attributeExploded);
- if (!empty($attributeExploded)) {
- foreach ($attributeExploded as $attributeExplodedValue) {
- $htmlDecodedAttributeString = html_entity_decode($attributeExplodedValue, ENT_COMPAT, 'UTF-8');
- $base64DecodedString = base64_decode($attributeExplodedValue);
- $base64UrlDecodedString = base64_decode(urldecode($attributeExplodedValue));
- if (
- $this->isXssString($base64DecodedString) ||
- $this->isXssString($base64UrlDecodedString) ||
- $this->isXssString($htmlDecodedAttributeString) ||
- $this->isXssString(urldecode($htmlDecodedAttributeString))
- ) {
- $nodeAttributeValue = '';
- break;
- }
- }
- }
- } elseif ($nodeAttributeValue) {
- $htmlDecodedString = html_entity_decode($nodeAttributeValue, ENT_COMPAT, 'UTF-8');
- if (
- $this->isXssString($htmlDecodedString) ||
- $this->isXssString(urldecode($htmlDecodedString))
- ) {
- $nodeAttributeValue = '';
- }
- }
- }
- }
-
- if (!empty($node['childNodes'])) {
- $this->parseMutationArrayRecursivelyToSanitizeNodes($node['childNodes']);
- }
- }
- }
-
- private function isXssString($value)
- {
- if (
- !empty($value) &&
- (
- stripos($value, 'script:') !== false ||
- stripos($value, 'javascript') !== false ||
- stripos($value, 'ecmascript') !== false ||
- stripos($value, '
-```
-
-### Polyfill differences from standard interface
-
-#### MutationObserver
-
-* Implemented using a recursive `setTimeout` (every ~30 ms) rather than using a `setImmediate` polyfill; so calls will be made less frequently and likely with more data than the standard MutationObserver. In addition, it can miss changes that occur and then are lost in the interval window.
-* Setting an observed elements html using `innerHTML` will call `childList` observer listeners with several mutations with only 1 addedNode or removed node per mutation. With the standard you would have 1 call with multiple nodes in addedNodes and removedNodes node lists.
-* With `childList` and `subtree` changes in node order (eg first element gets swapped with last) should fire a `addedNode` and `removedNode` mutation but the correct node may not always be identified.
-
-#### MutationRecord
-
-* `addedNodes` and `removedNodes` are arrays instead of `NodeList`s
-* `oldValue` is always called with attribute changes
-* `nextSibling` and `previousSibling` correctfullness is questionable (hard to know if the order of appended items). I'd suggest not relying on them anyway (my tests are extremely permissive with these attributes)
-
-### Supported MutationObserverInit properties
-
-Currently supports the following [MutationObserverInit properties](https://developer.mozilla.org/en/docs/Web/API/MutationObserver#MutationObserverInit):
-
-* **childList**: Set to truthy if mutations to target's immediate children are to be observed.
-* **subtree**: Set to truthy to do deep scans on a target's children.
-* **attributes**: Set to truthy if mutations to target's children are to be observed. As explained in #4, the `style` attribute may not be matched in ie<8.
-* **attributeFilter**: Set to an array of attribute local names (without namespace) if not all attribute mutations need to be observed.
-* **attributeOldValue**: doesn't do anything attributes are always called with old value
-* **characterData**: currently follows Mozilla's implementation in that it will only watch `textNodes` values and not, like in webkit, where setting .innerHTML will add a characterData mutation.
-
-### Performance
-
-By default, the polyfill will check observed nodes about 25 times per second (30 ms interval) for mutations. Try running [these jsperf.com tests](http://jsperf.com/mutationobserver-shim) and the JSLitmus tests in the test suite for usage performance tests. It may be worthwile to adapt `MutationObserver._period` based on UA or heuristics (todo).
-
-From my tests observing any size element without `subtree` enabled is relatively cheap. Although I've optimized the subtree check to the best of my abilities it can be costly on large trees. You can draw your own conclusions based on the JSLitmus and jsperf tests noting that you can expect the `mo` to do its check 28+ times a second (by default).
-
-Although supported, I'd recommend against watching `attributes` on the `subtree` on large structures, as the check is complex and expensive on terrible hardware like my phone :(
-
-The included minified file has been tuned for performance.
-
-### Compatibility
-
-I've tested and verified compatibility in the following browsers + [these Sauce browsers](https://saucelabs.com/u/mutationobserver)
-
-* Internet Explorer 8 (emulated), 9, 10 in win7 and win8
-* Firefox 4, 21, 24, 26 in OSX, win7 and win8
-* Opera 11.8, 12.16 in win7
-* "Internet" on Android HTC One V
-* Blackberry 6.0.16
-
-Try [running the test suite](https://rawgithub.com/megawac/MutationObserver.js/master/test/index.html) and see some simple example usage:
-
-* http://jsbin.com/suqewogone listen to images being appended dynamically
-* http://jsbin.com/bapohopuwi autoscroll an element as new content is added
-
-See http://dev.opera.com/articles/view/mutation-observers-tutorial/ for some sample usage.
diff --git a/files/plugin-HeatmapSessionRecording-5.2.6/libs/MutationObserver.js/dist/README.md b/files/plugin-HeatmapSessionRecording-5.2.6/libs/MutationObserver.js/dist/README.md
deleted file mode 100644
index a3e83b2..0000000
--- a/files/plugin-HeatmapSessionRecording-5.2.6/libs/MutationObserver.js/dist/README.md
+++ /dev/null
@@ -1,7 +0,0 @@
-###Compiled files
-
-*Compiled by Google closure compiler in `ADVANCED_OPTIMIZATIONS`*
-
-- Original: 25 kB
-- Minified: 3.7 kB
-- Gzipped: 1.6 kB
diff --git a/files/plugin-HeatmapSessionRecording-5.2.6/libs/MutationObserver.js/dist/mutationobserver.min.js b/files/plugin-HeatmapSessionRecording-5.2.6/libs/MutationObserver.js/dist/mutationobserver.min.js
deleted file mode 100644
index 94e8949..0000000
--- a/files/plugin-HeatmapSessionRecording-5.2.6/libs/MutationObserver.js/dist/mutationobserver.min.js
+++ /dev/null
@@ -1,10 +0,0 @@
-// mutationobserver-shim v0.3.2 (github.com/megawac/MutationObserver.js)
-// Authors: Graeme Yeates (github.com/megawac)
-window.MutationObserver=window.MutationObserver||function(w){function v(a){this.i=[];this.m=a}function I(a){(function c(){var d=a.takeRecords();d.length&&a.m(d,a);a.h=setTimeout(c,v._period)})()}function p(a){var b={type:null,target:null,addedNodes:[],removedNodes:[],previousSibling:null,nextSibling:null,attributeName:null,attributeNamespace:null,oldValue:null},c;for(c in a)b[c]!==w&&a[c]!==w&&(b[c]=a[c]);return b}function J(a,b){var c=C(a,b);return function(d){var f=d.length,n;b.a&&3===a.nodeType&&
-a.nodeValue!==c.a&&d.push(new p({type:"characterData",target:a,oldValue:c.a}));b.b&&c.b&&A(d,a,c.b,b.f);if(b.c||b.g)n=K(d,a,c,b);if(n||d.length!==f)c=C(a,b)}}function L(a,b){return b.value}function M(a,b){return"style"!==b.name?b.value:a.style.cssText}function A(a,b,c,d){for(var f={},n=b.attributes,k,g,x=n.length;x--;)k=n[x],g=k.name,d&&d[g]===w||(D(b,k)!==c[g]&&a.push(p({type:"attributes",target:b,attributeName:g,oldValue:c[g],attributeNamespace:k.namespaceURI})),f[g]=!0);for(g in c)f[g]||a.push(p({target:b,
-type:"attributes",attributeName:g,oldValue:c[g]}))}function K(a,b,c,d){function f(b,c,f,k,y){var g=b.length-1;y=-~((g-y)/2);for(var h,l,e;e=b.pop();)h=f[e.j],l=k[e.l],d.c&&y&&Math.abs(e.j-e.l)>=g&&(a.push(p({type:"childList",target:c,addedNodes:[h],removedNodes:[h],nextSibling:h.nextSibling,previousSibling:h.previousSibling})),y--),d.b&&l.b&&A(a,h,l.b,d.f),d.a&&3===h.nodeType&&h.nodeValue!==l.a&&a.push(p({type:"characterData",target:h,oldValue:l.a})),d.g&&n(h,l)}function n(b,c){for(var g=b.childNodes,
-q=c.c,x=g.length,v=q?q.length:0,h,l,e,m,t,z=0,u=0,r=0;u
-
-This work is free. You can redistribute it and/or modify it under the
-terms of the Do What The Fuck You Want To Public License, Version 2,
-as published by Sam Hocevar. See http://www.wtfpl.net/ for more details.
-
-This program is free software. It comes without any warranty, to
-the extent permitted by applicable law. You can redistribute it
-and/or modify it under the terms of the Do What The Fuck You Want
-To Public License, Version 2, as published by Sam Hocevar. See
-http://www.wtfpl.net/ for more details.
\ No newline at end of file
diff --git a/files/plugin-HeatmapSessionRecording-5.2.6/libs/MutationObserver.js/package.json b/files/plugin-HeatmapSessionRecording-5.2.6/libs/MutationObserver.js/package.json
deleted file mode 100644
index f99c9bc..0000000
--- a/files/plugin-HeatmapSessionRecording-5.2.6/libs/MutationObserver.js/package.json
+++ /dev/null
@@ -1,49 +0,0 @@
-{
- "name": "mutationobserver-shim",
- "short name": "mutationobserver",
- "description": "MutationObserver shim for ES3 environments",
- "version": "0.3.2",
- "keywords": [
- "DOM",
- "observer",
- "mutation observer",
- "MutationObserver"
- ],
- "authors": [
- {
- "name": "Graeme Yeates",
- "email": "github.com/megawac"
- }
- ],
- "repository": {
- "type": "git",
- "git": "git@github.com:megawac/MutationObserver.js.git",
- "url": "github.com/megawac/MutationObserver.js"
- },
- "main": "dist/mutationobserver.min.js",
- "scripts": {
- "test": "grunt test --verbose"
- },
- "files": [
- "MutationObserver.js",
- "dist/mutationobserver.min.js"
- ],
- "license": {
- "type": "WTFPL",
- "version": "v2 2004",
- "url": "http://www.wtfpl.net/"
- },
- "devDependencies": {
- "grunt": "~0.4.2",
- "grunt-bumpup": "~0.5.0",
- "grunt-closurecompiler": "0.9",
- "grunt-contrib-connect": "0.7",
- "grunt-contrib-jshint": ">= 0.8",
- "grunt-contrib-qunit": "~0.5.0",
- "grunt-file-info": "~1.0.14",
- "grunt-saucelabs": "~4.1.2",
- "grunt-tagrelease": "~0.3.1",
- "matchdep": "~0.3.0",
- "phantomjs": "1.9.x"
- }
-}
\ No newline at end of file
diff --git a/files/plugin-HeatmapSessionRecording-5.2.6/libs/mutation-summary/COPYING b/files/plugin-HeatmapSessionRecording-5.2.6/libs/mutation-summary/COPYING
deleted file mode 100644
index 65ee1c1..0000000
--- a/files/plugin-HeatmapSessionRecording-5.2.6/libs/mutation-summary/COPYING
+++ /dev/null
@@ -1,202 +0,0 @@
-
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
-TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
-1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
-2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
-3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
-4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
-5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
-6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
-7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
-8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
-9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
-END OF TERMS AND CONDITIONS
-
-APPENDIX: How to apply the Apache License to your work.
-
- To apply the Apache License to your work, attach the following
- boilerplate notice, with the fields enclosed by brackets "[]"
- replaced with your own identifying information. (Don't include
- the brackets!) The text should be enclosed in the appropriate
- comment syntax for the file format. We also recommend that a
- file or class name and description of purpose be included on the
- same "printed page" as the copyright notice for easier
- identification within third-party archives.
-
-Copyright [yyyy] [name of copyright owner]
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
\ No newline at end of file
diff --git a/files/plugin-HeatmapSessionRecording-5.2.6/libs/mutation-summary/README.md b/files/plugin-HeatmapSessionRecording-5.2.6/libs/mutation-summary/README.md
deleted file mode 100644
index 5eac04f..0000000
--- a/files/plugin-HeatmapSessionRecording-5.2.6/libs/mutation-summary/README.md
+++ /dev/null
@@ -1,59 +0,0 @@
-# What is this? #
-
-Mutation Summary is a JavaScript library that makes observing changes to the DOM fast, easy and safe.
-
-It's built on top of (and requires) a new browser API called [DOM Mutation Observers](http://dom.spec.whatwg.org/#mutation-observers).
-
- * [Browsers which currently implement DOM Mutation Observers](DOMMutationObservers.md#browser-availability).
- * [DOM Mutation Observers API and its relationship to this library and (the deprecated) DOM Mutation Events](DOMMutationObservers.md).
-
-
-
-# Why do I need it? #
-
-Mutation Summary does five main things for you:
-
- * **It tells you how the document is different now from how it was.** As its name suggests, it summarizes what’s happened. It’s as if it takes a picture of the document when you first create it, and then again after each time it calls you back. When things have changed, it calls you with a concise description of exactly what’s different now from the last picture it took for you.
- * **It handles any and all changes, no matter how complex.** All kinds of things can happen to the DOM: values can change and but put back to what they were, large parts can be pulled out, changed, rearranged, put back. Mutation Summary can take any crazy thing you throw at it. Go ahead, tear the document to shreds, Mutation Summary won’t even blink.
- * **It lets you express what kinds of things you’re interested in.** It presents a query API that lets you tell it exactly what kinds of changes you’re interested in. This includes support for simple CSS-like selector descriptions of elements you care about.
- * **It’s fast.** The time and memory it takes is dependant on number of changes that occurred (which typically involves only a few nodes) -- not the size of your document (which is commonly thousands of nodes).
- * **It can automatically ignore changes you make during your callback.** Mutation Summary is going to call you back when changes have occurred. If you need to react to those changes by making more changes -- won’t you hear about those changes the next time it calls you back? Not unless you [ask for that](APIReference.md#configuration-options). By default, it stops watching the document immediately before it calls you back and resumes watching as soon as your callback finishes.
-
-# What is it useful for? #
-
-Lots of things, here are some examples:
-
- * **Browser extensions.** Want to make a browser extension that creates a link to your mapping application whenever an address appears in a page? You’ll need to know when those addresses appear (and disappear).
- * **Implement missing HTML capabilities.** Think building web apps is too darn hard and you know what’s missing from HTML that would make it a snap? Writing the code for the desired behavior is only half the battle--you’ll also need to know when those elements and attributes show up and what happens to them. In fact, there’s already two widely used classes of libraries which do exactly this, but don’t currently have a good way to observe changes to the DOM.
- * **UI Widget** libraries, e.g. Dojo Widgets
- * **Templating** and/or **Databinding** libraries, e.g. Angular or KnockoutJS
- * **Text Editors.** HTML Text editors often want to observe what’s being input and “fix it up” so that they can maintain a consistent WYSWIG UI.
-
-# What is this _not_ useful for? #
-
-The intent here isn't to be all things to all use-cases. Mutation Summary is not meant to:
-
- * **Use the DOM as some sort of state-transition machine.** It won't report transient states that the DOM moved through. It will only tell you what the difference is between the previous state and the present one.
- * **Observing complex selectors.** It offers support for a simple [subset of CSS selectors](APIReference.md#supported-selector-syntax). Want to observe all elements that match `“div[foo] span.bar > p:first-child”`? Unfortunately, efficiently computing that is much harder and currently outside the scope of this library.
-
-Note that both of the above use cases are possible given the data that the underlying Mutation Observers API provides -- we simply judged them to be outside the "80% use case" that we targeted with this particular library.
-
-# Where can Mutation Summary be used? #
-
-The Mutation Summary library depends on the presence of the Mutation Observer DOM API. Mutation Observers are available in
-
- * [Google Chrome](https://www.google.com/chrome)
- * [Firefox](http://www.mozilla.org/en-US/firefox/new/)
- * [Safari](http://www.apple.com/safari/)
- * [Opera](http://www.opera.com/)
- * [IE11](http://www.microsoft.com/ie)
-
-Mutation Observers is the work of the [W3C WebApps working group](http://www.w3.org/2008/webapps/). In the future it will be implemented in other browsers (we’ll keep the above list of supporting browsers as up-to-date as possible).
-
-# Great. I want to get started. What’s next? #
-
- * Check out the [tutorial](Tutorial.md) and the [API reference](APIReference.md).
-
-# Google groups discussion list #
-
- * [mutation-summary-discuss@googlegroups.com](https://groups.google.com/group/mutation-summary-discuss)
diff --git a/files/plugin-HeatmapSessionRecording-5.2.6/libs/mutation-summary/package.json b/files/plugin-HeatmapSessionRecording-5.2.6/libs/mutation-summary/package.json
deleted file mode 100644
index 3029ee6..0000000
--- a/files/plugin-HeatmapSessionRecording-5.2.6/libs/mutation-summary/package.json
+++ /dev/null
@@ -1,30 +0,0 @@
-{
- "name": "mutation-summary",
- "version": "0.0.0",
- "description": "Makes observing the DOM fast and easy",
- "main": "src/mutation-summary.js",
- "directories": {
- "example": "examples",
- "test": "tests"
- },
- "scripts": {
- "test": "echo \"Error: no test specified\" && exit 1"
- },
- "repository": {
- "type": "git",
- "url": "https://code.google.com/p/mutation-summary/"
- },
- "author": "",
- "license": "Apache 2.0",
- "devDependencies": {
- "chai": "*",
- "mocha": "*"
- }
-}
-
-
-
-
-
-
-
diff --git a/files/plugin-HeatmapSessionRecording-5.2.6/libs/mutation-summary/src/mutation-summary.js b/files/plugin-HeatmapSessionRecording-5.2.6/libs/mutation-summary/src/mutation-summary.js
deleted file mode 100644
index feef885..0000000
--- a/files/plugin-HeatmapSessionRecording-5.2.6/libs/mutation-summary/src/mutation-summary.js
+++ /dev/null
@@ -1,1406 +0,0 @@
-// Copyright 2011 Google Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-var __extends = (this && this.__extends) || (function () {
- var extendStatics = function (d, b) {
- extendStatics = Object.setPrototypeOf ||
- ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
- function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
- return extendStatics(d, b);
- };
- return function (d, b) {
- if (typeof b !== "function" && b !== null)
- throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
- extendStatics(d, b);
- function __() { this.constructor = d; }
- d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
- };
-})();
-var MutationObserverCtor;
-if (typeof WebKitMutationObserver !== 'undefined')
- MutationObserverCtor = WebKitMutationObserver;
-else
- MutationObserverCtor = MutationObserver;
-if (MutationObserverCtor === undefined) {
- console.error('DOM Mutation Observers are required.');
- console.error('https://developer.mozilla.org/en-US/docs/DOM/MutationObserver');
- throw Error('DOM Mutation Observers are required');
-}
-var NodeMap = /** @class */ (function () {
- function NodeMap() {
- this.nodes = [];
- this.values = [];
- }
- NodeMap.prototype.isIndex = function (s) {
- return +s === s >>> 0;
- };
- NodeMap.prototype.nodeId = function (node) {
- var id = node[NodeMap.ID_PROP];
- if (!id)
- id = node[NodeMap.ID_PROP] = NodeMap.nextId_++;
- return id;
- };
- NodeMap.prototype.set = function (node, value) {
- var id = this.nodeId(node);
- this.nodes[id] = node;
- this.values[id] = value;
- };
- NodeMap.prototype.get = function (node) {
- var id = this.nodeId(node);
- return this.values[id];
- };
- NodeMap.prototype.has = function (node) {
- return this.nodeId(node) in this.nodes;
- };
- NodeMap.prototype["delete"] = function (node) {
- var id = this.nodeId(node);
- delete this.nodes[id];
- this.values[id] = undefined;
- };
- NodeMap.prototype.keys = function () {
- var nodes = [];
- for (var id in this.nodes) {
- if (!this.isIndex(id))
- continue;
- nodes.push(this.nodes[id]);
- }
- return nodes;
- };
- NodeMap.ID_PROP = '__mutation_summary_node_map_id__';
- NodeMap.nextId_ = 1;
- return NodeMap;
-}());
-/**
- * var reachableMatchableProduct = [
- * // STAYED_OUT, ENTERED, STAYED_IN, EXITED
- * [ STAYED_OUT, STAYED_OUT, STAYED_OUT, STAYED_OUT ], // STAYED_OUT
- * [ STAYED_OUT, ENTERED, ENTERED, STAYED_OUT ], // ENTERED
- * [ STAYED_OUT, ENTERED, STAYED_IN, EXITED ], // STAYED_IN
- * [ STAYED_OUT, STAYED_OUT, EXITED, EXITED ] // EXITED
- * ];
- */
-var Movement;
-(function (Movement) {
- Movement[Movement["STAYED_OUT"] = 0] = "STAYED_OUT";
- Movement[Movement["ENTERED"] = 1] = "ENTERED";
- Movement[Movement["STAYED_IN"] = 2] = "STAYED_IN";
- Movement[Movement["REPARENTED"] = 3] = "REPARENTED";
- Movement[Movement["REORDERED"] = 4] = "REORDERED";
- Movement[Movement["EXITED"] = 5] = "EXITED";
-})(Movement || (Movement = {}));
-function enteredOrExited(changeType) {
- return changeType === Movement.ENTERED || changeType === Movement.EXITED;
-}
-var NodeChange = /** @class */ (function () {
- function NodeChange(node, childList, attributes, characterData, oldParentNode, added, attributeOldValues, characterDataOldValue) {
- if (childList === void 0) { childList = false; }
- if (attributes === void 0) { attributes = false; }
- if (characterData === void 0) { characterData = false; }
- if (oldParentNode === void 0) { oldParentNode = null; }
- if (added === void 0) { added = false; }
- if (attributeOldValues === void 0) { attributeOldValues = null; }
- if (characterDataOldValue === void 0) { characterDataOldValue = null; }
- this.node = node;
- this.childList = childList;
- this.attributes = attributes;
- this.characterData = characterData;
- this.oldParentNode = oldParentNode;
- this.added = added;
- this.attributeOldValues = attributeOldValues;
- this.characterDataOldValue = characterDataOldValue;
- this.isCaseInsensitive =
- this.node.nodeType === Node.ELEMENT_NODE &&
- this.node instanceof HTMLElement &&
- this.node.ownerDocument instanceof HTMLDocument;
- }
- NodeChange.prototype.getAttributeOldValue = function (name) {
- if (!this.attributeOldValues)
- return undefined;
- if (this.isCaseInsensitive)
- name = name.toLowerCase();
- return this.attributeOldValues[name];
- };
- NodeChange.prototype.getAttributeNamesMutated = function () {
- var names = [];
- if (!this.attributeOldValues)
- return names;
- for (var name in this.attributeOldValues) {
- names.push(name);
- }
- return names;
- };
- NodeChange.prototype.attributeMutated = function (name, oldValue) {
- this.attributes = true;
- this.attributeOldValues = this.attributeOldValues || {};
- if (name in this.attributeOldValues)
- return;
- this.attributeOldValues[name] = oldValue;
- };
- NodeChange.prototype.characterDataMutated = function (oldValue) {
- if (this.characterData)
- return;
- this.characterData = true;
- this.characterDataOldValue = oldValue;
- };
- // Note: is it possible to receive a removal followed by a removal. This
- // can occur if the removed node is added to an non-observed node, that
- // node is added to the observed area, and then the node removed from
- // it.
- NodeChange.prototype.removedFromParent = function (parent) {
- this.childList = true;
- if (this.added || this.oldParentNode)
- this.added = false;
- else
- this.oldParentNode = parent;
- };
- NodeChange.prototype.insertedIntoParent = function () {
- this.childList = true;
- this.added = true;
- };
- // An node's oldParent is
- // -its present parent, if its parentNode was not changed.
- // -null if the first thing that happened to it was an add.
- // -the node it was removed from if the first thing that happened to it
- // was a remove.
- NodeChange.prototype.getOldParent = function () {
- if (this.childList) {
- if (this.oldParentNode)
- return this.oldParentNode;
- if (this.added)
- return null;
- }
- return this.node.parentNode;
- };
- return NodeChange;
-}());
-var ChildListChange = /** @class */ (function () {
- function ChildListChange() {
- this.added = new NodeMap();
- this.removed = new NodeMap();
- this.maybeMoved = new NodeMap();
- this.oldPrevious = new NodeMap();
- this.moved = undefined;
- }
- return ChildListChange;
-}());
-var TreeChanges = /** @class */ (function (_super) {
- __extends(TreeChanges, _super);
- function TreeChanges(rootNode, mutations) {
- var _this = _super.call(this) || this;
- _this.rootNode = rootNode;
- _this.reachableCache = undefined;
- _this.wasReachableCache = undefined;
- _this.anyParentsChanged = false;
- _this.anyAttributesChanged = false;
- _this.anyCharacterDataChanged = false;
- for (var m = 0; m < mutations.length; m++) {
- var mutation = mutations[m];
- switch (mutation.type) {
- case 'childList':
- _this.anyParentsChanged = true;
- for (var i = 0; i < mutation.removedNodes.length; i++) {
- var node = mutation.removedNodes[i];
- _this.getChange(node).removedFromParent(mutation.target);
- }
- for (var i = 0; i < mutation.addedNodes.length; i++) {
- var node = mutation.addedNodes[i];
- _this.getChange(node).insertedIntoParent();
- }
- break;
- case 'attributes':
- _this.anyAttributesChanged = true;
- var change = _this.getChange(mutation.target);
- change.attributeMutated(mutation.attributeName, mutation.oldValue);
- break;
- case 'characterData':
- _this.anyCharacterDataChanged = true;
- var change = _this.getChange(mutation.target);
- change.characterDataMutated(mutation.oldValue);
- break;
- }
- }
- return _this;
- }
- TreeChanges.prototype.getChange = function (node) {
- var change = this.get(node);
- if (!change) {
- change = new NodeChange(node);
- this.set(node, change);
- }
- return change;
- };
- TreeChanges.prototype.getOldParent = function (node) {
- var change = this.get(node);
- return change ? change.getOldParent() : node.parentNode;
- };
- TreeChanges.prototype.getIsReachable = function (node) {
- if (node === this.rootNode)
- return true;
- if (!node)
- return false;
- this.reachableCache = this.reachableCache || new NodeMap();
- var isReachable = this.reachableCache.get(node);
- if (isReachable === undefined) {
- isReachable = this.getIsReachable(node.parentNode);
- this.reachableCache.set(node, isReachable);
- }
- return isReachable;
- };
- // A node wasReachable if its oldParent wasReachable.
- TreeChanges.prototype.getWasReachable = function (node) {
- if (node === this.rootNode)
- return true;
- if (!node)
- return false;
- this.wasReachableCache = this.wasReachableCache || new NodeMap();
- var wasReachable = this.wasReachableCache.get(node);
- if (wasReachable === undefined) {
- wasReachable = this.getWasReachable(this.getOldParent(node));
- this.wasReachableCache.set(node, wasReachable);
- }
- return wasReachable;
- };
- TreeChanges.prototype.reachabilityChange = function (node) {
- if (this.getIsReachable(node)) {
- return this.getWasReachable(node) ?
- Movement.STAYED_IN : Movement.ENTERED;
- }
- return this.getWasReachable(node) ?
- Movement.EXITED : Movement.STAYED_OUT;
- };
- return TreeChanges;
-}(NodeMap));
-var MutationProjection = /** @class */ (function () {
- // TOOD(any)
- function MutationProjection(rootNode, mutations, selectors, calcReordered, calcOldPreviousSibling) {
- this.rootNode = rootNode;
- this.mutations = mutations;
- this.selectors = selectors;
- this.calcReordered = calcReordered;
- this.calcOldPreviousSibling = calcOldPreviousSibling;
- this.treeChanges = new TreeChanges(rootNode, mutations);
- this.entered = [];
- this.exited = [];
- this.stayedIn = new NodeMap();
- this.visited = new NodeMap();
- this.childListChangeMap = undefined;
- this.characterDataOnly = undefined;
- this.matchCache = undefined;
- this.processMutations();
- }
- MutationProjection.prototype.processMutations = function () {
- if (!this.treeChanges.anyParentsChanged &&
- !this.treeChanges.anyAttributesChanged)
- return;
- var changedNodes = this.treeChanges.keys();
- for (var i = 0; i < changedNodes.length; i++) {
- this.visitNode(changedNodes[i], undefined);
- }
- };
- MutationProjection.prototype.visitNode = function (node, parentReachable) {
- if (this.visited.has(node))
- return;
- this.visited.set(node, true);
- var change = this.treeChanges.get(node);
- var reachable = parentReachable;
- // node inherits its parent's reachability change unless
- // its parentNode was mutated.
- if ((change && change.childList) || reachable == undefined)
- reachable = this.treeChanges.reachabilityChange(node);
- if (reachable === Movement.STAYED_OUT)
- return;
- // Cache match results for sub-patterns.
- this.matchabilityChange(node);
- if (reachable === Movement.ENTERED) {
- this.entered.push(node);
- }
- else if (reachable === Movement.EXITED) {
- this.exited.push(node);
- this.ensureHasOldPreviousSiblingIfNeeded(node);
- }
- else if (reachable === Movement.STAYED_IN) {
- var movement = Movement.STAYED_IN;
- if (change && change.childList) {
- if (change.oldParentNode !== node.parentNode) {
- movement = Movement.REPARENTED;
- this.ensureHasOldPreviousSiblingIfNeeded(node);
- }
- else if (this.calcReordered && this.wasReordered(node)) {
- movement = Movement.REORDERED;
- }
- }
- this.stayedIn.set(node, movement);
- }
- if (reachable === Movement.STAYED_IN)
- return;
- // reachable === ENTERED || reachable === EXITED.
- for (var child = node.firstChild; child; child = child.nextSibling) {
- this.visitNode(child, reachable);
- }
- };
- MutationProjection.prototype.ensureHasOldPreviousSiblingIfNeeded = function (node) {
- if (!this.calcOldPreviousSibling)
- return;
- this.processChildlistChanges();
- var parentNode = node.parentNode;
- var nodeChange = this.treeChanges.get(node);
- if (nodeChange && nodeChange.oldParentNode)
- parentNode = nodeChange.oldParentNode;
- var change = this.childListChangeMap.get(parentNode);
- if (!change) {
- change = new ChildListChange();
- this.childListChangeMap.set(parentNode, change);
- }
- if (!change.oldPrevious.has(node)) {
- change.oldPrevious.set(node, node.previousSibling);
- }
- };
- MutationProjection.prototype.getChanged = function (summary, selectors, characterDataOnly) {
- this.selectors = selectors;
- this.characterDataOnly = characterDataOnly;
- for (var i = 0; i < this.entered.length; i++) {
- var node = this.entered[i];
- var matchable = this.matchabilityChange(node);
- if (matchable === Movement.ENTERED || matchable === Movement.STAYED_IN)
- summary.added.push(node);
- }
- var stayedInNodes = this.stayedIn.keys();
- for (var i = 0; i < stayedInNodes.length; i++) {
- var node = stayedInNodes[i];
- var matchable = this.matchabilityChange(node);
- if (matchable === Movement.ENTERED) {
- summary.added.push(node);
- }
- else if (matchable === Movement.EXITED) {
- summary.removed.push(node);
- }
- else if (matchable === Movement.STAYED_IN && (summary.reparented || summary.reordered)) {
- var movement = this.stayedIn.get(node);
- if (summary.reparented && movement === Movement.REPARENTED)
- summary.reparented.push(node);
- else if (summary.reordered && movement === Movement.REORDERED)
- summary.reordered.push(node);
- }
- }
- for (var i = 0; i < this.exited.length; i++) {
- var node = this.exited[i];
- var matchable = this.matchabilityChange(node);
- if (matchable === Movement.EXITED || matchable === Movement.STAYED_IN)
- summary.removed.push(node);
- }
- };
- MutationProjection.prototype.getOldParentNode = function (node) {
- var change = this.treeChanges.get(node);
- if (change && change.childList)
- return change.oldParentNode ? change.oldParentNode : null;
- var reachabilityChange = this.treeChanges.reachabilityChange(node);
- if (reachabilityChange === Movement.STAYED_OUT || reachabilityChange === Movement.ENTERED)
- throw Error('getOldParentNode requested on invalid node.');
- return node.parentNode;
- };
- MutationProjection.prototype.getOldPreviousSibling = function (node) {
- var parentNode = node.parentNode;
- var nodeChange = this.treeChanges.get(node);
- if (nodeChange && nodeChange.oldParentNode)
- parentNode = nodeChange.oldParentNode;
- var change = this.childListChangeMap.get(parentNode);
- if (!change)
- throw Error('getOldPreviousSibling requested on invalid node.');
- return change.oldPrevious.get(node);
- };
- MutationProjection.prototype.getOldAttribute = function (element, attrName) {
- var change = this.treeChanges.get(element);
- if (!change || !change.attributes)
- throw Error('getOldAttribute requested on invalid node.');
- var value = change.getAttributeOldValue(attrName);
- if (value === undefined)
- throw Error('getOldAttribute requested for unchanged attribute name.');
- return value;
- };
- MutationProjection.prototype.attributeChangedNodes = function (includeAttributes) {
- if (!this.treeChanges.anyAttributesChanged)
- return {}; // No attributes mutations occurred.
- var attributeFilter;
- var caseInsensitiveFilter;
- if (includeAttributes) {
- attributeFilter = {};
- caseInsensitiveFilter = {};
- for (var i = 0; i < includeAttributes.length; i++) {
- var attrName = includeAttributes[i];
- attributeFilter[attrName] = true;
- caseInsensitiveFilter[attrName.toLowerCase()] = attrName;
- }
- }
- var result = {};
- var nodes = this.treeChanges.keys();
- for (var i = 0; i < nodes.length; i++) {
- var node = nodes[i];
- var change = this.treeChanges.get(node);
- if (!change.attributes)
- continue;
- if (Movement.STAYED_IN !== this.treeChanges.reachabilityChange(node) ||
- Movement.STAYED_IN !== this.matchabilityChange(node)) {
- continue;
- }
- var element = node;
- var changedAttrNames = change.getAttributeNamesMutated();
- for (var j = 0; j < changedAttrNames.length; j++) {
- var attrName = changedAttrNames[j];
- if (attributeFilter &&
- !attributeFilter[attrName] &&
- !(change.isCaseInsensitive && caseInsensitiveFilter[attrName])) {
- continue;
- }
- var oldValue = change.getAttributeOldValue(attrName);
- if (oldValue === element.getAttribute(attrName))
- continue;
- if (caseInsensitiveFilter && change.isCaseInsensitive)
- attrName = caseInsensitiveFilter[attrName];
- result[attrName] = result[attrName] || [];
- result[attrName].push(element);
- }
- }
- return result;
- };
- MutationProjection.prototype.getOldCharacterData = function (node) {
- var change = this.treeChanges.get(node);
- if (!change || !change.characterData)
- throw Error('getOldCharacterData requested on invalid node.');
- return change.characterDataOldValue;
- };
- MutationProjection.prototype.getCharacterDataChanged = function () {
- if (!this.treeChanges.anyCharacterDataChanged)
- return []; // No characterData mutations occurred.
- var nodes = this.treeChanges.keys();
- var result = [];
- for (var i = 0; i < nodes.length; i++) {
- var target = nodes[i];
- if (Movement.STAYED_IN !== this.treeChanges.reachabilityChange(target))
- continue;
- var change = this.treeChanges.get(target);
- if (!change.characterData ||
- target.textContent == change.characterDataOldValue)
- continue;
- result.push(target);
- }
- return result;
- };
- MutationProjection.prototype.computeMatchabilityChange = function (selector, el) {
- if (!this.matchCache)
- this.matchCache = [];
- if (!this.matchCache[selector.uid])
- this.matchCache[selector.uid] = new NodeMap();
- var cache = this.matchCache[selector.uid];
- var result = cache.get(el);
- if (result === undefined) {
- result = selector.matchabilityChange(el, this.treeChanges.get(el));
- cache.set(el, result);
- }
- return result;
- };
- MutationProjection.prototype.matchabilityChange = function (node) {
- var _this = this;
- // TODO(rafaelw): Include PI, CDATA?
- // Only include text nodes.
- if (this.characterDataOnly) {
- switch (node.nodeType) {
- case Node.COMMENT_NODE:
- case Node.TEXT_NODE:
- return Movement.STAYED_IN;
- default:
- return Movement.STAYED_OUT;
- }
- }
- // No element filter. Include all nodes.
- if (!this.selectors)
- return Movement.STAYED_IN;
- // Element filter. Exclude non-elements.
- if (node.nodeType !== Node.ELEMENT_NODE)
- return Movement.STAYED_OUT;
- var el = node;
- var matchChanges = this.selectors.map(function (selector) {
- return _this.computeMatchabilityChange(selector, el);
- });
- var accum = Movement.STAYED_OUT;
- var i = 0;
- while (accum !== Movement.STAYED_IN && i < matchChanges.length) {
- switch (matchChanges[i]) {
- case Movement.STAYED_IN:
- accum = Movement.STAYED_IN;
- break;
- case Movement.ENTERED:
- if (accum === Movement.EXITED)
- accum = Movement.STAYED_IN;
- else
- accum = Movement.ENTERED;
- break;
- case Movement.EXITED:
- if (accum === Movement.ENTERED)
- accum = Movement.STAYED_IN;
- else
- accum = Movement.EXITED;
- break;
- }
- i++;
- }
- return accum;
- };
- MutationProjection.prototype.getChildlistChange = function (el) {
- var change = this.childListChangeMap.get(el);
- if (!change) {
- change = new ChildListChange();
- this.childListChangeMap.set(el, change);
- }
- return change;
- };
- MutationProjection.prototype.processChildlistChanges = function () {
- if (this.childListChangeMap)
- return;
- this.childListChangeMap = new NodeMap();
- for (var i = 0; i < this.mutations.length; i++) {
- var mutation = this.mutations[i];
- if (mutation.type != 'childList')
- continue;
- if (this.treeChanges.reachabilityChange(mutation.target) !== Movement.STAYED_IN &&
- !this.calcOldPreviousSibling)
- continue;
- var change = this.getChildlistChange(mutation.target);
- var oldPrevious = mutation.previousSibling;
- function recordOldPrevious(node, previous) {
- if (!node ||
- change.oldPrevious.has(node) ||
- change.added.has(node) ||
- change.maybeMoved.has(node))
- return;
- if (previous &&
- (change.added.has(previous) ||
- change.maybeMoved.has(previous)))
- return;
- change.oldPrevious.set(node, previous);
- }
- for (var j = 0; j < mutation.removedNodes.length; j++) {
- var node = mutation.removedNodes[j];
- recordOldPrevious(node, oldPrevious);
- if (change.added.has(node)) {
- change.added["delete"](node);
- }
- else {
- change.removed.set(node, true);
- change.maybeMoved["delete"](node);
- }
- oldPrevious = node;
- }
- recordOldPrevious(mutation.nextSibling, oldPrevious);
- for (var j = 0; j < mutation.addedNodes.length; j++) {
- var node = mutation.addedNodes[j];
- if (change.removed.has(node)) {
- change.removed["delete"](node);
- change.maybeMoved.set(node, true);
- }
- else {
- change.added.set(node, true);
- }
- }
- }
- };
- MutationProjection.prototype.wasReordered = function (node) {
- if (!this.treeChanges.anyParentsChanged)
- return false;
- this.processChildlistChanges();
- var parentNode = node.parentNode;
- var nodeChange = this.treeChanges.get(node);
- if (nodeChange && nodeChange.oldParentNode)
- parentNode = nodeChange.oldParentNode;
- var change = this.childListChangeMap.get(parentNode);
- if (!change)
- return false;
- if (change.moved)
- return change.moved.get(node);
- change.moved = new NodeMap();
- var pendingMoveDecision = new NodeMap();
- function isMoved(node) {
- if (!node)
- return false;
- if (!change.maybeMoved.has(node))
- return false;
- var didMove = change.moved.get(node);
- if (didMove !== undefined)
- return didMove;
- if (pendingMoveDecision.has(node)) {
- didMove = true;
- }
- else {
- pendingMoveDecision.set(node, true);
- didMove = getPrevious(node) !== getOldPrevious(node);
- }
- if (pendingMoveDecision.has(node)) {
- pendingMoveDecision["delete"](node);
- change.moved.set(node, didMove);
- }
- else {
- didMove = change.moved.get(node);
- }
- return didMove;
- }
- var oldPreviousCache = new NodeMap();
- function getOldPrevious(node) {
- var oldPrevious = oldPreviousCache.get(node);
- if (oldPrevious !== undefined)
- return oldPrevious;
- oldPrevious = change.oldPrevious.get(node);
- while (oldPrevious &&
- (change.removed.has(oldPrevious) || isMoved(oldPrevious))) {
- oldPrevious = getOldPrevious(oldPrevious);
- }
- if (oldPrevious === undefined)
- oldPrevious = node.previousSibling;
- oldPreviousCache.set(node, oldPrevious);
- return oldPrevious;
- }
- var previousCache = new NodeMap();
- function getPrevious(node) {
- if (previousCache.has(node))
- return previousCache.get(node);
- var previous = node.previousSibling;
- while (previous && (change.added.has(previous) || isMoved(previous)))
- previous = previous.previousSibling;
- previousCache.set(node, previous);
- return previous;
- }
- change.maybeMoved.keys().forEach(isMoved);
- return change.moved.get(node);
- };
- return MutationProjection;
-}());
-var Summary = /** @class */ (function () {
- function Summary(projection, query) {
- var _this = this;
- this.projection = projection;
- this.added = [];
- this.removed = [];
- this.reparented = query.all || query.element || query.characterData ? [] : undefined;
- this.reordered = query.all ? [] : undefined;
- projection.getChanged(this, query.elementFilter, query.characterData);
- if (query.all || query.attribute || query.attributeList) {
- var filter = query.attribute ? [query.attribute] : query.attributeList;
- var attributeChanged = projection.attributeChangedNodes(filter);
- if (query.attribute) {
- this.valueChanged = attributeChanged[query.attribute] || [];
- }
- else {
- this.attributeChanged = attributeChanged;
- if (query.attributeList) {
- query.attributeList.forEach(function (attrName) {
- if (!_this.attributeChanged.hasOwnProperty(attrName))
- _this.attributeChanged[attrName] = [];
- });
- }
- }
- }
- if (query.all || query.characterData) {
- var characterDataChanged = projection.getCharacterDataChanged();
- if (query.characterData)
- this.valueChanged = characterDataChanged;
- else
- this.characterDataChanged = characterDataChanged;
- }
- if (this.reordered)
- this.getOldPreviousSibling = projection.getOldPreviousSibling.bind(projection);
- }
- Summary.prototype.getOldParentNode = function (node) {
- return this.projection.getOldParentNode(node);
- };
- Summary.prototype.getOldAttribute = function (node, name) {
- return this.projection.getOldAttribute(node, name);
- };
- Summary.prototype.getOldCharacterData = function (node) {
- return this.projection.getOldCharacterData(node);
- };
- Summary.prototype.getOldPreviousSibling = function (node) {
- return this.projection.getOldPreviousSibling(node);
- };
- return Summary;
-}());
-// TODO(rafaelw): Allow ':' and '.' as valid name characters.
-var validNameInitialChar = /[a-zA-Z_]+/;
-var validNameNonInitialChar = /[a-zA-Z0-9_\-]+/;
-// TODO(rafaelw): Consider allowing backslash in the attrValue.
-// TODO(rafaelw): There's got a to be way to represent this state machine
-// more compactly???
-function escapeQuotes(value) {
- return '"' + value.replace(/"/, '\\\"') + '"';
-}
-var Qualifier = /** @class */ (function () {
- function Qualifier() {
- }
- Qualifier.prototype.matches = function (oldValue) {
- if (oldValue === null)
- return false;
- if (this.attrValue === undefined)
- return true;
- if (!this.contains)
- return this.attrValue == oldValue;
- var tokens = oldValue.split(' ');
- for (var i = 0; i < tokens.length; i++) {
- if (this.attrValue === tokens[i])
- return true;
- }
- return false;
- };
- Qualifier.prototype.toString = function () {
- if (this.attrName === 'class' && this.contains)
- return '.' + this.attrValue;
- if (this.attrName === 'id' && !this.contains)
- return '#' + this.attrValue;
- if (this.contains)
- return '[' + this.attrName + '~=' + escapeQuotes(this.attrValue) + ']';
- if ('attrValue' in this)
- return '[' + this.attrName + '=' + escapeQuotes(this.attrValue) + ']';
- return '[' + this.attrName + ']';
- };
- return Qualifier;
-}());
-var Selector = /** @class */ (function () {
- function Selector() {
- this.uid = Selector.nextUid++;
- this.qualifiers = [];
- }
- Object.defineProperty(Selector.prototype, "caseInsensitiveTagName", {
- get: function () {
- return this.tagName.toUpperCase();
- },
- enumerable: false,
- configurable: true
- });
- Object.defineProperty(Selector.prototype, "selectorString", {
- get: function () {
- return this.tagName + this.qualifiers.join('');
- },
- enumerable: false,
- configurable: true
- });
- Selector.prototype.isMatching = function (el) {
- return el[Selector.matchesSelector](this.selectorString);
- };
- Selector.prototype.wasMatching = function (el, change, isMatching) {
- if (!change || !change.attributes)
- return isMatching;
- var tagName = change.isCaseInsensitive ? this.caseInsensitiveTagName : this.tagName;
- if (tagName !== '*' && tagName !== el.tagName)
- return false;
- var attributeOldValues = [];
- var anyChanged = false;
- for (var i = 0; i < this.qualifiers.length; i++) {
- var qualifier = this.qualifiers[i];
- var oldValue = change.getAttributeOldValue(qualifier.attrName);
- attributeOldValues.push(oldValue);
- anyChanged = anyChanged || (oldValue !== undefined);
- }
- if (!anyChanged)
- return isMatching;
- for (var i = 0; i < this.qualifiers.length; i++) {
- var qualifier = this.qualifiers[i];
- var oldValue = attributeOldValues[i];
- if (oldValue === undefined)
- oldValue = el.getAttribute(qualifier.attrName);
- if (!qualifier.matches(oldValue))
- return false;
- }
- return true;
- };
- Selector.prototype.matchabilityChange = function (el, change) {
- var isMatching = this.isMatching(el);
- if (isMatching)
- return this.wasMatching(el, change, isMatching) ? Movement.STAYED_IN : Movement.ENTERED;
- else
- return this.wasMatching(el, change, isMatching) ? Movement.EXITED : Movement.STAYED_OUT;
- };
- Selector.parseSelectors = function (input) {
- var selectors = [];
- var currentSelector;
- var currentQualifier;
- function newSelector() {
- if (currentSelector) {
- if (currentQualifier) {
- currentSelector.qualifiers.push(currentQualifier);
- currentQualifier = undefined;
- }
- selectors.push(currentSelector);
- }
- currentSelector = new Selector();
- }
- function newQualifier() {
- if (currentQualifier)
- currentSelector.qualifiers.push(currentQualifier);
- currentQualifier = new Qualifier();
- }
- var WHITESPACE = /\s/;
- var valueQuoteChar;
- var SYNTAX_ERROR = 'Invalid or unsupported selector syntax.';
- var SELECTOR = 1;
- var TAG_NAME = 2;
- var QUALIFIER = 3;
- var QUALIFIER_NAME_FIRST_CHAR = 4;
- var QUALIFIER_NAME = 5;
- var ATTR_NAME_FIRST_CHAR = 6;
- var ATTR_NAME = 7;
- var EQUIV_OR_ATTR_QUAL_END = 8;
- var EQUAL = 9;
- var ATTR_QUAL_END = 10;
- var VALUE_FIRST_CHAR = 11;
- var VALUE = 12;
- var QUOTED_VALUE = 13;
- var SELECTOR_SEPARATOR = 14;
- var state = SELECTOR;
- var i = 0;
- while (i < input.length) {
- var c = input[i++];
- switch (state) {
- case SELECTOR:
- if (c.match(validNameInitialChar)) {
- newSelector();
- currentSelector.tagName = c;
- state = TAG_NAME;
- break;
- }
- if (c == '*') {
- newSelector();
- currentSelector.tagName = '*';
- state = QUALIFIER;
- break;
- }
- if (c == '.') {
- newSelector();
- newQualifier();
- currentSelector.tagName = '*';
- currentQualifier.attrName = 'class';
- currentQualifier.contains = true;
- state = QUALIFIER_NAME_FIRST_CHAR;
- break;
- }
- if (c == '#') {
- newSelector();
- newQualifier();
- currentSelector.tagName = '*';
- currentQualifier.attrName = 'id';
- state = QUALIFIER_NAME_FIRST_CHAR;
- break;
- }
- if (c == '[') {
- newSelector();
- newQualifier();
- currentSelector.tagName = '*';
- currentQualifier.attrName = '';
- state = ATTR_NAME_FIRST_CHAR;
- break;
- }
- if (c.match(WHITESPACE))
- break;
- throw Error(SYNTAX_ERROR);
- case TAG_NAME:
- if (c.match(validNameNonInitialChar)) {
- currentSelector.tagName += c;
- break;
- }
- if (c == '.') {
- newQualifier();
- currentQualifier.attrName = 'class';
- currentQualifier.contains = true;
- state = QUALIFIER_NAME_FIRST_CHAR;
- break;
- }
- if (c == '#') {
- newQualifier();
- currentQualifier.attrName = 'id';
- state = QUALIFIER_NAME_FIRST_CHAR;
- break;
- }
- if (c == '[') {
- newQualifier();
- currentQualifier.attrName = '';
- state = ATTR_NAME_FIRST_CHAR;
- break;
- }
- if (c.match(WHITESPACE)) {
- state = SELECTOR_SEPARATOR;
- break;
- }
- if (c == ',') {
- state = SELECTOR;
- break;
- }
- throw Error(SYNTAX_ERROR);
- case QUALIFIER:
- if (c == '.') {
- newQualifier();
- currentQualifier.attrName = 'class';
- currentQualifier.contains = true;
- state = QUALIFIER_NAME_FIRST_CHAR;
- break;
- }
- if (c == '#') {
- newQualifier();
- currentQualifier.attrName = 'id';
- state = QUALIFIER_NAME_FIRST_CHAR;
- break;
- }
- if (c == '[') {
- newQualifier();
- currentQualifier.attrName = '';
- state = ATTR_NAME_FIRST_CHAR;
- break;
- }
- if (c.match(WHITESPACE)) {
- state = SELECTOR_SEPARATOR;
- break;
- }
- if (c == ',') {
- state = SELECTOR;
- break;
- }
- throw Error(SYNTAX_ERROR);
- case QUALIFIER_NAME_FIRST_CHAR:
- if (c.match(validNameInitialChar)) {
- currentQualifier.attrValue = c;
- state = QUALIFIER_NAME;
- break;
- }
- throw Error(SYNTAX_ERROR);
- case QUALIFIER_NAME:
- if (c.match(validNameNonInitialChar)) {
- currentQualifier.attrValue += c;
- break;
- }
- if (c == '.') {
- newQualifier();
- currentQualifier.attrName = 'class';
- currentQualifier.contains = true;
- state = QUALIFIER_NAME_FIRST_CHAR;
- break;
- }
- if (c == '#') {
- newQualifier();
- currentQualifier.attrName = 'id';
- state = QUALIFIER_NAME_FIRST_CHAR;
- break;
- }
- if (c == '[') {
- newQualifier();
- state = ATTR_NAME_FIRST_CHAR;
- break;
- }
- if (c.match(WHITESPACE)) {
- state = SELECTOR_SEPARATOR;
- break;
- }
- if (c == ',') {
- state = SELECTOR;
- break;
- }
- throw Error(SYNTAX_ERROR);
- case ATTR_NAME_FIRST_CHAR:
- if (c.match(validNameInitialChar)) {
- currentQualifier.attrName = c;
- state = ATTR_NAME;
- break;
- }
- if (c.match(WHITESPACE))
- break;
- throw Error(SYNTAX_ERROR);
- case ATTR_NAME:
- if (c.match(validNameNonInitialChar)) {
- currentQualifier.attrName += c;
- break;
- }
- if (c.match(WHITESPACE)) {
- state = EQUIV_OR_ATTR_QUAL_END;
- break;
- }
- if (c == '~') {
- currentQualifier.contains = true;
- state = EQUAL;
- break;
- }
- if (c == '=') {
- currentQualifier.attrValue = '';
- state = VALUE_FIRST_CHAR;
- break;
- }
- if (c == ']') {
- state = QUALIFIER;
- break;
- }
- throw Error(SYNTAX_ERROR);
- case EQUIV_OR_ATTR_QUAL_END:
- if (c == '~') {
- currentQualifier.contains = true;
- state = EQUAL;
- break;
- }
- if (c == '=') {
- currentQualifier.attrValue = '';
- state = VALUE_FIRST_CHAR;
- break;
- }
- if (c == ']') {
- state = QUALIFIER;
- break;
- }
- if (c.match(WHITESPACE))
- break;
- throw Error(SYNTAX_ERROR);
- case EQUAL:
- if (c == '=') {
- currentQualifier.attrValue = '';
- state = VALUE_FIRST_CHAR;
- break;
- }
- throw Error(SYNTAX_ERROR);
- case ATTR_QUAL_END:
- if (c == ']') {
- state = QUALIFIER;
- break;
- }
- if (c.match(WHITESPACE))
- break;
- throw Error(SYNTAX_ERROR);
- case VALUE_FIRST_CHAR:
- if (c.match(WHITESPACE))
- break;
- if (c == '"' || c == "'") {
- valueQuoteChar = c;
- state = QUOTED_VALUE;
- break;
- }
- currentQualifier.attrValue += c;
- state = VALUE;
- break;
- case VALUE:
- if (c.match(WHITESPACE)) {
- state = ATTR_QUAL_END;
- break;
- }
- if (c == ']') {
- state = QUALIFIER;
- break;
- }
- if (c == "'" || c == '"')
- throw Error(SYNTAX_ERROR);
- currentQualifier.attrValue += c;
- break;
- case QUOTED_VALUE:
- if (c == valueQuoteChar) {
- state = ATTR_QUAL_END;
- break;
- }
- currentQualifier.attrValue += c;
- break;
- case SELECTOR_SEPARATOR:
- if (c.match(WHITESPACE))
- break;
- if (c == ',') {
- state = SELECTOR;
- break;
- }
- throw Error(SYNTAX_ERROR);
- }
- }
- switch (state) {
- case SELECTOR:
- case TAG_NAME:
- case QUALIFIER:
- case QUALIFIER_NAME:
- case SELECTOR_SEPARATOR:
- // Valid end states.
- newSelector();
- break;
- default:
- throw Error(SYNTAX_ERROR);
- }
- if (!selectors.length)
- throw Error(SYNTAX_ERROR);
- return selectors;
- };
- Selector.nextUid = 1;
- Selector.matchesSelector = (function () {
- var element = document.createElement('div');
- if (typeof element['webkitMatchesSelector'] === 'function')
- return 'webkitMatchesSelector';
- if (typeof element['mozMatchesSelector'] === 'function')
- return 'mozMatchesSelector';
- if (typeof element['msMatchesSelector'] === 'function')
- return 'msMatchesSelector';
- return 'matchesSelector';
- })();
- return Selector;
-}());
-var attributeFilterPattern = /^([a-zA-Z:_]+[a-zA-Z0-9_\-:\.]*)$/;
-function validateAttribute(attribute) {
- if (typeof attribute != 'string')
- throw Error('Invalid request opion. attribute must be a non-zero length string.');
- attribute = attribute.trim();
- if (!attribute)
- throw Error('Invalid request opion. attribute must be a non-zero length string.');
- if (!attribute.match(attributeFilterPattern))
- throw Error('Invalid request option. invalid attribute name: ' + attribute);
- return attribute;
-}
-function validateElementAttributes(attribs) {
- if (!attribs.trim().length)
- throw Error('Invalid request option: elementAttributes must contain at least one attribute.');
- var lowerAttributes = {};
- var attributes = {};
- var tokens = attribs.split(/\s+/);
- for (var i = 0; i < tokens.length; i++) {
- var name = tokens[i];
- if (!name)
- continue;
- var name = validateAttribute(name);
- var nameLower = name.toLowerCase();
- if (lowerAttributes[nameLower])
- throw Error('Invalid request option: observing multiple case variations of the same attribute is not supported.');
- attributes[name] = true;
- lowerAttributes[nameLower] = true;
- }
- return Object.keys(attributes);
-}
-function elementFilterAttributes(selectors) {
- var attributes = {};
- selectors.forEach(function (selector) {
- selector.qualifiers.forEach(function (qualifier) {
- attributes[qualifier.attrName] = true;
- });
- });
- return Object.keys(attributes);
-}
-var MutationSummary = /** @class */ (function () {
- function MutationSummary(opts) {
- var _this = this;
- this.connected = false;
- this.options = MutationSummary.validateOptions(opts);
- this.observerOptions = MutationSummary.createObserverOptions(this.options.queries);
- this.root = this.options.rootNode;
- this.callback = this.options.callback;
- this.elementFilter = Array.prototype.concat.apply([], this.options.queries.map(function (query) {
- return query.elementFilter ? query.elementFilter : [];
- }));
- if (!this.elementFilter.length)
- this.elementFilter = undefined;
- this.calcReordered = this.options.queries.some(function (query) {
- return query.all;
- });
- this.queryValidators = []; // TODO(rafaelw): Shouldn't always define this.
- if (MutationSummary.createQueryValidator) {
- this.queryValidators = this.options.queries.map(function (query) {
- return MutationSummary.createQueryValidator(_this.root, query);
- });
- }
- this.observer = new MutationObserverCtor(function (mutations) {
- _this.observerCallback(mutations);
- });
- this.reconnect();
- }
- MutationSummary.createObserverOptions = function (queries) {
- var observerOptions = {
- childList: true,
- subtree: true
- };
- var attributeFilter;
- function observeAttributes(attributes) {
- if (observerOptions.attributes && !attributeFilter)
- return; // already observing all.
- observerOptions.attributes = true;
- observerOptions.attributeOldValue = true;
- if (!attributes) {
- // observe all.
- attributeFilter = undefined;
- return;
- }
- // add to observed.
- attributeFilter = attributeFilter || {};
- attributes.forEach(function (attribute) {
- attributeFilter[attribute] = true;
- attributeFilter[attribute.toLowerCase()] = true;
- });
- }
- queries.forEach(function (query) {
- if (query.characterData) {
- observerOptions.characterData = true;
- observerOptions.characterDataOldValue = true;
- return;
- }
- if (query.all) {
- observeAttributes();
- observerOptions.characterData = true;
- observerOptions.characterDataOldValue = true;
- return;
- }
- if (query.attribute) {
- observeAttributes([query.attribute.trim()]);
- return;
- }
- var attributes = elementFilterAttributes(query.elementFilter).concat(query.attributeList || []);
- if (attributes.length)
- observeAttributes(attributes);
- });
- if (attributeFilter)
- observerOptions.attributeFilter = Object.keys(attributeFilter);
- return observerOptions;
- };
- MutationSummary.validateOptions = function (options) {
- for (var prop in options) {
- if (!(prop in MutationSummary.optionKeys))
- throw Error('Invalid option: ' + prop);
- }
- if (typeof options.callback !== 'function')
- throw Error('Invalid options: callback is required and must be a function');
- if (!options.queries || !options.queries.length)
- throw Error('Invalid options: queries must contain at least one query request object.');
- var opts = {
- callback: options.callback,
- rootNode: options.rootNode || document,
- observeOwnChanges: !!options.observeOwnChanges,
- oldPreviousSibling: !!options.oldPreviousSibling,
- queries: []
- };
- for (var i = 0; i < options.queries.length; i++) {
- var request = options.queries[i];
- // all
- if (request.all) {
- if (Object.keys(request).length > 1)
- throw Error('Invalid request option. all has no options.');
- opts.queries.push({ all: true });
- continue;
- }
- // attribute
- if ('attribute' in request) {
- var query = {
- attribute: validateAttribute(request.attribute)
- };
- query.elementFilter = Selector.parseSelectors('*[' + query.attribute + ']');
- if (Object.keys(request).length > 1)
- throw Error('Invalid request option. attribute has no options.');
- opts.queries.push(query);
- continue;
- }
- // element
- if ('element' in request) {
- var requestOptionCount = Object.keys(request).length;
- var query = {
- element: request.element,
- elementFilter: Selector.parseSelectors(request.element)
- };
- if (request.hasOwnProperty('elementAttributes')) {
- query.attributeList = validateElementAttributes(request.elementAttributes);
- requestOptionCount--;
- }
- if (requestOptionCount > 1)
- throw Error('Invalid request option. element only allows elementAttributes option.');
- opts.queries.push(query);
- continue;
- }
- // characterData
- if (request.characterData) {
- if (Object.keys(request).length > 1)
- throw Error('Invalid request option. characterData has no options.');
- opts.queries.push({ characterData: true });
- continue;
- }
- throw Error('Invalid request option. Unknown query request.');
- }
- return opts;
- };
- MutationSummary.prototype.createSummaries = function (mutations) {
- if (!mutations || !mutations.length)
- return [];
- var projection = new MutationProjection(this.root, mutations, this.elementFilter, this.calcReordered, this.options.oldPreviousSibling);
- var summaries = [];
- for (var i = 0; i < this.options.queries.length; i++) {
- summaries.push(new Summary(projection, this.options.queries[i]));
- }
- return summaries;
- };
- MutationSummary.prototype.checkpointQueryValidators = function () {
- this.queryValidators.forEach(function (validator) {
- if (validator)
- validator.recordPreviousState();
- });
- };
- MutationSummary.prototype.runQueryValidators = function (summaries) {
- this.queryValidators.forEach(function (validator, index) {
- if (validator)
- validator.validate(summaries[index]);
- });
- };
- MutationSummary.prototype.changesToReport = function (summaries) {
- return summaries.some(function (summary) {
- var summaryProps = ['added', 'removed', 'reordered', 'reparented',
- 'valueChanged', 'characterDataChanged'];
- if (summaryProps.some(function (prop) { return summary[prop] && summary[prop].length; }))
- return true;
- if (summary.attributeChanged) {
- var attrNames = Object.keys(summary.attributeChanged);
- var attrsChanged = attrNames.some(function (attrName) {
- return !!summary.attributeChanged[attrName].length;
- });
- if (attrsChanged)
- return true;
- }
- return false;
- });
- };
- MutationSummary.prototype.observerCallback = function (mutations) {
- if (!this.options.observeOwnChanges)
- this.observer.disconnect();
- var summaries = this.createSummaries(mutations);
- this.runQueryValidators(summaries);
- if (this.options.observeOwnChanges)
- this.checkpointQueryValidators();
- if (this.changesToReport(summaries))
- this.callback(summaries);
- // disconnect() may have been called during the callback.
- if (!this.options.observeOwnChanges && this.connected) {
- this.checkpointQueryValidators();
- this.observer.observe(this.root, this.observerOptions);
- }
- };
- MutationSummary.prototype.reconnect = function () {
- if (this.connected)
- throw Error('Already connected');
- this.observer.observe(this.root, this.observerOptions);
- this.connected = true;
- this.checkpointQueryValidators();
- };
- MutationSummary.prototype.takeSummaries = function () {
- if (!this.connected)
- throw Error('Not connected');
- var summaries = this.createSummaries(this.observer.takeRecords());
- return this.changesToReport(summaries) ? summaries : undefined;
- };
- MutationSummary.prototype.disconnect = function () {
- var summaries = this.takeSummaries();
- this.observer.disconnect();
- this.connected = false;
- return summaries;
- };
- MutationSummary.NodeMap = NodeMap; // exposed for use in TreeMirror.
- MutationSummary.parseElementFilter = Selector.parseSelectors; // exposed for testing.
- MutationSummary.optionKeys = {
- 'callback': true,
- 'queries': true,
- 'rootNode': true,
- 'oldPreviousSibling': true,
- 'observeOwnChanges': true
- };
- return MutationSummary;
-}());
diff --git a/files/plugin-HeatmapSessionRecording-5.2.6/libs/mutation-summary/src/mutation-summary.ts b/files/plugin-HeatmapSessionRecording-5.2.6/libs/mutation-summary/src/mutation-summary.ts
deleted file mode 100644
index ee3a268..0000000
--- a/files/plugin-HeatmapSessionRecording-5.2.6/libs/mutation-summary/src/mutation-summary.ts
+++ /dev/null
@@ -1,1750 +0,0 @@
-// Copyright 2011 Google Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-var MutationObserverCtor;
-if (typeof WebKitMutationObserver !== 'undefined')
- MutationObserverCtor = WebKitMutationObserver;
-else
- MutationObserverCtor = MutationObserver;
-
-if (MutationObserverCtor === undefined) {
- console.error('DOM Mutation Observers are required.');
- console.error('https://developer.mozilla.org/en-US/docs/DOM/MutationObserver');
- throw Error('DOM Mutation Observers are required');
-}
-
-interface StringMap {
- [key: string]: T;
-}
-
-interface NumberMap {
- [key: number]: T;
-}
-
-class NodeMap {
-
- private static ID_PROP = '__mutation_summary_node_map_id__';
- private static nextId_:number = 1;
-
- private nodes:Node[];
- private values:T[];
-
- constructor() {
- this.nodes = [];
- this.values = [];
- }
-
- private isIndex(s:string):boolean {
- return +s === s >>> 0;
- }
-
- private nodeId(node:Node) {
- var id = node[NodeMap.ID_PROP];
- if (!id)
- id = node[NodeMap.ID_PROP] = NodeMap.nextId_++;
- return id;
- }
-
- set(node:Node, value:T) {
- var id = this.nodeId(node);
- this.nodes[id] = node;
- this.values[id] = value;
- }
-
- get(node:Node):T {
- var id = this.nodeId(node);
- return this.values[id];
- }
-
- has(node:Node):boolean {
- return this.nodeId(node) in this.nodes;
- }
-
- delete(node:Node) {
- var id = this.nodeId(node);
- delete this.nodes[id];
- this.values[id] = undefined;
- }
-
- keys():Node[] {
- var nodes:Node[] = [];
- for (var id in this.nodes) {
- if (!this.isIndex(id))
- continue;
- nodes.push(this.nodes[id]);
- }
-
- return nodes;
- }
-}
-
-/**
- * var reachableMatchableProduct = [
- * // STAYED_OUT, ENTERED, STAYED_IN, EXITED
- * [ STAYED_OUT, STAYED_OUT, STAYED_OUT, STAYED_OUT ], // STAYED_OUT
- * [ STAYED_OUT, ENTERED, ENTERED, STAYED_OUT ], // ENTERED
- * [ STAYED_OUT, ENTERED, STAYED_IN, EXITED ], // STAYED_IN
- * [ STAYED_OUT, STAYED_OUT, EXITED, EXITED ] // EXITED
- * ];
- */
-
-enum Movement {
- STAYED_OUT,
- ENTERED,
- STAYED_IN,
- REPARENTED,
- REORDERED,
- EXITED
-}
-
-function enteredOrExited(changeType:Movement):boolean {
- return changeType === Movement.ENTERED || changeType === Movement.EXITED;
-}
-
-class NodeChange {
-
- public isCaseInsensitive:boolean;
-
- constructor(public node:Node,
- public childList:boolean = false,
- public attributes:boolean = false,
- public characterData:boolean = false,
- public oldParentNode:Node = null,
- public added:boolean = false,
- private attributeOldValues:StringMap = null,
- public characterDataOldValue:string = null) {
- this.isCaseInsensitive =
- this.node.nodeType === Node.ELEMENT_NODE &&
- this.node instanceof HTMLElement &&
- this.node.ownerDocument instanceof HTMLDocument;
- }
-
- getAttributeOldValue(name:string):string {
- if (!this.attributeOldValues)
- return undefined;
- if (this.isCaseInsensitive)
- name = name.toLowerCase();
- return this.attributeOldValues[name];
- }
-
- getAttributeNamesMutated():string[] {
- var names:string[] = [];
- if (!this.attributeOldValues)
- return names;
- for (var name in this.attributeOldValues) {
- names.push(name);
- }
- return names;
- }
-
- attributeMutated(name:string, oldValue:string) {
- this.attributes = true;
- this.attributeOldValues = this.attributeOldValues || {};
-
- if (name in this.attributeOldValues)
- return;
-
- this.attributeOldValues[name] = oldValue;
- }
-
- characterDataMutated(oldValue:string) {
- if (this.characterData)
- return;
- this.characterData = true;
- this.characterDataOldValue = oldValue;
- }
-
- // Note: is it possible to receive a removal followed by a removal. This
- // can occur if the removed node is added to an non-observed node, that
- // node is added to the observed area, and then the node removed from
- // it.
- removedFromParent(parent:Node) {
- this.childList = true;
- if (this.added || this.oldParentNode)
- this.added = false;
- else
- this.oldParentNode = parent;
- }
-
- insertedIntoParent() {
- this.childList = true;
- this.added = true;
- }
-
- // An node's oldParent is
- // -its present parent, if its parentNode was not changed.
- // -null if the first thing that happened to it was an add.
- // -the node it was removed from if the first thing that happened to it
- // was a remove.
- getOldParent() {
- if (this.childList) {
- if (this.oldParentNode)
- return this.oldParentNode;
- if (this.added)
- return null;
- }
-
- return this.node.parentNode;
- }
-}
-
-class ChildListChange {
-
- public added:NodeMap;
- public removed:NodeMap;
- public maybeMoved:NodeMap;
- public oldPrevious:NodeMap;
- public moved:NodeMap;
-
- constructor() {
- this.added = new NodeMap();
- this.removed = new NodeMap();
- this.maybeMoved = new NodeMap();
- this.oldPrevious = new NodeMap();
- this.moved = undefined;
- }
-}
-
-class TreeChanges extends NodeMap {
-
- public anyParentsChanged:boolean;
- public anyAttributesChanged:boolean;
- public anyCharacterDataChanged:boolean;
-
- private reachableCache:NodeMap;
- private wasReachableCache:NodeMap;
-
- private rootNode:Node;
-
- constructor(rootNode:Node, mutations:MutationRecord[]) {
- super();
-
- this.rootNode = rootNode;
- this.reachableCache = undefined;
- this.wasReachableCache = undefined;
- this.anyParentsChanged = false;
- this.anyAttributesChanged = false;
- this.anyCharacterDataChanged = false;
-
- for (var m = 0; m < mutations.length; m++) {
- var mutation = mutations[m];
- switch (mutation.type) {
-
- case 'childList':
- this.anyParentsChanged = true;
- for (var i = 0; i < mutation.removedNodes.length; i++) {
- var node = mutation.removedNodes[i];
- this.getChange(node).removedFromParent(mutation.target);
- }
- for (var i = 0; i < mutation.addedNodes.length; i++) {
- var node = mutation.addedNodes[i];
- this.getChange(node).insertedIntoParent();
- }
- break;
-
- case 'attributes':
- this.anyAttributesChanged = true;
- var change = this.getChange(mutation.target);
- change.attributeMutated(mutation.attributeName, mutation.oldValue);
- break;
-
- case 'characterData':
- this.anyCharacterDataChanged = true;
- var change = this.getChange(mutation.target);
- change.characterDataMutated(mutation.oldValue);
- break;
- }
- }
- }
-
- getChange(node:Node):NodeChange {
- var change = this.get(node);
- if (!change) {
- change = new NodeChange(node);
- this.set(node, change);
- }
- return change;
- }
-
- getOldParent(node:Node):Node {
- var change = this.get(node);
- return change ? change.getOldParent() : node.parentNode;
- }
-
- getIsReachable(node:Node):boolean {
- if (node === this.rootNode)
- return true;
- if (!node)
- return false;
-
- this.reachableCache = this.reachableCache || new NodeMap();
- var isReachable = this.reachableCache.get(node);
- if (isReachable === undefined) {
- isReachable = this.getIsReachable(node.parentNode);
- this.reachableCache.set(node, isReachable);
- }
- return isReachable;
- }
-
- // A node wasReachable if its oldParent wasReachable.
- getWasReachable(node:Node):boolean {
- if (node === this.rootNode)
- return true;
- if (!node)
- return false;
-
- this.wasReachableCache = this.wasReachableCache || new NodeMap();
- var wasReachable:boolean = this.wasReachableCache.get(node);
- if (wasReachable === undefined) {
- wasReachable = this.getWasReachable(this.getOldParent(node));
- this.wasReachableCache.set(node, wasReachable);
- }
- return wasReachable;
- }
-
- reachabilityChange(node:Node):Movement {
- if (this.getIsReachable(node)) {
- return this.getWasReachable(node) ?
- Movement.STAYED_IN : Movement.ENTERED;
- }
-
- return this.getWasReachable(node) ?
- Movement.EXITED : Movement.STAYED_OUT;
- }
-}
-
-class MutationProjection {
-
- private treeChanges:TreeChanges;
- private entered:Node[];
- private exited:Node[];
- private stayedIn:NodeMap;
- private visited:NodeMap;
- private childListChangeMap:NodeMap;
- private characterDataOnly:boolean;
- private matchCache:NumberMap>;
-
- // TOOD(any)
- constructor(public rootNode:Node,
- public mutations:MutationRecord[],
- public selectors:Selector[],
- public calcReordered:boolean,
- public calcOldPreviousSibling:boolean) {
-
- this.treeChanges = new TreeChanges(rootNode, mutations);
- this.entered = [];
- this.exited = [];
- this.stayedIn = new NodeMap();
- this.visited = new NodeMap();
- this.childListChangeMap = undefined;
- this.characterDataOnly = undefined;
- this.matchCache = undefined;
-
- this.processMutations();
- }
-
- processMutations() {
- if (!this.treeChanges.anyParentsChanged &&
- !this.treeChanges.anyAttributesChanged)
- return;
-
- var changedNodes:Node[] = this.treeChanges.keys();
- for (var i = 0; i < changedNodes.length; i++) {
- this.visitNode(changedNodes[i], undefined);
- }
- }
-
- visitNode(node:Node, parentReachable:Movement) {
- if (this.visited.has(node))
- return;
-
- this.visited.set(node, true);
-
- var change = this.treeChanges.get(node);
- var reachable = parentReachable;
-
- // node inherits its parent's reachability change unless
- // its parentNode was mutated.
- if ((change && change.childList) || reachable == undefined)
- reachable = this.treeChanges.reachabilityChange(node);
-
- if (reachable === Movement.STAYED_OUT)
- return;
-
- // Cache match results for sub-patterns.
- this.matchabilityChange(node);
-
- if (reachable === Movement.ENTERED) {
- this.entered.push(node);
- } else if (reachable === Movement.EXITED) {
- this.exited.push(node);
- this.ensureHasOldPreviousSiblingIfNeeded(node);
-
- } else if (reachable === Movement.STAYED_IN) {
- var movement = Movement.STAYED_IN;
-
- if (change && change.childList) {
- if (change.oldParentNode !== node.parentNode) {
- movement = Movement.REPARENTED;
- this.ensureHasOldPreviousSiblingIfNeeded(node);
- } else if (this.calcReordered && this.wasReordered(node)) {
- movement = Movement.REORDERED;
- }
- }
-
- this.stayedIn.set(node, movement);
- }
-
- if (reachable === Movement.STAYED_IN)
- return;
-
- // reachable === ENTERED || reachable === EXITED.
- for (var child = node.firstChild; child; child = child.nextSibling) {
- this.visitNode(child, reachable);
- }
- }
-
- ensureHasOldPreviousSiblingIfNeeded(node:Node) {
- if (!this.calcOldPreviousSibling)
- return;
-
- this.processChildlistChanges();
-
- var parentNode = node.parentNode;
- var nodeChange = this.treeChanges.get(node);
- if (nodeChange && nodeChange.oldParentNode)
- parentNode = nodeChange.oldParentNode;
-
- var change = this.childListChangeMap.get(parentNode);
- if (!change) {
- change = new ChildListChange();
- this.childListChangeMap.set(parentNode, change);
- }
-
- if (!change.oldPrevious.has(node)) {
- change.oldPrevious.set(node, node.previousSibling);
- }
- }
-
- getChanged(summary:Summary, selectors:Selector[], characterDataOnly:boolean) {
- this.selectors = selectors;
- this.characterDataOnly = characterDataOnly;
-
- for (var i = 0; i < this.entered.length; i++) {
- var node = this.entered[i];
- var matchable = this.matchabilityChange(node);
- if (matchable === Movement.ENTERED || matchable === Movement.STAYED_IN)
- summary.added.push(node);
- }
-
- var stayedInNodes = this.stayedIn.keys();
- for (var i = 0; i < stayedInNodes.length; i++) {
- var node = stayedInNodes[i];
- var matchable = this.matchabilityChange(node);
-
- if (matchable === Movement.ENTERED) {
- summary.added.push(node);
- } else if (matchable === Movement.EXITED) {
- summary.removed.push(node);
- } else if (matchable === Movement.STAYED_IN && (summary.reparented || summary.reordered)) {
- var movement:Movement = this.stayedIn.get(node);
- if (summary.reparented && movement === Movement.REPARENTED)
- summary.reparented.push(node);
- else if (summary.reordered && movement === Movement.REORDERED)
- summary.reordered.push(node);
- }
- }
-
- for (var i = 0; i < this.exited.length; i++) {
- var node = this.exited[i];
- var matchable = this.matchabilityChange(node);
- if (matchable === Movement.EXITED || matchable === Movement.STAYED_IN)
- summary.removed.push(node);
- }
- }
-
- getOldParentNode(node:Node):Node {
- var change = this.treeChanges.get(node);
- if (change && change.childList)
- return change.oldParentNode ? change.oldParentNode : null;
-
- var reachabilityChange = this.treeChanges.reachabilityChange(node);
- if (reachabilityChange === Movement.STAYED_OUT || reachabilityChange === Movement.ENTERED)
- throw Error('getOldParentNode requested on invalid node.');
-
- return node.parentNode;
- }
-
- getOldPreviousSibling(node:Node):Node {
- var parentNode = node.parentNode;
- var nodeChange = this.treeChanges.get(node);
- if (nodeChange && nodeChange.oldParentNode)
- parentNode = nodeChange.oldParentNode;
-
- var change = this.childListChangeMap.get(parentNode);
- if (!change)
- throw Error('getOldPreviousSibling requested on invalid node.');
-
- return change.oldPrevious.get(node);
- }
-
- getOldAttribute(element:Node, attrName:string):string {
- var change = this.treeChanges.get(element);
- if (!change || !change.attributes)
- throw Error('getOldAttribute requested on invalid node.');
-
- var value = change.getAttributeOldValue(attrName);
- if (value === undefined)
- throw Error('getOldAttribute requested for unchanged attribute name.');
-
- return value;
- }
-
- attributeChangedNodes(includeAttributes:string[]):StringMap {
- if (!this.treeChanges.anyAttributesChanged)
- return {}; // No attributes mutations occurred.
-
- var attributeFilter:StringMap;
- var caseInsensitiveFilter:StringMap;
- if (includeAttributes) {
- attributeFilter = {};
- caseInsensitiveFilter = {};
- for (var i = 0; i < includeAttributes.length; i++) {
- var attrName:string = includeAttributes[i];
- attributeFilter[attrName] = true;
- caseInsensitiveFilter[attrName.toLowerCase()] = attrName;
- }
- }
-
- var result:StringMap = {};
- var nodes = this.treeChanges.keys();
-
- for (var i = 0; i < nodes.length; i++) {
- var node = nodes[i];
-
- var change = this.treeChanges.get(node);
- if (!change.attributes)
- continue;
-
- if (Movement.STAYED_IN !== this.treeChanges.reachabilityChange(node) ||
- Movement.STAYED_IN !== this.matchabilityChange(node)) {
- continue;
- }
-
- var element = node;
- var changedAttrNames = change.getAttributeNamesMutated();
- for (var j = 0; j < changedAttrNames.length; j++) {
- var attrName = changedAttrNames[j];
-
- if (attributeFilter &&
- !attributeFilter[attrName] &&
- !(change.isCaseInsensitive && caseInsensitiveFilter[attrName])) {
- continue;
- }
-
- var oldValue = change.getAttributeOldValue(attrName);
- if (oldValue === element.getAttribute(attrName))
- continue;
-
- if (caseInsensitiveFilter && change.isCaseInsensitive)
- attrName = caseInsensitiveFilter[attrName];
-
- result[attrName] = result[attrName] || [];
- result[attrName].push(element);
- }
- }
-
- return result;
- }
-
- getOldCharacterData(node:Node):string {
- var change = this.treeChanges.get(node);
- if (!change || !change.characterData)
- throw Error('getOldCharacterData requested on invalid node.');
-
- return change.characterDataOldValue;
- }
-
- getCharacterDataChanged():Node[] {
- if (!this.treeChanges.anyCharacterDataChanged)
- return []; // No characterData mutations occurred.
-
- var nodes = this.treeChanges.keys();
- var result:Node[] = [];
- for (var i = 0; i < nodes.length; i++) {
- var target = nodes[i];
- if (Movement.STAYED_IN !== this.treeChanges.reachabilityChange(target))
- continue;
-
- var change = this.treeChanges.get(target);
- if (!change.characterData ||
- target.textContent == change.characterDataOldValue)
- continue
-
- result.push(target);
- }
-
- return result;
- }
-
- computeMatchabilityChange(selector:Selector, el:Element):Movement {
- if (!this.matchCache)
- this.matchCache = [];
- if (!this.matchCache[selector.uid])
- this.matchCache[selector.uid] = new NodeMap();
-
- var cache = this.matchCache[selector.uid];
- var result = cache.get(el);
- if (result === undefined) {
- result = selector.matchabilityChange(el, this.treeChanges.get(el));
- cache.set(el, result);
- }
- return result;
- }
-
- matchabilityChange(node:Node) {
- // TODO(rafaelw): Include PI, CDATA?
- // Only include text nodes.
- if (this.characterDataOnly) {
- switch (node.nodeType) {
- case Node.COMMENT_NODE:
- case Node.TEXT_NODE:
- return Movement.STAYED_IN;
- default:
- return Movement.STAYED_OUT;
- }
- }
-
- // No element filter. Include all nodes.
- if (!this.selectors)
- return Movement.STAYED_IN;
-
- // Element filter. Exclude non-elements.
- if (node.nodeType !== Node.ELEMENT_NODE)
- return Movement.STAYED_OUT;
-
- var el = node;
-
- var matchChanges = this.selectors.map((selector:Selector) => {
- return this.computeMatchabilityChange(selector, el);
- });
-
- var accum:Movement = Movement.STAYED_OUT;
- var i = 0;
-
- while (accum !== Movement.STAYED_IN && i < matchChanges.length) {
- switch(matchChanges[i]) {
- case Movement.STAYED_IN:
- accum = Movement.STAYED_IN;
- break;
- case Movement.ENTERED:
- if (accum === Movement.EXITED)
- accum = Movement.STAYED_IN;
- else
- accum = Movement.ENTERED;
- break;
- case Movement.EXITED:
- if (accum === Movement.ENTERED)
- accum = Movement.STAYED_IN;
- else
- accum = Movement.EXITED;
- break;
- }
-
- i++;
- }
-
- return accum;
- }
-
- getChildlistChange(el:Element):ChildListChange {
- var change = this.childListChangeMap.get(el);
- if (!change) {
- change = new ChildListChange();
- this.childListChangeMap.set(el, change);
- }
-
- return change;
- }
-
- processChildlistChanges() {
- if (this.childListChangeMap)
- return;
-
- this.childListChangeMap = new NodeMap();
-
- for (var i = 0; i < this.mutations.length; i++) {
- var mutation = this.mutations[i];
- if (mutation.type != 'childList')
- continue;
-
- if (this.treeChanges.reachabilityChange(mutation.target) !== Movement.STAYED_IN &&
- !this.calcOldPreviousSibling)
- continue;
-
- var change = this.getChildlistChange(mutation.target);
-
- var oldPrevious = mutation.previousSibling;
-
- function recordOldPrevious(node:Node, previous:Node) {
- if (!node ||
- change.oldPrevious.has(node) ||
- change.added.has(node) ||
- change.maybeMoved.has(node))
- return;
-
- if (previous &&
- (change.added.has(previous) ||
- change.maybeMoved.has(previous)))
- return;
-
- change.oldPrevious.set(node, previous);
- }
-
- for (var j = 0; j < mutation.removedNodes.length; j++) {
- var node = mutation.removedNodes[j];
- recordOldPrevious(node, oldPrevious);
-
- if (change.added.has(node)) {
- change.added.delete(node);
- } else {
- change.removed.set(node, true);
- change.maybeMoved.delete(node);
- }
-
- oldPrevious = node;
- }
-
- recordOldPrevious(mutation.nextSibling, oldPrevious);
-
- for (var j = 0; j < mutation.addedNodes.length; j++) {
- var node = mutation.addedNodes[j];
- if (change.removed.has(node)) {
- change.removed.delete(node);
- change.maybeMoved.set(node, true);
- } else {
- change.added.set(node, true);
- }
- }
- }
- }
-
- wasReordered(node:Node) {
- if (!this.treeChanges.anyParentsChanged)
- return false;
-
- this.processChildlistChanges();
-
- var parentNode = node.parentNode;
- var nodeChange = this.treeChanges.get(node);
- if (nodeChange && nodeChange.oldParentNode)
- parentNode = nodeChange.oldParentNode;
-
- var change = this.childListChangeMap.get(parentNode);
- if (!change)
- return false;
-
- if (change.moved)
- return change.moved.get(node);
-
- change.moved = new NodeMap();
- var pendingMoveDecision = new NodeMap();
-
- function isMoved(node:Node) {
- if (!node)
- return false;
- if (!change.maybeMoved.has(node))
- return false;
-
- var didMove = change.moved.get(node);
- if (didMove !== undefined)
- return didMove;
-
- if (pendingMoveDecision.has(node)) {
- didMove = true;
- } else {
- pendingMoveDecision.set(node, true);
- didMove = getPrevious(node) !== getOldPrevious(node);
- }
-
- if (pendingMoveDecision.has(node)) {
- pendingMoveDecision.delete(node);
- change.moved.set(node, didMove);
- } else {
- didMove = change.moved.get(node);
- }
-
- return didMove;
- }
-
- var oldPreviousCache = new NodeMap();
- function getOldPrevious(node:Node):Node {
- var oldPrevious = oldPreviousCache.get(node);
- if (oldPrevious !== undefined)
- return oldPrevious;
-
- oldPrevious = change.oldPrevious.get(node);
- while (oldPrevious &&
- (change.removed.has(oldPrevious) || isMoved(oldPrevious))) {
- oldPrevious = getOldPrevious(oldPrevious);
- }
-
- if (oldPrevious === undefined)
- oldPrevious = node.previousSibling;
- oldPreviousCache.set(node, oldPrevious);
-
- return oldPrevious;
- }
-
- var previousCache = new NodeMap();
- function getPrevious(node:Node):Node {
- if (previousCache.has(node))
- return previousCache.get(node);
-
- var previous = node.previousSibling;
- while (previous && (change.added.has(previous) || isMoved(previous)))
- previous = previous.previousSibling;
-
- previousCache.set(node, previous);
- return previous;
- }
-
- change.maybeMoved.keys().forEach(isMoved);
- return change.moved.get(node);
- }
-}
-
-class Summary {
- public added:Node[];
- public removed:Node[];
- public reparented:Node[];
- public reordered:Node[];
- public valueChanged:Node[];
- public attributeChanged:StringMap;
- public characterDataChanged:Node[];
-
- constructor(private projection:MutationProjection, query:Query) {
- this.added = [];
- this.removed = [];
- this.reparented = query.all || query.element || query.characterData ? [] : undefined;
- this.reordered = query.all ? [] : undefined;
-
- projection.getChanged(this, query.elementFilter, query.characterData);
-
- if (query.all || query.attribute || query.attributeList) {
- var filter = query.attribute ? [ query.attribute ] : query.attributeList;
- var attributeChanged = projection.attributeChangedNodes(filter);
-
- if (query.attribute) {
- this.valueChanged = attributeChanged[query.attribute] || [];
- } else {
- this.attributeChanged = attributeChanged;
- if (query.attributeList) {
- query.attributeList.forEach((attrName) => {
- if (!this.attributeChanged.hasOwnProperty(attrName))
- this.attributeChanged[attrName] = [];
- });
- }
- }
- }
-
- if (query.all || query.characterData) {
- var characterDataChanged = projection.getCharacterDataChanged()
-
- if (query.characterData)
- this.valueChanged = characterDataChanged;
- else
- this.characterDataChanged = characterDataChanged;
- }
-
- if (this.reordered)
- this.getOldPreviousSibling = projection.getOldPreviousSibling.bind(projection);
- }
-
- getOldParentNode(node:Node):Node {
- return this.projection.getOldParentNode(node);
- }
-
- getOldAttribute(node:Node, name: string):string {
- return this.projection.getOldAttribute(node, name);
- }
-
- getOldCharacterData(node:Node):string {
- return this.projection.getOldCharacterData(node);
- }
-
- getOldPreviousSibling(node:Node):Node {
- return this.projection.getOldPreviousSibling(node);
- }
-}
-
-// TODO(rafaelw): Allow ':' and '.' as valid name characters.
-var validNameInitialChar = /[a-zA-Z_]+/;
-var validNameNonInitialChar = /[a-zA-Z0-9_\-]+/;
-
-// TODO(rafaelw): Consider allowing backslash in the attrValue.
-// TODO(rafaelw): There's got a to be way to represent this state machine
-// more compactly???
-
-function escapeQuotes(value:string):string {
- return '"' + value.replace(/"/, '\\\"') + '"';
-}
-
-class Qualifier {
- public attrName:string;
- public attrValue:string;
- public contains:boolean;
-
- constructor() {}
-
- public matches(oldValue:string):boolean {
- if (oldValue === null)
- return false;
-
- if (this.attrValue === undefined)
- return true;
-
- if (!this.contains)
- return this.attrValue == oldValue;
-
- var tokens = oldValue.split(' ');
- for (var i = 0; i < tokens.length; i++) {
- if (this.attrValue === tokens[i])
- return true;
- }
-
- return false;
- }
-
- public toString():string {
- if (this.attrName === 'class' && this.contains)
- return '.' + this.attrValue;
-
- if (this.attrName === 'id' && !this.contains)
- return '#' + this.attrValue;
-
- if (this.contains)
- return '[' + this.attrName + '~=' + escapeQuotes(this.attrValue) + ']';
-
- if ('attrValue' in this)
- return '[' + this.attrName + '=' + escapeQuotes(this.attrValue) + ']';
-
- return '[' + this.attrName + ']';
- }
-}
-
-class Selector {
- private static nextUid:number = 1;
- private static matchesSelector:string = (function(){
- var element = document.createElement('div');
- if (typeof element['webkitMatchesSelector'] === 'function')
- return 'webkitMatchesSelector';
- if (typeof element['mozMatchesSelector'] === 'function')
- return 'mozMatchesSelector';
- if (typeof element['msMatchesSelector'] === 'function')
- return 'msMatchesSelector';
-
- return 'matchesSelector';
- })();
-
- public tagName:string;
- public qualifiers:Qualifier[];
- public uid:number;
-
- private get caseInsensitiveTagName():string {
- return this.tagName.toUpperCase();
- }
-
- get selectorString() {
- return this.tagName + this.qualifiers.join('');
- }
-
- constructor() {
- this.uid = Selector.nextUid++;
- this.qualifiers = [];
- }
-
- private isMatching(el:Element):boolean {
- return el[Selector.matchesSelector](this.selectorString);
- }
-
- private wasMatching(el:Element, change:NodeChange, isMatching:boolean):boolean {
- if (!change || !change.attributes)
- return isMatching;
-
- var tagName = change.isCaseInsensitive ? this.caseInsensitiveTagName : this.tagName;
- if (tagName !== '*' && tagName !== el.tagName)
- return false;
-
- var attributeOldValues:string[] = [];
- var anyChanged = false;
- for (var i = 0; i < this.qualifiers.length; i++) {
- var qualifier = this.qualifiers[i];
- var oldValue = change.getAttributeOldValue(qualifier.attrName);
- attributeOldValues.push(oldValue);
- anyChanged = anyChanged || (oldValue !== undefined);
- }
-
- if (!anyChanged)
- return isMatching;
-
- for (var i = 0; i < this.qualifiers.length; i++) {
- var qualifier = this.qualifiers[i];
- var oldValue = attributeOldValues[i];
- if (oldValue === undefined)
- oldValue = el.getAttribute(qualifier.attrName);
- if (!qualifier.matches(oldValue))
- return false;
- }
-
- return true;
- }
-
- public matchabilityChange(el:Element, change:NodeChange):Movement {
- var isMatching = this.isMatching(el);
- if (isMatching)
- return this.wasMatching(el, change, isMatching) ? Movement.STAYED_IN : Movement.ENTERED;
- else
- return this.wasMatching(el, change, isMatching) ? Movement.EXITED : Movement.STAYED_OUT;
- }
-
- public static parseSelectors(input:string):Selector[] {
- var selectors:Selector[] = [];
- var currentSelector:Selector;
- var currentQualifier:Qualifier;
-
- function newSelector() {
- if (currentSelector) {
- if (currentQualifier) {
- currentSelector.qualifiers.push(currentQualifier);
- currentQualifier = undefined;
- }
-
- selectors.push(currentSelector);
- }
- currentSelector = new Selector();
- }
-
- function newQualifier() {
- if (currentQualifier)
- currentSelector.qualifiers.push(currentQualifier);
-
- currentQualifier = new Qualifier();
- }
-
- var WHITESPACE = /\s/;
- var valueQuoteChar:string;
- var SYNTAX_ERROR = 'Invalid or unsupported selector syntax.';
-
- var SELECTOR = 1;
- var TAG_NAME = 2;
- var QUALIFIER = 3;
- var QUALIFIER_NAME_FIRST_CHAR = 4;
- var QUALIFIER_NAME = 5;
- var ATTR_NAME_FIRST_CHAR = 6;
- var ATTR_NAME = 7;
- var EQUIV_OR_ATTR_QUAL_END = 8;
- var EQUAL = 9;
- var ATTR_QUAL_END = 10;
- var VALUE_FIRST_CHAR = 11;
- var VALUE = 12;
- var QUOTED_VALUE = 13;
- var SELECTOR_SEPARATOR = 14;
-
- var state = SELECTOR;
- var i = 0;
- while (i < input.length) {
- var c = input[i++];
-
- switch (state) {
- case SELECTOR:
- if (c.match(validNameInitialChar)) {
- newSelector();
- currentSelector.tagName = c;
- state = TAG_NAME;
- break;
- }
-
- if (c == '*') {
- newSelector();
- currentSelector.tagName = '*';
- state = QUALIFIER;
- break;
- }
-
- if (c == '.') {
- newSelector();
- newQualifier();
- currentSelector.tagName = '*';
- currentQualifier.attrName = 'class';
- currentQualifier.contains = true;
- state = QUALIFIER_NAME_FIRST_CHAR;
- break;
- }
- if (c == '#') {
- newSelector();
- newQualifier();
- currentSelector.tagName = '*';
- currentQualifier.attrName = 'id';
- state = QUALIFIER_NAME_FIRST_CHAR;
- break;
- }
- if (c == '[') {
- newSelector();
- newQualifier();
- currentSelector.tagName = '*';
- currentQualifier.attrName = '';
- state = ATTR_NAME_FIRST_CHAR;
- break;
- }
-
- if (c.match(WHITESPACE))
- break;
-
- throw Error(SYNTAX_ERROR);
-
- case TAG_NAME:
- if (c.match(validNameNonInitialChar)) {
- currentSelector.tagName += c;
- break;
- }
-
- if (c == '.') {
- newQualifier();
- currentQualifier.attrName = 'class';
- currentQualifier.contains = true;
- state = QUALIFIER_NAME_FIRST_CHAR;
- break;
- }
- if (c == '#') {
- newQualifier();
- currentQualifier.attrName = 'id';
- state = QUALIFIER_NAME_FIRST_CHAR;
- break;
- }
- if (c == '[') {
- newQualifier();
- currentQualifier.attrName = '';
- state = ATTR_NAME_FIRST_CHAR;
- break;
- }
-
- if (c.match(WHITESPACE)) {
- state = SELECTOR_SEPARATOR;
- break;
- }
-
- if (c == ',') {
- state = SELECTOR;
- break;
- }
-
- throw Error(SYNTAX_ERROR);
-
- case QUALIFIER:
- if (c == '.') {
- newQualifier();
- currentQualifier.attrName = 'class';
- currentQualifier.contains = true;
- state = QUALIFIER_NAME_FIRST_CHAR;
- break;
- }
- if (c == '#') {
- newQualifier();
- currentQualifier.attrName = 'id';
- state = QUALIFIER_NAME_FIRST_CHAR;
- break;
- }
- if (c == '[') {
- newQualifier();
- currentQualifier.attrName = '';
- state = ATTR_NAME_FIRST_CHAR;
- break;
- }
-
- if (c.match(WHITESPACE)) {
- state = SELECTOR_SEPARATOR;
- break;
- }
-
- if (c == ',') {
- state = SELECTOR;
- break;
- }
-
- throw Error(SYNTAX_ERROR);
-
- case QUALIFIER_NAME_FIRST_CHAR:
- if (c.match(validNameInitialChar)) {
- currentQualifier.attrValue = c;
- state = QUALIFIER_NAME;
- break;
- }
-
- throw Error(SYNTAX_ERROR);
-
- case QUALIFIER_NAME:
- if (c.match(validNameNonInitialChar)) {
- currentQualifier.attrValue += c;
- break;
- }
-
- if (c == '.') {
- newQualifier();
- currentQualifier.attrName = 'class';
- currentQualifier.contains = true;
- state = QUALIFIER_NAME_FIRST_CHAR;
- break;
- }
- if (c == '#') {
- newQualifier();
- currentQualifier.attrName = 'id';
- state = QUALIFIER_NAME_FIRST_CHAR;
- break;
- }
- if (c == '[') {
- newQualifier();
- state = ATTR_NAME_FIRST_CHAR;
- break;
- }
-
- if (c.match(WHITESPACE)) {
- state = SELECTOR_SEPARATOR;
- break;
- }
- if (c == ',') {
- state = SELECTOR;
- break
- }
-
- throw Error(SYNTAX_ERROR);
-
- case ATTR_NAME_FIRST_CHAR:
- if (c.match(validNameInitialChar)) {
- currentQualifier.attrName = c;
- state = ATTR_NAME;
- break;
- }
-
- if (c.match(WHITESPACE))
- break;
-
- throw Error(SYNTAX_ERROR);
-
- case ATTR_NAME:
- if (c.match(validNameNonInitialChar)) {
- currentQualifier.attrName += c;
- break;
- }
-
- if (c.match(WHITESPACE)) {
- state = EQUIV_OR_ATTR_QUAL_END;
- break;
- }
-
- if (c == '~') {
- currentQualifier.contains = true;
- state = EQUAL;
- break;
- }
-
- if (c == '=') {
- currentQualifier.attrValue = '';
- state = VALUE_FIRST_CHAR;
- break;
- }
-
- if (c == ']') {
- state = QUALIFIER;
- break;
- }
-
- throw Error(SYNTAX_ERROR);
-
- case EQUIV_OR_ATTR_QUAL_END:
- if (c == '~') {
- currentQualifier.contains = true;
- state = EQUAL;
- break;
- }
-
- if (c == '=') {
- currentQualifier.attrValue = '';
- state = VALUE_FIRST_CHAR;
- break;
- }
-
- if (c == ']') {
- state = QUALIFIER;
- break;
- }
-
- if (c.match(WHITESPACE))
- break;
-
- throw Error(SYNTAX_ERROR);
-
- case EQUAL:
- if (c == '=') {
- currentQualifier.attrValue = '';
- state = VALUE_FIRST_CHAR
- break;
- }
-
- throw Error(SYNTAX_ERROR);
-
- case ATTR_QUAL_END:
- if (c == ']') {
- state = QUALIFIER;
- break;
- }
-
- if (c.match(WHITESPACE))
- break;
-
- throw Error(SYNTAX_ERROR);
-
- case VALUE_FIRST_CHAR:
- if (c.match(WHITESPACE))
- break;
-
- if (c == '"' || c == "'") {
- valueQuoteChar = c;
- state = QUOTED_VALUE;
- break;
- }
-
- currentQualifier.attrValue += c;
- state = VALUE;
- break;
-
- case VALUE:
- if (c.match(WHITESPACE)) {
- state = ATTR_QUAL_END;
- break;
- }
- if (c == ']') {
- state = QUALIFIER;
- break;
- }
- if (c == "'" || c == '"')
- throw Error(SYNTAX_ERROR);
-
- currentQualifier.attrValue += c;
- break;
-
- case QUOTED_VALUE:
- if (c == valueQuoteChar) {
- state = ATTR_QUAL_END;
- break;
- }
-
- currentQualifier.attrValue += c;
- break;
-
- case SELECTOR_SEPARATOR:
- if (c.match(WHITESPACE))
- break;
-
- if (c == ',') {
- state = SELECTOR;
- break
- }
-
- throw Error(SYNTAX_ERROR);
- }
- }
-
- switch (state) {
- case SELECTOR:
- case TAG_NAME:
- case QUALIFIER:
- case QUALIFIER_NAME:
- case SELECTOR_SEPARATOR:
- // Valid end states.
- newSelector();
- break;
- default:
- throw Error(SYNTAX_ERROR);
- }
-
- if (!selectors.length)
- throw Error(SYNTAX_ERROR);
-
- return selectors;
- }
-}
-
-var attributeFilterPattern = /^([a-zA-Z:_]+[a-zA-Z0-9_\-:\.]*)$/;
-
-function validateAttribute(attribute:string) {
- if (typeof attribute != 'string')
- throw Error('Invalid request opion. attribute must be a non-zero length string.');
-
- attribute = attribute.trim();
-
- if (!attribute)
- throw Error('Invalid request opion. attribute must be a non-zero length string.');
-
-
- if (!attribute.match(attributeFilterPattern))
- throw Error('Invalid request option. invalid attribute name: ' + attribute);
-
- return attribute;
-}
-
-function validateElementAttributes(attribs:string):string[] {
- if (!attribs.trim().length)
- throw Error('Invalid request option: elementAttributes must contain at least one attribute.');
-
- var lowerAttributes = {};
- var attributes = {};
-
- var tokens = attribs.split(/\s+/);
- for (var i = 0; i < tokens.length; i++) {
- var name = tokens[i];
- if (!name)
- continue;
-
- var name = validateAttribute(name);
- var nameLower = name.toLowerCase();
- if (lowerAttributes[nameLower])
- throw Error('Invalid request option: observing multiple case variations of the same attribute is not supported.');
-
- attributes[name] = true;
- lowerAttributes[nameLower] = true;
- }
-
- return Object.keys(attributes);
-}
-
-
-
-function elementFilterAttributes(selectors:Selector[]):string[] {
- var attributes:StringMap = {};
-
- selectors.forEach((selector) => {
- selector.qualifiers.forEach((qualifier) => {
- attributes[qualifier.attrName] = true;
- });
- });
-
- return Object.keys(attributes);
-}
-
-interface Query {
- element?:string;
- attribute?:string;
- all?:boolean;
- characterData?:boolean;
- elementAttributes?:string;
- attributeList?:string[];
- elementFilter?:Selector[];
-}
-
-interface Options {
- callback:(summaries:Summary[]) => any;
- queries: Query[];
- rootNode?:Node;
- oldPreviousSibling?:boolean;
- observeOwnChanges?:boolean;
-}
-
-class MutationSummary {
-
- public static NodeMap = NodeMap; // exposed for use in TreeMirror.
- public static parseElementFilter = Selector.parseSelectors; // exposed for testing.
-
- public static createQueryValidator:(root:Node, query:Query)=>any;
- private connected:boolean;
- private options:Options;
- private observer:MutationObserver;
- private observerOptions:MutationObserverInit;
- private root:Node;
- private callback:(summaries:Summary[])=>any;
- private elementFilter:Selector[];
- private calcReordered:boolean;
- private queryValidators:any[];
-
- private static optionKeys:StringMap = {
- 'callback': true, // required
- 'queries': true, // required
- 'rootNode': true,
- 'oldPreviousSibling': true,
- 'observeOwnChanges': true
- };
-
- private static createObserverOptions(queries:Query[]):MutationObserverInit {
- var observerOptions:MutationObserverInit = {
- childList: true,
- subtree: true
- };
-
- var attributeFilter:StringMap;
- function observeAttributes(attributes?:string[]) {
- if (observerOptions.attributes && !attributeFilter)
- return; // already observing all.
-
- observerOptions.attributes = true;
- observerOptions.attributeOldValue = true;
-
- if (!attributes) {
- // observe all.
- attributeFilter = undefined;
- return;
- }
-
- // add to observed.
- attributeFilter = attributeFilter || {};
- attributes.forEach((attribute) => {
- attributeFilter[attribute] = true;
- attributeFilter[attribute.toLowerCase()] = true;
- });
- }
-
- queries.forEach((query) => {
- if (query.characterData) {
- observerOptions.characterData = true;
- observerOptions.characterDataOldValue = true;
- return;
- }
-
- if (query.all) {
- observeAttributes();
- observerOptions.characterData = true;
- observerOptions.characterDataOldValue = true;
- return;
- }
-
- if (query.attribute) {
- observeAttributes([query.attribute.trim()]);
- return;
- }
-
- var attributes = elementFilterAttributes(query.elementFilter).concat(query.attributeList || []);
- if (attributes.length)
- observeAttributes(attributes);
- });
-
- if (attributeFilter)
- observerOptions.attributeFilter = Object.keys(attributeFilter);
-
- return observerOptions;
- }
-
- private static validateOptions(options:Options):Options {
- for (var prop in options) {
- if (!(prop in MutationSummary.optionKeys))
- throw Error('Invalid option: ' + prop);
- }
-
- if (typeof options.callback !== 'function')
- throw Error('Invalid options: callback is required and must be a function');
-
- if (!options.queries || !options.queries.length)
- throw Error('Invalid options: queries must contain at least one query request object.');
-
- var opts:Options = {
- callback: options.callback,
- rootNode: options.rootNode || document,
- observeOwnChanges: !!options.observeOwnChanges,
- oldPreviousSibling: !!options.oldPreviousSibling,
- queries: []
- };
-
- for (var i = 0; i < options.queries.length; i++) {
- var request = options.queries[i];
-
- // all
- if (request.all) {
- if (Object.keys(request).length > 1)
- throw Error('Invalid request option. all has no options.');
-
- opts.queries.push({all: true});
- continue;
- }
-
- // attribute
- if ('attribute' in request) {
- var query:Query = {
- attribute: validateAttribute(request.attribute)
- };
-
- query.elementFilter = Selector.parseSelectors('*[' + query.attribute + ']');
-
- if (Object.keys(request).length > 1)
- throw Error('Invalid request option. attribute has no options.');
-
- opts.queries.push(query);
- continue;
- }
-
- // element
- if ('element' in request) {
- var requestOptionCount = Object.keys(request).length;
- var query:Query = {
- element: request.element,
- elementFilter: Selector.parseSelectors(request.element)
- };
-
- if (request.hasOwnProperty('elementAttributes')) {
- query.attributeList = validateElementAttributes(request.elementAttributes);
- requestOptionCount--;
- }
-
- if (requestOptionCount > 1)
- throw Error('Invalid request option. element only allows elementAttributes option.');
-
- opts.queries.push(query);
- continue;
- }
-
- // characterData
- if (request.characterData) {
- if (Object.keys(request).length > 1)
- throw Error('Invalid request option. characterData has no options.');
-
- opts.queries.push({ characterData: true });
- continue;
- }
-
- throw Error('Invalid request option. Unknown query request.');
- }
-
- return opts;
- }
-
- private createSummaries(mutations:MutationRecord[]):Summary[] {
- if (!mutations || !mutations.length)
- return [];
-
- var projection = new MutationProjection(this.root, mutations, this.elementFilter, this.calcReordered, this.options.oldPreviousSibling);
-
- var summaries:Summary[] = [];
- for (var i = 0; i < this.options.queries.length; i++) {
- summaries.push(new Summary(projection, this.options.queries[i]));
- }
-
- return summaries;
- }
-
- private checkpointQueryValidators() {
- this.queryValidators.forEach((validator) => {
- if (validator)
- validator.recordPreviousState();
- });
- }
-
- private runQueryValidators(summaries:Summary[]) {
- this.queryValidators.forEach((validator, index) => {
- if (validator)
- validator.validate(summaries[index]);
- });
- }
-
- private changesToReport(summaries:Summary[]):boolean {
- return summaries.some((summary) => {
- var summaryProps = ['added', 'removed', 'reordered', 'reparented',
- 'valueChanged', 'characterDataChanged'];
- if (summaryProps.some(function(prop) { return summary[prop] && summary[prop].length; }))
- return true;
-
- if (summary.attributeChanged) {
- var attrNames = Object.keys(summary.attributeChanged);
- var attrsChanged = attrNames.some((attrName) => {
- return !!summary.attributeChanged[attrName].length
- });
- if (attrsChanged)
- return true;
- }
- return false;
- });
- }
-
- constructor(opts:Options) {
- this.connected = false;
- this.options = MutationSummary.validateOptions(opts);
- this.observerOptions = MutationSummary.createObserverOptions(this.options.queries);
- this.root = this.options.rootNode;
- this.callback = this.options.callback;
-
- this.elementFilter = Array.prototype.concat.apply([], this.options.queries.map((query) => {
- return query.elementFilter ? query.elementFilter : [];
- }));
- if (!this.elementFilter.length)
- this.elementFilter = undefined;
-
- this.calcReordered = this.options.queries.some((query) => {
- return query.all;
- });
-
- this.queryValidators = []; // TODO(rafaelw): Shouldn't always define this.
- if (MutationSummary.createQueryValidator) {
- this.queryValidators = this.options.queries.map((query) => {
- return MutationSummary.createQueryValidator(this.root, query);
- });
- }
-
- this.observer = new MutationObserverCtor((mutations:MutationRecord[]) => {
- this.observerCallback(mutations);
- });
-
- this.reconnect();
- }
-
- private observerCallback(mutations:MutationRecord[]) {
- if (!this.options.observeOwnChanges)
- this.observer.disconnect();
-
- var summaries = this.createSummaries(mutations);
- this.runQueryValidators(summaries);
-
- if (this.options.observeOwnChanges)
- this.checkpointQueryValidators();
-
- if (this.changesToReport(summaries))
- this.callback(summaries);
-
- // disconnect() may have been called during the callback.
- if (!this.options.observeOwnChanges && this.connected) {
- this.checkpointQueryValidators();
- this.observer.observe(this.root, this.observerOptions);
- }
- }
-
- reconnect() {
- if (this.connected)
- throw Error('Already connected');
-
- this.observer.observe(this.root, this.observerOptions);
- this.connected = true;
- this.checkpointQueryValidators();
- }
-
- takeSummaries():Summary[] {
- if (!this.connected)
- throw Error('Not connected');
-
- var summaries = this.createSummaries(this.observer.takeRecords());
- return this.changesToReport(summaries) ? summaries : undefined;
- }
-
- disconnect():Summary[] {
- var summaries = this.takeSummaries();
- this.observer.disconnect();
- this.connected = false;
- return summaries;
- }
-}
-
diff --git a/files/plugin-HeatmapSessionRecording-5.2.6/libs/mutation-summary/util/tree-mirror.js b/files/plugin-HeatmapSessionRecording-5.2.6/libs/mutation-summary/util/tree-mirror.js
deleted file mode 100644
index fb63e09..0000000
--- a/files/plugin-HeatmapSessionRecording-5.2.6/libs/mutation-summary/util/tree-mirror.js
+++ /dev/null
@@ -1,268 +0,0 @@
-///
-var TreeMirror = /** @class */ (function () {
- function TreeMirror(root, delegate) {
- this.root = root;
- this.delegate = delegate;
- this.idMap = {};
- }
- TreeMirror.prototype.initialize = function (rootId, children) {
- this.idMap[rootId] = this.root;
- for (var i = 0; i < children.length; i++)
- this.deserializeNode(children[i], this.root);
- };
- TreeMirror.prototype.applyChanged = function (removed, addedOrMoved, attributes, text) {
- var _this = this;
- // NOTE: Applying the changes can result in an attempting to add a child
- // to a parent which is presently an ancestor of the parent. This can occur
- // based on random ordering of moves. The way we handle this is to first
- // remove all changed nodes from their parents, then apply.
- addedOrMoved.forEach(function (data) {
- var node = _this.deserializeNode(data);
- var parent = _this.deserializeNode(data.parentNode);
- var previous = _this.deserializeNode(data.previousSibling);
- if (node.parentNode)
- node.parentNode.removeChild(node);
- });
- removed.forEach(function (data) {
- var node = _this.deserializeNode(data);
- if (node.parentNode)
- node.parentNode.removeChild(node);
- });
- addedOrMoved.forEach(function (data) {
- var node = _this.deserializeNode(data);
- var parent = _this.deserializeNode(data.parentNode);
- var previous = _this.deserializeNode(data.previousSibling);
- parent.insertBefore(node, previous ? previous.nextSibling : parent.firstChild);
- });
- attributes.forEach(function (data) {
- var node = _this.deserializeNode(data);
- Object.keys(data.attributes).forEach(function (attrName) {
- var newVal = data.attributes[attrName];
- if (newVal === null) {
- node.removeAttribute(attrName);
- }
- else {
- if (!_this.delegate ||
- !_this.delegate.setAttribute ||
- !_this.delegate.setAttribute(node, attrName, newVal)) {
- node.setAttribute(attrName, newVal);
- }
- }
- });
- });
- text.forEach(function (data) {
- var node = _this.deserializeNode(data);
- node.textContent = data.textContent;
- });
- removed.forEach(function (node) {
- delete _this.idMap[node.id];
- });
- };
- TreeMirror.prototype.deserializeNode = function (nodeData, parent) {
- var _this = this;
- if (nodeData === null)
- return null;
- var node = this.idMap[nodeData.id];
- if (node)
- return node;
- var doc = this.root.ownerDocument;
- if (doc === null)
- doc = this.root;
- switch (nodeData.nodeType) {
- case Node.COMMENT_NODE:
- node = doc.createComment(nodeData.textContent);
- break;
- case Node.TEXT_NODE:
- node = doc.createTextNode(nodeData.textContent);
- break;
- case Node.DOCUMENT_TYPE_NODE:
- node = doc.implementation.createDocumentType(nodeData.name, nodeData.publicId, nodeData.systemId);
- break;
- case Node.ELEMENT_NODE:
- if (this.delegate && this.delegate.createElement)
- node = this.delegate.createElement(nodeData.tagName);
- if (!node)
- try {
- node = doc.createElement(nodeData.tagName);
- }
- catch (e) {
- console.log("Removing invalid node", nodeData);
- return null;
- }
- Object.keys(nodeData.attributes).forEach(function (name) {
- if (!_this.delegate ||
- !_this.delegate.setAttribute ||
- !_this.delegate.setAttribute(node, name, nodeData.attributes[name])) {
- try {
- node.setAttribute(name, nodeData.attributes[name]);
- }
- catch (e) {
- console.log("Removing node due to invalid attribute", nodeData);
- return null;
- }
- }
- });
- break;
- }
- if (!node)
- throw "ouch";
- this.idMap[nodeData.id] = node;
- if (parent)
- parent.appendChild(node);
- if (nodeData.childNodes) {
- for (var i = 0; i < nodeData.childNodes.length; i++)
- this.deserializeNode(nodeData.childNodes[i], node);
- }
- return node;
- };
- return TreeMirror;
-}());
-var TreeMirrorClient = /** @class */ (function () {
- function TreeMirrorClient(target, mirror, testingQueries) {
- var _this = this;
- this.target = target;
- this.mirror = mirror;
- this.nextId = 1;
- this.knownNodes = new MutationSummary.NodeMap();
- var rootId = this.serializeNode(target).id;
- var children = [];
- for (var child = target.firstChild; child; child = child.nextSibling)
- children.push(this.serializeNode(child, true));
- this.mirror.initialize(rootId, children);
- var self = this;
- var queries = [{ all: true }];
- if (testingQueries)
- queries = queries.concat(testingQueries);
- this.mutationSummary = new MutationSummary({
- rootNode: target,
- callback: function (summaries) {
- _this.applyChanged(summaries);
- },
- queries: queries
- });
- }
- TreeMirrorClient.prototype.disconnect = function () {
- if (this.mutationSummary) {
- this.mutationSummary.disconnect();
- this.mutationSummary = undefined;
- }
- };
- TreeMirrorClient.prototype.rememberNode = function (node) {
- var id = this.nextId++;
- this.knownNodes.set(node, id);
- return id;
- };
- TreeMirrorClient.prototype.forgetNode = function (node) {
- this.knownNodes["delete"](node);
- };
- TreeMirrorClient.prototype.serializeNode = function (node, recursive) {
- if (node === null)
- return null;
- var id = this.knownNodes.get(node);
- if (id !== undefined) {
- return { id: id };
- }
- var data = {
- nodeType: node.nodeType,
- id: this.rememberNode(node)
- };
- switch (data.nodeType) {
- case Node.DOCUMENT_TYPE_NODE:
- var docType = node;
- data.name = docType.name;
- data.publicId = docType.publicId;
- data.systemId = docType.systemId;
- break;
- case Node.COMMENT_NODE:
- case Node.TEXT_NODE:
- data.textContent = node.textContent;
- break;
- case Node.ELEMENT_NODE:
- var elm = node;
- data.tagName = elm.tagName;
- data.attributes = {};
- for (var i = 0; i < elm.attributes.length; i++) {
- var attr = elm.attributes[i];
- data.attributes[attr.name] = attr.value;
- }
- if (recursive && elm.childNodes.length) {
- data.childNodes = [];
- for (var child = elm.firstChild; child; child = child.nextSibling)
- data.childNodes.push(this.serializeNode(child, true));
- }
- break;
- }
- return data;
- };
- TreeMirrorClient.prototype.serializeAddedAndMoved = function (added, reparented, reordered) {
- var _this = this;
- var all = added.concat(reparented).concat(reordered);
- var parentMap = new MutationSummary.NodeMap();
- all.forEach(function (node) {
- var parent = node.parentNode;
- var children = parentMap.get(parent);
- if (!children) {
- children = new MutationSummary.NodeMap();
- parentMap.set(parent, children);
- }
- children.set(node, true);
- });
- var moved = [];
- parentMap.keys().forEach(function (parent) {
- var children = parentMap.get(parent);
- var keys = children.keys();
- while (keys.length) {
- var node = keys[0];
- while (node.previousSibling && children.has(node.previousSibling))
- node = node.previousSibling;
- while (node && children.has(node)) {
- var data = _this.serializeNode(node);
- data.previousSibling = _this.serializeNode(node.previousSibling);
- data.parentNode = _this.serializeNode(node.parentNode);
- moved.push(data);
- children["delete"](node);
- node = node.nextSibling;
- }
- var keys = children.keys();
- }
- });
- return moved;
- };
- TreeMirrorClient.prototype.serializeAttributeChanges = function (attributeChanged) {
- var _this = this;
- var map = new MutationSummary.NodeMap();
- Object.keys(attributeChanged).forEach(function (attrName) {
- attributeChanged[attrName].forEach(function (element) {
- var record = map.get(element);
- if (!record) {
- record = _this.serializeNode(element);
- record.attributes = {};
- map.set(element, record);
- }
- record.attributes[attrName] = element.getAttribute(attrName);
- });
- });
- return map.keys().map(function (node) {
- return map.get(node);
- });
- };
- TreeMirrorClient.prototype.applyChanged = function (summaries) {
- var _this = this;
- var summary = summaries[0];
- var removed = summary.removed.map(function (node) {
- return _this.serializeNode(node);
- });
- var moved = this.serializeAddedAndMoved(summary.added, summary.reparented, summary.reordered);
- var attributes = this.serializeAttributeChanges(summary.attributeChanged);
- var text = summary.characterDataChanged.map(function (node) {
- var data = _this.serializeNode(node);
- data.textContent = node.textContent;
- return data;
- });
- this.mirror.applyChanged(removed, moved, attributes, text);
- summary.removed.forEach(function (node) {
- _this.forgetNode(node);
- });
- };
- return TreeMirrorClient;
-}());
diff --git a/files/plugin-HeatmapSessionRecording-5.2.6/libs/mutation-summary/util/tree-mirror.ts b/files/plugin-HeatmapSessionRecording-5.2.6/libs/mutation-summary/util/tree-mirror.ts
deleted file mode 100644
index fd5f0d1..0000000
--- a/files/plugin-HeatmapSessionRecording-5.2.6/libs/mutation-summary/util/tree-mirror.ts
+++ /dev/null
@@ -1,375 +0,0 @@
-///
-
-// Copyright 2013 Google Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-interface NodeData {
- id:number;
- nodeType?:number;
- name?:string;
- publicId?:string;
- systemId?:string;
- textContent?:string;
- tagName?:string;
- attributes?:StringMap;
- childNodes?:NodeData[];
-}
-
-interface PositionData extends NodeData {
- previousSibling:NodeData;
- parentNode:NodeData;
-}
-
-interface AttributeData extends NodeData {
- attributes:StringMap;
-}
-
-interface TextData extends NodeData{
- textContent:string;
-}
-
-class TreeMirror {
-
- private idMap:NumberMap;
-
- constructor(public root:Node, public delegate?:any) {
- this.idMap = {};
- }
-
- initialize(rootId:number, children:NodeData[]) {
- this.idMap[rootId] = this.root;
-
- for (var i = 0; i < children.length; i++)
- this.deserializeNode(children[i], this.root);
- }
-
- applyChanged(removed:NodeData[],
- addedOrMoved:PositionData[],
- attributes:AttributeData[],
- text:TextData[]) {
-
- // NOTE: Applying the changes can result in an attempting to add a child
- // to a parent which is presently an ancestor of the parent. This can occur
- // based on random ordering of moves. The way we handle this is to first
- // remove all changed nodes from their parents, then apply.
- addedOrMoved.forEach((data:PositionData) => {
- var node = this.deserializeNode(data);
- var parent = this.deserializeNode(data.parentNode);
- var previous = this.deserializeNode(data.previousSibling);
- if (node.parentNode)
- node.parentNode.removeChild(node);
- });
-
- removed.forEach((data:NodeData) => {
- var node = this.deserializeNode(data);
- if (node.parentNode)
- node.parentNode.removeChild(node);
- });
-
- addedOrMoved.forEach((data:PositionData) => {
- var node = this.deserializeNode(data);
- var parent = this.deserializeNode(data.parentNode);
- var previous = this.deserializeNode(data.previousSibling);
- parent.insertBefore(node,
- previous ? previous.nextSibling : parent.firstChild);
- });
-
- attributes.forEach((data:AttributeData) => {
- var node = this.deserializeNode(data);
- Object.keys(data.attributes).forEach((attrName) => {
- var newVal = data.attributes[attrName];
- if (newVal === null) {
- node.removeAttribute(attrName);
- } else {
- if (!this.delegate ||
- !this.delegate.setAttribute ||
- !this.delegate.setAttribute(node, attrName, newVal)) {
- node.setAttribute(attrName, newVal);
- }
- }
- });
- });
-
- text.forEach((data:TextData) => {
- var node = this.deserializeNode(data);
- node.textContent = data.textContent;
- });
-
- removed.forEach((node:NodeData) => {
- delete this.idMap[node.id];
- });
- }
-
- private deserializeNode(nodeData:NodeData, parent?:Element):Node {
- if (nodeData === null)
- return null;
-
- var node:Node = this.idMap[nodeData.id];
- if (node)
- return node;
-
- var doc = this.root.ownerDocument;
- if (doc === null)
- doc = this.root;
-
- switch(nodeData.nodeType) {
- case Node.COMMENT_NODE:
- node = doc.createComment(nodeData.textContent);
- break;
-
- case Node.TEXT_NODE:
- node = doc.createTextNode(nodeData.textContent);
- break;
-
- case Node.DOCUMENT_TYPE_NODE:
- node = doc.implementation.createDocumentType(nodeData.name, nodeData.publicId, nodeData.systemId);
- break;
-
- case Node.ELEMENT_NODE:
- if (this.delegate && this.delegate.createElement)
- node = this.delegate.createElement(nodeData.tagName);
- if (!node)
- try {
- node = doc.createElement(nodeData.tagName);
- } catch (e) {
- console.log("Removing invalid node", nodeData);
- return null;
- }
-
- Object.keys(nodeData.attributes).forEach((name) => {
- if (!this.delegate ||
- !this.delegate.setAttribute ||
- !this.delegate.setAttribute(node, name, nodeData.attributes[name])) {
- try {
- (node).setAttribute(name, nodeData.attributes[name]);
- } catch (e) {
- console.log("Removing node due to invalid attribute", nodeData);
- return null;
- }
- }
- });
-
- break;
- }
-
- if (!node)
- throw "ouch";
-
- this.idMap[nodeData.id] = node;
-
- if (parent)
- parent.appendChild(node);
-
- if (nodeData.childNodes) {
- for (var i = 0; i < nodeData.childNodes.length; i++)
- this.deserializeNode(nodeData.childNodes[i], node);
- }
-
- return node;
- }
-}
-
-class TreeMirrorClient {
- private nextId:number;
-
- private mutationSummary:MutationSummary;
- private knownNodes:NodeMap;
-
- constructor(public target:Node, public mirror:any, testingQueries:Query[]) {
- this.nextId = 1;
- this.knownNodes = new MutationSummary.NodeMap();
-
- var rootId = this.serializeNode(target).id;
- var children:NodeData[] = [];
- for (var child = target.firstChild; child; child = child.nextSibling)
- children.push(this.serializeNode(child, true));
-
- this.mirror.initialize(rootId, children);
-
- var self = this;
-
- var queries = [{ all: true }];
-
- if (testingQueries)
- queries = queries.concat(testingQueries);
-
- this.mutationSummary = new MutationSummary({
- rootNode: target,
- callback: (summaries:Summary[]) => {
- this.applyChanged(summaries);
- },
- queries: queries
- });
- }
-
-
- disconnect() {
- if (this.mutationSummary) {
- this.mutationSummary.disconnect();
- this.mutationSummary = undefined;
- }
- }
-
- private rememberNode(node:Node):number {
- var id = this.nextId++;
- this.knownNodes.set(node, id);
- return id;
- }
-
- private forgetNode(node:Node) {
- this.knownNodes.delete(node);
- }
-
- private serializeNode(node:Node, recursive?:boolean):NodeData {
- if (node === null)
- return null;
-
- var id = this.knownNodes.get(node);
- if (id !== undefined) {
- return { id: id };
- }
-
- var data:NodeData = {
- nodeType: node.nodeType,
- id: this.rememberNode(node)
- };
-
- switch(data.nodeType) {
- case Node.DOCUMENT_TYPE_NODE:
- var docType = node;
- data.name = docType.name;
- data.publicId = docType.publicId;
- data.systemId = docType.systemId;
- break;
-
- case Node.COMMENT_NODE:
- case Node.TEXT_NODE:
- data.textContent = node.textContent;
- break;
-
- case Node.ELEMENT_NODE:
- var elm = node;
- data.tagName = elm.tagName;
- data.attributes = {};
- for (var i = 0; i < elm.attributes.length; i++) {
- var attr = elm.attributes[i];
- data.attributes[attr.name] = attr.value;
- }
-
- if (recursive && elm.childNodes.length) {
- data.childNodes = [];
-
- for (var child = elm.firstChild; child; child = child.nextSibling)
- data.childNodes.push(this.serializeNode(child, true));
- }
- break;
- }
-
- return data;
- }
-
- private serializeAddedAndMoved(added:Node[],
- reparented:Node[],
- reordered:Node[]):PositionData[] {
- var all = added.concat(reparented).concat(reordered);
-
- var parentMap = new MutationSummary.NodeMap>();
-
- all.forEach((node) => {
- var parent = node.parentNode;
- var children = parentMap.get(parent)
- if (!children) {
- children = new MutationSummary.NodeMap();
- parentMap.set(parent, children);
- }
-
- children.set(node, true);
- });
-
- var moved:PositionData[] = [];
-
- parentMap.keys().forEach((parent) => {
- var children = parentMap.get(parent);
-
- var keys = children.keys();
- while (keys.length) {
- var node = keys[0];
- while (node.previousSibling && children.has(node.previousSibling))
- node = node.previousSibling;
-
- while (node && children.has(node)) {
- var data = this.serializeNode(node);
- data.previousSibling = this.serializeNode(node.previousSibling);
- data.parentNode = this.serializeNode(node.parentNode);
- moved.push(data);
- children.delete(node);
- node = node.nextSibling;
- }
-
- var keys = children.keys();
- }
- });
-
- return moved;
- }
-
- private serializeAttributeChanges(attributeChanged:StringMap):AttributeData[] {
- var map = new MutationSummary.NodeMap();
-
- Object.keys(attributeChanged).forEach((attrName) => {
- attributeChanged[attrName].forEach((element) => {
- var record = map.get(element);
- if (!record) {
- record = this.serializeNode(element);
- record.attributes = {};
- map.set(element, record);
- }
-
- record.attributes[attrName] = element.getAttribute(attrName);
- });
- });
-
- return map.keys().map((node:Node) => {
- return map.get(node);
- });
- }
-
- applyChanged(summaries:Summary[]) {
- var summary:Summary = summaries[0]
-
- var removed:NodeData[] = summary.removed.map((node:Node) => {
- return this.serializeNode(node);
- });
-
- var moved:PositionData[] =
- this.serializeAddedAndMoved(summary.added,
- summary.reparented,
- summary.reordered);
-
- var attributes:AttributeData[] =
- this.serializeAttributeChanges(summary.attributeChanged);
-
- var text:TextData[] = summary.characterDataChanged.map((node:Node) => {
- var data = this.serializeNode(node);
- data.textContent = node.textContent;
- return data;
- });
-
- this.mirror.applyChanged(removed, moved, attributes, text);
-
- summary.removed.forEach((node:Node) => {
- this.forgetNode(node);
- });
- }
-}
diff --git a/files/plugin-HeatmapSessionRecording-5.2.6/libs/svg.js/CHANGELOG.md b/files/plugin-HeatmapSessionRecording-5.2.6/libs/svg.js/CHANGELOG.md
deleted file mode 100644
index 6d9eb1e..0000000
--- a/files/plugin-HeatmapSessionRecording-5.2.6/libs/svg.js/CHANGELOG.md
+++ /dev/null
@@ -1,642 +0,0 @@
-# Change Log
-
-All notable changes to this project will be documented in this file.
-
-The document follows the conventions described in [“Keep a CHANGELOG”](http://keepachangelog.com).
-
-
-====
-
-
-## UNRELEASED 3.0.0
-
-### Added
-- added `'random'` option and `randomize()` method to `SVG.Color` -> __TODO!__
-- added `precision()` method to round numeric element attributes -> __TODO!__
-- added specs for `SVG.FX` -> __TODO!__
-
-### Changed
-- made transform-methods relative as default (breaking change)
-- changed SVG() to use querySelector instead of getElementById (breaking change) -> __TODO!__
-- made `parents()` method on `SVG.Element` return an instance of SVG.Set (breaking change) -> __TODO!__
-- replaced static reference to `masker` in `SVG.Mask` with the `masker()` method (breaking change) -> __TODO!__
-- replaced static reference to `clipper` in `SVG.ClipPath` with the `clipper()` method (breaking change) -> __TODO!__
-- replaced static reference to `targets` in `SVG.Mask` and `SVG.ClipPath` with the `targets()` method (breaking change) -> __TODO!__
-- moved all regexes to `SVG.regex` (in color, element, pointarray, style, transform and viewbox) -> __TODO!__
-
-### Fixed
-- fixed a bug in clipping and masking where empty nodes persists after removal -> __TODO!__
-- fixed a bug in IE11 with `mouseenter` and `mouseleave` -> __TODO!__
-
-
-## [2.6.1] - 2017-04-25
-
-### Fixed
-- fixed a bug in path parser which made it stop parsing when hitting z command (#665)
-
-## [2.6.0] - 2017-04-21
-
-### Added
-- added `options` object to `SVG.on()` and `el.on()` (#661)
-
-### Changed
-- back to sloppy mode because of problems with plugins (#660)
-
-
-## [2.5.3] - 2017-04-15
-
-### Added
-- added gitter badge in readme
-
-
-### Fixed
-- fixed svg.js.d.ts (#644 #648)
-- fixed bug in `el.flip()` which causes an error when calling flip without any argument
-
-### Removed
-- component.json (#652)
-
-
-## [2.5.2] - 2017-04-11
-
-### Changed
-- SVG.js is now running in strict mode
-
-### Fixed
-- `clear()` does not remove the parser in svg documents anymore
-- `len` not declared in FX module, making it a global variable (9737e8a)
-- `bbox` not declared in SVG.Box.transform in the Box module (131df0f)
-- `namespace` not declared in the Event module (e89c97e)
-
-
-## [2.5.1] - 2017-03-27
-
-### Changed
-- make svgjs ready to be used on the server
-
-### Fixed
-- fixed `SVG.PathArray.parse` that did not correctly parsed flat arrays
-- prevented unnecessary parsing of point or path strings
-
-
-## [2.5.0] - 2017-03-10
-
-### Added
-- added a plot and array method to `SVG.TextPath` (#582)
-- added `clone()` method to `SVG.Array/PointArray/PathArray` (#590)
-- added `font()` method to `SVG.Tspan`
-- added `SVG.Box()`
-- added `transform()` method to boxes
-- added `event()` to `SVG.Element` to retrieve the event that was fired last on the element (#550)
-
-### Changed
-- changed CHANGELOG to follow the conventions described in [“Keep a CHANGELOG”](http://keepachangelog.com) (#578)
-- make the method plot a getter when no parameter is passed for `SVG.Polyline`,`SVG.Polygon`, `SVG.Line`, `SVG.Path` (related #547)
-- allow `SVG.PointArray` to be passed flat array
-- change the regexp `SVG.PointArray` use to parse string to allow more flexibility in the way spaces and commas can be used
-- allow `plot` to be called with 4 parameters when animating an `SVG.Line`
-- relative value for `SVG.Number` are now calculated in its `morph` method (related #547)
-- clean up the implementation of the `initAnimation` method of the FX module (#547, #552, #584)
-- deprecated `.tbox()`. `.tbox()` now map to `.rbox()`. If you are using `.tbox()`, you can substitute it with `.rbox()` (#594, #602)
-- all boxes now accept 4 values or an object on creation
-- `el.rbox()` now always returns the right boxes in screen coordinates and has an additional paramater to transform the box into other coordinate systems
-- `font()` method can now be used like `attr()` method (#620)
-- events are now cancelable by default (#550)
-
-### Fixed
-- fixed a bug in the plain morphing part of `SVG.MorphObj` that is in the FX module
-- fixed bug which produces an error when removing an event from a node which was formerly removed with a global `off()` (#518)
-- fixed a bug in `size()` for poly elements when their height/width is zero (#505)
-- viewbox now also accepts strings and arrays as constructor arguments
-- `SVG.Array` now accepts a comma seperated string and returns array of numbers instead of strings
-- `SVG.Matrix` now accepts an array as input
-- `SVG.Element.matrix()` now accepts also 6 values
-- `dx()/dy()` now accepts percentage values, too but only if the value on the element is already percentage
-- `flip()` now flips on both axis when no parameter is passed
-- fixed bug with `documentElement.contains()` in IE
-- fixed offset produced by svg parser (#553)
-- fixed a bug with clone which didnt copy over dom data (#621)
-
-
-## [2.4.0] - 2017-01-14
-
-### Added
-- added support for basic path animations (#561)
-
-
-## [2.3.7] - 2017-01-14
-
-### Added
-- added code coverage https://coveralls.io/github/svgdotjs/svg.js (3e614d4)
-- added `npm run test:quick` which aim at being fast rather than correct - great for git hooks (981ce24)
-
-### Changed
-- moved project to [svgdotjs](https://github.com/svgdotjs)
-- made matrixify work with transformation chain separated by commas (#543)
-- updated dev dependencies; request and gulp-chmod - `npm run build` now requires nodejs 4.x+
-
-### Fixed
-- fixed `SVG.Matrix.skew()` (#545)
-- fixed broken animations, if using polyfills for es6/7 proposals (#504)
-- fixed and improved `SVG.FX.dequeue()` (#546)
-- fixed an error in `SVG.FX.step`, if custom properties is added to `Array.prototype` (#549)
-
-
-## [2.3.6] - 2016-10-21
-
-### Changed
-- make SVG.FX.loop modify the last situation instead of the current one (#532)
-
-### Fixed
-- fixed leading and trailing space in SVG.PointArray would return NaN for some points (695f26a) (#529)
-- fixed test of `SVG.FX.afterAll` (#534)
-- fixed `SVG.FX.speed()` (#536)
-
-
-## [2.3.5] - 2016-10-13
-
-### Added
-- added automated unit tests via [Travis](https://travis-ci.org/svgdotjs/svg.js) (#527)
-- added `npm run build` to build a new version of SVG.js without requiring gulp to be globally installed
-
-### Changed
-- calling `fill()`, `stroke()` without an argument is now a nop
-- Polygon now accepts comma less points to achieve parity with Adobe Illustrator (#529)
-- updated dependencies
-
-
-## [2.3.4] - 2016-08-04
-
-### Changed
-- reworked parent module for speed improvemenents
-- reworked `filterSVGElements` utility to use a for loop instead of the native filter function
-
-
-## [2.3.3] - 2016-08-02
-
-### Added
-- add error callback on image loading (#508)
-
-### Fixed
-- fixed bug when getting bbox of text elements which are not in the dom (#514)
-- fixed bug when getting bbox of element which is hidden with css (#516)
-
-
-## [2.3.2] - 2016-06-21
-
-### Added
-- added specs for `SVG.ViewBox`
-- added `parent` parameter for `clone()`
-- added spec for mentioned issue
-
-### Fixed
-- fixed string parsing in viewbox (#483)
-- fixed bbox when element is not in the dom (#480)
-- fixed line constructor which doesn't work with Array as input (#487)
-- fixed problem in IE with `document.contains` (#490) related to (#480)
-- fixed `undo` when undoing transformations (#494)
-
-
-## [2.3.1] - 2016-05-05
-
-### Added
-- added typings for svg.js (#470)
-
-### Fixed
-- fixed `SVG.morph()` (#473)
-- fixed parser error (#471)
-- fixed bug in `SVG.Color` with new fx
-- fixed `radius()` for circles when animating and other related code (#477)
-- fixed bug where `stop(true)` throws an error when element is not animated (#475)
-- fixed bug in `add()` when altering svgs with whitespaces
-- fixed bug in `SVG.Doc().create` where size was set to 100% even if size was already specified
-- fixed bug in `parse()` from `SVG.PathArray` which does not correctly handled `S` and `T` (#485)
-
-
-## [2.3.0] - 2016-03-30
-
-### Added
-- added `SVG.Point` which serves as Wrapper to the native `SVGPoint` (#437)
-- added `element.point(x,y)` which transforms a point from screen coordinates to the elements space (#403)
-- added `element.is()` which helps to check for the object instance faster (instanceof check)
-- added more fx specs
-
-### Changed
-- textpath now is a parent element, the lines method of text will return the tspans inside the textpath (#450)
-- fx module rewritten to support animation chaining and several other stuff (see docs)
-
-### Fixed
-- fixed `svgjs:data` attribute which was not set properly in all browsers (#428)
-- fixed `isNumber` and `numberAndUnit` regex (#405)
-- fixed error where a parent node is not found when loading an image but the canvas was cleared (#447)
-- fixed absolute transformation animations (not perfect but better)
-- fixed event listeners which didnt work correctly when identic funtions used
-
-
-## [2.2.5] - 2015-12-29
-
-### Added
-- added check for existence of node (#431)
-
-### Changed
-- `group.move()` now allows string numbers as input (#433)
-- `matrixify()` will not apply the calculated matrix to the node anymore
-
-
-## [2.2.4] - 2015-12-12
-
-### Fixed
-- fixed `transform()` which returns the matrix values (a-f) now, too (#423)
-- double newlines (\n\n) are correctly handled as blank line from `text()`
-- fixed use of scrollX vs pageXOffset in `rbox()` (#425)
-- fixed target array in mask and clip which was removed instead of reinitialized (#429)
-
-
-## [2.2.3] - 2015-11-30
-
-### Fixed
-- fixed null check in image (see 2.2.2)
-- fixed bug related to the new path parser (see 2.2.2)
-- fixed amd loader (#412)
-
-
-## [2.2.2] - 2015-11-28
-
-### Added
-- added null check in image onload callback (#415)
-
-### Changed
-- documentation rework (#407) [thanks @snowyplover]
-
-### Fixed
-- fixed leading point bug in path parsing (#416)
-
-
-## [2.2.1] - 2015-11-18
-
-### Added
-- added workaround for `SvgPathSeg` which is removed in Chrome 48 (#409)
-- added `gbox()` to group to get bbox with translation included (#405)
-
-### Fixed
-- fixed dom data which was not cleaned up properly (#398)
-
-
-## [2.2.0] - 2015-11-06
-
-### Added
-- added `ungroup()/flatten()` (#238), `toParent()` and `toDoc()`
-- added UMD-Wrapper with possibility to pass custom window object (#352)
-- added `morph()` method for paths via plugin [svg.pathmorphing.js](https://github.com/Fuzzyma/svg.pathmorphing.js)
-- added support for css selectors within the `parent()` method
-- added `parents()` method to get an array of all parenting elements
-
-### Changed
-- svgjs now saves crucial data in the dom before export and restores them when element is adopted
-
-### Fixed
-- fixed pattern and gradient animation (#385)
-- fixed mask animation in Firefox (#287)
-- fixed return value of `text()` after import/clone (#393)
-
-
-## [2.1.1] - 2015-10-03
-
-### Added
-- added custom context binding to event callback (default is the element the event is bound to)
-
-
-## [2.1.0] - 2015-09-20
-
-### Added
-- added transform to pattern and gradients (#383)
-
-### Fixed
-- fixed clone of textnodes (#369)
-- fixed transformlists in IE (#372)
-- fixed typo that leads to broken gradients (#370)
-- fixed animate radius for circles (#367)
-
-
-## [2.0.2] - 2015-06-22
-
-### Fixed
-- Fixed zoom consideration in circle and ellipse
-
-
-## [2.0.1] - 2015-06-21
-
-### Added
-- added possibility to remove all events from a certain namespace
-
-### Fixed
-- fixed bug with `doc()` which always should return root svg
-- fixed bug in `SVG.FX` when animating with `plot()`
-
-### Removed
-- removed target reference from use which caused bugs in `dmove()` and `use()` with external file
-- removed scale consideration in `move()` duo to incompatibilities with other move-functions e.g. in `SVG.PointArray`
-
-
-## [2.0.0] - 2015-06-11
-
-### Added
-- implemented an SVG adoption system to be able to manipulate existing SVG's not created with svg.js
-- added polyfill for IE9 and IE10 custom events [thanks @Fuzzyma]
-- added DOM query selector with the `select()` method globally or on parent elements
-- added the intentionally neglected `SVG.Circle` element
-- added `rx()` and `ry()` to `SVG.Rect`, `SVG.Circle`, `SVG.Ellispe` and `SVG.FX`
-- added support to clone manually built text elements
-- added `svg.wiml.js` plugin to plugins list
-- added `ctm()` method to for matrix-centric transformations
-- added `morph()` method to `SVG.Matrix`
-- added support for new matrix system to `SVG.FX`
-- added `native()` method to elements and matrix to get to the native api
-- added `untransform()` method to remove all transformations
-- added raw svg import functionality with the `svg()` method
-- added coding style description to README
-- added reverse functionality for animations
-- documented the `situation` object in `SVG.FX`
-- added distinction between relative and absolute matrix transformations
-- implemented the `element()` method using the `SVG.Bare` class to create elements that are not described by SVG.js
-- added `w` and `h` properties as shorthand for `width` and `height` to `SVG.BBox`
-- added `SVG.TBox` to get a bounding box that is affected by transformation values
-- added event-based or complete detaching of event listeners in `off()` method
-
-### Changed
-- changed `parent` reference on elements to `parent()` method
-- using `CustomEvent` instead of `Event` to be able to fire events with a `detail` object [thanks @Fuzzyma]
-- renamed `SVG.TSpan` class to `SVG.Tspan` to play nice with the adoption system
-- completely reworked `clone()` method to use the adoption system
-- completely reworked transformations to be chainable and more true to their nature
-- changed `lines` reference to `lines()` on `SVG.Text`
-- changed `track` reference to `track()` on `SVG.Text`
-- changed `textPath` reference to `textPath()` on `SVG.Text`
-- changed `array` reference to `array()` method on `SVG.Polyline`, `SVG.Polygon` and `SVG.Path`
-- reworked sup-pixel offset implementation to be more compact
-- switched from Ruby's `rake` to Node's `gulp` for building [thanks to Alex Ewerlöf]
-- changed `to()` method to `at()` method in `SVG.FX`
-- renamed `SVG.SetFX` to `SVG.FX.Set`
-- reworked `SVG.Number` to return new instances with calculations rather than itself
-- reworked animatable matrix rotations
-- removed `SVG.Symbol` but kept the `symbol()` method using the new `element()` method
-
-### Fixed
-- fixed bug in `radius()` method when `y` value equals `0`
-- fixed a bug where events are not detached properly
-
-
-## [1.0.0-rc.9] - 2014-06-17
-
-### Added
-- added `SVG.Marker`
-- added `SVG.Symbol`
-- added `first()` and `last()` methods to `SVG.Set`
-- added `length()` method to `SVG.Text` and `SVG.TSpan` to calculate total text length
-- added `reference()` method to get referenced elements from a given attribute value
-
-### Changed
-- `SVG.get()` will now also fetch elements with a `xlink:href="#elementId"` or `url(#elementId)` value given
-
-### Fixed
-- fixed infinite loop in viewbox when element has a percentage width / height [thanks @shabegger]
-
-
-## [1.0.0-rc.8] - 2014-06-12
-
-### Fixed
-- fixed bug in `SVG.off`
-- fixed offset by window scroll position in `rbox()` [thanks @bryhoyt]
-
-
-## [1.0.0-rc.7] - 2014-06-11
-
-### Added
-- added `classes()`, `hasClass()`, `addClass()`, `removeClass()` and `toggleClass()` [thanks @pklingem]
-
-### Changed
-- binding events listeners to svg.js instance
-- calling `after()` when calling `stop(true)` (fulfill flag) [thanks @vird]
-- text element fires `rebuild` event whenever the `rebuild()` method is called
-
-### Fixed
-- fixed a bug where `Element#style()` would not save empty values in IE11 [thanks @Shtong]
-- fixed `SVG is not defined error` [thanks @anvaka]
-- fixed a bug in `move()`on text elements with a string based value
-- fix for `text()` method on text element when acting as getter [thanks @Lochemage]
-- fix in `style()` method with a css string [thanks @TobiasHeckel]
-
-
-## [1.0.0-rc.6] - 2014-03-03
-
-### Added
-- added `leading()` method to `SVG.FX`
-- added `reverse()` method to `SVG.Array` (and thereby also to `SVG.PointArray` and `SVG.PathArray`)
-- added `fulfill` option to `stop()` method in `SVG.FX` to finalise animations
-- added more output values to `bbox()` and `rbox()` methods
-
-### Changed
-- fine-tuned text element positioning
-- calling `at()` method directly on morphable svg.js instances in `SVG.FX` module
-- moved most `_private` methods to local named functions
-- moved helpers to a separate file
-
-### Fixed
-- fixed a bug in text `dy()` method
-
-### Removed
-- removed internal representation for `style`
-
-
-## [1.0.0-rc.5] - 2014-02-14
-
-### Added
-- added `plain()` method to `SVG.Text` element to add plain text content, without tspans
-- added `plain()` method to parent elements to create a text element without tspans
-- added `build()` to enable/disable build mode
-
-### Changed
-- updated `SVG.TSpan` to accept nested tspan elements, not unlike the `text()` method in `SVG.Text`
-- removed the `relative()` method in favour of `dx()`, `dy()` and `dmove()`
-- switched form objects to arrays in `SVG.PathArray` for compatibility with other libraries and better performance on parsing and rendering (up-to 48% faster than 1.0.0-rc.4)
-- refined docs on element-specific methods and `SVG.PathArray` structure
-- reworked `leading()` implementation to be more font-size "aware"
-- refactored the `attr` method on `SVG.Element`
-- applied Helvetica as default font
-- building `SVG.FX` class with `SVG.invent()` function
-
-### Removed
-- removed verbose style application to tspans
-
-
-## [1.0.0-rc.4] - 2014-02-04
-
-### Added
-- automatic pattern creation by passing an image url or instance as `fill` attribute on elements
-- added `loaded()` method to image tag
-- added `pointAt()` method to `SVG.Path`, wrapping the native `getPointAtLength()`
-
-### Changed
-- switched to `MAJOR`.`MINOR`.`PATCH` versioning format to play nice with package managers
-- made svg.pattern.js part of the core library
-- moved `length()` method to sugar module
-
-### Fixed
-- fix in `animate('=').to()`
-- fix for arcs in patharray `toString()` method [thanks @dotnetCarpenter]
-
-
-## [v1.0rc3] - 2014-02-03
-
-### Added
-- added the `SVG.invent` function to ease invention of new elements
-- added second values for `animate('2s')`
-- added `length()` mehtod to path, wrapping the native `getTotalLength()`
-
-### Changed
-- using `SVG.invent` to generate core shapes as well for leaner code
-
-### Fixed
-- fix for html-less documents
-- fix for arcs in patharray `toString()` method
-
-
-## [v1.0rc2] - 2014-02-01
-
-### Added
-- added `index()` method to `SVG.Parent` and `SVG.Set`
-- added `morph()` and `at()` methods to `SVG.Number` for unit morphing
-
-### Changed
-- modified `cx()` and `cy()` methods on elements with native `x`, `y`, `width` and `height` attributes for better performance
-
-
-## [v1.0rc1] - 2014-01-31
-
-### Added
-- added `SVG.PathArray` for real path transformations
-- added `bbox()` method to `SVG.Set`
-- added `relative()` method for moves relative to the current position
-- added `morph()` and `at()` methods to `SVG.Color` for color morphing
-
-### Changed
-- enabled proportional resizing on `size()` method with `null` for either `width` or `height` values
-- moved data module to separate file
-- `data()` method now accepts object for for multiple key / value assignments
-
-### Removed
-- removed `unbiased` system for paths
-
-
-## [v0.38] - 2014-01-28
-
-### Added
-- added `loop()` method to `SVG.FX`
-
-### Changed
-- switched from `setInterval` to `requestAnimFrame` for animations
-
-
-## [v0.37] - 2014-01-26
-
-### Added
-- added `get()` to `SVG.Set`
-
-### Changed
-- moved `SVG.PointArray` to a separate file
-
-
-## [v0.36] - 2014-01-25
-
-### Added
-- added `linkTo()`, `addTo()` and `putIn()` methods on `SVG.Element`
-
-### Changed
-- provided more detailed documentation on parent elements
-
-### Fixed
-
-
-## [v0.35] - 2014-01-23
-
-### Added
-- added `SVG.A` element with the `link()`
-
-
-## [v0.34] - 2014-01-23
-
-### Added
-- added `pause()` and `play()` to `SVG.FX`
-
-### Changed
-- storing animation values in `situation` object
-
-
-## [v0.33] - 2014-01-22
-
-### Added
-- added `has()` method to `SVG.Set`
-- added `width()` and `height()` as setter and getter methods on all shapes
-- added `replace()` method to elements
-- added `radius()` method to `SVG.Rect` and `SVG.Ellipse`
-- added reference to parent node in defs
-
-### Changed
-- moved sub-pixel offset fix to be an optional method (e.g. `SVG('drawing').fixSubPixelOffset()`)
-- merged plotable.js and path.js
-
-
-## [v0.32]
-
-### Added
-- added library to [cdnjs](http://cdnjs.com)
-
-
-
-[2.6.0]: https://github.com/svgdotjs/svg.js/releases/tag/2.6.0
-[2.5.3]: https://github.com/svgdotjs/svg.js/releases/tag/2.5.3
-[2.5.2]: https://github.com/svgdotjs/svg.js/releases/tag/2.5.2
-[2.5.1]: https://github.com/svgdotjs/svg.js/releases/tag/2.5.1
-[2.5.0]: https://github.com/svgdotjs/svg.js/releases/tag/2.5.0
-[2.4.0]: https://github.com/svgdotjs/svg.js/releases/tag/2.4.0
-
-[2.3.7]: https://github.com/svgdotjs/svg.js/releases/tag/2.3.7
-[2.3.6]: https://github.com/svgdotjs/svg.js/releases/tag/2.3.6
-[2.3.5]: https://github.com/svgdotjs/svg.js/releases/tag/2.3.5
-[2.3.4]: https://github.com/svgdotjs/svg.js/releases/tag/2.3.4
-[2.3.3]: https://github.com/svgdotjs/svg.js/releases/tag/2.3.3
-[2.3.2]: https://github.com/svgdotjs/svg.js/releases/tag/2.3.2
-[2.3.1]: https://github.com/svgdotjs/svg.js/releases/tag/2.3.1
-[2.3.0]: https://github.com/svgdotjs/svg.js/releases/tag/2.3.0
-
-[2.2.5]: https://github.com/svgdotjs/svg.js/releases/tag/2.2.5
-[2.2.4]: https://github.com/svgdotjs/svg.js/releases/tag/2.2.4
-[2.2.3]: https://github.com/svgdotjs/svg.js/releases/tag/2.2.3
-[2.2.2]: https://github.com/svgdotjs/svg.js/releases/tag/2.2.2
-[2.2.1]: https://github.com/svgdotjs/svg.js/releases/tag/2.2.1
-[2.2.0]: https://github.com/svgdotjs/svg.js/releases/tag/2.2.0
-
-[2.1.1]: https://github.com/svgdotjs/svg.js/releases/tag/2.1.1
-[2.1.0]: https://github.com/svgdotjs/svg.js/releases/tag/2.1.0
-
-[2.0.2]: https://github.com/svgdotjs/svg.js/releases/tag/2.0.2
-[2.0.1]: https://github.com/svgdotjs/svg.js/releases/tag/2.0.1
-[2.0.0]: https://github.com/svgdotjs/svg.js/releases/tag/2.0.0
-
-[1.0.0-rc.9]: https://github.com/svgdotjs/svg.js/releases/tag/1.0.0-rc.9
-[1.0.0-rc.8]: https://github.com/svgdotjs/svg.js/releases/tag/1.0.0-rc.8
-[1.0.0-rc.7]: https://github.com/svgdotjs/svg.js/releases/tag/1.0.0-rc.7
-[1.0.0-rc.6]: https://github.com/svgdotjs/svg.js/releases/tag/1.0.0-rc.6
-[1.0.0-rc.5]: https://github.com/svgdotjs/svg.js/releases/tag/1.0.0-rc.5
-[1.0.0-rc.4]: https://github.com/svgdotjs/svg.js/releases/tag/1.0.0-rc.4
-[v1.0rc3]: https://github.com/svgdotjs/svg.js/releases/tag/v1.0rc3
-[v1.0rc2]: https://github.com/svgdotjs/svg.js/releases/tag/v1.0rc2
-[v1.0rc1]: https://github.com/svgdotjs/svg.js/releases/tag/v1.0rc1
-
-[v0.38]: https://github.com/svgdotjs/svg.js/releases/tag/v0.38
-[v0.37]: https://github.com/svgdotjs/svg.js/releases/tag/v0.37
-[v0.36]: https://github.com/svgdotjs/svg.js/releases/tag/v0.36
-[v0.35]: https://github.com/svgdotjs/svg.js/releases/tag/v0.35
-[v0.34]: https://github.com/svgdotjs/svg.js/releases/tag/v0.34
-[v0.33]: https://github.com/svgdotjs/svg.js/releases/tag/v0.33
-[v0.32]: https://github.com/svgdotjs/svg.js/releases/tag/v0.32
diff --git a/files/plugin-HeatmapSessionRecording-5.2.6/libs/svg.js/LICENSE.txt b/files/plugin-HeatmapSessionRecording-5.2.6/libs/svg.js/LICENSE.txt
deleted file mode 100644
index 148b70a..0000000
--- a/files/plugin-HeatmapSessionRecording-5.2.6/libs/svg.js/LICENSE.txt
+++ /dev/null
@@ -1,21 +0,0 @@
-Copyright (c) 2012-2017 Wout Fierens
-https://svgdotjs.github.io/
-
-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/files/plugin-HeatmapSessionRecording-5.2.6/libs/svg.js/README.md b/files/plugin-HeatmapSessionRecording-5.2.6/libs/svg.js/README.md
deleted file mode 100644
index b88c5a5..0000000
--- a/files/plugin-HeatmapSessionRecording-5.2.6/libs/svg.js/README.md
+++ /dev/null
@@ -1,29 +0,0 @@
-# SVG.js
-
-[](https://travis-ci.org/svgdotjs/svg.js)
-[](https://coveralls.io/github/svgdotjs/svg.js?branch=master)
-[](https://cdnjs.com/libraries/svg.js)
-[](https://gitter.im/svgdotjs/svg.js?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
-
-__A lightweight library for manipulating and animating SVG, without any dependencies.__
-
-SVG.js is licensed under the terms of the MIT License.
-
-## Installation
-
-#### Bower:
-
-`bower install svg.js`
-
-#### Node:
-
-`npm install svg.js`
-
-#### Cdnjs:
-
-[https://cdnjs.com/libraries/svg.js](https://cdnjs.com/libraries/svg.js)
-
-## Documentation
-Check [https://svgdotjs.github.io](https://svgdotjs.github.io/) to learn more.
-
-[](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=pay%40woutfierens.com&lc=US&item_name=SVG.JS¤cy_code=EUR&bn=PP-DonationsBF%3Abtn_donate_74x21.png%3ANonHostedGuest)
diff --git a/files/plugin-HeatmapSessionRecording-5.2.6/libs/svg.js/dist/svg.js b/files/plugin-HeatmapSessionRecording-5.2.6/libs/svg.js/dist/svg.js
deleted file mode 100644
index d2fd5d3..0000000
--- a/files/plugin-HeatmapSessionRecording-5.2.6/libs/svg.js/dist/svg.js
+++ /dev/null
@@ -1,5518 +0,0 @@
-/*!
-* svg.js - A lightweight library for manipulating and animating SVG.
-* @version 2.6.1
-* https://svgdotjs.github.io/
-*
-* @copyright Wout Fierens
-* @license MIT
-*
-* BUILT: Tue Apr 25 2017 11:58:09 GMT+0200 (Mitteleuropäische Sommerzeit)
-*/;
-(function(root, factory) {
- /* istanbul ignore next */
- if (typeof define === 'function' && define.amd) {
- define(function(){
- return factory(root, root.document)
- })
- } else if (typeof exports === 'object') {
- module.exports = root.document ? factory(root, root.document) : function(w){ return factory(w, w.document) }
- } else {
- root.SVG = factory(root, root.document)
- }
-}(typeof window !== "undefined" ? window : this, function(window, document) {
-
-// The main wrapping element
-var SVG = this.SVG = function(element) {
- if (SVG.supported) {
- element = new SVG.Doc(element)
-
- if(!SVG.parser.draw)
- SVG.prepare()
-
- return element
- }
-}
-
-// Default namespaces
-SVG.ns = 'http://www.w3.org/2000/svg'
-SVG.xmlns = 'http://www.w3.org/2000/xmlns/'
-SVG.xlink = 'http://www.w3.org/1999/xlink'
-SVG.svgjs = 'http://svgjs.com/svgjs'
-
-// Svg support test
-SVG.supported = (function() {
- return !! document.createElementNS &&
- !! document.createElementNS(SVG.ns,'svg').createSVGRect
-})()
-
-// Don't bother to continue if SVG is not supported
-if (!SVG.supported) return false
-
-// Element id sequence
-SVG.did = 1000
-
-// Get next named element id
-SVG.eid = function(name) {
- return 'Svgjs' + capitalize(name) + (SVG.did++)
-}
-
-// Method for element creation
-SVG.create = function(name) {
- // create element
- var element = document.createElementNS(this.ns, name)
-
- // apply unique id
- element.setAttribute('id', this.eid(name))
-
- return element
-}
-
-// Method for extending objects
-SVG.extend = function() {
- var modules, methods, key, i
-
- // Get list of modules
- modules = [].slice.call(arguments)
-
- // Get object with extensions
- methods = modules.pop()
-
- for (i = modules.length - 1; i >= 0; i--)
- if (modules[i])
- for (key in methods)
- modules[i].prototype[key] = methods[key]
-
- // Make sure SVG.Set inherits any newly added methods
- if (SVG.Set && SVG.Set.inherit)
- SVG.Set.inherit()
-}
-
-// Invent new element
-SVG.invent = function(config) {
- // Create element initializer
- var initializer = typeof config.create == 'function' ?
- config.create :
- function() {
- this.constructor.call(this, SVG.create(config.create))
- }
-
- // Inherit prototype
- if (config.inherit)
- initializer.prototype = new config.inherit
-
- // Extend with methods
- if (config.extend)
- SVG.extend(initializer, config.extend)
-
- // Attach construct method to parent
- if (config.construct)
- SVG.extend(config.parent || SVG.Container, config.construct)
-
- return initializer
-}
-
-// Adopt existing svg elements
-SVG.adopt = function(node) {
- // check for presence of node
- if (!node) return null
-
- // make sure a node isn't already adopted
- if (node.instance) return node.instance
-
- // initialize variables
- var element
-
- // adopt with element-specific settings
- if (node.nodeName == 'svg')
- element = node.parentNode instanceof window.SVGElement ? new SVG.Nested : new SVG.Doc
- else if (node.nodeName == 'linearGradient')
- element = new SVG.Gradient('linear')
- else if (node.nodeName == 'radialGradient')
- element = new SVG.Gradient('radial')
- else if (SVG[capitalize(node.nodeName)])
- element = new SVG[capitalize(node.nodeName)]
- else
- element = new SVG.Element(node)
-
- // ensure references
- element.type = node.nodeName
- element.node = node
- node.instance = element
-
- // SVG.Class specific preparations
- if (element instanceof SVG.Doc)
- element.namespace().defs()
-
- // pull svgjs data from the dom (getAttributeNS doesn't work in html5)
- element.setData(JSON.parse(node.getAttribute('svgjs:data')) || {})
-
- return element
-}
-
-// Initialize parsing element
-SVG.prepare = function() {
- // Select document body and create invisible svg element
- var body = document.getElementsByTagName('body')[0]
- , draw = (body ? new SVG.Doc(body) : SVG.adopt(document.documentElement).nested()).size(2, 0)
-
- // Create parser object
- SVG.parser = {
- body: body || document.documentElement
- , draw: draw.style('opacity:0;position:absolute;left:-100%;top:-100%;overflow:hidden').node
- , poly: draw.polyline().node
- , path: draw.path().node
- , native: SVG.create('svg')
- }
-}
-
-SVG.parser = {
- native: SVG.create('svg')
-}
-
-document.addEventListener('DOMContentLoaded', function() {
- if(!SVG.parser.draw)
- SVG.prepare()
-}, false)
-
-// Storage for regular expressions
-SVG.regex = {
- // Parse unit value
- numberAndUnit: /^([+-]?(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?)([a-z%]*)$/i
-
- // Parse hex value
-, hex: /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i
-
- // Parse rgb value
-, rgb: /rgb\((\d+),(\d+),(\d+)\)/
-
- // Parse reference id
-, reference: /#([a-z0-9\-_]+)/i
-
- // splits a transformation chain
-, transforms: /\)\s*,?\s*/
-
- // Whitespace
-, whitespace: /\s/g
-
- // Test hex value
-, isHex: /^#[a-f0-9]{3,6}$/i
-
- // Test rgb value
-, isRgb: /^rgb\(/
-
- // Test css declaration
-, isCss: /[^:]+:[^;]+;?/
-
- // Test for blank string
-, isBlank: /^(\s+)?$/
-
- // Test for numeric string
-, isNumber: /^[+-]?(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?$/i
-
- // Test for percent value
-, isPercent: /^-?[\d\.]+%$/
-
- // Test for image url
-, isImage: /\.(jpg|jpeg|png|gif|svg)(\?[^=]+.*)?/i
-
- // split at whitespace and comma
-, delimiter: /[\s,]+/
-
- // The following regex are used to parse the d attribute of a path
-
- // Matches all hyphens which are not after an exponent
-, hyphen: /([^e])\-/gi
-
- // Replaces and tests for all path letters
-, pathLetters: /[MLHVCSQTAZ]/gi
-
- // yes we need this one, too
-, isPathLetter: /[MLHVCSQTAZ]/i
-
- // matches 0.154.23.45
-, numbersWithDots: /((\d?\.\d+(?:e[+-]?\d+)?)((?:\.\d+(?:e[+-]?\d+)?)+))+/gi
-
- // matches .
-, dots: /\./g
-}
-
-SVG.utils = {
- // Map function
- map: function(array, block) {
- var i
- , il = array.length
- , result = []
-
- for (i = 0; i < il; i++)
- result.push(block(array[i]))
-
- return result
- }
-
- // Filter function
-, filter: function(array, block) {
- var i
- , il = array.length
- , result = []
-
- for (i = 0; i < il; i++)
- if (block(array[i]))
- result.push(array[i])
-
- return result
- }
-
- // Degrees to radians
-, radians: function(d) {
- return d % 360 * Math.PI / 180
- }
-
- // Radians to degrees
-, degrees: function(r) {
- return r * 180 / Math.PI % 360
- }
-
-, filterSVGElements: function(nodes) {
- return this.filter( nodes, function(el) { return el instanceof window.SVGElement })
- }
-
-}
-
-SVG.defaults = {
- // Default attribute values
- attrs: {
- // fill and stroke
- 'fill-opacity': 1
- , 'stroke-opacity': 1
- , 'stroke-width': 0
- , 'stroke-linejoin': 'miter'
- , 'stroke-linecap': 'butt'
- , fill: '#000000'
- , stroke: '#000000'
- , opacity: 1
- // position
- , x: 0
- , y: 0
- , cx: 0
- , cy: 0
- // size
- , width: 0
- , height: 0
- // radius
- , r: 0
- , rx: 0
- , ry: 0
- // gradient
- , offset: 0
- , 'stop-opacity': 1
- , 'stop-color': '#000000'
- // text
- , 'font-size': 16
- , 'font-family': 'Helvetica, Arial, sans-serif'
- , 'text-anchor': 'start'
- }
-
-}
-// Module for color convertions
-SVG.Color = function(color) {
- var match
-
- // initialize defaults
- this.r = 0
- this.g = 0
- this.b = 0
-
- if(!color) return
-
- // parse color
- if (typeof color === 'string') {
- if (SVG.regex.isRgb.test(color)) {
- // get rgb values
- match = SVG.regex.rgb.exec(color.replace(SVG.regex.whitespace,''))
-
- // parse numeric values
- this.r = parseInt(match[1])
- this.g = parseInt(match[2])
- this.b = parseInt(match[3])
-
- } else if (SVG.regex.isHex.test(color)) {
- // get hex values
- match = SVG.regex.hex.exec(fullHex(color))
-
- // parse numeric values
- this.r = parseInt(match[1], 16)
- this.g = parseInt(match[2], 16)
- this.b = parseInt(match[3], 16)
-
- }
-
- } else if (typeof color === 'object') {
- this.r = color.r
- this.g = color.g
- this.b = color.b
-
- }
-
-}
-
-SVG.extend(SVG.Color, {
- // Default to hex conversion
- toString: function() {
- return this.toHex()
- }
- // Build hex value
-, toHex: function() {
- return '#'
- + compToHex(this.r)
- + compToHex(this.g)
- + compToHex(this.b)
- }
- // Build rgb value
-, toRgb: function() {
- return 'rgb(' + [this.r, this.g, this.b].join() + ')'
- }
- // Calculate true brightness
-, brightness: function() {
- return (this.r / 255 * 0.30)
- + (this.g / 255 * 0.59)
- + (this.b / 255 * 0.11)
- }
- // Make color morphable
-, morph: function(color) {
- this.destination = new SVG.Color(color)
-
- return this
- }
- // Get morphed color at given position
-, at: function(pos) {
- // make sure a destination is defined
- if (!this.destination) return this
-
- // normalise pos
- pos = pos < 0 ? 0 : pos > 1 ? 1 : pos
-
- // generate morphed color
- return new SVG.Color({
- r: ~~(this.r + (this.destination.r - this.r) * pos)
- , g: ~~(this.g + (this.destination.g - this.g) * pos)
- , b: ~~(this.b + (this.destination.b - this.b) * pos)
- })
- }
-
-})
-
-// Testers
-
-// Test if given value is a color string
-SVG.Color.test = function(color) {
- color += ''
- return SVG.regex.isHex.test(color)
- || SVG.regex.isRgb.test(color)
-}
-
-// Test if given value is a rgb object
-SVG.Color.isRgb = function(color) {
- return color && typeof color.r == 'number'
- && typeof color.g == 'number'
- && typeof color.b == 'number'
-}
-
-// Test if given value is a color
-SVG.Color.isColor = function(color) {
- return SVG.Color.isRgb(color) || SVG.Color.test(color)
-}
-// Module for array conversion
-SVG.Array = function(array, fallback) {
- array = (array || []).valueOf()
-
- // if array is empty and fallback is provided, use fallback
- if (array.length == 0 && fallback)
- array = fallback.valueOf()
-
- // parse array
- this.value = this.parse(array)
-}
-
-SVG.extend(SVG.Array, {
- // Make array morphable
- morph: function(array) {
- this.destination = this.parse(array)
-
- // normalize length of arrays
- if (this.value.length != this.destination.length) {
- var lastValue = this.value[this.value.length - 1]
- , lastDestination = this.destination[this.destination.length - 1]
-
- while(this.value.length > this.destination.length)
- this.destination.push(lastDestination)
- while(this.value.length < this.destination.length)
- this.value.push(lastValue)
- }
-
- return this
- }
- // Clean up any duplicate points
-, settle: function() {
- // find all unique values
- for (var i = 0, il = this.value.length, seen = []; i < il; i++)
- if (seen.indexOf(this.value[i]) == -1)
- seen.push(this.value[i])
-
- // set new value
- return this.value = seen
- }
- // Get morphed array at given position
-, at: function(pos) {
- // make sure a destination is defined
- if (!this.destination) return this
-
- // generate morphed array
- for (var i = 0, il = this.value.length, array = []; i < il; i++)
- array.push(this.value[i] + (this.destination[i] - this.value[i]) * pos)
-
- return new SVG.Array(array)
- }
- // Convert array to string
-, toString: function() {
- return this.value.join(' ')
- }
- // Real value
-, valueOf: function() {
- return this.value
- }
- // Parse whitespace separated string
-, parse: function(array) {
- array = array.valueOf()
-
- // if already is an array, no need to parse it
- if (Array.isArray(array)) return array
-
- return this.split(array)
- }
- // Strip unnecessary whitespace
-, split: function(string) {
- return string.trim().split(SVG.regex.delimiter).map(parseFloat)
- }
- // Reverse array
-, reverse: function() {
- this.value.reverse()
-
- return this
- }
-, clone: function() {
- var clone = new this.constructor()
- clone.value = array_clone(this.value)
- return clone
- }
-})
-// Poly points array
-SVG.PointArray = function(array, fallback) {
- SVG.Array.call(this, array, fallback || [[0,0]])
-}
-
-// Inherit from SVG.Array
-SVG.PointArray.prototype = new SVG.Array
-SVG.PointArray.prototype.constructor = SVG.PointArray
-
-SVG.extend(SVG.PointArray, {
- // Convert array to string
- toString: function() {
- // convert to a poly point string
- for (var i = 0, il = this.value.length, array = []; i < il; i++)
- array.push(this.value[i].join(','))
-
- return array.join(' ')
- }
- // Convert array to line object
-, toLine: function() {
- return {
- x1: this.value[0][0]
- , y1: this.value[0][1]
- , x2: this.value[1][0]
- , y2: this.value[1][1]
- }
- }
- // Get morphed array at given position
-, at: function(pos) {
- // make sure a destination is defined
- if (!this.destination) return this
-
- // generate morphed point string
- for (var i = 0, il = this.value.length, array = []; i < il; i++)
- array.push([
- this.value[i][0] + (this.destination[i][0] - this.value[i][0]) * pos
- , this.value[i][1] + (this.destination[i][1] - this.value[i][1]) * pos
- ])
-
- return new SVG.PointArray(array)
- }
- // Parse point string and flat array
-, parse: function(array) {
- var points = []
-
- array = array.valueOf()
-
- // if it is an array
- if (Array.isArray(array)) {
- // and it is not flat, there is no need to parse it
- if(Array.isArray(array[0])) {
- return array
- }
- } else { // Else, it is considered as a string
- // parse points
- array = array.trim().split(SVG.regex.delimiter).map(parseFloat)
- }
-
- // validate points - https://svgwg.org/svg2-draft/shapes.html#DataTypePoints
- // Odd number of coordinates is an error. In such cases, drop the last odd coordinate.
- if (array.length % 2 !== 0) array.pop()
-
- // wrap points in two-tuples and parse points as floats
- for(var i = 0, len = array.length; i < len; i = i + 2)
- points.push([ array[i], array[i+1] ])
-
- return points
- }
- // Move point string
-, move: function(x, y) {
- var box = this.bbox()
-
- // get relative offset
- x -= box.x
- y -= box.y
-
- // move every point
- if (!isNaN(x) && !isNaN(y))
- for (var i = this.value.length - 1; i >= 0; i--)
- this.value[i] = [this.value[i][0] + x, this.value[i][1] + y]
-
- return this
- }
- // Resize poly string
-, size: function(width, height) {
- var i, box = this.bbox()
-
- // recalculate position of all points according to new size
- for (i = this.value.length - 1; i >= 0; i--) {
- if(box.width) this.value[i][0] = ((this.value[i][0] - box.x) * width) / box.width + box.x
- if(box.height) this.value[i][1] = ((this.value[i][1] - box.y) * height) / box.height + box.y
- }
-
- return this
- }
- // Get bounding box of points
-, bbox: function() {
- SVG.parser.poly.setAttribute('points', this.toString())
-
- return SVG.parser.poly.getBBox()
- }
-})
-
-var pathHandlers = {
- M: function(c, p, p0) {
- p.x = p0.x = c[0]
- p.y = p0.y = c[1]
-
- return ['M', p.x, p.y]
- },
- L: function(c, p) {
- p.x = c[0]
- p.y = c[1]
- return ['L', c[0], c[1]]
- },
- H: function(c, p) {
- p.x = c[0]
- return ['H', c[0]]
- },
- V: function(c, p) {
- p.y = c[0]
- return ['V', c[0]]
- },
- C: function(c, p) {
- p.x = c[4]
- p.y = c[5]
- return ['C', c[0], c[1], c[2], c[3], c[4], c[5]]
- },
- S: function(c, p) {
- p.x = c[2]
- p.y = c[3]
- return ['S', c[0], c[1], c[2], c[3]]
- },
- Q: function(c, p) {
- p.x = c[2]
- p.y = c[3]
- return ['Q', c[0], c[1], c[2], c[3]]
- },
- T: function(c, p) {
- p.x = c[0]
- p.y = c[1]
- return ['T', c[0], c[1]]
- },
- Z: function(c, p, p0) {
- p.x = p0.x
- p.y = p0.y
- return ['Z']
- },
- A: function(c, p) {
- p.x = c[5]
- p.y = c[6]
- return ['A', c[0], c[1], c[2], c[3], c[4], c[5], c[6]]
- }
-}
-
-var mlhvqtcsa = 'mlhvqtcsaz'.split('')
-
-for(var i = 0, il = mlhvqtcsa.length; i < il; ++i){
- pathHandlers[mlhvqtcsa[i]] = (function(i){
- return function(c, p, p0) {
- if(i == 'H') c[0] = c[0] + p.x
- else if(i == 'V') c[0] = c[0] + p.y
- else if(i == 'A'){
- c[5] = c[5] + p.x,
- c[6] = c[6] + p.y
- }
- else
- for(var j = 0, jl = c.length; j < jl; ++j) {
- c[j] = c[j] + (j%2 ? p.y : p.x)
- }
-
- return pathHandlers[i](c, p, p0)
- }
- })(mlhvqtcsa[i].toUpperCase())
-}
-
-// Path points array
-SVG.PathArray = function(array, fallback) {
- SVG.Array.call(this, array, fallback || [['M', 0, 0]])
-}
-
-// Inherit from SVG.Array
-SVG.PathArray.prototype = new SVG.Array
-SVG.PathArray.prototype.constructor = SVG.PathArray
-
-SVG.extend(SVG.PathArray, {
- // Convert array to string
- toString: function() {
- return arrayToString(this.value)
- }
- // Move path string
-, move: function(x, y) {
- // get bounding box of current situation
- var box = this.bbox()
-
- // get relative offset
- x -= box.x
- y -= box.y
-
- if (!isNaN(x) && !isNaN(y)) {
- // move every point
- for (var l, i = this.value.length - 1; i >= 0; i--) {
- l = this.value[i][0]
-
- if (l == 'M' || l == 'L' || l == 'T') {
- this.value[i][1] += x
- this.value[i][2] += y
-
- } else if (l == 'H') {
- this.value[i][1] += x
-
- } else if (l == 'V') {
- this.value[i][1] += y
-
- } else if (l == 'C' || l == 'S' || l == 'Q') {
- this.value[i][1] += x
- this.value[i][2] += y
- this.value[i][3] += x
- this.value[i][4] += y
-
- if (l == 'C') {
- this.value[i][5] += x
- this.value[i][6] += y
- }
-
- } else if (l == 'A') {
- this.value[i][6] += x
- this.value[i][7] += y
- }
-
- }
- }
-
- return this
- }
- // Resize path string
-, size: function(width, height) {
- // get bounding box of current situation
- var i, l, box = this.bbox()
-
- // recalculate position of all points according to new size
- for (i = this.value.length - 1; i >= 0; i--) {
- l = this.value[i][0]
-
- if (l == 'M' || l == 'L' || l == 'T') {
- this.value[i][1] = ((this.value[i][1] - box.x) * width) / box.width + box.x
- this.value[i][2] = ((this.value[i][2] - box.y) * height) / box.height + box.y
-
- } else if (l == 'H') {
- this.value[i][1] = ((this.value[i][1] - box.x) * width) / box.width + box.x
-
- } else if (l == 'V') {
- this.value[i][1] = ((this.value[i][1] - box.y) * height) / box.height + box.y
-
- } else if (l == 'C' || l == 'S' || l == 'Q') {
- this.value[i][1] = ((this.value[i][1] - box.x) * width) / box.width + box.x
- this.value[i][2] = ((this.value[i][2] - box.y) * height) / box.height + box.y
- this.value[i][3] = ((this.value[i][3] - box.x) * width) / box.width + box.x
- this.value[i][4] = ((this.value[i][4] - box.y) * height) / box.height + box.y
-
- if (l == 'C') {
- this.value[i][5] = ((this.value[i][5] - box.x) * width) / box.width + box.x
- this.value[i][6] = ((this.value[i][6] - box.y) * height) / box.height + box.y
- }
-
- } else if (l == 'A') {
- // resize radii
- this.value[i][1] = (this.value[i][1] * width) / box.width
- this.value[i][2] = (this.value[i][2] * height) / box.height
-
- // move position values
- this.value[i][6] = ((this.value[i][6] - box.x) * width) / box.width + box.x
- this.value[i][7] = ((this.value[i][7] - box.y) * height) / box.height + box.y
- }
-
- }
-
- return this
- }
- // Test if the passed path array use the same path data commands as this path array
-, equalCommands: function(pathArray) {
- var i, il, equalCommands
-
- pathArray = new SVG.PathArray(pathArray)
-
- equalCommands = this.value.length === pathArray.value.length
- for(i = 0, il = this.value.length; equalCommands && i < il; i++) {
- equalCommands = this.value[i][0] === pathArray.value[i][0]
- }
-
- return equalCommands
- }
- // Make path array morphable
-, morph: function(pathArray) {
- pathArray = new SVG.PathArray(pathArray)
-
- if(this.equalCommands(pathArray)) {
- this.destination = pathArray
- } else {
- this.destination = null
- }
-
- return this
- }
- // Get morphed path array at given position
-, at: function(pos) {
- // make sure a destination is defined
- if (!this.destination) return this
-
- var sourceArray = this.value
- , destinationArray = this.destination.value
- , array = [], pathArray = new SVG.PathArray()
- , i, il, j, jl
-
- // Animate has specified in the SVG spec
- // See: https://www.w3.org/TR/SVG11/paths.html#PathElement
- for (i = 0, il = sourceArray.length; i < il; i++) {
- array[i] = [sourceArray[i][0]]
- for(j = 1, jl = sourceArray[i].length; j < jl; j++) {
- array[i][j] = sourceArray[i][j] + (destinationArray[i][j] - sourceArray[i][j]) * pos
- }
- // For the two flags of the elliptical arc command, the SVG spec say:
- // Flags and booleans are interpolated as fractions between zero and one, with any non-zero value considered to be a value of one/true
- // Elliptical arc command as an array followed by corresponding indexes:
- // ['A', rx, ry, x-axis-rotation, large-arc-flag, sweep-flag, x, y]
- // 0 1 2 3 4 5 6 7
- if(array[i][0] === 'A') {
- array[i][4] = +(array[i][4] != 0)
- array[i][5] = +(array[i][5] != 0)
- }
- }
-
- // Directly modify the value of a path array, this is done this way for performance
- pathArray.value = array
- return pathArray
- }
- // Absolutize and parse path to array
-, parse: function(array) {
- // if it's already a patharray, no need to parse it
- if (array instanceof SVG.PathArray) return array.valueOf()
-
- // prepare for parsing
- var i, x0, y0, s, seg, arr
- , x = 0
- , y = 0
- , paramCnt = { 'M':2, 'L':2, 'H':1, 'V':1, 'C':6, 'S':4, 'Q':4, 'T':2, 'A':7, 'Z':0 }
-
- if(typeof array == 'string'){
-
- array = array
- .replace(SVG.regex.numbersWithDots, pathRegReplace) // convert 45.123.123 to 45.123 .123
- .replace(SVG.regex.pathLetters, ' $& ') // put some room between letters and numbers
- .replace(SVG.regex.hyphen, '$1 -') // add space before hyphen
- .trim() // trim
- .split(SVG.regex.delimiter) // split into array
-
- }else{
- array = array.reduce(function(prev, curr){
- return [].concat.call(prev, curr)
- }, [])
- }
-
- // array now is an array containing all parts of a path e.g. ['M', '0', '0', 'L', '30', '30' ...]
- var arr = []
- , p = new SVG.Point()
- , p0 = new SVG.Point()
- , index = 0
- , len = array.length
-
- do{
- // Test if we have a path letter
- if(SVG.regex.isPathLetter.test(array[index])){
- s = array[index]
- ++index
- // If last letter was a move command and we got no new, it defaults to [L]ine
- }else if(s == 'M'){
- s = 'L'
- }else if(s == 'm'){
- s = 'l'
- }
-
- arr.push(pathHandlers[s].call(null,
- array.slice(index, (index = index + paramCnt[s.toUpperCase()])).map(parseFloat),
- p, p0
- )
- )
-
- }while(len > index)
-
- return arr
-
- }
- // Get bounding box of path
-, bbox: function() {
- SVG.parser.path.setAttribute('d', this.toString())
-
- return SVG.parser.path.getBBox()
- }
-
-})
-
-// Module for unit convertions
-SVG.Number = SVG.invent({
- // Initialize
- create: function(value, unit) {
- // initialize defaults
- this.value = 0
- this.unit = unit || ''
-
- // parse value
- if (typeof value === 'number') {
- // ensure a valid numeric value
- this.value = isNaN(value) ? 0 : !isFinite(value) ? (value < 0 ? -3.4e+38 : +3.4e+38) : value
-
- } else if (typeof value === 'string') {
- unit = value.match(SVG.regex.numberAndUnit)
-
- if (unit) {
- // make value numeric
- this.value = parseFloat(unit[1])
-
- // normalize
- if (unit[5] == '%')
- this.value /= 100
- else if (unit[5] == 's')
- this.value *= 1000
-
- // store unit
- this.unit = unit[5]
- }
-
- } else {
- if (value instanceof SVG.Number) {
- this.value = value.valueOf()
- this.unit = value.unit
- }
- }
-
- }
- // Add methods
-, extend: {
- // Stringalize
- toString: function() {
- return (
- this.unit == '%' ?
- ~~(this.value * 1e8) / 1e6:
- this.unit == 's' ?
- this.value / 1e3 :
- this.value
- ) + this.unit
- }
- , toJSON: function() {
- return this.toString()
- }
- , // Convert to primitive
- valueOf: function() {
- return this.value
- }
- // Add number
- , plus: function(number) {
- number = new SVG.Number(number)
- return new SVG.Number(this + number, this.unit || number.unit)
- }
- // Subtract number
- , minus: function(number) {
- number = new SVG.Number(number)
- return new SVG.Number(this - number, this.unit || number.unit)
- }
- // Multiply number
- , times: function(number) {
- number = new SVG.Number(number)
- return new SVG.Number(this * number, this.unit || number.unit)
- }
- // Divide number
- , divide: function(number) {
- number = new SVG.Number(number)
- return new SVG.Number(this / number, this.unit || number.unit)
- }
- // Convert to different unit
- , to: function(unit) {
- var number = new SVG.Number(this)
-
- if (typeof unit === 'string')
- number.unit = unit
-
- return number
- }
- // Make number morphable
- , morph: function(number) {
- this.destination = new SVG.Number(number)
-
- if(number.relative) {
- this.destination.value += this.value
- }
-
- return this
- }
- // Get morphed number at given position
- , at: function(pos) {
- // Make sure a destination is defined
- if (!this.destination) return this
-
- // Generate new morphed number
- return new SVG.Number(this.destination)
- .minus(this)
- .times(pos)
- .plus(this)
- }
-
- }
-})
-
-
-SVG.Element = SVG.invent({
- // Initialize node
- create: function(node) {
- // make stroke value accessible dynamically
- this._stroke = SVG.defaults.attrs.stroke
- this._event = null
-
- // initialize data object
- this.dom = {}
-
- // create circular reference
- if (this.node = node) {
- this.type = node.nodeName
- this.node.instance = this
-
- // store current attribute value
- this._stroke = node.getAttribute('stroke') || this._stroke
- }
- }
-
- // Add class methods
-, extend: {
- // Move over x-axis
- x: function(x) {
- return this.attr('x', x)
- }
- // Move over y-axis
- , y: function(y) {
- return this.attr('y', y)
- }
- // Move by center over x-axis
- , cx: function(x) {
- return x == null ? this.x() + this.width() / 2 : this.x(x - this.width() / 2)
- }
- // Move by center over y-axis
- , cy: function(y) {
- return y == null ? this.y() + this.height() / 2 : this.y(y - this.height() / 2)
- }
- // Move element to given x and y values
- , move: function(x, y) {
- return this.x(x).y(y)
- }
- // Move element by its center
- , center: function(x, y) {
- return this.cx(x).cy(y)
- }
- // Set width of element
- , width: function(width) {
- return this.attr('width', width)
- }
- // Set height of element
- , height: function(height) {
- return this.attr('height', height)
- }
- // Set element size to given width and height
- , size: function(width, height) {
- var p = proportionalSize(this, width, height)
-
- return this
- .width(new SVG.Number(p.width))
- .height(new SVG.Number(p.height))
- }
- // Clone element
- , clone: function(parent, withData) {
- // write dom data to the dom so the clone can pickup the data
- this.writeDataToDom()
-
- // clone element and assign new id
- var clone = assignNewId(this.node.cloneNode(true))
-
- // insert the clone in the given parent or after myself
- if(parent) parent.add(clone)
- else this.after(clone)
-
- return clone
- }
- // Remove element
- , remove: function() {
- if (this.parent())
- this.parent().removeElement(this)
-
- return this
- }
- // Replace element
- , replace: function(element) {
- this.after(element).remove()
-
- return element
- }
- // Add element to given container and return self
- , addTo: function(parent) {
- return parent.put(this)
- }
- // Add element to given container and return container
- , putIn: function(parent) {
- return parent.add(this)
- }
- // Get / set id
- , id: function(id) {
- return this.attr('id', id)
- }
- // Checks whether the given point inside the bounding box of the element
- , inside: function(x, y) {
- var box = this.bbox()
-
- return x > box.x
- && y > box.y
- && x < box.x + box.width
- && y < box.y + box.height
- }
- // Show element
- , show: function() {
- return this.style('display', '')
- }
- // Hide element
- , hide: function() {
- return this.style('display', 'none')
- }
- // Is element visible?
- , visible: function() {
- return this.style('display') != 'none'
- }
- // Return id on string conversion
- , toString: function() {
- return this.attr('id')
- }
- // Return array of classes on the node
- , classes: function() {
- var attr = this.attr('class')
-
- return attr == null ? [] : attr.trim().split(SVG.regex.delimiter)
- }
- // Return true if class exists on the node, false otherwise
- , hasClass: function(name) {
- return this.classes().indexOf(name) != -1
- }
- // Add class to the node
- , addClass: function(name) {
- if (!this.hasClass(name)) {
- var array = this.classes()
- array.push(name)
- this.attr('class', array.join(' '))
- }
-
- return this
- }
- // Remove class from the node
- , removeClass: function(name) {
- if (this.hasClass(name)) {
- this.attr('class', this.classes().filter(function(c) {
- return c != name
- }).join(' '))
- }
-
- return this
- }
- // Toggle the presence of a class on the node
- , toggleClass: function(name) {
- return this.hasClass(name) ? this.removeClass(name) : this.addClass(name)
- }
- // Get referenced element form attribute value
- , reference: function(attr) {
- return SVG.get(this.attr(attr))
- }
- // Returns the parent element instance
- , parent: function(type) {
- var parent = this
-
- // check for parent
- if(!parent.node.parentNode) return null
-
- // get parent element
- parent = SVG.adopt(parent.node.parentNode)
-
- if(!type) return parent
-
- // loop trough ancestors if type is given
- while(parent && parent.node instanceof window.SVGElement){
- if(typeof type === 'string' ? parent.matches(type) : parent instanceof type) return parent
- parent = SVG.adopt(parent.node.parentNode)
- }
- }
- // Get parent document
- , doc: function() {
- return this instanceof SVG.Doc ? this : this.parent(SVG.Doc)
- }
- // return array of all ancestors of given type up to the root svg
- , parents: function(type) {
- var parents = [], parent = this
-
- do{
- parent = parent.parent(type)
- if(!parent || !parent.node) break
-
- parents.push(parent)
- } while(parent.parent)
-
- return parents
- }
- // matches the element vs a css selector
- , matches: function(selector){
- return matches(this.node, selector)
- }
- // Returns the svg node to call native svg methods on it
- , native: function() {
- return this.node
- }
- // Import raw svg
- , svg: function(svg) {
- // create temporary holder
- var well = document.createElement('svg')
-
- // act as a setter if svg is given
- if (svg && this instanceof SVG.Parent) {
- // dump raw svg
- well.innerHTML = ''
-
- // transplant nodes
- for (var i = 0, il = well.firstChild.childNodes.length; i < il; i++)
- this.node.appendChild(well.firstChild.firstChild)
-
- // otherwise act as a getter
- } else {
- // create a wrapping svg element in case of partial content
- well.appendChild(svg = document.createElement('svg'))
-
- // write svgjs data to the dom
- this.writeDataToDom()
-
- // insert a copy of this node
- svg.appendChild(this.node.cloneNode(true))
-
- // return target element
- return well.innerHTML.replace(/^
diff --git a/files/plugin-HeatmapSessionRecording-5.2.4/vue/src/ManageHeatmap/Manage.vue b/files/plugin-HeatmapSessionRecording-5.3.1/vue/src/ManageHeatmap/Manage.vue
similarity index 100%
rename from files/plugin-HeatmapSessionRecording-5.2.4/vue/src/ManageHeatmap/Manage.vue
rename to files/plugin-HeatmapSessionRecording-5.3.1/vue/src/ManageHeatmap/Manage.vue
diff --git a/files/plugin-HeatmapSessionRecording-5.2.4/vue/src/ManageSessionRecording/Edit.vue b/files/plugin-HeatmapSessionRecording-5.3.1/vue/src/ManageSessionRecording/Edit.vue
similarity index 100%
rename from files/plugin-HeatmapSessionRecording-5.2.4/vue/src/ManageSessionRecording/Edit.vue
rename to files/plugin-HeatmapSessionRecording-5.3.1/vue/src/ManageSessionRecording/Edit.vue
diff --git a/files/plugin-HeatmapSessionRecording-5.2.4/vue/src/ManageSessionRecording/List.vue b/files/plugin-HeatmapSessionRecording-5.3.1/vue/src/ManageSessionRecording/List.vue
similarity index 100%
rename from files/plugin-HeatmapSessionRecording-5.2.4/vue/src/ManageSessionRecording/List.vue
rename to files/plugin-HeatmapSessionRecording-5.3.1/vue/src/ManageSessionRecording/List.vue
diff --git a/files/plugin-HeatmapSessionRecording-5.2.4/vue/src/ManageSessionRecording/Manage.vue b/files/plugin-HeatmapSessionRecording-5.3.1/vue/src/ManageSessionRecording/Manage.vue
similarity index 100%
rename from files/plugin-HeatmapSessionRecording-5.2.4/vue/src/ManageSessionRecording/Manage.vue
rename to files/plugin-HeatmapSessionRecording-5.3.1/vue/src/ManageSessionRecording/Manage.vue
diff --git a/files/plugin-HeatmapSessionRecording-5.2.4/vue/src/MatomoJsNotWritable/MatomoJsNotWritableAlert.vue b/files/plugin-HeatmapSessionRecording-5.3.1/vue/src/MatomoJsNotWritable/MatomoJsNotWritableAlert.vue
similarity index 100%
rename from files/plugin-HeatmapSessionRecording-5.2.4/vue/src/MatomoJsNotWritable/MatomoJsNotWritableAlert.vue
rename to files/plugin-HeatmapSessionRecording-5.3.1/vue/src/MatomoJsNotWritable/MatomoJsNotWritableAlert.vue
diff --git a/files/plugin-HeatmapSessionRecording-5.2.4/vue/src/SessionRecordingVis/SessionRecordingVis.less b/files/plugin-HeatmapSessionRecording-5.3.1/vue/src/SessionRecordingVis/SessionRecordingVis.less
similarity index 100%
rename from files/plugin-HeatmapSessionRecording-5.2.4/vue/src/SessionRecordingVis/SessionRecordingVis.less
rename to files/plugin-HeatmapSessionRecording-5.3.1/vue/src/SessionRecordingVis/SessionRecordingVis.less
diff --git a/files/plugin-HeatmapSessionRecording-5.2.4/vue/src/SessionRecordingVis/SessionRecordingVis.vue b/files/plugin-HeatmapSessionRecording-5.3.1/vue/src/SessionRecordingVis/SessionRecordingVis.vue
similarity index 100%
rename from files/plugin-HeatmapSessionRecording-5.2.4/vue/src/SessionRecordingVis/SessionRecordingVis.vue
rename to files/plugin-HeatmapSessionRecording-5.3.1/vue/src/SessionRecordingVis/SessionRecordingVis.vue
diff --git a/files/plugin-HeatmapSessionRecording-5.2.4/vue/src/Tooltip/Tooltip.less b/files/plugin-HeatmapSessionRecording-5.3.1/vue/src/Tooltip/Tooltip.less
similarity index 100%
rename from files/plugin-HeatmapSessionRecording-5.2.4/vue/src/Tooltip/Tooltip.less
rename to files/plugin-HeatmapSessionRecording-5.3.1/vue/src/Tooltip/Tooltip.less
diff --git a/files/plugin-HeatmapSessionRecording-5.2.4/vue/src/Tooltip/Tooltip.vue b/files/plugin-HeatmapSessionRecording-5.3.1/vue/src/Tooltip/Tooltip.vue
similarity index 100%
rename from files/plugin-HeatmapSessionRecording-5.2.4/vue/src/Tooltip/Tooltip.vue
rename to files/plugin-HeatmapSessionRecording-5.3.1/vue/src/Tooltip/Tooltip.vue
diff --git a/files/plugin-HeatmapSessionRecording-5.2.4/vue/src/getIframeWindow.ts b/files/plugin-HeatmapSessionRecording-5.3.1/vue/src/getIframeWindow.ts
similarity index 100%
rename from files/plugin-HeatmapSessionRecording-5.2.4/vue/src/getIframeWindow.ts
rename to files/plugin-HeatmapSessionRecording-5.3.1/vue/src/getIframeWindow.ts
diff --git a/files/plugin-HeatmapSessionRecording-5.2.4/vue/src/index.ts b/files/plugin-HeatmapSessionRecording-5.3.1/vue/src/index.ts
similarity index 100%
rename from files/plugin-HeatmapSessionRecording-5.2.4/vue/src/index.ts
rename to files/plugin-HeatmapSessionRecording-5.3.1/vue/src/index.ts
diff --git a/files/plugin-HeatmapSessionRecording-5.2.4/vue/src/oneAtATime.ts b/files/plugin-HeatmapSessionRecording-5.3.1/vue/src/oneAtATime.ts
similarity index 100%
rename from files/plugin-HeatmapSessionRecording-5.2.4/vue/src/oneAtATime.ts
rename to files/plugin-HeatmapSessionRecording-5.3.1/vue/src/oneAtATime.ts
diff --git a/files/plugin-HeatmapSessionRecording-5.2.4/vue/src/types.ts b/files/plugin-HeatmapSessionRecording-5.3.1/vue/src/types.ts
similarity index 100%
rename from files/plugin-HeatmapSessionRecording-5.2.4/vue/src/types.ts
rename to files/plugin-HeatmapSessionRecording-5.3.1/vue/src/types.ts
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/API.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/API.php
deleted file mode 100644
index 9c00f9b..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/API.php
+++ /dev/null
@@ -1,410 +0,0 @@
-SearchEngineKeywordsPerformance API lets you download all your SEO search keywords from Google,
- * Bing & Yahoo and Yandex, as well as getting a detailed overview of how search robots crawl your websites and any
- * error they may encounter.
- *
- * 1) download all your search keywords as they were searched on Google, Bing & Yahoo and Yandex. This includes Google
- * Images, Google Videos and Google News. This lets you view all keywords normally hidden from view behind "keyword not defined".
- * With this plugin you can view them all!
- *
- * 2) download all crawling overview stats and metrics from Bring and Yahoo and Google. Many metrics are available such
- * as: Crawled pages, Crawl errors, Connection timeouts, HTTP-Status Code 301 (Permanently moved), HTTP-Status Code
- * 400-499 (Request errors), All other HTTP-Status Codes, Total pages in index, Robots.txt exclusion, DNS failures,
- * HTTP-Status Code 200-299, HTTP-Status Code 301 (Temporarily moved), HTTP-Status Code 500-599 (Internal server
- * errors), Malware infected sites, Total inbound links.
- *
- * @package Piwik\Plugins\SearchEngineKeywordsPerformance
- */
-class API extends \Piwik\Plugin\API
-{
- /**
- * Returns Keyword data used on any search
- * Combines imported search keywords with those returned by Referrers plugin
- *
- * @param string|int|array $idSite A single ID (eg, `'1'`), multiple IDs (eg, `'1,2,3'` or `array(1, 2, 3)`),
- * or `'all'`.
- * @param string $period 'day', `'week'`, `'month'`, `'year'` or `'range'`
- * @param Date|string $date 'YYYY-MM-DD', magic keywords (ie, 'today'; {@link Date::factory()}
- * or date range (ie, 'YYYY-MM-DD,YYYY-MM-DD').
- * @return DataTable|DataTable\Map
- */
- public function getKeywords($idSite, $period, $date)
- {
- $keywordsDataTable = $this->getKeywordsImported($idSite, $period, $date);
- $keywordsDataTable->deleteColumns([\Piwik\Plugins\SearchEngineKeywordsPerformance\Metrics::POSITION, \Piwik\Plugins\SearchEngineKeywordsPerformance\Metrics::NB_IMPRESSIONS, \Piwik\Plugins\SearchEngineKeywordsPerformance\Metrics::CTR]);
- $keywordsDataTable->filter('ColumnCallbackDeleteRow', [\Piwik\Plugins\SearchEngineKeywordsPerformance\Metrics::NB_CLICKS, function ($clicks) {
- return $clicks === 0;
- }]);
- $keywordsDataTable->filter('ReplaceColumnNames', [[\Piwik\Plugins\SearchEngineKeywordsPerformance\Metrics::NB_CLICKS => 'nb_visits']]);
- $setting = new \Piwik\Plugins\SearchEngineKeywordsPerformance\MeasurableSettings($idSite);
- $googleEnabled = !empty($setting->googleSearchConsoleUrl) && $setting->googleSearchConsoleUrl->getValue();
- $bingEnabled = !empty($setting->bingSiteUrl) && $setting->bingSiteUrl->getValue();
- $referrersApi = new \Piwik\Plugins\Referrers\API();
- $referrersKeywords = $referrersApi->getSearchEngines($idSite, $period, $date, \false, \true);
- if ($keywordsDataTable instanceof DataTable\Map) {
- $referrerTables = $referrersKeywords->getDataTables();
- foreach ($keywordsDataTable->getDataTables() as $label => $table) {
- if (!empty($referrerTables[$label])) {
- $this->combineKeywordReports($table, $referrerTables[$label], $googleEnabled, $bingEnabled, $period);
- }
- }
- } else {
- $this->combineKeywordReports($keywordsDataTable, $referrersKeywords, $googleEnabled, $bingEnabled, $period);
- }
- return $keywordsDataTable;
- }
- private function combineKeywordReports(DataTable $keywordsDataTable, DataTable $referrersKeywords, $googleEnabled, $bingEnabled, $period)
- {
- foreach ($referrersKeywords->getRowsWithoutSummaryRow() as $searchEngineRow) {
- $label = $searchEngineRow->getColumn('label');
- if (strpos($label, 'Google') !== \false && $googleEnabled) {
- continue;
- }
- if (strpos($label, 'Bing') !== \false && $bingEnabled && $period !== 'day') {
- continue;
- }
- if (strpos($label, 'Yahoo') !== \false && $bingEnabled && $period !== 'day') {
- continue;
- }
- $keywordsTable = $searchEngineRow->getSubtable();
- if (empty($keywordsTable) || !$keywordsTable->getRowsCount()) {
- continue;
- }
- foreach ($keywordsTable->getRowsWithoutSummaryRow() as $keywordRow) {
- if ($keywordRow->getColumn('label') == \Piwik\Plugins\Referrers\API::LABEL_KEYWORD_NOT_DEFINED) {
- continue;
- }
- $keywordsDataTable->addRow(new DataTable\Row([DataTable\Row::COLUMNS => ['label' => $keywordRow->getColumn('label'), 'nb_visits' => $keywordRow->getColumn(\Piwik\Metrics::INDEX_NB_VISITS)]]));
- }
- }
- $keywordsDataTable->filter('GroupBy', ['label']);
- $keywordsDataTable->filter('ReplaceSummaryRowLabel');
- }
- /**
- * Returns Keyword data used on any imported search engine
- *
- * @param string|int|array $idSite A single ID (eg, `'1'`), multiple IDs (eg, `'1,2,3'` or `array(1, 2, 3)`),
- * or `'all'`.
- * @param string $period 'day', `'week'`, `'month'`, `'year'` or `'range'`
- * @param Date|string $date 'YYYY-MM-DD', magic keywords (ie, 'today'; {@link Date::factory()}
- * or date range (ie, 'YYYY-MM-DD,YYYY-MM-DD').
- * @return DataTable|DataTable\Map
- */
- public function getKeywordsImported($idSite, $period, $date)
- {
- $googleWebKwds = $this->getKeywordsGoogleWeb($idSite, $period, $date);
- $googleImgKwds = $this->getKeywordsGoogleImage($idSite, $period, $date);
- $googleVidKwds = $this->getKeywordsGoogleVideo($idSite, $period, $date);
- $googleNwsKwds = $this->getKeywordsGoogleNews($idSite, $period, $date);
- $bingKeywords = $this->getKeywordsBing($idSite, $period, $date);
- $yandexKeywords = $this->getKeywordsYandex($idSite, $period, $date);
- return $this->combineDataTables([$googleWebKwds, $googleImgKwds, $googleVidKwds, $googleNwsKwds, $bingKeywords, $yandexKeywords]);
- }
- /**
- * Returns Keyword data used on Google
- *
- * @param string|int|array $idSite A single ID (eg, `'1'`), multiple IDs (eg, `'1,2,3'` or `array(1, 2, 3)`),
- * or `'all'`.
- * @param string $period 'day', `'week'`, `'month'`, `'year'` or `'range'`
- * @param Date|string $date 'YYYY-MM-DD', magic keywords (ie, 'today'; {@link Date::factory()}
- * or date range (ie, 'YYYY-MM-DD,YYYY-MM-DD').
- * @return DataTable|DataTable\Map
- */
- public function getKeywordsGoogle($idSite, $period, $date)
- {
- $googleWebKwds = $this->getKeywordsGoogleWeb($idSite, $period, $date);
- $googleImgKwds = $this->getKeywordsGoogleImage($idSite, $period, $date);
- $googleVidKwds = $this->getKeywordsGoogleVideo($idSite, $period, $date);
- $googleNwsKwds = $this->getKeywordsGoogleNews($idSite, $period, $date);
- return $this->combineDataTables([$googleWebKwds, $googleImgKwds, $googleVidKwds, $googleNwsKwds]);
- }
- /**
- * Returns a DataTable with the given datatables combined
- *
- * @param DataTable[]|DataTable\Map[] $dataTablesToCombine
- *
- * @return DataTable|DataTable\Map
- */
- protected function combineDataTables(array $dataTablesToCombine)
- {
- if (reset($dataTablesToCombine) instanceof DataTable\Map) {
- $dataTable = new DataTable\Map();
- $dataTables = [];
- foreach ($dataTablesToCombine as $dataTableMap) {
- /** @var DataTable\Map $dataTableMap */
- $tables = $dataTableMap->getDataTables();
- foreach ($tables as $label => $table) {
- if (empty($dataTables[$label])) {
- $dataTables[$label] = new DataTable();
- $dataTables[$label]->setAllTableMetadata($table->getAllTableMetadata());
- $dataTables[$label]->setMetadata(DataTable::COLUMN_AGGREGATION_OPS_METADATA_NAME, \Piwik\Plugins\SearchEngineKeywordsPerformance\Metrics::getColumnsAggregationOperations());
- }
- $dataTables[$label]->addDataTable($table);
- }
- }
- foreach ($dataTables as $label => $table) {
- $dataTable->addTable($table, $label);
- }
- } else {
- $dataTable = new DataTable();
- $dataTable->setAllTableMetadata(reset($dataTablesToCombine)->getAllTableMetadata());
- $dataTable->setMetadata(DataTable::COLUMN_AGGREGATION_OPS_METADATA_NAME, \Piwik\Plugins\SearchEngineKeywordsPerformance\Metrics::getColumnsAggregationOperations());
- foreach ($dataTablesToCombine as $table) {
- $dataTable->addDataTable($table);
- }
- }
- return $dataTable;
- }
- /**
- * Returns Bing keyword data used on search
- *
- * @param string|int|array $idSite A single ID (eg, `'1'`), multiple IDs (eg, `'1,2,3'` or `array(1, 2, 3)`),
- * or `'all'`.
- * @param string $period 'day', `'week'`, `'month'`, `'year'` or `'range'`
- * @param Date|string $date 'YYYY-MM-DD', magic keywords (ie, 'today'; {@link Date::factory()}
- * or date range (ie, 'YYYY-MM-DD,YYYY-MM-DD').
- * @return DataTable|DataTable\Map
- */
- public function getKeywordsBing($idSite, $period, $date)
- {
- if (!Bing::getInstance()->isSupportedPeriod($date, $period)) {
- if (Period::isMultiplePeriod($date, $period)) {
- return new DataTable\Map();
- }
- return new DataTable();
- }
- if (!SearchEngineKeywordsPerformance::isReportEnabled('Bing')) {
- return SearchEngineKeywordsPerformance::commonEmptyDataTable($period, $date);
- }
- $dataTable = $this->getDataTable(BingRecordBuilder::KEYWORDS_BING_RECORD_NAME, $idSite, $period, $date);
- return $dataTable;
- }
- /**
- * Returns Yandex keyword data used on search
- *
- * @param string|int|array $idSite A single ID (eg, `'1'`), multiple IDs (eg, `'1,2,3'` or `array(1, 2, 3)`),
- * or `'all'`.
- * @param string $period 'day', `'week'`, `'month'`, `'year'` or `'range'`
- * @param Date|string $date 'YYYY-MM-DD', magic keywords (ie, 'today'; {@link Date::factory()}
- * or date range (ie, 'YYYY-MM-DD,YYYY-MM-DD').
- * @return DataTable|DataTable\Map
- */
- public function getKeywordsYandex($idSite, $period, $date)
- {
- if (!SearchEngineKeywordsPerformance::isReportEnabled('Yandex')) {
- return SearchEngineKeywordsPerformance::commonEmptyDataTable($period, $date);
- }
- $dataTable = $this->getDataTable(YandexRecordBuilders::KEYWORDS_YANDEX_RECORD_NAME, $idSite, $period, $date);
- return $dataTable;
- }
- /**
- * Returns Google keyword data used on Web search
- *
- * @param string|int|array $idSite A single ID (eg, `'1'`), multiple IDs (eg, `'1,2,3'` or `array(1, 2, 3)`),
- * or `'all'`.
- * @param string $period 'day', `'week'`, `'month'`, `'year'` or `'range'`
- * @param Date|string $date 'YYYY-MM-DD', magic keywords (ie, 'today'; {@link Date::factory()}
- * or date range (ie, 'YYYY-MM-DD,YYYY-MM-DD').
- * @return DataTable|DataTable\Map
- */
- public function getKeywordsGoogleWeb($idSite, $period, $date)
- {
- if (!SearchEngineKeywordsPerformance::isReportEnabled('Google', 'web')) {
- return SearchEngineKeywordsPerformance::commonEmptyDataTable($period, $date);
- }
- $dataTable = $this->getDataTable(GoogleRecordBuilder::KEYWORDS_GOOGLE_WEB_RECORD_NAME, $idSite, $period, $date);
- return $dataTable;
- }
- /**
- * Returns Google keyword data used on Image search
- *
- * @param string|int|array $idSite A single ID (eg, `'1'`), multiple IDs (eg, `'1,2,3'` or `array(1, 2, 3)`),
- * or `'all'`.
- * @param string $period 'day', `'week'`, `'month'`, `'year'` or `'range'`
- * @param Date|string $date 'YYYY-MM-DD', magic keywords (ie, 'today'; {@link Date::factory()}
- * or date range (ie, 'YYYY-MM-DD,YYYY-MM-DD').
- * @return DataTable|DataTable\Map
- */
- public function getKeywordsGoogleImage($idSite, $period, $date)
- {
- if (!SearchEngineKeywordsPerformance::isReportEnabled('Google', 'image')) {
- return SearchEngineKeywordsPerformance::commonEmptyDataTable($period, $date);
- }
- $dataTable = $this->getDataTable(GoogleRecordBuilder::KEYWORDS_GOOGLE_IMAGE_RECORD_NAME, $idSite, $period, $date);
- return $dataTable;
- }
- /**
- * Returns Google keyword data used on Video search
- *
- * @param string|int|array $idSite A single ID (eg, `'1'`), multiple IDs (eg, `'1,2,3'` or `array(1, 2, 3)`),
- * or `'all'`.
- * @param string $period 'day', `'week'`, `'month'`, `'year'` or `'range'`
- * @param Date|string $date 'YYYY-MM-DD', magic keywords (ie, 'today'; {@link Date::factory()}
- * or date range (ie, 'YYYY-MM-DD,YYYY-MM-DD').
- * @return DataTable|DataTable\Map
- */
- public function getKeywordsGoogleVideo($idSite, $period, $date)
- {
- if (!SearchEngineKeywordsPerformance::isReportEnabled('Google', 'video')) {
- return SearchEngineKeywordsPerformance::commonEmptyDataTable($period, $date);
- }
- $dataTable = $this->getDataTable(GoogleRecordBuilder::KEYWORDS_GOOGLE_VIDEO_RECORD_NAME, $idSite, $period, $date);
- return $dataTable;
- }
- /**
- * Returns Google keyword data used on News search
- *
- * @param string|int|array $idSite A single ID (eg, `'1'`), multiple IDs (eg, `'1,2,3'` or `array(1, 2, 3)`),
- * or `'all'`.
- * @param string $period 'day', `'week'`, `'month'`, `'year'` or `'range'`
- * @param Date|string $date 'YYYY-MM-DD', magic keywords (ie, 'today'; {@link Date::factory()}
- * or date range (ie, 'YYYY-MM-DD,YYYY-MM-DD').
- * @return DataTable|DataTable\Map
- */
- public function getKeywordsGoogleNews($idSite, $period, $date)
- {
- if (!SearchEngineKeywordsPerformance::isReportEnabled('Google', 'news')) {
- return SearchEngineKeywordsPerformance::commonEmptyDataTable($period, $date);
- }
- $dataTable = $this->getDataTable(GoogleRecordBuilder::KEYWORDS_GOOGLE_NEWS_RECORD_NAME, $idSite, $period, $date);
- return $dataTable;
- }
- /**
- * Returns crawling metrics for Bing
- *
- * @param string|int|array $idSite A single ID (eg, `'1'`), multiple IDs (eg, `'1,2,3'` or `array(1, 2, 3)`),
- * or `'all'`.
- * @param string $period 'day', `'week'`, `'month'`, `'year'` or `'range'`
- * @param Date|string $date 'YYYY-MM-DD', magic keywords (ie, 'today'; {@link Date::factory()}
- * or date range (ie, 'YYYY-MM-DD,YYYY-MM-DD').
- * @return DataTable|DataTable\Map
- */
- public function getCrawlingOverviewBing($idSite, $period, $date)
- {
- Piwik::checkUserHasViewAccess($idSite);
- $archive = Archive::build($idSite, $period, $date);
- $dataTable = $archive->getDataTableFromNumeric([
- BingRecordBuilder::CRAWLSTATS_CRAWLED_PAGES_RECORD_NAME,
- BingRecordBuilder::CRAWLSTATS_IN_INDEX_RECORD_NAME,
- BingRecordBuilder::CRAWLSTATS_IN_LINKS_RECORD_NAME,
- BingRecordBuilder::CRAWLSTATS_MALWARE_RECORD_NAME,
- BingRecordBuilder::CRAWLSTATS_BLOCKED_ROBOTS_RECORD_NAME,
- BingRecordBuilder::CRAWLSTATS_ERRORS_RECORD_NAME,
- BingRecordBuilder::CRAWLSTATS_DNS_FAILURE_RECORD_NAME,
- BingRecordBuilder::CRAWLSTATS_TIMEOUT_RECORD_NAME,
- BingRecordBuilder::CRAWLSTATS_CODE_2XX_RECORD_NAME,
- BingRecordBuilder::CRAWLSTATS_CODE_301_RECORD_NAME,
- BingRecordBuilder::CRAWLSTATS_CODE_302_RECORD_NAME,
- BingRecordBuilder::CRAWLSTATS_CODE_4XX_RECORD_NAME,
- BingRecordBuilder::CRAWLSTATS_CODE_5XX_RECORD_NAME,
- BingRecordBuilder::CRAWLSTATS_OTHER_CODES_RECORD_NAME
- ]);
- return $dataTable;
- }
- /**
- * Returns crawling metrics for Yandex
- *
- * @param string|int|array $idSite A single ID (eg, `'1'`), multiple IDs (eg, `'1,2,3'` or `array(1, 2, 3)`),
- * or `'all'`.
- * @param string $period 'day', `'week'`, `'month'`, `'year'` or `'range'`
- * @param Date|string $date 'YYYY-MM-DD', magic keywords (ie, 'today'; {@link Date::factory()}
- * or date range (ie, 'YYYY-MM-DD,YYYY-MM-DD').
- * @return DataTable|DataTable\Map
- */
- public function getCrawlingOverviewYandex($idSite, $period, $date)
- {
- Piwik::checkUserHasViewAccess($idSite);
- $archive = Archive::build($idSite, $period, $date);
- $dataTable = $archive->getDataTableFromNumeric([
- YandexRecordBuilders::CRAWLSTATS_CRAWLED_PAGES_RECORD_NAME,
- YandexRecordBuilders::CRAWLSTATS_APPEARED_PAGES_RECORD_NAME,
- YandexRecordBuilders::CRAWLSTATS_REMOVED_PAGES_RECORD_NAME,
- YandexRecordBuilders::CRAWLSTATS_IN_INDEX_RECORD_NAME,
- YandexRecordBuilders::CRAWLSTATS_CODE_2XX_RECORD_NAME,
- YandexRecordBuilders::CRAWLSTATS_CODE_3XX_RECORD_NAME,
- YandexRecordBuilders::CRAWLSTATS_CODE_4XX_RECORD_NAME,
- YandexRecordBuilders::CRAWLSTATS_CODE_5XX_RECORD_NAME,
- YandexRecordBuilders::CRAWLSTATS_ERRORS_RECORD_NAME
- ]);
- return $dataTable;
- }
- /**
- * Returns list of pages that had an error while crawling for Bing
- *
- * Note: This methods returns data imported lately. It does not support any historical reports
- *
- * @param $idSite
- *
- * @return DataTable
- */
- public function getCrawlingErrorExamplesBing($idSite)
- {
- Piwik::checkUserHasViewAccess($idSite);
- $dataTable = new DataTable();
- $settings = new \Piwik\Plugins\SearchEngineKeywordsPerformance\MeasurableSettings($idSite);
- $bingSiteSetting = $settings->bingSiteUrl;
- if (empty($bingSiteSetting) || empty($bingSiteSetting->getValue())) {
- return $dataTable;
- }
- list($apiKey, $bingSiteUrl) = explode('##', $bingSiteSetting->getValue());
- $model = new \Piwik\Plugins\SearchEngineKeywordsPerformance\Model\Bing();
- $data = $model->getCrawlErrors($bingSiteUrl);
- if (empty($data)) {
- return $dataTable;
- }
- $dataTable->addRowsFromSerializedArray($data);
- $dataTable->filter('ColumnCallbackAddMetadata', array('label', 'url'));
- $dataTable->filter('ColumnCallbackReplace', array('label', function ($val) use ($bingSiteUrl) {
- return preg_replace('|https?://[^/]*/|i', '', $val);
- }));
- return $dataTable;
- }
- /**
- * Returns datatable for the requested archive
- *
- * @param string $name name of the archive to use
- * @param string|int|array $idSite A single ID (eg, `'1'`), multiple IDs (eg, `'1,2,3'` or `array(1, 2, 3)`),
- * or `'all'`.
- * @param string $period 'day', `'week'`, `'month'`, `'year'` or `'range'`
- * @param Date|string $date 'YYYY-MM-DD', magic keywords (ie, 'today'; {@link Date::factory()}
- * or date range (ie, 'YYYY-MM-DD,YYYY-MM-DD').
- * @return DataTable|DataTable\Map
- */
- private function getDataTable($name, $idSite, $period, $date)
- {
- Piwik::checkUserHasViewAccess($idSite);
- $archive = Archive::build($idSite, $period, $date, $segment = \false);
- $dataTable = $archive->getDataTable($name);
- $dataTable->queueFilter('ReplaceSummaryRowLabel');
- return $dataTable;
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Activity/AccountAdded.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Activity/AccountAdded.php
deleted file mode 100644
index 245770b..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Activity/AccountAdded.php
+++ /dev/null
@@ -1,46 +0,0 @@
- All channels > Channel type*
- * *Acquisition > All channels > Referrers*
- * *Acquisition > Search Engines*
-* Show related reports for reports showing imported keywords to show originally tracked keywords instead
-* Translations for German and Albanian
-
-__3.3.2__
-* Fix sorting for keyword tables
-* Improved compatibility with Roll-Up Reporting plugin
-* Translation updates
-
-__3.3.1__
-* Ensure at least one keyword type is configured for Google imports
-* Deprecated Property Set and Android App imports
-* Improve sorting of keyword reports by adding a secondary sort column
-* Added proper handling for new Domain properties on Google Search Console
-
-__3.3.0__
-* Fixed bug with incorrect numbers for reports including day stats for Bing
-* Improved validation of uploaded Google client configs
-* Updated dependencies
-* Deprecated Google Crawl Errors reports (due to Google API deprecation).
- Old reports will still be available, but no new data can be imported after end of March '19.
- New installs won't show those reports at all.
-* Translation updates
-
-__3.2.7__
-* Fixed notice occurring if search import is force enabled
-
-__3.2.6__
-* Allow force enabling crawling error reports.
-* Improve handling of Google import (avoid importing property set data since it does not exist)
-
-__3.2.5__
-* Security improvements
-* Theme updates
-
-__3.2.4__
-* Improve handling of Bing Crawl Errors (fixes a notice while import)
-* Improve Google import handling of empty results
-* Security improvements
-* UI improvements
-* Translations for Polish
-
-__3.2.3__
-* Various code improvements
-* Translations for Chinese (Taiwan) and Italian
-
-__3.2.0__
-* Changes the _Combined Keywords_ report to also include keywords reported by Referrers.getKeywords
-* Adds new reports _Combined imported keywords_ (which is what the combined keywords was before)
-* Replaces Referrers.getKeywords reports in order to change name and show it as related report
-* Move all reports to the Search Engines & Keywords category (showing Search Engines last)
-
-__3.1.0__
-* New crawl errors reports und Pages > crawl errors showing pages having crawl issues on Google and Bing/Yahoo!
-
-__3.0.10__
-* Improved error handling
-* Row evolution for combined keywords reports
-* Fixed error when generating scheduled reports with evolution charts
-
-__3.0.9__
-* Renamed Piwik to Matomo
-
-__3.0.8__
-* Possibility to show keyword position as float instead of integer
-
-__3.0.7__
-* Added commands to trigger import using console command
-* Various UI/UX improvements
-
-__3.0.6__
-* Now uses Piwik proxy config if defined
-
-__3.0__
-* Possibility to import keyords & crawl stats from Google Search Console
-* Setting per website if web, image and/or video keywords should be imported
-* Possibility to import keywords & crawl stats from Bing/Yahoo! Webmaster API
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Categories/CrawlingOverviewSubcategory.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Categories/CrawlingOverviewSubcategory.php
deleted file mode 100644
index df098d4..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Categories/CrawlingOverviewSubcategory.php
+++ /dev/null
@@ -1,31 +0,0 @@
-' . Piwik::translate('SearchEngineKeywordsPerformance_CrawlingOverview1') . '
';
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Categories/SearchKeywordsSubcategory.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Categories/SearchKeywordsSubcategory.php
deleted file mode 100644
index a60d2ec..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Categories/SearchKeywordsSubcategory.php
+++ /dev/null
@@ -1,26 +0,0 @@
-configuration = $configuration;
- }
- /**
- * Returns configured client api keys
- *
- * @return array
- */
- public function getAccounts()
- {
- return $this->configuration->getAccounts();
- }
- /**
- * Removes client api key
- *
- * @param string $apiKey
- * @return boolean
- */
- public function removeAccount($apiKey)
- {
- $this->configuration->removeAccount($apiKey);
- Piwik::postEvent(
- 'SearchEngineKeywordsPerformance.AccountRemoved',
- [['provider' => \Piwik\Plugins\SearchEngineKeywordsPerformance\Provider\Bing::getInstance()->getName(), 'account' => substr($apiKey, 0, 5) . '*****' . substr($apiKey, -5, 5)]]
- );
- return \true;
- }
- /**
- * Adds a client api key
- *
- * @param $apiKey
- * @param $username
- * @return boolean
- */
- public function addAccount($apiKey, $username)
- {
- $this->configuration->addAccount($apiKey, $username);
- Piwik::postEvent('SearchEngineKeywordsPerformance.AccountAdded', [['provider' => \Piwik\Plugins\SearchEngineKeywordsPerformance\Provider\Bing::getInstance()->getName(), 'account' => substr($apiKey, 0, 5) . '*****' . substr($apiKey, -5, 5)]]);
- return \true;
- }
- /**
- * Returns if client is configured
- *
- * @return bool
- */
- public function isConfigured()
- {
- return count($this->getAccounts()) > 0;
- }
- /**
- * Checks if API key can be used to query the API
- *
- * @param $apiKey
- * @return bool
- * @throws \Exception
- */
- public function testConfiguration($apiKey)
- {
- $data = $this->sendAPIRequest($apiKey, 'GetUserSites');
- if (empty($data)) {
- throw new \Exception('Unknown error');
- }
- return \true;
- }
- /**
- * Returns the urls, keyword data is available for (in connected google account)
- *
- * @param $apiKey
- *
- * @return array
- */
- public function getAvailableUrls($apiKey, $removeUrlsWithoutAccess = \true)
- {
- try {
- $data = $this->sendAPIRequest($apiKey, 'GetUserSites');
- } catch (\Exception $e) {
- return [];
- }
- if (empty($data) || !is_array($data['d'])) {
- return [];
- }
- $urls = [];
- foreach ($data['d'] as $item) {
- if (!$removeUrlsWithoutAccess || $item['IsVerified']) {
- $urls[$item['Url']] = $item['IsVerified'];
- }
- }
- return $urls;
- }
- /**
- * Returns search anyalytics data from Bing API
- *
- * @param string $apiKey
- * @param string $url
- * @return array
- */
- public function getSearchAnalyticsData($apiKey, $url)
- {
- $keywordDataSets = $this->sendAPIRequest($apiKey, 'GetQueryStats', ['siteUrl' => $url]);
- $keywords = [];
- if (empty($keywordDataSets['d']) || !is_array($keywordDataSets['d'])) {
- return [];
- }
- foreach ($keywordDataSets['d'] as $keywordDataSet) {
- $timestamp = substr($keywordDataSet['Date'], 6, 10);
- $date = date('Y-m-d', $timestamp);
- if (!isset($keywords[$date])) {
- $keywords[$date] = [];
- }
- $keywords[$date][] = ['keyword' => $keywordDataSet['Query'], 'clicks' => $keywordDataSet['Clicks'], 'impressions' => $keywordDataSet['Impressions'], 'position' => $keywordDataSet['AvgImpressionPosition']];
- }
- return $keywords;
- }
- /**
- * Returns crawl statistics from Bing API
- *
- * @param string $apiKey
- * @param string $url
- * @return array
- */
- public function getCrawlStats($apiKey, $url)
- {
- $crawlStatsDataSets = $this->sendAPIRequest($apiKey, 'GetCrawlStats', ['siteUrl' => $url]);
- $crawlStats = [];
- if (empty($crawlStatsDataSets) || !is_array($crawlStatsDataSets['d'])) {
- return [];
- }
- foreach ($crawlStatsDataSets['d'] as $crawlStatsDataSet) {
- $timestamp = substr($crawlStatsDataSet['Date'], 6, 10);
- $date = date('Y-m-d', $timestamp);
- unset($crawlStatsDataSet['Date']);
- $crawlStats[$date] = $crawlStatsDataSet;
- }
- return $crawlStats;
- }
- /**
- * Returns urls with crawl issues from Bing API
- *
- * @param string $apiKey
- * @param string $url
- * @return array
- */
- public function getUrlWithCrawlIssues($apiKey, $url)
- {
- $crawlErrorsDataSets = $this->sendAPIRequest($apiKey, 'GetCrawlIssues', ['siteUrl' => $url]);
- $crawlErrors = [];
- if (empty($crawlErrorsDataSets) || !is_array($crawlErrorsDataSets['d'])) {
- return [];
- }
- $crawlIssueMapping = [1 => 'Code301', 2 => 'Code302', 4 => 'Code4xx', 8 => 'Code5xx', 16 => 'BlockedByRobotsTxt', 32 => 'ContainsMalware', 64 => 'ImportantUrlBlockedByRobotsTxt'];
- foreach ($crawlErrorsDataSets['d'] as $crawlStatsDataSet) {
- $issues = $crawlStatsDataSet['Issues'];
- $messages = [];
- foreach ($crawlIssueMapping as $code => $message) {
- if ($issues & $code) {
- $messages[] = $message;
- }
- }
- $crawlStatsDataSet['Issues'] = implode(',', $messages);
- $crawlErrors[] = $crawlStatsDataSet;
- }
- return $crawlErrors;
- }
- /**
- * Executes a API-Request to Bing with the given parameters
- *
- * @param string $apiKey
- * @param string $method
- * @param array $params
- * @return mixed
- * @throws InvalidCredentialsException
- * @throws \Exception
- */
- protected function sendAPIRequest($apiKey, $method, $params = [])
- {
- $params['apikey'] = $apiKey;
- $this->throwIfThrottled($apiKey);
- $url = $this->baseAPIUrl . $method . '?' . Http::buildQuery($params);
- $retries = 0;
- while ($retries < 5) {
- try {
- $additionalHeaders = ['X-Forwarded-For: ' . (!empty($_SERVER['HTTP_X_FORWARDED_FOR']) ? $_SERVER['HTTP_X_FORWARDED_FOR'] . ',' : '') . IP::getIpFromHeader()];
- $response = Http::sendHttpRequestBy(Http::getTransportMethod(), $url, 2000, null, null, null, 0, false, false, false, false, 'GET', null, null, null, $additionalHeaders);
- $response = json_decode($response, \true);
- } catch (\Exception $e) {
- if ($retries < 4) {
- $retries++;
- usleep($retries * 500);
- continue;
- }
- throw $e;
- }
- if (!empty($response['ErrorCode'])) {
- $isThrottledHost = strpos($response['Message'], 'ThrottleHost') !== \false || $response['ErrorCode'] == self::API_ERROR_THROTTLE_HOST;
- $isThrottledUser = strpos($response['Message'], 'ThrottleUser') !== \false || $response['ErrorCode'] == self::API_ERROR_THROTTLE_USER;
- $isThrottledIp = strpos($response['Message'], 'ThrottleIP') !== false;
- $isThrottled = $isThrottledHost || $isThrottledUser || $isThrottledIp;
- $isUnknownError = $response['ErrorCode'] === self::API_ERROR_UNKNOWN;
- // we retry each request up to 5 times, if the error is unknown or the connection was throttled
- if (($isThrottled || $isUnknownError) && $retries < 4) {
- $retries++;
- usleep($retries * 500);
- continue;
- }
- // if connection is still throttled after retrying, we block additional requests for some time
- if ($isThrottled) {
- Option::set($this->getThrottleOptionKey($apiKey), Date::getNowTimestamp());
- $this->throwIfThrottled($apiKey, $response['ErrorCode']);
- }
- if ($isUnknownError) {
- throw new UnknownAPIException($response['Message'], $response['ErrorCode']);
- }
- $authenticationError = strpos($response['Message'], 'NotAuthorized') !== \false
- || strpos($response['Message'], 'InvalidApiKey') !== \false
- || in_array($response['ErrorCode'], [self::API_ERROR_NOT_AUTHORIZED, self::API_ERROR_INVALID_API_KEY]);
- if ($authenticationError) {
- throw new InvalidCredentialsException($response['Message'], $response['ErrorCode']);
- }
- throw new \Exception($response['Message'], $response['ErrorCode']);
- }
- return $response;
- }
- return null;
- }
- protected function getThrottleOptionKey($apiKey)
- {
- return sprintf(self::OPTION_NAME_THROTTLE_TIME, md5($apiKey));
- }
- public function throwIfThrottled($apiKey, $errorCode = null)
- {
- $throttleTime = Option::get($this->getThrottleOptionKey($apiKey));
- if (empty($throttleTime)) {
- return;
- }
- try {
- $throttleDate = Date::factory((int) $throttleTime);
- } catch (\Exception $e) {
- return;
- }
- if (Date::now()->subHour(self::THROTTLE_BREAK_HOURS)->isEarlier($throttleDate)) {
- $errorCode = !empty($errorCode) ? $errorCode : self::API_ERROR_THROTTLE_USER;
- throw new RateLimitApiException('API requests temporarily throttled till ' . $throttleDate->addHour(self::THROTTLE_BREAK_HOURS)->getDatetime(), $errorCode);
- }
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Client/Configuration/BaseConfiguration.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Client/Configuration/BaseConfiguration.php
deleted file mode 100644
index af01cc9..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Client/Configuration/BaseConfiguration.php
+++ /dev/null
@@ -1,49 +0,0 @@
-accounts)) {
- $accounts = Option::get(self::CLIENT_CONFIG_OPTION_NAME);
- $accounts = @json_decode($accounts, \true);
- if (is_array($accounts)) {
- $this->accounts = $accounts;
- }
- }
- return $this->accounts;
- }
- /**
- * Adds new account
- *
- * @param $apiKey
- * @param $username
- */
- public function addAccount($apiKey, $username)
- {
- $currentAccounts = (array) $this->getAccounts();
- if (array_key_exists($apiKey, $currentAccounts)) {
- return;
- }
- $currentAccounts[$apiKey] = ['apiKey' => $apiKey, 'username' => $username, 'created' => time()];
- $this->setAccounts($currentAccounts);
- }
- /**
- * Removes account with given API-Key
- *
- * @param $apiKey
- */
- public function removeAccount($apiKey)
- {
- $currentAccounts = (array) $this->getAccounts();
- $this->checkPermissionToRemoveAccount($apiKey, $currentAccounts);
- unset($currentAccounts[$apiKey]);
- $this->setAccounts($currentAccounts);
- }
- protected function setAccounts($newAccounts)
- {
- $accounts = json_encode($newAccounts);
- Option::set(self::CLIENT_CONFIG_OPTION_NAME, $accounts);
- $this->accounts = [];
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Client/Configuration/Google.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Client/Configuration/Google.php
deleted file mode 100644
index f98383e..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Client/Configuration/Google.php
+++ /dev/null
@@ -1,178 +0,0 @@
-accounts)) {
- $accounts = Option::get(self::OAUTH_CONFIG_OPTION_NAME);
- $accounts = @json_decode($accounts, \true);
- if (is_array($accounts) && !empty($accounts)) {
- $this->accounts = $accounts;
- }
- }
- return $this->accounts;
- }
- /**
- * adds new account data
- *
- * @param string $id
- * @param array $accountData
- * @param string $username
- */
- public function addAccount($id, $accountData, $username)
- {
- $currentAccounts = (array) $this->getAccounts();
- $id = (string) $id;
- if (array_key_exists($id, $currentAccounts)) {
- return;
- }
- $currentAccounts[$id] = ['config' => $accountData, 'username' => $username, 'created' => time()];
- $this->setAccounts($currentAccounts);
- }
- /**
- * removes account data
- *
- * @param string $id
- */
- public function removeAccount($id)
- {
- $currentAccounts = (array) $this->getAccounts();
- $id = (string) $id;
- $this->checkPermissionToRemoveAccount($id, $currentAccounts);
- unset($currentAccounts[$id]);
- $this->setAccounts($currentAccounts);
- }
- protected function setAccounts($newAccounts)
- {
- $accounts = json_encode($newAccounts);
- Option::set(self::OAUTH_CONFIG_OPTION_NAME, $accounts);
- $this->accounts = $newAccounts;
- }
- /**
- * Returns the access token for the given account id
- *
- * @param string $accountId
- * @return mixed|null
- */
- public function getAccessToken($accountId)
- {
- $accounts = $this->getAccounts();
- if (array_key_exists($accountId, $accounts)) {
- return $accounts[$accountId]['config']['accessToken'];
- }
- return null;
- }
- /**
- * Returns the user info for the given account id
- *
- * @param string $accountId
- * @return mixed|null
- */
- public function getUserInfo($accountId)
- {
- $accounts = $this->getAccounts();
- if (array_key_exists($accountId, $accounts)) {
- return $accounts[$accountId]['config']['userInfo'];
- }
- return null;
- }
- /**
- * Returns stored client config
- *
- * @return mixed|null
- */
- public function getClientConfig()
- {
- if (empty($this->clientConfig)) {
- $config = Common::unsanitizeInputValue(Option::get(self::CLIENT_CONFIG_OPTION_NAME));
- if (!empty($config) && ($config = @json_decode($config, \true))) {
- $this->clientConfig = $config;
- }
- }
- return $this->clientConfig;
- }
- /**
- * Sets client config to be used for querying google api
- *
- * NOTE: Check for valid config should be done before
- *
- * @param string $config json encoded client config
- */
- public function setClientConfig($config)
- {
- Option::set(self::CLIENT_CONFIG_OPTION_NAME, $config);
- }
- /**
- * Delete the Google client config option so that the customer will be prompted to upload a new one or use the Cloud
- * config.
- *
- * @return void
- */
- public function deleteClientConfig(): void
- {
- Option::delete(self::CLIENT_CONFIG_OPTION_NAME);
- }
- /**
- * Returns path to client config file that is used for automatic import
- *
- * @return string
- */
- protected function getConfigurationFilename()
- {
- return dirname(dirname(dirname(__FILE__))) . \DIRECTORY_SEPARATOR . 'client_secrets.json';
- }
- /**
- * Imports client config from shipped config file if available
- *
- * @return bool
- */
- public function importShippedClientConfigIfAvailable()
- {
- $configFile = $this->getConfigurationFilename();
- if (!file_exists($configFile)) {
- return \false;
- }
- $config = file_get_contents($configFile);
- if ($decoded = @json_decode($config, \true)) {
- $this->setClientConfig($config);
- return \true;
- }
- return \false;
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Client/Configuration/Yandex.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Client/Configuration/Yandex.php
deleted file mode 100644
index c5881ef..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Client/Configuration/Yandex.php
+++ /dev/null
@@ -1,130 +0,0 @@
-accounts)) {
- $accounts = Option::get(self::OAUTH_CONFIG_OPTION_NAME);
- $accounts = @json_decode($accounts, \true);
- if (is_array($accounts) && !empty($accounts)) {
- $this->accounts = $accounts;
- }
- }
- return $this->accounts;
- }
- /**
- * adds new account data
- *
- * @param string $id
- * @param array $accountData
- * @param string $username
- */
- public function addAccount($id, $accountData, $username)
- {
- $currentAccounts = (array) $this->getAccounts();
- $currentAccounts[$id] = ['config' => $accountData, 'username' => $username, 'created' => time()];
- $this->setAccounts($currentAccounts);
- }
- /**
- * removes account data
- *
- * @param string $id
- */
- public function removeAccount($id)
- {
- $currentAccounts = (array) $this->getAccounts();
- $this->checkPermissionToRemoveAccount($id, $currentAccounts);
- unset($currentAccounts[$id]);
- $this->setAccounts($currentAccounts);
- }
- protected function setAccounts($newAccounts)
- {
- $accounts = json_encode($newAccounts);
- Option::set(self::OAUTH_CONFIG_OPTION_NAME, $accounts);
- $this->accounts = [];
- }
- /**
- * Returns the access token for the given account id
- *
- * @param string $accountId
- * @return mixed|null
- */
- public function getAccessToken($accountId)
- {
- $accounts = $this->getAccounts();
- if (array_key_exists($accountId, $accounts)) {
- return $accounts[$accountId]['config']['accessToken'];
- }
- return null;
- }
- /**
- * Returns the user info for the given account id
- *
- * @param string $accountId
- * @return mixed|null
- */
- public function getUserInfo($accountId)
- {
- $accounts = $this->getAccounts();
- if (array_key_exists($accountId, $accounts)) {
- return $accounts[$accountId]['config']['userInfo'];
- }
- return null;
- }
- /**
- * Returns stored client config
- *
- * @return mixed|null
- */
- public function getClientConfig()
- {
- if (empty($this->clientConfig)) {
- $config = Common::unsanitizeInputValue(Option::get(self::CLIENT_CONFIG_OPTION_NAME));
- if (!empty($config) && ($config = @json_decode($config, \true))) {
- $this->clientConfig = $config;
- }
- }
- return $this->clientConfig;
- }
- /**
- * Sets client config to be used for querying yandex api
- *
- * NOTE: Check for valid config should be done before
- *
- * @param string $config json encoded client config
- */
- public function setClientConfig($clientId, $clientSecret)
- {
- $config = ['id' => $clientId, 'secret' => $clientSecret, 'date' => time()];
- Option::set(self::CLIENT_CONFIG_OPTION_NAME, json_encode($config));
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Client/Google.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Client/Google.php
deleted file mode 100644
index c285ceb..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Client/Google.php
+++ /dev/null
@@ -1,489 +0,0 @@
-configuration = $configuration;
- }
- /**
- * @return \Google\Client
- */
- protected function getGoogleClient()
- {
- $googleClient = StaticContainer::get('SearchEngineKeywordsPerformance.Google.googleClient');
- $proxyHost = Config::getInstance()->proxy['host'];
- if ($proxyHost) {
- $proxyPort = Config::getInstance()->proxy['port'];
- $proxyUser = Config::getInstance()->proxy['username'];
- $proxyPassword = Config::getInstance()->proxy['password'];
- if ($proxyUser) {
- $proxy = sprintf('http://%s:%s@%s:%s', $proxyUser, $proxyPassword, $proxyHost, $proxyPort);
- } else {
- $proxy = sprintf('http://%s:%s', $proxyHost, $proxyPort);
- }
- $httpClient = new \Matomo\Dependencies\SearchEngineKeywordsPerformance\GuzzleHttp\Client(['proxy' => $proxy, 'exceptions' => \false, 'base_uri' => \Matomo\Dependencies\SearchEngineKeywordsPerformance\Google\Client::API_BASE_PATH]);
- $googleClient->setHttpClient($httpClient);
- }
- return $googleClient;
- }
- /**
- * Passes through a direct call to the \Google\Client class
- *
- * @param string $method
- * @param array $params
- * @return mixed
- * @throws MissingClientConfigException
- * @throws MissingOAuthConfigException
- */
- public function __call($method, $params = [])
- {
- return call_user_func_array([$this->getConfiguredClient('', \true), $method], $params);
- }
- /**
- * Process the given auth code to gain access and refresh token from google api
- *
- * @param string $authCode
- * @throws MissingClientConfigException
- */
- public function processAuthCode($authCode)
- {
- try {
- $client = $this->getConfiguredClient('');
- } catch (MissingOAuthConfigException $e) {
- // ignore missing oauth config
- }
- $accessToken = $client->fetchAccessTokenWithAuthCode($authCode);
- $userInfo = $this->getUserInfoByAccessToken($accessToken);
- $id = $userInfo->getId();
- $this->addAccount($id, $accessToken, Piwik::getCurrentUserLogin());
- Piwik::postEvent('SearchEngineKeywordsPerformance.AccountAdded', [['provider' => \Piwik\Plugins\SearchEngineKeywordsPerformance\Provider\Google::getInstance()->getName(), 'account' => $userInfo->getName()]]);
- }
- /**
- * Sets the client configuration
- *
- * @param $config
- * @return boolean
- */
- public function setClientConfig($config)
- {
- try {
- $client = $this->getGoogleClient();
- $configArray = @json_decode($config, \true);
- $this->configureClient($client, $configArray);
- } catch (\Exception $e) {
- return \false;
- }
- $this->configuration->setClientConfig($config);
- Piwik::postEvent('SearchEngineKeywordsPerformance.GoogleClientConfigChanged');
- return \true;
- }
- /**
- * Delete the Google client config option so that the customer will be prompted to upload a new one or use the Cloud
- * config.
- *
- * @return void
- */
- public function deleteClientConfig(): void
- {
- $this->configuration->deleteClientConfig();
- Piwik::postEvent('SearchEngineKeywordsPerformance.GoogleClientConfigChanged');
- }
- /**
- * @param \Google\Client $client
- * @param array $config
- *
- * @throws MissingClientConfigException
- */
- protected function configureClient($client, $config)
- {
- try {
- @$client->setAuthConfig($config);
- } catch (\Exception $e) {
- throw new MissingClientConfigException();
- }
- // no client config available
- if (!$client->getClientId() || !$client->getClientSecret()) {
- throw new MissingClientConfigException();
- }
- }
- /**
- * Returns configured client api keys
- *
- * @return array
- */
- public function getAccounts()
- {
- return $this->configuration->getAccounts();
- }
- /**
- * Removes client api key
- *
- * @param $id
- * @return bool
- */
- public function removeAccount($id)
- {
- $userInfo = $this->getUserInfo($id);
- $this->configuration->removeAccount($id);
- Piwik::postEvent('SearchEngineKeywordsPerformance.AccountRemoved', [['provider' => \Piwik\Plugins\SearchEngineKeywordsPerformance\Provider\Google::getInstance()->getName(), 'account' => $userInfo['name']]]);
- return \true;
- }
- /**
- * Adds a client api key
- *
- * @param $id
- * @param $config
- * @param $username
- * @return boolean
- */
- public function addAccount($id, $accessToken, $username)
- {
- $userInfo = $this->getUserInfoByAccessToken($accessToken);
- $config = ['userInfo' => ['picture' => $userInfo->picture, 'name' => $userInfo->name], 'accessToken' => $accessToken];
- $this->configuration->addAccount($id, $config, $username);
- return \true;
- }
- /**
- * Returns if client is configured
- *
- * @return bool
- */
- public function isConfigured()
- {
- return $this->configuration->getClientConfig() && count($this->configuration->getAccounts()) > 0;
- }
- /**
- * Returns configured \Google\Client object
- *
- * @param string $accessToken
- * @param bool $ignoreMissingConfigs
- * @return \Google\Client
- * @throws MissingClientConfigException
- * @throws MissingOAuthConfigException
- */
- public function getConfiguredClient($accessToken, $ignoreMissingConfigs = \false)
- {
- $client = $this->getGoogleClient();
- try {
- $this->configure($client, $accessToken);
- } catch (\Exception $e) {
- if (!$ignoreMissingConfigs) {
- throw $e;
- }
- }
- return $client;
- }
- /**
- * Returns the Auth Url (including the given state param)
- *
- * @param $state
- * @return string
- * @throws MissingClientConfigException
- * @throws MissingOAuthConfigException
- */
- public function createAuthUrl($state)
- {
- $client = $this->getConfiguredClient('', \true);
- $client->setState($state);
- $client->setPrompt('consent');
- return $client->createAuthUrl();
- }
- /**
- * Loads configuration and sets common configuration for \Google\Client
- *
- * @param \Google\Client $client
- * @param string $accessToken
- * @throws MissingOAuthConfigException
- * @throws MissingClientConfigException
- */
- protected function configure($client, $accessToken)
- {
- // import shipped client config if available
- if (!$this->configuration->getClientConfig()) {
- $this->configuration->importShippedClientConfigIfAvailable();
- }
- $clientConfig = $this->configuration->getClientConfig();
- $this->configureClient($client, $clientConfig);
- // Copied this bit about the redirect_uris from the GA Importer Authorization class
- //since there ie no host defined when running via console it results in error, but we don't need to set any URI when running console commands so can be ignored
- $expectedUri = Url::getCurrentUrlWithoutQueryString() . '?module=SearchEngineKeywordsPerformance&action=processAuthCode';
- if (
- !empty($clientConfig['web']['redirect_uris']) &&
- !Common::isRunningConsoleCommand() &&
- !PluginsArchiver::isArchivingProcessActive() &&
- !$this->isMiscCron() &&
- stripos($expectedUri, 'unknown/_/console?') === false // To handle case where we are unable to determine the correct URI
- ) {
- $uri = $this->getValidUri($clientConfig['web']['redirect_uris']);
- if (empty($uri)) {
- throw new \Exception(Piwik::translate('SearchEngineKeywordsPerformance_InvalidRedirectUriInClientConfiguration', [$expectedUri]));
- }
- $client->setRedirectUri($uri);
- }
- try {
- $client->setAccessToken($accessToken);
- } catch (\Exception $e) {
- throw new MissingOAuthConfigException($e->getMessage());
- }
- }
- public function getUserInfo($accountId)
- {
- return $this->configuration->getUserInfo($accountId);
- }
- protected function getUserInfoByAccessToken($accessToken)
- {
- $service = new \Matomo\Dependencies\SearchEngineKeywordsPerformance\Google\Service\Oauth2($this->getConfiguredClient($accessToken));
- return $service->userinfo->get();
- }
- /**
- * Checks if account can be used to query the API
- *
- * @param string $accountId
- * @return bool
- * @throws \Exception
- */
- public function testConfiguration($accountId)
- {
- $accessToken = $this->configuration->getAccessToken($accountId);
- try {
- $service = new \Matomo\Dependencies\SearchEngineKeywordsPerformance\Google\Service\SearchConsole($this->getConfiguredClient($accessToken));
- $service->sites->listSites();
- } catch (\Exception $e) {
- $this->handleServiceException($e);
- throw $e;
- }
- return \true;
- }
- /**
- * Returns the urls keyword data is available for (in connected google account)
- *
- * @param string $accountId
- * @param bool $removeUrlsWithoutAccess wether to return unverified urls
- * @return array
- */
- public function getAvailableUrls($accountId, $removeUrlsWithoutAccess = \true)
- {
- $accessToken = $this->configuration->getAccessToken($accountId);
- $sites = [];
- try {
- $service = new \Matomo\Dependencies\SearchEngineKeywordsPerformance\Google\Service\SearchConsole($this->getConfiguredClient($accessToken));
- $service->getClient()->getCache()->clear();
- //After Guzzle upgrade this seems to fetch same token for all the accounts, to solve that we are clearing the caache explicitly
- $response = $service->sites->listSites();
- } catch (\Exception $e) {
- return $sites;
- }
- foreach ($response as $site) {
- if (!$removeUrlsWithoutAccess || $site['permissionLevel'] != 'siteUnverifiedUser') {
- $sites[$site['siteUrl']] = $site['permissionLevel'];
- }
- }
- return $sites;
- }
- /**
- * Returns the search analytics data from google search console for the given parameters
- *
- * @param string $accountId
- * @param string $url url, eg. http://matomo.org
- * @param string $date day string, eg. 2016-12-24
- * @param string $type 'web', 'image', 'video' or 'news'
- * @param int $limit maximum of rows to fetch
- * @return \Google\Service\SearchConsole\SearchAnalyticsQueryResponse
- * @throws InvalidClientConfigException
- * @throws InvalidCredentialsException
- * @throws MissingOAuthConfigException
- * @throws MissingClientConfigException
- * @throws UnknownAPIException
- */
- public function getSearchAnalyticsData($accountId, $url, $date, $type = 'web', $limit = 500)
- {
- $accessToken = $this->configuration->getAccessToken($accountId);
- if (empty($accessToken)) {
- throw new MissingOAuthConfigException();
- }
- $limit = min($limit, 5000);
- // maximum allowed by API is 5.000
- // Google API is only able to handle dates up to ~490 days old
- $threeMonthBefore = Date::now()->subDay(500);
- $archivedDate = Date::factory($date);
- if ($archivedDate->isEarlier($threeMonthBefore) || $archivedDate->isToday()) {
- Log::debug("[SearchEngineKeywordsPerformance] Skip fetching keywords from Search Console for today and dates more than 500 days in the past");
- return null;
- }
- $service = new \Matomo\Dependencies\SearchEngineKeywordsPerformance\Google\Service\SearchConsole($this->getConfiguredClient($accessToken));
- $request = new \Matomo\Dependencies\SearchEngineKeywordsPerformance\Google\Service\SearchConsole\SearchAnalyticsQueryRequest();
- $request->setStartDate($date);
- $request->setEndDate($date);
- $request->setDimensions(['query']);
- $request->setRowLimit($limit);
- $request->setSearchType($type);
- $request->setDataState('all');
- $retries = 0;
- while ($retries < 5) {
- try {
- $response = $service->searchanalytics->query($url, $request);
- return $response;
- } catch (\Exception $e) {
- $this->handleServiceException($e, $retries < 4);
- usleep(500 * $retries);
- $retries++;
- }
- }
- return null;
- }
- /**
- * Returns an array of dates where search analytics data is availabe for on search console
- *
- * @param string $accountId
- * @param string $url url, eg. http://matomo.org
- * @param boolean $onlyFinalized
- * @return array
- * @throws MissingClientConfigException
- * @throws MissingOAuthConfigException
- * @throws InvalidClientConfigException
- * @throws InvalidCredentialsException
- * @throws UnknownAPIException
- */
- public function getDatesWithSearchAnalyticsData($accountId, $url, $onlyFinalized = \true)
- {
- $accessToken = $this->configuration->getAccessToken($accountId);
- $service = new \Matomo\Dependencies\SearchEngineKeywordsPerformance\Google\Service\SearchConsole($this->getConfiguredClient($accessToken));
- $request = new \Matomo\Dependencies\SearchEngineKeywordsPerformance\Google\Service\SearchConsole\SearchAnalyticsQueryRequest();
- $request->setStartDate(Date::now()->subDay(StaticContainer::get('SearchEngineKeywordsPerformance.Google.ImportLastDaysMax'))->toString());
- $request->setEndDate(Date::now()->toString());
- $request->setDimensions(['date']);
- if ($onlyFinalized === \false) {
- $request->setDataState('all');
- }
- $retries = 0;
- while ($retries < 5) {
- try {
- $entries = $service->searchanalytics->query($url, $request);
- if (empty($entries) || !($rows = $entries->getRows())) {
- return [];
- }
- $days = [];
- foreach ($rows as $row) {
- /** @var \Google\Service\SearchConsole\ApiDataRow $row */
- $keys = $keys = $row->getKeys();
- $days[] = array_shift($keys);
- }
- return array_unique($days);
- } catch (\Exception $e) {
- $this->handleServiceException($e, $retries < 4);
- $retries++;
- usleep(500 * $retries);
- }
- }
- return [];
- }
- /**
- * @param \Exception $e
- * @param bool $ignoreUnknowns
- * @throws InvalidClientConfigException
- * @throws InvalidCredentialsException
- * @throws UnknownAPIException
- */
- protected function handleServiceException($e, $ignoreUnknowns = \false)
- {
- if (!$e instanceof \Matomo\Dependencies\SearchEngineKeywordsPerformance\Google\Service\Exception) {
- if (!PluginsArchiver::isArchivingProcessActive()) {
- Log::debug('Exception: ' . $e->getMessage());
- }
- return;
- }
- $error = json_decode($e->getMessage(), \true);
- if (!empty($error['error']) && $error['error'] == 'invalid_client') {
- // invalid credentials
- throw new InvalidClientConfigException($error['error_description']);
- } elseif (!empty($error['error']['code']) && $error['error']['code'] == 401) {
- // invalid credentials
- throw new InvalidCredentialsException($error['error']['message'], $error['error']['code']);
- } elseif (!empty($error['error']['code']) && $error['error']['code'] == 403) {
- // no access for given resource (website / app)
- throw new InvalidCredentialsException($error['error']['message'], $error['error']['code']);
- } elseif (!empty($error['error']['code']) && in_array($error['error']['code'], [500, 503]) && !$ignoreUnknowns) {
- // backend or api server error
- throw new UnknownAPIException($error['error']['message'], $error['error']['code']);
- } else {
- if (!PluginsArchiver::isArchivingProcessActive()) {
- Log::debug('Exception: ' . $e->getMessage());
- }
- }
- }
- /**
- * Returns a valid uri. Copied from GA Importer Authorization class.
- *
- * @param array $uris
- * @return string
- */
- private function getValidUri(array $uris): string
- {
- $validUri = Url::getCurrentUrlWithoutQueryString() . '?module=SearchEngineKeywordsPerformance&action=processAuthCode';
- $settingURL = SettingsPiwik::getPiwikUrl();
- if (stripos($settingURL, 'index.php') === false) {
- $settingURL .= 'index.php';
- }
- // Some MWP installs was not working as expected when using Url::getCurrentUrlWithoutQueryString()
- $validUriFallback = $settingURL . '?module=SearchEngineKeywordsPerformance&action=processAuthCode';
- foreach ($uris as $uri) {
- if (stripos($uri, $validUri) !== \false || stripos($uri, $validUriFallback) !== \false) {
- return $uri;
- }
- }
- return '';
- }
-
- private function isMiscCron()
- {
- $currentURL = Url::getCurrentUrlWithoutQueryString();
-
- return (stripos($currentURL, 'misc/cron/archive.php') !== false);
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Client/Yandex.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Client/Yandex.php
deleted file mode 100644
index 5056dea..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Client/Yandex.php
+++ /dev/null
@@ -1,545 +0,0 @@
-configuration = $configuration;
- }
- /**
- * Returns if client is configured
- *
- * @return bool
- */
- public function isConfigured()
- {
- return $this->isClientConfigured() && count($this->configuration->getAccounts()) > 0;
- }
- /**
- * Returns if oauth client config is available
- */
- public function isClientConfigured()
- {
- return \true && $this->getClientConfig();
- }
- /**
- * Returns the client config
- *
- * @return mixed|null
- */
- public function getClientConfig()
- {
- return $this->configuration->getClientConfig();
- }
- /**
- * Checks if account can be used to query the API
- *
- * @param string $accountId
- * @return bool
- * @throws \Exception
- */
- public function testConfiguration($accountId)
- {
- $accessToken = $this->configuration->getAccessToken($accountId);
- $this->getHosts($accessToken);
- return \true;
- }
- /**
- * Updates the client config
- *
- * @param string $clientId new client id
- * @param string $clientSecret new client secret
- */
- public function setClientConfig($clientId, $clientSecret)
- {
- $this->configuration->setClientConfig($clientId, $clientSecret);
- Piwik::postEvent('SearchEngineKeywordsPerformance.GoogleClientConfigChanged');
- }
- /**
- * Returns the urls keyword data is available for (in connected yandex account)
- *
- * @param string $accountId
- * @param bool $removeUrlsWithoutAccess whether to return unverified urls
- * @return array
- */
- public function getAvailableUrls($accountId, $removeUrlsWithoutAccess = \true)
- {
- $accessToken = $this->configuration->getAccessToken($accountId);
- $sites = [];
- try {
- $availableSites = $this->getHosts($accessToken);
- } catch (\Exception $e) {
- return $sites;
- }
- if (property_exists($availableSites, 'hosts')) {
- foreach ($availableSites->hosts as $availableSite) {
- if (!$removeUrlsWithoutAccess || $availableSite->verified) {
- $sites[$availableSite->unicode_host_url] = ['verified' => $availableSite->verified, 'host_id' => $availableSite->host_id];
- }
- }
- }
- return $sites;
- }
- /**
- * Returns popular search queries from Yandex Webmaster API
- *
- * @param string $accountId
- * @param string $hostId
- * @param string $date
- * @return ?array
- * @throws InvalidCredentialsException
- * @throws RateLimitApiException
- * @throws UnknownAPIException
- */
- public function getSearchAnalyticsData($accountId, $hostId, $date)
- {
- $accessToken = $this->configuration->getAccessToken($accountId);
- $archivedDate = Date::factory($date);
- if ($archivedDate->isToday()) {
- Log::debug("[SearchEngineKeywordsPerformance] Skip fetching keywords from Yandex Webmaster for today.");
- return null;
- }
- $date = strtotime($date);
- $searchQueries = $this->retryApiMethod(function () use ($accessToken, $hostId, $date) {
- return $this->getPopularQueries($accessToken, $hostId, $date);
- });
- if (empty($searchQueries) || empty($searchQueries->queries)) {
- return null;
- }
- $keywords = [];
- foreach ($searchQueries->queries as $query) {
- $keywords[] = ['keyword' => $query->query_text, 'clicks' => $query->indicators->TOTAL_CLICKS, 'impressions' => $query->indicators->TOTAL_SHOWS, 'position' => $query->indicators->AVG_SHOW_POSITION];
- }
- return $keywords;
- }
- /**
- * Returns crawl statistics from Yandex Webmaster API
- *
- * @param string $accountId
- * @param string $hostId
- * @return array
- * @throws InvalidCredentialsException
- * @throws RateLimitApiException
- * @throws UnknownAPIException
- */
- public function getCrawlStats($accountId, $hostId, $date)
- {
- $accessToken = $this->configuration->getAccessToken($accountId);
- $archivedDate = Date::factory($date);
- if ($archivedDate->isToday()) {
- Log::debug("[SearchEngineKeywordsPerformance] Skip fetching crawl stats from Yandex Webmaster for today.");
- return null;
- }
- $dateTs = strtotime($date);
- $crawlStatsByDate = [];
- $crawlStats = $this->retryApiMethod(function () use ($accessToken, $hostId, $dateTs) {
- return $this->getIndexingHistory($accessToken, $hostId, $dateTs);
- });
- if (!empty($crawlStats) && !empty($crawlStats->indicators)) {
- $indicators = (array) $crawlStats->indicators;
- foreach ($indicators as $indicator => $indicatorByDate) {
- foreach ($indicatorByDate as $dateItem) {
- if (strpos($dateItem->date, $date) === 0) {
- $crawlStatsByDate[$indicator] = (int) $dateItem->value;
- }
- }
- }
- }
- $pagesInIndex = $this->retryApiMethod(function () use ($accessToken, $hostId, $dateTs) {
- return $this->getPagesInIndex($accessToken, $hostId, $dateTs);
- });
- if (!empty($pagesInIndex) && !empty($pagesInIndex->history)) {
- $history = (array) $pagesInIndex->history;
- foreach ($history as $entry) {
- // Look for matching date
- if (strpos($entry->date, $date) === 0) {
- $crawlStatsByDate['SEARCHABLE'] = (int) $entry->value;
- }
- }
- }
- $pageChanges = $this->retryApiMethod(function () use ($accessToken, $hostId, $dateTs) {
- return $this->getPageChangesInSearch($accessToken, $hostId, $dateTs);
- });
- if (!empty($pageChanges) && !empty($pageChanges->indicators)) {
- $indicators = (array) $pageChanges->indicators;
- foreach ($indicators as $indicator => $indicatorByDate) {
- foreach ($indicatorByDate as $dateItem) {
- // Look for matching date
- if (strpos($dateItem->date, $date) === 0) {
- $crawlStatsByDate[$indicator] = (int) $dateItem->value;
- }
- }
- }
- }
- return $crawlStatsByDate;
- }
- /**
- * @param callback $method
- * @return mixed
- * @throws \Exception
- * @throws InvalidCredentialsException
- * @throws RateLimitApiException
- * @throws UnknownAPIException
- */
- protected function retryApiMethod($method)
- {
- $retries = 0;
- while ($retries < 5) {
- try {
- return $method();
- } catch (InvalidCredentialsException $e) {
- throw $e;
- } catch (\Exception $e) {
- if ($retries >= 4) {
- throw $e;
- }
- usleep(500);
- $retries++;
- }
- }
- }
- /**
- * Process the given auth code to gain access and refresh token from yandex api
- *
- * @param string $authCode
- * @throws InvalidCredentialsException
- * @throws MissingClientConfigException
- * @throws RateLimitApiException
- * @throws UnknownAPIException
- */
- public function processAuthCode($authCode)
- {
- if (!$this->isClientConfigured()) {
- throw new MissingClientConfigException();
- }
- $accessToken = $this->fetchAccessTokenWithAuthCode($authCode);
- $userId = $this->getYandexUserId($accessToken);
- $this->addAccount($userId, $accessToken, Piwik::getCurrentUserLogin());
- $userInfo = $this->getUserInfo($userId);
- Piwik::postEvent('SearchEngineKeywordsPerformance.AccountAdded', [['provider' => \Piwik\Plugins\SearchEngineKeywordsPerformance\Provider\Yandex::getInstance()->getName(), 'account' => $userInfo['name']]]);
- }
- /**
- * Returns user information for given account id
- *
- * @param $accountId
- * @return array|null
- */
- public function getUserInfo($accountId)
- {
- return $this->configuration->getUserInfo($accountId);
- }
- /**
- * Fetches an access token from Yandex OAuth with the given auth code
- *
- * @param string $authCode
- * @return string
- * @throws \Exception
- */
- protected function fetchAccessTokenWithAuthCode($authCode)
- {
- $clientConfig = $this->getClientConfig();
- $response = Http::sendHttpRequestBy(
- Http::getTransportMethod(),
- 'https://oauth.yandex.com/token',
- 2000,
- null,
- null,
- null,
- 0,
- \false,
- \false,
- \false,
- \false,
- 'POST',
- $clientConfig['id'],
- $clientConfig['secret'],
- 'grant_type=authorization_code&code=' . $authCode
- );
- $result = json_decode($response, \true);
- if (isset($result['error'])) {
- throw new \Exception($result['error_description']);
- }
- if (isset($result['access_token'])) {
- return $result['access_token'];
- }
- throw new \Exception('Unknown Error');
- }
- /**
- * Returns Yandex OAuth url
- *
- * @return string
- */
- public function createAuthUrl()
- {
- $clientConfig = $this->getClientConfig();
- return 'https://oauth.yandex.com/authorize?response_type=code&client_id=' . $clientConfig['id'];
- }
- /**
- * Returns connected oauth accounts
- *
- * @return array
- */
- public function getAccounts()
- {
- return $this->configuration->getAccounts();
- }
- /**
- * Removes oauth account
- *
- * @param string $id
- * @return boolean
- */
- public function removeAccount($id)
- {
- $userInfo = $this->getUserInfo($id);
- $this->configuration->removeAccount($id);
- Piwik::postEvent('SearchEngineKeywordsPerformance.AccountRemoved', [['provider' => \Piwik\Plugins\SearchEngineKeywordsPerformance\Provider\Yandex::getInstance()->getName(), 'account' => $userInfo['name']]]);
- return \true;
- }
- /**
- * Adds a oauth account
- *
- * @param string $id
- * @param string $config
- * @param string $username
- * @return boolean
- */
- public function addAccount($id, $accessToken, $username)
- {
- $userInfo = $this->getUserInfoByAccessToken($accessToken);
- $config = ['userInfo' => ['picture' => 'https://avatars.yandex.net/get-yapic/' . $userInfo['default_avatar_id'] . '/islands-retina-50', 'name' => $userInfo['display_name']], 'accessToken' => $accessToken];
- $this->configuration->addAccount($id, $config, $username);
- return \true;
- }
- /**
- * Fetches user info from Yandex Passport API
- *
- * @param string $accessToken
- * @return mixed
- * @throws InvalidCredentialsException
- * @throws UnknownAPIException
- */
- protected function getUserInfoByAccessToken($accessToken)
- {
- $url = 'https://login.yandex.ru/info';
- $response = Http::sendHttpRequestBy(Http::getTransportMethod(), $url, 2000, null, null, null, 0, \false, \false, \false, \false, 'GET', null, null, null, ['Authorization: OAuth ' . $accessToken]);
- $result = json_decode($response, \true);
- if (isset($result['error'])) {
- throw new InvalidCredentialsException($result['error_description'], $result['error']);
- }
- if (empty($result) || !is_array($result) || !isset($result['display_name'])) {
- throw new UnknownAPIException('Unable to receive user information');
- }
- return $result;
- }
- /**
- * @param string $accessToken
- * @param string $hostId
- * @param string $date
- * @return mixed
- * @throws InvalidCredentialsException
- * @throws RateLimitApiException
- * @throws UnknownAPIException
- */
- protected function getPopularQueries($accessToken, $hostId, $date)
- {
- return $this->sendApiRequest(
- $accessToken,
- 'user/' . $this->getYandexUserId($accessToken) . '/hosts/' . $hostId . '/search-queries/popular/',
- ['date_from' => date(\DATE_ATOM, $date), 'date_to' => date(\DATE_ATOM, $date + 24 * 3600 - 1), 'order_by' => 'TOTAL_CLICKS', 'query_indicator' => ['TOTAL_CLICKS', 'TOTAL_SHOWS', 'AVG_SHOW_POSITION', 'AVG_CLICK_POSITION'], 'limit' => 500]
- );
- }
- /**
- * @param string $accessToken
- * @param string $hostId
- * @param string $date
- * @return mixed
- * @throws InvalidCredentialsException
- * @throws RateLimitApiException
- * @throws UnknownAPIException
- */
- protected function getIndexingHistory($accessToken, $hostId, $date)
- {
- // note we query a weeks data as otherwise the results might not contain the date we actually want to look at
- return $this->sendApiRequest(
- $accessToken,
- 'user/' . $this->getYandexUserId($accessToken) . '/hosts/' . $hostId . '/indexing/history/',
- array('date_from' => date(\DATE_ATOM, $date - 7 * 24 * 3600), 'date_to' => date(\DATE_ATOM, $date + 24 * 3600 - 1))
- );
- }
- /**
- * @param string $accessToken
- * @param string $hostId
- * @param string $date
- * @return mixed
- * @throws InvalidCredentialsException
- * @throws RateLimitApiException
- * @throws UnknownAPIException
- */
- protected function getPagesInIndex($accessToken, $hostId, $date)
- {
- // note we query a weeks data as otherwise the results might not contain the date we actually want to look at
- return $this->sendApiRequest(
- $accessToken,
- 'user/' . $this->getYandexUserId($accessToken) . '/hosts/' . $hostId . '/search-urls/in-search/history/',
- array('date_from' => date(\DATE_ATOM, $date - 7 * 24 * 3600), 'date_to' => date(\DATE_ATOM, $date + 24 * 3600 - 1))
- );
- }
- /**
- * @param string $accessToken
- * @param string $hostId
- * @param string $date
- * @return mixed
- * @throws InvalidCredentialsException
- * @throws RateLimitApiException
- * @throws UnknownAPIException
- */
- protected function getPageChangesInSearch($accessToken, $hostId, $date)
- {
- // note we query a weeks data as otherwise the results might not contain the date we actually want to look at
- return $this->sendApiRequest(
- $accessToken,
- 'user/' . $this->getYandexUserId($accessToken) . '/hosts/' . $hostId . '/search-urls/events/history/',
- array('date_from' => date(\DATE_ATOM, $date - 7 * 24 * 3600), 'date_to' => date(\DATE_ATOM, $date + 24 * 3600 - 1))
- );
- }
- /**
- * Returns the available hosts for the given access token
- * @param string $accessToken
- * @return object
- * @throws InvalidCredentialsException
- * @throws RateLimitApiException
- * @throws UnknownAPIException
- */
- protected function getHosts($accessToken)
- {
- return $this->sendApiRequest($accessToken, 'user/' . $this->getYandexUserId($accessToken) . '/hosts');
- }
- /**
- * Returns the Yandex User ID for the given access token
- * @param string $accessToken
- * @return string
- * @throws InvalidCredentialsException
- * @throws RateLimitApiException
- * @throws UnknownAPIException
- */
- protected function getYandexUserId($accessToken)
- {
- static $userIdByToken = [];
- if (!empty($userIdByToken[$accessToken])) {
- return $userIdByToken[$accessToken];
- }
- $result = $this->sendApiRequest($accessToken, 'user');
- if (!empty($result->user_id)) {
- $userIdByToken[$accessToken] = $result->user_id;
- return $userIdByToken[$accessToken];
- }
- throw new InvalidCredentialsException('Unable to find user ID');
- }
- /**
- * @param string $accessToken
- * @param string $method
- * @param array $params
- * @return mixed
- * @throws InvalidCredentialsException
- * @throws RateLimitApiException
- * @throws UnknownAPIException
- */
- protected function sendApiRequest($accessToken, $method, $params = [])
- {
- $urlParams = [];
- foreach ($params as $name => $value) {
- if (is_array($value)) {
- foreach ($value as $val) {
- $urlParams[] = $name . '=' . urlencode($val);
- }
- continue;
- }
- $urlParams[] = $name . '=' . urlencode($value);
- }
- $url = $this->baseAPIUrl . $method . '?' . implode('&', $urlParams);
- $additionalHeaders = ['Authorization: OAuth ' . $accessToken, 'Accept: application/json', 'Content-type: application/json'];
- $response = Http::sendHttpRequestBy(
- Http::getTransportMethod(),
- $url,
- $timeout = 60,
- $userAgent = null,
- $destinationPath = null,
- $file = null,
- $followDepth = 0,
- $acceptLanguage = \false,
- $acceptInvalidSslCertificate = \false,
- $byteRange = \false,
- $getExtendedInfo = \true,
- $httpMethod = 'GET',
- $httpUsername = '',
- $httpPassword = '',
- $requestBody = null,
- $additionalHeaders
- );
- if (empty($response['data'])) {
- throw new \Exception('Yandex API returned no data: ' . var_export($response, \true));
- }
- $data = json_decode($response['data'], \false, 512, \JSON_BIGINT_AS_STRING);
- if (!empty($data->error_code)) {
- switch ($data->error_code) {
- case 'INVALID_OAUTH_TOKEN':
- case 'INVALID_USER_ID':
- throw new InvalidCredentialsException($data->error_message, (int) $data->error_code);
- case 'QUOTA_EXCEEDED':
- case 'TOO_MANY_REQUESTS_ERROR':
- throw new RateLimitApiException($data->error_message, (int) $data->error_code);
- }
- throw new UnknownAPIException($data->error_message, (int) $data->error_code);
- }
- return $data;
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Columns/Keyword.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Columns/Keyword.php
deleted file mode 100644
index 8745447..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Columns/Keyword.php
+++ /dev/null
@@ -1,28 +0,0 @@
-setName('searchengines:import-bing')->setDescription('Imports Bing Keywords')->addNoValueOption('force', 'f', 'Force reimport for data')->addRequiredValueOption('idsite', '', 'Site id');
- }
- /**
- * @return int
- */
- protected function doExecute(): int
- {
- $input = $this->getInput();
- $output = $this->getOutput();
- $output->writeln("Starting to import Bing Keywords");
- $start = microtime(\true);
- $idSite = $input->getOption('idsite');
- $setting = new MeasurableSettings($idSite);
- $bingSiteUrl = $setting->bingSiteUrl;
- if (!$bingSiteUrl || !$bingSiteUrl->getValue()) {
- $output->writeln("Site with ID {$idSite} not configured for Bing Import");
- }
- $importer = new Bing($idSite, $input->hasOption('force'));
- $importer->importAllAvailableData();
- $output->writeln("Finished in " . round(microtime(\true) - $start, 3) . "s");
- return self::SUCCESS;
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Commands/ImportGoogle.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Commands/ImportGoogle.php
deleted file mode 100644
index 0f59541..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Commands/ImportGoogle.php
+++ /dev/null
@@ -1,55 +0,0 @@
-setName('searchengines:import-google')->setDescription('Imports Google Keywords')
- ->addNoValueOption('force', 'f', 'Force reimport for data')
- ->addRequiredValueOption('idsite', '', 'Site id')
- ->addOptionalValueOption('date', 'd', 'specific date');
- }
- /**
- * @return int
- */
- protected function doExecute(): int
- {
- $input = $this->getInput();
- $output = $this->getOutput();
- $output->writeln("Starting to import Google Keywords");
- $start = microtime(\true);
- $idSite = $input->getOption('idsite');
- $setting = new MeasurableSettings($idSite);
- $searchConsoleUrl = $setting->googleSearchConsoleUrl;
- if (!$searchConsoleUrl || !$searchConsoleUrl->getValue()) {
- $output->writeln("Site with ID {$idSite} not configured for Google Import");
- }
- $importer = new Google($idSite, $input->getOption('force'));
- $date = $input->getOption('date') ? $input->getOption('date') : null;
- $importer->importAllAvailableData($date);
- $output->writeln("Finished in " . round(microtime(\true) - $start, 3) . "s");
- return self::SUCCESS;
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Commands/ImportYandex.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Commands/ImportYandex.php
deleted file mode 100644
index f8d243e..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Commands/ImportYandex.php
+++ /dev/null
@@ -1,55 +0,0 @@
-setName('searchengines:import-yandex')->setDescription('Imports Yandex Keywords')
- ->addNoValueOption('force', 'f', 'Force reimport for data')
- ->addRequiredValueOption('idsite', '', 'Site id')
- ->addOptionalValueOption('date', 'd', 'specific date');
- }
- /**
- * @return int
- */
- protected function doExecute(): int
- {
- $input = $this->getInput();
- $output = $this->getOutput();
- $output->writeln("Starting to import Yandex Keywords");
- $start = microtime(\true);
- $idSite = $input->getOption('idsite');
- $setting = new MeasurableSettings($idSite);
- $yandexSiteUrl = $setting->yandexAccountAndHostId;
- if (!$yandexSiteUrl || !$yandexSiteUrl->getValue()) {
- $output->writeln("Site with ID {$idSite} not configured for Yandex Import");
- }
- $importer = new Yandex($idSite, $input->hasOption('force'));
- $date = $input->hasOption('date') ? $input->getOption('date') : 100;
- $importer->importAllAvailableData($date);
- $output->writeln("Finished in " . round(microtime(\true) - $start, 3) . "s");
- return self::SUCCESS;
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Controller.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Controller.php
deleted file mode 100644
index ee30156..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Controller.php
+++ /dev/null
@@ -1,1125 +0,0 @@
-showNotificationIfNoWebsiteConfigured($provider);
- }
- SearchEngineKeywordsPerformance::displayNotificationIfRecentApiErrorsExist($viewVariables['providers']);
-
- $viewVariables['providers'] = array_map(function (ProviderAbstract $provider) {
- return $this->toProviderArray($provider);
- }, $viewVariables['providers']);
-
- return $this->renderTemplate('index', $viewVariables);
- }
-
- private function toProviderArray(ProviderAbstract $provider)
- {
- return [
- 'id' => $provider->getId(),
- 'is_configured' => $provider->isConfigured(),
- 'configured_site_ids' => $provider->getConfiguredSiteIds(),
- 'problems' => $provider->getConfigurationProblems(),
- 'is_experimental' => $provider->isExperimental(),
- 'logos' => $provider->getLogoUrls(),
- 'name' => $provider->getName(),
- 'description' => $provider->getDescription(),
- 'note' => $provider->getNote(),
- ];
- }
-
- private function showNotificationIfNoWebsiteConfigured(ProviderAbstract $provider)
- {
- if (!$provider->isConfigured()) {
- return;
- }
-
- if (count($provider->getConfiguredSiteIds()) == 0) {
- $notification = new Notification(Piwik::translate(
- 'SearchEngineKeywordsPerformance_NoWebsiteConfiguredWarning',
- $provider->getName()
- ));
- $notification->context = Notification::CONTEXT_WARNING;
- Notification\Manager::notify($provider->getId() . 'nowebsites', $notification);
- }
-
- $errors = $provider->getConfigurationProblems();
-
- if (count($errors['sites'])) {
- $notification = new Notification(Piwik::translate(
- 'SearchEngineKeywordsPerformance_ProviderXSitesWarning',
- [$provider->getName()]
- ));
- $notification->context = Notification::CONTEXT_WARNING;
- $notification->raw = true;
- Notification\Manager::notify($provider->getId() . 'siteswarning', $notification);
- }
-
- if (count($errors['accounts'])) {
- $notification = new Notification(Piwik::translate(
- 'SearchEngineKeywordsPerformance_ProviderXAccountWarning',
- [$provider->getName()]
- ));
- $notification->context = Notification::CONTEXT_WARNING;
- $notification->raw = true;
- Notification\Manager::notify($provider->getId() . 'accountwarning', $notification);
- }
- }
-
- private function getCurrentSite()
- {
- if ($this->site instanceof Site) {
- return ['id' => $this->site->getId(), 'name' => $this->site->getName()];
- }
-
- $sites = Request::processRequest('SitesManager.getSitesWithAdminAccess', [], []);
-
- if (!empty($sites[0])) {
- return ['id' => $sites[0]['idsite'], 'name' => $sites[0]['name']];
- }
-
- return [];
- }
-
- /*****************************************************************************************
- * Configuration actions for Google provider
- */
-
- /**
- * Show Google configuration page
- *
- * @param bool $hasOAuthError indicates if a oAuth access error occurred
- * @return string
- */
- public function configureGoogle($hasOAuthError = false)
- {
- Piwik::checkUserHasSomeAdminAccess();
-
- $configSaved = $this->configureGoogleClientIfProvided();
- if (false === $configSaved) {
- $notification = new Notification(Piwik::translate('SearchEngineKeywordsPerformance_ClientConfigSaveError'));
- $notification->context = Notification::CONTEXT_ERROR;
- Notification\Manager::notify('clientConfigSaved', $notification);
- }
-
- $errorMessage = Common::getRequestVar('error', '');
- if (!empty($errorMessage)) {
- if ($errorMessage === 'access_denied') {
- $errorMessage = Piwik::translate('SearchEngineKeywordsPerformance_OauthFailedMessage');
- } elseif ($errorMessage === 'jwt_validation_error') {
- $errorMessage = Piwik::translate('General_ExceptionSecurityCheckFailed');
- }
- $notification = new Notification($errorMessage);
- $notification->context = Notification::CONTEXT_ERROR;
- $notification->type = Notification::TYPE_TRANSIENT;
- Notification\Manager::notify('configureerror', $notification);
- }
-
- $googleClient = ProviderGoogle::getInstance()->getClient();
- $clientConfigured = true;
-
- try {
- $googleClient->getConfiguredClient('');
- } catch (MissingClientConfigException $e) {
- $clientConfigured = false;
- } catch (MissingOAuthConfigException $e) {
- // ignore missing accounts
- } catch (\Exception $e) {
- // Catch any general exceptions because they likely won't be recoverable. Delete the config so that they can try again
- // If we don't delete the config, the customer won't have any way to fix the issue
- $googleClient->deleteClientConfig();
-
- // Make sure we cancel the success notification because that could confuse the customer since things failed
- Notification\Manager::cancel('clientConfigSaved');
-
- // Mark the client as not configured and notify the user that something is wrong with the configuration
- $clientConfigured = false;
- $notification = new Notification($e->getMessage());
- $notification->context = Notification::CONTEXT_ERROR;
- $notification->type = Notification::TYPE_TRANSIENT;
- Notification\Manager::notify('configureerror', $notification);
- }
-
- $this->addGoogleSiteConfigIfProvided();
- $this->removeGoogleSiteConfigIfProvided();
- $this->removeGoogleAccountIfProvided();
-
- $urlOptions = [];
- $accounts = $googleClient->getAccounts();
- $countOfAccountsWithAccess = 0;
-
- foreach ($accounts as $id => &$account) {
- $userInfo = $googleClient->getUserInfo($id);
- $urls = $googleClient->getAvailableUrls($id, false);
- $account['picture'] = $userInfo['picture'];
- $account['name'] = $userInfo['name'];
- $account['urls'] = $urls;
- $account['hasAccess'] = Piwik::hasUserSuperUserAccessOrIsTheUser($account['username']);
- if ($account['hasAccess']) {
- ++$countOfAccountsWithAccess;
- }
- $account['created_formatted'] = Date::factory(date(
- 'Y-m-d',
- $account['created']
- ))->getLocalized(Date::DATE_FORMAT_LONG);
- try {
- $googleClient->testConfiguration($id);
- } catch (\Exception $e) {
- $account['hasError'] = $e->getMessage();
- }
-
- if ($account['hasAccess']) {
- foreach ($googleClient->getAvailableUrls($id) as $url => $status) {
- $urlOptions[$id . '##' . $url] = $url . ' (' . $account['name'] . ')';
- }
- }
- }
-
- $isClientConfigurable = StaticContainer::get('SearchEngineKeywordsPerformance.Google.isClientConfigurable');
-
- $viewVariables = [];
- $viewVariables['isConfigured'] = $googleClient->isConfigured();
- $viewVariables['clientId'] = $googleClient->getClientId();
- $viewVariables['auth_nonce'] = Nonce::getNonce('SEKP.google.auth');
- $viewVariables['clientSecret'] = preg_replace('/\w/', '*', $googleClient->getClientSecret() ?? '');
- $viewVariables['isClientConfigured'] = $clientConfigured;
- $viewVariables['isClientConfigurable'] = $isClientConfigurable;
- $viewVariables['isOAuthConfigured'] = count($accounts) > 0;
- $viewVariables['accounts'] = $accounts;
- $viewVariables['urlOptions'] = $urlOptions;
- $viewVariables['hasOAuthError'] = $hasOAuthError;
- $viewVariables['configuredMeasurables'] = ProviderGoogle::getInstance()->getConfiguredSiteIds();
- $viewVariables['nonce'] = Nonce::getNonce('SEKP.google.config');
- $viewVariables['sitesInfos'] = [];
- $viewVariables['currentSite'] = $this->getCurrentSite();
- $viewVariables['countOfAccountsWithAccess'] = $countOfAccountsWithAccess;
- $viewVariables['addGoogleSiteConfigNonce'] = Nonce::getNonce(self::GOOGLE_ADD_SITE_CONFIG_NONCE_KEY);
- $viewVariables['removeGoogleSiteConfigNonce'] = Nonce::getNonce(self::GOOGLE_REMOVE_SITE_CONFIG_NONCE_KEY);
- $viewVariables['removeGoogleAccountNonce'] = Nonce::getNonce(self::GOOGLE_REMOVE_ACCOUNT_NONCE_KEY);
-
- $siteIds = $viewVariables['configuredMeasurables'];
-
- foreach ($siteIds as $siteId => $config) {
- $googleSiteUrl = $config['googleSearchConsoleUrl'];
- $viewVariables['sitesInfos'][$siteId] = Site::getSite($siteId);
- $lastRun = Option::get('GoogleImporterTask_LastRun_' . $siteId);
-
- if ($lastRun) {
- $lastRun = date('Y-m-d H:i', $lastRun) . ' UTC';
- } else {
- $lastRun = Piwik::translate('General_Never');
- }
-
- $viewVariables['sitesInfos'][$siteId]['lastRun'] = $lastRun;
-
- [$accountId, $url] = explode('##', $googleSiteUrl);
-
- try {
- $viewVariables['sitesInfos'][$siteId]['accountValid'] = $googleClient->testConfiguration($accountId);
- } catch (\Exception $e) {
- $viewVariables['sitesInfos'][$siteId]['accountValid'] = false;
- }
-
- $urls = $googleClient->getAvailableUrls($accountId);
-
- $viewVariables['sitesInfos'][$siteId]['urlValid'] = key_exists($url, $urls);
- }
-
- if (!empty($this->securityPolicy)) {
- $this->securityPolicy->addPolicy('img-src', '*.googleusercontent.com');
- }
-
- $configureConnectionProps = [];
- $configureConnectionProps['baseUrl'] = Url::getCurrentUrlWithoutQueryString();
- $configureConnectionProps['baseDomain'] = Url::getCurrentScheme() . '://' . Url::getCurrentHost();
- $configureConnectionProps['manualConfigNonce'] = $viewVariables['nonce'];
- $configureConnectionProps['primaryText'] = Piwik::translate('SearchEngineKeywordsPerformance_ConfigureTheImporterLabel1');
-
- // There are certain cases where index.php isn't part of the baseUrl when it should be. Append it if missing.
- if (stripos($configureConnectionProps['baseUrl'], 'index.php') === false) {
- $configureConnectionProps['baseUrl'] .= 'index.php';
- }
-
- $isConnectAccountsActivated = Manager::getInstance()->isPluginActivated('ConnectAccounts');
- $authBaseUrl = $isConnectAccountsActivated ? "https://" . StaticContainer::get('CloudAccountsInstanceId') . '/index.php?' : '';
- $jwt = Common::getRequestVar('state', '', 'string');
- if (empty($jwt) && Piwik::hasUserSuperUserAccess() && $isConnectAccountsActivated) {
- // verify an existing user by supplying a jwt too
- $jwt = ConnectHelper::buildOAuthStateJwt(
- SettingsPiwik::getPiwikInstanceId(),
- ConnectAccounts::INITIATED_BY_SEK
- );
- }
- $googleAuthUrl = '';
- if ($isConnectAccountsActivated) {
- $strategyName = GoogleSearchConnect::getStrategyName();
- $googleAuthUrl = $authBaseUrl . Http::buildQuery([
- 'module' => 'ConnectAccounts',
- 'action' => 'initiateOauth',
- 'state' => $jwt,
- 'strategy' => $strategyName
- ]);
- $configureConnectionProps['strategy'] = $strategyName;
- $configureConnectionProps['connectedWith'] = 'Google';
- $configureConnectionProps['unlinkUrl'] = Url::getCurrentUrlWithoutQueryString() . '?' . Http::buildQuery([
- 'module' => 'ConnectAccounts',
- 'action' => 'unlink',
- 'nonce' => ConnectHelper::getUnlinkNonce(),
- 'strategy' => $strategyName
- ]);
- $configureConnectionProps['authUrl'] = $googleAuthUrl;
- $configureConnectionProps['connectAccountsUrl'] = $googleAuthUrl;
- $configureConnectionProps['connectAccountsBtnText'] = Piwik::translate('ConnectAccounts_ConnectWithGoogleText');
- }
-
- $configureConnectionProps['isConnectAccountsActivated'] = $isConnectAccountsActivated;
- if ($isConnectAccountsActivated) {
- $configureConnectionProps['radioOptions'] = [
- 'connectAccounts' => Piwik::translate('SearchEngineKeywordsPerformance_OptionQuickConnectWithGoogle'),
- 'manual' => Piwik::translate('ConnectAccounts_OptionAdvancedConnectWithGa'),
- ];
- }
- $configureConnectionProps['googleAuthUrl'] = $googleAuthUrl;
- $faqUrl = Url::addCampaignParametersToMatomoLink('https://matomo.org/faq/reports/import-google-search-keywords-in-matomo/#how-to-set-up-google-search-console-and-verify-your-website');
- $faqAnchorOpen = "";
- $configureConnectionProps['manualConfigText'] = Piwik::translate('SearchEngineKeywordsPerformance_ConfigureTheImporterLabel2')
- . ' ' . Piwik::translate('SearchEngineKeywordsPerformance_ConfigureTheImporterLabel3', [
- $faqAnchorOpen,
- '',
- ]) . '
' . Piwik::translate('SearchEngineKeywordsPerformance_OAuthExampleText')
- . ' ' . Piwik::translate('SearchEngineKeywordsPerformance_GoogleAuthorizedJavaScriptOrigin')
- . ": {$configureConnectionProps['baseDomain']} "
- . Piwik::translate('SearchEngineKeywordsPerformance_GoogleAuthorizedRedirectUri')
- . ": {$configureConnectionProps['baseUrl']}?module=SearchEngineKeywordsPerformance&action=processAuthCode";
-
- $viewVariables['configureConnectionProps'] = $configureConnectionProps;
- $viewVariables['extensions'] = self::getComponentExtensions();
- $viewVariables['removeConfigUrl'] = Url::getCurrentQueryStringWithParametersModified([ 'action' => 'removeGoogleClientConfig' ]);
-
- return $this->renderTemplate('google\configuration', $viewVariables);
- }
-
- /**
- * Save Google client configuration if set in request
- *
- * @return bool|null bool on success or failure, null if not data present in request
- */
- protected function configureGoogleClientIfProvided()
- {
- $googleClient = ProviderGoogle::getInstance()->getClient();
-
- $config = Common::getRequestVar('client', '');
-
- if (empty($config) && !empty($_FILES['clientfile'])) {
- if (!empty($_FILES['clientfile']['error'])) {
- return false;
- }
-
- $file = $_FILES['clientfile']['tmp_name'];
- if (!file_exists($file)) {
- return false;
- }
-
- $config = file_get_contents($_FILES['clientfile']['tmp_name']);
- }
-
- if (!empty($config)) {
- Nonce::checkNonce('SEKP.google.config', Common::getRequestVar('config_nonce'));
- try {
- $config = Common::unsanitizeInputValue($config);
- $saveResult = $googleClient->setClientConfig($config);
- if (!$saveResult) {
- return false;
- }
-
- // Show success notification
- $notification = new Notification(Piwik::translate('SearchEngineKeywordsPerformance_ClientConfigImported'));
- $notification->context = Notification::CONTEXT_SUCCESS;
- Notification\Manager::notify('clientConfigSaved', $notification);
-
- // Redirect so that it's the correct URL and doesn't try to resubmit the form if the customer refreshes
- Url::redirectToUrl(Url::getCurrentUrlWithoutQueryString() . Url::getCurrentQueryStringWithParametersModified([
- 'action' => 'configureGoogle',
- 'code' => null,
- 'scope' => null,
- 'state' => null,
- 'error' => null,
- ]));
- } catch (\Exception $e) {
- return false;
- }
- }
-
- return null;
- }
-
- /**
- * Save google configuration for a site if given in request
- */
- protected function addGoogleSiteConfigIfProvided()
- {
- $googleSiteId = Common::getRequestVar('googleSiteId', '');
- $googleAccountAndUrl = Common::getRequestVar('googleAccountAndUrl', '');
- $googleTypes = explode(',', Common::getRequestVar('googleTypes', ''));
-
- if (!empty($googleSiteId) && !empty($googleAccountAndUrl)) {
- $request = \Piwik\Request::fromRequest();
- Nonce::checkNonce(self::GOOGLE_ADD_SITE_CONFIG_NONCE_KEY, $request->getStringParameter('addSiteConfigNonce', ''));
- // Do not allow to configure websites with unsupported type or force enabled config
- if (SearchEngineKeywordsPerformance::isGoogleForceEnabled($googleSiteId) || WebsiteMeasurableType::ID !== Site::getTypeFor($googleSiteId)) {
- $notification = new Notification(
- Piwik::translate('SearchEngineKeywordsPerformance_WebsiteTypeUnsupported', [
- Site::getNameFor($googleSiteId)
- ])
- );
-
- if (class_exists('\Piwik\Plugins\RollUpReporting\Type') && \Piwik\Plugins\RollUpReporting\Type::ID === Site::getTypeFor($googleSiteId)) {
- $notification->message .= ' ' . Piwik::translate('SearchEngineKeywordsPerformance_WebsiteTypeUnsupportedRollUp');
- }
-
- $notification->context = Notification::CONTEXT_ERROR;
- $notification->raw = true;
- $notification->flags = Notification::FLAG_CLEAR;
- Notification\Manager::notify('websiteNotConfigurable', $notification);
-
- return;
- }
-
- $measurableSettings = new MeasurableSettings($googleSiteId);
- $measurableSettings->googleConfigCreatedBy->setValue(Piwik::getCurrentUserLogin());
-
- //Need to explicitly setIsWritableByCurrentUser=true, since it can be set as false when we instantiate MeasurableSettings object due to previously added by another user
- $measurableSettings->googleSearchConsoleUrl->setIsWritableByCurrentUser(true);
- $measurableSettings->googleWebKeywords->setIsWritableByCurrentUser(true);
- $measurableSettings->googleImageKeywords->setIsWritableByCurrentUser(true);
- $measurableSettings->googleNewsKeywords->setIsWritableByCurrentUser(true);
- $measurableSettings->googleVideoKeywords->setIsWritableByCurrentUser(true);
-
- $measurableSettings->googleSearchConsoleUrl->setValue($googleAccountAndUrl);
- $measurableSettings->googleWebKeywords->setValue(in_array('web', $googleTypes));
- $measurableSettings->googleImageKeywords->setValue(in_array('image', $googleTypes));
- $measurableSettings->googleNewsKeywords->setValue(in_array('news', $googleTypes));
- $measurableSettings->googleVideoKeywords->setValue(in_array('video', $googleTypes));
- $measurableSettings->save();
-
- $notification = new Notification(
- Piwik::translate('SearchEngineKeywordsPerformance_WebsiteSuccessfulConfigured', [
- Site::getNameFor($googleSiteId),
- '',
- ''
- ])
- );
- $notification->context = Notification::CONTEXT_SUCCESS;
- $notification->raw = true;
- $notification->flags = Notification::FLAG_CLEAR;
- Notification\Manager::notify('websiteConfigured', $notification);
- }
- }
-
- /**
- * Removes a Google account if `remove` param is given in request
- */
- protected function removeGoogleAccountIfProvided()
- {
- $remove = Common::getRequestVar('remove', '');
-
- if (!empty($remove)) {
- $request = \Piwik\Request::fromRequest();
- Nonce::checkNonce(self::GOOGLE_REMOVE_ACCOUNT_NONCE_KEY, $request->getStringParameter('removeAccountNonce', ''));
- ProviderGoogle::getInstance()->getClient()->removeAccount($remove);
-
- $sitesWithConfig = ProviderGoogle::getInstance()->getConfiguredSiteIds();
- foreach ($sitesWithConfig as $siteId => $siteConfig) {
- $googleSetting = explode('##', $siteConfig['googleSearchConsoleUrl']);
- if (!empty($googleSetting[0]) && $googleSetting[0] == $remove) {
- $config = new MeasurableSettings($siteId);
- $config->googleSearchConsoleUrl->setValue('0');
- $config->save();
- }
- }
- }
- }
-
- /**
- * Removes a Google site config if `removeConfig` param is given in request
- */
- protected function removeGoogleSiteConfigIfProvided()
- {
- $removeConfig = Common::getRequestVar('removeConfig', '');
-
- if (!empty($removeConfig)) {
- $request = \Piwik\Request::fromRequest();
- Nonce::checkNonce(self::GOOGLE_REMOVE_SITE_CONFIG_NONCE_KEY, $request->getStringParameter('removeSiteConfigNonce', ''));
- $measurableSettings = new MeasurableSettings($removeConfig);
- $measurableSettings->googleSearchConsoleUrl->setValue('0');
- $measurableSettings->save();
- }
- }
-
- /**
- * Delete the Google client config option so that the customer will be prompted to upload a new one or use the Cloud
- * config. Then refresh the page so show the change.
- */
- public function removeGoogleClientConfig()
- {
- Piwik::checkUserHasSuperUserAccess();
-
- Nonce::checkNonce('SEKP.google.config', Common::getRequestVar('config_nonce'));
-
- ProviderGoogle::getInstance()->getClient()->deleteClientConfig();
-
- Url::redirectToUrl(Url::getCurrentUrlWithoutQueryString() . Url::getCurrentQueryStringWithParametersModified([
- 'action' => 'configureGoogle',
- 'code' => null,
- 'scope' => null,
- 'state' => null,
- 'error' => null,
- ]));
- }
-
- public function forwardToAuth()
- {
- Piwik::checkUserHasSomeAdminAccess();
-
- Nonce::checkNonce('SEKP.google.auth', Common::getRequestVar('auth_nonce'));
-
- $client = ProviderGoogle::getInstance()->getClient();
- $state = Nonce::getNonce(self::OAUTH_STATE_NONCE_NAME, 900);
-
- Url::redirectToUrl($client->createAuthUrl($state));
- }
-
- protected function getSession()
- {
- return new SessionNamespace('searchperformance');
- }
-
- /**
- * Processes the response from google oauth service
- *
- * @return string
- * @throws \Exception
- */
- public function processAuthCode()
- {
- Piwik::checkUserHasSomeAdminAccess();
-
- $error = Common::getRequestVar('error', '');
- $oauthCode = Common::getRequestVar('code', '');
-
- if (!$error) {
- $state = Common::getRequestVar('state');
- if ($state && !empty($_SERVER['HTTP_REFERER']) && stripos($_SERVER['HTTP_REFERER'], 'https://accounts.google.') === 0) {
- //We need tp update this, else it will fail for referer like https://accounts.google.co.in
- $_SERVER['HTTP_REFERER'] = 'https://accounts.google.com';
- }
- try {
- Nonce::checkNonce(static::OAUTH_STATE_NONCE_NAME, $state, defined('PIWIK_TEST_MODE') ? null : 'google.com');
- } catch (\Exception $ex) {
- $error = $ex->getMessage();
- }
- }
-
- if ($error) {
- return $this->configureGoogle(true);
- }
-
- try {
- ProviderGoogle::getInstance()->getClient()->processAuthCode($oauthCode);
- } catch (\Exception $e) {
- return $this->configureGoogle($e->getMessage());
- }
-
- // we need idSite in the url to display all the menus like Conversion Import after redirect
- $siteInfo = $this->getCurrentSite();
- // reload index action to prove everything is configured
- Url::redirectToUrl(Url::getCurrentUrlWithoutQueryString() . Url::getCurrentQueryStringWithParametersModified([
- 'action' => 'configureGoogle',
- 'idSite' => (isset($siteInfo['id']) ? $siteInfo['id'] : 0),
- 'code' => null,
- 'scope' => null,
- 'state' => null
- ]));
- }
- /******************************************************************************************
- *****************************************************************************************/
-
- /*****************************************************************************************
- *****************************************************************************************
- * Configuration actions for Bing provider
- */
-
- /**
- * Show configuration page for Bing
- *
- * @return string
- */
- public function configureBing()
- {
- Piwik::checkUserHasSomeAdminAccess();
-
- $viewVariables = [];
- $viewVariables['apikey'] = '';
- $bingClient = ProviderBing::getInstance()->getClient();
-
- $apiKey = Common::getRequestVar('apikey', '');
-
- if (!empty($apiKey)) {
- Nonce::checkNonce('SEKP.bing.config', Common::getRequestVar('config_nonce'));
- try {
- $bingClient->testConfiguration($apiKey);
- $bingClient->addAccount($apiKey, Piwik::getCurrentUserLogin());
- } catch (\Exception $e) {
- $viewVariables['error'] = $e->getMessage();
- $viewVariables['apikey'] = $apiKey;
- }
- }
-
- $this->addBingSiteConfigIfProvided();
- $this->removeBingSiteConfigIfProvided();
- $this->removeBingAccountIfProvided();
-
- $urlOptions = [];
- $accounts = $bingClient->getAccounts();
- $countOfAccountsWithAccess = 0;
- foreach ($accounts as &$account) {
- $account['urls'] = [];
- $account['created_formatted'] = Date::factory(date(
- 'Y-m-d',
- $account['created']
- ))->getLocalized(Date::DATE_FORMAT_LONG);
- $account['hasAccess'] = Piwik::hasUserSuperUserAccessOrIsTheUser($account['username']);
- if ($account['hasAccess']) {
- ++$countOfAccountsWithAccess;
- }
- try {
- $bingClient->testConfiguration($account['apiKey']);
- } catch (\Exception $e) {
- $account['hasError'] = $e->getMessage();
- continue;
- }
-
- $account['urls'] = $bingClient->getAvailableUrls($account['apiKey'], false);
-
- if ($account['hasAccess']) {
- foreach ($bingClient->getAvailableUrls($account['apiKey']) as $url => $status) {
- $urlOptions[$account['apiKey'] . '##' . $url] = $url . ' (' . substr(
- $account['apiKey'],
- 0,
- 5
- ) . '*****' . substr($account['apiKey'], -5, 5) . ')';
- }
- }
- }
-
- $viewVariables['nonce'] = Nonce::getNonce('SEKP.bing.config');
- $viewVariables['accounts'] = $accounts;
- $viewVariables['urlOptions'] = $urlOptions;
- $viewVariables['configuredMeasurables'] = ProviderBing::getInstance()->getConfiguredSiteIds();
- $viewVariables['sitesInfos'] = [];
- $viewVariables['currentSite'] = $this->getCurrentSite();
- $viewVariables['countOfAccountsWithAccess'] = $countOfAccountsWithAccess;
- $viewVariables['addBingSiteConfigNonce'] = Nonce::getNonce(self::BING_ADD_SITE_CONFIG_NONCE_KEY);
- $viewVariables['removeBingSiteConfigNonce'] = Nonce::getNonce(self::BING_REMOVE_SITE_CONFIG_NONCE_KEY);
- $viewVariables['removeBingAccountNonce'] = Nonce::getNonce(self::BING_REMOVE_ACCOUNT_NONCE_KEY);
-
- $siteIds = $viewVariables['configuredMeasurables'];
-
- foreach ($siteIds as $siteId => $config) {
- $viewVariables['sitesInfos'][$siteId] = Site::getSite($siteId);
- $lastRun = Option::get('BingImporterTask_LastRun_' . $siteId);
-
- if ($lastRun) {
- $lastRun = date('Y-m-d H:i', $lastRun) . ' UTC';
- } else {
- $lastRun = Piwik::translate('General_Never');
- }
-
- $viewVariables['sitesInfos'][$siteId]['lastRun'] = $lastRun;
-
- $bingSiteUrl = $config['bingSiteUrl'];
- [$apiKey, $url] = explode('##', $bingSiteUrl);
-
- try {
- $viewVariables['sitesInfos'][$siteId]['accountValid'] = $bingClient->testConfiguration($apiKey);
- } catch (\Exception $e) {
- $viewVariables['sitesInfos'][$siteId]['accountValid'] = false;
- }
-
- $urls = $bingClient->getAvailableUrls($apiKey);
-
- $viewVariables['sitesInfos'][$siteId]['urlValid'] = key_exists($url, $urls);
- }
-
- return $this->renderTemplate('bing\configuration', $viewVariables);
- }
-
- /**
- * Save Bing configuration for a site if given in request
- */
- protected function addBingSiteConfigIfProvided()
- {
- $bingSiteId = Common::getRequestVar('bingSiteId', '');
- $bingAccountAndUrl = Common::getRequestVar('bingAccountAndUrl', '');
-
- if (!empty($bingSiteId) && !empty($bingAccountAndUrl)) {
- $request = \Piwik\Request::fromRequest();
- Nonce::checkNonce(self::BING_ADD_SITE_CONFIG_NONCE_KEY, $request->getStringParameter('addSiteConfigNonce', ''));
- // Do not allow to configure websites with unsupported type or force enabled config
- if (SearchEngineKeywordsPerformance::isBingForceEnabled($bingSiteId) || WebsiteMeasurableType::ID !== Site::getTypeFor($bingSiteId)) {
- $notification = new Notification(
- Piwik::translate('SearchEngineKeywordsPerformance_WebsiteTypeUnsupported', [
- Site::getNameFor($bingSiteId)
- ])
- );
-
- if (class_exists('\Piwik\Plugins\RollUpReporting\Type') && \Piwik\Plugins\RollUpReporting\Type::ID === Site::getTypeFor($bingSiteId)) {
- $notification->message .= ' ' . Piwik::translate('SearchEngineKeywordsPerformance_WebsiteTypeUnsupportedRollUp');
- }
-
- $notification->context = Notification::CONTEXT_ERROR;
- $notification->raw = true;
- $notification->flags = Notification::FLAG_CLEAR;
- Notification\Manager::notify('websiteNotConfigurable', $notification);
-
- return;
- }
-
- $measurableSettings = new MeasurableSettings($bingSiteId);
- $measurableSettings->bingConfigCreatedBy->setValue(Piwik::getCurrentUserLogin());
-
- //Need to explicitly setIsWritableByCurrentUser=true, since it can be set as false when we instantiate MeasurableSettings object due to previously added by another user
- $measurableSettings->bingSiteUrl->setIsWritableByCurrentUser(true);
-
- $measurableSettings->bingSiteUrl->setValue($bingAccountAndUrl);
- $measurableSettings->save();
-
- $notification = new Notification(
- Piwik::translate('SearchEngineKeywordsPerformance_WebsiteSuccessfulConfigured', [
- Site::getNameFor($bingSiteId),
- '',
- ''
- ])
- );
- $notification->context = Notification::CONTEXT_SUCCESS;
- $notification->raw = true;
- $notification->flags = Notification::FLAG_CLEAR;
- Notification\Manager::notify('websiteConfigured', $notification);
- }
- }
-
- /**
- * Removes a Bing account if `remove` param is given in request
- */
- protected function removeBingAccountIfProvided()
- {
- $remove = Common::getRequestVar('remove', '');
-
- if (!empty($remove)) {
- $request = \Piwik\Request::fromRequest();
- Nonce::checkNonce(self::BING_REMOVE_ACCOUNT_NONCE_KEY, $request->getStringParameter('removeAccountNonce', ''));
- ProviderBing::getInstance()->getClient()->removeAccount($remove);
-
- $sitesWithConfig = ProviderBing::getInstance()->getConfiguredSiteIds();
- foreach ($sitesWithConfig as $siteId => $siteConfig) {
- $bingSetting = explode('##', $siteConfig['bingSiteUrl']);
- if (!empty($bingSetting[0]) && $bingSetting[0] == $remove) {
- $config = new MeasurableSettings($siteId);
- $config->bingSiteUrl->setValue('0');
- $config->save();
- }
- }
- }
- }
-
- /**
- * Removes a Bing site config if `removeConfig` param is given in request
- */
- protected function removeBingSiteConfigIfProvided()
- {
- $removeConfig = Common::getRequestVar('removeConfig', '');
-
- if (!empty($removeConfig)) {
- $request = \Piwik\Request::fromRequest();
- Nonce::checkNonce(self::BING_REMOVE_SITE_CONFIG_NONCE_KEY, $request->getStringParameter('removeSiteConfigNonce', ''));
- $measurableSettings = new MeasurableSettings($removeConfig);
- $measurableSettings->bingSiteUrl->setValue('0');
- $measurableSettings->save();
- }
- }
- /******************************************************************************************
- *****************************************************************************************/
-
-
- /*****************************************************************************************
- *****************************************************************************************
- * Configuration actions for Yandex provider
- */
-
- /**
- * Show Yandex configuration page
- *
- * @param bool $hasOAuthError indicates if a oAuth access error occurred
- * @return string
- */
- public function configureYandex($hasOAuthError = false)
- {
- Piwik::checkUserHasSomeAdminAccess();
-
- $configSaved = $this->configureYandexClientIfProvided();
-
- if (true === $configSaved) {
- $notification = new Notification(Piwik::translate('SearchEngineKeywordsPerformance_ClientConfigImported'));
- $notification->context = Notification::CONTEXT_SUCCESS;
- Notification\Manager::notify('clientConfigSaved', $notification);
- } elseif (false === $configSaved) {
- $notification = new Notification(Piwik::translate('SearchEngineKeywordsPerformance_ClientConfigSaveError'));
- $notification->context = Notification::CONTEXT_ERROR;
- Notification\Manager::notify('clientConfigSaved', $notification);
- }
-
- $yandexClient = ProviderYandex::getInstance()->getClient();
- $clientConfigured = $yandexClient->isClientConfigured();
-
- $this->addYandexSiteConfigIfProvided();
- $this->removeYandexSiteConfigIfProvided();
- $this->removeYandexAccountIfProvided();
-
- $urlOptions = [];
- $accounts = $yandexClient->getAccounts();
- $countOfAccountsWithAccess = 0;
-
- foreach ($accounts as $id => &$account) {
- $userInfo = $yandexClient->getUserInfo($id);
- $account['urls'] = [];
- $account['picture'] = $userInfo['picture'];
- $account['name'] = $userInfo['name'];
- $account['created_formatted'] = Date::factory(date(
- 'Y-m-d',
- $account['created']
- ))->getLocalized(Date::DATE_FORMAT_LONG);
- $account['authDaysAgo'] = floor((time() - $account['created']) / (3600 * 24));
- $account['hasAccess'] = Piwik::hasUserSuperUserAccessOrIsTheUser($account['username']);
- if ($account['hasAccess']) {
- ++$countOfAccountsWithAccess;
- }
-
- try {
- $yandexClient->testConfiguration($id);
- } catch (\Exception $e) {
- $account['hasError'] = $e->getMessage();
- continue;
- }
-
- $account['urls'] = $yandexClient->getAvailableUrls($id, false);
-
- if ($account['hasAccess']) {
- foreach ($yandexClient->getAvailableUrls($id) as $url => $hostData) {
- $urlOptions[$id . '##' . $hostData['host_id']] = $url . ' (' . $account['name'] . ')';
- }
- }
- }
-
- $clientConfig = $yandexClient->getClientConfig();
- $viewVariables = [];
- $viewVariables['isConfigured'] = $yandexClient->isConfigured();
- $viewVariables['auth_nonce'] = Nonce::getNonce('SEKP.yandex.auth');
- $viewVariables['clientId'] = isset($clientConfig['id']) ? $clientConfig['id'] : '';
- $viewVariables['clientSecret'] = preg_replace('/\w/', '*', isset($clientConfig['secret']) ? $clientConfig['secret'] : '');
- $viewVariables['isClientConfigured'] = $clientConfigured;
- $viewVariables['isOAuthConfigured'] = count($accounts) > 0;
- $viewVariables['accounts'] = $accounts;
- $viewVariables['urlOptions'] = $urlOptions;
- $viewVariables['hasOAuthError'] = $hasOAuthError;
- $viewVariables['configuredMeasurables'] = ProviderYandex::getInstance()->getConfiguredSiteIds();
- $viewVariables['nonce'] = Nonce::getNonce('SEKP.yandex.config');
- $viewVariables['addYandexSiteConfigNonce'] = Nonce::getNonce(self::YANDEX_ADD_SITE_CONFIG_NONCE_KEY);
- $viewVariables['removeYandexSiteConfigNonce'] = Nonce::getNonce(self::YANDEX_REMOVE_SITE_CONFIG_NONCE_KEY);
- $viewVariables['removeYandexAccountNonce'] = Nonce::getNonce(self::YANDEX_REMOVE_ACCOUNT_NONCE_KEY);
- $viewVariables['sitesInfos'] = [];
- $viewVariables['currentSite'] = $this->getCurrentSite();
- $viewVariables['currentSite'] = $this->getCurrentSite();
- $viewVariables['countOfAccountsWithAccess'] = $countOfAccountsWithAccess;
-
- $siteIds = $viewVariables['configuredMeasurables'];
-
- foreach ($siteIds as $siteId => $config) {
- $viewVariables['sitesInfos'][$siteId] = Site::getSite($siteId);
- $lastRun = Option::get('YandexImporterTask_LastRun_' . $siteId);
-
- if ($lastRun) {
- $lastRun = date('Y-m-d H:i', $lastRun) . ' UTC';
- } else {
- $lastRun = Piwik::translate('General_Never');
- }
-
- $viewVariables['sitesInfos'][$siteId]['lastRun'] = $lastRun;
-
- $yandexAccountAndHostId = $config['yandexAccountAndHostId'];
- [$accountId, $url] = explode('##', $yandexAccountAndHostId);
-
- try {
- $viewVariables['sitesInfos'][$siteId]['accountValid'] = $yandexClient->testConfiguration($accountId);
- } catch (\Exception $e) {
- $viewVariables['sitesInfos'][$siteId]['accountValid'] = false;
- }
-
- try {
- $urls = $yandexClient->getAvailableUrls($accountId);
- } catch (\Exception $e) {
- $urls = [];
- }
-
- $viewVariables['sitesInfos'][$siteId]['urlValid'] = false;
-
- foreach ($urls as $data) {
- if ($data['host_id'] == $url) {
- $viewVariables['sitesInfos'][$siteId]['urlValid'] = true;
- }
- }
- }
-
- if (!empty($this->securityPolicy)) {
- $this->securityPolicy->addPolicy('img-src', 'avatars.yandex.net');
- }
-
- $viewVariables['baseUrl'] = Url::getCurrentUrlWithoutQueryString();
- $viewVariables['baseDomain'] = Url::getCurrentScheme() . '://' . Url::getCurrentHost();
-
- return $this->renderTemplate('yandex\configuration', $viewVariables);
- }
-
- /**
- * Save Yandex configuration if set in request
- *
- * @return bool|null bool on success or failure, null if not data present in request
- */
- protected function configureYandexClientIfProvided()
- {
- $clientId = Common::getRequestVar('clientid', '');
- $clientSecret = Common::getRequestVar('clientsecret', '');
-
- if (!empty($clientSecret) || !empty($clientId)) {
- Nonce::checkNonce('SEKP.yandex.config', Common::getRequestVar('config_nonce'));
-
- $clientUpdated = false;
-
- if (!empty($clientSecret) && !empty($clientId)) {
- $yandexClient = ProviderYandex::getInstance()->getClient();
- $yandexClient->setClientConfig($clientId, $clientSecret);
- $clientUpdated = true;
- }
-
- return $clientUpdated;
- }
-
- return null;
- }
-
- /**
- * Save yandex configuration for a site if given in request
- */
- protected function addYandexSiteConfigIfProvided()
- {
- $yandexSiteId = Common::getRequestVar('yandexSiteId', '');
- $yandexAccountAndHostId = Common::getRequestVar('yandexAccountAndHostId', '');
-
- if (!empty($yandexSiteId) && !empty($yandexAccountAndHostId)) {
- $request = \Piwik\Request::fromRequest();
- Nonce::checkNonce(self::YANDEX_ADD_SITE_CONFIG_NONCE_KEY, $request->getStringParameter('addSiteConfigNonce', ''));
- $measurableSettings = new MeasurableSettings($yandexSiteId);
- $measurableSettings->yandexConfigCreatedBy->setValue(Piwik::getCurrentUserLogin());
-
- //Need to explicitly setIsWritableByCurrentUser=true, since it can be set as false when we instantiate MeasurableSettings object due to previously added by another user
- $measurableSettings->yandexAccountAndHostId->setIsWritableByCurrentUser(true);
-
- $measurableSettings->yandexAccountAndHostId->setValue($yandexAccountAndHostId);
-
- $measurableSettings->save();
-
- $notification = new Notification(
- Piwik::translate('SearchEngineKeywordsPerformance_WebsiteSuccessfulConfigured', [
- Site::getNameFor($yandexSiteId),
- '',
- ''
- ])
- );
- $notification->context = Notification::CONTEXT_SUCCESS;
- $notification->raw = true;
- $notification->flags = Notification::FLAG_CLEAR;
- Notification\Manager::notify('websiteConfigured', $notification);
- }
- }
-
- /**
- * Removes a Yandex account if `remove` param is given in request
- */
- protected function removeYandexAccountIfProvided()
- {
- $remove = Common::getRequestVar('remove', '');
-
- if (!empty($remove)) {
- $request = \Piwik\Request::fromRequest();
- Nonce::checkNonce(self::YANDEX_REMOVE_ACCOUNT_NONCE_KEY, $request->getStringParameter('removeAccountNonce', ''));
- ProviderYandex::getInstance()->getClient()->removeAccount($remove);
-
- $sitesWithConfig = ProviderYandex::getInstance()->getConfiguredSiteIds();
- foreach ($sitesWithConfig as $siteId => $siteConfig) {
- $yandexSetting = explode('##', $siteConfig['yandexAccountAndHostId']);
- if (!empty($yandexSetting[0]) && $yandexSetting[0] == $remove) {
- $config = new MeasurableSettings($siteId);
- $config->yandexAccountAndHostId->setValue('0');
- $config->save();
- }
- }
- }
- }
-
- /**
- * Removes a Yandex site config if `removeConfig` param is given in request
- */
- protected function removeYandexSiteConfigIfProvided()
- {
- $removeConfig = Common::getRequestVar('removeConfig', '');
-
- if (!empty($removeConfig)) {
- $request = \Piwik\Request::fromRequest();
- Nonce::checkNonce(self::YANDEX_REMOVE_SITE_CONFIG_NONCE_KEY, $request->getStringParameter('removeSiteConfigNonce', ''));
- $measurableSettings = new MeasurableSettings($removeConfig);
- $measurableSettings->yandexAccountAndHostId->setValue('0');
- $measurableSettings->save();
- }
- }
-
-
- public function forwardToYandexAuth()
- {
- Piwik::checkUserHasSomeAdminAccess();
-
- Nonce::checkNonce('SEKP.yandex.auth', Common::getRequestVar('auth_nonce'));
-
- $session = $this->getSession();
- $session->yandexauthtime = time() + 60 * 15;
-
- Url::redirectToUrl(ProviderYandex::getInstance()->getClient()->createAuthUrl());
- }
-
- /**
- * Processes an auth code given by Yandex
- */
- public function processYandexAuthCode()
- {
- Piwik::checkUserHasSomeAdminAccess();
-
- $error = Common::getRequestVar('error', '');
- $oauthCode = Common::getRequestVar('code', '');
- $timeLimit = $this->getSession()->yandexauthtime;
-
- // if the auth wasn't triggered within the allowed time frame
- if (!$timeLimit || time() > $timeLimit) {
- $error = true;
- }
-
- if ($error) {
- return $this->configureYandex(true);
- }
-
- try {
- ProviderYandex::getInstance()->getClient()->processAuthCode($oauthCode);
- } catch (\Exception $e) {
- return $this->configureYandex($e->getMessage());
- }
-
- // we need idSite in the url to display all the menus like Conversion Import after redirect
- $siteInfo = $this->getCurrentSite();
-
- // reload index action to prove everything is configured
- Url::redirectToUrl(Url::getCurrentUrlWithoutQueryString() . Url::getCurrentQueryStringWithParametersModified([
- 'action' => 'configureYandex',
- 'idSite' => (isset($siteInfo['id']) ? $siteInfo['id'] : 0),
- 'code' => null
- ]));
- }
-
- /**
- * Get the map of component extensions to be passed into the Vue template. This allows other plugins to provide
- * content to display in the template. In this case this plugin will display one component, but that can be
- * overridden by the ConnectAccounts plugin to display a somewhat different component. This is doing something
- * similar to what we use {{ postEvent('MyPlugin.MyEventInATemplate) }} for in Twig templates.
- *
- * @return array Map of component extensions. Like [ 'plugin' => 'PluginName', 'component' => 'ComponentName' ]
- * See {@link https://developer.matomo.org/guides/in-depth-vue#allowing-plugins-to-add-content-to-your-vue-components the developer documentation} for more information.
- */
- public static function getComponentExtensions(): array
- {
- $componentExtensions = [];
- Piwik::postEvent('SearchEngineKeywordsPerformance.getGoogleConfigComponentExtensions', [
- &$componentExtensions
- ]);
- return $componentExtensions;
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Diagnostic/BingAccountDiagnostic.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Diagnostic/BingAccountDiagnostic.php
deleted file mode 100644
index 754876a..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Diagnostic/BingAccountDiagnostic.php
+++ /dev/null
@@ -1,74 +0,0 @@
-translator = $translator;
- }
- public function execute()
- {
- $client = ProviderBing::getInstance()->getClient();
- $accounts = $client->getAccounts();
- if (empty($accounts)) {
- return [];
- // skip if no accounts configured
- }
- $errors = ProviderBing::getInstance()->getConfigurationProblems();
- $resultAccounts = new DiagnosticResult(Bing::getInstance()->getName() . ' - ' . $this->translator->translate('SearchEngineKeywordsPerformance_ConfiguredAccounts'));
- foreach ($accounts as $account) {
- if (array_key_exists($account['apiKey'], $errors['accounts'])) {
- $item = new DiagnosticResultItem(DiagnosticResult::STATUS_ERROR, $this->obfuscateApiKey($account['apiKey']) . ': ' . $errors['accounts'][$account['apiKey']]);
- } else {
- $item = new DiagnosticResultItem(DiagnosticResult::STATUS_OK, $this->obfuscateApiKey($account['apiKey']) . ': ' . $this->translator->translate('SearchEngineKeywordsPerformance_BingAccountOk'));
- }
- $resultAccounts->addItem($item);
- }
- $resultMeasurables = new DiagnosticResult(Bing::getInstance()->getName() . ' - ' . $this->translator->translate('SearchEngineKeywordsPerformance_MeasurableConfig'));
- $configuredSiteIds = ProviderBing::getInstance()->getConfiguredSiteIds();
- foreach ($configuredSiteIds as $configuredSiteId => $config) {
- if (array_key_exists($configuredSiteId, $errors['sites'])) {
- $item = new DiagnosticResultItem(DiagnosticResult::STATUS_ERROR, Site::getNameFor($configuredSiteId) . ' (' . Site::getMainUrlFor($configuredSiteId) . ')' . ': ' . $errors['sites'][$configuredSiteId]);
- } else {
- $item = new DiagnosticResultItem(DiagnosticResult::STATUS_OK, Site::getNameFor($configuredSiteId) . ' (' . Site::getMainUrlFor($configuredSiteId) . ')');
- }
- $resultMeasurables->addItem($item);
- }
- return [$resultAccounts, $resultMeasurables];
- }
- protected function obfuscateApiKey($apiKey)
- {
- return substr($apiKey, 0, 5) . '*****' . substr($apiKey, -5, 5);
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Diagnostic/GoogleAccountDiagnostic.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Diagnostic/GoogleAccountDiagnostic.php
deleted file mode 100644
index c7dc492..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Diagnostic/GoogleAccountDiagnostic.php
+++ /dev/null
@@ -1,71 +0,0 @@
-translator = $translator;
- }
- public function execute()
- {
- $client = ProviderGoogle::getInstance()->getClient();
- $accounts = $client->getAccounts();
- if (empty($accounts)) {
- return [];
- // skip if no accounts configured
- }
- $errors = ProviderGoogle::getInstance()->getConfigurationProblems();
- $resultAccounts = new DiagnosticResult(Google::getInstance()->getName() . ' - ' . $this->translator->translate('SearchEngineKeywordsPerformance_ConfiguredAccounts'));
- foreach ($accounts as $id => $account) {
- $userInfo = $client->getUserInfo($id);
- if (array_key_exists($id, $errors['accounts'])) {
- $item = new DiagnosticResultItem(DiagnosticResult::STATUS_ERROR, $userInfo['name'] . ': ' . $errors['accounts'][$id]);
- } else {
- $item = new DiagnosticResultItem(DiagnosticResult::STATUS_OK, $userInfo['name'] . ': ' . $this->translator->translate('SearchEngineKeywordsPerformance_GoogleAccountOk'));
- }
- $resultAccounts->addItem($item);
- }
- $resultMeasurables = new DiagnosticResult(Google::getInstance()->getName() . ' - ' . $this->translator->translate('SearchEngineKeywordsPerformance_MeasurableConfig'));
- $configuredSiteIds = ProviderGoogle::getInstance()->getConfiguredSiteIds();
- foreach ($configuredSiteIds as $configuredSiteId => $config) {
- if (array_key_exists($configuredSiteId, $errors['sites'])) {
- $item = new DiagnosticResultItem(DiagnosticResult::STATUS_ERROR, Site::getNameFor($configuredSiteId) . ' (' . Site::getMainUrlFor($configuredSiteId) . ')' . ': ' . $errors['sites'][$configuredSiteId]);
- } else {
- $item = new DiagnosticResultItem(DiagnosticResult::STATUS_OK, Site::getNameFor($configuredSiteId) . ' (' . Site::getMainUrlFor($configuredSiteId) . ')');
- }
- $resultMeasurables->addItem($item);
- }
- return [$resultAccounts, $resultMeasurables];
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Diagnostic/YandexAccountDiagnostic.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Diagnostic/YandexAccountDiagnostic.php
deleted file mode 100644
index a2a2f60..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Diagnostic/YandexAccountDiagnostic.php
+++ /dev/null
@@ -1,76 +0,0 @@
-translator = $translator;
- }
- public function execute()
- {
- $client = ProviderYandex::getInstance()->getClient();
- $accounts = $client->getAccounts();
- if (empty($accounts)) {
- return [];
- // skip if no accounts configured
- }
- $errors = ProviderYandex::getInstance()->getConfigurationProblems();
- $resultAccounts = new DiagnosticResult(Yandex::getInstance()->getName() . ' - ' . $this->translator->translate('SearchEngineKeywordsPerformance_ConfiguredAccounts'));
- foreach ($accounts as $id => $account) {
- $userInfo = $client->getUserInfo($id);
- $oauthDaysAgo = floor((time() - $account['created']) / (3600 * 24));
- if (array_key_exists($id, $errors['accounts'])) {
- $item = new DiagnosticResultItem(DiagnosticResult::STATUS_ERROR, $userInfo['name'] . ': ' . $errors['accounts'][$id]);
- } else {
- if ($oauthDaysAgo >= 150) {
- $item = new DiagnosticResultItem(DiagnosticResult::STATUS_WARNING, $userInfo['name'] . ': ' . $this->translator->translate('SearchEngineKeywordsPerformance_OAuthAccessWillTimeOutSoon', 180 - $oauthDaysAgo));
- } else {
- $item = new DiagnosticResultItem(DiagnosticResult::STATUS_OK, $userInfo['name'] . ': ' . $this->translator->translate('SearchEngineKeywordsPerformance_YandexAccountOk'));
- }
- }
- $resultAccounts->addItem($item);
- }
- $resultMeasurables = new DiagnosticResult(Yandex::getInstance()->getName() . ' - ' . $this->translator->translate('SearchEngineKeywordsPerformance_MeasurableConfig'));
- $configuredSiteIds = ProviderYandex::getInstance()->getConfiguredSiteIds();
- foreach ($configuredSiteIds as $configuredSiteId => $config) {
- if (array_key_exists($configuredSiteId, $errors['sites'])) {
- $item = new DiagnosticResultItem(DiagnosticResult::STATUS_ERROR, Site::getNameFor($configuredSiteId) . ' (' . Site::getMainUrlFor($configuredSiteId) . ')' . ': ' . $errors['sites'][$configuredSiteId]);
- } else {
- $item = new DiagnosticResultItem(DiagnosticResult::STATUS_OK, Site::getNameFor($configuredSiteId) . ' (' . Site::getMainUrlFor($configuredSiteId) . ')');
- }
- $resultMeasurables->addItem($item);
- }
- return [$resultAccounts, $resultMeasurables];
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Exceptions/InvalidClientConfigException.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Exceptions/InvalidClientConfigException.php
deleted file mode 100644
index 8da8b3e..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Exceptions/InvalidClientConfigException.php
+++ /dev/null
@@ -1,21 +0,0 @@
-idSite = $idSite;
- $this->force = $force;
- $setting = new MeasurableSettings($idSite);
- $searchConsoleUrl = $setting->bingSiteUrl;
- $siteConfig = $searchConsoleUrl->getValue();
- [$this->apiKey, $this->bingSiteUrl] = explode('##', $siteConfig);
- }
- protected static function getRowCountToImport()
- {
- return Config::getInstance()->General['datatable_archiving_maximum_rows_referrers'];
- }
- /**
- * Run importer for all available data
- */
- public function importAllAvailableData()
- {
- $dates = self::importAvailablePeriods($this->apiKey, $this->bingSiteUrl, $this->force);
- if (empty($dates)) {
- return;
- }
- $days = $weeks = $months = $years = [];
- foreach ($dates as $date) {
- $date = Date::factory($date);
- $day = new Day($date);
- $days[$day->toString()] = $day;
- $week = new Week($date);
- $weeks[$week->getRangeString()] = $week;
- $month = new Month($date);
- $months[$month->getRangeString()] = $month;
- $year = new Year($date);
- $years[$year->getRangeString()] = $year;
- }
- $periods = $days + $weeks + $months + $years;
- foreach ($periods as $period) {
- $this->completeExistingArchiveIfAny($period);
- }
- }
- /**
- * Imports available data to model storage if not already done
- *
- * @param string $apiKey API key to use
- * @param string $url url, eg http://matomo.org
- * @return array
- */
- public static function importAvailablePeriods($apiKey, $url, $force = \false)
- {
- if (self::$dataImported && !defined('PIWIK_TEST_MODE')) {
- return [];
- }
- $datesImported = [];
- $logger = StaticContainer::get(LoggerInterface::class);
- $model = new BingModel();
- $logger->debug("[SearchEngineKeywordsPerformance] Fetching Bing keywords for {$url}");
- try {
- $keywordData = StaticContainer::get('Piwik\\Plugins\\SearchEngineKeywordsPerformance\\Client\\Bing')->getSearchAnalyticsData($apiKey, $url);
- foreach ($keywordData as $date => $keywords) {
- $availableKeywords = $model->getKeywordData($url, $date);
- $datesImported[] = $date;
- if (!empty($availableKeywords) && !$force) {
- continue;
- // skip as data was already imported before
- }
- $dataTable = self::getKeywordsAsDataTable($keywords);
- if ($dataTable) {
- $keywordData = $dataTable->getSerialized(self::getRowCountToImport(), null, Metrics::NB_CLICKS);
- $logger->debug("[SearchEngineKeywordsPerformance] Importing Bing keywords for {$url} / {$date}");
- $model->archiveKeywordData($url, $date, $keywordData[0]);
- }
- }
- } catch (InvalidCredentialsException $e) {
- $logger->info('[SearchEngineKeywordsPerformance] Exception while importing Bing keywords for ' . $url . ': ' . $e->getMessage());
- Provider::getInstance()->recordNewApiErrorForProvider();
- } catch (UnknownAPIException $e) {
- $logger->info('[SearchEngineKeywordsPerformance] Exception while importing Bing keywords for ' . $url . ': ' . $e->getMessage());
- Provider::getInstance()->recordNewApiErrorForProvider();
- } catch (RateLimitApiException $e) {
- $logger->info('[SearchEngineKeywordsPerformance] Exception while importing Bing keywords for ' . $url . ' ErrorCode: ' . $e->getCode() . ' ErrorMessage: ' . $e->getMessage());
- } catch (\Exception $e) {
- $logger->error('[SearchEngineKeywordsPerformance] Exception while importing Bing keywords for ' . $url . ': ' . $e->getMessage());
- Provider::getInstance()->recordNewApiErrorForProvider();
- }
- $logger->debug("[SearchEngineKeywordsPerformance] Fetching Bing crawl stats for {$url}");
- try {
- $crawlStatsDataSets = StaticContainer::get('Piwik\\Plugins\\SearchEngineKeywordsPerformance\\Client\\Bing')->getCrawlStats($apiKey, $url);
- foreach ($crawlStatsDataSets as $date => $crawlStats) {
- $availableCrawlStats = $model->getCrawlStatsData($url, $date);
- $datesImported[] = $date;
- if (!empty($availableCrawlStats)) {
- continue;
- // skip as data was already imported before
- }
- $dataTable = self::getCrawlStatsAsDataTable($crawlStats);
- if ($dataTable) {
- $keywordData = $dataTable->getSerialized();
- $logger->debug("[SearchEngineKeywordsPerformance] Importing Bing crawl stats for {$url} / {$date}");
- $model->archiveCrawlStatsData($url, $date, $keywordData[0]);
- }
- }
- } catch (InvalidCredentialsException $e) {
- $logger->info('[SearchEngineKeywordsPerformance] Exception while importing Bing crawl stats for ' . $url . ': ' . $e->getMessage());
- Provider::getInstance()->recordNewApiErrorForProvider();
- } catch (UnknownAPIException $e) {
- $logger->info('[SearchEngineKeywordsPerformance] Exception while importing Bing crawl stats for ' . $url . ': ' . $e->getMessage());
- Provider::getInstance()->recordNewApiErrorForProvider();
- } catch (RateLimitApiException $e) {
- $logger->info('[SearchEngineKeywordsPerformance] Exception while importing Bing keywords for ' . $url . ' ErrorCode: ' . $e->getCode() . ' ErrorMessage: ' . $e->getMessage());
- } catch (\Exception $e) {
- $logger->error('[SearchEngineKeywordsPerformance] Exception while importing Bing crawl stats for ' . $url . ': ' . $e->getMessage());
- Provider::getInstance()->recordNewApiErrorForProvider();
- }
- try {
- $crawlErrorsDataSets = StaticContainer::get('Piwik\\Plugins\\SearchEngineKeywordsPerformance\\Client\\Bing')->getUrlWithCrawlIssues($apiKey, $url);
- $logger->debug("[SearchEngineKeywordsPerformance] Importing Bing crawl issues for {$url}");
- $dataTable = self::getCrawlErrorsAsDataTable($crawlErrorsDataSets);
- if ($dataTable->getRowsCount()) {
- $crawlErrorsData = $dataTable->getSerialized();
- $model->archiveCrawlErrors($url, $crawlErrorsData[0]);
- }
- } catch (InvalidCredentialsException $e) {
- $logger->info('[SearchEngineKeywordsPerformance] Exception while importing Bing crawl issues for ' . $url . ': ' . $e->getMessage());
- Provider::getInstance()->recordNewApiErrorForProvider();
- } catch (UnknownAPIException $e) {
- $logger->info('[SearchEngineKeywordsPerformance] Exception while importing Bing crawl issues for ' . $url . ': ' . $e->getMessage());
- Provider::getInstance()->recordNewApiErrorForProvider();
- } catch (RateLimitApiException $e) {
- $logger->info('[SearchEngineKeywordsPerformance] Exception while importing Bing crawl issues for ' . $url . ' ErrorCode: ' . $e->getCode() . ' ErrorMessage: ' . $e->getMessage());
- } catch (\Exception $e) {
- $logger->error('[SearchEngineKeywordsPerformance] Exception while importing Bing crawl issues for ' . $url . ': ' . $e->getMessage());
- Provider::getInstance()->recordNewApiErrorForProvider();
- }
- $datesImported = array_unique($datesImported);
- sort($datesImported);
- self::$dataImported = \true;
- return $datesImported;
- }
- protected static function getKeywordsAsDataTable($keywords)
- {
- $dataTable = new DataTable();
- foreach ($keywords as $keywordDataSet) {
- $rowData = [
- DataTable\Row::COLUMNS => [
- 'label' => $keywordDataSet['keyword'],
- Metrics::NB_CLICKS => (int) $keywordDataSet['clicks'],
- Metrics::NB_IMPRESSIONS => (int) $keywordDataSet['impressions'],
- Metrics::CTR => (float) round($keywordDataSet['clicks'] / $keywordDataSet['impressions'], 2),
- Metrics::POSITION => (float) $keywordDataSet['position']
- ]
- ];
- $row = new DataTable\Row($rowData);
- $dataTable->addRow($row);
- }
- return $dataTable;
- }
- protected static function getCrawlStatsAsDataTable($crawlStats)
- {
- $dataTable = new DataTable();
- foreach ($crawlStats as $label => $pagesCount) {
- $rowData = [DataTable\Row::COLUMNS => ['label' => $label, Metrics::NB_PAGES => (int) $pagesCount]];
- $row = new DataTable\Row($rowData);
- $dataTable->addRow($row);
- }
- return $dataTable;
- }
- protected static function getCrawlErrorsAsDataTable($crawlErrors)
- {
- $dataTable = new DataTable();
- foreach ($crawlErrors as $crawlError) {
- $rowData = [DataTable\Row::COLUMNS => ['label' => $crawlError['Url'], 'category' => $crawlError['Issues'], 'inLinks' => $crawlError['InLinks'], 'responseCode' => $crawlError['HttpCode']]];
- $row = new DataTable\Row($rowData);
- $dataTable->addRow($row);
- }
- return $dataTable;
- }
- /**
- * Runs the Archiving for SearchEngineKeywordsPerformance plugin if an archive for the given period already exists
- *
- * @param \Piwik\Period $period
- */
- protected function completeExistingArchiveIfAny($period)
- {
- $parameters = new Parameters(new Site($this->idSite), $period, new Segment('', [$this->idSite]));
- $parameters->setRequestedPlugin('SearchEngineKeywordsPerformance');
- $parameters->onlyArchiveRequestedPlugin();
- $result = ArchiveSelector::getArchiveIdAndVisits($parameters, $period->getDateStart()->getDateStartUTC());
- $idArchive = $result[0][0] ?? null;
- if (empty($idArchive)) {
- return;
- // ignore periods that weren't archived before
- }
- $archiveWriter = new ArchiveWriter($parameters);
- $archiveWriter->idArchive = $idArchive;
- $archiveProcessor = new ArchiveProcessor($parameters, $archiveWriter, new LogAggregator($parameters));
- $archiveProcessor->setNumberOfVisits(1, 1);
- $bingRecordBuilder = BingRecordBuilder::make($this->idSite);
- if (empty($bingRecordBuilder)) {
- return;
- }
- if ($period instanceof Day) {
- $bingRecordBuilder->buildFromLogs($archiveProcessor);
- } else {
- $bingRecordBuilder->buildForNonDayPeriod($archiveProcessor);
- }
- $archiveWriter->flushSpools();
- DataTableManager::getInstance()->deleteAll();
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Importer/Google.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Importer/Google.php
deleted file mode 100644
index 613d72f..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Importer/Google.php
+++ /dev/null
@@ -1,361 +0,0 @@
-idSite = $idSite;
- $this->force = $force;
- $setting = new MeasurableSettings($idSite);
- $searchConsoleUrl = $setting->googleSearchConsoleUrl;
- [$this->accountId, $this->searchConsoleUrl] = explode('##', $searchConsoleUrl->getValue());
- }
- protected static function getRowCountToImport()
- {
- return Config::getInstance()->General['datatable_archiving_maximum_rows_referrers'];
- }
- /**
- * Triggers keyword import and plugin archiving for all dates search console has data for
- *
- * @param string|int|null $limitKeywordDates if integer given: limits the amount of imported dates to the last
- * available X if string given: only imports keywords for the given
- * string date
- * @return void
- */
- public function importAllAvailableData($limitKeywordDates = null)
- {
- // if specific date given
- if (is_string($limitKeywordDates) && strlen($limitKeywordDates) == 10) {
- $availableDates = [$limitKeywordDates];
- } else {
- $availableDates = self::getAvailableDates($this->accountId, $this->searchConsoleUrl);
- sort($availableDates);
- if ($limitKeywordDates > 0) {
- $limitKeywordDates += 5;
- // always import 5 days more in the past, to ensure that non final data is imported again.
- $availableDates = array_slice($availableDates, -$limitKeywordDates, $limitKeywordDates);
- }
- }
- $this->importKeywordsForListOfDates($availableDates);
- $this->completeExistingArchivesForListOfDates($availableDates);
- }
- protected function importKeywordsForListOfDates($datesToImport)
- {
- foreach ($datesToImport as $date) {
- foreach (self::$typesToImport as $type) {
- $this->importKeywordsIfNecessary($this->accountId, $this->searchConsoleUrl, $date, $type, $this->force);
- }
- }
- }
- protected function completeExistingArchivesForListOfDates($datesToComplete)
- {
- $days = $weeks = $months = $years = [];
- sort($datesToComplete);
- foreach ($datesToComplete as $date) {
- $date = Date::factory($date);
- $day = new Day($date);
- $days[$day->toString()] = $day;
- $week = new Week($date);
- $weeks[$week->getRangeString()] = $week;
- $month = new Month($date);
- $months[$month->getRangeString()] = $month;
- $year = new Year($date);
- $years[$year->getRangeString()] = $year;
- }
- $periods = $days + $weeks + $months + $years;
- foreach ($periods as $period) {
- $this->completeExistingArchiveIfAny($period);
- }
- }
- /**
- * Imports keyword to model storage if not already done
- *
- * @param string $accountId google account id
- * @param string $url url, eg http://matomo.org
- * @param string $date date string, eg 2016-12-24
- * @param string $type 'web', 'image', 'video' or 'news'
- * @param bool $force force reimport
- * @return boolean
- */
- public function importKeywordsIfNecessary($accountId, $url, $date, $type, $force = \false)
- {
- $model = new GoogleModel();
- $logger = StaticContainer::get(LoggerInterface::class);
- $keywordData = $model->getKeywordData($url, $date, $type);
- // check if available data is temporary and force a reimport in that case
- if ($keywordData) {
- $dataTable = new DataTable();
- $dataTable->addRowsFromSerializedArray($keywordData);
- $isTemporary = $dataTable->getMetadata(self::DATATABLE_METADATA_TEMPORARY);
- if ($isTemporary === \true) {
- $logger->info('[SearchEngineKeywordsPerformance] Forcing reimport Google keywords for ' . $url . ' as imported data was not final.');
- $force = \true;
- }
- }
- if ($keywordData && !$force) {
- $logger->info('[SearchEngineKeywordsPerformance] Skipping import of Google keywords for ' . $date . ' and ' . $url . ' as data already imported.');
- return \false;
- // skip if data already available and no reimport forced
- }
- $dataTable = $this->getKeywordsFromConsoleAsDataTable($accountId, $url, $date, $type);
- if ($dataTable) {
- $keywordData = $dataTable->getSerialized(self::getRowCountToImport(), null, Metrics::NB_CLICKS);
- $model->archiveKeywordData($url, $date, $type, $keywordData[0]);
- return \true;
- }
- return \false;
- }
- protected static function getAvailableDates($accountId, $url)
- {
- $logger = StaticContainer::get(LoggerInterface::class);
- try {
- if (!array_key_exists($accountId . $url, self::$availableDates) || defined('PIWIK_TEST_MODE')) {
- $finalDates = StaticContainer::get('Piwik\\Plugins\\SearchEngineKeywordsPerformance\\Client\\Google')->getDatesWithSearchAnalyticsData($accountId, $url);
- self::$availableDates[$accountId . $url] = StaticContainer::get('Piwik\\Plugins\\SearchEngineKeywordsPerformance\\Client\\Google')->getDatesWithSearchAnalyticsData($accountId, $url, \false);
- self::$availableDatesNonFinal[$accountId . $url] = array_diff(self::$availableDates[$accountId . $url], $finalDates);
- }
- } catch (InvalidCredentialsException $e) {
- $logger->info('[SearchEngineKeywordsPerformance] Exception while importing Google keywords for ' . $url . ': ' . $e->getMessage());
- Provider::getInstance()->recordNewApiErrorForProvider();
- return [];
- } catch (InvalidClientConfigException $e) {
- $logger->info('[SearchEngineKeywordsPerformance] Exception while importing Google keywords for ' . $url . ': ' . $e->getMessage());
- Provider::getInstance()->recordNewApiErrorForProvider();
- return [];
- } catch (MissingOAuthConfigException $e) {
- $logger->info('[SearchEngineKeywordsPerformance] Exception while importing Google keywords for ' . $url . ': ' . $e->getMessage());
- Provider::getInstance()->recordNewApiErrorForProvider();
- return [];
- } catch (MissingClientConfigException $e) {
- $logger->info('[SearchEngineKeywordsPerformance] Exception while importing Google keywords for ' . $url . ': ' . $e->getMessage());
- Provider::getInstance()->recordNewApiErrorForProvider();
- return [];
- } catch (UnknownAPIException $e) {
- $logger->info('[SearchEngineKeywordsPerformance] Exception while importing Google keywords for ' . $url . ': ' . $e->getMessage());
- Provider::getInstance()->recordNewApiErrorForProvider();
- return [];
- } catch (\Exception $e) {
- $logger->error('[SearchEngineKeywordsPerformance] Exception while importing Google keywords for ' . $url . ': ' . $e->getMessage());
- Provider::getInstance()->recordNewApiErrorForProvider();
- return [];
- }
- if (array_key_exists($accountId . $url, self::$availableDates)) {
- return self::$availableDates[$accountId . $url];
- }
- return [];
- }
- private static function isFinalDate($accountId, $url, $date)
- {
- if (array_key_exists($accountId . $url, self::$availableDatesNonFinal)) {
- return !in_array($date, self::$availableDatesNonFinal[$accountId . $url]);
- }
- return \true;
- }
- /**
- * Fetches data from google search console and migrates it to a Matomo Datatable
- *
- * @param string $accountId google account id
- * @param string $url url, eg http://matomo.org
- * @param string $date date string, eg 2016-12-24
- * @param string $type 'web', 'image', 'video' or 'news'
- * @return null|DataTable
- */
- protected function getKeywordsFromConsoleAsDataTable($accountId, $url, $date, $type)
- {
- $dataTable = new DataTable();
- $logger = StaticContainer::get(LoggerInterface::class);
- try {
- if (!defined('PIWIK_TEST_MODE') && !$this->isImportAllowedForDate($date)) {
- $logger->debug("[SearchEngineKeywordsPerformance] Skip fetching keywords from Search Console for today and dates more than 500 days in the past: " . $date);
- return null;
- }
- $availableDates = self::getAvailableDates($accountId, $url);
- if (!in_array($date, $availableDates)) {
- $logger->debug("[SearchEngineKeywordsPerformance] No {$type} keywords available for {$date} and {$url}");
- return null;
- }
- $logger->debug("[SearchEngineKeywordsPerformance] Fetching {$type} keywords for {$date} and {$url}");
- $keywordData = StaticContainer::get('Piwik\\Plugins\\SearchEngineKeywordsPerformance\\Client\\Google')->getSearchAnalyticsData($accountId, $url, $date, $type, self::getRowCountToImport());
- } catch (InvalidCredentialsException $e) {
- $logger->info('[SearchEngineKeywordsPerformance] Exception while importing Google keywords for ' . $url . ': ' . $e->getMessage());
- Provider::getInstance()->recordNewApiErrorForProvider();
- return null;
- } catch (InvalidClientConfigException $e) {
- $logger->info('[SearchEngineKeywordsPerformance] Exception while importing Google keywords for ' . $url . ': ' . $e->getMessage());
- Provider::getInstance()->recordNewApiErrorForProvider();
- return null;
- } catch (MissingOAuthConfigException $e) {
- $logger->info('[SearchEngineKeywordsPerformance] Exception while importing Google keywords for ' . $url . ': ' . $e->getMessage());
- Provider::getInstance()->recordNewApiErrorForProvider();
- return null;
- } catch (MissingClientConfigException $e) {
- $logger->info('[SearchEngineKeywordsPerformance] Exception while importing Google keywords for ' . $url . ': ' . $e->getMessage());
- Provider::getInstance()->recordNewApiErrorForProvider();
- return null;
- } catch (UnknownAPIException $e) {
- $logger->info('[SearchEngineKeywordsPerformance] Exception while importing Google keywords for ' . $url . ': ' . $e->getMessage());
- Provider::getInstance()->recordNewApiErrorForProvider();
- return null;
- } catch (\Exception $e) {
- $logger->error('[SearchEngineKeywordsPerformance] Exception while importing Google keywords for ' . $url . ': ' . $e->getMessage());
- Provider::getInstance()->recordNewApiErrorForProvider();
- return null;
- }
- if (!self::isFinalDate($accountId, $url, $date)) {
- $dataTable->setMetadata(self::DATATABLE_METADATA_TEMPORARY, \true);
- }
- if (empty($keywordData) || !($rows = $keywordData->getRows())) {
- return $dataTable;
- // return empty table so it will be stored
- }
- foreach ($rows as $keywordDataSet) {
- /** @var \Google\Service\SearchConsole\ApiDataRow $keywordDataSet */
- $keys = $keywordDataSet->getKeys();
- $rowData = [
- DataTable\Row::COLUMNS => [
- 'label' => reset($keys),
- Metrics::NB_CLICKS => (int) $keywordDataSet->getClicks(),
- Metrics::NB_IMPRESSIONS => (int) $keywordDataSet->getImpressions(),
- Metrics::CTR => (float) $keywordDataSet->getCtr(),
- Metrics::POSITION => (float) $keywordDataSet->getPosition()
- ]
- ];
- $row = new DataTable\Row($rowData);
- $dataTable->addRow($row);
- }
- unset($keywordData);
- return $dataTable;
- }
- protected function isImportAllowedForDate($date): bool
- {
- $site = new Site($this->idSite);
- $siteCreationDate = $site->getCreationDate()->subDay(30);
- $earliestDate = Date::now()->subDay(500);
- $earliestImportDate = $siteCreationDate->isEarlier($earliestDate) ? $earliestDate : $siteCreationDate;
- $archivedDate = Date::factory($date);
- if ($archivedDate->isEarlier($earliestImportDate) || $archivedDate->isToday()) {
- return \false;
- }
- return \true;
- }
- /**
- * Runs the Archiving for SearchEngineKeywordsPerformance plugin if an archive for the given period already exists
- *
- * @param \Piwik\Period $period
- */
- protected function completeExistingArchiveIfAny($period)
- {
- $parameters = new Parameters(new Site($this->idSite), $period, new Segment('', [$this->idSite]));
- $parameters->setRequestedPlugin('SearchEngineKeywordsPerformance');
- $parameters->onlyArchiveRequestedPlugin();
- $result = ArchiveSelector::getArchiveIdAndVisits($parameters, $period->getDateStart()->getDateStartUTC());
- $idArchive = $result[0][0] ?? null;
- if (empty($idArchive)) {
- return;
- // ignore periods that weren't archived before
- }
- $archiveWriter = new ArchiveWriter($parameters);
- $archiveWriter->idArchive = $idArchive;
- $archiveProcessor = new ArchiveProcessor($parameters, $archiveWriter, new LogAggregator($parameters));
- $archiveProcessor->setNumberOfVisits(1, 1);
- /** @var GoogleRecordBuilder[] $recordBuilders */
- $recordBuilders = GoogleRecordBuilder::makeAll($this->idSite);
- if (empty($recordBuilders)) {
- return;
- }
- foreach ($recordBuilders as $builder) {
- if ($period instanceof Day) {
- $builder->buildFromLogs($archiveProcessor);
- } else {
- $builder->buildForNonDayPeriod($archiveProcessor);
- }
- }
- $archiveWriter->flushSpools();
- DataTableManager::getInstance()->deleteAll();
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Importer/Yandex.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Importer/Yandex.php
deleted file mode 100644
index b2ee231..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Importer/Yandex.php
+++ /dev/null
@@ -1,292 +0,0 @@
-idSite = $idSite;
- $this->force = $force;
- $setting = new MeasurableSettings($idSite);
- $yandexConfig = $setting->yandexAccountAndHostId;
- $siteConfig = $yandexConfig->getValue();
- [$this->accountId, $this->yandexHostId] = explode('##', $siteConfig);
- }
- protected static function getRowCountToImport()
- {
- return Config::getInstance()->General['datatable_archiving_maximum_rows_referrers'];
- }
- /**
- * Run importer for all available data
- */
- public function importAllAvailableData($limitDays = 100)
- {
- if (is_string($limitDays) && strlen($limitDays) == 10) {
- $dates = [$limitDays];
- } else {
- for ($i = 0; $i <= $limitDays; $i++) {
- $dates[] = date('Y-m-d', strtotime("-{$i} days"));
- }
- }
- foreach ($dates as $date) {
- self::importAvailableDataForDate($this->accountId, $this->yandexHostId, $date, $this->force);
- }
- if (empty($dates)) {
- return;
- }
- $this->completeExistingArchivesForListOfDates($dates);
- }
- protected function completeExistingArchivesForListOfDates($datesToComplete)
- {
- $days = $weeks = $months = $years = [];
- sort($datesToComplete);
- foreach ($datesToComplete as $date) {
- $date = Date::factory($date);
- $day = new Day($date);
- $days[$day->toString()] = $day;
- $week = new Week($date);
- $weeks[$week->getRangeString()] = $week;
- $month = new Month($date);
- $months[$month->getRangeString()] = $month;
- $year = new Year($date);
- $years[$year->getRangeString()] = $year;
- }
- $periods = $days + $weeks + $months + $years;
- foreach ($periods as $period) {
- $this->completeExistingArchiveIfAny($period);
- }
- }
- /**
- * Imports available data to model storage if not already done
- *
- * @param string $accountId Id oc account to use
- * @param string $hostId url, eg https:piwik.org:443
- * @param string $date date, eg 2019-05-20
- * @return array
- */
- public static function importAvailableDataForDate($accountId, $hostId, $date, $force = \false)
- {
- $datesImported = [];
- $timestamp = strtotime($date);
- if ($timestamp > time()) {
- return [];
- // no import for dates in the future
- }
- $logger = StaticContainer::get(LoggerInterface::class);
- if ($timestamp > time() - self::MAX_DAYS_KEYWORD_DATA_DELAY * 24 * 3600) {
- $force = \true;
- // always reimport the last few days
- }
- $model = new YandexModel();
- try {
- $availableKeywordsDataTable = new DataTable();
- $availableKeywords = $model->getKeywordData($hostId, $date);
- if (!empty($availableKeywords)) {
- $availableKeywordsDataTable->addRowsFromSerializedArray($availableKeywords);
- }
- // Only assume keywords were imported if there are actually some rows available, otherwise try to import them (again)
- if ($availableKeywordsDataTable->getRowsCountWithoutSummaryRow() > 0 && !$force) {
- $logger->debug("[SearchEngineKeywordsPerformance] Yandex keywords already imported for {$hostId} and date {$date}");
- } else {
- $logger->debug("[SearchEngineKeywordsPerformance] Fetching Yandex keywords for {$hostId} and date {$date}");
- $keywords = StaticContainer::get('Piwik\\Plugins\\SearchEngineKeywordsPerformance\\Client\\Yandex')->getSearchAnalyticsData($accountId, $hostId, $date);
- $datesImported[] = $date;
- $dataTable = self::getKeywordsAsDataTable($keywords);
- // do not store empty results for the last days
- if ($dataTable && ($dataTable->getRowsCountWithoutSummaryRow() > 0 || $timestamp < time() - self::MAX_DAYS_KEYWORD_DATA_DELAY * 24 * 3600)) {
- $keywordData = $dataTable->getSerialized(self::getRowCountToImport(), null, Metrics::NB_CLICKS);
- $logger->debug("[SearchEngineKeywordsPerformance] Importing Yandex keywords for {$hostId} / {$date}");
- $model->archiveKeywordData($hostId, $date, $keywordData[0]);
- }
- }
- } catch (InvalidCredentialsException $e) {
- $logger->info('[SearchEngineKeywordsPerformance] Exception while importing Yandex keywords for ' . $hostId . ': ' . $e->getMessage());
- Provider::getInstance()->recordNewApiErrorForProvider();
- } catch (RateLimitApiException $e) {
- $logger->info('[SearchEngineKeywordsPerformance] Exception while importing Yandex keywords for ' . $hostId . ': ' . $e->getMessage());
- } catch (\Exception $e) {
- $logger->error('[SearchEngineKeywordsPerformance] Exception while importing Yandex keywords for ' . $hostId . ': ' . $e->getMessage());
- Provider::getInstance()->recordNewApiErrorForProvider();
- }
- try {
- $availableCrawlStats = $model->getCrawlStatsData($hostId, $date);
- if (!empty($availableCrawlStats) && !$force) {
- $logger->debug("[SearchEngineKeywordsPerformance] Yandex crawl stats already imported for {$hostId} and date {$date}");
- } else {
- $logger->debug("[SearchEngineKeywordsPerformance] Fetching Yandex crawl stats for {$hostId} and date {$date}");
- $crawlStats = StaticContainer::get('Piwik\\Plugins\\SearchEngineKeywordsPerformance\\Client\\Yandex')->getCrawlStats($accountId, $hostId, $date);
- $datesImported[] = $date;
- $dataTable = self::getCrawlStatsAsDataTable($crawlStats);
- if ($dataTable) {
- $keywordData = $dataTable->getSerialized();
- $logger->debug("[SearchEngineKeywordsPerformance] Importing Yandex crawl stats for {$hostId} and date {$date}");
- $model->archiveCrawlStatsData($hostId, $date, $keywordData[0]);
- }
- }
- } catch (InvalidCredentialsException $e) {
- $logger->info('[SearchEngineKeywordsPerformance] Exception while importing Yandex crawl stats for ' . $hostId . ': ' . $e->getMessage());
- Provider::getInstance()->recordNewApiErrorForProvider();
- } catch (RateLimitApiException $e) {
- $logger->info('[SearchEngineKeywordsPerformance] Exception while importing Yandex crawl stats for ' . $hostId . ': ' . $e->getMessage());
- } catch (\Exception $e) {
- // ignore empty server reply as they seem temporary only
- if (strpos($e->getMessage(), 'Empty reply from server')) {
- $logger->info('[SearchEngineKeywordsPerformance] Exception while importing Yandex crawl stats for ' . $hostId . ': ' . $e->getMessage());
- } else {
- $logger->error('[SearchEngineKeywordsPerformance] Exception while importing Yandex crawl stats for ' . $hostId . ': ' . $e->getMessage());
- }
- Provider::getInstance()->recordNewApiErrorForProvider();
- }
- $datesImported = array_unique($datesImported);
- sort($datesImported);
- return $datesImported;
- }
- protected static function getKeywordsAsDataTable($keywords)
- {
- $dataTable = new DataTable();
- if (empty($keywords)) {
- return $dataTable;
- }
- foreach ($keywords as $keywordDataSet) {
- // If the keyword is empty, that will cause an error if we try to add the row. Skip and move on to the next.
- if (empty($keywordDataSet['keyword'])) {
- continue;
- }
- $rowData = [
- DataTable\Row::COLUMNS => [
- 'label' => $keywordDataSet['keyword'],
- Metrics::NB_CLICKS => (int) $keywordDataSet['clicks'],
- Metrics::NB_IMPRESSIONS => (int) $keywordDataSet['impressions'],
- Metrics::CTR => (float) round($keywordDataSet['clicks'] / $keywordDataSet['impressions'], 2),
- Metrics::POSITION => (float) $keywordDataSet['position']
- ]
- ];
- $row = new DataTable\Row($rowData);
- $dataTable->addRow($row);
- }
- return $dataTable;
- }
- protected static function getCrawlStatsAsDataTable($crawlStats)
- {
- $dataTable = new DataTable();
- if (empty($crawlStats) || !is_array($crawlStats)) {
- return $dataTable;
- }
- foreach ($crawlStats as $label => $pagesCount) {
- if (empty($label)) {
- continue;
- }
- $rowData = [DataTable\Row::COLUMNS => ['label' => $label, Metrics::NB_PAGES => (int) $pagesCount]];
- $row = new DataTable\Row($rowData);
- $dataTable->addRow($row);
- }
- return $dataTable;
- }
- /**
- * Runs the Archiving for SearchEngineKeywordsPerformance plugin if an archive for the given period already exists
- *
- * @param \Piwik\Period $period
- */
- protected function completeExistingArchiveIfAny($period)
- {
- $parameters = new Parameters(new Site($this->idSite), $period, new Segment('', [$this->idSite]));
- $parameters->setRequestedPlugin('SearchEngineKeywordsPerformance');
- $parameters->onlyArchiveRequestedPlugin();
- $result = ArchiveSelector::getArchiveIdAndVisits($parameters, $period->getDateStart()->getDateStartUTC());
- $idArchive = $result[0][0] ?? null;
- if (empty($idArchive)) {
- return;
- // ignore periods that weren't archived before
- }
- $archiveWriter = new ArchiveWriter($parameters);
- $archiveWriter->idArchive = $idArchive;
- $archiveProcessor = new ArchiveProcessor($parameters, $archiveWriter, new LogAggregator($parameters));
- $archiveProcessor->setNumberOfVisits(1, 1);
- $builder = YandexRecordBuilder::make($this->idSite);
- if (empty($builder)) {
- return;
- }
- if ($period instanceof Day) {
- $builder->buildFromLogs($archiveProcessor);
- } else {
- $builder->buildForNonDayPeriod($archiveProcessor);
- }
- $archiveWriter->flushSpools();
- DataTableManager::getInstance()->deleteAll();
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/LICENSE b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/LICENSE
deleted file mode 100644
index 4686f35..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/LICENSE
+++ /dev/null
@@ -1,49 +0,0 @@
-InnoCraft License
-
-This InnoCraft End User License Agreement (the "InnoCraft EULA") is between you and InnoCraft Ltd (NZBN 6106769) ("InnoCraft"). If you are agreeing to this Agreement not as an individual but on behalf of your company, then "Customer" or "you" means your company, and you are binding your company to this Agreement. InnoCraft may modify this Agreement from time to time, subject to the terms in Section (xii) below.
-
-By clicking on the "I’ve read and accept the terms & conditions (https://shop.matomo.org/terms-conditions/)" (or similar button) that is presented to you at the time of your Order, or by using or accessing InnoCraft products, you indicate your assent to be bound by this Agreement.
-
-
-InnoCraft EULA
-
-(i) InnoCraft is the licensor of the Plugin for Matomo Analytics (the "Software").
-
-(ii) Subject to the terms and conditions of this Agreement, InnoCraft grants you a limited, worldwide, non-exclusive, non-transferable and non-sublicensable license to install and use the Software only on hardware systems owned, leased or controlled by you, during the applicable License Term. The term of each Software license ("License Term") will be specified in your Order. Your License Term will end upon any breach of this Agreement.
-
-(iii) Unless otherwise specified in your Order, for each Software license that you purchase, you may install one production instance of the Software in a Matomo Analytics instance owned or operated by you, and accessible via one URL ("Matomo instance"). Additional licenses must be purchased in order to deploy the Software in multiple Matomo instances, including when these multiple Matomo instances are hosted on a single hardware system.
-
-(iv) Licenses granted by InnoCraft are granted subject to the condition that you must ensure the maximum number of Authorized Users and Authorized Sites that are able to access and use the Software is equal to the number of User and Site Licenses for which the necessary fees have been paid to InnoCraft for the Subscription period. You may upgrade your license at any time on payment of the appropriate fees to InnoCraft in order to increase the maximum number of authorized users or sites. The number of User and Site Licenses granted to you is dependent on the fees paid by you. “User License” means a license granted under this EULA to you to permit an Authorized User to use the Software. “Authorized User” means a person who has an account in the Matomo instance and for which the necessary fees (“Subscription fees”) have been paid to InnoCraft for the current license term. "Site License" means a license granted under this EULA to you to permit an Authorized Site to use the Matomo Marketplace Plugin. “Authorized Sites” means a website or a measurable within Matomo instance and for which the necessary fees (“Subscription fees”) have been paid to InnoCraft for the current license term. These restrictions also apply if you install the Matomo Analytics Platform as part of your WordPress.
-
-(v) Piwik Analytics was renamed to Matomo Analytics in January 2018. The same terms and conditions as well as any restrictions or grants apply if you are using any version of Piwik.
-
-(vi) The Software requires a license key in order to operate, which will be delivered to the email addresses specified in your Order when we have received payment of the applicable fees.
-
-(vii) Any information that InnoCraft may collect from you or your device will be subject to InnoCraft Privacy Policy (https://www.innocraft.com/privacy).
-
-(viii) You are bound by the Matomo Marketplace Terms and Conditions (https://shop.matomo.org/terms-conditions/).
-
-(ix) You may not reverse engineer or disassemble or re-distribute the Software in whole or in part, or create any derivative works from or sublicense any rights in the Software, unless otherwise expressly authorized in writing by InnoCraft.
-
-(x) The Software is protected by copyright and other intellectual property laws and treaties. InnoCraft own all title, copyright and other intellectual property rights in the Software, and the Software is licensed to you directly by InnoCraft, not sold.
-
-(xi) The Software is provided under an "as is" basis and without any support or maintenance. Nothing in this Agreement shall require InnoCraft to provide you with support or fixes to any bug, failure, mis-performance or other defect in The Software. InnoCraft may provide you, from time to time, according to his sole discretion, with updates of the Software. You hereby warrant to keep the Software up-to-date and install all relevant updates. InnoCraft shall provide any update free of charge.
-
-(xii) The Software is provided "as is", and InnoCraft hereby disclaim all warranties, including but not limited to any implied warranties of title, non-infringement, merchantability or fitness for a particular purpose. InnoCraft shall not be liable or responsible in any way for any losses or damage of any kind, including lost profits or other indirect or consequential damages, relating to your use of or reliance upon the Software.
-
-(xiii) We may update or modify this Agreement from time to time, including the referenced Privacy Policy and the Matomo Marketplace Terms and Conditions. If a revision meaningfully reduces your rights, we will use reasonable efforts to notify you (by, for example, sending an email to the billing or technical contact you designate in the applicable Order). If we modify the Agreement during your License Term or Subscription Term, the modified version will be effective upon your next renewal of a License Term.
-
-
-About InnoCraft Ltd
-
-At InnoCraft Ltd, we create innovating quality products to grow your business and to maximize your success.
-
-Our software products are built on top of Matomo Analytics: the leading open digital analytics platform used by more than one million websites worldwide. We are the creators and makers of the Matomo Analytics platform.
-
-
-Contact
-
-Email: contact@innocraft.com
-Contact form: https://www.innocraft.com/#contact
-Website: https://www.innocraft.com/
-Buy our products: Premium Features for Matomo Analytics https://plugins.matomo.org/premium
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/MeasurableSettings.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/MeasurableSettings.php
deleted file mode 100644
index 2172fc8..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/MeasurableSettings.php
+++ /dev/null
@@ -1,182 +0,0 @@
-configureGoogleSettings();
- $this->configureBingSettings();
- $this->configureYandexSettings();
- }
- /**
- * Configures Settings used for Google Search Console Import
- */
- protected function configureGoogleSettings()
- {
- $googleClient = ProviderGoogle::getInstance()->getClient();
- // check if google search console is configured and available for website type
- if (!\Piwik\Plugins\SearchEngineKeywordsPerformance\SearchEngineKeywordsPerformance::isGoogleForceEnabled($this->idSite) && (!$this->hasMeasurableType(WebsiteMeasurableType::ID) || !$googleClient->isConfigured())) {
- return;
- }
- $this->googleConfigCreatedBy = $this->makeSetting('googleconfigcreatedby', '', FieldConfig::TYPE_STRING, function (FieldConfig $field) {
- $field->uiControl = FieldConfig::UI_CONTROL_HIDDEN;
- });
- $this->googleSearchConsoleUrl = $this->makeSetting('searchconsoleurl', '0', FieldConfig::TYPE_STRING, function (FieldConfig $field) use ($googleClient) {
- $field->title = Piwik::translate('SearchEngineKeywordsPerformance_GoogleSearchConsoleUrl');
- $field->description = Piwik::translate('SearchEngineKeywordsPerformance_GoogleSearchConsoleUrlDescription');
- $field->uiControl = FieldConfig::UI_CONTROL_SINGLE_SELECT;
- $field->availableValues = ['0' => Piwik::translate('SearchEngineKeywordsPerformance_NotAvailable')];
- foreach ($googleClient->getAccounts() as $id => $account) {
- if (Piwik::hasUserSuperUserAccessOrIsTheUser($account['username'])) {
- $availableSites = $googleClient->getAvailableUrls($id);
- foreach ($availableSites as $url => $accessLevel) {
- $value = $id . '##' . $url;
- $field->availableValues[$value] = $url;
- }
- }
- }
- });
- $this->googleWebKeywords = $this->makeSetting('googlewebkeywords', \true, FieldConfig::TYPE_BOOL, function (FieldConfig $field) {
- $field->title = Piwik::translate('SearchEngineKeywordsPerformance_FetchWebKeyword');
- $field->description = Piwik::translate('SearchEngineKeywordsPerformance_FetchWebKeywordDesc');
- $field->uiControl = FieldConfig::UI_CONTROL_CHECKBOX;
- $field->condition = 'searchconsoleurl';
- });
- $this->googleImageKeywords = $this->makeSetting('googleimagekeywords', \false, FieldConfig::TYPE_BOOL, function (FieldConfig $field) {
- $field->title = Piwik::translate('SearchEngineKeywordsPerformance_FetchImageKeyword');
- $field->description = Piwik::translate('SearchEngineKeywordsPerformance_FetchImageKeywordDesc');
- $field->uiControl = FieldConfig::UI_CONTROL_CHECKBOX;
- $field->condition = 'searchconsoleurl && searchconsoleurl.indexOf(\'android-app\') == -1';
- });
- $this->googleVideoKeywords = $this->makeSetting('googlevideokeywords', \false, FieldConfig::TYPE_BOOL, function (FieldConfig $field) {
- $field->title = Piwik::translate('SearchEngineKeywordsPerformance_FetchVideoKeyword');
- $field->description = Piwik::translate('SearchEngineKeywordsPerformance_FetchVideoKeywordDesc');
- $field->uiControl = FieldConfig::UI_CONTROL_CHECKBOX;
- $field->condition = 'searchconsoleurl && searchconsoleurl.indexOf(\'android-app\') == -1';
- });
- $this->googleNewsKeywords = $this->makeSetting('googlenewskeywords', \false, FieldConfig::TYPE_BOOL, function (FieldConfig $field) {
- $field->title = Piwik::translate('SearchEngineKeywordsPerformance_FetchNewsKeyword');
- $field->description = Piwik::translate('SearchEngineKeywordsPerformance_FetchNewsKeywordDesc');
- $field->uiControl = FieldConfig::UI_CONTROL_CHECKBOX;
- $field->condition = 'searchconsoleurl && searchconsoleurl.indexOf(\'android-app\') == -1';
- });
- $createdByUser = $this->googleConfigCreatedBy->getValue();
- if (!empty($createdByUser) && !Piwik::hasUserSuperUserAccessOrIsTheUser($createdByUser)) {
- $this->googleSearchConsoleUrl->setIsWritableByCurrentUser(\false);
- $this->googleWebKeywords->setIsWritableByCurrentUser(\false);
- $this->googleImageKeywords->setIsWritableByCurrentUser(\false);
- $this->googleVideoKeywords->setIsWritableByCurrentUser(\false);
- $this->googleNewsKeywords->setIsWritableByCurrentUser(\false);
- }
- }
- /**
- * Configures Settings used for Bing Webmaster API Import
- */
- protected function configureBingSettings()
- {
- $bingClient = ProviderBing::getInstance()->getClient();
- // check if Bing Webmaster API is configured and available for website type
- if (!\Piwik\Plugins\SearchEngineKeywordsPerformance\SearchEngineKeywordsPerformance::isBingForceEnabled($this->idSite) && (!$this->hasMeasurableType(WebsiteMeasurableType::ID) || !$bingClient->isConfigured())) {
- return;
- }
- $this->bingConfigCreatedBy = $this->makeSetting('bingconfigcreatedby', '', FieldConfig::TYPE_STRING, function (FieldConfig $field) {
- $field->uiControl = FieldConfig::UI_CONTROL_HIDDEN;
- });
- $this->bingSiteUrl = $this->makeSetting('bingsiteurl', '0', FieldConfig::TYPE_STRING, function (FieldConfig $field) use ($bingClient) {
- $field->title = Piwik::translate('SearchEngineKeywordsPerformance_BingWebmasterApiUrl');
- $field->description = Piwik::translate('SearchEngineKeywordsPerformance_BingWebmasterApiUrlDescription');
- $field->uiControl = FieldConfig::UI_CONTROL_SINGLE_SELECT;
- $field->availableValues = ['0' => Piwik::translate('SearchEngineKeywordsPerformance_NotAvailable')];
- foreach ($bingClient->getAccounts() as $account) {
- if (Piwik::hasUserSuperUserAccessOrIsTheUser($account['username'])) {
- $availableSites = $bingClient->getAvailableUrls($account['apiKey']);
- foreach ($availableSites as $url => $isVerified) {
- $value = $account['apiKey'] . '##' . $url;
- $field->availableValues[$value] = $url;
- }
- }
- }
- });
- $createdByUser = $this->bingConfigCreatedBy->getValue();
- if (!empty($createdByUser) && !Piwik::hasUserSuperUserAccessOrIsTheUser($createdByUser)) {
- $this->bingSiteUrl->setIsWritableByCurrentUser(\false);
- }
- }
- /**
- * Configures Settings used for Yandex Webmaster API Import
- */
- protected function configureYandexSettings()
- {
- $yandexClient = ProviderYandex::getInstance()->getClient();
- // check if Yandex Webmaster API is configured and available for website type
- if (!$this->hasMeasurableType(WebsiteMeasurableType::ID) || !$yandexClient->isConfigured()) {
- return;
- }
- $this->yandexConfigCreatedBy = $this->makeSetting('yandexconfigcreatedby', '', FieldConfig::TYPE_STRING, function (FieldConfig $field) {
- $field->uiControl = FieldConfig::UI_CONTROL_HIDDEN;
- });
- $this->yandexAccountAndHostId = $this->makeSetting('yandexAccountAndHostId', '0', FieldConfig::TYPE_STRING, function (FieldConfig $field) use ($yandexClient) {
- $field->title = Piwik::translate('SearchEngineKeywordsPerformance_YandexWebmasterApiUrl');
- $field->description = Piwik::translate('SearchEngineKeywordsPerformance_YandexWebmasterApiUrlDescription');
- $field->uiControl = FieldConfig::UI_CONTROL_SINGLE_SELECT;
- $field->availableValues = ['0' => Piwik::translate('SearchEngineKeywordsPerformance_NotAvailable')];
- foreach ($yandexClient->getAccounts() as $id => $account) {
- if (Piwik::hasUserSuperUserAccessOrIsTheUser($account['username'])) {
- $availableSites = $yandexClient->getAvailableUrls($id);
- foreach ($availableSites as $url => $hostData) {
- $value = $id . '##' . $hostData['host_id'];
- $field->availableValues[$value] = $url;
- }
- }
- }
- });
- $createdByUser = $this->yandexConfigCreatedBy->getValue();
- if (!empty($createdByUser) && !Piwik::hasUserSuperUserAccessOrIsTheUser($createdByUser)) {
- $this->yandexAccountAndHostId->setIsWritableByCurrentUser(\false);
- }
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Menu.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Menu.php
deleted file mode 100644
index d71cd44..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Menu.php
+++ /dev/null
@@ -1,30 +0,0 @@
-addSystemItem('SearchEngineKeywordsPerformance_AdminMenuTitle', $this->urlForAction('index'), $order = 50);
- }
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Metrics.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Metrics.php
deleted file mode 100644
index f9fbd33..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Metrics.php
+++ /dev/null
@@ -1,144 +0,0 @@
- Piwik::translate('SearchEngineKeywordsPerformance_Clicks'),
- self::NB_IMPRESSIONS => Piwik::translate('SearchEngineKeywordsPerformance_Impressions'),
- self::CTR => Piwik::translate('SearchEngineKeywordsPerformance_Ctr'),
- self::POSITION => Piwik::translate('SearchEngineKeywordsPerformance_Position')
- ];
- }
- /**
- * Returns metric semantic types for this plugin's metrics.
- *
- * @return array
- */
- public static function getMetricSemanticTypes(): array
- {
- return [self::NB_CLICKS => Dimension::TYPE_NUMBER, self::NB_IMPRESSIONS => Dimension::TYPE_NUMBER, self::CTR => Dimension::TYPE_NUMBER, self::POSITION => Dimension::TYPE_NUMBER];
- }
- /**
- * Return metric documentations
- *
- * @return array
- */
- public static function getMetricsDocumentation()
- {
- return [
- self::NB_CLICKS => Piwik::translate('SearchEngineKeywordsPerformance_ClicksDocumentation'),
- self::NB_IMPRESSIONS => Piwik::translate('SearchEngineKeywordsPerformance_ImpressionsDocumentation'),
- self::CTR => Piwik::translate('SearchEngineKeywordsPerformance_CtrDocumentation'),
- self::POSITION => Piwik::translate('SearchEngineKeywordsPerformance_PositionDocumentation'),
- Bing::CRAWLSTATS_OTHER_CODES_RECORD_NAME => Piwik::translate('SearchEngineKeywordsPerformance_BingCrawlStatsOtherCodesDesc'),
- Bing::CRAWLSTATS_BLOCKED_ROBOTS_RECORD_NAME => Piwik::translate('SearchEngineKeywordsPerformance_BingCrawlBlockedByRobotsTxtDesc'),
- Bing::CRAWLSTATS_CODE_2XX_RECORD_NAME => Piwik::translate('SearchEngineKeywordsPerformance_BingCrawlHttpStatus2xxDesc'),
- Bing::CRAWLSTATS_CODE_301_RECORD_NAME => Piwik::translate('SearchEngineKeywordsPerformance_BingCrawlHttpStatus301Desc'),
- Bing::CRAWLSTATS_CODE_302_RECORD_NAME => Piwik::translate('SearchEngineKeywordsPerformance_BingCrawlHttpStatus302Desc'),
- Bing::CRAWLSTATS_CODE_4XX_RECORD_NAME => Piwik::translate('SearchEngineKeywordsPerformance_BingCrawlHttpStatus4xxDesc'),
- Bing::CRAWLSTATS_CODE_5XX_RECORD_NAME => Piwik::translate('SearchEngineKeywordsPerformance_BingCrawlHttpStatus5xxDesc'),
- Bing::CRAWLSTATS_TIMEOUT_RECORD_NAME => Piwik::translate('SearchEngineKeywordsPerformance_BingCrawlConnectionTimeoutDesc'),
- Bing::CRAWLSTATS_MALWARE_RECORD_NAME => Piwik::translate('SearchEngineKeywordsPerformance_BingCrawlMalwareInfectedDesc'),
- Bing::CRAWLSTATS_ERRORS_RECORD_NAME => Piwik::translate('SearchEngineKeywordsPerformance_BingCrawlErrorsDesc'),
- Bing::CRAWLSTATS_CRAWLED_PAGES_RECORD_NAME => Piwik::translate('SearchEngineKeywordsPerformance_BingCrawlCrawledPagesDesc'),
- Bing::CRAWLSTATS_DNS_FAILURE_RECORD_NAME => Piwik::translate('SearchEngineKeywordsPerformance_BingCrawlDNSFailuresDesc'),
- Bing::CRAWLSTATS_IN_INDEX_RECORD_NAME => Piwik::translate('SearchEngineKeywordsPerformance_BingCrawlPagesInIndexDesc'),
- Bing::CRAWLSTATS_IN_LINKS_RECORD_NAME => Piwik::translate('SearchEngineKeywordsPerformance_BingCrawlInboundLinkDesc'),
- Yandex::CRAWLSTATS_IN_INDEX_RECORD_NAME => Piwik::translate('SearchEngineKeywordsPerformance_YandexCrawlInIndexDesc'),
- Yandex::CRAWLSTATS_APPEARED_PAGES_RECORD_NAME => Piwik::translate('SearchEngineKeywordsPerformance_YandexCrawlAppearedPagesDesc'),
- Yandex::CRAWLSTATS_REMOVED_PAGES_RECORD_NAME => Piwik::translate('SearchEngineKeywordsPerformance_YandexCrawlRemovedPagesDesc'),
- Yandex::CRAWLSTATS_CRAWLED_PAGES_RECORD_NAME => Piwik::translate('SearchEngineKeywordsPerformance_YandexCrawlCrawledPagesDesc'),
- Yandex::CRAWLSTATS_CODE_2XX_RECORD_NAME => Piwik::translate('SearchEngineKeywordsPerformance_YandexCrawlHttpStatus2xxDesc'),
- Yandex::CRAWLSTATS_CODE_3XX_RECORD_NAME => Piwik::translate('SearchEngineKeywordsPerformance_YandexCrawlHttpStatus3xxDesc'),
- Yandex::CRAWLSTATS_CODE_4XX_RECORD_NAME => Piwik::translate('SearchEngineKeywordsPerformance_YandexCrawlHttpStatus4xxDesc'),
- Yandex::CRAWLSTATS_CODE_5XX_RECORD_NAME => Piwik::translate('SearchEngineKeywordsPerformance_YandexCrawlHttpStatus5xxDesc'),
- Yandex::CRAWLSTATS_ERRORS_RECORD_NAME => Piwik::translate('SearchEngineKeywordsPerformance_YandexCrawlErrorsDesc')
- ];
- }
- public static function getMetricIdsToProcessReportTotal()
- {
- return [self::NB_CLICKS, self::NB_IMPRESSIONS];
- }
- /**
- * Returns operations used to aggregate the metric columns
- *
- * @return array
- */
- public static function getColumnsAggregationOperations()
- {
- /*
- * Calculate average CTR based on summed impressions and summed clicks
- */
- $calcCtr = function ($val1, $val2, $thisRow, $rowToSum) {
- $sumImpressions = $thisRow->getColumn(\Piwik\Plugins\SearchEngineKeywordsPerformance\Metrics::NB_IMPRESSIONS) + $rowToSum->getColumn(\Piwik\Plugins\SearchEngineKeywordsPerformance\Metrics::NB_IMPRESSIONS);
- $sumClicks = $thisRow->getColumn(\Piwik\Plugins\SearchEngineKeywordsPerformance\Metrics::NB_CLICKS) + $rowToSum->getColumn(\Piwik\Plugins\SearchEngineKeywordsPerformance\Metrics::NB_CLICKS);
- if (!$sumImpressions) {
- return 0.0;
- }
- return round($sumClicks / $sumImpressions, 2);
- };
- /*
- * Calculate average position based on impressions and positions
- */
- $calcPosition = function ($val1, $val2, $thisRow, $rowToSum) {
- return round(
- (
- $thisRow->getColumn(\Piwik\Plugins\SearchEngineKeywordsPerformance\Metrics::NB_IMPRESSIONS)
- * $thisRow->getColumn(\Piwik\Plugins\SearchEngineKeywordsPerformance\Metrics::POSITION)
- + $rowToSum->getColumn(\Piwik\Plugins\SearchEngineKeywordsPerformance\Metrics::NB_IMPRESSIONS)
- * $rowToSum->getColumn(\Piwik\Plugins\SearchEngineKeywordsPerformance\Metrics::POSITION)
- ) / (
- $thisRow->getColumn(\Piwik\Plugins\SearchEngineKeywordsPerformance\Metrics::NB_IMPRESSIONS)
- + $rowToSum->getColumn(\Piwik\Plugins\SearchEngineKeywordsPerformance\Metrics::NB_IMPRESSIONS)
- ),
- 2
- );
- };
- return [\Piwik\Plugins\SearchEngineKeywordsPerformance\Metrics::CTR => $calcCtr, \Piwik\Plugins\SearchEngineKeywordsPerformance\Metrics::POSITION => $calcPosition];
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Model/Bing.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Model/Bing.php
deleted file mode 100644
index 973ccd5..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Model/Bing.php
+++ /dev/null
@@ -1,168 +0,0 @@
-table = Common::prefixTable(self::$rawTableName);
- }
- /**
- * Installs required database table
- */
- public static function install()
- {
- $table = "`url` VARCHAR( 170 ) NOT NULL ,\n\t\t\t\t\t `date` DATE NOT NULL ,\n\t\t\t\t\t `data` MEDIUMBLOB,\n\t\t\t\t\t `type` VARCHAR( 15 ) NOT NULL,\n\t\t\t\t\t PRIMARY KEY ( `url` , `date` , `type` )";
- // Key length = 170 + 3 byte (date) + 15 = 188
- DbHelper::createTable(self::$rawTableName, $table);
- }
- /**
- * Saves keywords for given url and day
- *
- * @param string $url url, eg. http://matomo.org
- * @param string $date a day string, eg. 2016-12-24
- * @param string $keywords serialized keyword data
- * @return bool
- */
- public function archiveKeywordData($url, $date, $keywords)
- {
- return $this->archiveData($url, $date, $keywords, 'keywords');
- }
- /**
- * Returns the saved keyword data for given parameters (or null if not available)
- *
- * @param string $url url, eg. http://matomo.org
- * @param string $date a day string, eg. 2016-12-24
- * @return null|string serialized keyword data
- */
- public function getKeywordData($url, $date)
- {
- return $this->getData($url, $date, 'keywords');
- }
- /**
- * Returns the latest date keyword data is available for
- *
- * @param string $url url, eg. http://matomo.org
- * @return null|string
- */
- public function getLatestDateKeywordDataIsAvailableFor($url)
- {
- $date = Db::fetchOne('SELECT `date` FROM ' . $this->table . ' WHERE `url` = ? AND `type` = ? ORDER BY `date` DESC LIMIT 1', [$url, 'keywords']);
- return $date;
- }
- /**
- * Saves crawl stats for given url and day
- *
- * @param string $url url, eg. http://matomo.org
- * @param string $date a day string, eg. 2016-12-24
- * @param string $keywords serialized keyword data
- * @return bool
- */
- public function archiveCrawlStatsData($url, $date, $keywords)
- {
- return $this->archiveData($url, $date, $keywords, 'crawlstats');
- }
- /**
- * Returns the saved crawl stats for given parameters (or null if not available)
- *
- * @param string $url url, eg. http://matomo.org
- * @param string $date a day string, eg. 2016-12-24
- * @return null|string serialized keyword data
- */
- public function getCrawlStatsData($url, $date)
- {
- return $this->getData($url, $date, 'crawlstats');
- }
- /**
- * Saves crawl error for given url
- *
- * @param string $url url, eg. http://matomo.org
- * @param string $keywords serialized keyword data
- * @return bool
- */
- public function archiveCrawlErrors($url, $keywords)
- {
- return $this->archiveData($url, '0000-00-00', $keywords, 'crawlerrors');
- }
- /**
- * Returns the saved crawl stats for given parameters (or null if not available)
- *
- * @param string $url url, eg. http://matomo.org
- * @return null|string serialized keyword data
- */
- public function getCrawlErrors($url)
- {
- return $this->getData($url, '0000-00-00', 'crawlerrors');
- }
- /**
- * Returns the saved data for given parameters (or null if not available)
- *
- * @param string $url url, eg. http://matomo.org
- * @param string $date a day string, eg. 2016-12-24
- * @param string $type type of data, like keywords, crawlstats,...
- * @return null|string serialized data
- */
- protected function getData($url, $date, $type)
- {
- $keywordData = Db::fetchOne('SELECT `data` FROM ' . $this->table . ' WHERE `url` = ? AND `date` = ? AND `type` = ?', [$url, $date, $type]);
- if ($keywordData) {
- return $this->uncompress($keywordData);
- }
- return null;
- }
- /**
- * Saves data for given type, url and day
- *
- * @param string $url url, eg. http://matomo.org
- * @param string $date a day string, eg. 2016-12-24
- * @param string $keywords serialized keyword data
- * @param string $type type of data, like keywords, crawlstats,...
- * @return bool
- */
- protected function archiveData($url, $date, $data, $type)
- {
- $query = "REPLACE INTO " . $this->table . " (`url`, `date`, `data`, `type`) VALUES (?,?,?,?)";
- $bindSql = [];
- $bindSql[] = $url;
- $bindSql[] = $date;
- $bindSql[] = $this->compress($data);
- $bindSql[] = $type;
- Db::query($query, $bindSql);
- return \true;
- }
- protected function compress($data)
- {
- if (Db::get()->hasBlobDataType()) {
- $data = gzcompress($data);
- }
- return $data;
- }
- protected function uncompress($data)
- {
- if (Db::get()->hasBlobDataType()) {
- $data = gzuncompress($data);
- }
- return $data;
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Model/Google.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Model/Google.php
deleted file mode 100644
index b815517..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Model/Google.php
+++ /dev/null
@@ -1,131 +0,0 @@
-table = Common::prefixTable(self::$rawTableName);
- }
- /**
- * Installs required database table
- */
- public static function install()
- {
- $dashboard = "`url` VARCHAR( 170 ) NOT NULL ,\n\t\t\t\t\t `date` DATE NOT NULL ,\n\t\t\t\t\t `data` MEDIUMBLOB,\n\t\t\t\t\t `type` VARCHAR( 15 ),\n\t\t\t\t\t PRIMARY KEY ( `url` , `date`, `type` )";
- // Key length = 170 + 3 byte (date) + 15 = 188
- DbHelper::createTable(self::$rawTableName, $dashboard);
- }
- /**
- * Saves keywords for given url and day
- *
- * @param string $url url, eg. http://matomo.org
- * @param string $date a day string, eg. 2016-12-24
- * @param string $type 'web', 'image', 'video' or 'news'
- * @param string $keywords serialized keyword data
- * @return bool
- */
- public function archiveKeywordData($url, $date, $type, $keywords)
- {
- return $this->archiveData($url, $date, $keywords, 'keywords' . $type);
- }
- /**
- * Returns the saved keyword data for given parameters (or null if not available)
- *
- * @param string $url url, eg. http://matomo.org
- * @param string $date a day string, eg. 2016-12-24
- * @param string $type 'web', 'image', 'video' or 'news'
- * @return null|string serialized keyword data
- */
- public function getKeywordData($url, $date, $type)
- {
- return $this->getData($url, $date, 'keywords' . $type);
- }
- /**
- * Returns the latest date keyword data is available for
- *
- * @param string $url url, eg. http://matomo.org
- * @param string|null $type 'web', 'image', 'video' or 'news'
- * @return null|string
- */
- public function getLatestDateKeywordDataIsAvailableFor($url, $type = null)
- {
- if ($type === null) {
- $date = Db::fetchOne('SELECT `date` FROM ' . $this->table . ' WHERE `url` = ? AND `type` LIKE ? ORDER BY `date` DESC LIMIT 1', [$url, 'keywords%']);
- } else {
- $date = Db::fetchOne('SELECT `date` FROM ' . $this->table . ' WHERE `url` = ? AND `type` = ? ORDER BY `date` DESC LIMIT 1', [$url, 'keywords' . $type]);
- }
- return $date;
- }
- /**
- * Returns the saved data for given parameters (or null if not available)
- *
- * @param string $url url, eg. http://matomo.org
- * @param string $date a day string, eg. 2016-12-24
- * @param string $type type of data, like keywords, crawlstats,...
- * @return null|string serialized data
- */
- protected function getData($url, $date, $type)
- {
- $keywordData = Db::fetchOne('SELECT `data` FROM ' . $this->table . ' WHERE `url` = ? AND `date` = ? AND `type` = ?', [$url, $date, $type]);
- if ($keywordData) {
- return $this->uncompress($keywordData);
- }
- return null;
- }
- /**
- * Saves data for given type, url and day
- *
- * @param string $url url, eg. http://matomo.org
- * @param string $date a day string, eg. 2016-12-24
- * @param string $data serialized keyword data
- * @param string $type type of data, like keywords, crawlstats,...
- * @return bool
- */
- protected function archiveData($url, $date, $data, $type)
- {
- $query = "REPLACE INTO " . $this->table . " (`url`, `date`, `data`, `type`) VALUES (?,?,?,?)";
- $bindSql = [];
- $bindSql[] = $url;
- $bindSql[] = $date;
- $bindSql[] = $this->compress($data);
- $bindSql[] = $type;
- Db::query($query, $bindSql);
- return \true;
- }
- protected function compress($data)
- {
- if (Db::get()->hasBlobDataType()) {
- $data = gzcompress($data);
- }
- return $data;
- }
- protected function uncompress($data)
- {
- if (Db::get()->hasBlobDataType()) {
- $data = gzuncompress($data);
- }
- return $data;
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Model/Yandex.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Model/Yandex.php
deleted file mode 100644
index 5d8d4be..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Model/Yandex.php
+++ /dev/null
@@ -1,147 +0,0 @@
-table = Common::prefixTable(self::$rawTableName);
- }
- /**
- * Installs required database table
- */
- public static function install()
- {
- $table = "`url` VARCHAR( 170 ) NOT NULL ,\n\t\t\t\t\t `date` DATE NOT NULL ,\n\t\t\t\t\t `data` MEDIUMBLOB,\n\t\t\t\t\t `type` VARCHAR(15) NOT NULL,\n\t\t\t\t\t PRIMARY KEY ( `url` , `date` , `type` )";
- // Key length = 170 + 3 byte (date) + 15 = 188
- DbHelper::createTable(self::$rawTableName, $table);
- }
- /**
- * Saves keywords for given url and day
- *
- * @param string $url url, eg. http://piwik.org
- * @param string $date a day string, eg. 2016-12-24
- * @param string $keywords serialized keyword data
- * @return bool
- */
- public function archiveKeywordData($url, $date, $keywords)
- {
- return $this->archiveData($url, $date, $keywords, 'keywords');
- }
- /**
- * Returns the saved keyword data for given parameters (or null if not available)
- *
- * @param string $url url, eg. http://piwik.org
- * @param string $date a day string, eg. 2016-12-24
- * @return null|string serialized keyword data
- */
- public function getKeywordData($url, $date)
- {
- return $this->getData($url, $date, 'keywords');
- }
- /**
- * Returns the latest date keyword data is available for
- *
- * @param string $url url, eg. http://piwik.org
- * @return null|string
- */
- public function getLatestDateKeywordDataIsAvailableFor($url)
- {
- $date = Db::fetchOne('SELECT `date` FROM ' . $this->table . ' WHERE `url` = ? AND `type` = ? ORDER BY `date` DESC LIMIT 1', array($url, 'keywords'));
- return $date;
- }
- /**
- * Saves crawl stats for given url and day
- *
- * @param string $url url, eg. http://piwik.org
- * @param string $date a day string, eg. 2016-12-24
- * @param string $keywords serialized keyword data
- * @return bool
- */
- public function archiveCrawlStatsData($url, $date, $keywords)
- {
- return $this->archiveData($url, $date, $keywords, 'crawlstats');
- }
- /**
- * Returns the saved crawl stats for given parameters (or null if not available)
- *
- * @param string $url url, eg. http://piwik.org
- * @param string $date a day string, eg. 2016-12-24
- * @return null|string serialized keyword data
- */
- public function getCrawlStatsData($url, $date)
- {
- return $this->getData($url, $date, 'crawlstats');
- }
- /**
- * Returns the saved data for given parameters (or null if not available)
- *
- * @param string $url url, eg. http://piwik.org
- * @param string $date a day string, eg. 2016-12-24
- * @param string $type type of data, like keywords, crawlstats,...
- * @return null|string serialized data
- */
- protected function getData($url, $date, $type)
- {
- $keywordData = Db::fetchOne('SELECT `data` FROM ' . $this->table . ' WHERE `url` = ? AND `date` = ? AND `type` = ?', [$url, $date, $type]);
- if ($keywordData) {
- return $this->uncompress($keywordData);
- }
- return null;
- }
- /**
- * Saves data for given type, url and day
- *
- * @param string $url url, eg. http://piwik.org
- * @param string $date a day string, eg. 2016-12-24
- * @param string $keywords serialized keyword data
- * @param string $type type of data, like keywords, crawlstats,...
- * @return bool
- */
- protected function archiveData($url, $date, $data, $type)
- {
- $query = "REPLACE INTO " . $this->table . " (`url`, `date`, `data`, `type`) VALUES (?,?,?,?)";
- $bindSql = [];
- $bindSql[] = $url;
- $bindSql[] = $date;
- $bindSql[] = $this->compress($data);
- $bindSql[] = $type;
- Db::query($query, $bindSql);
- return \true;
- }
- protected function compress($data)
- {
- if (Db::get()->hasBlobDataType()) {
- return gzcompress($data);
- }
- return $data;
- }
- protected function uncompress($data)
- {
- if (Db::get()->hasBlobDataType()) {
- return gzuncompress($data);
- }
- return $data;
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Monolog/Handler/SEKPSystemLogHandler.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Monolog/Handler/SEKPSystemLogHandler.php
deleted file mode 100644
index ab91f05..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Monolog/Handler/SEKPSystemLogHandler.php
+++ /dev/null
@@ -1,33 +0,0 @@
-getClient()->isConfigured();
- }
- public function isSupportedPeriod($date, $period)
- {
- // disabled for date ranges that need days for processing
- if ($period == 'range') {
- $periodObject = new Range($period, $date);
- $subPeriods = $periodObject->getSubperiods();
- foreach ($subPeriods as $subPeriod) {
- if ($subPeriod->getLabel() == 'day') {
- return \false;
- }
- }
- }
- // bing statistics are not available for single days
- if ($period == 'day') {
- return \false;
- }
- return \true;
- }
- /**
- * @inheritdoc
- */
- public function getConfiguredSiteIds()
- {
- $configuredSites = [];
- foreach ($this->getMeasurableHelper()->getAllSiteSettings() as $siteId => $settings) {
- $createdByUser = !is_null($settings->bingConfigCreatedBy) ? $settings->bingConfigCreatedBy->getValue() : '';
- $siteConfig = [];
- if ($settings->bingSiteUrl && $settings->bingSiteUrl->getValue()) {
- $siteConfig['bingSiteUrl'] = $settings->bingSiteUrl->getValue();
- $siteConfig['createdByUser'] = $createdByUser;
- $siteConfig['isDeletionAllowed'] = empty($createdByUser) || Piwik::hasUserSuperUserAccessOrIsTheUser($createdByUser);
- }
- if (!empty($siteConfig)) {
- $configuredSites[$siteId] = $siteConfig;
- }
- }
- return $configuredSites;
- }
- public function getConfigurationProblems()
- {
- return ['sites' => $this->getSiteErrors(), 'accounts' => $this->getAccountErrors()];
- }
- protected function getSiteErrors()
- {
- $errors = [];
- $client = $this->getClient();
- $accounts = $client->getAccounts();
- $configuredSiteIds = $this->getConfiguredSiteIds();
- foreach ($configuredSiteIds as $configuredSiteId => $config) {
- $bingSiteUrl = $config['bingSiteUrl'];
- list($apiKey, $url) = explode('##', $bingSiteUrl);
- if (!key_exists($apiKey, $accounts)) {
- $errors[$configuredSiteId] = Piwik::translate('SearchEngineKeywordsPerformance_AccountDoesNotExist', [$this->obfuscateApiKey($apiKey)]);
- continue;
- }
- $urls = $client->getAvailableUrls($apiKey);
- if (!key_exists($url, $urls)) {
- $errors[$configuredSiteId] = Piwik::translate('SearchEngineKeywordsPerformance_ConfiguredUrlNotAvailable');
- continue;
- }
- }
- return $errors;
- }
- protected function getAccountErrors()
- {
- $errors = [];
- $client = $this->getClient();
- $accounts = $client->getAccounts();
- if (empty($accounts)) {
- return [];
- }
- foreach ($accounts as $id => $account) {
- try {
- $client->testConfiguration($account['apiKey']);
- } catch (\Exception $e) {
- $errors[$id] = Piwik::translate('SearchEngineKeywordsPerformance_BingAccountError', $e->getMessage());
- }
- }
- return $errors;
- }
- protected function obfuscateApiKey($apiKey)
- {
- return substr($apiKey, 0, 5) . '*****' . substr($apiKey, -5, 5);
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Provider/Google.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Provider/Google.php
deleted file mode 100644
index cc2c951..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Provider/Google.php
+++ /dev/null
@@ -1,147 +0,0 @@
-getClient()->isConfigured();
- }
- /**
- * @inheritdoc
- */
- public function getConfiguredSiteIds()
- {
- $configuredSites = [];
- foreach ($this->getMeasurableHelper()->getAllSiteSettings() as $siteId => $settings) {
- $createdByUser = !is_null($settings->googleConfigCreatedBy) ? $settings->googleConfigCreatedBy->getValue() : '';
- $siteConfig = [];
- if ($settings->googleSearchConsoleUrl && $settings->googleSearchConsoleUrl->getValue()) {
- $siteConfig['googleSearchConsoleUrl'] = $settings->googleSearchConsoleUrl->getValue();
- $siteConfig['googleWebKeywords'] = $settings->googleWebKeywords->getValue();
- $siteConfig['googleImageKeywords'] = $settings->googleImageKeywords->getValue();
- $siteConfig['googleVideoKeywords'] = $settings->googleVideoKeywords->getValue();
- $siteConfig['googleNewsKeywords'] = $settings->googleNewsKeywords->getValue();
- $siteConfig['createdByUser'] = $createdByUser;
- $siteConfig['isDeletionAllowed'] = empty($createdByUser) || Piwik::hasUserSuperUserAccessOrIsTheUser($createdByUser);
- }
- if (!empty($siteConfig)) {
- $configuredSites[$siteId] = $siteConfig;
- }
- }
- return $configuredSites;
- }
- public function getConfigurationProblems()
- {
- $errors = ['sites' => $this->getSiteErrors(), 'accounts' => $this->getAccountErrors()];
- return $errors;
- }
- protected function getSiteErrors()
- {
- $errors = [];
- $client = $this->getClient();
- $accounts = $client->getAccounts();
- $configuredSiteIds = $this->getConfiguredSiteIds();
- foreach ($configuredSiteIds as $configuredSiteId => $config) {
- $googleSiteUrl = $config['googleSearchConsoleUrl'];
- list($accountId, $url) = explode('##', $googleSiteUrl);
- if (!key_exists($accountId, $accounts)) {
- $errors[$configuredSiteId] = Piwik::translate('SearchEngineKeywordsPerformance_AccountDoesNotExist', ['']);
- continue;
- }
- // Property Sets and Apps are deprecated and will be removed, so warn users why it doesn't work anymore
- // @todo can be removed in august 2019
- if (strpos($url, 'sc-set:') === 0) {
- $errors[$configuredSiteId] = 'You are using a property set for importing. Property sets have been deprecated/removed by Google. To ensure no error occurs, please choose another site for import';
- continue;
- }
- if (strpos($url, 'android-app:') === 0) {
- $errors[$configuredSiteId] = 'You are using a Android App for importing. Importing Android Apps has been deprecated/removed by Google. To ensure no error occurs, please choose another site for import';
- continue;
- }
- $urls = $client->getAvailableUrls($accountId);
- if (!key_exists($url, $urls)) {
- $errors[$configuredSiteId] = Piwik::translate('SearchEngineKeywordsPerformance_ConfiguredUrlNotAvailable');
- continue;
- }
- }
- return $errors;
- }
- protected function getAccountErrors()
- {
- $errors = [];
- $client = $this->getClient();
- $accounts = $client->getAccounts();
- if (empty($accounts)) {
- return [];
- }
- foreach ($accounts as $id => $account) {
- try {
- $client->testConfiguration($id);
- } catch (\Exception $e) {
- $errors[$id] = $e->getMessage();
- }
- }
- return $errors;
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Provider/Helper/MeasurableHelper.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Provider/Helper/MeasurableHelper.php
deleted file mode 100644
index 995fab8..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Provider/Helper/MeasurableHelper.php
+++ /dev/null
@@ -1,53 +0,0 @@
-allSiteSettings)) {
- return $this->allSiteSettings;
- }
-
- $siteManagerModel = StaticContainer::get(SitesManagerModel::class);
- $allSiteIds = $siteManagerModel->getSitesId();
- $this->allSiteSettings = [];
- foreach ($allSiteIds as $siteId) {
- if (!Piwik::isUserHasAdminAccess($siteId)) {
- continue;
- // skip sites without access
- }
- $this->allSiteSettings[$siteId] = $this->getMeasurableSettings($siteId);
- }
-
- return $this->allSiteSettings;
- }
-
- protected function getMeasurableSettings(int $idSite): MeasurableSettings
- {
- return new MeasurableSettings($idSite);
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Provider/ProviderAbstract.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Provider/ProviderAbstract.php
deleted file mode 100644
index 4755515..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Provider/ProviderAbstract.php
+++ /dev/null
@@ -1,151 +0,0 @@
- [], accounts => [] ]
- */
- abstract public function getConfigurationProblems();
- /**
- * Record a new timestamp for the current provider indicating an API error occurred.
- *
- * @return void
- */
- public function recordNewApiErrorForProvider(): void
- {
- Option::set(self::OPTION_PREFIX_LAST_ERROR_TIME . $this->getId(), time());
- }
- /**
- * Get the timestamp of the most recent API error for the current provider. If none is found, 0 is returned.
- *
- * @return int Unix timestamp or 0;
- */
- public function getLastApiErrorTimestamp(): int
- {
- $option = Option::get(self::OPTION_PREFIX_LAST_ERROR_TIME . $this->getId());
- if (empty($option)) {
- return 0;
- }
- return (int) $option;
- }
- /**
- * Checks if there has been an API error for the current provider within the past week.
- *
- * @return bool Indicates whether the most recent API error was less than a week ago.
- */
- public function hasApiErrorWithinWeek(): bool
- {
- $timestamp = $this->getLastApiErrorTimestamp();
- if ($timestamp === 0) {
- return \false;
- }
- return $timestamp > strtotime('-1 week');
- }
- /**
- * If there's been an API error within the past week a message string is provided. Otherwise, the string is empty.
- *
- * @return string Either the message or empty string depending on whether there's been a recent error.
- */
- public function getRecentApiErrorMessage(): string
- {
- $message = '';
- if ($this->hasApiErrorWithinWeek()) {
- $message = '' . $this->getName() . ' - Most recent error: ' . (new Formatter())->getPrettyTimeFromSeconds(time() - $this->getLastApiErrorTimestamp()) . ' ago';
- }
- return $message;
- }
-
- protected function getMeasurableHelper(): MeasurableHelper
- {
- return MeasurableHelper::getInstance();
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Provider/Yandex.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Provider/Yandex.php
deleted file mode 100644
index ce70f3d..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Provider/Yandex.php
+++ /dev/null
@@ -1,147 +0,0 @@
-getClient()->isConfigured();
- }
- /**
- * @inheritdoc
- */
- public function getConfiguredSiteIds()
- {
- $configuredSites = [];
- foreach ($this->getMeasurableHelper()->getAllSiteSettings() as $siteId => $settings) {
- $siteConfig = [];
- $createdByUser = !is_null($settings->yandexConfigCreatedBy) ? $settings->yandexConfigCreatedBy->getValue() : '';
- if ($settings->yandexAccountAndHostId && $settings->yandexAccountAndHostId->getValue()) {
- $siteConfig['yandexAccountAndHostId'] = $settings->yandexAccountAndHostId->getValue();
- $siteConfig['createdByUser'] = $createdByUser;
- $siteConfig['isDeletionAllowed'] = empty($createdByUser) || Piwik::hasUserSuperUserAccessOrIsTheUser($createdByUser);
- }
- if (!empty($siteConfig)) {
- $configuredSites[$siteId] = $siteConfig;
- }
- }
- return $configuredSites;
- }
- public function getConfigurationProblems()
- {
- $errors = ['sites' => $this->getSiteErrors(), 'accounts' => $this->getAccountErrors()];
- return $errors;
- }
- protected function getSiteErrors()
- {
- $errors = [];
- $client = $this->getClient();
- $accounts = $client->getAccounts();
- $configuredSiteIds = $this->getConfiguredSiteIds();
- foreach ($configuredSiteIds as $configuredSiteId => $config) {
- $yandexSiteUrl = $config['yandexAccountAndHostId'];
- list($accountId, $url) = explode('##', $yandexSiteUrl);
- if (!key_exists($accountId, $accounts)) {
- $errors[$configuredSiteId] = Piwik::translate('SearchEngineKeywordsPerformance_AccountDoesNotExist', ['']);
- continue;
- }
- $urls = [];
- try {
- $urlArray = $client->getAvailableUrls($accountId);
- foreach ($urlArray as $item) {
- $urls[] = $item['host_id'];
- }
- } catch (\Exception $e) {
- }
- if (!in_array($url, $urls)) {
- $errors[$configuredSiteId] = Piwik::translate('SearchEngineKeywordsPerformance_ConfiguredUrlNotAvailable');
- continue;
- }
- }
- return $errors;
- }
- protected function getAccountErrors()
- {
- $errors = [];
- $client = $this->getClient();
- $accounts = $client->getAccounts();
- if (empty($accounts)) {
- return [];
- }
- foreach ($accounts as $id => $account) {
- try {
- $client->testConfiguration($id);
- } catch (\Exception $e) {
- $errors[$id] = $e->getMessage();
- }
- }
- return $errors;
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/README.md b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/README.md
deleted file mode 100644
index 9e56904..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/README.md
+++ /dev/null
@@ -1,87 +0,0 @@
-# Search Engine Keywords Performance Plugin for Matomo
-
-## Description
-
-Uncover the keywords people use to find your site in the search engines. Learn which keywords are driving the most traffic, leads, and sales.
-
-There was a time when Google Analytics let you see what keywords people searched for to find your site. But one day, Google curtailed this critical information behind two fateful, cryptic words: "(not provided)."
-
-Since then, there was no way you could access this data. Unless you used Matomo's Search Engine Keywords Performance plugin, that is.
-
-With Search Engine Keywords Performance, the keywords people use to find your site become a dimension in your "Referrers" reports.
-
-Monitor your keywords' positions and boost your SEO performance like in the old days.
-
-### How Search Engine Keywords Performance Works
-
-#### All the Keywords Search Engines Don't Want You to See In One Report
-
-
-
-
Google, Yahoo, and Bing may not want you to see what keywords get you traffic, but we do. How? By leveraging their APIs.
-
Slice the keywords data with one of the 90+ dimensions and mix them with metrics like impressions, clicks, CTR, and the average position in the SERPs.
-
-
-
-
-
-
-#### Get An In-Depth Look at Your Crawling Performance
-
-
-
-
No matter how well you optimise your site, without proper crawling, your SEO efforts will be in vain.
-
Discover the number of pages crawled and indexed, 404 pages found, and other issues that could affect your crawling performance in Yahoo and Bing.
-
The page crawling error reports will show you what pages could not be crawled by a search engine with a detailed reason, so you can fix them right away.
-
-
-
-
-
-
-#### Identify What Keywords Your Images and Videos Bring You Traffic
-
-
-
-
Considering that YouTube and Google Images are the second and third largest search engines, your videos and images can drive significant organic traffic to your site.
-
With the Search Engine Keywords Performance plugin, you can uncover every keyword they rank for and how many visitors they attract, among other metrics.
-
-
-
-
-
-
-#### See How Your Keyword Performance Evolves Over Time
-
-
-
-
Track your top keywords and see how your metrics and KPIs unfold. Monitor, identify, and optimise your SEO strategy for opportunities to get the highest return from your efforts.
-
-
-
-
-
-
-### Try Search Engine Keywords Performance Today
-
-Unveil the true picture of your SEO performance with Matomo's Search Engine Keywords Performance plugin. See once again what keywords you rank for and take your organic traffic to the next level.
-
-It's time you enjoy an unparalleled data-driven SEO strategy with Matomo. Start your 30-day free trial today.
-
-## Dependencies
-This plugin had its vendored dependencies scoped using [matomo scoper](https://github.com/matomo-org/matomo-scoper). This means that composer packages are prefixed so that they won't conflict with the same libraries used by other plugins. If you need to update a dependency, you should be able to run `composer install` to populate the vendor directory, make sure that you have the [DevPluginCommands plugin](https://github.com/innocraft/dev-plugin-commands) installed, and run the following command `./console devplugincommands:process-dependencies --plugin="SearchEngineKeywordsPerformance" --downgrade-php` to scope and transpile the dependencies.
-
-### Features
-* New Search Keywords report in Matomo Referrers section.
-* View Keywords analytics by search type (web VS image VS video).
-* View combined Keywords across all search engines (Google + Bing + Yahoo + Yandex).
-* Monitor Keyword rankings and Search Engine Optimisation performance for each keyword with [Row Evolution](https://matomo.org/docs/row-evolution/).
-* New Crawling overview report show how Search engines bots crawl your websites (Bing + Yahoo and Yandex).
-* View crawling overview key metrics (for Bing + Yahoo and Yandex): crawled pages, total pages in index, total inboud links, robots.txt exclusion page count, crawl errors, DNS failures, connection timeouts, page redirects (301, 302 http status), error pages (4xx http status), internet error pages (5xx http status).
-* Import the detailed list of search keywords for Google search, Google images and Google Videos directly from Google Search Console.
-* Import the detailed list of search keywords from Bing and Yahoo! search directly from Bing Webmaster Tools.
-* Import the detailed list of search keywords from Yandex search directly from Yandex Webmaster API.
-* View all crawling errors with detailed reasons like server errors, robots.txt exclusions, not found pages, ... (Bing + Yahoo)
-* Possibility to add support for other search engines that provide their data through an API (contact us).
-* Get your Keyword analytics SEO reports by [email](https://matomo.org/docs/email-reports/) to you, your colleagues or customers.
-* Export your Keyword analytics report using the [Search Keywords Performance Monitor API](http://developer.matomo.org/api-reference/reporting-api#SearchEngineKeywordsPerformance).
\ No newline at end of file
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/RecordBuilders/Base.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/RecordBuilders/Base.php
deleted file mode 100644
index dbf86c2..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/RecordBuilders/Base.php
+++ /dev/null
@@ -1,32 +0,0 @@
-maxRowsInTable = PiwikConfig::getInstance()->General['datatable_archiving_maximum_rows_referrers'];
- $this->columnToSortByBeforeTruncation = Metrics::NB_CLICKS;
- $this->columnAggregationOps = Metrics::getColumnsAggregationOperations();
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/RecordBuilders/Bing.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/RecordBuilders/Bing.php
deleted file mode 100644
index f376b1c..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/RecordBuilders/Bing.php
+++ /dev/null
@@ -1,204 +0,0 @@
-apiKey = $apiKey;
- $this->apiUrl = $apiUrl;
- $this->logger = $logger;
- $this->columnAggregationOps = array_merge(Metrics::getColumnsAggregationOperations(), [
- self::CRAWLSTATS_OTHER_CODES_RECORD_NAME => 'max',
- self::CRAWLSTATS_BLOCKED_ROBOTS_RECORD_NAME => 'max',
- self::CRAWLSTATS_CODE_2XX_RECORD_NAME => 'max',
- self::CRAWLSTATS_CODE_301_RECORD_NAME => 'max',
- self::CRAWLSTATS_CODE_302_RECORD_NAME => 'max',
- self::CRAWLSTATS_CODE_4XX_RECORD_NAME => 'max',
- self::CRAWLSTATS_CODE_5XX_RECORD_NAME => 'max',
- self::CRAWLSTATS_TIMEOUT_RECORD_NAME => 'max',
- self::CRAWLSTATS_MALWARE_RECORD_NAME => 'max',
- self::CRAWLSTATS_ERRORS_RECORD_NAME => 'max',
- self::CRAWLSTATS_CRAWLED_PAGES_RECORD_NAME => 'max',
- self::CRAWLSTATS_DNS_FAILURE_RECORD_NAME => 'max',
- self::CRAWLSTATS_IN_INDEX_RECORD_NAME => 'max',
- self::CRAWLSTATS_IN_LINKS_RECORD_NAME => 'max'
- ]);
- }
- public function getRecordMetadata(ArchiveProcessor $archiveProcessor): array
- {
- return [
- Record::make(Record::TYPE_BLOB, self::KEYWORDS_BING_RECORD_NAME),
- Record::make(Record::TYPE_NUMERIC, self::CRAWLSTATS_OTHER_CODES_RECORD_NAME),
- Record::make(Record::TYPE_NUMERIC, self::CRAWLSTATS_BLOCKED_ROBOTS_RECORD_NAME),
- Record::make(Record::TYPE_NUMERIC, self::CRAWLSTATS_CODE_2XX_RECORD_NAME),
- Record::make(Record::TYPE_NUMERIC, self::CRAWLSTATS_CODE_301_RECORD_NAME),
- Record::make(Record::TYPE_NUMERIC, self::CRAWLSTATS_CODE_302_RECORD_NAME),
- Record::make(Record::TYPE_NUMERIC, self::CRAWLSTATS_CODE_4XX_RECORD_NAME),
- Record::make(Record::TYPE_NUMERIC, self::CRAWLSTATS_CODE_5XX_RECORD_NAME),
- Record::make(Record::TYPE_NUMERIC, self::CRAWLSTATS_TIMEOUT_RECORD_NAME),
- Record::make(Record::TYPE_NUMERIC, self::CRAWLSTATS_MALWARE_RECORD_NAME),
- Record::make(Record::TYPE_NUMERIC, self::CRAWLSTATS_ERRORS_RECORD_NAME),
- Record::make(Record::TYPE_NUMERIC, self::CRAWLSTATS_CRAWLED_PAGES_RECORD_NAME),
- Record::make(Record::TYPE_NUMERIC, self::CRAWLSTATS_DNS_FAILURE_RECORD_NAME),
- Record::make(Record::TYPE_NUMERIC, self::CRAWLSTATS_IN_INDEX_RECORD_NAME),
- Record::make(Record::TYPE_NUMERIC, self::CRAWLSTATS_IN_LINKS_RECORD_NAME)
- ];
- }
- protected function aggregate(ArchiveProcessor $archiveProcessor): array
- {
- $records = [];
- $parameters = $archiveProcessor->getParams();
- $date = $parameters->getDateStart()->setTimezone('UTC')->toString('Y-m-d');
- $this->logger->debug("[SearchEngineKeywordsPerformance] Archiving bing records for {$date} and {$this->apiUrl}");
- $dataTable = $this->getKeywordsAsDataTable($date);
- if (empty($dataTable)) {
- // ensure data is present (if available)
- BingImporter::importAvailablePeriods($this->apiKey, $this->apiUrl);
- $dataTable = $this->getKeywordsAsDataTable($date);
- }
- if (!empty($dataTable)) {
- $this->logger->debug("[SearchEngineKeywordsPerformance] Archiving bing keywords for {$date} and {$this->apiUrl}");
- $records[self::KEYWORDS_BING_RECORD_NAME] = $dataTable;
- }
- $this->archiveDayCrawlStatNumerics($records, $date);
- return $records;
- }
- /**
- * Returns keyword data for given parameters as DataTable
- */
- protected function getKeywordsAsDataTable(string $date): ?DataTable
- {
- $model = new BingModel();
- $keywordData = $model->getKeywordData($this->apiUrl, $date);
- if (!empty($keywordData)) {
- $dataTable = new DataTable();
- $dataTable->addRowsFromSerializedArray($keywordData);
- return $dataTable;
- }
- return null;
- }
- /**
- * Inserts various numeric records for crawl stats
- */
- protected function archiveDayCrawlStatNumerics(array &$records, string $date): void
- {
- $dataTable = $this->getCrawlStatsAsDataTable($date);
- if (!empty($dataTable)) {
- Log::debug("[SearchEngineKeywordsPerformance] Archiving bing crawl stats for {$date} and {$this->apiUrl}");
- $getValue = function ($label) use ($dataTable) {
- $row = $dataTable->getRowFromLabel($label);
- if ($row) {
- return (int) $row->getColumn(Metrics::NB_PAGES);
- }
- return 0;
- };
- $records = array_merge($records, [
- self::CRAWLSTATS_OTHER_CODES_RECORD_NAME => $getValue('AllOtherCodes'),
- self::CRAWLSTATS_BLOCKED_ROBOTS_RECORD_NAME => $getValue('BlockedByRobotsTxt'),
- self::CRAWLSTATS_CODE_2XX_RECORD_NAME => $getValue('Code2xx'),
- self::CRAWLSTATS_CODE_301_RECORD_NAME => $getValue('Code301'),
- self::CRAWLSTATS_CODE_302_RECORD_NAME => $getValue('Code302'),
- self::CRAWLSTATS_CODE_4XX_RECORD_NAME => $getValue('Code4xx'),
- self::CRAWLSTATS_CODE_5XX_RECORD_NAME => $getValue('Code5xx'),
- self::CRAWLSTATS_TIMEOUT_RECORD_NAME => $getValue('ConnectionTimeout'),
- self::CRAWLSTATS_MALWARE_RECORD_NAME => $getValue('ContainsMalware'),
- self::CRAWLSTATS_ERRORS_RECORD_NAME => $getValue('CrawlErrors'),
- self::CRAWLSTATS_CRAWLED_PAGES_RECORD_NAME => $getValue('CrawledPages'),
- self::CRAWLSTATS_DNS_FAILURE_RECORD_NAME => $getValue('DnsFailures'),
- self::CRAWLSTATS_IN_INDEX_RECORD_NAME => $getValue('InIndex'),
- self::CRAWLSTATS_IN_LINKS_RECORD_NAME => $getValue('InLinks')
- ]);
- Common::destroy($dataTable);
- unset($dataTable);
- }
- }
- /**
- * Returns crawl stats for given parameters as DataTable
- */
- protected function getCrawlStatsAsDataTable(string $date): ?DataTable
- {
- $model = new BingModel();
- $keywordData = $model->getCrawlStatsData($this->apiUrl, $date);
- if (!empty($keywordData)) {
- $dataTable = new DataTable();
- $dataTable->addRowsFromSerializedArray($keywordData);
- return $dataTable;
- }
- return null;
- }
- public static function make(int $idSite): ?self
- {
- $site = new Site($idSite);
- $setting = new MeasurableSettings($site->getId(), $site->getType());
- $bingSiteUrl = $setting->bingSiteUrl;
- $doesNotHaveBing = empty($bingSiteUrl) || !$bingSiteUrl->getValue() || \false === strpos($bingSiteUrl->getValue(), '##');
- if ($doesNotHaveBing) {
- // bing api not activated for that site
- return null;
- }
- list($apiKey, $url) = explode('##', $bingSiteUrl->getValue());
- return StaticContainer::getContainer()->make(\Piwik\Plugins\SearchEngineKeywordsPerformance\RecordBuilders\Bing::class, ['apiKey' => $apiKey, 'apiUrl' => $url]);
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/RecordBuilders/Google.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/RecordBuilders/Google.php
deleted file mode 100644
index 796f408..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/RecordBuilders/Google.php
+++ /dev/null
@@ -1,155 +0,0 @@
-accountId = $accountId;
- $this->searchConsoleUrl = $searchConsoleUrl;
- $this->recordName = $recordName;
- $this->logger = $logger;
- }
- public function getRecordMetadata(ArchiveProcessor $archiveProcessor): array
- {
- return [ArchiveProcessor\Record::make(Record::TYPE_BLOB, $this->recordName)];
- }
- protected function aggregate(ArchiveProcessor $archiveProcessor): array
- {
- $parameters = $archiveProcessor->getParams();
- $date = $parameters->getDateStart()->setTimezone('UTC')->toString('Y-m-d');
- $record = $this->aggregateDayBySearchType($archiveProcessor, $this->recordName, $date);
- if (empty($record)) {
- return [];
- }
- return [$this->recordName => $record];
- }
- public function isEnabled(ArchiveProcessor $archiveProcessor): bool
- {
- $segment = $archiveProcessor->getParams()->getSegment();
- if (!$segment->isEmpty()) {
- $this->logger->debug("Skip Archiving for SearchEngineKeywordsPerformance plugin for segments");
- return \false;
- // do not archive data for segments
- }
- return \true;
- }
- /**
- * Aggregates data for a given day by type of search
- */
- protected function aggregateDayBySearchType(ArchiveProcessor $archiveProcessor, string $recordName, string $date): ?DataTable
- {
- $types = [self::KEYWORDS_GOOGLE_WEB_RECORD_NAME => 'web', self::KEYWORDS_GOOGLE_IMAGE_RECORD_NAME => 'image', self::KEYWORDS_GOOGLE_VIDEO_RECORD_NAME => 'video', self::KEYWORDS_GOOGLE_NEWS_RECORD_NAME => 'news'];
- $this->logger->debug("[SearchEngineKeywordsPerformance] Archiving {$types[$recordName]} keywords for {$date} and {$this->searchConsoleUrl}");
- $dataTable = $this->getKeywordsAsDataTable($archiveProcessor, $date, $types[$recordName]);
- if (empty($dataTable)) {
- return null;
- }
- return $dataTable;
- }
- /**
- * Returns keyword data for given parameters as DataTable
- */
- protected function getKeywordsAsDataTable(ArchiveProcessor $archiveProcessor, string $date, string $type): ?DataTable
- {
- // ensure keywords are present (if available)
- $googleImporter = new GoogleImporter($archiveProcessor->getParams()->getSite()->getId());
- $googleImporter->importKeywordsIfNecessary($this->accountId, $this->searchConsoleUrl, $date, $type);
- $model = new GoogleModel();
- $keywordData = $model->getKeywordData($this->searchConsoleUrl, $date, $type);
- if (!empty($keywordData)) {
- $dataTable = new DataTable();
- $dataTable->addRowsFromSerializedArray($keywordData);
- return $dataTable;
- }
- return null;
- }
- public static function makeAll(int $idSite): array
- {
- $site = new Site($idSite);
- $settings = new MeasurableSettings($site->getId(), $site->getType());
- $searchConsoleUrl = $settings->googleSearchConsoleUrl;
- if (empty($searchConsoleUrl) || !$searchConsoleUrl->getValue() || \false === strpos($searchConsoleUrl->getValue(), '##')) {
- return [];
- // search console not activated for that site
- }
- $searchConsoleSetting = $settings->googleSearchConsoleUrl->getValue();
- list($accountId, $searchConsoleUrl) = explode('##', $searchConsoleSetting);
- $archives = [];
- if ($settings->googleWebKeywords->getValue()) {
- $archives[] = self::KEYWORDS_GOOGLE_WEB_RECORD_NAME;
- }
- if ($settings->googleImageKeywords->getValue()) {
- $archives[] = self::KEYWORDS_GOOGLE_IMAGE_RECORD_NAME;
- }
- if ($settings->googleVideoKeywords->getValue()) {
- $archives[] = self::KEYWORDS_GOOGLE_VIDEO_RECORD_NAME;
- }
- if ($settings->googleNewsKeywords->getValue()) {
- $archives[] = self::KEYWORDS_GOOGLE_NEWS_RECORD_NAME;
- }
- $logger = StaticContainer::get(LoggerInterface::class);
- $builders = array_map(function ($recordName) use ($accountId, $searchConsoleUrl, $logger) {
- return new self($accountId, $searchConsoleUrl, $recordName, $logger);
- }, $archives);
- return $builders;
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/RecordBuilders/Yandex.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/RecordBuilders/Yandex.php
deleted file mode 100644
index 140a5b8..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/RecordBuilders/Yandex.php
+++ /dev/null
@@ -1,196 +0,0 @@
-accountId = $accountId;
- $this->hostId = $hostId;
- $this->logger = $logger;
- $this->columnAggregationOps = array_merge(Metrics::getColumnsAggregationOperations(), [
- self::CRAWLSTATS_IN_INDEX_RECORD_NAME => 'max',
- self::CRAWLSTATS_APPEARED_PAGES_RECORD_NAME => 'max',
- self::CRAWLSTATS_REMOVED_PAGES_RECORD_NAME => 'max',
- self::CRAWLSTATS_CRAWLED_PAGES_RECORD_NAME => 'max',
- self::CRAWLSTATS_CODE_2XX_RECORD_NAME => 'max',
- self::CRAWLSTATS_CODE_3XX_RECORD_NAME => 'max',
- self::CRAWLSTATS_CODE_4XX_RECORD_NAME => 'max',
- self::CRAWLSTATS_CODE_5XX_RECORD_NAME => 'max',
- self::CRAWLSTATS_ERRORS_RECORD_NAME => 'max'
- ]);
- }
- public function getRecordMetadata(ArchiveProcessor $archiveProcessor): array
- {
- return [
- Record::make(Record::TYPE_BLOB, self::KEYWORDS_YANDEX_RECORD_NAME),
- Record::make(Record::TYPE_NUMERIC, self::CRAWLSTATS_IN_INDEX_RECORD_NAME),
- Record::make(Record::TYPE_NUMERIC, self::CRAWLSTATS_APPEARED_PAGES_RECORD_NAME),
- Record::make(Record::TYPE_NUMERIC, self::CRAWLSTATS_REMOVED_PAGES_RECORD_NAME),
- Record::make(Record::TYPE_NUMERIC, self::CRAWLSTATS_CRAWLED_PAGES_RECORD_NAME),
- Record::make(Record::TYPE_NUMERIC, self::CRAWLSTATS_CODE_2XX_RECORD_NAME),
- Record::make(Record::TYPE_NUMERIC, self::CRAWLSTATS_CODE_3XX_RECORD_NAME),
- Record::make(Record::TYPE_NUMERIC, self::CRAWLSTATS_CODE_4XX_RECORD_NAME),
- Record::make(Record::TYPE_NUMERIC, self::CRAWLSTATS_CODE_5XX_RECORD_NAME),
- Record::make(Record::TYPE_NUMERIC, self::CRAWLSTATS_ERRORS_RECORD_NAME)
- ];
- }
- protected function aggregate(ArchiveProcessor $archiveProcessor): array
- {
- $records = [];
- $parameters = $archiveProcessor->getParams();
- $date = $parameters->getDateStart()->setTimezone('UTC')->toString('Y-m-d');
- $this->logger->debug("[SearchEngineKeywordsPerformance] Archiving yandex records for {$date} and {$this->hostId}");
- $dataTable = $this->getKeywordsAsDataTable($date);
- if (empty($dataTable)) {
- // ensure data is present (if available)
- YandexImporter::importAvailableDataForDate($this->accountId, $this->hostId, $date);
- $dataTable = $this->getKeywordsAsDataTable($date);
- }
- if (!empty($dataTable)) {
- Log::debug("[SearchEngineKeywordsPerformance] Archiving yandex keywords for {$date} and {$this->hostId}");
- $records[self::KEYWORDS_YANDEX_RECORD_NAME] = $dataTable;
- }
- $records = array_merge($records, $this->archiveDayCrawlStatNumerics($date));
- return $records;
- }
- public function isEnabled(ArchiveProcessor $archiveProcessor): bool
- {
- $segment = $archiveProcessor->getParams()->getSegment();
- if (!$segment->isEmpty()) {
- $this->logger->debug("Skip Archiving for SearchEngineKeywordsPerformance plugin for segments");
- return \false;
- // do not archive data for segments
- }
- return \true;
- }
- /**
- * Returns keyword data for given parameters as DataTable
- */
- protected function getKeywordsAsDataTable(string $date): ?DataTable
- {
- $model = new YandexModel();
- $keywordData = $model->getKeywordData($this->hostId, $date);
- if (!empty($keywordData)) {
- $dataTable = new DataTable();
- $dataTable->addRowsFromSerializedArray($keywordData);
- return $dataTable;
- }
- return null;
- }
- /**
- * Returns keyword data for given parameters as DataTable
- */
- protected function archiveDayCrawlStatNumerics(string $date): array
- {
- $dataTable = $this->getCrawlStatsAsDataTable($date);
- if (!empty($dataTable)) {
- $this->logger->debug("[SearchEngineKeywordsPerformance] Archiving yandex crawl stats for {$date} and {$this->hostId}");
- $getValue = function ($label) use ($dataTable) {
- $row = $dataTable->getRowFromLabel($label);
- if ($row) {
- return (int) $row->getColumn(Metrics::NB_PAGES);
- }
- return 0;
- };
- $numericRecords = [
- self::CRAWLSTATS_IN_INDEX_RECORD_NAME => $getValue('SEARCHABLE'),
- self::CRAWLSTATS_APPEARED_PAGES_RECORD_NAME => $getValue('APPEARED_IN_SEARCH'),
- self::CRAWLSTATS_REMOVED_PAGES_RECORD_NAME => $getValue('REMOVED_FROM_SEARCH'),
- self::CRAWLSTATS_CRAWLED_PAGES_RECORD_NAME => $getValue('HTTP_2XX') + $getValue('HTTP_3XX') + $getValue('HTTP_4XX') + $getValue('HTTP_5XX') + $getValue('OTHER'),
- self::CRAWLSTATS_CODE_2XX_RECORD_NAME => $getValue('HTTP_2XX'),
- self::CRAWLSTATS_CODE_3XX_RECORD_NAME => $getValue('HTTP_3XX'),
- self::CRAWLSTATS_CODE_4XX_RECORD_NAME => $getValue('HTTP_4XX'),
- self::CRAWLSTATS_CODE_5XX_RECORD_NAME => $getValue('HTTP_5XX'),
- self::CRAWLSTATS_ERRORS_RECORD_NAME => $getValue('OTHER')
- ];
- Common::destroy($dataTable);
- unset($dataTable);
- return $numericRecords;
- }
- return [];
- }
- /**
- * Returns crawl stats for given parameters as DataTable
- */
- protected function getCrawlStatsAsDataTable(string $date): ?DataTable
- {
- $model = new YandexModel();
- $keywordData = $model->getCrawlStatsData($this->hostId, $date);
- if (!empty($keywordData)) {
- $dataTable = new DataTable();
- $dataTable->addRowsFromSerializedArray($keywordData);
- return $dataTable;
- }
- return null;
- }
- public static function make(int $idSite): ?self
- {
- $site = new Site($idSite);
- $setting = new MeasurableSettings($site->getId(), $site->getType());
- $yandexConfig = $setting->yandexAccountAndHostId;
- $doesNotHaveYandex = empty($yandexConfig) || !$yandexConfig->getValue() || \false === strpos($yandexConfig->getValue(), '##');
- if ($doesNotHaveYandex) {
- // yandex api not activated for that site
- return null;
- }
- list($accountId, $hostId) = explode('##', $yandexConfig->getValue());
- return StaticContainer::getContainer()->make(self::class, ['accountId' => $accountId, 'hostId' => $hostId]);
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Reports/Base.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Reports/Base.php
deleted file mode 100644
index 2006c39..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Reports/Base.php
+++ /dev/null
@@ -1,205 +0,0 @@
-categoryId = 'Referrers_Referrers';
- $this->subcategoryId = 'Referrers_SubmenuSearchEngines';
- $this->defaultSortColumn = Metrics::NB_CLICKS;
- $this->metrics = Metrics::getKeywordMetrics();
- $this->processedMetrics = [];
- if (property_exists($this, 'onlineGuideUrl')) {
- $this->onlineGuideUrl = Url::addCampaignParametersToMatomoLink('https://matomo.org/guide/installation-maintenance/import-search-keywords/');
- }
- }
- public function getMetricsDocumentation()
- {
- return Metrics::getMetricsDocumentation();
- }
- public function configureReportMetadata(&$availableReports, $infos)
- {
- $this->idSite = $infos['idSite'];
- parent::configureReportMetadata($availableReports, $infos);
- }
- public function configureView(ViewDataTable $view)
- {
- $view->config->addTranslations(['label' => $this->dimension->getName()]);
- $view->config->show_limit_control = \true;
- $view->config->show_all_views_icons = \false;
- $view->config->show_table_all_columns = \false;
- $view->config->columns_to_display = ['label', Metrics::NB_CLICKS, Metrics::NB_IMPRESSIONS, Metrics::CTR, Metrics::POSITION];
- $view->requestConfig->filter_limit = 10;
- $this->configureSegmentNotSupported($view);
- }
- public function getSecondarySortColumnCallback()
- {
- return function ($firstSortColumn, $table) {
- return $firstSortColumn === Metrics::NB_CLICKS ? Metrics::NB_IMPRESSIONS : Metrics::NB_CLICKS;
- };
- }
- protected function configureSegmentNotSupported(ViewDataTable $view)
- {
- // show 'not supported' message if segment is chosen
- if (Common::getRequestVar('segment', '')) {
- $view->config->show_footer_message .= '
';
- if (property_exists($view->config, 'show_header_message')) {
- $view->config->show_header_message = $message;
- } else {
- $view->config->show_footer_message .= $message;
- }
- }
- public function getStylesheetFiles(&$stylesheets)
- {
- $stylesheets[] = "plugins/SearchEngineKeywordsPerformance/stylesheets/styles.less";
- $stylesheets[] = "plugins/SearchEngineKeywordsPerformance/vue/src/Configure/ConfigureConnection.less";
- }
- public function addDefaultMetricSemanticTypes(&$types): void
- {
- $types = array_merge($types, \Piwik\Plugins\SearchEngineKeywordsPerformance\Metrics::getMetricSemanticTypes());
- }
- public function addMetricTranslations(&$translations)
- {
- $translations = array_merge($translations, \Piwik\Plugins\SearchEngineKeywordsPerformance\Metrics::getMetricsTranslations());
- }
- public function addMetricDocumentationTranslations(&$translations)
- {
- $translations = array_merge($translations, \Piwik\Plugins\SearchEngineKeywordsPerformance\Metrics::getMetricsDocumentation());
- }
- public function checkIsLowerMetricValueBetter(&$isLowerBetter, $metric)
- {
- if ($metric === \Piwik\Plugins\SearchEngineKeywordsPerformance\Metrics::POSITION) {
- $isLowerBetter = \true;
- }
- }
- public function getClientSideTranslationKeys(&$translationKeys)
- {
- $translationKeys[] = "SearchEngineKeywordsPerformance_LinksToUrl";
- $translationKeys[] = "SearchEngineKeywordsPerformance_SitemapsContainingUrl";
- $translationKeys[] = 'SearchEngineKeywordsPerformance_SearchEngineKeywordsPerformance';
- $translationKeys[] = 'SearchEngineKeywordsPerformance_ConfigurationDescription';
- $translationKeys[] = 'SearchEngineKeywordsPerformance_ProviderListDescription';
- $translationKeys[] = 'SearchEngineKeywordsPerformance_ChangeConfiguration';
- $translationKeys[] = 'SearchEngineKeywordsPerformance_SetupConfiguration';
- $translationKeys[] = 'SearchEngineKeywordsPerformance_BingConfigurationTitle';
- $translationKeys[] = 'SearchEngineKeywordsPerformance_BingConfigurationDescription';
- $translationKeys[] = 'SearchEngineKeywordsPerformance_ConfigureMeasurables';
- $translationKeys[] = 'SearchEngineKeywordsPerformance_ConfigureMeasurableBelow';
- $translationKeys[] = 'SearchEngineKeywordsPerformance_ConfigRemovalConfirm';
- $translationKeys[] = 'SearchEngineKeywordsPerformance_DomainProperty';
- $translationKeys[] = 'General_Measurable';
- $translationKeys[] = 'Mobile_Account';
- $translationKeys[] = 'Goals_URL';
- $translationKeys[] = 'SearchEngineKeywordsPerformance_LastImport';
- $translationKeys[] = 'SearchEngineKeywordsPerformance_NoWebsiteConfigured';
- $translationKeys[] = 'SearchEngineKeywordsPerformance_AddConfiguration';
- $translationKeys[] = 'CoreHome_ChooseX';
- $translationKeys[] = 'SearchEngineKeywordsPerformance_UrlOfAccount';
- $translationKeys[] = 'General_Save';
- $translationKeys[] = 'SearchEngineKeywordsPerformance_ManageAPIKeys';
- $translationKeys[] = 'SearchEngineKeywordsPerformance_AccountRemovalConfirm';
- $translationKeys[] = 'SearchEngineKeywordsPerformance_AccountAddedBy';
- $translationKeys[] = 'SearchEngineKeywordsPerformance_BingAccountError';
- $translationKeys[] = 'SearchEngineKeywordsPerformance_AccountNoAccess';
- $translationKeys[] = 'SearchEngineKeywordsPerformance_AvailableSites';
- $translationKeys[] = 'SearchEngineKeywordsPerformance_UnverifiedSites';
- $translationKeys[] = 'General_Remove';
- $translationKeys[] = 'SearchEngineKeywordsPerformance_AddAPIKey';
- $translationKeys[] = 'SearchEngineKeywordsPerformance_BingAPIKeyInstruction';
- $translationKeys[] = 'SearchEngineKeywordsPerformance_APIKey';
- $translationKeys[] = 'SearchEngineKeywordsPerformance_GoogleConfigurationTitle';
- $translationKeys[] = 'SearchEngineKeywordsPerformance_GoogleConfigurationDescription';
- $translationKeys[] = 'SearchEngineKeywordsPerformance_EnabledSearchTypes';
- $translationKeys[] = 'SearchEngineKeywordsPerformance_KeywordTypeWeb';
- $translationKeys[] = 'SearchEngineKeywordsPerformance_KeywordTypeImage';
- $translationKeys[] = 'SearchEngineKeywordsPerformance_KeywordTypeVideo';
- $translationKeys[] = 'SearchEngineKeywordsPerformance_KeywordTypeNews';
- $translationKeys[] = 'SearchEngineKeywordsPerformance_DomainPropertyInfo';
- $translationKeys[] = 'General_Delete';
- $translationKeys[] = 'SearchEngineKeywordsPerformance_ConnectGoogleAccounts';
- $translationKeys[] = 'SearchEngineKeywordsPerformance_CurrentlyConnectedAccounts';
- $translationKeys[] = 'SearchEngineKeywordsPerformance_ConnectFirstAccount';
- $translationKeys[] = 'SearchEngineKeywordsPerformance_OAuthError';
- $translationKeys[] = 'SearchEngineKeywordsPerformance_AccountConnectionValidationError';
- $translationKeys[] = 'SearchEngineKeywordsPerformance_ReAddAccountIfPermanentError';
- $translationKeys[] = 'SearchEngineKeywordsPerformance_ConnectAccount';
- $translationKeys[] = 'SearchEngineKeywordsPerformance_ConnectAccountDescription';
- $translationKeys[] = 'SearchEngineKeywordsPerformance_RequiredAccessTypes';
- $translationKeys[] = 'SearchEngineKeywordsPerformance_GoogleAccountAccessTypeSearchConsoleData';
- $translationKeys[] = 'SearchEngineKeywordsPerformance_GoogleAccountAccessTypeProfileInfo';
- $translationKeys[] = 'SearchEngineKeywordsPerformance_GoogleAccountAccessTypeOfflineAccess';
- $translationKeys[] = 'SearchEngineKeywordsPerformance_StartOAuth';
- $translationKeys[] = 'SearchEngineKeywordsPerformance_OAuthClientConfig';
- $translationKeys[] = 'SearchEngineKeywordsPerformance_ClientId';
- $translationKeys[] = 'SearchEngineKeywordsPerformance_ClientSecret';
- $translationKeys[] = 'SearchEngineKeywordsPerformance_HowToGetOAuthClientConfig';
- $translationKeys[] = 'SearchEngineKeywordsPerformance_VisitOAuthHowTo';
- $translationKeys[] = 'SearchEngineKeywordsPerformance_UploadOAuthClientConfig';
- $translationKeys[] = 'SearchEngineKeywordsPerformance_GoogleUploadOrPasteClientConfig';
- $translationKeys[] = 'SearchEngineKeywordsPerformance_ConfigurationFile';
- $translationKeys[] = 'SearchEngineKeywordsPerformance_Configuration';
- $translationKeys[] = 'SearchEngineKeywordsPerformance_CreatedBy';
- $translationKeys[] = 'SearchEngineKeywordsPerformance_YandexConfigurationTitle';
- $translationKeys[] = 'SearchEngineKeywordsPerformance_YandexConfigurationDescription';
- $translationKeys[] = 'SearchEngineKeywordsPerformance_ConnectYandexAccounts';
- $translationKeys[] = 'SearchEngineKeywordsPerformance_ReAuthenticateIfPermanentError';
- $translationKeys[] = 'SearchEngineKeywordsPerformance_OAuthAccessTimedOut';
- $translationKeys[] = 'SearchEngineKeywordsPerformance_OAuthAccessWillTimeOutSoon';
- $translationKeys[] = 'SearchEngineKeywordsPerformance_OAuthAccessWillTimeOut';
- $translationKeys[] = 'SearchEngineKeywordsPerformance_Reauthenticate';
- $translationKeys[] = 'SearchEngineKeywordsPerformance_ConnectAccountYandex';
- $translationKeys[] = 'SearchEngineKeywordsPerformance_SetUpOAuthClientConfig';
- $translationKeys[] = 'SearchEngineKeywordsPerformance_ProvideYandexClientConfig';
- $translationKeys[] = 'SearchEngineKeywordsPerformance_URLPrefixProperty';
- $translationKeys[] = 'SearchEngineKeywordsPerformance_URLPrefixPropertyInfo';
- $translationKeys[] = "SearchEngineKeywordsPerformance_OAuthExampleText";
- $translationKeys[] = "SearchEngineKeywordsPerformance_GoogleAuthorizedJavaScriptOrigin";
- $translationKeys[] = "SearchEngineKeywordsPerformance_GoogleAuthorizedRedirectUri";
- $translationKeys[] = "SearchEngineKeywordsPerformance_YandexFieldUrlToAppSite";
- $translationKeys[] = "SearchEngineKeywordsPerformance_YandexFieldCallbackUri";
- $translationKeys[] = "SearchEngineKeywordsPerformance_RecentApiErrorsWarning";
- $translationKeys[] = "SearchEngineKeywordsPerformance_ConfigureTheImporterLabel1";
- $translationKeys[] = "SearchEngineKeywordsPerformance_ConfigureTheImporterLabel2";
- $translationKeys[] = "SearchEngineKeywordsPerformance_ConfigureTheImporterLabel3";
- $translationKeys[] = "SearchEngineKeywordsPerformance_OauthFailedMessage";
- $translationKeys[] = "General_Upload";
- $translationKeys[] = 'SearchEngineKeywordsPerformance_Uploading';
- $translationKeys[] = 'SearchEngineKeywordsPerformance_DeleteUploadedClientConfig';
- $translationKeys[] = 'SearchEngineKeywordsPerformance_GooglePendingConfigurationErrorMessage';
- if (Manager::getInstance()->isPluginActivated('ConnectAccounts')) {
- $translationKeys[] = "ConnectAccounts_ConfigureGoogleAuthHelp1";
- $translationKeys[] = "ConnectAccounts_ConfigureGoogleAuthHelp2";
- $translationKeys[] = "ConnectAccounts_OptionQuickConnectWithGa";
- $translationKeys[] = "ConnectAccounts_OptionAdvancedConnectWithGa";
- $translationKeys[] = "ConnectAccounts_ConnectedWithBody";
- $translationKeys[] = "ConnectAccounts_ReAuthorizeBody";
- $translationKeys[] = "ConnectAccounts_ReAuthorizeBtnText";
- $translationKeys[] = "ConnectAccounts_ConnectedWithHeader";
- $translationKeys[] = "ConnectAccounts_ConnectedWithBody[beforeLink]";
- $translationKeys[] = "ConnectAccounts_ConnectedWithBody[linkText]";
- $translationKeys[] = "ConnectAccounts_GaImportBtn";
- }
- }
- /**
- * Installation
- */
- public function install()
- {
- GoogleModel::install();
- BingModel::install();
- YandexModel::install();
- }
- public static function isGoogleForceEnabled($idSite)
- {
- return self::isSearchEngineForceEnabled('google', $idSite);
- }
- public static function isBingForceEnabled($idSite)
- {
- return self::isSearchEngineForceEnabled('bing', $idSite);
- }
- public static function isYandexForceEnabled($idSite)
- {
- return self::isSearchEngineForceEnabled('yandex', $idSite);
- }
- public static function isSearchEngineForceEnabled($searchEngine, $idSite)
- {
- if (!is_numeric($idSite) || $idSite <= 0) {
- return \false;
- }
- $cache = Cache::getTransientCache();
- $cacheKey = 'SearchEngineKeywordsPerformance.isSearchEngineForceEnabled.' . $searchEngine . '.' . $idSite;
- if ($cache->contains($cacheKey)) {
- return $cache->fetch($cacheKey);
- }
- $result = \false;
- /**
- * @ignore
- */
- Piwik::postEvent('SearchEngineKeywordsPerformance.isSearchEngineForceEnabled', [&$result, $searchEngine, $idSite]);
- // force enable reports for rollups where child pages are configured
- if (class_exists('\\Piwik\\Plugins\\RollUpReporting\\Type') && \Piwik\Plugins\RollUpReporting\Type::ID === Site::getTypeFor($idSite)) {
- //Need to execute this as a superuser, since a user can have access to a rollup site but not all the child sites
- Access::doAsSuperUser(function () use ($searchEngine, $idSite, &$result) {
- $rollUpModel = new \Piwik\Plugins\RollUpReporting\Model();
- $childIdSites = $rollUpModel->getChildIdSites($idSite);
- foreach ($childIdSites as $childIdSite) {
- $measurableSettings = new \Piwik\Plugins\SearchEngineKeywordsPerformance\MeasurableSettings($childIdSite);
- if ($searchEngine === 'google' && $measurableSettings->googleSearchConsoleUrl && $measurableSettings->googleSearchConsoleUrl->getValue()) {
- $result = \true;
- break;
- }
- if ($searchEngine === 'yandex' && $measurableSettings->yandexAccountAndHostId && $measurableSettings->yandexAccountAndHostId->getValue()) {
- $result = \true;
- break;
- }
- if ($searchEngine === 'bing' && $measurableSettings->bingSiteUrl && $measurableSettings->bingSiteUrl->getValue()) {
- $result = \true;
- break;
- }
- }
- });
- }
- $cache->save($cacheKey, $result);
- return $result;
- }
- /**
- * Take the list of providers and determine if any of them have had any recent API errors that need to be surfaced
- * to the customer as a notification. If there are any, it generates the notification message and displays it.
- *
- * @param array $providers Collection of providers (like Google, Bing, ...) that extend the ProviderAbstract class.
- * @return void
- * @throws \Exception
- */
- public static function displayNotificationIfRecentApiErrorsExist(array $providers): void
- {
- $recentErrorMessages = [];
- foreach ($providers as $provider) {
- $message = '';
- if ($provider->hasApiErrorWithinWeek()) {
- $message = $provider->getRecentApiErrorMessage();
- }
- if (!empty($message)) {
- $recentErrorMessages[] = $message;
- }
- }
- // Show notification if there have been errors
- if (count($recentErrorMessages) > 0) {
- $providerNameString = implode(' ', $recentErrorMessages);
- $notification = new Notification(Piwik::translate('SearchEngineKeywordsPerformance_RecentApiErrorsWarning', [$providerNameString]));
- $notification->context = Notification::CONTEXT_WARNING;
- $notification->raw = \true;
- Notification\Manager::notify('sekp_api_errors', $notification);
- }
- }
- public function getGoogleConfigComponent(&$componentExtensions)
- {
- $googleClient = ProviderGoogle::getInstance()->getClient();
- $clientConfigured = \true;
- // try to configure client (which imports provided client configs)
- try {
- $googleClient->getConfiguredClient('');
- } catch (\Exception $e) {
- // ignore errors
- $clientConfigured = \false;
- }
- if (!$clientConfigured) {
- // Only set index 0 if it hasn't already been set, since we want ConnectAccounts to take precedence
- $componentExtensions[0] = $componentExtensions[0] ?? ['plugin' => 'SearchEngineKeywordsPerformance', 'component' => 'ConfigureConnection'];
- }
- return $componentExtensions;
- }
-
-
- public static function isReportEnabled($reportType, $googleType = '')
- {
- $report = new \Piwik\Plugins\SearchEngineKeywordsPerformance\Reports\GetKeywords();
- if ($reportType === 'Yandex') {
- return $report->isYandexEnabled();
- } elseif ($reportType === 'Bing') {
- return $report->isBingEnabled();
- } elseif ($reportType === 'Google' && !empty($googleType)) {
- return $report->isGoogleEnabledForType($googleType);
- }
-
- return false;
- }
-
- public static function commonEmptyDataTable($period, $date)
- {
- if (Period::isMultiplePeriod($date, $period)) {
- return new DataTable\Map();
- }
- return new DataTable();
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/SystemSettings.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/SystemSettings.php
deleted file mode 100644
index b38d3c5..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/SystemSettings.php
+++ /dev/null
@@ -1,41 +0,0 @@
-roundKeywordPosition = $this->createRoundKeywordPosition();
- }
- private function createRoundKeywordPosition()
- {
- return $this->makeSetting('roundKeywordPosition', $default = \true, FieldConfig::TYPE_BOOL, function (FieldConfig $field) {
- $field->title = Piwik::translate('SearchEngineKeywordsPerformance_RoundKeywordPosition');
- $field->uiControl = FieldConfig::UI_CONTROL_CHECKBOX;
- });
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Tasks.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Tasks.php
deleted file mode 100644
index b826484..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Tasks.php
+++ /dev/null
@@ -1,101 +0,0 @@
-getAllSitesId();
- foreach ($siteIds as $idSite) {
- $setting = new \Piwik\Plugins\SearchEngineKeywordsPerformance\MeasurableSettings($idSite);
- $searchConsoleUrl = $setting->googleSearchConsoleUrl;
- if ($searchConsoleUrl && $searchConsoleUrl->getValue()) {
- $this->daily('runImportsGoogle', $idSite);
- }
- $bingSiteUrl = $setting->bingSiteUrl;
- if ($bingSiteUrl && $bingSiteUrl->getValue()) {
- $this->daily('runImportsBing', $idSite);
- }
- $yandexConfig = $setting->yandexAccountAndHostId;
- if ($yandexConfig && $yandexConfig->getValue()) {
- $this->daily('runImportsYandex', $idSite);
- }
- }
- }
- /**
- * Run Google importer for the last X available dates
- * To calculate the amount of imported days a timestamp of the last run will be saved
- * and checked how many days it was ago. This ensures dates will be imported even if
- * the tasks doesn't run some days. And it also ensure that all available dates will be
- * imported on the first run, as no last run has been saved before
- *
- * @param int $idSite
- */
- public function runImportsGoogle($idSite)
- {
- $lastRun = Option::get('GoogleImporterTask_LastRun_' . $idSite);
- $now = time();
- $limitDays = 0;
- if ($lastRun) {
- $difference = $now - $lastRun;
- $limitDays = ceil($difference / (3600 * 24));
- }
- $importer = new GoogleImporter($idSite);
- $importer->importAllAvailableData($limitDays);
- Option::set('GoogleImporterTask_LastRun_' . $idSite, $now);
- }
- /**
- * Run Bing importer
- *
- * @param int $idSite
- */
- public function runImportsBing($idSite)
- {
- $importer = new BingImporter($idSite);
- $importer->importAllAvailableData();
- Option::set('BingImporterTask_LastRun_' . $idSite, time());
- }
- /**
- * Run Yandex importer
- *
- * @param int $idSite
- */
- public function runImportsYandex($idSite)
- {
- $lastRun = Option::get('YandexImporterTask_LastRun_' . $idSite);
- $now = time();
- $limitDays = 100;
- // import 100 days initially
- if ($lastRun) {
- $difference = $now - $lastRun;
- $limitDays = ceil($difference / (3600 * 24)) + 7;
- }
- $importer = new YandexImporter($idSite);
- $importer->importAllAvailableData($limitDays);
- Option::set('YandexImporterTask_LastRun_' . $idSite, time());
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Updates/3.5.0.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Updates/3.5.0.php
deleted file mode 100644
index 99b14f7..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Updates/3.5.0.php
+++ /dev/null
@@ -1,45 +0,0 @@
-migration = $factory;
- }
- public function getMigrations(Updater $updater)
- {
- $migrations = [];
- $migrations[] = $this->migration->db->changeColumnType('bing_stats', 'type', 'VARCHAR(15)');
- $migrations[] = $this->migration->db->changeColumnType('bing_stats', 'url', 'VARCHAR(170)');
- $migrations[] = $this->migration->db->changeColumnType('google_stats', 'url', 'VARCHAR(170)');
- return $migrations;
- }
- public function doUpdate(Updater $updater)
- {
- $updater->executeMigrations(__FILE__, $this->getMigrations($updater));
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Updates/4.1.0.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Updates/4.1.0.php
deleted file mode 100644
index 4294903..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/Updates/4.1.0.php
+++ /dev/null
@@ -1,30 +0,0 @@
- \true,
- 'Piwik\\Plugins\\SearchEngineKeywordsPerformance\\Client\\Google' => \Piwik\DI::autowire(),
- 'diagnostics.optional' => \Piwik\DI::add([
- \Piwik\DI::get('Piwik\\Plugins\\SearchEngineKeywordsPerformance\\Diagnostic\\BingAccountDiagnostic'),
- \Piwik\DI::get('Piwik\\Plugins\\SearchEngineKeywordsPerformance\\Diagnostic\\GoogleAccountDiagnostic'),
- \Piwik\DI::get('Piwik\\Plugins\\SearchEngineKeywordsPerformance\\Diagnostic\\YandexAccountDiagnostic')
- ]),
- // defines the number of days the plugin will try to import Google keywords for
- // Google API itself currently supports up to 500 days in the past
- 'SearchEngineKeywordsPerformance.Google.ImportLastDaysMax' => 365,
- 'SearchEngineKeywordsPerformance.Google.googleClient' => function (\Piwik\Container\Container $c) {
- $googleClient = new \Matomo\Dependencies\SearchEngineKeywordsPerformance\Google\Client();
- $googleClient->addScope(\Matomo\Dependencies\SearchEngineKeywordsPerformance\Google\Service\SearchConsole::WEBMASTERS_READONLY);
- $googleClient->addScope(\Matomo\Dependencies\SearchEngineKeywordsPerformance\Google\Service\Oauth2::USERINFO_PROFILE);
- $googleClient->setAccessType('offline');
- $googleClient->setApprovalPrompt('force');
- $redirectUrl = Url::getCurrentUrlWithoutQueryString() . '?module=SearchEngineKeywordsPerformance&action=processAuthCode';
- $googleClient->setRedirectUri($redirectUrl);
- return $googleClient;
- },
-];
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/docs/index.md b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/docs/index.md
deleted file mode 100644
index f8e8d71..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/docs/index.md
+++ /dev/null
@@ -1,3 +0,0 @@
-## Documentation
-
-The [Search Engine Keywords Performance User Guide](https://matomo.org/docs/search-engine-keywords-performance/) and the [Search Engine Keywords Performance FAQ](https://matomo.org/faq/search-engine-keywords-performance/) cover how to get the most out of this plugin.
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/images/Bing.png b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/images/Bing.png
deleted file mode 100644
index 3436b29..0000000
Binary files a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/images/Bing.png and /dev/null differ
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/images/Google.png b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/images/Google.png
deleted file mode 100644
index b0699bf..0000000
Binary files a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/images/Google.png and /dev/null differ
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/images/Yahoo.png b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/images/Yahoo.png
deleted file mode 100644
index ce31701..0000000
Binary files a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/images/Yahoo.png and /dev/null differ
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/images/Yandex.png b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/images/Yandex.png
deleted file mode 100644
index 4271c86..0000000
Binary files a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/images/Yandex.png and /dev/null differ
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/lang/bg.json b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/lang/bg.json
deleted file mode 100644
index 75425f8..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/lang/bg.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "SearchEngineKeywordsPerformance": {
- "AccountAddedBy": "Добавено от %1$s на %2$s",
- "AccountConnectionValidationError": "Възникна грешка при валидиране на връзката с акаунта:"
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/lang/de.json b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/lang/de.json
deleted file mode 100644
index ed91db3..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/lang/de.json
+++ /dev/null
@@ -1,224 +0,0 @@
-{
- "SearchEngineKeywordsPerformance": {
- "APIKey": "API-Key",
- "AccountAddedBy": "Hinzugefügt von %1$s am %2$s",
- "AccountConnectionValidationError": "Beim Überprüfen der Konto-Verknüpfung ist ein Fehler aufgetreten:",
- "AccountDoesNotExist": "Das konfigurierte Konto %1$s existiert nicht mehr",
- "AccountNoAccess": "Dieses Konto hat derzeit keinen Zugriff auf irgendeine Website.",
- "AccountRemovalConfirm": "Sie sind im Begriff das Konto %1$s zu löschen. Dies deaktiviert den Import für all noch verknüpften Websites. Trotzdem fortfahren?",
- "ActivityAccountAdded": "hat ein neues Konto für die Suchbegriff-Anbindung von %1$s hinzugefügt: %2$s",
- "ActivityAccountRemoved": "hat ein Konto für die Suchbegriff-Anbindung von %1$s entfernt: %2$s",
- "ActivityGoogleClientConfigChanged": "Hat die Google-Client Konfiguration geändert.",
- "ActivityYandexClientConfigChanged": "Hat die Yandex-Client Konfiguration geändert.",
- "AddAPIKey": "API-Key hinzufügen",
- "AddConfiguration": "Konfiguration hinzufügen",
- "AllReferrersImported": "Verweise (mit importierten Suchbegriffen)",
- "AllReferrersOriginal": "Verweise (mit getrackten Suchbegriffen)",
- "AvailableSites": "Für den Import verfügbare Websites:",
- "BingAPIKeyInstruction": "Melden Sie sich bei den %1$sBing Webmaster Tools%2$s an, dann fügen Sie ihre Website zu Bing Webmaster hinzu. Sobald diese bestätigt wurde, können Sie %3$sihren API-Key kopieren%4$s.",
- "BingAccountError": "Bei der Überprüfung des API-Keys ist ein Fehler aufgetreten: %1$s. Falls Sie diesen API-Key gerade erst in den Bing Webmaster Tools erzeugt haben, versuchen Sie es in einigen Minuten nochmal (API-Keys für die Bing Webmaster Tools benötigen eine Weile bis sie aktiviert sind).",
- "BingAccountOk": "API-Key erfolgreich überprüft",
- "BingConfigurationDescription": "Der Zugriff auf die Bing Webmaster Tools benötigt einen API-Key. Hier können Sie API-Keys hinzufügen, um auf die Daten Ihrer Website zuzugreifen.",
- "BingConfigurationTitle": "Import über Bing Webmaster Tools konfigurieren",
- "BingCrawlBlockedByRobotsTxt": "Robots.txt Ausnahmen",
- "BingCrawlBlockedByRobotsTxtDesc": "URLs, deren Zugriff aktuell durch die robots.txt Ihrer Website verhindert wird.",
- "BingCrawlConnectionTimeout": "Verbindungs-Timeouts ",
- "BingCrawlConnectionTimeoutDesc": "Diese Zahl steht für aktuelle Ereignisse, bei denen Bing aufgrund von Verbindungsfehlern nicht auf Ihre Website zugreifen konnte. Dies könnte ein vorübergehendes Problem sein, aber Sie sollten Ihre Serverprotokolle überprüfen, um zu sehen, ob Anfragen unbeabsichtigt verloren gehen.",
- "BingCrawlCrawledPages": "Gecrawlte Seiten",
- "BingCrawlCrawledPagesDesc": "Anzahl der Seiten die der Bing Crawler abgerufen hat.",
- "BingCrawlDNSFailures": "DNS Fehler",
- "BingCrawlDNSFailuresDesc": "Dieser Fehlertyp katalogisiert aktuelle Fehler, die bei der Kommunikation mit dem DNS-Server aufgetreten sind, als der Bot versuchte, auf Ihre Seiten zuzugreifen. Möglicherweise war Ihr Server ausgefallen, oder es gab eine Fehlkonfiguration, die ein DNS-Routing verhinderte, z.B. wurde TTL auf 0 gesetzt.",
- "BingCrawlErrors": "Crawlerfehler bei Bing",
- "BingCrawlErrorsDesc": "Anzahl der aufgetretenen Fehler für den Bing-Crawler.",
- "BingCrawlErrorsFromDateX": "Der Bericht zeigt Crawling-Fehler, die kürzlich von Bing gemeldet wurden. Er liefert keine historischen Daten. Zuletzt aktualisiert: %s",
- "BingCrawlHttpStatus2xx": "HTTP-Status 200-299",
- "BingCrawlHttpStatus2xxDesc": "Diese Codes treten auf, wenn der Server eine Seite erfolgreich bereitstellt",
- "BingCrawlHttpStatus301": "HTTP-Status 301 (Dauerhaft verschoben)",
- "BingCrawlHttpStatus301Desc": "Diese Codes treten auf, wenn Inhalte dauerhaft von einem Ort (URL) zu einem anderen verschoben wurden.",
- "BingCrawlHttpStatus302": "HTTP-Status 302 (Temporär verschoben)",
- "BingCrawlHttpStatus302Desc": "Diese Codes treten auf, wenn Sie Inhalte vorübergehend von einem Ort (URL) zu einem anderen verschoben haben.",
- "BingCrawlHttpStatus4xx": "HTTP-Status 400-499 (Anfragefehler)",
- "BingCrawlHttpStatus4xxDesc": "Diese Codes treten auf, wenn wahrscheinlich ein Fehler in der Anfrage vorlag, der den Server daran hinderte, sie zu verarbeiten.",
- "BingCrawlHttpStatus5xx": "HTTP Code 500-599 (Interne Server-Fehler)",
- "BingCrawlHttpStatus5xxDesc": "Diese Codes treten auf, wenn der Server eine scheinbar gültige Anforderung nicht beantworten konnte.",
- "BingCrawlImportantBlockedByRobotsTxt": "Ausschluss einer wichtigen Seite durch robots.txt",
- "BingCrawlInboundLink": "Eingehende Link insgesamt",
- "BingCrawlInboundLinkDesc": "Eingehende Links, die Bing bekannt sind und auf URLs auf Ihrer Website verweisen. Dies sind Links von Websites außerhalb Ihrer eigenen, die auf Ihre Inhalte verweisen.",
- "BingCrawlMalwareInfected": "Mit Malware infizierte Seiten",
- "BingCrawlMalwareInfectedDesc": "Alle Seiten-URLs, die Bing gefunden hat und die infiziert sind oder mit Malware in Verbindung gebracht werden, werden in diesem Abschnitt zusammengefasst.",
- "BingCrawlPagesInIndex": "Seiten insg. im Index",
- "BingCrawlPagesInIndexDesc": "Gesamtzahl der Seiten die im Bing Index vorhanden sind",
- "BingCrawlStatsOtherCodes": "Alle übrigen HTTP-Status",
- "BingCrawlStatsOtherCodesDesc": "Gruppiert alle anderen Codes, die keinem anderen Wert entsprechen (z.B. 1xx oder Informationscodes).",
- "BingCrawlingStats": "Crawl-Übersicht für Bing und Yahoo!",
- "BingCrawlingStatsDocumentation": "Die Crawl-Übersicht ermöglicht es Ihnen, Informationen zum Crawlen anzuzeigen, wie z.B. Fehler, die der Suchbot beim Besuch einer Seite feststellt, Elemente, die durch Ihre robots.txt-Datei blockiert werden und URLs, die möglicherweise von Malware befallen sind.",
- "BingKeywordImport": "Import von Suchbegriffen auf Bing",
- "BingKeywords": "Suchbegriffe (auf Bing und Yahoo!)",
- "BingKeywordsDocumentation": "Suchbegriffe, die in der Suche auf Bing oder Yahoo! verwendet wurden und Links zu Ihrer Website in der Suchergebnisliste generiert haben.",
- "BingKeywordsNoRangeReports": "Keywords auf Bing und Yahoo! können nur für benutzerdefinierte Datumsbereiche mit vollständigen Wochen oder Monaten verarbeitet werden, da sie nicht als Tagesberichte verfügbar sind.",
- "BingKeywordsNotDaily": "Keywords zu Bing und Yahoo! sind nur als Wochenberichte verfügbar. Es gibt keine Keyword-Daten für einzelne Tage.",
- "BingWebmasterApiUrl": "Url für Bing Webmaster Tools",
- "BingWebmasterApiUrlDescription": "Geben Sie die URL an, mit der diese Website in Ihren Bing Webmaster Tools verfügbar ist",
- "Category": "Kategorie",
- "ChangeConfiguration": "Konfiguration ändern",
- "Clicks": "Klicks",
- "ClicksDocumentation": "Hier wird jeder Klick auf einen Link auf einer Suchergebnisseite gezählt, der zu Ihrer Website zeigt.",
- "ClientConfigImported": "Client-Konfiguration wurde erfolgreich importiert!",
- "ClientConfigSaveError": "Beim Speichern der Client-Konfiguration ist ein Fehler aufgetreten. Bitte überprüfen Sie, ob die angegebene Konfiguration gültig ist, und versuchen Sie es erneut.",
- "ClientId": "Client-ID",
- "ClientSecret": "Clientschlüssel",
- "ConfigAvailableNoWebsiteConfigured": "Anbindung erfolgreich konfiguriert, allerdings sind derzeit keine Websites für den Import konfiguriert.",
- "ConfigRemovalConfirm": "Sie sind dabei, die Konfiguration für %1$s zu entfernen. Der Import von Keywords für diese Website wird deaktiviert. Trotzdem fortfahren?",
- "Configuration": "Konfiguration",
- "ConfigurationDescription": "Dieses Plugin ermöglicht es Ihnen alle Suchbegriffe, nach denen Ihre Benutzer auf Suchmaschinen gesucht haben, direkt in Matomo zu importieren.",
- "ConfigurationFile": "Konfigurationsdatei",
- "ConfigurationValid": "Ihre OAuth Konfiguration ist gültig.",
- "ConfigureMeasurableBelow": "Um eine Website zu konfigurieren, klicken Sie einfach den Button unterhalb oder konfigurieren Sie dies direkt in den Website-Einstellungen.",
- "ConfigureMeasurables": "Websites konfigurieren",
- "ConfiguredAccounts": "Konfigurierte Accounts",
- "ConfiguredUrlNotAvailable": "Die konfigurierte URL steht für dieses Konto nicht zur Verfügung",
- "ConnectAccount": "Konto verknüpfen",
- "ConnectAccountDescription": "Bitte klicken Sie auf den folgenden Button. Sie werden dann zu %1$s weitergeleitet, um dem Zugriff zuzustimmen.",
- "ConnectAccountYandex": "Die Authentifizierung für Yandex-Konten ist nur %1$s Tage lang gültig. Jedes Konto muss innerhalb dieser Zeit neu authentifiziert werden, damit Importe korrekt funktionieren.",
- "ConnectFirstAccount": "Beginnen Sie, indem Sie Ihr erstes Konto verknüpfen.",
- "ConnectGoogleAccounts": "Google Konten verknüpfen",
- "ConnectYandexAccounts": "Yandex Konten verknüpfen",
- "ContainingSitemaps": "Enthaltende Sitemaps",
- "CrawlingErrors": "Crawling-Fehler",
- "CrawlingOverview1": "Die Crawling-Übersicht enthält die wichtigsten Informationen darüber, wie die Suchmaschinen Ihre Websites crawlen. Diese Metriken werden etwa einmal pro Tag mit Daten aktualisiert, die von den Suchmaschinen bereitgestellt werden.",
- "CrawlingStats": "Crawling Übersicht",
- "Ctr": "CTR",
- "CtrDocumentation": "Klickrate: Gibt das Verhältnis an wie häufig Benutzer, die einen Link auf Ihre Website auf einer Suchergebnisseite gesehen haben auch darauf geklickt haben.",
- "CurrentlyConnectedAccounts": "Aktuell sind %1$s Konten verknüpft.",
- "Domain": "Domain",
- "DomainProperty": "Domain-Property",
- "DomainPropertyInfo": "Enthält alle Subdomains (m, www etc.) und beide Protokolle (http, https).",
- "EnabledSearchTypes": "Abzurufende Keyword-Arten",
- "FetchImageKeyword": "Bilder-Keywords abrufen",
- "FetchImageKeywordDesc": "Abrufen von Keywords welche in der Google Bildsuche verwendet wurden",
- "FetchNewsKeyword": "News-Keywords abrufen",
- "FetchNewsKeywordDesc": "Abrufen von Keywords welche in auf Google News verwendet wurden",
- "FetchVideoKeyword": "Video-Keywords abrufen",
- "FetchVideoKeywordDesc": "Abrufen von Keywords welche in der Google Videosuche verwendet wurden",
- "FetchWebKeyword": "Web-Keywords abrufen",
- "FetchWebKeywordDesc": "Abrufen von Keywords welche in der Google Websuche verwendet wurden",
- "FirstDetected": "Zuerst erkannt",
- "GoogleAccountAccessTypeOfflineAccess": "Offline Zugriff wird benötigt damit die Suchbegriffe auf dann im Hintergrund importiert werden können, wenn Sie gerade nicht aktiv eingeloggt sind.",
- "GoogleAccountAccessTypeProfileInfo": "Personenbezogene Daten aufrufen wird verwendet, um den Namen der aktuell verbundenen Konten anzuzeigen.",
- "GoogleAccountAccessTypeSearchConsoleData": "Search Console-Daten ist erforderlich, um Zugriff auf Ihre Google-Suchbegriffe zu erhalten.",
- "GoogleAccountError": "Bei der Überprüfung des OAuth-Zugriffs ist ein Fehler aufgetreten: %1$s",
- "GoogleAccountOk": "OAuth-Zugriff erfolgreich überprüft.",
- "GoogleConfigurationDescription": "Google Search Console verwendet OAuth zur Authentifizierung und Autorisierung.",
- "GoogleConfigurationTitle": "Import von Google Search Console konfigurieren",
- "GoogleDataNotFinal": "Die Suchbegriffe in diesem Bericht enthalten möglicherweise noch nicht die endgültigen Daten. Google stellt endgültige Suchbegriffe mit einer Verzögerung von 2 Tagen bereit. Suchbegriffe für neuere Tage werden erneut importiert, bis sie als endgültig gemeldet werden.",
- "GoogleDataProvidedWithDelay": "Google stellt Suchbegriffe mit einer Verzögerung zur Verfügung. Die Suchbegriffe für dieses Datum werden etwas später importiert.",
- "GoogleKeywordImport": "Google Keyword Import",
- "GoogleSearchConsoleUrl": "Url für Google Search Console",
- "GoogleSearchConsoleUrlDescription": "Geben Sie die URL an, mit der diese Website in Ihrer Google Search Console verfügbar ist",
- "GoogleUploadOrPasteClientConfig": "Bitte laden Sie Ihre Google OAuth Client-Konfiguration hoch oder fügen Sie sie in das untenstehende Feld ein.",
- "HowToGetOAuthClientConfig": "Woher bekomme ich meine OAuth-Client Konfiguration",
- "ImageKeywords": "Bilder Suchbegriffe auf Google",
- "ImageKeywordsDocumentation": "Suchbegriffe, die in der Google-Bildersuche verwendet wurden und Links zu Ihrer Website in der Suchergebnisliste generiert haben.",
- "Impressions": "Impressionen",
- "ImpressionsDocumentation": "Als Impression zählt die Anzeige Ihrer Website auf einer Suchergebnisseite.",
- "IntegrationConfigured": "Anbindung erfolgreich konfiguriert",
- "IntegrationNotConfigured": "Anbindung noch nicht konfiguriert",
- "KeywordStatistics": "Suchbegriffe",
- "KeywordTypeImage": "Bild",
- "KeywordTypeNews": "News",
- "KeywordTypeVideo": "Video",
- "KeywordTypeWeb": "Web",
- "KeywordsCombined": "Suchbegriffe (kombiniert)",
- "KeywordsCombinedDocumentation": "Bericht, der alle von Matomo erkannten und von Suchmaschinen importierten Keywords kombiniert. Dieser Bericht enthält nur die Besuchsmetrik. Sie können zu einem der zugehörigen Berichte wechseln, um detaillierte Kennzahlen zu erhalten.",
- "KeywordsCombinedImported": "Importierte Suchbegriffe kombiniert",
- "KeywordsCombinedImportedDocumentation": "Dieser Bericht zeigt alle Suchbegriffe die von allen konfigurierten Suchmaschinen importiert wurden.",
- "KeywordsReferrers": "Suchbegriffe (inklusive nicht definierter)",
- "KeywordsSubtableImported": "Importierte Keywords",
- "KeywordsSubtableOriginal": "Tracked Keywords (inkl. nicht definierte)",
- "LastCrawled": "Zuletzt gecrawlt",
- "LastDetected": "Zuletzt erkannt",
- "LastImport": "Letzter Import",
- "LatestAvailableDate": "Die neuesten verfügbaren Keyword-Daten sind für %1$s",
- "LinksToUrl": "Links auf %s",
- "ManageAPIKeys": "API-Schlüssel verwalten",
- "MeasurableConfig": "Konfigurierte Websites",
- "NewsKeywords": "Suchbegriffe auf Google News",
- "NewsKeywordsDocumentation": "Suchbegriffe, die in der Google-Newssuche verwendet wurden und Links zu Ihrer Website in der Suchergebnisliste generiert haben.",
- "NoSegmentation": "Der Bericht unterstützt keine Segmentierung. Bei den angezeigten Daten handelt es sich um Ihre standardmäßigen, unsegmentierten Berichtsdaten.",
- "NoWebsiteConfigured": "Es ist derzeit keine Website konfiguriert. Um den Import für eine Website zu aktivieren, konfigurieren Sie dies bitte hier.",
- "NoWebsiteConfiguredWarning": "Import von %s nicht vollständig konfiguriert. Sie müssen eine Website konfigurieren, um den Import zu aktivieren.",
- "NotAvailable": "Nicht verfügbar",
- "OAuthAccessTimedOut": "Der OAuth-Zugang für dieses Konto hat möglicherweise sein Zeitlimit überschritten. Sie müssen sich neu authentifizieren, damit die Importe für dieses Konto wieder funktionieren.",
- "OAuthAccessWillTimeOut": "Der OAuth-Zugang für dieses Konto läuft nach %1$s Tagen ab. Noch %2$s Tage verbleibend",
- "OAuthAccessWillTimeOutSoon": "Der OAuth-Zugang für dieses Konto läuft in etwa %1$s Tagen ab. Bitte authentifizieren Sie sich erneut, um zu vermeiden, dass Importe für dieses Konto nicht mehr funktionieren.",
- "OAuthClientConfig": "OAuth-Client Konfiguration",
- "OAuthError": "Innerhalb des OAuth-Prozesses ist ein Fehler aufgetreten. Bitte versuchen Sie es erneut und stellen Sie sicher, dass Sie die angeforderten Berechtigungen akzeptieren.",
- "Platform": "Plattform",
- "Position": "durchschn. Position",
- "PositionDocumentation": "Durchschnittliche Position Ihrer Website in der Suchergebnisliste (für diesen Suchbegriff).",
- "ProvideYandexClientConfig": "Bitte fügen Sie Ihre Yandex OAuth-Client-Konfiguration ein.",
- "ProviderBingDescription": "Importieren Sie alle Keywords, die verwendet werden, um Ihre Website bei Bing und Yahoo! zu finden.",
- "ProviderBingNote": "Anmerkung: Microsoft stellt Suchbegriffe nur jeden Samstag für ganze Wochen zur Verfügung. Daher kann es ein paar Tage dauern bis die ersten Suchbegriffe in den Berichten angezeigt werden. Zudem stehen diese nur für Wochen-, Monats- sowie Jahres-Berichte zur Verfügung.",
- "ProviderGoogleDescription": "Importieren Sie alle Keywords, mit denen Ihre Website in der Google-Suche gefunden wird. Berichte zeigen Ihre Keywords für jeden Suchtyp separat an (Web, Bilder und Videos).",
- "ProviderGoogleNote": "Anmerkung: Google stellt finale Suchbegriffe mit einer Verzögerung von 2 Tagen zur Verfügung. Nicht endgültige Daten für neuere Tage werden bereits angezeigt, werden aber erneut importiert, bis sie endgültig sind. Der erste Import kann möglicherweise Ihre historischen Suchbegriffe der letzten bis zu 486 Tagen importieren.",
- "ProviderListDescription": "Wenn Sie unten eine (oder mehrere) Suchmaschinen erfolgreich eingerichtet haben, können Sie konfigurieren, in welche Website(s) Matomo Ihre Suchbegriffe importieren soll.",
- "ProviderXAccountWarning": "Probleme bei der Kontokonfiguration erkannt Bitte überprüfen Sie die konfigurierten Konten für%s.",
- "ProviderXSitesWarning": "Probleme bei der Website-Konfiguration erkannt Bitte überprüfen Sie die konfigurierten Webseiten für %s.",
- "ProviderYandexDescription": "Importieren Sie alle Suchbegriffe, mit denen Ihre Website in der Yandex-Suche gefunden wird.",
- "ProviderYandexNote": "Anmerkung: Yandex stellt Suchbegriffe mit einem Versatz von bis zu 5 Tagen zur Verfügung. Beim ersten Import wird versucht, Ihre historischen Suchbegriffe der letzten bis zu 100 Tagen zu importieren.",
- "ReAddAccountIfPermanentError": "Sollte dieser Fehler dauerhaft auftreten, entfernen Sie bitte das Konto und verknüpfen Sie es erneut.",
- "ReAuthenticateIfPermanentError": "Sollte dieser Fehler dauerhaft auftreten, versuchen Sie, das Konto erneut zu authentifizieren oder es zu entfernen und erneut zu verbinden.",
- "Reauthenticate": "Erneut authentifizieren",
- "ReportShowMaximumValues": "Bei den angezeigten Werten handelt es sich um die Maximalwerte, die im gewählten Zeitraum auftraten.",
- "RequiredAccessTypes": "Folgende Zugriffsrechte werden benötigt:",
- "ResponseCode": "Response-Code",
- "RoundKeywordPosition": "Runden der Keyword-Position",
- "SearchEngineKeywordsPerformance": "Leistung von Suchmaschinen-Keywords",
- "SearchEnginesImported": "Suchmaschinen (mit importierten Suchbegriffen)",
- "SearchEnginesOriginal": "Suchmaschinen (mit getrackten Suchbegriffen)",
- "SetUpOAuthClientConfig": "Einrichten Ihrer OAuth-Client-Konfiguration",
- "SetupConfiguration": "Einrichten der Konfiguration",
- "SitemapsContainingUrl": "Sitemaps die %s beinhalten",
- "StartOAuth": "OAuth-Prozess starten",
- "URLPrefix": "URL-Präfix",
- "URLPrefixProperty": "URL-Präfix Property",
- "URLPrefixPropertyInfo": "Enthält nur URLs mit exakt angegebenem Präfix, einschließlich Protokoll (http oder https). Wenn Ihre Property alle Protokolle oder Subdomains (http, https, www, m usw.) umfassen soll, können Sie stattdessen eine Domain-Property hinzufügen.",
- "UnverifiedSites": "Unbestätigte Websites:",
- "UploadOAuthClientConfig": "Laden Sie Ihre OAuth-Client Konfiguration hoch",
- "UrlOfAccount": "URL (Konto)",
- "VideoKeywords": "Video Suchbegriffe auf Google",
- "VideoKeywordsDocumentation": "Suchbegriffe, die in der GoogleVideosuche verwendet wurden und Links zu Ihrer Website in der Suchergebnisliste generiert haben.",
- "VisitOAuthHowTo": "Bitte besuchen Sie unseren %1$sOnline-Guide%2$s, um zu erfahren, wie Sie Ihre %3$s OAuth-Client-Konfiguration einrichten.",
- "WebKeywords": "Web Suchbegriffe auf Google",
- "WebKeywordsDocumentation": "Suchbegriffe, die in der Google-Websuche verwendet wurden und Links zu Ihrer Website in der Suchergebnisliste generiert haben.",
- "WebsiteSuccessfulConfigured": "Herzlichen Glückwunsch! Sie haben den Keywordimport für die Website %1$s erfolgreich konfiguriert. Es kann einige Tage dauern, bis Ihre ersten Suchbegriffe importiert und in Referrers > Search Keywords angezeigt werden. Weitere Informationen über Verzögerungen und Einschränkungen beim Import von Keywords finden Sie in unseren %2$sFAQs%3$s.",
- "WebsiteTypeUnsupported": "Die ausgewählte Messgröße %1$s kann nicht konfiguriert werden, da sie einen nicht unterstützten Typ hat. Es werden nur Messgrößen vom Typ 'Website' unterstützt.",
- "WebsiteTypeUnsupportedRollUp": "Hinweis: Roll-Up-Sites kombinieren automatisch die importierten Daten aller ihrer Unterseiten",
- "YandexConfigurationDescription": "Yandex verwendet OAuth zur Authentifizierung und Autorisierung.",
- "YandexConfigurationTitle": "Import von Yandex Webmaster API konfigurieren",
- "YandexCrawlAppearedPages": "In der Suche erschienene Seiten",
- "YandexCrawlAppearedPagesDesc": "Seiten die neu in den Suchindex von Yandex aufgenommen wurden",
- "YandexCrawlCrawledPages": "Gecrawlte Seiten",
- "YandexCrawlCrawledPagesDesc": "Anzahl der Seiten die der Yandex Crawler abgerufen hat.",
- "YandexCrawlErrors": "Andere Abfragefehler",
- "YandexCrawlErrorsDesc": "Gecrawlte Seiten, die aus einem anderen Grund fehlgeschlagen sind",
- "YandexCrawlHttpStatus2xx": "HTTP-Status 200-299",
- "YandexCrawlHttpStatus2xxDesc": "Gecrawlte Seiten mit einem 2xx-Code",
- "YandexCrawlHttpStatus3xx": "HTTP-Code 300-399 (verschobene Seiten)",
- "YandexCrawlHttpStatus3xxDesc": "Gecrawlte Seiten mit einem 3xx-Code",
- "YandexCrawlHttpStatus4xx": "HTTP-Status 400-499 (Anfragefehler)",
- "YandexCrawlHttpStatus4xxDesc": "Gecrawlte Seiten mit einem 4xx-Code",
- "YandexCrawlHttpStatus5xx": "HTTP Code 500-599 (Interne Server-Fehler)",
- "YandexCrawlHttpStatus5xxDesc": "Gecrawlte Seiten mit einem 5xx-Code",
- "YandexCrawlInIndex": "Seiten insg. im Index",
- "YandexCrawlInIndexDesc": "Gesamtzahl der Seiten die im Yandex Suchindex vorhanden sind",
- "YandexCrawlRemovedPages": "Aus der Suche entfernte Seiten",
- "YandexCrawlRemovedPagesDesc": "Seiten die aus dem Suchindex von Yandex entfernt wurden",
- "YandexCrawlingStats": "Crawl-Übersicht für Yandex!",
- "YandexCrawlingStatsDocumentation": "In der Crawl-Übersicht können Sie Crawl-bezogene Informationen anzeigen, z. B. Fehler, auf die der Suchbot beim Besuch einer Seite stößt, durch Ihre robots.txt-Datei blockierte Elemente oder die Gesamtzahl der Seiten im Index.",
- "YandexKeywords": "Suchbegriffe auf Yandex",
- "YandexKeywordsDocumentation": "Suchbegriffe, die in der Suche auf Yandex verwendet wurden und Links zu Ihrer Website in der Suchergebnisliste generiert haben.",
- "YandexWebmasterApiUrl": "Url für Yandex Webmaster Tools",
- "YandexWebmasterApiUrlDescription": "Geben Sie die URL an, mit der diese Website in Ihren Yandex Webmaster Tools verfügbar ist"
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/lang/en.json b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/lang/en.json
deleted file mode 100644
index 06085fd..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/lang/en.json
+++ /dev/null
@@ -1,240 +0,0 @@
-{
- "SearchEngineKeywordsPerformance": {
- "AccountAddedBy": "Added by %1$s<\/em> on %2$s<\/em>",
- "AccountConnectionValidationError": "An error occured while validating the account connection:",
- "AccountDoesNotExist": "Configured account %1$s does not exist anymore",
- "AccountNoAccess": "This account does not currently have access to any website.",
- "AccountRemovalConfirm": "You are about to remove the account %1$s. This might disable the keywords import for any connected website(s). Proceed anyway?",
- "ActivityAccountAdded": "added a new account for keyword provider %1$s: %2$s",
- "ActivityAccountRemoved": "removed an account for keyword provider %1$s: %2$s",
- "ActivityGoogleClientConfigChanged": "changed the Google client configuration.",
- "ActivityYandexClientConfigChanged": "changed the Yandex client configuration.",
- "AddAPIKey": "Add API Key",
- "AddConfiguration": "Add Configuration",
- "AdminMenuTitle": "Search Performance",
- "APIKey": "API Key",
- "AvailableSites": "Websites available for import:",
- "Domain": "Domain",
- "DomainProperty": "Domain property",
- "DomainPropertyInfo": "Includes all subdomains (m, www, and so on) and both protocols (http, https).",
- "URLPrefix": "URL-prefix",
- "URLPrefixProperty": "URL-prefix property",
- "URLPrefixPropertyInfo": "Includes only URLs with the specified exact prefix, including the protocol (http\/https). If you want your property to match any protocol or subdomain (http\/https\/www.\/m. and so on), consider adding a Domain property instead.",
- "BingAccountError": "An error occurred while validating the API Key: %1$s. If you have just generated this API key in Bing Webmaster Tools please try again in one or two minutes (API keys in Bing Webmaster Tools take a little while to be activated).",
- "BingAccountOk": "API Key successfully checked",
- "BingAPIKeyInstruction": "Sign in at %1$sBing Webmaster Tools%2$s, then add your website in Bing Webmaster. After you have validated it, you can %3$scopy your API key%4$s.",
- "BingConfigurationDescription": "Bing Webmaster Tools needs an API key to be accessed. Here you can add API keys to access your websites data.",
- "BingConfigurationTitle": "Configure import from Bing Webmaster Tools",
- "BingCrawlBlockedByRobotsTxt": "Robots.txt exclusion",
- "BingCrawlBlockedByRobotsTxtDesc": "URLs currently blocked by your site’s robots.txt.",
- "BingCrawlConnectionTimeout": "Connection timeouts",
- "BingCrawlConnectionTimeoutDesc": "This number represents recent occurences when Bing could not access your site due to connection errors. This could be a temporary issue but you should check your server logs to see if you are accidentally dropping requests.",
- "BingCrawlCrawledPages": "Crawled pages",
- "BingCrawlCrawledPagesDesc": "Number of pages the Bing crawler requested.",
- "BingCrawlDNSFailures": "DNS failures",
- "BingCrawlDNSFailuresDesc": "This issue type catalogs recent errors encountered trying to communicate with the DNS server when the bot tried to access your pages. Possibly your server was down, or there was a misconfiguration that prevented DNS routing, for example TTL was set to 0.",
- "BingCrawlErrors": "Crawl errors on Bing",
- "BingCrawlErrorsDesc": "Number of errors occured for the Bing crawler.",
- "BingCrawlErrorsFromDateX": "The report show crawling errors recently reported by Bing. It does not provide any historical data. Last updated %s",
- "BingCrawlHttpStatus2xx": "HTTP Code 200-299",
- "BingCrawlHttpStatus2xxDesc": "These codes appear when the server serves a page successfully",
- "BingCrawlHttpStatus301": "HTTP Code 301 (Permanently moved)",
- "BingCrawlHttpStatus301Desc": "These codes appear when you have permanently moved content from one location (URL) to another.",
- "BingCrawlHttpStatus302": "HTTP Code 302 (Temporarily moved)",
- "BingCrawlHttpStatus302Desc": "These codes appear when you have temporarily moved content from one location (URL) to another.",
- "BingCrawlHttpStatus4xx": "HTTP Code 400-499 (Request errors)",
- "BingCrawlHttpStatus4xxDesc": "These codes appear when there was a likely an error in the request which prevented the server from being able to process it.",
- "BingCrawlHttpStatus5xx": "HTTP Code 500-599 (Internal server errors)",
- "BingCrawlHttpStatus5xxDesc": "These codes appear when the server failed to fulfill an apparently valid request.",
- "BingCrawlImportantBlockedByRobotsTxt": "Robots.txt exclusion of important page",
- "BingCrawlInboundLink": "Total inbound links",
- "BingCrawlInboundLinkDesc": "Inbound links Bing is aware of, pointed at URLs on your website. These are links, from websites external of your own, that have been pointed towards your content.",
- "BingCrawlingStats": "Crawl overview for Bing and Yahoo!",
- "BingCrawlingStatsDocumentation": "The Crawl overview allows you to view crawl related information such as errors encountered by the search bot when visiting a page, items blocked by your robots.txt file and URLs potentially affected by malware.",
- "BingCrawlMalwareInfected": "Malware infected websites",
- "BingCrawlMalwareInfectedDesc": "Any page URLs that Bing found that are infected or associated with malware will be grouped in this section.",
- "BingCrawlPagesInIndex": "Total pages in index",
- "BingCrawlPagesInIndexDesc": "Total number of pages available in Bing index",
- "BingCrawlStatsOtherCodes": "All other HTTP status codes",
- "BingCrawlStatsOtherCodesDesc": "Groups all other codes that are not matched by any other value (such as 1xx or informational codes).",
- "BingKeywordImport": "Bing keyword import",
- "BingKeywords": "Keywords (on Bing and Yahoo!)",
- "BingKeywordsDocumentation": "Keywords used in Bing or Yahoo! search that generated links to your website in the search results list.",
- "BingKeywordsNoRangeReports": "Keywords on Bing and Yahoo! can only be processed for custom date ranges including full weeks or months as they are not available as daily reports.",
- "BingKeywordsNotDaily": "Keywords on Bing and Yahoo! are only available as weekly reports. There is no keyword data for days periods.",
- "BingWebmasterApiUrl": "Url for Bing Webmaster Tools",
- "BingWebmasterApiUrlDescription": "Provide the url this website is available in your Bing Webmaster Tools",
- "Category": "Category",
- "ChangeConfiguration": "Change configuration",
- "Clicks": "Clicks",
- "ClicksDocumentation": "A click is counted each time someone clicks on a link pointing to your website on a search engine results page.",
- "ClientConfigImported": "Client config has been successfully imported!",
- "ClientConfigSaveError": "An error occured while saving the client config. Please check if the config provided is valid, and try again.",
- "ClientId": "Client id",
- "ClientSecret": "Client secret",
- "ConfigAvailableNoWebsiteConfigured": "Integration successfully configured, but currently no website configured for import.",
- "ConfigRemovalConfirm": "You are about to remove the configuration for %1$s. Import of Keywords for that website will be disabled. Proceed anyway?",
- "Configuration": "Configuration",
- "ConfigurationDescription": "This plugin allows you to import directly into Matomo all keywords searched by your users on search engines.",
- "ConfigurationFile": "Configuration file",
- "ConfigurationValid": "Your OAuth configuration is valid.",
- "ConfiguredAccounts": "configured accounts",
- "ConfiguredUrlNotAvailable": "Configured URL is not available for this account",
- "ConfigureMeasurableBelow": "To configure a website, simply click the button below or configure it directly in the website settings.",
- "ConfigureMeasurables": "Configure websites",
- "ConfigureTheImporterLabel1": "Import your Google Search Console keywords and analyse them using Matomo’s powerful analytics tools. Once you connect the importer, select which websites to import and Matomo will start importing keywords for them as part of the scheduled archiving process.",
- "ConfigureTheImporterLabel2": "In order to import your data from Google Search Console, Matomo need access to this data.",
- "ConfigureTheImporterLabel3": "To start, %1$sfollow our instructions to retrieve your OAuth Client configuration%2$s. Then upload the client configuration file using the button below.",
- "ConnectAccount": "Connect Account",
- "ConnectAccountDescription": "Please click on the button below to be redirected to %1$s where you need to grant access.",
- "ConnectAccountYandex": "Authentication for Yandex accounts is only valid for %1$s days. Each account needs to be reauthenticated within that time to ensure imports work correctly.",
- "ConnectFirstAccount": "Start by connecting your first account below.",
- "ConnectGoogleAccounts": "Connect Google Account(s)",
- "ContainingSitemaps": "Containing Sitemaps",
- "CrawlingErrors": "Crawling errors",
- "ConnectYandexAccounts": "Connect Yandex Account(s)",
- "CrawlingStats": "Crawling overview",
- "Ctr": "CTR",
- "CtrDocumentation": "Clickthrough rate: A ratio showing how often people who see a search engine results page with a link to your website, end up clicking it.",
- "CurrentlyConnectedAccounts": "There are currently %1$s accounts connected.",
- "CreatedBy" : "Created By",
- "DeleteUploadedClientConfig": "If you'd like to remove the uploaded client configuration, click below",
- "EnabledSearchTypes": "Keyword types to fetch",
- "FetchImageKeyword": "Fetch image keywords",
- "FetchImageKeywordDesc": "Fetch keywords used in Google image search",
- "FetchNewsKeyword": "Fetch news keywords",
- "FetchNewsKeywordDesc": "Fetch keywords used in Google News",
- "FetchVideoKeyword": "Fetch video keywords",
- "FetchVideoKeywordDesc": "Fetch keywords used in Google video search",
- "FetchWebKeyword": "Fetch web keywords",
- "FetchWebKeywordDesc": "Fetch keywords used in Google web search",
- "FirstDetected": "First detected",
- "GoogleAccountAccessTypeOfflineAccess": "Offline access<\/strong> is required to be able to import your search keywords even when you are not currently logged in.",
- "GoogleAccountAccessTypeProfileInfo": "Profile info<\/strong> is used to show the name of the account(s) currently connected.",
- "GoogleAccountAccessTypeSearchConsoleData": "Search Console data<\/strong> is required to get access to your Google search keywords.",
- "GoogleAccountError": "An error occurred while validating the OAuth access: %1$s",
- "GoogleAccountOk": "OAuth access successfully checked.",
- "GoogleAuthorizedJavaScriptOrigin": "Authorized JavaScript origin",
- "GoogleAuthorizedRedirectUri": "Authorized redirect URI",
- "GoogleConfigurationDescription": "Google Search Console uses OAuth for authentication and authorization.",
- "GoogleConfigurationTitle": "Configure import from Google Search Console",
- "GoogleDataProvidedWithDelay": "Google provides keywords data with a delay. Keywords for this date will be imported a bit later.",
- "GoogleDataNotFinal": "The keywords data in this report may not yet contain the final data. Google provides final keywords data with a delay of 2 days. Keywords for more recent days will be re-imported until they are reported as final.",
- "GoogleKeywordImport": "Google keyword import",
- "GooglePendingConfigurationErrorMessage": "Configuration is pending. Please ask a super user to complete the configuration.",
- "GoogleSearchConsoleUrl": "Url for Google Search Console",
- "GoogleSearchConsoleUrlDescription": "Provide the url this website is available in your Google Search Console",
- "GoogleUploadOrPasteClientConfig": "Please upload your Google OAuth client configuration, or paste it into the field below.",
- "HowToGetOAuthClientConfig": "How to get your OAuth Client configuration",
- "ImageKeywords": "Image keywords on Google",
- "ImageKeywordsDocumentation": "Keywords used in Google image<\/b> search that generated links to your website in the search result list.",
- "Impressions": "Impressions",
- "ImpressionsDocumentation": "An impression is counted each time your website is displayed in a search engine results page.",
- "IntegrationConfigured": "Integration successfully configured",
- "IntegrationNotConfigured": "Integration not yet configured",
- "InvalidRedirectUriInClientConfiguration": "Invalid redirect_uris, at least 1 uri should match the uri \"%1$s\" in the uploaded configuration file",
- "KeywordsCombined": "Combined keywords",
- "KeywordsCombinedDocumentation": "Report combining all keywords detected by Matomo and imported from search engines. This report only includes the visit metric. You can switch to one of the related report to get detailed metrics.",
- "KeywordsCombinedImported": "Combined imported keywords",
- "KeywordsCombinedImportedDocumentation": "Report showing all keywords imported from all configured search engines.",
- "KeywordsReferrers": "Keywords (including not defined)",
- "KeywordStatistics": "Search Keywords",
- "KeywordTypeImage": "image",
- "KeywordTypeVideo": "video",
- "KeywordTypeWeb": "web",
- "KeywordTypeNews": "news",
- "LastCrawled": "Last crawled",
- "LastDetected": "Last detected",
- "LastImport": "Last Import",
- "LatestAvailableDate": "Most recent keyword data available is for %1$s",
- "LinksToUrl": "Links to %s",
- "ManageAPIKeys": "Manage API Keys",
- "MeasurableConfig": "configured websites",
- "NoSegmentation": "Report does not support segmentation. The data displayed is your standard, unsegmented report data.",
- "NotAvailable": "Not Available",
- "NoWebsiteConfigured": "There is currently no website configured. To enable the import for a specific website, please set up the configuration here.",
- "NoWebsiteConfiguredWarning": "Import for %s not fully configured. You need to configure some websites to enable the import.",
- "OAuthAccessTimedOut": "The OAuth access for this account may have timed out. You will need to reauthenticate to get the imports working again for this account.",
- "OAuthAccessWillTimeOutSoon": "The OAuth access for this account will time out in around %1$s days. Please reauthenticate to avoid any imports for this account to stop working.",
- "OAuthAccessWillTimeOut": "The OAuth access for this account will time out after %1$s days. %2$s days left<\/strong>",
- "OAuthClientConfig": "OAuth Client Configuration",
- "OAuthError": "An error occurred within the OAuth process. Please try again and ensure you accept the requested permissions.",
- "OAuthExampleText": "The configuration requires the fields listed below. Please use the values provided:",
- "OauthFailedMessage": "We encountered an issue during the authorization process for your Google Search Console. To try again, please click the button below. If the problem persists, please contact our support team for assistance. They will assist you in resolving the issue and getting your Google Search Console keywords imported.", "Platform": "Platform",
- "Position": "Avg. position",
- "PositionDocumentation": "Average position of your website in the search engine results list (for this keyword).",
- "ProviderBingDescription": "Import all keywords used to find your website on Bing<\/strong> and Yahoo!<\/strong> search.",
- "ProviderBingNote": "Note:<\/u> Microsoft provides keywords data every saturday and only for whole weeks. As a result your keywords for Bing and Yahoo will take a few days to appear in your reports and will only be available when viewing weeks, months or years.",
- "ProviderGoogleDescription": "Import all keywords used to find your website on Google<\/strong> search. Reports will show your keywords for each search type separately (Web, Images and Videos).",
- "ProviderGoogleNote": "Note:<\/u> Google provides final keywords data with a delay of 2 days. Non final data for more recent days will already be shown, but will be re-imported until they are final. Your first import may be able to import your historical keyword data for up to the last 486 days.",
- "ProviderListDescription": "When you have successfully setup one (or more) search engine below, you can configure into which website(s) should Matomo import your search keywords.",
- "ProviderXAccountWarning": "Account configuration problems detected<\/strong> Please check the configured accounts for %s<\/strong>.",
- "ProviderXSitesWarning": "Website configuration problems detected<\/strong> Please check the configured websites for %s<\/strong>.",
- "ProviderYandexDescription": "Import all keywords used to find your website on Yandex<\/strong> search.",
- "ProviderYandexNote": "Note:<\/u> Yandex provides the keywords with a delay of up to 5 days. The first import will try to import your historical keywords for up to the last 100 days.",
- "ProvideYandexClientConfig": "Please insert your Yandex OAuth client configuration.",
- "Reauthenticate": "Reauthenticate",
- "ReAddAccountIfPermanentError": "If this is a permanent error, try removing the account and connect it again.",
- "ReAuthenticateIfPermanentError": "If this is a permanent error, try to reauthenticate the account or remove and connect it again.",
- "RecentApiErrorsWarning": "Keyword import errors detected<\/strong>
Please check the configurations for: %s
If your configuration is correct and the errors persist, please contact support.",
- "ReportShowMaximumValues": "Values displayed are the maximum values which occurred during this period.",
- "RequiredAccessTypes": "These access types are required:",
- "ResponseCode": "Response code",
- "RoundKeywordPosition": "Round keyword position",
- "SearchEngineKeywordsPerformance": "Search Engine Keywords Performance",
- "SetupConfiguration": "Setup configuration",
- "SitemapsContainingUrl": "Sitemaps containing %s",
- "SetUpOAuthClientConfig": "Setup your OAuth client configuration",
- "KeywordsSubtableOriginal": "Tracked keywords (including not defined)",
- "KeywordsSubtableImported": "Imported keywords",
- "AllReferrersOriginal": "Referrers (with tracked keywords)",
- "AllReferrersImported": "Referrers (with imported keywords)",
- "SearchEnginesOriginal": "Search Engines (with tracked keywords)",
- "SearchEnginesImported": "Search Engines (with imported keywords)",
- "StartOAuth": "Start OAuth Process",
- "UnverifiedSites": "Unverified websites:",
- "UploadOAuthClientConfig": "Upload your OAuth client configuration",
- "Uploading": "Uploading...",
- "UrlOfAccount": "URL (Account)",
- "VideoKeywords": "Video keywords on Google",
- "VideoKeywordsDocumentation": "Keywords used in Google video<\/b> search that generated links to your website in the search result list.",
- "NewsKeywords": "News keywords on Google",
- "NewsKeywordsDocumentation": "Keywords used in Google News<\/b> search that generated links to your website in the search result list.",
- "VisitOAuthHowTo": "Please visit our %1$sonline guide%2$s to learn how to set up your %3$s OAuth client configuration.",
- "WebKeywords": "Web keywords on Google",
- "WebKeywordsDocumentation": "Keywords used in Google web<\/b> search that generated links to your website in the search result list.",
- "WebsiteSuccessfulConfigured": "Congratulations! You have successfully configured keyword import for the website %1$s. It might take a few days until your first search keywords will be imported and displayed in Referrers > Search Keywords. You can find more information about keyword import delays and limitations in our %2$sFAQ%3$s",
- "WebsiteTypeUnsupported": "The selected measurable %1$s can't be configured as it has an unsupported type. Only measurables of type 'website' are supported.",
- "WebsiteTypeUnsupportedRollUp": "Note: Roll-Up sites will automatically combine the imported data of all their child sites",
- "YandexConfigurationDescription": "Yandex Webmaster API uses OAuth for authentication and authorization.",
- "YandexConfigurationTitle": "Configure import from Yandex Webmaster API",
- "YandexCrawlingStats": "Crawl overview for Yandex!",
- "YandexCrawlingStatsDocumentation": "The Crawl overview allows you to view crawl related information such as errors encountered by the search bot when visiting a page, items blocked by your robots.txt file and the total number of pages in index.",
- "YandexCrawlHttpStatus2xx": "HTTP Code 200-299",
- "YandexCrawlHttpStatus2xxDesc": "Crawled Pages with a 2xx code",
- "YandexCrawlHttpStatus3xx": "HTTP Code 300-399 (Moved pages)",
- "YandexCrawlHttpStatus3xxDesc": "Crawled Pages with a 3xx code",
- "YandexCrawlHttpStatus4xx": "HTTP Code 400-499 (Request errors)",
- "YandexCrawlHttpStatus4xxDesc": "Crawled Pages with a 4xx code",
- "YandexCrawlHttpStatus5xx": "HTTP Code 500-599 (Internal server errors)",
- "YandexCrawlHttpStatus5xxDesc": "Crawled Pages with a 5xx code",
- "YandexCrawlErrors": "Other request errors",
- "YandexCrawlErrorsDesc": "Crawled paged that failed for any other reason",
- "YandexCrawlCrawledPages": "Crawled Pages",
- "YandexCrawlCrawledPagesDesc": "Number of pages the Yandex crawler requested.",
- "YandexCrawlInIndex": "Total pages in index",
- "YandexCrawlInIndexDesc": "Total number of pages available in Yandex search index",
- "YandexCrawlAppearedPages": "Pages appeared in search",
- "YandexCrawlAppearedPagesDesc": "Pages that were newly added to Yandex search index",
- "YandexCrawlRemovedPages": "Pages removed from search",
- "YandexCrawlRemovedPagesDesc": "Pages that were removed from Yandex search index",
- "YandexFieldCallbackUri": "Callback URI",
- "YandexFieldUrlToAppSite": "URL to app site",
- "YandexKeywords": "Keywords on Yandex",
- "YandexKeywordsDocumentation": "Keywords used in Yandex search that generated links to your website in the search results list.",
- "YandexWebmasterApiUrl": "Url for Yandex Webmaster Tools",
- "YandexWebmasterApiUrlDescription": "Provide the url this website is available in your Yandex Webmaster Tools",
- "CrawlingOverview1": "The Crawling overview reports all the most critical information about how Search Engines robots crawl your websites. These metrics are updated approximately once per day with data provided by the search engines.",
- "OptionQuickConnectWithGoogle": "Quick connect with Google (recommended)"
- }
-}
\ No newline at end of file
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/lang/es.json b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/lang/es.json
deleted file mode 100644
index 8da2b24..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/lang/es.json
+++ /dev/null
@@ -1,170 +0,0 @@
-{
- "SearchEngineKeywordsPerformance": {
- "APIKey": "Clave API",
- "AccountAddedBy": "Agregado por %1$s en %2$s",
- "AccountConnectionValidationError": "Ocurrió un error al validar la conexión de la cuenta:",
- "AccountDoesNotExist": "La cuenta configurada %1$s ya no existe más",
- "AccountNoAccess": "Esta cuenta no tiene acceso a ningún sitio web.",
- "AccountRemovalConfirm": "Estás a punto de eliminar la cuenta %1$s. Esto podría deshabilitar la importación de palabras clave para cualquiera de los sitio(s) web conectado(s). ¿Proceder de todas maneras?",
- "ActivityAccountAdded": "agregó una nueva cuenta para el proveedor de palabras clave %1$s: %2$s",
- "ActivityAccountRemoved": "eliminó una cuenta del proveedor de palabras clave %1$s:%2$s",
- "ActivityGoogleClientConfigChanged": "cambió la configuración del cliente Google.",
- "AddAPIKey": "Agregar clave API",
- "AddConfiguration": "Agregar configuración",
- "AdminMenuTitle": "Performance de la búsqueda",
- "AvailableSites": "Sitios de internet disponibles para importar:",
- "BingAccountError": "Se produjo un error al validar la clave API: %1$s. Si acaba de generar esta clave API en Bing Webmaster Tools, inténtelo nuevamente en uno o dos minutos (las claves API en Bing Webmaster Tools tardan un poco en ser activadas).",
- "BingAccountOk": "Clave API verificada exitosamente",
- "BingConfigurationDescription": "Bing Webmaster Tools necesita una clave API para poder acceder. Aquí puede agregar claves API para acceder a los datos de sus sitios web.",
- "BingConfigurationTitle": "Configurar importación desde Bing Webmasters Tools",
- "BingCrawlBlockedByRobotsTxt": "Exclusión Robots.txt",
- "BingCrawlBlockedByRobotsTxtDesc": "URLs bloqueados actualmente por el archivo robots.txt de su sitio.",
- "BingCrawlConnectionTimeout": "Tiempos de espera de conexión",
- "BingCrawlConnectionTimeoutDesc": "Este número representa las incidencias recientes cuando Bing no pudo acceder a su sitio debido a errores de conexión. Esto podría ser un problema temporal, pero debe revisar los registros de su servidor para ver si está eliminando accidentalmente solicitudes.",
- "BingCrawlCrawledPages": "Páginas rastreadas",
- "BingCrawlCrawledPagesDesc": "Número de páginas solicitadas por el rastreador de Bing.",
- "BingCrawlDNSFailures": "Fallos DNS",
- "BingCrawlDNSFailuresDesc": "Este tipo de problema cataloga errores recientes encontrados al comunicarse con el servidor DNS cuando el bot intentaba acceder a sus páginas. Es posible que su servidor no funcionara o que hubiera una mala configuración que impidiera el enrutamiento de DNS, por ejemplo, TTL se estableció en 0.",
- "BingCrawlErrors": "Errores de rastreo en Bing",
- "BingCrawlErrorsDesc": "Número de errores ocurridos del rastreador Bing.",
- "BingCrawlErrorsFromDateX": "El informe muestra errores de seguimiento recientemente reportados por Bing. No proporciona ningún dato histórico. Última actualización %s",
- "BingCrawlHttpStatus2xx": "HTTP Código 200-299",
- "BingCrawlHttpStatus2xxDesc": "Estos códigos aparecen cuando el servidor presenta una página exitosamente",
- "BingCrawlHttpStatus301": "HTTP Código 301 (Movido temporariamente)",
- "BingCrawlHttpStatus301Desc": "Estos códigos aparecen cuando ha mudado permanentemente el contenido de una ubicación (URL) a otra.",
- "BingCrawlHttpStatus302": "HTTP Código 302 (Movido temporariamente)",
- "BingCrawlHttpStatus302Desc": "Estos códigos aparecen cuando ha movido temporalmente el contenido de una ubicación (URL) a otra.",
- "BingCrawlHttpStatus4xx": "HTTP Código 400-499 (Errores de solicitud)",
- "BingCrawlHttpStatus4xxDesc": "Estos códigos aparecen probablemente cuando hubo un error en la solicitud que impidió que el servidor pudiera procesarlo.",
- "BingCrawlHttpStatus5xx": "HTTP Código 500-599 (Errores internos del servidor)",
- "BingCrawlHttpStatus5xxDesc": "Estos códigos aparecen cuando el servidor no cumple con una solicitud aparentemente válida.",
- "BingCrawlImportantBlockedByRobotsTxt": "Exclusión Robots.txt de página destacada",
- "BingCrawlInboundLink": "Total de enlaces entrantes",
- "BingCrawlInboundLinkDesc": "Los enlaces entrantes que Bing conoce, apuntan a las URL de su sitio web. Estos son enlaces, desde sitios web externos a los suyos, que han sido apuntados hacia su contenido.",
- "BingCrawlMalwareInfected": "Sitios de internet infectados con malware",
- "BingCrawlMalwareInfectedDesc": "Cualquier dirección URL de página que Bing haya encontrado que esté infectada o asociada con malware se agrupará en esta sección.",
- "BingCrawlPagesInIndex": "Páginas totales en el índice",
- "BingCrawlPagesInIndexDesc": "Número total de páginas disponibles en el índice Bing",
- "BingCrawlStatsOtherCodes": "Todos los códigos de estados HTTP",
- "BingCrawlStatsOtherCodesDesc": "Agrupa todos los demás códigos que no coinciden con ningún otro valor (como 1xx o códigos informativos).",
- "BingCrawlingStats": "Resumen de rastreo para Bing y Yahoo!",
- "BingCrawlingStatsDocumentation": "El resumen de rastreo le permite ver información relacionada con el rastreo, tales como los errores encontrados por el robot de búsqueda al visitar una página, los elementos bloqueados por su archivo robots.txt y las URL potencialmente afectadas por malware.",
- "BingKeywordImport": "Importar palabras clave Bing",
- "BingKeywords": "Palabras claves (en Bing y Yahoo!)",
- "BingKeywordsDocumentation": "Palabras clave utilizadas en las búsquedas de Bing o Yahoo! que generaron los enlaces a su sitio web en la lista de los resultados de la búsqueda",
- "BingKeywordsNoRangeReports": "Palabras clave en Bing y Yahoo! solo se pueden utilizar para intervalos de fechas personalizados que incluyen semanas completas o meses, ya que no están disponibles como informes diarios.",
- "BingKeywordsNotDaily": "Palabras clave en Bing y Yahoo! sólo están disponibles como informes semanales. No hay datos de palabras clave para períodos de días.",
- "BingWebmasterApiUrl": "Url de Bing Webmaster Tools",
- "BingWebmasterApiUrlDescription": "Proporcione la dirección URL de este sitio web así está disponible en su Bing Webmaster Tools",
- "Category": "Categoría",
- "ChangeConfiguration": "Cambiar configuración",
- "Clicks": "Clics",
- "ClicksDocumentation": "Un clic se cuenta cada vez que alguien hace clic en un enlace que apunta a su sitio web en una página de resultados del motor de búsqueda.",
- "ClientConfigImported": "La configuración del cliente ha sido importada con éxito!",
- "ClientConfigSaveError": "Se produjo un error al guardar la configuración del cliente. Verifique si la configuración proporcionada es válida e intente nuevamente.",
- "ClientId": "id de cliente",
- "ClientSecret": "Cliente secreto",
- "ConfigAvailableNoWebsiteConfigured": "Integración exitosamente configurada, pero actualmente no hay sitio web configurado para importar.",
- "ConfigRemovalConfirm": "Está a punto de eliminar la configuración de %1$s. La importación de palabras clave para ese sitio web será deshabilitada. ¿Proceder de todas maneras?",
- "Configuration": "Configuración",
- "ConfigurationDescription": "Este complemento le permite directamente importar en Matomo todas las palabras claves buscadas por sus usuarios en los motores de búsqueda.",
- "ConfigurationFile": "Archivo de configuración",
- "ConfigurationValid": "Su configuración OAuth es válida.",
- "ConfigureMeasurableBelow": "Para configurar un sitio web, simplemente haga clic en el botón a continuación o configúrelo directamente en la configuración del sitio web.",
- "ConfigureMeasurables": "Configurar sitios de internet",
- "ConfiguredAccounts": "cuentas configuradas",
- "ConfiguredUrlNotAvailable": "La URL configurada no está disponible para esta cuenta",
- "ConnectAccount": "Conectar cuenta",
- "ConnectFirstAccount": "Comience por conectar su primera cuenta a continuación.",
- "ConnectGoogleAccounts": "Conectar cuenta(s) Google",
- "ContainingSitemaps": "Conteniendo mapas de sitio",
- "CrawlingErrors": "Errores de rastreo",
- "CrawlingStats": "Descripción de los rastreos",
- "Ctr": "CTR",
- "CtrDocumentation": "Porcentaje de clics: una proporción que muestra la frecuencia con la que las personas que ven una página de resultados vía motor de búsqueda con un enlace a su sitio web terminan haciendo clic en el mismo.",
- "CurrentlyConnectedAccounts": "Actualmente hay %1$s cuentas conectadas.",
- "Domain": "Dominio",
- "DomainProperty": "Propiedades de dominio",
- "DomainPropertyInfo": "Incluye todos los subdominios (m, www, etc.) y ambos protocolos (http y https).",
- "EnabledSearchTypes": "Tipos de palabras clave a recolectar",
- "FetchImageKeyword": "Recolectar palabras claves de las imágenes",
- "FetchImageKeywordDesc": "Recolectar palabras claves usadas en la búsqueda de imágenes de Google",
- "FetchVideoKeyword": "Recolectar palabras claves de los videos",
- "FetchVideoKeywordDesc": "Recolectar palabras claves usadas en la búsqueda de videos de Google",
- "FetchWebKeyword": "Recolectar palabras claves de la web",
- "FetchWebKeywordDesc": "Recolectar palabras claves usadas en las búsquedas web de Google",
- "FirstDetected": "Primera detectada",
- "GoogleAccountAccessTypeOfflineAccess": "Acceso sin conexión es necesario para poder importar sus palabras clave de búsqueda incluso cuando no esté actualmente conectado.",
- "GoogleAccountAccessTypeProfileInfo": "Información de perfil es usada para mostrar el nombre de las actuales cuenta(s) conectadas.",
- "GoogleAccountAccessTypeSearchConsoleData": "Datos de la consola de búsqueda es necesaria para obtener acceso a sus palabras clave de búsqueda en Google",
- "GoogleAccountError": "Se produjo un error al validar el acceso OAuth: %1$s",
- "GoogleAccountOk": "Acceso OAuth verificado exitosamente.",
- "GoogleConfigurationDescription": "Google Search Console usa OAuth para autenticación y autorización.",
- "GoogleConfigurationTitle": "Configurar importación desde Google Search Console",
- "GoogleKeywordImport": "Importar palabras clave Google",
- "GoogleSearchConsoleUrl": "URL para la Google Search Console",
- "GoogleSearchConsoleUrlDescription": "Proporcione la URL, este sitio web está disponible en su Consola de búsqueda de Google",
- "GoogleUploadOrPasteClientConfig": "Por favor, suba la configuración de su cliente de Google OAuth o péguela a continuación en el campo.",
- "HowToGetOAuthClientConfig": "Cómo obtener la configuración de su cliente OAuth",
- "ImageKeywords": "Palabras clave de la imagen en Google",
- "ImageKeywordsDocumentation": "Palabras clave en búsquedas de Google Imágenes que generaron enlace a su sitio web en la lista resultante de la búsqueda.",
- "Impressions": "Impresiones",
- "ImpressionsDocumentation": "Se contabiliza una impresión cada vez que se muestra su sitio web en una página de resultados del motor de búsqueda.",
- "IntegrationConfigured": "Integración configurada exitosamente",
- "IntegrationNotConfigured": "Integración aun no configurada",
- "KeywordStatistics": "Buscar palabras claves",
- "KeywordTypeImage": "imagen",
- "KeywordTypeVideo": "video",
- "KeywordTypeWeb": "web",
- "KeywordsCombined": "Palabras claves combinadas",
- "KeywordsCombinedDocumentation": "Informe que combina todas las palabras clave detectadas por Matomo e importadas desde los motores de búsqueda. Este informe solo incluye la métrica de la visita. Puede cambiar a uno de los informes relacionados para obtener métricas detalladas.",
- "KeywordsCombinedImported": "Palabras clave importadas combinadas",
- "KeywordsCombinedImportedDocumentation": "Informe que muestra todas las palabras clave importadas de todos los motores de búsqueda configurados.",
- "KeywordsReferrers": "Palabras clave (incluyendo las no definidas)",
- "LastCrawled": "Ultimo rastreo",
- "LastDetected": "Ultima detectada",
- "LastImport": "Ultima importación",
- "LatestAvailableDate": "Los datos de palabras clave más recientes disponibles son para %1$s",
- "LinksToUrl": "Enlaces a %s",
- "ManageAPIKeys": "Administrar claves API",
- "MeasurableConfig": "Sitios de internet configurados",
- "NoSegmentation": "El informe no admite la segmentación. Los datos que se muestran son sus datos de informe estándar, no segmentados.",
- "NoWebsiteConfigured": "Actualmente no hay ningún sitio web configurado. Para habilitar la importación de un sitio web específico, ajuste la configuración aquí.",
- "NoWebsiteConfiguredWarning": "Importación para %s no está totalmente configurado. Es necesario ajustar algunos sitios web para habilitar la importación.",
- "NotAvailable": "no disponible",
- "OAuthClientConfig": "Configuración del cliente OAuth",
- "OAuthError": "Un error ocurrió durante el proceso OAuth. Por favor inténtelo nuevamente y asegúrese de aceptar los permisos solicitados.",
- "Platform": "Plataforma",
- "Position": "Posición promedio",
- "PositionDocumentation": "Posición promedio de su sitio web en la lista de resultados del motor de búsqueda (para esta palabra clave).",
- "ProviderBingDescription": "Importar todas las palabras claves usadas para encontrar su sitio web en las búsquedas hechas por Bing y Yahoo.",
- "ProviderBingNote": "Nota: Microsoft proporciona datos de palabras clave todos los sábados y solo durante semanas enteras. Como resultado, sus palabras clave para Bing y Yahoo tardarán unos días en aparecer en sus informes y solo estarán disponibles cuando las vea en semanas, meses o años.",
- "ProviderGoogleDescription": "Importe todas las palabras clave utilizadas para encontrar su sitio web en la búsqueda de Google. Los informes mostrarán sus palabras clave para cada tipo de búsqueda por separado (Web, imágenes y videos).",
- "ProviderListDescription": "Cuando haya configurado correctamente uno (o más) motores de búsqueda, puede configurar en qué sitios web(s) debe Matomo importar sus palabras clave de búsqueda.",
- "ProviderXAccountWarning": "Problemas de configuración de la cuenta detectados Por favor, compruebe las cuentas configuradas %s.",
- "ProviderXSitesWarning": "Problemas de configuración del sitio web detectados Por favor verifique los sitios web configurados %s.",
- "ReAddAccountIfPermanentError": "Si este es un error permanente, intente eliminar la cuenta y conéctela nuevamente.",
- "RequiredAccessTypes": "Estos tipos de acceso son necesarios:",
- "ResponseCode": "Código de respuesta",
- "RoundKeywordPosition": "Ronda de posición de palabras claves",
- "SearchEngineKeywordsPerformance": "Rendimiento de las palabras claves en los motores de búsqueda",
- "SetupConfiguration": "Ajustes de configuración",
- "SitemapsContainingUrl": "Mapas de sitio conteniendo %s",
- "StartOAuth": "Iniciar proceso OAuth",
- "URLPrefix": "Prefijo de la URL",
- "URLPrefixProperty": "Propiedades de prefijo de URL",
- "URLPrefixPropertyInfo": "Incluye solo las URL con el prefijo exacto especificado, incluido el protocolo (http/https). Si quieres que tu propiedad abarque más protocolos o subdominios (http/https/www./m., etc.), quizás te interese más añadir una propiedad de dominio.",
- "UnverifiedSites": "Sitios de internet sin verificar:",
- "UploadOAuthClientConfig": "Cargue su configuración de cliente OAuth",
- "UrlOfAccount": "URL (Cuenta)",
- "VideoKeywords": "Palabras clave de videos en Google",
- "VideoKeywordsDocumentation": "Palabras clave utilizadas en la búsqueda de videos de Google que generaron enlaces a su sitio web en la lista de resultados de búsqueda.",
- "WebKeywords": "Palabras clave de la web en Google",
- "WebKeywordsDocumentation": "Palabras clave utilizadas en la búsqueda web de Google que generaron enlaces a su sitio web en la lista de resultados de búsqueda.",
- "WebsiteSuccessfulConfigured": "Felicidades! Ha configurado correctamente la importación de palabras clave para el sitio web %1$s. Es posible que pasen unos días hasta que sus primeras palabras clave de búsqueda se importen y se muestren en Referencias > Palabras clave de búsqueda. Puede encontrar más información sobre los retrasos y limitaciones de importación de palabras clave en nuestras %2$sPreguntas frecuentes%3$s",
- "YandexCrawlHttpStatus2xx": "HTTP Código 200-299",
- "YandexCrawlHttpStatus4xx": "HTTP Código 400-499 (Errores de solicitud)",
- "YandexCrawlHttpStatus5xx": "HTTP Código 500-599 (Errores internos del servidor)",
- "YandexCrawlInIndex": "Páginas totales en el índice"
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/lang/fr.json b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/lang/fr.json
deleted file mode 100644
index a33569f..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/lang/fr.json
+++ /dev/null
@@ -1,241 +0,0 @@
-{
- "SearchEngineKeywordsPerformance": {
- "APIKey": "Clé API",
- "AccountAddedBy": "Ajouté par %1$s sur %2$s",
- "AccountConnectionValidationError": "Une erreur s'est produite lors de la validation de la connexion du compte :",
- "AccountDoesNotExist": "Le compte configuré %1$s n'existe plus",
- "AccountNoAccess": "Ce compte n'a actuellement accès à aucun site web.",
- "AccountRemovalConfirm": "Vous êtes sur le point de supprimer le compte %1$s. Cela pourrait désactiver l'importation de mots-clés pour tous les site(s) connecté(s). Souhaitez-vous poursuivre ?",
- "ActivityAccountAdded": "a ajouté un nouveau compte pour le fournisseur de mots-clés %1$s : %2$s",
- "ActivityAccountRemoved": "a supprimé un compte pour le fournisseur de mots-clés %1$s : %2$s",
- "ActivityGoogleClientConfigChanged": "a modifié le fichier de configuration du client Google.",
- "ActivityYandexClientConfigChanged": "a modifié le fichier de configuration du client Yandex.",
- "AddAPIKey": "Ajouter la clé API",
- "AddConfiguration": "Ajouter la configuration",
- "AdminMenuTitle": "Performance de la recherche",
- "AllReferrersImported": "Référents (avec mots-clés importés)",
- "AllReferrersOriginal": "Référents (avec mots-clés suivis)",
- "AvailableSites": "Sites disponibles pour l'import :",
- "BingAPIKeyInstruction": "Connectez-vous à %1$sBing Webmaster Tools%2$s, puis ajoutez votre site Web dans Bing Webmaster Tools. Après l'avoir validé, vous pouvez %3$scopier votre clé API%4$s.",
- "BingAccountError": "Une erreur s'est produite lors de la validation de la clé API : %1$s. Si vous venez de générer cette clé API dans le service Bing Webmaster Tools, veuillez réessayer dans une ou deux minutes (les clés API dans Bing Webmaster Tools mettent un peu de temps à s'activer).",
- "BingAccountOk": "Clé API vérifiée avec succès",
- "BingConfigurationDescription": "Bing Webmaster Tools nécessite une clé API pour être accessible. Vous pouvez ajouter ici des clés API pour accéder aux données de vos sites web.",
- "BingConfigurationTitle": "Configurer l'import à partir de Bing Webmaster Tools",
- "BingCrawlBlockedByRobotsTxt": "Exclusion du fichier Robots.txt",
- "BingCrawlBlockedByRobotsTxtDesc": "Ces URLs sont actuellement bloquées par le fichier robots.txt de votre site.",
- "BingCrawlConnectionTimeout": "Dépassement du délai de connexion",
- "BingCrawlConnectionTimeoutDesc": "Ce nombre représente les occurrences récentes où Bing n'a pas pu accéder à votre site en raison d'erreurs de connexion. Il peut s'agir d'un problème temporaire, mais vous devriez vérifier les journaux de votre serveur pour voir si les requêtes ne sont pas accidentellement bloquées.",
- "BingCrawlCrawledPages": "Pages crawlées",
- "BingCrawlCrawledPagesDesc": "Nombre de pages parcourus par le crawler de Bing.",
- "BingCrawlDNSFailures": "Erreurs DNS",
- "BingCrawlDNSFailuresDesc": "Ce type de problème répertorie les erreurs récentes rencontrées lors de la tentative de communication avec le serveur DNS lorsque le robot a essayé d'accéder à vos pages. Il est possible que votre serveur soit en panne, ou qu'une mauvaise configuration empêche le routage DNS, par exemple, le TTL a été fixé à 0.",
- "BingCrawlErrors": "Erreurs de crawl sur Bing",
- "BingCrawlErrorsDesc": "Nombre d'erreurs survenues pour le crawler Bing.",
- "BingCrawlErrorsFromDateX": "Le rapport montre les erreurs de crawl récemment rencontrées par Bing. Il ne fournit pas de données historiques. Dernière mise à jour %s",
- "BingCrawlHttpStatus2xx": "Code HTTP 200-299",
- "BingCrawlHttpStatus2xxDesc": "Ces codes apparaissent lorsque le serveur renvoi une page avec succès",
- "BingCrawlHttpStatus301": "Code HTTP 301 (redirigé de façon permanente)",
- "BingCrawlHttpStatus301Desc": "Ces codes apparaissent lorsque vous avez déplacé de façon permanente un contenu d'un emplacement (URL) à un autre.",
- "BingCrawlHttpStatus302": "Code HTTP 302 (déplacé temporairement)",
- "BingCrawlHttpStatus302Desc": "Ces codes apparaissent lorsque vous avez temporairement déplacé du contenu d'un emplacement (URL) à un autre.",
- "BingCrawlHttpStatus4xx": "Code HTTP 400-499 (erreurs de requêtes)",
- "BingCrawlHttpStatus4xxDesc": "Ces codes apparaissent lorsqu'il y a probablement une erreur dans la requête ce qui a empêché le serveur de la traiter.",
- "BingCrawlHttpStatus5xx": "Code HTTP 500-599 (erreurs internes du serveur)",
- "BingCrawlHttpStatus5xxDesc": "Ces codes apparaissent lorsque le serveur n'a pas réussi à satisfaire une demande apparemment valide.",
- "BingCrawlImportantBlockedByRobotsTxt": "Exclusion d'une page importante dans le fichier Robots.txt",
- "BingCrawlInboundLink": "Nombre total de liens entrants",
- "BingCrawlInboundLinkDesc": "Liens entrants dont Bing a connaissance, pointant vers des URLs de votre site Web. Il s'agit de liens, provenant de sites Web extérieurs au vôtre, qui ont été dirigés vers votre contenu.",
- "BingCrawlMalwareInfected": "Sites web infectés par des logiciels malveillants",
- "BingCrawlMalwareInfectedDesc": "Toutes les URL de pages trouvées par Bing qui sont infectées ou associées à des logiciels malveillants seront regroupées dans cette section.",
- "BingCrawlPagesInIndex": "Nombre total de pages dans l'index",
- "BingCrawlPagesInIndexDesc": "Nombre total de pages disponibles dans l'index Bing",
- "BingCrawlStatsOtherCodes": "Tous les autres codes d'état HTTP",
- "BingCrawlStatsOtherCodesDesc": "Regroupe tous les autres codes qui ne correspondent à aucune autre valeur (tels que les codes 1xx ou informatifs).",
- "BingCrawlingStats": "Aperçu des crawls pour Bing et Yahoo !",
- "BingCrawlingStatsDocumentation": "La vue d'ensemble du crawl vous permet de visualiser les informations relatives au crawl, telles que les erreurs rencontrées par le robot de recherche lors de la visite d'une page, les éléments bloqués par votre fichier robots.txt et les URL potentiellement affectées par des logiciels malveillants.",
- "BingKeywordImport": "Import des mots-clés Bing",
- "BingKeywords": "Mots-clés (sur Bing et Yahoo !)",
- "BingKeywordsDocumentation": "Mots clés utilisés dans la recherche Bing ou Yahoo ! qui ont généré des liens vers votre site web dans la liste des résultats de recherche.",
- "BingKeywordsNoRangeReports": "Les mots-clés sur Bing et Yahoo ! ne peuvent être traités que pour des plages de dates personnalisées, y compris des semaines ou des mois entiers, car ils ne sont pas disponibles sous forme de rapports quotidiens.",
- "BingKeywordsNotDaily": "Les mots-clés sur Bing et Yahoo ! ne sont disponibles que sous forme de rapports hebdomadaires. Il n'y a pas de données sur les mots-clés pour les périodes de plusieurs jours.",
- "BingWebmasterApiUrl": "Url pour Bing Webmaster Tools",
- "BingWebmasterApiUrlDescription": "Fournissez l'url de ce site Web dans vos outils pour les webmasters de Bing",
- "Category": "Catégorie",
- "ChangeConfiguration": "Modifier la configuration",
- "Clicks": "Clics",
- "ClicksDocumentation": "Un clic est comptabilisé à chaque fois que quelqu'un clique sur un lien pointant vers votre site web lorsqu'il est sur une page de résultats d'un moteur de recherche.",
- "ClientConfigImported": "La configuration du client a été importée avec succès !",
- "ClientConfigSaveError": "Une erreur s'est produite lors de la sauvegarde de la configuration du client. Veuillez vérifier si la configuration fournie est valide, et réessayer.",
- "ClientId": "id du client",
- "ClientSecret": "Client secret",
- "ConfigAvailableNoWebsiteConfigured": "L'intégration a été effectuée avec succès, mais aucun site web n'est actuellement configuré pour l'import.",
- "ConfigRemovalConfirm": "Vous êtes sur le point de supprimer la configuration pour %1$s. L'import de mots-clés pour ce site Web sera désactivée. Souhaitez-vous continuer ?",
- "Configuration": "Configuration",
- "ConfigurationDescription": "Cette extension vous permet d'importer directement dans Matomo tous les mots-clés recherchés par vos utilisateurs sur les moteurs de recherche.",
- "ConfigurationFile": "Fichier de configuration",
- "ConfigurationValid": "Votre configuration OAuth est valide.",
- "ConfigureMeasurableBelow": "Pour configurer un site web, il suffit de cliquer sur le bouton ci-dessous ou de le configurer directement dans les paramètres du site web.",
- "ConfigureMeasurables": "Configurer les sites web",
- "ConfigureTheImporterLabel1": "Importez vos mots-clés de Google Search Console et analysez-les à l'aide des puissants outils d'analyse de Matomo. Une fois l'importateur connecté, sélectionnez les sites web à importer, et Matomo commencera à importer les mots-clés pour eux dans le cadre du processus d'archivage planifié.",
- "ConfigureTheImporterLabel2": "Afin d'importer vos données depuis Google Search Console, Matomo doit y avoir accès.",
- "ConfigureTheImporterLabel3": "Pour commencer, %1$ssuivez nos instructions pour récupérer la configuration de votre client OAuth%2$s. Ensuite, téléversez le fichier de configuration du client en utilisant le bouton ci-dessous.",
- "ConfiguredAccounts": "comptes configurés",
- "ConfiguredUrlNotAvailable": "L'URL configurée n'est pas disponible pour ce compte",
- "ConnectAccount": "Connecter le compte",
- "ConnectAccountDescription": "Veuillez cliquer sur le bouton ci-dessous pour être redirigé vers %1$s où vous devez accorder l'accès.",
- "ConnectAccountYandex": "L'authentification des comptes Yandex n'est valable que pendant %1$s jours. Chaque compte doit être réauthentifié dans ce délai pour que les imports fonctionnent correctement.",
- "ConnectFirstAccount": "Commencez par connecter votre premier compte ci-dessous.",
- "ConnectGoogleAccounts": "Connecter le(s) compte(s) Google",
- "ConnectYandexAccounts": "Connecter le(s) compte(s) Yandex",
- "ContainingSitemaps": "Qui contient les sitemaps",
- "CrawlingErrors": "Erreurs de crawl",
- "CrawlingOverview1": "Le récapitulatif d'exploration présente toutes les informations les plus importantes sur la façon dont les robots des moteurs de recherche explorent vos sites Web. Ces métriques sont mises à jour environ une fois par jour avec les données fournies par les moteurs de recherche.",
- "CrawlingStats": "Vue d'ensemble du crawl",
- "CreatedBy": "Créé par",
- "Ctr": "CTR",
- "CtrDocumentation": "Taux de clics (CTR) : Ratio montrant combien de fois les personnes qui voient une page de résultats de moteur de recherche avec un lien vers votre site web finissent par cliquer dessus.",
- "CurrentlyConnectedAccounts": "Il y a actuellement %1$s comptes connectés.",
- "DeleteUploadedClientConfig": "Si vous souhaitez supprimer la configuration du client téléversée, cliquez ci-dessous",
- "Domain": "Domaine",
- "DomainProperty": "Propriété de domaine",
- "DomainPropertyInfo": "Comprend tous les sous-domaines (m, www, etc.) et les deux protocoles (http, https).",
- "EnabledSearchTypes": "Types de mots-clés à récupérer",
- "FetchImageKeyword": "Récupérer les mots-clés pour les images",
- "FetchImageKeywordDesc": "Récupérer les mots-clés utilisés dans la recherche d'images sur Google",
- "FetchNewsKeyword": "Récupérer les mots clés des actualités",
- "FetchNewsKeywordDesc": "Récupérer les mots-clés utilisés dans Google News",
- "FetchVideoKeyword": "Récupérer les mots-clés liés aux vidéos",
- "FetchVideoKeywordDesc": "Récupérer les mots-clés utilisés dans la recherche de vidéos sur Google",
- "FetchWebKeyword": "Récupérer les mots-clés du web",
- "FetchWebKeywordDesc": "Récupérer les mots-clés utilisés dans les recherches sur le Web de Google",
- "FirstDetected": "Premier détecté",
- "GoogleAccountAccessTypeOfflineAccess": "L'accès hors ligne est nécessaire pour pouvoir importer vos mots-clés de recherche même si vous n'êtes pas actuellement connecté.",
- "GoogleAccountAccessTypeProfileInfo": "Infos sur le profil est utilisé pour montrer le nom du ou des comptes actuellement connectés.",
- "GoogleAccountAccessTypeSearchConsoleData": "Les données de la Search Console sont nécessaires pour avoir accès à vos mots-clés de recherche Google.",
- "GoogleAccountError": "Une erreur s'est produite lors de la validation de l'accès OAuth : %1$s",
- "GoogleAccountOk": "Accès OAuth vérifié avec succès.",
- "GoogleAuthorizedJavaScriptOrigin": "Origine JavaScript autorisée",
- "GoogleAuthorizedRedirectUri": "URI de redirection autorisée",
- "GoogleConfigurationDescription": "La Google Search Console utilise OAuth pour l'authentification et l'autorisation.",
- "GoogleConfigurationTitle": "Configurer l'import à partir de la Google Search Console",
- "GoogleDataNotFinal": "Les données relatives aux mots-clés figurant dans ce rapport peuvent ne pas contenir les données définitives. Google fournit les données définitives des mots-clés avec un retard de 2 jours. Les mots-clés des jours plus récents seront réimportés jusqu'à ce qu'ils soient déclarés comme définitifs.",
- "GoogleDataProvidedWithDelay": "Google fournit des données sur les mots-clés avec un certain délais. Les mots-clés pour cette date seront importés un peu plus tard.",
- "GoogleKeywordImport": "Import de mots-clés Google",
- "GooglePendingConfigurationErrorMessage": "La configuration est en attente. Veuillez demander à un super utilisateur de la compléter.",
- "GoogleSearchConsoleUrl": "Url pour la Google Search Console",
- "GoogleSearchConsoleUrlDescription": "Fournissez l'url de ce site web dans votre Google Search Console",
- "GoogleUploadOrPasteClientConfig": "Veuillez télécharger votre configuration du client Google OAuth ou la coller dans le champ ci-dessous.",
- "HowToGetOAuthClientConfig": "Comment obtenir la configuration de votre client OAuth",
- "ImageKeywords": "Mots-clés de l'image sur Google",
- "ImageKeywordsDocumentation": "Mots clés utilisés dans la recherche Google image qui ont généré des liens vers votre site web dans la liste des résultats de recherche.",
- "Impressions": "Impressions",
- "ImpressionsDocumentation": "Une impression est comptée chaque fois que votre site web est affiché dans une page de résultats d'un moteur de recherche.",
- "IntegrationConfigured": "L'intégration a été configurée avec succès",
- "IntegrationNotConfigured": "L'intégration n'a pas été encore configurée",
- "InvalidRedirectUriInClientConfiguration": "URI de redirection invalides, au moins une URI doit correspondre à l'URI \"%1$s\" dans le fichier de configuration téléversé",
- "KeywordStatistics": "Mots-clés de recherche",
- "KeywordTypeImage": "image",
- "KeywordTypeNews": "actualités",
- "KeywordTypeVideo": "vidéo",
- "KeywordTypeWeb": "web",
- "KeywordsCombined": "Mots clés combinés",
- "KeywordsCombinedDocumentation": "Rapport combinant tous les mots-clés détectés par Matomo et importés des moteurs de recherche. Ce rapport ne comprend que la métrique des visites. Vous pouvez passer à l'un des rapports connexes pour obtenir des mesures détaillées.",
- "KeywordsCombinedImported": "Tous les mots-clés combinés importés",
- "KeywordsCombinedImportedDocumentation": "Rapport montrant tous les mots-clés importés de tous les moteurs de recherche configurés.",
- "KeywordsReferrers": "Mots-clés (y compris non définis)",
- "KeywordsSubtableImported": "Mots clés importés",
- "KeywordsSubtableOriginal": "Mots-clés suivis (y compris non définis)",
- "LastCrawled": "Dernier crawlé",
- "LastDetected": "Dernier détecté",
- "LastImport": "Dernier import",
- "LatestAvailableDate": "Les données de mots-clés les plus récentes sont celles de %1$s",
- "LinksToUrl": "Liens vers %s",
- "ManageAPIKeys": "Gérer les clés API",
- "MeasurableConfig": "sites web configurés",
- "NewsKeywords": "Mots clés Google Actualités",
- "NewsKeywordsDocumentation": "Mots-clés utilisés dans la recherche Google Actualités qui ont généré des liens vers votre site web dans la liste des résultats de recherche.",
- "NoSegmentation": "Le rapport ne prend pas en charge la segmentation. Les données affichées sont celles de votre rapport standard, non segmenté.",
- "NoWebsiteConfigured": "Il n'y a actuellement aucun site web configuré. Pour activer l'import pour un site web spécifique, veuillez configurer la configuration ici.",
- "NoWebsiteConfiguredWarning": "L'import pour %s n'est pas entièrement configuré. Vous devez configurer certains sites Web pour permettre l'importation.",
- "NotAvailable": "Non disponible",
- "OAuthAccessTimedOut": "L'accès OAuth pour ce compte a peut-être expiré. Vous devrez vous réauthentifier pour que les imports fonctionnent à nouveau pour ce compte.",
- "OAuthAccessWillTimeOut": "L'accès OAuth pour ce compte expirera après %1$s jours. %2$s jours restants",
- "OAuthAccessWillTimeOutSoon": "L'accès OAuth pour ce compte expirera dans environ %1$s jours. Veuillez vous réauthentifier pour éviter que ce compte ne cesse de fonctionner.",
- "OAuthClientConfig": "Configuration du client OAuth",
- "OAuthError": "Une erreur s'est produite dans le processus OAuth. Veuillez réessayer et vous assurer que vous acceptez les permissions demandées.",
- "OAuthExampleText": "La configuration nécessite les champs listés ci-dessous. Veuillez utiliser les valeurs fournies :",
- "OauthFailedMessage": "Nous avons rencontré un problème lors du processus d'autorisation pour votre Google Search Console. Pour réessayer, veuillez cliquer sur le bouton ci-dessous. Si le problème persiste, veuillez contacter notre équipe d'assistance. Elle vous aidera à résoudre le problème et à importer vos mots-clés de Google Search Console.",
- "OptionQuickConnectWithGoogle": "Connexion rapide avec Google (recommandé)",
- "Platform": "Plate-forme",
- "Position": "Position moyenne",
- "PositionDocumentation": "Position moyenne de votre site web dans la liste des résultats des moteurs de recherche (pour ce mot clé).",
- "ProvideYandexClientConfig": "Veuillez insérer la configuration de votre client Yandex OAuth.",
- "ProviderBingDescription": "Importer tous les mots clés utilisés pour trouver votre site web sur les moteurs de recherche Bing et Yahoo!.",
- "ProviderBingNote": "Remarque: Microsoft fournit des données sur les mots-clés tous les samedis et uniquement pour des semaines entières. Par conséquent, vos mots-clés pour Bing et Yahoo mettront quelques jours à apparaître dans vos rapports et ne seront disponibles que lors de la consultation des semaines, mois ou années.",
- "ProviderGoogleDescription": "Importez tous les mots-clés utilisés pour trouver votre site Web sur la recherche Google. Les rapports montreront vos mots-clés pour chaque type de recherche séparément (Web, Images et Vidéos).",
- "ProviderGoogleNote": "Remarque: Google fournit les données définitives des mots-clés avec un retard de 2 jours. Les données non finales pour les jours plus récents seront déjà affichées, mais seront réimportées jusqu'à ce qu'elles soient définitives. Votre premier import peut permettre d'importer vos données historiques de mots-clés jusqu'aux 486 derniers jours.",
- "ProviderListDescription": "Lorsque vous avez configuré avec succès un (ou plusieurs) moteur de recherche ci-dessous, vous pouvez configurer dans quel(s) site(s) web Matomo doit importer vos mots-clés de recherche.",
- "ProviderXAccountWarning": "Problème de configuration de compte détecté Veuillez vérifier les comptes configurés pour %s.",
- "ProviderXSitesWarning": "Problèmes de configuration de site détectés Veuillez vérifier la configuration des sites pour %s.",
- "ProviderYandexDescription": "Importez tous les mots-clés utilisés pour trouver votre site web sur la recherche Yandex.",
- "ProviderYandexNote": "Remarque: Yandex fournit les mots-clés avec un retard allant jusqu'à 5 jours. La première importation tentera d'importer vos mots-clés historiques jusqu'aux 100 derniers jours.",
- "ReAddAccountIfPermanentError": "S'il s'agit d'une erreur permanente, essayez de supprimer le compte et de le connecter à nouveau.",
- "ReAuthenticateIfPermanentError": "S'il s'agit d'une erreur permanente, essayez de réauthentifier le compte ou de le supprimer et de le connecter à nouveau.",
- "Reauthenticate": "Réauthentification",
- "RecentApiErrorsWarning": "Erreurs d'importation de mots-clés détectées
Veuillez vérifier les configurations pour : %s
Si votre configuration est correcte et que les erreurs persistent, veuillez contacter notre support.",
- "ReportShowMaximumValues": "Les valeurs affichées sont les valeurs maximales qui se sont produites pendant cette période.",
- "RequiredAccessTypes": "Ces types d'accès sont nécessaires :",
- "ResponseCode": "Code de réponse",
- "RoundKeywordPosition": "Position arrondi des mots-clés",
- "SearchEngineKeywordsPerformance": "Performance des mots-clés dans les moteurs de recherche",
- "SearchEnginesImported": "Moteurs de recherche (avec mots-clés importés)",
- "SearchEnginesOriginal": "Moteurs de recherche (avec mots-clés suivis)",
- "SetUpOAuthClientConfig": "Configurer votre client OAuth",
- "SetupConfiguration": "Configuration de l'installation",
- "SitemapsContainingUrl": "Sitemaps contenant %s",
- "StartOAuth": "Démarrer le processus OAuth",
- "URLPrefix": "Préfixe de l'URL",
- "URLPrefixProperty": "Propriété de préfixe d'URL",
- "URLPrefixPropertyInfo": "Comprend uniquement les URL avec le préfixe exact indiqué, y compris le protocole (http/https). Si vous souhaitez que votre propriété corresponde à n'importe quel protocole ou sous-domaine (http/https/www/m, etc.), envisagez plutôt d'ajouter une propriété de domaine.",
- "UnverifiedSites": "Sites web non vérifiés :",
- "UploadOAuthClientConfig": "Téléversez la configuration de votre client OAuth",
- "Uploading": "Téléversement en cours...",
- "UrlOfAccount": "URL (Compte)",
- "VideoKeywords": "Mots clés vidéo sur Google",
- "VideoKeywordsDocumentation": "Mots-clés utilisés dans la recherche Google vidéo qui ont généré des liens vers votre site web dans la liste des résultats de recherche.",
- "VisitOAuthHowTo": "Veuillez consulter notre guide %1$sen ligne%2$s pour savoir comment mettre en place votre configuration client OAuth %3$s.",
- "WebKeywords": "Mots clés issus de la recherche Google Web",
- "WebKeywordsDocumentation": "Mots-clés utilisés dans la recherche Google web qui ont généré des liens vers votre site web dans la liste des résultats de recherche.",
- "WebsiteSuccessfulConfigured": "Félicitations! Vous avez configuré avec succès l'import de mots-clés pour le site Web %1$s. Il se peut que quelques jours s'écoulent avant que vos premiers mots-clés de recherche soient importés et affichés dans Référents > Mots-clés de recherche. Vous pouvez trouver plus d'informations sur les délais et les limitations de l'import de mots-clés dans notre %2$sFAQ%3$s",
- "WebsiteTypeUnsupported": "L’élément mesurable sélectionné %1$s ne peut pas être configuré car il a un type non pris en charge. Seuls les éléments mesurables de type 'site web' sont supportés.",
- "WebsiteTypeUnsupportedRollUp": "Remarque : les sites de type \"Roll-Up\" combinent automatiquement les données importées de tous leurs sites associés",
- "YandexConfigurationDescription": "Yandex Webmaster API utilise OAuth pour l'authentification et l'autorisation.",
- "YandexConfigurationTitle": "Configurer l'import à partir de Yandex Webmaster API",
- "YandexCrawlAppearedPages": "Pages apparaissant dans la recherche",
- "YandexCrawlAppearedPagesDesc": "Pages nouvellement ajoutées à l'index de recherche Yandex",
- "YandexCrawlCrawledPages": "Pages explorées",
- "YandexCrawlCrawledPagesDesc": "Nombre de pages demandées par le crawler Yandex.",
- "YandexCrawlErrors": "Autres erreurs de requêtes",
- "YandexCrawlErrorsDesc": "Pages explorées qui ont échoué pour une toute autre raison",
- "YandexCrawlHttpStatus2xx": "Code HTTP 200-299",
- "YandexCrawlHttpStatus2xxDesc": "Pages explorées avec un code 2xx",
- "YandexCrawlHttpStatus3xx": "Code HTTP 300-399 (pages déplacées)",
- "YandexCrawlHttpStatus3xxDesc": "Pages explorées avec un code 3xx",
- "YandexCrawlHttpStatus4xx": "Code HTTP 400-499 (erreurs de requête)",
- "YandexCrawlHttpStatus4xxDesc": "Pages explorées avec un code 4xx",
- "YandexCrawlHttpStatus5xx": "Code HTTP 500-599 (erreurs internes du serveur)",
- "YandexCrawlHttpStatus5xxDesc": "Pages explorées avec un code 5xx",
- "YandexCrawlInIndex": "Nombre total de pages dans l'index",
- "YandexCrawlInIndexDesc": "Nombre total de pages disponibles dans l'index de recherche Yandex",
- "YandexCrawlRemovedPages": "Pages retirées de la recherche",
- "YandexCrawlRemovedPagesDesc": "Pages retirées de l'index de recherche Yandex",
- "YandexCrawlingStats": "Récapitulatif du crawl pour Yandex !",
- "YandexCrawlingStatsDocumentation": "Le récapitulatif du crawl vous permet de visualiser les informations relatives au crawl, telles que les erreurs rencontrées par le robot de recherche lors de la visite d'une page, les éléments bloqués par votre fichier robots.txt et le nombre total de pages dans l'index.",
- "YandexFieldCallbackUri": "URI de rappel",
- "YandexFieldUrlToAppSite": "URL du site de l'application",
- "YandexKeywords": "Mots clés sur Yandex",
- "YandexKeywordsDocumentation": "Mots clés utilisés dans la recherche Yandex qui ont généré des liens vers votre site web dans la liste des résultats de recherche.",
- "YandexWebmasterApiUrl": "Url pour Yandex Webmaster Tools",
- "YandexWebmasterApiUrlDescription": "Fournissez l'url de ce site dans vos Yandex Webmaster Tools"
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/lang/it.json b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/lang/it.json
deleted file mode 100644
index 5f1cff9..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/lang/it.json
+++ /dev/null
@@ -1,225 +0,0 @@
-{
- "SearchEngineKeywordsPerformance": {
- "AccountAddedBy": "Aggiunta da %1$s il %2$s",
- "AccountConnectionValidationError": "Si è verificato un errore durante la convalida della connessione all'account:",
- "AccountDoesNotExist": "L'account configurato %1$s non esiste più",
- "AccountNoAccess": "Al momento questo account non ha accesso ad alcun sito web.",
- "AccountRemovalConfirm": "Stai per rimuovere l'account %1$s. Ciò potrebbe disabilitare l'importazione delle parole chiave per tutti i siti web collegati. Vuoi procedere comunque?",
- "ActivityAccountAdded": "aggiunto un nuovo account per il provider di parole chiave: %1$s: %2$s",
- "ActivityAccountRemoved": "rimosso un account per il provider di parole chiave %1$s: %2$s",
- "ActivityGoogleClientConfigChanged": "configurazione del client di Google cambiata.",
- "ActivityYandexClientConfigChanged": "configurazione client Yandex cambiata",
- "AddAPIKey": "Aggiungi Chiave API",
- "AddConfiguration": "Aggiungi Configurazione",
- "AdminMenuTitle": "Rendimento Ricerca",
- "APIKey": "Chiave API",
- "AvailableSites": "Siti disponibili per l'importazione:",
- "Domain": "Dominio",
- "DomainProperty": "Proprietà dominio",
- "DomainPropertyInfo": "Include tutti i sottodomini (m, www e così via) e entrambi i protocolli (http, https).",
- "URLPrefix": "Prefisso URL",
- "URLPrefixProperty": "Proprietà del prefisso URL",
- "URLPrefixPropertyInfo": "Include solo gli URL con il prefisso esatto specificato, incluso il protocollo (http o https). Se vuoi che la tua proprietà corrisponda a un protocollo o a un sottodominio (http/https/www./m. e così via), prendi in considerazione l'aggiunta di una proprietà Dominio.",
- "BingAccountError": "Si è verificato un errore durante la convalida della chiave API: %1$s. Se hai appena generato questa chiave API in Strumenti per Bing Webmaster Tools, riprova tra uno o due minuti (le chiavi API in Bing Webmaster Tools richiedono un po' di tempo per essere attivate).",
- "BingAccountOk": "Chiave API verificata con successo",
- "BingAPIKeyInstruction": "Accedi a %1$sBing Webmaster Tools%2$s, quindi aggiungi il tuo sito web a Bing Webmaster. Dopo averlo convalidato, puoi %3$scopiare la tua chiave API%4$s.",
- "BingConfigurationDescription": "Bing Webmaster Tools richiede una chiave API per l'accesso. Qui puoi aggiungere le chiavi API per accedere ai dati dei tuoi siti web.",
- "BingConfigurationTitle": "Configura l'importazione da Bing Webmaster Tools",
- "BingCrawlBlockedByRobotsTxt": "Esclusioni tramite robots.txt",
- "BingCrawlBlockedByRobotsTxtDesc": "URL attualmente bloccati dal file robots.txt del tuo sito.",
- "BingCrawlConnectionTimeout": "Timeout della connessione",
- "BingCrawlConnectionTimeoutDesc": "Questo numero rappresenta le occorrenze recenti quando Bing non ha potuto accedere al tuo sito a causa di errori di connessione. Questo potrebbe essere un problema temporaneo, ma è necessario controllare i log del server per vedere se si stanno accidentalmente perdendo le richieste.",
- "BingCrawlCrawledPages": "Pagine esplorate",
- "BingCrawlCrawledPagesDesc": "Numero di pagine richieste dal crawler di Bing.",
- "BingCrawlDNSFailures": "Insuccessi DNS",
- "BingCrawlDNSFailuresDesc": "Questo tipo di problema cataloga gli errori recenti riscontrati durante il tentativo di comunicare con il server DNS quando il bot ha tentato di accedere alle tue pagine. Forse il tuo server era inattivo, oppure c'era un errore di configurazione che impediva il routing DNS, ad esempio TTL era impostato a 0.",
- "BingCrawlErrors": "Errori di scansione su Bing",
- "BingCrawlErrorsDesc": "Numero di errori verificatisi per il crawler di Bing.",
- "BingCrawlErrorsFromDateX": "Il report mostra errori di scansione recentemente segnalati da Bing. Non fornisce dati storici. Ultimo aggiornamento %s",
- "BingCrawlHttpStatus2xx": "Codici HTTP 200-299",
- "BingCrawlHttpStatus2xxDesc": "Questi codici vengono visualizzati quando il server presenta una pagina correttamente",
- "BingCrawlHttpStatus301": "Codice HTTP 301 (Spostata definitivamente)",
- "BingCrawlHttpStatus301Desc": "Questi codici vengono visualizzati quando si sposta permanentemente il contenuto da una posizione (URL) a un'altra.",
- "BingCrawlHttpStatus302": "Codice HTTP 302 (Spostata temporaneamente)",
- "BingCrawlHttpStatus302Desc": "Questi codici vengono visualizzati quando si sposta temporaneamente il contenuto da una posizione (URL) a un'altra.",
- "BingCrawlHttpStatus4xx": "Codici HTTP 400-499 (Errori richiesta)",
- "BingCrawlHttpStatus4xxDesc": "Questi codici vengono visualizzati quando c'è stato probabilmente un errore nella richiesta che ha impedito al server di elaborarla.",
- "BingCrawlHttpStatus5xx": "Codici HTTP 500-599 (Errori interni al server)",
- "BingCrawlHttpStatus5xxDesc": "Questi codici vengono visualizzati quando il server non è riuscito a soddisfare una richiesta apparentemente valida.",
- "BingCrawlImportantBlockedByRobotsTxt": "Esclusione tramite robots.txt di una pagina importante",
- "BingCrawlInboundLink": "Totale link in entrata",
- "BingCrawlInboundLinkDesc": "I collegamenti in entrata di cui Bing è a conoscenza, hanno puntato agli URL sul tuo sito web. Questi sono collegamenti da siti web esterni al tuo che sono stati indirizzati verso i tuoi contenuti.",
- "BingCrawlingStats": "Panoramica della scansione per Bing e Yahoo!",
- "BingCrawlingStatsDocumentation": "La panoramica Scansione consente di visualizzare informazioni correlate alla ricerca per l'indicizzazione, quali errori riscontrati dal bot di ricerca quando visita una pagina, elementi bloccati dal proprio file robots.txt e URL potenzialmente interessati da malware.",
- "BingCrawlMalwareInfected": "Siti web infettati da malware",
- "BingCrawlMalwareInfectedDesc": "In questa sezione sono raggruppati gli URL delle pagine che Bing ha rilevato come infette o associate a malware.",
- "BingCrawlPagesInIndex": "Totale delle pagine nell'indice",
- "BingCrawlPagesInIndexDesc": "Numero totale delle pagine disponibili nell'indice di Bing",
- "BingCrawlStatsOtherCodes": "Tutti gli altri codici di stato HTTP",
- "BingCrawlStatsOtherCodesDesc": "Raggruppa tutti gli altri codici che non corrispondono a nessun altro valore (come 1xx o codici informativi).",
- "BingKeywordImport": "Importazione di parole chiave Bing",
- "BingKeywords": "Parole chiave (su Bing e Yahoo!)",
- "BingKeywordsDocumentation": "Parole chiave utilizzate nella ricerca di Bing o Yahoo! che hanno generato collegamenti al tuo sito web nell'elenco dei risultati.",
- "BingKeywordsNoRangeReports": "Parole chiave su Bing e Yahoo! che possono essere elaborate solo per intervalli di date personalizzati, comprese settimane o mesi interi in quanto non sono disponibili come rapporti giornalieri.",
- "BingKeywordsNotDaily": "Parole chiave su Bing e Yahoo! che sono disponibili solo come rapporti settimanali. Non ci sono dati sulle parole chiave per i periodi di giorni.",
- "BingWebmasterApiUrl": "Url di Bing Webmaster Tools",
- "BingWebmasterApiUrlDescription": "Fornisce l'url di questo sito Web disponibile in Bing Webmaster Tools",
- "Category": "Categoria",
- "ChangeConfiguration": "Cambia configurazione",
- "Clicks": "Clicks",
- "ClicksDocumentation": "Viene conteggiato un click ogni volta che un utente clicca su un link che punta al tuo sito web sulla pagina dei risultati di un motore di ricerca.",
- "ClientConfigImported": "La configurazione del client è stata importata con successo!",
- "ClientConfigSaveError": "Si è verificato un errore durante il salvataggio della configurazione del client. Si prega di verificare se la configurazione fornita è valida e poi riprovare.",
- "ClientId": "Id client",
- "ClientSecret": "Segreto del client",
- "ConfigAvailableNoWebsiteConfigured": "Integrazione correttamente configurata, ma attualmente nessun sito web è configurato per l'importazione.",
- "ConfigRemovalConfirm": "Stai per rimuovere la configurazione per %1$s. L'importazione di parole chiave per quel sito web sarà disabilitata. Procedere comunque?",
- "Configuration": "Configurazione",
- "ConfigurationDescription": "Questo plugin consente di importare direttamente in Matomo tutte le parole chiave cercate dagli utenti sui motori di ricerca.",
- "ConfigurationFile": "File di configurazione",
- "ConfigurationValid": "La tua configurazione OAuth è valida.",
- "ConfiguredAccounts": "account configurati",
- "ConfiguredUrlNotAvailable": "L'URL configurato non è disponibile per questo account",
- "ConfigureMeasurableBelow": "Per configurare un sito Web, è sufficiente cliccare sul pulsante in basso o configurarlo direttamente nelle sue impostazioni.",
- "ConfigureMeasurables": "Configura siti web",
- "ConnectAccount": "Collega Account",
- "ConnectAccountDescription": "Clicca sul pulsante in basso per essere reindirizzati a %1$s dove è necessario dare l'accesso.",
- "ConnectAccountYandex": "L'autenticazione per gli account Yandex è valida solo per %1$s giorni. Ogni account deve essere nuovamente autenticato entro questo tempo per garantire che le importazioni funzionino correttamente.",
- "ConnectFirstAccount": "Inizia collegando il tuo primo account qui sotto.",
- "ConnectGoogleAccounts": "Collega Account di Google",
- "ContainingSitemaps": "Contenenti Sitemap",
- "CrawlingErrors": "Errori di scansione",
- "ConnectYandexAccounts": "Collega account Yandex",
- "CrawlingStats": "Panoramica scansione",
- "Ctr": "Percentuale di clicks (CTR)",
- "CtrDocumentation": "Percentuale di click: report che mostra la frequenza con cui le persone che vedono la pagina dei risultati di un motore di ricerca con un link al tuo sito web finiscono per cliccarci sopra.",
- "CurrentlyConnectedAccounts": "Al momento sei collegato con %1$s accounts.",
- "EnabledSearchTypes": "Tipi di parole chiave da recuperare",
- "FetchImageKeyword": "Recupera parole chiave immagine",
- "FetchImageKeywordDesc": "Recupera le parole chiave utilizzate nella ricerca immagini di Google",
- "FetchNewsKeyword": "Recupera le parole chiave delle notizie",
- "FetchNewsKeywordDesc": "Recupera le parole chiave usate in Google News",
- "FetchVideoKeyword": "Recupera parole chiave video",
- "FetchVideoKeywordDesc": "Recupera le parole chiave utilizzate nella ricerca video di Google",
- "FetchWebKeyword": "Recupera parole chiave web",
- "FetchWebKeywordDesc": "Recupera le parole chiave utilizzate nella ricerca web di Google",
- "FirstDetected": "Prima individuata",
- "GoogleAccountAccessTypeOfflineAccess": "È necessario l'Accesso offline per poter importare le parole chiave di ricerca anche quando non si è connessi.",
- "GoogleAccountAccessTypeProfileInfo": "Le Informazioni del profilo vengono utilizzate per mostrare il nome degli account attualmente connessi.",
- "GoogleAccountAccessTypeSearchConsoleData": "I Dati della Console di Ricerca sono necessari per ottenere l'accesso alle tue parole chiave di ricerca di Google.",
- "GoogleAccountError": "Si è verificato un errore durante la convalida dell'accesso OAuth: %1$s",
- "GoogleAccountOk": "Accesso OAuth verificato con successo.",
- "GoogleConfigurationDescription": "La Console di Ricerca di Google utilizza OAuth per l'autenticazione e l'autorizzazione.",
- "GoogleConfigurationTitle": "Configura l'importazione dalla Console di Ricerca di Google",
- "GoogleDataProvidedWithDelay": "Google fornisce i dati delle parole chiave con un ritardo. Le parole chiave per questa data verranno importate un po' più tardi.",
- "GoogleDataNotFinal": "I dati delle parole chiave in questo report potrebbero non contenere ancora i dati finali. Google fornisce i dati finali sulle parole chiave con un ritardo di 2 giorni. Le parole chiave per i giorni più recenti verranno reimportate fino a quando non verranno segnalate come definitive.",
- "GoogleKeywordImport": "Importazione di parole chiave di Google",
- "GoogleSearchConsoleUrl": "Url per la Console di Ricerca di Google",
- "GoogleSearchConsoleUrlDescription": "Indica l'url per questo sito web disponibile nella tua Search Console di Google",
- "GoogleUploadOrPasteClientConfig": "Carica la configurazione del client Google OAuth o incollala nel campo sottostante.",
- "HowToGetOAuthClientConfig": "Come ottenere la configurazione del tuo client OAuth",
- "ImageKeywords": "Parole chiave immagini su Google",
- "ImageKeywordsDocumentation": "Parole chiave utilizzate nella ricerca per immagini di Google che hanno generato collegamenti al tuo sito web nell'elenco dei risultati della ricerca.",
- "Impressions": "Impressioni",
- "ImpressionsDocumentation": "Viene conteggiata un'impressione ogni volta che il tuo sito web viene visualizzato in una pagina dei risultati dei motori di ricerca.",
- "IntegrationConfigured": "Integrazione configurata con successo",
- "IntegrationNotConfigured": "Integrazione non ancora configurata",
- "KeywordsCombined": "Keyword combinate",
- "KeywordsCombinedDocumentation": "Report che combina tutte le parole chiave rilevate da Matomo e importate dai motori di ricerca. Questo report include solo la metrica visita. È possibile passare a uno dei report correlati per ottenere delle metriche dettagliate.",
- "KeywordsCombinedImported": "Keyword importate combinate",
- "KeywordsCombinedImportedDocumentation": "Segnala tutte le parole chiave importate da tutti i motori di ricerca configurati.",
- "KeywordsReferrers": "Parole chiave (incluse quelle non definite)",
- "KeywordStatistics": "Keywords di Ricerca",
- "KeywordTypeImage": "immagine",
- "KeywordTypeVideo": "video",
- "KeywordTypeWeb": "web",
- "KeywordTypeNews": "notizie",
- "LastCrawled": "Ultima scansione",
- "LastDetected": "Ultima rilevata",
- "LastImport": "Ultima importazione",
- "LatestAvailableDate": "Dati delle parole chiave più recenti disponibili per %1$s",
- "LinksToUrl": "Collegamenti a %s",
- "ManageAPIKeys": "Gestisci Chiavi API",
- "MeasurableConfig": "siti configurati",
- "NoSegmentation": "Il report non supporta la segmentazione. I dati visualizzati sono i dati del report standard non segmentati.",
- "NotAvailable": "Non disponibile",
- "NoWebsiteConfigured": "Al momento non ci sono siti web configurati. Per abilitare l'importazione per un sito web specifico, impostare qui la configurazione.",
- "NoWebsiteConfiguredWarning": "Importazione per %s non completamente configurata. È necessario configurare alcuni siti web per abilitare l'importazione.",
- "OAuthAccessTimedOut": "L'accesso OAuth per questo account potrebbe essere scaduto. Sarà necessario eseguire nuovamente l'autenticazione per ripristinare il funzionamento delle importazioni per questo account.",
- "OAuthAccessWillTimeOutSoon": "L'accesso OAuth per questo account scadrà tra circa %1$s giorni. Esegui nuovamente l'autenticazione per evitare che le importazioni per questo account smettano di funzionare.",
- "OAuthAccessWillTimeOut": "L'accesso OAuth per questo account scadrà dopo %1$s %2$s giorni. giorni rimasti",
- "OAuthClientConfig": "Configurazione Client OAuth",
- "OAuthError": "Si è verificato un errore all'interno del processo OAuth. Si prega di riprovare e di assicurarsi di accettare le autorizzazioni richieste.",
- "Platform": "Piattaforma",
- "Position": "Media della Posizione",
- "PositionDocumentation": "Media della posizione del tuo sito web nell'elenco dei risultati dei motori di ricerca (per questa parola chiave).",
- "ProviderBingDescription": "Importa tutte le keyword utilizzate per trovare il tuo sito web sulla ricerca di Bing e Yahoo!.",
- "ProviderBingNote": "Nota: Microsoft fornisce dati sulle parole chiave ogni sabato e solo per settimane complete. Di conseguenza, le parole chiave per Bing e Yahoo impiegheranno alcuni giorni per comparire nei tuoi report e saranno disponibili solo durante la visualizzazione di settimane, mesi o anni.",
- "ProviderGoogleDescription": "Importa tutte le parole chiave utilizzate per trovare il tuo sito web sulla ricerca di Google. I report mostreranno le tue parole chiave per ogni tipo di ricerca separatamente (Web, Immagini e Video).",
- "ProviderGoogleNote": "Nota: Google fornisce i dati finali sulle parole chiave con un ritardo di 2 giorni. I dati non definitivi per i giorni più recenti verranno già visualizzati, ma verranno reimportati fino a quando non saranno definitivi. La tua prima importazione potrebbe essere in grado di importare i dati storici delle parole chiave fino agli ultimi 486 giorni.",
- "ProviderListDescription": "Dopo avere impostato correttamente uno (o più) motori di ricerca qui di seguito, puoi configurare in quale sito (o siti) Matomo deve importare le tue parole chiave di ricerca.",
- "ProviderXAccountWarning": "Rilevati problemi di configurazione dell'account Si prega di verificare gli account configurati per %s.",
- "ProviderXSitesWarning": "Rilevati problemi di configurazione di un sito web Si prega di verificare i siti configurati per %s.",
- "ProviderYandexDescription": "Importa tutte le parole chiave utilizzate per trovare il tuo sito web nella ricerca Yandex.",
- "ProviderYandexNote": "Nota: Yandex fornisce le parole chiave con un ritardo fino a 5 giorni. La prima importazione proverà a importare le tue parole chiave storiche fino agli ultimi 100 giorni.",
- "ProvideYandexClientConfig": "Inserisci la configurazione del tuo client OAuth Yandex.",
- "Reauthenticate": "Autenticati di nuovo",
- "ReAddAccountIfPermanentError": "Se questo è un errore permanente, prova a rimuovere l'account e a ricollegarlo.",
- "ReAuthenticateIfPermanentError": "Se si tratta di un errore permanente, prova ad autenticare nuovamente l'account o rimuovilo e ricollegalo.",
- "ReportShowMaximumValues": "I valori visualizzati sono i valori massimi che si sono verificati durante questo periodo.",
- "RequiredAccessTypes": "Sono richiesti questi tipi di accesso:",
- "ResponseCode": "Codice risposta",
- "RoundKeywordPosition": "Posizione round keyword",
- "SearchEngineKeywordsPerformance": "Rendimentodelle keyword dei motori di ricerca",
- "SetupConfiguration": "Imposta configurazione",
- "SitemapsContainingUrl": "Sitemap che contengono %s",
- "SetUpOAuthClientConfig": "Imposta la configurazione del tuo client OAuth",
- "KeywordsSubtableOriginal": "Keyword tracciate (incluse quelle non definite)",
- "KeywordsSubtableImported": "Keyword importate",
- "AllReferrersOriginal": "Referrer (con keyword tracciate)",
- "AllReferrersImported": "Referrer (con keyword importate)",
- "SearchEnginesOriginal": "Motori di ricerca (con keyword tracciate)",
- "SearchEnginesImported": "Motori di ricerca (con keyword importate)",
- "StartOAuth": "Inizia Processo OAuth",
- "UnverifiedSites": "Siti non verificati:",
- "UploadOAuthClientConfig": "Carica la configurazione del tuo client OAuth",
- "UrlOfAccount": "URL (Account)",
- "VideoKeywords": "Parole chiave per video su Google",
- "VideoKeywordsDocumentation": "Parole chiave utilizzate nella ricerca video di Google che hanno generato collegamenti al tuo sito web nell'elenco dei risultati della ricerca.",
- "NewsKeywords": "Parole chiave news su Google",
- "NewsKeywordsDocumentation": "Parole chiave utilizzate nella ricerca di Google News che hanno generato collegamenti al tuo sito web nell'elenco dei risultati di ricerca.",
- "VisitOAuthHowTo": "Visita la nostra %1$sguida in linea%2$s per scoprire come impostare la configurazione del tuo %3$s client OAuth.",
- "WebKeywords": "Parole chiave web su Google",
- "WebKeywordsDocumentation": "Parole chiave utilizzate nella ricerca web di Google che hanno generato collegamenti al tuo sito web nell'elenco dei risultati della ricerca.",
- "WebsiteSuccessfulConfigured": "Congratulazioni! Hai configurato correttamente l'importazione delle parole chiave per il sito web %1$s. Potrebbero essere necessari alcuni giorni prima che le prime parole chiave di ricerca vengano importate e visualizzate in Referenti > Keywords di Ricerca. Puoi trovare ulteriori informazioni su ritardi e limitazioni delle importazioni delle parole chiave nelle nostre %2$sFAQ%3$s",
- "WebsiteTypeUnsupported": "Il misurabile selezionato %1$s non può essere configurato perché è di un tipo non supportato. Sono supportati solamente i misurabili di tipo 'sito web'.",
- "WebsiteTypeUnsupportedRollUp": "Nota: I siti Roll-Up combineranno automaticamente i dati importati di tutti i siti figlio",
- "YandexConfigurationDescription": "L'API Webmaster di Yandex utilizza OAuth per l'autenticazione e l'autorizzazione.",
- "YandexConfigurationTitle": "Configura l'importazione dall'API Webmaster di Yandex",
- "YandexCrawlingStats": "Guarda una panoramica su Yandex!",
- "YandexCrawlingStatsDocumentation": "La panoramica della Scansione ti consente di visualizzare le informazioni relative alla scansione come gli errori riscontrati dal bot di ricerca durante la visita di una pagina, gli elementi bloccati dal tuo file robots.txt e il numero totale di pagine nell'indice.",
- "YandexCrawlHttpStatus2xx": "Codici HTTP 200-299",
- "YandexCrawlHttpStatus2xxDesc": "Pagine con un codice 2xx esplorate",
- "YandexCrawlHttpStatus3xx": "Codici HTTP 300-399 (Pagine spostate)",
- "YandexCrawlHttpStatus3xxDesc": "Pagine con un codice 3xx esplorate",
- "YandexCrawlHttpStatus4xx": "Codici HTTP 400-499 (Errori richiesta)",
- "YandexCrawlHttpStatus4xxDesc": "Pagine con un codice 4xx esplorate",
- "YandexCrawlHttpStatus5xx": "Codici HTTP 500-599 (Errori interni al server)",
- "YandexCrawlHttpStatus5xxDesc": "Pagine con un codice 5xx esplorate",
- "YandexCrawlErrors": "Altri errori richiesta",
- "YandexCrawlErrorsDesc": "Pagine esplorate che hanno fallito per qualsiasi altra ragione",
- "YandexCrawlCrawledPages": "Pagine Esplorate",
- "YandexCrawlCrawledPagesDesc": "Numero di pagine richieste dal crawler Yandex",
- "YandexCrawlInIndex": "Totale delle pagine nell'indice",
- "YandexCrawlInIndexDesc": "Numero totale di pagine disponibili nell'indice di ricerca Yandex",
- "YandexCrawlAppearedPages": "Pagine apparse nella ricerca",
- "YandexCrawlAppearedPagesDesc": "Pagine che sono state appena aggiunte all'indice di ricerca Yandex",
- "YandexCrawlRemovedPages": "Pagine rimosse dalla ricerca",
- "YandexCrawlRemovedPagesDesc": "Pagine che sono state rimosse dall'indice di ricerca Yandex",
- "YandexKeywords": "Parole chiave su Yandex",
- "YandexKeywordsDocumentation": "Parole chiave utilizzate nella ricerca Yandex che hanno generato collegamenti al tuo sito Web nell'elenco dei risultati di ricerca.",
- "YandexWebmasterApiUrl": "Url di Yandex Webmaster Tools",
- "YandexWebmasterApiUrlDescription": "Fornisci l'url di questo sito web disponibile nei tuoi Strumenti per i Webmaster di Yandex",
- "CrawlingOverview1": "La panoramica delle scansioni riporta tutte le informazioni più importanti su come i robot dei motori di ricerca eseguono la scansione dei tuoi siti web. Queste metriche vengono aggiornate circa una volta al giorno con i dati forniti dai motori di ricerca."
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/lang/nl.json b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/lang/nl.json
deleted file mode 100644
index fb5a46c..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/lang/nl.json
+++ /dev/null
@@ -1,183 +0,0 @@
-{
- "SearchEngineKeywordsPerformance": {
- "AccountAddedBy": "Toegevoegd door %1$s<\/em> op %2$s<\/em>",
- "AccountConnectionValidationError": "Er is een fout opgetreden tijdens het valideren van de connectie met het account:",
- "AccountDoesNotExist": "Dit account %1$sbestaat niet meer.",
- "AccountNoAccess": "Dit account heeft momenteel geen toegang tot een website.",
- "AccountRemovalConfirm": "Je staat op het punt het account %1$s te verwijderen. Dit kan het importeren van zoekwoorden voor alle gekoppelde website(s) uitschakelen. Toch doorgaan?",
- "ActivityAccountAdded": "een nieuw account voor keyword provider %1$s is toegevoegd: %2$s",
- "ActivityAccountRemoved": "een account voor keyword provider %1$s is verwijderd: %2$s",
- "ActivityGoogleClientConfigChanged": "de configuratie van de Google-client gewijzigd.",
- "ActivityYandexClientConfigChanged": "de configuratie van de Yandex client gewijzigd.",
- "AddAPIKey": "API Key toegevoegd",
- "AddConfiguration": "Configuratie is toegevoegd",
- "AdminMenuTitle": "Zoekprestaties",
- "APIKey": "API Key",
- "AvailableSites": "Beschikbare websites voor import:",
- "Domain": "Domein",
- "DomainProperty": "Domein property",
- "DomainPropertyInfo": "Bevat alle subdomeinen (m, www, enzovoort) en beide protocollen (http, https).",
- "URLPrefix": "URL-voorvoegsel",
- "URLPrefixProperty": "Property met URL-voorvoegsel",
- "URLPrefixPropertyInfo": "Bevat alleen URL's met het exact opgegeven voorvoegsel, inclusief het protocol (http\/https). Als je wilt dat je property overeenkomt met elk protocol of subdomein (http\/https\/www.\/m. enzovoort), overweeg dan een domein property toe te voegen.",
- "BingAccountError": "Er is een fout opgetreden tijdens het valideren van de API Key: %1$s. Wanneer je de API Key zojuist heb gegenereerd in Bing Webmast Tools probeer het dan nog eens over één of twee minuten(API Keys in Bing Webmaster Tools hebben even tijd nodig om te worden geactiveerd)",
- "BingAccountOk": "API Key is succesvol gecontroleerd",
- "BingConfigurationDescription": "De Bing Webmaster Tools heeft een API Key nodig om te openen. Hier kan je je API Key toevoegen om toegang te krijgen tot je website data.",
- "BingConfigurationTitle": "Configureer de import van Bing Webmaster Tools",
- "BingCrawlBlockedByRobotsTxt": "Robots.txt uitgesloten",
- "BingCrawlBlockedByRobotsTxtDesc": "URL's momenteel geblokkeerd door de websites robots.txt",
- "BingCrawlConnectionTimeout": "Connectie time outs",
- "BingCrawlConnectionTimeoutDesc": "Dit nummer toont het aantal recente keren dat Bing je website niet heeft kunnen benaderen door connectie problemen. Dit kan een tijdelijk probleem zijn maar je zou je server logs kunnen controleren om te zien of er verzoeken verloren gaan.",
- "BingCrawlCrawledPages": "Doorzochte pagina's",
- "BingCrawlCrawledPagesDesc": "Aantal pagina the Bing crawler heeft aangevraagd.",
- "BingCrawlDNSFailures": "DNS storing",
- "BingCrawlDNSFailuresDesc": "Dit issue type verzameld recente fouten die zijn tegen gekomen bij het communiceren met de DNS server wanneer de bot toegang tot je website probeerde te krijgen. Mogelijk stond de server uit, of de instellingen stonden niet goed waardoor DNS routing werd tegengehouden, bijvoorbeeld TTL stond op 0.",
- "BingCrawlErrors": "Crawl errors op Bing",
- "BingCrawlErrorsDesc": "Aantal foutmeldingen die voorkwamen bij de Bing crawler",
- "BingCrawlErrorsFromDateX": "Dit rapport toont crawling fouten welke recent zijn gerapporteerd door Bing. Het toont geen historische data. Laatste update %s",
- "BingCrawlHttpStatus2xx": "HTTP Code 200-299",
- "BingCrawlHttpStatus2xxDesc": "Deze codes verschijnen wanneer de server een pagina succesvol laad",
- "BingCrawlHttpStatus301": "HTTP Code 301 (Permanent verwijderd)",
- "BingCrawlHttpStatus301Desc": "Deze codes verschijnen wanneer bepaalde content permanent is verplaatst van de ene locatie (URL) naar een andere.",
- "BingCrawlHttpStatus302": "HTTP Code 302 (Tijdelijk verwijderd)",
- "BingCrawlHttpStatus302Desc": "Deze codes verschijnen wanneer bepaalde content tijdelijk is verplaatst van de ene locatie (URL) naar een andere.",
- "BingCrawlHttpStatus4xx": "HTTP Code 400-499 (Request errors)",
- "BingCrawlHttpStatus4xxDesc": "Deze codes verschijnen wanneer er waarschijnlijk een fout was het verzoek welke ervoor zorgde dat de server het niet kon verwerken.",
- "BingCrawlHttpStatus5xx": "HTTP Code 500-599 (Interne server errors)",
- "BingCrawlHttpStatus5xxDesc": "Deze codes verschijnen wanneer het een server niet lukt om een schijnbaar geldig verzoek uit te voeren.",
- "BingCrawlImportantBlockedByRobotsTxt": "Robots.txt uitsluiting van belangrijke pagina",
- "BingCrawlInboundLink": "Totaal inbound links",
- "BingCrawlInboundLinkDesc": "Inbound links waar Bing weet van heeft, gericht op URL's op jouw website. Deze links zijn, van externe websites of van jezelf, welke gelinkt zijn naar je content.",
- "BingCrawlingStats": "Crawl overzicht voor Bing en Yahoo!",
- "BingCrawlingStatsDocumentation": "Het crawl overzicht laat je crawl gerelateerde informatie zien zoals fouten die ondervonden zijn door zoek bot bij het bezoeken van een pagina, items geblokkeerd door je robots.txt bestand en URL's welke potentieel getroffen zijn door malware.",
- "BingCrawlMalwareInfected": "Met malware geïnfecteerde websites",
- "BingCrawlMalwareInfectedDesc": "Elke pagina URL die Bing heeft gevonden welke geïnfecteerd of geassocieerd worden met malware worden in dit deel gegroepeerd.",
- "BingCrawlPagesInIndex": "Totaal pagina's in index",
- "BingCrawlPagesInIndexDesc": "Totaal aantal pagina's beschikbaar in de Bing index",
- "BingCrawlStatsOtherCodes": "Alle andere HTTP status codes",
- "BingCrawlStatsOtherCodesDesc": "Overige groepen codes die niet overeenkomen met elke andere waarde (zoals 1xx of informatieve codes)",
- "BingKeywordImport": "Bing zoekwoorden import",
- "BingKeywords": "Zoekwoorden (on Bing en Yahoo!)",
- "BingKeywordsDocumentation": "Zoekwoorden gebruikt in Bing of Yahoo! zoekmachine die gegenereerde links naar je website in het zoekresultaten overzicht tonen.",
- "BingKeywordsNoRangeReports": "Zoekwoorden op Bing en Yahoo! kunnen alleen verwerkt worden voor aangepaste datum periodes inclusief volledige weken of maanden aangezien de dagelijkse rapporten niet beschikbaar zijn.",
- "BingKeywordsNotDaily": "Zoekwoorden van Bing en Yahoo! zijn alleen beschikbaar als wekelijkse rapporten. Er is geen sleutelwoord data beschikbaar voor perioden van een dag.",
- "BingWebmasterApiUrl": "URL voor Bing Webmaster Tools",
- "BingWebmasterApiUrlDescription": "Geef de URL voor deze website welke beschikbaar is in je Bing Webmaster Tools",
- "Category": "Categorie",
- "ChangeConfiguration": "Wijzig configuratie",
- "Clicks": "Kliks",
- "ClicksDocumentation": "Een klik wordt elke keer geteld wanneer iemand klikt op een link welke gericht is op jouw website vanaf een zoekmachine resultaat pagina.",
- "ClientConfigImported": "Client configuratie is succesvol geïmporteerd!",
- "ClientConfigSaveError": "Er is een fout opgetreden tijdens het opslaan van de client configuratie. Controleer of de configuratie goed is en probeer het dan nogmaals.",
- "ClientId": "Client id",
- "ClientSecret": "Client geheim",
- "ConfigAvailableNoWebsiteConfigured": "De integratie is succesvol geconfigureerd. Er zijn nog geen websites geconfigureerd voor het importeren.",
- "ConfigRemovalConfirm": "Je staat op het punt om de instellingen for %1$s te verwijderen. Het importeren van zoekwoorden voor die website zal worden uitgeschakeld. Toch doorgaan?",
- "Configuration": "Configuratie",
- "ConfigurationDescription": "Deze plugin geeft je de mogelijkheid om alle zoekwoorden ingevoerd door gebruikers op een zoekmachine direct te importeren in Matomo.",
- "ConfigurationFile": "Configuratie bestand",
- "ConfigurationValid": "De OAuth configuratie is geldig.",
- "ConfiguredAccounts": "geconfigureerde accounts",
- "ConfiguredUrlNotAvailable": "De geconfigureerde URL is niet beschikbaar voor dit account",
- "ConfigureMeasurableBelow": "Om een website te configureren, klik daarvoor op de button hieronder of configureer het direct in de website instellingen.",
- "ConfigureMeasurables": "Configureer websites",
- "ConnectAccount": "Koppel account",
- "ConnectFirstAccount": "Begin hieronder met het koppelen van je eerste account.",
- "ConnectGoogleAccounts": "Koppel Google Account(s)",
- "ContainingSitemaps": "Bevat Sitemaps",
- "CrawlingErrors": "Crawling fouten",
- "ConnectYandexAccounts": "Koppel Yandex Account(s)",
- "CrawlingStats": "Crawling overzicht",
- "Ctr": "CTR",
- "CtrDocumentation": "Clickthrough rate: een ratio van hoe vaak mensen die vanaf een zoekmachine resultaten pagina met een link naar je website op je website terecht komen door op de link te klikken.",
- "CurrentlyConnectedAccounts": "Er zijn momenteel %1$s accounts gekoppeld.",
- "EnabledSearchTypes": "Zoekwoorden types om op te halen",
- "FetchImageKeyword": "Opgehaalde plaatjes zoekwoorden",
- "FetchImageKeywordDesc": "Opgehaalde zoekwoorden gebruikt in Google image search",
- "FetchVideoKeyword": "Opgehaalde video zoekwoorden",
- "FetchVideoKeywordDesc": "Opgehaalde zoekwoorden gebruikt in Google video search",
- "FetchWebKeyword": "Ophalen web zoekwoorden",
- "FetchWebKeywordDesc": "Opgehaalde zoekwoorden gebruikt in Google web search",
- "FirstDetected": "Als eerst gevonden",
- "GoogleAccountAccessTypeOfflineAccess": "Offline toegang<\/strong>is vereist om in staat te zijn om de zoekwoorden te importeren, zelfs wanneer je niet ingelogd bent.",
- "GoogleAccountAccessTypeProfileInfo": "Profiel info<\/strong>wordt gebruikt om de namen van de account(s) te tonen die momenteel gekoppeld zijn.",
- "GoogleAccountAccessTypeSearchConsoleData": "Search Console Data<\/strong>is vereist om toegang te krijgen tot je Google Search Keywords.",
- "GoogleAccountError": "Er is een fout opgetreden tijdens het valideren van OAuth toegang: %1$s",
- "GoogleAccountOk": "OAuth toegang is succesvol gecontroleerd.",
- "GoogleConfigurationDescription": "Google Search Console gebruikt OAuth voor authenticate en autorisatie.",
- "GoogleConfigurationTitle": "Configureer import van Google Search Console",
- "GoogleKeywordImport": "Google zoekwoorden import",
- "GoogleSearchConsoleUrl": "URL voor Google Search Console",
- "GoogleSearchConsoleUrlDescription": "Verschaf de url voor deze website waarmee deze beschikbaar is in je Google Search Console",
- "GoogleUploadOrPasteClientConfig": "Upload je Google OAuth configuratie, of plak het in het veld hieronder.",
- "HowToGetOAuthClientConfig": "Waar vind je je OAuth Client configuratie",
- "ImageKeywords": "Plaatjes zoekwoorden op Google",
- "ImageKeywordsDocumentation": "Zoekwoorden gebruikt in Google image<\/b>search die een link hebben gegenereerd naar je website in het zoekresultaten overzicht.",
- "Impressions": "Impressies",
- "ImpressionsDocumentation": "Een impressie wordt geteld elke keer wanneer je website wordt getoond in een zoekmachine resultaat pagina.",
- "IntegrationConfigured": "Integratie is succesvol geconfigureerd",
- "IntegrationNotConfigured": "Integratie is nog niet geconfigureerd",
- "KeywordsCombined": "Gecombineerde zoekwoorden",
- "KeywordsCombinedDocumentation": "Het rapport combineert alle zoekwoorden gevonden door Matomo en geïmporteerd uit zoekmachines. Dit rapport bevat alleen de bezoekers statistieken. Je kan naar een ander rapport gaan om meer gedetailleerde statistieken te zien.",
- "KeywordsCombinedImported": "Gecombineerde geïmporteerde zoekwoorden",
- "KeywordsCombinedImportedDocumentation": "Het rapport toont alle zoekwoorden welke geïmporteerd zijn vanuit alle geconfigureerde zoekmachines.",
- "KeywordsReferrers": "Sleutelwoorden (inclusief zoekwoord niet gedefinieerd)",
- "KeywordStatistics": "Zoekwoorden",
- "KeywordTypeImage": "plaatje",
- "KeywordTypeVideo": "video",
- "KeywordTypeWeb": "web",
- "KeywordTypeNews": "nieuws",
- "LastCrawled": "Laatst crawled",
- "LastDetected": "Laatst gedetecteerde",
- "LastImport": "Laatste import",
- "LatestAvailableDate": "Meest recente zoekwoorden data is beschikbaar voor %1$s",
- "LinksToUrl": "Links naar %s",
- "ManageAPIKeys": "Beheer API Keys",
- "MeasurableConfig": "geconfigureerde websites",
- "NoSegmentation": "Het rapport ondersteund geen segmentatie. De data die getoond wordt is standaard, niet gesegmenteerde rapportage data.",
- "NotAvailable": "Niet beschikbaar",
- "NoWebsiteConfigured": "Er is momenteel geen website geconfigureerd. Om het importeren voor een specifieke website te activeren, stel hier je configuratie in.",
- "NoWebsiteConfiguredWarning": "Import voor %s is niet volledig ingericht. Voor sommige website moeten de instellingen geconfigureerd worden om het importeren te activeren.",
- "OAuthClientConfig": "OAuth Client Configuratie",
- "OAuthError": "Er is een fout opgetreden in het OAuth proces. Probeer het nogmaals en zorg ervoor dat je de verzochte permissies accepteert.",
- "Platform": "Platform",
- "Position": "Gemiddelde positie",
- "PositionDocumentation": "Gemiddelde positie van je website in de zoekresultaten pagina (voor dit zoekwoord).",
- "ProviderBingDescription": "Importeer alle zoekwoorden die gebruikt zijn om je website te vinden via Bing<\/strong> en Yahoo! <\/strong>.",
- "ProviderBingNote": "Let op: <\/u> Microsoft levert zoekwoorden data elke zaterdag en alleen voor een hele week. Dat heeft als gevolg dat de zoekwoorden van Bing en Yahoo! een aantal dagen nodig hebben om in het rapport te verschijnen en alleen zichtbaar zijn wanneer er weken, maanden of jaren als bereik zijn geselecteerd.",
- "ProviderGoogleDescription": "Importeer all zoekwoorden die gebruikt zijn op de Google zoekmachine <\/strong>. De zoekwoorden worden onderverdeeld in het rapport onder de verschillende zoek opties (web, plaatjes en video's)",
- "ProviderListDescription": "Wanneer je één )of meer) zoek machines succesvol hebt ingericht, kan je aangeven in welke website(s) Matomo de zoekwoorden moet importeren.",
- "ProviderXAccountWarning": "Account configuratie probleem ontdekt <\/strong> Controleer de geconfigureerde accounts voor %s<\/strong>.",
- "ProviderXSitesWarning": "Website configuratie problemen ontdekt <\/strong> Controleer de geconfigureerde accounts voor %s<\/strong>",
- "ReAddAccountIfPermanentError": "Wanneer dit een permanente fout is, probeer dan het account te verwijderen en koppel het account opnieuw.",
- "RequiredAccessTypes": "Deze toegangstypen zijn verplicht:",
- "ResponseCode": "Reactie code",
- "RoundKeywordPosition": "Round zoekwoord positie",
- "SearchEngineKeywordsPerformance": "Zoekmachine zoekwoorden prestaties",
- "SetupConfiguration": "Setup configuratie",
- "SitemapsContainingUrl": "Sitemaps bevat %s",
- "KeywordsSubtableOriginal": "Bijgehouden zoekwoorden (inclusief niet gedefinieerde)",
- "KeywordsSubtableImported": "Geïmporteerde zoekwoorden",
- "AllReferrersOriginal": "Referrers (met bijgehouden zoekwoorden)",
- "AllReferrersImported": "Referrers (met geïmporteerde zoekwoorden)",
- "SearchEnginesOriginal": "Zoekmachines (met bijgehouden zoekwoorden)",
- "SearchEnginesImported": "Zoekmachines (met geïmporteerde zoekwoorden)",
- "StartOAuth": "Start OAuth Proces",
- "UnverifiedSites": "Niet gevalideerde websites:",
- "UploadOAuthClientConfig": "Upload je OAuth client configuratie",
- "UrlOfAccount": "URL (Account)",
- "VideoKeywords": "Video zoekwoorden op Google",
- "VideoKeywordsDocumentation": "Zoekwoorden die zijn gebruikt in de zoekfunctie van Google video<\/b> search die gegenereerde links naar je website in het zoekresultaten overzicht tonen.",
- "NewsKeywords": "Nieuws zoekwoorden op Google",
- "WebKeywords": "Web zoekwoorden op Google",
- "WebKeywordsDocumentation": "Zoekwoorden die zijn gebruikt in de zoekfunctie van Google web<\/b> search die gegenereerde links naar je website in het zoekresultaten overzicht tonen.",
- "WebsiteSuccessfulConfigured": "Gefeliciteerd! Je hebt succesvol de zoekwoorden import voor website %1$s geconfigureerd. Het kan een paar dagen duren voordat de eerste zoekwoorden worden geïmporteerd en getoond worden in Herkomst > Zoekwoorden. Meer informatie over de vertraging voor het importeren van zoekwoorden kan je vinden in onze %2$sFAQ%3$s",
- "WebsiteTypeUnsupported": "De geselecteerde meetwaarde %1$s kan niet geconfigureerd worden aangezien het een niet ondersteunde type is. Alleen meetwaarde 'website' worden ondersteund.",
- "WebsiteTypeUnsupportedRollUp": "Opmerking: Roll-Up sites combineert automatisch de geïmporteerde gegevens van al hun onderliggende sites",
- "YandexCrawlingStats": "Crawl overzicht voor Yandex!",
- "YandexCrawlHttpStatus2xx": "HTTP Code 200-299",
- "YandexCrawlHttpStatus4xx": "HTTP Code 400-499 (Request errors)",
- "YandexCrawlHttpStatus5xx": "HTTP Code 500-599 (Interne server errors)",
- "YandexCrawlInIndex": "Totaal pagina's in index"
- }
-}
\ No newline at end of file
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/lang/pl.json b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/lang/pl.json
deleted file mode 100644
index 771aa94..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/lang/pl.json
+++ /dev/null
@@ -1,178 +0,0 @@
-{
- "SearchEngineKeywordsPerformance": {
- "AccountAddedBy": "Dodane przez %1$s<\/em>- %2$s<\/em>",
- "AccountConnectionValidationError": "Wystąpił błąd podczas weryfikacji połączenia konta:",
- "AccountDoesNotExist": "Skonfigurowane konto %1$s już nie istnieje",
- "AccountNoAccess": "To konto nie posiada obecnie dostępu do żadnego serwisu.",
- "AccountRemovalConfirm": "Zamierzasz usunąć konto %1$s. Może to spowodować niedostępność zaimportowanych słów kluczowych dla dowolnego połączonego z nim serwisu. Czy na pewno kontynuować?",
- "ActivityAccountAdded": "dodano nowe konto dostawcy słów kluczowych %1$s: %2$s",
- "ActivityAccountRemoved": "usunięto konto dostawcy słów kluczowych %1$s: %2$s",
- "ActivityGoogleClientConfigChanged": "zmodyfikowano konfigurację klienta Google.",
- "AddAPIKey": "Dodaj klucz API",
- "AddConfiguration": "Dodaj konfigurację",
- "AdminMenuTitle": "Wydajność wyszukiwania",
- "APIKey": "Klucz API",
- "AvailableSites": "Serwisy dostępne do zaimportowania:",
- "Domain": "Domena",
- "DomainProperty": "Usługa domeny",
- "DomainPropertyInfo": "Obejmuje wszystkie subdomeny (m, www itp.) i oba protokoły (http, https).",
- "URLPrefix": "Prefiks adresu URL",
- "URLPrefixProperty": "Usługa z prefiksem URL",
- "URLPrefixPropertyInfo": "Obejmuje tylko adresy URL z dokładnie określonym prefiksem, w tym protokołem (http\/https). Jeśli chcesz, by usługa pasowała do dowolnego protokołu lub subdomeny (http\/https\/www.\/m. itp.), zamiast tej usługi dodaj usługę domeny.",
- "BingAccountError": "Wystąpił błąd podczas weryfikacji klucza API: %1$s. Jeśli klucz został wygenerowany przed chwilą w Narzędziach Webmastera Bing, proszę spróbuj ponownie za minutę lub dwie (klucze API w tym narzędziu potrzebują chwilę na aktywację).",
- "BingAccountOk": "Klucz API zweryfikowany pozytywnie",
- "BingConfigurationDescription": "Narzędzia Webmastera Bing wymagają dostępowego klucza API. Tu możesz dodać klucz API, aby uzyskać dostęp do danych swoich serwisów.",
- "BingConfigurationTitle": "Skonfiguruj import z Narzędzi dla Webmasterów Bing",
- "BingCrawlBlockedByRobotsTxt": "Wykluczenia robots.txt",
- "BingCrawlBlockedByRobotsTxtDesc": "Adresy URL obecnie blokowane przez plik robots.txt.",
- "BingCrawlConnectionTimeout": "Wygaszone połączenia",
- "BingCrawlConnectionTimeoutDesc": "Ta liczba prezentuje ostatnie próby połączenia, podczas których Bing nie było w stanie uzyskać dostępu do serwisu ze względu na błędy połączenia. Może to być sytuacja przejściowa, ale zalecamy weryfikację logów serwera pod kątem przypadkowo zerwanych połączeń.",
- "BingCrawlCrawledPages": "Zindeksowane strony",
- "BingCrawlCrawledPagesDesc": "Liczba odwiedzonych przez robota Bing stron.",
- "BingCrawlDNSFailures": "Błędy DNS",
- "BingCrawlDNSFailuresDesc": "Ten typ błędów zawiera błędy powstałe podczas próby rozwiązania adresu Twojego serwisu przy pomocy serwera DNS. Prawdopodobną przyczyną sytuacji mogło być wyłączenie serwera lub błędna konfiguracja serwera DNS uniemożliwiająca routing, jak na przykład ustawienie TTL na 0.",
- "BingCrawlErrors": "Błędy indeksowania robota Bing",
- "BingCrawlErrorsDesc": "Liczba błędów zauważonych przez robota Bing.",
- "BingCrawlErrorsFromDateX": "Ten raport wskazuje błędy indeksowania zgłoszone przez robota Bing. Nie zawiera danych historycznych. Ostatnia aktualizacja %s",
- "BingCrawlHttpStatus2xx": "Kody HTTP 200-299",
- "BingCrawlHttpStatus2xxDesc": "Te kody są zwracane przez serwer, gdy strona zostanie wygenerowana poprawnie",
- "BingCrawlHttpStatus301": "Kod HTTP 301 (Trwale przeniesiony)",
- "BingCrawlHttpStatus301Desc": "Ten kod występuje gdy na stałe przeniesiesz zawartość z jednej lokalizacji (adresu URL) do innej.",
- "BingCrawlHttpStatus302": "Kod HTTP 302 (Przeniesiony czasowo)",
- "BingCrawlHttpStatus302Desc": "Ten kod jest zwracany przez serwer dla zawartości, którą czasowo przeniesiono z jednej lokalizacji (adres URL) do innej.",
- "BingCrawlHttpStatus4xx": "Kody HTTP 400 - 499 (Błędy żądania)",
- "BingCrawlHttpStatus4xxDesc": "Kody te są zwracane, gdy zaistnieje obawa, że żądanie wysłane do serwera było niepoprawne, co uniemożliwiło serwerowi jego przetworzenie.",
- "BingCrawlHttpStatus5xx": "Kody HTTP 500 - 599 (Wewnętrzne błędy serwera)",
- "BingCrawlHttpStatus5xxDesc": "Te kody zwracane są w sytuacji , gdy serwerowi nie uda się zwrócić odpowiedzi dla poprawnego żądania.",
- "BingCrawlImportantBlockedByRobotsTxt": "Ważna strona wykluczona w pliku robots.txt",
- "BingCrawlInboundLink": "Link wprowadzające",
- "BingCrawlInboundLinkDesc": "Liczba linków postrzeganych przez Bing jako linki kierujące do wybranego serwisu. Są to linki z zewnętrznych stron, które wskazują na Twoje treści.",
- "BingCrawlingStats": "Przegląd indeksowania Bing i Yahoo!",
- "BingCrawlingStatsDocumentation": "Zestawienie indeksowania pozwala Ci zapoznać się z informacjami, które pochodzą z interfejsu robota takimi jak błędy indeksowania, elementy blokowane przez Twój plik robots.txt i adresu URL potencjalnie zainfekowane malware'm.",
- "BingCrawlMalwareInfected": "Strony zainfekowane malware",
- "BingCrawlMalwareInfectedDesc": "Dowolne strony, które Bing uzna za zainfekowane lub powiązane z malware zostaną zgrupowane w tej sekcji.",
- "BingCrawlPagesInIndex": "Liczba zindeksowanych stron",
- "BingCrawlPagesInIndexDesc": "Całkowita liczba stron dostępnych w indeksie Bing",
- "BingCrawlStatsOtherCodes": "Pozostałe kody HTTP",
- "BingCrawlStatsOtherCodesDesc": "Zawiera pozostałe kody, które nie zostały dopasowane (takie jak 1xx czy kody informacyjne).",
- "BingKeywordImport": "Import słów kluczowych z Bing",
- "BingKeywords": "Słowa kluczowe (Bing i Yahoo!)",
- "BingKeywordsDocumentation": "Słowa kluczowe użyte w wyszukiwaniach Bing lub Yahoo!, które spowodowały wygenerowanie linków do Twojego serwisu na liście wyników.",
- "BingKeywordsNoRangeReports": "Słowa kluczowe dla wyszukiwarek Bing lub Yahoo! mogą być przetwarzane jedynie w zakresie dat obejmujących pełne tygodnie lub miesiące, ponieważ nie są dostępne jako raporty dzienne.",
- "BingKeywordsNotDaily": "Słowa kluczowe w Bing i Yahoo! dostępne są jedynie jako raporty tygodniowe. Nie występują tam zestawienia dzienne.",
- "BingWebmasterApiUrl": "Adres Narzędzi Webmastera Bing",
- "BingWebmasterApiUrlDescription": "Wprowadź adres serwisu dostępny w Twoich Narzędziach Webmastera Bing",
- "Category": "Kategoria",
- "ChangeConfiguration": "Zmiana konfiguracji",
- "Clicks": "Kliknięcia",
- "ClicksDocumentation": "Kliknięcie zaliczane jest za każdym razem, gdy odwiedzający kliknie w link prowadzący do Twojego serwisu ze strony wyników wyszukiwarki.",
- "ClientConfigImported": "Konfiguracja klienta została poprawnie zaimportowana!",
- "ClientConfigSaveError": "Wystąpił błąd podczas zapisu konfiguracji klienta. Proszę upewnij się, że podana konfiguracja jest poprawna i spróbuj ponownie.",
- "ClientId": "ID klienta",
- "ClientSecret": "Hasło klienta",
- "ConfigAvailableNoWebsiteConfigured": "Integracja została poprawnie skonfigurowana, lecz nie skonfigurowano żadnego serwisu do importu.",
- "ConfigRemovalConfirm": "Zamierzasz usunąć konfigurację dla %1$s. Import słów kluczowych dla tego serwisu zostanie wyłączony. Czy chcesz kontynuować?",
- "Configuration": "Ustawienia",
- "ConfigurationDescription": "Ta wtyczka pozwala Ci zaimportować bezpośrednio do Matomo wszystkie słowa kluczowe wyszukiwane przez Twoich odwiedzających w wyszukiwarkach.",
- "ConfigurationFile": "Plik ustawień",
- "ConfigurationValid": "Twoja konfiguracja OAuth jest prawidłowa.",
- "ConfiguredAccounts": "ustawione konta",
- "ConfiguredUrlNotAvailable": "Ustawiony adres URL nie jest dostępny dla tego konta",
- "ConfigureMeasurableBelow": "Aby skonfigurować serwis, kliknij przycisk poniżej lub skonfiguruj go bezpośrednio w ustawieniach serwisu.",
- "ConfigureMeasurables": "Skonfiguruj serwisy",
- "ConnectAccount": "Podłącz konto",
- "ConnectFirstAccount": "Zacznij od podłączenia poniżej pierwszego konta.",
- "ConnectGoogleAccounts": "Połącz konto(a) Google",
- "ContainingSitemaps": "Zawierające mapy strony",
- "CrawlingErrors": "Błędy indeksowania",
- "CrawlingStats": "Przegląd indeksowania",
- "Ctr": "CTR",
- "CtrDocumentation": "Współczynnik kliknięć: współczynnik pokazujący jak często użytkownicy wyszukiwarki klikają link do Twojego serwisu wyświetlany na stronie wyników.",
- "CurrentlyConnectedAccounts": "Obecnie podłączone są %1$s konto\/a.",
- "EnabledSearchTypes": "Przechwytywane słowa kluczowe",
- "FetchImageKeyword": "Przechwytuj słowa kluczowe grafik",
- "FetchImageKeywordDesc": "Przechwytuj słowa kluczowe użyte w wyszukiwarce grafik Google",
- "FetchVideoKeyword": "Przechwytuj słowa kluczowe wideo",
- "FetchVideoKeywordDesc": "Przechwytuj słowa kluczowe użyte w wyszukiwarce wideo Google",
- "FetchWebKeyword": "Przechwytuj słowa kluczowe wyszukiwarki",
- "FetchWebKeywordDesc": "Przechwytuj słowa kluczowe użyte w wyszukiwarce Google",
- "FirstDetected": "Pierwsze wykryte",
- "GoogleAccountAccessTypeOfflineAccess": "Dostęp offline<\/strong> jest wymagany do importu Twoich słów kluczowych podczas, gdy ty nie jesteś zalogowany\/a.",
- "GoogleAccountAccessTypeProfileInfo": "Dane profilu<\/strong> wykorzystujemy do wyświetlenia nazwy obecnie podłączonego kont(a).",
- "GoogleAccountAccessTypeSearchConsoleData": "Dane Konsoli Wyszukiwania<\/strong> są niezbędne do uzyskania dostępu do Twoich słów kluczowych w Google.",
- "GoogleAccountError": "Wystąpił błąd podczas walidacji dostępu OAuth: %1$s",
- "GoogleAccountOk": "Dostęp OAuth zweryfikowany poprawnie.",
- "GoogleConfigurationDescription": "Konsola Wyszukiwania Google wykorzystuje OAuth do autentykacji i autoryzacji.",
- "GoogleConfigurationTitle": "Skonfiguruj import z Konsoli Wyszukiwania Google",
- "GoogleKeywordImport": "Import słów kluczowych Google",
- "GoogleSearchConsoleUrl": "Adres Konsoli Wyszukiwania Google",
- "GoogleSearchConsoleUrlDescription": "Wprowadź adres, pod którym ta strona dostępna jest w Twojej Konsoli Wyszukiwania Google",
- "GoogleUploadOrPasteClientConfig": "Proszę prześlij swoją konfigurację klienta Google OAuth, lub wklej ją w pola poniżej.",
- "HowToGetOAuthClientConfig": "Skąd pobrać konfigurację klienta OAuth",
- "ImageKeywords": "Słowa kluczowe grafik w Google",
- "ImageKeywordsDocumentation": "Słowa kluczowe użyte w wyszukiwarce grafik<\/b> Google, które na liście wyników wygenerowały linki do Twojego serwisu.",
- "Impressions": "Dopasowania",
- "ImpressionsDocumentation": "Dopasowanie zostanie zaliczone za każdym razem, gdy Twój serwis pojawi się na stronie wyników wyszukiwania wyszukiwarki.",
- "IntegrationConfigured": "Integracja skonfigurowana pomyślnie",
- "IntegrationNotConfigured": "Integracja jeszcze nie skonfigurowana",
- "KeywordsCombined": "Skojarzone słowa kluczowe",
- "KeywordsCombinedDocumentation": "Raport kojarzący wszystkie słowa kluczowe wykryte przez Matomo i zaimportowane z wyszukiwarki. Raport ten prezentuje jedynie wskaźniki odwiedzin. Możesz przełączyć się na powiązany raport, aby uzyskać więcej szczegółowych wskaźników.",
- "KeywordsCombinedImported": "Skojarzone słowa kluczowe zaimportowane",
- "KeywordsCombinedImportedDocumentation": "Raport prezentujący wszystkie zaimportowane słowa kluczowe ze wszystkich skonfigurowanych wyszukiwarek.",
- "KeywordsReferrers": "Słowa kluczowe (włączając niezdefiniowane)",
- "KeywordStatistics": "Wyszukiwane słowa kluczowe",
- "KeywordTypeImage": "grafika",
- "KeywordTypeVideo": "wideo",
- "KeywordTypeWeb": "sieć",
- "LastCrawled": "Ostatnia indeksacja",
- "LastDetected": "Ostatnie sprawdzenie",
- "LastImport": "Ostatni import",
- "LatestAvailableDate": "Najświeższe słowa kluczowe dostępne dla %1$s",
- "LinksToUrl": "Linkuje do %s",
- "ManageAPIKeys": "Zarządzaj kluczami API",
- "MeasurableConfig": "skonfigurowane serwisy",
- "NoSegmentation": "Raport nie wspiera segmentacji. Dane wyświetlane są w standardowym, ciągłym raporcie.",
- "NotAvailable": "Niedostępne",
- "NoWebsiteConfigured": "Nie masz żadnego skonfigurowanego serwisu. Import dla wybranego serwisu możliwy jest dopiero po skonfigurowaniu go tu.",
- "NoWebsiteConfiguredWarning": "Import dla %s nie jest w pełni skonfigurowany. Musisz skonfigurować serwis, aby umożliwić import.",
- "OAuthClientConfig": "Konfiguracja klienta OAuth",
- "OAuthError": "Wystąpił błąd podczas autentykacji OAuth. Proszę spróbuj ponownie i upewnij się, że zaakceptujesz wymagane uprawnienia.",
- "Platform": "Platforma",
- "Position": "Śr. pozycja",
- "PositionDocumentation": "Średnia pozycja Twojego serwisu na liście wyników wyszukiwania (dla tego słowa kluczowego).",
- "ProviderBingDescription": "Importuj wszystkie słowa kluczowe użyte do odnalezienia Twojego serwisu w Bing'u<\/strong> i Yahoo!<\/strong>.",
- "ProviderBingNote": "Uwaga:<\/u> Microsoft dostarcza zestawienia słów kluczowych w każdą sobotę i tylko dla pełnych tygodni. W rezultacie Twoje słowa kluczowe z Bing i Yahoo! potrzebują paru dni, aby pojawić się w Twoich raportach i dostępne są tylko w widokach tygodniowych, miesięcznych i rocznych.",
- "ProviderGoogleDescription": "Importuj wszystkie słowa kluczowe użyte do odnalezienia Twojego serwisu w Google<\/strong>. Raporty prezentują słowa kluczowe podzielone na typy wyszukiwań (sieć, grafika i wideo).",
- "ProviderListDescription": "Po zakończeniu konfiguracji jednej (lub kilku) wyszukiwarek, możesz poniżej skonfigurować dla których serwisów Matomo będzie importowało słowa kluczowe.",
- "ProviderXAccountWarning": "Wykryto błędy konfiguracji konta<\/strong> Proszę sprawdź skonfigurowane serwisu pod kątem %s<\/strong>.",
- "ProviderXSitesWarning": "Wykryto błędy konfiguracji serwisu<\/strong> Proszę sprawdź skonfigurowane serwisy pod koątem %s<\/strong>.",
- "ReAddAccountIfPermanentError": "Jeśli ten błąd będzie się powtarzał, spróbuj usunąć i ponownie dodać konto.",
- "RequiredAccessTypes": "Wymagane typy dostępów:",
- "ResponseCode": "Kod odpowiedzi",
- "RoundKeywordPosition": "Przybliżona pozycja słowa kluczowego",
- "SearchEngineKeywordsPerformance": "Wydajność wyszukiwania słów kluczowych",
- "SetupConfiguration": "Rozpocznij konfigurację",
- "SitemapsContainingUrl": "Mapy stron zawierają %s",
- "KeywordsSubtableOriginal": "Śledzone słowa kluczowe (włączając niezdefiniowane)",
- "KeywordsSubtableImported": "Zaimportowane słowa kluczowe",
- "AllReferrersOriginal": "Odnośniki (ze śledzonymi słowa kluczowe)",
- "AllReferrersImported": "Odnośniki (z zaimportowanymi słowa kluczowe)",
- "SearchEnginesOriginal": "Wyszukiwarki (z śledzonymi słowami kluczowymi)",
- "SearchEnginesImported": "Wyszukiwarki (z zaimportowanymi słowami kluczowymi)",
- "StartOAuth": "Rozpocznij autoryzację OAuth",
- "UnverifiedSites": "Niezweryfikowane serwisy:",
- "UploadOAuthClientConfig": "Prześlij swoją konfigurację klienta OAuth",
- "UrlOfAccount": "Adres (Konto)",
- "VideoKeywords": "Słowa kluczowe w wynikach Google Wideo",
- "VideoKeywordsDocumentation": "Słowa kluczowe użyte w wyszukiwarce Filmy<\/b> Google, które na liście wyników wygenerowały linki do Twojego serwisu.",
- "WebKeywords": "Wszystkie słowa kluczowe Google",
- "WebKeywordsDocumentation": "Słowa kluczowe użyte w wyszukiwarce Wszystko<\/b> Google, które na liście wyników wygenerowały linki do Twojego serwisu.",
- "WebsiteSuccessfulConfigured": "Gratulacje! Udało Ci się poprawnie skonfigurować import słów kluczowych dla serwisu %1$s. Do importu i pojawienia się pierwszych słów kluczowych w Odnośniki > Słowa kluczowe może upłynąć kilka dni. Więcej informacji odnośnie opóźnień podczas importu słów kluczowych i ograniczeń znajdziesz w naszym %2$sFAQ%3$s",
- "WebsiteTypeUnsupported": "Wybrany wskaźnik %1$s nie może zostać skonfigurowany ponieważ ma niewspierany typ. Tylko wskaźniki typu 'website' są wspierane.",
- "WebsiteTypeUnsupportedRollUp": "Uwaga: Dla stron zbiorczych zaimportowane dane automatycznie zostaną połączone dla wszystkich podstron",
- "YandexCrawlHttpStatus2xx": "Kody HTTP 200-299",
- "YandexCrawlHttpStatus4xx": "Kody HTTP 400 - 499 (Błędy żądania)",
- "YandexCrawlHttpStatus5xx": "Kody HTTP 500 - 599 (Wewnętrzne błędy serwera)",
- "YandexCrawlInIndex": "Liczba zindeksowanych stron"
- }
-}
\ No newline at end of file
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/lang/pt.json b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/lang/pt.json
deleted file mode 100644
index 5bcb03e..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/lang/pt.json
+++ /dev/null
@@ -1,178 +0,0 @@
-{
- "SearchEngineKeywordsPerformance": {
- "AccountAddedBy": "Adicionado por %1$s a %2$s",
- "AccountConnectionValidationError": "Ocorreu um erro a validar a ligação à conta:",
- "AccountDoesNotExist": "A conta configurada %1$s já não existe",
- "AccountNoAccess": "Atualmente esta conta não tem acesso a qualquer site.",
- "AccountRemovalConfirm": "Você vai remover a conta %1$s. Isto pode desativar a importação de palavras-chave para quaisquer sites ligados. Continuar mesmo assim?",
- "ActivityAccountAdded": "foi adicionada uma nova conta para fornecimento de palavras-chave %1$s: %2$s",
- "ActivityAccountRemoved": "removeu uma conta para fornecimento de palavras-chave %1$s: %2$s",
- "ActivityGoogleClientConfigChanged": "a configuração do cliente Google foi alterada.",
- "AddAPIKey": "Adicionar uma chave da API",
- "AddConfiguration": "Adicionar configuração",
- "AdminMenuTitle": "Desempenho da pesquisa",
- "APIKey": "Chave da API",
- "AvailableSites": "Sites disponíveis para importação:",
- "Domain": "Domínio",
- "DomainProperty": "Propriedade do domínio",
- "DomainPropertyInfo": "Inclui todos os subdomínios (m, www e assim por diante) e os ambos protocolos (http e https).",
- "URLPrefix": "Prefixo do endereço",
- "URLPrefixProperty": "Propriedade do prefixo do endereço",
- "URLPrefixPropertyInfo": "Inclui somente endereços com o prefixo exato especificado, incluindo o protocolo (http/https). Se quiser que sua propriedade corresponda a qualquer protocolo ou subdomínio (http/https/www./m e assim por diante), adicione uma propriedade do domínio.",
- "BingAccountError": "Ocorreu um erro ao validar a chave da API: %1$s. Se acabou de ferar esta chave da API nas Bing Webmaster Tools, por favor tente novamente dentro de um ou dois minutos (as chaves da API nas Bing Webmaster Tools demoram algum tempo até serem ativadas).",
- "BingAccountOk": "Chave da API confirmada com sucesso",
- "BingConfigurationDescription": "As Bing Webmaster Tools necessitam de uma chave da API para serem acedidas. Pode adicionar aqui chaves da API para aceder aos dados dos seus sites.",
- "BingConfigurationTitle": "Configurar a importação das Bing Webmaster Tools",
- "BingCrawlBlockedByRobotsTxt": "Exclusão do Robots.txt",
- "BingCrawlBlockedByRobotsTxtDesc": "Endereços atualmente bloqueados pelo robots.txt do seu site.",
- "BingCrawlConnectionTimeout": "Ligações expiradas",
- "BingCrawlConnectionTimeoutDesc": "Este número representa ocorrências recentes quando o Bing não conseguiu aceder ao seu site devido a erros de ligação. Isto pode ser um problema temporário mas deve confirmar os registos do servidor para confirmar se está, acidentalmente, a perder pedidos.",
- "BingCrawlCrawledPages": "Páginas indexadas",
- "BingCrawlCrawledPagesDesc": "Número de páginas que o rastreador do Bing solicitou.",
- "BingCrawlDNSFailures": "Falhas de DNS",
- "BingCrawlDNSFailuresDesc": "Este tipo de problema cataloga erros recentes encontrados ao tentar comunicar com o servidor de DNS quando o bot tentou aceder às suas páginas. Possivelmente o servidor esteve em baixo ou ocorreu uma falha na configuração que impediu o encaminhamento DNS, por exemplo, o TTL foi definido como 0.",
- "BingCrawlErrors": "Erros de indexação no Bing",
- "BingCrawlErrorsDesc": "O número de erros que ocorreram para o indexador do Bing.",
- "BingCrawlErrorsFromDateX": "O relatório mostra erros de indexação reportados recentemente pelo Bing. Não fornece qualquer dado histórico. Última atualização: %s",
- "BingCrawlHttpStatus2xx": "Código HTTP 200-299",
- "BingCrawlHttpStatus2xxDesc": "Estes códigos aparecem quando um servidor serve uma página com sucesso",
- "BingCrawlHttpStatus301": "Código HTTP 301 (Movido de forma permanente)",
- "BingCrawlHttpStatus301Desc": "Estes códigos aparecem quando moveu, de forma permanente, conteúdos de uma localização (endereço) para outra.",
- "BingCrawlHttpStatus302": "Código HTTP 302 (Movido de forma temporária)",
- "BingCrawlHttpStatus302Desc": "Estes códigos aparecem quando moveu, de forma temporária, conteúdos de uma localização (endereço) para outra.",
- "BingCrawlHttpStatus4xx": "Código HTTP 400-499 (Erros de solicitação)",
- "BingCrawlHttpStatus4xxDesc": "Estes erros aparecem quando provavelmente ocorreu um erro no pedido que impediu o servidor de o processar.",
- "BingCrawlHttpStatus5xx": "Código HTTP 500-599 (Erros interno do servidor)",
- "BingCrawlHttpStatus5xxDesc": "Estes códigos aparecem quando o servidor não conseguiu satisfazer um pedido aparentemente válido.",
- "BingCrawlImportantBlockedByRobotsTxt": "Exclusão de uma página importante por parte do robots.txt",
- "BingCrawlInboundLink": "Total de ligações de entrada",
- "BingCrawlInboundLinkDesc": "Ligações de entrada que apontam para o seu site e que o Bing conhece. Estas são ligações que sites externos ao seu, apontam para o seu conteúdo.",
- "BingCrawlingStats": "Visão geral da indexação para o Bing e Yahoo!",
- "BingCrawlingStatsDocumentation": "A visão geral da indexação permite-lhe ver informação relacionada com o rastreamento, tais como erros encontrados pelo bot de pesquisa ao visitar uma página, itens bloqueados pelo seu ficheiro robots.txt e endereços potencialmente afetados por software malicioso.",
- "BingCrawlMalwareInfected": "Sites infetados com software malicioso",
- "BingCrawlMalwareInfectedDesc": "Quaisquer endereços de páginas que o Bing encontrou e que estão infetadas ou associadas a software malicioso serão agrupadas nesta secção.",
- "BingCrawlPagesInIndex": "Total de páginas no índice",
- "BingCrawlPagesInIndexDesc": "Número total de páginas disponíveis no índice do Bing",
- "BingCrawlStatsOtherCodes": "Todos os outros códigos de estado HTTP",
- "BingCrawlStatsOtherCodesDesc": "Agrupa todos os outros códigos que não coincidem com qualquer outro valor (tais como 1xx ou códigos de informação).",
- "BingKeywordImport": "Importação de palavras-chave do Bing",
- "BingKeywords": "Palavras-chave (no Bing e Yahoo!)",
- "BingKeywordsDocumentation": "Palavras-chave utilizadas na pesquisa do Bing ou Yahoo! que geraram ligações para o seu site na listagem de resultados de pesquisa.",
- "BingKeywordsNoRangeReports": "As palavras-chave no Bing e Yahoo! apenas podem ser processadas para intervalos de datas personalizados, incluindo semanas ou meses completos dado que não estão disponíveis como relatórios diários.",
- "BingKeywordsNotDaily": "As palavras-chave no Bing e Yahoo! apenas estão disponíveis como relatórios semanais. Não existem dados de palavras-chave para períodos diários.",
- "BingWebmasterApiUrl": "Endereço para as Bing Webmaster Tools",
- "BingWebmasterApiUrlDescription": "Forneça o endereço no qual este site está disponível nas suas Bing Webmaster Tools",
- "Category": "Categoria",
- "ChangeConfiguration": "Alterar configuração",
- "Clicks": "Cliques",
- "ClicksDocumentation": "É contabilizado um clique de cada vez que alguém clica numa ligação que aponta para o seu site numa página de resultados do motor de pesquisa.",
- "ClientConfigImported": "A configuração do cliente foi importada com sucesso!",
- "ClientConfigSaveError": "Ocorreu um erro ao guardar a configuração do cliente. Por favor, confirme se a configuração fornecida é válida e tente novamente.",
- "ClientId": "ID do cliente",
- "ClientSecret": "Segredo do cliente",
- "ConfigAvailableNoWebsiteConfigured": "A integração foi configurada com sucesso, mas neste momento não existe nenhum site configurado para importação.",
- "ConfigRemovalConfirm": "Você vai remover a configuração para %1$s. A importação de palavras-chave para esse site vai ser desativada. Continuar mesmo assim?",
- "Configuration": "Configuração",
- "ConfigurationDescription": "Esta extensão permite-lhe importar diretamente para o Matomo todas as palavras-chave pesquisadas pelos seus utilizadores em motores de pesquisa.",
- "ConfigurationFile": "Ficheiro de configuração",
- "ConfigurationValid": "A sua configuração OAuth é válida.",
- "ConfiguredAccounts": "contas configuradas",
- "ConfiguredUrlNotAvailable": "O endereço configurado não está disponível para esta conta",
- "ConfigureMeasurableBelow": "Para configurar um site, simplesmente clique no botão abaixo ou configure o mesmo diretamente nas definições do site.",
- "ConfigureMeasurables": "Configurar sites",
- "ConnectAccount": "Associar conta",
- "ConnectFirstAccount": "Comece por associar a sua primeira conta abaixo.",
- "ConnectGoogleAccounts": "Associar Conta(s) Google",
- "ContainingSitemaps": "Mapas do site incluídos",
- "CrawlingErrors": "Erros de indexação",
- "CrawlingStats": "Visão geral da indexação",
- "Ctr": "CTR",
- "CtrDocumentation": "Taxa de cliques CTR: Uma taxa que mostra com que frequência as pessoas que vêm uma página de resultados com uma ligação para o seu site, acabam por clicar na mesma.",
- "CurrentlyConnectedAccounts": "Atualmente existem %1$s contas associadas.",
- "EnabledSearchTypes": "Tipos de palavras-chave a obter",
- "FetchImageKeyword": "Obter palavras-chave de imagens",
- "FetchImageKeywordDesc": "Obter palavras-chave utilizadas na pesquisa de imagens do Google",
- "FetchVideoKeyword": "Obter palavras-chave de vídeos",
- "FetchVideoKeywordDesc": "Obter palavras-chave utilizadas na pesquisa de vídeos do Google",
- "FetchWebKeyword": "Obter palavras-chave da web",
- "FetchWebKeywordDesc": "Obter palavras-chave utilizadas na pesquisa web do Google",
- "FirstDetected": "Detetado pela primeira vez",
- "GoogleAccountAccessTypeOfflineAccess": "Acesso offline é necessário para ser possível importar palavras-chave mesmo quando não tem sessão iniciada.",
- "GoogleAccountAccessTypeProfileInfo": "A informação do perfil é utilizada para mostrar o nome da(s) conta(s) atualmente associada(s).",
- "GoogleAccountAccessTypeSearchConsoleData": "Dados da consola de pesquisa é necessário para obter acesso às suas palavras-chave da pesquisa do Google.",
- "GoogleAccountError": "Ocorreu um erro ao validar o acesso OAuth: %1$s",
- "GoogleAccountOk": "Acesso OAuth confirmado com sucesso.",
- "GoogleConfigurationDescription": "A consola de pesquisa do Google utiliza o OAuth para autenticação e autorização.",
- "GoogleConfigurationTitle": "Configurar a importação da consola de pesquisa do Google",
- "GoogleKeywordImport": "Importação das palavras-chave do Google",
- "GoogleSearchConsoleUrl": "Endereço para a consola de pesquisa do Google",
- "GoogleSearchConsoleUrlDescription": "Forneça o endereço no qual este site está disponível na Consola de pesquisa do Google",
- "GoogleUploadOrPasteClientConfig": "Por favor, envie a sua configuração do cliente Google OAuth ou insira a mesma no campo abaixo.",
- "HowToGetOAuthClientConfig": "Como obter a sua configuração do cliente Google OAuth",
- "ImageKeywords": "Palavras-chave de imagem no Google",
- "ImageKeywordsDocumentation": "Palavras-chave utilizadas na pesquisa de imagens do Google que geraram ligações para o seu site na lista de resultados de pesquisa.",
- "Impressions": "Impressões",
- "ImpressionsDocumentation": "É contabillizada uma impressão sempre que o seu site é apresentado numa página de resultados de pesquisa.",
- "IntegrationConfigured": "Integração configurada com sucesso",
- "IntegrationNotConfigured": "Integração não configurada",
- "KeywordsCombined": "Palavras-chave combinadas",
- "KeywordsCombinedDocumentation": "Relatório que combina todas as palavras-chave detetadas pelo Matomo e importadas dos motores de pesquisa. Este relatório apenas inclui a métrica das visitas. Pode mudar para um dos relatórios relacionados para obter métricas detalhadas.",
- "KeywordsCombinedImported": "Palavras-chaves importadas combinadas",
- "KeywordsCombinedImportedDocumentation": "Relatório que mostra todas as palavras-chave importadas de todos os motores de pesquisa configurados.",
- "KeywordsReferrers": "Palavras-chave (incluindo não definidas)",
- "KeywordStatistics": "Palavras-chave de Pesquisa",
- "KeywordTypeImage": "imagem",
- "KeywordTypeVideo": "vídeo",
- "KeywordTypeWeb": "web",
- "LastCrawled": "Última indexação",
- "LastDetected": "Última deteção",
- "LastImport": "Última importação",
- "LatestAvailableDate": "Os dados mais recentes de palavras-chave são para %1$s",
- "LinksToUrl": "Ligações para %s",
- "ManageAPIKeys": "Gerir Chaves da API",
- "MeasurableConfig": "sites configurados",
- "NoSegmentation": "O relatório não suporta segmentação. Os dados apresentados são os dados predefinidos e não-segmentados.",
- "NotAvailable": "Não disponível",
- "NoWebsiteConfigured": "Não existe atualmente nenhum site configurado. Para ativar a importação para um site específico, por favor, defina a configuração aqui.",
- "NoWebsiteConfiguredWarning": "A importação para %s não está totalmente configurada. Necessita de configurar alguns sites para ativar a importação.",
- "OAuthClientConfig": "Configuração do cliente OAuth",
- "OAuthError": "Ocorreu um erro no processo OAuth. Por favor, tente novamente e garanta que aceita as permissões solicitadas.",
- "Platform": "Plataforma",
- "Position": "Posição média",
- "PositionDocumentation": "Posição média do seu site na lista de resultados do motor de pesquisa (para esta palavra-chave).",
- "ProviderBingDescription": "Importar todas as palavras-chave utilizadas para encontrar o seu site na pesquisa do Bing e Yahoo!.",
- "ProviderBingNote": "Nota: A Microsoft fornece dados de palavras-chave todos os sábados e apenas para semanas inteiras. Como consequência, as suas palavras-chave do Bing e Yahoo irão demorar alguns dias a serem apresentadas nos seus relatórios e só estarão disponíveis quando visualizar semanas, meses ou anos.",
- "ProviderGoogleDescription": "Importar todas as palavras-chave utilizadas para encontrar o seu site na pesquisa do Google. Os relatórios irão mostrar as suas palavras-chave separadamente para cada tipo de pesquisa (Web, Imagens e Vídeos).",
- "ProviderListDescription": "Quando tiver configurado com sucesso um (ou mais) motor(es) de pesquisa em baixo, pode configurar para que site(s) da Web deverá o Matomo importar as suas palavras-chave de pesquisa.",
- "ProviderXAccountWarning": "Detetados problemas de configuração de conta Por favor, confirme as contas configuradas para %s.",
- "ProviderXSitesWarning": "Detetados problemas de configuração do site da Web Por favor, confirme os sites da Web configurados para %s.",
- "ReAddAccountIfPermanentError": "Este é um erro permanente, tente remover a conta e associe a mesma novamente.",
- "RequiredAccessTypes": "São necessários estes tipos de acesso:",
- "ResponseCode": "Código de resposta",
- "RoundKeywordPosition": "Posição arredondada da palavra-chave",
- "SearchEngineKeywordsPerformance": "Desempenho das palavras chave no motor de pesquisa",
- "SetupConfiguration": "Configuração",
- "SitemapsContainingUrl": "Mapas de site que contêm %s",
- "KeywordsSubtableOriginal": "Palavras chave rastreadas (incluindo não definidas)",
- "KeywordsSubtableImported": "Palavras-chave importadas",
- "AllReferrersOriginal": "Referentes (com palavras-chave rastreadas)",
- "AllReferrersImported": "Referentes (com palavras-chave importadas)",
- "SearchEnginesOriginal": "Motores de pesquisa (com palavras-chave rastreadas)",
- "SearchEnginesImported": "Motores de pesquisa (com palavras-chave importadas)",
- "StartOAuth": "Iniciar processo OAuth",
- "UnverifiedSites": "Sites não-confirmados:",
- "UploadOAuthClientConfig": "Enviar a configuração do cliente OAuth",
- "UrlOfAccount": "Endereço (conta)",
- "VideoKeywords": "Palavras-chave de vídeo no Google",
- "VideoKeywordsDocumentation": "As palavras-chave utilizadas na pesquisa vídeo do Google que geraram ligações para o seu site na lista de resultados de pesquisa.",
- "WebKeywords": "Palavras-chave da Web no Google",
- "WebKeywordsDocumentation": "As palavras-chave utilizadas na pesquisa da Web do Google que geraram hiperligações para o seu site da Web na lista de resultados de pesquisa.",
- "WebsiteSuccessfulConfigured": "Parabéns! Configurou com sucesso a importação de palavras-chave para o site %1$s. Pode demorar alguns dias até que as suas primeiras palavras-chave de pesquisa sejam importadas e apresentadas em Referentes > Palavras-chave de pesquisa. Pode encontrar mais informação sobre os atrasos e limitações na importação de palavras-chave na nossa %2$sFAQ%3$s",
- "WebsiteTypeUnsupported": "A métrica %1$s selecionada não pode ser configurada dados que não é um tipo suportado. Apenas métricas do tipo 'site' são suportadas.",
- "WebsiteTypeUnsupportedRollUp": "Nota: Sites agregados irão combinar automaticamente os dados importados de todos os respetivos sites descendentes.",
- "YandexCrawlHttpStatus2xx": "Código HTTP 200-299",
- "YandexCrawlHttpStatus4xx": "Código HTTP 400-499 (Erros de solicitação)",
- "YandexCrawlHttpStatus5xx": "Código HTTP 500-599 (Erros interno do servidor)",
- "YandexCrawlInIndex": "Total de páginas no índice"
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/lang/ru.json b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/lang/ru.json
deleted file mode 100644
index d662b53..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/lang/ru.json
+++ /dev/null
@@ -1,81 +0,0 @@
-{
- "SearchEngineKeywordsPerformance": {
- "APIKey": "API-ключ",
- "AccountAddedBy": "Добавлено %1$s для %2$s",
- "AccountConnectionValidationError": "Произошла ошибка при проверке подключения учетной записи:",
- "AccountDoesNotExist": "Настроенный аккаунт %1$s больше не существует",
- "AccountNoAccess": "У данной учётной записи сейчас нет доступа к какому либо веб-сайту.",
- "AccountRemovalConfirm": "Вы собираетесь удалить аккаунт %1$s. Это может отключить импорт ключевых слов для любых подключенных веб-сайтов. Все равно продолжить?",
- "ActivityAccountAdded": "добавлен новый аккаунт для провайдера ключевых слов %1$s: %2$s",
- "ActivityAccountRemoved": "удалён аккаунт для провайдера ключевых слов %1$s: %2$s",
- "ActivityGoogleClientConfigChanged": "изменили конфигурацию клиента Google.",
- "AddAPIKey": "Добавить API-ключ",
- "AddConfiguration": "Добавить конфигурацию",
- "AdminMenuTitle": "Поисковые фразы",
- "AvailableSites": "Сайты, доступные для импорта:",
- "BingAPIKeyInstruction": "Войдите в %1$sBing Webmaster Tools%2$s, затем добавьте свой сайт в Bing Webmaster. После его проверки вы можете %3$sскопировать свой API-ключ%4$s.",
- "BingAccountError": "Произошла ошибка при проверке API-ключа: %1$s. Если вы только что сгенерировали этот API-ключ в Bing Webmaster Tools, повторите попытку через пару минут (для активации API-ключей в Bing Webmaster Tools требуется некоторое время).",
- "BingAccountOk": "API-ключ успешно проверен",
- "BingConfigurationDescription": "Для доступа к Bing Webmaster Tools необходим ключ API. Здесь вы можете добавить API-ключи для доступа к данным вашего сайта.",
- "BingConfigurationTitle": "Настройка импорта из Bing Webmaster Tools",
- "BingCrawlBlockedByRobotsTxt": "Исключение robots.txt",
- "BingCrawlBlockedByRobotsTxtDesc": "URLы в настоящее время заблокированы в файле robots.txt.",
- "BingCrawlConnectionTimeout": "Тайм-ауты соединения",
- "BingCrawlConnectionTimeoutDesc": "Это число отражает недавние случаи, когда Bing не мог получить доступ к вашему сайту из-за ошибок подключения. Это может быть временная проблема, но вы должны проверить журналы вашего сервера, чтобы убедиться, что вы случайно не закрываете запросы.",
- "BingCrawlCrawledPages": "Просканировано страниц",
- "BingCrawlCrawledPagesDesc": "Количество страниц, просканированных Bing.",
- "BingCrawlDNSFailures": "Сбои DNS",
- "BingCrawlDNSFailuresDesc": "Этот тип проблемы каталогизирует недавние ошибки, возникающие при попытке связаться с DNS-сервером, когда бот пытался получить доступ к вашим страницам. Возможно, ваш сервер не работает или произошла неправильная конфигурация, которая препятствовала маршрутизации DNS, например, для TTL было установлено значение 0.",
- "BingCrawlErrors": "Ошибки сканирования у Bing",
- "BingCrawlErrorsDesc": "Количество ошибок, произошедших у сканера Bing.",
- "BingCrawlErrorsFromDateX": "Отчет показывает ошибки сканирования, недавно обнаруженные Bing. Он не предоставляет никаких исторических данных. Последнее обновление %s",
- "BingCrawlHttpStatus2xx": "HTTP код 200-299",
- "BingCrawlHttpStatus2xxDesc": "Эти коды означают успешную загрузку страниц",
- "BingCrawlHttpStatus301": "HTTP код 301 (постоянный редирект)",
- "BingCrawlHttpStatus301Desc": "Этот код означает, что вы навсегда переместили контент из одного местоположения (URL-адрес) в другое.",
- "BingCrawlHttpStatus302": "HTTP код 302 (временный редирект)",
- "BingCrawlHttpStatus302Desc": "Этот код означает, что вы временно переместили контент из одного местоположения (URL-адрес) в другое.",
- "BingCrawlHttpStatus4xx": "HTTP код 400-499 (ошибки запроса)",
- "BingCrawlHttpStatus4xxDesc": "Эти коды означают, что в запросе, вероятно, произошла ошибка, из-за которой сервер не смог её обработать.",
- "BingCrawlHttpStatus5xx": "HTTP код 500-599 (ошибки сервера)",
- "BingCrawlHttpStatus5xxDesc": "Эти коды означают, когда сервер не в состоянии выполнить корректный запрос.",
- "BingCrawlImportantBlockedByRobotsTxt": "Исключение важной страницы robots.txt",
- "BingCrawlInboundLink": "Всего входящих ссылок",
- "BingCrawlPagesInIndexDesc": "Общее количество страниц, доступных в индексе Bing",
- "BingCrawlingStats": "Обзор сканирования для Bing и Yahoo!",
- "BingKeywords": "Ключевые слова (на Bing и Yahoo!)",
- "BingKeywordsNoRangeReports": "Ключевые слова на Bing и Yahoo! могут обрабатываться только для пользовательских диапазонов дат, включая полные недели или месяцы, поскольку они недоступны в качестве ежедневных отчётов.",
- "BingWebmasterApiUrl": "URL для инструментов веб-мастеров Bing",
- "ChangeConfiguration": "Изменить конфигурацию",
- "ConfigureMeasurableBelow": "Чтобы настроить сайт, просто нажмите кнопку ниже или настройте его прямо в настройках сайта.",
- "ConfigureMeasurables": "Настроить веб-сайты",
- "ConnectAccount": "Подключить аккаунт",
- "ConnectGoogleAccounts": "Подключить аккаунт(ы) Google",
- "CrawlingErrors": "Ошибки сканирования",
- "CrawlingStats": "Обзор сканирования",
- "Domain": "Доменный ресурс",
- "DomainProperty": "Доменный ресурс",
- "DomainPropertyInfo": "Включает URL с любыми субдоменами (m, www и др.) и обоими префиксами протокола (http, https).",
- "GoogleConfigurationTitle": "Настройка импорта из Google Search Console",
- "GoogleSearchConsoleUrl": "URL для консоли поиска Google",
- "ImageKeywords": "Ключевые слова изображений",
- "KeywordsCombined": "Словосочетания",
- "KeywordsCombinedImported": "Импортированные словосочетания",
- "KeywordsReferrers": "Ключевые слова (исключая импорт)",
- "ManageAPIKeys": "Управление API-ключами",
- "ProviderBingDescription": "Импортируйте все ключевые слова, используемые для поиска вашего сайта в поиске Bing и Yahoo!.",
- "ProviderBingNote": "Примечание: Microsoft предоставляет данные о ключевых словах каждую субботу и только неделей целиком. В результате ваши ключевые слова для Bing и Yahoo появятся в ваших отчётах через несколько дней и будут доступны только при просмотре недель, месяцев или лет.",
- "ProviderGoogleDescription": "Импортируйте все ключевые слова, используемые для поиска вашего сайта в поиске Google. Отчёты будут показывать ваши ключевые слова для каждого типа поиска отдельно (общий топ, изображения или видео).",
- "SearchEngineKeywordsPerformance": "Поисковые запросы и ключевые слова",
- "SetupConfiguration": "Настройка конфигурации",
- "URLPrefix": "Ресурс с префиксом в URL",
- "URLPrefixProperty": "Ресурс с префиксом в URL",
- "URLPrefixPropertyInfo": "Включает только URL с конкретным префиксом, в том числе указывающим на протокол (http или https). Если вам нужно, чтобы к ресурсу относились URL с любым префиксом протокола или субдоменом (http, https, www, m и т. д.), лучше добавить доменный ресурс.",
- "VideoKeywords": "Ключевые слова видео",
- "WebKeywords": "Ключевые слова общего топа",
- "WebsiteSuccessfulConfigured": "Поздравляем! Вы успешно настроили импорт ключевых слов для сайта %1$s. Это может занять несколько дней, прежде чем ваши первые поисковые ключевые слова будут импортированы и отображены в меню Источники > Ключевые слова. Вы можете найти больше информации о задержках и ограничениях импорта ключевых слов в нашем %2$sFAQ%3$s",
- "YandexCrawlHttpStatus2xx": "HTTP код 200-299",
- "YandexCrawlHttpStatus4xx": "HTTP код 400-499 (ошибки запроса)",
- "YandexCrawlHttpStatus5xx": "HTTP код 500-599 (ошибки сервера)"
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/lang/sq.json b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/lang/sq.json
deleted file mode 100644
index 99c1766..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/lang/sq.json
+++ /dev/null
@@ -1,240 +0,0 @@
-{
- "SearchEngineKeywordsPerformance": {
- "APIKey": "Kyç API",
- "AccountAddedBy": "Shtuar nga %1$s në %2$s",
- "AccountConnectionValidationError": "Ndodhi një gabim teksa vleftësohej lidhja e llogarisë:",
- "AccountDoesNotExist": "Llogaria e formësuar %1$s s’ekziston më",
- "AccountNoAccess": "Kjo llogari s’ka hyrje në ndonjë sajt.",
- "AccountRemovalConfirm": "Ju ndan një hap nga heqja e kësaj llogarie %1$s. Kjo mund të sjellë çaktivizimin e importimit të fjalëkyçeve për cilindo sajte(e) të lidhur. Të vazhdohet sido qoftë?",
- "ActivityAccountAdded": "u shtua llogari e re për furnizues fjalëkyçesh %1$s: %2$s",
- "ActivityAccountRemoved": "u hoq llogari për furnizues fjalëkyçesh %1$s: %2$s",
- "ActivityGoogleClientConfigChanged": "ndryshoi formësimi për klientin Google.",
- "ActivityYandexClientConfigChanged": "u ndryshua formësimi i klientit Yandex.",
- "AddAPIKey": "Shtoni Kyç API",
- "AddConfiguration": "Shtoni Formësim",
- "AdminMenuTitle": "Funksionim Kërkimi",
- "AllReferrersImported": "Referues (me fjalëkyçe të importuar)",
- "AllReferrersOriginal": "Referues (me fjalëkyçe të ndjekur)",
- "AvailableSites": "Sajte të gatshëm për import:",
- "BingAPIKeyInstruction": "Bëni hyrjen që nga %1$sBing Webmaster Tools%2$s, mandej shtoni sajtin tuaj te Bing Webmaster. Pasi të jetë vlerësuar, mund të %3$skopjoni kyçin tuaj API%4$s.",
- "BingAccountError": "Ndodhi një gabim teksa vleftësohej Kyçi API: %1$s. Nëse sapo e keni krijuar këtë kyç API te Bing Webmaster Tools, ju lutemi riprovoni pas një a dy minutash (kyçet API në Bing Webmaster Tools duan pakëz kohë të aktivizohen).",
- "BingAccountOk": "Kyç API i kontrolluar me sukses",
- "BingConfigurationDescription": "Bing Webmaster Tools lyp një kyç API, që të mund të përdoret. Këtu mund të shtoni kyçe API për hyrje te të dhënat e sajtit tuaj.",
- "BingConfigurationTitle": "Formësoni importim prej Bing Webmaster Tools",
- "BingCrawlBlockedByRobotsTxt": "Përjashtim nga robots.txt",
- "BingCrawlBlockedByRobotsTxtDesc": "URL të bllokuara aktualisht nga robots.txt i sajtit tuaj.",
- "BingCrawlConnectionTimeout": "Mbarim kohe për lidhjet",
- "BingCrawlConnectionTimeoutDesc": "Ky numër përfaqëson rastet së fundi kur Bing s’u fut dot te sajti juaj për shkak gabimesh lidhjeje. Ky mund të jetë një problem i përkohshëm, por do të duhej të shihnit regjistrat e shërbyesit për të parë se s’jeni duke mos pranuar aksidentalisht kërkesa.",
- "BingCrawlCrawledPages": "Faqe të indeksuara",
- "BingCrawlCrawledPagesDesc": "Numër faqesh të kërkuara nga indeksuesi i Bing-ut.",
- "BingCrawlDNSFailures": "Dështime DNS",
- "BingCrawlDNSFailuresDesc": "Ky lloj problemi katalogon gabime së fundi, të hasura teksa bëheshin përpjekje për të komunikuar me shërbyesin DNS, kur roboti u përpoq të hynte në faqet tuaja. Ka gjasa që shërbyesi juaj të ishte jashtë funksionimi, ose pati një keqformësim i cili pengoi rrugëzim DNS, për shembull, TTL qe caktuar 0.",
- "BingCrawlErrors": "Gabimi indeksimi në Bing",
- "BingCrawlErrorsDesc": "Numër gabimesh të hasura nga indeksuesi i Bing-ut.",
- "BingCrawlErrorsFromDateX": "Raporti shfaq gabime indeksimi të raportuara së fundi nga Bing-u. Nuk jep të dhëna historike. Përditësuar së fundi më %s",
- "BingCrawlHttpStatus2xx": "Kod HTTP 200-299",
- "BingCrawlHttpStatus2xxDesc": "Këto kode shfaqen kur shërbyesi e shërben me sukses një faqe",
- "BingCrawlHttpStatus301": "Kod HTTP 301 (Lëvizur përgjithmonë)",
- "BingCrawlHttpStatus301Desc": "Këto kode shfaqen kur keni lëvizur përgjithmonë lëndë nga një vendndodhje (URL) te një tjetër.",
- "BingCrawlHttpStatus302": "Kod HTTP 302 (Lëvizur përkohësisht)",
- "BingCrawlHttpStatus302Desc": "Këto kode shfaqen kur keni lëvizur përkohësisht lëndë nga një vendndodhje (URL) te një tjetër.",
- "BingCrawlHttpStatus4xx": "Kod HTTP 400-499 (Gabime kërkese)",
- "BingCrawlHttpStatus4xxDesc": "Këto kode shfaqen kur, sipas gjasash, pati një gabim te kërkesa, çka e pengoi shërbyesin të mundte ta përpunonte.",
- "BingCrawlHttpStatus5xx": "Kod HTTP 500-599 (Gabime të brendshme shërbyesi)",
- "BingCrawlHttpStatus5xxDesc": "Këto kode shfaqen kur shërbyesi s’arriti të plotësonte një kërkesë në dukje të vlefshme.",
- "BingCrawlImportantBlockedByRobotsTxt": "Përjashtim nga robots.txt faqeje të rëndësishme",
- "BingCrawlInboundLink": "Lidhje ardhëse gjithsej",
- "BingCrawlInboundLinkDesc": "Lidhje ardhëse të njohura nga Bing, që shpien te URL në sajtin tuaj. Këto janë lidhje, prej sajtesh tjetër nga ai i juaji, që shpien te lëndë e juaja.",
- "BingCrawlMalwareInfected": "Sajte të infektuar me “malware”",
- "BingCrawlMalwareInfectedDesc": "Në këtë ndarje do të grupohen çfarëdo URL faqeje gjetur nga Bing-u, e cila është e infektuar ose e lidhur me malware.",
- "BingCrawlPagesInIndex": "Faqe gjithsej në tregues",
- "BingCrawlPagesInIndexDesc": "Numër faqesh gjithsej të pranishme në indeksin e Bing-ut",
- "BingCrawlStatsOtherCodes": "Krejt kodet e tjera për gjendje HTTP",
- "BingCrawlStatsOtherCodesDesc": "Grupon krejt kodet e tjerë që nuk kanë përputhje me ndonjë vlerë tjetër (bie fjala, 1xx ose kode informative).",
- "BingCrawlingStats": "Përmbledhje indeksimi për Bing dhe Yahoo!",
- "BingCrawlingStatsDocumentation": "Përmbledhja e indeksimit ju lejon të shihni informacion të lidhur me indeksimin, bie fjala, gabime të hasur nga roboti i kërkimeve kur vizitohet një faqe, objekte të bllokuar nga kartela juaj robots.txt dhe URL që mund të jenë prekur nga malware.",
- "BingKeywordImport": "Importim fjalëkyçesh Bing",
- "BingKeywords": "Fjalëkyçe (në Bing dhe Yahoo!)",
- "BingKeywordsDocumentation": "Fjalëkyçe të përdorur në kërkime Bing ose Yahoo! që prodhojnë lidhje për te sajti juaj te lista e përfundimeve të kërkimit.",
- "BingKeywordsNoRangeReports": "Fjalëkyçe në Bing dhe Yahoo! që mund të përpunohen vetëm për intervale vetjakë datash, përfshi javë ose muaj të plotë, meqë s’mund të kihen si raporte ditore.",
- "BingKeywordsNotDaily": "Fjalëkyçe në Bing dhe Yahoo! mund të kihen vetëm si raporte ditore. S’ka të dhëna fjalëkyçesh për periudha ditësh.",
- "BingWebmasterApiUrl": "Url për Bing Webmaster Tools",
- "BingWebmasterApiUrlDescription": "Jepni URL-në te e cila gjendet ky sajt te Bing Webmaster Tools tuaja",
- "Category": "Kategori",
- "ChangeConfiguration": "Ndryshoni formësimin",
- "Clicks": "Klikime",
- "ClicksDocumentation": "Si klikim llogaritet sa herë që dikush klikon mbi një lidhje që shpie te sajti juaj, në një faqe përfundimesh motori kërkimesh.",
- "ClientConfigImported": "Formësimi i klientit u importua me sukses!",
- "ClientConfigSaveError": "Ndodhi një gabim teksa ruhej formësimi i klientit. Ju lutemi, kontrolloni nëse formësimi i dhënë është i vlefshëm dhe riprovoni.",
- "ClientId": "ID klienti",
- "ClientSecret": "E fshehtë klienti",
- "ConfigAvailableNoWebsiteConfigured": "Integrimi i formësua me sukses, por aktualisht nuk ka sajt të formësuar për import.",
- "ConfigRemovalConfirm": "Ju ndan një hap nga heqja e formësimit për %1$s. Importimi i Fjalëkyçeve për atë sajt do të çaktivizohet. Të veprohet, sido qoftë?",
- "Configuration": "Formësim",
- "ConfigurationDescription": "Kjo shtojcë ju lejon të importoni drejt e në Matomo krejt fjalëkyçet e kërkuar nga përdoruesit tuaj në motorë kërkimesh.",
- "ConfigurationFile": "Kartelë formësimi",
- "ConfigurationValid": "Formësimi juaj OAuth është i vlefshëm.",
- "ConfigureMeasurableBelow": "Për të formësuar një sajt, thjesht klikoni mbi butonin më poshtë ose formësojeni drejt e te rregullimet e sajtit.",
- "ConfigureMeasurables": "Formësoni sajte",
- "ConfigureTheImporterLabel1": "Importoni fjalëkyçet tuaja Google Search Console dhe analizojini duke përdorur mjetet e fuqishme statistikore të Matomo-s. Pasi të lidhni importuesin, përzgjidhni cilët sajte të importohen dhe Matomo-ja do të nisë të importojë fjalëkyçe për ta, si pjesë e një procesi arkivimi të planifikuar.",
- "ConfigureTheImporterLabel2": "Që të importoni të dhënat tuaja nga Konsolë Google Search, Matomo ka nevojë të hyjë në këto të dhëna.",
- "ConfigureTheImporterLabel3": "Për t’ia filluar, %1$sndiqni udhëzimet tona për të marrë formësimin e Klientit tuaj OAuth%2$s. Mandej ngarkojeni kartelën e formësimit të klientit duke përdorur butonin më poshtë.",
- "ConfiguredAccounts": "llogari të formësuara",
- "ConfiguredUrlNotAvailable": "Për këtë llogari s’ka URL të formësuar",
- "ConnectAccount": "Lidhni Llogari",
- "ConnectAccountDescription": "Ju lutemi, klikoni mbi butonin më poshtë që të ridrejtoheni te %1$s, ku ju duhet të akordoni hyrje.",
- "ConnectAccountYandex": "Mirëfilltësimi për llogari Yandex është i vlefshëm vetëm për %1$s ditë. Çdo llogari lypset të rimirëfilltësohet brenda asaj kohe, për të siguruar që importimet funksionojnë saktë.",
- "ConnectFirstAccount": "Fillojani duke lidhur llogarinë tuaj të parë më poshtë.",
- "ConnectGoogleAccounts": "Lidhni Llogari Google",
- "ConnectYandexAccounts": "Lidhni Llogari Yandex",
- "ContainingSitemaps": "Përmban Harta Sajtesh",
- "CrawlingErrors": "Gabime indeksimi",
- "CrawlingOverview1": "Përmbledhja e Indeksimit raporton informacionet më kritike rreth se si indeksojnë sajtet tuaj robotë Motorësh Kërkimi. Këto vlera përditësohen afërsisht një herë në ditë me të dhëna të furnizuara nga motorët e kërkimeve.",
- "CrawlingStats": "Përmbledhje indeksimi",
- "CreatedBy": "Krijuar Nga",
- "Ctr": "CTR",
- "CtrDocumentation": "Koeficient klikimi: Një përpjesëtim që shfaq se sa shpesh persona që shohin një faqe përfundimesh motori kërkimesh me një lidhje për te sajti juaj, e klikojnë atë.",
- "CurrentlyConnectedAccounts": "Aktualisht ka %1$s llogari të lidhura.",
- "DeleteUploadedClientConfig": "Nëse do të donit të hiqnit formësimin e ngarkuar të klientit, klikoni më poshtë",
- "Domain": "Përkatësi",
- "DomainProperty": "Veti përkatësie",
- "DomainPropertyInfo": "Përfshin krejt nënpërkatësitë (m, www, e me radhë) dhe që të dy protokollet (http, https).",
- "EnabledSearchTypes": "Lloje fjalëkyçesh për t’u sjellë",
- "FetchImageKeyword": "Sill fjalëkyçe figurash",
- "FetchImageKeywordDesc": "Sill fjalëkyçe të përdorur në kërkime figurash në Google",
- "FetchNewsKeyword": "Sill fjalëkyçe të rinj",
- "FetchNewsKeywordDesc": "Sill fjalëkyçe të përdorur në Google News",
- "FetchVideoKeyword": "Sill fjalëkyçe video",
- "FetchVideoKeywordDesc": "Sill fjalëkyçe të përdorur në kërkime videosh në Google",
- "FetchWebKeyword": "Sill fjalëkyçe web",
- "FetchWebKeywordDesc": "Sill fjalëkyçe të përdorur në kërkime web përmes Google-it",
- "FirstDetected": "Pikasur së pari",
- "GoogleAccountAccessTypeOfflineAccess": "Përdorimi jashtë linje është i domosdoshëm për të qenë në gjendje të importohen fjalëkyçet tuaj të kërkimit, edhe kur s’jeni i futur në llogarinë tuaj.",
- "GoogleAccountAccessTypeProfileInfo": "Të dhëna profili përdoren për të shfaqur emrin e llogarisë(ve) të lidhura në atë çast.",
- "GoogleAccountAccessTypeSearchConsoleData": "Të dhënat e Konsolës së Kërkimeve janë të domosdoshme për të pasur hyrje te fjalëkyçet tuaj të kërkimeve me Google.",
- "GoogleAccountError": "Ndodhi një gabim teksa vleftësohej hyrje OAuth: %1$s",
- "GoogleAccountOk": "Hyrja OAuth u kontrollua me sukses.",
- "GoogleAuthorizedJavaScriptOrigin": "Origjinë JavaScript-i të autorizuar",
- "GoogleAuthorizedRedirectUri": "URI ridrejtimi të autorizuar",
- "GoogleConfigurationDescription": "Konsola e Kërkimeve me Google përdor OAuth për mirëfilltësim dhe autorizim.",
- "GoogleConfigurationTitle": "Formësoni importim prej Konsolës së Kërkimeve me Google",
- "GoogleDataNotFinal": "Të dhënat e këtij raporti për fjalëkyçet mund të mos përmbajnë ende të dhënat përfundimtare. Google i furnizon të dhënat përfundimtare të fjalëkyçeve me një vonesë prej 2 ditësh. Fjalëkyçet për ditë më të afërta do të riimportohen, deri sa të raportohen si përfundimtare.",
- "GoogleDataProvidedWithDelay": "Google i furnizon të dhënat e fjalëkyçeve me një vonesë. Fjalëkyçet për këtë datë do të importohen pakëz më vonë.",
- "GoogleKeywordImport": "Importim fjalëkyçesh Google",
- "GooglePendingConfigurationErrorMessage": "Formësimi është pezull. Ju lutemi, kërkojini një superpërdoruesi të plotësojë formësimin.",
- "GoogleSearchConsoleUrl": "Url për Konsol Kërkimesh me Google",
- "GoogleSearchConsoleUrlDescription": "Jepni URL-në ku gjendet ky sajt te Konsola juaj e Kërkimeve me Google",
- "GoogleUploadOrPasteClientConfig": "Ju lutemi, ngarkoni formësimin e klientit tuaj për Google OAuth, ose hidheni atë te fusha më poshtë.",
- "HowToGetOAuthClientConfig": "Si të merrni formësimin tuaj për OAuth Client",
- "ImageKeywords": "Fjalëkyçe figurash në Google",
- "ImageKeywordsDocumentation": "Fjalëkyçe të përdorur në kërkime figurash me Google, të cilët prodhuan lidhje për te sajti juaj, te lista e përfundimeve të kërkimit.",
- "Impressions": "Përshtypje",
- "ImpressionsDocumentation": "Si përshtypje llogaritet çdo herë që sajti juaj është shfaqur në një faqe përfundimesh motori kërkimesh.",
- "IntegrationConfigured": "Integrim i formësuar me sukses",
- "IntegrationNotConfigured": "Integrim ende i paformësuar",
- "InvalidRedirectUriInClientConfiguration": "redirect_uris të pavlefshëm, të paktën 1 URI duhet të ketë përputhje me URI-n “%1$s” te kartela e ngarkuar për formësimin",
- "KeywordStatistics": "Fjalëkyçe Kërkimi",
- "KeywordTypeImage": "figurë",
- "KeywordTypeNews": "lajme",
- "KeywordTypeVideo": "video",
- "KeywordTypeWeb": "web",
- "KeywordsCombined": "Fjalëkyçe gjithsej",
- "KeywordsCombinedDocumentation": "Raport që ndërthur krejt fjalëkyçet e pikasur nga Matomo dhe importuar prej motorësh kërkimesh. Ky raport përfshin vetëm vlera për vizitat. Për të pasur vlera të hollësishme, mund të kaloni te një nga raportet përkatës.",
- "KeywordsCombinedImported": "Fjalëkyçe të importuar gjithsej",
- "KeywordsCombinedImportedDocumentation": "Raport që shfaq krejt fjalëkyçet e importuar prej krejt motorëve të kërkimit të formësuar.",
- "KeywordsReferrers": "Fjalëkyçe (përfshi të papërkufizuarit)",
- "KeywordsSubtableImported": "Fjalëkyçe të importuar",
- "KeywordsSubtableOriginal": "Fjalëkyçe të ndjekur (përfshi të papërkufizuarit)",
- "LastCrawled": "Indeksuar së fundi",
- "LastDetected": "Pikasur së fundi",
- "LastImport": "Importimi i Fundit",
- "LatestAvailableDate": "Të dhënat më të freskëta që mund të kihen për fjalëkyçet janë për %1$s",
- "LinksToUrl": "Lidhje për te %s",
- "ManageAPIKeys": "Administroni Kyçe API",
- "MeasurableConfig": "sajte të formësuar",
- "NewsKeywords": "Fjalëkyçe lajmesh në Google",
- "NewsKeywordsDocumentation": "Fjalëkyçe të përdorur në kërkime Lajme Google, të cilët kanë prodhuar lidhje për te sajti juaj, te lista e përfundimeve të kërkimit.",
- "NoSegmentation": "Raporti nuk mbulon segmentim. Të dhënat e shfaqura janë të dhënat tuaja standarde, të pasegmentuara, të raportit.",
- "NoWebsiteConfigured": "S’ka sajt të formësuar. Për të aktivizuar importimin për sajtin e dhënë, ju lutemi, ujdisni këtu formësimin.",
- "NoWebsiteConfiguredWarning": "Importim për %s i paformësuar plotësisht. Lypset të formësoni disa sajte që të aktivizohet importimi.",
- "NotAvailable": "S’ka",
- "OAuthAccessTimedOut": "Hyrjes me mirëfilltësim OAuth për këtë llogari mund t’i ketë mbaruar koha. Do t’ju duhet të ribëni mirëfilltësimin, që të funksionojnë sërish importimet për këtë llogari.",
- "OAuthAccessWillTimeOut": "Hyrjes me OAuth për këtë llogari do t’i mbarojë koha pas %1$s ditësh. Edhe %2$s ditë",
- "OAuthAccessWillTimeOutSoon": "Hyrjes me OAuth për këtë llogari do t’i mbarojë koha pas rreth %1$s ditësh. Ju lutemi, ribëni mirëfilltësimin, për të shmangur ndaljen e çfarëdo importimesh për këtë llogari.",
- "OAuthClientConfig": "Formësim Klienti OAuth",
- "OAuthError": "Ndodhi një gabim brenda procesit OAuth. Ju lutemi, riprovoni dhe sigurohuni të pranoni lejet e domosdoshme.",
- "OAuthExampleText": "Formësimi lyp fushat e treguara më poshtë. Ju lutemi, përdorni vlerat e dhëna:",
- "OauthFailedMessage": "Hasëm një problem gjatë procesit të autorizimit për Konsolën tuaj Google Search. Që të riprovohet, ju lutemi, klikoni mbi butonin më poshtë. Nëse problemi vazhdon, ju lutemi, lidhuni me ekipin tonë të asistencës për ndihmë. Do t’ju ndihmojnë në zgjidhjen e problemit dhe importimin e fjalëkyçeve tuaj Google Search Console.",
- "OptionQuickConnectWithGoogle": "Lidhuni shpejt, me Google (e rekomanduar)",
- "Platform": "Platformë",
- "Position": "Pozicion mesatar",
- "PositionDocumentation": "Pozicioni mesatar i sajtit tuaj te lista e përfundimeve prej motorësh kërkimi (për këtë fjalëkyç).",
- "ProvideYandexClientConfig": "Ju lutemi, jepni formësimin tuaj për klientit tuaj Yandex OAuth.",
- "ProviderBingDescription": "Importoni krejt fjalëkyçet e përdorur për të gjetur sajtin tuaj në kërkime me Bing dhe Yahoo!.",
- "ProviderBingNote": "Shënim: Microsoft-i furnizon fjalëkyçe çdo të shtunë dhe vetëm për javë të plota. Si rrjedhojë, fjalëkyçet tuaj për Bing-un dhe Yahoo-n do të duan disa ditë, para se të shfaqen në raportet tuaj dhe do të jenë vetëm për javë, muaj ose vite.",
- "ProviderGoogleDescription": "Importoni krejt fjalëkyçet e përdorur për të gjetur sajtin tuaj përmes kërkimesh Google. Raportet do të shfaqin fjalëkyçet tuaj veçmas për çdo lloj kërkimi (Web, Figura dhe Video).",
- "ProviderGoogleNote": "Shënim: Google furnizon të dhëna përfundimtare fjalëkyçesh me një vonesë prej 2 ditësh. Të dhëna përfundimtare për ditë më të afërta do të tregohen gjithashtu, por do të riimportohen, deri sa të jenë përfundimtare. Importimi juaj i parë mund të jetë në gjendje të importojë të dhënat tuaja historike mbi fjalëkyçet për deri 486 ditë më herët.",
- "ProviderListDescription": "Kur keni ujdisur me sukses një (ose më tepër) motor kërkimi më poshtë, mund të formësoni në cilin sajt(e) duhet të importojë Matomo fjalëkyçet tuaj të kërkimit.",
- "ProviderXAccountWarning": "U pikasën probleme formësimi llogarish Ju lutemi, kontrolloni llogaritë e formësuara për %s.",
- "ProviderXSitesWarning": "U pikasën probleme formësimi sajtesh Ju lutemi, kontrolloni sajtet e formësuar për %s.",
- "ProviderYandexDescription": "Importoni krejt fjalëkyçet e përdorur për të gjetur sajtin tuaj në kërkime me Yandex.",
- "ProviderYandexNote": "Shënim: Yandex-i furnizon të dhëna fjalëkyçesh me një vonesë deri 5 ditësh. Importimi i parë do të provojë të importojë të dhënat tuaja historike mbi fjalëkyçet për deri 100 ditë e fundit.",
- "ReAddAccountIfPermanentError": "Nëse ky është një gabim i vazhdueshëm, provoni ta hiqni llogarinë dhe ta rilidhni.",
- "ReAuthenticateIfPermanentError": "Nëse ky është një gabim që nuk ikën, provoni të bëni rimirëfilltësimin e llogarisë ose ta hiqni dhe ta lidhini sërish.",
- "Reauthenticate": "Ribëni mirëfilltësimin",
- "RecentApiErrorsWarning": "U pikasën gabime importimi fjalëkyçesh
Ju lutemi, kontrolloni formësimet për: %s
Nëse formësimi juaj është i saktë dhe gabimet vazhdojnë, ju lutemi, lidhuni me asistencën.",
- "ReportShowMaximumValues": "Vlerat e shfaqura janë vlerat maksimum që u hasën gjatë kësaj periudhe.",
- "RequiredAccessTypes": "Këto lloje hyrjeje janë të domosdoshëm:",
- "ResponseCode": "Kod përgjigjeje",
- "RoundKeywordPosition": "Pozicion i rrumbullakosur fjalëkyçi",
- "SearchEngineKeywordsPerformance": "Funksionim Fjalëkyçesh Motori Kërkimesh",
- "SearchEnginesImported": "Motorë Kërkimesh (me fjalëkyçe të importuar)",
- "SearchEnginesOriginal": "Motorë Kërkimesh (me fjalëkyçe të ndjekur)",
- "SetUpOAuthClientConfig": "Ujdisni formësimin e klientit tuaj OAuth",
- "SetupConfiguration": "Formësim rregullimi",
- "SitemapsContainingUrl": "Harta sajtesh që përmbajnë %s",
- "StartOAuth": "Fillo Procesin OAuth",
- "URLPrefix": "Prefiks URL-sh",
- "URLPrefixProperty": "Veti prefiksi URLsh",
- "URLPrefixPropertyInfo": "Përfshin vetëm URL-të me saktësisht prefiksin e treguar, përfshi protokollin (http/https). Nëse doni që vetia juaj të ketë përputhje me çfarëdo protokolli ose nënpërkatësie (http/https/www./m. e me radhë), shihni mundësinë e shtimit të një vetie Përkatësi.",
- "UnverifiedSites": "Sajte të paverifikuar:",
- "UploadOAuthClientConfig": "Ngarkoni formësimin e klientit tuaj OAuth",
- "Uploading": "Po ngarkohet…",
- "UrlOfAccount": "URL (Llogari)",
- "VideoKeywords": "Fjalëkyçe video në Google",
- "VideoKeywordsDocumentation": "Fjalëkyçe të përdorur në kërkime videosh me Google, të cilët kanë prodhuar lidhje për te sajti juaj, te lista e përfundimeve të kërkimit.",
- "VisitOAuthHowTo": "Ju lutemi, vizitoni %1$sudhërrëfyesin tonë në internet%2$s që të mësoni se si të ujdisni formësimin e klientit tuaj OAuth%3$s.",
- "WebKeywords": "Fjalëkyçe Web në Google",
- "WebKeywordsDocumentation": "Fjalëkyçe të përdorur në kërkime web me Google, të cilët kanë prodhuar lidhje për te sajti juaj, te lista e përfundimeve të kërkimit.",
- "WebsiteSuccessfulConfigured": "Përgëzime! E formësuat me sukses importimin e fjalëkyçeve për sajtin %1$s. Mund të duhen disa ditë derisa të importohen fjalëkyçet tuaj të parë të kërkimit dhe të shfaqen te Referues > Fjalëkyçe Kërkimesh. Te %2$sFAQ%3$s jonë mund të gjeni më tepër informacion mbi vonesa dhe kufizime importimi fjalëkyçesh",
- "WebsiteTypeUnsupported": "Matja e përzgjedhur %1$s s’mund të formësohet, ngaqë është e një lloji të pambuluar. Mbulohen vetëm matje të llojit “sajt”.",
- "WebsiteTypeUnsupportedRollUp": "Shënim: Sajtet Agregat do të ndërthurin automatikisht të dhënat e importuara të krejt sajteve pjella",
- "YandexConfigurationDescription": "Yandex Webmaster API përdor OAuth për mirëfilltësim dhe autorizim.",
- "YandexConfigurationTitle": "Formësoni importim prej Yandex Webmaster API",
- "YandexCrawlAppearedPages": "Faqe të pranishme në kërkim",
- "YandexCrawlAppearedPagesDesc": "Faqe që qenë shtuar rishtas te indeks kërkimesh Yandex",
- "YandexCrawlCrawledPages": "Faqe të Indeksuara",
- "YandexCrawlCrawledPagesDesc": "Numër faqesh të kërkuara nga indeksuesi i Yandex-it.",
- "YandexCrawlErrors": "Gabime të tjera kërkesash",
- "YandexCrawlErrorsDesc": "Faqe të indeksuara që dështuan për çfarëdo arsye tjetër",
- "YandexCrawlHttpStatus2xx": "Kod HTTP 200-299",
- "YandexCrawlHttpStatus2xxDesc": "Faqe të Indeksuara me një kod 2xx",
- "YandexCrawlHttpStatus3xx": "Kod HTTP 300-399 (Faqe të lëvizura)",
- "YandexCrawlHttpStatus3xxDesc": "Faqe të Indeksuara me një kod 3xx",
- "YandexCrawlHttpStatus4xx": "Kod HTTP 400-499 (Gabime kërkese)",
- "YandexCrawlHttpStatus4xxDesc": "Faqe të Indeksuara me një kod 4xx",
- "YandexCrawlHttpStatus5xx": "Kod HTTP 500-599 (Gabime të brendshme shërbyesi)",
- "YandexCrawlHttpStatus5xxDesc": "Faqe të Indeksuara me një kod 5xx",
- "YandexCrawlInIndex": "Faqe gjithsej në tregues",
- "YandexCrawlInIndexDesc": "Numër faqesh gjithsej të pranishme në indeks kërkimesh Yandex",
- "YandexCrawlRemovedPages": "Faqe të hequra prej kërkimi",
- "YandexCrawlRemovedPagesDesc": "Faqe që qenë hequr prej treguesi kërkimesh Yandex",
- "YandexCrawlingStats": "Përmbledhje indeksimi për Yandex!",
- "YandexCrawlingStatsDocumentation": "Përmbledhja e indeksimit ju lejon të shihni informacion të lidhur me indeksimin, bie fjala, gabime të hasur nga roboti i kërkimeve kur vizitohet një faqe, objekte të bllokuar nga kartela juaj robots.txt dhe numri gjithsej i faqeve në tregues.",
- "YandexFieldUrlToAppSite": "URL për te sajt aplikacioni",
- "YandexKeywords": "Fjalëkyçe në Yandex",
- "YandexKeywordsDocumentation": "Fjalëkyçe të përdorur në kërkime Yandex që prodhojnë lidhje për te sajti juaj te lista e përfundimeve të kërkimit.",
- "YandexWebmasterApiUrl": "Url për Yandex Webmaster Tools",
- "YandexWebmasterApiUrlDescription": "Jepni URL-në te e cila gjendet ky sajt te Yandex Webmaster Tools tuajat"
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/lang/sv.json b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/lang/sv.json
deleted file mode 100644
index d40ae7b..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/lang/sv.json
+++ /dev/null
@@ -1,37 +0,0 @@
-{
- "SearchEngineKeywordsPerformance": {
- "APIKey": "API-nyckel",
- "AccountAddedBy": "Lades till av %1$s vid %2$s",
- "AccountConnectionValidationError": "Ett fel inträffade när kontoanslutningen skulle valideras:",
- "AccountDoesNotExist": "Konfigurerat konto %1$s existerar inte längre",
- "AccountNoAccess": "Detta konto har för närvarande inte åtkomst till någon webbplats.",
- "AccountRemovalConfirm": "Du är på väg att ta bort kontot %1$s. Detta kan inaktivera import av nyckelord för anslutna webbplats(er). Vill du fortsätta ändå?",
- "ActivityAccountAdded": "la till ett nytt konto för leverans av nyckelord %1$s: %2$s",
- "ActivityAccountRemoved": "tog bort ett konto för leverans av nyckelord %1$s: %2$s",
- "ActivityGoogleClientConfigChanged": "ändrade klientkonfigurationen för Google.",
- "ActivityYandexClientConfigChanged": "ändrade klientkonfiguration för Yandex.",
- "AddAPIKey": "Lägg till API-nyckel",
- "AddConfiguration": "Lägg till konfiguration",
- "AdminMenuTitle": "Sökprestation",
- "AvailableSites": "Webbplatser som kan importeras:",
- "BingAccountOk": "API-nyckel kontrollerad framgångsrikt",
- "BingConfigurationDescription": "Bing Webmaster Tools behöver en API-nyckel för att gå att nå. Här kan du lägga till API-nycklar för åtkomst till din webbplats data.",
- "BingConfigurationTitle": "Konfigurera import från Bing Webmaster Tools",
- "BingCrawlBlockedByRobotsTxt": "Robots.txt exkludering",
- "BingCrawlBlockedByRobotsTxtDesc": "URLar som för närvarande blockeras av din webbplats robots.txt.",
- "BingCrawlConnectionTimeout": "Timeout för anslutning",
- "BingCrawlCrawledPages": "Kravlade sidor",
- "BingCrawlCrawledPagesDesc": "Antal sidor som Bings crawler anslöt till.",
- "BingCrawlDNSFailures": "DNS-misslyckanden",
- "BingCrawlErrorsDesc": "Antal fel som inträffade för Bings crawler.",
- "BingCrawlHttpStatus2xx": "HTTP-kod 200-299",
- "BingCrawlHttpStatus2xxDesc": "De här koderna visas när servern lyckades skicka webbsidan",
- "BingCrawlHttpStatus301": "HTTP-kod 301 (Permanently moved)",
- "BingCrawlHttpStatus301Desc": "Dessa koder visas när du permanent flyttat innehåll från en plats (URL) till en annan.",
- "Domain": "Domän",
- "DomainProperty": "Domänegendom",
- "DomainPropertyInfo": "Inkluderar alla subdomäner (m, www, och så vidare) och båda protokoll (http, https).",
- "URLPrefix": "URL-prefix",
- "URLPrefixProperty": "URL-prefix för egendom"
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/lang/tr.json b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/lang/tr.json
deleted file mode 100644
index 94012ba..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/lang/tr.json
+++ /dev/null
@@ -1,241 +0,0 @@
-{
- "SearchEngineKeywordsPerformance": {
- "APIKey": "API anahtarı",
- "AccountAddedBy": "%1$s tarafından %2$s zamanında eklendi",
- "AccountConnectionValidationError": "Hesap bağlantısı doğrulanırken bir sorun çıktı:",
- "AccountDoesNotExist": "Yapılandırılmış %1$s hesabı artık yok",
- "AccountNoAccess": "Bu hesabın şu anda herhangi bir siteye erişimi yok.",
- "AccountRemovalConfirm": "%1$s hesabını silmek üzeresiniz. Bu işlem bağlı sitelerden anahtar sözcüklerin içe aktarılmasını kullanımdan kaldırabilir. İlerlemek istediğinize emin misiniz?",
- "ActivityAccountAdded": "yeni bir anahtar sözcük hizmeti sağlayıcısı hesabı ekledi %1$s: %2$s",
- "ActivityAccountRemoved": "bir anahtar sözcük hizmeti sağlayıcısı hesabını sildi %1$s: %2$s",
- "ActivityGoogleClientConfigChanged": "Google istemci yapılandırmasını değiştirdi.",
- "ActivityYandexClientConfigChanged": "Yandex istemci yapılandırmasını değiştirdi.",
- "AddAPIKey": "API anahtarı ekle",
- "AddConfiguration": "Yapılandırma ekle",
- "AdminMenuTitle": "Arama başarımı",
- "AllReferrersImported": "Yönlendirenler (içe aktarılmış anahtar sözcükler ile)",
- "AllReferrersOriginal": "Yönlendirenler (izlenen anahtar sözcükler ile)",
- "AvailableSites": "İçe aktarma için kullanılabilecek siteler:",
- "BingAPIKeyInstruction": "%1$sBing Webmaster Tools%2$s sitesinde bir hesap açın ve siteyi Bing Webmaster üzerine ekleyin. Siteyi doğruladıktan sonra %3$sAPI anahtarınızı kopyalayın%4$s.",
- "BingAccountError": "API anahtarı doğrulanırken bir sorun çıktı: %1$s. Bing Webmaster Tools ile bu API anahtarını yeni oluşturduysanız bir kaç dakika sonra yeniden deneyin (Bing Webmaster Tools API anahtarlarının etkinleştirilmesi biraz zaman alabilir).",
- "BingAccountOk": "API anahtarı doğrulandı",
- "BingConfigurationDescription": "Bing Webmaster Tools kullanmak için bir API anahtarına gerek vardır. Sitelerinizin verilerine erişmek için gereken API anahtarlarını buradan ekleyebilirsiniz.",
- "BingConfigurationTitle": "Bing Webmaster Tools üzerinden içe aktarmayı yapılandırın",
- "BingCrawlBlockedByRobotsTxt": "Robots.txt katılmaması",
- "BingCrawlBlockedByRobotsTxtDesc": "Sitenin robots.txt dosyasını engelleyen adresler.",
- "BingCrawlConnectionTimeout": "Bağlantı zaman aşımları",
- "BingCrawlConnectionTimeoutDesc": "Bu değer yakın zamanda bağlantı sorunları nedeniyle Bing tarafından sitenize erişilememe sayısını gösterir. Bu durum geçici bir sorundan kaynaklanıyor olabilir ancak istekleri kazara reddedip etmediğinizi öğrenmek için sunucu günlüğü kayıtlarını gözden geçirmeniz iyi olur.",
- "BingCrawlCrawledPages": "Derlenen sayfa sayısı",
- "BingCrawlCrawledPagesDesc": "Bing crawler tarafından istekte bulunulan sayfa sayısı.",
- "BingCrawlDNSFailures": "DNS sorunları",
- "BingCrawlDNSFailuresDesc": "Bu sorun türünde bot tarafından yakın zamanda sayfalarınıza erişmek için DNS sunucu ile iletişim kurulmaya çalışılırken yaşanan sorunlar görüntülenir. Sunucunuz çalışmıyor olabilir ya da TTL değerinin 0 olarak ayarlanması gibi DNS yöneltmesinin yapılmasını engelleyen bir yapılandırma hatası olabilir.",
- "BingCrawlErrors": "Bing derleme sorunları",
- "BingCrawlErrorsDesc": "Bing crawler tarafından karşılaşılan sorun sayısı.",
- "BingCrawlErrorsFromDateX": "Bu rapor, yakın zamanda Bing tarafından karşılaşılan derleme sorunlarını içerir. Geçmişe dönük herhangi bir veri bulunmaz. Son güncelleme: %s",
- "BingCrawlHttpStatus2xx": "HTTP Kodları 200-299",
- "BingCrawlHttpStatus2xxDesc": "Sunucu sayfayı doğru olarak sunduğunda bu kodlar görüntülenir",
- "BingCrawlHttpStatus301": "HTTP Kodu 301 (Kalıcı olarak taşındı)",
- "BingCrawlHttpStatus301Desc": "İçerik bir konumdan (adres) başka bir konuma kalıcı olarak taşındığında bu kod görüntülenir.",
- "BingCrawlHttpStatus302": "HTTP Kodu 302 (Geçici olarak taşındı)",
- "BingCrawlHttpStatus302Desc": "İçerik bir konumdan (adres) başka bir konuma geçici olarak taşındığında bu kod görüntülenir.",
- "BingCrawlHttpStatus4xx": "HTTP Kodları 400-499 (İstek sorunları)",
- "BingCrawlHttpStatus4xxDesc": "Bu kodlar sunucunun yapılan isteklerde bulunan hatalar nedeniyle istekleri işleyememesi durumunda görüntülenir.",
- "BingCrawlHttpStatus5xx": "HTTP Kodları 500-599 (İç sunucu sorunları)",
- "BingCrawlHttpStatus5xxDesc": "Bu kodlar sunucunun açıkca geçerli olan istekleri karşılayamaması durumunda görüntülenir.",
- "BingCrawlImportantBlockedByRobotsTxt": "Önemli sayfada robots.txt katılmaması",
- "BingCrawlInboundLink": "Gelen bağlantı toplamı",
- "BingCrawlInboundLinkDesc": "Gelen bağlantılar Bing tarafından algılanan sitenize yönelmiş adreslerdir. Bunlar, kendi sitenizden gelen ve içeriğinize işaret eden bağlantılardır.",
- "BingCrawlMalwareInfected": "Zararlı yazılımdan etkilenmiş siteler",
- "BingCrawlMalwareInfectedDesc": "Bing tarafından zararlı bir yazılımın bulaştığı ya da ilgisi olduğu anlaşılan sayfa adresleri bu bölümde görüntülenir.",
- "BingCrawlPagesInIndex": "Dizindeki sayfa sayısı",
- "BingCrawlPagesInIndexDesc": "Bing arama dizinindeki toplam sayfa sayısı",
- "BingCrawlStatsOtherCodes": "Tüm diğer HTTP durum kodları",
- "BingCrawlStatsOtherCodesDesc": "Başka değerler ile eşleşmeyen tüm diğer kodları bir araya getirir (1xx ya da bilgilendirme kodları gibi).",
- "BingCrawlingStats": "Bing ve Yahoo! için derleme özeti",
- "BingCrawlingStatsDocumentation": "Derleme özetinde bir sayfa ziyaret edildiğinde arama botu tarafından karşılaşılan sorunlar, robots.txt dosyanız tarafından engellenen ögeler ve zararlı yazılımlar tarafından etkilenmiş adresler gibi derleme ile ilgili bilgiler bulunur.",
- "BingKeywordImport": "Bing anahtar sözcük içe aktarma",
- "BingKeywords": "Anahtar sözcükler (Bing ve Yahoo! üzerinde)",
- "BingKeywordsDocumentation": "Bing ya da Yahoo! arama sonuçlarında sitenize bağlantılar oluşturmak için kullanılan anahtar sözcükler.",
- "BingKeywordsNoRangeReports": "Bing ve Yahoo! üzerindeki anahtar sözcükler günlük raporlar olarak kullanılamadığından yalnızca tam haftalar ya da aylar gibi özel tarih aralıkları için işlenebilir.",
- "BingKeywordsNotDaily": "Bing ve Yahoo! üzerindeki anahtar sözcükler yalnızca haftalık raporlar olarak kullanılabilir. Anahtar sözcük verileri günlük olarak kullanılamaz.",
- "BingWebmasterApiUrl": "Bing Webmaster Tools adresi",
- "BingWebmasterApiUrlDescription": "Bu sitenin Bing Webmaster Tools üzerindeki adresini yazın",
- "Category": "Kategori",
- "ChangeConfiguration": "Yapılandırmayı değiştir",
- "Clicks": "Tıklanma",
- "ClicksDocumentation": "Birisi bir arama motorunun sonuç sayfasında siteyi gösteren bir bağlantıya tıkladığında bir tıklama sayılır.",
- "ClientConfigImported": "İstemci yapılandırması içe aktarıldı!",
- "ClientConfigSaveError": "İstemci yapılandırması içe aktarılırken bir sorun çıktı. Lütfen belirtilen yapılandırmanın geçerli olduğundan emin olduktan sonra yeniden deneyin.",
- "ClientId": "İstemci kodu",
- "ClientSecret": "İstemci parolası",
- "ConfigAvailableNoWebsiteConfigured": "Bütünleştirme yapılandırması tamamlandı, ancak şu anda içe aktarılmak için bir site yapılandırılmamış.",
- "ConfigRemovalConfirm": "%1$s yapılandırmasını silmek üzereseniz. Bu site için anahtar sözcükler içe aktarılmayacak. İlerlemek istiyor musunuz?",
- "Configuration": "Yapılandırma",
- "ConfigurationDescription": "Bu uygulama eki, sitenin kullanıcıları tarafından arama motorlarına sorulan anahtar sözcükleri doğrudan Matomo içine aktarır.",
- "ConfigurationFile": "Yapılandırma dosyası",
- "ConfigurationValid": "OAuth yapılandırmanız geçersiz.",
- "ConfigureMeasurableBelow": "Bir siteyi yapılandırmak için aşağıdaki düğmeye tıklayın ya da doğrudan site ayarları bölümüne gidin.",
- "ConfigureMeasurables": "Siteleri yapılandır",
- "ConfigureTheImporterLabel1": "Google Search Console anahtar sözcüklerinizi içe aktarın ve güçlü Matomo analiz araçlarını kullanarak inceleyin. İçe aktarıcıyı bağlantısını kurduktan sonra, içe aktarılacak siteleri seçin. Matomo, programlanmış arşivleme sürecinin bir parçası olarak sitelerin anahtar sözcüklerini içe aktarmaya başlar.",
- "ConfigureTheImporterLabel2": "Verilerinizi Google Search Console üzerinden içe aktarmak için Matomo bu verilere erişmelidir.",
- "ConfigureTheImporterLabel3": "Başlamak için, %1$sOAuth İstemci yapılandırmanızı alma yönergelerini izleyin%2$s. Ardından, aşağıdaki düğmeyi kullanarak istemci yapılandırma dosyasını yükleyin.",
- "ConfiguredAccounts": "yapılandırılmış hesaplar",
- "ConfiguredUrlNotAvailable": "Bu hesabın yapılandırılmış adresine erişilemiyor",
- "ConnectAccount": "Hesap bağla",
- "ConnectAccountDescription": "Gerekli izinleri vermek için aşağıdaki düğme üzerine tıklayarak %1$s sitesine gidin.",
- "ConnectAccountYandex": "Yandex hesapları için kimlik doğrulaması yalnızca %1$s gün süreyle geçerlidir. İçe aktarma işlemlerinin sorunsuz yapılabilmesi için her hesap kimliğinin bu süre içinde yeniden doğrulanması gerekir.",
- "ConnectFirstAccount": "Aşağıdan ilk hesabınızı bağlayarak başlayın.",
- "ConnectGoogleAccounts": "Google hesaplarını bağla",
- "ConnectYandexAccounts": "Yandex hesaplarını bağla",
- "ContainingSitemaps": "Site haritaları bulunan",
- "CrawlingErrors": "Derleme sorunları",
- "CrawlingOverview1": "Derleme özeti raporu, arama motoru robotlarının siteleri nasıl derlediği ile ilgili kritik bilgileri içerir. Bu ölçümler, aşağı yukarı her gün arama motorları tarafından sağlanan verilerle güncellenir.",
- "CrawlingStats": "Derleme özeti",
- "CreatedBy": "Oluşturan",
- "Ctr": "Tıklayıp geçme oranı",
- "CtrDocumentation": "Tıklayıp geçme oranı: Kişilerin ne sıklıkta arama sonuçları sayfasında sitenin bağlantısını görüp tıkladığının oranı.",
- "CurrentlyConnectedAccounts": "Şu anda bağlı %1$s hesap var.",
- "DeleteUploadedClientConfig": "Yüklenen istemci yapılandırmasını kaldırmak istiyorsanız aşağıya tıklayın",
- "Domain": "Etki alanı",
- "DomainProperty": "Etki alanı mülkü",
- "DomainPropertyInfo": "Tüm alt etki alanlarını (m, www gibi) ve iki iletişim kuralını da (http, https) kapsar.",
- "EnabledSearchTypes": "Alınacak anahtar sözcük türleri",
- "FetchImageKeyword": "Görsel anahtar sözcükleri alınsın",
- "FetchImageKeywordDesc": "Bu seçenek etkinleştirildiğinde, Google görsel aramasında kullanılan anahtar sözcükler alınır",
- "FetchNewsKeyword": "Yeni anahtar sözcükler alınsın",
- "FetchNewsKeywordDesc": "Bu seçenek etkinleştirildiğinde, Google Haberler için kullanılan anahtar sözcükler alınır",
- "FetchVideoKeyword": "Görüntü anahtar sözcükleri alınsın",
- "FetchVideoKeywordDesc": "Bu seçenek etkinleştirildiğinde, Google görüntü aramasında kullanılan anahtar sözcükler alınır",
- "FetchWebKeyword": "Site anahtar sözcükleri alınsın",
- "FetchWebKeywordDesc": "Bu seçenek etkinleştirildiğinde, Google site aramasında kullanılan anahtar sözcükler alınır",
- "FirstDetected": "İlk algılanan",
- "GoogleAccountAccessTypeOfflineAccess": "Şu anda oturum açmamış olsanız da arama anahtar sözcüklerini içe aktarmak için çevrinmdışı erişim gereklidir.",
- "GoogleAccountAccessTypeProfileInfo": "Profil bilgileri şu anda bağlı olan hesapların adlarını görüntülemek için kullanılır.",
- "GoogleAccountAccessTypeSearchConsoleData": "Konsol verilerinde arama Google arama anahtar sözcüklerini alabilmek için gereklidir.",
- "GoogleAccountError": "OAuth erişimi doğrulanırken bir sorun çıktı: %1$s",
- "GoogleAccountOk": "OAuth erişimi doğrulandı.",
- "GoogleAuthorizedJavaScriptOrigin": "İzin verilen JavaScript kaynağı",
- "GoogleAuthorizedRedirectUri": "İzin verilen yönlendirme adresi",
- "GoogleConfigurationDescription": "Google arama konsolunda kimlik doğrulaması için OAuth kullanılır.",
- "GoogleConfigurationTitle": "Google arama konsolundan içe aktarmayı yapılandır",
- "GoogleDataNotFinal": "Bu rapordaki anahtar sözcükler henüz son verileri içermiyor olabilir. Google, son anahtar sözcükleri 2 gün gecikme ile sağlar. Daha yakın zamandaki anahtar sözcükler, son olarak bildirildiğinde yeniden içe aktarılır.",
- "GoogleDataProvidedWithDelay": "Google, anahtar sözcük verilerini bir gecikme ile sağlar. Bu tarihteki anahtar sözcükler biraz daha sonra içe aktarılacak.",
- "GoogleKeywordImport": "Google anahtar sözcükleri içe aktarma",
- "GooglePendingConfigurationErrorMessage": "Yapılandırma bekliyor. Lütfen bir süper kullanıcıdan yapılandırmayı tamamlamasını isteyin.",
- "GoogleSearchConsoleUrl": "Google arama konsolu adresi",
- "GoogleSearchConsoleUrlDescription": "Bu sitenin Google arama konsolu üzerindeki adresini yazın",
- "GoogleUploadOrPasteClientConfig": "Lütfen Google OAuth istemci yapılandırmanızı yükleyin ya da aşağıdaki alana yapıştırın.",
- "HowToGetOAuthClientConfig": "OAuth istemci yapılandırmasını almak",
- "ImageKeywords": "Google üzerindeki görsel anahtar sözcükleri",
- "ImageKeywordsDocumentation": "Google görsel arama sonuçlarında sitenize bağlantılar oluşturmak için kullanılan anahtar sözcükler.",
- "Impressions": "Gösterimler",
- "ImpressionsDocumentation": "Bir arama motoru sonuç sayfasında siteyi görüntülediğinde bir gösterim sayılır.",
- "IntegrationConfigured": "Bütünleştirme yapılandırılmış",
- "IntegrationNotConfigured": "Bütünleştirme yapılandırılmamış",
- "InvalidRedirectUriInClientConfiguration": "redirect_uris değeri geçersiz. En az 1 uri yüklenen yapılandırma dosyasındaki \"%1$s\" uri değeri ile eşleşmelidir",
- "KeywordStatistics": "Arama anahtar sözcükleri",
- "KeywordTypeImage": "görsel",
- "KeywordTypeNews": "haberler",
- "KeywordTypeVideo": "görüntü",
- "KeywordTypeWeb": "site",
- "KeywordsCombined": "Birleştirilmiş anahtar sözcükler",
- "KeywordsCombinedDocumentation": "Bu rapor, Matomo tarafından algılanan ve arama motorlarından içe aktarılan tüm anahtar sözcüklerin birleştirilmiş görünümünü içerir. İçinde yalnızca ziyaret ölçümü bulunur. Daha ayrıntılı ölçümleri görebilmek için ilgili raporlardan birine geçebilirsiniz.",
- "KeywordsCombinedImported": "Birleştirilmiş içe aktarılan sözcükler",
- "KeywordsCombinedImportedDocumentation": "Yapılandırılmış tüm arama motorlarından içe aktarılan tüm anahtar sözcükleri görüntüleyen rapor.",
- "KeywordsReferrers": "Anahtar sözcükler (tanımlanmamışlar dahil)",
- "KeywordsSubtableImported": "İçe aktarılmış anahtar sözcükler",
- "KeywordsSubtableOriginal": "İzlenen anahtar sözcükler (tanımlanmamışlar dahil)",
- "LastCrawled": "Son derlenen",
- "LastDetected": "Son algılanan",
- "LastImport": "Son içe aktarma",
- "LatestAvailableDate": "%1$s için kullanılabilecek son anahtar sözcük verileri",
- "LinksToUrl": "%s adresine bağlanan",
- "ManageAPIKeys": "API anahtarları yönetimi",
- "MeasurableConfig": "yapılandırılmış siteler",
- "NewsKeywords": "Google üzerindeki haber anahtar sözcükleri",
- "NewsKeywordsDocumentation": "Google Haberler arama sonuçlarında sitenize bağlantılar oluşturmak için kullanılan anahtar sözcükler.",
- "NoSegmentation": "Bu rapor dilimleri desteklemiyor. Standart, dilimlenmemiş veriler görüntüleniyor.",
- "NoWebsiteConfigured": "Henüz yapılandırılmış bir site yok. Belirli bir sitenin içe aktarılmasını kullanıma almak için buradan yapılandırmayı tamamlayabilirsiniz.",
- "NoWebsiteConfiguredWarning": "%s için içe aktarma tam olarak yapılandırılmamış. İçe aktarmayı kullanıma almak için bazı siteler yapılandırmalısınız.",
- "NotAvailable": "Kullanılamaz",
- "OAuthAccessTimedOut": "Bu hesap için OAuth erişiminin süresi dolmuş olabilir. Bu hesap ile içe aktarma işlemlerinin yapılabilmesi için kimliği yeniden doğrulamanız gerekecek.",
- "OAuthAccessWillTimeOut": "Bu hesap için OAuth erişiminin süresi %1$s gün içinde dolacak. %2$s gün kaldı",
- "OAuthAccessWillTimeOutSoon": "Bu hesap için OAuth erişiminin süresi %1$s gün içinde dolacak. Lütfen bu hesap ile içe aktarma işlemlerinin yapılabilmesi için kimliği yeniden doğrulayın.",
- "OAuthClientConfig": "OAuth istemci yapılandırması",
- "OAuthError": "OAuth işlemi sırasında bir sorun çıktı. Lütfen yeniden deneyin ve gerekli izinleri verdiğinizden emin olun.",
- "OAuthExampleText": "Yapılandırma için aşağıdaki alanlar gereklidir. Lütfen belirtilen değerleri kullanın:",
- "OauthFailedMessage": "Google Search Console için yetkilendirme işlemi sırasında bir sorunla karşılaştık. Lütfen yeniden denemek için aşağıdaki düğmeye tıklayın. Sorun sürerse, yardım almak için destek ekibimizle görüşün. Ekibimiz sorunu çözmenize ve Google Search Console anahjtar sözcüklerinizi içe aktarmanıza yardımcı olur.",
- "OptionQuickConnectWithGoogle": "Google ile hızlı bağlan (önerilir)",
- "Platform": "Platform",
- "Position": "Ortalama konum",
- "PositionDocumentation": "Arama sonuçlarında sitenin ortalama konumu (bu anahtar sözcük için).",
- "ProvideYandexClientConfig": "Lütfen Yandex Oauth istemci yapılandırmanızı ekleyin.",
- "ProviderBingDescription": "Bing ve Yahoo!, aramalarında siteyi bulmak için kullanılan tüm anahtar sözcükleri içe aktarır.",
- "ProviderBingNote": "Not: Microsoft, anahtar sözcük verilerini her Cumartesi günü bir hafta süre ile yayınlar. Bunun sonucu olarak Bing ve Yahoo için anahtar sözcüklerinizin raporlara eklenmesi bir kaç gün sürer ve yalnızca haftalık, aylık ve yıllık aralıklarda görüntülenir.",
- "ProviderGoogleDescription": "Google, aramalarında siteyi bulmak için kullanılan tüm anahtar sözcükleri içe aktarır. Raporlarda anahtar sözcükler her bir arama türüne göre ayrılarak görüntülenir (Site, Görsel ve Görüntü).",
- "ProviderGoogleNote": "Not: Google son anahtar sözcük verilerini 2 gün gecikmeli olarak yayınlar. Daha yakın günlerdeki son olmayan veriler her zaman görüntülenir ancak son olarak bildirildiğinde yeniden içe aktarılır. İlk içe aktarımda anahtar sözcük verilerinin 486 güne kadar olan geçmişi de içe aktarılabilir.",
- "ProviderListDescription": "Aşağıdaki bir (ya da bir kaç) arama motorunu ayarladığınızda, Matomo tarafından arama anahtar sözcüklerinin içe aktarılacağı siteleri yapılandırabilirsiniz.",
- "ProviderXAccountWarning": "Hesap yapılandırma sorunları bulundu Lütfen %s için yapılandırılmış hesapları denetleyin.",
- "ProviderXSitesWarning": "Site yapılandırma sorunları bulundu Lütfen %s için yapılandırılmış siteleri denetleyin.",
- "ProviderYandexDescription": "Yandex aramalarında siteyi bulmak için kullanılan tüm anahtar sözcükleri içe aktarır.",
- "ProviderYandexNote": "Not: Yandex anahtar sözcük verilerini 5 güne kadar gecikmeli olarak yayınlar. İlk içe aktarımda anahtar sözcük verilerinin 100 güne kadar olan geçmişi de içe aktarılabilir.",
- "ReAddAccountIfPermanentError": "Sorun düzelmiyorsa hesabı kaldırıp bağlantıyı yeniden kurmayı deneyin.",
- "ReAuthenticateIfPermanentError": "Sorun düzelmiyorsa kimliği yeniden doğrulamayı ya da hesabı kaldırıp bağlantıyı yeniden kurmayı deneyin.",
- "Reauthenticate": "Kimliği yeniden doğrula",
- "RecentApiErrorsWarning": "Anahtar sözcük içe aktarma sorunları bulundu
- {% if not hasAdminPriviliges %}
- Did you know?
- An Admin or Super User can Configure Search Performance to import all your search keywords into Matomo.
- {% else %}
- Did you know?
- You can Configure
- Search Performance to import all your search keywords into Matomo.
- {% endif %}
-
\ No newline at end of file
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/templates/yandex/configuration.twig b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/templates/yandex/configuration.twig
deleted file mode 100644
index 52d6f35..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/templates/yandex/configuration.twig
+++ /dev/null
@@ -1,31 +0,0 @@
-{% extends 'admin.twig' %}
-
-{% set title %}{{ 'SearchEngineKeywordsPerformance_SearchEngineKeywordsPerformance'|translate }}{% endset %}
-
-{% block content %}
-
-
-
-{% endblock %}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/autoload.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/autoload.php
deleted file mode 100644
index 717d21e..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/autoload.php
+++ /dev/null
@@ -1,10 +0,0 @@
-
- * 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 ?string */
- private $vendorDir;
-
- // PSR-4
- /**
- * @var array[]
- * @psalm-var array>
- */
- private $prefixLengthsPsr4 = array();
- /**
- * @var array[]
- * @psalm-var array>
- */
- private $prefixDirsPsr4 = array();
- /**
- * @var array[]
- * @psalm-var array
- */
- private $fallbackDirsPsr4 = array();
-
- // PSR-0
- /**
- * @var array[]
- * @psalm-var array>
- */
- private $prefixesPsr0 = array();
- /**
- * @var array[]
- * @psalm-var array
- */
- private $fallbackDirsPsr0 = array();
-
- /** @var bool */
- private $useIncludePath = false;
-
- /**
- * @var string[]
- * @psalm-var array
- */
- private $classMap = array();
-
- /** @var bool */
- private $classMapAuthoritative = false;
-
- /**
- * @var bool[]
- * @psalm-var array
- */
- private $missingClasses = array();
-
- /** @var ?string */
- private $apcuPrefix;
-
- /**
- * @var self[]
- */
- private static $registeredLoaders = array();
-
- /**
- * @param ?string $vendorDir
- */
- public function __construct($vendorDir = null)
- {
- $this->vendorDir = $vendorDir;
- }
-
- /**
- * @return string[]
- */
- public function getPrefixes()
- {
- if (!empty($this->prefixesPsr0)) {
- return call_user_func_array('array_merge', array_values($this->prefixesPsr0));
- }
-
- return array();
- }
-
- /**
- * @return array[]
- * @psalm-return array>
- */
- public function getPrefixesPsr4()
- {
- return $this->prefixDirsPsr4;
- }
-
- /**
- * @return array[]
- * @psalm-return array
- */
- public function getFallbackDirs()
- {
- return $this->fallbackDirsPsr0;
- }
-
- /**
- * @return array[]
- * @psalm-return array
- */
- public function getFallbackDirsPsr4()
- {
- return $this->fallbackDirsPsr4;
- }
-
- /**
- * @return string[] Array of classname => path
- * @psalm-return array
- */
- public function getClassMap()
- {
- return $this->classMap;
- }
-
- /**
- * @param string[] $classMap Class to filename map
- * @psalm-param array $classMap
- *
- * @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 string[]|string $paths The PSR-0 root directories
- * @param bool $prepend Whether to prepend the directories
- *
- * @return void
- */
- public function add($prefix, $paths, $prepend = false)
- {
- if (!$prefix) {
- if ($prepend) {
- $this->fallbackDirsPsr0 = array_merge(
- (array) $paths,
- $this->fallbackDirsPsr0
- );
- } else {
- $this->fallbackDirsPsr0 = array_merge(
- $this->fallbackDirsPsr0,
- (array) $paths
- );
- }
-
- return;
- }
-
- $first = $prefix[0];
- if (!isset($this->prefixesPsr0[$first][$prefix])) {
- $this->prefixesPsr0[$first][$prefix] = (array) $paths;
-
- return;
- }
- if ($prepend) {
- $this->prefixesPsr0[$first][$prefix] = array_merge(
- (array) $paths,
- $this->prefixesPsr0[$first][$prefix]
- );
- } else {
- $this->prefixesPsr0[$first][$prefix] = array_merge(
- $this->prefixesPsr0[$first][$prefix],
- (array) $paths
- );
- }
- }
-
- /**
- * Registers a set of PSR-4 directories for a given namespace, either
- * appending or prepending to the ones previously set for this namespace.
- *
- * @param string $prefix The prefix/namespace, with trailing '\\'
- * @param string[]|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)
- {
- if (!$prefix) {
- // Register directories for the root namespace.
- if ($prepend) {
- $this->fallbackDirsPsr4 = array_merge(
- (array) $paths,
- $this->fallbackDirsPsr4
- );
- } else {
- $this->fallbackDirsPsr4 = array_merge(
- $this->fallbackDirsPsr4,
- (array) $paths
- );
- }
- } elseif (!isset($this->prefixDirsPsr4[$prefix])) {
- // Register directories for a new namespace.
- $length = strlen($prefix);
- if ('\\' !== $prefix[$length - 1]) {
- throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
- }
- $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
- $this->prefixDirsPsr4[$prefix] = (array) $paths;
- } elseif ($prepend) {
- // Prepend directories for an already registered namespace.
- $this->prefixDirsPsr4[$prefix] = array_merge(
- (array) $paths,
- $this->prefixDirsPsr4[$prefix]
- );
- } else {
- // Append directories for an already registered namespace.
- $this->prefixDirsPsr4[$prefix] = array_merge(
- $this->prefixDirsPsr4[$prefix],
- (array) $paths
- );
- }
- }
-
- /**
- * Registers a set of PSR-0 directories for a given prefix,
- * replacing any others previously set for this prefix.
- *
- * @param string $prefix The prefix
- * @param string[]|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 string[]|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($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 indexed by their corresponding vendor directories.
- *
- * @return self[]
- */
- 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;
- }
-}
-
-/**
- * Scope isolated include.
- *
- * Prevents access to $this/self from included files.
- *
- * @param string $file
- * @return void
- * @private
- */
-function includeFile($file)
-{
- include $file;
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/composer/InstalledVersions.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/composer/InstalledVersions.php
deleted file mode 100644
index c6b54af..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/composer/InstalledVersions.php
+++ /dev/null
@@ -1,352 +0,0 @@
-
- * 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 || empty($installed['versions'][$packageName]['dev_requirement']);
- }
- }
-
- 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($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')) {
- $installed[] = self::$installedByVendor[$vendorDir] = require $vendorDir.'/composer/installed.php';
- 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') {
- self::$installed = require __DIR__ . '/installed.php';
- } else {
- self::$installed = array();
- }
- }
- $installed[] = self::$installed;
-
- return $installed;
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/composer/LICENSE b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/composer/LICENSE
deleted file mode 100644
index f27399a..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/composer/LICENSE
+++ /dev/null
@@ -1,21 +0,0 @@
-
-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/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/composer/autoload_classmap.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/composer/autoload_classmap.php
deleted file mode 100644
index 0fb0a2c..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/composer/autoload_classmap.php
+++ /dev/null
@@ -1,10 +0,0 @@
- $vendorDir . '/composer/InstalledVersions.php',
-);
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/composer/autoload_files.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/composer/autoload_files.php
deleted file mode 100644
index 5333040..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/composer/autoload_files.php
+++ /dev/null
@@ -1,16 +0,0 @@
- $vendorDir . '/ralouphie/getallheaders/src/getallheaders.php',
- 'c964ee0ededf28c96ebd9db5099ef910' => $vendorDir . '/guzzlehttp/promises/src/functions_include.php',
- '6e3fae29631ef280660b3cdad06f25a8' => $vendorDir . '/symfony/deprecation-contracts/function.php',
- '37a3dc5111fe8f707ab4c132ef1dbc62' => $vendorDir . '/guzzlehttp/guzzle/src/functions_include.php',
- '1f87db08236948d07391152dccb70f04' => $vendorDir . '/google/apiclient-services/autoload.php',
- 'decc78cc4436b1292c6c0d151b19445c' => $vendorDir . '/phpseclib/phpseclib/phpseclib/bootstrap.php',
- 'a8d3953fd9959404dd22d3dfcd0a79f0' => $vendorDir . '/google/apiclient/src/aliases.php',
-);
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/composer/autoload_namespaces.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/composer/autoload_namespaces.php
deleted file mode 100644
index 15a2ff3..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/composer/autoload_namespaces.php
+++ /dev/null
@@ -1,9 +0,0 @@
- array($vendorDir . '/phpseclib/phpseclib/phpseclib'),
- 'Psr\\Http\\Message\\' => array($vendorDir . '/psr/http-factory/src', $vendorDir . '/psr/http-message/src'),
- 'Psr\\Http\\Client\\' => array($vendorDir . '/psr/http-client/src'),
- 'Psr\\Cache\\' => array($vendorDir . '/psr/cache/src'),
- 'ParagonIE\\ConstantTime\\' => array($vendorDir . '/paragonie/constant_time_encoding/src'),
- 'GuzzleHttp\\Psr7\\' => array($vendorDir . '/guzzlehttp/psr7/src'),
- 'GuzzleHttp\\Promise\\' => array($vendorDir . '/guzzlehttp/promises/src'),
- 'GuzzleHttp\\' => array($vendorDir . '/guzzlehttp/guzzle/src'),
- 'Google\\Service\\' => array($vendorDir . '/google/apiclient-services/src'),
- 'Google\\Auth\\' => array($vendorDir . '/google/auth/src'),
- 'Google\\' => array($vendorDir . '/google/apiclient/src'),
- 'Firebase\\JWT\\' => array($vendorDir . '/firebase/php-jwt/src'),
-);
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/composer/autoload_real.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/composer/autoload_real.php
deleted file mode 100644
index 2691ae8..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/composer/autoload_real.php
+++ /dev/null
@@ -1,55 +0,0 @@
-register(true);
-
- $includeFiles = \Composer\Autoload\ComposerStaticInita45dbc566c3f138ca6114173227009ed::$files;
- foreach ($includeFiles as $fileIdentifier => $file) {
- composerRequirea45dbc566c3f138ca6114173227009ed($fileIdentifier, $file);
- }
-
- return $loader;
- }
-}
-
-/**
- * @param string $fileIdentifier
- * @param string $file
- * @return void
- */
-function composerRequirea45dbc566c3f138ca6114173227009ed($fileIdentifier, $file)
-{
- if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
- $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
-
- require $file;
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/composer/autoload_static.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/composer/autoload_static.php
deleted file mode 100644
index 2bb076a..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/composer/autoload_static.php
+++ /dev/null
@@ -1,105 +0,0 @@
-
- array (
- 'phpseclib3\\' => 11,
- ),
- 'P' =>
- array (
- 'Psr\\Http\\Message\\' => 17,
- 'Psr\\Http\\Client\\' => 16,
- 'Psr\\Cache\\' => 10,
- 'ParagonIE\\ConstantTime\\' => 23,
- ),
- 'G' =>
- array (
- 'GuzzleHttp\\Psr7\\' => 16,
- 'GuzzleHttp\\Promise\\' => 19,
- 'GuzzleHttp\\' => 11,
- 'Google\\Service\\' => 15,
- 'Google\\Auth\\' => 12,
- 'Google\\' => 7,
- ),
- 'F' =>
- array (
- 'Firebase\\JWT\\' => 13,
- ),
- );
-
- public static $prefixDirsPsr4 = array (
- 'phpseclib3\\' =>
- array (
- 0 => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib',
- ),
- 'Psr\\Http\\Message\\' =>
- array (
- 0 => __DIR__ . '/..' . '/psr/http-factory/src',
- 1 => __DIR__ . '/..' . '/psr/http-message/src',
- ),
- 'Psr\\Http\\Client\\' =>
- array (
- 0 => __DIR__ . '/..' . '/psr/http-client/src',
- ),
- 'Psr\\Cache\\' =>
- array (
- 0 => __DIR__ . '/..' . '/psr/cache/src',
- ),
- 'ParagonIE\\ConstantTime\\' =>
- array (
- 0 => __DIR__ . '/..' . '/paragonie/constant_time_encoding/src',
- ),
- 'GuzzleHttp\\Psr7\\' =>
- array (
- 0 => __DIR__ . '/..' . '/guzzlehttp/psr7/src',
- ),
- 'GuzzleHttp\\Promise\\' =>
- array (
- 0 => __DIR__ . '/..' . '/guzzlehttp/promises/src',
- ),
- 'GuzzleHttp\\' =>
- array (
- 0 => __DIR__ . '/..' . '/guzzlehttp/guzzle/src',
- ),
- 'Google\\Service\\' =>
- array (
- 0 => __DIR__ . '/..' . '/google/apiclient-services/src',
- ),
- 'Google\\Auth\\' =>
- array (
- 0 => __DIR__ . '/..' . '/google/auth/src',
- ),
- 'Google\\' =>
- array (
- 0 => __DIR__ . '/..' . '/google/apiclient/src',
- ),
- 'Firebase\\JWT\\' =>
- array (
- 0 => __DIR__ . '/..' . '/firebase/php-jwt/src',
- ),
- );
-
- public static $classMap = array (
- 'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
- );
-
- public static function getInitializer(ClassLoader $loader)
- {
- return \Closure::bind(function () use ($loader) {
- $loader->prefixLengthsPsr4 = ComposerStaticInita45dbc566c3f138ca6114173227009ed::$prefixLengthsPsr4;
- $loader->prefixDirsPsr4 = ComposerStaticInita45dbc566c3f138ca6114173227009ed::$prefixDirsPsr4;
- $loader->classMap = ComposerStaticInita45dbc566c3f138ca6114173227009ed::$classMap;
-
- }, null, ClassLoader::class);
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/composer/installed.json b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/composer/installed.json
deleted file mode 100644
index ee778d0..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/composer/installed.json
+++ /dev/null
@@ -1,1156 +0,0 @@
-{
- "packages": [
- {
- "name": "firebase/php-jwt",
- "version": "v6.10.0",
- "version_normalized": "6.10.0.0",
- "source": {
- "type": "git",
- "url": "https://github.com/firebase/php-jwt.git",
- "reference": "a49db6f0a5033aef5143295342f1c95521b075ff"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/firebase/php-jwt/zipball/a49db6f0a5033aef5143295342f1c95521b075ff",
- "reference": "a49db6f0a5033aef5143295342f1c95521b075ff",
- "shasum": ""
- },
- "require": {
- "php": "^7.4||^8.0"
- },
- "require-dev": {
- "guzzlehttp/guzzle": "^6.5||^7.4",
- "phpspec/prophecy-phpunit": "^2.0",
- "phpunit/phpunit": "^9.5",
- "psr/cache": "^1.0||^2.0",
- "psr/http-client": "^1.0",
- "psr/http-factory": "^1.0"
- },
- "suggest": {
- "ext-sodium": "Support EdDSA (Ed25519) signatures",
- "paragonie/sodium_compat": "Support EdDSA (Ed25519) signatures when libsodium is not present"
- },
- "time": "2023-12-01T16:26:39+00:00",
- "type": "library",
- "installation-source": "dist",
- "autoload": {
- "psr-4": {
- "Firebase\\JWT\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "BSD-3-Clause"
- ],
- "authors": [
- {
- "name": "Neuman Vong",
- "email": "neuman+pear@twilio.com",
- "role": "Developer"
- },
- {
- "name": "Anant Narayanan",
- "email": "anant@php.net",
- "role": "Developer"
- }
- ],
- "description": "A simple library to encode and decode JSON Web Tokens (JWT) in PHP. Should conform to the current spec.",
- "homepage": "https://github.com/firebase/php-jwt",
- "keywords": [
- "jwt",
- "php"
- ],
- "support": {
- "issues": "https://github.com/firebase/php-jwt/issues",
- "source": "https://github.com/firebase/php-jwt/tree/v6.10.0"
- },
- "install-path": "../firebase/php-jwt"
- },
- {
- "name": "google/apiclient",
- "version": "v2.15.3",
- "version_normalized": "2.15.3.0",
- "source": {
- "type": "git",
- "url": "https://github.com/googleapis/google-api-php-client.git",
- "reference": "e70273c06d18824de77e114247ae3102f8aec64d"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/googleapis/google-api-php-client/zipball/e70273c06d18824de77e114247ae3102f8aec64d",
- "reference": "e70273c06d18824de77e114247ae3102f8aec64d",
- "shasum": ""
- },
- "require": {
- "firebase/php-jwt": "~6.0",
- "google/apiclient-services": "~0.200",
- "google/auth": "^1.33",
- "guzzlehttp/guzzle": "^6.5.8||^7.4.5",
- "guzzlehttp/psr7": "^1.8.4||^2.2.1",
- "monolog/monolog": "^2.9||^3.0",
- "php": "^7.4|^8.0",
- "phpseclib/phpseclib": "^3.0.34"
- },
- "require-dev": {
- "cache/filesystem-adapter": "^1.1",
- "composer/composer": "^1.10.22",
- "phpcompatibility/php-compatibility": "^9.2",
- "phpspec/prophecy-phpunit": "^2.0",
- "phpunit/phpunit": "^9.5",
- "squizlabs/php_codesniffer": "^3.8",
- "symfony/css-selector": "~2.1",
- "symfony/dom-crawler": "~2.1"
- },
- "suggest": {
- "cache/filesystem-adapter": "For caching certs and tokens (using Google\\Client::setCache)"
- },
- "time": "2024-01-04T19:15:22+00:00",
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-main": "2.x-dev"
- }
- },
- "installation-source": "dist",
- "autoload": {
- "files": [
- "src/aliases.php"
- ],
- "psr-4": {
- "Google\\": "src/"
- },
- "classmap": [
- "src/aliases.php"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "Apache-2.0"
- ],
- "description": "Client library for Google APIs",
- "homepage": "http://developers.google.com/api-client-library/php",
- "keywords": [
- "google"
- ],
- "support": {
- "issues": "https://github.com/googleapis/google-api-php-client/issues",
- "source": "https://github.com/googleapis/google-api-php-client/tree/v2.15.3"
- },
- "install-path": "../google/apiclient"
- },
- {
- "name": "google/apiclient-services",
- "version": "v0.224.1",
- "version_normalized": "0.224.1.0",
- "source": {
- "type": "git",
- "url": "https://github.com/googleapis/google-api-php-client-services.git",
- "reference": "06e515176ebf32c3dcf7c01b3f377af6bfca6ae3"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/googleapis/google-api-php-client-services/zipball/06e515176ebf32c3dcf7c01b3f377af6bfca6ae3",
- "reference": "06e515176ebf32c3dcf7c01b3f377af6bfca6ae3",
- "shasum": ""
- },
- "require": {
- "php": ">=5.6"
- },
- "require-dev": {
- "phpunit/phpunit": "^5.7||^8.5.13"
- },
- "time": "2021-12-05T12:26:30+00:00",
- "type": "library",
- "installation-source": "dist",
- "autoload": {
- "files": [
- "autoload.php"
- ],
- "psr-4": {
- "Google\\Service\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "Apache-2.0"
- ],
- "description": "Client library for Google APIs",
- "homepage": "http://developers.google.com/api-client-library/php",
- "keywords": [
- "google"
- ],
- "support": {
- "issues": "https://github.com/googleapis/google-api-php-client-services/issues",
- "source": "https://github.com/googleapis/google-api-php-client-services/tree/v0.224.1"
- },
- "install-path": "../google/apiclient-services"
- },
- {
- "name": "google/auth",
- "version": "v1.34.0",
- "version_normalized": "1.34.0.0",
- "source": {
- "type": "git",
- "url": "https://github.com/googleapis/google-auth-library-php.git",
- "reference": "155daeadfd2f09743f611ea493b828d382519575"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/googleapis/google-auth-library-php/zipball/155daeadfd2f09743f611ea493b828d382519575",
- "reference": "155daeadfd2f09743f611ea493b828d382519575",
- "shasum": ""
- },
- "require": {
- "firebase/php-jwt": "^6.0",
- "guzzlehttp/guzzle": "^6.2.1|^7.0",
- "guzzlehttp/psr7": "^2.4.5",
- "php": "^7.4||^8.0",
- "psr/cache": "^1.0||^2.0||^3.0",
- "psr/http-message": "^1.1||^2.0"
- },
- "require-dev": {
- "guzzlehttp/promises": "^2.0",
- "kelvinmo/simplejwt": "0.7.1",
- "phpseclib/phpseclib": "^3.0",
- "phpspec/prophecy-phpunit": "^2.0",
- "phpunit/phpunit": "^9.0.0",
- "sebastian/comparator": ">=1.2.3",
- "squizlabs/php_codesniffer": "^3.5"
- },
- "suggest": {
- "phpseclib/phpseclib": "May be used in place of OpenSSL for signing strings or for token management. Please require version ^2."
- },
- "time": "2024-01-03T20:45:15+00:00",
- "type": "library",
- "installation-source": "dist",
- "autoload": {
- "psr-4": {
- "Google\\Auth\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "Apache-2.0"
- ],
- "description": "Google Auth Library for PHP",
- "homepage": "http://github.com/google/google-auth-library-php",
- "keywords": [
- "Authentication",
- "google",
- "oauth2"
- ],
- "support": {
- "docs": "https://googleapis.github.io/google-auth-library-php/main/",
- "issues": "https://github.com/googleapis/google-auth-library-php/issues",
- "source": "https://github.com/googleapis/google-auth-library-php/tree/v1.34.0"
- },
- "install-path": "../google/auth"
- },
- {
- "name": "guzzlehttp/guzzle",
- "version": "7.8.1",
- "version_normalized": "7.8.1.0",
- "source": {
- "type": "git",
- "url": "https://github.com/guzzle/guzzle.git",
- "reference": "41042bc7ab002487b876a0683fc8dce04ddce104"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/guzzle/guzzle/zipball/41042bc7ab002487b876a0683fc8dce04ddce104",
- "reference": "41042bc7ab002487b876a0683fc8dce04ddce104",
- "shasum": ""
- },
- "require": {
- "ext-json": "*",
- "guzzlehttp/promises": "^1.5.3 || ^2.0.1",
- "guzzlehttp/psr7": "^1.9.1 || ^2.5.1",
- "php": "^7.2.5 || ^8.0",
- "psr/http-client": "^1.0",
- "symfony/deprecation-contracts": "^2.2 || ^3.0"
- },
- "provide": {
- "psr/http-client-implementation": "1.0"
- },
- "require-dev": {
- "bamarni/composer-bin-plugin": "^1.8.2",
- "ext-curl": "*",
- "php-http/client-integration-tests": "dev-master#2c025848417c1135031fdf9c728ee53d0a7ceaee as 3.0.999",
- "php-http/message-factory": "^1.1",
- "phpunit/phpunit": "^8.5.36 || ^9.6.15",
- "psr/log": "^1.1 || ^2.0 || ^3.0"
- },
- "suggest": {
- "ext-curl": "Required for CURL handler support",
- "ext-intl": "Required for Internationalized Domain Name (IDN) support",
- "psr/log": "Required for using the Log middleware"
- },
- "time": "2023-12-03T20:35:24+00:00",
- "type": "library",
- "extra": {
- "bamarni-bin": {
- "bin-links": true,
- "forward-command": false
- }
- },
- "installation-source": "dist",
- "autoload": {
- "files": [
- "src/functions_include.php"
- ],
- "psr-4": {
- "GuzzleHttp\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Graham Campbell",
- "email": "hello@gjcampbell.co.uk",
- "homepage": "https://github.com/GrahamCampbell"
- },
- {
- "name": "Michael Dowling",
- "email": "mtdowling@gmail.com",
- "homepage": "https://github.com/mtdowling"
- },
- {
- "name": "Jeremy Lindblom",
- "email": "jeremeamia@gmail.com",
- "homepage": "https://github.com/jeremeamia"
- },
- {
- "name": "George Mponos",
- "email": "gmponos@gmail.com",
- "homepage": "https://github.com/gmponos"
- },
- {
- "name": "Tobias Nyholm",
- "email": "tobias.nyholm@gmail.com",
- "homepage": "https://github.com/Nyholm"
- },
- {
- "name": "Márk Sági-Kazár",
- "email": "mark.sagikazar@gmail.com",
- "homepage": "https://github.com/sagikazarmark"
- },
- {
- "name": "Tobias Schultze",
- "email": "webmaster@tubo-world.de",
- "homepage": "https://github.com/Tobion"
- }
- ],
- "description": "Guzzle is a PHP HTTP client library",
- "keywords": [
- "client",
- "curl",
- "framework",
- "http",
- "http client",
- "psr-18",
- "psr-7",
- "rest",
- "web service"
- ],
- "support": {
- "issues": "https://github.com/guzzle/guzzle/issues",
- "source": "https://github.com/guzzle/guzzle/tree/7.8.1"
- },
- "funding": [
- {
- "url": "https://github.com/GrahamCampbell",
- "type": "github"
- },
- {
- "url": "https://github.com/Nyholm",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle",
- "type": "tidelift"
- }
- ],
- "install-path": "../guzzlehttp/guzzle"
- },
- {
- "name": "guzzlehttp/promises",
- "version": "1.5.3",
- "version_normalized": "1.5.3.0",
- "source": {
- "type": "git",
- "url": "https://github.com/guzzle/promises.git",
- "reference": "67ab6e18aaa14d753cc148911d273f6e6cb6721e"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/guzzle/promises/zipball/67ab6e18aaa14d753cc148911d273f6e6cb6721e",
- "reference": "67ab6e18aaa14d753cc148911d273f6e6cb6721e",
- "shasum": ""
- },
- "require": {
- "php": ">=5.5"
- },
- "require-dev": {
- "symfony/phpunit-bridge": "^4.4 || ^5.1"
- },
- "time": "2023-05-21T12:31:43+00:00",
- "type": "library",
- "installation-source": "dist",
- "autoload": {
- "files": [
- "src/functions_include.php"
- ],
- "psr-4": {
- "GuzzleHttp\\Promise\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Graham Campbell",
- "email": "hello@gjcampbell.co.uk",
- "homepage": "https://github.com/GrahamCampbell"
- },
- {
- "name": "Michael Dowling",
- "email": "mtdowling@gmail.com",
- "homepage": "https://github.com/mtdowling"
- },
- {
- "name": "Tobias Nyholm",
- "email": "tobias.nyholm@gmail.com",
- "homepage": "https://github.com/Nyholm"
- },
- {
- "name": "Tobias Schultze",
- "email": "webmaster@tubo-world.de",
- "homepage": "https://github.com/Tobion"
- }
- ],
- "description": "Guzzle promises library",
- "keywords": [
- "promise"
- ],
- "support": {
- "issues": "https://github.com/guzzle/promises/issues",
- "source": "https://github.com/guzzle/promises/tree/1.5.3"
- },
- "funding": [
- {
- "url": "https://github.com/GrahamCampbell",
- "type": "github"
- },
- {
- "url": "https://github.com/Nyholm",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/promises",
- "type": "tidelift"
- }
- ],
- "install-path": "../guzzlehttp/promises"
- },
- {
- "name": "guzzlehttp/psr7",
- "version": "2.5.1",
- "version_normalized": "2.5.1.0",
- "source": {
- "type": "git",
- "url": "https://github.com/guzzle/psr7.git",
- "reference": "a0b3a03e8e8005257fbc408ce5f0fd0a8274dc7f"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/guzzle/psr7/zipball/a0b3a03e8e8005257fbc408ce5f0fd0a8274dc7f",
- "reference": "a0b3a03e8e8005257fbc408ce5f0fd0a8274dc7f",
- "shasum": ""
- },
- "require": {
- "php": "^7.2.5 || ^8.0",
- "psr/http-factory": "^1.0",
- "psr/http-message": "^1.1 || ^2.0",
- "ralouphie/getallheaders": "^3.0"
- },
- "provide": {
- "psr/http-factory-implementation": "1.0",
- "psr/http-message-implementation": "1.0"
- },
- "require-dev": {
- "bamarni/composer-bin-plugin": "^1.8.1",
- "http-interop/http-factory-tests": "^0.9",
- "phpunit/phpunit": "^8.5.29 || ^9.5.23"
- },
- "suggest": {
- "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses"
- },
- "time": "2023-08-03T15:02:42+00:00",
- "type": "library",
- "extra": {
- "bamarni-bin": {
- "bin-links": true,
- "forward-command": false
- }
- },
- "installation-source": "dist",
- "autoload": {
- "psr-4": {
- "GuzzleHttp\\Psr7\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Graham Campbell",
- "email": "hello@gjcampbell.co.uk",
- "homepage": "https://github.com/GrahamCampbell"
- },
- {
- "name": "Michael Dowling",
- "email": "mtdowling@gmail.com",
- "homepage": "https://github.com/mtdowling"
- },
- {
- "name": "George Mponos",
- "email": "gmponos@gmail.com",
- "homepage": "https://github.com/gmponos"
- },
- {
- "name": "Tobias Nyholm",
- "email": "tobias.nyholm@gmail.com",
- "homepage": "https://github.com/Nyholm"
- },
- {
- "name": "Márk Sági-Kazár",
- "email": "mark.sagikazar@gmail.com",
- "homepage": "https://github.com/sagikazarmark"
- },
- {
- "name": "Tobias Schultze",
- "email": "webmaster@tubo-world.de",
- "homepage": "https://github.com/Tobion"
- },
- {
- "name": "Márk Sági-Kazár",
- "email": "mark.sagikazar@gmail.com",
- "homepage": "https://sagikazarmark.hu"
- }
- ],
- "description": "PSR-7 message implementation that also provides common utility methods",
- "keywords": [
- "http",
- "message",
- "psr-7",
- "request",
- "response",
- "stream",
- "uri",
- "url"
- ],
- "support": {
- "issues": "https://github.com/guzzle/psr7/issues",
- "source": "https://github.com/guzzle/psr7/tree/2.5.1"
- },
- "funding": [
- {
- "url": "https://github.com/GrahamCampbell",
- "type": "github"
- },
- {
- "url": "https://github.com/Nyholm",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7",
- "type": "tidelift"
- }
- ],
- "install-path": "../guzzlehttp/psr7"
- },
- {
- "name": "paragonie/constant_time_encoding",
- "version": "v2.6.3",
- "version_normalized": "2.6.3.0",
- "source": {
- "type": "git",
- "url": "https://github.com/paragonie/constant_time_encoding.git",
- "reference": "58c3f47f650c94ec05a151692652a868995d2938"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/58c3f47f650c94ec05a151692652a868995d2938",
- "reference": "58c3f47f650c94ec05a151692652a868995d2938",
- "shasum": ""
- },
- "require": {
- "php": "^7|^8"
- },
- "require-dev": {
- "phpunit/phpunit": "^6|^7|^8|^9",
- "vimeo/psalm": "^1|^2|^3|^4"
- },
- "time": "2022-06-14T06:56:20+00:00",
- "type": "library",
- "installation-source": "dist",
- "autoload": {
- "psr-4": {
- "ParagonIE\\ConstantTime\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Paragon Initiative Enterprises",
- "email": "security@paragonie.com",
- "homepage": "https://paragonie.com",
- "role": "Maintainer"
- },
- {
- "name": "Steve 'Sc00bz' Thomas",
- "email": "steve@tobtu.com",
- "homepage": "https://www.tobtu.com",
- "role": "Original Developer"
- }
- ],
- "description": "Constant-time Implementations of RFC 4648 Encoding (Base-64, Base-32, Base-16)",
- "keywords": [
- "base16",
- "base32",
- "base32_decode",
- "base32_encode",
- "base64",
- "base64_decode",
- "base64_encode",
- "bin2hex",
- "encoding",
- "hex",
- "hex2bin",
- "rfc4648"
- ],
- "support": {
- "email": "info@paragonie.com",
- "issues": "https://github.com/paragonie/constant_time_encoding/issues",
- "source": "https://github.com/paragonie/constant_time_encoding"
- },
- "install-path": "../paragonie/constant_time_encoding"
- },
- {
- "name": "paragonie/random_compat",
- "version": "v9.99.100",
- "version_normalized": "9.99.100.0",
- "source": {
- "type": "git",
- "url": "https://github.com/paragonie/random_compat.git",
- "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/paragonie/random_compat/zipball/996434e5492cb4c3edcb9168db6fbb1359ef965a",
- "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a",
- "shasum": ""
- },
- "require": {
- "php": ">= 7"
- },
- "require-dev": {
- "phpunit/phpunit": "4.*|5.*",
- "vimeo/psalm": "^1"
- },
- "suggest": {
- "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes."
- },
- "time": "2020-10-15T08:29:30+00:00",
- "type": "library",
- "installation-source": "dist",
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Paragon Initiative Enterprises",
- "email": "security@paragonie.com",
- "homepage": "https://paragonie.com"
- }
- ],
- "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7",
- "keywords": [
- "csprng",
- "polyfill",
- "pseudorandom",
- "random"
- ],
- "support": {
- "email": "info@paragonie.com",
- "issues": "https://github.com/paragonie/random_compat/issues",
- "source": "https://github.com/paragonie/random_compat"
- },
- "install-path": "../paragonie/random_compat"
- },
- {
- "name": "phpseclib/phpseclib",
- "version": "3.0.36",
- "version_normalized": "3.0.36.0",
- "source": {
- "type": "git",
- "url": "https://github.com/phpseclib/phpseclib.git",
- "reference": "c2fb5136162d4be18fdd4da9980696f3aee96d7b"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/c2fb5136162d4be18fdd4da9980696f3aee96d7b",
- "reference": "c2fb5136162d4be18fdd4da9980696f3aee96d7b",
- "shasum": ""
- },
- "require": {
- "paragonie/constant_time_encoding": "^1|^2",
- "paragonie/random_compat": "^1.4|^2.0|^9.99.99",
- "php": ">=5.6.1"
- },
- "require-dev": {
- "phpunit/phpunit": "*"
- },
- "suggest": {
- "ext-dom": "Install the DOM extension to load XML formatted public keys.",
- "ext-gmp": "Install the GMP (GNU Multiple Precision) extension in order to speed up arbitrary precision integer arithmetic operations.",
- "ext-libsodium": "SSH2/SFTP can make use of some algorithms provided by the libsodium-php extension.",
- "ext-mcrypt": "Install the Mcrypt extension in order to speed up a few other cryptographic operations.",
- "ext-openssl": "Install the OpenSSL extension in order to speed up a wide variety of cryptographic operations."
- },
- "time": "2024-02-26T05:13:14+00:00",
- "type": "library",
- "installation-source": "dist",
- "autoload": {
- "files": [
- "phpseclib/bootstrap.php"
- ],
- "psr-4": {
- "phpseclib3\\": "phpseclib/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Jim Wigginton",
- "email": "terrafrost@php.net",
- "role": "Lead Developer"
- },
- {
- "name": "Patrick Monnerat",
- "email": "pm@datasphere.ch",
- "role": "Developer"
- },
- {
- "name": "Andreas Fischer",
- "email": "bantu@phpbb.com",
- "role": "Developer"
- },
- {
- "name": "Hans-Jürgen Petrich",
- "email": "petrich@tronic-media.com",
- "role": "Developer"
- },
- {
- "name": "Graham Campbell",
- "email": "graham@alt-three.com",
- "role": "Developer"
- }
- ],
- "description": "PHP Secure Communications Library - Pure-PHP implementations of RSA, AES, SSH2, SFTP, X.509 etc.",
- "homepage": "http://phpseclib.sourceforge.net",
- "keywords": [
- "BigInteger",
- "aes",
- "asn.1",
- "asn1",
- "blowfish",
- "crypto",
- "cryptography",
- "encryption",
- "rsa",
- "security",
- "sftp",
- "signature",
- "signing",
- "ssh",
- "twofish",
- "x.509",
- "x509"
- ],
- "support": {
- "issues": "https://github.com/phpseclib/phpseclib/issues",
- "source": "https://github.com/phpseclib/phpseclib/tree/3.0.36"
- },
- "funding": [
- {
- "url": "https://github.com/terrafrost",
- "type": "github"
- },
- {
- "url": "https://www.patreon.com/phpseclib",
- "type": "patreon"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/phpseclib/phpseclib",
- "type": "tidelift"
- }
- ],
- "install-path": "../phpseclib/phpseclib"
- },
- {
- "name": "psr/cache",
- "version": "1.0.1",
- "version_normalized": "1.0.1.0",
- "source": {
- "type": "git",
- "url": "https://github.com/php-fig/cache.git",
- "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/php-fig/cache/zipball/d11b50ad223250cf17b86e38383413f5a6764bf8",
- "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8",
- "shasum": ""
- },
- "require": {
- "php": ">=5.3.0"
- },
- "time": "2016-08-06T20:24:11+00:00",
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "1.0.x-dev"
- }
- },
- "installation-source": "dist",
- "autoload": {
- "psr-4": {
- "Psr\\Cache\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "PHP-FIG",
- "homepage": "http://www.php-fig.org/"
- }
- ],
- "description": "Common interface for caching libraries",
- "keywords": [
- "cache",
- "psr",
- "psr-6"
- ],
- "support": {
- "source": "https://github.com/php-fig/cache/tree/master"
- },
- "install-path": "../psr/cache"
- },
- {
- "name": "psr/http-client",
- "version": "1.0.3",
- "version_normalized": "1.0.3.0",
- "source": {
- "type": "git",
- "url": "https://github.com/php-fig/http-client.git",
- "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/php-fig/http-client/zipball/bb5906edc1c324c9a05aa0873d40117941e5fa90",
- "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90",
- "shasum": ""
- },
- "require": {
- "php": "^7.0 || ^8.0",
- "psr/http-message": "^1.0 || ^2.0"
- },
- "time": "2023-09-23T14:17:50+00:00",
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "1.0.x-dev"
- }
- },
- "installation-source": "dist",
- "autoload": {
- "psr-4": {
- "Psr\\Http\\Client\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "PHP-FIG",
- "homepage": "https://www.php-fig.org/"
- }
- ],
- "description": "Common interface for HTTP clients",
- "homepage": "https://github.com/php-fig/http-client",
- "keywords": [
- "http",
- "http-client",
- "psr",
- "psr-18"
- ],
- "support": {
- "source": "https://github.com/php-fig/http-client"
- },
- "install-path": "../psr/http-client"
- },
- {
- "name": "psr/http-factory",
- "version": "1.0.2",
- "version_normalized": "1.0.2.0",
- "source": {
- "type": "git",
- "url": "https://github.com/php-fig/http-factory.git",
- "reference": "e616d01114759c4c489f93b099585439f795fe35"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/php-fig/http-factory/zipball/e616d01114759c4c489f93b099585439f795fe35",
- "reference": "e616d01114759c4c489f93b099585439f795fe35",
- "shasum": ""
- },
- "require": {
- "php": ">=7.0.0",
- "psr/http-message": "^1.0 || ^2.0"
- },
- "time": "2023-04-10T20:10:41+00:00",
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "1.0.x-dev"
- }
- },
- "installation-source": "dist",
- "autoload": {
- "psr-4": {
- "Psr\\Http\\Message\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "PHP-FIG",
- "homepage": "https://www.php-fig.org/"
- }
- ],
- "description": "Common interfaces for PSR-7 HTTP message factories",
- "keywords": [
- "factory",
- "http",
- "message",
- "psr",
- "psr-17",
- "psr-7",
- "request",
- "response"
- ],
- "support": {
- "source": "https://github.com/php-fig/http-factory/tree/1.0.2"
- },
- "install-path": "../psr/http-factory"
- },
- {
- "name": "psr/http-message",
- "version": "2.0",
- "version_normalized": "2.0.0.0",
- "source": {
- "type": "git",
- "url": "https://github.com/php-fig/http-message.git",
- "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/php-fig/http-message/zipball/402d35bcb92c70c026d1a6a9883f06b2ead23d71",
- "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71",
- "shasum": ""
- },
- "require": {
- "php": "^7.2 || ^8.0"
- },
- "time": "2023-04-04T09:54:51+00:00",
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "2.0.x-dev"
- }
- },
- "installation-source": "dist",
- "autoload": {
- "psr-4": {
- "Psr\\Http\\Message\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "PHP-FIG",
- "homepage": "https://www.php-fig.org/"
- }
- ],
- "description": "Common interface for HTTP messages",
- "homepage": "https://github.com/php-fig/http-message",
- "keywords": [
- "http",
- "http-message",
- "psr",
- "psr-7",
- "request",
- "response"
- ],
- "support": {
- "source": "https://github.com/php-fig/http-message/tree/2.0"
- },
- "install-path": "../psr/http-message"
- },
- {
- "name": "ralouphie/getallheaders",
- "version": "3.0.3",
- "version_normalized": "3.0.3.0",
- "source": {
- "type": "git",
- "url": "https://github.com/ralouphie/getallheaders.git",
- "reference": "120b605dfeb996808c31b6477290a714d356e822"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822",
- "reference": "120b605dfeb996808c31b6477290a714d356e822",
- "shasum": ""
- },
- "require": {
- "php": ">=5.6"
- },
- "require-dev": {
- "php-coveralls/php-coveralls": "^2.1",
- "phpunit/phpunit": "^5 || ^6.5"
- },
- "time": "2019-03-08T08:55:37+00:00",
- "type": "library",
- "installation-source": "dist",
- "autoload": {
- "files": [
- "src/getallheaders.php"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Ralph Khattar",
- "email": "ralph.khattar@gmail.com"
- }
- ],
- "description": "A polyfill for getallheaders.",
- "support": {
- "issues": "https://github.com/ralouphie/getallheaders/issues",
- "source": "https://github.com/ralouphie/getallheaders/tree/develop"
- },
- "install-path": "../ralouphie/getallheaders"
- },
- {
- "name": "symfony/deprecation-contracts",
- "version": "v3.4.0",
- "version_normalized": "3.4.0.0",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/deprecation-contracts.git",
- "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/7c3aff79d10325257a001fcf92d991f24fc967cf",
- "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf",
- "shasum": ""
- },
- "require": {
- "php": ">=8.1"
- },
- "time": "2023-05-23T14:45:45+00:00",
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-main": "3.4-dev"
- },
- "thanks": {
- "name": "symfony/contracts",
- "url": "https://github.com/symfony/contracts"
- }
- },
- "installation-source": "dist",
- "autoload": {
- "files": [
- "function.php"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Nicolas Grekas",
- "email": "p@tchwork.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "https://symfony.com/contributors"
- }
- ],
- "description": "A generic function and convention to trigger deprecation notices",
- "homepage": "https://symfony.com",
- "support": {
- "source": "https://github.com/symfony/deprecation-contracts/tree/v3.4.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"
- }
- ],
- "install-path": "../symfony/deprecation-contracts"
- }
- ],
- "dev": true,
- "dev-package-names": []
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/composer/installed.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/composer/installed.php
deleted file mode 100644
index 749765b..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/composer/installed.php
+++ /dev/null
@@ -1,197 +0,0 @@
- array(
- 'name' => '__root__',
- 'pretty_version' => 'dev-5.x-dev',
- 'version' => 'dev-5.x-dev',
- 'reference' => 'c8681aedeabf58cf88284235a697df3ca885ff99',
- 'type' => 'library',
- 'install_path' => __DIR__ . '/../../',
- 'aliases' => array(),
- 'dev' => true,
- ),
- 'versions' => array(
- '__root__' => array(
- 'pretty_version' => 'dev-5.x-dev',
- 'version' => 'dev-5.x-dev',
- 'reference' => 'c8681aedeabf58cf88284235a697df3ca885ff99',
- 'type' => 'library',
- 'install_path' => __DIR__ . '/../../',
- 'aliases' => array(),
- 'dev_requirement' => false,
- ),
- 'firebase/php-jwt' => array(
- 'pretty_version' => 'v6.10.0',
- 'version' => '6.10.0.0',
- 'reference' => 'a49db6f0a5033aef5143295342f1c95521b075ff',
- 'type' => 'library',
- 'install_path' => __DIR__ . '/../firebase/php-jwt',
- 'aliases' => array(),
- 'dev_requirement' => false,
- ),
- 'google/apiclient' => array(
- 'pretty_version' => 'v2.15.3',
- 'version' => '2.15.3.0',
- 'reference' => 'e70273c06d18824de77e114247ae3102f8aec64d',
- 'type' => 'library',
- 'install_path' => __DIR__ . '/../google/apiclient',
- 'aliases' => array(),
- 'dev_requirement' => false,
- ),
- 'google/apiclient-services' => array(
- 'pretty_version' => 'v0.224.1',
- 'version' => '0.224.1.0',
- 'reference' => '06e515176ebf32c3dcf7c01b3f377af6bfca6ae3',
- 'type' => 'library',
- 'install_path' => __DIR__ . '/../google/apiclient-services',
- 'aliases' => array(),
- 'dev_requirement' => false,
- ),
- 'google/auth' => array(
- 'pretty_version' => 'v1.34.0',
- 'version' => '1.34.0.0',
- 'reference' => '155daeadfd2f09743f611ea493b828d382519575',
- 'type' => 'library',
- 'install_path' => __DIR__ . '/../google/auth',
- 'aliases' => array(),
- 'dev_requirement' => false,
- ),
- 'guzzlehttp/guzzle' => array(
- 'pretty_version' => '7.8.1',
- 'version' => '7.8.1.0',
- 'reference' => '41042bc7ab002487b876a0683fc8dce04ddce104',
- 'type' => 'library',
- 'install_path' => __DIR__ . '/../guzzlehttp/guzzle',
- 'aliases' => array(),
- 'dev_requirement' => false,
- ),
- 'guzzlehttp/promises' => array(
- 'pretty_version' => '1.5.3',
- 'version' => '1.5.3.0',
- 'reference' => '67ab6e18aaa14d753cc148911d273f6e6cb6721e',
- 'type' => 'library',
- 'install_path' => __DIR__ . '/../guzzlehttp/promises',
- 'aliases' => array(),
- 'dev_requirement' => false,
- ),
- 'guzzlehttp/psr7' => array(
- 'pretty_version' => '2.5.1',
- 'version' => '2.5.1.0',
- 'reference' => 'a0b3a03e8e8005257fbc408ce5f0fd0a8274dc7f',
- 'type' => 'library',
- 'install_path' => __DIR__ . '/../guzzlehttp/psr7',
- 'aliases' => array(),
- 'dev_requirement' => false,
- ),
- 'monolog/monolog' => array(
- 'dev_requirement' => false,
- 'replaced' => array(
- 0 => '*',
- ),
- ),
- 'paragonie/constant_time_encoding' => array(
- 'pretty_version' => 'v2.6.3',
- 'version' => '2.6.3.0',
- 'reference' => '58c3f47f650c94ec05a151692652a868995d2938',
- 'type' => 'library',
- 'install_path' => __DIR__ . '/../paragonie/constant_time_encoding',
- 'aliases' => array(),
- 'dev_requirement' => false,
- ),
- 'paragonie/random_compat' => array(
- 'pretty_version' => 'v9.99.100',
- 'version' => '9.99.100.0',
- 'reference' => '996434e5492cb4c3edcb9168db6fbb1359ef965a',
- 'type' => 'library',
- 'install_path' => __DIR__ . '/../paragonie/random_compat',
- 'aliases' => array(),
- 'dev_requirement' => false,
- ),
- 'phpseclib/phpseclib' => array(
- 'pretty_version' => '3.0.36',
- 'version' => '3.0.36.0',
- 'reference' => 'c2fb5136162d4be18fdd4da9980696f3aee96d7b',
- 'type' => 'library',
- 'install_path' => __DIR__ . '/../phpseclib/phpseclib',
- 'aliases' => array(),
- 'dev_requirement' => false,
- ),
- 'psr/cache' => array(
- 'pretty_version' => '1.0.1',
- 'version' => '1.0.1.0',
- 'reference' => 'd11b50ad223250cf17b86e38383413f5a6764bf8',
- 'type' => 'library',
- 'install_path' => __DIR__ . '/../psr/cache',
- 'aliases' => array(),
- 'dev_requirement' => false,
- ),
- 'psr/http-client' => array(
- 'pretty_version' => '1.0.3',
- 'version' => '1.0.3.0',
- 'reference' => 'bb5906edc1c324c9a05aa0873d40117941e5fa90',
- 'type' => 'library',
- 'install_path' => __DIR__ . '/../psr/http-client',
- 'aliases' => array(),
- 'dev_requirement' => false,
- ),
- 'psr/http-client-implementation' => array(
- 'dev_requirement' => false,
- 'provided' => array(
- 0 => '1.0',
- ),
- ),
- 'psr/http-factory' => array(
- 'pretty_version' => '1.0.2',
- 'version' => '1.0.2.0',
- 'reference' => 'e616d01114759c4c489f93b099585439f795fe35',
- 'type' => 'library',
- 'install_path' => __DIR__ . '/../psr/http-factory',
- 'aliases' => array(),
- 'dev_requirement' => false,
- ),
- 'psr/http-factory-implementation' => array(
- 'dev_requirement' => false,
- 'provided' => array(
- 0 => '1.0',
- ),
- ),
- 'psr/http-message' => array(
- 'pretty_version' => '2.0',
- 'version' => '2.0.0.0',
- 'reference' => '402d35bcb92c70c026d1a6a9883f06b2ead23d71',
- 'type' => 'library',
- 'install_path' => __DIR__ . '/../psr/http-message',
- 'aliases' => array(),
- 'dev_requirement' => false,
- ),
- 'psr/http-message-implementation' => array(
- 'dev_requirement' => false,
- 'provided' => array(
- 0 => '1.0',
- ),
- ),
- 'psr/log' => array(
- 'dev_requirement' => false,
- 'replaced' => array(
- 0 => '*',
- ),
- ),
- 'ralouphie/getallheaders' => array(
- 'pretty_version' => '3.0.3',
- 'version' => '3.0.3.0',
- 'reference' => '120b605dfeb996808c31b6477290a714d356e822',
- 'type' => 'library',
- 'install_path' => __DIR__ . '/../ralouphie/getallheaders',
- 'aliases' => array(),
- 'dev_requirement' => false,
- ),
- 'symfony/deprecation-contracts' => array(
- 'pretty_version' => 'v3.4.0',
- 'version' => '3.4.0.0',
- 'reference' => '7c3aff79d10325257a001fcf92d991f24fc967cf',
- 'type' => 'library',
- 'install_path' => __DIR__ . '/../symfony/deprecation-contracts',
- 'aliases' => array(),
- 'dev_requirement' => false,
- ),
- ),
-);
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/firebase/php-jwt/LICENSE b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/firebase/php-jwt/LICENSE
deleted file mode 100644
index 11c0146..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/firebase/php-jwt/LICENSE
+++ /dev/null
@@ -1,30 +0,0 @@
-Copyright (c) 2011, Neuman Vong
-
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
-
- * Redistributions in binary form must reproduce the above
- copyright notice, this list of conditions and the following
- disclaimer in the documentation and/or other materials provided
- with the distribution.
-
- * Neither the name of the copyright holder nor the names of other
- 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/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/firebase/php-jwt/src/BeforeValidException.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/firebase/php-jwt/src/BeforeValidException.php
deleted file mode 100644
index abe5695..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/firebase/php-jwt/src/BeforeValidException.php
+++ /dev/null
@@ -1,19 +0,0 @@
-payload = $payload;
- }
- public function getPayload() : object
- {
- return $this->payload;
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/firebase/php-jwt/src/CachedKeySet.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/firebase/php-jwt/src/CachedKeySet.php
deleted file mode 100644
index 0c088e6..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/firebase/php-jwt/src/CachedKeySet.php
+++ /dev/null
@@ -1,226 +0,0 @@
-
- */
-class CachedKeySet implements ArrayAccess
-{
- /**
- * @var string
- */
- private $jwksUri;
- /**
- * @var ClientInterface
- */
- private $httpClient;
- /**
- * @var RequestFactoryInterface
- */
- private $httpFactory;
- /**
- * @var CacheItemPoolInterface
- */
- private $cache;
- /**
- * @var ?int
- */
- private $expiresAfter;
- /**
- * @var ?CacheItemInterface
- */
- private $cacheItem;
- /**
- * @var array>
- */
- private $keySet;
- /**
- * @var string
- */
- private $cacheKey;
- /**
- * @var string
- */
- private $cacheKeyPrefix = 'jwks';
- /**
- * @var int
- */
- private $maxKeyLength = 64;
- /**
- * @var bool
- */
- private $rateLimit;
- /**
- * @var string
- */
- private $rateLimitCacheKey;
- /**
- * @var int
- */
- private $maxCallsPerMinute = 10;
- /**
- * @var string|null
- */
- private $defaultAlg;
- public function __construct(string $jwksUri, ClientInterface $httpClient, RequestFactoryInterface $httpFactory, CacheItemPoolInterface $cache, int $expiresAfter = null, bool $rateLimit = \false, string $defaultAlg = null)
- {
- $this->jwksUri = $jwksUri;
- $this->httpClient = $httpClient;
- $this->httpFactory = $httpFactory;
- $this->cache = $cache;
- $this->expiresAfter = $expiresAfter;
- $this->rateLimit = $rateLimit;
- $this->defaultAlg = $defaultAlg;
- $this->setCacheKeys();
- }
- /**
- * @param string $keyId
- * @return Key
- */
- public function offsetGet($keyId) : Key
- {
- if (!$this->keyIdExists($keyId)) {
- throw new OutOfBoundsException('Key ID not found');
- }
- return JWK::parseKey($this->keySet[$keyId], $this->defaultAlg);
- }
- /**
- * @param string $keyId
- * @return bool
- */
- public function offsetExists($keyId) : bool
- {
- return $this->keyIdExists($keyId);
- }
- /**
- * @param string $offset
- * @param Key $value
- */
- public function offsetSet($offset, $value) : void
- {
- throw new LogicException('Method not implemented');
- }
- /**
- * @param string $offset
- */
- public function offsetUnset($offset) : void
- {
- throw new LogicException('Method not implemented');
- }
- /**
- * @return array
- */
- private function formatJwksForCache(string $jwks) : array
- {
- $jwks = json_decode($jwks, \true);
- if (!isset($jwks['keys'])) {
- throw new UnexpectedValueException('"keys" member must exist in the JWK Set');
- }
- if (empty($jwks['keys'])) {
- throw new InvalidArgumentException('JWK Set did not contain any keys');
- }
- $keys = [];
- foreach ($jwks['keys'] as $k => $v) {
- $kid = isset($v['kid']) ? $v['kid'] : $k;
- $keys[(string) $kid] = $v;
- }
- return $keys;
- }
- private function keyIdExists(string $keyId) : bool
- {
- if (null === $this->keySet) {
- $item = $this->getCacheItem();
- // Try to load keys from cache
- if ($item->isHit()) {
- // item found! retrieve it
- $this->keySet = $item->get();
- // If the cached item is a string, the JWKS response was cached (previous behavior).
- // Parse this into expected format array instead.
- if (\is_string($this->keySet)) {
- $this->keySet = $this->formatJwksForCache($this->keySet);
- }
- }
- }
- if (!isset($this->keySet[$keyId])) {
- if ($this->rateLimitExceeded()) {
- return \false;
- }
- $request = $this->httpFactory->createRequest('GET', $this->jwksUri);
- $jwksResponse = $this->httpClient->sendRequest($request);
- if ($jwksResponse->getStatusCode() !== 200) {
- throw new UnexpectedValueException(sprintf('HTTP Error: %d %s for URI "%s"', $jwksResponse->getStatusCode(), $jwksResponse->getReasonPhrase(), $this->jwksUri), $jwksResponse->getStatusCode());
- }
- $this->keySet = $this->formatJwksForCache((string) $jwksResponse->getBody());
- if (!isset($this->keySet[$keyId])) {
- return \false;
- }
- $item = $this->getCacheItem();
- $item->set($this->keySet);
- if ($this->expiresAfter) {
- $item->expiresAfter($this->expiresAfter);
- }
- $this->cache->save($item);
- }
- return \true;
- }
- private function rateLimitExceeded() : bool
- {
- if (!$this->rateLimit) {
- return \false;
- }
- $cacheItem = $this->cache->getItem($this->rateLimitCacheKey);
- if (!$cacheItem->isHit()) {
- $cacheItem->expiresAfter(1);
- // # of calls are cached each minute
- }
- $callsPerMinute = (int) $cacheItem->get();
- if (++$callsPerMinute > $this->maxCallsPerMinute) {
- return \true;
- }
- $cacheItem->set($callsPerMinute);
- $this->cache->save($cacheItem);
- return \false;
- }
- private function getCacheItem() : CacheItemInterface
- {
- if (\is_null($this->cacheItem)) {
- $this->cacheItem = $this->cache->getItem($this->cacheKey);
- }
- return $this->cacheItem;
- }
- private function setCacheKeys() : void
- {
- if (empty($this->jwksUri)) {
- throw new RuntimeException('JWKS URI is empty');
- }
- // ensure we do not have illegal characters
- $key = preg_replace('|[^a-zA-Z0-9_\\.!]|', '', $this->jwksUri);
- // add prefix
- $key = $this->cacheKeyPrefix . $key;
- // Hash keys if they exceed $maxKeyLength of 64
- if (\strlen($key) > $this->maxKeyLength) {
- $key = substr(hash('sha256', $key), 0, $this->maxKeyLength);
- }
- $this->cacheKey = $key;
- if ($this->rateLimit) {
- // add prefix
- $rateLimitKey = $this->cacheKeyPrefix . 'ratelimit' . $key;
- // Hash keys if they exceed $maxKeyLength of 64
- if (\strlen($rateLimitKey) > $this->maxKeyLength) {
- $rateLimitKey = substr(hash('sha256', $rateLimitKey), 0, $this->maxKeyLength);
- }
- $this->rateLimitCacheKey = $rateLimitKey;
- }
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/firebase/php-jwt/src/ExpiredException.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/firebase/php-jwt/src/ExpiredException.php
deleted file mode 100644
index 3525011..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/firebase/php-jwt/src/ExpiredException.php
+++ /dev/null
@@ -1,19 +0,0 @@
-payload = $payload;
- }
- public function getPayload() : object
- {
- return $this->payload;
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/firebase/php-jwt/src/JWK.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/firebase/php-jwt/src/JWK.php
deleted file mode 100644
index 680053c..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/firebase/php-jwt/src/JWK.php
+++ /dev/null
@@ -1,267 +0,0 @@
-
- * @license http://opensource.org/licenses/BSD-3-Clause 3-clause BSD
- * @link https://github.com/firebase/php-jwt
- */
-class JWK
-{
- private const OID = '1.2.840.10045.2.1';
- private const ASN1_OBJECT_IDENTIFIER = 0x6;
- private const ASN1_SEQUENCE = 0x10;
- // also defined in JWT
- private const ASN1_BIT_STRING = 0x3;
- private const EC_CURVES = [
- 'P-256' => '1.2.840.10045.3.1.7',
- // Len: 64
- 'secp256k1' => '1.3.132.0.10',
- // Len: 64
- 'P-384' => '1.3.132.0.34',
- ];
- // For keys with "kty" equal to "OKP" (Octet Key Pair), the "crv" parameter must contain the key subtype.
- // This library supports the following subtypes:
- private const OKP_SUBTYPES = ['Ed25519' => \true];
- /**
- * Parse a set of JWK keys
- *
- * @param array $jwks The JSON Web Key Set as an associative array
- * @param string $defaultAlg The algorithm for the Key object if "alg" is not set in the
- * JSON Web Key Set
- *
- * @return array An associative array of key IDs (kid) to Key objects
- *
- * @throws InvalidArgumentException Provided JWK Set is empty
- * @throws UnexpectedValueException Provided JWK Set was invalid
- * @throws DomainException OpenSSL failure
- *
- * @uses parseKey
- */
- public static function parseKeySet(array $jwks, string $defaultAlg = null) : array
- {
- $keys = [];
- if (!isset($jwks['keys'])) {
- throw new UnexpectedValueException('"keys" member must exist in the JWK Set');
- }
- if (empty($jwks['keys'])) {
- throw new InvalidArgumentException('JWK Set did not contain any keys');
- }
- foreach ($jwks['keys'] as $k => $v) {
- $kid = isset($v['kid']) ? $v['kid'] : $k;
- if ($key = self::parseKey($v, $defaultAlg)) {
- $keys[(string) $kid] = $key;
- }
- }
- if (0 === \count($keys)) {
- throw new UnexpectedValueException('No supported algorithms found in JWK Set');
- }
- return $keys;
- }
- /**
- * Parse a JWK key
- *
- * @param array $jwk An individual JWK
- * @param string $defaultAlg The algorithm for the Key object if "alg" is not set in the
- * JSON Web Key Set
- *
- * @return Key The key object for the JWK
- *
- * @throws InvalidArgumentException Provided JWK is empty
- * @throws UnexpectedValueException Provided JWK was invalid
- * @throws DomainException OpenSSL failure
- *
- * @uses createPemFromModulusAndExponent
- */
- public static function parseKey(array $jwk, string $defaultAlg = null) : ?Key
- {
- if (empty($jwk)) {
- throw new InvalidArgumentException('JWK must not be empty');
- }
- if (!isset($jwk['kty'])) {
- throw new UnexpectedValueException('JWK must contain a "kty" parameter');
- }
- if (!isset($jwk['alg'])) {
- if (\is_null($defaultAlg)) {
- // The "alg" parameter is optional in a KTY, but an algorithm is required
- // for parsing in this library. Use the $defaultAlg parameter when parsing the
- // key set in order to prevent this error.
- // @see https://datatracker.ietf.org/doc/html/rfc7517#section-4.4
- throw new UnexpectedValueException('JWK must contain an "alg" parameter');
- }
- $jwk['alg'] = $defaultAlg;
- }
- switch ($jwk['kty']) {
- case 'RSA':
- if (!empty($jwk['d'])) {
- throw new UnexpectedValueException('RSA private keys are not supported');
- }
- if (!isset($jwk['n']) || !isset($jwk['e'])) {
- throw new UnexpectedValueException('RSA keys must contain values for both "n" and "e"');
- }
- $pem = self::createPemFromModulusAndExponent($jwk['n'], $jwk['e']);
- $publicKey = \openssl_pkey_get_public($pem);
- if (\false === $publicKey) {
- throw new DomainException('OpenSSL error: ' . \openssl_error_string());
- }
- return new Key($publicKey, $jwk['alg']);
- case 'EC':
- if (isset($jwk['d'])) {
- // The key is actually a private key
- throw new UnexpectedValueException('Key data must be for a public key');
- }
- if (empty($jwk['crv'])) {
- throw new UnexpectedValueException('crv not set');
- }
- if (!isset(self::EC_CURVES[$jwk['crv']])) {
- throw new DomainException('Unrecognised or unsupported EC curve');
- }
- if (empty($jwk['x']) || empty($jwk['y'])) {
- throw new UnexpectedValueException('x and y not set');
- }
- $publicKey = self::createPemFromCrvAndXYCoordinates($jwk['crv'], $jwk['x'], $jwk['y']);
- return new Key($publicKey, $jwk['alg']);
- case 'OKP':
- if (isset($jwk['d'])) {
- // The key is actually a private key
- throw new UnexpectedValueException('Key data must be for a public key');
- }
- if (!isset($jwk['crv'])) {
- throw new UnexpectedValueException('crv not set');
- }
- if (empty(self::OKP_SUBTYPES[$jwk['crv']])) {
- throw new DomainException('Unrecognised or unsupported OKP key subtype');
- }
- if (empty($jwk['x'])) {
- throw new UnexpectedValueException('x not set');
- }
- // This library works internally with EdDSA keys (Ed25519) encoded in standard base64.
- $publicKey = JWT::convertBase64urlToBase64($jwk['x']);
- return new Key($publicKey, $jwk['alg']);
- default:
- break;
- }
- return null;
- }
- /**
- * Converts the EC JWK values to pem format.
- *
- * @param string $crv The EC curve (only P-256 & P-384 is supported)
- * @param string $x The EC x-coordinate
- * @param string $y The EC y-coordinate
- *
- * @return string
- */
- private static function createPemFromCrvAndXYCoordinates(string $crv, string $x, string $y) : string
- {
- $pem = self::encodeDER(self::ASN1_SEQUENCE, self::encodeDER(self::ASN1_SEQUENCE, self::encodeDER(self::ASN1_OBJECT_IDENTIFIER, self::encodeOID(self::OID)) . self::encodeDER(self::ASN1_OBJECT_IDENTIFIER, self::encodeOID(self::EC_CURVES[$crv]))) . self::encodeDER(self::ASN1_BIT_STRING, \chr(0x0) . \chr(0x4) . JWT::urlsafeB64Decode($x) . JWT::urlsafeB64Decode($y)));
- return sprintf("-----BEGIN PUBLIC KEY-----\n%s\n-----END PUBLIC KEY-----\n", wordwrap(base64_encode($pem), 64, "\n", \true));
- }
- /**
- * Create a public key represented in PEM format from RSA modulus and exponent information
- *
- * @param string $n The RSA modulus encoded in Base64
- * @param string $e The RSA exponent encoded in Base64
- *
- * @return string The RSA public key represented in PEM format
- *
- * @uses encodeLength
- */
- private static function createPemFromModulusAndExponent(string $n, string $e) : string
- {
- $mod = JWT::urlsafeB64Decode($n);
- $exp = JWT::urlsafeB64Decode($e);
- $modulus = \pack('Ca*a*', 2, self::encodeLength(\strlen($mod)), $mod);
- $publicExponent = \pack('Ca*a*', 2, self::encodeLength(\strlen($exp)), $exp);
- $rsaPublicKey = \pack('Ca*a*a*', 48, self::encodeLength(\strlen($modulus) + \strlen($publicExponent)), $modulus, $publicExponent);
- // sequence(oid(1.2.840.113549.1.1.1), null)) = rsaEncryption.
- $rsaOID = \pack('H*', '300d06092a864886f70d0101010500');
- // hex version of MA0GCSqGSIb3DQEBAQUA
- $rsaPublicKey = \chr(0) . $rsaPublicKey;
- $rsaPublicKey = \chr(3) . self::encodeLength(\strlen($rsaPublicKey)) . $rsaPublicKey;
- $rsaPublicKey = \pack('Ca*a*', 48, self::encodeLength(\strlen($rsaOID . $rsaPublicKey)), $rsaOID . $rsaPublicKey);
- return "-----BEGIN PUBLIC KEY-----\r\n" . \chunk_split(\base64_encode($rsaPublicKey), 64) . '-----END PUBLIC KEY-----';
- }
- /**
- * DER-encode the length
- *
- * DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4. See
- * {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 paragraph 8.1.3} for more information.
- *
- * @param int $length
- * @return string
- */
- private static function encodeLength(int $length) : string
- {
- if ($length <= 0x7f) {
- return \chr($length);
- }
- $temp = \ltrim(\pack('N', $length), \chr(0));
- return \pack('Ca*', 0x80 | \strlen($temp), $temp);
- }
- /**
- * Encodes a value into a DER object.
- * Also defined in Firebase\JWT\JWT
- *
- * @param int $type DER tag
- * @param string $value the value to encode
- * @return string the encoded object
- */
- private static function encodeDER(int $type, string $value) : string
- {
- $tag_header = 0;
- if ($type === self::ASN1_SEQUENCE) {
- $tag_header |= 0x20;
- }
- // Type
- $der = \chr($tag_header | $type);
- // Length
- $der .= \chr(\strlen($value));
- return $der . $value;
- }
- /**
- * Encodes a string into a DER-encoded OID.
- *
- * @param string $oid the OID string
- * @return string the binary DER-encoded OID
- */
- private static function encodeOID(string $oid) : string
- {
- $octets = explode('.', $oid);
- // Get the first octet
- $first = (int) array_shift($octets);
- $second = (int) array_shift($octets);
- $oid = \chr($first * 40 + $second);
- // Iterate over subsequent octets
- foreach ($octets as $octet) {
- if ($octet == 0) {
- $oid .= \chr(0x0);
- continue;
- }
- $bin = '';
- while ($octet) {
- $bin .= \chr(0x80 | $octet & 0x7f);
- $octet >>= 7;
- }
- $bin[0] = $bin[0] & \chr(0x7f);
- // Convert to big endian if necessary
- if (pack('V', 65534) == pack('L', 65534)) {
- $oid .= strrev($bin);
- } else {
- $oid .= $bin;
- }
- }
- return $oid;
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/firebase/php-jwt/src/JWT.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/firebase/php-jwt/src/JWT.php
deleted file mode 100644
index 32add50..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/firebase/php-jwt/src/JWT.php
+++ /dev/null
@@ -1,572 +0,0 @@
-
- * @author Anant Narayanan
- * @license http://opensource.org/licenses/BSD-3-Clause 3-clause BSD
- * @link https://github.com/firebase/php-jwt
- */
-class JWT
-{
- private const ASN1_INTEGER = 0x2;
- private const ASN1_SEQUENCE = 0x10;
- private const ASN1_BIT_STRING = 0x3;
- /**
- * When checking nbf, iat or expiration times,
- * we want to provide some extra leeway time to
- * account for clock skew.
- *
- * @var int
- */
- public static $leeway = 0;
- /**
- * Allow the current timestamp to be specified.
- * Useful for fixing a value within unit testing.
- * Will default to PHP time() value if null.
- *
- * @var ?int
- */
- public static $timestamp = null;
- /**
- * @var array
- */
- public static $supported_algs = ['ES384' => ['openssl', 'SHA384'], 'ES256' => ['openssl', 'SHA256'], 'ES256K' => ['openssl', 'SHA256'], 'HS256' => ['hash_hmac', 'SHA256'], 'HS384' => ['hash_hmac', 'SHA384'], 'HS512' => ['hash_hmac', 'SHA512'], 'RS256' => ['openssl', 'SHA256'], 'RS384' => ['openssl', 'SHA384'], 'RS512' => ['openssl', 'SHA512'], 'EdDSA' => ['sodium_crypto', 'EdDSA']];
- /**
- * Decodes a JWT string into a PHP object.
- *
- * @param string $jwt The JWT
- * @param Key|ArrayAccess|array $keyOrKeyArray The Key or associative array of key IDs
- * (kid) to Key objects.
- * If the algorithm used is asymmetric, this is
- * the public key.
- * Each Key object contains an algorithm and
- * matching key.
- * Supported algorithms are 'ES384','ES256',
- * 'HS256', 'HS384', 'HS512', 'RS256', 'RS384'
- * and 'RS512'.
- * @param stdClass $headers Optional. Populates stdClass with headers.
- *
- * @return stdClass The JWT's payload as a PHP object
- *
- * @throws InvalidArgumentException Provided key/key-array was empty or malformed
- * @throws DomainException Provided JWT is malformed
- * @throws UnexpectedValueException Provided JWT was invalid
- * @throws SignatureInvalidException Provided JWT was invalid because the signature verification failed
- * @throws BeforeValidException Provided JWT is trying to be used before it's eligible as defined by 'nbf'
- * @throws BeforeValidException Provided JWT is trying to be used before it's been created as defined by 'iat'
- * @throws ExpiredException Provided JWT has since expired, as defined by the 'exp' claim
- *
- * @uses jsonDecode
- * @uses urlsafeB64Decode
- */
- public static function decode(string $jwt, $keyOrKeyArray, stdClass &$headers = null) : stdClass
- {
- // Validate JWT
- $timestamp = \is_null(static::$timestamp) ? \time() : static::$timestamp;
- if (empty($keyOrKeyArray)) {
- throw new InvalidArgumentException('Key may not be empty');
- }
- $tks = \explode('.', $jwt);
- if (\count($tks) !== 3) {
- throw new UnexpectedValueException('Wrong number of segments');
- }
- list($headb64, $bodyb64, $cryptob64) = $tks;
- $headerRaw = static::urlsafeB64Decode($headb64);
- if (null === ($header = static::jsonDecode($headerRaw))) {
- throw new UnexpectedValueException('Invalid header encoding');
- }
- if ($headers !== null) {
- $headers = $header;
- }
- $payloadRaw = static::urlsafeB64Decode($bodyb64);
- if (null === ($payload = static::jsonDecode($payloadRaw))) {
- throw new UnexpectedValueException('Invalid claims encoding');
- }
- if (\is_array($payload)) {
- // prevent PHP Fatal Error in edge-cases when payload is empty array
- $payload = (object) $payload;
- }
- if (!$payload instanceof stdClass) {
- throw new UnexpectedValueException('Payload must be a JSON object');
- }
- $sig = static::urlsafeB64Decode($cryptob64);
- if (empty($header->alg)) {
- throw new UnexpectedValueException('Empty algorithm');
- }
- if (empty(static::$supported_algs[$header->alg])) {
- throw new UnexpectedValueException('Algorithm not supported');
- }
- $key = self::getKey($keyOrKeyArray, property_exists($header, 'kid') ? $header->kid : null);
- // Check the algorithm
- if (!self::constantTimeEquals($key->getAlgorithm(), $header->alg)) {
- // See issue #351
- throw new UnexpectedValueException('Incorrect key for this algorithm');
- }
- if (\in_array($header->alg, ['ES256', 'ES256K', 'ES384'], \true)) {
- // OpenSSL expects an ASN.1 DER sequence for ES256/ES256K/ES384 signatures
- $sig = self::signatureToDER($sig);
- }
- if (!self::verify("{$headb64}.{$bodyb64}", $sig, $key->getKeyMaterial(), $header->alg)) {
- throw new SignatureInvalidException('Signature verification failed');
- }
- // Check the nbf if it is defined. This is the time that the
- // token can actually be used. If it's not yet that time, abort.
- if (isset($payload->nbf) && floor($payload->nbf) > $timestamp + static::$leeway) {
- $ex = new BeforeValidException('Cannot handle token with nbf prior to ' . \date(DateTime::ISO8601, (int) $payload->nbf));
- $ex->setPayload($payload);
- throw $ex;
- }
- // Check that this token has been created before 'now'. This prevents
- // using tokens that have been created for later use (and haven't
- // correctly used the nbf claim).
- if (!isset($payload->nbf) && isset($payload->iat) && floor($payload->iat) > $timestamp + static::$leeway) {
- $ex = new BeforeValidException('Cannot handle token with iat prior to ' . \date(DateTime::ISO8601, (int) $payload->iat));
- $ex->setPayload($payload);
- throw $ex;
- }
- // Check if this token has expired.
- if (isset($payload->exp) && $timestamp - static::$leeway >= $payload->exp) {
- $ex = new ExpiredException('Expired token');
- $ex->setPayload($payload);
- throw $ex;
- }
- return $payload;
- }
- /**
- * Converts and signs a PHP array into a JWT string.
- *
- * @param array $payload PHP array
- * @param string|resource|OpenSSLAsymmetricKey|OpenSSLCertificate $key The secret key.
- * @param string $alg Supported algorithms are 'ES384','ES256', 'ES256K', 'HS256',
- * 'HS384', 'HS512', 'RS256', 'RS384', and 'RS512'
- * @param string $keyId
- * @param array $head An array with header elements to attach
- *
- * @return string A signed JWT
- *
- * @uses jsonEncode
- * @uses urlsafeB64Encode
- */
- public static function encode(array $payload, $key, string $alg, string $keyId = null, array $head = null) : string
- {
- $header = ['typ' => 'JWT'];
- if (isset($head) && \is_array($head)) {
- $header = \array_merge($header, $head);
- }
- $header['alg'] = $alg;
- if ($keyId !== null) {
- $header['kid'] = $keyId;
- }
- $segments = [];
- $segments[] = static::urlsafeB64Encode((string) static::jsonEncode($header));
- $segments[] = static::urlsafeB64Encode((string) static::jsonEncode($payload));
- $signing_input = \implode('.', $segments);
- $signature = static::sign($signing_input, $key, $alg);
- $segments[] = static::urlsafeB64Encode($signature);
- return \implode('.', $segments);
- }
- /**
- * Sign a string with a given key and algorithm.
- *
- * @param string $msg The message to sign
- * @param string|resource|OpenSSLAsymmetricKey|OpenSSLCertificate $key The secret key.
- * @param string $alg Supported algorithms are 'EdDSA', 'ES384', 'ES256', 'ES256K', 'HS256',
- * 'HS384', 'HS512', 'RS256', 'RS384', and 'RS512'
- *
- * @return string An encrypted message
- *
- * @throws DomainException Unsupported algorithm or bad key was specified
- */
- public static function sign(string $msg, $key, string $alg) : string
- {
- if (empty(static::$supported_algs[$alg])) {
- throw new DomainException('Algorithm not supported');
- }
- list($function, $algorithm) = static::$supported_algs[$alg];
- switch ($function) {
- case 'hash_hmac':
- if (!\is_string($key)) {
- throw new InvalidArgumentException('key must be a string when using hmac');
- }
- return \hash_hmac($algorithm, $msg, $key, \true);
- case 'openssl':
- $signature = '';
- $success = \openssl_sign($msg, $signature, $key, $algorithm);
- // @phpstan-ignore-line
- if (!$success) {
- throw new DomainException('OpenSSL unable to sign data');
- }
- if ($alg === 'ES256' || $alg === 'ES256K') {
- $signature = self::signatureFromDER($signature, 256);
- } elseif ($alg === 'ES384') {
- $signature = self::signatureFromDER($signature, 384);
- }
- return $signature;
- case 'sodium_crypto':
- if (!\function_exists('sodium_crypto_sign_detached')) {
- throw new DomainException('libsodium is not available');
- }
- if (!\is_string($key)) {
- throw new InvalidArgumentException('key must be a string when using EdDSA');
- }
- try {
- // The last non-empty line is used as the key.
- $lines = array_filter(explode("\n", $key));
- $key = base64_decode((string) end($lines));
- if (\strlen($key) === 0) {
- throw new DomainException('Key cannot be empty string');
- }
- return sodium_crypto_sign_detached($msg, $key);
- } catch (Exception $e) {
- throw new DomainException($e->getMessage(), 0, $e);
- }
- }
- throw new DomainException('Algorithm not supported');
- }
- /**
- * Verify a signature with the message, key and method. Not all methods
- * are symmetric, so we must have a separate verify and sign method.
- *
- * @param string $msg The original message (header and body)
- * @param string $signature The original signature
- * @param string|resource|OpenSSLAsymmetricKey|OpenSSLCertificate $keyMaterial For Ed*, ES*, HS*, a string key works. for RS*, must be an instance of OpenSSLAsymmetricKey
- * @param string $alg The algorithm
- *
- * @return bool
- *
- * @throws DomainException Invalid Algorithm, bad key, or OpenSSL failure
- */
- private static function verify(string $msg, string $signature, $keyMaterial, string $alg) : bool
- {
- if (empty(static::$supported_algs[$alg])) {
- throw new DomainException('Algorithm not supported');
- }
- list($function, $algorithm) = static::$supported_algs[$alg];
- switch ($function) {
- case 'openssl':
- $success = \openssl_verify($msg, $signature, $keyMaterial, $algorithm);
- // @phpstan-ignore-line
- if ($success === 1) {
- return \true;
- }
- if ($success === 0) {
- return \false;
- }
- // returns 1 on success, 0 on failure, -1 on error.
- throw new DomainException('OpenSSL error: ' . \openssl_error_string());
- case 'sodium_crypto':
- if (!\function_exists('sodium_crypto_sign_verify_detached')) {
- throw new DomainException('libsodium is not available');
- }
- if (!\is_string($keyMaterial)) {
- throw new InvalidArgumentException('key must be a string when using EdDSA');
- }
- try {
- // The last non-empty line is used as the key.
- $lines = array_filter(explode("\n", $keyMaterial));
- $key = base64_decode((string) end($lines));
- if (\strlen($key) === 0) {
- throw new DomainException('Key cannot be empty string');
- }
- if (\strlen($signature) === 0) {
- throw new DomainException('Signature cannot be empty string');
- }
- return sodium_crypto_sign_verify_detached($signature, $msg, $key);
- } catch (Exception $e) {
- throw new DomainException($e->getMessage(), 0, $e);
- }
- case 'hash_hmac':
- default:
- if (!\is_string($keyMaterial)) {
- throw new InvalidArgumentException('key must be a string when using hmac');
- }
- $hash = \hash_hmac($algorithm, $msg, $keyMaterial, \true);
- return self::constantTimeEquals($hash, $signature);
- }
- }
- /**
- * Decode a JSON string into a PHP object.
- *
- * @param string $input JSON string
- *
- * @return mixed The decoded JSON string
- *
- * @throws DomainException Provided string was invalid JSON
- */
- public static function jsonDecode(string $input)
- {
- $obj = \json_decode($input, \false, 512, \JSON_BIGINT_AS_STRING);
- if ($errno = \json_last_error()) {
- self::handleJsonError($errno);
- } elseif ($obj === null && $input !== 'null') {
- throw new DomainException('Null result with non-null input');
- }
- return $obj;
- }
- /**
- * Encode a PHP array into a JSON string.
- *
- * @param array $input A PHP array
- *
- * @return string JSON representation of the PHP array
- *
- * @throws DomainException Provided object could not be encoded to valid JSON
- */
- public static function jsonEncode(array $input) : string
- {
- if (\PHP_VERSION_ID >= 50400) {
- $json = \json_encode($input, \JSON_UNESCAPED_SLASHES);
- } else {
- // PHP 5.3 only
- $json = \json_encode($input);
- }
- if ($errno = \json_last_error()) {
- self::handleJsonError($errno);
- } elseif ($json === 'null') {
- throw new DomainException('Null result with non-null input');
- }
- if ($json === \false) {
- throw new DomainException('Provided object could not be encoded to valid JSON');
- }
- return $json;
- }
- /**
- * Decode a string with URL-safe Base64.
- *
- * @param string $input A Base64 encoded string
- *
- * @return string A decoded string
- *
- * @throws InvalidArgumentException invalid base64 characters
- */
- public static function urlsafeB64Decode(string $input) : string
- {
- return \base64_decode(self::convertBase64UrlToBase64($input));
- }
- /**
- * Convert a string in the base64url (URL-safe Base64) encoding to standard base64.
- *
- * @param string $input A Base64 encoded string with URL-safe characters (-_ and no padding)
- *
- * @return string A Base64 encoded string with standard characters (+/) and padding (=), when
- * needed.
- *
- * @see https://www.rfc-editor.org/rfc/rfc4648
- */
- public static function convertBase64UrlToBase64(string $input) : string
- {
- $remainder = \strlen($input) % 4;
- if ($remainder) {
- $padlen = 4 - $remainder;
- $input .= \str_repeat('=', $padlen);
- }
- return \strtr($input, '-_', '+/');
- }
- /**
- * Encode a string with URL-safe Base64.
- *
- * @param string $input The string you want encoded
- *
- * @return string The base64 encode of what you passed in
- */
- public static function urlsafeB64Encode(string $input) : string
- {
- return \str_replace('=', '', \strtr(\base64_encode($input), '+/', '-_'));
- }
- /**
- * Determine if an algorithm has been provided for each Key
- *
- * @param Key|ArrayAccess|array $keyOrKeyArray
- * @param string|null $kid
- *
- * @throws UnexpectedValueException
- *
- * @return Key
- */
- private static function getKey($keyOrKeyArray, ?string $kid) : Key
- {
- if ($keyOrKeyArray instanceof Key) {
- return $keyOrKeyArray;
- }
- if (empty($kid) && $kid !== '0') {
- throw new UnexpectedValueException('"kid" empty, unable to lookup correct key');
- }
- if ($keyOrKeyArray instanceof CachedKeySet) {
- // Skip "isset" check, as this will automatically refresh if not set
- return $keyOrKeyArray[$kid];
- }
- if (!isset($keyOrKeyArray[$kid])) {
- throw new UnexpectedValueException('"kid" invalid, unable to lookup correct key');
- }
- return $keyOrKeyArray[$kid];
- }
- /**
- * @param string $left The string of known length to compare against
- * @param string $right The user-supplied string
- * @return bool
- */
- public static function constantTimeEquals(string $left, string $right) : bool
- {
- if (\function_exists('hash_equals')) {
- return \hash_equals($left, $right);
- }
- $len = \min(self::safeStrlen($left), self::safeStrlen($right));
- $status = 0;
- for ($i = 0; $i < $len; $i++) {
- $status |= \ord($left[$i]) ^ \ord($right[$i]);
- }
- $status |= self::safeStrlen($left) ^ self::safeStrlen($right);
- return $status === 0;
- }
- /**
- * Helper method to create a JSON error.
- *
- * @param int $errno An error number from json_last_error()
- *
- * @throws DomainException
- *
- * @return void
- */
- private static function handleJsonError(int $errno) : void
- {
- $messages = [\JSON_ERROR_DEPTH => 'Maximum stack depth exceeded', \JSON_ERROR_STATE_MISMATCH => 'Invalid or malformed JSON', \JSON_ERROR_CTRL_CHAR => 'Unexpected control character found', \JSON_ERROR_SYNTAX => 'Syntax error, malformed JSON', \JSON_ERROR_UTF8 => 'Malformed UTF-8 characters'];
- throw new DomainException(isset($messages[$errno]) ? $messages[$errno] : 'Unknown JSON error: ' . $errno);
- }
- /**
- * Get the number of bytes in cryptographic strings.
- *
- * @param string $str
- *
- * @return int
- */
- private static function safeStrlen(string $str) : int
- {
- if (\function_exists('mb_strlen')) {
- return \mb_strlen($str, '8bit');
- }
- return \strlen($str);
- }
- /**
- * Convert an ECDSA signature to an ASN.1 DER sequence
- *
- * @param string $sig The ECDSA signature to convert
- * @return string The encoded DER object
- */
- private static function signatureToDER(string $sig) : string
- {
- // Separate the signature into r-value and s-value
- $length = max(1, (int) (\strlen($sig) / 2));
- list($r, $s) = \str_split($sig, $length);
- // Trim leading zeros
- $r = \ltrim($r, "\x00");
- $s = \ltrim($s, "\x00");
- // Convert r-value and s-value from unsigned big-endian integers to
- // signed two's complement
- if (\ord($r[0]) > 0x7f) {
- $r = "\x00" . $r;
- }
- if (\ord($s[0]) > 0x7f) {
- $s = "\x00" . $s;
- }
- return self::encodeDER(self::ASN1_SEQUENCE, self::encodeDER(self::ASN1_INTEGER, $r) . self::encodeDER(self::ASN1_INTEGER, $s));
- }
- /**
- * Encodes a value into a DER object.
- *
- * @param int $type DER tag
- * @param string $value the value to encode
- *
- * @return string the encoded object
- */
- private static function encodeDER(int $type, string $value) : string
- {
- $tag_header = 0;
- if ($type === self::ASN1_SEQUENCE) {
- $tag_header |= 0x20;
- }
- // Type
- $der = \chr($tag_header | $type);
- // Length
- $der .= \chr(\strlen($value));
- return $der . $value;
- }
- /**
- * Encodes signature from a DER object.
- *
- * @param string $der binary signature in DER format
- * @param int $keySize the number of bits in the key
- *
- * @return string the signature
- */
- private static function signatureFromDER(string $der, int $keySize) : string
- {
- // OpenSSL returns the ECDSA signatures as a binary ASN.1 DER SEQUENCE
- list($offset, $_) = self::readDER($der);
- list($offset, $r) = self::readDER($der, $offset);
- list($offset, $s) = self::readDER($der, $offset);
- // Convert r-value and s-value from signed two's compliment to unsigned
- // big-endian integers
- $r = \ltrim($r, "\x00");
- $s = \ltrim($s, "\x00");
- // Pad out r and s so that they are $keySize bits long
- $r = \str_pad($r, $keySize / 8, "\x00", \STR_PAD_LEFT);
- $s = \str_pad($s, $keySize / 8, "\x00", \STR_PAD_LEFT);
- return $r . $s;
- }
- /**
- * Reads binary DER-encoded data and decodes into a single object
- *
- * @param string $der the binary data in DER format
- * @param int $offset the offset of the data stream containing the object
- * to decode
- *
- * @return array{int, string|null} the new offset and the decoded object
- */
- private static function readDER(string $der, int $offset = 0) : array
- {
- $pos = $offset;
- $size = \strlen($der);
- $constructed = \ord($der[$pos]) >> 5 & 0x1;
- $type = \ord($der[$pos++]) & 0x1f;
- // Length
- $len = \ord($der[$pos++]);
- if ($len & 0x80) {
- $n = $len & 0x1f;
- $len = 0;
- while ($n-- && $pos < $size) {
- $len = $len << 8 | \ord($der[$pos++]);
- }
- }
- // Value
- if ($type === self::ASN1_BIT_STRING) {
- $pos++;
- // Skip the first contents octet (padding indicator)
- $data = \substr($der, $pos, $len - 1);
- $pos += $len - 1;
- } elseif (!$constructed) {
- $data = \substr($der, $pos, $len);
- $pos += $len;
- } else {
- $data = null;
- }
- return [$pos, $data];
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/firebase/php-jwt/src/JWTExceptionWithPayloadInterface.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/firebase/php-jwt/src/JWTExceptionWithPayloadInterface.php
deleted file mode 100644
index dcfc18f..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/firebase/php-jwt/src/JWTExceptionWithPayloadInterface.php
+++ /dev/null
@@ -1,20 +0,0 @@
-keyMaterial = $keyMaterial;
- $this->algorithm = $algorithm;
- }
- /**
- * Return the algorithm valid for this key
- *
- * @return string
- */
- public function getAlgorithm() : string
- {
- return $this->algorithm;
- }
- /**
- * @return string|resource|OpenSSLAsymmetricKey|OpenSSLCertificate
- */
- public function getKeyMaterial()
- {
- return $this->keyMaterial;
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/firebase/php-jwt/src/SignatureInvalidException.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/firebase/php-jwt/src/SignatureInvalidException.php
deleted file mode 100644
index 5c57363..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/firebase/php-jwt/src/SignatureInvalidException.php
+++ /dev/null
@@ -1,7 +0,0 @@
- 'Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\Google_Client', 'Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\Google\\Service' => 'Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\Google_Service', 'Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\Google\\Service\\Resource' => 'Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\Google_Service_Resource', 'Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\Google\\Model' => 'Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\Google_Model', 'Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\Google\\Collection' => 'Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\Google_Collection'];
- foreach ($servicesClassMap as $alias => $class) {
- \class_alias($class, $alias);
- }
- }
-}
-\spl_autoload_register(function ($class) {
- $class = preg_replace('/^Piwik\\\\Dependencies\\\\/', 'Matomo\\Dependencies\\', $class);
-
- if (0 === \strpos($class, 'Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\Google_Service_')) {
- // Autoload the new class, which will also create an alias for the
- // old class by changing underscores to namespaces:
- // Google_Service_Speech_Resource_Operations
- // => Google\Service\Speech\Resource\Operations
- $classExists = \class_exists($newClass = \str_replace('_', '\\', $class));
- if ($classExists) {
- return \true;
- }
- }
-}, \true, \true);
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/renovate.json b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/renovate.json
deleted file mode 100644
index b31203b..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/renovate.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "extends": [
- "config:base"
- ],
- "pinVersions": false,
- "rebaseStalePrs": true
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/Oauth2.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/Oauth2.php
deleted file mode 100644
index 9d707d0..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/Oauth2.php
+++ /dev/null
@@ -1,82 +0,0 @@
-
- * Obtains end-user authorization grants for use with other Google APIs.
- *
- *
- * For more information about this service, see the API
- * Documentation
- *
- *
- * @author Google, Inc.
- */
-class Oauth2 extends \Matomo\Dependencies\SearchEngineKeywordsPerformance\Google\Service
-{
- /** View your email address. */
- const USERINFO_EMAIL = "https://www.googleapis.com/auth/userinfo.email";
- /** See your personal info, including any personal info you've made publicly available. */
- const USERINFO_PROFILE = "https://www.googleapis.com/auth/userinfo.profile";
- /** Associate you with your personal info on Google. */
- const OPENID = "openid";
- public $userinfo;
- public $userinfo_v2_me;
- private $base_methods;
- /**
- * Constructs the internal representation of the Oauth2 service.
- *
- * @param Client|array $clientOrConfig The client used to deliver requests, or a
- * config array to pass to a new Client instance.
- * @param string $rootUrl The root URL used for requests to the service.
- */
- public function __construct($clientOrConfig = [], $rootUrl = null)
- {
- parent::__construct($clientOrConfig);
- $this->rootUrl = $rootUrl ?: 'https://www.googleapis.com/';
- $this->servicePath = '';
- $this->batchPath = 'batch/oauth2/v2';
- $this->version = 'v2';
- $this->serviceName = 'oauth2';
- $this->userinfo = new Oauth2\Resource\Userinfo($this, $this->serviceName, 'userinfo', ['methods' => ['get' => ['path' => 'oauth2/v2/userinfo', 'httpMethod' => 'GET', 'parameters' => []]]]);
- $this->userinfo_v2_me = new Oauth2\Resource\UserinfoV2Me($this, $this->serviceName, 'me', ['methods' => ['get' => ['path' => 'userinfo/v2/me', 'httpMethod' => 'GET', 'parameters' => []]]]);
- $this->base_methods = new Resource($this, $this->serviceName, '', ['methods' => ['tokeninfo' => ['path' => 'oauth2/v2/tokeninfo', 'httpMethod' => 'POST', 'parameters' => ['access_token' => ['location' => 'query', 'type' => 'string'], 'id_token' => ['location' => 'query', 'type' => 'string']]]]]);
- }
- /**
- * (tokeninfo)
- *
- * @param array $optParams Optional parameters.
- *
- * @opt_param string access_token
- * @opt_param string id_token
- * @return Tokeninfo
- */
- public function tokeninfo($optParams = [])
- {
- $params = [];
- $params = array_merge($params, $optParams);
- return $this->base_methods->call('tokeninfo', [$params], Tokeninfo::class);
- }
-}
-// Adding a class alias for backwards compatibility with the previous class name.
-class_alias(Oauth2::class, 'Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\Google_Service_Oauth2');
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/Oauth2/Resource/Userinfo.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/Oauth2/Resource/Userinfo.php
deleted file mode 100644
index 1c22318..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/Oauth2/Resource/Userinfo.php
+++ /dev/null
@@ -1,45 +0,0 @@
-
- * $oauth2Service = new Google\Service\Oauth2(...);
- * $userinfo = $oauth2Service->userinfo;
- *
- */
-class Userinfo extends \Matomo\Dependencies\SearchEngineKeywordsPerformance\Google\Service\Resource
-{
- /**
- * (userinfo.get)
- *
- * @param array $optParams Optional parameters.
- * @return UserinfoModel
- */
- public function get($optParams = [])
- {
- $params = [];
- $params = array_merge($params, $optParams);
- return $this->call('get', [$params], UserinfoModel::class);
- }
-}
-// Adding a class alias for backwards compatibility with the previous class name.
-class_alias(Userinfo::class, 'Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\Google_Service_Oauth2_Resource_Userinfo');
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/Oauth2/Resource/UserinfoV2.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/Oauth2/Resource/UserinfoV2.php
deleted file mode 100644
index 7d62bf2..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/Oauth2/Resource/UserinfoV2.php
+++ /dev/null
@@ -1,32 +0,0 @@
-
- * $oauth2Service = new Google\Service\Oauth2(...);
- * $v2 = $oauth2Service->v2;
- *
- */
-class UserinfoV2 extends \Matomo\Dependencies\SearchEngineKeywordsPerformance\Google\Service\Resource
-{
-}
-// Adding a class alias for backwards compatibility with the previous class name.
-class_alias(UserinfoV2::class, 'Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\Google_Service_Oauth2_Resource_UserinfoV2');
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/Oauth2/Resource/UserinfoV2Me.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/Oauth2/Resource/UserinfoV2Me.php
deleted file mode 100644
index 40cf84c..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/Oauth2/Resource/UserinfoV2Me.php
+++ /dev/null
@@ -1,45 +0,0 @@
-
- * $oauth2Service = new Google\Service\Oauth2(...);
- * $me = $oauth2Service->me;
- *
- */
-class UserinfoV2Me extends \Matomo\Dependencies\SearchEngineKeywordsPerformance\Google\Service\Resource
-{
- /**
- * (me.get)
- *
- * @param array $optParams Optional parameters.
- * @return Userinfo
- */
- public function get($optParams = [])
- {
- $params = [];
- $params = array_merge($params, $optParams);
- return $this->call('get', [$params], UserinfoModel::class);
- }
-}
-// Adding a class alias for backwards compatibility with the previous class name.
-class_alias(UserinfoV2Me::class, 'Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\Google_Service_Oauth2_Resource_UserinfoV2Me');
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/Oauth2/Tokeninfo.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/Oauth2/Tokeninfo.php
deleted file mode 100644
index 0e1383c..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/Oauth2/Tokeninfo.php
+++ /dev/null
@@ -1,88 +0,0 @@
- "expires_in", "issuedTo" => "issued_to", "userId" => "user_id", "verifiedEmail" => "verified_email"];
- public $audience;
- public $email;
- public $expiresIn;
- public $issuedTo;
- public $scope;
- public $userId;
- public $verifiedEmail;
- public function setAudience($audience)
- {
- $this->audience = $audience;
- }
- public function getAudience()
- {
- return $this->audience;
- }
- public function setEmail($email)
- {
- $this->email = $email;
- }
- public function getEmail()
- {
- return $this->email;
- }
- public function setExpiresIn($expiresIn)
- {
- $this->expiresIn = $expiresIn;
- }
- public function getExpiresIn()
- {
- return $this->expiresIn;
- }
- public function setIssuedTo($issuedTo)
- {
- $this->issuedTo = $issuedTo;
- }
- public function getIssuedTo()
- {
- return $this->issuedTo;
- }
- public function setScope($scope)
- {
- $this->scope = $scope;
- }
- public function getScope()
- {
- return $this->scope;
- }
- public function setUserId($userId)
- {
- $this->userId = $userId;
- }
- public function getUserId()
- {
- return $this->userId;
- }
- public function setVerifiedEmail($verifiedEmail)
- {
- $this->verifiedEmail = $verifiedEmail;
- }
- public function getVerifiedEmail()
- {
- return $this->verifiedEmail;
- }
-}
-// Adding a class alias for backwards compatibility with the previous class name.
-class_alias(Tokeninfo::class, 'Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\Google_Service_Oauth2_Tokeninfo');
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/Oauth2/Userinfo.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/Oauth2/Userinfo.php
deleted file mode 100644
index 49f82aa..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/Oauth2/Userinfo.php
+++ /dev/null
@@ -1,124 +0,0 @@
- "family_name", "givenName" => "given_name", "verifiedEmail" => "verified_email"];
- public $email;
- public $familyName;
- public $gender;
- public $givenName;
- public $hd;
- public $id;
- public $link;
- public $locale;
- public $name;
- public $picture;
- public $verifiedEmail;
- public function setEmail($email)
- {
- $this->email = $email;
- }
- public function getEmail()
- {
- return $this->email;
- }
- public function setFamilyName($familyName)
- {
- $this->familyName = $familyName;
- }
- public function getFamilyName()
- {
- return $this->familyName;
- }
- public function setGender($gender)
- {
- $this->gender = $gender;
- }
- public function getGender()
- {
- return $this->gender;
- }
- public function setGivenName($givenName)
- {
- $this->givenName = $givenName;
- }
- public function getGivenName()
- {
- return $this->givenName;
- }
- public function setHd($hd)
- {
- $this->hd = $hd;
- }
- public function getHd()
- {
- return $this->hd;
- }
- public function setId($id)
- {
- $this->id = $id;
- }
- public function getId()
- {
- return $this->id;
- }
- public function setLink($link)
- {
- $this->link = $link;
- }
- public function getLink()
- {
- return $this->link;
- }
- public function setLocale($locale)
- {
- $this->locale = $locale;
- }
- public function getLocale()
- {
- return $this->locale;
- }
- public function setName($name)
- {
- $this->name = $name;
- }
- public function getName()
- {
- return $this->name;
- }
- public function setPicture($picture)
- {
- $this->picture = $picture;
- }
- public function getPicture()
- {
- return $this->picture;
- }
- public function setVerifiedEmail($verifiedEmail)
- {
- $this->verifiedEmail = $verifiedEmail;
- }
- public function getVerifiedEmail()
- {
- return $this->verifiedEmail;
- }
-}
-// Adding a class alias for backwards compatibility with the previous class name.
-class_alias(Userinfo::class, 'Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\Google_Service_Oauth2_Userinfo');
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/SearchConsole.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/SearchConsole.php
deleted file mode 100644
index 076b9af..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/SearchConsole.php
+++ /dev/null
@@ -1,67 +0,0 @@
-
- * The Search Console API provides access to both Search Console data (verified
- * users only) and to public information on an URL basis (anyone)
- *
- *
- * For more information about this service, see the API
- * Documentation
- *
- *
- * @author Google, Inc.
- */
-class SearchConsole extends \Matomo\Dependencies\SearchEngineKeywordsPerformance\Google\Service
-{
- /** View and manage Search Console data for your verified sites. */
- const WEBMASTERS = "https://www.googleapis.com/auth/webmasters";
- /** View Search Console data for your verified sites. */
- const WEBMASTERS_READONLY = "https://www.googleapis.com/auth/webmasters.readonly";
- public $searchanalytics;
- public $sitemaps;
- public $sites;
- public $urlTestingTools_mobileFriendlyTest;
- /**
- * Constructs the internal representation of the SearchConsole service.
- *
- * @param Client|array $clientOrConfig The client used to deliver requests, or a
- * config array to pass to a new Client instance.
- * @param string $rootUrl The root URL used for requests to the service.
- */
- public function __construct($clientOrConfig = [], $rootUrl = null)
- {
- parent::__construct($clientOrConfig);
- $this->rootUrl = $rootUrl ?: 'https://searchconsole.googleapis.com/';
- $this->servicePath = '';
- $this->batchPath = 'batch';
- $this->version = 'v1';
- $this->serviceName = 'searchconsole';
- $this->searchanalytics = new SearchConsole\Resource\Searchanalytics($this, $this->serviceName, 'searchanalytics', ['methods' => ['query' => ['path' => 'webmasters/v3/sites/{siteUrl}/searchAnalytics/query', 'httpMethod' => 'POST', 'parameters' => ['siteUrl' => ['location' => 'path', 'type' => 'string', 'required' => \true]]]]]);
- $this->sitemaps = new SearchConsole\Resource\Sitemaps($this, $this->serviceName, 'sitemaps', ['methods' => ['delete' => ['path' => 'webmasters/v3/sites/{siteUrl}/sitemaps/{feedpath}', 'httpMethod' => 'DELETE', 'parameters' => ['siteUrl' => ['location' => 'path', 'type' => 'string', 'required' => \true], 'feedpath' => ['location' => 'path', 'type' => 'string', 'required' => \true]]], 'get' => ['path' => 'webmasters/v3/sites/{siteUrl}/sitemaps/{feedpath}', 'httpMethod' => 'GET', 'parameters' => ['siteUrl' => ['location' => 'path', 'type' => 'string', 'required' => \true], 'feedpath' => ['location' => 'path', 'type' => 'string', 'required' => \true]]], 'list' => ['path' => 'webmasters/v3/sites/{siteUrl}/sitemaps', 'httpMethod' => 'GET', 'parameters' => ['siteUrl' => ['location' => 'path', 'type' => 'string', 'required' => \true], 'sitemapIndex' => ['location' => 'query', 'type' => 'string']]], 'submit' => ['path' => 'webmasters/v3/sites/{siteUrl}/sitemaps/{feedpath}', 'httpMethod' => 'PUT', 'parameters' => ['siteUrl' => ['location' => 'path', 'type' => 'string', 'required' => \true], 'feedpath' => ['location' => 'path', 'type' => 'string', 'required' => \true]]]]]);
- $this->sites = new SearchConsole\Resource\Sites($this, $this->serviceName, 'sites', ['methods' => ['add' => ['path' => 'webmasters/v3/sites/{siteUrl}', 'httpMethod' => 'PUT', 'parameters' => ['siteUrl' => ['location' => 'path', 'type' => 'string', 'required' => \true]]], 'delete' => ['path' => 'webmasters/v3/sites/{siteUrl}', 'httpMethod' => 'DELETE', 'parameters' => ['siteUrl' => ['location' => 'path', 'type' => 'string', 'required' => \true]]], 'get' => ['path' => 'webmasters/v3/sites/{siteUrl}', 'httpMethod' => 'GET', 'parameters' => ['siteUrl' => ['location' => 'path', 'type' => 'string', 'required' => \true]]], 'list' => ['path' => 'webmasters/v3/sites', 'httpMethod' => 'GET', 'parameters' => []]]]);
- $this->urlTestingTools_mobileFriendlyTest = new SearchConsole\Resource\UrlTestingToolsMobileFriendlyTest($this, $this->serviceName, 'mobileFriendlyTest', ['methods' => ['run' => ['path' => 'v1/urlTestingTools/mobileFriendlyTest:run', 'httpMethod' => 'POST', 'parameters' => []]]]);
- }
-}
-// Adding a class alias for backwards compatibility with the previous class name.
-class_alias(SearchConsole::class, 'Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\Google_Service_SearchConsole');
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/SearchConsole/ApiDataRow.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/SearchConsole/ApiDataRow.php
deleted file mode 100644
index fc941c9..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/SearchConsole/ApiDataRow.php
+++ /dev/null
@@ -1,70 +0,0 @@
-clicks = $clicks;
- }
- public function getClicks()
- {
- return $this->clicks;
- }
- public function setCtr($ctr)
- {
- $this->ctr = $ctr;
- }
- public function getCtr()
- {
- return $this->ctr;
- }
- public function setImpressions($impressions)
- {
- $this->impressions = $impressions;
- }
- public function getImpressions()
- {
- return $this->impressions;
- }
- public function setKeys($keys)
- {
- $this->keys = $keys;
- }
- public function getKeys()
- {
- return $this->keys;
- }
- public function setPosition($position)
- {
- $this->position = $position;
- }
- public function getPosition()
- {
- return $this->position;
- }
-}
-// Adding a class alias for backwards compatibility with the previous class name.
-class_alias(ApiDataRow::class, 'Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\Google_Service_SearchConsole_ApiDataRow');
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/SearchConsole/ApiDimensionFilter.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/SearchConsole/ApiDimensionFilter.php
deleted file mode 100644
index f5c1305..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/SearchConsole/ApiDimensionFilter.php
+++ /dev/null
@@ -1,51 +0,0 @@
-dimension = $dimension;
- }
- public function getDimension()
- {
- return $this->dimension;
- }
- public function setExpression($expression)
- {
- $this->expression = $expression;
- }
- public function getExpression()
- {
- return $this->expression;
- }
- public function setOperator($operator)
- {
- $this->operator = $operator;
- }
- public function getOperator()
- {
- return $this->operator;
- }
-}
-// Adding a class alias for backwards compatibility with the previous class name.
-class_alias(ApiDimensionFilter::class, 'Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\Google_Service_SearchConsole_ApiDimensionFilter');
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/SearchConsole/ApiDimensionFilterGroup.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/SearchConsole/ApiDimensionFilterGroup.php
deleted file mode 100644
index 42b8c14..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/SearchConsole/ApiDimensionFilterGroup.php
+++ /dev/null
@@ -1,50 +0,0 @@
-filters = $filters;
- }
- /**
- * @return ApiDimensionFilter[]
- */
- public function getFilters()
- {
- return $this->filters;
- }
- public function setGroupType($groupType)
- {
- $this->groupType = $groupType;
- }
- public function getGroupType()
- {
- return $this->groupType;
- }
-}
-// Adding a class alias for backwards compatibility with the previous class name.
-class_alias(ApiDimensionFilterGroup::class, 'Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\Google_Service_SearchConsole_ApiDimensionFilterGroup');
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/SearchConsole/BlockedResource.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/SearchConsole/BlockedResource.php
deleted file mode 100644
index b974ae0..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/SearchConsole/BlockedResource.php
+++ /dev/null
@@ -1,33 +0,0 @@
-url = $url;
- }
- public function getUrl()
- {
- return $this->url;
- }
-}
-// Adding a class alias for backwards compatibility with the previous class name.
-class_alias(BlockedResource::class, 'Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\Google_Service_SearchConsole_BlockedResource');
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/SearchConsole/Image.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/SearchConsole/Image.php
deleted file mode 100644
index b8ec4e4..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/SearchConsole/Image.php
+++ /dev/null
@@ -1,42 +0,0 @@
-data = $data;
- }
- public function getData()
- {
- return $this->data;
- }
- public function setMimeType($mimeType)
- {
- $this->mimeType = $mimeType;
- }
- public function getMimeType()
- {
- return $this->mimeType;
- }
-}
-// Adding a class alias for backwards compatibility with the previous class name.
-class_alias(Image::class, 'Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\Google_Service_SearchConsole_Image');
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/SearchConsole/MobileFriendlyIssue.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/SearchConsole/MobileFriendlyIssue.php
deleted file mode 100644
index e187f3c..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/SearchConsole/MobileFriendlyIssue.php
+++ /dev/null
@@ -1,33 +0,0 @@
-rule = $rule;
- }
- public function getRule()
- {
- return $this->rule;
- }
-}
-// Adding a class alias for backwards compatibility with the previous class name.
-class_alias(MobileFriendlyIssue::class, 'Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\Google_Service_SearchConsole_MobileFriendlyIssue');
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/SearchConsole/Resource/Searchanalytics.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/SearchConsole/Resource/Searchanalytics.php
deleted file mode 100644
index 8be08f1..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/SearchConsole/Resource/Searchanalytics.php
+++ /dev/null
@@ -1,54 +0,0 @@
-
- * $searchconsoleService = new Google\Service\SearchConsole(...);
- * $searchanalytics = $searchconsoleService->searchanalytics;
- *
- */
-class Searchanalytics extends \Matomo\Dependencies\SearchEngineKeywordsPerformance\Google\Service\Resource
-{
- /**
- * Query your data with filters and parameters that you define. Returns zero or
- * more rows grouped by the row keys that you define. You must define a date
- * range of one or more days. When date is one of the group by values, any days
- * without data are omitted from the result list. If you need to know which days
- * have data, issue a broad date range query grouped by date for any metric, and
- * see which day rows are returned. (searchanalytics.query)
- *
- * @param string $siteUrl The site's URL, including protocol. For example:
- * `http://www.example.com/`.
- * @param SearchAnalyticsQueryRequest $postBody
- * @param array $optParams Optional parameters.
- * @return SearchAnalyticsQueryResponse
- */
- public function query($siteUrl, SearchAnalyticsQueryRequest $postBody, $optParams = [])
- {
- $params = ['siteUrl' => $siteUrl, 'postBody' => $postBody];
- $params = array_merge($params, $optParams);
- return $this->call('query', [$params], SearchAnalyticsQueryResponse::class);
- }
-}
-// Adding a class alias for backwards compatibility with the previous class name.
-class_alias(Searchanalytics::class, 'Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\Google_Service_SearchConsole_Resource_Searchanalytics');
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/SearchConsole/Resource/Sitemaps.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/SearchConsole/Resource/Sitemaps.php
deleted file mode 100644
index 5708dc8..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/SearchConsole/Resource/Sitemaps.php
+++ /dev/null
@@ -1,99 +0,0 @@
-
- * $searchconsoleService = new Google\Service\SearchConsole(...);
- * $sitemaps = $searchconsoleService->sitemaps;
- *
- */
-class Sitemaps extends \Matomo\Dependencies\SearchEngineKeywordsPerformance\Google\Service\Resource
-{
- /**
- * Deletes a sitemap from this site. (sitemaps.delete)
- *
- * @param string $siteUrl The site's URL, including protocol. For example:
- * `http://www.example.com/`.
- * @param string $feedpath The URL of the actual sitemap. For example:
- * `http://www.example.com/sitemap.xml`.
- * @param array $optParams Optional parameters.
- */
- public function delete($siteUrl, $feedpath, $optParams = [])
- {
- $params = ['siteUrl' => $siteUrl, 'feedpath' => $feedpath];
- $params = array_merge($params, $optParams);
- return $this->call('delete', [$params]);
- }
- /**
- * Retrieves information about a specific sitemap. (sitemaps.get)
- *
- * @param string $siteUrl The site's URL, including protocol. For example:
- * `http://www.example.com/`.
- * @param string $feedpath The URL of the actual sitemap. For example:
- * `http://www.example.com/sitemap.xml`.
- * @param array $optParams Optional parameters.
- * @return WmxSitemap
- */
- public function get($siteUrl, $feedpath, $optParams = [])
- {
- $params = ['siteUrl' => $siteUrl, 'feedpath' => $feedpath];
- $params = array_merge($params, $optParams);
- return $this->call('get', [$params], WmxSitemap::class);
- }
- /**
- * Lists the [sitemaps-entries](/webmaster-tools/v3/sitemaps) submitted for this
- * site, or included in the sitemap index file (if `sitemapIndex` is specified
- * in the request). (sitemaps.listSitemaps)
- *
- * @param string $siteUrl The site's URL, including protocol. For example:
- * `http://www.example.com/`.
- * @param array $optParams Optional parameters.
- *
- * @opt_param string sitemapIndex A URL of a site's sitemap index. For example:
- * `http://www.example.com/sitemapindex.xml`.
- * @return SitemapsListResponse
- */
- public function listSitemaps($siteUrl, $optParams = [])
- {
- $params = ['siteUrl' => $siteUrl];
- $params = array_merge($params, $optParams);
- return $this->call('list', [$params], SitemapsListResponse::class);
- }
- /**
- * Submits a sitemap for a site. (sitemaps.submit)
- *
- * @param string $siteUrl The site's URL, including protocol. For example:
- * `http://www.example.com/`.
- * @param string $feedpath The URL of the actual sitemap. For example:
- * `http://www.example.com/sitemap.xml`.
- * @param array $optParams Optional parameters.
- */
- public function submit($siteUrl, $feedpath, $optParams = [])
- {
- $params = ['siteUrl' => $siteUrl, 'feedpath' => $feedpath];
- $params = array_merge($params, $optParams);
- return $this->call('submit', [$params]);
- }
-}
-// Adding a class alias for backwards compatibility with the previous class name.
-class_alias(Sitemaps::class, 'Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\Google_Service_SearchConsole_Resource_Sitemaps');
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/SearchConsole/Resource/Sites.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/SearchConsole/Resource/Sites.php
deleted file mode 100644
index 24b5934..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/SearchConsole/Resource/Sites.php
+++ /dev/null
@@ -1,86 +0,0 @@
-
- * $searchconsoleService = new Google\Service\SearchConsole(...);
- * $sites = $searchconsoleService->sites;
- *
- */
-class Sites extends \Matomo\Dependencies\SearchEngineKeywordsPerformance\Google\Service\Resource
-{
- /**
- * Adds a site to the set of the user's sites in Search Console. (sites.add)
- *
- * @param string $siteUrl The URL of the site to add.
- * @param array $optParams Optional parameters.
- */
- public function add($siteUrl, $optParams = [])
- {
- $params = ['siteUrl' => $siteUrl];
- $params = array_merge($params, $optParams);
- return $this->call('add', [$params]);
- }
- /**
- * Removes a site from the set of the user's Search Console sites.
- * (sites.delete)
- *
- * @param string $siteUrl The URI of the property as defined in Search Console.
- * **Examples:** `http://www.example.com/` or `sc-domain:example.com`.
- * @param array $optParams Optional parameters.
- */
- public function delete($siteUrl, $optParams = [])
- {
- $params = ['siteUrl' => $siteUrl];
- $params = array_merge($params, $optParams);
- return $this->call('delete', [$params]);
- }
- /**
- * Retrieves information about specific site. (sites.get)
- *
- * @param string $siteUrl The URI of the property as defined in Search Console.
- * **Examples:** `http://www.example.com/` or `sc-domain:example.com`.
- * @param array $optParams Optional parameters.
- * @return WmxSite
- */
- public function get($siteUrl, $optParams = [])
- {
- $params = ['siteUrl' => $siteUrl];
- $params = array_merge($params, $optParams);
- return $this->call('get', [$params], WmxSite::class);
- }
- /**
- * Lists the user's Search Console sites. (sites.listSites)
- *
- * @param array $optParams Optional parameters.
- * @return SitesListResponse
- */
- public function listSites($optParams = [])
- {
- $params = [];
- $params = array_merge($params, $optParams);
- return $this->call('list', [$params], SitesListResponse::class);
- }
-}
-// Adding a class alias for backwards compatibility with the previous class name.
-class_alias(Sites::class, 'Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\Google_Service_SearchConsole_Resource_Sites');
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/SearchConsole/Resource/UrlTestingTools.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/SearchConsole/Resource/UrlTestingTools.php
deleted file mode 100644
index 9e022ce..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/SearchConsole/Resource/UrlTestingTools.php
+++ /dev/null
@@ -1,32 +0,0 @@
-
- * $searchconsoleService = new Google\Service\SearchConsole(...);
- * $urlTestingTools = $searchconsoleService->urlTestingTools;
- *
- */
-class UrlTestingTools extends \Matomo\Dependencies\SearchEngineKeywordsPerformance\Google\Service\Resource
-{
-}
-// Adding a class alias for backwards compatibility with the previous class name.
-class_alias(UrlTestingTools::class, 'Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\Google_Service_SearchConsole_Resource_UrlTestingTools');
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/SearchConsole/Resource/UrlTestingToolsMobileFriendlyTest.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/SearchConsole/Resource/UrlTestingToolsMobileFriendlyTest.php
deleted file mode 100644
index 0d43a14..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/SearchConsole/Resource/UrlTestingToolsMobileFriendlyTest.php
+++ /dev/null
@@ -1,47 +0,0 @@
-
- * $searchconsoleService = new Google\Service\SearchConsole(...);
- * $mobileFriendlyTest = $searchconsoleService->mobileFriendlyTest;
- *
- */
-class UrlTestingToolsMobileFriendlyTest extends \Matomo\Dependencies\SearchEngineKeywordsPerformance\Google\Service\Resource
-{
- /**
- * Runs Mobile-Friendly Test for a given URL. (mobileFriendlyTest.run)
- *
- * @param RunMobileFriendlyTestRequest $postBody
- * @param array $optParams Optional parameters.
- * @return RunMobileFriendlyTestResponse
- */
- public function run(RunMobileFriendlyTestRequest $postBody, $optParams = [])
- {
- $params = ['postBody' => $postBody];
- $params = array_merge($params, $optParams);
- return $this->call('run', [$params], RunMobileFriendlyTestResponse::class);
- }
-}
-// Adding a class alias for backwards compatibility with the previous class name.
-class_alias(UrlTestingToolsMobileFriendlyTest::class, 'Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\Google_Service_SearchConsole_Resource_UrlTestingToolsMobileFriendlyTest');
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/SearchConsole/ResourceIssue.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/SearchConsole/ResourceIssue.php
deleted file mode 100644
index 1484a00..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/SearchConsole/ResourceIssue.php
+++ /dev/null
@@ -1,40 +0,0 @@
-blockedResource = $blockedResource;
- }
- /**
- * @return BlockedResource
- */
- public function getBlockedResource()
- {
- return $this->blockedResource;
- }
-}
-// Adding a class alias for backwards compatibility with the previous class name.
-class_alias(ResourceIssue::class, 'Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\Google_Service_SearchConsole_ResourceIssue');
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/SearchConsole/RunMobileFriendlyTestRequest.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/SearchConsole/RunMobileFriendlyTestRequest.php
deleted file mode 100644
index bec92cc..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/SearchConsole/RunMobileFriendlyTestRequest.php
+++ /dev/null
@@ -1,42 +0,0 @@
-requestScreenshot = $requestScreenshot;
- }
- public function getRequestScreenshot()
- {
- return $this->requestScreenshot;
- }
- public function setUrl($url)
- {
- $this->url = $url;
- }
- public function getUrl()
- {
- return $this->url;
- }
-}
-// Adding a class alias for backwards compatibility with the previous class name.
-class_alias(RunMobileFriendlyTestRequest::class, 'Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\Google_Service_SearchConsole_RunMobileFriendlyTestRequest');
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/SearchConsole/RunMobileFriendlyTestResponse.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/SearchConsole/RunMobileFriendlyTestResponse.php
deleted file mode 100644
index 6f16f10..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/SearchConsole/RunMobileFriendlyTestResponse.php
+++ /dev/null
@@ -1,98 +0,0 @@
-mobileFriendliness = $mobileFriendliness;
- }
- public function getMobileFriendliness()
- {
- return $this->mobileFriendliness;
- }
- /**
- * @param MobileFriendlyIssue[]
- */
- public function setMobileFriendlyIssues($mobileFriendlyIssues)
- {
- $this->mobileFriendlyIssues = $mobileFriendlyIssues;
- }
- /**
- * @return MobileFriendlyIssue[]
- */
- public function getMobileFriendlyIssues()
- {
- return $this->mobileFriendlyIssues;
- }
- /**
- * @param ResourceIssue[]
- */
- public function setResourceIssues($resourceIssues)
- {
- $this->resourceIssues = $resourceIssues;
- }
- /**
- * @return ResourceIssue[]
- */
- public function getResourceIssues()
- {
- return $this->resourceIssues;
- }
- /**
- * @param Image
- */
- public function setScreenshot(Image $screenshot)
- {
- $this->screenshot = $screenshot;
- }
- /**
- * @return Image
- */
- public function getScreenshot()
- {
- return $this->screenshot;
- }
- /**
- * @param TestStatus
- */
- public function setTestStatus(TestStatus $testStatus)
- {
- $this->testStatus = $testStatus;
- }
- /**
- * @return TestStatus
- */
- public function getTestStatus()
- {
- return $this->testStatus;
- }
-}
-// Adding a class alias for backwards compatibility with the previous class name.
-class_alias(RunMobileFriendlyTestResponse::class, 'Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\Google_Service_SearchConsole_RunMobileFriendlyTestResponse');
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/SearchConsole/SearchAnalyticsQueryRequest.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/SearchConsole/SearchAnalyticsQueryRequest.php
deleted file mode 100644
index ad7a15e..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/SearchConsole/SearchAnalyticsQueryRequest.php
+++ /dev/null
@@ -1,122 +0,0 @@
-aggregationType = $aggregationType;
- }
- public function getAggregationType()
- {
- return $this->aggregationType;
- }
- public function setDataState($dataState)
- {
- $this->dataState = $dataState;
- }
- public function getDataState()
- {
- return $this->dataState;
- }
- /**
- * @param ApiDimensionFilterGroup[]
- */
- public function setDimensionFilterGroups($dimensionFilterGroups)
- {
- $this->dimensionFilterGroups = $dimensionFilterGroups;
- }
- /**
- * @return ApiDimensionFilterGroup[]
- */
- public function getDimensionFilterGroups()
- {
- return $this->dimensionFilterGroups;
- }
- public function setDimensions($dimensions)
- {
- $this->dimensions = $dimensions;
- }
- public function getDimensions()
- {
- return $this->dimensions;
- }
- public function setEndDate($endDate)
- {
- $this->endDate = $endDate;
- }
- public function getEndDate()
- {
- return $this->endDate;
- }
- public function setRowLimit($rowLimit)
- {
- $this->rowLimit = $rowLimit;
- }
- public function getRowLimit()
- {
- return $this->rowLimit;
- }
- public function setSearchType($searchType)
- {
- $this->searchType = $searchType;
- }
- public function getSearchType()
- {
- return $this->searchType;
- }
- public function setStartDate($startDate)
- {
- $this->startDate = $startDate;
- }
- public function getStartDate()
- {
- return $this->startDate;
- }
- public function setStartRow($startRow)
- {
- $this->startRow = $startRow;
- }
- public function getStartRow()
- {
- return $this->startRow;
- }
- public function setType($type)
- {
- $this->type = $type;
- }
- public function getType()
- {
- return $this->type;
- }
-}
-// Adding a class alias for backwards compatibility with the previous class name.
-class_alias(SearchAnalyticsQueryRequest::class, 'Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\Google_Service_SearchConsole_SearchAnalyticsQueryRequest');
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/SearchConsole/SearchAnalyticsQueryResponse.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/SearchConsole/SearchAnalyticsQueryResponse.php
deleted file mode 100644
index 40f4dbd..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/SearchConsole/SearchAnalyticsQueryResponse.php
+++ /dev/null
@@ -1,50 +0,0 @@
-responseAggregationType = $responseAggregationType;
- }
- public function getResponseAggregationType()
- {
- return $this->responseAggregationType;
- }
- /**
- * @param ApiDataRow[]
- */
- public function setRows($rows)
- {
- $this->rows = $rows;
- }
- /**
- * @return ApiDataRow[]
- */
- public function getRows()
- {
- return $this->rows;
- }
-}
-// Adding a class alias for backwards compatibility with the previous class name.
-class_alias(SearchAnalyticsQueryResponse::class, 'Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\Google_Service_SearchConsole_SearchAnalyticsQueryResponse');
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/SearchConsole/SitemapsListResponse.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/SearchConsole/SitemapsListResponse.php
deleted file mode 100644
index 3a8e4f8..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/SearchConsole/SitemapsListResponse.php
+++ /dev/null
@@ -1,41 +0,0 @@
-sitemap = $sitemap;
- }
- /**
- * @return WmxSitemap[]
- */
- public function getSitemap()
- {
- return $this->sitemap;
- }
-}
-// Adding a class alias for backwards compatibility with the previous class name.
-class_alias(SitemapsListResponse::class, 'Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\Google_Service_SearchConsole_SitemapsListResponse');
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/SearchConsole/SitesListResponse.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/SearchConsole/SitesListResponse.php
deleted file mode 100644
index 794bac0..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/SearchConsole/SitesListResponse.php
+++ /dev/null
@@ -1,41 +0,0 @@
-siteEntry = $siteEntry;
- }
- /**
- * @return WmxSite[]
- */
- public function getSiteEntry()
- {
- return $this->siteEntry;
- }
-}
-// Adding a class alias for backwards compatibility with the previous class name.
-class_alias(SitesListResponse::class, 'Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\Google_Service_SearchConsole_SitesListResponse');
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/SearchConsole/TestStatus.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/SearchConsole/TestStatus.php
deleted file mode 100644
index f542027..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/SearchConsole/TestStatus.php
+++ /dev/null
@@ -1,42 +0,0 @@
-details = $details;
- }
- public function getDetails()
- {
- return $this->details;
- }
- public function setStatus($status)
- {
- $this->status = $status;
- }
- public function getStatus()
- {
- return $this->status;
- }
-}
-// Adding a class alias for backwards compatibility with the previous class name.
-class_alias(TestStatus::class, 'Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\Google_Service_SearchConsole_TestStatus');
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/SearchConsole/WmxSite.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/SearchConsole/WmxSite.php
deleted file mode 100644
index 40b9f4d..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/SearchConsole/WmxSite.php
+++ /dev/null
@@ -1,42 +0,0 @@
-permissionLevel = $permissionLevel;
- }
- public function getPermissionLevel()
- {
- return $this->permissionLevel;
- }
- public function setSiteUrl($siteUrl)
- {
- $this->siteUrl = $siteUrl;
- }
- public function getSiteUrl()
- {
- return $this->siteUrl;
- }
-}
-// Adding a class alias for backwards compatibility with the previous class name.
-class_alias(WmxSite::class, 'Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\Google_Service_SearchConsole_WmxSite');
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/SearchConsole/WmxSitemap.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/SearchConsole/WmxSitemap.php
deleted file mode 100644
index babe038..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/SearchConsole/WmxSitemap.php
+++ /dev/null
@@ -1,113 +0,0 @@
-contents = $contents;
- }
- /**
- * @return WmxSitemapContent[]
- */
- public function getContents()
- {
- return $this->contents;
- }
- public function setErrors($errors)
- {
- $this->errors = $errors;
- }
- public function getErrors()
- {
- return $this->errors;
- }
- public function setIsPending($isPending)
- {
- $this->isPending = $isPending;
- }
- public function getIsPending()
- {
- return $this->isPending;
- }
- public function setIsSitemapsIndex($isSitemapsIndex)
- {
- $this->isSitemapsIndex = $isSitemapsIndex;
- }
- public function getIsSitemapsIndex()
- {
- return $this->isSitemapsIndex;
- }
- public function setLastDownloaded($lastDownloaded)
- {
- $this->lastDownloaded = $lastDownloaded;
- }
- public function getLastDownloaded()
- {
- return $this->lastDownloaded;
- }
- public function setLastSubmitted($lastSubmitted)
- {
- $this->lastSubmitted = $lastSubmitted;
- }
- public function getLastSubmitted()
- {
- return $this->lastSubmitted;
- }
- public function setPath($path)
- {
- $this->path = $path;
- }
- public function getPath()
- {
- return $this->path;
- }
- public function setType($type)
- {
- $this->type = $type;
- }
- public function getType()
- {
- return $this->type;
- }
- public function setWarnings($warnings)
- {
- $this->warnings = $warnings;
- }
- public function getWarnings()
- {
- return $this->warnings;
- }
-}
-// Adding a class alias for backwards compatibility with the previous class name.
-class_alias(WmxSitemap::class, 'Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\Google_Service_SearchConsole_WmxSitemap');
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/SearchConsole/WmxSitemapContent.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/SearchConsole/WmxSitemapContent.php
deleted file mode 100644
index cb500e8..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/src/SearchConsole/WmxSitemapContent.php
+++ /dev/null
@@ -1,51 +0,0 @@
-indexed = $indexed;
- }
- public function getIndexed()
- {
- return $this->indexed;
- }
- public function setSubmitted($submitted)
- {
- $this->submitted = $submitted;
- }
- public function getSubmitted()
- {
- return $this->submitted;
- }
- public function setType($type)
- {
- $this->type = $type;
- }
- public function getType()
- {
- return $this->type;
- }
-}
-// Adding a class alias for backwards compatibility with the previous class name.
-class_alias(WmxSitemapContent::class, 'Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\Google_Service_SearchConsole_WmxSitemapContent');
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/synth.metadata b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/synth.metadata
deleted file mode 100644
index ccae829..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/synth.metadata
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "sources": [
- {
- "git": {
- "name": ".",
- "remote": "https://github.com/googleapis/google-api-php-client-services.git",
- "sha": "6056867755775c54a179bc49f29028c76b7ae0c2"
- }
- },
- {
- "git": {
- "name": "discovery-artifact-manager",
- "remote": "https://github.com/googleapis/discovery-artifact-manager.git",
- "sha": "4052db7ca555cbaf48bfaf93f32e575d7a3ff1d5"
- }
- }
- ]
-}
\ No newline at end of file
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/synth.py b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/synth.py
deleted file mode 100644
index 5dd63e2..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient-services/synth.py
+++ /dev/null
@@ -1,119 +0,0 @@
-# Copyright 2020 Google LLC
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-"""This script is used to synthesize generated parts of this library."""
-
-import synthtool as s
-from synthtool.__main__ import extra_args
-from synthtool import log, shell
-from synthtool.sources import git
-import logging
-from os import path, remove
-from pathlib import Path
-import glob
-import json
-import re
-import sys
-from packaging import version
-
-logging.basicConfig(level=logging.DEBUG)
-
-VERSION_REGEX = r"([^\.]*)\.(.+)\.json$"
-
-TEMPLATE_VERSIONS = [
- "default",
-]
-discovery_url = "https://github.com/googleapis/discovery-artifact-manager.git"
-
-repository = Path('.')
-
-log.debug(f"Cloning {discovery_url}.")
-discovery = git.clone(discovery_url)
-
-log.debug("Cleaning output directory.")
-shell.run("rm -rf .cache".split(), cwd=repository)
-
-log.debug("Installing dependencies.")
-shell.run(
- "python2 -m pip install -e generator/ --user".split(),
- cwd=repository
-)
-
-def generate_service(disco: str):
- m = re.search(VERSION_REGEX, disco)
- name = m.group(1)
- version = m.group(2)
- template = TEMPLATE_VERSIONS[-1] # Generate for latest version
-
- log.info(f"Generating {name} {version} ({template}).")
-
- output_dir = repository / ".cache" / name / version
- input_file = discovery / "discoveries" / disco
-
- command = (
- f"python2 -m googleapis.codegen --output_dir={output_dir}" +
- f" --input={input_file} --language=php --language_variant={template}" +
- f" --package_path=api/services"
- )
-
- shell.run(f"mkdir -p {output_dir}".split(), cwd=repository / "generator")
- shell.run(command.split(), cwd=repository, hide_output=False)
-
- s.copy(output_dir, f"src")
-
-def all_discoveries(skip=None, prefer=None):
- """Returns a map of API IDs to Discovery document filenames.
-
- Args:
- skip (list, optional): a list of API IDs to skip.
- prefer (list, optional): a list of API IDs to include.
-
- Returns:
- list(string): A list of Discovery document filenames.
- """
- discos = {}
- for file in sorted(glob.glob(str(discovery / 'discoveries/*.*.json'))):
- api_id = None
- with open(file) as api_file:
- api_id = json.load(api_file)['id']
- # If an API has already been visited, skip it.
- if api_id in discos:
- continue
- # Skip APIs explicitly listed in "skip" arg
- if skip and api_id in skip:
- continue
- discos[api_id] = path.basename(file)
-
- # Skip APIs not preferred in index.json and not listed in "prefer" arg
- index = {}
- with open(str(discovery / 'discoveries/index.json')) as file:
- index = json.load(file)
- for api in index['items']:
- api_id = api['id']
- if prefer and api_id in prefer:
- continue
- if api['preferred']:
- continue
- discos.pop(api_id, None)
-
- return discos.values()
-
-def generate_services(services):
- for service in services:
- generate_service(service)
-
-skip = ['discovery:v1', 'websecurityscanner:v1']
-prefer = ['admin:directory_v1', 'admin:datatransfer_v1']
-discoveries = all_discoveries(skip, prefer)
-generate_services(discoveries)
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient/LICENSE b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient/LICENSE
deleted file mode 100644
index a148ba5..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient/LICENSE
+++ /dev/null
@@ -1,203 +0,0 @@
-Apache License
-Version 2.0, January 2004
-http://www.apache.org/licenses/
-
-TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
-1. Definitions.
-
-"License" shall mean the terms and conditions for use, reproduction,
-and distribution as defined by Sections 1 through 9 of this document.
-
-"Licensor" shall mean the copyright owner or entity authorized by
-the copyright owner that is granting the License.
-
-"Legal Entity" shall mean the union of the acting entity and all
-other entities that control, are controlled by, or are under common
-control with that entity. For the purposes of this definition,
-"control" means (i) the power, direct or indirect, to cause the
-direction or management of such entity, whether by contract or
-otherwise, or (ii) ownership of fifty percent (50%) or more of the
-outstanding shares, or (iii) beneficial ownership of such entity.
-
-"You" (or "Your") shall mean an individual or Legal Entity
-exercising permissions granted by this License.
-
-"Source" form shall mean the preferred form for making modifications,
-including but not limited to software source code, documentation
-source, and configuration files.
-
-"Object" form shall mean any form resulting from mechanical
-transformation or translation of a Source form, including but
-not limited to compiled object code, generated documentation,
-and conversions to other media types.
-
-"Work" shall mean the work of authorship, whether in Source or
-Object form, made available under the License, as indicated by a
-copyright notice that is included in or attached to the work
-(an example is provided in the Appendix below).
-
-"Derivative Works" shall mean any work, whether in Source or Object
-form, that is based on (or derived from) the Work and for which the
-editorial revisions, annotations, elaborations, or other modifications
-represent, as a whole, an original work of authorship. For the purposes
-of this License, Derivative Works shall not include works that remain
-separable from, or merely link (or bind by name) to the interfaces of,
-the Work and Derivative Works thereof.
-
-"Contribution" shall mean any work of authorship, including
-the original version of the Work and any modifications or additions
-to that Work or Derivative Works thereof, that is intentionally
-submitted to Licensor for inclusion in the Work by the copyright owner
-or by an individual or Legal Entity authorized to submit on behalf of
-the copyright owner. For the purposes of this definition, "submitted"
-means any form of electronic, verbal, or written communication sent
-to the Licensor or its representatives, including but not limited to
-communication on electronic mailing lists, source code control systems,
-and issue tracking systems that are managed by, or on behalf of, the
-Licensor for the purpose of discussing and improving the Work, but
-excluding communication that is conspicuously marked or otherwise
-designated in writing by the copyright owner as "Not a Contribution."
-
-"Contributor" shall mean Licensor and any individual or Legal Entity
-on behalf of whom a Contribution has been received by Licensor and
-subsequently incorporated within the Work.
-
-2. Grant of Copyright License. Subject to the terms and conditions of
-this License, each Contributor hereby grants to You a perpetual,
-worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-copyright license to reproduce, prepare Derivative Works of,
-publicly display, publicly perform, sublicense, and distribute the
-Work and such Derivative Works in Source or Object form.
-
-3. Grant of Patent License. Subject to the terms and conditions of
-this License, each Contributor hereby grants to You a perpetual,
-worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-(except as stated in this section) patent license to make, have made,
-use, offer to sell, sell, import, and otherwise transfer the Work,
-where such license applies only to those patent claims licensable
-by such Contributor that are necessarily infringed by their
-Contribution(s) alone or by combination of their Contribution(s)
-with the Work to which such Contribution(s) was submitted. If You
-institute patent litigation against any entity (including a
-cross-claim or counterclaim in a lawsuit) alleging that the Work
-or a Contribution incorporated within the Work constitutes direct
-or contributory patent infringement, then any patent licenses
-granted to You under this License for that Work shall terminate
-as of the date such litigation is filed.
-
-4. Redistribution. You may reproduce and distribute copies of the
-Work or Derivative Works thereof in any medium, with or without
-modifications, and in Source or Object form, provided that You
-meet the following conditions:
-
-(a) You must give any other recipients of the Work or
-Derivative Works a copy of this License; and
-
-(b) You must cause any modified files to carry prominent notices
-stating that You changed the files; and
-
-(c) You must retain, in the Source form of any Derivative Works
-that You distribute, all copyright, patent, trademark, and
-attribution notices from the Source form of the Work,
-excluding those notices that do not pertain to any part of
-the Derivative Works; and
-
-(d) If the Work includes a "NOTICE" text file as part of its
-distribution, then any Derivative Works that You distribute must
-include a readable copy of the attribution notices contained
-within such NOTICE file, excluding those notices that do not
-pertain to any part of the Derivative Works, in at least one
-of the following places: within a NOTICE text file distributed
-as part of the Derivative Works; within the Source form or
-documentation, if provided along with the Derivative Works; or,
-within a display generated by the Derivative Works, if and
-wherever such third-party notices normally appear. The contents
-of the NOTICE file are for informational purposes only and
-do not modify the License. You may add Your own attribution
-notices within Derivative Works that You distribute, alongside
-or as an addendum to the NOTICE text from the Work, provided
-that such additional attribution notices cannot be construed
-as modifying the License.
-
-You may add Your own copyright statement to Your modifications and
-may provide additional or different license terms and conditions
-for use, reproduction, or distribution of Your modifications, or
-for any such Derivative Works as a whole, provided Your use,
-reproduction, and distribution of the Work otherwise complies with
-the conditions stated in this License.
-
-5. Submission of Contributions. Unless You explicitly state otherwise,
-any Contribution intentionally submitted for inclusion in the Work
-by You to the Licensor shall be under the terms and conditions of
-this License, without any additional terms or conditions.
-Notwithstanding the above, nothing herein shall supersede or modify
-the terms of any separate license agreement you may have executed
-with Licensor regarding such Contributions.
-
-6. Trademarks. This License does not grant permission to use the trade
-names, trademarks, service marks, or product names of the Licensor,
-except as required for reasonable and customary use in describing the
-origin of the Work and reproducing the content of the NOTICE file.
-
-7. Disclaimer of Warranty. Unless required by applicable law or
-agreed to in writing, Licensor provides the Work (and each
-Contributor provides its Contributions) on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-implied, including, without limitation, any warranties or conditions
-of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
-PARTICULAR PURPOSE. You are solely responsible for determining the
-appropriateness of using or redistributing the Work and assume any
-risks associated with Your exercise of permissions under this License.
-
-8. Limitation of Liability. In no event and under no legal theory,
-whether in tort (including negligence), contract, or otherwise,
-unless required by applicable law (such as deliberate and grossly
-negligent acts) or agreed to in writing, shall any Contributor be
-liable to You for damages, including any direct, indirect, special,
-incidental, or consequential damages of any character arising as a
-result of this License or out of the use or inability to use the
-Work (including but not limited to damages for loss of goodwill,
-work stoppage, computer failure or malfunction, or any and all
-other commercial damages or losses), even if such Contributor
-has been advised of the possibility of such damages.
-
-9. Accepting Warranty or Additional Liability. While redistributing
-the Work or Derivative Works thereof, You may choose to offer,
-and charge a fee for, acceptance of support, warranty, indemnity,
-or other liability obligations and/or rights consistent with this
-License. However, in accepting such obligations, You may act only
-on Your own behalf and on Your sole responsibility, not on behalf
-of any other Contributor, and only if You agree to indemnify,
-defend, and hold each Contributor harmless for any liability
-incurred by, or claims asserted against, such Contributor by reason
-of your accepting any such warranty or additional liability.
-
-END OF TERMS AND CONDITIONS
-
-APPENDIX: How to apply the Apache License to your work.
-
-To apply the Apache License to your work, attach the following
-boilerplate notice, with the fields enclosed by brackets "[]"
-replaced with your own identifying information. (Don't include
-the brackets!) The text should be enclosed in the appropriate
-comment syntax for the file format. We also recommend that a
-file or class name and description of purpose be included on the
-same "printed page" as the copyright notice for easier
-identification within third-party archives.
-
-Copyright [yyyy] [name of copyright owner]
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-
-
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient/src/AccessToken/Revoke.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient/src/AccessToken/Revoke.php
deleted file mode 100644
index 9ac4da2..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient/src/AccessToken/Revoke.php
+++ /dev/null
@@ -1,65 +0,0 @@
-http = $http;
- }
- /**
- * Revoke an OAuth2 access token or refresh token. This method will revoke the current access
- * token, if a token isn't provided.
- *
- * @param string|array $token The token (access token or a refresh token) that should be revoked.
- * @return boolean Returns True if the revocation was successful, otherwise False.
- */
- public function revokeToken($token)
- {
- if (is_array($token)) {
- if (isset($token['refresh_token'])) {
- $token = $token['refresh_token'];
- } else {
- $token = $token['access_token'];
- }
- }
- $body = Psr7\Utils::streamFor(http_build_query(['token' => $token]));
- $request = new Request('POST', Client::OAUTH2_REVOKE_URI, ['Cache-Control' => 'no-store', 'Content-Type' => 'application/x-www-form-urlencoded'], $body);
- $httpHandler = HttpHandlerFactory::build($this->http);
- $response = $httpHandler($request);
- return $response->getStatusCode() == 200;
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient/src/AccessToken/Verify.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient/src/AccessToken/Verify.php
deleted file mode 100644
index 7793e4d..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient/src/AccessToken/Verify.php
+++ /dev/null
@@ -1,217 +0,0 @@
-http = $http;
- $this->cache = $cache;
- $this->jwt = $jwt ?: $this->getJwtService();
- }
- /**
- * Verifies an id token and returns the authenticated apiLoginTicket.
- * Throws an exception if the id token is not valid.
- * The audience parameter can be used to control which id tokens are
- * accepted. By default, the id token must have been issued to this OAuth2 client.
- *
- * @param string $idToken the ID token in JWT format
- * @param string $audience Optional. The audience to verify against JWt "aud"
- * @return array|false the token payload, if successful
- */
- public function verifyIdToken($idToken, $audience = null)
- {
- if (empty($idToken)) {
- throw new LogicException('id_token cannot be null');
- }
- // set phpseclib constants if applicable
- $this->setPhpsecConstants();
- // Check signature
- $certs = $this->getFederatedSignOnCerts();
- foreach ($certs as $cert) {
- try {
- $args = [$idToken];
- $publicKey = $this->getPublicKey($cert);
- if (class_exists(Key::class)) {
- $args[] = new Key($publicKey, 'RS256');
- } else {
- $args[] = $publicKey;
- $args[] = ['RS256'];
- }
- $payload = \call_user_func_array([$this->jwt, 'decode'], $args);
- if (property_exists($payload, 'aud')) {
- if ($audience && $payload->aud != $audience) {
- return \false;
- }
- }
- // support HTTP and HTTPS issuers
- // @see https://developers.google.com/identity/sign-in/web/backend-auth
- $issuers = [self::OAUTH2_ISSUER, self::OAUTH2_ISSUER_HTTPS];
- if (!isset($payload->iss) || !in_array($payload->iss, $issuers)) {
- return \false;
- }
- return (array) $payload;
- } catch (ExpiredException $e) {
- // @phpstan-ignore-line
- return \false;
- } catch (ExpiredExceptionV3 $e) {
- return \false;
- } catch (SignatureInvalidException $e) {
- // continue
- } catch (DomainException $e) {
- // continue
- }
- }
- return \false;
- }
- private function getCache()
- {
- return $this->cache;
- }
- /**
- * Retrieve and cache a certificates file.
- *
- * @param string $url location
- * @throws \Google\Exception
- * @return array certificates
- */
- private function retrieveCertsFromLocation($url)
- {
- // If we're retrieving a local file, just grab it.
- if (0 !== strpos($url, 'http')) {
- if (!($file = file_get_contents($url))) {
- throw new GoogleException("Failed to retrieve verification certificates: '" . $url . "'.");
- }
- return json_decode($file, \true);
- }
- // @phpstan-ignore-next-line
- $response = $this->http->get($url);
- if ($response->getStatusCode() == 200) {
- return json_decode((string) $response->getBody(), \true);
- }
- throw new GoogleException(sprintf('Failed to retrieve verification certificates: "%s".', $response->getBody()->getContents()), $response->getStatusCode());
- }
- // Gets federated sign-on certificates to use for verifying identity tokens.
- // Returns certs as array structure, where keys are key ids, and values
- // are PEM encoded certificates.
- private function getFederatedSignOnCerts()
- {
- $certs = null;
- if ($cache = $this->getCache()) {
- $cacheItem = $cache->getItem('federated_signon_certs_v3');
- $certs = $cacheItem->get();
- }
- if (!$certs) {
- $certs = $this->retrieveCertsFromLocation(self::FEDERATED_SIGNON_CERT_URL);
- if ($cache) {
- $cacheItem->expiresAt(new DateTime('+1 hour'));
- $cacheItem->set($certs);
- $cache->save($cacheItem);
- }
- }
- if (!isset($certs['keys'])) {
- throw new InvalidArgumentException('federated sign-on certs expects "keys" to be set');
- }
- return $certs['keys'];
- }
- private function getJwtService()
- {
- $jwt = new JWT();
- if ($jwt::$leeway < 1) {
- // Ensures JWT leeway is at least 1
- // @see https://github.com/google/google-api-php-client/issues/827
- $jwt::$leeway = 1;
- }
- return $jwt;
- }
- private function getPublicKey($cert)
- {
- $modulus = new BigInteger($this->jwt->urlsafeB64Decode($cert['n']), 256);
- $exponent = new BigInteger($this->jwt->urlsafeB64Decode($cert['e']), 256);
- $component = ['n' => $modulus, 'e' => $exponent];
- $loader = PublicKeyLoader::load($component);
- return $loader->toString('PKCS8');
- }
- /**
- * phpseclib calls "phpinfo" by default, which requires special
- * whitelisting in the AppEngine VM environment. This function
- * sets constants to bypass the need for phpseclib to check phpinfo
- *
- * @see phpseclib/Math/BigInteger
- * @see https://github.com/GoogleCloudPlatform/getting-started-php/issues/85
- */
- private function setPhpsecConstants()
- {
- if (filter_var(getenv('GAE_VM'), \FILTER_VALIDATE_BOOLEAN)) {
- if (!defined('Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\MATH_BIGINTEGER_OPENSSL_ENABLED')) {
- define('Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\MATH_BIGINTEGER_OPENSSL_ENABLED', \true);
- }
- if (!defined('Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\CRYPT_RSA_MODE')) {
- define('Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\CRYPT_RSA_MODE', AES::ENGINE_OPENSSL);
- }
- }
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient/src/AuthHandler/AuthHandlerFactory.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient/src/AuthHandler/AuthHandlerFactory.php
deleted file mode 100644
index efd004f..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient/src/AuthHandler/AuthHandlerFactory.php
+++ /dev/null
@@ -1,47 +0,0 @@
-cache = $cache;
- $this->cacheConfig = $cacheConfig;
- }
- public function attachCredentials(ClientInterface $http, CredentialsLoader $credentials, callable $tokenCallback = null)
- {
- // use the provided cache
- if ($this->cache) {
- $credentials = new FetchAuthTokenCache($credentials, $this->cacheConfig, $this->cache);
- }
- return $this->attachCredentialsCache($http, $credentials, $tokenCallback);
- }
- public function attachCredentialsCache(ClientInterface $http, FetchAuthTokenCache $credentials, callable $tokenCallback = null)
- {
- // if we end up needing to make an HTTP request to retrieve credentials, we
- // can use our existing one, but we need to throw exceptions so the error
- // bubbles up.
- $authHttp = $this->createAuthHttp($http);
- $authHttpHandler = HttpHandlerFactory::build($authHttp);
- $middleware = new AuthTokenMiddleware($credentials, $authHttpHandler, $tokenCallback);
- $config = $http->getConfig();
- $config['handler']->remove('google_auth');
- $config['handler']->push($middleware, 'google_auth');
- $config['auth'] = 'google_auth';
- $http = new Client($config);
- return $http;
- }
- public function attachToken(ClientInterface $http, array $token, array $scopes)
- {
- $tokenFunc = function ($scopes) use($token) {
- return $token['access_token'];
- };
- $middleware = new ScopedAccessTokenMiddleware($tokenFunc, $scopes, $this->cacheConfig, $this->cache);
- $config = $http->getConfig();
- $config['handler']->remove('google_auth');
- $config['handler']->push($middleware, 'google_auth');
- $config['auth'] = 'scoped';
- $http = new Client($config);
- return $http;
- }
- public function attachKey(ClientInterface $http, $key)
- {
- $middleware = new SimpleMiddleware(['key' => $key]);
- $config = $http->getConfig();
- $config['handler']->remove('google_auth');
- $config['handler']->push($middleware, 'google_auth');
- $config['auth'] = 'simple';
- $http = new Client($config);
- return $http;
- }
- private function createAuthHttp(ClientInterface $http)
- {
- return new Client(['http_errors' => \true] + $http->getConfig());
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient/src/AuthHandler/Guzzle7AuthHandler.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient/src/AuthHandler/Guzzle7AuthHandler.php
deleted file mode 100644
index 967861a..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient/src/AuthHandler/Guzzle7AuthHandler.php
+++ /dev/null
@@ -1,25 +0,0 @@
-config = array_merge([
- 'application_name' => '',
- // Don't change these unless you're working against a special development
- // or testing environment.
- 'base_path' => self::API_BASE_PATH,
- // https://developers.google.com/console
- 'client_id' => '',
- 'client_secret' => '',
- // Can be a path to JSON credentials or an array representing those
- // credentials (@see Google\Client::setAuthConfig), or an instance of
- // Google\Auth\CredentialsLoader.
- 'credentials' => null,
- // @see Google\Client::setScopes
- 'scopes' => null,
- // Sets X-Goog-User-Project, which specifies a user project to bill
- // for access charges associated with the request
- 'quota_project' => null,
- 'redirect_uri' => null,
- 'state' => null,
- // Simple API access key, also from the API console. Ensure you get
- // a Server key, and not a Browser key.
- 'developer_key' => '',
- // For use with Google Cloud Platform
- // fetch the ApplicationDefaultCredentials, if applicable
- // @see https://developers.google.com/identity/protocols/application-default-credentials
- 'use_application_default_credentials' => \false,
- 'signing_key' => null,
- 'signing_algorithm' => null,
- 'subject' => null,
- // Other OAuth2 parameters.
- 'hd' => '',
- 'prompt' => '',
- 'openid.realm' => '',
- 'include_granted_scopes' => null,
- 'login_hint' => '',
- 'request_visible_actions' => '',
- 'access_type' => 'online',
- 'approval_prompt' => 'auto',
- // Task Runner retry configuration
- // @see Google\Task\Runner
- 'retry' => [],
- 'retry_map' => null,
- // Cache class implementing Psr\Cache\CacheItemPoolInterface.
- // Defaults to Google\Auth\Cache\MemoryCacheItemPool.
- 'cache' => null,
- // cache config for downstream auth caching
- 'cache_config' => [],
- // function to be called when an access token is fetched
- // follows the signature function ($cacheKey, $accessToken)
- 'token_callback' => null,
- // Service class used in Google\Client::verifyIdToken.
- // Explicitly pass this in to avoid setting JWT::$leeway
- 'jwt' => null,
- // Setting api_format_v2 will return more detailed error messages
- // from certain APIs.
- 'api_format_v2' => \false,
- ], $config);
- if (!is_null($this->config['credentials'])) {
- if ($this->config['credentials'] instanceof CredentialsLoader) {
- $this->credentials = $this->config['credentials'];
- } else {
- $this->setAuthConfig($this->config['credentials']);
- }
- unset($this->config['credentials']);
- }
- if (!is_null($this->config['scopes'])) {
- $this->setScopes($this->config['scopes']);
- unset($this->config['scopes']);
- }
- // Set a default token callback to update the in-memory access token
- if (is_null($this->config['token_callback'])) {
- $this->config['token_callback'] = function ($cacheKey, $newAccessToken) {
- $this->setAccessToken([
- 'access_token' => $newAccessToken,
- 'expires_in' => 3600,
- // Google default
- 'created' => time(),
- ]);
- };
- }
- if (!is_null($this->config['cache'])) {
- $this->setCache($this->config['cache']);
- unset($this->config['cache']);
- }
- }
- /**
- * Get a string containing the version of the library.
- *
- * @return string
- */
- public function getLibraryVersion()
- {
- return self::LIBVER;
- }
- /**
- * For backwards compatibility
- * alias for fetchAccessTokenWithAuthCode
- *
- * @param string $code string code from accounts.google.com
- * @return array access token
- * @deprecated
- */
- public function authenticate($code)
- {
- return $this->fetchAccessTokenWithAuthCode($code);
- }
- /**
- * Attempt to exchange a code for an valid authentication token.
- * Helper wrapped around the OAuth 2.0 implementation.
- *
- * @param string $code code from accounts.google.com
- * @param string $codeVerifier the code verifier used for PKCE (if applicable)
- * @return array access token
- */
- public function fetchAccessTokenWithAuthCode($code, $codeVerifier = null)
- {
- if (strlen($code) == 0) {
- throw new InvalidArgumentException("Invalid code");
- }
- $auth = $this->getOAuth2Service();
- $auth->setCode($code);
- $auth->setRedirectUri($this->getRedirectUri());
- if ($codeVerifier) {
- $auth->setCodeVerifier($codeVerifier);
- }
- $httpHandler = HttpHandlerFactory::build($this->getHttpClient());
- $creds = $auth->fetchAuthToken($httpHandler);
- if ($creds && isset($creds['access_token'])) {
- $creds['created'] = time();
- $this->setAccessToken($creds);
- }
- return $creds;
- }
- /**
- * For backwards compatibility
- * alias for fetchAccessTokenWithAssertion
- *
- * @return array access token
- * @deprecated
- */
- public function refreshTokenWithAssertion()
- {
- return $this->fetchAccessTokenWithAssertion();
- }
- /**
- * Fetches a fresh access token with a given assertion token.
- * @param ClientInterface $authHttp optional.
- * @return array access token
- */
- public function fetchAccessTokenWithAssertion(ClientInterface $authHttp = null)
- {
- if (!$this->isUsingApplicationDefaultCredentials()) {
- throw new DomainException('set the JSON service account credentials using' . ' Google\\Client::setAuthConfig or set the path to your JSON file' . ' with the "GOOGLE_APPLICATION_CREDENTIALS" environment variable' . ' and call Google\\Client::useApplicationDefaultCredentials to' . ' refresh a token with assertion.');
- }
- $this->getLogger()->log('info', 'OAuth2 access token refresh with Signed JWT assertion grants.');
- $credentials = $this->createApplicationDefaultCredentials();
- $httpHandler = HttpHandlerFactory::build($authHttp);
- $creds = $credentials->fetchAuthToken($httpHandler);
- if ($creds && isset($creds['access_token'])) {
- $creds['created'] = time();
- $this->setAccessToken($creds);
- }
- return $creds;
- }
- /**
- * For backwards compatibility
- * alias for fetchAccessTokenWithRefreshToken
- *
- * @param string $refreshToken
- * @return array access token
- */
- public function refreshToken($refreshToken)
- {
- return $this->fetchAccessTokenWithRefreshToken($refreshToken);
- }
- /**
- * Fetches a fresh OAuth 2.0 access token with the given refresh token.
- * @param string $refreshToken
- * @return array access token
- */
- public function fetchAccessTokenWithRefreshToken($refreshToken = null)
- {
- if (null === $refreshToken) {
- if (!isset($this->token['refresh_token'])) {
- throw new LogicException('refresh token must be passed in or set as part of setAccessToken');
- }
- $refreshToken = $this->token['refresh_token'];
- }
- $this->getLogger()->info('OAuth2 access token refresh');
- $auth = $this->getOAuth2Service();
- $auth->setRefreshToken($refreshToken);
- $httpHandler = HttpHandlerFactory::build($this->getHttpClient());
- $creds = $auth->fetchAuthToken($httpHandler);
- if ($creds && isset($creds['access_token'])) {
- $creds['created'] = time();
- if (!isset($creds['refresh_token'])) {
- $creds['refresh_token'] = $refreshToken;
- }
- $this->setAccessToken($creds);
- }
- return $creds;
- }
- /**
- * Create a URL to obtain user authorization.
- * The authorization endpoint allows the user to first
- * authenticate, and then grant/deny the access request.
- * @param string|array $scope The scope is expressed as an array or list of space-delimited strings.
- * @param array $queryParams Querystring params to add to the authorization URL.
- * @return string
- */
- public function createAuthUrl($scope = null, array $queryParams = [])
- {
- if (empty($scope)) {
- $scope = $this->prepareScopes();
- }
- if (is_array($scope)) {
- $scope = implode(' ', $scope);
- }
- // only accept one of prompt or approval_prompt
- $approvalPrompt = $this->config['prompt'] ? null : $this->config['approval_prompt'];
- // include_granted_scopes should be string "true", string "false", or null
- $includeGrantedScopes = $this->config['include_granted_scopes'] === null ? null : var_export($this->config['include_granted_scopes'], \true);
- $params = array_filter(['access_type' => $this->config['access_type'], 'approval_prompt' => $approvalPrompt, 'hd' => $this->config['hd'], 'include_granted_scopes' => $includeGrantedScopes, 'login_hint' => $this->config['login_hint'], 'openid.realm' => $this->config['openid.realm'], 'prompt' => $this->config['prompt'], 'redirect_uri' => $this->config['redirect_uri'], 'response_type' => 'code', 'scope' => $scope, 'state' => $this->config['state']]) + $queryParams;
- // If the list of scopes contains plus.login, add request_visible_actions
- // to auth URL.
- $rva = $this->config['request_visible_actions'];
- if (strlen($rva) > 0 && \false !== strpos($scope, 'plus.login')) {
- $params['request_visible_actions'] = $rva;
- }
- $auth = $this->getOAuth2Service();
- return (string) $auth->buildFullAuthorizationUri($params);
- }
- /**
- * Adds auth listeners to the HTTP client based on the credentials
- * set in the Google API Client object
- *
- * @param ClientInterface $http the http client object.
- * @return ClientInterface the http client object
- */
- public function authorize(ClientInterface $http = null)
- {
- $http = $http ?: $this->getHttpClient();
- $authHandler = $this->getAuthHandler();
- // These conditionals represent the decision tree for authentication
- // 1. Check if a Google\Auth\CredentialsLoader instance has been supplied via the "credentials" option
- // 2. Check for Application Default Credentials
- // 3a. Check for an Access Token
- // 3b. If access token exists but is expired, try to refresh it
- // 4. Check for API Key
- if ($this->credentials) {
- return $authHandler->attachCredentials($http, $this->credentials, $this->config['token_callback']);
- }
- if ($this->isUsingApplicationDefaultCredentials()) {
- $credentials = $this->createApplicationDefaultCredentials();
- return $authHandler->attachCredentialsCache($http, $credentials, $this->config['token_callback']);
- }
- if ($token = $this->getAccessToken()) {
- $scopes = $this->prepareScopes();
- // add refresh subscriber to request a new token
- if (isset($token['refresh_token']) && $this->isAccessTokenExpired()) {
- $credentials = $this->createUserRefreshCredentials($scopes, $token['refresh_token']);
- return $authHandler->attachCredentials($http, $credentials, $this->config['token_callback']);
- }
- return $authHandler->attachToken($http, $token, (array) $scopes);
- }
- if ($key = $this->config['developer_key']) {
- return $authHandler->attachKey($http, $key);
- }
- return $http;
- }
- /**
- * Set the configuration to use application default credentials for
- * authentication
- *
- * @see https://developers.google.com/identity/protocols/application-default-credentials
- * @param boolean $useAppCreds
- */
- public function useApplicationDefaultCredentials($useAppCreds = \true)
- {
- $this->config['use_application_default_credentials'] = $useAppCreds;
- }
- /**
- * To prevent useApplicationDefaultCredentials from inappropriately being
- * called in a conditional
- *
- * @see https://developers.google.com/identity/protocols/application-default-credentials
- */
- public function isUsingApplicationDefaultCredentials()
- {
- return $this->config['use_application_default_credentials'];
- }
- /**
- * Set the access token used for requests.
- *
- * Note that at the time requests are sent, tokens are cached. A token will be
- * cached for each combination of service and authentication scopes. If a
- * cache pool is not provided, creating a new instance of the client will
- * allow modification of access tokens. If a persistent cache pool is
- * provided, in order to change the access token, you must clear the cached
- * token by calling `$client->getCache()->clear()`. (Use caution in this case,
- * as calling `clear()` will remove all cache items, including any items not
- * related to Google API PHP Client.)
- *
- * @param string|array $token
- * @throws InvalidArgumentException
- */
- public function setAccessToken($token)
- {
- if (is_string($token)) {
- if ($json = json_decode($token, \true)) {
- $token = $json;
- } else {
- // assume $token is just the token string
- $token = ['access_token' => $token];
- }
- }
- if ($token == null) {
- throw new InvalidArgumentException('invalid json token');
- }
- if (!isset($token['access_token'])) {
- throw new InvalidArgumentException("Invalid token format");
- }
- $this->token = $token;
- }
- public function getAccessToken()
- {
- return $this->token;
- }
- /**
- * @return string|null
- */
- public function getRefreshToken()
- {
- if (isset($this->token['refresh_token'])) {
- return $this->token['refresh_token'];
- }
- return null;
- }
- /**
- * Returns if the access_token is expired.
- * @return bool Returns True if the access_token is expired.
- */
- public function isAccessTokenExpired()
- {
- if (!$this->token) {
- return \true;
- }
- $created = 0;
- if (isset($this->token['created'])) {
- $created = $this->token['created'];
- } elseif (isset($this->token['id_token'])) {
- // check the ID token for "iat"
- // signature verification is not required here, as we are just
- // using this for convenience to save a round trip request
- // to the Google API server
- $idToken = $this->token['id_token'];
- if (substr_count($idToken, '.') == 2) {
- $parts = explode('.', $idToken);
- $payload = json_decode(base64_decode($parts[1]), \true);
- if ($payload && isset($payload['iat'])) {
- $created = $payload['iat'];
- }
- }
- }
- if (!isset($this->token['expires_in'])) {
- // if the token does not have an "expires_in", then it's considered expired
- return \true;
- }
- // If the token is set to expire in the next 30 seconds.
- return $created + ($this->token['expires_in'] - 30) < time();
- }
- /**
- * @deprecated See UPGRADING.md for more information
- */
- public function getAuth()
- {
- throw new BadMethodCallException('This function no longer exists. See UPGRADING.md for more information');
- }
- /**
- * @deprecated See UPGRADING.md for more information
- */
- public function setAuth($auth)
- {
- throw new BadMethodCallException('This function no longer exists. See UPGRADING.md for more information');
- }
- /**
- * Set the OAuth 2.0 Client ID.
- * @param string $clientId
- */
- public function setClientId($clientId)
- {
- $this->config['client_id'] = $clientId;
- }
- public function getClientId()
- {
- return $this->config['client_id'];
- }
- /**
- * Set the OAuth 2.0 Client Secret.
- * @param string $clientSecret
- */
- public function setClientSecret($clientSecret)
- {
- $this->config['client_secret'] = $clientSecret;
- }
- public function getClientSecret()
- {
- return $this->config['client_secret'];
- }
- /**
- * Set the OAuth 2.0 Redirect URI.
- * @param string $redirectUri
- */
- public function setRedirectUri($redirectUri)
- {
- $this->config['redirect_uri'] = $redirectUri;
- }
- public function getRedirectUri()
- {
- return $this->config['redirect_uri'];
- }
- /**
- * Set OAuth 2.0 "state" parameter to achieve per-request customization.
- * @see http://tools.ietf.org/html/draft-ietf-oauth-v2-22#section-3.1.2.2
- * @param string $state
- */
- public function setState($state)
- {
- $this->config['state'] = $state;
- }
- /**
- * @param string $accessType Possible values for access_type include:
- * {@code "offline"} to request offline access from the user.
- * {@code "online"} to request online access from the user.
- */
- public function setAccessType($accessType)
- {
- $this->config['access_type'] = $accessType;
- }
- /**
- * @param string $approvalPrompt Possible values for approval_prompt include:
- * {@code "force"} to force the approval UI to appear.
- * {@code "auto"} to request auto-approval when possible. (This is the default value)
- */
- public function setApprovalPrompt($approvalPrompt)
- {
- $this->config['approval_prompt'] = $approvalPrompt;
- }
- /**
- * Set the login hint, email address or sub id.
- * @param string $loginHint
- */
- public function setLoginHint($loginHint)
- {
- $this->config['login_hint'] = $loginHint;
- }
- /**
- * Set the application name, this is included in the User-Agent HTTP header.
- * @param string $applicationName
- */
- public function setApplicationName($applicationName)
- {
- $this->config['application_name'] = $applicationName;
- }
- /**
- * If 'plus.login' is included in the list of requested scopes, you can use
- * this method to define types of app activities that your app will write.
- * You can find a list of available types here:
- * @link https://developers.google.com/+/api/moment-types
- *
- * @param array $requestVisibleActions Array of app activity types
- */
- public function setRequestVisibleActions($requestVisibleActions)
- {
- if (is_array($requestVisibleActions)) {
- $requestVisibleActions = implode(" ", $requestVisibleActions);
- }
- $this->config['request_visible_actions'] = $requestVisibleActions;
- }
- /**
- * Set the developer key to use, these are obtained through the API Console.
- * @see http://code.google.com/apis/console-help/#generatingdevkeys
- * @param string $developerKey
- */
- public function setDeveloperKey($developerKey)
- {
- $this->config['developer_key'] = $developerKey;
- }
- /**
- * Set the hd (hosted domain) parameter streamlines the login process for
- * Google Apps hosted accounts. By including the domain of the user, you
- * restrict sign-in to accounts at that domain.
- * @param string $hd the domain to use.
- */
- public function setHostedDomain($hd)
- {
- $this->config['hd'] = $hd;
- }
- /**
- * Set the prompt hint. Valid values are none, consent and select_account.
- * If no value is specified and the user has not previously authorized
- * access, then the user is shown a consent screen.
- * @param string $prompt
- * {@code "none"} Do not display any authentication or consent screens. Must not be specified with other values.
- * {@code "consent"} Prompt the user for consent.
- * {@code "select_account"} Prompt the user to select an account.
- */
- public function setPrompt($prompt)
- {
- $this->config['prompt'] = $prompt;
- }
- /**
- * openid.realm is a parameter from the OpenID 2.0 protocol, not from OAuth
- * 2.0. It is used in OpenID 2.0 requests to signify the URL-space for which
- * an authentication request is valid.
- * @param string $realm the URL-space to use.
- */
- public function setOpenidRealm($realm)
- {
- $this->config['openid.realm'] = $realm;
- }
- /**
- * If this is provided with the value true, and the authorization request is
- * granted, the authorization will include any previous authorizations
- * granted to this user/application combination for other scopes.
- * @param bool $include the URL-space to use.
- */
- public function setIncludeGrantedScopes($include)
- {
- $this->config['include_granted_scopes'] = $include;
- }
- /**
- * sets function to be called when an access token is fetched
- * @param callable $tokenCallback - function ($cacheKey, $accessToken)
- */
- public function setTokenCallback(callable $tokenCallback)
- {
- $this->config['token_callback'] = $tokenCallback;
- }
- /**
- * Revoke an OAuth2 access token or refresh token. This method will revoke the current access
- * token, if a token isn't provided.
- *
- * @param string|array|null $token The token (access token or a refresh token) that should be revoked.
- * @return boolean Returns True if the revocation was successful, otherwise False.
- */
- public function revokeToken($token = null)
- {
- $tokenRevoker = new Revoke($this->getHttpClient());
- return $tokenRevoker->revokeToken($token ?: $this->getAccessToken());
- }
- /**
- * Verify an id_token. This method will verify the current id_token, if one
- * isn't provided.
- *
- * @throws LogicException If no token was provided and no token was set using `setAccessToken`.
- * @throws UnexpectedValueException If the token is not a valid JWT.
- * @param string|null $idToken The token (id_token) that should be verified.
- * @return array|false Returns the token payload as an array if the verification was
- * successful, false otherwise.
- */
- public function verifyIdToken($idToken = null)
- {
- $tokenVerifier = new Verify($this->getHttpClient(), $this->getCache(), $this->config['jwt']);
- if (null === $idToken) {
- $token = $this->getAccessToken();
- if (!isset($token['id_token'])) {
- throw new LogicException('id_token must be passed in or set as part of setAccessToken');
- }
- $idToken = $token['id_token'];
- }
- return $tokenVerifier->verifyIdToken($idToken, $this->getClientId());
- }
- /**
- * Set the scopes to be requested. Must be called before createAuthUrl().
- * Will remove any previously configured scopes.
- * @param string|array $scope_or_scopes, ie:
- * array(
- * 'https://www.googleapis.com/auth/plus.login',
- * 'https://www.googleapis.com/auth/moderator'
- * );
- */
- public function setScopes($scope_or_scopes)
- {
- $this->requestedScopes = [];
- $this->addScope($scope_or_scopes);
- }
- /**
- * This functions adds a scope to be requested as part of the OAuth2.0 flow.
- * Will append any scopes not previously requested to the scope parameter.
- * A single string will be treated as a scope to request. An array of strings
- * will each be appended.
- * @param string|string[] $scope_or_scopes e.g. "profile"
- */
- public function addScope($scope_or_scopes)
- {
- if (is_string($scope_or_scopes) && !in_array($scope_or_scopes, $this->requestedScopes)) {
- $this->requestedScopes[] = $scope_or_scopes;
- } elseif (is_array($scope_or_scopes)) {
- foreach ($scope_or_scopes as $scope) {
- $this->addScope($scope);
- }
- }
- }
- /**
- * Returns the list of scopes requested by the client
- * @return array the list of scopes
- *
- */
- public function getScopes()
- {
- return $this->requestedScopes;
- }
- /**
- * @return string|null
- * @visible For Testing
- */
- public function prepareScopes()
- {
- if (empty($this->requestedScopes)) {
- return null;
- }
- return implode(' ', $this->requestedScopes);
- }
- /**
- * Helper method to execute deferred HTTP requests.
- *
- * @template T
- * @param RequestInterface $request
- * @param class-string|false|null $expectedClass
- * @throws \Google\Exception
- * @return mixed|T|ResponseInterface
- */
- public function execute(RequestInterface $request, $expectedClass = null)
- {
- $request = $request->withHeader('User-Agent', sprintf('%s %s%s', $this->config['application_name'], self::USER_AGENT_SUFFIX, $this->getLibraryVersion()))->withHeader('x-goog-api-client', sprintf('gl-php/%s gdcl/%s', phpversion(), $this->getLibraryVersion()));
- if ($this->config['api_format_v2']) {
- $request = $request->withHeader('X-GOOG-API-FORMAT-VERSION', '2');
- }
- // call the authorize method
- // this is where most of the grunt work is done
- $http = $this->authorize();
- return REST::execute($http, $request, $expectedClass, $this->config['retry'], $this->config['retry_map']);
- }
- /**
- * Declare whether batch calls should be used. This may increase throughput
- * by making multiple requests in one connection.
- *
- * @param boolean $useBatch True if the batch support should
- * be enabled. Defaults to False.
- */
- public function setUseBatch($useBatch)
- {
- // This is actually an alias for setDefer.
- $this->setDefer($useBatch);
- }
- /**
- * Are we running in Google AppEngine?
- * return bool
- */
- public function isAppEngine()
- {
- return isset($_SERVER['SERVER_SOFTWARE']) && strpos($_SERVER['SERVER_SOFTWARE'], 'Google App Engine') !== \false;
- }
- public function setConfig($name, $value)
- {
- $this->config[$name] = $value;
- }
- public function getConfig($name, $default = null)
- {
- return isset($this->config[$name]) ? $this->config[$name] : $default;
- }
- /**
- * For backwards compatibility
- * alias for setAuthConfig
- *
- * @param string $file the configuration file
- * @throws \Google\Exception
- * @deprecated
- */
- public function setAuthConfigFile($file)
- {
- $this->setAuthConfig($file);
- }
- /**
- * Set the auth config from new or deprecated JSON config.
- * This structure should match the file downloaded from
- * the "Download JSON" button on in the Google Developer
- * Console.
- * @param string|array $config the configuration json
- * @throws \Google\Exception
- */
- public function setAuthConfig($config)
- {
- if (is_string($config)) {
- if (!file_exists($config)) {
- throw new InvalidArgumentException(sprintf('file "%s" does not exist', $config));
- }
- $json = file_get_contents($config);
- if (!($config = json_decode($json, \true))) {
- throw new LogicException('invalid json for auth config');
- }
- }
- $key = isset($config['installed']) ? 'installed' : 'web';
- if (isset($config['type']) && $config['type'] == 'service_account') {
- // application default credentials
- $this->useApplicationDefaultCredentials();
- // set the information from the config
- $this->setClientId($config['client_id']);
- $this->config['client_email'] = $config['client_email'];
- $this->config['signing_key'] = $config['private_key'];
- $this->config['signing_algorithm'] = 'HS256';
- } elseif (isset($config[$key])) {
- // old-style
- $this->setClientId($config[$key]['client_id']);
- $this->setClientSecret($config[$key]['client_secret']);
- if (isset($config[$key]['redirect_uris'])) {
- $this->setRedirectUri($config[$key]['redirect_uris'][0]);
- }
- } else {
- // new-style
- $this->setClientId($config['client_id']);
- $this->setClientSecret($config['client_secret']);
- if (isset($config['redirect_uris'])) {
- $this->setRedirectUri($config['redirect_uris'][0]);
- }
- }
- }
- /**
- * Use when the service account has been delegated domain wide access.
- *
- * @param string $subject an email address account to impersonate
- */
- public function setSubject($subject)
- {
- $this->config['subject'] = $subject;
- }
- /**
- * Declare whether making API calls should make the call immediately, or
- * return a request which can be called with ->execute();
- *
- * @param boolean $defer True if calls should not be executed right away.
- */
- public function setDefer($defer)
- {
- $this->deferExecution = $defer;
- }
- /**
- * Whether or not to return raw requests
- * @return boolean
- */
- public function shouldDefer()
- {
- return $this->deferExecution;
- }
- /**
- * @return OAuth2 implementation
- */
- public function getOAuth2Service()
- {
- if (!isset($this->auth)) {
- $this->auth = $this->createOAuth2Service();
- }
- return $this->auth;
- }
- /**
- * create a default google auth object
- */
- protected function createOAuth2Service()
- {
- $auth = new OAuth2(['clientId' => $this->getClientId(), 'clientSecret' => $this->getClientSecret(), 'authorizationUri' => self::OAUTH2_AUTH_URL, 'tokenCredentialUri' => self::OAUTH2_TOKEN_URI, 'redirectUri' => $this->getRedirectUri(), 'issuer' => $this->config['client_id'], 'signingKey' => $this->config['signing_key'], 'signingAlgorithm' => $this->config['signing_algorithm']]);
- return $auth;
- }
- /**
- * Set the Cache object
- * @param CacheItemPoolInterface $cache
- */
- public function setCache(CacheItemPoolInterface $cache)
- {
- $this->cache = $cache;
- }
- /**
- * @return CacheItemPoolInterface
- */
- public function getCache()
- {
- if (!$this->cache) {
- $this->cache = $this->createDefaultCache();
- }
- return $this->cache;
- }
- /**
- * @param array $cacheConfig
- */
- public function setCacheConfig(array $cacheConfig)
- {
- $this->config['cache_config'] = $cacheConfig;
- }
- /**
- * Set the Logger object
- * @param LoggerInterface $logger
- */
- public function setLogger(LoggerInterface $logger)
- {
- $this->logger = $logger;
- }
- /**
- * @return LoggerInterface
- */
- public function getLogger()
- {
- if (!isset($this->logger)) {
- $this->logger = $this->createDefaultLogger();
- }
- return $this->logger;
- }
- protected function createDefaultLogger()
- {
- $logger = new Logger('google-api-php-client');
- if ($this->isAppEngine()) {
- $handler = new MonologSyslogHandler('app', \LOG_USER, Logger::NOTICE);
- } else {
- $handler = new MonologStreamHandler('php://stderr', Logger::NOTICE);
- }
- $logger->pushHandler($handler);
- return $logger;
- }
- protected function createDefaultCache()
- {
- return new MemoryCacheItemPool();
- }
- /**
- * Set the Http Client object
- * @param ClientInterface $http
- */
- public function setHttpClient(ClientInterface $http)
- {
- $this->http = $http;
- }
- /**
- * @return ClientInterface
- */
- public function getHttpClient()
- {
- if (null === $this->http) {
- $this->http = $this->createDefaultHttpClient();
- }
- return $this->http;
- }
- /**
- * Set the API format version.
- *
- * `true` will use V2, which may return more useful error messages.
- *
- * @param bool $value
- */
- public function setApiFormatV2($value)
- {
- $this->config['api_format_v2'] = (bool) $value;
- }
- protected function createDefaultHttpClient()
- {
- $guzzleVersion = null;
- if (defined('Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\GuzzleHttp\\ClientInterface::MAJOR_VERSION')) {
- $guzzleVersion = ClientInterface::MAJOR_VERSION;
- } elseif (defined('Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\GuzzleHttp\\ClientInterface::VERSION')) {
- $guzzleVersion = (int) substr(ClientInterface::VERSION, 0, 1);
- }
- if (5 === $guzzleVersion) {
- $options = ['base_url' => $this->config['base_path'], 'defaults' => ['exceptions' => \false]];
- if ($this->isAppEngine()) {
- if (class_exists(StreamHandler::class)) {
- // set StreamHandler on AppEngine by default
- $options['handler'] = new StreamHandler();
- $options['defaults']['verify'] = '/etc/ca-certificates.crt';
- }
- }
- } elseif (6 === $guzzleVersion || 7 === $guzzleVersion) {
- // guzzle 6 or 7
- $options = ['base_uri' => $this->config['base_path'], 'http_errors' => \false];
- } else {
- throw new LogicException('Could not find supported version of Guzzle.');
- }
- return new GuzzleClient($options);
- }
- /**
- * @return FetchAuthTokenCache
- */
- private function createApplicationDefaultCredentials()
- {
- $scopes = $this->prepareScopes();
- $sub = $this->config['subject'];
- $signingKey = $this->config['signing_key'];
- // create credentials using values supplied in setAuthConfig
- if ($signingKey) {
- $serviceAccountCredentials = ['client_id' => $this->config['client_id'], 'client_email' => $this->config['client_email'], 'private_key' => $signingKey, 'type' => 'service_account', 'quota_project_id' => $this->config['quota_project']];
- $credentials = CredentialsLoader::makeCredentials($scopes, $serviceAccountCredentials);
- } else {
- // When $sub is provided, we cannot pass cache classes to ::getCredentials
- // because FetchAuthTokenCache::setSub does not exist.
- // The result is when $sub is provided, calls to ::onGce are not cached.
- $credentials = ApplicationDefaultCredentials::getCredentials($scopes, null, $sub ? null : $this->config['cache_config'], $sub ? null : $this->getCache(), $this->config['quota_project']);
- }
- // for service account domain-wide authority (impersonating a user)
- // @see https://developers.google.com/identity/protocols/OAuth2ServiceAccount
- if ($sub) {
- if (!$credentials instanceof ServiceAccountCredentials) {
- throw new DomainException('domain-wide authority requires service account credentials');
- }
- $credentials->setSub($sub);
- }
- // If we are not using FetchAuthTokenCache yet, create it now
- if (!$credentials instanceof FetchAuthTokenCache) {
- $credentials = new FetchAuthTokenCache($credentials, $this->config['cache_config'], $this->getCache());
- }
- return $credentials;
- }
- protected function getAuthHandler()
- {
- // Be very careful using the cache, as the underlying auth library's cache
- // implementation is naive, and the cache keys do not account for user
- // sessions.
- //
- // @see https://github.com/google/google-api-php-client/issues/821
- return AuthHandlerFactory::build($this->getCache(), $this->config['cache_config']);
- }
- private function createUserRefreshCredentials($scope, $refreshToken)
- {
- $creds = array_filter(['client_id' => $this->getClientId(), 'client_secret' => $this->getClientSecret(), 'refresh_token' => $refreshToken]);
- return new UserRefreshCredentials($scope, $creds);
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient/src/Collection.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient/src/Collection.php
deleted file mode 100644
index 83fd2c7..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient/src/Collection.php
+++ /dev/null
@@ -1,104 +0,0 @@
-{$this->collection_key}) && is_array($this->{$this->collection_key})) {
- reset($this->{$this->collection_key});
- }
- }
- /** @return mixed */
- #[\ReturnTypeWillChange]
- public function current()
- {
- $this->coerceType($this->key());
- if (is_array($this->{$this->collection_key})) {
- return current($this->{$this->collection_key});
- }
- }
- /** @return mixed */
- #[\ReturnTypeWillChange]
- public function key()
- {
- if (isset($this->{$this->collection_key}) && is_array($this->{$this->collection_key})) {
- return key($this->{$this->collection_key});
- }
- }
- /** @return mixed */
- #[\ReturnTypeWillChange]
- public function next()
- {
- return next($this->{$this->collection_key});
- }
- /** @return bool */
- #[\ReturnTypeWillChange]
- public function valid()
- {
- $key = $this->key();
- return $key !== null && $key !== \false;
- }
- /** @return int */
- #[\ReturnTypeWillChange]
- public function count()
- {
- if (!isset($this->{$this->collection_key})) {
- return 0;
- }
- return count($this->{$this->collection_key});
- }
- /** @return bool */
- #[\ReturnTypeWillChange]
- public function offsetExists($offset)
- {
- if (!is_numeric($offset)) {
- return parent::offsetExists($offset);
- }
- return isset($this->{$this->collection_key}[$offset]);
- }
- /** @return mixed */
- #[\ReturnTypeWillChange]
- public function offsetGet($offset)
- {
- if (!is_numeric($offset)) {
- return parent::offsetGet($offset);
- }
- $this->coerceType($offset);
- return $this->{$this->collection_key}[$offset];
- }
- /** @return void */
- #[\ReturnTypeWillChange]
- public function offsetSet($offset, $value)
- {
- if (!is_numeric($offset)) {
- parent::offsetSet($offset, $value);
- }
- $this->{$this->collection_key}[$offset] = $value;
- }
- /** @return void */
- #[\ReturnTypeWillChange]
- public function offsetUnset($offset)
- {
- if (!is_numeric($offset)) {
- parent::offsetUnset($offset);
- }
- unset($this->{$this->collection_key}[$offset]);
- }
- private function coerceType($offset)
- {
- $keyType = $this->keyType($this->collection_key);
- if ($keyType && !is_object($this->{$this->collection_key}[$offset])) {
- $this->{$this->collection_key}[$offset] = new $keyType($this->{$this->collection_key}[$offset]);
- }
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient/src/Exception.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient/src/Exception.php
deleted file mode 100644
index 462066e..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient/src/Exception.php
+++ /dev/null
@@ -1,23 +0,0 @@
-client = $client;
- $this->boundary = $boundary ?: mt_rand();
- $this->rootUrl = rtrim($rootUrl ?: $this->client->getConfig('base_path'), '/');
- $this->batchPath = $batchPath ?: self::BATCH_PATH;
- }
- public function add(RequestInterface $request, $key = \false)
- {
- if (\false == $key) {
- $key = mt_rand();
- }
- $this->requests[$key] = $request;
- }
- public function execute()
- {
- $body = '';
- $classes = [];
- $batchHttpTemplate = <<requests as $key => $request) {
- $firstLine = sprintf('%s %s HTTP/%s', $request->getMethod(), $request->getRequestTarget(), $request->getProtocolVersion());
- $content = (string) $request->getBody();
- $headers = '';
- foreach ($request->getHeaders() as $name => $values) {
- $headers .= sprintf("%s:%s\r\n", $name, implode(', ', $values));
- }
- $body .= sprintf($batchHttpTemplate, $this->boundary, $key, $firstLine, $headers, $content ? "\n" . $content : '');
- $classes['response-' . $key] = $request->getHeaderLine('X-Php-Expected-Class');
- }
- $body .= "--{$this->boundary}--";
- $body = trim($body);
- $url = $this->rootUrl . '/' . $this->batchPath;
- $headers = ['Content-Type' => sprintf('multipart/mixed; boundary=%s', $this->boundary), 'Content-Length' => (string) strlen($body)];
- $request = new Request('POST', $url, $headers, $body);
- $response = $this->client->execute($request);
- return $this->parseResponse($response, $classes);
- }
- public function parseResponse(ResponseInterface $response, $classes = [])
- {
- $contentType = $response->getHeaderLine('content-type');
- $contentType = explode(';', $contentType);
- $boundary = \false;
- foreach ($contentType as $part) {
- $part = explode('=', $part, 2);
- if (isset($part[0]) && 'boundary' == trim($part[0])) {
- $boundary = $part[1];
- }
- }
- $body = (string) $response->getBody();
- if (!empty($body)) {
- $body = str_replace("--{$boundary}--", "--{$boundary}", $body);
- $parts = explode("--{$boundary}", $body);
- $responses = [];
- $requests = array_values($this->requests);
- foreach ($parts as $i => $part) {
- $part = trim($part);
- if (!empty($part)) {
- list($rawHeaders, $part) = explode("\r\n\r\n", $part, 2);
- $headers = $this->parseRawHeaders($rawHeaders);
- $status = substr($part, 0, strpos($part, "\n"));
- $status = explode(" ", $status);
- $status = $status[1];
- list($partHeaders, $partBody) = $this->parseHttpResponse($part, 0);
- $response = new Response((int) $status, $partHeaders, Psr7\Utils::streamFor($partBody));
- // Need content id.
- $key = $headers['content-id'];
- try {
- $response = REST::decodeHttpResponse($response, $requests[$i - 1]);
- } catch (GoogleServiceException $e) {
- // Store the exception as the response, so successful responses
- // can be processed.
- $response = $e;
- }
- $responses[$key] = $response;
- }
- }
- return $responses;
- }
- return null;
- }
- private function parseRawHeaders($rawHeaders)
- {
- $headers = [];
- $responseHeaderLines = explode("\r\n", $rawHeaders);
- foreach ($responseHeaderLines as $headerLine) {
- if ($headerLine && strpos($headerLine, ':') !== \false) {
- list($header, $value) = explode(': ', $headerLine, 2);
- $header = strtolower($header);
- if (isset($headers[$header])) {
- $headers[$header] = array_merge((array) $headers[$header], (array) $value);
- } else {
- $headers[$header] = $value;
- }
- }
- }
- return $headers;
- }
- /**
- * Used by the IO lib and also the batch processing.
- *
- * @param string $respData
- * @param int $headerSize
- * @return array
- */
- private function parseHttpResponse($respData, $headerSize)
- {
- // check proxy header
- foreach (self::$CONNECTION_ESTABLISHED_HEADERS as $established_header) {
- if (stripos($respData, $established_header) !== \false) {
- // existed, remove it
- $respData = str_ireplace($established_header, '', $respData);
- // Subtract the proxy header size unless the cURL bug prior to 7.30.0
- // is present which prevented the proxy header size from being taken into
- // account.
- // @TODO look into this
- // if (!$this->needsQuirk()) {
- // $headerSize -= strlen($established_header);
- // }
- break;
- }
- }
- if ($headerSize) {
- $responseBody = substr($respData, $headerSize);
- $responseHeaders = substr($respData, 0, $headerSize);
- } else {
- $responseSegments = explode("\r\n\r\n", $respData, 2);
- $responseHeaders = $responseSegments[0];
- $responseBody = isset($responseSegments[1]) ? $responseSegments[1] : null;
- }
- $responseHeaders = $this->parseRawHeaders($responseHeaders);
- return [$responseHeaders, $responseBody];
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient/src/Http/MediaFileUpload.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient/src/Http/MediaFileUpload.php
deleted file mode 100644
index eaae907..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient/src/Http/MediaFileUpload.php
+++ /dev/null
@@ -1,273 +0,0 @@
-client = $client;
- $this->request = $request;
- $this->mimeType = $mimeType;
- $this->data = $data;
- $this->resumable = $resumable;
- $this->chunkSize = $chunkSize;
- $this->progress = 0;
- $this->process();
- }
- /**
- * Set the size of the file that is being uploaded.
- * @param int $size - int file size in bytes
- */
- public function setFileSize($size)
- {
- $this->size = $size;
- }
- /**
- * Return the progress on the upload
- * @return int progress in bytes uploaded.
- */
- public function getProgress()
- {
- return $this->progress;
- }
- /**
- * Send the next part of the file to upload.
- * @param string|bool $chunk Optional. The next set of bytes to send. If false will
- * use $data passed at construct time.
- */
- public function nextChunk($chunk = \false)
- {
- $resumeUri = $this->getResumeUri();
- if (\false == $chunk) {
- $chunk = substr($this->data, $this->progress, $this->chunkSize);
- }
- $lastBytePos = $this->progress + strlen($chunk) - 1;
- $headers = ['content-range' => "bytes {$this->progress}-{$lastBytePos}/{$this->size}", 'content-length' => (string) strlen($chunk), 'expect' => ''];
- $request = new Request('PUT', $resumeUri, $headers, Psr7\Utils::streamFor($chunk));
- return $this->makePutRequest($request);
- }
- /**
- * Return the HTTP result code from the last call made.
- * @return int code
- */
- public function getHttpResultCode()
- {
- return $this->httpResultCode;
- }
- /**
- * Sends a PUT-Request to google drive and parses the response,
- * setting the appropiate variables from the response()
- *
- * @param RequestInterface $request the Request which will be send
- *
- * @return false|mixed false when the upload is unfinished or the decoded http response
- *
- */
- private function makePutRequest(RequestInterface $request)
- {
- $response = $this->client->execute($request);
- $this->httpResultCode = $response->getStatusCode();
- if (308 == $this->httpResultCode) {
- // Track the amount uploaded.
- $range = $response->getHeaderLine('range');
- if ($range) {
- $range_array = explode('-', $range);
- $this->progress = (int) $range_array[1] + 1;
- }
- // Allow for changing upload URLs.
- $location = $response->getHeaderLine('location');
- if ($location) {
- $this->resumeUri = $location;
- }
- // No problems, but upload not complete.
- return \false;
- }
- return REST::decodeHttpResponse($response, $this->request);
- }
- /**
- * Resume a previously unfinished upload
- * @param string $resumeUri the resume-URI of the unfinished, resumable upload.
- */
- public function resume($resumeUri)
- {
- $this->resumeUri = $resumeUri;
- $headers = ['content-range' => "bytes */{$this->size}", 'content-length' => '0'];
- $httpRequest = new Request('PUT', $this->resumeUri, $headers);
- return $this->makePutRequest($httpRequest);
- }
- /**
- * @return RequestInterface
- * @visible for testing
- */
- private function process()
- {
- $this->transformToUploadUrl();
- $request = $this->request;
- $postBody = '';
- $contentType = \false;
- $meta = json_decode((string) $request->getBody(), \true);
- $uploadType = $this->getUploadType($meta);
- $request = $request->withUri(Uri::withQueryValue($request->getUri(), 'uploadType', $uploadType));
- $mimeType = $this->mimeType ?: $request->getHeaderLine('content-type');
- if (self::UPLOAD_RESUMABLE_TYPE == $uploadType) {
- $contentType = $mimeType;
- $postBody = is_string($meta) ? $meta : json_encode($meta);
- } elseif (self::UPLOAD_MEDIA_TYPE == $uploadType) {
- $contentType = $mimeType;
- $postBody = $this->data;
- } elseif (self::UPLOAD_MULTIPART_TYPE == $uploadType) {
- // This is a multipart/related upload.
- $boundary = $this->boundary ?: mt_rand();
- $boundary = str_replace('"', '', $boundary);
- $contentType = 'multipart/related; boundary=' . $boundary;
- $related = "--{$boundary}\r\n";
- $related .= "Content-Type: application/json; charset=UTF-8\r\n";
- $related .= "\r\n" . json_encode($meta) . "\r\n";
- $related .= "--{$boundary}\r\n";
- $related .= "Content-Type: {$mimeType}\r\n";
- $related .= "Content-Transfer-Encoding: base64\r\n";
- $related .= "\r\n" . base64_encode($this->data) . "\r\n";
- $related .= "--{$boundary}--";
- $postBody = $related;
- }
- $request = $request->withBody(Psr7\Utils::streamFor($postBody));
- if ($contentType) {
- $request = $request->withHeader('content-type', $contentType);
- }
- return $this->request = $request;
- }
- /**
- * Valid upload types:
- * - resumable (UPLOAD_RESUMABLE_TYPE)
- * - media (UPLOAD_MEDIA_TYPE)
- * - multipart (UPLOAD_MULTIPART_TYPE)
- * @param string|false $meta
- * @return string
- * @visible for testing
- */
- public function getUploadType($meta)
- {
- if ($this->resumable) {
- return self::UPLOAD_RESUMABLE_TYPE;
- }
- if (\false == $meta && $this->data) {
- return self::UPLOAD_MEDIA_TYPE;
- }
- return self::UPLOAD_MULTIPART_TYPE;
- }
- public function getResumeUri()
- {
- if (null === $this->resumeUri) {
- $this->resumeUri = $this->fetchResumeUri();
- }
- return $this->resumeUri;
- }
- private function fetchResumeUri()
- {
- $body = $this->request->getBody();
- $headers = ['content-type' => 'application/json; charset=UTF-8', 'content-length' => $body->getSize(), 'x-upload-content-type' => $this->mimeType, 'x-upload-content-length' => $this->size, 'expect' => ''];
- foreach ($headers as $key => $value) {
- $this->request = $this->request->withHeader($key, $value);
- }
- $response = $this->client->execute($this->request, \false);
- $location = $response->getHeaderLine('location');
- $code = $response->getStatusCode();
- if (200 == $code && \true == $location) {
- return $location;
- }
- $message = $code;
- $body = json_decode((string) $this->request->getBody(), \true);
- if (isset($body['error']['errors'])) {
- $message .= ': ';
- foreach ($body['error']['errors'] as $error) {
- $message .= "{$error['domain']}, {$error['message']};";
- }
- $message = rtrim($message, ';');
- }
- $error = "Failed to start the resumable upload (HTTP {$message})";
- $this->client->getLogger()->error($error);
- throw new GoogleException($error);
- }
- private function transformToUploadUrl()
- {
- $parts = parse_url((string) $this->request->getUri());
- if (!isset($parts['path'])) {
- $parts['path'] = '';
- }
- $parts['path'] = '/upload' . $parts['path'];
- $uri = Uri::fromParts($parts);
- $this->request = $this->request->withUri($uri);
- }
- public function setChunkSize($chunkSize)
- {
- $this->chunkSize = $chunkSize;
- }
- public function getRequest()
- {
- return $this->request;
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient/src/Http/REST.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient/src/Http/REST.php
deleted file mode 100644
index 0160b0f..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient/src/Http/REST.php
+++ /dev/null
@@ -1,153 +0,0 @@
-|false|null $expectedClass
- * @param array $config
- * @param array $retryMap
- * @return mixed|T|null
- * @throws \Google\Service\Exception on server side error (ie: not authenticated,
- * invalid or malformed post body, invalid url)
- */
- public static function execute(ClientInterface $client, RequestInterface $request, $expectedClass = null, $config = [], $retryMap = null)
- {
- $runner = new Runner($config, sprintf('%s %s', $request->getMethod(), (string) $request->getUri()), [self::class, 'doExecute'], [$client, $request, $expectedClass]);
- if (null !== $retryMap) {
- $runner->setRetryMap($retryMap);
- }
- return $runner->run();
- }
- /**
- * Executes a Psr\Http\Message\RequestInterface
- *
- * @template T
- * @param ClientInterface $client
- * @param RequestInterface $request
- * @param class-string|false|null $expectedClass
- * @return mixed|T|null
- * @throws \Google\Service\Exception on server side error (ie: not authenticated,
- * invalid or malformed post body, invalid url)
- */
- public static function doExecute(ClientInterface $client, RequestInterface $request, $expectedClass = null)
- {
- try {
- $httpHandler = HttpHandlerFactory::build($client);
- $response = $httpHandler($request);
- } catch (RequestException $e) {
- // if Guzzle throws an exception, catch it and handle the response
- if (!$e->hasResponse()) {
- throw $e;
- }
- $response = $e->getResponse();
- // specific checking for Guzzle 5: convert to PSR7 response
- if (interface_exists('Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\GuzzleHttp\\Message\\ResponseInterface') && $response instanceof \Matomo\Dependencies\SearchEngineKeywordsPerformance\GuzzleHttp\Message\ResponseInterface) {
- $response = new Response($response->getStatusCode(), $response->getHeaders() ?: [], $response->getBody(), $response->getProtocolVersion(), $response->getReasonPhrase());
- }
- }
- return self::decodeHttpResponse($response, $request, $expectedClass);
- }
- /**
- * Decode an HTTP Response.
- * @static
- *
- * @template T
- * @param RequestInterface $response The http response to be decoded.
- * @param ResponseInterface $response
- * @param class-string|false|null $expectedClass
- * @return mixed|T|null
- * @throws \Google\Service\Exception
- */
- public static function decodeHttpResponse(ResponseInterface $response, RequestInterface $request = null, $expectedClass = null)
- {
- $code = $response->getStatusCode();
- // retry strategy
- if (intVal($code) >= 400) {
- // if we errored out, it should be safe to grab the response body
- $body = (string) $response->getBody();
- // Check if we received errors, and add those to the Exception for convenience
- throw new GoogleServiceException($body, $code, null, self::getResponseErrors($body));
- }
- // Ensure we only pull the entire body into memory if the request is not
- // of media type
- $body = self::decodeBody($response, $request);
- if ($expectedClass = self::determineExpectedClass($expectedClass, $request)) {
- $json = json_decode($body, \true);
- return new $expectedClass($json);
- }
- return $response;
- }
- private static function decodeBody(ResponseInterface $response, RequestInterface $request = null)
- {
- if (self::isAltMedia($request)) {
- // don't decode the body, it's probably a really long string
- return '';
- }
- return (string) $response->getBody();
- }
- private static function determineExpectedClass($expectedClass, RequestInterface $request = null)
- {
- // "false" is used to explicitly prevent an expected class from being returned
- if (\false === $expectedClass) {
- return null;
- }
- // if we don't have a request, we just use what's passed in
- if (null === $request) {
- return $expectedClass;
- }
- // return what we have in the request header if one was not supplied
- return $expectedClass ?: $request->getHeaderLine('X-Php-Expected-Class');
- }
- private static function getResponseErrors($body)
- {
- $json = json_decode($body, \true);
- if (isset($json['error']['errors'])) {
- return $json['error']['errors'];
- }
- return null;
- }
- private static function isAltMedia(RequestInterface $request = null)
- {
- if ($request && ($qs = $request->getUri()->getQuery())) {
- parse_str($qs, $query);
- if (isset($query['alt']) && $query['alt'] == 'media') {
- return \true;
- }
- }
- return \false;
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient/src/Model.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient/src/Model.php
deleted file mode 100644
index 3c8ac56..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient/src/Model.php
+++ /dev/null
@@ -1,301 +0,0 @@
-mapTypes($array);
- }
- $this->gapiInit();
- }
- /**
- * Getter that handles passthrough access to the data array, and lazy object creation.
- * @param string $key Property name.
- * @return mixed The value if any, or null.
- */
- public function __get($key)
- {
- $keyType = $this->keyType($key);
- $keyDataType = $this->dataType($key);
- if ($keyType && !isset($this->processed[$key])) {
- if (isset($this->modelData[$key])) {
- $val = $this->modelData[$key];
- } elseif ($keyDataType == 'array' || $keyDataType == 'map') {
- $val = [];
- } else {
- $val = null;
- }
- if ($this->isAssociativeArray($val)) {
- if ($keyDataType && 'map' == $keyDataType) {
- foreach ($val as $arrayKey => $arrayItem) {
- $this->modelData[$key][$arrayKey] = new $keyType($arrayItem);
- }
- } else {
- $this->modelData[$key] = new $keyType($val);
- }
- } elseif (is_array($val)) {
- $arrayObject = [];
- foreach ($val as $arrayIndex => $arrayItem) {
- $arrayObject[$arrayIndex] = new $keyType($arrayItem);
- }
- $this->modelData[$key] = $arrayObject;
- }
- $this->processed[$key] = \true;
- }
- return isset($this->modelData[$key]) ? $this->modelData[$key] : null;
- }
- /**
- * Initialize this object's properties from an array.
- *
- * @param array $array Used to seed this object's properties.
- * @return void
- */
- protected function mapTypes($array)
- {
- // Hard initialise simple types, lazy load more complex ones.
- foreach ($array as $key => $val) {
- if ($keyType = $this->keyType($key)) {
- $dataType = $this->dataType($key);
- if ($dataType == 'array' || $dataType == 'map') {
- $this->{$key} = [];
- foreach ($val as $itemKey => $itemVal) {
- if ($itemVal instanceof $keyType) {
- $this->{$key}[$itemKey] = $itemVal;
- } else {
- $this->{$key}[$itemKey] = new $keyType($itemVal);
- }
- }
- } elseif ($val instanceof $keyType) {
- $this->{$key} = $val;
- } else {
- $this->{$key} = new $keyType($val);
- }
- unset($array[$key]);
- } elseif (property_exists($this, $key)) {
- $this->{$key} = $val;
- unset($array[$key]);
- } elseif (property_exists($this, $camelKey = $this->camelCase($key))) {
- // This checks if property exists as camelCase, leaving it in array as snake_case
- // in case of backwards compatibility issues.
- $this->{$camelKey} = $val;
- }
- }
- $this->modelData = $array;
- }
- /**
- * Blank initialiser to be used in subclasses to do post-construction initialisation - this
- * avoids the need for subclasses to have to implement the variadics handling in their
- * constructors.
- */
- protected function gapiInit()
- {
- return;
- }
- /**
- * Create a simplified object suitable for straightforward
- * conversion to JSON. This is relatively expensive
- * due to the usage of reflection, but shouldn't be called
- * a whole lot, and is the most straightforward way to filter.
- */
- public function toSimpleObject()
- {
- $object = new stdClass();
- // Process all other data.
- foreach ($this->modelData as $key => $val) {
- $result = $this->getSimpleValue($val);
- if ($result !== null) {
- $object->{$key} = $this->nullPlaceholderCheck($result);
- }
- }
- // Process all public properties.
- $reflect = new ReflectionObject($this);
- $props = $reflect->getProperties(ReflectionProperty::IS_PUBLIC);
- foreach ($props as $member) {
- $name = $member->getName();
- $result = $this->getSimpleValue($this->{$name});
- if ($result !== null) {
- $name = $this->getMappedName($name);
- $object->{$name} = $this->nullPlaceholderCheck($result);
- }
- }
- return $object;
- }
- /**
- * Handle different types of values, primarily
- * other objects and map and array data types.
- */
- private function getSimpleValue($value)
- {
- if ($value instanceof Model) {
- return $value->toSimpleObject();
- } elseif (is_array($value)) {
- $return = [];
- foreach ($value as $key => $a_value) {
- $a_value = $this->getSimpleValue($a_value);
- if ($a_value !== null) {
- $key = $this->getMappedName($key);
- $return[$key] = $this->nullPlaceholderCheck($a_value);
- }
- }
- return $return;
- }
- return $value;
- }
- /**
- * Check whether the value is the null placeholder and return true null.
- */
- private function nullPlaceholderCheck($value)
- {
- if ($value === self::NULL_VALUE) {
- return null;
- }
- return $value;
- }
- /**
- * If there is an internal name mapping, use that.
- */
- private function getMappedName($key)
- {
- if (isset($this->internal_gapi_mappings, $this->internal_gapi_mappings[$key])) {
- $key = $this->internal_gapi_mappings[$key];
- }
- return $key;
- }
- /**
- * Returns true only if the array is associative.
- * @param array $array
- * @return bool True if the array is associative.
- */
- protected function isAssociativeArray($array)
- {
- if (!is_array($array)) {
- return \false;
- }
- $keys = array_keys($array);
- foreach ($keys as $key) {
- if (is_string($key)) {
- return \true;
- }
- }
- return \false;
- }
- /**
- * Verify if $obj is an array.
- * @throws \Google\Exception Thrown if $obj isn't an array.
- * @param array $obj Items that should be validated.
- * @param string $method Method expecting an array as an argument.
- */
- public function assertIsArray($obj, $method)
- {
- if ($obj && !is_array($obj)) {
- throw new GoogleException("Incorrect parameter type passed to {$method}(). Expected an array.");
- }
- }
- /** @return bool */
- #[\ReturnTypeWillChange]
- public function offsetExists($offset)
- {
- return isset($this->{$offset}) || isset($this->modelData[$offset]);
- }
- /** @return mixed */
- #[\ReturnTypeWillChange]
- public function offsetGet($offset)
- {
- return isset($this->{$offset}) ? $this->{$offset} : $this->__get($offset);
- }
- /** @return void */
- #[\ReturnTypeWillChange]
- public function offsetSet($offset, $value)
- {
- if (property_exists($this, $offset)) {
- $this->{$offset} = $value;
- } else {
- $this->modelData[$offset] = $value;
- $this->processed[$offset] = \true;
- }
- }
- /** @return void */
- #[\ReturnTypeWillChange]
- public function offsetUnset($offset)
- {
- unset($this->modelData[$offset]);
- }
- protected function keyType($key)
- {
- $keyType = $key . "Type";
- // ensure keyType is a valid class
- if (property_exists($this, $keyType) && $this->{$keyType} !== null && class_exists($this->{$keyType})) {
- return $this->{$keyType};
- }
- }
- protected function dataType($key)
- {
- $dataType = $key . "DataType";
- if (property_exists($this, $dataType)) {
- return $this->{$dataType};
- }
- }
- public function __isset($key)
- {
- return isset($this->modelData[$key]);
- }
- public function __unset($key)
- {
- unset($this->modelData[$key]);
- }
- /**
- * Convert a string to camelCase
- * @param string $value
- * @return string
- */
- private function camelCase($value)
- {
- $value = ucwords(str_replace(['-', '_'], ' ', $value));
- $value = str_replace(' ', '', $value);
- $value[0] = strtolower($value[0]);
- return $value;
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient/src/Service.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient/src/Service.php
deleted file mode 100644
index 531cbc9..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient/src/Service.php
+++ /dev/null
@@ -1,63 +0,0 @@
-client = $clientOrConfig;
- } elseif (is_array($clientOrConfig)) {
- $this->client = new Client($clientOrConfig ?: []);
- } else {
- $errorMessage = 'constructor must be array or instance of Google\\Client';
- if (class_exists('TypeError')) {
- throw new TypeError($errorMessage);
- }
- trigger_error($errorMessage, \E_USER_ERROR);
- }
- }
- /**
- * Return the associated Google\Client class.
- * @return \Google\Client
- */
- public function getClient()
- {
- return $this->client;
- }
- /**
- * Create a new HTTP Batch handler for this service
- *
- * @return Batch
- */
- public function createBatch()
- {
- return new Batch($this->client, \false, $this->rootUrl, $this->batchPath);
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient/src/Service/Exception.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient/src/Service/Exception.php
deleted file mode 100644
index 2b7b708..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient/src/Service/Exception.php
+++ /dev/null
@@ -1,65 +0,0 @@
->|null $errors List of errors returned in an HTTP
- * response or null. Defaults to [].
- */
- public function __construct($message, $code = 0, Exception $previous = null, $errors = [])
- {
- if (version_compare(\PHP_VERSION, '5.3.0') >= 0) {
- parent::__construct($message, $code, $previous);
- } else {
- parent::__construct($message, $code);
- }
- $this->errors = $errors;
- }
- /**
- * An example of the possible errors returned.
- *
- * [
- * {
- * "domain": "global",
- * "reason": "authError",
- * "message": "Invalid Credentials",
- * "locationType": "header",
- * "location": "Authorization",
- * }
- * ]
- *
- * @return array>|null List of errors returned in an HTTP response or null.
- */
- public function getErrors()
- {
- return $this->errors;
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient/src/Service/Resource.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient/src/Service/Resource.php
deleted file mode 100644
index a7578a9..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient/src/Service/Resource.php
+++ /dev/null
@@ -1,214 +0,0 @@
- ['type' => 'string', 'location' => 'query'], 'fields' => ['type' => 'string', 'location' => 'query'], 'trace' => ['type' => 'string', 'location' => 'query'], 'userIp' => ['type' => 'string', 'location' => 'query'], 'quotaUser' => ['type' => 'string', 'location' => 'query'], 'data' => ['type' => 'string', 'location' => 'body'], 'mimeType' => ['type' => 'string', 'location' => 'header'], 'uploadType' => ['type' => 'string', 'location' => 'query'], 'mediaUpload' => ['type' => 'complex', 'location' => 'query'], 'prettyPrint' => ['type' => 'string', 'location' => 'query']];
- /** @var string $rootUrl */
- private $rootUrl;
- /** @var \Google\Client $client */
- private $client;
- /** @var string $serviceName */
- private $serviceName;
- /** @var string $servicePath */
- private $servicePath;
- /** @var string $resourceName */
- private $resourceName;
- /** @var array $methods */
- private $methods;
- public function __construct($service, $serviceName, $resourceName, $resource)
- {
- $this->rootUrl = $service->rootUrl;
- $this->client = $service->getClient();
- $this->servicePath = $service->servicePath;
- $this->serviceName = $serviceName;
- $this->resourceName = $resourceName;
- $this->methods = is_array($resource) && isset($resource['methods']) ? $resource['methods'] : [$resourceName => $resource];
- }
- /**
- * TODO: This function needs simplifying.
- *
- * @template T
- * @param string $name
- * @param array $arguments
- * @param class-string $expectedClass - optional, the expected class name
- * @return mixed|T|ResponseInterface|RequestInterface
- * @throws \Google\Exception
- */
- public function call($name, $arguments, $expectedClass = null)
- {
- if (!isset($this->methods[$name])) {
- $this->client->getLogger()->error('Service method unknown', ['service' => $this->serviceName, 'resource' => $this->resourceName, 'method' => $name]);
- throw new GoogleException("Unknown function: " . "{$this->serviceName}->{$this->resourceName}->{$name}()");
- }
- $method = $this->methods[$name];
- $parameters = $arguments[0];
- // postBody is a special case since it's not defined in the discovery
- // document as parameter, but we abuse the param entry for storing it.
- $postBody = null;
- if (isset($parameters['postBody'])) {
- if ($parameters['postBody'] instanceof Model) {
- // In the cases the post body is an existing object, we want
- // to use the smart method to create a simple object for
- // for JSONification.
- $parameters['postBody'] = $parameters['postBody']->toSimpleObject();
- } elseif (is_object($parameters['postBody'])) {
- // If the post body is another kind of object, we will try and
- // wrangle it into a sensible format.
- $parameters['postBody'] = $this->convertToArrayAndStripNulls($parameters['postBody']);
- }
- $postBody = (array) $parameters['postBody'];
- unset($parameters['postBody']);
- }
- // TODO: optParams here probably should have been
- // handled already - this may well be redundant code.
- if (isset($parameters['optParams'])) {
- $optParams = $parameters['optParams'];
- unset($parameters['optParams']);
- $parameters = array_merge($parameters, $optParams);
- }
- if (!isset($method['parameters'])) {
- $method['parameters'] = [];
- }
- $method['parameters'] = array_merge($this->stackParameters, $method['parameters']);
- foreach ($parameters as $key => $val) {
- if ($key != 'postBody' && !isset($method['parameters'][$key])) {
- $this->client->getLogger()->error('Service parameter unknown', ['service' => $this->serviceName, 'resource' => $this->resourceName, 'method' => $name, 'parameter' => $key]);
- throw new GoogleException("({$name}) unknown parameter: '{$key}'");
- }
- }
- foreach ($method['parameters'] as $paramName => $paramSpec) {
- if (isset($paramSpec['required']) && $paramSpec['required'] && !isset($parameters[$paramName])) {
- $this->client->getLogger()->error('Service parameter missing', ['service' => $this->serviceName, 'resource' => $this->resourceName, 'method' => $name, 'parameter' => $paramName]);
- throw new GoogleException("({$name}) missing required param: '{$paramName}'");
- }
- if (isset($parameters[$paramName])) {
- $value = $parameters[$paramName];
- $parameters[$paramName] = $paramSpec;
- $parameters[$paramName]['value'] = $value;
- unset($parameters[$paramName]['required']);
- } else {
- // Ensure we don't pass nulls.
- unset($parameters[$paramName]);
- }
- }
- $this->client->getLogger()->info('Service Call', ['service' => $this->serviceName, 'resource' => $this->resourceName, 'method' => $name, 'arguments' => $parameters]);
- // build the service uri
- $url = $this->createRequestUri($method['path'], $parameters);
- // NOTE: because we're creating the request by hand,
- // and because the service has a rootUrl property
- // the "base_uri" of the Http Client is not accounted for
- $request = new Request($method['httpMethod'], $url, $postBody ? ['content-type' => 'application/json'] : [], $postBody ? json_encode($postBody) : '');
- // support uploads
- if (isset($parameters['data'])) {
- $mimeType = isset($parameters['mimeType']) ? $parameters['mimeType']['value'] : 'application/octet-stream';
- $data = $parameters['data']['value'];
- $upload = new MediaFileUpload($this->client, $request, $mimeType, $data);
- // pull down the modified request
- $request = $upload->getRequest();
- }
- // if this is a media type, we will return the raw response
- // rather than using an expected class
- if (isset($parameters['alt']) && $parameters['alt']['value'] == 'media') {
- $expectedClass = null;
- }
- // if the client is marked for deferring, rather than
- // execute the request, return the response
- if ($this->client->shouldDefer()) {
- // @TODO find a better way to do this
- $request = $request->withHeader('X-Php-Expected-Class', $expectedClass);
- return $request;
- }
- return $this->client->execute($request, $expectedClass);
- }
- protected function convertToArrayAndStripNulls($o)
- {
- $o = (array) $o;
- foreach ($o as $k => $v) {
- if ($v === null) {
- unset($o[$k]);
- } elseif (is_object($v) || is_array($v)) {
- $o[$k] = $this->convertToArrayAndStripNulls($o[$k]);
- }
- }
- return $o;
- }
- /**
- * Parse/expand request parameters and create a fully qualified
- * request uri.
- * @static
- * @param string $restPath
- * @param array $params
- * @return string $requestUrl
- */
- public function createRequestUri($restPath, $params)
- {
- // Override the default servicePath address if the $restPath use a /
- if ('/' == substr($restPath, 0, 1)) {
- $requestUrl = substr($restPath, 1);
- } else {
- $requestUrl = $this->servicePath . $restPath;
- }
- // code for leading slash
- if ($this->rootUrl) {
- if ('/' !== substr($this->rootUrl, -1) && '/' !== substr($requestUrl, 0, 1)) {
- $requestUrl = '/' . $requestUrl;
- }
- $requestUrl = $this->rootUrl . $requestUrl;
- }
- $uriTemplateVars = [];
- $queryVars = [];
- foreach ($params as $paramName => $paramSpec) {
- if ($paramSpec['type'] == 'boolean') {
- $paramSpec['value'] = $paramSpec['value'] ? 'true' : 'false';
- }
- if ($paramSpec['location'] == 'path') {
- $uriTemplateVars[$paramName] = $paramSpec['value'];
- } elseif ($paramSpec['location'] == 'query') {
- if (is_array($paramSpec['value'])) {
- foreach ($paramSpec['value'] as $value) {
- $queryVars[] = $paramName . '=' . rawurlencode(rawurldecode($value));
- }
- } else {
- $queryVars[] = $paramName . '=' . rawurlencode(rawurldecode($paramSpec['value']));
- }
- }
- }
- if (count($uriTemplateVars)) {
- $uriTemplateParser = new UriTemplate();
- $requestUrl = $uriTemplateParser->parse($requestUrl, $uriTemplateVars);
- }
- if (count($queryVars)) {
- $requestUrl .= '?' . implode('&', $queryVars);
- }
- return $requestUrl;
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient/src/Task/Composer.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient/src/Task/Composer.php
deleted file mode 100644
index 5cb3190..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient/src/Task/Composer.php
+++ /dev/null
@@ -1,77 +0,0 @@
-getComposer();
- $extra = $composer->getPackage()->getExtra();
- $servicesToKeep = isset($extra['google/apiclient-services']) ? $extra['google/apiclient-services'] : [];
- if ($servicesToKeep) {
- $vendorDir = $composer->getConfig()->get('vendor-dir');
- $serviceDir = sprintf('%s/google/apiclient-services/src/Google/Service', $vendorDir);
- if (!is_dir($serviceDir)) {
- // path for google/apiclient-services >= 0.200.0
- $serviceDir = sprintf('%s/google/apiclient-services/src', $vendorDir);
- }
- self::verifyServicesToKeep($serviceDir, $servicesToKeep);
- $finder = self::getServicesToRemove($serviceDir, $servicesToKeep);
- $filesystem = $filesystem ?: new Filesystem();
- if (0 !== ($count = count($finder))) {
- $event->getIO()->write(sprintf('Removing %s google services', $count));
- foreach ($finder as $file) {
- $realpath = $file->getRealPath();
- $filesystem->remove($realpath);
- $filesystem->remove($realpath . '.php');
- }
- }
- }
- }
- /**
- * @throws InvalidArgumentException when the service doesn't exist
- */
- private static function verifyServicesToKeep($serviceDir, array $servicesToKeep)
- {
- $finder = (new Finder())->directories()->depth('== 0');
- foreach ($servicesToKeep as $service) {
- if (!preg_match('/^[a-zA-Z0-9]*$/', $service)) {
- throw new InvalidArgumentException(sprintf('Invalid Google service name "%s"', $service));
- }
- try {
- $finder->in($serviceDir . '/' . $service);
- } catch (InvalidArgumentException $e) {
- throw new InvalidArgumentException(sprintf('Google service "%s" does not exist or was removed previously', $service));
- }
- }
- }
- private static function getServicesToRemove($serviceDir, array $servicesToKeep)
- {
- // find all files in the current directory
- return (new Finder())->directories()->depth('== 0')->in($serviceDir)->exclude($servicesToKeep);
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient/src/Task/Exception.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient/src/Task/Exception.php
deleted file mode 100644
index 5cc4c37..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient/src/Task/Exception.php
+++ /dev/null
@@ -1,23 +0,0 @@
- self::TASK_RETRY_ALWAYS,
- '503' => self::TASK_RETRY_ALWAYS,
- 'rateLimitExceeded' => self::TASK_RETRY_ALWAYS,
- 'userRateLimitExceeded' => self::TASK_RETRY_ALWAYS,
- 6 => self::TASK_RETRY_ALWAYS,
- // CURLE_COULDNT_RESOLVE_HOST
- 7 => self::TASK_RETRY_ALWAYS,
- // CURLE_COULDNT_CONNECT
- 28 => self::TASK_RETRY_ALWAYS,
- // CURLE_OPERATION_TIMEOUTED
- 35 => self::TASK_RETRY_ALWAYS,
- // CURLE_SSL_CONNECT_ERROR
- 52 => self::TASK_RETRY_ALWAYS,
- // CURLE_GOT_NOTHING
- 'lighthouseError' => self::TASK_RETRY_NEVER,
- ];
- /**
- * Creates a new task runner with exponential backoff support.
- *
- * @param array $config The task runner config
- * @param string $name The name of the current task (used for logging)
- * @param callable $action The task to run and possibly retry
- * @param array $arguments The task arguments
- * @throws \Google\Task\Exception when misconfigured
- */
- // @phpstan-ignore-next-line
- public function __construct($config, $name, $action, array $arguments = [])
- {
- if (isset($config['initial_delay'])) {
- if ($config['initial_delay'] < 0) {
- throw new GoogleTaskException('Task configuration `initial_delay` must not be negative.');
- }
- $this->delay = $config['initial_delay'];
- }
- if (isset($config['max_delay'])) {
- if ($config['max_delay'] <= 0) {
- throw new GoogleTaskException('Task configuration `max_delay` must be greater than 0.');
- }
- $this->maxDelay = $config['max_delay'];
- }
- if (isset($config['factor'])) {
- if ($config['factor'] <= 0) {
- throw new GoogleTaskException('Task configuration `factor` must be greater than 0.');
- }
- $this->factor = $config['factor'];
- }
- if (isset($config['jitter'])) {
- if ($config['jitter'] <= 0) {
- throw new GoogleTaskException('Task configuration `jitter` must be greater than 0.');
- }
- $this->jitter = $config['jitter'];
- }
- if (isset($config['retries'])) {
- if ($config['retries'] < 0) {
- throw new GoogleTaskException('Task configuration `retries` must not be negative.');
- }
- $this->maxAttempts += $config['retries'];
- }
- if (!is_callable($action)) {
- throw new GoogleTaskException('Task argument `$action` must be a valid callable.');
- }
- $this->action = $action;
- $this->arguments = $arguments;
- }
- /**
- * Checks if a retry can be attempted.
- *
- * @return boolean
- */
- public function canAttempt()
- {
- return $this->attempts < $this->maxAttempts;
- }
- /**
- * Runs the task and (if applicable) automatically retries when errors occur.
- *
- * @return mixed
- * @throws \Google\Service\Exception on failure when no retries are available.
- */
- public function run()
- {
- while ($this->attempt()) {
- try {
- return call_user_func_array($this->action, $this->arguments);
- } catch (GoogleServiceException $exception) {
- $allowedRetries = $this->allowedRetries($exception->getCode(), $exception->getErrors());
- if (!$this->canAttempt() || !$allowedRetries) {
- throw $exception;
- }
- if ($allowedRetries > 0) {
- $this->maxAttempts = min($this->maxAttempts, $this->attempts + $allowedRetries);
- }
- }
- }
- }
- /**
- * Runs a task once, if possible. This is useful for bypassing the `run()`
- * loop.
- *
- * NOTE: If this is not the first attempt, this function will sleep in
- * accordance to the backoff configurations before running the task.
- *
- * @return boolean
- */
- public function attempt()
- {
- if (!$this->canAttempt()) {
- return \false;
- }
- if ($this->attempts > 0) {
- $this->backOff();
- }
- $this->attempts++;
- return \true;
- }
- /**
- * Sleeps in accordance to the backoff configurations.
- */
- private function backOff()
- {
- $delay = $this->getDelay();
- usleep((int) ($delay * 1000000));
- }
- /**
- * Gets the delay (in seconds) for the current backoff period.
- *
- * @return int
- */
- private function getDelay()
- {
- $jitter = $this->getJitter();
- $factor = $this->attempts > 1 ? $this->factor + $jitter : 1 + abs($jitter);
- return $this->delay = min($this->maxDelay, $this->delay * $factor);
- }
- /**
- * Gets the current jitter (random number between -$this->jitter and
- * $this->jitter).
- *
- * @return float
- */
- private function getJitter()
- {
- return $this->jitter * 2 * mt_rand() / mt_getrandmax() - $this->jitter;
- }
- /**
- * Gets the number of times the associated task can be retried.
- *
- * NOTE: -1 is returned if the task can be retried indefinitely
- *
- * @return integer
- */
- public function allowedRetries($code, $errors = [])
- {
- if (isset($this->retryMap[$code])) {
- return $this->retryMap[$code];
- }
- if (!empty($errors) && isset($errors[0]['reason'], $this->retryMap[$errors[0]['reason']])) {
- return $this->retryMap[$errors[0]['reason']];
- }
- return 0;
- }
- public function setRetryMap($retryMap)
- {
- $this->retryMap = $retryMap;
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient/src/Utils/UriTemplate.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient/src/Utils/UriTemplate.php
deleted file mode 100644
index 611b907..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient/src/Utils/UriTemplate.php
+++ /dev/null
@@ -1,264 +0,0 @@
- "reserved", "/" => "segments", "." => "dotprefix", "#" => "fragment", ";" => "semicolon", "?" => "form", "&" => "continuation"];
- /**
- * @var array
- * These are the characters which should not be URL encoded in reserved
- * strings.
- */
- private $reserved = ["=", ",", "!", "@", "|", ":", "/", "?", "#", "[", "]", '$', "&", "'", "(", ")", "*", "+", ";"];
- private $reservedEncoded = ["%3D", "%2C", "%21", "%40", "%7C", "%3A", "%2F", "%3F", "%23", "%5B", "%5D", "%24", "%26", "%27", "%28", "%29", "%2A", "%2B", "%3B"];
- public function parse($string, array $parameters)
- {
- return $this->resolveNextSection($string, $parameters);
- }
- /**
- * This function finds the first matching {...} block and
- * executes the replacement. It then calls itself to find
- * subsequent blocks, if any.
- */
- private function resolveNextSection($string, $parameters)
- {
- $start = strpos($string, "{");
- if ($start === \false) {
- return $string;
- }
- $end = strpos($string, "}");
- if ($end === \false) {
- return $string;
- }
- $string = $this->replace($string, $start, $end, $parameters);
- return $this->resolveNextSection($string, $parameters);
- }
- private function replace($string, $start, $end, $parameters)
- {
- // We know a data block will have {} round it, so we can strip that.
- $data = substr($string, $start + 1, $end - $start - 1);
- // If the first character is one of the reserved operators, it effects
- // the processing of the stream.
- if (isset($this->operators[$data[0]])) {
- $op = $this->operators[$data[0]];
- $data = substr($data, 1);
- $prefix = "";
- $prefix_on_missing = \false;
- switch ($op) {
- case "reserved":
- // Reserved means certain characters should not be URL encoded
- $data = $this->replaceVars($data, $parameters, ",", null, \true);
- break;
- case "fragment":
- // Comma separated with fragment prefix. Bare values only.
- $prefix = "#";
- $prefix_on_missing = \true;
- $data = $this->replaceVars($data, $parameters, ",", null, \true);
- break;
- case "segments":
- // Slash separated data. Bare values only.
- $prefix = "/";
- $data = $this->replaceVars($data, $parameters, "/");
- break;
- case "dotprefix":
- // Dot separated data. Bare values only.
- $prefix = ".";
- $prefix_on_missing = \true;
- $data = $this->replaceVars($data, $parameters, ".");
- break;
- case "semicolon":
- // Semicolon prefixed and separated. Uses the key name
- $prefix = ";";
- $data = $this->replaceVars($data, $parameters, ";", "=", \false, \true, \false);
- break;
- case "form":
- // Standard URL format. Uses the key name
- $prefix = "?";
- $data = $this->replaceVars($data, $parameters, "&", "=");
- break;
- case "continuation":
- // Standard URL, but with leading ampersand. Uses key name.
- $prefix = "&";
- $data = $this->replaceVars($data, $parameters, "&", "=");
- break;
- }
- // Add the initial prefix character if data is valid.
- if ($data || $data !== \false && $prefix_on_missing) {
- $data = $prefix . $data;
- }
- } else {
- // If no operator we replace with the defaults.
- $data = $this->replaceVars($data, $parameters);
- }
- // This is chops out the {...} and replaces with the new section.
- return substr($string, 0, $start) . $data . substr($string, $end + 1);
- }
- private function replaceVars($section, $parameters, $sep = ",", $combine = null, $reserved = \false, $tag_empty = \false, $combine_on_empty = \true)
- {
- if (strpos($section, ",") === \false) {
- // If we only have a single value, we can immediately process.
- return $this->combine($section, $parameters, $sep, $combine, $reserved, $tag_empty, $combine_on_empty);
- } else {
- // If we have multiple values, we need to split and loop over them.
- // Each is treated individually, then glued together with the
- // separator character.
- $vars = explode(",", $section);
- return $this->combineList(
- $vars,
- $sep,
- $parameters,
- $combine,
- $reserved,
- \false,
- // Never emit empty strings in multi-param replacements
- $combine_on_empty
- );
- }
- }
- public function combine($key, $parameters, $sep, $combine, $reserved, $tag_empty, $combine_on_empty)
- {
- $length = \false;
- $explode = \false;
- $skip_final_combine = \false;
- $value = \false;
- // Check for length restriction.
- if (strpos($key, ":") !== \false) {
- list($key, $length) = explode(":", $key);
- }
- // Check for explode parameter.
- if ($key[strlen($key) - 1] == "*") {
- $explode = \true;
- $key = substr($key, 0, -1);
- $skip_final_combine = \true;
- }
- // Define the list separator.
- $list_sep = $explode ? $sep : ",";
- if (isset($parameters[$key])) {
- $data_type = $this->getDataType($parameters[$key]);
- switch ($data_type) {
- case self::TYPE_SCALAR:
- $value = $this->getValue($parameters[$key], $length);
- break;
- case self::TYPE_LIST:
- $values = [];
- foreach ($parameters[$key] as $pkey => $pvalue) {
- $pvalue = $this->getValue($pvalue, $length);
- if ($combine && $explode) {
- $values[$pkey] = $key . $combine . $pvalue;
- } else {
- $values[$pkey] = $pvalue;
- }
- }
- $value = implode($list_sep, $values);
- if ($value == '') {
- return '';
- }
- break;
- case self::TYPE_MAP:
- $values = [];
- foreach ($parameters[$key] as $pkey => $pvalue) {
- $pvalue = $this->getValue($pvalue, $length);
- if ($explode) {
- $pkey = $this->getValue($pkey, $length);
- $values[] = $pkey . "=" . $pvalue;
- // Explode triggers = combine.
- } else {
- $values[] = $pkey;
- $values[] = $pvalue;
- }
- }
- $value = implode($list_sep, $values);
- if ($value == '') {
- return \false;
- }
- break;
- }
- } elseif ($tag_empty) {
- // If we are just indicating empty values with their key name, return that.
- return $key;
- } else {
- // Otherwise we can skip this variable due to not being defined.
- return \false;
- }
- if ($reserved) {
- $value = str_replace($this->reservedEncoded, $this->reserved, $value);
- }
- // If we do not need to include the key name, we just return the raw
- // value.
- if (!$combine || $skip_final_combine) {
- return $value;
- }
- // Else we combine the key name: foo=bar, if value is not the empty string.
- return $key . ($value != '' || $combine_on_empty ? $combine . $value : '');
- }
- /**
- * Return the type of a passed in value
- */
- private function getDataType($data)
- {
- if (is_array($data)) {
- reset($data);
- if (key($data) !== 0) {
- return self::TYPE_MAP;
- }
- return self::TYPE_LIST;
- }
- return self::TYPE_SCALAR;
- }
- /**
- * Utility function that merges multiple combine calls
- * for multi-key templates.
- */
- private function combineList($vars, $sep, $parameters, $combine, $reserved, $tag_empty, $combine_on_empty)
- {
- $ret = [];
- foreach ($vars as $var) {
- $response = $this->combine($var, $parameters, $sep, $combine, $reserved, $tag_empty, $combine_on_empty);
- if ($response === \false) {
- continue;
- }
- $ret[] = $response;
- }
- return implode($sep, $ret);
- }
- /**
- * Utility function to encode and trim values
- */
- private function getValue($value, $length)
- {
- if ($length) {
- $value = substr($value, 0, $length);
- }
- $value = rawurlencode($value);
- return $value;
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient/src/aliases.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient/src/aliases.php
deleted file mode 100644
index 2591fb0..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/apiclient/src/aliases.php
+++ /dev/null
@@ -1,80 +0,0 @@
- 'Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\Google_Client', 'Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\Google\\Service' => 'Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\Google_Service', 'Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\Google\\AccessToken\\Revoke' => 'Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\Google_AccessToken_Revoke', 'Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\Google\\AccessToken\\Verify' => 'Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\Google_AccessToken_Verify', 'Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\Google\\Model' => 'Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\Google_Model', 'Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\Google\\Utils\\UriTemplate' => 'Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\Google_Utils_UriTemplate', 'Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\Google\\AuthHandler\\Guzzle6AuthHandler' => 'Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\Google_AuthHandler_Guzzle6AuthHandler', 'Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\Google\\AuthHandler\\Guzzle7AuthHandler' => 'Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\Google_AuthHandler_Guzzle7AuthHandler', 'Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\Google\\AuthHandler\\AuthHandlerFactory' => 'Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\Google_AuthHandler_AuthHandlerFactory', 'Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\Google\\Http\\Batch' => 'Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\Google_Http_Batch', 'Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\Google\\Http\\MediaFileUpload' => 'Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\Google_Http_MediaFileUpload', 'Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\Google\\Http\\REST' => 'Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\Google_Http_REST', 'Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\Google\\Task\\Retryable' => 'Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\Google_Task_Retryable', 'Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\Google\\Task\\Exception' => 'Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\Google_Task_Exception', 'Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\Google\\Task\\Runner' => 'Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\Google_Task_Runner', 'Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\Google\\Collection' => 'Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\Google_Collection', 'Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\Google\\Service\\Exception' => 'Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\Google_Service_Exception', 'Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\Google\\Service\\Resource' => 'Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\Google_Service_Resource', 'Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\Google\\Exception' => 'Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\Google_Exception'];
-foreach ($classMap as $class => $alias) {
- \class_alias($class, $alias);
-}
-/**
- * This class needs to be defined explicitly as scripts must be recognized by
- * the autoloader.
- */
-class Google_Task_Composer extends \Matomo\Dependencies\SearchEngineKeywordsPerformance\Google\Task\Composer
-{
-}
-/** @phpstan-ignore-next-line */
-if (\false) {
- class Google_AccessToken_Revoke extends \Matomo\Dependencies\SearchEngineKeywordsPerformance\Google\AccessToken\Revoke
- {
- }
- class Google_AccessToken_Verify extends \Matomo\Dependencies\SearchEngineKeywordsPerformance\Google\AccessToken\Verify
- {
- }
- class Google_AuthHandler_AuthHandlerFactory extends \Matomo\Dependencies\SearchEngineKeywordsPerformance\Google\AuthHandler\AuthHandlerFactory
- {
- }
- class Google_AuthHandler_Guzzle6AuthHandler extends \Matomo\Dependencies\SearchEngineKeywordsPerformance\Google\AuthHandler\Guzzle6AuthHandler
- {
- }
- class Google_AuthHandler_Guzzle7AuthHandler extends \Matomo\Dependencies\SearchEngineKeywordsPerformance\Google\AuthHandler\Guzzle7AuthHandler
- {
- }
- class Google_Client extends \Matomo\Dependencies\SearchEngineKeywordsPerformance\Google\Client
- {
- }
- class Google_Collection extends \Matomo\Dependencies\SearchEngineKeywordsPerformance\Google\Collection
- {
- }
- class Google_Exception extends \Matomo\Dependencies\SearchEngineKeywordsPerformance\Google\Exception
- {
- }
- class Google_Http_Batch extends \Matomo\Dependencies\SearchEngineKeywordsPerformance\Google\Http\Batch
- {
- }
- class Google_Http_MediaFileUpload extends \Matomo\Dependencies\SearchEngineKeywordsPerformance\Google\Http\MediaFileUpload
- {
- }
- class Google_Http_REST extends \Matomo\Dependencies\SearchEngineKeywordsPerformance\Google\Http\REST
- {
- }
- class Google_Model extends \Matomo\Dependencies\SearchEngineKeywordsPerformance\Google\Model
- {
- }
- class Google_Service extends \Matomo\Dependencies\SearchEngineKeywordsPerformance\Google\Service
- {
- }
- class Google_Service_Exception extends \Matomo\Dependencies\SearchEngineKeywordsPerformance\Google\Service\Exception
- {
- }
- class Google_Service_Resource extends \Matomo\Dependencies\SearchEngineKeywordsPerformance\Google\Service\Resource
- {
- }
- class Google_Task_Exception extends \Matomo\Dependencies\SearchEngineKeywordsPerformance\Google\Task\Exception
- {
- }
- interface Google_Task_Retryable extends \Matomo\Dependencies\SearchEngineKeywordsPerformance\Google\Task\Retryable
- {
- }
- class Google_Task_Runner extends \Matomo\Dependencies\SearchEngineKeywordsPerformance\Google\Task\Runner
- {
- }
- class Google_Utils_UriTemplate extends \Matomo\Dependencies\SearchEngineKeywordsPerformance\Google\Utils\UriTemplate
- {
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/COPYING b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/COPYING
deleted file mode 100644
index b5d5055..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/COPYING
+++ /dev/null
@@ -1,202 +0,0 @@
-
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
- APPENDIX: How to apply the Apache License to your work.
-
- To apply the Apache License to your work, attach the following
- boilerplate notice, with the fields enclosed by brackets "[]"
- replaced with your own identifying information. (Don't include
- the brackets!) The text should be enclosed in the appropriate
- comment syntax for the file format. We also recommend that a
- file or class name and description of purpose be included on the
- same "printed page" as the copyright notice for easier
- identification within third-party archives.
-
- Copyright 2015 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/LICENSE b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/LICENSE
deleted file mode 100644
index a148ba5..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/LICENSE
+++ /dev/null
@@ -1,203 +0,0 @@
-Apache License
-Version 2.0, January 2004
-http://www.apache.org/licenses/
-
-TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
-1. Definitions.
-
-"License" shall mean the terms and conditions for use, reproduction,
-and distribution as defined by Sections 1 through 9 of this document.
-
-"Licensor" shall mean the copyright owner or entity authorized by
-the copyright owner that is granting the License.
-
-"Legal Entity" shall mean the union of the acting entity and all
-other entities that control, are controlled by, or are under common
-control with that entity. For the purposes of this definition,
-"control" means (i) the power, direct or indirect, to cause the
-direction or management of such entity, whether by contract or
-otherwise, or (ii) ownership of fifty percent (50%) or more of the
-outstanding shares, or (iii) beneficial ownership of such entity.
-
-"You" (or "Your") shall mean an individual or Legal Entity
-exercising permissions granted by this License.
-
-"Source" form shall mean the preferred form for making modifications,
-including but not limited to software source code, documentation
-source, and configuration files.
-
-"Object" form shall mean any form resulting from mechanical
-transformation or translation of a Source form, including but
-not limited to compiled object code, generated documentation,
-and conversions to other media types.
-
-"Work" shall mean the work of authorship, whether in Source or
-Object form, made available under the License, as indicated by a
-copyright notice that is included in or attached to the work
-(an example is provided in the Appendix below).
-
-"Derivative Works" shall mean any work, whether in Source or Object
-form, that is based on (or derived from) the Work and for which the
-editorial revisions, annotations, elaborations, or other modifications
-represent, as a whole, an original work of authorship. For the purposes
-of this License, Derivative Works shall not include works that remain
-separable from, or merely link (or bind by name) to the interfaces of,
-the Work and Derivative Works thereof.
-
-"Contribution" shall mean any work of authorship, including
-the original version of the Work and any modifications or additions
-to that Work or Derivative Works thereof, that is intentionally
-submitted to Licensor for inclusion in the Work by the copyright owner
-or by an individual or Legal Entity authorized to submit on behalf of
-the copyright owner. For the purposes of this definition, "submitted"
-means any form of electronic, verbal, or written communication sent
-to the Licensor or its representatives, including but not limited to
-communication on electronic mailing lists, source code control systems,
-and issue tracking systems that are managed by, or on behalf of, the
-Licensor for the purpose of discussing and improving the Work, but
-excluding communication that is conspicuously marked or otherwise
-designated in writing by the copyright owner as "Not a Contribution."
-
-"Contributor" shall mean Licensor and any individual or Legal Entity
-on behalf of whom a Contribution has been received by Licensor and
-subsequently incorporated within the Work.
-
-2. Grant of Copyright License. Subject to the terms and conditions of
-this License, each Contributor hereby grants to You a perpetual,
-worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-copyright license to reproduce, prepare Derivative Works of,
-publicly display, publicly perform, sublicense, and distribute the
-Work and such Derivative Works in Source or Object form.
-
-3. Grant of Patent License. Subject to the terms and conditions of
-this License, each Contributor hereby grants to You a perpetual,
-worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-(except as stated in this section) patent license to make, have made,
-use, offer to sell, sell, import, and otherwise transfer the Work,
-where such license applies only to those patent claims licensable
-by such Contributor that are necessarily infringed by their
-Contribution(s) alone or by combination of their Contribution(s)
-with the Work to which such Contribution(s) was submitted. If You
-institute patent litigation against any entity (including a
-cross-claim or counterclaim in a lawsuit) alleging that the Work
-or a Contribution incorporated within the Work constitutes direct
-or contributory patent infringement, then any patent licenses
-granted to You under this License for that Work shall terminate
-as of the date such litigation is filed.
-
-4. Redistribution. You may reproduce and distribute copies of the
-Work or Derivative Works thereof in any medium, with or without
-modifications, and in Source or Object form, provided that You
-meet the following conditions:
-
-(a) You must give any other recipients of the Work or
-Derivative Works a copy of this License; and
-
-(b) You must cause any modified files to carry prominent notices
-stating that You changed the files; and
-
-(c) You must retain, in the Source form of any Derivative Works
-that You distribute, all copyright, patent, trademark, and
-attribution notices from the Source form of the Work,
-excluding those notices that do not pertain to any part of
-the Derivative Works; and
-
-(d) If the Work includes a "NOTICE" text file as part of its
-distribution, then any Derivative Works that You distribute must
-include a readable copy of the attribution notices contained
-within such NOTICE file, excluding those notices that do not
-pertain to any part of the Derivative Works, in at least one
-of the following places: within a NOTICE text file distributed
-as part of the Derivative Works; within the Source form or
-documentation, if provided along with the Derivative Works; or,
-within a display generated by the Derivative Works, if and
-wherever such third-party notices normally appear. The contents
-of the NOTICE file are for informational purposes only and
-do not modify the License. You may add Your own attribution
-notices within Derivative Works that You distribute, alongside
-or as an addendum to the NOTICE text from the Work, provided
-that such additional attribution notices cannot be construed
-as modifying the License.
-
-You may add Your own copyright statement to Your modifications and
-may provide additional or different license terms and conditions
-for use, reproduction, or distribution of Your modifications, or
-for any such Derivative Works as a whole, provided Your use,
-reproduction, and distribution of the Work otherwise complies with
-the conditions stated in this License.
-
-5. Submission of Contributions. Unless You explicitly state otherwise,
-any Contribution intentionally submitted for inclusion in the Work
-by You to the Licensor shall be under the terms and conditions of
-this License, without any additional terms or conditions.
-Notwithstanding the above, nothing herein shall supersede or modify
-the terms of any separate license agreement you may have executed
-with Licensor regarding such Contributions.
-
-6. Trademarks. This License does not grant permission to use the trade
-names, trademarks, service marks, or product names of the Licensor,
-except as required for reasonable and customary use in describing the
-origin of the Work and reproducing the content of the NOTICE file.
-
-7. Disclaimer of Warranty. Unless required by applicable law or
-agreed to in writing, Licensor provides the Work (and each
-Contributor provides its Contributions) on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-implied, including, without limitation, any warranties or conditions
-of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
-PARTICULAR PURPOSE. You are solely responsible for determining the
-appropriateness of using or redistributing the Work and assume any
-risks associated with Your exercise of permissions under this License.
-
-8. Limitation of Liability. In no event and under no legal theory,
-whether in tort (including negligence), contract, or otherwise,
-unless required by applicable law (such as deliberate and grossly
-negligent acts) or agreed to in writing, shall any Contributor be
-liable to You for damages, including any direct, indirect, special,
-incidental, or consequential damages of any character arising as a
-result of this License or out of the use or inability to use the
-Work (including but not limited to damages for loss of goodwill,
-work stoppage, computer failure or malfunction, or any and all
-other commercial damages or losses), even if such Contributor
-has been advised of the possibility of such damages.
-
-9. Accepting Warranty or Additional Liability. While redistributing
-the Work or Derivative Works thereof, You may choose to offer,
-and charge a fee for, acceptance of support, warranty, indemnity,
-or other liability obligations and/or rights consistent with this
-License. However, in accepting such obligations, You may act only
-on Your own behalf and on Your sole responsibility, not on behalf
-of any other Contributor, and only if You agree to indemnify,
-defend, and hold each Contributor harmless for any liability
-incurred by, or claims asserted against, such Contributor by reason
-of your accepting any such warranty or additional liability.
-
-END OF TERMS AND CONDITIONS
-
-APPENDIX: How to apply the Apache License to your work.
-
-To apply the Apache License to your work, attach the following
-boilerplate notice, with the fields enclosed by brackets "[]"
-replaced with your own identifying information. (Don't include
-the brackets!) The text should be enclosed in the appropriate
-comment syntax for the file format. We also recommend that a
-file or class name and description of purpose be included on the
-same "printed page" as the copyright notice for easier
-identification within third-party archives.
-
-Copyright [yyyy] [name of copyright owner]
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-
-
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/VERSION b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/VERSION
deleted file mode 100644
index 7aa332e..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/VERSION
+++ /dev/null
@@ -1 +0,0 @@
-1.33.0
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/autoload.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/autoload.php
deleted file mode 100644
index 621f00e..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/autoload.php
+++ /dev/null
@@ -1,35 +0,0 @@
- 3) {
- // Maximum class file path depth in this project is 3.
- $classPath = \array_slice($classPath, 0, 3);
- }
- $filePath = \dirname(__FILE__) . '/src/' . \implode('/', $classPath) . '.php';
- if (\file_exists($filePath)) {
- require_once $filePath;
- }
-}
-\spl_autoload_register('oauth2client_php_autoload');
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/AccessToken.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/AccessToken.php
deleted file mode 100644
index d7906c3..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/AccessToken.php
+++ /dev/null
@@ -1,430 +0,0 @@
-httpHandler = $httpHandler ?: HttpHandlerFactory::build(HttpClientCache::getHttpClient());
- $this->cache = $cache ?: new MemoryCacheItemPool();
- }
- /**
- * Verifies an id token and returns the authenticated apiLoginTicket.
- * Throws an exception if the id token is not valid.
- * The audience parameter can be used to control which id tokens are
- * accepted. By default, the id token must have been issued to this OAuth2 client.
- *
- * @param string $token The JSON Web Token to be verified.
- * @param array $options [optional] {
- * Configuration options.
- * @type string $audience The indended recipient of the token.
- * @type string $issuer The intended issuer of the token.
- * @type string $cacheKey The cache key of the cached certs. Defaults to
- * the sha1 of $certsLocation if provided, otherwise is set to
- * "federated_signon_certs_v3".
- * @type string $certsLocation The location (remote or local) from which
- * to retrieve certificates, if not cached. This value should only be
- * provided in limited circumstances in which you are sure of the
- * behavior.
- * @type bool $throwException Whether the function should throw an
- * exception if the verification fails. This is useful for
- * determining the reason verification failed.
- * }
- * @return array|false the token payload, if successful, or false if not.
- * @throws InvalidArgumentException If certs could not be retrieved from a local file.
- * @throws InvalidArgumentException If received certs are in an invalid format.
- * @throws InvalidArgumentException If the cert alg is not supported.
- * @throws RuntimeException If certs could not be retrieved from a remote location.
- * @throws UnexpectedValueException If the token issuer does not match.
- * @throws UnexpectedValueException If the token audience does not match.
- */
- public function verify($token, array $options = [])
- {
- $audience = $options['audience'] ?? null;
- $issuer = $options['issuer'] ?? null;
- $certsLocation = $options['certsLocation'] ?? self::FEDERATED_SIGNON_CERT_URL;
- $cacheKey = $options['cacheKey'] ?? $this->getCacheKeyFromCertLocation($certsLocation);
- $throwException = $options['throwException'] ?? \false;
- // for backwards compatibility
- // Check signature against each available cert.
- $certs = $this->getCerts($certsLocation, $cacheKey, $options);
- $alg = $this->determineAlg($certs);
- if (!in_array($alg, ['RS256', 'ES256'])) {
- throw new InvalidArgumentException('unrecognized "alg" in certs, expected ES256 or RS256');
- }
- try {
- if ($alg == 'RS256') {
- return $this->verifyRs256($token, $certs, $audience, $issuer);
- }
- return $this->verifyEs256($token, $certs, $audience, $issuer);
- } catch (ExpiredException $e) {
- // firebase/php-jwt 5+
- } catch (SignatureInvalidException $e) {
- // firebase/php-jwt 5+
- } catch (InvalidTokenException $e) {
- // simplejwt
- } catch (InvalidArgumentException $e) {
- } catch (UnexpectedValueException $e) {
- }
- if ($throwException) {
- throw $e;
- }
- return \false;
- }
- /**
- * Identifies the expected algorithm to verify by looking at the "alg" key
- * of the provided certs.
- *
- * @param array $certs Certificate array according to the JWK spec (see
- * https://tools.ietf.org/html/rfc7517).
- * @return string The expected algorithm, such as "ES256" or "RS256".
- */
- private function determineAlg(array $certs)
- {
- $alg = null;
- foreach ($certs as $cert) {
- if (empty($cert['alg'])) {
- throw new InvalidArgumentException('certs expects "alg" to be set');
- }
- $alg = $alg ?: $cert['alg'];
- if ($alg != $cert['alg']) {
- throw new InvalidArgumentException('More than one alg detected in certs');
- }
- }
- return $alg;
- }
- /**
- * Verifies an ES256-signed JWT.
- *
- * @param string $token The JSON Web Token to be verified.
- * @param array $certs Certificate array according to the JWK spec (see
- * https://tools.ietf.org/html/rfc7517).
- * @param string|null $audience If set, returns false if the provided
- * audience does not match the "aud" claim on the JWT.
- * @param string|null $issuer If set, returns false if the provided
- * issuer does not match the "iss" claim on the JWT.
- * @return array the token payload, if successful, or false if not.
- */
- private function verifyEs256($token, array $certs, $audience = null, $issuer = null)
- {
- $this->checkSimpleJwt();
- $jwkset = new KeySet();
- foreach ($certs as $cert) {
- $jwkset->add(KeyFactory::create($cert, 'php'));
- }
- // Validate the signature using the key set and ES256 algorithm.
- $jwt = $this->callSimpleJwtDecode([$token, $jwkset, 'ES256']);
- $payload = $jwt->getClaims();
- if ($audience) {
- if (!isset($payload['aud']) || $payload['aud'] != $audience) {
- throw new UnexpectedValueException('Audience does not match');
- }
- }
- // @see https://cloud.google.com/iap/docs/signed-headers-howto#verifying_the_jwt_payload
- $issuer = $issuer ?: self::IAP_ISSUER;
- if (!isset($payload['iss']) || $payload['iss'] !== $issuer) {
- throw new UnexpectedValueException('Issuer does not match');
- }
- return $payload;
- }
- /**
- * Verifies an RS256-signed JWT.
- *
- * @param string $token The JSON Web Token to be verified.
- * @param array $certs Certificate array according to the JWK spec (see
- * https://tools.ietf.org/html/rfc7517).
- * @param string|null $audience If set, returns false if the provided
- * audience does not match the "aud" claim on the JWT.
- * @param string|null $issuer If set, returns false if the provided
- * issuer does not match the "iss" claim on the JWT.
- * @return array the token payload, if successful, or false if not.
- */
- private function verifyRs256($token, array $certs, $audience = null, $issuer = null)
- {
- $this->checkAndInitializePhpsec();
- $keys = [];
- foreach ($certs as $cert) {
- if (empty($cert['kid'])) {
- throw new InvalidArgumentException('certs expects "kid" to be set');
- }
- if (empty($cert['n']) || empty($cert['e'])) {
- throw new InvalidArgumentException('RSA certs expects "n" and "e" to be set');
- }
- $publicKey = $this->loadPhpsecPublicKey($cert['n'], $cert['e']);
- // create an array of key IDs to certs for the JWT library
- $keys[$cert['kid']] = new Key($publicKey, 'RS256');
- }
- $payload = $this->callJwtStatic('decode', [$token, $keys]);
- if ($audience) {
- if (!property_exists($payload, 'aud') || $payload->aud != $audience) {
- throw new UnexpectedValueException('Audience does not match');
- }
- }
- // support HTTP and HTTPS issuers
- // @see https://developers.google.com/identity/sign-in/web/backend-auth
- $issuers = $issuer ? [$issuer] : [self::OAUTH2_ISSUER, self::OAUTH2_ISSUER_HTTPS];
- if (!isset($payload->iss) || !in_array($payload->iss, $issuers)) {
- throw new UnexpectedValueException('Issuer does not match');
- }
- return (array) $payload;
- }
- /**
- * Revoke an OAuth2 access token or refresh token. This method will revoke the current access
- * token, if a token isn't provided.
- *
- * @param string|array $token The token (access token or a refresh token) that should be revoked.
- * @param array $options [optional] Configuration options.
- * @return bool Returns True if the revocation was successful, otherwise False.
- */
- public function revoke($token, array $options = [])
- {
- if (is_array($token)) {
- if (isset($token['refresh_token'])) {
- $token = $token['refresh_token'];
- } else {
- $token = $token['access_token'];
- }
- }
- $body = Utils::streamFor(http_build_query(['token' => $token]));
- $request = new Request('POST', self::OAUTH2_REVOKE_URI, ['Cache-Control' => 'no-store', 'Content-Type' => 'application/x-www-form-urlencoded'], $body);
- $httpHandler = $this->httpHandler;
- $response = $httpHandler($request, $options);
- return $response->getStatusCode() == 200;
- }
- /**
- * Gets federated sign-on certificates to use for verifying identity tokens.
- * Returns certs as array structure, where keys are key ids, and values
- * are PEM encoded certificates.
- *
- * @param string $location The location from which to retrieve certs.
- * @param string $cacheKey The key under which to cache the retrieved certs.
- * @param array $options [optional] Configuration options.
- * @return array
- * @throws InvalidArgumentException If received certs are in an invalid format.
- */
- private function getCerts($location, $cacheKey, array $options = [])
- {
- $cacheItem = $this->cache->getItem($cacheKey);
- $certs = $cacheItem ? $cacheItem->get() : null;
- $expireTime = null;
- if (!$certs) {
- list($certs, $expireTime) = $this->retrieveCertsFromLocation($location, $options);
- }
- if (!isset($certs['keys'])) {
- if ($location !== self::IAP_CERT_URL) {
- throw new InvalidArgumentException('federated sign-on certs expects "keys" to be set');
- }
- throw new InvalidArgumentException('certs expects "keys" to be set');
- }
- // Push caching off until after verifying certs are in a valid format.
- // Don't want to cache bad data.
- if ($expireTime) {
- $cacheItem->expiresAt(new DateTime($expireTime));
- $cacheItem->set($certs);
- $this->cache->save($cacheItem);
- }
- return $certs['keys'];
- }
- /**
- * Retrieve and cache a certificates file.
- *
- * @param string $url location
- * @param array $options [optional] Configuration options.
- * @return array{array, string}
- * @throws InvalidArgumentException If certs could not be retrieved from a local file.
- * @throws RuntimeException If certs could not be retrieved from a remote location.
- */
- private function retrieveCertsFromLocation($url, array $options = [])
- {
- // If we're retrieving a local file, just grab it.
- $expireTime = '+1 hour';
- if (strpos($url, 'http') !== 0) {
- if (!file_exists($url)) {
- throw new InvalidArgumentException(sprintf('Failed to retrieve verification certificates from path: %s.', $url));
- }
- return [json_decode((string) file_get_contents($url), \true), $expireTime];
- }
- $httpHandler = $this->httpHandler;
- $response = $httpHandler(new Request('GET', $url), $options);
- if ($response->getStatusCode() == 200) {
- if ($cacheControl = $response->getHeaderLine('Cache-Control')) {
- array_map(function ($value) use(&$expireTime) {
- list($key, $value) = explode('=', $value) + [null, null];
- if (trim($key) == 'max-age') {
- $expireTime = '+' . $value . ' seconds';
- }
- }, explode(',', $cacheControl));
- }
- return [json_decode((string) $response->getBody(), \true), $expireTime];
- }
- throw new RuntimeException(sprintf('Failed to retrieve verification certificates: "%s".', $response->getBody()->getContents()), $response->getStatusCode());
- }
- /**
- * @return void
- */
- private function checkAndInitializePhpsec()
- {
- if (!$this->checkAndInitializePhpsec2() && !$this->checkPhpsec3()) {
- throw new RuntimeException('Please require phpseclib/phpseclib v2 or v3 to use this utility.');
- }
- }
- /**
- * @return string
- * @throws TypeError If the key cannot be initialized to a string.
- */
- private function loadPhpsecPublicKey(string $modulus, string $exponent) : string
- {
- if (class_exists(RSA::class) && class_exists(BigInteger2::class)) {
- $key = new RSA();
- $key->loadKey(['n' => new BigInteger2($this->callJwtStatic('urlsafeB64Decode', [$modulus]), 256), 'e' => new BigInteger2($this->callJwtStatic('urlsafeB64Decode', [$exponent]), 256)]);
- return $key->getPublicKey();
- }
- $key = PublicKeyLoader::load(['n' => new BigInteger3($this->callJwtStatic('urlsafeB64Decode', [$modulus]), 256), 'e' => new BigInteger3($this->callJwtStatic('urlsafeB64Decode', [$exponent]), 256)]);
- $formattedPublicKey = $key->toString('PKCS8');
- if (!is_string($formattedPublicKey)) {
- throw new TypeError('Failed to initialize the key');
- }
- return $formattedPublicKey;
- }
- /**
- * @return bool
- */
- private function checkAndInitializePhpsec2() : bool
- {
- if (!class_exists('phpseclib\\Crypt\\RSA')) {
- return \false;
- }
- /**
- * phpseclib calls "phpinfo" by default, which requires special
- * whitelisting in the AppEngine VM environment. This function
- * sets constants to bypass the need for phpseclib to check phpinfo
- *
- * @see phpseclib/Math/BigInteger
- * @see https://github.com/GoogleCloudPlatform/getting-started-php/issues/85
- * @codeCoverageIgnore
- */
- if (filter_var(getenv('GAE_VM'), \FILTER_VALIDATE_BOOLEAN)) {
- if (!defined('Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\MATH_BIGINTEGER_OPENSSL_ENABLED')) {
- define('Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\MATH_BIGINTEGER_OPENSSL_ENABLED', \true);
- }
- if (!defined('Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\CRYPT_RSA_MODE')) {
- define('Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\CRYPT_RSA_MODE', RSA::MODE_OPENSSL);
- }
- }
- return \true;
- }
- /**
- * @return bool
- */
- private function checkPhpsec3() : bool
- {
- return class_exists('Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\phpseclib3\\Crypt\\RSA');
- }
- /**
- * @return void
- */
- private function checkSimpleJwt()
- {
- // @codeCoverageIgnoreStart
- if (!class_exists(SimpleJwt::class)) {
- throw new RuntimeException('Please require kelvinmo/simplejwt ^0.2 to use this utility.');
- }
- // @codeCoverageIgnoreEnd
- }
- /**
- * Provide a hook to mock calls to the JWT static methods.
- *
- * @param string $method
- * @param array $args
- * @return mixed
- */
- protected function callJwtStatic($method, array $args = [])
- {
- return call_user_func_array([JWT::class, $method], $args);
- // @phpstan-ignore-line
- }
- /**
- * Provide a hook to mock calls to the JWT static methods.
- *
- * @param array $args
- * @return mixed
- */
- protected function callSimpleJwtDecode(array $args = [])
- {
- return call_user_func_array([SimpleJwt::class, 'decode'], $args);
- }
- /**
- * Generate a cache key based on the cert location using sha1 with the
- * exception of using "federated_signon_certs_v3" to preserve BC.
- *
- * @param string $certsLocation
- * @return string
- */
- private function getCacheKeyFromCertLocation($certsLocation)
- {
- $key = $certsLocation === self::FEDERATED_SIGNON_CERT_URL ? 'federated_signon_certs_v3' : sha1($certsLocation);
- return 'google_auth_certs_cache|' . $key;
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/ApplicationDefaultCredentials.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/ApplicationDefaultCredentials.php
deleted file mode 100644
index ab9b094..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/ApplicationDefaultCredentials.php
+++ /dev/null
@@ -1,301 +0,0 @@
-push($middleware);
- *
- * $client = new Client([
- * 'handler' => $stack,
- * 'base_uri' => 'https://www.googleapis.com/taskqueue/v1beta2/projects/',
- * 'auth' => 'google_auth' // authorize all requests
- * ]);
- *
- * $res = $client->get('myproject/taskqueues/myqueue');
- * ```
- */
-class ApplicationDefaultCredentials
-{
- /**
- * @deprecated
- *
- * Obtains an AuthTokenSubscriber that uses the default FetchAuthTokenInterface
- * implementation to use in this environment.
- *
- * If supplied, $scope is used to in creating the credentials instance if
- * this does not fallback to the compute engine defaults.
- *
- * @param string|string[] $scope the scope of the access request, expressed
- * either as an Array or as a space-delimited String.
- * @param callable $httpHandler callback which delivers psr7 request
- * @param array $cacheConfig configuration for the cache when it's present
- * @param CacheItemPoolInterface $cache A cache implementation, may be
- * provided if you have one already available for use.
- * @return AuthTokenSubscriber
- * @throws DomainException if no implementation can be obtained.
- */
- public static function getSubscriber(
- // @phpstan-ignore-line
- $scope = null,
- callable $httpHandler = null,
- array $cacheConfig = null,
- CacheItemPoolInterface $cache = null
- )
- {
- $creds = self::getCredentials($scope, $httpHandler, $cacheConfig, $cache);
- /** @phpstan-ignore-next-line */
- return new AuthTokenSubscriber($creds, $httpHandler);
- }
- /**
- * Obtains an AuthTokenMiddleware that uses the default FetchAuthTokenInterface
- * implementation to use in this environment.
- *
- * If supplied, $scope is used to in creating the credentials instance if
- * this does not fallback to the compute engine defaults.
- *
- * @param string|string[] $scope the scope of the access request, expressed
- * either as an Array or as a space-delimited String.
- * @param callable $httpHandler callback which delivers psr7 request
- * @param array $cacheConfig configuration for the cache when it's present
- * @param CacheItemPoolInterface $cache A cache implementation, may be
- * provided if you have one already available for use.
- * @param string $quotaProject specifies a project to bill for access
- * charges associated with the request.
- * @return AuthTokenMiddleware
- * @throws DomainException if no implementation can be obtained.
- */
- public static function getMiddleware($scope = null, callable $httpHandler = null, array $cacheConfig = null, CacheItemPoolInterface $cache = null, $quotaProject = null)
- {
- $creds = self::getCredentials($scope, $httpHandler, $cacheConfig, $cache, $quotaProject);
- return new AuthTokenMiddleware($creds, $httpHandler);
- }
- /**
- * Obtains the default FetchAuthTokenInterface implementation to use
- * in this environment.
- *
- * @param string|string[] $scope the scope of the access request, expressed
- * either as an Array or as a space-delimited String.
- * @param callable $httpHandler callback which delivers psr7 request
- * @param array $cacheConfig configuration for the cache when it's present
- * @param CacheItemPoolInterface $cache A cache implementation, may be
- * provided if you have one already available for use.
- * @param string $quotaProject specifies a project to bill for access
- * charges associated with the request.
- * @param string|string[] $defaultScope The default scope to use if no
- * user-defined scopes exist, expressed either as an Array or as a
- * space-delimited string.
- * @param string $universeDomain Specifies a universe domain to use for the
- * calling client library
- *
- * @return FetchAuthTokenInterface
- * @throws DomainException if no implementation can be obtained.
- */
- public static function getCredentials($scope = null, callable $httpHandler = null, array $cacheConfig = null, CacheItemPoolInterface $cache = null, $quotaProject = null, $defaultScope = null, string $universeDomain = null)
- {
- $creds = null;
- $jsonKey = CredentialsLoader::fromEnv() ?: CredentialsLoader::fromWellKnownFile();
- $anyScope = $scope ?: $defaultScope;
- if (!$httpHandler) {
- if (!($client = HttpClientCache::getHttpClient())) {
- $client = new Client();
- HttpClientCache::setHttpClient($client);
- }
- $httpHandler = HttpHandlerFactory::build($client);
- }
- if (is_null($quotaProject)) {
- // if a quota project isn't specified, try to get one from the env var
- $quotaProject = CredentialsLoader::quotaProjectFromEnv();
- }
- if (!is_null($jsonKey)) {
- if ($quotaProject) {
- $jsonKey['quota_project_id'] = $quotaProject;
- }
- if ($universeDomain) {
- $jsonKey['universe_domain'] = $universeDomain;
- }
- $creds = CredentialsLoader::makeCredentials($scope, $jsonKey, $defaultScope);
- } elseif (AppIdentityCredentials::onAppEngine() && !GCECredentials::onAppEngineFlexible()) {
- $creds = new AppIdentityCredentials($anyScope);
- } elseif (self::onGce($httpHandler, $cacheConfig, $cache)) {
- $creds = new GCECredentials(null, $anyScope, null, $quotaProject, null, $universeDomain);
- $creds->setIsOnGce(\true);
- // save the credentials a trip to the metadata server
- }
- if (is_null($creds)) {
- throw new DomainException(self::notFound());
- }
- if (!is_null($cache)) {
- $creds = new FetchAuthTokenCache($creds, $cacheConfig, $cache);
- }
- return $creds;
- }
- /**
- * Obtains an AuthTokenMiddleware which will fetch an ID token to use in the
- * Authorization header. The middleware is configured with the default
- * FetchAuthTokenInterface implementation to use in this environment.
- *
- * If supplied, $targetAudience is used to set the "aud" on the resulting
- * ID token.
- *
- * @param string $targetAudience The audience for the ID token.
- * @param callable $httpHandler callback which delivers psr7 request
- * @param array $cacheConfig configuration for the cache when it's present
- * @param CacheItemPoolInterface $cache A cache implementation, may be
- * provided if you have one already available for use.
- * @return AuthTokenMiddleware
- * @throws DomainException if no implementation can be obtained.
- */
- public static function getIdTokenMiddleware($targetAudience, callable $httpHandler = null, array $cacheConfig = null, CacheItemPoolInterface $cache = null)
- {
- $creds = self::getIdTokenCredentials($targetAudience, $httpHandler, $cacheConfig, $cache);
- return new AuthTokenMiddleware($creds, $httpHandler);
- }
- /**
- * Obtains an ProxyAuthTokenMiddleware which will fetch an ID token to use in the
- * Authorization header. The middleware is configured with the default
- * FetchAuthTokenInterface implementation to use in this environment.
- *
- * If supplied, $targetAudience is used to set the "aud" on the resulting
- * ID token.
- *
- * @param string $targetAudience The audience for the ID token.
- * @param callable $httpHandler callback which delivers psr7 request
- * @param array $cacheConfig configuration for the cache when it's present
- * @param CacheItemPoolInterface $cache A cache implementation, may be
- * provided if you have one already available for use.
- * @return ProxyAuthTokenMiddleware
- * @throws DomainException if no implementation can be obtained.
- */
- public static function getProxyIdTokenMiddleware($targetAudience, callable $httpHandler = null, array $cacheConfig = null, CacheItemPoolInterface $cache = null)
- {
- $creds = self::getIdTokenCredentials($targetAudience, $httpHandler, $cacheConfig, $cache);
- return new ProxyAuthTokenMiddleware($creds, $httpHandler);
- }
- /**
- * Obtains the default FetchAuthTokenInterface implementation to use
- * in this environment, configured with a $targetAudience for fetching an ID
- * token.
- *
- * @param string $targetAudience The audience for the ID token.
- * @param callable $httpHandler callback which delivers psr7 request
- * @param array $cacheConfig configuration for the cache when it's present
- * @param CacheItemPoolInterface $cache A cache implementation, may be
- * provided if you have one already available for use.
- * @return FetchAuthTokenInterface
- * @throws DomainException if no implementation can be obtained.
- * @throws InvalidArgumentException if JSON "type" key is invalid
- */
- public static function getIdTokenCredentials($targetAudience, callable $httpHandler = null, array $cacheConfig = null, CacheItemPoolInterface $cache = null)
- {
- $creds = null;
- $jsonKey = CredentialsLoader::fromEnv() ?: CredentialsLoader::fromWellKnownFile();
- if (!$httpHandler) {
- if (!($client = HttpClientCache::getHttpClient())) {
- $client = new Client();
- HttpClientCache::setHttpClient($client);
- }
- $httpHandler = HttpHandlerFactory::build($client);
- }
- if (!is_null($jsonKey)) {
- if (!array_key_exists('type', $jsonKey)) {
- throw new \InvalidArgumentException('json key is missing the type field');
- }
- if ($jsonKey['type'] == 'authorized_user') {
- throw new InvalidArgumentException('ID tokens are not supported for end user credentials');
- }
- if ($jsonKey['type'] != 'service_account') {
- throw new InvalidArgumentException('invalid value in the type field');
- }
- $creds = new ServiceAccountCredentials(null, $jsonKey, null, $targetAudience);
- } elseif (self::onGce($httpHandler, $cacheConfig, $cache)) {
- $creds = new GCECredentials(null, null, $targetAudience);
- $creds->setIsOnGce(\true);
- // save the credentials a trip to the metadata server
- }
- if (is_null($creds)) {
- throw new DomainException(self::notFound());
- }
- if (!is_null($cache)) {
- $creds = new FetchAuthTokenCache($creds, $cacheConfig, $cache);
- }
- return $creds;
- }
- /**
- * @return string
- */
- private static function notFound()
- {
- $msg = 'Your default credentials were not found. To set up ';
- $msg .= 'Application Default Credentials, see ';
- $msg .= 'https://cloud.google.com/docs/authentication/external/set-up-adc';
- return $msg;
- }
- /**
- * @param callable $httpHandler
- * @param array $cacheConfig
- * @param CacheItemPoolInterface $cache
- * @return bool
- */
- private static function onGce(callable $httpHandler = null, array $cacheConfig = null, CacheItemPoolInterface $cache = null)
- {
- $gceCacheConfig = [];
- foreach (['lifetime', 'prefix'] as $key) {
- if (isset($cacheConfig['gce_' . $key])) {
- $gceCacheConfig[$key] = $cacheConfig['gce_' . $key];
- }
- }
- return (new GCECache($gceCacheConfig, $cache))->onGce($httpHandler);
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/Cache/InvalidArgumentException.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/Cache/InvalidArgumentException.php
deleted file mode 100644
index 1414ac7..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/Cache/InvalidArgumentException.php
+++ /dev/null
@@ -1,23 +0,0 @@
-key = $key;
- }
- /**
- * {@inheritdoc}
- */
- public function getKey()
- {
- return $this->key;
- }
- /**
- * {@inheritdoc}
- */
- public function get()
- {
- return $this->isHit() ? $this->value : null;
- }
- /**
- * {@inheritdoc}
- */
- public function isHit()
- {
- if (!$this->isHit) {
- return \false;
- }
- if ($this->expiration === null) {
- return \true;
- }
- return $this->currentTime()->getTimestamp() < $this->expiration->getTimestamp();
- }
- /**
- * {@inheritdoc}
- */
- public function set($value)
- {
- $this->isHit = \true;
- $this->value = $value;
- return $this;
- }
- /**
- * {@inheritdoc}
- */
- public function expiresAt($expiration)
- {
- if ($this->isValidExpiration($expiration)) {
- $this->expiration = $expiration;
- return $this;
- }
- $error = sprintf('Argument 1 passed to %s::expiresAt() must implement interface DateTimeInterface, %s given', get_class($this), gettype($expiration));
- throw new TypeError($error);
- }
- /**
- * {@inheritdoc}
- */
- public function expiresAfter($time)
- {
- if (is_int($time)) {
- $this->expiration = $this->currentTime()->add(new \DateInterval("PT{$time}S"));
- } elseif ($time instanceof \DateInterval) {
- $this->expiration = $this->currentTime()->add($time);
- } elseif ($time === null) {
- $this->expiration = $time;
- } else {
- $message = 'Argument 1 passed to %s::expiresAfter() must be an ' . 'instance of DateInterval or of the type integer, %s given';
- $error = sprintf($message, get_class($this), gettype($time));
- throw new TypeError($error);
- }
- return $this;
- }
- /**
- * Determines if an expiration is valid based on the rules defined by PSR6.
- *
- * @param mixed $expiration
- * @return bool
- */
- private function isValidExpiration($expiration)
- {
- if ($expiration === null) {
- return \true;
- }
- if ($expiration instanceof DateTimeInterface) {
- return \true;
- }
- return \false;
- }
- /**
- * @return DateTime
- */
- protected function currentTime()
- {
- return new DateTime('now', new DateTimeZone('UTC'));
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/Cache/MemoryCacheItemPool.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/Cache/MemoryCacheItemPool.php
deleted file mode 100644
index 7ce3614..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/Cache/MemoryCacheItemPool.php
+++ /dev/null
@@ -1,161 +0,0 @@
-getItems([$key]));
- // @phpstan-ignore-line
- }
- /**
- * {@inheritdoc}
- *
- * @return iterable
- * A traversable collection of Cache Items keyed by the cache keys of
- * each item. A Cache item will be returned for each key, even if that
- * key is not found. However, if no keys are specified then an empty
- * traversable MUST be returned instead.
- */
- public function getItems(array $keys = []) : iterable
- {
- $items = [];
- $itemClass = \PHP_VERSION_ID >= 80000 ? TypedItem::class : Item::class;
- foreach ($keys as $key) {
- $items[$key] = $this->hasItem($key) ? clone $this->items[$key] : new $itemClass($key);
- }
- return $items;
- }
- /**
- * {@inheritdoc}
- *
- * @return bool
- * True if item exists in the cache, false otherwise.
- */
- public function hasItem($key) : bool
- {
- $this->isValidKey($key);
- return isset($this->items[$key]) && $this->items[$key]->isHit();
- }
- /**
- * {@inheritdoc}
- *
- * @return bool
- * True if the pool was successfully cleared. False if there was an error.
- */
- public function clear() : bool
- {
- $this->items = [];
- $this->deferredItems = [];
- return \true;
- }
- /**
- * {@inheritdoc}
- *
- * @return bool
- * True if the item was successfully removed. False if there was an error.
- */
- public function deleteItem($key) : bool
- {
- return $this->deleteItems([$key]);
- }
- /**
- * {@inheritdoc}
- *
- * @return bool
- * True if the items were successfully removed. False if there was an error.
- */
- public function deleteItems(array $keys) : bool
- {
- array_walk($keys, [$this, 'isValidKey']);
- foreach ($keys as $key) {
- unset($this->items[$key]);
- }
- return \true;
- }
- /**
- * {@inheritdoc}
- *
- * @return bool
- * True if the item was successfully persisted. False if there was an error.
- */
- public function save(CacheItemInterface $item) : bool
- {
- $this->items[$item->getKey()] = $item;
- return \true;
- }
- /**
- * {@inheritdoc}
- *
- * @return bool
- * False if the item could not be queued or if a commit was attempted and failed. True otherwise.
- */
- public function saveDeferred(CacheItemInterface $item) : bool
- {
- $this->deferredItems[$item->getKey()] = $item;
- return \true;
- }
- /**
- * {@inheritdoc}
- *
- * @return bool
- * True if all not-yet-saved items were successfully saved or there were none. False otherwise.
- */
- public function commit() : bool
- {
- foreach ($this->deferredItems as $item) {
- $this->save($item);
- }
- $this->deferredItems = [];
- return \true;
- }
- /**
- * Determines if the provided key is valid.
- *
- * @param string $key
- * @return bool
- * @throws InvalidArgumentException
- */
- private function isValidKey($key)
- {
- $invalidCharacters = '{}()/\\\\@:';
- if (!is_string($key) || preg_match("#[{$invalidCharacters}]#", $key)) {
- throw new InvalidArgumentException('The provided key is not valid: ' . var_export($key, \true));
- }
- return \true;
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/Cache/SysVCacheItemPool.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/Cache/SysVCacheItemPool.php
deleted file mode 100644
index 9d81bd8..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/Cache/SysVCacheItemPool.php
+++ /dev/null
@@ -1,207 +0,0 @@
-
- */
- private $options;
- /**
- * @var bool
- */
- private $hasLoadedItems = \false;
- /**
- * Create a SystemV shared memory based CacheItemPool.
- *
- * @param array $options {
- * [optional] Configuration options.
- *
- * @type int $variableKey The variable key for getting the data from the shared memory. **Defaults to** 1.
- * @type string $proj The project identifier for ftok. This needs to be a one character string.
- * **Defaults to** 'A'.
- * @type int $memsize The memory size in bytes for shm_attach. **Defaults to** 10000.
- * @type int $perm The permission for shm_attach. **Defaults to** 0600.
- * }
- */
- public function __construct($options = [])
- {
- if (!extension_loaded('sysvshm')) {
- throw new \RuntimeException('sysvshm extension is required to use this ItemPool');
- }
- $this->options = $options + ['variableKey' => self::VAR_KEY, 'proj' => self::DEFAULT_PROJ, 'memsize' => self::DEFAULT_MEMSIZE, 'perm' => self::DEFAULT_PERM];
- $this->items = [];
- $this->deferredItems = [];
- $this->sysvKey = ftok(__FILE__, $this->options['proj']);
- }
- /**
- * @param mixed $key
- * @return CacheItemInterface
- */
- public function getItem($key) : CacheItemInterface
- {
- $this->loadItems();
- return current($this->getItems([$key]));
- // @phpstan-ignore-line
- }
- /**
- * @param array $keys
- * @return iterable
- */
- public function getItems(array $keys = []) : iterable
- {
- $this->loadItems();
- $items = [];
- $itemClass = \PHP_VERSION_ID >= 80000 ? TypedItem::class : Item::class;
- foreach ($keys as $key) {
- $items[$key] = $this->hasItem($key) ? clone $this->items[$key] : new $itemClass($key);
- }
- return $items;
- }
- /**
- * {@inheritdoc}
- */
- public function hasItem($key) : bool
- {
- $this->loadItems();
- return isset($this->items[$key]) && $this->items[$key]->isHit();
- }
- /**
- * {@inheritdoc}
- */
- public function clear() : bool
- {
- $this->items = [];
- $this->deferredItems = [];
- return $this->saveCurrentItems();
- }
- /**
- * {@inheritdoc}
- */
- public function deleteItem($key) : bool
- {
- return $this->deleteItems([$key]);
- }
- /**
- * {@inheritdoc}
- */
- public function deleteItems(array $keys) : bool
- {
- if (!$this->hasLoadedItems) {
- $this->loadItems();
- }
- foreach ($keys as $key) {
- unset($this->items[$key]);
- }
- return $this->saveCurrentItems();
- }
- /**
- * {@inheritdoc}
- */
- public function save(CacheItemInterface $item) : bool
- {
- if (!$this->hasLoadedItems) {
- $this->loadItems();
- }
- $this->items[$item->getKey()] = $item;
- return $this->saveCurrentItems();
- }
- /**
- * {@inheritdoc}
- */
- public function saveDeferred(CacheItemInterface $item) : bool
- {
- $this->deferredItems[$item->getKey()] = $item;
- return \true;
- }
- /**
- * {@inheritdoc}
- */
- public function commit() : bool
- {
- foreach ($this->deferredItems as $item) {
- if ($this->save($item) === \false) {
- return \false;
- }
- }
- $this->deferredItems = [];
- return \true;
- }
- /**
- * Save the current items.
- *
- * @return bool true when success, false upon failure
- */
- private function saveCurrentItems()
- {
- $shmid = shm_attach($this->sysvKey, $this->options['memsize'], $this->options['perm']);
- if ($shmid !== \false) {
- $ret = shm_put_var($shmid, $this->options['variableKey'], $this->items);
- shm_detach($shmid);
- return $ret;
- }
- return \false;
- }
- /**
- * Load the items from the shared memory.
- *
- * @return bool true when success, false upon failure
- */
- private function loadItems()
- {
- $shmid = shm_attach($this->sysvKey, $this->options['memsize'], $this->options['perm']);
- if ($shmid !== \false) {
- $data = @shm_get_var($shmid, $this->options['variableKey']);
- if (!empty($data)) {
- $this->items = $data;
- } else {
- $this->items = [];
- }
- shm_detach($shmid);
- $this->hasLoadedItems = \true;
- return \true;
- }
- return \false;
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/Cache/TypedItem.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/Cache/TypedItem.php
deleted file mode 100644
index 1bab6ab..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/Cache/TypedItem.php
+++ /dev/null
@@ -1,152 +0,0 @@
-key = $key;
- $this->key = $key;
- $this->expiration = null;
- }
- /**
- * {@inheritdoc}
- */
- public function getKey() : string
- {
- return $this->key;
- }
- /**
- * {@inheritdoc}
- * @return mixed
- */
- public function get()
- {
- return $this->isHit() ? $this->value : null;
- }
- /**
- * {@inheritdoc}
- */
- public function isHit() : bool
- {
- if (!$this->isHit) {
- return \false;
- }
- if ($this->expiration === null) {
- return \true;
- }
- return $this->currentTime()->getTimestamp() < $this->expiration->getTimestamp();
- }
- /**
- * {@inheritdoc}
- * @param mixed $value
- * @return static
- */
- public function set($value)
- {
- $this->isHit = \true;
- $this->value = $value;
- return $this;
- }
- /**
- * {@inheritdoc}
- * @return static
- */
- public function expiresAt($expiration)
- {
- if ($this->isValidExpiration($expiration)) {
- $this->expiration = $expiration;
- return $this;
- }
- $error = sprintf('Argument 1 passed to %s::expiresAt() must implement interface DateTimeInterface, %s given', get_class($this), gettype($expiration));
- throw new \TypeError($error);
- }
- /**
- * {@inheritdoc}
- * @return static
- */
- public function expiresAfter($time)
- {
- if (is_int($time)) {
- $this->expiration = $this->currentTime()->add(new \DateInterval("PT{$time}S"));
- } elseif ($time instanceof \DateInterval) {
- $this->expiration = $this->currentTime()->add($time);
- } elseif ($time === null) {
- $this->expiration = $time;
- } else {
- $message = 'Argument 1 passed to %s::expiresAfter() must be an ' . 'instance of DateInterval or of the type integer, %s given';
- $error = sprintf($message, get_class($this), gettype($time));
- throw new \TypeError($error);
- }
- return $this;
- }
- /**
- * Determines if an expiration is valid based on the rules defined by PSR6.
- *
- * @param mixed $expiration
- * @return bool
- */
- private function isValidExpiration($expiration)
- {
- if ($expiration === null) {
- return \true;
- }
- // We test for two types here due to the fact the DateTimeInterface
- // was not introduced until PHP 5.5. Checking for the DateTime type as
- // well allows us to support 5.4.
- if ($expiration instanceof \DateTimeInterface) {
- return \true;
- }
- return \false;
- }
- /**
- * @return \DateTime
- */
- protected function currentTime()
- {
- return new \DateTime('now', new \DateTimeZone('UTC'));
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/CacheTrait.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/CacheTrait.php
deleted file mode 100644
index a8f55f2..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/CacheTrait.php
+++ /dev/null
@@ -1,96 +0,0 @@
-
- */
- private $cacheConfig;
- /**
- * @var ?CacheItemPoolInterface
- */
- private $cache;
- /**
- * Gets the cached value if it is present in the cache when that is
- * available.
- *
- * @param mixed $k
- *
- * @return mixed
- */
- private function getCachedValue($k)
- {
- if (is_null($this->cache)) {
- return null;
- }
- $key = $this->getFullCacheKey($k);
- if (is_null($key)) {
- return null;
- }
- $cacheItem = $this->cache->getItem($key);
- if ($cacheItem->isHit()) {
- return $cacheItem->get();
- }
- }
- /**
- * Saves the value in the cache when that is available.
- *
- * @param mixed $k
- * @param mixed $v
- * @return mixed
- */
- private function setCachedValue($k, $v)
- {
- if (is_null($this->cache)) {
- return null;
- }
- $key = $this->getFullCacheKey($k);
- if (is_null($key)) {
- return null;
- }
- $cacheItem = $this->cache->getItem($key);
- $cacheItem->set($v);
- $cacheItem->expiresAfter($this->cacheConfig['lifetime']);
- return $this->cache->save($cacheItem);
- }
- /**
- * @param null|string $key
- * @return null|string
- */
- private function getFullCacheKey($key)
- {
- if (is_null($key)) {
- return null;
- }
- $key = $this->cacheConfig['prefix'] . $key;
- // ensure we do not have illegal characters
- $key = preg_replace('|[^a-zA-Z0-9_\\.!]|', '', $key);
- // Hash keys if they exceed $maxKeyLength (defaults to 64)
- if ($this->maxKeyLength && strlen($key) > $this->maxKeyLength) {
- $key = substr(hash('sha256', $key), 0, $this->maxKeyLength);
- }
- return $key;
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/CredentialSource/AwsNativeSource.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/CredentialSource/AwsNativeSource.php
deleted file mode 100644
index 17f3a22..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/CredentialSource/AwsNativeSource.php
+++ /dev/null
@@ -1,287 +0,0 @@
-audience = $audience;
- $this->regionalCredVerificationUrl = $regionalCredVerificationUrl;
- $this->regionUrl = $regionUrl;
- $this->securityCredentialsUrl = $securityCredentialsUrl;
- $this->imdsv2SessionTokenUrl = $imdsv2SessionTokenUrl;
- }
- public function fetchSubjectToken(callable $httpHandler = null) : string
- {
- if (is_null($httpHandler)) {
- $httpHandler = HttpHandlerFactory::build(HttpClientCache::getHttpClient());
- }
- $headers = [];
- if ($this->imdsv2SessionTokenUrl) {
- $headers = ['X-aws-ec2-metadata-token' => self::getImdsV2SessionToken($this->imdsv2SessionTokenUrl, $httpHandler)];
- }
- if (!($signingVars = self::getSigningVarsFromEnv())) {
- if (!$this->securityCredentialsUrl) {
- throw new \LogicException('Unable to get credentials from ENV, and no security credentials URL provided');
- }
- $signingVars = self::getSigningVarsFromUrl($httpHandler, $this->securityCredentialsUrl, self::getRoleName($httpHandler, $this->securityCredentialsUrl, $headers), $headers);
- }
- if (!($region = self::getRegionFromEnv())) {
- if (!$this->regionUrl) {
- throw new \LogicException('Unable to get region from ENV, and no region URL provided');
- }
- $region = self::getRegionFromUrl($httpHandler, $this->regionUrl, $headers);
- }
- $url = str_replace('{region}', $region, $this->regionalCredVerificationUrl);
- $host = parse_url($url)['host'] ?? '';
- // From here we use the signing vars to create the signed request to receive a token
- [$accessKeyId, $secretAccessKey, $securityToken] = $signingVars;
- $headers = self::getSignedRequestHeaders($region, $host, $accessKeyId, $secretAccessKey, $securityToken);
- // Inject x-goog-cloud-target-resource into header
- $headers['x-goog-cloud-target-resource'] = $this->audience;
- // Format headers as they're expected in the subject token
- $formattedHeaders = array_map(function ($k, $v) {
- return ['key' => $k, 'value' => $v];
- }, array_keys($headers), $headers);
- $request = ['headers' => $formattedHeaders, 'method' => 'POST', 'url' => $url];
- return urlencode(json_encode($request) ?: '');
- }
- /**
- * @internal
- */
- public static function getImdsV2SessionToken(string $imdsV2Url, callable $httpHandler) : string
- {
- $headers = ['X-aws-ec2-metadata-token-ttl-seconds' => '21600'];
- $request = new Request('PUT', $imdsV2Url, $headers);
- $response = $httpHandler($request);
- return (string) $response->getBody();
- }
- /**
- * @see http://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html
- *
- * @internal
- *
- * @return array
- */
- public static function getSignedRequestHeaders(string $region, string $host, string $accessKeyId, string $secretAccessKey, ?string $securityToken) : array
- {
- $service = 'sts';
- # Create a date for headers and the credential string in ISO-8601 format
- $amzdate = date('Ymd\\THis\\Z');
- $datestamp = date('Ymd');
- # Date w/o time, used in credential scope
- # Create the canonical headers and signed headers. Header names
- # must be trimmed and lowercase, and sorted in code point order from
- # low to high. Note that there is a trailing \n.
- $canonicalHeaders = sprintf("host:%s\nx-amz-date:%s\n", $host, $amzdate);
- if ($securityToken) {
- $canonicalHeaders .= sprintf("x-amz-security-token:%s\n", $securityToken);
- }
- # Step 5: Create the list of signed headers. This lists the headers
- # in the canonicalHeaders list, delimited with ";" and in alpha order.
- # Note: The request can include any headers; $canonicalHeaders and
- # $signedHeaders lists those that you want to be included in the
- # hash of the request. "Host" and "x-amz-date" are always required.
- $signedHeaders = 'host;x-amz-date';
- if ($securityToken) {
- $signedHeaders .= ';x-amz-security-token';
- }
- # Step 6: Create payload hash (hash of the request body content). For GET
- # requests, the payload is an empty string ("").
- $payloadHash = hash('sha256', '');
- # Step 7: Combine elements to create canonical request
- $canonicalRequest = implode("\n", [
- 'POST',
- // method
- '/',
- // canonical URL
- self::CRED_VERIFICATION_QUERY,
- // query string
- $canonicalHeaders,
- $signedHeaders,
- $payloadHash,
- ]);
- # ************* TASK 2: CREATE THE STRING TO SIGN*************
- # Match the algorithm to the hashing algorithm you use, either SHA-1 or
- # SHA-256 (recommended)
- $algorithm = 'AWS4-HMAC-SHA256';
- $scope = implode('/', [$datestamp, $region, $service, 'aws4_request']);
- $stringToSign = implode("\n", [$algorithm, $amzdate, $scope, hash('sha256', $canonicalRequest)]);
- # ************* TASK 3: CALCULATE THE SIGNATURE *************
- # Create the signing key using the function defined above.
- // (done above)
- $signingKey = self::getSignatureKey($secretAccessKey, $datestamp, $region, $service);
- # Sign the string_to_sign using the signing_key
- $signature = bin2hex(self::hmacSign($signingKey, $stringToSign));
- # ************* TASK 4: ADD SIGNING INFORMATION TO THE REQUEST *************
- # The signing information can be either in a query string value or in
- # a header named Authorization. This code shows how to use a header.
- # Create authorization header and add to request headers
- $authorizationHeader = sprintf('%s Credential=%s/%s, SignedHeaders=%s, Signature=%s', $algorithm, $accessKeyId, $scope, $signedHeaders, $signature);
- # The request can include any headers, but MUST include "host", "x-amz-date",
- # and (for this scenario) "Authorization". "host" and "x-amz-date" must
- # be included in the canonical_headers and signed_headers, as noted
- # earlier. Order here is not significant.
- $headers = ['host' => $host, 'x-amz-date' => $amzdate, 'Authorization' => $authorizationHeader];
- if ($securityToken) {
- $headers['x-amz-security-token'] = $securityToken;
- }
- return $headers;
- }
- /**
- * @internal
- */
- public static function getRegionFromEnv() : ?string
- {
- $region = getenv('AWS_REGION');
- if (empty($region)) {
- $region = getenv('AWS_DEFAULT_REGION');
- }
- return $region ?: null;
- }
- /**
- * @internal
- *
- * @param callable $httpHandler
- * @param string $regionUrl
- * @param array $headers Request headers to send in with the request.
- */
- public static function getRegionFromUrl(callable $httpHandler, string $regionUrl, array $headers) : string
- {
- // get the region/zone from the region URL
- $regionRequest = new Request('GET', $regionUrl, $headers);
- $regionResponse = $httpHandler($regionRequest);
- // Remove last character. For example, if us-east-2b is returned,
- // the region would be us-east-2.
- return substr((string) $regionResponse->getBody(), 0, -1);
- }
- /**
- * @internal
- *
- * @param callable $httpHandler
- * @param string $securityCredentialsUrl
- * @param array $headers Request headers to send in with the request.
- */
- public static function getRoleName(callable $httpHandler, string $securityCredentialsUrl, array $headers) : string
- {
- // Get the AWS role name
- $roleRequest = new Request('GET', $securityCredentialsUrl, $headers);
- $roleResponse = $httpHandler($roleRequest);
- $roleName = (string) $roleResponse->getBody();
- return $roleName;
- }
- /**
- * @internal
- *
- * @param callable $httpHandler
- * @param string $securityCredentialsUrl
- * @param array $headers Request headers to send in with the request.
- * @return array{string, string, ?string}
- */
- public static function getSigningVarsFromUrl(callable $httpHandler, string $securityCredentialsUrl, string $roleName, array $headers) : array
- {
- // Get the AWS credentials
- $credsRequest = new Request('GET', $securityCredentialsUrl . '/' . $roleName, $headers);
- $credsResponse = $httpHandler($credsRequest);
- $awsCreds = json_decode((string) $credsResponse->getBody(), \true);
- return [
- $awsCreds['AccessKeyId'],
- // accessKeyId
- $awsCreds['SecretAccessKey'],
- // secretAccessKey
- $awsCreds['Token'],
- ];
- }
- /**
- * @internal
- *
- * @return array{string, string, ?string}
- */
- public static function getSigningVarsFromEnv() : ?array
- {
- $accessKeyId = getenv('AWS_ACCESS_KEY_ID');
- $secretAccessKey = getenv('AWS_SECRET_ACCESS_KEY');
- if ($accessKeyId && $secretAccessKey) {
- return [$accessKeyId, $secretAccessKey, getenv('AWS_SESSION_TOKEN') ?: null];
- }
- return null;
- }
- /**
- * Return HMAC hash in binary string
- */
- private static function hmacSign(string $key, string $msg) : string
- {
- return hash_hmac('sha256', self::utf8Encode($msg), $key, \true);
- }
- /**
- * @TODO add a fallback when mbstring is not available
- */
- private static function utf8Encode(string $string) : string
- {
- return mb_convert_encoding($string, 'UTF-8', 'ISO-8859-1');
- }
- private static function getSignatureKey(string $key, string $dateStamp, string $regionName, string $serviceName) : string
- {
- $kDate = self::hmacSign(self::utf8Encode('AWS4' . $key), $dateStamp);
- $kRegion = self::hmacSign($kDate, $regionName);
- $kService = self::hmacSign($kRegion, $serviceName);
- $kSigning = self::hmacSign($kService, 'aws4_request');
- return $kSigning;
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/CredentialSource/FileSource.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/CredentialSource/FileSource.php
deleted file mode 100644
index 1020376..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/CredentialSource/FileSource.php
+++ /dev/null
@@ -1,69 +0,0 @@
-file = $file;
- if ($format === 'json' && is_null($subjectTokenFieldName)) {
- throw new InvalidArgumentException('subject_token_field_name must be set when format is JSON');
- }
- $this->format = $format;
- $this->subjectTokenFieldName = $subjectTokenFieldName;
- }
- public function fetchSubjectToken(callable $httpHandler = null) : string
- {
- $contents = file_get_contents($this->file);
- if ($this->format === 'json') {
- if (!($json = json_decode((string) $contents, \true))) {
- throw new UnexpectedValueException('Unable to decode JSON file');
- }
- if (!isset($json[$this->subjectTokenFieldName])) {
- throw new UnexpectedValueException('subject_token_field_name not found in JSON file');
- }
- $contents = $json[$this->subjectTokenFieldName];
- }
- return $contents;
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/CredentialSource/UrlSource.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/CredentialSource/UrlSource.php
deleted file mode 100644
index 09d216d..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/CredentialSource/UrlSource.php
+++ /dev/null
@@ -1,83 +0,0 @@
-
- */
- private $headers;
- /**
- * @param string $url The URL to fetch the subject token from.
- * @param string $format The format of the token in the response. Can be null or "json".
- * @param string $subjectTokenFieldName The name of the field containing the token in the response. This is required
- * when format is "json".
- * @param array $headers Request headers to send in with the request to the URL.
- */
- public function __construct(string $url, string $format = null, string $subjectTokenFieldName = null, array $headers = null)
- {
- $this->url = $url;
- if ($format === 'json' && is_null($subjectTokenFieldName)) {
- throw new InvalidArgumentException('subject_token_field_name must be set when format is JSON');
- }
- $this->format = $format;
- $this->subjectTokenFieldName = $subjectTokenFieldName;
- $this->headers = $headers;
- }
- public function fetchSubjectToken(callable $httpHandler = null) : string
- {
- if (is_null($httpHandler)) {
- $httpHandler = HttpHandlerFactory::build(HttpClientCache::getHttpClient());
- }
- $request = new Request('GET', $this->url, $this->headers ?: []);
- $response = $httpHandler($request);
- $body = (string) $response->getBody();
- if ($this->format === 'json') {
- if (!($json = json_decode((string) $body, \true))) {
- throw new UnexpectedValueException('Unable to decode JSON response');
- }
- if (!isset($json[$this->subjectTokenFieldName])) {
- throw new UnexpectedValueException('subject_token_field_name not found in JSON file');
- }
- $body = $json[$this->subjectTokenFieldName];
- }
- return $body;
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/Credentials/AppIdentityCredentials.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/Credentials/AppIdentityCredentials.php
deleted file mode 100644
index 977395d..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/Credentials/AppIdentityCredentials.php
+++ /dev/null
@@ -1,209 +0,0 @@
-push($middleware);
- *
- * $client = new Client([
- * 'handler' => $stack,
- * 'base_uri' => 'https://www.googleapis.com/books/v1',
- * 'auth' => 'google_auth'
- * ]);
- *
- * $res = $client->get('volumes?q=Henry+David+Thoreau&country=US');
- * ```
- */
-class AppIdentityCredentials extends CredentialsLoader implements SignBlobInterface, ProjectIdProviderInterface
-{
- /**
- * Result of fetchAuthToken.
- *
- * @var array
- */
- protected $lastReceivedToken;
- /**
- * Array of OAuth2 scopes to be requested.
- *
- * @var string[]
- */
- private $scope;
- /**
- * @var string
- */
- private $clientName;
- /**
- * @param string|string[] $scope One or more scopes.
- */
- public function __construct($scope = [])
- {
- $this->scope = is_array($scope) ? $scope : explode(' ', (string) $scope);
- }
- /**
- * Determines if this an App Engine instance, by accessing the
- * SERVER_SOFTWARE environment variable (prod) or the APPENGINE_RUNTIME
- * environment variable (dev).
- *
- * @return bool true if this an App Engine Instance, false otherwise
- */
- public static function onAppEngine()
- {
- $appEngineProduction = isset($_SERVER['SERVER_SOFTWARE']) && 0 === strpos($_SERVER['SERVER_SOFTWARE'], 'Google App Engine');
- if ($appEngineProduction) {
- return \true;
- }
- $appEngineDevAppServer = isset($_SERVER['APPENGINE_RUNTIME']) && $_SERVER['APPENGINE_RUNTIME'] == 'php';
- if ($appEngineDevAppServer) {
- return \true;
- }
- return \false;
- }
- /**
- * Implements FetchAuthTokenInterface#fetchAuthToken.
- *
- * Fetches the auth tokens using the AppIdentityService if available.
- * As the AppIdentityService uses protobufs to fetch the access token,
- * the GuzzleHttp\ClientInterface instance passed in will not be used.
- *
- * @param callable $httpHandler callback which delivers psr7 request
- * @return array {
- * A set of auth related metadata, containing the following
- *
- * @type string $access_token
- * @type string $expiration_time
- * }
- */
- public function fetchAuthToken(callable $httpHandler = null)
- {
- try {
- $this->checkAppEngineContext();
- } catch (\Exception $e) {
- return [];
- }
- /** @phpstan-ignore-next-line */
- $token = AppIdentityService::getAccessToken($this->scope);
- $this->lastReceivedToken = $token;
- return $token;
- }
- /**
- * Sign a string using AppIdentityService.
- *
- * @param string $stringToSign The string to sign.
- * @param bool $forceOpenSsl [optional] Does not apply to this credentials
- * type.
- * @return string The signature, base64-encoded.
- * @throws \Exception If AppEngine SDK or mock is not available.
- */
- public function signBlob($stringToSign, $forceOpenSsl = \false)
- {
- $this->checkAppEngineContext();
- /** @phpstan-ignore-next-line */
- return base64_encode(AppIdentityService::signForApp($stringToSign)['signature']);
- }
- /**
- * Get the project ID from AppIdentityService.
- *
- * Returns null if AppIdentityService is unavailable.
- *
- * @param callable $httpHandler Not used by this type.
- * @return string|null
- */
- public function getProjectId(callable $httpHandler = null)
- {
- try {
- $this->checkAppEngineContext();
- } catch (\Exception $e) {
- return null;
- }
- /** @phpstan-ignore-next-line */
- return AppIdentityService::getApplicationId();
- }
- /**
- * Get the client name from AppIdentityService.
- *
- * Subsequent calls to this method will return a cached value.
- *
- * @param callable $httpHandler Not used in this implementation.
- * @return string
- * @throws \Exception If AppEngine SDK or mock is not available.
- */
- public function getClientName(callable $httpHandler = null)
- {
- $this->checkAppEngineContext();
- if (!$this->clientName) {
- /** @phpstan-ignore-next-line */
- $this->clientName = AppIdentityService::getServiceAccountName();
- }
- return $this->clientName;
- }
- /**
- * @return array{access_token:string,expires_at:int}|null
- */
- public function getLastReceivedToken()
- {
- if ($this->lastReceivedToken) {
- return ['access_token' => $this->lastReceivedToken['access_token'], 'expires_at' => $this->lastReceivedToken['expiration_time']];
- }
- return null;
- }
- /**
- * Caching is handled by the underlying AppIdentityService, return empty string
- * to prevent caching.
- *
- * @return string
- */
- public function getCacheKey()
- {
- return '';
- }
- /**
- * @return void
- */
- private function checkAppEngineContext()
- {
- if (!self::onAppEngine() || !class_exists('Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\google\\appengine\\api\\app_identity\\AppIdentityService')) {
- throw new \Exception('This class must be run in App Engine, or you must include the AppIdentityService ' . 'mock class defined in tests/mocks/AppIdentityService.php');
- }
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/Credentials/ExternalAccountCredentials.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/Credentials/ExternalAccountCredentials.php
deleted file mode 100644
index 565a1d7..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/Credentials/ExternalAccountCredentials.php
+++ /dev/null
@@ -1,177 +0,0 @@
- $jsonKey JSON credentials as an associative array.
- */
- public function __construct($scope, array $jsonKey)
- {
- if (!array_key_exists('type', $jsonKey)) {
- throw new InvalidArgumentException('json key is missing the type field');
- }
- if ($jsonKey['type'] !== self::EXTERNAL_ACCOUNT_TYPE) {
- throw new InvalidArgumentException(sprintf('expected "%s" type but received "%s"', self::EXTERNAL_ACCOUNT_TYPE, $jsonKey['type']));
- }
- if (!array_key_exists('token_url', $jsonKey)) {
- throw new InvalidArgumentException('json key is missing the token_url field');
- }
- if (!array_key_exists('audience', $jsonKey)) {
- throw new InvalidArgumentException('json key is missing the audience field');
- }
- if (!array_key_exists('subject_token_type', $jsonKey)) {
- throw new InvalidArgumentException('json key is missing the subject_token_type field');
- }
- if (!array_key_exists('credential_source', $jsonKey)) {
- throw new InvalidArgumentException('json key is missing the credential_source field');
- }
- if (array_key_exists('service_account_impersonation_url', $jsonKey)) {
- $this->serviceAccountImpersonationUrl = $jsonKey['service_account_impersonation_url'];
- }
- $this->quotaProject = $jsonKey['quota_project_id'] ?? null;
- $this->auth = new OAuth2(['tokenCredentialUri' => $jsonKey['token_url'], 'audience' => $jsonKey['audience'], 'scope' => $scope, 'subjectTokenType' => $jsonKey['subject_token_type'], 'subjectTokenFetcher' => self::buildCredentialSource($jsonKey)]);
- }
- /**
- * @param array $jsonKey
- */
- private static function buildCredentialSource(array $jsonKey) : ExternalAccountCredentialSourceInterface
- {
- $credentialSource = $jsonKey['credential_source'];
- if (isset($credentialSource['file'])) {
- return new FileSource($credentialSource['file'], $credentialSource['format']['type'] ?? null, $credentialSource['format']['subject_token_field_name'] ?? null);
- }
- if (isset($credentialSource['environment_id']) && 1 === preg_match('/^aws(\\d+)$/', $credentialSource['environment_id'], $matches)) {
- if ($matches[1] !== '1') {
- throw new InvalidArgumentException("aws version \"{$matches[1]}\" is not supported in the current build.");
- }
- if (!array_key_exists('regional_cred_verification_url', $credentialSource)) {
- throw new InvalidArgumentException('The regional_cred_verification_url field is required for aws1 credential source.');
- }
- if (!array_key_exists('audience', $jsonKey)) {
- throw new InvalidArgumentException('aws1 credential source requires an audience to be set in the JSON file.');
- }
- return new AwsNativeSource(
- $jsonKey['audience'],
- $credentialSource['regional_cred_verification_url'],
- // $regionalCredVerificationUrl
- $credentialSource['region_url'] ?? null,
- // $regionUrl
- $credentialSource['url'] ?? null,
- // $securityCredentialsUrl
- $credentialSource['imdsv2_session_token_url'] ?? null
- );
- }
- if (isset($credentialSource['url'])) {
- return new UrlSource($credentialSource['url'], $credentialSource['format']['type'] ?? null, $credentialSource['format']['subject_token_field_name'] ?? null, $credentialSource['headers'] ?? null);
- }
- throw new InvalidArgumentException('Unable to determine credential source from json key.');
- }
- /**
- * @param string $stsToken
- * @param callable $httpHandler
- *
- * @return array {
- * A set of auth related metadata, containing the following
- *
- * @type string $access_token
- * @type int $expires_at
- * }
- */
- private function getImpersonatedAccessToken(string $stsToken, callable $httpHandler = null) : array
- {
- if (!isset($this->serviceAccountImpersonationUrl)) {
- throw new InvalidArgumentException('service_account_impersonation_url must be set in JSON credentials.');
- }
- $request = new Request('POST', $this->serviceAccountImpersonationUrl, ['Content-Type' => 'application/json', 'Authorization' => 'Bearer ' . $stsToken], (string) json_encode(['lifetime' => sprintf('%ss', OAuth2::DEFAULT_EXPIRY_SECONDS), 'scope' => $this->auth->getScope()]));
- if (is_null($httpHandler)) {
- $httpHandler = HttpHandlerFactory::build(HttpClientCache::getHttpClient());
- }
- $response = $httpHandler($request);
- $body = json_decode((string) $response->getBody(), \true);
- return ['access_token' => $body['accessToken'], 'expires_at' => strtotime($body['expireTime'])];
- }
- /**
- * @param callable $httpHandler
- *
- * @return array {
- * A set of auth related metadata, containing the following
- *
- * @type string $access_token
- * @type int $expires_at (impersonated service accounts only)
- * @type int $expires_in (identity pool only)
- * @type string $issued_token_type (identity pool only)
- * @type string $token_type (identity pool only)
- * }
- */
- public function fetchAuthToken(callable $httpHandler = null)
- {
- $stsToken = $this->auth->fetchAuthToken($httpHandler);
- if (isset($this->serviceAccountImpersonationUrl)) {
- return $this->getImpersonatedAccessToken($stsToken['access_token'], $httpHandler);
- }
- return $stsToken;
- }
- public function getCacheKey()
- {
- return $this->auth->getCacheKey();
- }
- public function getLastReceivedToken()
- {
- return $this->auth->getLastReceivedToken();
- }
- /**
- * Get the quota project used for this API request
- *
- * @return string|null
- */
- public function getQuotaProject()
- {
- return $this->quotaProject;
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/Credentials/GCECredentials.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/Credentials/GCECredentials.php
deleted file mode 100644
index cd344fd..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/Credentials/GCECredentials.php
+++ /dev/null
@@ -1,493 +0,0 @@
-push($middleware);
- *
- * $client = new Client([
- * 'handler' => $stack,
- * 'base_uri' => 'https://www.googleapis.com/taskqueue/v1beta2/projects/',
- * 'auth' => 'google_auth'
- * ]);
- *
- * $res = $client->get('myproject/taskqueues/myqueue');
- */
-class GCECredentials extends CredentialsLoader implements SignBlobInterface, ProjectIdProviderInterface, GetQuotaProjectInterface
-{
- use IamSignerTrait;
- // phpcs:disable
- const cacheKey = 'GOOGLE_AUTH_PHP_GCE';
- // phpcs:enable
- /**
- * The metadata IP address on appengine instances.
- *
- * The IP is used instead of the domain 'metadata' to avoid slow responses
- * when not on Compute Engine.
- */
- const METADATA_IP = '169.254.169.254';
- /**
- * The metadata path of the default token.
- */
- const TOKEN_URI_PATH = 'v1/instance/service-accounts/default/token';
- /**
- * The metadata path of the default id token.
- */
- const ID_TOKEN_URI_PATH = 'v1/instance/service-accounts/default/identity';
- /**
- * The metadata path of the client ID.
- */
- const CLIENT_ID_URI_PATH = 'v1/instance/service-accounts/default/email';
- /**
- * The metadata path of the project ID.
- */
- const PROJECT_ID_URI_PATH = 'v1/project/project-id';
- /**
- * The metadata path of the project ID.
- */
- const UNIVERSE_DOMAIN_URI_PATH = 'v1/universe/universe_domain';
- /**
- * The header whose presence indicates GCE presence.
- */
- const FLAVOR_HEADER = 'Metadata-Flavor';
- /**
- * The Linux file which contains the product name.
- */
- private const GKE_PRODUCT_NAME_FILE = '/sys/class/dmi/id/product_name';
- /**
- * Note: the explicit `timeout` and `tries` below is a workaround. The underlying
- * issue is that resolving an unknown host on some networks will take
- * 20-30 seconds; making this timeout short fixes the issue, but
- * could lead to false negatives in the event that we are on GCE, but
- * the metadata resolution was particularly slow. The latter case is
- * "unlikely" since the expected 4-nines time is about 0.5 seconds.
- * This allows us to limit the total ping maximum timeout to 1.5 seconds
- * for developer desktop scenarios.
- */
- const MAX_COMPUTE_PING_TRIES = 3;
- const COMPUTE_PING_CONNECTION_TIMEOUT_S = 0.5;
- /**
- * Flag used to ensure that the onGCE test is only done once;.
- *
- * @var bool
- */
- private $hasCheckedOnGce = \false;
- /**
- * Flag that stores the value of the onGCE check.
- *
- * @var bool
- */
- private $isOnGce = \false;
- /**
- * Result of fetchAuthToken.
- *
- * @var array
- */
- protected $lastReceivedToken;
- /**
- * @var string|null
- */
- private $clientName;
- /**
- * @var string|null
- */
- private $projectId;
- /**
- * @var string
- */
- private $tokenUri;
- /**
- * @var string
- */
- private $targetAudience;
- /**
- * @var string|null
- */
- private $quotaProject;
- /**
- * @var string|null
- */
- private $serviceAccountIdentity;
- /**
- * @var string
- */
- private $universeDomain;
- /**
- * @param Iam $iam [optional] An IAM instance.
- * @param string|string[] $scope [optional] the scope of the access request,
- * expressed either as an array or as a space-delimited string.
- * @param string $targetAudience [optional] The audience for the ID token.
- * @param string $quotaProject [optional] Specifies a project to bill for access
- * charges associated with the request.
- * @param string $serviceAccountIdentity [optional] Specify a service
- * account identity name to use instead of "default".
- * @param string $universeDomain [optional] Specify a universe domain to use
- * instead of fetching one from the metadata server.
- */
- public function __construct(Iam $iam = null, $scope = null, $targetAudience = null, $quotaProject = null, $serviceAccountIdentity = null, string $universeDomain = null)
- {
- $this->iam = $iam;
- if ($scope && $targetAudience) {
- throw new InvalidArgumentException('Scope and targetAudience cannot both be supplied');
- }
- $tokenUri = self::getTokenUri($serviceAccountIdentity);
- if ($scope) {
- if (is_string($scope)) {
- $scope = explode(' ', $scope);
- }
- $scope = implode(',', $scope);
- $tokenUri = $tokenUri . '?scopes=' . $scope;
- } elseif ($targetAudience) {
- $tokenUri = self::getIdTokenUri($serviceAccountIdentity);
- $tokenUri = $tokenUri . '?audience=' . $targetAudience;
- $this->targetAudience = $targetAudience;
- }
- $this->tokenUri = $tokenUri;
- $this->quotaProject = $quotaProject;
- $this->serviceAccountIdentity = $serviceAccountIdentity;
- $this->universeDomain = $universeDomain;
- }
- /**
- * The full uri for accessing the default token.
- *
- * @param string $serviceAccountIdentity [optional] Specify a service
- * account identity name to use instead of "default".
- * @return string
- */
- public static function getTokenUri($serviceAccountIdentity = null)
- {
- $base = 'http://' . self::METADATA_IP . '/computeMetadata/';
- $base .= self::TOKEN_URI_PATH;
- if ($serviceAccountIdentity) {
- return str_replace('/default/', '/' . $serviceAccountIdentity . '/', $base);
- }
- return $base;
- }
- /**
- * The full uri for accessing the default service account.
- *
- * @param string $serviceAccountIdentity [optional] Specify a service
- * account identity name to use instead of "default".
- * @return string
- */
- public static function getClientNameUri($serviceAccountIdentity = null)
- {
- $base = 'http://' . self::METADATA_IP . '/computeMetadata/';
- $base .= self::CLIENT_ID_URI_PATH;
- if ($serviceAccountIdentity) {
- return str_replace('/default/', '/' . $serviceAccountIdentity . '/', $base);
- }
- return $base;
- }
- /**
- * The full uri for accesesing the default identity token.
- *
- * @param string $serviceAccountIdentity [optional] Specify a service
- * account identity name to use instead of "default".
- * @return string
- */
- private static function getIdTokenUri($serviceAccountIdentity = null)
- {
- $base = 'http://' . self::METADATA_IP . '/computeMetadata/';
- $base .= self::ID_TOKEN_URI_PATH;
- if ($serviceAccountIdentity) {
- return str_replace('/default/', '/' . $serviceAccountIdentity . '/', $base);
- }
- return $base;
- }
- /**
- * The full uri for accessing the default project ID.
- *
- * @return string
- */
- private static function getProjectIdUri()
- {
- $base = 'http://' . self::METADATA_IP . '/computeMetadata/';
- return $base . self::PROJECT_ID_URI_PATH;
- }
- /**
- * The full uri for accessing the default universe domain.
- *
- * @return string
- */
- private static function getUniverseDomainUri()
- {
- $base = 'http://' . self::METADATA_IP . '/computeMetadata/';
- return $base . self::UNIVERSE_DOMAIN_URI_PATH;
- }
- /**
- * Determines if this an App Engine Flexible instance, by accessing the
- * GAE_INSTANCE environment variable.
- *
- * @return bool true if this an App Engine Flexible Instance, false otherwise
- */
- public static function onAppEngineFlexible()
- {
- return substr((string) getenv('GAE_INSTANCE'), 0, 4) === 'aef-';
- }
- /**
- * Determines if this a GCE instance, by accessing the expected metadata
- * host.
- * If $httpHandler is not specified a the default HttpHandler is used.
- *
- * @param callable $httpHandler callback which delivers psr7 request
- * @return bool True if this a GCEInstance, false otherwise
- */
- public static function onGce(callable $httpHandler = null)
- {
- $httpHandler = $httpHandler ?: HttpHandlerFactory::build(HttpClientCache::getHttpClient());
- $checkUri = 'http://' . self::METADATA_IP;
- for ($i = 1; $i <= self::MAX_COMPUTE_PING_TRIES; $i++) {
- try {
- // Comment from: oauth2client/client.py
- //
- // Note: the explicit `timeout` below is a workaround. The underlying
- // issue is that resolving an unknown host on some networks will take
- // 20-30 seconds; making this timeout short fixes the issue, but
- // could lead to false negatives in the event that we are on GCE, but
- // the metadata resolution was particularly slow. The latter case is
- // "unlikely".
- $resp = $httpHandler(new Request('GET', $checkUri, [self::FLAVOR_HEADER => 'Google']), ['timeout' => self::COMPUTE_PING_CONNECTION_TIMEOUT_S]);
- return $resp->getHeaderLine(self::FLAVOR_HEADER) == 'Google';
- } catch (ClientException $e) {
- } catch (ServerException $e) {
- } catch (RequestException $e) {
- } catch (ConnectException $e) {
- }
- }
- if (\PHP_OS === 'Windows') {
- // @TODO: implement GCE residency detection on Windows
- return \false;
- }
- // Detect GCE residency on Linux
- return self::detectResidencyLinux(self::GKE_PRODUCT_NAME_FILE);
- }
- private static function detectResidencyLinux(string $productNameFile) : bool
- {
- if (file_exists($productNameFile)) {
- $productName = trim((string) file_get_contents($productNameFile));
- return 0 === strpos($productName, 'Google');
- }
- return \false;
- }
- /**
- * Implements FetchAuthTokenInterface#fetchAuthToken.
- *
- * Fetches the auth tokens from the GCE metadata host if it is available.
- * If $httpHandler is not specified a the default HttpHandler is used.
- *
- * @param callable $httpHandler callback which delivers psr7 request
- *
- * @return array {
- * A set of auth related metadata, based on the token type.
- *
- * @type string $access_token for access tokens
- * @type int $expires_in for access tokens
- * @type string $token_type for access tokens
- * @type string $id_token for ID tokens
- * }
- * @throws \Exception
- */
- public function fetchAuthToken(callable $httpHandler = null)
- {
- $httpHandler = $httpHandler ?: HttpHandlerFactory::build(HttpClientCache::getHttpClient());
- if (!$this->hasCheckedOnGce) {
- $this->isOnGce = self::onGce($httpHandler);
- $this->hasCheckedOnGce = \true;
- }
- if (!$this->isOnGce) {
- return [];
- // return an empty array with no access token
- }
- $response = $this->getFromMetadata($httpHandler, $this->tokenUri);
- if ($this->targetAudience) {
- return $this->lastReceivedToken = ['id_token' => $response];
- }
- if (null === ($json = json_decode($response, \true))) {
- throw new \Exception('Invalid JSON response');
- }
- $json['expires_at'] = time() + $json['expires_in'];
- // store this so we can retrieve it later
- $this->lastReceivedToken = $json;
- return $json;
- }
- /**
- * @return string
- */
- public function getCacheKey()
- {
- return self::cacheKey;
- }
- /**
- * @return array|null
- */
- public function getLastReceivedToken()
- {
- if ($this->lastReceivedToken) {
- if (array_key_exists('id_token', $this->lastReceivedToken)) {
- return $this->lastReceivedToken;
- }
- return ['access_token' => $this->lastReceivedToken['access_token'], 'expires_at' => $this->lastReceivedToken['expires_at']];
- }
- return null;
- }
- /**
- * Get the client name from GCE metadata.
- *
- * Subsequent calls will return a cached value.
- *
- * @param callable $httpHandler callback which delivers psr7 request
- * @return string
- */
- public function getClientName(callable $httpHandler = null)
- {
- if ($this->clientName) {
- return $this->clientName;
- }
- $httpHandler = $httpHandler ?: HttpHandlerFactory::build(HttpClientCache::getHttpClient());
- if (!$this->hasCheckedOnGce) {
- $this->isOnGce = self::onGce($httpHandler);
- $this->hasCheckedOnGce = \true;
- }
- if (!$this->isOnGce) {
- return '';
- }
- $this->clientName = $this->getFromMetadata($httpHandler, self::getClientNameUri($this->serviceAccountIdentity));
- return $this->clientName;
- }
- /**
- * Fetch the default Project ID from compute engine.
- *
- * Returns null if called outside GCE.
- *
- * @param callable $httpHandler Callback which delivers psr7 request
- * @return string|null
- */
- public function getProjectId(callable $httpHandler = null)
- {
- if ($this->projectId) {
- return $this->projectId;
- }
- $httpHandler = $httpHandler ?: HttpHandlerFactory::build(HttpClientCache::getHttpClient());
- if (!$this->hasCheckedOnGce) {
- $this->isOnGce = self::onGce($httpHandler);
- $this->hasCheckedOnGce = \true;
- }
- if (!$this->isOnGce) {
- return null;
- }
- $this->projectId = $this->getFromMetadata($httpHandler, self::getProjectIdUri());
- return $this->projectId;
- }
- /**
- * Fetch the default universe domain from the metadata server.
- *
- * @param callable $httpHandler Callback which delivers psr7 request
- * @return string
- */
- public function getUniverseDomain(callable $httpHandler = null) : string
- {
- if (null !== $this->universeDomain) {
- return $this->universeDomain;
- }
- $httpHandler = $httpHandler ?: HttpHandlerFactory::build(HttpClientCache::getHttpClient());
- if (!$this->hasCheckedOnGce) {
- $this->isOnGce = self::onGce($httpHandler);
- $this->hasCheckedOnGce = \true;
- }
- try {
- $this->universeDomain = $this->getFromMetadata($httpHandler, self::getUniverseDomainUri());
- } catch (ClientException $e) {
- // If the metadata server exists, but returns a 404 for the universe domain, the auth
- // libraries should safely assume this is an older metadata server running in GCU, and
- // should return the default universe domain.
- if (!$e->hasResponse() || 404 != $e->getResponse()->getStatusCode()) {
- throw $e;
- }
- $this->universeDomain = self::DEFAULT_UNIVERSE_DOMAIN;
- }
- // We expect in some cases the metadata server will return an empty string for the universe
- // domain. In this case, the auth library MUST return the default universe domain.
- if ('' === $this->universeDomain) {
- $this->universeDomain = self::DEFAULT_UNIVERSE_DOMAIN;
- }
- return $this->universeDomain;
- }
- /**
- * Fetch the value of a GCE metadata server URI.
- *
- * @param callable $httpHandler An HTTP Handler to deliver PSR7 requests.
- * @param string $uri The metadata URI.
- * @return string
- */
- private function getFromMetadata(callable $httpHandler, $uri)
- {
- $resp = $httpHandler(new Request('GET', $uri, [self::FLAVOR_HEADER => 'Google']));
- return (string) $resp->getBody();
- }
- /**
- * Get the quota project used for this API request
- *
- * @return string|null
- */
- public function getQuotaProject()
- {
- return $this->quotaProject;
- }
- /**
- * Set whether or not we've already checked the GCE environment.
- *
- * @param bool $isOnGce
- *
- * @return void
- */
- public function setIsOnGce($isOnGce)
- {
- // Implicitly set hasCheckedGce to true
- $this->hasCheckedOnGce = \true;
- // Set isOnGce
- $this->isOnGce = $isOnGce;
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/Credentials/IAMCredentials.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/Credentials/IAMCredentials.php
deleted file mode 100644
index 2becc55..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/Credentials/IAMCredentials.php
+++ /dev/null
@@ -1,77 +0,0 @@
-selector = $selector;
- $this->token = $token;
- }
- /**
- * export a callback function which updates runtime metadata.
- *
- * @return callable updateMetadata function
- */
- public function getUpdateMetadataFunc()
- {
- return [$this, 'updateMetadata'];
- }
- /**
- * Updates metadata with the appropriate header metadata.
- *
- * @param array $metadata metadata hashmap
- * @param string $unusedAuthUri optional auth uri
- * @param callable $httpHandler callback which delivers psr7 request
- * Note: this param is unused here, only included here for
- * consistency with other credentials class
- *
- * @return array updated metadata hashmap
- */
- public function updateMetadata($metadata, $unusedAuthUri = null, callable $httpHandler = null)
- {
- $metadata_copy = $metadata;
- $metadata_copy[self::SELECTOR_KEY] = $this->selector;
- $metadata_copy[self::TOKEN_KEY] = $this->token;
- return $metadata_copy;
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/Credentials/ImpersonatedServiceAccountCredentials.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/Credentials/ImpersonatedServiceAccountCredentials.php
deleted file mode 100644
index 8d38694..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/Credentials/ImpersonatedServiceAccountCredentials.php
+++ /dev/null
@@ -1,120 +0,0 @@
- $jsonKey JSON credential file path or JSON credentials
- * as an associative array.
- */
- public function __construct($scope, $jsonKey)
- {
- if (is_string($jsonKey)) {
- if (!file_exists($jsonKey)) {
- throw new \InvalidArgumentException('file does not exist');
- }
- $json = file_get_contents($jsonKey);
- if (!($jsonKey = json_decode((string) $json, \true))) {
- throw new \LogicException('invalid json for auth config');
- }
- }
- if (!array_key_exists('service_account_impersonation_url', $jsonKey)) {
- throw new \LogicException('json key is missing the service_account_impersonation_url field');
- }
- if (!array_key_exists('source_credentials', $jsonKey)) {
- throw new \LogicException('json key is missing the source_credentials field');
- }
- $this->impersonatedServiceAccountName = $this->getImpersonatedServiceAccountNameFromUrl($jsonKey['service_account_impersonation_url']);
- $this->sourceCredentials = new UserRefreshCredentials($scope, $jsonKey['source_credentials']);
- }
- /**
- * Helper function for extracting the Server Account Name from the URL saved in the account
- * credentials file.
- *
- * @param $serviceAccountImpersonationUrl string URL from "service_account_impersonation_url"
- * @return string Service account email or ID.
- */
- private function getImpersonatedServiceAccountNameFromUrl(string $serviceAccountImpersonationUrl) : string
- {
- $fields = explode('/', $serviceAccountImpersonationUrl);
- $lastField = end($fields);
- $splitter = explode(':', $lastField);
- return $splitter[0];
- }
- /**
- * Get the client name from the keyfile
- *
- * In this implementation, it will return the issuers email from the oauth token.
- *
- * @param callable|null $unusedHttpHandler not used by this credentials type.
- * @return string Token issuer email
- */
- public function getClientName(callable $unusedHttpHandler = null)
- {
- return $this->impersonatedServiceAccountName;
- }
- /**
- * @param callable $httpHandler
- *
- * @return array {
- * A set of auth related metadata, containing the following
- *
- * @type string $access_token
- * @type int $expires_in
- * @type string $scope
- * @type string $token_type
- * @type string $id_token
- * }
- */
- public function fetchAuthToken(callable $httpHandler = null)
- {
- return $this->sourceCredentials->fetchAuthToken($httpHandler);
- }
- /**
- * @return string
- */
- public function getCacheKey()
- {
- return $this->sourceCredentials->getCacheKey();
- }
- /**
- * @return array
- */
- public function getLastReceivedToken()
- {
- return $this->sourceCredentials->getLastReceivedToken();
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/Credentials/InsecureCredentials.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/Credentials/InsecureCredentials.php
deleted file mode 100644
index 0048d71..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/Credentials/InsecureCredentials.php
+++ /dev/null
@@ -1,62 +0,0 @@
- ''];
- /**
- * Fetches the auth token. In this case it returns an empty string.
- *
- * @param callable $httpHandler
- * @return array{access_token:string} A set of auth related metadata
- */
- public function fetchAuthToken(callable $httpHandler = null)
- {
- return $this->token;
- }
- /**
- * Returns the cache key. In this case it returns a null value, disabling
- * caching.
- *
- * @return string|null
- */
- public function getCacheKey()
- {
- return null;
- }
- /**
- * Fetches the last received token. In this case, it returns the same empty string
- * auth token.
- *
- * @return array{access_token:string}
- */
- public function getLastReceivedToken()
- {
- return $this->token;
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/Credentials/ServiceAccountCredentials.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/Credentials/ServiceAccountCredentials.php
deleted file mode 100644
index 07deac5..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/Credentials/ServiceAccountCredentials.php
+++ /dev/null
@@ -1,312 +0,0 @@
-push($middleware);
- *
- * $client = new Client([
- * 'handler' => $stack,
- * 'base_uri' => 'https://www.googleapis.com/taskqueue/v1beta2/projects/',
- * 'auth' => 'google_auth' // authorize all requests
- * ]);
- *
- * $res = $client->get('myproject/taskqueues/myqueue');
- */
-class ServiceAccountCredentials extends CredentialsLoader implements GetQuotaProjectInterface, SignBlobInterface, ProjectIdProviderInterface
-{
- use ServiceAccountSignerTrait;
- /**
- * The OAuth2 instance used to conduct authorization.
- *
- * @var OAuth2
- */
- protected $auth;
- /**
- * The quota project associated with the JSON credentials
- *
- * @var string
- */
- protected $quotaProject;
- /**
- * @var string|null
- */
- protected $projectId;
- /**
- * @var array|null
- */
- private $lastReceivedJwtAccessToken;
- /**
- * @var bool
- */
- private $useJwtAccessWithScope = \false;
- /**
- * @var ServiceAccountJwtAccessCredentials|null
- */
- private $jwtAccessCredentials;
- /**
- * @var string
- */
- private $universeDomain;
- /**
- * Create a new ServiceAccountCredentials.
- *
- * @param string|string[]|null $scope the scope of the access request, expressed
- * either as an Array or as a space-delimited String.
- * @param string|array $jsonKey JSON credential file path or JSON credentials
- * as an associative array
- * @param string $sub an email address account to impersonate, in situations when
- * the service account has been delegated domain wide access.
- * @param string $targetAudience The audience for the ID token.
- */
- public function __construct($scope, $jsonKey, $sub = null, $targetAudience = null)
- {
- if (is_string($jsonKey)) {
- if (!file_exists($jsonKey)) {
- throw new \InvalidArgumentException('file does not exist');
- }
- $jsonKeyStream = file_get_contents($jsonKey);
- if (!($jsonKey = json_decode((string) $jsonKeyStream, \true))) {
- throw new \LogicException('invalid json for auth config');
- }
- }
- if (!array_key_exists('client_email', $jsonKey)) {
- throw new \InvalidArgumentException('json key is missing the client_email field');
- }
- if (!array_key_exists('private_key', $jsonKey)) {
- throw new \InvalidArgumentException('json key is missing the private_key field');
- }
- if (array_key_exists('quota_project_id', $jsonKey)) {
- $this->quotaProject = (string) $jsonKey['quota_project_id'];
- }
- if ($scope && $targetAudience) {
- throw new InvalidArgumentException('Scope and targetAudience cannot both be supplied');
- }
- $additionalClaims = [];
- if ($targetAudience) {
- $additionalClaims = ['target_audience' => $targetAudience];
- }
- $this->auth = new OAuth2(['audience' => self::TOKEN_CREDENTIAL_URI, 'issuer' => $jsonKey['client_email'], 'scope' => $scope, 'signingAlgorithm' => 'RS256', 'signingKey' => $jsonKey['private_key'], 'sub' => $sub, 'tokenCredentialUri' => self::TOKEN_CREDENTIAL_URI, 'additionalClaims' => $additionalClaims]);
- $this->projectId = $jsonKey['project_id'] ?? null;
- $this->universeDomain = $jsonKey['universe_domain'] ?? self::DEFAULT_UNIVERSE_DOMAIN;
- }
- /**
- * When called, the ServiceAccountCredentials will use an instance of
- * ServiceAccountJwtAccessCredentials to fetch (self-sign) an access token
- * even when only scopes are supplied. Otherwise,
- * ServiceAccountJwtAccessCredentials is only called when no scopes and an
- * authUrl (audience) is suppled.
- *
- * @return void
- */
- public function useJwtAccessWithScope()
- {
- $this->useJwtAccessWithScope = \true;
- }
- /**
- * @param callable $httpHandler
- *
- * @return array {
- * A set of auth related metadata, containing the following
- *
- * @type string $access_token
- * @type int $expires_in
- * @type string $token_type
- * }
- */
- public function fetchAuthToken(callable $httpHandler = null)
- {
- if ($this->useSelfSignedJwt()) {
- $jwtCreds = $this->createJwtAccessCredentials();
- $accessToken = $jwtCreds->fetchAuthToken($httpHandler);
- if ($lastReceivedToken = $jwtCreds->getLastReceivedToken()) {
- // Keep self-signed JWTs in memory as the last received token
- $this->lastReceivedJwtAccessToken = $lastReceivedToken;
- }
- return $accessToken;
- }
- return $this->auth->fetchAuthToken($httpHandler);
- }
- /**
- * @return string
- */
- public function getCacheKey()
- {
- $key = $this->auth->getIssuer() . ':' . $this->auth->getCacheKey();
- if ($sub = $this->auth->getSub()) {
- $key .= ':' . $sub;
- }
- return $key;
- }
- /**
- * @return array
- */
- public function getLastReceivedToken()
- {
- // If self-signed JWTs are being used, fetch the last received token
- // from memory. Else, fetch it from OAuth2
- return $this->useSelfSignedJwt() ? $this->lastReceivedJwtAccessToken : $this->auth->getLastReceivedToken();
- }
- /**
- * Get the project ID from the service account keyfile.
- *
- * Returns null if the project ID does not exist in the keyfile.
- *
- * @param callable $httpHandler Not used by this credentials type.
- * @return string|null
- */
- public function getProjectId(callable $httpHandler = null)
- {
- return $this->projectId;
- }
- /**
- * Updates metadata with the authorization token.
- *
- * @param array $metadata metadata hashmap
- * @param string $authUri optional auth uri
- * @param callable $httpHandler callback which delivers psr7 request
- * @return array updated metadata hashmap
- */
- public function updateMetadata($metadata, $authUri = null, callable $httpHandler = null)
- {
- // scope exists. use oauth implementation
- if (!$this->useSelfSignedJwt()) {
- return parent::updateMetadata($metadata, $authUri, $httpHandler);
- }
- $jwtCreds = $this->createJwtAccessCredentials();
- if ($this->auth->getScope()) {
- // Prefer user-provided "scope" to "audience"
- $updatedMetadata = $jwtCreds->updateMetadata($metadata, null, $httpHandler);
- } else {
- $updatedMetadata = $jwtCreds->updateMetadata($metadata, $authUri, $httpHandler);
- }
- if ($lastReceivedToken = $jwtCreds->getLastReceivedToken()) {
- // Keep self-signed JWTs in memory as the last received token
- $this->lastReceivedJwtAccessToken = $lastReceivedToken;
- }
- return $updatedMetadata;
- }
- /**
- * @return ServiceAccountJwtAccessCredentials
- */
- private function createJwtAccessCredentials()
- {
- if (!$this->jwtAccessCredentials) {
- // Create credentials for self-signing a JWT (JwtAccess)
- $credJson = ['private_key' => $this->auth->getSigningKey(), 'client_email' => $this->auth->getIssuer()];
- $this->jwtAccessCredentials = new ServiceAccountJwtAccessCredentials($credJson, $this->auth->getScope());
- }
- return $this->jwtAccessCredentials;
- }
- /**
- * @param string $sub an email address account to impersonate, in situations when
- * the service account has been delegated domain wide access.
- * @return void
- */
- public function setSub($sub)
- {
- $this->auth->setSub($sub);
- }
- /**
- * Get the client name from the keyfile.
- *
- * In this case, it returns the keyfile's client_email key.
- *
- * @param callable $httpHandler Not used by this credentials type.
- * @return string
- */
- public function getClientName(callable $httpHandler = null)
- {
- return $this->auth->getIssuer();
- }
- /**
- * Get the quota project used for this API request
- *
- * @return string|null
- */
- public function getQuotaProject()
- {
- return $this->quotaProject;
- }
- /**
- * Get the universe domain configured in the JSON credential.
- *
- * @return string
- */
- public function getUniverseDomain() : string
- {
- return $this->universeDomain;
- }
- /**
- * @return bool
- */
- private function useSelfSignedJwt()
- {
- // When a sub is supplied, the user is using domain-wide delegation, which not available
- // with self-signed JWTs
- if (null !== $this->auth->getSub()) {
- // If we are outside the GDU, we can't use domain-wide delegation
- if ($this->getUniverseDomain() !== self::DEFAULT_UNIVERSE_DOMAIN) {
- throw new \LogicException(sprintf('Service Account subject is configured for the credential. Domain-wide ' . 'delegation is not supported in universes other than %s.', self::DEFAULT_UNIVERSE_DOMAIN));
- }
- return \false;
- }
- // If claims are set, this call is for "id_tokens"
- if ($this->auth->getAdditionalClaims()) {
- return \false;
- }
- // When true, ServiceAccountCredentials will always use JwtAccess for access tokens
- if ($this->useJwtAccessWithScope) {
- return \true;
- }
- // If the universe domain is outside the GDU, use JwtAccess for access tokens
- if ($this->getUniverseDomain() !== self::DEFAULT_UNIVERSE_DOMAIN) {
- return \true;
- }
- return is_null($this->auth->getScope());
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/Credentials/ServiceAccountJwtAccessCredentials.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/Credentials/ServiceAccountJwtAccessCredentials.php
deleted file mode 100644
index 81fa9fd..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/Credentials/ServiceAccountJwtAccessCredentials.php
+++ /dev/null
@@ -1,171 +0,0 @@
- $jsonKey JSON credential file path or JSON credentials
- * as an associative array
- * @param string|string[] $scope the scope of the access request, expressed
- * either as an Array or as a space-delimited String.
- */
- public function __construct($jsonKey, $scope = null)
- {
- if (is_string($jsonKey)) {
- if (!file_exists($jsonKey)) {
- throw new \InvalidArgumentException('file does not exist');
- }
- $jsonKeyStream = file_get_contents($jsonKey);
- if (!($jsonKey = json_decode((string) $jsonKeyStream, \true))) {
- throw new \LogicException('invalid json for auth config');
- }
- }
- if (!array_key_exists('client_email', $jsonKey)) {
- throw new \InvalidArgumentException('json key is missing the client_email field');
- }
- if (!array_key_exists('private_key', $jsonKey)) {
- throw new \InvalidArgumentException('json key is missing the private_key field');
- }
- if (array_key_exists('quota_project_id', $jsonKey)) {
- $this->quotaProject = (string) $jsonKey['quota_project_id'];
- }
- $this->auth = new OAuth2(['issuer' => $jsonKey['client_email'], 'sub' => $jsonKey['client_email'], 'signingAlgorithm' => 'RS256', 'signingKey' => $jsonKey['private_key'], 'scope' => $scope]);
- $this->projectId = $jsonKey['project_id'] ?? null;
- }
- /**
- * Updates metadata with the authorization token.
- *
- * @param array $metadata metadata hashmap
- * @param string $authUri optional auth uri
- * @param callable $httpHandler callback which delivers psr7 request
- * @return array updated metadata hashmap
- */
- public function updateMetadata($metadata, $authUri = null, callable $httpHandler = null)
- {
- $scope = $this->auth->getScope();
- if (empty($authUri) && empty($scope)) {
- return $metadata;
- }
- $this->auth->setAudience($authUri);
- return parent::updateMetadata($metadata, $authUri, $httpHandler);
- }
- /**
- * Implements FetchAuthTokenInterface#fetchAuthToken.
- *
- * @param callable $httpHandler
- *
- * @return null|array{access_token:string} A set of auth related metadata
- */
- public function fetchAuthToken(callable $httpHandler = null)
- {
- $audience = $this->auth->getAudience();
- $scope = $this->auth->getScope();
- if (empty($audience) && empty($scope)) {
- return null;
- }
- if (!empty($audience) && !empty($scope)) {
- throw new \UnexpectedValueException('Cannot sign both audience and scope in JwtAccess');
- }
- $access_token = $this->auth->toJwt();
- // Set the self-signed access token in OAuth2 for getLastReceivedToken
- $this->auth->setAccessToken($access_token);
- return ['access_token' => $access_token];
- }
- /**
- * @return string
- */
- public function getCacheKey()
- {
- return $this->auth->getCacheKey();
- }
- /**
- * @return array
- */
- public function getLastReceivedToken()
- {
- return $this->auth->getLastReceivedToken();
- }
- /**
- * Get the project ID from the service account keyfile.
- *
- * Returns null if the project ID does not exist in the keyfile.
- *
- * @param callable $httpHandler Not used by this credentials type.
- * @return string|null
- */
- public function getProjectId(callable $httpHandler = null)
- {
- return $this->projectId;
- }
- /**
- * Get the client name from the keyfile.
- *
- * In this case, it returns the keyfile's client_email key.
- *
- * @param callable $httpHandler Not used by this credentials type.
- * @return string
- */
- public function getClientName(callable $httpHandler = null)
- {
- return $this->auth->getIssuer();
- }
- /**
- * Get the quota project used for this API request
- *
- * @return string|null
- */
- public function getQuotaProject()
- {
- return $this->quotaProject;
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/Credentials/UserRefreshCredentials.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/Credentials/UserRefreshCredentials.php
deleted file mode 100644
index dd215e4..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/Credentials/UserRefreshCredentials.php
+++ /dev/null
@@ -1,130 +0,0 @@
- $jsonKey JSON credential file path or JSON credentials
- * as an associative array
- */
- public function __construct($scope, $jsonKey)
- {
- if (is_string($jsonKey)) {
- if (!file_exists($jsonKey)) {
- throw new \InvalidArgumentException('file does not exist');
- }
- $json = file_get_contents($jsonKey);
- if (!($jsonKey = json_decode((string) $json, \true))) {
- throw new \LogicException('invalid json for auth config');
- }
- }
- if (!array_key_exists('client_id', $jsonKey)) {
- throw new \InvalidArgumentException('json key is missing the client_id field');
- }
- if (!array_key_exists('client_secret', $jsonKey)) {
- throw new \InvalidArgumentException('json key is missing the client_secret field');
- }
- if (!array_key_exists('refresh_token', $jsonKey)) {
- throw new \InvalidArgumentException('json key is missing the refresh_token field');
- }
- $this->auth = new OAuth2(['clientId' => $jsonKey['client_id'], 'clientSecret' => $jsonKey['client_secret'], 'refresh_token' => $jsonKey['refresh_token'], 'scope' => $scope, 'tokenCredentialUri' => self::TOKEN_CREDENTIAL_URI]);
- if (array_key_exists('quota_project_id', $jsonKey)) {
- $this->quotaProject = (string) $jsonKey['quota_project_id'];
- }
- }
- /**
- * @param callable $httpHandler
- *
- * @return array {
- * A set of auth related metadata, containing the following
- *
- * @type string $access_token
- * @type int $expires_in
- * @type string $scope
- * @type string $token_type
- * @type string $id_token
- * }
- */
- public function fetchAuthToken(callable $httpHandler = null)
- {
- return $this->auth->fetchAuthToken($httpHandler);
- }
- /**
- * @return string
- */
- public function getCacheKey()
- {
- return $this->auth->getClientId() . ':' . $this->auth->getCacheKey();
- }
- /**
- * @return array
- */
- public function getLastReceivedToken()
- {
- return $this->auth->getLastReceivedToken();
- }
- /**
- * Get the quota project used for this API request
- *
- * @return string|null
- */
- public function getQuotaProject()
- {
- return $this->quotaProject;
- }
- /**
- * Get the granted scopes (if they exist) for the last fetched token.
- *
- * @return string|null
- */
- public function getGrantedScope()
- {
- return $this->auth->getGrantedScope();
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/CredentialsLoader.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/CredentialsLoader.php
deleted file mode 100644
index 1b586d6..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/CredentialsLoader.php
+++ /dev/null
@@ -1,242 +0,0 @@
-|null JSON key | null
- */
- public static function fromEnv()
- {
- $path = getenv(self::ENV_VAR);
- if (empty($path)) {
- return null;
- }
- if (!file_exists($path)) {
- $cause = 'file ' . $path . ' does not exist';
- throw new \DomainException(self::unableToReadEnv($cause));
- }
- $jsonKey = file_get_contents($path);
- return json_decode((string) $jsonKey, \true);
- }
- /**
- * Load a JSON key from a well known path.
- *
- * The well known path is OS dependent:
- *
- * * windows: %APPDATA%/gcloud/application_default_credentials.json
- * * others: $HOME/.config/gcloud/application_default_credentials.json
- *
- * If the file does not exist, this returns null.
- *
- * @return array|null JSON key | null
- */
- public static function fromWellKnownFile()
- {
- $rootEnv = self::isOnWindows() ? 'APPDATA' : 'HOME';
- $path = [getenv($rootEnv)];
- if (!self::isOnWindows()) {
- $path[] = self::NON_WINDOWS_WELL_KNOWN_PATH_BASE;
- }
- $path[] = self::WELL_KNOWN_PATH;
- $path = implode(\DIRECTORY_SEPARATOR, $path);
- if (!file_exists($path)) {
- return null;
- }
- $jsonKey = file_get_contents($path);
- return json_decode((string) $jsonKey, \true);
- }
- /**
- * Create a new Credentials instance.
- *
- * @param string|string[] $scope the scope of the access request, expressed
- * either as an Array or as a space-delimited String.
- * @param array $jsonKey the JSON credentials.
- * @param string|string[] $defaultScope The default scope to use if no
- * user-defined scopes exist, expressed either as an Array or as a
- * space-delimited string.
- *
- * @return ServiceAccountCredentials|UserRefreshCredentials|ImpersonatedServiceAccountCredentials|ExternalAccountCredentials
- */
- public static function makeCredentials($scope, array $jsonKey, $defaultScope = null)
- {
- if (!array_key_exists('type', $jsonKey)) {
- throw new \InvalidArgumentException('json key is missing the type field');
- }
- if ($jsonKey['type'] == 'service_account') {
- // Do not pass $defaultScope to ServiceAccountCredentials
- return new ServiceAccountCredentials($scope, $jsonKey);
- }
- if ($jsonKey['type'] == 'authorized_user') {
- $anyScope = $scope ?: $defaultScope;
- return new UserRefreshCredentials($anyScope, $jsonKey);
- }
- if ($jsonKey['type'] == 'impersonated_service_account') {
- $anyScope = $scope ?: $defaultScope;
- return new ImpersonatedServiceAccountCredentials($anyScope, $jsonKey);
- }
- if ($jsonKey['type'] == 'external_account') {
- $anyScope = $scope ?: $defaultScope;
- return new ExternalAccountCredentials($anyScope, $jsonKey);
- }
- throw new \InvalidArgumentException('invalid value in the type field');
- }
- /**
- * Create an authorized HTTP Client from an instance of FetchAuthTokenInterface.
- *
- * @param FetchAuthTokenInterface $fetcher is used to fetch the auth token
- * @param array $httpClientOptions (optional) Array of request options to apply.
- * @param callable $httpHandler (optional) http client to fetch the token.
- * @param callable $tokenCallback (optional) function to be called when a new token is fetched.
- * @return \GuzzleHttp\Client
- */
- public static function makeHttpClient(FetchAuthTokenInterface $fetcher, array $httpClientOptions = [], callable $httpHandler = null, callable $tokenCallback = null)
- {
- $middleware = new Middleware\AuthTokenMiddleware($fetcher, $httpHandler, $tokenCallback);
- $stack = \Matomo\Dependencies\SearchEngineKeywordsPerformance\GuzzleHttp\HandlerStack::create();
- $stack->push($middleware);
- return new \Matomo\Dependencies\SearchEngineKeywordsPerformance\GuzzleHttp\Client(['handler' => $stack, 'auth' => 'google_auth'] + $httpClientOptions);
- }
- /**
- * Create a new instance of InsecureCredentials.
- *
- * @return InsecureCredentials
- */
- public static function makeInsecureCredentials()
- {
- return new InsecureCredentials();
- }
- /**
- * Fetch a quota project from the environment variable
- * GOOGLE_CLOUD_QUOTA_PROJECT. Return null if
- * GOOGLE_CLOUD_QUOTA_PROJECT is not specified.
- *
- * @return string|null
- */
- public static function quotaProjectFromEnv()
- {
- return getenv(self::QUOTA_PROJECT_ENV_VAR) ?: null;
- }
- /**
- * Gets a callable which returns the default device certification.
- *
- * @throws UnexpectedValueException
- * @return callable|null
- */
- public static function getDefaultClientCertSource()
- {
- if (!($clientCertSourceJson = self::loadDefaultClientCertSourceFile())) {
- return null;
- }
- $clientCertSourceCmd = $clientCertSourceJson['cert_provider_command'];
- return function () use($clientCertSourceCmd) {
- $cmd = array_map('escapeshellarg', $clientCertSourceCmd);
- exec(implode(' ', $cmd), $output, $returnVar);
- if (0 === $returnVar) {
- return implode(\PHP_EOL, $output);
- }
- throw new RuntimeException('"cert_provider_command" failed with a nonzero exit code');
- };
- }
- /**
- * Determines whether or not the default device certificate should be loaded.
- *
- * @return bool
- */
- public static function shouldLoadClientCertSource()
- {
- return filter_var(getenv(self::MTLS_CERT_ENV_VAR), \FILTER_VALIDATE_BOOLEAN);
- }
- /**
- * @return array{cert_provider_command:string[]}|null
- */
- private static function loadDefaultClientCertSourceFile()
- {
- $rootEnv = self::isOnWindows() ? 'APPDATA' : 'HOME';
- $path = sprintf('%s/%s', getenv($rootEnv), self::MTLS_WELL_KNOWN_PATH);
- if (!file_exists($path)) {
- return null;
- }
- $jsonKey = file_get_contents($path);
- $clientCertSourceJson = json_decode((string) $jsonKey, \true);
- if (!$clientCertSourceJson) {
- throw new UnexpectedValueException('Invalid client cert source JSON');
- }
- if (!isset($clientCertSourceJson['cert_provider_command'])) {
- throw new UnexpectedValueException('cert source requires "cert_provider_command"');
- }
- if (!is_array($clientCertSourceJson['cert_provider_command'])) {
- throw new UnexpectedValueException('cert source expects "cert_provider_command" to be an array');
- }
- return $clientCertSourceJson;
- }
- /**
- * Get the universe domain from the credential. Defaults to "googleapis.com"
- * for all credential types which do not support universe domain.
- *
- * @return string
- */
- public function getUniverseDomain() : string
- {
- return self::DEFAULT_UNIVERSE_DOMAIN;
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/ExternalAccountCredentialSourceInterface.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/ExternalAccountCredentialSourceInterface.php
deleted file mode 100644
index 463bec1..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/ExternalAccountCredentialSourceInterface.php
+++ /dev/null
@@ -1,23 +0,0 @@
- $cacheConfig Configuration for the cache
- * @param CacheItemPoolInterface $cache
- */
- public function __construct(FetchAuthTokenInterface $fetcher, array $cacheConfig = null, CacheItemPoolInterface $cache)
- {
- $this->fetcher = $fetcher;
- $this->cache = $cache;
- $this->cacheConfig = array_merge(['lifetime' => 1500, 'prefix' => ''], (array) $cacheConfig);
- }
- /**
- * @return FetchAuthTokenInterface
- */
- public function getFetcher()
- {
- return $this->fetcher;
- }
- /**
- * Implements FetchAuthTokenInterface#fetchAuthToken.
- *
- * Checks the cache for a valid auth token and fetches the auth tokens
- * from the supplied fetcher.
- *
- * @param callable $httpHandler callback which delivers psr7 request
- * @return array the response
- * @throws \Exception
- */
- public function fetchAuthToken(callable $httpHandler = null)
- {
- if ($cached = $this->fetchAuthTokenFromCache()) {
- return $cached;
- }
- $auth_token = $this->fetcher->fetchAuthToken($httpHandler);
- $this->saveAuthTokenInCache($auth_token);
- return $auth_token;
- }
- /**
- * @return string
- */
- public function getCacheKey()
- {
- return $this->getFullCacheKey($this->fetcher->getCacheKey());
- }
- /**
- * @return array|null
- */
- public function getLastReceivedToken()
- {
- return $this->fetcher->getLastReceivedToken();
- }
- /**
- * Get the client name from the fetcher.
- *
- * @param callable $httpHandler An HTTP handler to deliver PSR7 requests.
- * @return string
- */
- public function getClientName(callable $httpHandler = null)
- {
- if (!$this->fetcher instanceof SignBlobInterface) {
- throw new \RuntimeException('Credentials fetcher does not implement ' . 'Google\\Auth\\SignBlobInterface');
- }
- return $this->fetcher->getClientName($httpHandler);
- }
- /**
- * Sign a blob using the fetcher.
- *
- * @param string $stringToSign The string to sign.
- * @param bool $forceOpenSsl Require use of OpenSSL for local signing. Does
- * not apply to signing done using external services. **Defaults to**
- * `false`.
- * @return string The resulting signature.
- * @throws \RuntimeException If the fetcher does not implement
- * `Google\Auth\SignBlobInterface`.
- */
- public function signBlob($stringToSign, $forceOpenSsl = \false)
- {
- if (!$this->fetcher instanceof SignBlobInterface) {
- throw new \RuntimeException('Credentials fetcher does not implement ' . 'Google\\Auth\\SignBlobInterface');
- }
- // Pass the access token from cache to GCECredentials for signing a blob.
- // This saves a call to the metadata server when a cached token exists.
- if ($this->fetcher instanceof Credentials\GCECredentials) {
- $cached = $this->fetchAuthTokenFromCache();
- $accessToken = $cached['access_token'] ?? null;
- return $this->fetcher->signBlob($stringToSign, $forceOpenSsl, $accessToken);
- }
- return $this->fetcher->signBlob($stringToSign, $forceOpenSsl);
- }
- /**
- * Get the quota project used for this API request from the credentials
- * fetcher.
- *
- * @return string|null
- */
- public function getQuotaProject()
- {
- if ($this->fetcher instanceof GetQuotaProjectInterface) {
- return $this->fetcher->getQuotaProject();
- }
- return null;
- }
- /*
- * Get the Project ID from the fetcher.
- *
- * @param callable $httpHandler Callback which delivers psr7 request
- * @return string|null
- * @throws \RuntimeException If the fetcher does not implement
- * `Google\Auth\ProvidesProjectIdInterface`.
- */
- public function getProjectId(callable $httpHandler = null)
- {
- if (!$this->fetcher instanceof ProjectIdProviderInterface) {
- throw new \RuntimeException('Credentials fetcher does not implement ' . 'Google\\Auth\\ProvidesProjectIdInterface');
- }
- return $this->fetcher->getProjectId($httpHandler);
- }
- /*
- * Get the Universe Domain from the fetcher.
- *
- * @return string
- */
- public function getUniverseDomain() : string
- {
- if ($this->fetcher instanceof GetUniverseDomainInterface) {
- return $this->fetcher->getUniverseDomain();
- }
- return GetUniverseDomainInterface::DEFAULT_UNIVERSE_DOMAIN;
- }
- /**
- * Updates metadata with the authorization token.
- *
- * @param array $metadata metadata hashmap
- * @param string $authUri optional auth uri
- * @param callable $httpHandler callback which delivers psr7 request
- * @return array updated metadata hashmap
- * @throws \RuntimeException If the fetcher does not implement
- * `Google\Auth\UpdateMetadataInterface`.
- */
- public function updateMetadata($metadata, $authUri = null, callable $httpHandler = null)
- {
- if (!$this->fetcher instanceof UpdateMetadataInterface) {
- throw new \RuntimeException('Credentials fetcher does not implement ' . 'Google\\Auth\\UpdateMetadataInterface');
- }
- $cached = $this->fetchAuthTokenFromCache($authUri);
- if ($cached) {
- // Set the access token in the `Authorization` metadata header so
- // the downstream call to updateMetadata know they don't need to
- // fetch another token.
- if (isset($cached['access_token'])) {
- $metadata[self::AUTH_METADATA_KEY] = ['Bearer ' . $cached['access_token']];
- } elseif (isset($cached['id_token'])) {
- $metadata[self::AUTH_METADATA_KEY] = ['Bearer ' . $cached['id_token']];
- }
- }
- $newMetadata = $this->fetcher->updateMetadata($metadata, $authUri, $httpHandler);
- if (!$cached && ($token = $this->fetcher->getLastReceivedToken())) {
- $this->saveAuthTokenInCache($token, $authUri);
- }
- return $newMetadata;
- }
- /**
- * @param string|null $authUri
- * @return array|null
- */
- private function fetchAuthTokenFromCache($authUri = null)
- {
- // Use the cached value if its available.
- //
- // TODO: correct caching; update the call to setCachedValue to set the expiry
- // to the value returned with the auth token.
- //
- // TODO: correct caching; enable the cache to be cleared.
- // if $authUri is set, use it as the cache key
- $cacheKey = $authUri ? $this->getFullCacheKey($authUri) : $this->fetcher->getCacheKey();
- $cached = $this->getCachedValue($cacheKey);
- if (is_array($cached)) {
- if (empty($cached['expires_at'])) {
- // If there is no expiration data, assume token is not expired.
- // (for JwtAccess and ID tokens)
- return $cached;
- }
- if (time() + $this->eagerRefreshThresholdSeconds < $cached['expires_at']) {
- // access token is not expired
- return $cached;
- }
- }
- return null;
- }
- /**
- * @param array $authToken
- * @param string|null $authUri
- * @return void
- */
- private function saveAuthTokenInCache($authToken, $authUri = null)
- {
- if (isset($authToken['access_token']) || isset($authToken['id_token'])) {
- // if $authUri is set, use it as the cache key
- $cacheKey = $authUri ? $this->getFullCacheKey($authUri) : $this->fetcher->getCacheKey();
- $this->setCachedValue($cacheKey, $authToken);
- }
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/FetchAuthTokenInterface.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/FetchAuthTokenInterface.php
deleted file mode 100644
index 368af0a..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/FetchAuthTokenInterface.php
+++ /dev/null
@@ -1,52 +0,0 @@
- a hash of auth tokens
- */
- public function fetchAuthToken(callable $httpHandler = null);
- /**
- * Obtains a key that can used to cache the results of #fetchAuthToken.
- *
- * If the value is empty, the auth token is not cached.
- *
- * @return string a key that may be used to cache the auth token.
- */
- public function getCacheKey();
- /**
- * Returns an associative array with the token and
- * expiration time.
- *
- * @return null|array {
- * The last received access token.
- *
- * @type string $access_token The access token string.
- * @type int $expires_at The time the token expires as a UNIX timestamp.
- * }
- */
- public function getLastReceivedToken();
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/GCECache.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/GCECache.php
deleted file mode 100644
index 661bc63..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/GCECache.php
+++ /dev/null
@@ -1,70 +0,0 @@
- $cacheConfig Configuration for the cache
- * @param CacheItemPoolInterface $cache
- */
- public function __construct(array $cacheConfig = null, CacheItemPoolInterface $cache = null)
- {
- $this->cache = $cache;
- $this->cacheConfig = array_merge(['lifetime' => 1500, 'prefix' => ''], (array) $cacheConfig);
- }
- /**
- * Caches the result of onGce so the metadata server is not called multiple
- * times.
- *
- * @param callable $httpHandler callback which delivers psr7 request
- * @return bool True if this a GCEInstance, false otherwise
- */
- public function onGce(callable $httpHandler = null)
- {
- if (is_null($this->cache)) {
- return GCECredentials::onGce($httpHandler);
- }
- $cacheKey = self::GCE_CACHE_KEY;
- $onGce = $this->getCachedValue($cacheKey);
- if (is_null($onGce)) {
- $onGce = GCECredentials::onGce($httpHandler);
- $this->setCachedValue($cacheKey, $onGce);
- }
- return $onGce;
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/GetQuotaProjectInterface.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/GetQuotaProjectInterface.php
deleted file mode 100644
index 6ea732e..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/GetQuotaProjectInterface.php
+++ /dev/null
@@ -1,32 +0,0 @@
-client = $client;
- }
- /**
- * Accepts a PSR-7 request and an array of options and returns a PSR-7 response.
- *
- * @param RequestInterface $request
- * @param array $options
- * @return ResponseInterface
- */
- public function __invoke(RequestInterface $request, array $options = [])
- {
- return $this->client->send($request, $options);
- }
- /**
- * Accepts a PSR-7 request and an array of options and returns a PromiseInterface
- *
- * @param RequestInterface $request
- * @param array $options
- *
- * @return \GuzzleHttp\Promise\PromiseInterface
- */
- public function async(RequestInterface $request, array $options = [])
- {
- return $this->client->sendAsync($request, $options);
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/HttpHandler/Guzzle7HttpHandler.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/HttpHandler/Guzzle7HttpHandler.php
deleted file mode 100644
index 7b2cce1..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/HttpHandler/Guzzle7HttpHandler.php
+++ /dev/null
@@ -1,22 +0,0 @@
-remove('http_errors');
- $stack->unshift(Middleware::httpErrors($bodySummarizer), 'http_errors');
- }
- $client = new Client(['handler' => $stack]);
- }
- $version = null;
- if (defined('Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\GuzzleHttp\\ClientInterface::MAJOR_VERSION')) {
- $version = ClientInterface::MAJOR_VERSION;
- } elseif (defined('Matomo\\Dependencies\\SearchEngineKeywordsPerformance\\GuzzleHttp\\ClientInterface::VERSION')) {
- $version = (int) substr(ClientInterface::VERSION, 0, 1);
- }
- switch ($version) {
- case 6:
- return new Guzzle6HttpHandler($client);
- case 7:
- return new Guzzle7HttpHandler($client);
- default:
- throw new \Exception('Version not supported');
- }
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/Iam.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/Iam.php
deleted file mode 100644
index 96f3acb..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/Iam.php
+++ /dev/null
@@ -1,79 +0,0 @@
-httpHandler = $httpHandler ?: HttpHandlerFactory::build(HttpClientCache::getHttpClient());
- }
- /**
- * Sign a string using the IAM signBlob API.
- *
- * Note that signing using IAM requires your service account to have the
- * `iam.serviceAccounts.signBlob` permission, part of the "Service Account
- * Token Creator" IAM role.
- *
- * @param string $email The service account email.
- * @param string $accessToken An access token from the service account.
- * @param string $stringToSign The string to be signed.
- * @param array $delegates [optional] A list of service account emails to
- * add to the delegate chain. If omitted, the value of `$email` will
- * be used.
- * @return string The signed string, base64-encoded.
- */
- public function signBlob($email, $accessToken, $stringToSign, array $delegates = [])
- {
- $httpHandler = $this->httpHandler;
- $name = sprintf(self::SERVICE_ACCOUNT_NAME, $email);
- $uri = self::IAM_API_ROOT . '/' . sprintf(self::SIGN_BLOB_PATH, $name);
- if ($delegates) {
- foreach ($delegates as &$delegate) {
- $delegate = sprintf(self::SERVICE_ACCOUNT_NAME, $delegate);
- }
- } else {
- $delegates = [$name];
- }
- $body = ['delegates' => $delegates, 'payload' => base64_encode($stringToSign)];
- $headers = ['Authorization' => 'Bearer ' . $accessToken];
- $request = new Psr7\Request('POST', $uri, $headers, Utils::streamFor(json_encode($body)));
- $res = $httpHandler($request);
- $body = json_decode((string) $res->getBody(), \true);
- return $body['signedBlob'];
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/IamSignerTrait.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/IamSignerTrait.php
deleted file mode 100644
index 4c898b6..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/IamSignerTrait.php
+++ /dev/null
@@ -1,58 +0,0 @@
-iam ?: new Iam($httpHandler);
- $email = $this->getClientName($httpHandler);
- if (is_null($accessToken)) {
- $previousToken = $this->getLastReceivedToken();
- $accessToken = $previousToken ? $previousToken['access_token'] : $this->fetchAuthToken($httpHandler)['access_token'];
- }
- return $signer->signBlob($email, $accessToken, $stringToSign);
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/Middleware/AuthTokenMiddleware.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/Middleware/AuthTokenMiddleware.php
deleted file mode 100644
index 7a7308d..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/Middleware/AuthTokenMiddleware.php
+++ /dev/null
@@ -1,138 +0,0 @@
-'
- */
-class AuthTokenMiddleware
-{
- /**
- * @var callable
- */
- private $httpHandler;
- /**
- * It must be an implementation of FetchAuthTokenInterface.
- * It may also implement UpdateMetadataInterface allowing direct
- * retrieval of auth related headers
- * @var FetchAuthTokenInterface
- */
- private $fetcher;
- /**
- * @var ?callable
- */
- private $tokenCallback;
- /**
- * Creates a new AuthTokenMiddleware.
- *
- * @param FetchAuthTokenInterface $fetcher is used to fetch the auth token
- * @param callable $httpHandler (optional) callback which delivers psr7 request
- * @param callable $tokenCallback (optional) function to be called when a new token is fetched.
- */
- public function __construct(FetchAuthTokenInterface $fetcher, callable $httpHandler = null, callable $tokenCallback = null)
- {
- $this->fetcher = $fetcher;
- $this->httpHandler = $httpHandler;
- $this->tokenCallback = $tokenCallback;
- }
- /**
- * Updates the request with an Authorization header when auth is 'google_auth'.
- *
- * use Google\Auth\Middleware\AuthTokenMiddleware;
- * use Google\Auth\OAuth2;
- * use GuzzleHttp\Client;
- * use GuzzleHttp\HandlerStack;
- *
- * $config = [...];
- * $oauth2 = new OAuth2($config)
- * $middleware = new AuthTokenMiddleware($oauth2);
- * $stack = HandlerStack::create();
- * $stack->push($middleware);
- *
- * $client = new Client([
- * 'handler' => $stack,
- * 'base_uri' => 'https://www.googleapis.com/taskqueue/v1beta2/projects/',
- * 'auth' => 'google_auth' // authorize all requests
- * ]);
- *
- * $res = $client->get('myproject/taskqueues/myqueue');
- *
- * @param callable $handler
- * @return \Closure
- */
- public function __invoke(callable $handler)
- {
- return function (RequestInterface $request, array $options) use($handler) {
- // Requests using "auth"="google_auth" will be authorized.
- if (!isset($options['auth']) || $options['auth'] !== 'google_auth') {
- return $handler($request, $options);
- }
- $request = $this->addAuthHeaders($request);
- if ($quotaProject = $this->getQuotaProject()) {
- $request = $request->withHeader(GetQuotaProjectInterface::X_GOOG_USER_PROJECT_HEADER, $quotaProject);
- }
- return $handler($request, $options);
- };
- }
- /**
- * Adds auth related headers to the request.
- *
- * @param RequestInterface $request
- * @return RequestInterface
- */
- private function addAuthHeaders(RequestInterface $request)
- {
- if (!$this->fetcher instanceof UpdateMetadataInterface || $this->fetcher instanceof FetchAuthTokenCache && !$this->fetcher->getFetcher() instanceof UpdateMetadataInterface) {
- $token = $this->fetcher->fetchAuthToken();
- $request = $request->withHeader('authorization', 'Bearer ' . ($token['access_token'] ?? $token['id_token'] ?? ''));
- } else {
- $headers = $this->fetcher->updateMetadata($request->getHeaders(), null, $this->httpHandler);
- $request = Utils::modifyRequest($request, ['set_headers' => $headers]);
- }
- if ($this->tokenCallback && ($token = $this->fetcher->getLastReceivedToken())) {
- if (array_key_exists('access_token', $token)) {
- call_user_func($this->tokenCallback, $this->fetcher->getCacheKey(), $token['access_token']);
- }
- }
- return $request;
- }
- /**
- * @return string|null
- */
- private function getQuotaProject()
- {
- if ($this->fetcher instanceof GetQuotaProjectInterface) {
- return $this->fetcher->getQuotaProject();
- }
- return null;
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/Middleware/ProxyAuthTokenMiddleware.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/Middleware/ProxyAuthTokenMiddleware.php
deleted file mode 100644
index 1e83dec..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/Middleware/ProxyAuthTokenMiddleware.php
+++ /dev/null
@@ -1,130 +0,0 @@
-'
- */
-class ProxyAuthTokenMiddleware
-{
- /**
- * @var callable
- */
- private $httpHandler;
- /**
- * @var FetchAuthTokenInterface
- */
- private $fetcher;
- /**
- * @var ?callable
- */
- private $tokenCallback;
- /**
- * Creates a new ProxyAuthTokenMiddleware.
- *
- * @param FetchAuthTokenInterface $fetcher is used to fetch the auth token
- * @param callable $httpHandler (optional) callback which delivers psr7 request
- * @param callable $tokenCallback (optional) function to be called when a new token is fetched.
- */
- public function __construct(FetchAuthTokenInterface $fetcher, callable $httpHandler = null, callable $tokenCallback = null)
- {
- $this->fetcher = $fetcher;
- $this->httpHandler = $httpHandler;
- $this->tokenCallback = $tokenCallback;
- }
- /**
- * Updates the request with an Authorization header when auth is 'google_auth'.
- *
- * use Google\Auth\Middleware\ProxyAuthTokenMiddleware;
- * use Google\Auth\OAuth2;
- * use GuzzleHttp\Client;
- * use GuzzleHttp\HandlerStack;
- *
- * $config = [...];
- * $oauth2 = new OAuth2($config)
- * $middleware = new ProxyAuthTokenMiddleware($oauth2);
- * $stack = HandlerStack::create();
- * $stack->push($middleware);
- *
- * $client = new Client([
- * 'handler' => $stack,
- * 'base_uri' => 'https://www.googleapis.com/taskqueue/v1beta2/projects/',
- * 'proxy_auth' => 'google_auth' // authorize all requests
- * ]);
- *
- * $res = $client->get('myproject/taskqueues/myqueue');
- *
- * @param callable $handler
- * @return \Closure
- */
- public function __invoke(callable $handler)
- {
- return function (RequestInterface $request, array $options) use($handler) {
- // Requests using "proxy_auth"="google_auth" will be authorized.
- if (!isset($options['proxy_auth']) || $options['proxy_auth'] !== 'google_auth') {
- return $handler($request, $options);
- }
- $request = $request->withHeader('proxy-authorization', 'Bearer ' . $this->fetchToken());
- if ($quotaProject = $this->getQuotaProject()) {
- $request = $request->withHeader(GetQuotaProjectInterface::X_GOOG_USER_PROJECT_HEADER, $quotaProject);
- }
- return $handler($request, $options);
- };
- }
- /**
- * Call fetcher to fetch the token.
- *
- * @return string|null
- */
- private function fetchToken()
- {
- $auth_tokens = $this->fetcher->fetchAuthToken($this->httpHandler);
- if (array_key_exists('access_token', $auth_tokens)) {
- // notify the callback if applicable
- if ($this->tokenCallback) {
- call_user_func($this->tokenCallback, $this->fetcher->getCacheKey(), $auth_tokens['access_token']);
- }
- return $auth_tokens['access_token'];
- }
- if (array_key_exists('id_token', $auth_tokens)) {
- return $auth_tokens['id_token'];
- }
- return null;
- }
- /**
- * @return string|null;
- */
- private function getQuotaProject()
- {
- if ($this->fetcher instanceof GetQuotaProjectInterface) {
- return $this->fetcher->getQuotaProject();
- }
- return null;
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/Middleware/ScopedAccessTokenMiddleware.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/Middleware/ScopedAccessTokenMiddleware.php
deleted file mode 100644
index 61a3ff5..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/Middleware/ScopedAccessTokenMiddleware.php
+++ /dev/null
@@ -1,140 +0,0 @@
-'
- */
-class ScopedAccessTokenMiddleware
-{
- use CacheTrait;
- const DEFAULT_CACHE_LIFETIME = 1500;
- /**
- * @var callable
- */
- private $tokenFunc;
- /**
- * @var array|string
- */
- private $scopes;
- /**
- * Creates a new ScopedAccessTokenMiddleware.
- *
- * @param callable $tokenFunc a token generator function
- * @param array|string $scopes the token authentication scopes
- * @param array $cacheConfig configuration for the cache when it's present
- * @param CacheItemPoolInterface $cache an implementation of CacheItemPoolInterface
- */
- public function __construct(callable $tokenFunc, $scopes, array $cacheConfig = null, CacheItemPoolInterface $cache = null)
- {
- $this->tokenFunc = $tokenFunc;
- if (!(is_string($scopes) || is_array($scopes))) {
- throw new \InvalidArgumentException('wants scope should be string or array');
- }
- $this->scopes = $scopes;
- if (!is_null($cache)) {
- $this->cache = $cache;
- $this->cacheConfig = array_merge(['lifetime' => self::DEFAULT_CACHE_LIFETIME, 'prefix' => ''], $cacheConfig);
- }
- }
- /**
- * Updates the request with an Authorization header when auth is 'scoped'.
- *
- * E.g this could be used to authenticate using the AppEngine
- * AppIdentityService.
- *
- * use google\appengine\api\app_identity\AppIdentityService;
- * use Google\Auth\Middleware\ScopedAccessTokenMiddleware;
- * use GuzzleHttp\Client;
- * use GuzzleHttp\HandlerStack;
- *
- * $scope = 'https://www.googleapis.com/auth/taskqueue'
- * $middleware = new ScopedAccessTokenMiddleware(
- * 'AppIdentityService::getAccessToken',
- * $scope,
- * [ 'prefix' => 'Google\Auth\ScopedAccessToken::' ],
- * $cache = new Memcache()
- * );
- * $stack = HandlerStack::create();
- * $stack->push($middleware);
- *
- * $client = new Client([
- * 'handler' => $stack,
- * 'base_url' => 'https://www.googleapis.com/taskqueue/v1beta2/projects/',
- * 'auth' => 'scoped' // authorize all requests
- * ]);
- *
- * $res = $client->get('myproject/taskqueues/myqueue');
- *
- * @param callable $handler
- * @return \Closure
- */
- public function __invoke(callable $handler)
- {
- return function (RequestInterface $request, array $options) use($handler) {
- // Requests using "auth"="scoped" will be authorized.
- if (!isset($options['auth']) || $options['auth'] !== 'scoped') {
- return $handler($request, $options);
- }
- $request = $request->withHeader('authorization', 'Bearer ' . $this->fetchToken());
- return $handler($request, $options);
- };
- }
- /**
- * @return string
- */
- private function getCacheKey()
- {
- $key = null;
- if (is_string($this->scopes)) {
- $key .= $this->scopes;
- } elseif (is_array($this->scopes)) {
- $key .= implode(':', $this->scopes);
- }
- return $key;
- }
- /**
- * Determine if token is available in the cache, if not call tokenFunc to
- * fetch it.
- *
- * @return string
- */
- private function fetchToken()
- {
- $cacheKey = $this->getCacheKey();
- $cached = $this->getCachedValue($cacheKey);
- if (!empty($cached)) {
- return $cached;
- }
- $token = call_user_func($this->tokenFunc, $this->scopes);
- $this->setCachedValue($cacheKey, $token);
- return $token;
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/Middleware/SimpleMiddleware.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/Middleware/SimpleMiddleware.php
deleted file mode 100644
index 4201173..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/Middleware/SimpleMiddleware.php
+++ /dev/null
@@ -1,86 +0,0 @@
-
- */
- private $config;
- /**
- * Create a new Simple plugin.
- *
- * The configuration array expects one option
- * - key: required, otherwise InvalidArgumentException is thrown
- *
- * @param array $config Configuration array
- */
- public function __construct(array $config)
- {
- if (!isset($config['key'])) {
- throw new \InvalidArgumentException('requires a key to have been set');
- }
- $this->config = array_merge(['key' => null], $config);
- }
- /**
- * Updates the request query with the developer key if auth is set to simple.
- *
- * use Google\Auth\Middleware\SimpleMiddleware;
- * use GuzzleHttp\Client;
- * use GuzzleHttp\HandlerStack;
- *
- * $my_key = 'is not the same as yours';
- * $middleware = new SimpleMiddleware(['key' => $my_key]);
- * $stack = HandlerStack::create();
- * $stack->push($middleware);
- *
- * $client = new Client([
- * 'handler' => $stack,
- * 'base_uri' => 'https://www.googleapis.com/discovery/v1/',
- * 'auth' => 'simple'
- * ]);
- *
- * $res = $client->get('drive/v2/rest');
- *
- * @param callable $handler
- * @return \Closure
- */
- public function __invoke(callable $handler)
- {
- return function (RequestInterface $request, array $options) use($handler) {
- // Requests using "auth"="scoped" will be authorized.
- if (!isset($options['auth']) || $options['auth'] !== 'simple') {
- return $handler($request, $options);
- }
- $query = Query::parse($request->getUri()->getQuery());
- $params = array_merge($query, $this->config);
- $uri = $request->getUri()->withQuery(Query::build($params));
- $request = $request->withUri($uri);
- return $handler($request, $options);
- };
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/OAuth2.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/OAuth2.php
deleted file mode 100644
index bc5ce46..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/OAuth2.php
+++ /dev/null
@@ -1,1515 +0,0 @@
-
- */
- public static $knownSigningAlgorithms = ['HS256', 'HS512', 'HS384', 'RS256'];
- /**
- * The well known grant types.
- *
- * @var array
- */
- public static $knownGrantTypes = ['authorization_code', 'refresh_token', 'password', 'client_credentials'];
- /**
- * - authorizationUri
- * The authorization server's HTTP endpoint capable of
- * authenticating the end-user and obtaining authorization.
- *
- * @var ?UriInterface
- */
- private $authorizationUri;
- /**
- * - tokenCredentialUri
- * The authorization server's HTTP endpoint capable of issuing
- * tokens and refreshing expired tokens.
- *
- * @var UriInterface
- */
- private $tokenCredentialUri;
- /**
- * The redirection URI used in the initial request.
- *
- * @var ?string
- */
- private $redirectUri;
- /**
- * A unique identifier issued to the client to identify itself to the
- * authorization server.
- *
- * @var string
- */
- private $clientId;
- /**
- * A shared symmetric secret issued by the authorization server, which is
- * used to authenticate the client.
- *
- * @var string
- */
- private $clientSecret;
- /**
- * The resource owner's username.
- *
- * @var ?string
- */
- private $username;
- /**
- * The resource owner's password.
- *
- * @var ?string
- */
- private $password;
- /**
- * The scope of the access request, expressed either as an Array or as a
- * space-delimited string.
- *
- * @var ?array
- */
- private $scope;
- /**
- * An arbitrary string designed to allow the client to maintain state.
- *
- * @var string
- */
- private $state;
- /**
- * The authorization code issued to this client.
- *
- * Only used by the authorization code access grant type.
- *
- * @var ?string
- */
- private $code;
- /**
- * The issuer ID when using assertion profile.
- *
- * @var ?string
- */
- private $issuer;
- /**
- * The target audience for assertions.
- *
- * @var string
- */
- private $audience;
- /**
- * The target sub when issuing assertions.
- *
- * @var string
- */
- private $sub;
- /**
- * The number of seconds assertions are valid for.
- *
- * @var int
- */
- private $expiry;
- /**
- * The signing key when using assertion profile.
- *
- * @var ?string
- */
- private $signingKey;
- /**
- * The signing key id when using assertion profile. Param kid in jwt header
- *
- * @var string
- */
- private $signingKeyId;
- /**
- * The signing algorithm when using an assertion profile.
- *
- * @var ?string
- */
- private $signingAlgorithm;
- /**
- * The refresh token associated with the access token to be refreshed.
- *
- * @var ?string
- */
- private $refreshToken;
- /**
- * The current access token.
- *
- * @var string
- */
- private $accessToken;
- /**
- * The current ID token.
- *
- * @var string
- */
- private $idToken;
- /**
- * The scopes granted to the current access token
- *
- * @var string
- */
- private $grantedScope;
- /**
- * The lifetime in seconds of the current access token.
- *
- * @var ?int
- */
- private $expiresIn;
- /**
- * The expiration time of the access token as a number of seconds since the
- * unix epoch.
- *
- * @var ?int
- */
- private $expiresAt;
- /**
- * The issue time of the access token as a number of seconds since the unix
- * epoch.
- *
- * @var ?int
- */
- private $issuedAt;
- /**
- * The current grant type.
- *
- * @var ?string
- */
- private $grantType;
- /**
- * When using an extension grant type, this is the set of parameters used by
- * that extension.
- *
- * @var array
- */
- private $extensionParams;
- /**
- * When using the toJwt function, these claims will be added to the JWT
- * payload.
- *
- * @var array
- */
- private $additionalClaims;
- /**
- * The code verifier for PKCE for OAuth 2.0. When set, the authorization
- * URI will contain the Code Challenge and Code Challenge Method querystring
- * parameters, and the token URI will contain the Code Verifier parameter.
- *
- * @see https://datatracker.ietf.org/doc/html/rfc7636
- * @var ?string
- */
- private $codeVerifier;
- /**
- * For STS requests.
- * A URI that indicates the target service or resource where the client
- * intends to use the requested security token.
- * @var string|null
- */
- private $resource;
- /**
- * For STS requests.
- * A fetcher for the "subject_token", which is a security token that
- * represents the identity of the party on behalf of whom the request is
- * being made.
- * @var \Matomo\Dependencies\SearchEngineKeywordsPerformance\Google\Auth\ExternalAccountCredentialSourceInterface|null
- */
- private $subjectTokenFetcher;
- /**
- * For STS requests.
- * An identifier, that indicates the type of the security token in the
- * subjectToken parameter.
- * @var string|null
- */
- private $subjectTokenType;
- /**
- * For STS requests.
- * A security token that represents the identity of the acting party.
- * @var string|null
- */
- private $actorToken;
- /**
- * For STS requests.
- * An identifier that indicates the type of the security token in the
- * actorToken parameter.
- * @var string|null
- */
- private $actorTokenType;
- /**
- * From STS response.
- * An identifier for the representation of the issued security token.
- * @var string|null
- */
- private $issuedTokenType;
- /**
- * Create a new OAuthCredentials.
- *
- * The configuration array accepts various options
- *
- * - authorizationUri
- * The authorization server's HTTP endpoint capable of
- * authenticating the end-user and obtaining authorization.
- *
- * - tokenCredentialUri
- * The authorization server's HTTP endpoint capable of issuing
- * tokens and refreshing expired tokens.
- *
- * - clientId
- * A unique identifier issued to the client to identify itself to the
- * authorization server.
- *
- * - clientSecret
- * A shared symmetric secret issued by the authorization server,
- * which is used to authenticate the client.
- *
- * - scope
- * The scope of the access request, expressed either as an Array
- * or as a space-delimited String.
- *
- * - state
- * An arbitrary string designed to allow the client to maintain state.
- *
- * - redirectUri
- * The redirection URI used in the initial request.
- *
- * - username
- * The resource owner's username.
- *
- * - password
- * The resource owner's password.
- *
- * - issuer
- * Issuer ID when using assertion profile
- *
- * - audience
- * Target audience for assertions
- *
- * - expiry
- * Number of seconds assertions are valid for
- *
- * - signingKey
- * Signing key when using assertion profile
- *
- * - signingKeyId
- * Signing key id when using assertion profile
- *
- * - refreshToken
- * The refresh token associated with the access token
- * to be refreshed.
- *
- * - accessToken
- * The current access token for this client.
- *
- * - idToken
- * The current ID token for this client.
- *
- * - extensionParams
- * When using an extension grant type, this is the set of parameters used
- * by that extension.
- *
- * - codeVerifier
- * The code verifier for PKCE for OAuth 2.0.
- *
- * - resource
- * The target service or resource where the client ntends to use the
- * requested security token.
- *
- * - subjectTokenFetcher
- * A fetcher for the "subject_token", which is a security token that
- * represents the identity of the party on behalf of whom the request is
- * being made.
- *
- * - subjectTokenType
- * An identifier that indicates the type of the security token in the
- * subjectToken parameter.
- *
- * - actorToken
- * A security token that represents the identity of the acting party.
- *
- * - actorTokenType
- * An identifier for the representation of the issued security token.
- *
- * @param array $config Configuration array
- */
- public function __construct(array $config)
- {
- $opts = array_merge(['expiry' => self::DEFAULT_EXPIRY_SECONDS, 'extensionParams' => [], 'authorizationUri' => null, 'redirectUri' => null, 'tokenCredentialUri' => null, 'state' => null, 'username' => null, 'password' => null, 'clientId' => null, 'clientSecret' => null, 'issuer' => null, 'sub' => null, 'audience' => null, 'signingKey' => null, 'signingKeyId' => null, 'signingAlgorithm' => null, 'scope' => null, 'additionalClaims' => [], 'codeVerifier' => null, 'resource' => null, 'subjectTokenFetcher' => null, 'subjectTokenType' => null, 'actorToken' => null, 'actorTokenType' => null], $config);
- $this->setAuthorizationUri($opts['authorizationUri']);
- $this->setRedirectUri($opts['redirectUri']);
- $this->setTokenCredentialUri($opts['tokenCredentialUri']);
- $this->setState($opts['state']);
- $this->setUsername($opts['username']);
- $this->setPassword($opts['password']);
- $this->setClientId($opts['clientId']);
- $this->setClientSecret($opts['clientSecret']);
- $this->setIssuer($opts['issuer']);
- $this->setSub($opts['sub']);
- $this->setExpiry($opts['expiry']);
- $this->setAudience($opts['audience']);
- $this->setSigningKey($opts['signingKey']);
- $this->setSigningKeyId($opts['signingKeyId']);
- $this->setSigningAlgorithm($opts['signingAlgorithm']);
- $this->setScope($opts['scope']);
- $this->setExtensionParams($opts['extensionParams']);
- $this->setAdditionalClaims($opts['additionalClaims']);
- $this->setCodeVerifier($opts['codeVerifier']);
- // for STS
- $this->resource = $opts['resource'];
- $this->subjectTokenFetcher = $opts['subjectTokenFetcher'];
- $this->subjectTokenType = $opts['subjectTokenType'];
- $this->actorToken = $opts['actorToken'];
- $this->actorTokenType = $opts['actorTokenType'];
- $this->updateToken($opts);
- }
- /**
- * Verifies the idToken if present.
- *
- * - if none is present, return null
- * - if present, but invalid, raises DomainException.
- * - otherwise returns the payload in the idtoken as a PHP object.
- *
- * The behavior of this method varies depending on the version of
- * `firebase/php-jwt` you are using. In versions 6.0 and above, you cannot
- * provide multiple $allowed_algs, and instead must provide an array of Key
- * objects as the $publicKey.
- *
- * @param string|Key|Key[] $publicKey The public key to use to authenticate the token
- * @param string|array $allowed_algs algorithm or array of supported verification algorithms.
- * Providing more than one algorithm will throw an exception.
- * @throws \DomainException if the token is missing an audience.
- * @throws \DomainException if the audience does not match the one set in
- * the OAuth2 class instance.
- * @throws \UnexpectedValueException If the token is invalid
- * @throws \InvalidArgumentException If more than one value for allowed_algs is supplied
- * @throws \Firebase\JWT\SignatureInvalidException If the signature is invalid.
- * @throws \Firebase\JWT\BeforeValidException If the token is not yet valid.
- * @throws \Firebase\JWT\ExpiredException If the token has expired.
- * @return null|object
- */
- public function verifyIdToken($publicKey = null, $allowed_algs = [])
- {
- $idToken = $this->getIdToken();
- if (is_null($idToken)) {
- return null;
- }
- $resp = $this->jwtDecode($idToken, $publicKey, $allowed_algs);
- if (!property_exists($resp, 'aud')) {
- throw new \DomainException('No audience found the id token');
- }
- if ($resp->aud != $this->getAudience()) {
- throw new \DomainException('Wrong audience present in the id token');
- }
- return $resp;
- }
- /**
- * Obtains the encoded jwt from the instance data.
- *
- * @param array $config array optional configuration parameters
- * @return string
- */
- public function toJwt(array $config = [])
- {
- if (is_null($this->getSigningKey())) {
- throw new \DomainException('No signing key available');
- }
- if (is_null($this->getSigningAlgorithm())) {
- throw new \DomainException('No signing algorithm specified');
- }
- $now = time();
- $opts = array_merge(['skew' => self::DEFAULT_SKEW_SECONDS], $config);
- $assertion = ['iss' => $this->getIssuer(), 'exp' => $now + $this->getExpiry(), 'iat' => $now - $opts['skew']];
- foreach ($assertion as $k => $v) {
- if (is_null($v)) {
- throw new \DomainException($k . ' should not be null');
- }
- }
- if (!is_null($this->getAudience())) {
- $assertion['aud'] = $this->getAudience();
- }
- if (!is_null($this->getScope())) {
- $assertion['scope'] = $this->getScope();
- }
- if (empty($assertion['scope']) && empty($assertion['aud'])) {
- throw new \DomainException('one of scope or aud should not be null');
- }
- if (!is_null($this->getSub())) {
- $assertion['sub'] = $this->getSub();
- }
- $assertion += $this->getAdditionalClaims();
- return JWT::encode($assertion, $this->getSigningKey(), $this->getSigningAlgorithm(), $this->getSigningKeyId());
- }
- /**
- * Generates a request for token credentials.
- *
- * @param callable $httpHandler callback which delivers psr7 request
- * @return RequestInterface the authorization Url.
- */
- public function generateCredentialsRequest(callable $httpHandler = null)
- {
- $uri = $this->getTokenCredentialUri();
- if (is_null($uri)) {
- throw new \DomainException('No token credential URI was set.');
- }
- $grantType = $this->getGrantType();
- $params = ['grant_type' => $grantType];
- switch ($grantType) {
- case 'authorization_code':
- $params['code'] = $this->getCode();
- $params['redirect_uri'] = $this->getRedirectUri();
- if ($this->codeVerifier) {
- $params['code_verifier'] = $this->codeVerifier;
- }
- $this->addClientCredentials($params);
- break;
- case 'password':
- $params['username'] = $this->getUsername();
- $params['password'] = $this->getPassword();
- $this->addClientCredentials($params);
- break;
- case 'refresh_token':
- $params['refresh_token'] = $this->getRefreshToken();
- $this->addClientCredentials($params);
- break;
- case self::JWT_URN:
- $params['assertion'] = $this->toJwt();
- break;
- case self::STS_URN:
- $token = $this->subjectTokenFetcher->fetchSubjectToken($httpHandler);
- $params['subject_token'] = $token;
- $params['subject_token_type'] = $this->subjectTokenType;
- $params += array_filter(['resource' => $this->resource, 'audience' => $this->audience, 'scope' => $this->getScope(), 'requested_token_type' => self::STS_REQUESTED_TOKEN_TYPE, 'actor_token' => $this->actorToken, 'actor_token_type' => $this->actorTokenType]);
- break;
- default:
- if (!is_null($this->getRedirectUri())) {
- # Grant type was supposed to be 'authorization_code', as there
- # is a redirect URI.
- throw new \DomainException('Missing authorization code');
- }
- unset($params['grant_type']);
- if (!is_null($grantType)) {
- $params['grant_type'] = $grantType;
- }
- $params = array_merge($params, $this->getExtensionParams());
- }
- $headers = ['Cache-Control' => 'no-store', 'Content-Type' => 'application/x-www-form-urlencoded'];
- return new Request('POST', $uri, $headers, Query::build($params));
- }
- /**
- * Fetches the auth tokens based on the current state.
- *
- * @param callable $httpHandler callback which delivers psr7 request
- * @return array the response
- */
- public function fetchAuthToken(callable $httpHandler = null)
- {
- if (is_null($httpHandler)) {
- $httpHandler = HttpHandlerFactory::build(HttpClientCache::getHttpClient());
- }
- $response = $httpHandler($this->generateCredentialsRequest($httpHandler));
- $credentials = $this->parseTokenResponse($response);
- $this->updateToken($credentials);
- if (isset($credentials['scope'])) {
- $this->setGrantedScope($credentials['scope']);
- }
- return $credentials;
- }
- /**
- * Obtains a key that can used to cache the results of #fetchAuthToken.
- *
- * The key is derived from the scopes.
- *
- * @return ?string a key that may be used to cache the auth token.
- */
- public function getCacheKey()
- {
- if (is_array($this->scope)) {
- return implode(':', $this->scope);
- }
- if ($this->audience) {
- return $this->audience;
- }
- // If scope has not set, return null to indicate no caching.
- return null;
- }
- /**
- * Parses the fetched tokens.
- *
- * @param ResponseInterface $resp the response.
- * @return array the tokens parsed from the response body.
- * @throws \Exception
- */
- public function parseTokenResponse(ResponseInterface $resp)
- {
- $body = (string) $resp->getBody();
- if ($resp->hasHeader('Content-Type') && $resp->getHeaderLine('Content-Type') == 'application/x-www-form-urlencoded') {
- $res = [];
- parse_str($body, $res);
- return $res;
- }
- // Assume it's JSON; if it's not throw an exception
- if (null === ($res = json_decode($body, \true))) {
- throw new \Exception('Invalid JSON response');
- }
- return $res;
- }
- /**
- * Updates an OAuth 2.0 client.
- *
- * Example:
- * ```
- * $oauth->updateToken([
- * 'refresh_token' => 'n4E9O119d',
- * 'access_token' => 'FJQbwq9',
- * 'expires_in' => 3600
- * ]);
- * ```
- *
- * @param array $config
- * The configuration parameters related to the token.
- *
- * - refresh_token
- * The refresh token associated with the access token
- * to be refreshed.
- *
- * - access_token
- * The current access token for this client.
- *
- * - id_token
- * The current ID token for this client.
- *
- * - expires_in
- * The time in seconds until access token expiration.
- *
- * - expires_at
- * The time as an integer number of seconds since the Epoch
- *
- * - issued_at
- * The timestamp that the token was issued at.
- * @return void
- */
- public function updateToken(array $config)
- {
- $opts = array_merge(['extensionParams' => [], 'access_token' => null, 'id_token' => null, 'expires_in' => null, 'expires_at' => null, 'issued_at' => null, 'scope' => null], $config);
- $this->setExpiresAt($opts['expires_at']);
- $this->setExpiresIn($opts['expires_in']);
- // By default, the token is issued at `Time.now` when `expiresIn` is set,
- // but this can be used to supply a more precise time.
- if (!is_null($opts['issued_at'])) {
- $this->setIssuedAt($opts['issued_at']);
- }
- $this->setAccessToken($opts['access_token']);
- $this->setIdToken($opts['id_token']);
- // The refresh token should only be updated if a value is explicitly
- // passed in, as some access token responses do not include a refresh
- // token.
- if (array_key_exists('refresh_token', $opts)) {
- $this->setRefreshToken($opts['refresh_token']);
- }
- // Required for STS response. An identifier for the representation of
- // the issued security token.
- if (array_key_exists('issued_token_type', $opts)) {
- $this->issuedTokenType = $opts['issued_token_type'];
- }
- }
- /**
- * Builds the authorization Uri that the user should be redirected to.
- *
- * @param array $config configuration options that customize the return url.
- * @return UriInterface the authorization Url.
- * @throws InvalidArgumentException
- */
- public function buildFullAuthorizationUri(array $config = [])
- {
- if (is_null($this->getAuthorizationUri())) {
- throw new InvalidArgumentException('requires an authorizationUri to have been set');
- }
- $params = array_merge(['response_type' => 'code', 'access_type' => 'offline', 'client_id' => $this->clientId, 'redirect_uri' => $this->redirectUri, 'state' => $this->state, 'scope' => $this->getScope()], $config);
- // Validate the auth_params
- if (is_null($params['client_id'])) {
- throw new InvalidArgumentException('missing the required client identifier');
- }
- if (is_null($params['redirect_uri'])) {
- throw new InvalidArgumentException('missing the required redirect URI');
- }
- if (!empty($params['prompt']) && !empty($params['approval_prompt'])) {
- throw new InvalidArgumentException('prompt and approval_prompt are mutually exclusive');
- }
- if ($this->codeVerifier) {
- $params['code_challenge'] = $this->getCodeChallenge($this->codeVerifier);
- $params['code_challenge_method'] = $this->getCodeChallengeMethod();
- }
- // Construct the uri object; return it if it is valid.
- $result = clone $this->authorizationUri;
- $existingParams = Query::parse($result->getQuery());
- $result = $result->withQuery(Query::build(array_merge($existingParams, $params)));
- if ($result->getScheme() != 'https') {
- throw new InvalidArgumentException('Authorization endpoint must be protected by TLS');
- }
- return $result;
- }
- /**
- * @return string|null
- */
- public function getCodeVerifier() : ?string
- {
- return $this->codeVerifier;
- }
- /**
- * A cryptographically random string that is used to correlate the
- * authorization request to the token request.
- *
- * The code verifier for PKCE for OAuth 2.0. When set, the authorization
- * URI will contain the Code Challenge and Code Challenge Method querystring
- * parameters, and the token URI will contain the Code Verifier parameter.
- *
- * @see https://datatracker.ietf.org/doc/html/rfc7636
- *
- * @param string|null $codeVerifier
- */
- public function setCodeVerifier(?string $codeVerifier) : void
- {
- $this->codeVerifier = $codeVerifier;
- }
- /**
- * Generates a random 128-character string for the "code_verifier" parameter
- * in PKCE for OAuth 2.0. This is a cryptographically random string that is
- * determined using random_int, hashed using "hash" and sha256, and base64
- * encoded.
- *
- * When this method is called, the code verifier is set on the object.
- *
- * @return string
- */
- public function generateCodeVerifier() : string
- {
- return $this->codeVerifier = $this->generateRandomString(128);
- }
- private function getCodeChallenge(string $randomString) : string
- {
- return rtrim(strtr(base64_encode(hash('sha256', $randomString, \true)), '+/', '-_'), '=');
- }
- private function getCodeChallengeMethod() : string
- {
- return 'S256';
- }
- private function generateRandomString(int $length) : string
- {
- $validChars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._~';
- $validCharsLen = strlen($validChars);
- $str = '';
- $i = 0;
- while ($i++ < $length) {
- $str .= $validChars[random_int(0, $validCharsLen - 1)];
- }
- return $str;
- }
- /**
- * Sets the authorization server's HTTP endpoint capable of authenticating
- * the end-user and obtaining authorization.
- *
- * @param string $uri
- * @return void
- */
- public function setAuthorizationUri($uri)
- {
- $this->authorizationUri = $this->coerceUri($uri);
- }
- /**
- * Gets the authorization server's HTTP endpoint capable of authenticating
- * the end-user and obtaining authorization.
- *
- * @return ?UriInterface
- */
- public function getAuthorizationUri()
- {
- return $this->authorizationUri;
- }
- /**
- * Gets the authorization server's HTTP endpoint capable of issuing tokens
- * and refreshing expired tokens.
- *
- * @return ?UriInterface
- */
- public function getTokenCredentialUri()
- {
- return $this->tokenCredentialUri;
- }
- /**
- * Sets the authorization server's HTTP endpoint capable of issuing tokens
- * and refreshing expired tokens.
- *
- * @param string $uri
- * @return void
- */
- public function setTokenCredentialUri($uri)
- {
- $this->tokenCredentialUri = $this->coerceUri($uri);
- }
- /**
- * Gets the redirection URI used in the initial request.
- *
- * @return ?string
- */
- public function getRedirectUri()
- {
- return $this->redirectUri;
- }
- /**
- * Sets the redirection URI used in the initial request.
- *
- * @param ?string $uri
- * @return void
- */
- public function setRedirectUri($uri)
- {
- if (is_null($uri)) {
- $this->redirectUri = null;
- return;
- }
- // redirect URI must be absolute
- if (!$this->isAbsoluteUri($uri)) {
- // "postmessage" is a reserved URI string in Google-land
- // @see https://developers.google.com/identity/sign-in/web/server-side-flow
- if ('postmessage' !== (string) $uri) {
- throw new InvalidArgumentException('Redirect URI must be absolute');
- }
- }
- $this->redirectUri = (string) $uri;
- }
- /**
- * Gets the scope of the access requests as a space-delimited String.
- *
- * @return ?string
- */
- public function getScope()
- {
- if (is_null($this->scope)) {
- return $this->scope;
- }
- return implode(' ', $this->scope);
- }
- /**
- * Sets the scope of the access request, expressed either as an Array or as
- * a space-delimited String.
- *
- * @param string|array|null $scope
- * @return void
- * @throws InvalidArgumentException
- */
- public function setScope($scope)
- {
- if (is_null($scope)) {
- $this->scope = null;
- } elseif (is_string($scope)) {
- $this->scope = explode(' ', $scope);
- } elseif (is_array($scope)) {
- foreach ($scope as $s) {
- $pos = strpos($s, ' ');
- if ($pos !== \false) {
- throw new InvalidArgumentException('array scope values should not contain spaces');
- }
- }
- $this->scope = $scope;
- } else {
- throw new InvalidArgumentException('scopes should be a string or array of strings');
- }
- }
- /**
- * Gets the current grant type.
- *
- * @return ?string
- */
- public function getGrantType()
- {
- if (!is_null($this->grantType)) {
- return $this->grantType;
- }
- // Returns the inferred grant type, based on the current object instance
- // state.
- if (!is_null($this->code)) {
- return 'authorization_code';
- }
- if (!is_null($this->refreshToken)) {
- return 'refresh_token';
- }
- if (!is_null($this->username) && !is_null($this->password)) {
- return 'password';
- }
- if (!is_null($this->issuer) && !is_null($this->signingKey)) {
- return self::JWT_URN;
- }
- if (!is_null($this->subjectTokenFetcher) && !is_null($this->subjectTokenType)) {
- return self::STS_URN;
- }
- return null;
- }
- /**
- * Sets the current grant type.
- *
- * @param string $grantType
- * @return void
- * @throws InvalidArgumentException
- */
- public function setGrantType($grantType)
- {
- if (in_array($grantType, self::$knownGrantTypes)) {
- $this->grantType = $grantType;
- } else {
- // validate URI
- if (!$this->isAbsoluteUri($grantType)) {
- throw new InvalidArgumentException('invalid grant type');
- }
- $this->grantType = (string) $grantType;
- }
- }
- /**
- * Gets an arbitrary string designed to allow the client to maintain state.
- *
- * @return string
- */
- public function getState()
- {
- return $this->state;
- }
- /**
- * Sets an arbitrary string designed to allow the client to maintain state.
- *
- * @param string $state
- * @return void
- */
- public function setState($state)
- {
- $this->state = $state;
- }
- /**
- * Gets the authorization code issued to this client.
- *
- * @return string
- */
- public function getCode()
- {
- return $this->code;
- }
- /**
- * Sets the authorization code issued to this client.
- *
- * @param string $code
- * @return void
- */
- public function setCode($code)
- {
- $this->code = $code;
- }
- /**
- * Gets the resource owner's username.
- *
- * @return string
- */
- public function getUsername()
- {
- return $this->username;
- }
- /**
- * Sets the resource owner's username.
- *
- * @param string $username
- * @return void
- */
- public function setUsername($username)
- {
- $this->username = $username;
- }
- /**
- * Gets the resource owner's password.
- *
- * @return string
- */
- public function getPassword()
- {
- return $this->password;
- }
- /**
- * Sets the resource owner's password.
- *
- * @param string $password
- * @return void
- */
- public function setPassword($password)
- {
- $this->password = $password;
- }
- /**
- * Sets a unique identifier issued to the client to identify itself to the
- * authorization server.
- *
- * @return string
- */
- public function getClientId()
- {
- return $this->clientId;
- }
- /**
- * Sets a unique identifier issued to the client to identify itself to the
- * authorization server.
- *
- * @param string $clientId
- * @return void
- */
- public function setClientId($clientId)
- {
- $this->clientId = $clientId;
- }
- /**
- * Gets a shared symmetric secret issued by the authorization server, which
- * is used to authenticate the client.
- *
- * @return string
- */
- public function getClientSecret()
- {
- return $this->clientSecret;
- }
- /**
- * Sets a shared symmetric secret issued by the authorization server, which
- * is used to authenticate the client.
- *
- * @param string $clientSecret
- * @return void
- */
- public function setClientSecret($clientSecret)
- {
- $this->clientSecret = $clientSecret;
- }
- /**
- * Gets the Issuer ID when using assertion profile.
- *
- * @return ?string
- */
- public function getIssuer()
- {
- return $this->issuer;
- }
- /**
- * Sets the Issuer ID when using assertion profile.
- *
- * @param string $issuer
- * @return void
- */
- public function setIssuer($issuer)
- {
- $this->issuer = $issuer;
- }
- /**
- * Gets the target sub when issuing assertions.
- *
- * @return ?string
- */
- public function getSub()
- {
- return $this->sub;
- }
- /**
- * Sets the target sub when issuing assertions.
- *
- * @param string $sub
- * @return void
- */
- public function setSub($sub)
- {
- $this->sub = $sub;
- }
- /**
- * Gets the target audience when issuing assertions.
- *
- * @return ?string
- */
- public function getAudience()
- {
- return $this->audience;
- }
- /**
- * Sets the target audience when issuing assertions.
- *
- * @param string $audience
- * @return void
- */
- public function setAudience($audience)
- {
- $this->audience = $audience;
- }
- /**
- * Gets the signing key when using an assertion profile.
- *
- * @return ?string
- */
- public function getSigningKey()
- {
- return $this->signingKey;
- }
- /**
- * Sets the signing key when using an assertion profile.
- *
- * @param string $signingKey
- * @return void
- */
- public function setSigningKey($signingKey)
- {
- $this->signingKey = $signingKey;
- }
- /**
- * Gets the signing key id when using an assertion profile.
- *
- * @return ?string
- */
- public function getSigningKeyId()
- {
- return $this->signingKeyId;
- }
- /**
- * Sets the signing key id when using an assertion profile.
- *
- * @param string $signingKeyId
- * @return void
- */
- public function setSigningKeyId($signingKeyId)
- {
- $this->signingKeyId = $signingKeyId;
- }
- /**
- * Gets the signing algorithm when using an assertion profile.
- *
- * @return ?string
- */
- public function getSigningAlgorithm()
- {
- return $this->signingAlgorithm;
- }
- /**
- * Sets the signing algorithm when using an assertion profile.
- *
- * @param ?string $signingAlgorithm
- * @return void
- */
- public function setSigningAlgorithm($signingAlgorithm)
- {
- if (is_null($signingAlgorithm)) {
- $this->signingAlgorithm = null;
- } elseif (!in_array($signingAlgorithm, self::$knownSigningAlgorithms)) {
- throw new InvalidArgumentException('unknown signing algorithm');
- } else {
- $this->signingAlgorithm = $signingAlgorithm;
- }
- }
- /**
- * Gets the set of parameters used by extension when using an extension
- * grant type.
- *
- * @return array
- */
- public function getExtensionParams()
- {
- return $this->extensionParams;
- }
- /**
- * Sets the set of parameters used by extension when using an extension
- * grant type.
- *
- * @param array $extensionParams
- * @return void
- */
- public function setExtensionParams($extensionParams)
- {
- $this->extensionParams = $extensionParams;
- }
- /**
- * Gets the number of seconds assertions are valid for.
- *
- * @return int
- */
- public function getExpiry()
- {
- return $this->expiry;
- }
- /**
- * Sets the number of seconds assertions are valid for.
- *
- * @param int $expiry
- * @return void
- */
- public function setExpiry($expiry)
- {
- $this->expiry = $expiry;
- }
- /**
- * Gets the lifetime of the access token in seconds.
- *
- * @return int
- */
- public function getExpiresIn()
- {
- return $this->expiresIn;
- }
- /**
- * Sets the lifetime of the access token in seconds.
- *
- * @param ?int $expiresIn
- * @return void
- */
- public function setExpiresIn($expiresIn)
- {
- if (is_null($expiresIn)) {
- $this->expiresIn = null;
- $this->issuedAt = null;
- } else {
- $this->issuedAt = time();
- $this->expiresIn = (int) $expiresIn;
- }
- }
- /**
- * Gets the time the current access token expires at.
- *
- * @return ?int
- */
- public function getExpiresAt()
- {
- if (!is_null($this->expiresAt)) {
- return $this->expiresAt;
- }
- if (!is_null($this->issuedAt) && !is_null($this->expiresIn)) {
- return $this->issuedAt + $this->expiresIn;
- }
- return null;
- }
- /**
- * Returns true if the acccess token has expired.
- *
- * @return bool
- */
- public function isExpired()
- {
- $expiration = $this->getExpiresAt();
- $now = time();
- return !is_null($expiration) && $now >= $expiration;
- }
- /**
- * Sets the time the current access token expires at.
- *
- * @param int $expiresAt
- * @return void
- */
- public function setExpiresAt($expiresAt)
- {
- $this->expiresAt = $expiresAt;
- }
- /**
- * Gets the time the current access token was issued at.
- *
- * @return ?int
- */
- public function getIssuedAt()
- {
- return $this->issuedAt;
- }
- /**
- * Sets the time the current access token was issued at.
- *
- * @param int $issuedAt
- * @return void
- */
- public function setIssuedAt($issuedAt)
- {
- $this->issuedAt = $issuedAt;
- }
- /**
- * Gets the current access token.
- *
- * @return ?string
- */
- public function getAccessToken()
- {
- return $this->accessToken;
- }
- /**
- * Sets the current access token.
- *
- * @param string $accessToken
- * @return void
- */
- public function setAccessToken($accessToken)
- {
- $this->accessToken = $accessToken;
- }
- /**
- * Gets the current ID token.
- *
- * @return ?string
- */
- public function getIdToken()
- {
- return $this->idToken;
- }
- /**
- * Sets the current ID token.
- *
- * @param string $idToken
- * @return void
- */
- public function setIdToken($idToken)
- {
- $this->idToken = $idToken;
- }
- /**
- * Get the granted space-separated scopes (if they exist) for the last
- * fetched token.
- *
- * @return string|null
- */
- public function getGrantedScope()
- {
- return $this->grantedScope;
- }
- /**
- * Sets the current ID token.
- *
- * @param string $grantedScope
- * @return void
- */
- public function setGrantedScope($grantedScope)
- {
- $this->grantedScope = $grantedScope;
- }
- /**
- * Gets the refresh token associated with the current access token.
- *
- * @return ?string
- */
- public function getRefreshToken()
- {
- return $this->refreshToken;
- }
- /**
- * Sets the refresh token associated with the current access token.
- *
- * @param string $refreshToken
- * @return void
- */
- public function setRefreshToken($refreshToken)
- {
- $this->refreshToken = $refreshToken;
- }
- /**
- * Sets additional claims to be included in the JWT token
- *
- * @param array $additionalClaims
- * @return void
- */
- public function setAdditionalClaims(array $additionalClaims)
- {
- $this->additionalClaims = $additionalClaims;
- }
- /**
- * Gets the additional claims to be included in the JWT token.
- *
- * @return array
- */
- public function getAdditionalClaims()
- {
- return $this->additionalClaims;
- }
- /**
- * Gets the additional claims to be included in the JWT token.
- *
- * @return ?string
- */
- public function getIssuedTokenType()
- {
- return $this->issuedTokenType;
- }
- /**
- * The expiration of the last received token.
- *
- * @return array|null
- */
- public function getLastReceivedToken()
- {
- if ($token = $this->getAccessToken()) {
- // the bare necessity of an auth token
- $authToken = ['access_token' => $token, 'expires_at' => $this->getExpiresAt()];
- } elseif ($idToken = $this->getIdToken()) {
- $authToken = ['id_token' => $idToken, 'expires_at' => $this->getExpiresAt()];
- } else {
- return null;
- }
- if ($expiresIn = $this->getExpiresIn()) {
- $authToken['expires_in'] = $expiresIn;
- }
- if ($issuedAt = $this->getIssuedAt()) {
- $authToken['issued_at'] = $issuedAt;
- }
- if ($refreshToken = $this->getRefreshToken()) {
- $authToken['refresh_token'] = $refreshToken;
- }
- return $authToken;
- }
- /**
- * Get the client ID.
- *
- * Alias of {@see Google\Auth\OAuth2::getClientId()}.
- *
- * @param callable $httpHandler
- * @return string
- * @access private
- */
- public function getClientName(callable $httpHandler = null)
- {
- return $this->getClientId();
- }
- /**
- * @todo handle uri as array
- *
- * @param ?string $uri
- * @return null|UriInterface
- */
- private function coerceUri($uri)
- {
- if (is_null($uri)) {
- return null;
- }
- return Utils::uriFor($uri);
- }
- /**
- * @param string $idToken
- * @param Key|Key[]|string|string[] $publicKey
- * @param string|string[] $allowedAlgs
- * @return object
- */
- private function jwtDecode($idToken, $publicKey, $allowedAlgs)
- {
- $keys = $this->getFirebaseJwtKeys($publicKey, $allowedAlgs);
- // Default exception if none are caught. We are using the same exception
- // class and message from firebase/php-jwt to preserve backwards
- // compatibility.
- $e = new \InvalidArgumentException('Key may not be empty');
- foreach ($keys as $key) {
- try {
- return JWT::decode($idToken, $key);
- } catch (\Exception $e) {
- // try next alg
- }
- }
- throw $e;
- }
- /**
- * @param Key|Key[]|string|string[] $publicKey
- * @param string|string[] $allowedAlgs
- * @return Key[]
- */
- private function getFirebaseJwtKeys($publicKey, $allowedAlgs)
- {
- // If $publicKey is instance of Key, return it
- if ($publicKey instanceof Key) {
- return [$publicKey];
- }
- // If $allowedAlgs is empty, $publicKey must be Key or Key[].
- if (empty($allowedAlgs)) {
- $keys = [];
- foreach ((array) $publicKey as $kid => $pubKey) {
- if (!$pubKey instanceof Key) {
- throw new \InvalidArgumentException(sprintf('When allowed algorithms is empty, the public key must' . 'be an instance of %s or an array of %s objects', Key::class, Key::class));
- }
- $keys[$kid] = $pubKey;
- }
- return $keys;
- }
- $allowedAlg = null;
- if (is_string($allowedAlgs)) {
- $allowedAlg = $allowedAlgs;
- } elseif (is_array($allowedAlgs)) {
- if (count($allowedAlgs) > 1) {
- throw new \InvalidArgumentException('To have multiple allowed algorithms, You must provide an' . ' array of Firebase\\JWT\\Key objects.' . ' See https://github.com/firebase/php-jwt for more information.');
- }
- $allowedAlg = array_pop($allowedAlgs);
- } else {
- throw new \InvalidArgumentException('allowed algorithms must be a string or array.');
- }
- if (is_array($publicKey)) {
- // When publicKey is greater than 1, create keys with the single alg.
- $keys = [];
- foreach ($publicKey as $kid => $pubKey) {
- if ($pubKey instanceof Key) {
- $keys[$kid] = $pubKey;
- } else {
- $keys[$kid] = new Key($pubKey, $allowedAlg);
- }
- }
- return $keys;
- }
- return [new Key($publicKey, $allowedAlg)];
- }
- /**
- * Determines if the URI is absolute based on its scheme and host or path
- * (RFC 3986).
- *
- * @param string $uri
- * @return bool
- */
- private function isAbsoluteUri($uri)
- {
- $uri = $this->coerceUri($uri);
- return $uri->getScheme() && ($uri->getHost() || $uri->getPath());
- }
- /**
- * @param array $params
- * @return array
- */
- private function addClientCredentials(&$params)
- {
- $clientId = $this->getClientId();
- $clientSecret = $this->getClientSecret();
- if ($clientId && $clientSecret) {
- $params['client_id'] = $clientId;
- $params['client_secret'] = $clientSecret;
- }
- return $params;
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/ProjectIdProviderInterface.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/ProjectIdProviderInterface.php
deleted file mode 100644
index a430786..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/ProjectIdProviderInterface.php
+++ /dev/null
@@ -1,32 +0,0 @@
-auth->getSigningKey();
- $signedString = '';
- if (class_exists('\\phpseclib\\Crypt\\RSA') && !$forceOpenssl) {
- $rsa = new RSA();
- $rsa->loadKey($privateKey);
- $rsa->setSignatureMode(RSA::SIGNATURE_PKCS1);
- $rsa->setHash('sha256');
- $signedString = $rsa->sign($stringToSign);
- } elseif (extension_loaded('openssl')) {
- openssl_sign($stringToSign, $signedString, $privateKey, 'sha256WithRSAEncryption');
- } else {
- // @codeCoverageIgnoreStart
- throw new \RuntimeException('OpenSSL is not installed.');
- }
- // @codeCoverageIgnoreEnd
- return base64_encode($signedString);
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/SignBlobInterface.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/SignBlobInterface.php
deleted file mode 100644
index 9209f1c..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/SignBlobInterface.php
+++ /dev/null
@@ -1,43 +0,0 @@
- $metadata metadata hashmap
- * @param string $authUri optional auth uri
- * @param callable $httpHandler callback which delivers psr7 request
- * @return array updated metadata hashmap
- */
- public function updateMetadata($metadata, $authUri = null, callable $httpHandler = null);
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/UpdateMetadataTrait.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/UpdateMetadataTrait.php
deleted file mode 100644
index a63a51f..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/google/auth/src/UpdateMetadataTrait.php
+++ /dev/null
@@ -1,62 +0,0 @@
- $metadata metadata hashmap
- * @param string $authUri optional auth uri
- * @param callable $httpHandler callback which delivers psr7 request
- * @return array updated metadata hashmap
- */
- public function updateMetadata($metadata, $authUri = null, callable $httpHandler = null)
- {
- if (isset($metadata[self::AUTH_METADATA_KEY])) {
- // Auth metadata has already been set
- return $metadata;
- }
- $result = $this->fetchAuthToken($httpHandler);
- $metadata_copy = $metadata;
- if (isset($result['access_token'])) {
- $metadata_copy[self::AUTH_METADATA_KEY] = ['Bearer ' . $result['access_token']];
- } elseif (isset($result['id_token'])) {
- $metadata_copy[self::AUTH_METADATA_KEY] = ['Bearer ' . $result['id_token']];
- }
- return $metadata_copy;
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/guzzle/LICENSE b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/guzzle/LICENSE
deleted file mode 100644
index fd2375d..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/guzzle/LICENSE
+++ /dev/null
@@ -1,27 +0,0 @@
-The MIT License (MIT)
-
-Copyright (c) 2011 Michael Dowling
-Copyright (c) 2012 Jeremy Lindblom
-Copyright (c) 2014 Graham Campbell
-Copyright (c) 2015 Márk Sági-Kazár
-Copyright (c) 2015 Tobias Schultze
-Copyright (c) 2016 Tobias Nyholm
-Copyright (c) 2016 George Mponos
-
-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/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/guzzle/src/BodySummarizer.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/guzzle/src/BodySummarizer.php
deleted file mode 100644
index 6792b70..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/guzzle/src/BodySummarizer.php
+++ /dev/null
@@ -1,23 +0,0 @@
-truncateAt = $truncateAt;
- }
- /**
- * Returns a summarized message body.
- */
- public function summarize(MessageInterface $message) : ?string
- {
- return $this->truncateAt === null ? \Matomo\Dependencies\SearchEngineKeywordsPerformance\GuzzleHttp\Psr7\Message::bodySummary($message) : \Matomo\Dependencies\SearchEngineKeywordsPerformance\GuzzleHttp\Psr7\Message::bodySummary($message, $this->truncateAt);
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/guzzle/src/BodySummarizerInterface.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/guzzle/src/BodySummarizerInterface.php
deleted file mode 100644
index 7f4ff59..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/guzzle/src/BodySummarizerInterface.php
+++ /dev/null
@@ -1,12 +0,0 @@
- 'http://www.foo.com/1.0/',
- * 'timeout' => 0,
- * 'allow_redirects' => false,
- * 'proxy' => '192.168.16.1:10'
- * ]);
- *
- * Client configuration settings include the following options:
- *
- * - handler: (callable) Function that transfers HTTP requests over the
- * wire. The function is called with a Psr7\Http\Message\RequestInterface
- * and array of transfer options, and must return a
- * GuzzleHttp\Promise\PromiseInterface that is fulfilled with a
- * Psr7\Http\Message\ResponseInterface on success.
- * If no handler is provided, a default handler will be created
- * that enables all of the request options below by attaching all of the
- * default middleware to the handler.
- * - base_uri: (string|UriInterface) Base URI of the client that is merged
- * into relative URIs. Can be a string or instance of UriInterface.
- * - **: any request option
- *
- * @param array $config Client configuration settings.
- *
- * @see \GuzzleHttp\RequestOptions for a list of available request options.
- */
- public function __construct(array $config = [])
- {
- if (!isset($config['handler'])) {
- $config['handler'] = HandlerStack::create();
- } elseif (!\is_callable($config['handler'])) {
- throw new InvalidArgumentException('handler must be a callable');
- }
- // Convert the base_uri to a UriInterface
- if (isset($config['base_uri'])) {
- $config['base_uri'] = Psr7\Utils::uriFor($config['base_uri']);
- }
- $this->configureDefaults($config);
- }
- /**
- * @param string $method
- * @param array $args
- *
- * @return PromiseInterface|ResponseInterface
- *
- * @deprecated Client::__call will be removed in guzzlehttp/guzzle:8.0.
- */
- public function __call($method, $args)
- {
- if (\count($args) < 1) {
- throw new InvalidArgumentException('Magic request methods require a URI and optional options array');
- }
- $uri = $args[0];
- $opts = $args[1] ?? [];
- return \substr($method, -5) === 'Async' ? $this->requestAsync(\substr($method, 0, -5), $uri, $opts) : $this->request($method, $uri, $opts);
- }
- /**
- * Asynchronously send an HTTP request.
- *
- * @param array $options Request options to apply to the given
- * request and to the transfer. See \GuzzleHttp\RequestOptions.
- */
- public function sendAsync(RequestInterface $request, array $options = []) : PromiseInterface
- {
- // Merge the base URI into the request URI if needed.
- $options = $this->prepareDefaults($options);
- return $this->transfer($request->withUri($this->buildUri($request->getUri(), $options), $request->hasHeader('Host')), $options);
- }
- /**
- * Send an HTTP request.
- *
- * @param array $options Request options to apply to the given
- * request and to the transfer. See \GuzzleHttp\RequestOptions.
- *
- * @throws GuzzleException
- */
- public function send(RequestInterface $request, array $options = []) : ResponseInterface
- {
- $options[RequestOptions::SYNCHRONOUS] = \true;
- return $this->sendAsync($request, $options)->wait();
- }
- /**
- * The HttpClient PSR (PSR-18) specify this method.
- *
- * {@inheritDoc}
- */
- public function sendRequest(RequestInterface $request) : ResponseInterface
- {
- $options[RequestOptions::SYNCHRONOUS] = \true;
- $options[RequestOptions::ALLOW_REDIRECTS] = \false;
- $options[RequestOptions::HTTP_ERRORS] = \false;
- return $this->sendAsync($request, $options)->wait();
- }
- /**
- * Create and send an asynchronous HTTP request.
- *
- * Use an absolute path to override the base path of the client, or a
- * relative path to append to the base path of the client. The URL can
- * contain the query string as well. Use an array to provide a URL
- * template and additional variables to use in the URL template expansion.
- *
- * @param string $method HTTP method
- * @param string|UriInterface $uri URI object or string.
- * @param array $options Request options to apply. See \GuzzleHttp\RequestOptions.
- */
- public function requestAsync(string $method, $uri = '', array $options = []) : PromiseInterface
- {
- $options = $this->prepareDefaults($options);
- // Remove request modifying parameter because it can be done up-front.
- $headers = $options['headers'] ?? [];
- $body = $options['body'] ?? null;
- $version = $options['version'] ?? '1.1';
- // Merge the URI into the base URI.
- $uri = $this->buildUri(Psr7\Utils::uriFor($uri), $options);
- if (\is_array($body)) {
- throw $this->invalidBody();
- }
- $request = new Psr7\Request($method, $uri, $headers, $body, $version);
- // Remove the option so that they are not doubly-applied.
- unset($options['headers'], $options['body'], $options['version']);
- return $this->transfer($request, $options);
- }
- /**
- * Create and send an HTTP request.
- *
- * Use an absolute path to override the base path of the client, or a
- * relative path to append to the base path of the client. The URL can
- * contain the query string as well.
- *
- * @param string $method HTTP method.
- * @param string|UriInterface $uri URI object or string.
- * @param array $options Request options to apply. See \GuzzleHttp\RequestOptions.
- *
- * @throws GuzzleException
- */
- public function request(string $method, $uri = '', array $options = []) : ResponseInterface
- {
- $options[RequestOptions::SYNCHRONOUS] = \true;
- return $this->requestAsync($method, $uri, $options)->wait();
- }
- /**
- * Get a client configuration option.
- *
- * These options include default request options of the client, a "handler"
- * (if utilized by the concrete client), and a "base_uri" if utilized by
- * the concrete client.
- *
- * @param string|null $option The config option to retrieve.
- *
- * @return mixed
- *
- * @deprecated Client::getConfig will be removed in guzzlehttp/guzzle:8.0.
- */
- public function getConfig(string $option = null)
- {
- return $option === null ? $this->config : $this->config[$option] ?? null;
- }
- private function buildUri(UriInterface $uri, array $config) : UriInterface
- {
- if (isset($config['base_uri'])) {
- $uri = Psr7\UriResolver::resolve(Psr7\Utils::uriFor($config['base_uri']), $uri);
- }
- if (isset($config['idn_conversion']) && $config['idn_conversion'] !== \false) {
- $idnOptions = $config['idn_conversion'] === \true ? \IDNA_DEFAULT : $config['idn_conversion'];
- $uri = Utils::idnUriConvert($uri, $idnOptions);
- }
- return $uri->getScheme() === '' && $uri->getHost() !== '' ? $uri->withScheme('http') : $uri;
- }
- /**
- * Configures the default options for a client.
- */
- private function configureDefaults(array $config) : void
- {
- $defaults = ['allow_redirects' => RedirectMiddleware::$defaultSettings, 'http_errors' => \true, 'decode_content' => \true, 'verify' => \true, 'cookies' => \false, 'idn_conversion' => \false];
- // Use the standard Linux HTTP_PROXY and HTTPS_PROXY if set.
- // We can only trust the HTTP_PROXY environment variable in a CLI
- // process due to the fact that PHP has no reliable mechanism to
- // get environment variables that start with "HTTP_".
- if (\PHP_SAPI === 'cli' && ($proxy = Utils::getenv('HTTP_PROXY'))) {
- $defaults['proxy']['http'] = $proxy;
- }
- if ($proxy = Utils::getenv('HTTPS_PROXY')) {
- $defaults['proxy']['https'] = $proxy;
- }
- if ($noProxy = Utils::getenv('NO_PROXY')) {
- $cleanedNoProxy = \str_replace(' ', '', $noProxy);
- $defaults['proxy']['no'] = \explode(',', $cleanedNoProxy);
- }
- $this->config = $config + $defaults;
- if (!empty($config['cookies']) && $config['cookies'] === \true) {
- $this->config['cookies'] = new CookieJar();
- }
- // Add the default user-agent header.
- if (!isset($this->config['headers'])) {
- $this->config['headers'] = ['User-Agent' => Utils::defaultUserAgent()];
- } else {
- // Add the User-Agent header if one was not already set.
- foreach (\array_keys($this->config['headers']) as $name) {
- if (\strtolower($name) === 'user-agent') {
- return;
- }
- }
- $this->config['headers']['User-Agent'] = Utils::defaultUserAgent();
- }
- }
- /**
- * Merges default options into the array.
- *
- * @param array $options Options to modify by reference
- */
- private function prepareDefaults(array $options) : array
- {
- $defaults = $this->config;
- if (!empty($defaults['headers'])) {
- // Default headers are only added if they are not present.
- $defaults['_conditional'] = $defaults['headers'];
- unset($defaults['headers']);
- }
- // Special handling for headers is required as they are added as
- // conditional headers and as headers passed to a request ctor.
- if (\array_key_exists('headers', $options)) {
- // Allows default headers to be unset.
- if ($options['headers'] === null) {
- $defaults['_conditional'] = [];
- unset($options['headers']);
- } elseif (!\is_array($options['headers'])) {
- throw new InvalidArgumentException('headers must be an array');
- }
- }
- // Shallow merge defaults underneath options.
- $result = $options + $defaults;
- // Remove null values.
- foreach ($result as $k => $v) {
- if ($v === null) {
- unset($result[$k]);
- }
- }
- return $result;
- }
- /**
- * Transfers the given request and applies request options.
- *
- * The URI of the request is not modified and the request options are used
- * as-is without merging in default options.
- *
- * @param array $options See \GuzzleHttp\RequestOptions.
- */
- private function transfer(RequestInterface $request, array $options) : PromiseInterface
- {
- $request = $this->applyOptions($request, $options);
- /** @var HandlerStack $handler */
- $handler = $options['handler'];
- try {
- return P\Create::promiseFor($handler($request, $options));
- } catch (\Exception $e) {
- return P\Create::rejectionFor($e);
- }
- }
- /**
- * Applies the array of request options to a request.
- */
- private function applyOptions(RequestInterface $request, array &$options) : RequestInterface
- {
- $modify = ['set_headers' => []];
- if (isset($options['headers'])) {
- if (array_keys($options['headers']) === range(0, count($options['headers']) - 1)) {
- throw new InvalidArgumentException('The headers array must have header name as keys.');
- }
- $modify['set_headers'] = $options['headers'];
- unset($options['headers']);
- }
- if (isset($options['form_params'])) {
- if (isset($options['multipart'])) {
- throw new InvalidArgumentException('You cannot use ' . 'form_params and multipart at the same time. Use the ' . 'form_params option if you want to send application/' . 'x-www-form-urlencoded requests, and the multipart ' . 'option to send multipart/form-data requests.');
- }
- $options['body'] = \http_build_query($options['form_params'], '', '&');
- unset($options['form_params']);
- // Ensure that we don't have the header in different case and set the new value.
- $options['_conditional'] = Psr7\Utils::caselessRemove(['Content-Type'], $options['_conditional']);
- $options['_conditional']['Content-Type'] = 'application/x-www-form-urlencoded';
- }
- if (isset($options['multipart'])) {
- $options['body'] = new Psr7\MultipartStream($options['multipart']);
- unset($options['multipart']);
- }
- if (isset($options['json'])) {
- $options['body'] = Utils::jsonEncode($options['json']);
- unset($options['json']);
- // Ensure that we don't have the header in different case and set the new value.
- $options['_conditional'] = Psr7\Utils::caselessRemove(['Content-Type'], $options['_conditional']);
- $options['_conditional']['Content-Type'] = 'application/json';
- }
- if (!empty($options['decode_content']) && $options['decode_content'] !== \true) {
- // Ensure that we don't have the header in different case and set the new value.
- $options['_conditional'] = Psr7\Utils::caselessRemove(['Accept-Encoding'], $options['_conditional']);
- $modify['set_headers']['Accept-Encoding'] = $options['decode_content'];
- }
- if (isset($options['body'])) {
- if (\is_array($options['body'])) {
- throw $this->invalidBody();
- }
- $modify['body'] = Psr7\Utils::streamFor($options['body']);
- unset($options['body']);
- }
- if (!empty($options['auth']) && \is_array($options['auth'])) {
- $value = $options['auth'];
- $type = isset($value[2]) ? \strtolower($value[2]) : 'basic';
- switch ($type) {
- case 'basic':
- // Ensure that we don't have the header in different case and set the new value.
- $modify['set_headers'] = Psr7\Utils::caselessRemove(['Authorization'], $modify['set_headers']);
- $modify['set_headers']['Authorization'] = 'Basic ' . \base64_encode("{$value[0]}:{$value[1]}");
- break;
- case 'digest':
- // @todo: Do not rely on curl
- $options['curl'][\CURLOPT_HTTPAUTH] = \CURLAUTH_DIGEST;
- $options['curl'][\CURLOPT_USERPWD] = "{$value[0]}:{$value[1]}";
- break;
- case 'ntlm':
- $options['curl'][\CURLOPT_HTTPAUTH] = \CURLAUTH_NTLM;
- $options['curl'][\CURLOPT_USERPWD] = "{$value[0]}:{$value[1]}";
- break;
- }
- }
- if (isset($options['query'])) {
- $value = $options['query'];
- if (\is_array($value)) {
- $value = \http_build_query($value, '', '&', \PHP_QUERY_RFC3986);
- }
- if (!\is_string($value)) {
- throw new InvalidArgumentException('query must be a string or array');
- }
- $modify['query'] = $value;
- unset($options['query']);
- }
- // Ensure that sink is not an invalid value.
- if (isset($options['sink'])) {
- // TODO: Add more sink validation?
- if (\is_bool($options['sink'])) {
- throw new InvalidArgumentException('sink must not be a boolean');
- }
- }
- if (isset($options['version'])) {
- $modify['version'] = $options['version'];
- }
- $request = Psr7\Utils::modifyRequest($request, $modify);
- if ($request->getBody() instanceof Psr7\MultipartStream) {
- // Use a multipart/form-data POST if a Content-Type is not set.
- // Ensure that we don't have the header in different case and set the new value.
- $options['_conditional'] = Psr7\Utils::caselessRemove(['Content-Type'], $options['_conditional']);
- $options['_conditional']['Content-Type'] = 'multipart/form-data; boundary=' . $request->getBody()->getBoundary();
- }
- // Merge in conditional headers if they are not present.
- if (isset($options['_conditional'])) {
- // Build up the changes so it's in a single clone of the message.
- $modify = [];
- foreach ($options['_conditional'] as $k => $v) {
- if (!$request->hasHeader($k)) {
- $modify['set_headers'][$k] = $v;
- }
- }
- $request = Psr7\Utils::modifyRequest($request, $modify);
- // Don't pass this internal value along to middleware/handlers.
- unset($options['_conditional']);
- }
- return $request;
- }
- /**
- * Return an InvalidArgumentException with pre-set message.
- */
- private function invalidBody() : InvalidArgumentException
- {
- return new InvalidArgumentException('Passing in the "body" request ' . 'option as an array to send a request is not supported. ' . 'Please use the "form_params" request option to send a ' . 'application/x-www-form-urlencoded request, or the "multipart" ' . 'request option to send a multipart/form-data request.');
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/guzzle/src/ClientInterface.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/guzzle/src/ClientInterface.php
deleted file mode 100644
index 217672e..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/guzzle/src/ClientInterface.php
+++ /dev/null
@@ -1,78 +0,0 @@
-request('GET', $uri, $options);
- }
- /**
- * Create and send an HTTP HEAD request.
- *
- * Use an absolute path to override the base path of the client, or a
- * relative path to append to the base path of the client. The URL can
- * contain the query string as well.
- *
- * @param string|UriInterface $uri URI object or string.
- * @param array $options Request options to apply.
- *
- * @throws GuzzleException
- */
- public function head($uri, array $options = []) : ResponseInterface
- {
- return $this->request('HEAD', $uri, $options);
- }
- /**
- * Create and send an HTTP PUT request.
- *
- * Use an absolute path to override the base path of the client, or a
- * relative path to append to the base path of the client. The URL can
- * contain the query string as well.
- *
- * @param string|UriInterface $uri URI object or string.
- * @param array $options Request options to apply.
- *
- * @throws GuzzleException
- */
- public function put($uri, array $options = []) : ResponseInterface
- {
- return $this->request('PUT', $uri, $options);
- }
- /**
- * Create and send an HTTP POST request.
- *
- * Use an absolute path to override the base path of the client, or a
- * relative path to append to the base path of the client. The URL can
- * contain the query string as well.
- *
- * @param string|UriInterface $uri URI object or string.
- * @param array $options Request options to apply.
- *
- * @throws GuzzleException
- */
- public function post($uri, array $options = []) : ResponseInterface
- {
- return $this->request('POST', $uri, $options);
- }
- /**
- * Create and send an HTTP PATCH request.
- *
- * Use an absolute path to override the base path of the client, or a
- * relative path to append to the base path of the client. The URL can
- * contain the query string as well.
- *
- * @param string|UriInterface $uri URI object or string.
- * @param array $options Request options to apply.
- *
- * @throws GuzzleException
- */
- public function patch($uri, array $options = []) : ResponseInterface
- {
- return $this->request('PATCH', $uri, $options);
- }
- /**
- * Create and send an HTTP DELETE request.
- *
- * Use an absolute path to override the base path of the client, or a
- * relative path to append to the base path of the client. The URL can
- * contain the query string as well.
- *
- * @param string|UriInterface $uri URI object or string.
- * @param array $options Request options to apply.
- *
- * @throws GuzzleException
- */
- public function delete($uri, array $options = []) : ResponseInterface
- {
- return $this->request('DELETE', $uri, $options);
- }
- /**
- * Create and send an asynchronous HTTP request.
- *
- * Use an absolute path to override the base path of the client, or a
- * relative path to append to the base path of the client. The URL can
- * contain the query string as well. Use an array to provide a URL
- * template and additional variables to use in the URL template expansion.
- *
- * @param string $method HTTP method
- * @param string|UriInterface $uri URI object or string.
- * @param array $options Request options to apply.
- */
- public abstract function requestAsync(string $method, $uri, array $options = []) : PromiseInterface;
- /**
- * Create and send an asynchronous HTTP GET request.
- *
- * Use an absolute path to override the base path of the client, or a
- * relative path to append to the base path of the client. The URL can
- * contain the query string as well. Use an array to provide a URL
- * template and additional variables to use in the URL template expansion.
- *
- * @param string|UriInterface $uri URI object or string.
- * @param array $options Request options to apply.
- */
- public function getAsync($uri, array $options = []) : PromiseInterface
- {
- return $this->requestAsync('GET', $uri, $options);
- }
- /**
- * Create and send an asynchronous HTTP HEAD request.
- *
- * Use an absolute path to override the base path of the client, or a
- * relative path to append to the base path of the client. The URL can
- * contain the query string as well. Use an array to provide a URL
- * template and additional variables to use in the URL template expansion.
- *
- * @param string|UriInterface $uri URI object or string.
- * @param array $options Request options to apply.
- */
- public function headAsync($uri, array $options = []) : PromiseInterface
- {
- return $this->requestAsync('HEAD', $uri, $options);
- }
- /**
- * Create and send an asynchronous HTTP PUT request.
- *
- * Use an absolute path to override the base path of the client, or a
- * relative path to append to the base path of the client. The URL can
- * contain the query string as well. Use an array to provide a URL
- * template and additional variables to use in the URL template expansion.
- *
- * @param string|UriInterface $uri URI object or string.
- * @param array $options Request options to apply.
- */
- public function putAsync($uri, array $options = []) : PromiseInterface
- {
- return $this->requestAsync('PUT', $uri, $options);
- }
- /**
- * Create and send an asynchronous HTTP POST request.
- *
- * Use an absolute path to override the base path of the client, or a
- * relative path to append to the base path of the client. The URL can
- * contain the query string as well. Use an array to provide a URL
- * template and additional variables to use in the URL template expansion.
- *
- * @param string|UriInterface $uri URI object or string.
- * @param array $options Request options to apply.
- */
- public function postAsync($uri, array $options = []) : PromiseInterface
- {
- return $this->requestAsync('POST', $uri, $options);
- }
- /**
- * Create and send an asynchronous HTTP PATCH request.
- *
- * Use an absolute path to override the base path of the client, or a
- * relative path to append to the base path of the client. The URL can
- * contain the query string as well. Use an array to provide a URL
- * template and additional variables to use in the URL template expansion.
- *
- * @param string|UriInterface $uri URI object or string.
- * @param array $options Request options to apply.
- */
- public function patchAsync($uri, array $options = []) : PromiseInterface
- {
- return $this->requestAsync('PATCH', $uri, $options);
- }
- /**
- * Create and send an asynchronous HTTP DELETE request.
- *
- * Use an absolute path to override the base path of the client, or a
- * relative path to append to the base path of the client. The URL can
- * contain the query string as well. Use an array to provide a URL
- * template and additional variables to use in the URL template expansion.
- *
- * @param string|UriInterface $uri URI object or string.
- * @param array $options Request options to apply.
- */
- public function deleteAsync($uri, array $options = []) : PromiseInterface
- {
- return $this->requestAsync('DELETE', $uri, $options);
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/guzzle/src/Cookie/CookieJar.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/guzzle/src/Cookie/CookieJar.php
deleted file mode 100644
index e212e48..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/guzzle/src/Cookie/CookieJar.php
+++ /dev/null
@@ -1,240 +0,0 @@
-strictMode = $strictMode;
- foreach ($cookieArray as $cookie) {
- if (!$cookie instanceof SetCookie) {
- $cookie = new SetCookie($cookie);
- }
- $this->setCookie($cookie);
- }
- }
- /**
- * Create a new Cookie jar from an associative array and domain.
- *
- * @param array $cookies Cookies to create the jar from
- * @param string $domain Domain to set the cookies to
- */
- public static function fromArray(array $cookies, string $domain) : self
- {
- $cookieJar = new self();
- foreach ($cookies as $name => $value) {
- $cookieJar->setCookie(new SetCookie(['Domain' => $domain, 'Name' => $name, 'Value' => $value, 'Discard' => \true]));
- }
- return $cookieJar;
- }
- /**
- * Evaluate if this cookie should be persisted to storage
- * that survives between requests.
- *
- * @param SetCookie $cookie Being evaluated.
- * @param bool $allowSessionCookies If we should persist session cookies
- */
- public static function shouldPersist(SetCookie $cookie, bool $allowSessionCookies = \false) : bool
- {
- if ($cookie->getExpires() || $allowSessionCookies) {
- if (!$cookie->getDiscard()) {
- return \true;
- }
- }
- return \false;
- }
- /**
- * Finds and returns the cookie based on the name
- *
- * @param string $name cookie name to search for
- *
- * @return SetCookie|null cookie that was found or null if not found
- */
- public function getCookieByName(string $name) : ?SetCookie
- {
- foreach ($this->cookies as $cookie) {
- if ($cookie->getName() !== null && \strcasecmp($cookie->getName(), $name) === 0) {
- return $cookie;
- }
- }
- return null;
- }
- public function toArray() : array
- {
- return \array_map(static function (SetCookie $cookie) : array {
- return $cookie->toArray();
- }, $this->getIterator()->getArrayCopy());
- }
- public function clear(string $domain = null, string $path = null, string $name = null) : void
- {
- if (!$domain) {
- $this->cookies = [];
- return;
- } elseif (!$path) {
- $this->cookies = \array_filter($this->cookies, static function (SetCookie $cookie) use($domain) : bool {
- return !$cookie->matchesDomain($domain);
- });
- } elseif (!$name) {
- $this->cookies = \array_filter($this->cookies, static function (SetCookie $cookie) use($path, $domain) : bool {
- return !($cookie->matchesPath($path) && $cookie->matchesDomain($domain));
- });
- } else {
- $this->cookies = \array_filter($this->cookies, static function (SetCookie $cookie) use($path, $domain, $name) {
- return !($cookie->getName() == $name && $cookie->matchesPath($path) && $cookie->matchesDomain($domain));
- });
- }
- }
- public function clearSessionCookies() : void
- {
- $this->cookies = \array_filter($this->cookies, static function (SetCookie $cookie) : bool {
- return !$cookie->getDiscard() && $cookie->getExpires();
- });
- }
- public function setCookie(SetCookie $cookie) : bool
- {
- // If the name string is empty (but not 0), ignore the set-cookie
- // string entirely.
- $name = $cookie->getName();
- if (!$name && $name !== '0') {
- return \false;
- }
- // Only allow cookies with set and valid domain, name, value
- $result = $cookie->validate();
- if ($result !== \true) {
- if ($this->strictMode) {
- throw new \RuntimeException('Invalid cookie: ' . $result);
- }
- $this->removeCookieIfEmpty($cookie);
- return \false;
- }
- // Resolve conflicts with previously set cookies
- foreach ($this->cookies as $i => $c) {
- // Two cookies are identical, when their path, and domain are
- // identical.
- if ($c->getPath() != $cookie->getPath() || $c->getDomain() != $cookie->getDomain() || $c->getName() != $cookie->getName()) {
- continue;
- }
- // The previously set cookie is a discard cookie and this one is
- // not so allow the new cookie to be set
- if (!$cookie->getDiscard() && $c->getDiscard()) {
- unset($this->cookies[$i]);
- continue;
- }
- // If the new cookie's expiration is further into the future, then
- // replace the old cookie
- if ($cookie->getExpires() > $c->getExpires()) {
- unset($this->cookies[$i]);
- continue;
- }
- // If the value has changed, we better change it
- if ($cookie->getValue() !== $c->getValue()) {
- unset($this->cookies[$i]);
- continue;
- }
- // The cookie exists, so no need to continue
- return \false;
- }
- $this->cookies[] = $cookie;
- return \true;
- }
- public function count() : int
- {
- return \count($this->cookies);
- }
- /**
- * @return \ArrayIterator
- */
- public function getIterator() : \ArrayIterator
- {
- return new \ArrayIterator(\array_values($this->cookies));
- }
- public function extractCookies(RequestInterface $request, ResponseInterface $response) : void
- {
- if ($cookieHeader = $response->getHeader('Set-Cookie')) {
- foreach ($cookieHeader as $cookie) {
- $sc = SetCookie::fromString($cookie);
- if (!$sc->getDomain()) {
- $sc->setDomain($request->getUri()->getHost());
- }
- if (0 !== \strpos($sc->getPath(), '/')) {
- $sc->setPath($this->getCookiePathFromRequest($request));
- }
- if (!$sc->matchesDomain($request->getUri()->getHost())) {
- continue;
- }
- // Note: At this point `$sc->getDomain()` being a public suffix should
- // be rejected, but we don't want to pull in the full PSL dependency.
- $this->setCookie($sc);
- }
- }
- }
- /**
- * Computes cookie path following RFC 6265 section 5.1.4
- *
- * @see https://datatracker.ietf.org/doc/html/rfc6265#section-5.1.4
- */
- private function getCookiePathFromRequest(RequestInterface $request) : string
- {
- $uriPath = $request->getUri()->getPath();
- if ('' === $uriPath) {
- return '/';
- }
- if (0 !== \strpos($uriPath, '/')) {
- return '/';
- }
- if ('/' === $uriPath) {
- return '/';
- }
- $lastSlashPos = \strrpos($uriPath, '/');
- if (0 === $lastSlashPos || \false === $lastSlashPos) {
- return '/';
- }
- return \substr($uriPath, 0, $lastSlashPos);
- }
- public function withCookieHeader(RequestInterface $request) : RequestInterface
- {
- $values = [];
- $uri = $request->getUri();
- $scheme = $uri->getScheme();
- $host = $uri->getHost();
- $path = $uri->getPath() ?: '/';
- foreach ($this->cookies as $cookie) {
- if ($cookie->matchesPath($path) && $cookie->matchesDomain($host) && !$cookie->isExpired() && (!$cookie->getSecure() || $scheme === 'https')) {
- $values[] = $cookie->getName() . '=' . $cookie->getValue();
- }
- }
- return $values ? $request->withHeader('Cookie', \implode('; ', $values)) : $request;
- }
- /**
- * If a cookie already exists and the server asks to set it again with a
- * null value, the cookie must be deleted.
- */
- private function removeCookieIfEmpty(SetCookie $cookie) : void
- {
- $cookieValue = $cookie->getValue();
- if ($cookieValue === null || $cookieValue === '') {
- $this->clear($cookie->getDomain(), $cookie->getPath(), $cookie->getName());
- }
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/guzzle/src/Cookie/CookieJarInterface.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/guzzle/src/Cookie/CookieJarInterface.php
deleted file mode 100644
index 977b7cb..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/guzzle/src/Cookie/CookieJarInterface.php
+++ /dev/null
@@ -1,74 +0,0 @@
-
- */
-interface CookieJarInterface extends \Countable, \IteratorAggregate
-{
- /**
- * Create a request with added cookie headers.
- *
- * If no matching cookies are found in the cookie jar, then no Cookie
- * header is added to the request and the same request is returned.
- *
- * @param RequestInterface $request Request object to modify.
- *
- * @return RequestInterface returns the modified request.
- */
- public function withCookieHeader(RequestInterface $request) : RequestInterface;
- /**
- * Extract cookies from an HTTP response and store them in the CookieJar.
- *
- * @param RequestInterface $request Request that was sent
- * @param ResponseInterface $response Response that was received
- */
- public function extractCookies(RequestInterface $request, ResponseInterface $response) : void;
- /**
- * Sets a cookie in the cookie jar.
- *
- * @param SetCookie $cookie Cookie to set.
- *
- * @return bool Returns true on success or false on failure
- */
- public function setCookie(SetCookie $cookie) : bool;
- /**
- * Remove cookies currently held in the cookie jar.
- *
- * Invoking this method without arguments will empty the whole cookie jar.
- * If given a $domain argument only cookies belonging to that domain will
- * be removed. If given a $domain and $path argument, cookies belonging to
- * the specified path within that domain are removed. If given all three
- * arguments, then the cookie with the specified name, path and domain is
- * removed.
- *
- * @param string|null $domain Clears cookies matching a domain
- * @param string|null $path Clears cookies matching a domain and path
- * @param string|null $name Clears cookies matching a domain, path, and name
- */
- public function clear(string $domain = null, string $path = null, string $name = null) : void;
- /**
- * Discard all sessions cookies.
- *
- * Removes cookies that don't have an expire field or a have a discard
- * field set to true. To be called when the user agent shuts down according
- * to RFC 2965.
- */
- public function clearSessionCookies() : void;
- /**
- * Converts the cookie jar to an array.
- */
- public function toArray() : array;
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/guzzle/src/Cookie/FileCookieJar.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/guzzle/src/Cookie/FileCookieJar.php
deleted file mode 100644
index fea38c2..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/guzzle/src/Cookie/FileCookieJar.php
+++ /dev/null
@@ -1,92 +0,0 @@
-filename = $cookieFile;
- $this->storeSessionCookies = $storeSessionCookies;
- if (\file_exists($cookieFile)) {
- $this->load($cookieFile);
- }
- }
- /**
- * Saves the file when shutting down
- */
- public function __destruct()
- {
- $this->save($this->filename);
- }
- /**
- * Saves the cookies to a file.
- *
- * @param string $filename File to save
- *
- * @throws \RuntimeException if the file cannot be found or created
- */
- public function save(string $filename) : void
- {
- $json = [];
- /** @var SetCookie $cookie */
- foreach ($this as $cookie) {
- if (CookieJar::shouldPersist($cookie, $this->storeSessionCookies)) {
- $json[] = $cookie->toArray();
- }
- }
- $jsonStr = Utils::jsonEncode($json);
- if (\false === \file_put_contents($filename, $jsonStr, \LOCK_EX)) {
- throw new \RuntimeException("Unable to save file {$filename}");
- }
- }
- /**
- * Load cookies from a JSON formatted file.
- *
- * Old cookies are kept unless overwritten by newly loaded ones.
- *
- * @param string $filename Cookie file to load.
- *
- * @throws \RuntimeException if the file cannot be loaded.
- */
- public function load(string $filename) : void
- {
- $json = \file_get_contents($filename);
- if (\false === $json) {
- throw new \RuntimeException("Unable to load file {$filename}");
- }
- if ($json === '') {
- return;
- }
- $data = Utils::jsonDecode($json, \true);
- if (\is_array($data)) {
- foreach ($data as $cookie) {
- $this->setCookie(new SetCookie($cookie));
- }
- } elseif (\is_scalar($data) && !empty($data)) {
- throw new \RuntimeException("Invalid cookie file: {$filename}");
- }
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/guzzle/src/Cookie/SessionCookieJar.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/guzzle/src/Cookie/SessionCookieJar.php
deleted file mode 100644
index fd0510e..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/guzzle/src/Cookie/SessionCookieJar.php
+++ /dev/null
@@ -1,71 +0,0 @@
-sessionKey = $sessionKey;
- $this->storeSessionCookies = $storeSessionCookies;
- $this->load();
- }
- /**
- * Saves cookies to session when shutting down
- */
- public function __destruct()
- {
- $this->save();
- }
- /**
- * Save cookies to the client session
- */
- public function save() : void
- {
- $json = [];
- /** @var SetCookie $cookie */
- foreach ($this as $cookie) {
- if (CookieJar::shouldPersist($cookie, $this->storeSessionCookies)) {
- $json[] = $cookie->toArray();
- }
- }
- $_SESSION[$this->sessionKey] = \json_encode($json);
- }
- /**
- * Load the contents of the client session into the data array
- */
- protected function load() : void
- {
- if (!isset($_SESSION[$this->sessionKey])) {
- return;
- }
- $data = \json_decode($_SESSION[$this->sessionKey], \true);
- if (\is_array($data)) {
- foreach ($data as $cookie) {
- $this->setCookie(new SetCookie($cookie));
- }
- } elseif (\strlen($data)) {
- throw new \RuntimeException('Invalid cookie data');
- }
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/guzzle/src/Cookie/SetCookie.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/guzzle/src/Cookie/SetCookie.php
deleted file mode 100644
index be0cc0c..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/guzzle/src/Cookie/SetCookie.php
+++ /dev/null
@@ -1,407 +0,0 @@
- null, 'Value' => null, 'Domain' => null, 'Path' => '/', 'Max-Age' => null, 'Expires' => null, 'Secure' => \false, 'Discard' => \false, 'HttpOnly' => \false];
- /**
- * @var array Cookie data
- */
- private $data;
- /**
- * Create a new SetCookie object from a string.
- *
- * @param string $cookie Set-Cookie header string
- */
- public static function fromString(string $cookie) : self
- {
- // Create the default return array
- $data = self::$defaults;
- // Explode the cookie string using a series of semicolons
- $pieces = \array_filter(\array_map('trim', \explode(';', $cookie)));
- // The name of the cookie (first kvp) must exist and include an equal sign.
- if (!isset($pieces[0]) || \strpos($pieces[0], '=') === \false) {
- return new self($data);
- }
- // Add the cookie pieces into the parsed data array
- foreach ($pieces as $part) {
- $cookieParts = \explode('=', $part, 2);
- $key = \trim($cookieParts[0]);
- $value = isset($cookieParts[1]) ? \trim($cookieParts[1], " \n\r\t\x00\v") : \true;
- // Only check for non-cookies when cookies have been found
- if (!isset($data['Name'])) {
- $data['Name'] = $key;
- $data['Value'] = $value;
- } else {
- foreach (\array_keys(self::$defaults) as $search) {
- if (!\strcasecmp($search, $key)) {
- if ($search === 'Max-Age') {
- if (is_numeric($value)) {
- $data[$search] = (int) $value;
- }
- } else {
- $data[$search] = $value;
- }
- continue 2;
- }
- }
- $data[$key] = $value;
- }
- }
- return new self($data);
- }
- /**
- * @param array $data Array of cookie data provided by a Cookie parser
- */
- public function __construct(array $data = [])
- {
- $this->data = self::$defaults;
- if (isset($data['Name'])) {
- $this->setName($data['Name']);
- }
- if (isset($data['Value'])) {
- $this->setValue($data['Value']);
- }
- if (isset($data['Domain'])) {
- $this->setDomain($data['Domain']);
- }
- if (isset($data['Path'])) {
- $this->setPath($data['Path']);
- }
- if (isset($data['Max-Age'])) {
- $this->setMaxAge($data['Max-Age']);
- }
- if (isset($data['Expires'])) {
- $this->setExpires($data['Expires']);
- }
- if (isset($data['Secure'])) {
- $this->setSecure($data['Secure']);
- }
- if (isset($data['Discard'])) {
- $this->setDiscard($data['Discard']);
- }
- if (isset($data['HttpOnly'])) {
- $this->setHttpOnly($data['HttpOnly']);
- }
- // Set the remaining values that don't have extra validation logic
- foreach (array_diff(array_keys($data), array_keys(self::$defaults)) as $key) {
- $this->data[$key] = $data[$key];
- }
- // Extract the Expires value and turn it into a UNIX timestamp if needed
- if (!$this->getExpires() && $this->getMaxAge()) {
- // Calculate the Expires date
- $this->setExpires(\time() + $this->getMaxAge());
- } elseif (null !== ($expires = $this->getExpires()) && !\is_numeric($expires)) {
- $this->setExpires($expires);
- }
- }
- public function __toString()
- {
- $str = $this->data['Name'] . '=' . ($this->data['Value'] ?? '') . '; ';
- foreach ($this->data as $k => $v) {
- if ($k !== 'Name' && $k !== 'Value' && $v !== null && $v !== \false) {
- if ($k === 'Expires') {
- $str .= 'Expires=' . \gmdate('D, d M Y H:i:s \\G\\M\\T', $v) . '; ';
- } else {
- $str .= ($v === \true ? $k : "{$k}={$v}") . '; ';
- }
- }
- }
- return \rtrim($str, '; ');
- }
- public function toArray() : array
- {
- return $this->data;
- }
- /**
- * Get the cookie name.
- *
- * @return string
- */
- public function getName()
- {
- return $this->data['Name'];
- }
- /**
- * Set the cookie name.
- *
- * @param string $name Cookie name
- */
- public function setName($name) : void
- {
- if (!is_string($name)) {
- trigger_deprecation('guzzlehttp/guzzle', '7.4', 'Not passing a string to %s::%s() is deprecated and will cause an error in 8.0.', __CLASS__, __FUNCTION__);
- }
- $this->data['Name'] = (string) $name;
- }
- /**
- * Get the cookie value.
- *
- * @return string|null
- */
- public function getValue()
- {
- return $this->data['Value'];
- }
- /**
- * Set the cookie value.
- *
- * @param string $value Cookie value
- */
- public function setValue($value) : void
- {
- if (!is_string($value)) {
- trigger_deprecation('guzzlehttp/guzzle', '7.4', 'Not passing a string to %s::%s() is deprecated and will cause an error in 8.0.', __CLASS__, __FUNCTION__);
- }
- $this->data['Value'] = (string) $value;
- }
- /**
- * Get the domain.
- *
- * @return string|null
- */
- public function getDomain()
- {
- return $this->data['Domain'];
- }
- /**
- * Set the domain of the cookie.
- *
- * @param string|null $domain
- */
- public function setDomain($domain) : void
- {
- if (!is_string($domain) && null !== $domain) {
- trigger_deprecation('guzzlehttp/guzzle', '7.4', 'Not passing a string or null to %s::%s() is deprecated and will cause an error in 8.0.', __CLASS__, __FUNCTION__);
- }
- $this->data['Domain'] = null === $domain ? null : (string) $domain;
- }
- /**
- * Get the path.
- *
- * @return string
- */
- public function getPath()
- {
- return $this->data['Path'];
- }
- /**
- * Set the path of the cookie.
- *
- * @param string $path Path of the cookie
- */
- public function setPath($path) : void
- {
- if (!is_string($path)) {
- trigger_deprecation('guzzlehttp/guzzle', '7.4', 'Not passing a string to %s::%s() is deprecated and will cause an error in 8.0.', __CLASS__, __FUNCTION__);
- }
- $this->data['Path'] = (string) $path;
- }
- /**
- * Maximum lifetime of the cookie in seconds.
- *
- * @return int|null
- */
- public function getMaxAge()
- {
- return null === $this->data['Max-Age'] ? null : (int) $this->data['Max-Age'];
- }
- /**
- * Set the max-age of the cookie.
- *
- * @param int|null $maxAge Max age of the cookie in seconds
- */
- public function setMaxAge($maxAge) : void
- {
- if (!is_int($maxAge) && null !== $maxAge) {
- trigger_deprecation('guzzlehttp/guzzle', '7.4', 'Not passing an int or null to %s::%s() is deprecated and will cause an error in 8.0.', __CLASS__, __FUNCTION__);
- }
- $this->data['Max-Age'] = $maxAge === null ? null : (int) $maxAge;
- }
- /**
- * The UNIX timestamp when the cookie Expires.
- *
- * @return string|int|null
- */
- public function getExpires()
- {
- return $this->data['Expires'];
- }
- /**
- * Set the unix timestamp for which the cookie will expire.
- *
- * @param int|string|null $timestamp Unix timestamp or any English textual datetime description.
- */
- public function setExpires($timestamp) : void
- {
- if (!is_int($timestamp) && !is_string($timestamp) && null !== $timestamp) {
- trigger_deprecation('guzzlehttp/guzzle', '7.4', 'Not passing an int, string or null to %s::%s() is deprecated and will cause an error in 8.0.', __CLASS__, __FUNCTION__);
- }
- $this->data['Expires'] = null === $timestamp ? null : (\is_numeric($timestamp) ? (int) $timestamp : \strtotime((string) $timestamp));
- }
- /**
- * Get whether or not this is a secure cookie.
- *
- * @return bool
- */
- public function getSecure()
- {
- return $this->data['Secure'];
- }
- /**
- * Set whether or not the cookie is secure.
- *
- * @param bool $secure Set to true or false if secure
- */
- public function setSecure($secure) : void
- {
- if (!is_bool($secure)) {
- trigger_deprecation('guzzlehttp/guzzle', '7.4', 'Not passing a bool to %s::%s() is deprecated and will cause an error in 8.0.', __CLASS__, __FUNCTION__);
- }
- $this->data['Secure'] = (bool) $secure;
- }
- /**
- * Get whether or not this is a session cookie.
- *
- * @return bool|null
- */
- public function getDiscard()
- {
- return $this->data['Discard'];
- }
- /**
- * Set whether or not this is a session cookie.
- *
- * @param bool $discard Set to true or false if this is a session cookie
- */
- public function setDiscard($discard) : void
- {
- if (!is_bool($discard)) {
- trigger_deprecation('guzzlehttp/guzzle', '7.4', 'Not passing a bool to %s::%s() is deprecated and will cause an error in 8.0.', __CLASS__, __FUNCTION__);
- }
- $this->data['Discard'] = (bool) $discard;
- }
- /**
- * Get whether or not this is an HTTP only cookie.
- *
- * @return bool
- */
- public function getHttpOnly()
- {
- return $this->data['HttpOnly'];
- }
- /**
- * Set whether or not this is an HTTP only cookie.
- *
- * @param bool $httpOnly Set to true or false if this is HTTP only
- */
- public function setHttpOnly($httpOnly) : void
- {
- if (!is_bool($httpOnly)) {
- trigger_deprecation('guzzlehttp/guzzle', '7.4', 'Not passing a bool to %s::%s() is deprecated and will cause an error in 8.0.', __CLASS__, __FUNCTION__);
- }
- $this->data['HttpOnly'] = (bool) $httpOnly;
- }
- /**
- * Check if the cookie matches a path value.
- *
- * A request-path path-matches a given cookie-path if at least one of
- * the following conditions holds:
- *
- * - The cookie-path and the request-path are identical.
- * - The cookie-path is a prefix of the request-path, and the last
- * character of the cookie-path is %x2F ("/").
- * - The cookie-path is a prefix of the request-path, and the first
- * character of the request-path that is not included in the cookie-
- * path is a %x2F ("/") character.
- *
- * @param string $requestPath Path to check against
- */
- public function matchesPath(string $requestPath) : bool
- {
- $cookiePath = $this->getPath();
- // Match on exact matches or when path is the default empty "/"
- if ($cookiePath === '/' || $cookiePath == $requestPath) {
- return \true;
- }
- // Ensure that the cookie-path is a prefix of the request path.
- if (0 !== \strpos($requestPath, $cookiePath)) {
- return \false;
- }
- // Match if the last character of the cookie-path is "/"
- if (\substr($cookiePath, -1, 1) === '/') {
- return \true;
- }
- // Match if the first character not included in cookie path is "/"
- return \substr($requestPath, \strlen($cookiePath), 1) === '/';
- }
- /**
- * Check if the cookie matches a domain value.
- *
- * @param string $domain Domain to check against
- */
- public function matchesDomain(string $domain) : bool
- {
- $cookieDomain = $this->getDomain();
- if (null === $cookieDomain) {
- return \true;
- }
- // Remove the leading '.' as per spec in RFC 6265.
- // https://datatracker.ietf.org/doc/html/rfc6265#section-5.2.3
- $cookieDomain = \ltrim(\strtolower($cookieDomain), '.');
- $domain = \strtolower($domain);
- // Domain not set or exact match.
- if ('' === $cookieDomain || $domain === $cookieDomain) {
- return \true;
- }
- // Matching the subdomain according to RFC 6265.
- // https://datatracker.ietf.org/doc/html/rfc6265#section-5.1.3
- if (\filter_var($domain, \FILTER_VALIDATE_IP)) {
- return \false;
- }
- return (bool) \preg_match('/\\.' . \preg_quote($cookieDomain, '/') . '$/', $domain);
- }
- /**
- * Check if the cookie is expired.
- */
- public function isExpired() : bool
- {
- return $this->getExpires() !== null && \time() > $this->getExpires();
- }
- /**
- * Check if the cookie is valid according to RFC 6265.
- *
- * @return bool|string Returns true if valid or an error message if invalid
- */
- public function validate()
- {
- $name = $this->getName();
- if ($name === '') {
- return 'The cookie name must not be empty';
- }
- // Check if any of the invalid characters are present in the cookie name
- if (\preg_match('/[\\x00-\\x20\\x22\\x28-\\x29\\x2c\\x2f\\x3a-\\x40\\x5c\\x7b\\x7d\\x7f]/', $name)) {
- return 'Cookie name must not contain invalid characters: ASCII ' . 'Control characters (0-31;127), space, tab and the ' . 'following characters: ()<>@,;:\\"/?={}';
- }
- // Value must not be null. 0 and empty string are valid. Empty strings
- // are technically against RFC 6265, but known to happen in the wild.
- $value = $this->getValue();
- if ($value === null) {
- return 'The cookie value must not be empty';
- }
- // Domains must not be empty, but can be 0. "0" is not a valid internet
- // domain, but may be used as server name in a private network.
- $domain = $this->getDomain();
- if ($domain === null || $domain === '') {
- return 'The cookie domain must not be empty';
- }
- return \true;
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/guzzle/src/Exception/BadResponseException.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/guzzle/src/Exception/BadResponseException.php
deleted file mode 100644
index c808c79..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/guzzle/src/Exception/BadResponseException.php
+++ /dev/null
@@ -1,31 +0,0 @@
-request = $request;
- $this->handlerContext = $handlerContext;
- }
- /**
- * Get the request that caused the exception
- */
- public function getRequest() : RequestInterface
- {
- return $this->request;
- }
- /**
- * Get contextual information about the error from the underlying handler.
- *
- * The contents of this array will vary depending on which handler you are
- * using. It may also be just an empty array. Relying on this data will
- * couple you to a specific handler, but can give more debug information
- * when needed.
- */
- public function getHandlerContext() : array
- {
- return $this->handlerContext;
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/guzzle/src/Exception/GuzzleException.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/guzzle/src/Exception/GuzzleException.php
deleted file mode 100644
index ca4ccab..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/guzzle/src/Exception/GuzzleException.php
+++ /dev/null
@@ -1,8 +0,0 @@
-getStatusCode() : 0;
- parent::__construct($message, $code, $previous);
- $this->request = $request;
- $this->response = $response;
- $this->handlerContext = $handlerContext;
- }
- /**
- * Wrap non-RequestExceptions with a RequestException
- */
- public static function wrapException(RequestInterface $request, \Throwable $e) : RequestException
- {
- return $e instanceof RequestException ? $e : new RequestException($e->getMessage(), $request, null, $e);
- }
- /**
- * Factory method to create a new exception with a normalized error message
- *
- * @param RequestInterface $request Request sent
- * @param ResponseInterface $response Response received
- * @param \Throwable|null $previous Previous exception
- * @param array $handlerContext Optional handler context
- * @param BodySummarizerInterface|null $bodySummarizer Optional body summarizer
- */
- public static function create(RequestInterface $request, ResponseInterface $response = null, \Throwable $previous = null, array $handlerContext = [], BodySummarizerInterface $bodySummarizer = null) : self
- {
- if (!$response) {
- return new self('Error completing request', $request, null, $previous, $handlerContext);
- }
- $level = (int) \floor($response->getStatusCode() / 100);
- if ($level === 4) {
- $label = 'Client error';
- $className = ClientException::class;
- } elseif ($level === 5) {
- $label = 'Server error';
- $className = ServerException::class;
- } else {
- $label = 'Unsuccessful request';
- $className = __CLASS__;
- }
- $uri = $request->getUri();
- $uri = static::obfuscateUri($uri);
- // Client Error: `GET /` resulted in a `404 Not Found` response:
- // ... (truncated)
- $message = \sprintf('%s: `%s %s` resulted in a `%s %s` response', $label, $request->getMethod(), $uri->__toString(), $response->getStatusCode(), $response->getReasonPhrase());
- $summary = ($bodySummarizer ?? new BodySummarizer())->summarize($response);
- if ($summary !== null) {
- $message .= ":\n{$summary}\n";
- }
- return new $className($message, $request, $response, $previous, $handlerContext);
- }
- /**
- * Obfuscates URI if there is a username and a password present
- */
- private static function obfuscateUri(UriInterface $uri) : UriInterface
- {
- $userInfo = $uri->getUserInfo();
- if (\false !== ($pos = \strpos($userInfo, ':'))) {
- return $uri->withUserInfo(\substr($userInfo, 0, $pos), '***');
- }
- return $uri;
- }
- /**
- * Get the request that caused the exception
- */
- public function getRequest() : RequestInterface
- {
- return $this->request;
- }
- /**
- * Get the associated response
- */
- public function getResponse() : ?ResponseInterface
- {
- return $this->response;
- }
- /**
- * Check if a response was received
- */
- public function hasResponse() : bool
- {
- return $this->response !== null;
- }
- /**
- * Get contextual information about the error from the underlying handler.
- *
- * The contents of this array will vary depending on which handler you are
- * using. It may also be just an empty array. Relying on this data will
- * couple you to a specific handler, but can give more debug information
- * when needed.
- */
- public function getHandlerContext() : array
- {
- return $this->handlerContext;
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/guzzle/src/Exception/ServerException.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/guzzle/src/Exception/ServerException.php
deleted file mode 100644
index 9bcbdea..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/guzzle/src/Exception/ServerException.php
+++ /dev/null
@@ -1,10 +0,0 @@
-maxHandles = $maxHandles;
- }
- public function create(RequestInterface $request, array $options) : EasyHandle
- {
- if (isset($options['curl']['body_as_string'])) {
- $options['_body_as_string'] = $options['curl']['body_as_string'];
- unset($options['curl']['body_as_string']);
- }
- $easy = new EasyHandle();
- $easy->request = $request;
- $easy->options = $options;
- $conf = $this->getDefaultConf($easy);
- $this->applyMethod($easy, $conf);
- $this->applyHandlerOptions($easy, $conf);
- $this->applyHeaders($easy, $conf);
- unset($conf['_headers']);
- // Add handler options from the request configuration options
- if (isset($options['curl'])) {
- $conf = \array_replace($conf, $options['curl']);
- }
- $conf[\CURLOPT_HEADERFUNCTION] = $this->createHeaderFn($easy);
- $easy->handle = $this->handles ? \array_pop($this->handles) : \curl_init();
- curl_setopt_array($easy->handle, $conf);
- return $easy;
- }
- public function release(EasyHandle $easy) : void
- {
- $resource = $easy->handle;
- unset($easy->handle);
- if (\count($this->handles) >= $this->maxHandles) {
- \curl_close($resource);
- } else {
- // Remove all callback functions as they can hold onto references
- // and are not cleaned up by curl_reset. Using curl_setopt_array
- // does not work for some reason, so removing each one
- // individually.
- \curl_setopt($resource, \CURLOPT_HEADERFUNCTION, null);
- \curl_setopt($resource, \CURLOPT_READFUNCTION, null);
- \curl_setopt($resource, \CURLOPT_WRITEFUNCTION, null);
- \curl_setopt($resource, \CURLOPT_PROGRESSFUNCTION, null);
- \curl_reset($resource);
- $this->handles[] = $resource;
- }
- }
- /**
- * Completes a cURL transaction, either returning a response promise or a
- * rejected promise.
- *
- * @param callable(RequestInterface, array): PromiseInterface $handler
- * @param CurlFactoryInterface $factory Dictates how the handle is released
- */
- public static function finish(callable $handler, EasyHandle $easy, CurlFactoryInterface $factory) : PromiseInterface
- {
- if (isset($easy->options['on_stats'])) {
- self::invokeStats($easy);
- }
- if (!$easy->response || $easy->errno) {
- return self::finishError($handler, $easy, $factory);
- }
- // Return the response if it is present and there is no error.
- $factory->release($easy);
- // Rewind the body of the response if possible.
- $body = $easy->response->getBody();
- if ($body->isSeekable()) {
- $body->rewind();
- }
- return new FulfilledPromise($easy->response);
- }
- private static function invokeStats(EasyHandle $easy) : void
- {
- $curlStats = \curl_getinfo($easy->handle);
- $curlStats['appconnect_time'] = \curl_getinfo($easy->handle, \CURLINFO_APPCONNECT_TIME);
- $stats = new TransferStats($easy->request, $easy->response, $curlStats['total_time'], $easy->errno, $curlStats);
- $easy->options['on_stats']($stats);
- }
- /**
- * @param callable(RequestInterface, array): PromiseInterface $handler
- */
- private static function finishError(callable $handler, EasyHandle $easy, CurlFactoryInterface $factory) : PromiseInterface
- {
- // Get error information and release the handle to the factory.
- $ctx = ['errno' => $easy->errno, 'error' => \curl_error($easy->handle), 'appconnect_time' => \curl_getinfo($easy->handle, \CURLINFO_APPCONNECT_TIME)] + \curl_getinfo($easy->handle);
- $ctx[self::CURL_VERSION_STR] = \curl_version()['version'];
- $factory->release($easy);
- // Retry when nothing is present or when curl failed to rewind.
- if (empty($easy->options['_err_message']) && (!$easy->errno || $easy->errno == 65)) {
- return self::retryFailedRewind($handler, $easy, $ctx);
- }
- return self::createRejection($easy, $ctx);
- }
- private static function createRejection(EasyHandle $easy, array $ctx) : PromiseInterface
- {
- static $connectionErrors = [\CURLE_OPERATION_TIMEOUTED => \true, \CURLE_COULDNT_RESOLVE_HOST => \true, \CURLE_COULDNT_CONNECT => \true, \CURLE_SSL_CONNECT_ERROR => \true, \CURLE_GOT_NOTHING => \true];
- if ($easy->createResponseException) {
- return P\Create::rejectionFor(new RequestException('An error was encountered while creating the response', $easy->request, $easy->response, $easy->createResponseException, $ctx));
- }
- // If an exception was encountered during the onHeaders event, then
- // return a rejected promise that wraps that exception.
- if ($easy->onHeadersException) {
- return P\Create::rejectionFor(new RequestException('An error was encountered during the on_headers event', $easy->request, $easy->response, $easy->onHeadersException, $ctx));
- }
- $message = \sprintf('cURL error %s: %s (%s)', $ctx['errno'], $ctx['error'], 'see https://curl.haxx.se/libcurl/c/libcurl-errors.html');
- $uriString = (string) $easy->request->getUri();
- if ($uriString !== '' && \false === \strpos($ctx['error'], $uriString)) {
- $message .= \sprintf(' for %s', $uriString);
- }
- // Create a connection exception if it was a specific error code.
- $error = isset($connectionErrors[$easy->errno]) ? new ConnectException($message, $easy->request, null, $ctx) : new RequestException($message, $easy->request, $easy->response, null, $ctx);
- return P\Create::rejectionFor($error);
- }
- /**
- * @return array
- */
- private function getDefaultConf(EasyHandle $easy) : array
- {
- $conf = ['_headers' => $easy->request->getHeaders(), \CURLOPT_CUSTOMREQUEST => $easy->request->getMethod(), \CURLOPT_URL => (string) $easy->request->getUri()->withFragment(''), \CURLOPT_RETURNTRANSFER => \false, \CURLOPT_HEADER => \false, \CURLOPT_CONNECTTIMEOUT => 300];
- if (\defined('CURLOPT_PROTOCOLS')) {
- $conf[\CURLOPT_PROTOCOLS] = \CURLPROTO_HTTP | \CURLPROTO_HTTPS;
- }
- $version = $easy->request->getProtocolVersion();
- if ($version == 1.1) {
- $conf[\CURLOPT_HTTP_VERSION] = \CURL_HTTP_VERSION_1_1;
- } elseif ($version == 2.0) {
- $conf[\CURLOPT_HTTP_VERSION] = \CURL_HTTP_VERSION_2_0;
- } else {
- $conf[\CURLOPT_HTTP_VERSION] = \CURL_HTTP_VERSION_1_0;
- }
- return $conf;
- }
- private function applyMethod(EasyHandle $easy, array &$conf) : void
- {
- $body = $easy->request->getBody();
- $size = $body->getSize();
- if ($size === null || $size > 0) {
- $this->applyBody($easy->request, $easy->options, $conf);
- return;
- }
- $method = $easy->request->getMethod();
- if ($method === 'PUT' || $method === 'POST') {
- // See https://datatracker.ietf.org/doc/html/rfc7230#section-3.3.2
- if (!$easy->request->hasHeader('Content-Length')) {
- $conf[\CURLOPT_HTTPHEADER][] = 'Content-Length: 0';
- }
- } elseif ($method === 'HEAD') {
- $conf[\CURLOPT_NOBODY] = \true;
- unset($conf[\CURLOPT_WRITEFUNCTION], $conf[\CURLOPT_READFUNCTION], $conf[\CURLOPT_FILE], $conf[\CURLOPT_INFILE]);
- }
- }
- private function applyBody(RequestInterface $request, array $options, array &$conf) : void
- {
- $size = $request->hasHeader('Content-Length') ? (int) $request->getHeaderLine('Content-Length') : null;
- // Send the body as a string if the size is less than 1MB OR if the
- // [curl][body_as_string] request value is set.
- if ($size !== null && $size < 1000000 || !empty($options['_body_as_string'])) {
- $conf[\CURLOPT_POSTFIELDS] = (string) $request->getBody();
- // Don't duplicate the Content-Length header
- $this->removeHeader('Content-Length', $conf);
- $this->removeHeader('Transfer-Encoding', $conf);
- } else {
- $conf[\CURLOPT_UPLOAD] = \true;
- if ($size !== null) {
- $conf[\CURLOPT_INFILESIZE] = $size;
- $this->removeHeader('Content-Length', $conf);
- }
- $body = $request->getBody();
- if ($body->isSeekable()) {
- $body->rewind();
- }
- $conf[\CURLOPT_READFUNCTION] = static function ($ch, $fd, $length) use($body) {
- return $body->read($length);
- };
- }
- // If the Expect header is not present, prevent curl from adding it
- if (!$request->hasHeader('Expect')) {
- $conf[\CURLOPT_HTTPHEADER][] = 'Expect:';
- }
- // cURL sometimes adds a content-type by default. Prevent this.
- if (!$request->hasHeader('Content-Type')) {
- $conf[\CURLOPT_HTTPHEADER][] = 'Content-Type:';
- }
- }
- private function applyHeaders(EasyHandle $easy, array &$conf) : void
- {
- foreach ($conf['_headers'] as $name => $values) {
- foreach ($values as $value) {
- $value = (string) $value;
- if ($value === '') {
- // cURL requires a special format for empty headers.
- // See https://github.com/guzzle/guzzle/issues/1882 for more details.
- $conf[\CURLOPT_HTTPHEADER][] = "{$name};";
- } else {
- $conf[\CURLOPT_HTTPHEADER][] = "{$name}: {$value}";
- }
- }
- }
- // Remove the Accept header if one was not set
- if (!$easy->request->hasHeader('Accept')) {
- $conf[\CURLOPT_HTTPHEADER][] = 'Accept:';
- }
- }
- /**
- * Remove a header from the options array.
- *
- * @param string $name Case-insensitive header to remove
- * @param array $options Array of options to modify
- */
- private function removeHeader(string $name, array &$options) : void
- {
- foreach (\array_keys($options['_headers']) as $key) {
- if (!\strcasecmp($key, $name)) {
- unset($options['_headers'][$key]);
- return;
- }
- }
- }
- private function applyHandlerOptions(EasyHandle $easy, array &$conf) : void
- {
- $options = $easy->options;
- if (isset($options['verify'])) {
- if ($options['verify'] === \false) {
- unset($conf[\CURLOPT_CAINFO]);
- $conf[\CURLOPT_SSL_VERIFYHOST] = 0;
- $conf[\CURLOPT_SSL_VERIFYPEER] = \false;
- } else {
- $conf[\CURLOPT_SSL_VERIFYHOST] = 2;
- $conf[\CURLOPT_SSL_VERIFYPEER] = \true;
- if (\is_string($options['verify'])) {
- // Throw an error if the file/folder/link path is not valid or doesn't exist.
- if (!\file_exists($options['verify'])) {
- throw new \InvalidArgumentException("SSL CA bundle not found: {$options['verify']}");
- }
- // If it's a directory or a link to a directory use CURLOPT_CAPATH.
- // If not, it's probably a file, or a link to a file, so use CURLOPT_CAINFO.
- if (\is_dir($options['verify']) || \is_link($options['verify']) === \true && ($verifyLink = \readlink($options['verify'])) !== \false && \is_dir($verifyLink)) {
- $conf[\CURLOPT_CAPATH] = $options['verify'];
- } else {
- $conf[\CURLOPT_CAINFO] = $options['verify'];
- }
- }
- }
- }
- if (!isset($options['curl'][\CURLOPT_ENCODING]) && !empty($options['decode_content'])) {
- $accept = $easy->request->getHeaderLine('Accept-Encoding');
- if ($accept) {
- $conf[\CURLOPT_ENCODING] = $accept;
- } else {
- // The empty string enables all available decoders and implicitly
- // sets a matching 'Accept-Encoding' header.
- $conf[\CURLOPT_ENCODING] = '';
- // But as the user did not specify any acceptable encodings we need
- // to overwrite this implicit header with an empty one.
- $conf[\CURLOPT_HTTPHEADER][] = 'Accept-Encoding:';
- }
- }
- if (!isset($options['sink'])) {
- // Use a default temp stream if no sink was set.
- $options['sink'] = \Matomo\Dependencies\SearchEngineKeywordsPerformance\GuzzleHttp\Psr7\Utils::tryFopen('php://temp', 'w+');
- }
- $sink = $options['sink'];
- if (!\is_string($sink)) {
- $sink = \Matomo\Dependencies\SearchEngineKeywordsPerformance\GuzzleHttp\Psr7\Utils::streamFor($sink);
- } elseif (!\is_dir(\dirname($sink))) {
- // Ensure that the directory exists before failing in curl.
- throw new \RuntimeException(\sprintf('Directory %s does not exist for sink value of %s', \dirname($sink), $sink));
- } else {
- $sink = new LazyOpenStream($sink, 'w+');
- }
- $easy->sink = $sink;
- $conf[\CURLOPT_WRITEFUNCTION] = static function ($ch, $write) use($sink) : int {
- return $sink->write($write);
- };
- $timeoutRequiresNoSignal = \false;
- if (isset($options['timeout'])) {
- $timeoutRequiresNoSignal |= $options['timeout'] < 1;
- $conf[\CURLOPT_TIMEOUT_MS] = $options['timeout'] * 1000;
- }
- // CURL default value is CURL_IPRESOLVE_WHATEVER
- if (isset($options['force_ip_resolve'])) {
- if ('v4' === $options['force_ip_resolve']) {
- $conf[\CURLOPT_IPRESOLVE] = \CURL_IPRESOLVE_V4;
- } elseif ('v6' === $options['force_ip_resolve']) {
- $conf[\CURLOPT_IPRESOLVE] = \CURL_IPRESOLVE_V6;
- }
- }
- if (isset($options['connect_timeout'])) {
- $timeoutRequiresNoSignal |= $options['connect_timeout'] < 1;
- $conf[\CURLOPT_CONNECTTIMEOUT_MS] = $options['connect_timeout'] * 1000;
- }
- if ($timeoutRequiresNoSignal && \strtoupper(\substr(\PHP_OS, 0, 3)) !== 'WIN') {
- $conf[\CURLOPT_NOSIGNAL] = \true;
- }
- if (isset($options['proxy'])) {
- if (!\is_array($options['proxy'])) {
- $conf[\CURLOPT_PROXY] = $options['proxy'];
- } else {
- $scheme = $easy->request->getUri()->getScheme();
- if (isset($options['proxy'][$scheme])) {
- $host = $easy->request->getUri()->getHost();
- if (isset($options['proxy']['no']) && Utils::isHostInNoProxy($host, $options['proxy']['no'])) {
- unset($conf[\CURLOPT_PROXY]);
- } else {
- $conf[\CURLOPT_PROXY] = $options['proxy'][$scheme];
- }
- }
- }
- }
- if (isset($options['crypto_method'])) {
- if (\STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT === $options['crypto_method']) {
- if (!defined('CURL_SSLVERSION_TLSv1_0')) {
- throw new \InvalidArgumentException('Invalid crypto_method request option: TLS 1.0 not supported by your version of cURL');
- }
- $conf[\CURLOPT_SSLVERSION] = \CURL_SSLVERSION_TLSv1_0;
- } elseif (\STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT === $options['crypto_method']) {
- if (!defined('CURL_SSLVERSION_TLSv1_1')) {
- throw new \InvalidArgumentException('Invalid crypto_method request option: TLS 1.1 not supported by your version of cURL');
- }
- $conf[\CURLOPT_SSLVERSION] = \CURL_SSLVERSION_TLSv1_1;
- } elseif (\STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT === $options['crypto_method']) {
- if (!defined('CURL_SSLVERSION_TLSv1_2')) {
- throw new \InvalidArgumentException('Invalid crypto_method request option: TLS 1.2 not supported by your version of cURL');
- }
- $conf[\CURLOPT_SSLVERSION] = \CURL_SSLVERSION_TLSv1_2;
- } elseif (defined('STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT') && \STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT === $options['crypto_method']) {
- if (!defined('CURL_SSLVERSION_TLSv1_3')) {
- throw new \InvalidArgumentException('Invalid crypto_method request option: TLS 1.3 not supported by your version of cURL');
- }
- $conf[\CURLOPT_SSLVERSION] = \CURL_SSLVERSION_TLSv1_3;
- } else {
- throw new \InvalidArgumentException('Invalid crypto_method request option: unknown version provided');
- }
- }
- if (isset($options['cert'])) {
- $cert = $options['cert'];
- if (\is_array($cert)) {
- $conf[\CURLOPT_SSLCERTPASSWD] = $cert[1];
- $cert = $cert[0];
- }
- if (!\file_exists($cert)) {
- throw new \InvalidArgumentException("SSL certificate not found: {$cert}");
- }
- // OpenSSL (versions 0.9.3 and later) also support "P12" for PKCS#12-encoded files.
- // see https://curl.se/libcurl/c/CURLOPT_SSLCERTTYPE.html
- $ext = pathinfo($cert, \PATHINFO_EXTENSION);
- if (preg_match('#^(der|p12)$#i', $ext)) {
- $conf[\CURLOPT_SSLCERTTYPE] = strtoupper($ext);
- }
- $conf[\CURLOPT_SSLCERT] = $cert;
- }
- if (isset($options['ssl_key'])) {
- if (\is_array($options['ssl_key'])) {
- if (\count($options['ssl_key']) === 2) {
- [$sslKey, $conf[\CURLOPT_SSLKEYPASSWD]] = $options['ssl_key'];
- } else {
- [$sslKey] = $options['ssl_key'];
- }
- }
- $sslKey = $sslKey ?? $options['ssl_key'];
- if (!\file_exists($sslKey)) {
- throw new \InvalidArgumentException("SSL private key not found: {$sslKey}");
- }
- $conf[\CURLOPT_SSLKEY] = $sslKey;
- }
- if (isset($options['progress'])) {
- $progress = $options['progress'];
- if (!\is_callable($progress)) {
- throw new \InvalidArgumentException('progress client option must be callable');
- }
- $conf[\CURLOPT_NOPROGRESS] = \false;
- $conf[\CURLOPT_PROGRESSFUNCTION] = static function ($resource, int $downloadSize, int $downloaded, int $uploadSize, int $uploaded) use($progress) {
- $progress($downloadSize, $downloaded, $uploadSize, $uploaded);
- };
- }
- if (!empty($options['debug'])) {
- $conf[\CURLOPT_STDERR] = Utils::debugResource($options['debug']);
- $conf[\CURLOPT_VERBOSE] = \true;
- }
- }
- /**
- * This function ensures that a response was set on a transaction. If one
- * was not set, then the request is retried if possible. This error
- * typically means you are sending a payload, curl encountered a
- * "Connection died, retrying a fresh connect" error, tried to rewind the
- * stream, and then encountered a "necessary data rewind wasn't possible"
- * error, causing the request to be sent through curl_multi_info_read()
- * without an error status.
- *
- * @param callable(RequestInterface, array): PromiseInterface $handler
- */
- private static function retryFailedRewind(callable $handler, EasyHandle $easy, array $ctx) : PromiseInterface
- {
- try {
- // Only rewind if the body has been read from.
- $body = $easy->request->getBody();
- if ($body->tell() > 0) {
- $body->rewind();
- }
- } catch (\RuntimeException $e) {
- $ctx['error'] = 'The connection unexpectedly failed without ' . 'providing an error. The request would have been retried, ' . 'but attempting to rewind the request body failed. ' . 'Exception: ' . $e;
- return self::createRejection($easy, $ctx);
- }
- // Retry no more than 3 times before giving up.
- if (!isset($easy->options['_curl_retries'])) {
- $easy->options['_curl_retries'] = 1;
- } elseif ($easy->options['_curl_retries'] == 2) {
- $ctx['error'] = 'The cURL request was retried 3 times ' . 'and did not succeed. The most likely reason for the failure ' . 'is that cURL was unable to rewind the body of the request ' . 'and subsequent retries resulted in the same error. Turn on ' . 'the debug option to see what went wrong. See ' . 'https://bugs.php.net/bug.php?id=47204 for more information.';
- return self::createRejection($easy, $ctx);
- } else {
- ++$easy->options['_curl_retries'];
- }
- return $handler($easy->request, $easy->options);
- }
- private function createHeaderFn(EasyHandle $easy) : callable
- {
- if (isset($easy->options['on_headers'])) {
- $onHeaders = $easy->options['on_headers'];
- if (!\is_callable($onHeaders)) {
- throw new \InvalidArgumentException('on_headers must be callable');
- }
- } else {
- $onHeaders = null;
- }
- return static function ($ch, $h) use($onHeaders, $easy, &$startingResponse) {
- $value = \trim($h);
- if ($value === '') {
- $startingResponse = \true;
- try {
- $easy->createResponse();
- } catch (\Exception $e) {
- $easy->createResponseException = $e;
- return -1;
- }
- if ($onHeaders !== null) {
- try {
- $onHeaders($easy->response);
- } catch (\Exception $e) {
- // Associate the exception with the handle and trigger
- // a curl header write error by returning 0.
- $easy->onHeadersException = $e;
- return -1;
- }
- }
- } elseif ($startingResponse) {
- $startingResponse = \false;
- $easy->headers = [$value];
- } else {
- $easy->headers[] = $value;
- }
- return \strlen($h);
- };
- }
- public function __destruct()
- {
- foreach ($this->handles as $id => $handle) {
- \curl_close($handle);
- unset($this->handles[$id]);
- }
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/guzzle/src/Handler/CurlFactoryInterface.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/guzzle/src/Handler/CurlFactoryInterface.php
deleted file mode 100644
index 4f96219..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/guzzle/src/Handler/CurlFactoryInterface.php
+++ /dev/null
@@ -1,23 +0,0 @@
-factory = $options['handle_factory'] ?? new CurlFactory(3);
- }
- public function __invoke(RequestInterface $request, array $options) : PromiseInterface
- {
- if (isset($options['delay'])) {
- \usleep($options['delay'] * 1000);
- }
- $easy = $this->factory->create($request, $options);
- \curl_exec($easy->handle);
- $easy->errno = \curl_errno($easy->handle);
- return CurlFactory::finish($this, $easy, $this->factory);
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/guzzle/src/Handler/CurlMultiHandler.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/guzzle/src/Handler/CurlMultiHandler.php
deleted file mode 100644
index c3dff44..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/guzzle/src/Handler/CurlMultiHandler.php
+++ /dev/null
@@ -1,220 +0,0 @@
- An array of delay times, indexed by handle id in `addRequest`.
- *
- * @see CurlMultiHandler::addRequest
- */
- private $delays = [];
- /**
- * @var array An associative array of CURLMOPT_* options and corresponding values for curl_multi_setopt()
- */
- private $options = [];
- /** @var resource|\CurlMultiHandle */
- private $_mh;
- /**
- * This handler accepts the following options:
- *
- * - handle_factory: An optional factory used to create curl handles
- * - select_timeout: Optional timeout (in seconds) to block before timing
- * out while selecting curl handles. Defaults to 1 second.
- * - options: An associative array of CURLMOPT_* options and
- * corresponding values for curl_multi_setopt()
- */
- public function __construct(array $options = [])
- {
- $this->factory = $options['handle_factory'] ?? new CurlFactory(50);
- if (isset($options['select_timeout'])) {
- $this->selectTimeout = $options['select_timeout'];
- } elseif ($selectTimeout = Utils::getenv('GUZZLE_CURL_SELECT_TIMEOUT')) {
- @trigger_error('Since guzzlehttp/guzzle 7.2.0: Using environment variable GUZZLE_CURL_SELECT_TIMEOUT is deprecated. Use option "select_timeout" instead.', \E_USER_DEPRECATED);
- $this->selectTimeout = (int) $selectTimeout;
- } else {
- $this->selectTimeout = 1;
- }
- $this->options = $options['options'] ?? [];
- // unsetting the property forces the first access to go through
- // __get().
- unset($this->_mh);
- }
- /**
- * @param string $name
- *
- * @return resource|\CurlMultiHandle
- *
- * @throws \BadMethodCallException when another field as `_mh` will be gotten
- * @throws \RuntimeException when curl can not initialize a multi handle
- */
- public function __get($name)
- {
- if ($name !== '_mh') {
- throw new \BadMethodCallException("Can not get other property as '_mh'.");
- }
- $multiHandle = \curl_multi_init();
- if (\false === $multiHandle) {
- throw new \RuntimeException('Can not initialize curl multi handle.');
- }
- $this->_mh = $multiHandle;
- foreach ($this->options as $option => $value) {
- // A warning is raised in case of a wrong option.
- curl_multi_setopt($this->_mh, $option, $value);
- }
- return $this->_mh;
- }
- public function __destruct()
- {
- if (isset($this->_mh)) {
- \curl_multi_close($this->_mh);
- unset($this->_mh);
- }
- }
- public function __invoke(RequestInterface $request, array $options) : PromiseInterface
- {
- $easy = $this->factory->create($request, $options);
- $id = (int) $easy->handle;
- $promise = new Promise([$this, 'execute'], function () use($id) {
- return $this->cancel($id);
- });
- $this->addRequest(['easy' => $easy, 'deferred' => $promise]);
- return $promise;
- }
- /**
- * Ticks the curl event loop.
- */
- public function tick() : void
- {
- // Add any delayed handles if needed.
- if ($this->delays) {
- $currentTime = Utils::currentTime();
- foreach ($this->delays as $id => $delay) {
- if ($currentTime >= $delay) {
- unset($this->delays[$id]);
- \curl_multi_add_handle($this->_mh, $this->handles[$id]['easy']->handle);
- }
- }
- }
- // Step through the task queue which may add additional requests.
- P\Utils::queue()->run();
- if ($this->active && \curl_multi_select($this->_mh, $this->selectTimeout) === -1) {
- // Perform a usleep if a select returns -1.
- // See: https://bugs.php.net/bug.php?id=61141
- \usleep(250);
- }
- while (\curl_multi_exec($this->_mh, $this->active) === \CURLM_CALL_MULTI_PERFORM) {
- }
- $this->processMessages();
- }
- /**
- * Runs until all outstanding connections have completed.
- */
- public function execute() : void
- {
- $queue = P\Utils::queue();
- while ($this->handles || !$queue->isEmpty()) {
- // If there are no transfers, then sleep for the next delay
- if (!$this->active && $this->delays) {
- \usleep($this->timeToNext());
- }
- $this->tick();
- }
- }
- private function addRequest(array $entry) : void
- {
- $easy = $entry['easy'];
- $id = (int) $easy->handle;
- $this->handles[$id] = $entry;
- if (empty($easy->options['delay'])) {
- \curl_multi_add_handle($this->_mh, $easy->handle);
- } else {
- $this->delays[$id] = Utils::currentTime() + $easy->options['delay'] / 1000;
- }
- }
- /**
- * Cancels a handle from sending and removes references to it.
- *
- * @param int $id Handle ID to cancel and remove.
- *
- * @return bool True on success, false on failure.
- */
- private function cancel($id) : bool
- {
- if (!is_int($id)) {
- trigger_deprecation('guzzlehttp/guzzle', '7.4', 'Not passing an integer to %s::%s() is deprecated and will cause an error in 8.0.', __CLASS__, __FUNCTION__);
- }
- // Cannot cancel if it has been processed.
- if (!isset($this->handles[$id])) {
- return \false;
- }
- $handle = $this->handles[$id]['easy']->handle;
- unset($this->delays[$id], $this->handles[$id]);
- \curl_multi_remove_handle($this->_mh, $handle);
- \curl_close($handle);
- return \true;
- }
- private function processMessages() : void
- {
- while ($done = \curl_multi_info_read($this->_mh)) {
- if ($done['msg'] !== \CURLMSG_DONE) {
- // if it's not done, then it would be premature to remove the handle. ref https://github.com/guzzle/guzzle/pull/2892#issuecomment-945150216
- continue;
- }
- $id = (int) $done['handle'];
- \curl_multi_remove_handle($this->_mh, $done['handle']);
- if (!isset($this->handles[$id])) {
- // Probably was cancelled.
- continue;
- }
- $entry = $this->handles[$id];
- unset($this->handles[$id], $this->delays[$id]);
- $entry['easy']->errno = $done['result'];
- $entry['deferred']->resolve(CurlFactory::finish($this, $entry['easy'], $this->factory));
- }
- }
- private function timeToNext() : int
- {
- $currentTime = Utils::currentTime();
- $nextTime = \PHP_INT_MAX;
- foreach ($this->delays as $time) {
- if ($time < $nextTime) {
- $nextTime = $time;
- }
- }
- return (int) \max(0, $nextTime - $currentTime) * 1000000;
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/guzzle/src/Handler/EasyHandle.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/guzzle/src/Handler/EasyHandle.php
deleted file mode 100644
index 7a6ca9c..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/guzzle/src/Handler/EasyHandle.php
+++ /dev/null
@@ -1,91 +0,0 @@
-headers);
- $normalizedKeys = Utils::normalizeHeaderKeys($headers);
- if (!empty($this->options['decode_content']) && isset($normalizedKeys['content-encoding'])) {
- $headers['x-encoded-content-encoding'] = $headers[$normalizedKeys['content-encoding']];
- unset($headers[$normalizedKeys['content-encoding']]);
- if (isset($normalizedKeys['content-length'])) {
- $headers['x-encoded-content-length'] = $headers[$normalizedKeys['content-length']];
- $bodyLength = (int) $this->sink->getSize();
- if ($bodyLength) {
- $headers[$normalizedKeys['content-length']] = $bodyLength;
- } else {
- unset($headers[$normalizedKeys['content-length']]);
- }
- }
- }
- // Attach a response to the easy handle with the parsed headers.
- $this->response = new Response($status, $headers, $this->sink, $ver, $reason);
- }
- /**
- * @param string $name
- *
- * @return void
- *
- * @throws \BadMethodCallException
- */
- public function __get($name)
- {
- $msg = $name === 'handle' ? 'The EasyHandle has been released' : 'Invalid property: ' . $name;
- throw new \BadMethodCallException($msg);
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/guzzle/src/Handler/HeaderProcessor.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/guzzle/src/Handler/HeaderProcessor.php
deleted file mode 100644
index 7864c14..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/guzzle/src/Handler/HeaderProcessor.php
+++ /dev/null
@@ -1,36 +0,0 @@
-|null $queue The parameters to be passed to the append function, as an indexed array.
- * @param callable|null $onFulfilled Callback to invoke when the return value is fulfilled.
- * @param callable|null $onRejected Callback to invoke when the return value is rejected.
- */
- public function __construct(array $queue = null, callable $onFulfilled = null, callable $onRejected = null)
- {
- $this->onFulfilled = $onFulfilled;
- $this->onRejected = $onRejected;
- if ($queue) {
- // array_values included for BC
- $this->append(...array_values($queue));
- }
- }
- public function __invoke(RequestInterface $request, array $options) : PromiseInterface
- {
- if (!$this->queue) {
- throw new \OutOfBoundsException('Mock queue is empty');
- }
- if (isset($options['delay']) && \is_numeric($options['delay'])) {
- \usleep((int) $options['delay'] * 1000);
- }
- $this->lastRequest = $request;
- $this->lastOptions = $options;
- $response = \array_shift($this->queue);
- if (isset($options['on_headers'])) {
- if (!\is_callable($options['on_headers'])) {
- throw new \InvalidArgumentException('on_headers must be callable');
- }
- try {
- $options['on_headers']($response);
- } catch (\Exception $e) {
- $msg = 'An error was encountered during the on_headers event';
- $response = new RequestException($msg, $request, $response, $e);
- }
- }
- if (\is_callable($response)) {
- $response = $response($request, $options);
- }
- $response = $response instanceof \Throwable ? P\Create::rejectionFor($response) : P\Create::promiseFor($response);
- return $response->then(function (?ResponseInterface $value) use($request, $options) {
- $this->invokeStats($request, $options, $value);
- if ($this->onFulfilled) {
- ($this->onFulfilled)($value);
- }
- if ($value !== null && isset($options['sink'])) {
- $contents = (string) $value->getBody();
- $sink = $options['sink'];
- if (\is_resource($sink)) {
- \fwrite($sink, $contents);
- } elseif (\is_string($sink)) {
- \file_put_contents($sink, $contents);
- } elseif ($sink instanceof StreamInterface) {
- $sink->write($contents);
- }
- }
- return $value;
- }, function ($reason) use($request, $options) {
- $this->invokeStats($request, $options, null, $reason);
- if ($this->onRejected) {
- ($this->onRejected)($reason);
- }
- return P\Create::rejectionFor($reason);
- });
- }
- /**
- * Adds one or more variadic requests, exceptions, callables, or promises
- * to the queue.
- *
- * @param mixed ...$values
- */
- public function append(...$values) : void
- {
- foreach ($values as $value) {
- if ($value instanceof ResponseInterface || $value instanceof \Throwable || $value instanceof PromiseInterface || \is_callable($value)) {
- $this->queue[] = $value;
- } else {
- throw new \TypeError('Expected a Response, Promise, Throwable or callable. Found ' . Utils::describeType($value));
- }
- }
- }
- /**
- * Get the last received request.
- */
- public function getLastRequest() : ?RequestInterface
- {
- return $this->lastRequest;
- }
- /**
- * Get the last received request options.
- */
- public function getLastOptions() : array
- {
- return $this->lastOptions;
- }
- /**
- * Returns the number of remaining items in the queue.
- */
- public function count() : int
- {
- return \count($this->queue);
- }
- public function reset() : void
- {
- $this->queue = [];
- }
- /**
- * @param mixed $reason Promise or reason.
- */
- private function invokeStats(RequestInterface $request, array $options, ResponseInterface $response = null, $reason = null) : void
- {
- if (isset($options['on_stats'])) {
- $transferTime = $options['transfer_time'] ?? 0;
- $stats = new TransferStats($request, $response, $transferTime, $reason);
- $options['on_stats']($stats);
- }
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/guzzle/src/Handler/Proxy.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/guzzle/src/Handler/Proxy.php
deleted file mode 100644
index aa4ca6b..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/guzzle/src/Handler/Proxy.php
+++ /dev/null
@@ -1,49 +0,0 @@
-withoutHeader('Expect');
- // Append a content-length header if body size is zero to match
- // cURL's behavior.
- if (0 === $request->getBody()->getSize()) {
- $request = $request->withHeader('Content-Length', '0');
- }
- return $this->createResponse($request, $options, $this->createStream($request, $options), $startTime);
- } catch (\InvalidArgumentException $e) {
- throw $e;
- } catch (\Exception $e) {
- // Determine if the error was a networking error.
- $message = $e->getMessage();
- // This list can probably get more comprehensive.
- if (\false !== \strpos($message, 'getaddrinfo') || \false !== \strpos($message, 'Connection refused') || \false !== \strpos($message, "couldn't connect to host") || \false !== \strpos($message, 'connection attempt failed')) {
- $e = new ConnectException($e->getMessage(), $request, $e);
- } else {
- $e = RequestException::wrapException($request, $e);
- }
- $this->invokeStats($options, $request, $startTime, null, $e);
- return P\Create::rejectionFor($e);
- }
- }
- private function invokeStats(array $options, RequestInterface $request, ?float $startTime, ResponseInterface $response = null, \Throwable $error = null) : void
- {
- if (isset($options['on_stats'])) {
- $stats = new TransferStats($request, $response, Utils::currentTime() - $startTime, $error, []);
- $options['on_stats']($stats);
- }
- }
- /**
- * @param resource $stream
- */
- private function createResponse(RequestInterface $request, array $options, $stream, ?float $startTime) : PromiseInterface
- {
- $hdrs = $this->lastHeaders;
- $this->lastHeaders = [];
- try {
- [$ver, $status, $reason, $headers] = HeaderProcessor::parseHeaders($hdrs);
- } catch (\Exception $e) {
- return P\Create::rejectionFor(new RequestException('An error was encountered while creating the response', $request, null, $e));
- }
- [$stream, $headers] = $this->checkDecode($options, $headers, $stream);
- $stream = Psr7\Utils::streamFor($stream);
- $sink = $stream;
- if (\strcasecmp('HEAD', $request->getMethod())) {
- $sink = $this->createSink($stream, $options);
- }
- try {
- $response = new Psr7\Response($status, $headers, $sink, $ver, $reason);
- } catch (\Exception $e) {
- return P\Create::rejectionFor(new RequestException('An error was encountered while creating the response', $request, null, $e));
- }
- if (isset($options['on_headers'])) {
- try {
- $options['on_headers']($response);
- } catch (\Exception $e) {
- return P\Create::rejectionFor(new RequestException('An error was encountered during the on_headers event', $request, $response, $e));
- }
- }
- // Do not drain when the request is a HEAD request because they have
- // no body.
- if ($sink !== $stream) {
- $this->drain($stream, $sink, $response->getHeaderLine('Content-Length'));
- }
- $this->invokeStats($options, $request, $startTime, $response, null);
- return new FulfilledPromise($response);
- }
- private function createSink(StreamInterface $stream, array $options) : StreamInterface
- {
- if (!empty($options['stream'])) {
- return $stream;
- }
- $sink = $options['sink'] ?? Psr7\Utils::tryFopen('php://temp', 'r+');
- return \is_string($sink) ? new Psr7\LazyOpenStream($sink, 'w+') : Psr7\Utils::streamFor($sink);
- }
- /**
- * @param resource $stream
- */
- private function checkDecode(array $options, array $headers, $stream) : array
- {
- // Automatically decode responses when instructed.
- if (!empty($options['decode_content'])) {
- $normalizedKeys = Utils::normalizeHeaderKeys($headers);
- if (isset($normalizedKeys['content-encoding'])) {
- $encoding = $headers[$normalizedKeys['content-encoding']];
- if ($encoding[0] === 'gzip' || $encoding[0] === 'deflate') {
- $stream = new Psr7\InflateStream(Psr7\Utils::streamFor($stream));
- $headers['x-encoded-content-encoding'] = $headers[$normalizedKeys['content-encoding']];
- // Remove content-encoding header
- unset($headers[$normalizedKeys['content-encoding']]);
- // Fix content-length header
- if (isset($normalizedKeys['content-length'])) {
- $headers['x-encoded-content-length'] = $headers[$normalizedKeys['content-length']];
- $length = (int) $stream->getSize();
- if ($length === 0) {
- unset($headers[$normalizedKeys['content-length']]);
- } else {
- $headers[$normalizedKeys['content-length']] = [$length];
- }
- }
- }
- }
- }
- return [$stream, $headers];
- }
- /**
- * Drains the source stream into the "sink" client option.
- *
- * @param string $contentLength Header specifying the amount of
- * data to read.
- *
- * @throws \RuntimeException when the sink option is invalid.
- */
- private function drain(StreamInterface $source, StreamInterface $sink, string $contentLength) : StreamInterface
- {
- // If a content-length header is provided, then stop reading once
- // that number of bytes has been read. This can prevent infinitely
- // reading from a stream when dealing with servers that do not honor
- // Connection: Close headers.
- Psr7\Utils::copyToStream($source, $sink, \strlen($contentLength) > 0 && (int) $contentLength > 0 ? (int) $contentLength : -1);
- $sink->seek(0);
- $source->close();
- return $sink;
- }
- /**
- * Create a resource and check to ensure it was created successfully
- *
- * @param callable $callback Callable that returns stream resource
- *
- * @return resource
- *
- * @throws \RuntimeException on error
- */
- private function createResource(callable $callback)
- {
- $errors = [];
- \set_error_handler(static function ($_, $msg, $file, $line) use(&$errors) : bool {
- $errors[] = ['message' => $msg, 'file' => $file, 'line' => $line];
- return \true;
- });
- try {
- $resource = $callback();
- } finally {
- \restore_error_handler();
- }
- if (!$resource) {
- $message = 'Error creating resource: ';
- foreach ($errors as $err) {
- foreach ($err as $key => $value) {
- $message .= "[{$key}] {$value}" . \PHP_EOL;
- }
- }
- throw new \RuntimeException(\trim($message));
- }
- return $resource;
- }
- /**
- * @return resource
- */
- private function createStream(RequestInterface $request, array $options)
- {
- static $methods;
- if (!$methods) {
- $methods = \array_flip(\get_class_methods(__CLASS__));
- }
- if (!\in_array($request->getUri()->getScheme(), ['http', 'https'])) {
- throw new RequestException(\sprintf("The scheme '%s' is not supported.", $request->getUri()->getScheme()), $request);
- }
- // HTTP/1.1 streams using the PHP stream wrapper require a
- // Connection: close header
- if ($request->getProtocolVersion() == '1.1' && !$request->hasHeader('Connection')) {
- $request = $request->withHeader('Connection', 'close');
- }
- // Ensure SSL is verified by default
- if (!isset($options['verify'])) {
- $options['verify'] = \true;
- }
- $params = [];
- $context = $this->getDefaultContext($request);
- if (isset($options['on_headers']) && !\is_callable($options['on_headers'])) {
- throw new \InvalidArgumentException('on_headers must be callable');
- }
- if (!empty($options)) {
- foreach ($options as $key => $value) {
- $method = "add_{$key}";
- if (isset($methods[$method])) {
- $this->{$method}($request, $context, $value, $params);
- }
- }
- }
- if (isset($options['stream_context'])) {
- if (!\is_array($options['stream_context'])) {
- throw new \InvalidArgumentException('stream_context must be an array');
- }
- $context = \array_replace_recursive($context, $options['stream_context']);
- }
- // Microsoft NTLM authentication only supported with curl handler
- if (isset($options['auth'][2]) && 'ntlm' === $options['auth'][2]) {
- throw new \InvalidArgumentException('Microsoft NTLM authentication only supported with curl handler');
- }
- $uri = $this->resolveHost($request, $options);
- $contextResource = $this->createResource(static function () use($context, $params) {
- return \stream_context_create($context, $params);
- });
- return $this->createResource(function () use($uri, &$http_response_header, $contextResource, $context, $options, $request) {
- $resource = @\fopen((string) $uri, 'r', \false, $contextResource);
- $this->lastHeaders = $http_response_header ?? [];
- if (\false === $resource) {
- throw new ConnectException(sprintf('Connection refused for URI %s', $uri), $request, null, $context);
- }
- if (isset($options['read_timeout'])) {
- $readTimeout = $options['read_timeout'];
- $sec = (int) $readTimeout;
- $usec = ($readTimeout - $sec) * 100000;
- \stream_set_timeout($resource, $sec, $usec);
- }
- return $resource;
- });
- }
- private function resolveHost(RequestInterface $request, array $options) : UriInterface
- {
- $uri = $request->getUri();
- if (isset($options['force_ip_resolve']) && !\filter_var($uri->getHost(), \FILTER_VALIDATE_IP)) {
- if ('v4' === $options['force_ip_resolve']) {
- $records = \dns_get_record($uri->getHost(), \DNS_A);
- if (\false === $records || !isset($records[0]['ip'])) {
- throw new ConnectException(\sprintf("Could not resolve IPv4 address for host '%s'", $uri->getHost()), $request);
- }
- return $uri->withHost($records[0]['ip']);
- }
- if ('v6' === $options['force_ip_resolve']) {
- $records = \dns_get_record($uri->getHost(), \DNS_AAAA);
- if (\false === $records || !isset($records[0]['ipv6'])) {
- throw new ConnectException(\sprintf("Could not resolve IPv6 address for host '%s'", $uri->getHost()), $request);
- }
- return $uri->withHost('[' . $records[0]['ipv6'] . ']');
- }
- }
- return $uri;
- }
- private function getDefaultContext(RequestInterface $request) : array
- {
- $headers = '';
- foreach ($request->getHeaders() as $name => $value) {
- foreach ($value as $val) {
- $headers .= "{$name}: {$val}\r\n";
- }
- }
- $context = ['http' => ['method' => $request->getMethod(), 'header' => $headers, 'protocol_version' => $request->getProtocolVersion(), 'ignore_errors' => \true, 'follow_location' => 0], 'ssl' => ['peer_name' => $request->getUri()->getHost()]];
- $body = (string) $request->getBody();
- if ('' !== $body) {
- $context['http']['content'] = $body;
- // Prevent the HTTP handler from adding a Content-Type header.
- if (!$request->hasHeader('Content-Type')) {
- $context['http']['header'] .= "Content-Type:\r\n";
- }
- }
- $context['http']['header'] = \rtrim($context['http']['header']);
- return $context;
- }
- /**
- * @param mixed $value as passed via Request transfer options.
- */
- private function add_proxy(RequestInterface $request, array &$options, $value, array &$params) : void
- {
- $uri = null;
- if (!\is_array($value)) {
- $uri = $value;
- } else {
- $scheme = $request->getUri()->getScheme();
- if (isset($value[$scheme])) {
- if (!isset($value['no']) || !Utils::isHostInNoProxy($request->getUri()->getHost(), $value['no'])) {
- $uri = $value[$scheme];
- }
- }
- }
- if (!$uri) {
- return;
- }
- $parsed = $this->parse_proxy($uri);
- $options['http']['proxy'] = $parsed['proxy'];
- if ($parsed['auth']) {
- if (!isset($options['http']['header'])) {
- $options['http']['header'] = [];
- }
- $options['http']['header'] .= "\r\nProxy-Authorization: {$parsed['auth']}";
- }
- }
- /**
- * Parses the given proxy URL to make it compatible with the format PHP's stream context expects.
- */
- private function parse_proxy(string $url) : array
- {
- $parsed = \parse_url($url);
- if ($parsed !== \false && isset($parsed['scheme']) && $parsed['scheme'] === 'http') {
- if (isset($parsed['host']) && isset($parsed['port'])) {
- $auth = null;
- if (isset($parsed['user']) && isset($parsed['pass'])) {
- $auth = \base64_encode("{$parsed['user']}:{$parsed['pass']}");
- }
- return ['proxy' => "tcp://{$parsed['host']}:{$parsed['port']}", 'auth' => $auth ? "Basic {$auth}" : null];
- }
- }
- // Return proxy as-is.
- return ['proxy' => $url, 'auth' => null];
- }
- /**
- * @param mixed $value as passed via Request transfer options.
- */
- private function add_timeout(RequestInterface $request, array &$options, $value, array &$params) : void
- {
- if ($value > 0) {
- $options['http']['timeout'] = $value;
- }
- }
- /**
- * @param mixed $value as passed via Request transfer options.
- */
- private function add_crypto_method(RequestInterface $request, array &$options, $value, array &$params) : void
- {
- if ($value === \STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT || $value === \STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT || $value === \STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT || defined('STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT') && $value === \STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT) {
- $options['http']['crypto_method'] = $value;
- return;
- }
- throw new \InvalidArgumentException('Invalid crypto_method request option: unknown version provided');
- }
- /**
- * @param mixed $value as passed via Request transfer options.
- */
- private function add_verify(RequestInterface $request, array &$options, $value, array &$params) : void
- {
- if ($value === \false) {
- $options['ssl']['verify_peer'] = \false;
- $options['ssl']['verify_peer_name'] = \false;
- return;
- }
- if (\is_string($value)) {
- $options['ssl']['cafile'] = $value;
- if (!\file_exists($value)) {
- throw new \RuntimeException("SSL CA bundle not found: {$value}");
- }
- } elseif ($value !== \true) {
- throw new \InvalidArgumentException('Invalid verify request option');
- }
- $options['ssl']['verify_peer'] = \true;
- $options['ssl']['verify_peer_name'] = \true;
- $options['ssl']['allow_self_signed'] = \false;
- }
- /**
- * @param mixed $value as passed via Request transfer options.
- */
- private function add_cert(RequestInterface $request, array &$options, $value, array &$params) : void
- {
- if (\is_array($value)) {
- $options['ssl']['passphrase'] = $value[1];
- $value = $value[0];
- }
- if (!\file_exists($value)) {
- throw new \RuntimeException("SSL certificate not found: {$value}");
- }
- $options['ssl']['local_cert'] = $value;
- }
- /**
- * @param mixed $value as passed via Request transfer options.
- */
- private function add_progress(RequestInterface $request, array &$options, $value, array &$params) : void
- {
- self::addNotification($params, static function ($code, $a, $b, $c, $transferred, $total) use($value) {
- if ($code == \STREAM_NOTIFY_PROGRESS) {
- // The upload progress cannot be determined. Use 0 for cURL compatibility:
- // https://curl.se/libcurl/c/CURLOPT_PROGRESSFUNCTION.html
- $value($total, $transferred, 0, 0);
- }
- });
- }
- /**
- * @param mixed $value as passed via Request transfer options.
- */
- private function add_debug(RequestInterface $request, array &$options, $value, array &$params) : void
- {
- if ($value === \false) {
- return;
- }
- static $map = [\STREAM_NOTIFY_CONNECT => 'CONNECT', \STREAM_NOTIFY_AUTH_REQUIRED => 'AUTH_REQUIRED', \STREAM_NOTIFY_AUTH_RESULT => 'AUTH_RESULT', \STREAM_NOTIFY_MIME_TYPE_IS => 'MIME_TYPE_IS', \STREAM_NOTIFY_FILE_SIZE_IS => 'FILE_SIZE_IS', \STREAM_NOTIFY_REDIRECTED => 'REDIRECTED', \STREAM_NOTIFY_PROGRESS => 'PROGRESS', \STREAM_NOTIFY_FAILURE => 'FAILURE', \STREAM_NOTIFY_COMPLETED => 'COMPLETED', \STREAM_NOTIFY_RESOLVE => 'RESOLVE'];
- static $args = ['severity', 'message', 'message_code', 'bytes_transferred', 'bytes_max'];
- $value = Utils::debugResource($value);
- $ident = $request->getMethod() . ' ' . $request->getUri()->withFragment('');
- self::addNotification($params, static function (int $code, ...$passed) use($ident, $value, $map, $args) : void {
- \fprintf($value, '<%s> [%s] ', $ident, $map[$code]);
- foreach (\array_filter($passed) as $i => $v) {
- \fwrite($value, $args[$i] . ': "' . $v . '" ');
- }
- \fwrite($value, "\n");
- });
- }
- private static function addNotification(array &$params, callable $notify) : void
- {
- // Wrap the existing function if needed.
- if (!isset($params['notification'])) {
- $params['notification'] = $notify;
- } else {
- $params['notification'] = self::callArray([$params['notification'], $notify]);
- }
- }
- private static function callArray(array $functions) : callable
- {
- return static function (...$args) use($functions) {
- foreach ($functions as $fn) {
- $fn(...$args);
- }
- };
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/guzzle/src/HandlerStack.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/guzzle/src/HandlerStack.php
deleted file mode 100644
index 0e5d429..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/guzzle/src/HandlerStack.php
+++ /dev/null
@@ -1,238 +0,0 @@
-push(Middleware::httpErrors(), 'http_errors');
- $stack->push(Middleware::redirect(), 'allow_redirects');
- $stack->push(Middleware::cookies(), 'cookies');
- $stack->push(Middleware::prepareBody(), 'prepare_body');
- return $stack;
- }
- /**
- * @param (callable(RequestInterface, array): PromiseInterface)|null $handler Underlying HTTP handler.
- */
- public function __construct(callable $handler = null)
- {
- $this->handler = $handler;
- }
- /**
- * Invokes the handler stack as a composed handler
- *
- * @return ResponseInterface|PromiseInterface
- */
- public function __invoke(RequestInterface $request, array $options)
- {
- $handler = $this->resolve();
- return $handler($request, $options);
- }
- /**
- * Dumps a string representation of the stack.
- *
- * @return string
- */
- public function __toString()
- {
- $depth = 0;
- $stack = [];
- if ($this->handler !== null) {
- $stack[] = '0) Handler: ' . $this->debugCallable($this->handler);
- }
- $result = '';
- foreach (\array_reverse($this->stack) as $tuple) {
- ++$depth;
- $str = "{$depth}) Name: '{$tuple[1]}', ";
- $str .= 'Function: ' . $this->debugCallable($tuple[0]);
- $result = "> {$str}\n{$result}";
- $stack[] = $str;
- }
- foreach (\array_keys($stack) as $k) {
- $result .= "< {$stack[$k]}\n";
- }
- return $result;
- }
- /**
- * Set the HTTP handler that actually returns a promise.
- *
- * @param callable(RequestInterface, array): PromiseInterface $handler Accepts a request and array of options and
- * returns a Promise.
- */
- public function setHandler(callable $handler) : void
- {
- $this->handler = $handler;
- $this->cached = null;
- }
- /**
- * Returns true if the builder has a handler.
- */
- public function hasHandler() : bool
- {
- return $this->handler !== null;
- }
- /**
- * Unshift a middleware to the bottom of the stack.
- *
- * @param callable(callable): callable $middleware Middleware function
- * @param string $name Name to register for this middleware.
- */
- public function unshift(callable $middleware, string $name = null) : void
- {
- \array_unshift($this->stack, [$middleware, $name]);
- $this->cached = null;
- }
- /**
- * Push a middleware to the top of the stack.
- *
- * @param callable(callable): callable $middleware Middleware function
- * @param string $name Name to register for this middleware.
- */
- public function push(callable $middleware, string $name = '') : void
- {
- $this->stack[] = [$middleware, $name];
- $this->cached = null;
- }
- /**
- * Add a middleware before another middleware by name.
- *
- * @param string $findName Middleware to find
- * @param callable(callable): callable $middleware Middleware function
- * @param string $withName Name to register for this middleware.
- */
- public function before(string $findName, callable $middleware, string $withName = '') : void
- {
- $this->splice($findName, $withName, $middleware, \true);
- }
- /**
- * Add a middleware after another middleware by name.
- *
- * @param string $findName Middleware to find
- * @param callable(callable): callable $middleware Middleware function
- * @param string $withName Name to register for this middleware.
- */
- public function after(string $findName, callable $middleware, string $withName = '') : void
- {
- $this->splice($findName, $withName, $middleware, \false);
- }
- /**
- * Remove a middleware by instance or name from the stack.
- *
- * @param callable|string $remove Middleware to remove by instance or name.
- */
- public function remove($remove) : void
- {
- if (!is_string($remove) && !is_callable($remove)) {
- trigger_deprecation('guzzlehttp/guzzle', '7.4', 'Not passing a callable or string to %s::%s() is deprecated and will cause an error in 8.0.', __CLASS__, __FUNCTION__);
- }
- $this->cached = null;
- $idx = \is_callable($remove) ? 0 : 1;
- $this->stack = \array_values(\array_filter($this->stack, static function ($tuple) use($idx, $remove) {
- return $tuple[$idx] !== $remove;
- }));
- }
- /**
- * Compose the middleware and handler into a single callable function.
- *
- * @return callable(RequestInterface, array): PromiseInterface
- */
- public function resolve() : callable
- {
- if ($this->cached === null) {
- if (($prev = $this->handler) === null) {
- throw new \LogicException('No handler has been specified');
- }
- foreach (\array_reverse($this->stack) as $fn) {
- /** @var callable(RequestInterface, array): PromiseInterface $prev */
- $prev = $fn[0]($prev);
- }
- $this->cached = $prev;
- }
- return $this->cached;
- }
- private function findByName(string $name) : int
- {
- foreach ($this->stack as $k => $v) {
- if ($v[1] === $name) {
- return $k;
- }
- }
- throw new \InvalidArgumentException("Middleware not found: {$name}");
- }
- /**
- * Splices a function into the middleware list at a specific position.
- */
- private function splice(string $findName, string $withName, callable $middleware, bool $before) : void
- {
- $this->cached = null;
- $idx = $this->findByName($findName);
- $tuple = [$middleware, $withName];
- if ($before) {
- if ($idx === 0) {
- \array_unshift($this->stack, $tuple);
- } else {
- $replacement = [$tuple, $this->stack[$idx]];
- \array_splice($this->stack, $idx, 1, $replacement);
- }
- } elseif ($idx === \count($this->stack) - 1) {
- $this->stack[] = $tuple;
- } else {
- $replacement = [$this->stack[$idx], $tuple];
- \array_splice($this->stack, $idx, 1, $replacement);
- }
- }
- /**
- * Provides a debug string for a given callable.
- *
- * @param callable|string $fn Function to write as a string.
- */
- private function debugCallable($fn) : string
- {
- if (\is_string($fn)) {
- return "callable({$fn})";
- }
- if (\is_array($fn)) {
- return \is_string($fn[0]) ? "callable({$fn[0]}::{$fn[1]})" : "callable(['" . \get_class($fn[0]) . "', '{$fn[1]}'])";
- }
- /** @var object $fn */
- return 'callable(' . \spl_object_hash($fn) . ')';
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/guzzle/src/MessageFormatter.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/guzzle/src/MessageFormatter.php
deleted file mode 100644
index cad16fb..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/guzzle/src/MessageFormatter.php
+++ /dev/null
@@ -1,168 +0,0 @@
->>>>>>>\n{request}\n<<<<<<<<\n{response}\n--------\n{error}";
- public const SHORT = '[{ts}] "{method} {target} HTTP/{version}" {code}';
- /**
- * @var string Template used to format log messages
- */
- private $template;
- /**
- * @param string $template Log message template
- */
- public function __construct(?string $template = self::CLF)
- {
- $this->template = $template ?: self::CLF;
- }
- /**
- * Returns a formatted message string.
- *
- * @param RequestInterface $request Request that was sent
- * @param ResponseInterface|null $response Response that was received
- * @param \Throwable|null $error Exception that was received
- */
- public function format(RequestInterface $request, ResponseInterface $response = null, \Throwable $error = null) : string
- {
- $cache = [];
- /** @var string */
- return \preg_replace_callback('/{\\s*([A-Za-z_\\-\\.0-9]+)\\s*}/', function (array $matches) use($request, $response, $error, &$cache) {
- if (isset($cache[$matches[1]])) {
- return $cache[$matches[1]];
- }
- $result = '';
- switch ($matches[1]) {
- case 'request':
- $result = Psr7\Message::toString($request);
- break;
- case 'response':
- $result = $response ? Psr7\Message::toString($response) : '';
- break;
- case 'req_headers':
- $result = \trim($request->getMethod() . ' ' . $request->getRequestTarget()) . ' HTTP/' . $request->getProtocolVersion() . "\r\n" . $this->headers($request);
- break;
- case 'res_headers':
- $result = $response ? \sprintf('HTTP/%s %d %s', $response->getProtocolVersion(), $response->getStatusCode(), $response->getReasonPhrase()) . "\r\n" . $this->headers($response) : 'NULL';
- break;
- case 'req_body':
- $result = $request->getBody()->__toString();
- break;
- case 'res_body':
- if (!$response instanceof ResponseInterface) {
- $result = 'NULL';
- break;
- }
- $body = $response->getBody();
- if (!$body->isSeekable()) {
- $result = 'RESPONSE_NOT_LOGGEABLE';
- break;
- }
- $result = $response->getBody()->__toString();
- break;
- case 'ts':
- case 'date_iso_8601':
- $result = \gmdate('c');
- break;
- case 'date_common_log':
- $result = \date('d/M/Y:H:i:s O');
- break;
- case 'method':
- $result = $request->getMethod();
- break;
- case 'version':
- $result = $request->getProtocolVersion();
- break;
- case 'uri':
- case 'url':
- $result = $request->getUri()->__toString();
- break;
- case 'target':
- $result = $request->getRequestTarget();
- break;
- case 'req_version':
- $result = $request->getProtocolVersion();
- break;
- case 'res_version':
- $result = $response ? $response->getProtocolVersion() : 'NULL';
- break;
- case 'host':
- $result = $request->getHeaderLine('Host');
- break;
- case 'hostname':
- $result = \gethostname();
- break;
- case 'code':
- $result = $response ? $response->getStatusCode() : 'NULL';
- break;
- case 'phrase':
- $result = $response ? $response->getReasonPhrase() : 'NULL';
- break;
- case 'error':
- $result = $error ? $error->getMessage() : 'NULL';
- break;
- default:
- // handle prefixed dynamic headers
- if (\strpos($matches[1], 'req_header_') === 0) {
- $result = $request->getHeaderLine(\substr($matches[1], 11));
- } elseif (\strpos($matches[1], 'res_header_') === 0) {
- $result = $response ? $response->getHeaderLine(\substr($matches[1], 11)) : 'NULL';
- }
- }
- $cache[$matches[1]] = $result;
- return $result;
- }, $this->template);
- }
- /**
- * Get headers from message as string
- */
- private function headers(MessageInterface $message) : string
- {
- $result = '';
- foreach ($message->getHeaders() as $name => $values) {
- $result .= $name . ': ' . \implode(', ', $values) . "\r\n";
- }
- return \trim($result);
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/guzzle/src/MessageFormatterInterface.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/guzzle/src/MessageFormatterInterface.php
deleted file mode 100644
index 2c3bfa8..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/guzzle/src/MessageFormatterInterface.php
+++ /dev/null
@@ -1,17 +0,0 @@
-withCookieHeader($request);
- return $handler($request, $options)->then(static function (ResponseInterface $response) use($cookieJar, $request) : ResponseInterface {
- $cookieJar->extractCookies($request, $response);
- return $response;
- });
- };
- };
- }
- /**
- * Middleware that throws exceptions for 4xx or 5xx responses when the
- * "http_errors" request option is set to true.
- *
- * @param BodySummarizerInterface|null $bodySummarizer The body summarizer to use in exception messages.
- *
- * @return callable(callable): callable Returns a function that accepts the next handler.
- */
- public static function httpErrors(BodySummarizerInterface $bodySummarizer = null) : callable
- {
- return static function (callable $handler) use($bodySummarizer) : callable {
- return static function ($request, array $options) use($handler, $bodySummarizer) {
- if (empty($options['http_errors'])) {
- return $handler($request, $options);
- }
- return $handler($request, $options)->then(static function (ResponseInterface $response) use($request, $bodySummarizer) {
- $code = $response->getStatusCode();
- if ($code < 400) {
- return $response;
- }
- throw RequestException::create($request, $response, null, [], $bodySummarizer);
- });
- };
- };
- }
- /**
- * Middleware that pushes history data to an ArrayAccess container.
- *
- * @param array|\ArrayAccess $container Container to hold the history (by reference).
- *
- * @return callable(callable): callable Returns a function that accepts the next handler.
- *
- * @throws \InvalidArgumentException if container is not an array or ArrayAccess.
- */
- public static function history(&$container) : callable
- {
- if (!\is_array($container) && !$container instanceof \ArrayAccess) {
- throw new \InvalidArgumentException('history container must be an array or object implementing ArrayAccess');
- }
- return static function (callable $handler) use(&$container) : callable {
- return static function (RequestInterface $request, array $options) use($handler, &$container) {
- return $handler($request, $options)->then(static function ($value) use($request, &$container, $options) {
- $container[] = ['request' => $request, 'response' => $value, 'error' => null, 'options' => $options];
- return $value;
- }, static function ($reason) use($request, &$container, $options) {
- $container[] = ['request' => $request, 'response' => null, 'error' => $reason, 'options' => $options];
- return P\Create::rejectionFor($reason);
- });
- };
- };
- }
- /**
- * Middleware that invokes a callback before and after sending a request.
- *
- * The provided listener cannot modify or alter the response. It simply
- * "taps" into the chain to be notified before returning the promise. The
- * before listener accepts a request and options array, and the after
- * listener accepts a request, options array, and response promise.
- *
- * @param callable $before Function to invoke before forwarding the request.
- * @param callable $after Function invoked after forwarding.
- *
- * @return callable Returns a function that accepts the next handler.
- */
- public static function tap(callable $before = null, callable $after = null) : callable
- {
- return static function (callable $handler) use($before, $after) : callable {
- return static function (RequestInterface $request, array $options) use($handler, $before, $after) {
- if ($before) {
- $before($request, $options);
- }
- $response = $handler($request, $options);
- if ($after) {
- $after($request, $options, $response);
- }
- return $response;
- };
- };
- }
- /**
- * Middleware that handles request redirects.
- *
- * @return callable Returns a function that accepts the next handler.
- */
- public static function redirect() : callable
- {
- return static function (callable $handler) : RedirectMiddleware {
- return new RedirectMiddleware($handler);
- };
- }
- /**
- * Middleware that retries requests based on the boolean result of
- * invoking the provided "decider" function.
- *
- * If no delay function is provided, a simple implementation of exponential
- * backoff will be utilized.
- *
- * @param callable $decider Function that accepts the number of retries,
- * a request, [response], and [exception] and
- * returns true if the request is to be retried.
- * @param callable $delay Function that accepts the number of retries and
- * returns the number of milliseconds to delay.
- *
- * @return callable Returns a function that accepts the next handler.
- */
- public static function retry(callable $decider, callable $delay = null) : callable
- {
- return static function (callable $handler) use($decider, $delay) : RetryMiddleware {
- return new RetryMiddleware($decider, $handler, $delay);
- };
- }
- /**
- * Middleware that logs requests, responses, and errors using a message
- * formatter.
- *
- * @phpstan-param \Psr\Log\LogLevel::* $logLevel Level at which to log requests.
- *
- * @param LoggerInterface $logger Logs messages.
- * @param MessageFormatterInterface|MessageFormatter $formatter Formatter used to create message strings.
- * @param string $logLevel Level at which to log requests.
- *
- * @return callable Returns a function that accepts the next handler.
- */
- public static function log(LoggerInterface $logger, $formatter, string $logLevel = 'info') : callable
- {
- // To be compatible with Guzzle 7.1.x we need to allow users to pass a MessageFormatter
- if (!$formatter instanceof MessageFormatter && !$formatter instanceof MessageFormatterInterface) {
- throw new \LogicException(sprintf('Argument 2 to %s::log() must be of type %s', self::class, MessageFormatterInterface::class));
- }
- return static function (callable $handler) use($logger, $formatter, $logLevel) : callable {
- return static function (RequestInterface $request, array $options = []) use($handler, $logger, $formatter, $logLevel) {
- return $handler($request, $options)->then(static function ($response) use($logger, $request, $formatter, $logLevel) : ResponseInterface {
- $message = $formatter->format($request, $response);
- $logger->log($logLevel, $message);
- return $response;
- }, static function ($reason) use($logger, $request, $formatter) : PromiseInterface {
- $response = $reason instanceof RequestException ? $reason->getResponse() : null;
- $message = $formatter->format($request, $response, P\Create::exceptionFor($reason));
- $logger->error($message);
- return P\Create::rejectionFor($reason);
- });
- };
- };
- }
- /**
- * This middleware adds a default content-type if possible, a default
- * content-length or transfer-encoding header, and the expect header.
- */
- public static function prepareBody() : callable
- {
- return static function (callable $handler) : PrepareBodyMiddleware {
- return new PrepareBodyMiddleware($handler);
- };
- }
- /**
- * Middleware that applies a map function to the request before passing to
- * the next handler.
- *
- * @param callable $fn Function that accepts a RequestInterface and returns
- * a RequestInterface.
- */
- public static function mapRequest(callable $fn) : callable
- {
- return static function (callable $handler) use($fn) : callable {
- return static function (RequestInterface $request, array $options) use($handler, $fn) {
- return $handler($fn($request), $options);
- };
- };
- }
- /**
- * Middleware that applies a map function to the resolved promise's
- * response.
- *
- * @param callable $fn Function that accepts a ResponseInterface and
- * returns a ResponseInterface.
- */
- public static function mapResponse(callable $fn) : callable
- {
- return static function (callable $handler) use($fn) : callable {
- return static function (RequestInterface $request, array $options) use($handler, $fn) {
- return $handler($request, $options)->then($fn);
- };
- };
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/guzzle/src/Pool.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/guzzle/src/Pool.php
deleted file mode 100644
index 7899284..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/guzzle/src/Pool.php
+++ /dev/null
@@ -1,116 +0,0 @@
- $rfn) {
- if ($rfn instanceof RequestInterface) {
- (yield $key => $client->sendAsync($rfn, $opts));
- } elseif (\is_callable($rfn)) {
- (yield $key => $rfn($opts));
- } else {
- throw new \InvalidArgumentException('Each value yielded by the iterator must be a Psr7\\Http\\Message\\RequestInterface or a callable that returns a promise that fulfills with a Psr7\\Message\\Http\\ResponseInterface object.');
- }
- }
- };
- $this->each = new EachPromise($requests(), $config);
- }
- /**
- * Get promise
- */
- public function promise() : PromiseInterface
- {
- return $this->each->promise();
- }
- /**
- * Sends multiple requests concurrently and returns an array of responses
- * and exceptions that uses the same ordering as the provided requests.
- *
- * IMPORTANT: This method keeps every request and response in memory, and
- * as such, is NOT recommended when sending a large number or an
- * indeterminate number of requests concurrently.
- *
- * @param ClientInterface $client Client used to send the requests
- * @param array|\Iterator $requests Requests to send concurrently.
- * @param array $options Passes through the options available in
- * {@see \GuzzleHttp\Pool::__construct}
- *
- * @return array Returns an array containing the response or an exception
- * in the same order that the requests were sent.
- *
- * @throws \InvalidArgumentException if the event format is incorrect.
- */
- public static function batch(ClientInterface $client, $requests, array $options = []) : array
- {
- $res = [];
- self::cmpCallback($options, 'fulfilled', $res);
- self::cmpCallback($options, 'rejected', $res);
- $pool = new static($client, $requests, $options);
- $pool->promise()->wait();
- \ksort($res);
- return $res;
- }
- /**
- * Execute callback(s)
- */
- private static function cmpCallback(array &$options, string $name, array &$results) : void
- {
- if (!isset($options[$name])) {
- $options[$name] = static function ($v, $k) use(&$results) {
- $results[$k] = $v;
- };
- } else {
- $currentFn = $options[$name];
- $options[$name] = static function ($v, $k) use(&$results, $currentFn) {
- $currentFn($v, $k);
- $results[$k] = $v;
- };
- }
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/guzzle/src/PrepareBodyMiddleware.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/guzzle/src/PrepareBodyMiddleware.php
deleted file mode 100644
index e73fd20..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/guzzle/src/PrepareBodyMiddleware.php
+++ /dev/null
@@ -1,86 +0,0 @@
-nextHandler = $nextHandler;
- }
- public function __invoke(RequestInterface $request, array $options) : PromiseInterface
- {
- $fn = $this->nextHandler;
- // Don't do anything if the request has no body.
- if ($request->getBody()->getSize() === 0) {
- return $fn($request, $options);
- }
- $modify = [];
- // Add a default content-type if possible.
- if (!$request->hasHeader('Content-Type')) {
- if ($uri = $request->getBody()->getMetadata('uri')) {
- if (is_string($uri) && ($type = Psr7\MimeType::fromFilename($uri))) {
- $modify['set_headers']['Content-Type'] = $type;
- }
- }
- }
- // Add a default content-length or transfer-encoding header.
- if (!$request->hasHeader('Content-Length') && !$request->hasHeader('Transfer-Encoding')) {
- $size = $request->getBody()->getSize();
- if ($size !== null) {
- $modify['set_headers']['Content-Length'] = $size;
- } else {
- $modify['set_headers']['Transfer-Encoding'] = 'chunked';
- }
- }
- // Add the expect header if needed.
- $this->addExpectHeader($request, $options, $modify);
- return $fn(Psr7\Utils::modifyRequest($request, $modify), $options);
- }
- /**
- * Add expect header
- */
- private function addExpectHeader(RequestInterface $request, array $options, array &$modify) : void
- {
- // Determine if the Expect header should be used
- if ($request->hasHeader('Expect')) {
- return;
- }
- $expect = $options['expect'] ?? null;
- // Return if disabled or if you're not using HTTP/1.1 or HTTP/2.0
- if ($expect === \false || $request->getProtocolVersion() < 1.1) {
- return;
- }
- // The expect header is unconditionally enabled
- if ($expect === \true) {
- $modify['set_headers']['Expect'] = '100-Continue';
- return;
- }
- // By default, send the expect header when the payload is > 1mb
- if ($expect === null) {
- $expect = 1048576;
- }
- // Always add if the body cannot be rewound, the size cannot be
- // determined, or the size is greater than the cutoff threshold
- $body = $request->getBody();
- $size = $body->getSize();
- if ($size === null || $size >= (int) $expect || !$body->isSeekable()) {
- $modify['set_headers']['Expect'] = '100-Continue';
- }
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/guzzle/src/RedirectMiddleware.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/guzzle/src/RedirectMiddleware.php
deleted file mode 100644
index ae4feea..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/guzzle/src/RedirectMiddleware.php
+++ /dev/null
@@ -1,162 +0,0 @@
- 5, 'protocols' => ['http', 'https'], 'strict' => \false, 'referer' => \false, 'track_redirects' => \false];
- /**
- * @var callable(RequestInterface, array): PromiseInterface
- */
- private $nextHandler;
- /**
- * @param callable(RequestInterface, array): PromiseInterface $nextHandler Next handler to invoke.
- */
- public function __construct(callable $nextHandler)
- {
- $this->nextHandler = $nextHandler;
- }
- public function __invoke(RequestInterface $request, array $options) : PromiseInterface
- {
- $fn = $this->nextHandler;
- if (empty($options['allow_redirects'])) {
- return $fn($request, $options);
- }
- if ($options['allow_redirects'] === \true) {
- $options['allow_redirects'] = self::$defaultSettings;
- } elseif (!\is_array($options['allow_redirects'])) {
- throw new \InvalidArgumentException('allow_redirects must be true, false, or array');
- } else {
- // Merge the default settings with the provided settings
- $options['allow_redirects'] += self::$defaultSettings;
- }
- if (empty($options['allow_redirects']['max'])) {
- return $fn($request, $options);
- }
- return $fn($request, $options)->then(function (ResponseInterface $response) use($request, $options) {
- return $this->checkRedirect($request, $options, $response);
- });
- }
- /**
- * @return ResponseInterface|PromiseInterface
- */
- public function checkRedirect(RequestInterface $request, array $options, ResponseInterface $response)
- {
- if (\strpos((string) $response->getStatusCode(), '3') !== 0 || !$response->hasHeader('Location')) {
- return $response;
- }
- $this->guardMax($request, $response, $options);
- $nextRequest = $this->modifyRequest($request, $options, $response);
- // If authorization is handled by curl, unset it if URI is cross-origin.
- if (Psr7\UriComparator::isCrossOrigin($request->getUri(), $nextRequest->getUri()) && defined('\\CURLOPT_HTTPAUTH')) {
- unset($options['curl'][\CURLOPT_HTTPAUTH], $options['curl'][\CURLOPT_USERPWD]);
- }
- if (isset($options['allow_redirects']['on_redirect'])) {
- $options['allow_redirects']['on_redirect']($request, $response, $nextRequest->getUri());
- }
- $promise = $this($nextRequest, $options);
- // Add headers to be able to track history of redirects.
- if (!empty($options['allow_redirects']['track_redirects'])) {
- return $this->withTracking($promise, (string) $nextRequest->getUri(), $response->getStatusCode());
- }
- return $promise;
- }
- /**
- * Enable tracking on promise.
- */
- private function withTracking(PromiseInterface $promise, string $uri, int $statusCode) : PromiseInterface
- {
- return $promise->then(static function (ResponseInterface $response) use($uri, $statusCode) {
- // Note that we are pushing to the front of the list as this
- // would be an earlier response than what is currently present
- // in the history header.
- $historyHeader = $response->getHeader(self::HISTORY_HEADER);
- $statusHeader = $response->getHeader(self::STATUS_HISTORY_HEADER);
- \array_unshift($historyHeader, $uri);
- \array_unshift($statusHeader, (string) $statusCode);
- return $response->withHeader(self::HISTORY_HEADER, $historyHeader)->withHeader(self::STATUS_HISTORY_HEADER, $statusHeader);
- });
- }
- /**
- * Check for too many redirects.
- *
- * @throws TooManyRedirectsException Too many redirects.
- */
- private function guardMax(RequestInterface $request, ResponseInterface $response, array &$options) : void
- {
- $current = $options['__redirect_count'] ?? 0;
- $options['__redirect_count'] = $current + 1;
- $max = $options['allow_redirects']['max'];
- if ($options['__redirect_count'] > $max) {
- throw new TooManyRedirectsException("Will not follow more than {$max} redirects", $request, $response);
- }
- }
- public function modifyRequest(RequestInterface $request, array $options, ResponseInterface $response) : RequestInterface
- {
- // Request modifications to apply.
- $modify = [];
- $protocols = $options['allow_redirects']['protocols'];
- // Use a GET request if this is an entity enclosing request and we are
- // not forcing RFC compliance, but rather emulating what all browsers
- // would do.
- $statusCode = $response->getStatusCode();
- if ($statusCode == 303 || $statusCode <= 302 && !$options['allow_redirects']['strict']) {
- $safeMethods = ['GET', 'HEAD', 'OPTIONS'];
- $requestMethod = $request->getMethod();
- $modify['method'] = in_array($requestMethod, $safeMethods) ? $requestMethod : 'GET';
- $modify['body'] = '';
- }
- $uri = self::redirectUri($request, $response, $protocols);
- if (isset($options['idn_conversion']) && $options['idn_conversion'] !== \false) {
- $idnOptions = $options['idn_conversion'] === \true ? \IDNA_DEFAULT : $options['idn_conversion'];
- $uri = Utils::idnUriConvert($uri, $idnOptions);
- }
- $modify['uri'] = $uri;
- Psr7\Message::rewindBody($request);
- // Add the Referer header if it is told to do so and only
- // add the header if we are not redirecting from https to http.
- if ($options['allow_redirects']['referer'] && $modify['uri']->getScheme() === $request->getUri()->getScheme()) {
- $uri = $request->getUri()->withUserInfo('');
- $modify['set_headers']['Referer'] = (string) $uri;
- } else {
- $modify['remove_headers'][] = 'Referer';
- }
- // Remove Authorization and Cookie headers if URI is cross-origin.
- if (Psr7\UriComparator::isCrossOrigin($request->getUri(), $modify['uri'])) {
- $modify['remove_headers'][] = 'Authorization';
- $modify['remove_headers'][] = 'Cookie';
- }
- return Psr7\Utils::modifyRequest($request, $modify);
- }
- /**
- * Set the appropriate URL on the request based on the location header.
- */
- private static function redirectUri(RequestInterface $request, ResponseInterface $response, array $protocols) : UriInterface
- {
- $location = Psr7\UriResolver::resolve($request->getUri(), new Psr7\Uri($response->getHeaderLine('Location')));
- // Ensure that the redirect URI is allowed based on the protocols.
- if (!\in_array($location->getScheme(), $protocols)) {
- throw new BadResponseException(\sprintf('Redirect URI, %s, does not use one of the allowed redirect protocols: %s', $location, \implode(', ', $protocols)), $request, $response);
- }
- return $location;
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/guzzle/src/RequestOptions.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/guzzle/src/RequestOptions.php
deleted file mode 100644
index 1e7a146..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/guzzle/src/RequestOptions.php
+++ /dev/null
@@ -1,244 +0,0 @@
-decider = $decider;
- $this->nextHandler = $nextHandler;
- $this->delay = $delay ?: __CLASS__ . '::exponentialDelay';
- }
- /**
- * Default exponential backoff delay function.
- *
- * @return int milliseconds.
- */
- public static function exponentialDelay(int $retries) : int
- {
- return (int) 2 ** ($retries - 1) * 1000;
- }
- public function __invoke(RequestInterface $request, array $options) : PromiseInterface
- {
- if (!isset($options['retries'])) {
- $options['retries'] = 0;
- }
- $fn = $this->nextHandler;
- return $fn($request, $options)->then($this->onFulfilled($request, $options), $this->onRejected($request, $options));
- }
- /**
- * Execute fulfilled closure
- */
- private function onFulfilled(RequestInterface $request, array $options) : callable
- {
- return function ($value) use($request, $options) {
- if (!($this->decider)($options['retries'], $request, $value, null)) {
- return $value;
- }
- return $this->doRetry($request, $options, $value);
- };
- }
- /**
- * Execute rejected closure
- */
- private function onRejected(RequestInterface $req, array $options) : callable
- {
- return function ($reason) use($req, $options) {
- if (!($this->decider)($options['retries'], $req, null, $reason)) {
- return P\Create::rejectionFor($reason);
- }
- return $this->doRetry($req, $options);
- };
- }
- private function doRetry(RequestInterface $request, array $options, ResponseInterface $response = null) : PromiseInterface
- {
- $options['delay'] = ($this->delay)(++$options['retries'], $response, $request);
- return $this($request, $options);
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/guzzle/src/TransferStats.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/guzzle/src/TransferStats.php
deleted file mode 100644
index 98c93e3..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/guzzle/src/TransferStats.php
+++ /dev/null
@@ -1,114 +0,0 @@
-request = $request;
- $this->response = $response;
- $this->transferTime = $transferTime;
- $this->handlerErrorData = $handlerErrorData;
- $this->handlerStats = $handlerStats;
- }
- public function getRequest() : RequestInterface
- {
- return $this->request;
- }
- /**
- * Returns the response that was received (if any).
- */
- public function getResponse() : ?ResponseInterface
- {
- return $this->response;
- }
- /**
- * Returns true if a response was received.
- */
- public function hasResponse() : bool
- {
- return $this->response !== null;
- }
- /**
- * Gets handler specific error data.
- *
- * This might be an exception, a integer representing an error code, or
- * anything else. Relying on this value assumes that you know what handler
- * you are using.
- *
- * @return mixed
- */
- public function getHandlerErrorData()
- {
- return $this->handlerErrorData;
- }
- /**
- * Get the effective URI the request was sent to.
- */
- public function getEffectiveUri() : UriInterface
- {
- return $this->request->getUri();
- }
- /**
- * Get the estimated time the request was being transferred by the handler.
- *
- * @return float|null Time in seconds.
- */
- public function getTransferTime() : ?float
- {
- return $this->transferTime;
- }
- /**
- * Gets an array of all of the handler specific transfer data.
- */
- public function getHandlerStats() : array
- {
- return $this->handlerStats;
- }
- /**
- * Get a specific handler statistic from the handler by name.
- *
- * @param string $stat Handler specific transfer stat to retrieve.
- *
- * @return mixed|null
- */
- public function getHandlerStat(string $stat)
- {
- return $this->handlerStats[$stat] ?? null;
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/guzzle/src/Utils.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/guzzle/src/Utils.php
deleted file mode 100644
index af3e1d1..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/guzzle/src/Utils.php
+++ /dev/null
@@ -1,339 +0,0 @@
-getHost()) {
- $asciiHost = self::idnToAsci($uri->getHost(), $options, $info);
- if ($asciiHost === \false) {
- $errorBitSet = $info['errors'] ?? 0;
- $errorConstants = array_filter(array_keys(get_defined_constants()), static function (string $name) : bool {
- return substr($name, 0, 11) === 'IDNA_ERROR_';
- });
- $errors = [];
- foreach ($errorConstants as $errorConstant) {
- if ($errorBitSet & constant($errorConstant)) {
- $errors[] = $errorConstant;
- }
- }
- $errorMessage = 'IDN conversion failed';
- if ($errors) {
- $errorMessage .= ' (errors: ' . implode(', ', $errors) . ')';
- }
- throw new InvalidArgumentException($errorMessage);
- }
- if ($uri->getHost() !== $asciiHost) {
- // Replace URI only if the ASCII version is different
- $uri = $uri->withHost($asciiHost);
- }
- }
- return $uri;
- }
- /**
- * @internal
- */
- public static function getenv(string $name) : ?string
- {
- if (isset($_SERVER[$name])) {
- return (string) $_SERVER[$name];
- }
- if (\PHP_SAPI === 'cli' && ($value = \getenv($name)) !== \false && $value !== null) {
- return (string) $value;
- }
- return null;
- }
- /**
- * @return string|false
- */
- private static function idnToAsci(string $domain, int $options, ?array &$info = [])
- {
- if (\function_exists('idn_to_ascii') && \defined('INTL_IDNA_VARIANT_UTS46')) {
- return \idn_to_ascii($domain, $options, \INTL_IDNA_VARIANT_UTS46, $info);
- }
- throw new \Error('ext-idn or symfony/polyfill-intl-idn not loaded or too old');
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/guzzle/src/functions.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/guzzle/src/functions.php
deleted file mode 100644
index bb1edf3..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/guzzle/src/functions.php
+++ /dev/null
@@ -1,158 +0,0 @@
-
-Copyright (c) 2015 Graham Campbell
-Copyright (c) 2017 Tobias Schultze
-Copyright (c) 2020 Tobias Nyholm
-
-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/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/promises/src/AggregateException.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/promises/src/AggregateException.php
deleted file mode 100644
index 3fb0645..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/promises/src/AggregateException.php
+++ /dev/null
@@ -1,14 +0,0 @@
-then(function ($v) { echo $v; });
- *
- * @param callable $generatorFn Generator function to wrap into a promise.
- *
- * @return Promise
- *
- * @link https://github.com/petkaantonov/bluebird/blob/master/API.md#generators inspiration
- */
-final class Coroutine implements PromiseInterface
-{
- /**
- * @var PromiseInterface|null
- */
- private $currentPromise;
- /**
- * @var Generator
- */
- private $generator;
- /**
- * @var Promise
- */
- private $result;
- public function __construct(callable $generatorFn)
- {
- $this->generator = $generatorFn();
- $this->result = new Promise(function () {
- while (isset($this->currentPromise)) {
- $this->currentPromise->wait();
- }
- });
- try {
- $this->nextCoroutine($this->generator->current());
- } catch (\Exception $exception) {
- $this->result->reject($exception);
- } catch (Throwable $throwable) {
- $this->result->reject($throwable);
- }
- }
- /**
- * Create a new coroutine.
- *
- * @return self
- */
- public static function of(callable $generatorFn)
- {
- return new self($generatorFn);
- }
- public function then(callable $onFulfilled = null, callable $onRejected = null)
- {
- return $this->result->then($onFulfilled, $onRejected);
- }
- public function otherwise(callable $onRejected)
- {
- return $this->result->otherwise($onRejected);
- }
- public function wait($unwrap = \true)
- {
- return $this->result->wait($unwrap);
- }
- public function getState()
- {
- return $this->result->getState();
- }
- public function resolve($value)
- {
- $this->result->resolve($value);
- }
- public function reject($reason)
- {
- $this->result->reject($reason);
- }
- public function cancel()
- {
- $this->currentPromise->cancel();
- $this->result->cancel();
- }
- private function nextCoroutine($yielded)
- {
- $this->currentPromise = Create::promiseFor($yielded)->then([$this, '_handleSuccess'], [$this, '_handleFailure']);
- }
- /**
- * @internal
- */
- public function _handleSuccess($value)
- {
- unset($this->currentPromise);
- try {
- $next = $this->generator->send($value);
- if ($this->generator->valid()) {
- $this->nextCoroutine($next);
- } else {
- $this->result->resolve($value);
- }
- } catch (Exception $exception) {
- $this->result->reject($exception);
- } catch (Throwable $throwable) {
- $this->result->reject($throwable);
- }
- }
- /**
- * @internal
- */
- public function _handleFailure($reason)
- {
- unset($this->currentPromise);
- try {
- $nextYield = $this->generator->throw(Create::exceptionFor($reason));
- // The throw was caught, so keep iterating on the coroutine
- $this->nextCoroutine($nextYield);
- } catch (Exception $exception) {
- $this->result->reject($exception);
- } catch (Throwable $throwable) {
- $this->result->reject($throwable);
- }
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/promises/src/Create.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/promises/src/Create.php
deleted file mode 100644
index 6886ad1..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/promises/src/Create.php
+++ /dev/null
@@ -1,75 +0,0 @@
-then([$promise, 'resolve'], [$promise, 'reject']);
- return $promise;
- }
- return new FulfilledPromise($value);
- }
- /**
- * Creates a rejected promise for a reason if the reason is not a promise.
- * If the provided reason is a promise, then it is returned as-is.
- *
- * @param mixed $reason Promise or reason.
- *
- * @return PromiseInterface
- */
- public static function rejectionFor($reason)
- {
- if ($reason instanceof PromiseInterface) {
- return $reason;
- }
- return new RejectedPromise($reason);
- }
- /**
- * Create an exception for a rejected promise value.
- *
- * @param mixed $reason
- *
- * @return \Exception|\Throwable
- */
- public static function exceptionFor($reason)
- {
- if ($reason instanceof \Exception || $reason instanceof \Throwable) {
- return $reason;
- }
- return new RejectionException($reason);
- }
- /**
- * Returns an iterator for the given value.
- *
- * @param mixed $value
- *
- * @return \Iterator
- */
- public static function iterFor($value)
- {
- if ($value instanceof \Iterator) {
- return $value;
- }
- if (is_array($value)) {
- return new \ArrayIterator($value);
- }
- return new \ArrayIterator([$value]);
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/promises/src/Each.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/promises/src/Each.php
deleted file mode 100644
index a8b1cd4..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/promises/src/Each.php
+++ /dev/null
@@ -1,66 +0,0 @@
- $onFulfilled, 'rejected' => $onRejected]))->promise();
- }
- /**
- * Like of, but only allows a certain number of outstanding promises at any
- * given time.
- *
- * $concurrency may be an integer or a function that accepts the number of
- * pending promises and returns a numeric concurrency limit value to allow
- * for dynamic a concurrency size.
- *
- * @param mixed $iterable
- * @param int|callable $concurrency
- * @param callable $onFulfilled
- * @param callable $onRejected
- *
- * @return PromiseInterface
- */
- public static function ofLimit($iterable, $concurrency, callable $onFulfilled = null, callable $onRejected = null)
- {
- return (new EachPromise($iterable, ['fulfilled' => $onFulfilled, 'rejected' => $onRejected, 'concurrency' => $concurrency]))->promise();
- }
- /**
- * Like limit, but ensures that no promise in the given $iterable argument
- * is rejected. If any promise is rejected, then the aggregate promise is
- * rejected with the encountered rejection.
- *
- * @param mixed $iterable
- * @param int|callable $concurrency
- * @param callable $onFulfilled
- *
- * @return PromiseInterface
- */
- public static function ofLimitAll($iterable, $concurrency, callable $onFulfilled = null)
- {
- return self::ofLimit($iterable, $concurrency, $onFulfilled, function ($reason, $idx, PromiseInterface $aggregate) {
- $aggregate->reject($reason);
- });
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/promises/src/EachPromise.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/promises/src/EachPromise.php
deleted file mode 100644
index f11752f..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/promises/src/EachPromise.php
+++ /dev/null
@@ -1,200 +0,0 @@
-iterable = Create::iterFor($iterable);
- if (isset($config['concurrency'])) {
- $this->concurrency = $config['concurrency'];
- }
- if (isset($config['fulfilled'])) {
- $this->onFulfilled = $config['fulfilled'];
- }
- if (isset($config['rejected'])) {
- $this->onRejected = $config['rejected'];
- }
- }
- /** @psalm-suppress InvalidNullableReturnType */
- public function promise()
- {
- if ($this->aggregate) {
- return $this->aggregate;
- }
- try {
- $this->createPromise();
- /** @psalm-assert Promise $this->aggregate */
- $this->iterable->rewind();
- $this->refillPending();
- } catch (\Throwable $e) {
- $this->aggregate->reject($e);
- } catch (\Exception $e) {
- $this->aggregate->reject($e);
- }
- /**
- * @psalm-suppress NullableReturnStatement
- * @phpstan-ignore-next-line
- */
- return $this->aggregate;
- }
- private function createPromise()
- {
- $this->mutex = \false;
- $this->aggregate = new Promise(function () {
- if ($this->checkIfFinished()) {
- return;
- }
- reset($this->pending);
- // Consume a potentially fluctuating list of promises while
- // ensuring that indexes are maintained (precluding array_shift).
- while ($promise = current($this->pending)) {
- next($this->pending);
- $promise->wait();
- if (Is::settled($this->aggregate)) {
- return;
- }
- }
- });
- // Clear the references when the promise is resolved.
- $clearFn = function () {
- $this->iterable = $this->concurrency = $this->pending = null;
- $this->onFulfilled = $this->onRejected = null;
- $this->nextPendingIndex = 0;
- };
- $this->aggregate->then($clearFn, $clearFn);
- }
- private function refillPending()
- {
- if (!$this->concurrency) {
- // Add all pending promises.
- while ($this->addPending() && $this->advanceIterator()) {
- }
- return;
- }
- // Add only up to N pending promises.
- $concurrency = is_callable($this->concurrency) ? call_user_func($this->concurrency, count($this->pending)) : $this->concurrency;
- $concurrency = max($concurrency - count($this->pending), 0);
- // Concurrency may be set to 0 to disallow new promises.
- if (!$concurrency) {
- return;
- }
- // Add the first pending promise.
- $this->addPending();
- // Note this is special handling for concurrency=1 so that we do
- // not advance the iterator after adding the first promise. This
- // helps work around issues with generators that might not have the
- // next value to yield until promise callbacks are called.
- while (--$concurrency && $this->advanceIterator() && $this->addPending()) {
- }
- }
- private function addPending()
- {
- if (!$this->iterable || !$this->iterable->valid()) {
- return \false;
- }
- $promise = Create::promiseFor($this->iterable->current());
- $key = $this->iterable->key();
- // Iterable keys may not be unique, so we use a counter to
- // guarantee uniqueness
- $idx = $this->nextPendingIndex++;
- $this->pending[$idx] = $promise->then(function ($value) use($idx, $key) {
- if ($this->onFulfilled) {
- call_user_func($this->onFulfilled, $value, $key, $this->aggregate);
- }
- $this->step($idx);
- }, function ($reason) use($idx, $key) {
- if ($this->onRejected) {
- call_user_func($this->onRejected, $reason, $key, $this->aggregate);
- }
- $this->step($idx);
- });
- return \true;
- }
- private function advanceIterator()
- {
- // Place a lock on the iterator so that we ensure to not recurse,
- // preventing fatal generator errors.
- if ($this->mutex) {
- return \false;
- }
- $this->mutex = \true;
- try {
- $this->iterable->next();
- $this->mutex = \false;
- return \true;
- } catch (\Throwable $e) {
- $this->aggregate->reject($e);
- $this->mutex = \false;
- return \false;
- } catch (\Exception $e) {
- $this->aggregate->reject($e);
- $this->mutex = \false;
- return \false;
- }
- }
- private function step($idx)
- {
- // If the promise was already resolved, then ignore this step.
- if (Is::settled($this->aggregate)) {
- return;
- }
- unset($this->pending[$idx]);
- // Only refill pending promises if we are not locked, preventing the
- // EachPromise to recursively invoke the provided iterator, which
- // cause a fatal error: "Cannot resume an already running generator"
- if ($this->advanceIterator() && !$this->checkIfFinished()) {
- // Add more pending promises if possible.
- $this->refillPending();
- }
- }
- private function checkIfFinished()
- {
- if (!$this->pending && !$this->iterable->valid()) {
- // Resolve the promise if there's nothing left to do.
- $this->aggregate->resolve(null);
- return \true;
- }
- return \false;
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/promises/src/FulfilledPromise.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/promises/src/FulfilledPromise.php
deleted file mode 100644
index c54b568..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/promises/src/FulfilledPromise.php
+++ /dev/null
@@ -1,69 +0,0 @@
-value = $value;
- }
- public function then(callable $onFulfilled = null, callable $onRejected = null)
- {
- // Return itself if there is no onFulfilled function.
- if (!$onFulfilled) {
- return $this;
- }
- $queue = Utils::queue();
- $p = new Promise([$queue, 'run']);
- $value = $this->value;
- $queue->add(static function () use($p, $value, $onFulfilled) {
- if (Is::pending($p)) {
- try {
- $p->resolve($onFulfilled($value));
- } catch (\Throwable $e) {
- $p->reject($e);
- } catch (\Exception $e) {
- $p->reject($e);
- }
- }
- });
- return $p;
- }
- public function otherwise(callable $onRejected)
- {
- return $this->then(null, $onRejected);
- }
- public function wait($unwrap = \true, $defaultDelivery = null)
- {
- return $unwrap ? $this->value : null;
- }
- public function getState()
- {
- return self::FULFILLED;
- }
- public function resolve($value)
- {
- if ($value !== $this->value) {
- throw new \LogicException("Cannot resolve a fulfilled promise");
- }
- }
- public function reject($reason)
- {
- throw new \LogicException("Cannot reject a fulfilled promise");
- }
- public function cancel()
- {
- // pass
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/promises/src/Is.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/promises/src/Is.php
deleted file mode 100644
index 64b7554..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/promises/src/Is.php
+++ /dev/null
@@ -1,43 +0,0 @@
-getState() === PromiseInterface::PENDING;
- }
- /**
- * Returns true if a promise is fulfilled or rejected.
- *
- * @return bool
- */
- public static function settled(PromiseInterface $promise)
- {
- return $promise->getState() !== PromiseInterface::PENDING;
- }
- /**
- * Returns true if a promise is fulfilled.
- *
- * @return bool
- */
- public static function fulfilled(PromiseInterface $promise)
- {
- return $promise->getState() === PromiseInterface::FULFILLED;
- }
- /**
- * Returns true if a promise is rejected.
- *
- * @return bool
- */
- public static function rejected(PromiseInterface $promise)
- {
- return $promise->getState() === PromiseInterface::REJECTED;
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/promises/src/Promise.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/promises/src/Promise.php
deleted file mode 100644
index 5b7a591..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/promises/src/Promise.php
+++ /dev/null
@@ -1,237 +0,0 @@
-waitFn = $waitFn;
- $this->cancelFn = $cancelFn;
- }
- public function then(callable $onFulfilled = null, callable $onRejected = null)
- {
- if ($this->state === self::PENDING) {
- $p = new Promise(null, [$this, 'cancel']);
- $this->handlers[] = [$p, $onFulfilled, $onRejected];
- $p->waitList = $this->waitList;
- $p->waitList[] = $this;
- return $p;
- }
- // Return a fulfilled promise and immediately invoke any callbacks.
- if ($this->state === self::FULFILLED) {
- $promise = Create::promiseFor($this->result);
- return $onFulfilled ? $promise->then($onFulfilled) : $promise;
- }
- // It's either cancelled or rejected, so return a rejected promise
- // and immediately invoke any callbacks.
- $rejection = Create::rejectionFor($this->result);
- return $onRejected ? $rejection->then(null, $onRejected) : $rejection;
- }
- public function otherwise(callable $onRejected)
- {
- return $this->then(null, $onRejected);
- }
- public function wait($unwrap = \true)
- {
- $this->waitIfPending();
- if ($this->result instanceof PromiseInterface) {
- return $this->result->wait($unwrap);
- }
- if ($unwrap) {
- if ($this->state === self::FULFILLED) {
- return $this->result;
- }
- // It's rejected so "unwrap" and throw an exception.
- throw Create::exceptionFor($this->result);
- }
- }
- public function getState()
- {
- return $this->state;
- }
- public function cancel()
- {
- if ($this->state !== self::PENDING) {
- return;
- }
- $this->waitFn = $this->waitList = null;
- if ($this->cancelFn) {
- $fn = $this->cancelFn;
- $this->cancelFn = null;
- try {
- $fn();
- } catch (\Throwable $e) {
- $this->reject($e);
- } catch (\Exception $e) {
- $this->reject($e);
- }
- }
- // Reject the promise only if it wasn't rejected in a then callback.
- /** @psalm-suppress RedundantCondition */
- if ($this->state === self::PENDING) {
- $this->reject(new CancellationException('Promise has been cancelled'));
- }
- }
- public function resolve($value)
- {
- $this->settle(self::FULFILLED, $value);
- }
- public function reject($reason)
- {
- $this->settle(self::REJECTED, $reason);
- }
- private function settle($state, $value)
- {
- if ($this->state !== self::PENDING) {
- // Ignore calls with the same resolution.
- if ($state === $this->state && $value === $this->result) {
- return;
- }
- throw $this->state === $state ? new \LogicException("The promise is already {$state}.") : new \LogicException("Cannot change a {$this->state} promise to {$state}");
- }
- if ($value === $this) {
- throw new \LogicException('Cannot fulfill or reject a promise with itself');
- }
- // Clear out the state of the promise but stash the handlers.
- $this->state = $state;
- $this->result = $value;
- $handlers = $this->handlers;
- $this->handlers = null;
- $this->waitList = $this->waitFn = null;
- $this->cancelFn = null;
- if (!$handlers) {
- return;
- }
- // If the value was not a settled promise or a thenable, then resolve
- // it in the task queue using the correct ID.
- if (!is_object($value) || !method_exists($value, 'then')) {
- $id = $state === self::FULFILLED ? 1 : 2;
- // It's a success, so resolve the handlers in the queue.
- Utils::queue()->add(static function () use($id, $value, $handlers) {
- foreach ($handlers as $handler) {
- self::callHandler($id, $value, $handler);
- }
- });
- } elseif ($value instanceof Promise && Is::pending($value)) {
- // We can just merge our handlers onto the next promise.
- $value->handlers = array_merge($value->handlers, $handlers);
- } else {
- // Resolve the handlers when the forwarded promise is resolved.
- $value->then(static function ($value) use($handlers) {
- foreach ($handlers as $handler) {
- self::callHandler(1, $value, $handler);
- }
- }, static function ($reason) use($handlers) {
- foreach ($handlers as $handler) {
- self::callHandler(2, $reason, $handler);
- }
- });
- }
- }
- /**
- * Call a stack of handlers using a specific callback index and value.
- *
- * @param int $index 1 (resolve) or 2 (reject).
- * @param mixed $value Value to pass to the callback.
- * @param array $handler Array of handler data (promise and callbacks).
- */
- private static function callHandler($index, $value, array $handler)
- {
- /** @var PromiseInterface $promise */
- $promise = $handler[0];
- // The promise may have been cancelled or resolved before placing
- // this thunk in the queue.
- if (Is::settled($promise)) {
- return;
- }
- try {
- if (isset($handler[$index])) {
- /*
- * If $f throws an exception, then $handler will be in the exception
- * stack trace. Since $handler contains a reference to the callable
- * itself we get a circular reference. We clear the $handler
- * here to avoid that memory leak.
- */
- $f = $handler[$index];
- unset($handler);
- $promise->resolve($f($value));
- } elseif ($index === 1) {
- // Forward resolution values as-is.
- $promise->resolve($value);
- } else {
- // Forward rejections down the chain.
- $promise->reject($value);
- }
- } catch (\Throwable $reason) {
- $promise->reject($reason);
- } catch (\Exception $reason) {
- $promise->reject($reason);
- }
- }
- private function waitIfPending()
- {
- if ($this->state !== self::PENDING) {
- return;
- } elseif ($this->waitFn) {
- $this->invokeWaitFn();
- } elseif ($this->waitList) {
- $this->invokeWaitList();
- } else {
- // If there's no wait function, then reject the promise.
- $this->reject('Cannot wait on a promise that has ' . 'no internal wait function. You must provide a wait ' . 'function when constructing the promise to be able to ' . 'wait on a promise.');
- }
- Utils::queue()->run();
- /** @psalm-suppress RedundantCondition */
- if ($this->state === self::PENDING) {
- $this->reject('Invoking the wait callback did not resolve the promise');
- }
- }
- private function invokeWaitFn()
- {
- try {
- $wfn = $this->waitFn;
- $this->waitFn = null;
- $wfn(\true);
- } catch (\Exception $reason) {
- if ($this->state === self::PENDING) {
- // The promise has not been resolved yet, so reject the promise
- // with the exception.
- $this->reject($reason);
- } else {
- // The promise was already resolved, so there's a problem in
- // the application.
- throw $reason;
- }
- }
- }
- private function invokeWaitList()
- {
- $waitList = $this->waitList;
- $this->waitList = null;
- foreach ($waitList as $result) {
- do {
- $result->waitIfPending();
- $result = $result->result;
- } while ($result instanceof Promise);
- if ($result instanceof PromiseInterface) {
- $result->wait(\false);
- }
- }
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/promises/src/PromiseInterface.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/promises/src/PromiseInterface.php
deleted file mode 100644
index e295178..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/promises/src/PromiseInterface.php
+++ /dev/null
@@ -1,87 +0,0 @@
-reason = $reason;
- }
- public function then(callable $onFulfilled = null, callable $onRejected = null)
- {
- // If there's no onRejected callback then just return self.
- if (!$onRejected) {
- return $this;
- }
- $queue = Utils::queue();
- $reason = $this->reason;
- $p = new Promise([$queue, 'run']);
- $queue->add(static function () use($p, $reason, $onRejected) {
- if (Is::pending($p)) {
- try {
- // Return a resolved promise if onRejected does not throw.
- $p->resolve($onRejected($reason));
- } catch (\Throwable $e) {
- // onRejected threw, so return a rejected promise.
- $p->reject($e);
- } catch (\Exception $e) {
- // onRejected threw, so return a rejected promise.
- $p->reject($e);
- }
- }
- });
- return $p;
- }
- public function otherwise(callable $onRejected)
- {
- return $this->then(null, $onRejected);
- }
- public function wait($unwrap = \true, $defaultDelivery = null)
- {
- if ($unwrap) {
- throw Create::exceptionFor($this->reason);
- }
- return null;
- }
- public function getState()
- {
- return self::REJECTED;
- }
- public function resolve($value)
- {
- throw new \LogicException("Cannot resolve a rejected promise");
- }
- public function reject($reason)
- {
- if ($reason !== $this->reason) {
- throw new \LogicException("Cannot reject a rejected promise");
- }
- }
- public function cancel()
- {
- // pass
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/promises/src/RejectionException.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/promises/src/RejectionException.php
deleted file mode 100644
index 484345b..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/promises/src/RejectionException.php
+++ /dev/null
@@ -1,40 +0,0 @@
-reason = $reason;
- $message = 'The promise was rejected';
- if ($description) {
- $message .= ' with reason: ' . $description;
- } elseif (is_string($reason) || is_object($reason) && method_exists($reason, '__toString')) {
- $message .= ' with reason: ' . $this->reason;
- } elseif ($reason instanceof \JsonSerializable) {
- $message .= ' with reason: ' . json_encode($this->reason, \JSON_PRETTY_PRINT);
- }
- parent::__construct($message);
- }
- /**
- * Returns the rejection reason.
- *
- * @return mixed
- */
- public function getReason()
- {
- return $this->reason;
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/promises/src/TaskQueue.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/promises/src/TaskQueue.php
deleted file mode 100644
index 60034de..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/promises/src/TaskQueue.php
+++ /dev/null
@@ -1,62 +0,0 @@
-run();
- */
-class TaskQueue implements TaskQueueInterface
-{
- private $enableShutdown = \true;
- private $queue = [];
- public function __construct($withShutdown = \true)
- {
- if ($withShutdown) {
- register_shutdown_function(function () {
- if ($this->enableShutdown) {
- // Only run the tasks if an E_ERROR didn't occur.
- $err = error_get_last();
- if (!$err || $err['type'] ^ \E_ERROR) {
- $this->run();
- }
- }
- });
- }
- }
- public function isEmpty()
- {
- return !$this->queue;
- }
- public function add(callable $task)
- {
- $this->queue[] = $task;
- }
- public function run()
- {
- while ($task = array_shift($this->queue)) {
- /** @var callable $task */
- $task();
- }
- }
- /**
- * The task queue will be run and exhausted by default when the process
- * exits IFF the exit is not the result of a PHP E_ERROR error.
- *
- * You can disable running the automatic shutdown of the queue by calling
- * this function. If you disable the task queue shutdown process, then you
- * MUST either run the task queue (as a result of running your event loop
- * or manually using the run() method) or wait on each outstanding promise.
- *
- * Note: This shutdown will occur before any destructors are triggered.
- */
- public function disableShutdown()
- {
- $this->enableShutdown = \false;
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/promises/src/TaskQueueInterface.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/promises/src/TaskQueueInterface.php
deleted file mode 100644
index a5fb1f7..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/promises/src/TaskQueueInterface.php
+++ /dev/null
@@ -1,22 +0,0 @@
-
- * while ($eventLoop->isRunning()) {
- * GuzzleHttp\Promise\Utils::queue()->run();
- * }
- *
- *
- * @param TaskQueueInterface $assign Optionally specify a new queue instance.
- *
- * @return TaskQueueInterface
- */
- public static function queue(TaskQueueInterface $assign = null)
- {
- static $queue;
- if ($assign) {
- $queue = $assign;
- } elseif (!$queue) {
- $queue = new TaskQueue();
- }
- return $queue;
- }
- /**
- * Adds a function to run in the task queue when it is next `run()` and
- * returns a promise that is fulfilled or rejected with the result.
- *
- * @param callable $task Task function to run.
- *
- * @return PromiseInterface
- */
- public static function task(callable $task)
- {
- $queue = self::queue();
- $promise = new Promise([$queue, 'run']);
- $queue->add(function () use($task, $promise) {
- try {
- if (Is::pending($promise)) {
- $promise->resolve($task());
- }
- } catch (\Throwable $e) {
- $promise->reject($e);
- } catch (\Exception $e) {
- $promise->reject($e);
- }
- });
- return $promise;
- }
- /**
- * Synchronously waits on a promise to resolve and returns an inspection
- * state array.
- *
- * Returns a state associative array containing a "state" key mapping to a
- * valid promise state. If the state of the promise is "fulfilled", the
- * array will contain a "value" key mapping to the fulfilled value of the
- * promise. If the promise is rejected, the array will contain a "reason"
- * key mapping to the rejection reason of the promise.
- *
- * @param PromiseInterface $promise Promise or value.
- *
- * @return array
- */
- public static function inspect(PromiseInterface $promise)
- {
- try {
- return ['state' => PromiseInterface::FULFILLED, 'value' => $promise->wait()];
- } catch (RejectionException $e) {
- return ['state' => PromiseInterface::REJECTED, 'reason' => $e->getReason()];
- } catch (\Throwable $e) {
- return ['state' => PromiseInterface::REJECTED, 'reason' => $e];
- } catch (\Exception $e) {
- return ['state' => PromiseInterface::REJECTED, 'reason' => $e];
- }
- }
- /**
- * Waits on all of the provided promises, but does not unwrap rejected
- * promises as thrown exception.
- *
- * Returns an array of inspection state arrays.
- *
- * @see inspect for the inspection state array format.
- *
- * @param PromiseInterface[] $promises Traversable of promises to wait upon.
- *
- * @return array
- */
- public static function inspectAll($promises)
- {
- $results = [];
- foreach ($promises as $key => $promise) {
- $results[$key] = self::inspect($promise);
- }
- return $results;
- }
- /**
- * Waits on all of the provided promises and returns the fulfilled values.
- *
- * Returns an array that contains the value of each promise (in the same
- * order the promises were provided). An exception is thrown if any of the
- * promises are rejected.
- *
- * @param iterable $promises Iterable of PromiseInterface objects to wait on.
- *
- * @return array
- *
- * @throws \Exception on error
- * @throws \Throwable on error in PHP >=7
- */
- public static function unwrap($promises)
- {
- $results = [];
- foreach ($promises as $key => $promise) {
- $results[$key] = $promise->wait();
- }
- return $results;
- }
- /**
- * Given an array of promises, return a promise that is fulfilled when all
- * the items in the array are fulfilled.
- *
- * The promise's fulfillment value is an array with fulfillment values at
- * respective positions to the original array. If any promise in the array
- * rejects, the returned promise is rejected with the rejection reason.
- *
- * @param mixed $promises Promises or values.
- * @param bool $recursive If true, resolves new promises that might have been added to the stack during its own resolution.
- *
- * @return PromiseInterface
- */
- public static function all($promises, $recursive = \false)
- {
- $results = [];
- $promise = Each::of($promises, function ($value, $idx) use(&$results) {
- $results[$idx] = $value;
- }, function ($reason, $idx, Promise $aggregate) {
- $aggregate->reject($reason);
- })->then(function () use(&$results) {
- ksort($results);
- return $results;
- });
- if (\true === $recursive) {
- $promise = $promise->then(function ($results) use($recursive, &$promises) {
- foreach ($promises as $promise) {
- if (Is::pending($promise)) {
- return self::all($promises, $recursive);
- }
- }
- return $results;
- });
- }
- return $promise;
- }
- /**
- * Initiate a competitive race between multiple promises or values (values
- * will become immediately fulfilled promises).
- *
- * When count amount of promises have been fulfilled, the returned promise
- * is fulfilled with an array that contains the fulfillment values of the
- * winners in order of resolution.
- *
- * This promise is rejected with a {@see AggregateException} if the number
- * of fulfilled promises is less than the desired $count.
- *
- * @param int $count Total number of promises.
- * @param mixed $promises Promises or values.
- *
- * @return PromiseInterface
- */
- public static function some($count, $promises)
- {
- $results = [];
- $rejections = [];
- return Each::of($promises, function ($value, $idx, PromiseInterface $p) use(&$results, $count) {
- if (Is::settled($p)) {
- return;
- }
- $results[$idx] = $value;
- if (count($results) >= $count) {
- $p->resolve(null);
- }
- }, function ($reason) use(&$rejections) {
- $rejections[] = $reason;
- })->then(function () use(&$results, &$rejections, $count) {
- if (count($results) !== $count) {
- throw new AggregateException('Not enough promises to fulfill count', $rejections);
- }
- ksort($results);
- return array_values($results);
- });
- }
- /**
- * Like some(), with 1 as count. However, if the promise fulfills, the
- * fulfillment value is not an array of 1 but the value directly.
- *
- * @param mixed $promises Promises or values.
- *
- * @return PromiseInterface
- */
- public static function any($promises)
- {
- return self::some(1, $promises)->then(function ($values) {
- return $values[0];
- });
- }
- /**
- * Returns a promise that is fulfilled when all of the provided promises have
- * been fulfilled or rejected.
- *
- * The returned promise is fulfilled with an array of inspection state arrays.
- *
- * @see inspect for the inspection state array format.
- *
- * @param mixed $promises Promises or values.
- *
- * @return PromiseInterface
- */
- public static function settle($promises)
- {
- $results = [];
- return Each::of($promises, function ($value, $idx) use(&$results) {
- $results[$idx] = ['state' => PromiseInterface::FULFILLED, 'value' => $value];
- }, function ($reason, $idx) use(&$results) {
- $results[$idx] = ['state' => PromiseInterface::REJECTED, 'reason' => $reason];
- })->then(function () use(&$results) {
- ksort($results);
- return $results;
- });
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/promises/src/functions.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/promises/src/functions.php
deleted file mode 100644
index 755a324..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/promises/src/functions.php
+++ /dev/null
@@ -1,334 +0,0 @@
-
- * while ($eventLoop->isRunning()) {
- * GuzzleHttp\Promise\queue()->run();
- * }
- *
- *
- * @param TaskQueueInterface $assign Optionally specify a new queue instance.
- *
- * @return TaskQueueInterface
- *
- * @deprecated queue will be removed in guzzlehttp/promises:2.0. Use Utils::queue instead.
- */
-function queue(TaskQueueInterface $assign = null)
-{
- return Utils::queue($assign);
-}
-/**
- * Adds a function to run in the task queue when it is next `run()` and returns
- * a promise that is fulfilled or rejected with the result.
- *
- * @param callable $task Task function to run.
- *
- * @return PromiseInterface
- *
- * @deprecated task will be removed in guzzlehttp/promises:2.0. Use Utils::task instead.
- */
-function task(callable $task)
-{
- return Utils::task($task);
-}
-/**
- * Creates a promise for a value if the value is not a promise.
- *
- * @param mixed $value Promise or value.
- *
- * @return PromiseInterface
- *
- * @deprecated promise_for will be removed in guzzlehttp/promises:2.0. Use Create::promiseFor instead.
- */
-function promise_for($value)
-{
- return Create::promiseFor($value);
-}
-/**
- * Creates a rejected promise for a reason if the reason is not a promise. If
- * the provided reason is a promise, then it is returned as-is.
- *
- * @param mixed $reason Promise or reason.
- *
- * @return PromiseInterface
- *
- * @deprecated rejection_for will be removed in guzzlehttp/promises:2.0. Use Create::rejectionFor instead.
- */
-function rejection_for($reason)
-{
- return Create::rejectionFor($reason);
-}
-/**
- * Create an exception for a rejected promise value.
- *
- * @param mixed $reason
- *
- * @return \Exception|\Throwable
- *
- * @deprecated exception_for will be removed in guzzlehttp/promises:2.0. Use Create::exceptionFor instead.
- */
-function exception_for($reason)
-{
- return Create::exceptionFor($reason);
-}
-/**
- * Returns an iterator for the given value.
- *
- * @param mixed $value
- *
- * @return \Iterator
- *
- * @deprecated iter_for will be removed in guzzlehttp/promises:2.0. Use Create::iterFor instead.
- */
-function iter_for($value)
-{
- return Create::iterFor($value);
-}
-/**
- * Synchronously waits on a promise to resolve and returns an inspection state
- * array.
- *
- * Returns a state associative array containing a "state" key mapping to a
- * valid promise state. If the state of the promise is "fulfilled", the array
- * will contain a "value" key mapping to the fulfilled value of the promise. If
- * the promise is rejected, the array will contain a "reason" key mapping to
- * the rejection reason of the promise.
- *
- * @param PromiseInterface $promise Promise or value.
- *
- * @return array
- *
- * @deprecated inspect will be removed in guzzlehttp/promises:2.0. Use Utils::inspect instead.
- */
-function inspect(PromiseInterface $promise)
-{
- return Utils::inspect($promise);
-}
-/**
- * Waits on all of the provided promises, but does not unwrap rejected promises
- * as thrown exception.
- *
- * Returns an array of inspection state arrays.
- *
- * @see inspect for the inspection state array format.
- *
- * @param PromiseInterface[] $promises Traversable of promises to wait upon.
- *
- * @return array
- *
- * @deprecated inspect will be removed in guzzlehttp/promises:2.0. Use Utils::inspectAll instead.
- */
-function inspect_all($promises)
-{
- return Utils::inspectAll($promises);
-}
-/**
- * Waits on all of the provided promises and returns the fulfilled values.
- *
- * Returns an array that contains the value of each promise (in the same order
- * the promises were provided). An exception is thrown if any of the promises
- * are rejected.
- *
- * @param iterable $promises Iterable of PromiseInterface objects to wait on.
- *
- * @return array
- *
- * @throws \Exception on error
- * @throws \Throwable on error in PHP >=7
- *
- * @deprecated unwrap will be removed in guzzlehttp/promises:2.0. Use Utils::unwrap instead.
- */
-function unwrap($promises)
-{
- return Utils::unwrap($promises);
-}
-/**
- * Given an array of promises, return a promise that is fulfilled when all the
- * items in the array are fulfilled.
- *
- * The promise's fulfillment value is an array with fulfillment values at
- * respective positions to the original array. If any promise in the array
- * rejects, the returned promise is rejected with the rejection reason.
- *
- * @param mixed $promises Promises or values.
- * @param bool $recursive If true, resolves new promises that might have been added to the stack during its own resolution.
- *
- * @return PromiseInterface
- *
- * @deprecated all will be removed in guzzlehttp/promises:2.0. Use Utils::all instead.
- */
-function all($promises, $recursive = \false)
-{
- return Utils::all($promises, $recursive);
-}
-/**
- * Initiate a competitive race between multiple promises or values (values will
- * become immediately fulfilled promises).
- *
- * When count amount of promises have been fulfilled, the returned promise is
- * fulfilled with an array that contains the fulfillment values of the winners
- * in order of resolution.
- *
- * This promise is rejected with a {@see AggregateException} if the number of
- * fulfilled promises is less than the desired $count.
- *
- * @param int $count Total number of promises.
- * @param mixed $promises Promises or values.
- *
- * @return PromiseInterface
- *
- * @deprecated some will be removed in guzzlehttp/promises:2.0. Use Utils::some instead.
- */
-function some($count, $promises)
-{
- return Utils::some($count, $promises);
-}
-/**
- * Like some(), with 1 as count. However, if the promise fulfills, the
- * fulfillment value is not an array of 1 but the value directly.
- *
- * @param mixed $promises Promises or values.
- *
- * @return PromiseInterface
- *
- * @deprecated any will be removed in guzzlehttp/promises:2.0. Use Utils::any instead.
- */
-function any($promises)
-{
- return Utils::any($promises);
-}
-/**
- * Returns a promise that is fulfilled when all of the provided promises have
- * been fulfilled or rejected.
- *
- * The returned promise is fulfilled with an array of inspection state arrays.
- *
- * @see inspect for the inspection state array format.
- *
- * @param mixed $promises Promises or values.
- *
- * @return PromiseInterface
- *
- * @deprecated settle will be removed in guzzlehttp/promises:2.0. Use Utils::settle instead.
- */
-function settle($promises)
-{
- return Utils::settle($promises);
-}
-/**
- * Given an iterator that yields promises or values, returns a promise that is
- * fulfilled with a null value when the iterator has been consumed or the
- * aggregate promise has been fulfilled or rejected.
- *
- * $onFulfilled is a function that accepts the fulfilled value, iterator index,
- * and the aggregate promise. The callback can invoke any necessary side
- * effects and choose to resolve or reject the aggregate if needed.
- *
- * $onRejected is a function that accepts the rejection reason, iterator index,
- * and the aggregate promise. The callback can invoke any necessary side
- * effects and choose to resolve or reject the aggregate if needed.
- *
- * @param mixed $iterable Iterator or array to iterate over.
- * @param callable $onFulfilled
- * @param callable $onRejected
- *
- * @return PromiseInterface
- *
- * @deprecated each will be removed in guzzlehttp/promises:2.0. Use Each::of instead.
- */
-function each($iterable, callable $onFulfilled = null, callable $onRejected = null)
-{
- return Each::of($iterable, $onFulfilled, $onRejected);
-}
-/**
- * Like each, but only allows a certain number of outstanding promises at any
- * given time.
- *
- * $concurrency may be an integer or a function that accepts the number of
- * pending promises and returns a numeric concurrency limit value to allow for
- * dynamic a concurrency size.
- *
- * @param mixed $iterable
- * @param int|callable $concurrency
- * @param callable $onFulfilled
- * @param callable $onRejected
- *
- * @return PromiseInterface
- *
- * @deprecated each_limit will be removed in guzzlehttp/promises:2.0. Use Each::ofLimit instead.
- */
-function each_limit($iterable, $concurrency, callable $onFulfilled = null, callable $onRejected = null)
-{
- return Each::ofLimit($iterable, $concurrency, $onFulfilled, $onRejected);
-}
-/**
- * Like each_limit, but ensures that no promise in the given $iterable argument
- * is rejected. If any promise is rejected, then the aggregate promise is
- * rejected with the encountered rejection.
- *
- * @param mixed $iterable
- * @param int|callable $concurrency
- * @param callable $onFulfilled
- *
- * @return PromiseInterface
- *
- * @deprecated each_limit_all will be removed in guzzlehttp/promises:2.0. Use Each::ofLimitAll instead.
- */
-function each_limit_all($iterable, $concurrency, callable $onFulfilled = null)
-{
- return Each::ofLimitAll($iterable, $concurrency, $onFulfilled);
-}
-/**
- * Returns true if a promise is fulfilled.
- *
- * @return bool
- *
- * @deprecated is_fulfilled will be removed in guzzlehttp/promises:2.0. Use Is::fulfilled instead.
- */
-function is_fulfilled(PromiseInterface $promise)
-{
- return Is::fulfilled($promise);
-}
-/**
- * Returns true if a promise is rejected.
- *
- * @return bool
- *
- * @deprecated is_rejected will be removed in guzzlehttp/promises:2.0. Use Is::rejected instead.
- */
-function is_rejected(PromiseInterface $promise)
-{
- return Is::rejected($promise);
-}
-/**
- * Returns true if a promise is fulfilled or rejected.
- *
- * @return bool
- *
- * @deprecated is_settled will be removed in guzzlehttp/promises:2.0. Use Is::settled instead.
- */
-function is_settled(PromiseInterface $promise)
-{
- return Is::settled($promise);
-}
-/**
- * Create a new coroutine.
- *
- * @see Coroutine
- *
- * @return PromiseInterface
- *
- * @deprecated coroutine will be removed in guzzlehttp/promises:2.0. Use Coroutine::of instead.
- */
-function coroutine(callable $generatorFn)
-{
- return Coroutine::of($generatorFn);
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/promises/src/functions_include.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/promises/src/functions_include.php
deleted file mode 100644
index 1a467ec..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/promises/src/functions_include.php
+++ /dev/null
@@ -1,8 +0,0 @@
-
-Copyright (c) 2015 Márk Sági-Kazár
-Copyright (c) 2015 Graham Campbell
-Copyright (c) 2016 Tobias Schultze
-Copyright (c) 2016 George Mponos
-Copyright (c) 2018 Tobias Nyholm
-
-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/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/AppendStream.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/AppendStream.php
deleted file mode 100644
index f77f82c..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/AppendStream.php
+++ /dev/null
@@ -1,205 +0,0 @@
-addStream($stream);
- }
- }
- public function __toString() : string
- {
- try {
- $this->rewind();
- return $this->getContents();
- } catch (\Throwable $e) {
- if (\PHP_VERSION_ID >= 70400) {
- throw $e;
- }
- trigger_error(sprintf('%s::__toString exception: %s', self::class, (string) $e), \E_USER_ERROR);
- return '';
- }
- }
- /**
- * Add a stream to the AppendStream
- *
- * @param StreamInterface $stream Stream to append. Must be readable.
- *
- * @throws \InvalidArgumentException if the stream is not readable
- */
- public function addStream(StreamInterface $stream) : void
- {
- if (!$stream->isReadable()) {
- throw new \InvalidArgumentException('Each stream must be readable');
- }
- // The stream is only seekable if all streams are seekable
- if (!$stream->isSeekable()) {
- $this->seekable = \false;
- }
- $this->streams[] = $stream;
- }
- public function getContents() : string
- {
- return Utils::copyToString($this);
- }
- /**
- * Closes each attached stream.
- */
- public function close() : void
- {
- $this->pos = $this->current = 0;
- $this->seekable = \true;
- foreach ($this->streams as $stream) {
- $stream->close();
- }
- $this->streams = [];
- }
- /**
- * Detaches each attached stream.
- *
- * Returns null as it's not clear which underlying stream resource to return.
- */
- public function detach()
- {
- $this->pos = $this->current = 0;
- $this->seekable = \true;
- foreach ($this->streams as $stream) {
- $stream->detach();
- }
- $this->streams = [];
- return null;
- }
- public function tell() : int
- {
- return $this->pos;
- }
- /**
- * Tries to calculate the size by adding the size of each stream.
- *
- * If any of the streams do not return a valid number, then the size of the
- * append stream cannot be determined and null is returned.
- */
- public function getSize() : ?int
- {
- $size = 0;
- foreach ($this->streams as $stream) {
- $s = $stream->getSize();
- if ($s === null) {
- return null;
- }
- $size += $s;
- }
- return $size;
- }
- public function eof() : bool
- {
- return !$this->streams || $this->current >= count($this->streams) - 1 && $this->streams[$this->current]->eof();
- }
- public function rewind() : void
- {
- $this->seek(0);
- }
- /**
- * Attempts to seek to the given position. Only supports SEEK_SET.
- */
- public function seek($offset, $whence = \SEEK_SET) : void
- {
- if (!$this->seekable) {
- throw new \RuntimeException('This AppendStream is not seekable');
- } elseif ($whence !== \SEEK_SET) {
- throw new \RuntimeException('The AppendStream can only seek with SEEK_SET');
- }
- $this->pos = $this->current = 0;
- // Rewind each stream
- foreach ($this->streams as $i => $stream) {
- try {
- $stream->rewind();
- } catch (\Exception $e) {
- throw new \RuntimeException('Unable to seek stream ' . $i . ' of the AppendStream', 0, $e);
- }
- }
- // Seek to the actual position by reading from each stream
- while ($this->pos < $offset && !$this->eof()) {
- $result = $this->read(min(8096, $offset - $this->pos));
- if ($result === '') {
- break;
- }
- }
- }
- /**
- * Reads from all of the appended streams until the length is met or EOF.
- */
- public function read($length) : string
- {
- $buffer = '';
- $total = count($this->streams) - 1;
- $remaining = $length;
- $progressToNext = \false;
- while ($remaining > 0) {
- // Progress to the next stream if needed.
- if ($progressToNext || $this->streams[$this->current]->eof()) {
- $progressToNext = \false;
- if ($this->current === $total) {
- break;
- }
- ++$this->current;
- }
- $result = $this->streams[$this->current]->read($remaining);
- if ($result === '') {
- $progressToNext = \true;
- continue;
- }
- $buffer .= $result;
- $remaining = $length - strlen($buffer);
- }
- $this->pos += strlen($buffer);
- return $buffer;
- }
- public function isReadable() : bool
- {
- return \true;
- }
- public function isWritable() : bool
- {
- return \false;
- }
- public function isSeekable() : bool
- {
- return $this->seekable;
- }
- public function write($string) : int
- {
- throw new \RuntimeException('Cannot write to an AppendStream');
- }
- /**
- * {@inheritdoc}
- *
- * @return mixed
- */
- public function getMetadata($key = null)
- {
- return $key ? null : [];
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/BufferStream.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/BufferStream.php
deleted file mode 100644
index c7a664a..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/BufferStream.php
+++ /dev/null
@@ -1,123 +0,0 @@
-hwm = $hwm;
- }
- public function __toString() : string
- {
- return $this->getContents();
- }
- public function getContents() : string
- {
- $buffer = $this->buffer;
- $this->buffer = '';
- return $buffer;
- }
- public function close() : void
- {
- $this->buffer = '';
- }
- public function detach()
- {
- $this->close();
- return null;
- }
- public function getSize() : ?int
- {
- return strlen($this->buffer);
- }
- public function isReadable() : bool
- {
- return \true;
- }
- public function isWritable() : bool
- {
- return \true;
- }
- public function isSeekable() : bool
- {
- return \false;
- }
- public function rewind() : void
- {
- $this->seek(0);
- }
- public function seek($offset, $whence = \SEEK_SET) : void
- {
- throw new \RuntimeException('Cannot seek a BufferStream');
- }
- public function eof() : bool
- {
- return strlen($this->buffer) === 0;
- }
- public function tell() : int
- {
- throw new \RuntimeException('Cannot determine the position of a BufferStream');
- }
- /**
- * Reads data from the buffer.
- */
- public function read($length) : string
- {
- $currentLength = strlen($this->buffer);
- if ($length >= $currentLength) {
- // No need to slice the buffer because we don't have enough data.
- $result = $this->buffer;
- $this->buffer = '';
- } else {
- // Slice up the result to provide a subset of the buffer.
- $result = substr($this->buffer, 0, $length);
- $this->buffer = substr($this->buffer, $length);
- }
- return $result;
- }
- /**
- * Writes data to the buffer.
- */
- public function write($string) : int
- {
- $this->buffer .= $string;
- if (strlen($this->buffer) >= $this->hwm) {
- return 0;
- }
- return strlen($string);
- }
- /**
- * {@inheritdoc}
- *
- * @return mixed
- */
- public function getMetadata($key = null)
- {
- if ($key === 'hwm') {
- return $this->hwm;
- }
- return $key ? null : [];
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/CachingStream.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/CachingStream.php
deleted file mode 100644
index 56dbfe6..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/CachingStream.php
+++ /dev/null
@@ -1,125 +0,0 @@
-remoteStream = $stream;
- $this->stream = $target ?: new Stream(Utils::tryFopen('php://temp', 'r+'));
- }
- public function getSize() : ?int
- {
- $remoteSize = $this->remoteStream->getSize();
- if (null === $remoteSize) {
- return null;
- }
- return max($this->stream->getSize(), $remoteSize);
- }
- public function rewind() : void
- {
- $this->seek(0);
- }
- public function seek($offset, $whence = \SEEK_SET) : void
- {
- if ($whence === \SEEK_SET) {
- $byte = $offset;
- } elseif ($whence === \SEEK_CUR) {
- $byte = $offset + $this->tell();
- } elseif ($whence === \SEEK_END) {
- $size = $this->remoteStream->getSize();
- if ($size === null) {
- $size = $this->cacheEntireStream();
- }
- $byte = $size + $offset;
- } else {
- throw new \InvalidArgumentException('Invalid whence');
- }
- $diff = $byte - $this->stream->getSize();
- if ($diff > 0) {
- // Read the remoteStream until we have read in at least the amount
- // of bytes requested, or we reach the end of the file.
- while ($diff > 0 && !$this->remoteStream->eof()) {
- $this->read($diff);
- $diff = $byte - $this->stream->getSize();
- }
- } else {
- // We can just do a normal seek since we've already seen this byte.
- $this->stream->seek($byte);
- }
- }
- public function read($length) : string
- {
- // Perform a regular read on any previously read data from the buffer
- $data = $this->stream->read($length);
- $remaining = $length - strlen($data);
- // More data was requested so read from the remote stream
- if ($remaining) {
- // If data was written to the buffer in a position that would have
- // been filled from the remote stream, then we must skip bytes on
- // the remote stream to emulate overwriting bytes from that
- // position. This mimics the behavior of other PHP stream wrappers.
- $remoteData = $this->remoteStream->read($remaining + $this->skipReadBytes);
- if ($this->skipReadBytes) {
- $len = strlen($remoteData);
- $remoteData = substr($remoteData, $this->skipReadBytes);
- $this->skipReadBytes = max(0, $this->skipReadBytes - $len);
- }
- $data .= $remoteData;
- $this->stream->write($remoteData);
- }
- return $data;
- }
- public function write($string) : int
- {
- // When appending to the end of the currently read stream, you'll want
- // to skip bytes from being read from the remote stream to emulate
- // other stream wrappers. Basically replacing bytes of data of a fixed
- // length.
- $overflow = strlen($string) + $this->tell() - $this->remoteStream->tell();
- if ($overflow > 0) {
- $this->skipReadBytes += $overflow;
- }
- return $this->stream->write($string);
- }
- public function eof() : bool
- {
- return $this->stream->eof() && $this->remoteStream->eof();
- }
- /**
- * Close both the remote stream and buffer stream
- */
- public function close() : void
- {
- $this->remoteStream->close();
- $this->stream->close();
- }
- private function cacheEntireStream() : int
- {
- $target = new FnStream(['write' => 'strlen']);
- Utils::copyToStream($this, $target);
- return $this->tell();
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/DroppingStream.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/DroppingStream.php
deleted file mode 100644
index 54774ae..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/DroppingStream.php
+++ /dev/null
@@ -1,40 +0,0 @@
-stream = $stream;
- $this->maxLength = $maxLength;
- }
- public function write($string) : int
- {
- $diff = $this->maxLength - $this->stream->getSize();
- // Begin returning 0 when the underlying stream is too large.
- if ($diff <= 0) {
- return 0;
- }
- // Write the stream or a subset of the stream if needed.
- if (strlen($string) < $diff) {
- return $this->stream->write($string);
- }
- return $this->stream->write(substr($string, 0, $diff));
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/Exception/MalformedUriException.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/Exception/MalformedUriException.php
deleted file mode 100644
index 1f6654a..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/Exception/MalformedUriException.php
+++ /dev/null
@@ -1,12 +0,0 @@
- */
- private $methods;
- /**
- * @param array $methods Hash of method name to a callable.
- */
- public function __construct(array $methods)
- {
- $this->methods = $methods;
- // Create the functions on the class
- foreach ($methods as $name => $fn) {
- $this->{'_fn_' . $name} = $fn;
- }
- }
- /**
- * Lazily determine which methods are not implemented.
- *
- * @throws \BadMethodCallException
- */
- public function __get(string $name) : void
- {
- throw new \BadMethodCallException(str_replace('_fn_', '', $name) . '() is not implemented in the FnStream');
- }
- /**
- * The close method is called on the underlying stream only if possible.
- */
- public function __destruct()
- {
- if (isset($this->_fn_close)) {
- call_user_func($this->_fn_close);
- }
- }
- /**
- * An unserialize would allow the __destruct to run when the unserialized value goes out of scope.
- *
- * @throws \LogicException
- */
- public function __wakeup() : void
- {
- throw new \LogicException('FnStream should never be unserialized');
- }
- /**
- * Adds custom functionality to an underlying stream by intercepting
- * specific method calls.
- *
- * @param StreamInterface $stream Stream to decorate
- * @param array $methods Hash of method name to a closure
- *
- * @return FnStream
- */
- public static function decorate(StreamInterface $stream, array $methods)
- {
- // If any of the required methods were not provided, then simply
- // proxy to the decorated stream.
- foreach (array_diff(self::SLOTS, array_keys($methods)) as $diff) {
- /** @var callable $callable */
- $callable = [$stream, $diff];
- $methods[$diff] = $callable;
- }
- return new self($methods);
- }
- public function __toString() : string
- {
- try {
- return call_user_func($this->_fn___toString);
- } catch (\Throwable $e) {
- if (\PHP_VERSION_ID >= 70400) {
- throw $e;
- }
- trigger_error(sprintf('%s::__toString exception: %s', self::class, (string) $e), \E_USER_ERROR);
- return '';
- }
- }
- public function close() : void
- {
- call_user_func($this->_fn_close);
- }
- public function detach()
- {
- return call_user_func($this->_fn_detach);
- }
- public function getSize() : ?int
- {
- return call_user_func($this->_fn_getSize);
- }
- public function tell() : int
- {
- return call_user_func($this->_fn_tell);
- }
- public function eof() : bool
- {
- return call_user_func($this->_fn_eof);
- }
- public function isSeekable() : bool
- {
- return call_user_func($this->_fn_isSeekable);
- }
- public function rewind() : void
- {
- call_user_func($this->_fn_rewind);
- }
- public function seek($offset, $whence = \SEEK_SET) : void
- {
- call_user_func($this->_fn_seek, $offset, $whence);
- }
- public function isWritable() : bool
- {
- return call_user_func($this->_fn_isWritable);
- }
- public function write($string) : int
- {
- return call_user_func($this->_fn_write, $string);
- }
- public function isReadable() : bool
- {
- return call_user_func($this->_fn_isReadable);
- }
- public function read($length) : string
- {
- return call_user_func($this->_fn_read, $length);
- }
- public function getContents() : string
- {
- return call_user_func($this->_fn_getContents);
- }
- /**
- * {@inheritdoc}
- *
- * @return mixed
- */
- public function getMetadata($key = null)
- {
- return call_user_func($this->_fn_getMetadata, $key);
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/Header.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/Header.php
deleted file mode 100644
index 688b1ee..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/Header.php
+++ /dev/null
@@ -1,117 +0,0 @@
-]+>|[^=]+/', $kvp, $matches)) {
- $m = $matches[0];
- if (isset($m[1])) {
- $part[trim($m[0], $trimmed)] = trim($m[1], $trimmed);
- } else {
- $part[] = trim($m[0], $trimmed);
- }
- }
- }
- if ($part) {
- $params[] = $part;
- }
- }
- }
- return $params;
- }
- /**
- * Converts an array of header values that may contain comma separated
- * headers into an array of headers with no comma separated values.
- *
- * @param string|array $header Header to normalize.
- *
- * @deprecated Use self::splitList() instead.
- */
- public static function normalize($header) : array
- {
- $result = [];
- foreach ((array) $header as $value) {
- foreach (self::splitList($value) as $parsed) {
- $result[] = $parsed;
- }
- }
- return $result;
- }
- /**
- * Splits a HTTP header defined to contain a comma-separated list into
- * each individual value. Empty values will be removed.
- *
- * Example headers include 'accept', 'cache-control' and 'if-none-match'.
- *
- * This method must not be used to parse headers that are not defined as
- * a list, such as 'user-agent' or 'set-cookie'.
- *
- * @param string|string[] $values Header value as returned by MessageInterface::getHeader()
- *
- * @return string[]
- */
- public static function splitList($values) : array
- {
- if (!\is_array($values)) {
- $values = [$values];
- }
- $result = [];
- foreach ($values as $value) {
- if (!\is_string($value)) {
- throw new \TypeError('$header must either be a string or an array containing strings.');
- }
- $v = '';
- $isQuoted = \false;
- $isEscaped = \false;
- for ($i = 0, $max = \strlen($value); $i < $max; ++$i) {
- if ($isEscaped) {
- $v .= $value[$i];
- $isEscaped = \false;
- continue;
- }
- if (!$isQuoted && $value[$i] === ',') {
- $v = \trim($v);
- if ($v !== '') {
- $result[] = $v;
- }
- $v = '';
- continue;
- }
- if ($isQuoted && $value[$i] === '\\') {
- $isEscaped = \true;
- $v .= $value[$i];
- continue;
- }
- if ($value[$i] === '"') {
- $isQuoted = !$isQuoted;
- $v .= $value[$i];
- continue;
- }
- $v .= $value[$i];
- }
- $v = \trim($v);
- if ($v !== '') {
- $result[] = $v;
- }
- }
- return $result;
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/HttpFactory.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/HttpFactory.php
deleted file mode 100644
index 6c51b07..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/HttpFactory.php
+++ /dev/null
@@ -1,76 +0,0 @@
-getSize();
- }
- return new UploadedFile($stream, $size, $error, $clientFilename, $clientMediaType);
- }
- public function createStream(string $content = '') : StreamInterface
- {
- return Utils::streamFor($content);
- }
- public function createStreamFromFile(string $file, string $mode = 'r') : StreamInterface
- {
- try {
- $resource = Utils::tryFopen($file, $mode);
- } catch (\RuntimeException $e) {
- if ('' === $mode || \false === \in_array($mode[0], ['r', 'w', 'a', 'x', 'c'], \true)) {
- throw new \InvalidArgumentException(sprintf('Invalid file opening mode "%s"', $mode), 0, $e);
- }
- throw $e;
- }
- return Utils::streamFor($resource);
- }
- public function createStreamFromResource($resource) : StreamInterface
- {
- return Utils::streamFor($resource);
- }
- public function createServerRequest(string $method, $uri, array $serverParams = []) : ServerRequestInterface
- {
- if (empty($method)) {
- if (!empty($serverParams['REQUEST_METHOD'])) {
- $method = $serverParams['REQUEST_METHOD'];
- } else {
- throw new \InvalidArgumentException('Cannot determine HTTP method');
- }
- }
- return new ServerRequest($method, $uri, [], null, '1.1', $serverParams);
- }
- public function createResponse(int $code = 200, string $reasonPhrase = '') : ResponseInterface
- {
- return new Response($code, [], null, '1.1', $reasonPhrase);
- }
- public function createRequest(string $method, $uri) : RequestInterface
- {
- return new Request($method, $uri);
- }
- public function createUri(string $uri = '') : UriInterface
- {
- return new Uri($uri);
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/InflateStream.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/InflateStream.php
deleted file mode 100644
index 2a9253c..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/InflateStream.php
+++ /dev/null
@@ -1,33 +0,0 @@
- 15 + 32]);
- $this->stream = $stream->isSeekable() ? new Stream($resource) : new NoSeekStream(new Stream($resource));
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/LazyOpenStream.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/LazyOpenStream.php
deleted file mode 100644
index e8ef4ac..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/LazyOpenStream.php
+++ /dev/null
@@ -1,41 +0,0 @@
-filename = $filename;
- $this->mode = $mode;
- // unsetting the property forces the first access to go through
- // __get().
- unset($this->stream);
- }
- /**
- * Creates the underlying stream lazily when required.
- */
- protected function createStream() : StreamInterface
- {
- return Utils::streamFor(Utils::tryFopen($this->filename, $this->mode));
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/LimitStream.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/LimitStream.php
deleted file mode 100644
index 6a0172f..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/LimitStream.php
+++ /dev/null
@@ -1,128 +0,0 @@
-stream = $stream;
- $this->setLimit($limit);
- $this->setOffset($offset);
- }
- public function eof() : bool
- {
- // Always return true if the underlying stream is EOF
- if ($this->stream->eof()) {
- return \true;
- }
- // No limit and the underlying stream is not at EOF
- if ($this->limit === -1) {
- return \false;
- }
- return $this->stream->tell() >= $this->offset + $this->limit;
- }
- /**
- * Returns the size of the limited subset of data
- */
- public function getSize() : ?int
- {
- if (null === ($length = $this->stream->getSize())) {
- return null;
- } elseif ($this->limit === -1) {
- return $length - $this->offset;
- } else {
- return min($this->limit, $length - $this->offset);
- }
- }
- /**
- * Allow for a bounded seek on the read limited stream
- */
- public function seek($offset, $whence = \SEEK_SET) : void
- {
- if ($whence !== \SEEK_SET || $offset < 0) {
- throw new \RuntimeException(sprintf('Cannot seek to offset %s with whence %s', $offset, $whence));
- }
- $offset += $this->offset;
- if ($this->limit !== -1) {
- if ($offset > $this->offset + $this->limit) {
- $offset = $this->offset + $this->limit;
- }
- }
- $this->stream->seek($offset);
- }
- /**
- * Give a relative tell()
- */
- public function tell() : int
- {
- return $this->stream->tell() - $this->offset;
- }
- /**
- * Set the offset to start limiting from
- *
- * @param int $offset Offset to seek to and begin byte limiting from
- *
- * @throws \RuntimeException if the stream cannot be seeked.
- */
- public function setOffset(int $offset) : void
- {
- $current = $this->stream->tell();
- if ($current !== $offset) {
- // If the stream cannot seek to the offset position, then read to it
- if ($this->stream->isSeekable()) {
- $this->stream->seek($offset);
- } elseif ($current > $offset) {
- throw new \RuntimeException("Could not seek to stream offset {$offset}");
- } else {
- $this->stream->read($offset - $current);
- }
- }
- $this->offset = $offset;
- }
- /**
- * Set the limit of bytes that the decorator allows to be read from the
- * stream.
- *
- * @param int $limit Number of bytes to allow to be read from the stream.
- * Use -1 for no limit.
- */
- public function setLimit(int $limit) : void
- {
- $this->limit = $limit;
- }
- public function read($length) : string
- {
- if ($this->limit === -1) {
- return $this->stream->read($length);
- }
- // Check if the current position is less than the total allowed
- // bytes + original offset
- $remaining = $this->offset + $this->limit - $this->stream->tell();
- if ($remaining > 0) {
- // Only return the amount of requested data, ensuring that the byte
- // limit is not exceeded
- return $this->stream->read(min($remaining, $length));
- }
- return '';
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/Message.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/Message.php
deleted file mode 100644
index d7265b9..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/Message.php
+++ /dev/null
@@ -1,189 +0,0 @@
-getMethod() . ' ' . $message->getRequestTarget()) . ' HTTP/' . $message->getProtocolVersion();
- if (!$message->hasHeader('host')) {
- $msg .= "\r\nHost: " . $message->getUri()->getHost();
- }
- } elseif ($message instanceof ResponseInterface) {
- $msg = 'HTTP/' . $message->getProtocolVersion() . ' ' . $message->getStatusCode() . ' ' . $message->getReasonPhrase();
- } else {
- throw new \InvalidArgumentException('Unknown message type');
- }
- foreach ($message->getHeaders() as $name => $values) {
- if (strtolower($name) === 'set-cookie') {
- foreach ($values as $value) {
- $msg .= "\r\n{$name}: " . $value;
- }
- } else {
- $msg .= "\r\n{$name}: " . implode(', ', $values);
- }
- }
- return "{$msg}\r\n\r\n" . $message->getBody();
- }
- /**
- * Get a short summary of the message body.
- *
- * Will return `null` if the response is not printable.
- *
- * @param MessageInterface $message The message to get the body summary
- * @param int $truncateAt The maximum allowed size of the summary
- */
- public static function bodySummary(MessageInterface $message, int $truncateAt = 120) : ?string
- {
- $body = $message->getBody();
- if (!$body->isSeekable() || !$body->isReadable()) {
- return null;
- }
- $size = $body->getSize();
- if ($size === 0) {
- return null;
- }
- $body->rewind();
- $summary = $body->read($truncateAt);
- $body->rewind();
- if ($size > $truncateAt) {
- $summary .= ' (truncated...)';
- }
- // Matches any printable character, including unicode characters:
- // letters, marks, numbers, punctuation, spacing, and separators.
- if (preg_match('/[^\\pL\\pM\\pN\\pP\\pS\\pZ\\n\\r\\t]/u', $summary) !== 0) {
- return null;
- }
- return $summary;
- }
- /**
- * Attempts to rewind a message body and throws an exception on failure.
- *
- * The body of the message will only be rewound if a call to `tell()`
- * returns a value other than `0`.
- *
- * @param MessageInterface $message Message to rewind
- *
- * @throws \RuntimeException
- */
- public static function rewindBody(MessageInterface $message) : void
- {
- $body = $message->getBody();
- if ($body->tell()) {
- $body->rewind();
- }
- }
- /**
- * Parses an HTTP message into an associative array.
- *
- * The array contains the "start-line" key containing the start line of
- * the message, "headers" key containing an associative array of header
- * array values, and a "body" key containing the body of the message.
- *
- * @param string $message HTTP request or response to parse.
- */
- public static function parseMessage(string $message) : array
- {
- if (!$message) {
- throw new \InvalidArgumentException('Invalid message');
- }
- $message = ltrim($message, "\r\n");
- $messageParts = preg_split("/\r?\n\r?\n/", $message, 2);
- if ($messageParts === \false || count($messageParts) !== 2) {
- throw new \InvalidArgumentException('Invalid message: Missing header delimiter');
- }
- [$rawHeaders, $body] = $messageParts;
- $rawHeaders .= "\r\n";
- // Put back the delimiter we split previously
- $headerParts = preg_split("/\r?\n/", $rawHeaders, 2);
- if ($headerParts === \false || count($headerParts) !== 2) {
- throw new \InvalidArgumentException('Invalid message: Missing status line');
- }
- [$startLine, $rawHeaders] = $headerParts;
- if (preg_match("/(?:^HTTP\\/|^[A-Z]+ \\S+ HTTP\\/)(\\d+(?:\\.\\d+)?)/i", $startLine, $matches) && $matches[1] === '1.0') {
- // Header folding is deprecated for HTTP/1.1, but allowed in HTTP/1.0
- $rawHeaders = preg_replace(Rfc7230::HEADER_FOLD_REGEX, ' ', $rawHeaders);
- }
- /** @var array[] $headerLines */
- $count = preg_match_all(Rfc7230::HEADER_REGEX, $rawHeaders, $headerLines, \PREG_SET_ORDER);
- // If these aren't the same, then one line didn't match and there's an invalid header.
- if ($count !== substr_count($rawHeaders, "\n")) {
- // Folding is deprecated, see https://tools.ietf.org/html/rfc7230#section-3.2.4
- if (preg_match(Rfc7230::HEADER_FOLD_REGEX, $rawHeaders)) {
- throw new \InvalidArgumentException('Invalid header syntax: Obsolete line folding');
- }
- throw new \InvalidArgumentException('Invalid header syntax');
- }
- $headers = [];
- foreach ($headerLines as $headerLine) {
- $headers[$headerLine[1]][] = $headerLine[2];
- }
- return ['start-line' => $startLine, 'headers' => $headers, 'body' => $body];
- }
- /**
- * Constructs a URI for an HTTP request message.
- *
- * @param string $path Path from the start-line
- * @param array $headers Array of headers (each value an array).
- */
- public static function parseRequestUri(string $path, array $headers) : string
- {
- $hostKey = array_filter(array_keys($headers), function ($k) {
- // Numeric array keys are converted to int by PHP.
- $k = (string) $k;
- return strtolower($k) === 'host';
- });
- // If no host is found, then a full URI cannot be constructed.
- if (!$hostKey) {
- return $path;
- }
- $host = $headers[reset($hostKey)][0];
- $scheme = substr($host, -4) === ':443' ? 'https' : 'http';
- return $scheme . '://' . $host . '/' . ltrim($path, '/');
- }
- /**
- * Parses a request message string into a request object.
- *
- * @param string $message Request message string.
- */
- public static function parseRequest(string $message) : RequestInterface
- {
- $data = self::parseMessage($message);
- $matches = [];
- if (!preg_match('/^[\\S]+\\s+([a-zA-Z]+:\\/\\/|\\/).*/', $data['start-line'], $matches)) {
- throw new \InvalidArgumentException('Invalid request string');
- }
- $parts = explode(' ', $data['start-line'], 3);
- $version = isset($parts[2]) ? explode('/', $parts[2])[1] : '1.1';
- $request = new Request($parts[0], $matches[1] === '/' ? self::parseRequestUri($parts[1], $data['headers']) : $parts[1], $data['headers'], $data['body'], $version);
- return $matches[1] === '/' ? $request : $request->withRequestTarget($parts[1]);
- }
- /**
- * Parses a response message string into a response object.
- *
- * @param string $message Response message string.
- */
- public static function parseResponse(string $message) : ResponseInterface
- {
- $data = self::parseMessage($message);
- // According to https://tools.ietf.org/html/rfc7230#section-3.1.2 the space
- // between status-code and reason-phrase is required. But browsers accept
- // responses without space and reason as well.
- if (!preg_match('/^HTTP\\/.* [0-9]{3}( .*|$)/', $data['start-line'])) {
- throw new \InvalidArgumentException('Invalid response string: ' . $data['start-line']);
- }
- $parts = explode(' ', $data['start-line'], 3);
- return new Response((int) $parts[1], $data['headers'], $data['body'], explode('/', $parts[0])[1], $parts[2] ?? null);
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/MessageTrait.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/MessageTrait.php
deleted file mode 100644
index 92fa427..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/MessageTrait.php
+++ /dev/null
@@ -1,212 +0,0 @@
- Map of all registered headers, as original name => array of values */
- private $headers = [];
- /** @var array Map of lowercase header name => original name at registration */
- private $headerNames = [];
- /** @var string */
- private $protocol = '1.1';
- /** @var StreamInterface|null */
- private $stream;
- public function getProtocolVersion() : string
- {
- return $this->protocol;
- }
- public function withProtocolVersion($version) : MessageInterface
- {
- if ($this->protocol === $version) {
- return $this;
- }
- $new = clone $this;
- $new->protocol = $version;
- return $new;
- }
- public function getHeaders() : array
- {
- return $this->headers;
- }
- public function hasHeader($header) : bool
- {
- return isset($this->headerNames[strtolower($header)]);
- }
- public function getHeader($header) : array
- {
- $header = strtolower($header);
- if (!isset($this->headerNames[$header])) {
- return [];
- }
- $header = $this->headerNames[$header];
- return $this->headers[$header];
- }
- public function getHeaderLine($header) : string
- {
- return implode(', ', $this->getHeader($header));
- }
- public function withHeader($header, $value) : MessageInterface
- {
- $this->assertHeader($header);
- $value = $this->normalizeHeaderValue($value);
- $normalized = strtolower($header);
- $new = clone $this;
- if (isset($new->headerNames[$normalized])) {
- unset($new->headers[$new->headerNames[$normalized]]);
- }
- $new->headerNames[$normalized] = $header;
- $new->headers[$header] = $value;
- return $new;
- }
- public function withAddedHeader($header, $value) : MessageInterface
- {
- $this->assertHeader($header);
- $value = $this->normalizeHeaderValue($value);
- $normalized = strtolower($header);
- $new = clone $this;
- if (isset($new->headerNames[$normalized])) {
- $header = $this->headerNames[$normalized];
- $new->headers[$header] = array_merge($this->headers[$header], $value);
- } else {
- $new->headerNames[$normalized] = $header;
- $new->headers[$header] = $value;
- }
- return $new;
- }
- public function withoutHeader($header) : MessageInterface
- {
- $normalized = strtolower($header);
- if (!isset($this->headerNames[$normalized])) {
- return $this;
- }
- $header = $this->headerNames[$normalized];
- $new = clone $this;
- unset($new->headers[$header], $new->headerNames[$normalized]);
- return $new;
- }
- public function getBody() : StreamInterface
- {
- if (!$this->stream) {
- $this->stream = Utils::streamFor('');
- }
- return $this->stream;
- }
- public function withBody(StreamInterface $body) : MessageInterface
- {
- if ($body === $this->stream) {
- return $this;
- }
- $new = clone $this;
- $new->stream = $body;
- return $new;
- }
- /**
- * @param array $headers
- */
- private function setHeaders(array $headers) : void
- {
- $this->headerNames = $this->headers = [];
- foreach ($headers as $header => $value) {
- // Numeric array keys are converted to int by PHP.
- $header = (string) $header;
- $this->assertHeader($header);
- $value = $this->normalizeHeaderValue($value);
- $normalized = strtolower($header);
- if (isset($this->headerNames[$normalized])) {
- $header = $this->headerNames[$normalized];
- $this->headers[$header] = array_merge($this->headers[$header], $value);
- } else {
- $this->headerNames[$normalized] = $header;
- $this->headers[$header] = $value;
- }
- }
- }
- /**
- * @param mixed $value
- *
- * @return string[]
- */
- private function normalizeHeaderValue($value) : array
- {
- if (!is_array($value)) {
- return $this->trimAndValidateHeaderValues([$value]);
- }
- if (count($value) === 0) {
- throw new \InvalidArgumentException('Header value can not be an empty array.');
- }
- return $this->trimAndValidateHeaderValues($value);
- }
- /**
- * Trims whitespace from the header values.
- *
- * Spaces and tabs ought to be excluded by parsers when extracting the field value from a header field.
- *
- * header-field = field-name ":" OWS field-value OWS
- * OWS = *( SP / HTAB )
- *
- * @param mixed[] $values Header values
- *
- * @return string[] Trimmed header values
- *
- * @see https://tools.ietf.org/html/rfc7230#section-3.2.4
- */
- private function trimAndValidateHeaderValues(array $values) : array
- {
- return array_map(function ($value) {
- if (!is_scalar($value) && null !== $value) {
- throw new \InvalidArgumentException(sprintf('Header value must be scalar or null but %s provided.', is_object($value) ? get_class($value) : gettype($value)));
- }
- $trimmed = trim((string) $value, " \t");
- $this->assertValue($trimmed);
- return $trimmed;
- }, array_values($values));
- }
- /**
- * @see https://tools.ietf.org/html/rfc7230#section-3.2
- *
- * @param mixed $header
- */
- private function assertHeader($header) : void
- {
- if (!is_string($header)) {
- throw new \InvalidArgumentException(sprintf('Header name must be a string but %s provided.', is_object($header) ? get_class($header) : gettype($header)));
- }
- if (!preg_match('/^[a-zA-Z0-9\'`#$%&*+.^_|~!-]+$/D', $header)) {
- throw new \InvalidArgumentException(sprintf('"%s" is not valid header name.', $header));
- }
- }
- /**
- * @see https://tools.ietf.org/html/rfc7230#section-3.2
- *
- * field-value = *( field-content / obs-fold )
- * field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ]
- * field-vchar = VCHAR / obs-text
- * VCHAR = %x21-7E
- * obs-text = %x80-FF
- * obs-fold = CRLF 1*( SP / HTAB )
- */
- private function assertValue(string $value) : void
- {
- // The regular expression intentionally does not support the obs-fold production, because as
- // per RFC 7230#3.2.4:
- //
- // A sender MUST NOT generate a message that includes
- // line folding (i.e., that has any field-value that contains a match to
- // the obs-fold rule) unless the message is intended for packaging
- // within the message/http media type.
- //
- // Clients must not send a request with line folding and a server sending folded headers is
- // likely very rare. Line folding is a fairly obscure feature of HTTP/1.1 and thus not accepting
- // folding is not likely to break any legitimate use case.
- if (!preg_match('/^[\\x20\\x09\\x21-\\x7E\\x80-\\xFF]*$/D', $value)) {
- throw new \InvalidArgumentException(sprintf('"%s" is not valid header value.', $value));
- }
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/MimeType.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/MimeType.php
deleted file mode 100644
index 2837625..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/MimeType.php
+++ /dev/null
@@ -1,27 +0,0 @@
- 'application/vnd.1000minds.decision-model+xml', '3dml' => 'text/vnd.in3d.3dml', '3ds' => 'image/x-3ds', '3g2' => 'video/3gpp2', '3gp' => 'video/3gp', '3gpp' => 'video/3gpp', '3mf' => 'model/3mf', '7z' => 'application/x-7z-compressed', '7zip' => 'application/x-7z-compressed', '123' => 'application/vnd.lotus-1-2-3', 'aab' => 'application/x-authorware-bin', 'aac' => 'audio/aac', 'aam' => 'application/x-authorware-map', 'aas' => 'application/x-authorware-seg', 'abw' => 'application/x-abiword', 'ac' => 'application/vnd.nokia.n-gage.ac+xml', 'ac3' => 'audio/ac3', 'acc' => 'application/vnd.americandynamics.acc', 'ace' => 'application/x-ace-compressed', 'acu' => 'application/vnd.acucobol', 'acutc' => 'application/vnd.acucorp', 'adp' => 'audio/adpcm', 'aep' => 'application/vnd.audiograph', 'afm' => 'application/x-font-type1', 'afp' => 'application/vnd.ibm.modcap', 'age' => 'application/vnd.age', 'ahead' => 'application/vnd.ahead.space', 'ai' => 'application/pdf', 'aif' => 'audio/x-aiff', 'aifc' => 'audio/x-aiff', 'aiff' => 'audio/x-aiff', 'air' => 'application/vnd.adobe.air-application-installer-package+zip', 'ait' => 'application/vnd.dvb.ait', 'ami' => 'application/vnd.amiga.ami', 'amr' => 'audio/amr', 'apk' => 'application/vnd.android.package-archive', 'apng' => 'image/apng', 'appcache' => 'text/cache-manifest', 'application' => 'application/x-ms-application', 'apr' => 'application/vnd.lotus-approach', 'arc' => 'application/x-freearc', 'arj' => 'application/x-arj', 'asc' => 'application/pgp-signature', 'asf' => 'video/x-ms-asf', 'asm' => 'text/x-asm', 'aso' => 'application/vnd.accpac.simply.aso', 'asx' => 'video/x-ms-asf', 'atc' => 'application/vnd.acucorp', 'atom' => 'application/atom+xml', 'atomcat' => 'application/atomcat+xml', 'atomdeleted' => 'application/atomdeleted+xml', 'atomsvc' => 'application/atomsvc+xml', 'atx' => 'application/vnd.antix.game-component', 'au' => 'audio/x-au', 'avci' => 'image/avci', 'avcs' => 'image/avcs', 'avi' => 'video/x-msvideo', 'avif' => 'image/avif', 'aw' => 'application/applixware', 'azf' => 'application/vnd.airzip.filesecure.azf', 'azs' => 'application/vnd.airzip.filesecure.azs', 'azv' => 'image/vnd.airzip.accelerator.azv', 'azw' => 'application/vnd.amazon.ebook', 'b16' => 'image/vnd.pco.b16', 'bat' => 'application/x-msdownload', 'bcpio' => 'application/x-bcpio', 'bdf' => 'application/x-font-bdf', 'bdm' => 'application/vnd.syncml.dm+wbxml', 'bdoc' => 'application/x-bdoc', 'bed' => 'application/vnd.realvnc.bed', 'bh2' => 'application/vnd.fujitsu.oasysprs', 'bin' => 'application/octet-stream', 'blb' => 'application/x-blorb', 'blorb' => 'application/x-blorb', 'bmi' => 'application/vnd.bmi', 'bmml' => 'application/vnd.balsamiq.bmml+xml', 'bmp' => 'image/bmp', 'book' => 'application/vnd.framemaker', 'box' => 'application/vnd.previewsystems.box', 'boz' => 'application/x-bzip2', 'bpk' => 'application/octet-stream', 'bpmn' => 'application/octet-stream', 'bsp' => 'model/vnd.valve.source.compiled-map', 'btif' => 'image/prs.btif', 'buffer' => 'application/octet-stream', 'bz' => 'application/x-bzip', 'bz2' => 'application/x-bzip2', 'c' => 'text/x-c', 'c4d' => 'application/vnd.clonk.c4group', 'c4f' => 'application/vnd.clonk.c4group', 'c4g' => 'application/vnd.clonk.c4group', 'c4p' => 'application/vnd.clonk.c4group', 'c4u' => 'application/vnd.clonk.c4group', 'c11amc' => 'application/vnd.cluetrust.cartomobile-config', 'c11amz' => 'application/vnd.cluetrust.cartomobile-config-pkg', 'cab' => 'application/vnd.ms-cab-compressed', 'caf' => 'audio/x-caf', 'cap' => 'application/vnd.tcpdump.pcap', 'car' => 'application/vnd.curl.car', 'cat' => 'application/vnd.ms-pki.seccat', 'cb7' => 'application/x-cbr', 'cba' => 'application/x-cbr', 'cbr' => 'application/x-cbr', 'cbt' => 'application/x-cbr', 'cbz' => 'application/x-cbr', 'cc' => 'text/x-c', 'cco' => 'application/x-cocoa', 'cct' => 'application/x-director', 'ccxml' => 'application/ccxml+xml', 'cdbcmsg' => 'application/vnd.contact.cmsg', 'cdf' => 'application/x-netcdf', 'cdfx' => 'application/cdfx+xml', 'cdkey' => 'application/vnd.mediastation.cdkey', 'cdmia' => 'application/cdmi-capability', 'cdmic' => 'application/cdmi-container', 'cdmid' => 'application/cdmi-domain', 'cdmio' => 'application/cdmi-object', 'cdmiq' => 'application/cdmi-queue', 'cdr' => 'application/cdr', 'cdx' => 'chemical/x-cdx', 'cdxml' => 'application/vnd.chemdraw+xml', 'cdy' => 'application/vnd.cinderella', 'cer' => 'application/pkix-cert', 'cfs' => 'application/x-cfs-compressed', 'cgm' => 'image/cgm', 'chat' => 'application/x-chat', 'chm' => 'application/vnd.ms-htmlhelp', 'chrt' => 'application/vnd.kde.kchart', 'cif' => 'chemical/x-cif', 'cii' => 'application/vnd.anser-web-certificate-issue-initiation', 'cil' => 'application/vnd.ms-artgalry', 'cjs' => 'application/node', 'cla' => 'application/vnd.claymore', 'class' => 'application/octet-stream', 'clkk' => 'application/vnd.crick.clicker.keyboard', 'clkp' => 'application/vnd.crick.clicker.palette', 'clkt' => 'application/vnd.crick.clicker.template', 'clkw' => 'application/vnd.crick.clicker.wordbank', 'clkx' => 'application/vnd.crick.clicker', 'clp' => 'application/x-msclip', 'cmc' => 'application/vnd.cosmocaller', 'cmdf' => 'chemical/x-cmdf', 'cml' => 'chemical/x-cml', 'cmp' => 'application/vnd.yellowriver-custom-menu', 'cmx' => 'image/x-cmx', 'cod' => 'application/vnd.rim.cod', 'coffee' => 'text/coffeescript', 'com' => 'application/x-msdownload', 'conf' => 'text/plain', 'cpio' => 'application/x-cpio', 'cpl' => 'application/cpl+xml', 'cpp' => 'text/x-c', 'cpt' => 'application/mac-compactpro', 'crd' => 'application/x-mscardfile', 'crl' => 'application/pkix-crl', 'crt' => 'application/x-x509-ca-cert', 'crx' => 'application/x-chrome-extension', 'cryptonote' => 'application/vnd.rig.cryptonote', 'csh' => 'application/x-csh', 'csl' => 'application/vnd.citationstyles.style+xml', 'csml' => 'chemical/x-csml', 'csp' => 'application/vnd.commonspace', 'csr' => 'application/octet-stream', 'css' => 'text/css', 'cst' => 'application/x-director', 'csv' => 'text/csv', 'cu' => 'application/cu-seeme', 'curl' => 'text/vnd.curl', 'cww' => 'application/prs.cww', 'cxt' => 'application/x-director', 'cxx' => 'text/x-c', 'dae' => 'model/vnd.collada+xml', 'daf' => 'application/vnd.mobius.daf', 'dart' => 'application/vnd.dart', 'dataless' => 'application/vnd.fdsn.seed', 'davmount' => 'application/davmount+xml', 'dbf' => 'application/vnd.dbf', 'dbk' => 'application/docbook+xml', 'dcr' => 'application/x-director', 'dcurl' => 'text/vnd.curl.dcurl', 'dd2' => 'application/vnd.oma.dd2+xml', 'ddd' => 'application/vnd.fujixerox.ddd', 'ddf' => 'application/vnd.syncml.dmddf+xml', 'dds' => 'image/vnd.ms-dds', 'deb' => 'application/x-debian-package', 'def' => 'text/plain', 'deploy' => 'application/octet-stream', 'der' => 'application/x-x509-ca-cert', 'dfac' => 'application/vnd.dreamfactory', 'dgc' => 'application/x-dgc-compressed', 'dic' => 'text/x-c', 'dir' => 'application/x-director', 'dis' => 'application/vnd.mobius.dis', 'disposition-notification' => 'message/disposition-notification', 'dist' => 'application/octet-stream', 'distz' => 'application/octet-stream', 'djv' => 'image/vnd.djvu', 'djvu' => 'image/vnd.djvu', 'dll' => 'application/octet-stream', 'dmg' => 'application/x-apple-diskimage', 'dmn' => 'application/octet-stream', 'dmp' => 'application/vnd.tcpdump.pcap', 'dms' => 'application/octet-stream', 'dna' => 'application/vnd.dna', 'doc' => 'application/msword', 'docm' => 'application/vnd.ms-word.template.macroEnabled.12', 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'dot' => 'application/msword', 'dotm' => 'application/vnd.ms-word.template.macroEnabled.12', 'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template', 'dp' => 'application/vnd.osgi.dp', 'dpg' => 'application/vnd.dpgraph', 'dra' => 'audio/vnd.dra', 'drle' => 'image/dicom-rle', 'dsc' => 'text/prs.lines.tag', 'dssc' => 'application/dssc+der', 'dtb' => 'application/x-dtbook+xml', 'dtd' => 'application/xml-dtd', 'dts' => 'audio/vnd.dts', 'dtshd' => 'audio/vnd.dts.hd', 'dump' => 'application/octet-stream', 'dvb' => 'video/vnd.dvb.file', 'dvi' => 'application/x-dvi', 'dwd' => 'application/atsc-dwd+xml', 'dwf' => 'model/vnd.dwf', 'dwg' => 'image/vnd.dwg', 'dxf' => 'image/vnd.dxf', 'dxp' => 'application/vnd.spotfire.dxp', 'dxr' => 'application/x-director', 'ear' => 'application/java-archive', 'ecelp4800' => 'audio/vnd.nuera.ecelp4800', 'ecelp7470' => 'audio/vnd.nuera.ecelp7470', 'ecelp9600' => 'audio/vnd.nuera.ecelp9600', 'ecma' => 'application/ecmascript', 'edm' => 'application/vnd.novadigm.edm', 'edx' => 'application/vnd.novadigm.edx', 'efif' => 'application/vnd.picsel', 'ei6' => 'application/vnd.pg.osasli', 'elc' => 'application/octet-stream', 'emf' => 'image/emf', 'eml' => 'message/rfc822', 'emma' => 'application/emma+xml', 'emotionml' => 'application/emotionml+xml', 'emz' => 'application/x-msmetafile', 'eol' => 'audio/vnd.digital-winds', 'eot' => 'application/vnd.ms-fontobject', 'eps' => 'application/postscript', 'epub' => 'application/epub+zip', 'es' => 'application/ecmascript', 'es3' => 'application/vnd.eszigno3+xml', 'esa' => 'application/vnd.osgi.subsystem', 'esf' => 'application/vnd.epson.esf', 'et3' => 'application/vnd.eszigno3+xml', 'etx' => 'text/x-setext', 'eva' => 'application/x-eva', 'evy' => 'application/x-envoy', 'exe' => 'application/octet-stream', 'exi' => 'application/exi', 'exp' => 'application/express', 'exr' => 'image/aces', 'ext' => 'application/vnd.novadigm.ext', 'ez' => 'application/andrew-inset', 'ez2' => 'application/vnd.ezpix-album', 'ez3' => 'application/vnd.ezpix-package', 'f' => 'text/x-fortran', 'f4v' => 'video/mp4', 'f77' => 'text/x-fortran', 'f90' => 'text/x-fortran', 'fbs' => 'image/vnd.fastbidsheet', 'fcdt' => 'application/vnd.adobe.formscentral.fcdt', 'fcs' => 'application/vnd.isac.fcs', 'fdf' => 'application/vnd.fdf', 'fdt' => 'application/fdt+xml', 'fe_launch' => 'application/vnd.denovo.fcselayout-link', 'fg5' => 'application/vnd.fujitsu.oasysgp', 'fgd' => 'application/x-director', 'fh' => 'image/x-freehand', 'fh4' => 'image/x-freehand', 'fh5' => 'image/x-freehand', 'fh7' => 'image/x-freehand', 'fhc' => 'image/x-freehand', 'fig' => 'application/x-xfig', 'fits' => 'image/fits', 'flac' => 'audio/x-flac', 'fli' => 'video/x-fli', 'flo' => 'application/vnd.micrografx.flo', 'flv' => 'video/x-flv', 'flw' => 'application/vnd.kde.kivio', 'flx' => 'text/vnd.fmi.flexstor', 'fly' => 'text/vnd.fly', 'fm' => 'application/vnd.framemaker', 'fnc' => 'application/vnd.frogans.fnc', 'fo' => 'application/vnd.software602.filler.form+xml', 'for' => 'text/x-fortran', 'fpx' => 'image/vnd.fpx', 'frame' => 'application/vnd.framemaker', 'fsc' => 'application/vnd.fsc.weblaunch', 'fst' => 'image/vnd.fst', 'ftc' => 'application/vnd.fluxtime.clip', 'fti' => 'application/vnd.anser-web-funds-transfer-initiation', 'fvt' => 'video/vnd.fvt', 'fxp' => 'application/vnd.adobe.fxp', 'fxpl' => 'application/vnd.adobe.fxp', 'fzs' => 'application/vnd.fuzzysheet', 'g2w' => 'application/vnd.geoplan', 'g3' => 'image/g3fax', 'g3w' => 'application/vnd.geospace', 'gac' => 'application/vnd.groove-account', 'gam' => 'application/x-tads', 'gbr' => 'application/rpki-ghostbusters', 'gca' => 'application/x-gca-compressed', 'gdl' => 'model/vnd.gdl', 'gdoc' => 'application/vnd.google-apps.document', 'ged' => 'text/vnd.familysearch.gedcom', 'geo' => 'application/vnd.dynageo', 'geojson' => 'application/geo+json', 'gex' => 'application/vnd.geometry-explorer', 'ggb' => 'application/vnd.geogebra.file', 'ggt' => 'application/vnd.geogebra.tool', 'ghf' => 'application/vnd.groove-help', 'gif' => 'image/gif', 'gim' => 'application/vnd.groove-identity-message', 'glb' => 'model/gltf-binary', 'gltf' => 'model/gltf+json', 'gml' => 'application/gml+xml', 'gmx' => 'application/vnd.gmx', 'gnumeric' => 'application/x-gnumeric', 'gpg' => 'application/gpg-keys', 'gph' => 'application/vnd.flographit', 'gpx' => 'application/gpx+xml', 'gqf' => 'application/vnd.grafeq', 'gqs' => 'application/vnd.grafeq', 'gram' => 'application/srgs', 'gramps' => 'application/x-gramps-xml', 'gre' => 'application/vnd.geometry-explorer', 'grv' => 'application/vnd.groove-injector', 'grxml' => 'application/srgs+xml', 'gsf' => 'application/x-font-ghostscript', 'gsheet' => 'application/vnd.google-apps.spreadsheet', 'gslides' => 'application/vnd.google-apps.presentation', 'gtar' => 'application/x-gtar', 'gtm' => 'application/vnd.groove-tool-message', 'gtw' => 'model/vnd.gtw', 'gv' => 'text/vnd.graphviz', 'gxf' => 'application/gxf', 'gxt' => 'application/vnd.geonext', 'gz' => 'application/gzip', 'gzip' => 'application/gzip', 'h' => 'text/x-c', 'h261' => 'video/h261', 'h263' => 'video/h263', 'h264' => 'video/h264', 'hal' => 'application/vnd.hal+xml', 'hbci' => 'application/vnd.hbci', 'hbs' => 'text/x-handlebars-template', 'hdd' => 'application/x-virtualbox-hdd', 'hdf' => 'application/x-hdf', 'heic' => 'image/heic', 'heics' => 'image/heic-sequence', 'heif' => 'image/heif', 'heifs' => 'image/heif-sequence', 'hej2' => 'image/hej2k', 'held' => 'application/atsc-held+xml', 'hh' => 'text/x-c', 'hjson' => 'application/hjson', 'hlp' => 'application/winhlp', 'hpgl' => 'application/vnd.hp-hpgl', 'hpid' => 'application/vnd.hp-hpid', 'hps' => 'application/vnd.hp-hps', 'hqx' => 'application/mac-binhex40', 'hsj2' => 'image/hsj2', 'htc' => 'text/x-component', 'htke' => 'application/vnd.kenameaapp', 'htm' => 'text/html', 'html' => 'text/html', 'hvd' => 'application/vnd.yamaha.hv-dic', 'hvp' => 'application/vnd.yamaha.hv-voice', 'hvs' => 'application/vnd.yamaha.hv-script', 'i2g' => 'application/vnd.intergeo', 'icc' => 'application/vnd.iccprofile', 'ice' => 'x-conference/x-cooltalk', 'icm' => 'application/vnd.iccprofile', 'ico' => 'image/x-icon', 'ics' => 'text/calendar', 'ief' => 'image/ief', 'ifb' => 'text/calendar', 'ifm' => 'application/vnd.shana.informed.formdata', 'iges' => 'model/iges', 'igl' => 'application/vnd.igloader', 'igm' => 'application/vnd.insors.igm', 'igs' => 'model/iges', 'igx' => 'application/vnd.micrografx.igx', 'iif' => 'application/vnd.shana.informed.interchange', 'img' => 'application/octet-stream', 'imp' => 'application/vnd.accpac.simply.imp', 'ims' => 'application/vnd.ms-ims', 'in' => 'text/plain', 'ini' => 'text/plain', 'ink' => 'application/inkml+xml', 'inkml' => 'application/inkml+xml', 'install' => 'application/x-install-instructions', 'iota' => 'application/vnd.astraea-software.iota', 'ipfix' => 'application/ipfix', 'ipk' => 'application/vnd.shana.informed.package', 'irm' => 'application/vnd.ibm.rights-management', 'irp' => 'application/vnd.irepository.package+xml', 'iso' => 'application/x-iso9660-image', 'itp' => 'application/vnd.shana.informed.formtemplate', 'its' => 'application/its+xml', 'ivp' => 'application/vnd.immervision-ivp', 'ivu' => 'application/vnd.immervision-ivu', 'jad' => 'text/vnd.sun.j2me.app-descriptor', 'jade' => 'text/jade', 'jam' => 'application/vnd.jam', 'jar' => 'application/java-archive', 'jardiff' => 'application/x-java-archive-diff', 'java' => 'text/x-java-source', 'jhc' => 'image/jphc', 'jisp' => 'application/vnd.jisp', 'jls' => 'image/jls', 'jlt' => 'application/vnd.hp-jlyt', 'jng' => 'image/x-jng', 'jnlp' => 'application/x-java-jnlp-file', 'joda' => 'application/vnd.joost.joda-archive', 'jp2' => 'image/jp2', 'jpe' => 'image/jpeg', 'jpeg' => 'image/jpeg', 'jpf' => 'image/jpx', 'jpg' => 'image/jpeg', 'jpg2' => 'image/jp2', 'jpgm' => 'video/jpm', 'jpgv' => 'video/jpeg', 'jph' => 'image/jph', 'jpm' => 'video/jpm', 'jpx' => 'image/jpx', 'js' => 'application/javascript', 'json' => 'application/json', 'json5' => 'application/json5', 'jsonld' => 'application/ld+json', 'jsonml' => 'application/jsonml+json', 'jsx' => 'text/jsx', 'jxr' => 'image/jxr', 'jxra' => 'image/jxra', 'jxrs' => 'image/jxrs', 'jxs' => 'image/jxs', 'jxsc' => 'image/jxsc', 'jxsi' => 'image/jxsi', 'jxss' => 'image/jxss', 'kar' => 'audio/midi', 'karbon' => 'application/vnd.kde.karbon', 'kdb' => 'application/octet-stream', 'kdbx' => 'application/x-keepass2', 'key' => 'application/x-iwork-keynote-sffkey', 'kfo' => 'application/vnd.kde.kformula', 'kia' => 'application/vnd.kidspiration', 'kml' => 'application/vnd.google-earth.kml+xml', 'kmz' => 'application/vnd.google-earth.kmz', 'kne' => 'application/vnd.kinar', 'knp' => 'application/vnd.kinar', 'kon' => 'application/vnd.kde.kontour', 'kpr' => 'application/vnd.kde.kpresenter', 'kpt' => 'application/vnd.kde.kpresenter', 'kpxx' => 'application/vnd.ds-keypoint', 'ksp' => 'application/vnd.kde.kspread', 'ktr' => 'application/vnd.kahootz', 'ktx' => 'image/ktx', 'ktx2' => 'image/ktx2', 'ktz' => 'application/vnd.kahootz', 'kwd' => 'application/vnd.kde.kword', 'kwt' => 'application/vnd.kde.kword', 'lasxml' => 'application/vnd.las.las+xml', 'latex' => 'application/x-latex', 'lbd' => 'application/vnd.llamagraphics.life-balance.desktop', 'lbe' => 'application/vnd.llamagraphics.life-balance.exchange+xml', 'les' => 'application/vnd.hhe.lesson-player', 'less' => 'text/less', 'lgr' => 'application/lgr+xml', 'lha' => 'application/octet-stream', 'link66' => 'application/vnd.route66.link66+xml', 'list' => 'text/plain', 'list3820' => 'application/vnd.ibm.modcap', 'listafp' => 'application/vnd.ibm.modcap', 'litcoffee' => 'text/coffeescript', 'lnk' => 'application/x-ms-shortcut', 'log' => 'text/plain', 'lostxml' => 'application/lost+xml', 'lrf' => 'application/octet-stream', 'lrm' => 'application/vnd.ms-lrm', 'ltf' => 'application/vnd.frogans.ltf', 'lua' => 'text/x-lua', 'luac' => 'application/x-lua-bytecode', 'lvp' => 'audio/vnd.lucent.voice', 'lwp' => 'application/vnd.lotus-wordpro', 'lzh' => 'application/octet-stream', 'm1v' => 'video/mpeg', 'm2a' => 'audio/mpeg', 'm2v' => 'video/mpeg', 'm3a' => 'audio/mpeg', 'm3u' => 'text/plain', 'm3u8' => 'application/vnd.apple.mpegurl', 'm4a' => 'audio/x-m4a', 'm4p' => 'application/mp4', 'm4s' => 'video/iso.segment', 'm4u' => 'application/vnd.mpegurl', 'm4v' => 'video/x-m4v', 'm13' => 'application/x-msmediaview', 'm14' => 'application/x-msmediaview', 'm21' => 'application/mp21', 'ma' => 'application/mathematica', 'mads' => 'application/mads+xml', 'maei' => 'application/mmt-aei+xml', 'mag' => 'application/vnd.ecowin.chart', 'maker' => 'application/vnd.framemaker', 'man' => 'text/troff', 'manifest' => 'text/cache-manifest', 'map' => 'application/json', 'mar' => 'application/octet-stream', 'markdown' => 'text/markdown', 'mathml' => 'application/mathml+xml', 'mb' => 'application/mathematica', 'mbk' => 'application/vnd.mobius.mbk', 'mbox' => 'application/mbox', 'mc1' => 'application/vnd.medcalcdata', 'mcd' => 'application/vnd.mcd', 'mcurl' => 'text/vnd.curl.mcurl', 'md' => 'text/markdown', 'mdb' => 'application/x-msaccess', 'mdi' => 'image/vnd.ms-modi', 'mdx' => 'text/mdx', 'me' => 'text/troff', 'mesh' => 'model/mesh', 'meta4' => 'application/metalink4+xml', 'metalink' => 'application/metalink+xml', 'mets' => 'application/mets+xml', 'mfm' => 'application/vnd.mfmp', 'mft' => 'application/rpki-manifest', 'mgp' => 'application/vnd.osgeo.mapguide.package', 'mgz' => 'application/vnd.proteus.magazine', 'mid' => 'audio/midi', 'midi' => 'audio/midi', 'mie' => 'application/x-mie', 'mif' => 'application/vnd.mif', 'mime' => 'message/rfc822', 'mj2' => 'video/mj2', 'mjp2' => 'video/mj2', 'mjs' => 'application/javascript', 'mk3d' => 'video/x-matroska', 'mka' => 'audio/x-matroska', 'mkd' => 'text/x-markdown', 'mks' => 'video/x-matroska', 'mkv' => 'video/x-matroska', 'mlp' => 'application/vnd.dolby.mlp', 'mmd' => 'application/vnd.chipnuts.karaoke-mmd', 'mmf' => 'application/vnd.smaf', 'mml' => 'text/mathml', 'mmr' => 'image/vnd.fujixerox.edmics-mmr', 'mng' => 'video/x-mng', 'mny' => 'application/x-msmoney', 'mobi' => 'application/x-mobipocket-ebook', 'mods' => 'application/mods+xml', 'mov' => 'video/quicktime', 'movie' => 'video/x-sgi-movie', 'mp2' => 'audio/mpeg', 'mp2a' => 'audio/mpeg', 'mp3' => 'audio/mpeg', 'mp4' => 'video/mp4', 'mp4a' => 'audio/mp4', 'mp4s' => 'application/mp4', 'mp4v' => 'video/mp4', 'mp21' => 'application/mp21', 'mpc' => 'application/vnd.mophun.certificate', 'mpd' => 'application/dash+xml', 'mpe' => 'video/mpeg', 'mpeg' => 'video/mpeg', 'mpf' => 'application/media-policy-dataset+xml', 'mpg' => 'video/mpeg', 'mpg4' => 'video/mp4', 'mpga' => 'audio/mpeg', 'mpkg' => 'application/vnd.apple.installer+xml', 'mpm' => 'application/vnd.blueice.multipass', 'mpn' => 'application/vnd.mophun.application', 'mpp' => 'application/vnd.ms-project', 'mpt' => 'application/vnd.ms-project', 'mpy' => 'application/vnd.ibm.minipay', 'mqy' => 'application/vnd.mobius.mqy', 'mrc' => 'application/marc', 'mrcx' => 'application/marcxml+xml', 'ms' => 'text/troff', 'mscml' => 'application/mediaservercontrol+xml', 'mseed' => 'application/vnd.fdsn.mseed', 'mseq' => 'application/vnd.mseq', 'msf' => 'application/vnd.epson.msf', 'msg' => 'application/vnd.ms-outlook', 'msh' => 'model/mesh', 'msi' => 'application/x-msdownload', 'msl' => 'application/vnd.mobius.msl', 'msm' => 'application/octet-stream', 'msp' => 'application/octet-stream', 'msty' => 'application/vnd.muvee.style', 'mtl' => 'model/mtl', 'mts' => 'model/vnd.mts', 'mus' => 'application/vnd.musician', 'musd' => 'application/mmt-usd+xml', 'musicxml' => 'application/vnd.recordare.musicxml+xml', 'mvb' => 'application/x-msmediaview', 'mvt' => 'application/vnd.mapbox-vector-tile', 'mwf' => 'application/vnd.mfer', 'mxf' => 'application/mxf', 'mxl' => 'application/vnd.recordare.musicxml', 'mxmf' => 'audio/mobile-xmf', 'mxml' => 'application/xv+xml', 'mxs' => 'application/vnd.triscape.mxs', 'mxu' => 'video/vnd.mpegurl', 'n-gage' => 'application/vnd.nokia.n-gage.symbian.install', 'n3' => 'text/n3', 'nb' => 'application/mathematica', 'nbp' => 'application/vnd.wolfram.player', 'nc' => 'application/x-netcdf', 'ncx' => 'application/x-dtbncx+xml', 'nfo' => 'text/x-nfo', 'ngdat' => 'application/vnd.nokia.n-gage.data', 'nitf' => 'application/vnd.nitf', 'nlu' => 'application/vnd.neurolanguage.nlu', 'nml' => 'application/vnd.enliven', 'nnd' => 'application/vnd.noblenet-directory', 'nns' => 'application/vnd.noblenet-sealer', 'nnw' => 'application/vnd.noblenet-web', 'npx' => 'image/vnd.net-fpx', 'nq' => 'application/n-quads', 'nsc' => 'application/x-conference', 'nsf' => 'application/vnd.lotus-notes', 'nt' => 'application/n-triples', 'ntf' => 'application/vnd.nitf', 'numbers' => 'application/x-iwork-numbers-sffnumbers', 'nzb' => 'application/x-nzb', 'oa2' => 'application/vnd.fujitsu.oasys2', 'oa3' => 'application/vnd.fujitsu.oasys3', 'oas' => 'application/vnd.fujitsu.oasys', 'obd' => 'application/x-msbinder', 'obgx' => 'application/vnd.openblox.game+xml', 'obj' => 'model/obj', 'oda' => 'application/oda', 'odb' => 'application/vnd.oasis.opendocument.database', 'odc' => 'application/vnd.oasis.opendocument.chart', 'odf' => 'application/vnd.oasis.opendocument.formula', 'odft' => 'application/vnd.oasis.opendocument.formula-template', 'odg' => 'application/vnd.oasis.opendocument.graphics', 'odi' => 'application/vnd.oasis.opendocument.image', 'odm' => 'application/vnd.oasis.opendocument.text-master', 'odp' => 'application/vnd.oasis.opendocument.presentation', 'ods' => 'application/vnd.oasis.opendocument.spreadsheet', 'odt' => 'application/vnd.oasis.opendocument.text', 'oga' => 'audio/ogg', 'ogex' => 'model/vnd.opengex', 'ogg' => 'audio/ogg', 'ogv' => 'video/ogg', 'ogx' => 'application/ogg', 'omdoc' => 'application/omdoc+xml', 'onepkg' => 'application/onenote', 'onetmp' => 'application/onenote', 'onetoc' => 'application/onenote', 'onetoc2' => 'application/onenote', 'opf' => 'application/oebps-package+xml', 'opml' => 'text/x-opml', 'oprc' => 'application/vnd.palm', 'opus' => 'audio/ogg', 'org' => 'text/x-org', 'osf' => 'application/vnd.yamaha.openscoreformat', 'osfpvg' => 'application/vnd.yamaha.openscoreformat.osfpvg+xml', 'osm' => 'application/vnd.openstreetmap.data+xml', 'otc' => 'application/vnd.oasis.opendocument.chart-template', 'otf' => 'font/otf', 'otg' => 'application/vnd.oasis.opendocument.graphics-template', 'oth' => 'application/vnd.oasis.opendocument.text-web', 'oti' => 'application/vnd.oasis.opendocument.image-template', 'otp' => 'application/vnd.oasis.opendocument.presentation-template', 'ots' => 'application/vnd.oasis.opendocument.spreadsheet-template', 'ott' => 'application/vnd.oasis.opendocument.text-template', 'ova' => 'application/x-virtualbox-ova', 'ovf' => 'application/x-virtualbox-ovf', 'owl' => 'application/rdf+xml', 'oxps' => 'application/oxps', 'oxt' => 'application/vnd.openofficeorg.extension', 'p' => 'text/x-pascal', 'p7a' => 'application/x-pkcs7-signature', 'p7b' => 'application/x-pkcs7-certificates', 'p7c' => 'application/pkcs7-mime', 'p7m' => 'application/pkcs7-mime', 'p7r' => 'application/x-pkcs7-certreqresp', 'p7s' => 'application/pkcs7-signature', 'p8' => 'application/pkcs8', 'p10' => 'application/x-pkcs10', 'p12' => 'application/x-pkcs12', 'pac' => 'application/x-ns-proxy-autoconfig', 'pages' => 'application/x-iwork-pages-sffpages', 'pas' => 'text/x-pascal', 'paw' => 'application/vnd.pawaafile', 'pbd' => 'application/vnd.powerbuilder6', 'pbm' => 'image/x-portable-bitmap', 'pcap' => 'application/vnd.tcpdump.pcap', 'pcf' => 'application/x-font-pcf', 'pcl' => 'application/vnd.hp-pcl', 'pclxl' => 'application/vnd.hp-pclxl', 'pct' => 'image/x-pict', 'pcurl' => 'application/vnd.curl.pcurl', 'pcx' => 'image/x-pcx', 'pdb' => 'application/x-pilot', 'pde' => 'text/x-processing', 'pdf' => 'application/pdf', 'pem' => 'application/x-x509-user-cert', 'pfa' => 'application/x-font-type1', 'pfb' => 'application/x-font-type1', 'pfm' => 'application/x-font-type1', 'pfr' => 'application/font-tdpfr', 'pfx' => 'application/x-pkcs12', 'pgm' => 'image/x-portable-graymap', 'pgn' => 'application/x-chess-pgn', 'pgp' => 'application/pgp', 'phar' => 'application/octet-stream', 'php' => 'application/x-httpd-php', 'php3' => 'application/x-httpd-php', 'php4' => 'application/x-httpd-php', 'phps' => 'application/x-httpd-php-source', 'phtml' => 'application/x-httpd-php', 'pic' => 'image/x-pict', 'pkg' => 'application/octet-stream', 'pki' => 'application/pkixcmp', 'pkipath' => 'application/pkix-pkipath', 'pkpass' => 'application/vnd.apple.pkpass', 'pl' => 'application/x-perl', 'plb' => 'application/vnd.3gpp.pic-bw-large', 'plc' => 'application/vnd.mobius.plc', 'plf' => 'application/vnd.pocketlearn', 'pls' => 'application/pls+xml', 'pm' => 'application/x-perl', 'pml' => 'application/vnd.ctc-posml', 'png' => 'image/png', 'pnm' => 'image/x-portable-anymap', 'portpkg' => 'application/vnd.macports.portpkg', 'pot' => 'application/vnd.ms-powerpoint', 'potm' => 'application/vnd.ms-powerpoint.presentation.macroEnabled.12', 'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template', 'ppa' => 'application/vnd.ms-powerpoint', 'ppam' => 'application/vnd.ms-powerpoint.addin.macroEnabled.12', 'ppd' => 'application/vnd.cups-ppd', 'ppm' => 'image/x-portable-pixmap', 'pps' => 'application/vnd.ms-powerpoint', 'ppsm' => 'application/vnd.ms-powerpoint.slideshow.macroEnabled.12', 'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow', 'ppt' => 'application/powerpoint', 'pptm' => 'application/vnd.ms-powerpoint.presentation.macroEnabled.12', 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation', 'pqa' => 'application/vnd.palm', 'prc' => 'model/prc', 'pre' => 'application/vnd.lotus-freelance', 'prf' => 'application/pics-rules', 'provx' => 'application/provenance+xml', 'ps' => 'application/postscript', 'psb' => 'application/vnd.3gpp.pic-bw-small', 'psd' => 'application/x-photoshop', 'psf' => 'application/x-font-linux-psf', 'pskcxml' => 'application/pskc+xml', 'pti' => 'image/prs.pti', 'ptid' => 'application/vnd.pvi.ptid1', 'pub' => 'application/x-mspublisher', 'pvb' => 'application/vnd.3gpp.pic-bw-var', 'pwn' => 'application/vnd.3m.post-it-notes', 'pya' => 'audio/vnd.ms-playready.media.pya', 'pyv' => 'video/vnd.ms-playready.media.pyv', 'qam' => 'application/vnd.epson.quickanime', 'qbo' => 'application/vnd.intu.qbo', 'qfx' => 'application/vnd.intu.qfx', 'qps' => 'application/vnd.publishare-delta-tree', 'qt' => 'video/quicktime', 'qwd' => 'application/vnd.quark.quarkxpress', 'qwt' => 'application/vnd.quark.quarkxpress', 'qxb' => 'application/vnd.quark.quarkxpress', 'qxd' => 'application/vnd.quark.quarkxpress', 'qxl' => 'application/vnd.quark.quarkxpress', 'qxt' => 'application/vnd.quark.quarkxpress', 'ra' => 'audio/x-realaudio', 'ram' => 'audio/x-pn-realaudio', 'raml' => 'application/raml+yaml', 'rapd' => 'application/route-apd+xml', 'rar' => 'application/x-rar', 'ras' => 'image/x-cmu-raster', 'rcprofile' => 'application/vnd.ipunplugged.rcprofile', 'rdf' => 'application/rdf+xml', 'rdz' => 'application/vnd.data-vision.rdz', 'relo' => 'application/p2p-overlay+xml', 'rep' => 'application/vnd.businessobjects', 'res' => 'application/x-dtbresource+xml', 'rgb' => 'image/x-rgb', 'rif' => 'application/reginfo+xml', 'rip' => 'audio/vnd.rip', 'ris' => 'application/x-research-info-systems', 'rl' => 'application/resource-lists+xml', 'rlc' => 'image/vnd.fujixerox.edmics-rlc', 'rld' => 'application/resource-lists-diff+xml', 'rm' => 'audio/x-pn-realaudio', 'rmi' => 'audio/midi', 'rmp' => 'audio/x-pn-realaudio-plugin', 'rms' => 'application/vnd.jcp.javame.midlet-rms', 'rmvb' => 'application/vnd.rn-realmedia-vbr', 'rnc' => 'application/relax-ng-compact-syntax', 'rng' => 'application/xml', 'roa' => 'application/rpki-roa', 'roff' => 'text/troff', 'rp9' => 'application/vnd.cloanto.rp9', 'rpm' => 'audio/x-pn-realaudio-plugin', 'rpss' => 'application/vnd.nokia.radio-presets', 'rpst' => 'application/vnd.nokia.radio-preset', 'rq' => 'application/sparql-query', 'rs' => 'application/rls-services+xml', 'rsa' => 'application/x-pkcs7', 'rsat' => 'application/atsc-rsat+xml', 'rsd' => 'application/rsd+xml', 'rsheet' => 'application/urc-ressheet+xml', 'rss' => 'application/rss+xml', 'rtf' => 'text/rtf', 'rtx' => 'text/richtext', 'run' => 'application/x-makeself', 'rusd' => 'application/route-usd+xml', 'rv' => 'video/vnd.rn-realvideo', 's' => 'text/x-asm', 's3m' => 'audio/s3m', 'saf' => 'application/vnd.yamaha.smaf-audio', 'sass' => 'text/x-sass', 'sbml' => 'application/sbml+xml', 'sc' => 'application/vnd.ibm.secure-container', 'scd' => 'application/x-msschedule', 'scm' => 'application/vnd.lotus-screencam', 'scq' => 'application/scvp-cv-request', 'scs' => 'application/scvp-cv-response', 'scss' => 'text/x-scss', 'scurl' => 'text/vnd.curl.scurl', 'sda' => 'application/vnd.stardivision.draw', 'sdc' => 'application/vnd.stardivision.calc', 'sdd' => 'application/vnd.stardivision.impress', 'sdkd' => 'application/vnd.solent.sdkm+xml', 'sdkm' => 'application/vnd.solent.sdkm+xml', 'sdp' => 'application/sdp', 'sdw' => 'application/vnd.stardivision.writer', 'sea' => 'application/octet-stream', 'see' => 'application/vnd.seemail', 'seed' => 'application/vnd.fdsn.seed', 'sema' => 'application/vnd.sema', 'semd' => 'application/vnd.semd', 'semf' => 'application/vnd.semf', 'senmlx' => 'application/senml+xml', 'sensmlx' => 'application/sensml+xml', 'ser' => 'application/java-serialized-object', 'setpay' => 'application/set-payment-initiation', 'setreg' => 'application/set-registration-initiation', 'sfd-hdstx' => 'application/vnd.hydrostatix.sof-data', 'sfs' => 'application/vnd.spotfire.sfs', 'sfv' => 'text/x-sfv', 'sgi' => 'image/sgi', 'sgl' => 'application/vnd.stardivision.writer-global', 'sgm' => 'text/sgml', 'sgml' => 'text/sgml', 'sh' => 'application/x-sh', 'shar' => 'application/x-shar', 'shex' => 'text/shex', 'shf' => 'application/shf+xml', 'shtml' => 'text/html', 'sid' => 'image/x-mrsid-image', 'sieve' => 'application/sieve', 'sig' => 'application/pgp-signature', 'sil' => 'audio/silk', 'silo' => 'model/mesh', 'sis' => 'application/vnd.symbian.install', 'sisx' => 'application/vnd.symbian.install', 'sit' => 'application/x-stuffit', 'sitx' => 'application/x-stuffitx', 'siv' => 'application/sieve', 'skd' => 'application/vnd.koan', 'skm' => 'application/vnd.koan', 'skp' => 'application/vnd.koan', 'skt' => 'application/vnd.koan', 'sldm' => 'application/vnd.ms-powerpoint.slide.macroenabled.12', 'sldx' => 'application/vnd.openxmlformats-officedocument.presentationml.slide', 'slim' => 'text/slim', 'slm' => 'text/slim', 'sls' => 'application/route-s-tsid+xml', 'slt' => 'application/vnd.epson.salt', 'sm' => 'application/vnd.stepmania.stepchart', 'smf' => 'application/vnd.stardivision.math', 'smi' => 'application/smil', 'smil' => 'application/smil', 'smv' => 'video/x-smv', 'smzip' => 'application/vnd.stepmania.package', 'snd' => 'audio/basic', 'snf' => 'application/x-font-snf', 'so' => 'application/octet-stream', 'spc' => 'application/x-pkcs7-certificates', 'spdx' => 'text/spdx', 'spf' => 'application/vnd.yamaha.smaf-phrase', 'spl' => 'application/x-futuresplash', 'spot' => 'text/vnd.in3d.spot', 'spp' => 'application/scvp-vp-response', 'spq' => 'application/scvp-vp-request', 'spx' => 'audio/ogg', 'sql' => 'application/x-sql', 'src' => 'application/x-wais-source', 'srt' => 'application/x-subrip', 'sru' => 'application/sru+xml', 'srx' => 'application/sparql-results+xml', 'ssdl' => 'application/ssdl+xml', 'sse' => 'application/vnd.kodak-descriptor', 'ssf' => 'application/vnd.epson.ssf', 'ssml' => 'application/ssml+xml', 'sst' => 'application/octet-stream', 'st' => 'application/vnd.sailingtracker.track', 'stc' => 'application/vnd.sun.xml.calc.template', 'std' => 'application/vnd.sun.xml.draw.template', 'stf' => 'application/vnd.wt.stf', 'sti' => 'application/vnd.sun.xml.impress.template', 'stk' => 'application/hyperstudio', 'stl' => 'model/stl', 'stpx' => 'model/step+xml', 'stpxz' => 'model/step-xml+zip', 'stpz' => 'model/step+zip', 'str' => 'application/vnd.pg.format', 'stw' => 'application/vnd.sun.xml.writer.template', 'styl' => 'text/stylus', 'stylus' => 'text/stylus', 'sub' => 'text/vnd.dvb.subtitle', 'sus' => 'application/vnd.sus-calendar', 'susp' => 'application/vnd.sus-calendar', 'sv4cpio' => 'application/x-sv4cpio', 'sv4crc' => 'application/x-sv4crc', 'svc' => 'application/vnd.dvb.service', 'svd' => 'application/vnd.svd', 'svg' => 'image/svg+xml', 'svgz' => 'image/svg+xml', 'swa' => 'application/x-director', 'swf' => 'application/x-shockwave-flash', 'swi' => 'application/vnd.aristanetworks.swi', 'swidtag' => 'application/swid+xml', 'sxc' => 'application/vnd.sun.xml.calc', 'sxd' => 'application/vnd.sun.xml.draw', 'sxg' => 'application/vnd.sun.xml.writer.global', 'sxi' => 'application/vnd.sun.xml.impress', 'sxm' => 'application/vnd.sun.xml.math', 'sxw' => 'application/vnd.sun.xml.writer', 't' => 'text/troff', 't3' => 'application/x-t3vm-image', 't38' => 'image/t38', 'taglet' => 'application/vnd.mynfc', 'tao' => 'application/vnd.tao.intent-module-archive', 'tap' => 'image/vnd.tencent.tap', 'tar' => 'application/x-tar', 'tcap' => 'application/vnd.3gpp2.tcap', 'tcl' => 'application/x-tcl', 'td' => 'application/urc-targetdesc+xml', 'teacher' => 'application/vnd.smart.teacher', 'tei' => 'application/tei+xml', 'teicorpus' => 'application/tei+xml', 'tex' => 'application/x-tex', 'texi' => 'application/x-texinfo', 'texinfo' => 'application/x-texinfo', 'text' => 'text/plain', 'tfi' => 'application/thraud+xml', 'tfm' => 'application/x-tex-tfm', 'tfx' => 'image/tiff-fx', 'tga' => 'image/x-tga', 'tgz' => 'application/x-tar', 'thmx' => 'application/vnd.ms-officetheme', 'tif' => 'image/tiff', 'tiff' => 'image/tiff', 'tk' => 'application/x-tcl', 'tmo' => 'application/vnd.tmobile-livetv', 'toml' => 'application/toml', 'torrent' => 'application/x-bittorrent', 'tpl' => 'application/vnd.groove-tool-template', 'tpt' => 'application/vnd.trid.tpt', 'tr' => 'text/troff', 'tra' => 'application/vnd.trueapp', 'trig' => 'application/trig', 'trm' => 'application/x-msterminal', 'ts' => 'video/mp2t', 'tsd' => 'application/timestamped-data', 'tsv' => 'text/tab-separated-values', 'ttc' => 'font/collection', 'ttf' => 'font/ttf', 'ttl' => 'text/turtle', 'ttml' => 'application/ttml+xml', 'twd' => 'application/vnd.simtech-mindmapper', 'twds' => 'application/vnd.simtech-mindmapper', 'txd' => 'application/vnd.genomatix.tuxedo', 'txf' => 'application/vnd.mobius.txf', 'txt' => 'text/plain', 'u3d' => 'model/u3d', 'u8dsn' => 'message/global-delivery-status', 'u8hdr' => 'message/global-headers', 'u8mdn' => 'message/global-disposition-notification', 'u8msg' => 'message/global', 'u32' => 'application/x-authorware-bin', 'ubj' => 'application/ubjson', 'udeb' => 'application/x-debian-package', 'ufd' => 'application/vnd.ufdl', 'ufdl' => 'application/vnd.ufdl', 'ulx' => 'application/x-glulx', 'umj' => 'application/vnd.umajin', 'unityweb' => 'application/vnd.unity', 'uoml' => 'application/vnd.uoml+xml', 'uri' => 'text/uri-list', 'uris' => 'text/uri-list', 'urls' => 'text/uri-list', 'usdz' => 'model/vnd.usdz+zip', 'ustar' => 'application/x-ustar', 'utz' => 'application/vnd.uiq.theme', 'uu' => 'text/x-uuencode', 'uva' => 'audio/vnd.dece.audio', 'uvd' => 'application/vnd.dece.data', 'uvf' => 'application/vnd.dece.data', 'uvg' => 'image/vnd.dece.graphic', 'uvh' => 'video/vnd.dece.hd', 'uvi' => 'image/vnd.dece.graphic', 'uvm' => 'video/vnd.dece.mobile', 'uvp' => 'video/vnd.dece.pd', 'uvs' => 'video/vnd.dece.sd', 'uvt' => 'application/vnd.dece.ttml+xml', 'uvu' => 'video/vnd.uvvu.mp4', 'uvv' => 'video/vnd.dece.video', 'uvva' => 'audio/vnd.dece.audio', 'uvvd' => 'application/vnd.dece.data', 'uvvf' => 'application/vnd.dece.data', 'uvvg' => 'image/vnd.dece.graphic', 'uvvh' => 'video/vnd.dece.hd', 'uvvi' => 'image/vnd.dece.graphic', 'uvvm' => 'video/vnd.dece.mobile', 'uvvp' => 'video/vnd.dece.pd', 'uvvs' => 'video/vnd.dece.sd', 'uvvt' => 'application/vnd.dece.ttml+xml', 'uvvu' => 'video/vnd.uvvu.mp4', 'uvvv' => 'video/vnd.dece.video', 'uvvx' => 'application/vnd.dece.unspecified', 'uvvz' => 'application/vnd.dece.zip', 'uvx' => 'application/vnd.dece.unspecified', 'uvz' => 'application/vnd.dece.zip', 'vbox' => 'application/x-virtualbox-vbox', 'vbox-extpack' => 'application/x-virtualbox-vbox-extpack', 'vcard' => 'text/vcard', 'vcd' => 'application/x-cdlink', 'vcf' => 'text/x-vcard', 'vcg' => 'application/vnd.groove-vcard', 'vcs' => 'text/x-vcalendar', 'vcx' => 'application/vnd.vcx', 'vdi' => 'application/x-virtualbox-vdi', 'vds' => 'model/vnd.sap.vds', 'vhd' => 'application/x-virtualbox-vhd', 'vis' => 'application/vnd.visionary', 'viv' => 'video/vnd.vivo', 'vlc' => 'application/videolan', 'vmdk' => 'application/x-virtualbox-vmdk', 'vob' => 'video/x-ms-vob', 'vor' => 'application/vnd.stardivision.writer', 'vox' => 'application/x-authorware-bin', 'vrml' => 'model/vrml', 'vsd' => 'application/vnd.visio', 'vsf' => 'application/vnd.vsf', 'vss' => 'application/vnd.visio', 'vst' => 'application/vnd.visio', 'vsw' => 'application/vnd.visio', 'vtf' => 'image/vnd.valve.source.texture', 'vtt' => 'text/vtt', 'vtu' => 'model/vnd.vtu', 'vxml' => 'application/voicexml+xml', 'w3d' => 'application/x-director', 'wad' => 'application/x-doom', 'wadl' => 'application/vnd.sun.wadl+xml', 'war' => 'application/java-archive', 'wasm' => 'application/wasm', 'wav' => 'audio/x-wav', 'wax' => 'audio/x-ms-wax', 'wbmp' => 'image/vnd.wap.wbmp', 'wbs' => 'application/vnd.criticaltools.wbs+xml', 'wbxml' => 'application/wbxml', 'wcm' => 'application/vnd.ms-works', 'wdb' => 'application/vnd.ms-works', 'wdp' => 'image/vnd.ms-photo', 'weba' => 'audio/webm', 'webapp' => 'application/x-web-app-manifest+json', 'webm' => 'video/webm', 'webmanifest' => 'application/manifest+json', 'webp' => 'image/webp', 'wg' => 'application/vnd.pmi.widget', 'wgt' => 'application/widget', 'wif' => 'application/watcherinfo+xml', 'wks' => 'application/vnd.ms-works', 'wm' => 'video/x-ms-wm', 'wma' => 'audio/x-ms-wma', 'wmd' => 'application/x-ms-wmd', 'wmf' => 'image/wmf', 'wml' => 'text/vnd.wap.wml', 'wmlc' => 'application/wmlc', 'wmls' => 'text/vnd.wap.wmlscript', 'wmlsc' => 'application/vnd.wap.wmlscriptc', 'wmv' => 'video/x-ms-wmv', 'wmx' => 'video/x-ms-wmx', 'wmz' => 'application/x-msmetafile', 'woff' => 'font/woff', 'woff2' => 'font/woff2', 'word' => 'application/msword', 'wpd' => 'application/vnd.wordperfect', 'wpl' => 'application/vnd.ms-wpl', 'wps' => 'application/vnd.ms-works', 'wqd' => 'application/vnd.wqd', 'wri' => 'application/x-mswrite', 'wrl' => 'model/vrml', 'wsc' => 'message/vnd.wfa.wsc', 'wsdl' => 'application/wsdl+xml', 'wspolicy' => 'application/wspolicy+xml', 'wtb' => 'application/vnd.webturbo', 'wvx' => 'video/x-ms-wvx', 'x3d' => 'model/x3d+xml', 'x3db' => 'model/x3d+fastinfoset', 'x3dbz' => 'model/x3d+binary', 'x3dv' => 'model/x3d-vrml', 'x3dvz' => 'model/x3d+vrml', 'x3dz' => 'model/x3d+xml', 'x32' => 'application/x-authorware-bin', 'x_b' => 'model/vnd.parasolid.transmit.binary', 'x_t' => 'model/vnd.parasolid.transmit.text', 'xaml' => 'application/xaml+xml', 'xap' => 'application/x-silverlight-app', 'xar' => 'application/vnd.xara', 'xav' => 'application/xcap-att+xml', 'xbap' => 'application/x-ms-xbap', 'xbd' => 'application/vnd.fujixerox.docuworks.binder', 'xbm' => 'image/x-xbitmap', 'xca' => 'application/xcap-caps+xml', 'xcs' => 'application/calendar+xml', 'xdf' => 'application/xcap-diff+xml', 'xdm' => 'application/vnd.syncml.dm+xml', 'xdp' => 'application/vnd.adobe.xdp+xml', 'xdssc' => 'application/dssc+xml', 'xdw' => 'application/vnd.fujixerox.docuworks', 'xel' => 'application/xcap-el+xml', 'xenc' => 'application/xenc+xml', 'xer' => 'application/patch-ops-error+xml', 'xfdf' => 'application/vnd.adobe.xfdf', 'xfdl' => 'application/vnd.xfdl', 'xht' => 'application/xhtml+xml', 'xhtml' => 'application/xhtml+xml', 'xhvml' => 'application/xv+xml', 'xif' => 'image/vnd.xiff', 'xl' => 'application/excel', 'xla' => 'application/vnd.ms-excel', 'xlam' => 'application/vnd.ms-excel.addin.macroEnabled.12', 'xlc' => 'application/vnd.ms-excel', 'xlf' => 'application/xliff+xml', 'xlm' => 'application/vnd.ms-excel', 'xls' => 'application/vnd.ms-excel', 'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12', 'xlsm' => 'application/vnd.ms-excel.sheet.macroEnabled.12', 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'xlt' => 'application/vnd.ms-excel', 'xltm' => 'application/vnd.ms-excel.template.macroEnabled.12', 'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template', 'xlw' => 'application/vnd.ms-excel', 'xm' => 'audio/xm', 'xml' => 'application/xml', 'xns' => 'application/xcap-ns+xml', 'xo' => 'application/vnd.olpc-sugar', 'xop' => 'application/xop+xml', 'xpi' => 'application/x-xpinstall', 'xpl' => 'application/xproc+xml', 'xpm' => 'image/x-xpixmap', 'xpr' => 'application/vnd.is-xpr', 'xps' => 'application/vnd.ms-xpsdocument', 'xpw' => 'application/vnd.intercon.formnet', 'xpx' => 'application/vnd.intercon.formnet', 'xsd' => 'application/xml', 'xsl' => 'application/xml', 'xslt' => 'application/xslt+xml', 'xsm' => 'application/vnd.syncml+xml', 'xspf' => 'application/xspf+xml', 'xul' => 'application/vnd.mozilla.xul+xml', 'xvm' => 'application/xv+xml', 'xvml' => 'application/xv+xml', 'xwd' => 'image/x-xwindowdump', 'xyz' => 'chemical/x-xyz', 'xz' => 'application/x-xz', 'yaml' => 'text/yaml', 'yang' => 'application/yang', 'yin' => 'application/yin+xml', 'yml' => 'text/yaml', 'ymp' => 'text/x-suse-ymp', 'z' => 'application/x-compress', 'z1' => 'application/x-zmachine', 'z2' => 'application/x-zmachine', 'z3' => 'application/x-zmachine', 'z4' => 'application/x-zmachine', 'z5' => 'application/x-zmachine', 'z6' => 'application/x-zmachine', 'z7' => 'application/x-zmachine', 'z8' => 'application/x-zmachine', 'zaz' => 'application/vnd.zzazz.deck+xml', 'zip' => 'application/zip', 'zir' => 'application/vnd.zul', 'zirz' => 'application/vnd.zul', 'zmm' => 'application/vnd.handheld-entertainment+xml', 'zsh' => 'text/x-scriptzsh'];
- /**
- * Determines the mimetype of a file by looking at its extension.
- *
- * @see https://raw.githubusercontent.com/jshttp/mime-db/master/db.json
- */
- public static function fromFilename(string $filename) : ?string
- {
- return self::fromExtension(pathinfo($filename, \PATHINFO_EXTENSION));
- }
- /**
- * Maps a file extensions to a mimetype.
- *
- * @see https://raw.githubusercontent.com/jshttp/mime-db/master/db.json
- */
- public static function fromExtension(string $extension) : ?string
- {
- return self::MIME_TYPES[strtolower($extension)] ?? null;
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/MultipartStream.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/MultipartStream.php
deleted file mode 100644
index 5dda6c7..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/MultipartStream.php
+++ /dev/null
@@ -1,124 +0,0 @@
-boundary = $boundary ?: bin2hex(random_bytes(20));
- $this->stream = $this->createStream($elements);
- }
- public function getBoundary() : string
- {
- return $this->boundary;
- }
- public function isWritable() : bool
- {
- return \false;
- }
- /**
- * Get the headers needed before transferring the content of a POST file
- *
- * @param array $headers
- */
- private function getHeaders(array $headers) : string
- {
- $str = '';
- foreach ($headers as $key => $value) {
- $str .= "{$key}: {$value}\r\n";
- }
- return "--{$this->boundary}\r\n" . trim($str) . "\r\n\r\n";
- }
- /**
- * Create the aggregate stream that will be used to upload the POST data
- */
- protected function createStream(array $elements = []) : StreamInterface
- {
- $stream = new AppendStream();
- foreach ($elements as $element) {
- if (!is_array($element)) {
- throw new \UnexpectedValueException('An array is expected');
- }
- $this->addElement($stream, $element);
- }
- // Add the trailing boundary with CRLF
- $stream->addStream(Utils::streamFor("--{$this->boundary}--\r\n"));
- return $stream;
- }
- private function addElement(AppendStream $stream, array $element) : void
- {
- foreach (['contents', 'name'] as $key) {
- if (!array_key_exists($key, $element)) {
- throw new \InvalidArgumentException("A '{$key}' key is required");
- }
- }
- $element['contents'] = Utils::streamFor($element['contents']);
- if (empty($element['filename'])) {
- $uri = $element['contents']->getMetadata('uri');
- if ($uri && \is_string($uri) && \substr($uri, 0, 6) !== 'php://' && \substr($uri, 0, 7) !== 'data://') {
- $element['filename'] = $uri;
- }
- }
- [$body, $headers] = $this->createElement($element['name'], $element['contents'], $element['filename'] ?? null, $element['headers'] ?? []);
- $stream->addStream(Utils::streamFor($this->getHeaders($headers)));
- $stream->addStream($body);
- $stream->addStream(Utils::streamFor("\r\n"));
- }
- private function createElement(string $name, StreamInterface $stream, ?string $filename, array $headers) : array
- {
- // Set a default content-disposition header if one was no provided
- $disposition = $this->getHeader($headers, 'content-disposition');
- if (!$disposition) {
- $headers['Content-Disposition'] = $filename === '0' || $filename ? sprintf('form-data; name="%s"; filename="%s"', $name, basename($filename)) : "form-data; name=\"{$name}\"";
- }
- // Set a default content-length header if one was no provided
- $length = $this->getHeader($headers, 'content-length');
- if (!$length) {
- if ($length = $stream->getSize()) {
- $headers['Content-Length'] = (string) $length;
- }
- }
- // Set a default Content-Type if one was not supplied
- $type = $this->getHeader($headers, 'content-type');
- if (!$type && ($filename === '0' || $filename)) {
- if ($type = MimeType::fromFilename($filename)) {
- $headers['Content-Type'] = $type;
- }
- }
- return [$stream, $headers];
- }
- private function getHeader(array $headers, string $key)
- {
- $lowercaseHeader = strtolower($key);
- foreach ($headers as $k => $v) {
- if (strtolower($k) === $lowercaseHeader) {
- return $v;
- }
- }
- return null;
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/NoSeekStream.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/NoSeekStream.php
deleted file mode 100644
index 8be49b0..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/NoSeekStream.php
+++ /dev/null
@@ -1,23 +0,0 @@
-source = $source;
- $this->size = $options['size'] ?? null;
- $this->metadata = $options['metadata'] ?? [];
- $this->buffer = new BufferStream();
- }
- public function __toString() : string
- {
- try {
- return Utils::copyToString($this);
- } catch (\Throwable $e) {
- if (\PHP_VERSION_ID >= 70400) {
- throw $e;
- }
- trigger_error(sprintf('%s::__toString exception: %s', self::class, (string) $e), \E_USER_ERROR);
- return '';
- }
- }
- public function close() : void
- {
- $this->detach();
- }
- public function detach()
- {
- $this->tellPos = 0;
- $this->source = null;
- return null;
- }
- public function getSize() : ?int
- {
- return $this->size;
- }
- public function tell() : int
- {
- return $this->tellPos;
- }
- public function eof() : bool
- {
- return $this->source === null;
- }
- public function isSeekable() : bool
- {
- return \false;
- }
- public function rewind() : void
- {
- $this->seek(0);
- }
- public function seek($offset, $whence = \SEEK_SET) : void
- {
- throw new \RuntimeException('Cannot seek a PumpStream');
- }
- public function isWritable() : bool
- {
- return \false;
- }
- public function write($string) : int
- {
- throw new \RuntimeException('Cannot write to a PumpStream');
- }
- public function isReadable() : bool
- {
- return \true;
- }
- public function read($length) : string
- {
- $data = $this->buffer->read($length);
- $readLen = strlen($data);
- $this->tellPos += $readLen;
- $remaining = $length - $readLen;
- if ($remaining) {
- $this->pump($remaining);
- $data .= $this->buffer->read($remaining);
- $this->tellPos += strlen($data) - $readLen;
- }
- return $data;
- }
- public function getContents() : string
- {
- $result = '';
- while (!$this->eof()) {
- $result .= $this->read(1000000);
- }
- return $result;
- }
- /**
- * {@inheritdoc}
- *
- * @return mixed
- */
- public function getMetadata($key = null)
- {
- if (!$key) {
- return $this->metadata;
- }
- return $this->metadata[$key] ?? null;
- }
- private function pump(int $length) : void
- {
- if ($this->source) {
- do {
- $data = call_user_func($this->source, $length);
- if ($data === \false || $data === null) {
- $this->source = null;
- return;
- }
- $this->buffer->write($data);
- $length -= strlen($data);
- } while ($length > 0);
- }
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/Query.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/Query.php
deleted file mode 100644
index f9d3f6f..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/Query.php
+++ /dev/null
@@ -1,104 +0,0 @@
- '1', 'foo[b]' => '2'])`.
- *
- * @param string $str Query string to parse
- * @param int|bool $urlEncoding How the query string is encoded
- */
- public static function parse(string $str, $urlEncoding = \true) : array
- {
- $result = [];
- if ($str === '') {
- return $result;
- }
- if ($urlEncoding === \true) {
- $decoder = function ($value) {
- return rawurldecode(str_replace('+', ' ', (string) $value));
- };
- } elseif ($urlEncoding === \PHP_QUERY_RFC3986) {
- $decoder = 'rawurldecode';
- } elseif ($urlEncoding === \PHP_QUERY_RFC1738) {
- $decoder = 'urldecode';
- } else {
- $decoder = function ($str) {
- return $str;
- };
- }
- foreach (explode('&', $str) as $kvp) {
- $parts = explode('=', $kvp, 2);
- $key = $decoder($parts[0]);
- $value = isset($parts[1]) ? $decoder($parts[1]) : null;
- if (!array_key_exists($key, $result)) {
- $result[$key] = $value;
- } else {
- if (!is_array($result[$key])) {
- $result[$key] = [$result[$key]];
- }
- $result[$key][] = $value;
- }
- }
- return $result;
- }
- /**
- * Build a query string from an array of key value pairs.
- *
- * This function can use the return value of `parse()` to build a query
- * string. This function does not modify the provided keys when an array is
- * encountered (like `http_build_query()` would).
- *
- * @param array $params Query string parameters.
- * @param int|false $encoding Set to false to not encode, PHP_QUERY_RFC3986
- * to encode using RFC3986, or PHP_QUERY_RFC1738
- * to encode using RFC1738.
- */
- public static function build(array $params, $encoding = \PHP_QUERY_RFC3986) : string
- {
- if (!$params) {
- return '';
- }
- if ($encoding === \false) {
- $encoder = function (string $str) : string {
- return $str;
- };
- } elseif ($encoding === \PHP_QUERY_RFC3986) {
- $encoder = 'rawurlencode';
- } elseif ($encoding === \PHP_QUERY_RFC1738) {
- $encoder = 'urlencode';
- } else {
- throw new \InvalidArgumentException('Invalid type');
- }
- $qs = '';
- foreach ($params as $k => $v) {
- $k = $encoder((string) $k);
- if (!is_array($v)) {
- $qs .= $k;
- $v = is_bool($v) ? (int) $v : $v;
- if ($v !== null) {
- $qs .= '=' . $encoder((string) $v);
- }
- $qs .= '&';
- } else {
- foreach ($v as $vv) {
- $qs .= $k;
- $vv = is_bool($vv) ? (int) $vv : $vv;
- if ($vv !== null) {
- $qs .= '=' . $encoder((string) $vv);
- }
- $qs .= '&';
- }
- }
- }
- return $qs ? (string) substr($qs, 0, -1) : '';
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/Request.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/Request.php
deleted file mode 100644
index 45c3eee..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/Request.php
+++ /dev/null
@@ -1,124 +0,0 @@
- $headers Request headers
- * @param string|resource|StreamInterface|null $body Request body
- * @param string $version Protocol version
- */
- public function __construct(string $method, $uri, array $headers = [], $body = null, string $version = '1.1')
- {
- $this->assertMethod($method);
- if (!$uri instanceof UriInterface) {
- $uri = new Uri($uri);
- }
- $this->method = strtoupper($method);
- $this->uri = $uri;
- $this->setHeaders($headers);
- $this->protocol = $version;
- if (!isset($this->headerNames['host'])) {
- $this->updateHostFromUri();
- }
- if ($body !== '' && $body !== null) {
- $this->stream = Utils::streamFor($body);
- }
- }
- public function getRequestTarget() : string
- {
- if ($this->requestTarget !== null) {
- return $this->requestTarget;
- }
- $target = $this->uri->getPath();
- if ($target === '') {
- $target = '/';
- }
- if ($this->uri->getQuery() != '') {
- $target .= '?' . $this->uri->getQuery();
- }
- return $target;
- }
- public function withRequestTarget($requestTarget) : RequestInterface
- {
- if (preg_match('#\\s#', $requestTarget)) {
- throw new InvalidArgumentException('Invalid request target provided; cannot contain whitespace');
- }
- $new = clone $this;
- $new->requestTarget = $requestTarget;
- return $new;
- }
- public function getMethod() : string
- {
- return $this->method;
- }
- public function withMethod($method) : RequestInterface
- {
- $this->assertMethod($method);
- $new = clone $this;
- $new->method = strtoupper($method);
- return $new;
- }
- public function getUri() : UriInterface
- {
- return $this->uri;
- }
- public function withUri(UriInterface $uri, $preserveHost = \false) : RequestInterface
- {
- if ($uri === $this->uri) {
- return $this;
- }
- $new = clone $this;
- $new->uri = $uri;
- if (!$preserveHost || !isset($this->headerNames['host'])) {
- $new->updateHostFromUri();
- }
- return $new;
- }
- private function updateHostFromUri() : void
- {
- $host = $this->uri->getHost();
- if ($host == '') {
- return;
- }
- if (($port = $this->uri->getPort()) !== null) {
- $host .= ':' . $port;
- }
- if (isset($this->headerNames['host'])) {
- $header = $this->headerNames['host'];
- } else {
- $header = 'Host';
- $this->headerNames['host'] = 'Host';
- }
- // Ensure Host is the first header.
- // See: http://tools.ietf.org/html/rfc7230#section-5.4
- $this->headers = [$header => [$host]] + $this->headers;
- }
- /**
- * @param mixed $method
- */
- private function assertMethod($method) : void
- {
- if (!is_string($method) || $method === '') {
- throw new InvalidArgumentException('Method must be a non-empty string.');
- }
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/Response.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/Response.php
deleted file mode 100644
index d880e8f..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/Response.php
+++ /dev/null
@@ -1,78 +0,0 @@
- 'Continue', 101 => 'Switching Protocols', 102 => 'Processing', 200 => 'OK', 201 => 'Created', 202 => 'Accepted', 203 => 'Non-Authoritative Information', 204 => 'No Content', 205 => 'Reset Content', 206 => 'Partial Content', 207 => 'Multi-status', 208 => 'Already Reported', 300 => 'Multiple Choices', 301 => 'Moved Permanently', 302 => 'Found', 303 => 'See Other', 304 => 'Not Modified', 305 => 'Use Proxy', 306 => 'Switch Proxy', 307 => 'Temporary Redirect', 308 => 'Permanent Redirect', 400 => 'Bad Request', 401 => 'Unauthorized', 402 => 'Payment Required', 403 => 'Forbidden', 404 => 'Not Found', 405 => 'Method Not Allowed', 406 => 'Not Acceptable', 407 => 'Proxy Authentication Required', 408 => 'Request Time-out', 409 => 'Conflict', 410 => 'Gone', 411 => 'Length Required', 412 => 'Precondition Failed', 413 => 'Request Entity Too Large', 414 => 'Request-URI Too Large', 415 => 'Unsupported Media Type', 416 => 'Requested range not satisfiable', 417 => 'Expectation Failed', 418 => 'I\'m a teapot', 422 => 'Unprocessable Entity', 423 => 'Locked', 424 => 'Failed Dependency', 425 => 'Unordered Collection', 426 => 'Upgrade Required', 428 => 'Precondition Required', 429 => 'Too Many Requests', 431 => 'Request Header Fields Too Large', 451 => 'Unavailable For Legal Reasons', 500 => 'Internal Server Error', 501 => 'Not Implemented', 502 => 'Bad Gateway', 503 => 'Service Unavailable', 504 => 'Gateway Time-out', 505 => 'HTTP Version not supported', 506 => 'Variant Also Negotiates', 507 => 'Insufficient Storage', 508 => 'Loop Detected', 510 => 'Not Extended', 511 => 'Network Authentication Required'];
- /** @var string */
- private $reasonPhrase;
- /** @var int */
- private $statusCode;
- /**
- * @param int $status Status code
- * @param array $headers Response headers
- * @param string|resource|StreamInterface|null $body Response body
- * @param string $version Protocol version
- * @param string|null $reason Reason phrase (when empty a default will be used based on the status code)
- */
- public function __construct(int $status = 200, array $headers = [], $body = null, string $version = '1.1', string $reason = null)
- {
- $this->assertStatusCodeRange($status);
- $this->statusCode = $status;
- if ($body !== '' && $body !== null) {
- $this->stream = Utils::streamFor($body);
- }
- $this->setHeaders($headers);
- if ($reason == '' && isset(self::PHRASES[$this->statusCode])) {
- $this->reasonPhrase = self::PHRASES[$this->statusCode];
- } else {
- $this->reasonPhrase = (string) $reason;
- }
- $this->protocol = $version;
- }
- public function getStatusCode() : int
- {
- return $this->statusCode;
- }
- public function getReasonPhrase() : string
- {
- return $this->reasonPhrase;
- }
- public function withStatus($code, $reasonPhrase = '') : ResponseInterface
- {
- $this->assertStatusCodeIsInteger($code);
- $code = (int) $code;
- $this->assertStatusCodeRange($code);
- $new = clone $this;
- $new->statusCode = $code;
- if ($reasonPhrase == '' && isset(self::PHRASES[$new->statusCode])) {
- $reasonPhrase = self::PHRASES[$new->statusCode];
- }
- $new->reasonPhrase = (string) $reasonPhrase;
- return $new;
- }
- /**
- * @param mixed $statusCode
- */
- private function assertStatusCodeIsInteger($statusCode) : void
- {
- if (filter_var($statusCode, \FILTER_VALIDATE_INT) === \false) {
- throw new \InvalidArgumentException('Status code must be an integer value.');
- }
- }
- private function assertStatusCodeRange(int $statusCode) : void
- {
- if ($statusCode < 100 || $statusCode >= 600) {
- throw new \InvalidArgumentException('Status code must be an integer value between 1xx and 5xx.');
- }
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/Rfc7230.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/Rfc7230.php
deleted file mode 100644
index 6c4c372..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/Rfc7230.php
+++ /dev/null
@@ -1,22 +0,0 @@
-@,;:\\\"/[\\]?={}\x01- ]++):[ \t]*+((?:[ \t]*+[!-~\x80-\xff]++)*+)[ \t]*+\r?\n)m";
- public const HEADER_FOLD_REGEX = "(\r?\n[ \t]++)";
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/ServerRequest.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/ServerRequest.php
deleted file mode 100644
index 75cdb57..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/ServerRequest.php
+++ /dev/null
@@ -1,270 +0,0 @@
- $headers Request headers
- * @param string|resource|StreamInterface|null $body Request body
- * @param string $version Protocol version
- * @param array $serverParams Typically the $_SERVER superglobal
- */
- public function __construct(string $method, $uri, array $headers = [], $body = null, string $version = '1.1', array $serverParams = [])
- {
- $this->serverParams = $serverParams;
- parent::__construct($method, $uri, $headers, $body, $version);
- }
- /**
- * Return an UploadedFile instance array.
- *
- * @param array $files An array which respect $_FILES structure
- *
- * @throws InvalidArgumentException for unrecognized values
- */
- public static function normalizeFiles(array $files) : array
- {
- $normalized = [];
- foreach ($files as $key => $value) {
- if ($value instanceof UploadedFileInterface) {
- $normalized[$key] = $value;
- } elseif (is_array($value) && isset($value['tmp_name'])) {
- $normalized[$key] = self::createUploadedFileFromSpec($value);
- } elseif (is_array($value)) {
- $normalized[$key] = self::normalizeFiles($value);
- continue;
- } else {
- throw new InvalidArgumentException('Invalid value in files specification');
- }
- }
- return $normalized;
- }
- /**
- * Create and return an UploadedFile instance from a $_FILES specification.
- *
- * If the specification represents an array of values, this method will
- * delegate to normalizeNestedFileSpec() and return that return value.
- *
- * @param array $value $_FILES struct
- *
- * @return UploadedFileInterface|UploadedFileInterface[]
- */
- private static function createUploadedFileFromSpec(array $value)
- {
- if (is_array($value['tmp_name'])) {
- return self::normalizeNestedFileSpec($value);
- }
- return new UploadedFile($value['tmp_name'], (int) $value['size'], (int) $value['error'], $value['name'], $value['type']);
- }
- /**
- * Normalize an array of file specifications.
- *
- * Loops through all nested files and returns a normalized array of
- * UploadedFileInterface instances.
- *
- * @return UploadedFileInterface[]
- */
- private static function normalizeNestedFileSpec(array $files = []) : array
- {
- $normalizedFiles = [];
- foreach (array_keys($files['tmp_name']) as $key) {
- $spec = ['tmp_name' => $files['tmp_name'][$key], 'size' => $files['size'][$key] ?? null, 'error' => $files['error'][$key] ?? null, 'name' => $files['name'][$key] ?? null, 'type' => $files['type'][$key] ?? null];
- $normalizedFiles[$key] = self::createUploadedFileFromSpec($spec);
- }
- return $normalizedFiles;
- }
- /**
- * Return a ServerRequest populated with superglobals:
- * $_GET
- * $_POST
- * $_COOKIE
- * $_FILES
- * $_SERVER
- */
- public static function fromGlobals() : ServerRequestInterface
- {
- $method = $_SERVER['REQUEST_METHOD'] ?? 'GET';
- $headers = getallheaders();
- $uri = self::getUriFromGlobals();
- $body = new CachingStream(new LazyOpenStream('php://input', 'r+'));
- $protocol = isset($_SERVER['SERVER_PROTOCOL']) ? str_replace('HTTP/', '', $_SERVER['SERVER_PROTOCOL']) : '1.1';
- $serverRequest = new ServerRequest($method, $uri, $headers, $body, $protocol, $_SERVER);
- return $serverRequest->withCookieParams($_COOKIE)->withQueryParams($_GET)->withParsedBody($_POST)->withUploadedFiles(self::normalizeFiles($_FILES));
- }
- private static function extractHostAndPortFromAuthority(string $authority) : array
- {
- $uri = 'http://' . $authority;
- $parts = parse_url($uri);
- if (\false === $parts) {
- return [null, null];
- }
- $host = $parts['host'] ?? null;
- $port = $parts['port'] ?? null;
- return [$host, $port];
- }
- /**
- * Get a Uri populated with values from $_SERVER.
- */
- public static function getUriFromGlobals() : UriInterface
- {
- $uri = new Uri('');
- $uri = $uri->withScheme(!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' ? 'https' : 'http');
- $hasPort = \false;
- if (isset($_SERVER['HTTP_HOST'])) {
- [$host, $port] = self::extractHostAndPortFromAuthority($_SERVER['HTTP_HOST']);
- if ($host !== null) {
- $uri = $uri->withHost($host);
- }
- if ($port !== null) {
- $hasPort = \true;
- $uri = $uri->withPort($port);
- }
- } elseif (isset($_SERVER['SERVER_NAME'])) {
- $uri = $uri->withHost($_SERVER['SERVER_NAME']);
- } elseif (isset($_SERVER['SERVER_ADDR'])) {
- $uri = $uri->withHost($_SERVER['SERVER_ADDR']);
- }
- if (!$hasPort && isset($_SERVER['SERVER_PORT'])) {
- $uri = $uri->withPort($_SERVER['SERVER_PORT']);
- }
- $hasQuery = \false;
- if (isset($_SERVER['REQUEST_URI'])) {
- $requestUriParts = explode('?', $_SERVER['REQUEST_URI'], 2);
- $uri = $uri->withPath($requestUriParts[0]);
- if (isset($requestUriParts[1])) {
- $hasQuery = \true;
- $uri = $uri->withQuery($requestUriParts[1]);
- }
- }
- if (!$hasQuery && isset($_SERVER['QUERY_STRING'])) {
- $uri = $uri->withQuery($_SERVER['QUERY_STRING']);
- }
- return $uri;
- }
- public function getServerParams() : array
- {
- return $this->serverParams;
- }
- public function getUploadedFiles() : array
- {
- return $this->uploadedFiles;
- }
- public function withUploadedFiles(array $uploadedFiles) : ServerRequestInterface
- {
- $new = clone $this;
- $new->uploadedFiles = $uploadedFiles;
- return $new;
- }
- public function getCookieParams() : array
- {
- return $this->cookieParams;
- }
- public function withCookieParams(array $cookies) : ServerRequestInterface
- {
- $new = clone $this;
- $new->cookieParams = $cookies;
- return $new;
- }
- public function getQueryParams() : array
- {
- return $this->queryParams;
- }
- public function withQueryParams(array $query) : ServerRequestInterface
- {
- $new = clone $this;
- $new->queryParams = $query;
- return $new;
- }
- /**
- * {@inheritdoc}
- *
- * @return array|object|null
- */
- public function getParsedBody()
- {
- return $this->parsedBody;
- }
- public function withParsedBody($data) : ServerRequestInterface
- {
- $new = clone $this;
- $new->parsedBody = $data;
- return $new;
- }
- public function getAttributes() : array
- {
- return $this->attributes;
- }
- /**
- * {@inheritdoc}
- *
- * @return mixed
- */
- public function getAttribute($attribute, $default = null)
- {
- if (\false === array_key_exists($attribute, $this->attributes)) {
- return $default;
- }
- return $this->attributes[$attribute];
- }
- public function withAttribute($attribute, $value) : ServerRequestInterface
- {
- $new = clone $this;
- $new->attributes[$attribute] = $value;
- return $new;
- }
- public function withoutAttribute($attribute) : ServerRequestInterface
- {
- if (\false === array_key_exists($attribute, $this->attributes)) {
- return $this;
- }
- $new = clone $this;
- unset($new->attributes[$attribute]);
- return $new;
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/Stream.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/Stream.php
deleted file mode 100644
index 35ba8c1..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/Stream.php
+++ /dev/null
@@ -1,237 +0,0 @@
-size = $options['size'];
- }
- $this->customMetadata = $options['metadata'] ?? [];
- $this->stream = $stream;
- $meta = stream_get_meta_data($this->stream);
- $this->seekable = $meta['seekable'];
- $this->readable = (bool) preg_match(self::READABLE_MODES, $meta['mode']);
- $this->writable = (bool) preg_match(self::WRITABLE_MODES, $meta['mode']);
- $this->uri = $this->getMetadata('uri');
- }
- /**
- * Closes the stream when the destructed
- */
- public function __destruct()
- {
- $this->close();
- }
- public function __toString() : string
- {
- try {
- if ($this->isSeekable()) {
- $this->seek(0);
- }
- return $this->getContents();
- } catch (\Throwable $e) {
- if (\PHP_VERSION_ID >= 70400) {
- throw $e;
- }
- trigger_error(sprintf('%s::__toString exception: %s', self::class, (string) $e), \E_USER_ERROR);
- return '';
- }
- }
- public function getContents() : string
- {
- if (!isset($this->stream)) {
- throw new \RuntimeException('Stream is detached');
- }
- if (!$this->readable) {
- throw new \RuntimeException('Cannot read from non-readable stream');
- }
- return Utils::tryGetContents($this->stream);
- }
- public function close() : void
- {
- if (isset($this->stream)) {
- if (is_resource($this->stream)) {
- fclose($this->stream);
- }
- $this->detach();
- }
- }
- public function detach()
- {
- if (!isset($this->stream)) {
- return null;
- }
- $result = $this->stream;
- unset($this->stream);
- $this->size = $this->uri = null;
- $this->readable = $this->writable = $this->seekable = \false;
- return $result;
- }
- public function getSize() : ?int
- {
- if ($this->size !== null) {
- return $this->size;
- }
- if (!isset($this->stream)) {
- return null;
- }
- // Clear the stat cache if the stream has a URI
- if ($this->uri) {
- clearstatcache(\true, $this->uri);
- }
- $stats = fstat($this->stream);
- if (is_array($stats) && isset($stats['size'])) {
- $this->size = $stats['size'];
- return $this->size;
- }
- return null;
- }
- public function isReadable() : bool
- {
- return $this->readable;
- }
- public function isWritable() : bool
- {
- return $this->writable;
- }
- public function isSeekable() : bool
- {
- return $this->seekable;
- }
- public function eof() : bool
- {
- if (!isset($this->stream)) {
- throw new \RuntimeException('Stream is detached');
- }
- return feof($this->stream);
- }
- public function tell() : int
- {
- if (!isset($this->stream)) {
- throw new \RuntimeException('Stream is detached');
- }
- $result = ftell($this->stream);
- if ($result === \false) {
- throw new \RuntimeException('Unable to determine stream position');
- }
- return $result;
- }
- public function rewind() : void
- {
- $this->seek(0);
- }
- public function seek($offset, $whence = \SEEK_SET) : void
- {
- $whence = (int) $whence;
- if (!isset($this->stream)) {
- throw new \RuntimeException('Stream is detached');
- }
- if (!$this->seekable) {
- throw new \RuntimeException('Stream is not seekable');
- }
- if (fseek($this->stream, $offset, $whence) === -1) {
- throw new \RuntimeException('Unable to seek to stream position ' . $offset . ' with whence ' . var_export($whence, \true));
- }
- }
- public function read($length) : string
- {
- if (!isset($this->stream)) {
- throw new \RuntimeException('Stream is detached');
- }
- if (!$this->readable) {
- throw new \RuntimeException('Cannot read from non-readable stream');
- }
- if ($length < 0) {
- throw new \RuntimeException('Length parameter cannot be negative');
- }
- if (0 === $length) {
- return '';
- }
- try {
- $string = fread($this->stream, $length);
- } catch (\Exception $e) {
- throw new \RuntimeException('Unable to read from stream', 0, $e);
- }
- if (\false === $string) {
- throw new \RuntimeException('Unable to read from stream');
- }
- return $string;
- }
- public function write($string) : int
- {
- if (!isset($this->stream)) {
- throw new \RuntimeException('Stream is detached');
- }
- if (!$this->writable) {
- throw new \RuntimeException('Cannot write to a non-writable stream');
- }
- // We can't know the size after writing anything
- $this->size = null;
- $result = fwrite($this->stream, $string);
- if ($result === \false) {
- throw new \RuntimeException('Unable to write to stream');
- }
- return $result;
- }
- /**
- * {@inheritdoc}
- *
- * @return mixed
- */
- public function getMetadata($key = null)
- {
- if (!isset($this->stream)) {
- return $key ? null : [];
- } elseif (!$key) {
- return $this->customMetadata + stream_get_meta_data($this->stream);
- } elseif (isset($this->customMetadata[$key])) {
- return $this->customMetadata[$key];
- }
- $meta = stream_get_meta_data($this->stream);
- return $meta[$key] ?? null;
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/StreamDecoratorTrait.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/StreamDecoratorTrait.php
deleted file mode 100644
index a476377..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/StreamDecoratorTrait.php
+++ /dev/null
@@ -1,133 +0,0 @@
-stream = $stream;
- }
- /**
- * Magic method used to create a new stream if streams are not added in
- * the constructor of a decorator (e.g., LazyOpenStream).
- *
- * @return StreamInterface
- */
- public function __get(string $name)
- {
- if ($name === 'stream') {
- $this->stream = $this->createStream();
- return $this->stream;
- }
- throw new \UnexpectedValueException("{$name} not found on class");
- }
- public function __toString() : string
- {
- try {
- if ($this->isSeekable()) {
- $this->seek(0);
- }
- return $this->getContents();
- } catch (\Throwable $e) {
- if (\PHP_VERSION_ID >= 70400) {
- throw $e;
- }
- trigger_error(sprintf('%s::__toString exception: %s', self::class, (string) $e), \E_USER_ERROR);
- return '';
- }
- }
- public function getContents() : string
- {
- return Utils::copyToString($this);
- }
- /**
- * Allow decorators to implement custom methods
- *
- * @return mixed
- */
- public function __call(string $method, array $args)
- {
- /** @var callable $callable */
- $callable = [$this->stream, $method];
- $result = call_user_func_array($callable, $args);
- // Always return the wrapped object if the result is a return $this
- return $result === $this->stream ? $this : $result;
- }
- public function close() : void
- {
- $this->stream->close();
- }
- /**
- * {@inheritdoc}
- *
- * @return mixed
- */
- public function getMetadata($key = null)
- {
- return $this->stream->getMetadata($key);
- }
- public function detach()
- {
- return $this->stream->detach();
- }
- public function getSize() : ?int
- {
- return $this->stream->getSize();
- }
- public function eof() : bool
- {
- return $this->stream->eof();
- }
- public function tell() : int
- {
- return $this->stream->tell();
- }
- public function isReadable() : bool
- {
- return $this->stream->isReadable();
- }
- public function isWritable() : bool
- {
- return $this->stream->isWritable();
- }
- public function isSeekable() : bool
- {
- return $this->stream->isSeekable();
- }
- public function rewind() : void
- {
- $this->seek(0);
- }
- public function seek($offset, $whence = \SEEK_SET) : void
- {
- $this->stream->seek($offset, $whence);
- }
- public function read($length) : string
- {
- return $this->stream->read($length);
- }
- public function write($string) : int
- {
- return $this->stream->write($string);
- }
- /**
- * Implement in subclasses to dynamically create streams when requested.
- *
- * @throws \BadMethodCallException
- */
- protected function createStream() : StreamInterface
- {
- throw new \BadMethodCallException('Not implemented');
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/StreamWrapper.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/StreamWrapper.php
deleted file mode 100644
index 39995f1..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/StreamWrapper.php
+++ /dev/null
@@ -1,114 +0,0 @@
-isReadable()) {
- $mode = $stream->isWritable() ? 'r+' : 'r';
- } elseif ($stream->isWritable()) {
- $mode = 'w';
- } else {
- throw new \InvalidArgumentException('The stream must be readable, ' . 'writable, or both.');
- }
- return fopen('guzzle://stream', $mode, \false, self::createStreamContext($stream));
- }
- /**
- * Creates a stream context that can be used to open a stream as a php stream resource.
- *
- * @return resource
- */
- public static function createStreamContext(StreamInterface $stream)
- {
- return stream_context_create(['guzzle' => ['stream' => $stream]]);
- }
- /**
- * Registers the stream wrapper if needed
- */
- public static function register() : void
- {
- if (!in_array('guzzle', stream_get_wrappers())) {
- stream_wrapper_register('guzzle', __CLASS__);
- }
- }
- public function stream_open(string $path, string $mode, int $options, string &$opened_path = null) : bool
- {
- $options = stream_context_get_options($this->context);
- if (!isset($options['guzzle']['stream'])) {
- return \false;
- }
- $this->mode = $mode;
- $this->stream = $options['guzzle']['stream'];
- return \true;
- }
- public function stream_read(int $count) : string
- {
- return $this->stream->read($count);
- }
- public function stream_write(string $data) : int
- {
- return $this->stream->write($data);
- }
- public function stream_tell() : int
- {
- return $this->stream->tell();
- }
- public function stream_eof() : bool
- {
- return $this->stream->eof();
- }
- public function stream_seek(int $offset, int $whence) : bool
- {
- $this->stream->seek($offset, $whence);
- return \true;
- }
- /**
- * @return resource|false
- */
- public function stream_cast(int $cast_as)
- {
- $stream = clone $this->stream;
- $resource = $stream->detach();
- return $resource ?? \false;
- }
- /**
- * @return array
- */
- public function stream_stat() : array
- {
- static $modeMap = ['r' => 33060, 'rb' => 33060, 'r+' => 33206, 'w' => 33188, 'wb' => 33188];
- return ['dev' => 0, 'ino' => 0, 'mode' => $modeMap[$this->mode], 'nlink' => 0, 'uid' => 0, 'gid' => 0, 'rdev' => 0, 'size' => $this->stream->getSize() ?: 0, 'atime' => 0, 'mtime' => 0, 'ctime' => 0, 'blksize' => 0, 'blocks' => 0];
- }
- /**
- * @return array
- */
- public function url_stat(string $path, int $flags) : array
- {
- return ['dev' => 0, 'ino' => 0, 'mode' => 0, 'nlink' => 0, 'uid' => 0, 'gid' => 0, 'rdev' => 0, 'size' => 0, 'atime' => 0, 'mtime' => 0, 'ctime' => 0, 'blksize' => 0, 'blocks' => 0];
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/UploadedFile.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/UploadedFile.php
deleted file mode 100644
index 4a00af8..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/UploadedFile.php
+++ /dev/null
@@ -1,152 +0,0 @@
-setError($errorStatus);
- $this->size = $size;
- $this->clientFilename = $clientFilename;
- $this->clientMediaType = $clientMediaType;
- if ($this->isOk()) {
- $this->setStreamOrFile($streamOrFile);
- }
- }
- /**
- * Depending on the value set file or stream variable
- *
- * @param StreamInterface|string|resource $streamOrFile
- *
- * @throws InvalidArgumentException
- */
- private function setStreamOrFile($streamOrFile) : void
- {
- if (is_string($streamOrFile)) {
- $this->file = $streamOrFile;
- } elseif (is_resource($streamOrFile)) {
- $this->stream = new Stream($streamOrFile);
- } elseif ($streamOrFile instanceof StreamInterface) {
- $this->stream = $streamOrFile;
- } else {
- throw new InvalidArgumentException('Invalid stream or file provided for UploadedFile');
- }
- }
- /**
- * @throws InvalidArgumentException
- */
- private function setError(int $error) : void
- {
- if (\false === in_array($error, UploadedFile::ERRORS, \true)) {
- throw new InvalidArgumentException('Invalid error status for UploadedFile');
- }
- $this->error = $error;
- }
- private function isStringNotEmpty($param) : bool
- {
- return is_string($param) && \false === empty($param);
- }
- /**
- * Return true if there is no upload error
- */
- private function isOk() : bool
- {
- return $this->error === \UPLOAD_ERR_OK;
- }
- public function isMoved() : bool
- {
- return $this->moved;
- }
- /**
- * @throws RuntimeException if is moved or not ok
- */
- private function validateActive() : void
- {
- if (\false === $this->isOk()) {
- throw new RuntimeException('Cannot retrieve stream due to upload error');
- }
- if ($this->isMoved()) {
- throw new RuntimeException('Cannot retrieve stream after it has already been moved');
- }
- }
- public function getStream() : StreamInterface
- {
- $this->validateActive();
- if ($this->stream instanceof StreamInterface) {
- return $this->stream;
- }
- /** @var string $file */
- $file = $this->file;
- return new LazyOpenStream($file, 'r+');
- }
- public function moveTo($targetPath) : void
- {
- $this->validateActive();
- if (\false === $this->isStringNotEmpty($targetPath)) {
- throw new InvalidArgumentException('Invalid path provided for move operation; must be a non-empty string');
- }
- if ($this->file) {
- $this->moved = \PHP_SAPI === 'cli' ? rename($this->file, $targetPath) : move_uploaded_file($this->file, $targetPath);
- } else {
- Utils::copyToStream($this->getStream(), new LazyOpenStream($targetPath, 'w'));
- $this->moved = \true;
- }
- if (\false === $this->moved) {
- throw new RuntimeException(sprintf('Uploaded file could not be moved to %s', $targetPath));
- }
- }
- public function getSize() : ?int
- {
- return $this->size;
- }
- public function getError() : int
- {
- return $this->error;
- }
- public function getClientFilename() : ?string
- {
- return $this->clientFilename;
- }
- public function getClientMediaType() : ?string
- {
- return $this->clientMediaType;
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/Uri.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/Uri.php
deleted file mode 100644
index 18e88f4..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/Uri.php
+++ /dev/null
@@ -1,570 +0,0 @@
- 80, 'https' => 443, 'ftp' => 21, 'gopher' => 70, 'nntp' => 119, 'news' => 119, 'telnet' => 23, 'tn3270' => 23, 'imap' => 143, 'pop' => 110, 'ldap' => 389];
- /**
- * Unreserved characters for use in a regex.
- *
- * @see https://tools.ietf.org/html/rfc3986#section-2.3
- */
- private const CHAR_UNRESERVED = 'a-zA-Z0-9_\\-\\.~';
- /**
- * Sub-delims for use in a regex.
- *
- * @see https://tools.ietf.org/html/rfc3986#section-2.2
- */
- private const CHAR_SUB_DELIMS = '!\\$&\'\\(\\)\\*\\+,;=';
- private const QUERY_SEPARATORS_REPLACEMENT = ['=' => '%3D', '&' => '%26'];
- /** @var string Uri scheme. */
- private $scheme = '';
- /** @var string Uri user info. */
- private $userInfo = '';
- /** @var string Uri host. */
- private $host = '';
- /** @var int|null Uri port. */
- private $port;
- /** @var string Uri path. */
- private $path = '';
- /** @var string Uri query string. */
- private $query = '';
- /** @var string Uri fragment. */
- private $fragment = '';
- /** @var string|null String representation */
- private $composedComponents;
- public function __construct(string $uri = '')
- {
- if ($uri !== '') {
- $parts = self::parse($uri);
- if ($parts === \false) {
- throw new MalformedUriException("Unable to parse URI: {$uri}");
- }
- $this->applyParts($parts);
- }
- }
- /**
- * UTF-8 aware \parse_url() replacement.
- *
- * The internal function produces broken output for non ASCII domain names
- * (IDN) when used with locales other than "C".
- *
- * On the other hand, cURL understands IDN correctly only when UTF-8 locale
- * is configured ("C.UTF-8", "en_US.UTF-8", etc.).
- *
- * @see https://bugs.php.net/bug.php?id=52923
- * @see https://www.php.net/manual/en/function.parse-url.php#114817
- * @see https://curl.haxx.se/libcurl/c/CURLOPT_URL.html#ENCODING
- *
- * @return array|false
- */
- private static function parse(string $url)
- {
- // If IPv6
- $prefix = '';
- if (preg_match('%^(.*://\\[[0-9:a-f]+\\])(.*?)$%', $url, $matches)) {
- /** @var array{0:string, 1:string, 2:string} $matches */
- $prefix = $matches[1];
- $url = $matches[2];
- }
- /** @var string */
- $encodedUrl = preg_replace_callback('%[^:/@?&=#]+%usD', static function ($matches) {
- return urlencode($matches[0]);
- }, $url);
- $result = parse_url($prefix . $encodedUrl);
- if ($result === \false) {
- return \false;
- }
- return array_map('urldecode', $result);
- }
- public function __toString() : string
- {
- if ($this->composedComponents === null) {
- $this->composedComponents = self::composeComponents($this->scheme, $this->getAuthority(), $this->path, $this->query, $this->fragment);
- }
- return $this->composedComponents;
- }
- /**
- * Composes a URI reference string from its various components.
- *
- * Usually this method does not need to be called manually but instead is used indirectly via
- * `Psr\Http\Message\UriInterface::__toString`.
- *
- * PSR-7 UriInterface treats an empty component the same as a missing component as
- * getQuery(), getFragment() etc. always return a string. This explains the slight
- * difference to RFC 3986 Section 5.3.
- *
- * Another adjustment is that the authority separator is added even when the authority is missing/empty
- * for the "file" scheme. This is because PHP stream functions like `file_get_contents` only work with
- * `file:///myfile` but not with `file:/myfile` although they are equivalent according to RFC 3986. But
- * `file:///` is the more common syntax for the file scheme anyway (Chrome for example redirects to
- * that format).
- *
- * @see https://tools.ietf.org/html/rfc3986#section-5.3
- */
- public static function composeComponents(?string $scheme, ?string $authority, string $path, ?string $query, ?string $fragment) : string
- {
- $uri = '';
- // weak type checks to also accept null until we can add scalar type hints
- if ($scheme != '') {
- $uri .= $scheme . ':';
- }
- if ($authority != '' || $scheme === 'file') {
- $uri .= '//' . $authority;
- }
- if ($authority != '' && $path != '' && $path[0] != '/') {
- $path = '/' . $path;
- }
- $uri .= $path;
- if ($query != '') {
- $uri .= '?' . $query;
- }
- if ($fragment != '') {
- $uri .= '#' . $fragment;
- }
- return $uri;
- }
- /**
- * Whether the URI has the default port of the current scheme.
- *
- * `Psr\Http\Message\UriInterface::getPort` may return null or the standard port. This method can be used
- * independently of the implementation.
- */
- public static function isDefaultPort(UriInterface $uri) : bool
- {
- return $uri->getPort() === null || isset(self::DEFAULT_PORTS[$uri->getScheme()]) && $uri->getPort() === self::DEFAULT_PORTS[$uri->getScheme()];
- }
- /**
- * Whether the URI is absolute, i.e. it has a scheme.
- *
- * An instance of UriInterface can either be an absolute URI or a relative reference. This method returns true
- * if it is the former. An absolute URI has a scheme. A relative reference is used to express a URI relative
- * to another URI, the base URI. Relative references can be divided into several forms:
- * - network-path references, e.g. '//example.com/path'
- * - absolute-path references, e.g. '/path'
- * - relative-path references, e.g. 'subpath'
- *
- * @see Uri::isNetworkPathReference
- * @see Uri::isAbsolutePathReference
- * @see Uri::isRelativePathReference
- * @see https://tools.ietf.org/html/rfc3986#section-4
- */
- public static function isAbsolute(UriInterface $uri) : bool
- {
- return $uri->getScheme() !== '';
- }
- /**
- * Whether the URI is a network-path reference.
- *
- * A relative reference that begins with two slash characters is termed an network-path reference.
- *
- * @see https://tools.ietf.org/html/rfc3986#section-4.2
- */
- public static function isNetworkPathReference(UriInterface $uri) : bool
- {
- return $uri->getScheme() === '' && $uri->getAuthority() !== '';
- }
- /**
- * Whether the URI is a absolute-path reference.
- *
- * A relative reference that begins with a single slash character is termed an absolute-path reference.
- *
- * @see https://tools.ietf.org/html/rfc3986#section-4.2
- */
- public static function isAbsolutePathReference(UriInterface $uri) : bool
- {
- return $uri->getScheme() === '' && $uri->getAuthority() === '' && isset($uri->getPath()[0]) && $uri->getPath()[0] === '/';
- }
- /**
- * Whether the URI is a relative-path reference.
- *
- * A relative reference that does not begin with a slash character is termed a relative-path reference.
- *
- * @see https://tools.ietf.org/html/rfc3986#section-4.2
- */
- public static function isRelativePathReference(UriInterface $uri) : bool
- {
- return $uri->getScheme() === '' && $uri->getAuthority() === '' && (!isset($uri->getPath()[0]) || $uri->getPath()[0] !== '/');
- }
- /**
- * Whether the URI is a same-document reference.
- *
- * A same-document reference refers to a URI that is, aside from its fragment
- * component, identical to the base URI. When no base URI is given, only an empty
- * URI reference (apart from its fragment) is considered a same-document reference.
- *
- * @param UriInterface $uri The URI to check
- * @param UriInterface|null $base An optional base URI to compare against
- *
- * @see https://tools.ietf.org/html/rfc3986#section-4.4
- */
- public static function isSameDocumentReference(UriInterface $uri, UriInterface $base = null) : bool
- {
- if ($base !== null) {
- $uri = UriResolver::resolve($base, $uri);
- return $uri->getScheme() === $base->getScheme() && $uri->getAuthority() === $base->getAuthority() && $uri->getPath() === $base->getPath() && $uri->getQuery() === $base->getQuery();
- }
- return $uri->getScheme() === '' && $uri->getAuthority() === '' && $uri->getPath() === '' && $uri->getQuery() === '';
- }
- /**
- * Creates a new URI with a specific query string value removed.
- *
- * Any existing query string values that exactly match the provided key are
- * removed.
- *
- * @param UriInterface $uri URI to use as a base.
- * @param string $key Query string key to remove.
- */
- public static function withoutQueryValue(UriInterface $uri, string $key) : UriInterface
- {
- $result = self::getFilteredQueryString($uri, [$key]);
- return $uri->withQuery(implode('&', $result));
- }
- /**
- * Creates a new URI with a specific query string value.
- *
- * Any existing query string values that exactly match the provided key are
- * removed and replaced with the given key value pair.
- *
- * A value of null will set the query string key without a value, e.g. "key"
- * instead of "key=value".
- *
- * @param UriInterface $uri URI to use as a base.
- * @param string $key Key to set.
- * @param string|null $value Value to set
- */
- public static function withQueryValue(UriInterface $uri, string $key, ?string $value) : UriInterface
- {
- $result = self::getFilteredQueryString($uri, [$key]);
- $result[] = self::generateQueryString($key, $value);
- return $uri->withQuery(implode('&', $result));
- }
- /**
- * Creates a new URI with multiple specific query string values.
- *
- * It has the same behavior as withQueryValue() but for an associative array of key => value.
- *
- * @param UriInterface $uri URI to use as a base.
- * @param array $keyValueArray Associative array of key and values
- */
- public static function withQueryValues(UriInterface $uri, array $keyValueArray) : UriInterface
- {
- $result = self::getFilteredQueryString($uri, array_keys($keyValueArray));
- foreach ($keyValueArray as $key => $value) {
- $result[] = self::generateQueryString((string) $key, $value !== null ? (string) $value : null);
- }
- return $uri->withQuery(implode('&', $result));
- }
- /**
- * Creates a URI from a hash of `parse_url` components.
- *
- * @see http://php.net/manual/en/function.parse-url.php
- *
- * @throws MalformedUriException If the components do not form a valid URI.
- */
- public static function fromParts(array $parts) : UriInterface
- {
- $uri = new self();
- $uri->applyParts($parts);
- $uri->validateState();
- return $uri;
- }
- public function getScheme() : string
- {
- return $this->scheme;
- }
- public function getAuthority() : string
- {
- $authority = $this->host;
- if ($this->userInfo !== '') {
- $authority = $this->userInfo . '@' . $authority;
- }
- if ($this->port !== null) {
- $authority .= ':' . $this->port;
- }
- return $authority;
- }
- public function getUserInfo() : string
- {
- return $this->userInfo;
- }
- public function getHost() : string
- {
- return $this->host;
- }
- public function getPort() : ?int
- {
- return $this->port;
- }
- public function getPath() : string
- {
- return $this->path;
- }
- public function getQuery() : string
- {
- return $this->query;
- }
- public function getFragment() : string
- {
- return $this->fragment;
- }
- public function withScheme($scheme) : UriInterface
- {
- $scheme = $this->filterScheme($scheme);
- if ($this->scheme === $scheme) {
- return $this;
- }
- $new = clone $this;
- $new->scheme = $scheme;
- $new->composedComponents = null;
- $new->removeDefaultPort();
- $new->validateState();
- return $new;
- }
- public function withUserInfo($user, $password = null) : UriInterface
- {
- $info = $this->filterUserInfoComponent($user);
- if ($password !== null) {
- $info .= ':' . $this->filterUserInfoComponent($password);
- }
- if ($this->userInfo === $info) {
- return $this;
- }
- $new = clone $this;
- $new->userInfo = $info;
- $new->composedComponents = null;
- $new->validateState();
- return $new;
- }
- public function withHost($host) : UriInterface
- {
- $host = $this->filterHost($host);
- if ($this->host === $host) {
- return $this;
- }
- $new = clone $this;
- $new->host = $host;
- $new->composedComponents = null;
- $new->validateState();
- return $new;
- }
- public function withPort($port) : UriInterface
- {
- $port = $this->filterPort($port);
- if ($this->port === $port) {
- return $this;
- }
- $new = clone $this;
- $new->port = $port;
- $new->composedComponents = null;
- $new->removeDefaultPort();
- $new->validateState();
- return $new;
- }
- public function withPath($path) : UriInterface
- {
- $path = $this->filterPath($path);
- if ($this->path === $path) {
- return $this;
- }
- $new = clone $this;
- $new->path = $path;
- $new->composedComponents = null;
- $new->validateState();
- return $new;
- }
- public function withQuery($query) : UriInterface
- {
- $query = $this->filterQueryAndFragment($query);
- if ($this->query === $query) {
- return $this;
- }
- $new = clone $this;
- $new->query = $query;
- $new->composedComponents = null;
- return $new;
- }
- public function withFragment($fragment) : UriInterface
- {
- $fragment = $this->filterQueryAndFragment($fragment);
- if ($this->fragment === $fragment) {
- return $this;
- }
- $new = clone $this;
- $new->fragment = $fragment;
- $new->composedComponents = null;
- return $new;
- }
- public function jsonSerialize() : string
- {
- return $this->__toString();
- }
- /**
- * Apply parse_url parts to a URI.
- *
- * @param array $parts Array of parse_url parts to apply.
- */
- private function applyParts(array $parts) : void
- {
- $this->scheme = isset($parts['scheme']) ? $this->filterScheme($parts['scheme']) : '';
- $this->userInfo = isset($parts['user']) ? $this->filterUserInfoComponent($parts['user']) : '';
- $this->host = isset($parts['host']) ? $this->filterHost($parts['host']) : '';
- $this->port = isset($parts['port']) ? $this->filterPort($parts['port']) : null;
- $this->path = isset($parts['path']) ? $this->filterPath($parts['path']) : '';
- $this->query = isset($parts['query']) ? $this->filterQueryAndFragment($parts['query']) : '';
- $this->fragment = isset($parts['fragment']) ? $this->filterQueryAndFragment($parts['fragment']) : '';
- if (isset($parts['pass'])) {
- $this->userInfo .= ':' . $this->filterUserInfoComponent($parts['pass']);
- }
- $this->removeDefaultPort();
- }
- /**
- * @param mixed $scheme
- *
- * @throws \InvalidArgumentException If the scheme is invalid.
- */
- private function filterScheme($scheme) : string
- {
- if (!is_string($scheme)) {
- throw new \InvalidArgumentException('Scheme must be a string');
- }
- return \strtr($scheme, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz');
- }
- /**
- * @param mixed $component
- *
- * @throws \InvalidArgumentException If the user info is invalid.
- */
- private function filterUserInfoComponent($component) : string
- {
- if (!is_string($component)) {
- throw new \InvalidArgumentException('User info must be a string');
- }
- return preg_replace_callback('/(?:[^%' . self::CHAR_UNRESERVED . self::CHAR_SUB_DELIMS . ']+|%(?![A-Fa-f0-9]{2}))/', [$this, 'rawurlencodeMatchZero'], $component);
- }
- /**
- * @param mixed $host
- *
- * @throws \InvalidArgumentException If the host is invalid.
- */
- private function filterHost($host) : string
- {
- if (!is_string($host)) {
- throw new \InvalidArgumentException('Host must be a string');
- }
- return \strtr($host, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz');
- }
- /**
- * @param mixed $port
- *
- * @throws \InvalidArgumentException If the port is invalid.
- */
- private function filterPort($port) : ?int
- {
- if ($port === null) {
- return null;
- }
- $port = (int) $port;
- if (0 > $port || 0xffff < $port) {
- throw new \InvalidArgumentException(sprintf('Invalid port: %d. Must be between 0 and 65535', $port));
- }
- return $port;
- }
- /**
- * @param string[] $keys
- *
- * @return string[]
- */
- private static function getFilteredQueryString(UriInterface $uri, array $keys) : array
- {
- $current = $uri->getQuery();
- if ($current === '') {
- return [];
- }
- $decodedKeys = array_map('rawurldecode', $keys);
- return array_filter(explode('&', $current), function ($part) use($decodedKeys) {
- return !in_array(rawurldecode(explode('=', $part)[0]), $decodedKeys, \true);
- });
- }
- private static function generateQueryString(string $key, ?string $value) : string
- {
- // Query string separators ("=", "&") within the key or value need to be encoded
- // (while preventing double-encoding) before setting the query string. All other
- // chars that need percent-encoding will be encoded by withQuery().
- $queryString = strtr($key, self::QUERY_SEPARATORS_REPLACEMENT);
- if ($value !== null) {
- $queryString .= '=' . strtr($value, self::QUERY_SEPARATORS_REPLACEMENT);
- }
- return $queryString;
- }
- private function removeDefaultPort() : void
- {
- if ($this->port !== null && self::isDefaultPort($this)) {
- $this->port = null;
- }
- }
- /**
- * Filters the path of a URI
- *
- * @param mixed $path
- *
- * @throws \InvalidArgumentException If the path is invalid.
- */
- private function filterPath($path) : string
- {
- if (!is_string($path)) {
- throw new \InvalidArgumentException('Path must be a string');
- }
- return preg_replace_callback('/(?:[^' . self::CHAR_UNRESERVED . self::CHAR_SUB_DELIMS . '%:@\\/]++|%(?![A-Fa-f0-9]{2}))/', [$this, 'rawurlencodeMatchZero'], $path);
- }
- /**
- * Filters the query string or fragment of a URI.
- *
- * @param mixed $str
- *
- * @throws \InvalidArgumentException If the query or fragment is invalid.
- */
- private function filterQueryAndFragment($str) : string
- {
- if (!is_string($str)) {
- throw new \InvalidArgumentException('Query and fragment must be a string');
- }
- return preg_replace_callback('/(?:[^' . self::CHAR_UNRESERVED . self::CHAR_SUB_DELIMS . '%:@\\/\\?]++|%(?![A-Fa-f0-9]{2}))/', [$this, 'rawurlencodeMatchZero'], $str);
- }
- private function rawurlencodeMatchZero(array $match) : string
- {
- return rawurlencode($match[0]);
- }
- private function validateState() : void
- {
- if ($this->host === '' && ($this->scheme === 'http' || $this->scheme === 'https')) {
- $this->host = self::HTTP_DEFAULT_HOST;
- }
- if ($this->getAuthority() === '') {
- if (0 === strpos($this->path, '//')) {
- throw new MalformedUriException('The path of a URI without an authority must not start with two slashes "//"');
- }
- if ($this->scheme === '' && \false !== strpos(explode('/', $this->path, 2)[0], ':')) {
- throw new MalformedUriException('A relative URI must not have a path beginning with a segment containing a colon');
- }
- }
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/UriComparator.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/UriComparator.php
deleted file mode 100644
index be2f9f5..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/UriComparator.php
+++ /dev/null
@@ -1,43 +0,0 @@
-getHost(), $modified->getHost()) !== 0) {
- return \true;
- }
- if ($original->getScheme() !== $modified->getScheme()) {
- return \true;
- }
- if (self::computePort($original) !== self::computePort($modified)) {
- return \true;
- }
- return \false;
- }
- private static function computePort(UriInterface $uri) : int
- {
- $port = $uri->getPort();
- if (null !== $port) {
- return $port;
- }
- return 'https' === $uri->getScheme() ? 443 : 80;
- }
- private function __construct()
- {
- // cannot be instantiated
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/UriNormalizer.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/UriNormalizer.php
deleted file mode 100644
index 6467cf2..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/UriNormalizer.php
+++ /dev/null
@@ -1,175 +0,0 @@
-getPath() === '' && ($uri->getScheme() === 'http' || $uri->getScheme() === 'https')) {
- $uri = $uri->withPath('/');
- }
- if ($flags & self::REMOVE_DEFAULT_HOST && $uri->getScheme() === 'file' && $uri->getHost() === 'localhost') {
- $uri = $uri->withHost('');
- }
- if ($flags & self::REMOVE_DEFAULT_PORT && $uri->getPort() !== null && Uri::isDefaultPort($uri)) {
- $uri = $uri->withPort(null);
- }
- if ($flags & self::REMOVE_DOT_SEGMENTS && !Uri::isRelativePathReference($uri)) {
- $uri = $uri->withPath(UriResolver::removeDotSegments($uri->getPath()));
- }
- if ($flags & self::REMOVE_DUPLICATE_SLASHES) {
- $uri = $uri->withPath(preg_replace('#//++#', '/', $uri->getPath()));
- }
- if ($flags & self::SORT_QUERY_PARAMETERS && $uri->getQuery() !== '') {
- $queryKeyValues = explode('&', $uri->getQuery());
- sort($queryKeyValues);
- $uri = $uri->withQuery(implode('&', $queryKeyValues));
- }
- return $uri;
- }
- /**
- * Whether two URIs can be considered equivalent.
- *
- * Both URIs are normalized automatically before comparison with the given $normalizations bitmask. The method also
- * accepts relative URI references and returns true when they are equivalent. This of course assumes they will be
- * resolved against the same base URI. If this is not the case, determination of equivalence or difference of
- * relative references does not mean anything.
- *
- * @param UriInterface $uri1 An URI to compare
- * @param UriInterface $uri2 An URI to compare
- * @param int $normalizations A bitmask of normalizations to apply, see constants
- *
- * @see https://tools.ietf.org/html/rfc3986#section-6.1
- */
- public static function isEquivalent(UriInterface $uri1, UriInterface $uri2, int $normalizations = self::PRESERVING_NORMALIZATIONS) : bool
- {
- return (string) self::normalize($uri1, $normalizations) === (string) self::normalize($uri2, $normalizations);
- }
- private static function capitalizePercentEncoding(UriInterface $uri) : UriInterface
- {
- $regex = '/(?:%[A-Fa-f0-9]{2})++/';
- $callback = function (array $match) {
- return strtoupper($match[0]);
- };
- return $uri->withPath(preg_replace_callback($regex, $callback, $uri->getPath()))->withQuery(preg_replace_callback($regex, $callback, $uri->getQuery()));
- }
- private static function decodeUnreservedCharacters(UriInterface $uri) : UriInterface
- {
- $regex = '/%(?:2D|2E|5F|7E|3[0-9]|[46][1-9A-F]|[57][0-9A])/i';
- $callback = function (array $match) {
- return rawurldecode($match[0]);
- };
- return $uri->withPath(preg_replace_callback($regex, $callback, $uri->getPath()))->withQuery(preg_replace_callback($regex, $callback, $uri->getQuery()));
- }
- private function __construct()
- {
- // cannot be instantiated
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/UriResolver.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/UriResolver.php
deleted file mode 100644
index edf6072..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/UriResolver.php
+++ /dev/null
@@ -1,180 +0,0 @@
-getScheme() != '') {
- return $rel->withPath(self::removeDotSegments($rel->getPath()));
- }
- if ($rel->getAuthority() != '') {
- $targetAuthority = $rel->getAuthority();
- $targetPath = self::removeDotSegments($rel->getPath());
- $targetQuery = $rel->getQuery();
- } else {
- $targetAuthority = $base->getAuthority();
- if ($rel->getPath() === '') {
- $targetPath = $base->getPath();
- $targetQuery = $rel->getQuery() != '' ? $rel->getQuery() : $base->getQuery();
- } else {
- if ($rel->getPath()[0] === '/') {
- $targetPath = $rel->getPath();
- } else {
- if ($targetAuthority != '' && $base->getPath() === '') {
- $targetPath = '/' . $rel->getPath();
- } else {
- $lastSlashPos = strrpos($base->getPath(), '/');
- if ($lastSlashPos === \false) {
- $targetPath = $rel->getPath();
- } else {
- $targetPath = substr($base->getPath(), 0, $lastSlashPos + 1) . $rel->getPath();
- }
- }
- }
- $targetPath = self::removeDotSegments($targetPath);
- $targetQuery = $rel->getQuery();
- }
- }
- return new Uri(Uri::composeComponents($base->getScheme(), $targetAuthority, $targetPath, $targetQuery, $rel->getFragment()));
- }
- /**
- * Returns the target URI as a relative reference from the base URI.
- *
- * This method is the counterpart to resolve():
- *
- * (string) $target === (string) UriResolver::resolve($base, UriResolver::relativize($base, $target))
- *
- * One use-case is to use the current request URI as base URI and then generate relative links in your documents
- * to reduce the document size or offer self-contained downloadable document archives.
- *
- * $base = new Uri('http://example.com/a/b/');
- * echo UriResolver::relativize($base, new Uri('http://example.com/a/b/c')); // prints 'c'.
- * echo UriResolver::relativize($base, new Uri('http://example.com/a/x/y')); // prints '../x/y'.
- * echo UriResolver::relativize($base, new Uri('http://example.com/a/b/?q')); // prints '?q'.
- * echo UriResolver::relativize($base, new Uri('http://example.org/a/b/')); // prints '//example.org/a/b/'.
- *
- * This method also accepts a target that is already relative and will try to relativize it further. Only a
- * relative-path reference will be returned as-is.
- *
- * echo UriResolver::relativize($base, new Uri('/a/b/c')); // prints 'c' as well
- */
- public static function relativize(UriInterface $base, UriInterface $target) : UriInterface
- {
- if ($target->getScheme() !== '' && ($base->getScheme() !== $target->getScheme() || $target->getAuthority() === '' && $base->getAuthority() !== '')) {
- return $target;
- }
- if (Uri::isRelativePathReference($target)) {
- // As the target is already highly relative we return it as-is. It would be possible to resolve
- // the target with `$target = self::resolve($base, $target);` and then try make it more relative
- // by removing a duplicate query. But let's not do that automatically.
- return $target;
- }
- if ($target->getAuthority() !== '' && $base->getAuthority() !== $target->getAuthority()) {
- return $target->withScheme('');
- }
- // We must remove the path before removing the authority because if the path starts with two slashes, the URI
- // would turn invalid. And we also cannot set a relative path before removing the authority, as that is also
- // invalid.
- $emptyPathUri = $target->withScheme('')->withPath('')->withUserInfo('')->withPort(null)->withHost('');
- if ($base->getPath() !== $target->getPath()) {
- return $emptyPathUri->withPath(self::getRelativePath($base, $target));
- }
- if ($base->getQuery() === $target->getQuery()) {
- // Only the target fragment is left. And it must be returned even if base and target fragment are the same.
- return $emptyPathUri->withQuery('');
- }
- // If the base URI has a query but the target has none, we cannot return an empty path reference as it would
- // inherit the base query component when resolving.
- if ($target->getQuery() === '') {
- $segments = explode('/', $target->getPath());
- /** @var string $lastSegment */
- $lastSegment = end($segments);
- return $emptyPathUri->withPath($lastSegment === '' ? './' : $lastSegment);
- }
- return $emptyPathUri;
- }
- private static function getRelativePath(UriInterface $base, UriInterface $target) : string
- {
- $sourceSegments = explode('/', $base->getPath());
- $targetSegments = explode('/', $target->getPath());
- array_pop($sourceSegments);
- $targetLastSegment = array_pop($targetSegments);
- foreach ($sourceSegments as $i => $segment) {
- if (isset($targetSegments[$i]) && $segment === $targetSegments[$i]) {
- unset($sourceSegments[$i], $targetSegments[$i]);
- } else {
- break;
- }
- }
- $targetSegments[] = $targetLastSegment;
- $relativePath = str_repeat('../', count($sourceSegments)) . implode('/', $targetSegments);
- // A reference to am empty last segment or an empty first sub-segment must be prefixed with "./".
- // This also applies to a segment with a colon character (e.g., "file:colon") that cannot be used
- // as the first segment of a relative-path reference, as it would be mistaken for a scheme name.
- if ('' === $relativePath || \false !== strpos(explode('/', $relativePath, 2)[0], ':')) {
- $relativePath = "./{$relativePath}";
- } elseif ('/' === $relativePath[0]) {
- if ($base->getAuthority() != '' && $base->getPath() === '') {
- // In this case an extra slash is added by resolve() automatically. So we must not add one here.
- $relativePath = ".{$relativePath}";
- } else {
- $relativePath = "./{$relativePath}";
- }
- }
- return $relativePath;
- }
- private function __construct()
- {
- // cannot be instantiated
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/Utils.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/Utils.php
deleted file mode 100644
index 24b9a8c..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/guzzlehttp/psr7/src/Utils.php
+++ /dev/null
@@ -1,375 +0,0 @@
- $v) {
- if (!is_string($k) || !in_array(strtolower($k), $keys)) {
- $result[$k] = $v;
- }
- }
- return $result;
- }
- /**
- * Copy the contents of a stream into another stream until the given number
- * of bytes have been read.
- *
- * @param StreamInterface $source Stream to read from
- * @param StreamInterface $dest Stream to write to
- * @param int $maxLen Maximum number of bytes to read. Pass -1
- * to read the entire stream.
- *
- * @throws \RuntimeException on error.
- */
- public static function copyToStream(StreamInterface $source, StreamInterface $dest, int $maxLen = -1) : void
- {
- $bufferSize = 8192;
- if ($maxLen === -1) {
- while (!$source->eof()) {
- if (!$dest->write($source->read($bufferSize))) {
- break;
- }
- }
- } else {
- $remaining = $maxLen;
- while ($remaining > 0 && !$source->eof()) {
- $buf = $source->read(min($bufferSize, $remaining));
- $len = strlen($buf);
- if (!$len) {
- break;
- }
- $remaining -= $len;
- $dest->write($buf);
- }
- }
- }
- /**
- * Copy the contents of a stream into a string until the given number of
- * bytes have been read.
- *
- * @param StreamInterface $stream Stream to read
- * @param int $maxLen Maximum number of bytes to read. Pass -1
- * to read the entire stream.
- *
- * @throws \RuntimeException on error.
- */
- public static function copyToString(StreamInterface $stream, int $maxLen = -1) : string
- {
- $buffer = '';
- if ($maxLen === -1) {
- while (!$stream->eof()) {
- $buf = $stream->read(1048576);
- if ($buf === '') {
- break;
- }
- $buffer .= $buf;
- }
- return $buffer;
- }
- $len = 0;
- while (!$stream->eof() && $len < $maxLen) {
- $buf = $stream->read($maxLen - $len);
- if ($buf === '') {
- break;
- }
- $buffer .= $buf;
- $len = strlen($buffer);
- }
- return $buffer;
- }
- /**
- * Calculate a hash of a stream.
- *
- * This method reads the entire stream to calculate a rolling hash, based
- * on PHP's `hash_init` functions.
- *
- * @param StreamInterface $stream Stream to calculate the hash for
- * @param string $algo Hash algorithm (e.g. md5, crc32, etc)
- * @param bool $rawOutput Whether or not to use raw output
- *
- * @throws \RuntimeException on error.
- */
- public static function hash(StreamInterface $stream, string $algo, bool $rawOutput = \false) : string
- {
- $pos = $stream->tell();
- if ($pos > 0) {
- $stream->rewind();
- }
- $ctx = hash_init($algo);
- while (!$stream->eof()) {
- hash_update($ctx, $stream->read(1048576));
- }
- $out = hash_final($ctx, $rawOutput);
- $stream->seek($pos);
- return $out;
- }
- /**
- * Clone and modify a request with the given changes.
- *
- * This method is useful for reducing the number of clones needed to mutate
- * a message.
- *
- * The changes can be one of:
- * - method: (string) Changes the HTTP method.
- * - set_headers: (array) Sets the given headers.
- * - remove_headers: (array) Remove the given headers.
- * - body: (mixed) Sets the given body.
- * - uri: (UriInterface) Set the URI.
- * - query: (string) Set the query string value of the URI.
- * - version: (string) Set the protocol version.
- *
- * @param RequestInterface $request Request to clone and modify.
- * @param array $changes Changes to apply.
- */
- public static function modifyRequest(RequestInterface $request, array $changes) : RequestInterface
- {
- if (!$changes) {
- return $request;
- }
- $headers = $request->getHeaders();
- if (!isset($changes['uri'])) {
- $uri = $request->getUri();
- } else {
- // Remove the host header if one is on the URI
- if ($host = $changes['uri']->getHost()) {
- $changes['set_headers']['Host'] = $host;
- if ($port = $changes['uri']->getPort()) {
- $standardPorts = ['http' => 80, 'https' => 443];
- $scheme = $changes['uri']->getScheme();
- if (isset($standardPorts[$scheme]) && $port != $standardPorts[$scheme]) {
- $changes['set_headers']['Host'] .= ':' . $port;
- }
- }
- }
- $uri = $changes['uri'];
- }
- if (!empty($changes['remove_headers'])) {
- $headers = self::caselessRemove($changes['remove_headers'], $headers);
- }
- if (!empty($changes['set_headers'])) {
- $headers = self::caselessRemove(array_keys($changes['set_headers']), $headers);
- $headers = $changes['set_headers'] + $headers;
- }
- if (isset($changes['query'])) {
- $uri = $uri->withQuery($changes['query']);
- }
- if ($request instanceof ServerRequestInterface) {
- $new = (new ServerRequest($changes['method'] ?? $request->getMethod(), $uri, $headers, $changes['body'] ?? $request->getBody(), $changes['version'] ?? $request->getProtocolVersion(), $request->getServerParams()))->withParsedBody($request->getParsedBody())->withQueryParams($request->getQueryParams())->withCookieParams($request->getCookieParams())->withUploadedFiles($request->getUploadedFiles());
- foreach ($request->getAttributes() as $key => $value) {
- $new = $new->withAttribute($key, $value);
- }
- return $new;
- }
- return new Request($changes['method'] ?? $request->getMethod(), $uri, $headers, $changes['body'] ?? $request->getBody(), $changes['version'] ?? $request->getProtocolVersion());
- }
- /**
- * Read a line from the stream up to the maximum allowed buffer length.
- *
- * @param StreamInterface $stream Stream to read from
- * @param int|null $maxLength Maximum buffer length
- */
- public static function readLine(StreamInterface $stream, ?int $maxLength = null) : string
- {
- $buffer = '';
- $size = 0;
- while (!$stream->eof()) {
- if ('' === ($byte = $stream->read(1))) {
- return $buffer;
- }
- $buffer .= $byte;
- // Break when a new line is found or the max length - 1 is reached
- if ($byte === "\n" || ++$size === $maxLength - 1) {
- break;
- }
- }
- return $buffer;
- }
- /**
- * Create a new stream based on the input type.
- *
- * Options is an associative array that can contain the following keys:
- * - metadata: Array of custom metadata.
- * - size: Size of the stream.
- *
- * This method accepts the following `$resource` types:
- * - `Psr\Http\Message\StreamInterface`: Returns the value as-is.
- * - `string`: Creates a stream object that uses the given string as the contents.
- * - `resource`: Creates a stream object that wraps the given PHP stream resource.
- * - `Iterator`: If the provided value implements `Iterator`, then a read-only
- * stream object will be created that wraps the given iterable. Each time the
- * stream is read from, data from the iterator will fill a buffer and will be
- * continuously called until the buffer is equal to the requested read size.
- * Subsequent read calls will first read from the buffer and then call `next`
- * on the underlying iterator until it is exhausted.
- * - `object` with `__toString()`: If the object has the `__toString()` method,
- * the object will be cast to a string and then a stream will be returned that
- * uses the string value.
- * - `NULL`: When `null` is passed, an empty stream object is returned.
- * - `callable` When a callable is passed, a read-only stream object will be
- * created that invokes the given callable. The callable is invoked with the
- * number of suggested bytes to read. The callable can return any number of
- * bytes, but MUST return `false` when there is no more data to return. The
- * stream object that wraps the callable will invoke the callable until the
- * number of requested bytes are available. Any additional bytes will be
- * buffered and used in subsequent reads.
- *
- * @param resource|string|int|float|bool|StreamInterface|callable|\Iterator|null $resource Entity body data
- * @param array{size?: int, metadata?: array} $options Additional options
- *
- * @throws \InvalidArgumentException if the $resource arg is not valid.
- */
- public static function streamFor($resource = '', array $options = []) : StreamInterface
- {
- if (is_scalar($resource)) {
- $stream = self::tryFopen('php://temp', 'r+');
- if ($resource !== '') {
- fwrite($stream, (string) $resource);
- fseek($stream, 0);
- }
- return new Stream($stream, $options);
- }
- switch (gettype($resource)) {
- case 'resource':
- /*
- * The 'php://input' is a special stream with quirks and inconsistencies.
- * We avoid using that stream by reading it into php://temp
- */
- /** @var resource $resource */
- if ((\stream_get_meta_data($resource)['uri'] ?? '') === 'php://input') {
- $stream = self::tryFopen('php://temp', 'w+');
- stream_copy_to_stream($resource, $stream);
- fseek($stream, 0);
- $resource = $stream;
- }
- return new Stream($resource, $options);
- case 'object':
- /** @var object $resource */
- if ($resource instanceof StreamInterface) {
- return $resource;
- } elseif ($resource instanceof \Iterator) {
- return new PumpStream(function () use($resource) {
- if (!$resource->valid()) {
- return \false;
- }
- $result = $resource->current();
- $resource->next();
- return $result;
- }, $options);
- } elseif (method_exists($resource, '__toString')) {
- return self::streamFor((string) $resource, $options);
- }
- break;
- case 'NULL':
- return new Stream(self::tryFopen('php://temp', 'r+'), $options);
- }
- if (is_callable($resource)) {
- return new PumpStream($resource, $options);
- }
- throw new \InvalidArgumentException('Invalid resource type: ' . gettype($resource));
- }
- /**
- * Safely opens a PHP stream resource using a filename.
- *
- * When fopen fails, PHP normally raises a warning. This function adds an
- * error handler that checks for errors and throws an exception instead.
- *
- * @param string $filename File to open
- * @param string $mode Mode used to open the file
- *
- * @return resource
- *
- * @throws \RuntimeException if the file cannot be opened
- */
- public static function tryFopen(string $filename, string $mode)
- {
- $ex = null;
- set_error_handler(static function (int $errno, string $errstr) use($filename, $mode, &$ex) : bool {
- $ex = new \RuntimeException(sprintf('Unable to open "%s" using mode "%s": %s', $filename, $mode, $errstr));
- return \true;
- });
- try {
- /** @var resource $handle */
- $handle = fopen($filename, $mode);
- } catch (\Throwable $e) {
- $ex = new \RuntimeException(sprintf('Unable to open "%s" using mode "%s": %s', $filename, $mode, $e->getMessage()), 0, $e);
- }
- restore_error_handler();
- if ($ex) {
- /** @var $ex \RuntimeException */
- throw $ex;
- }
- return $handle;
- }
- /**
- * Safely gets the contents of a given stream.
- *
- * When stream_get_contents fails, PHP normally raises a warning. This
- * function adds an error handler that checks for errors and throws an
- * exception instead.
- *
- * @param resource $stream
- *
- * @throws \RuntimeException if the stream cannot be read
- */
- public static function tryGetContents($stream) : string
- {
- $ex = null;
- set_error_handler(static function (int $errno, string $errstr) use(&$ex) : bool {
- $ex = new \RuntimeException(sprintf('Unable to read stream contents: %s', $errstr));
- return \true;
- });
- try {
- /** @var string|false $contents */
- $contents = stream_get_contents($stream);
- if ($contents === \false) {
- $ex = new \RuntimeException('Unable to read stream contents');
- }
- } catch (\Throwable $e) {
- $ex = new \RuntimeException(sprintf('Unable to read stream contents: %s', $e->getMessage()), 0, $e);
- }
- restore_error_handler();
- if ($ex) {
- /** @var $ex \RuntimeException */
- throw $ex;
- }
- return $contents;
- }
- /**
- * Returns a UriInterface for the given value.
- *
- * This function accepts a string or UriInterface and returns a
- * UriInterface for the given value. If the value is already a
- * UriInterface, it is returned as-is.
- *
- * @param string|UriInterface $uri
- *
- * @throws \InvalidArgumentException
- */
- public static function uriFor($uri) : UriInterface
- {
- if ($uri instanceof UriInterface) {
- return $uri;
- }
- if (is_string($uri)) {
- return new Uri($uri);
- }
- throw new \InvalidArgumentException('URI must be a string or UriInterface');
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/paragonie/constant_time_encoding/LICENSE.txt b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/paragonie/constant_time_encoding/LICENSE.txt
deleted file mode 100644
index 91acaca..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/paragonie/constant_time_encoding/LICENSE.txt
+++ /dev/null
@@ -1,48 +0,0 @@
-The MIT License (MIT)
-
-Copyright (c) 2016 - 2022 Paragon Initiative Enterprises
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-
-------------------------------------------------------------------------------
-This library was based on the work of Steve "Sc00bz" Thomas.
-------------------------------------------------------------------------------
-
-The MIT License (MIT)
-
-Copyright (c) 2014 Steve Thomas
-
-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/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/paragonie/constant_time_encoding/src/Base32.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/paragonie/constant_time_encoding/src/Base32.php
deleted file mode 100644
index 0b65be6..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/paragonie/constant_time_encoding/src/Base32.php
+++ /dev/null
@@ -1,404 +0,0 @@
- 96 && $src < 123) $ret += $src - 97 + 1; // -64
- $ret += (0x60 - $src & $src - 0x7b) >> 8 & $src - 96;
- // if ($src > 0x31 && $src < 0x38) $ret += $src - 24 + 1; // -23
- $ret += (0x31 - $src & $src - 0x38) >> 8 & $src - 23;
- return $ret;
- }
- /**
- * Uses bitwise operators instead of table-lookups to turn 5-bit integers
- * into 8-bit integers.
- *
- * Uppercase variant.
- *
- * @param int $src
- * @return int
- */
- protected static function decode5BitsUpper(int $src) : int
- {
- $ret = -1;
- // if ($src > 64 && $src < 91) $ret += $src - 65 + 1; // -64
- $ret += (0x40 - $src & $src - 0x5b) >> 8 & $src - 64;
- // if ($src > 0x31 && $src < 0x38) $ret += $src - 24 + 1; // -23
- $ret += (0x31 - $src & $src - 0x38) >> 8 & $src - 23;
- return $ret;
- }
- /**
- * Uses bitwise operators instead of table-lookups to turn 8-bit integers
- * into 5-bit integers.
- *
- * @param int $src
- * @return string
- */
- protected static function encode5Bits(int $src) : string
- {
- $diff = 0x61;
- // if ($src > 25) $ret -= 72;
- $diff -= 25 - $src >> 8 & 73;
- return \pack('C', $src + $diff);
- }
- /**
- * Uses bitwise operators instead of table-lookups to turn 8-bit integers
- * into 5-bit integers.
- *
- * Uppercase variant.
- *
- * @param int $src
- * @return string
- */
- protected static function encode5BitsUpper(int $src) : string
- {
- $diff = 0x41;
- // if ($src > 25) $ret -= 40;
- $diff -= 25 - $src >> 8 & 41;
- return \pack('C', $src + $diff);
- }
- /**
- * @param string $encodedString
- * @param bool $upper
- * @return string
- */
- public static function decodeNoPadding(string $encodedString, bool $upper = \false) : string
- {
- $srcLen = Binary::safeStrlen($encodedString);
- if ($srcLen === 0) {
- return '';
- }
- if (($srcLen & 7) === 0) {
- for ($j = 0; $j < 7 && $j < $srcLen; ++$j) {
- if ($encodedString[$srcLen - $j - 1] === '=') {
- throw new InvalidArgumentException("decodeNoPadding() doesn't tolerate padding");
- }
- }
- }
- return static::doDecode($encodedString, $upper, \true);
- }
- /**
- * Base32 decoding
- *
- * @param string $src
- * @param bool $upper
- * @param bool $strictPadding
- * @return string
- *
- * @throws TypeError
- * @psalm-suppress RedundantCondition
- */
- protected static function doDecode(string $src, bool $upper = \false, bool $strictPadding = \false) : string
- {
- // We do this to reduce code duplication:
- $method = $upper ? 'decode5BitsUpper' : 'decode5Bits';
- // Remove padding
- $srcLen = Binary::safeStrlen($src);
- if ($srcLen === 0) {
- return '';
- }
- if ($strictPadding) {
- if (($srcLen & 7) === 0) {
- for ($j = 0; $j < 7; ++$j) {
- if ($src[$srcLen - 1] === '=') {
- $srcLen--;
- } else {
- break;
- }
- }
- }
- if (($srcLen & 7) === 1) {
- throw new RangeException('Incorrect padding');
- }
- } else {
- $src = \rtrim($src, '=');
- $srcLen = Binary::safeStrlen($src);
- }
- $err = 0;
- $dest = '';
- // Main loop (no padding):
- for ($i = 0; $i + 8 <= $srcLen; $i += 8) {
- /** @var array $chunk */
- $chunk = \unpack('C*', Binary::safeSubstr($src, $i, 8));
- /** @var int $c0 */
- $c0 = static::$method($chunk[1]);
- /** @var int $c1 */
- $c1 = static::$method($chunk[2]);
- /** @var int $c2 */
- $c2 = static::$method($chunk[3]);
- /** @var int $c3 */
- $c3 = static::$method($chunk[4]);
- /** @var int $c4 */
- $c4 = static::$method($chunk[5]);
- /** @var int $c5 */
- $c5 = static::$method($chunk[6]);
- /** @var int $c6 */
- $c6 = static::$method($chunk[7]);
- /** @var int $c7 */
- $c7 = static::$method($chunk[8]);
- $dest .= \pack('CCCCC', ($c0 << 3 | $c1 >> 2) & 0xff, ($c1 << 6 | $c2 << 1 | $c3 >> 4) & 0xff, ($c3 << 4 | $c4 >> 1) & 0xff, ($c4 << 7 | $c5 << 2 | $c6 >> 3) & 0xff, ($c6 << 5 | $c7) & 0xff);
- $err |= ($c0 | $c1 | $c2 | $c3 | $c4 | $c5 | $c6 | $c7) >> 8;
- }
- // The last chunk, which may have padding:
- if ($i < $srcLen) {
- /** @var array $chunk */
- $chunk = \unpack('C*', Binary::safeSubstr($src, $i, $srcLen - $i));
- /** @var int $c0 */
- $c0 = static::$method($chunk[1]);
- if ($i + 6 < $srcLen) {
- /** @var int $c1 */
- $c1 = static::$method($chunk[2]);
- /** @var int $c2 */
- $c2 = static::$method($chunk[3]);
- /** @var int $c3 */
- $c3 = static::$method($chunk[4]);
- /** @var int $c4 */
- $c4 = static::$method($chunk[5]);
- /** @var int $c5 */
- $c5 = static::$method($chunk[6]);
- /** @var int $c6 */
- $c6 = static::$method($chunk[7]);
- $dest .= \pack('CCCC', ($c0 << 3 | $c1 >> 2) & 0xff, ($c1 << 6 | $c2 << 1 | $c3 >> 4) & 0xff, ($c3 << 4 | $c4 >> 1) & 0xff, ($c4 << 7 | $c5 << 2 | $c6 >> 3) & 0xff);
- $err |= ($c0 | $c1 | $c2 | $c3 | $c4 | $c5 | $c6) >> 8;
- if ($strictPadding) {
- $err |= $c6 << 5 & 0xff;
- }
- } elseif ($i + 5 < $srcLen) {
- /** @var int $c1 */
- $c1 = static::$method($chunk[2]);
- /** @var int $c2 */
- $c2 = static::$method($chunk[3]);
- /** @var int $c3 */
- $c3 = static::$method($chunk[4]);
- /** @var int $c4 */
- $c4 = static::$method($chunk[5]);
- /** @var int $c5 */
- $c5 = static::$method($chunk[6]);
- $dest .= \pack('CCCC', ($c0 << 3 | $c1 >> 2) & 0xff, ($c1 << 6 | $c2 << 1 | $c3 >> 4) & 0xff, ($c3 << 4 | $c4 >> 1) & 0xff, ($c4 << 7 | $c5 << 2) & 0xff);
- $err |= ($c0 | $c1 | $c2 | $c3 | $c4 | $c5) >> 8;
- } elseif ($i + 4 < $srcLen) {
- /** @var int $c1 */
- $c1 = static::$method($chunk[2]);
- /** @var int $c2 */
- $c2 = static::$method($chunk[3]);
- /** @var int $c3 */
- $c3 = static::$method($chunk[4]);
- /** @var int $c4 */
- $c4 = static::$method($chunk[5]);
- $dest .= \pack('CCC', ($c0 << 3 | $c1 >> 2) & 0xff, ($c1 << 6 | $c2 << 1 | $c3 >> 4) & 0xff, ($c3 << 4 | $c4 >> 1) & 0xff);
- $err |= ($c0 | $c1 | $c2 | $c3 | $c4) >> 8;
- if ($strictPadding) {
- $err |= $c4 << 7 & 0xff;
- }
- } elseif ($i + 3 < $srcLen) {
- /** @var int $c1 */
- $c1 = static::$method($chunk[2]);
- /** @var int $c2 */
- $c2 = static::$method($chunk[3]);
- /** @var int $c3 */
- $c3 = static::$method($chunk[4]);
- $dest .= \pack('CC', ($c0 << 3 | $c1 >> 2) & 0xff, ($c1 << 6 | $c2 << 1 | $c3 >> 4) & 0xff);
- $err |= ($c0 | $c1 | $c2 | $c3) >> 8;
- if ($strictPadding) {
- $err |= $c3 << 4 & 0xff;
- }
- } elseif ($i + 2 < $srcLen) {
- /** @var int $c1 */
- $c1 = static::$method($chunk[2]);
- /** @var int $c2 */
- $c2 = static::$method($chunk[3]);
- $dest .= \pack('CC', ($c0 << 3 | $c1 >> 2) & 0xff, ($c1 << 6 | $c2 << 1) & 0xff);
- $err |= ($c0 | $c1 | $c2) >> 8;
- if ($strictPadding) {
- $err |= $c2 << 6 & 0xff;
- }
- } elseif ($i + 1 < $srcLen) {
- /** @var int $c1 */
- $c1 = static::$method($chunk[2]);
- $dest .= \pack('C', ($c0 << 3 | $c1 >> 2) & 0xff);
- $err |= ($c0 | $c1) >> 8;
- if ($strictPadding) {
- $err |= $c1 << 6 & 0xff;
- }
- } else {
- $dest .= \pack('C', $c0 << 3 & 0xff);
- $err |= $c0 >> 8;
- }
- }
- $check = $err === 0;
- if (!$check) {
- throw new RangeException('Base32::doDecode() only expects characters in the correct base32 alphabet');
- }
- return $dest;
- }
- /**
- * Base32 Encoding
- *
- * @param string $src
- * @param bool $upper
- * @param bool $pad
- * @return string
- * @throws TypeError
- */
- protected static function doEncode(string $src, bool $upper = \false, $pad = \true) : string
- {
- // We do this to reduce code duplication:
- $method = $upper ? 'encode5BitsUpper' : 'encode5Bits';
- $dest = '';
- $srcLen = Binary::safeStrlen($src);
- // Main loop (no padding):
- for ($i = 0; $i + 5 <= $srcLen; $i += 5) {
- /** @var array $chunk */
- $chunk = \unpack('C*', Binary::safeSubstr($src, $i, 5));
- $b0 = $chunk[1];
- $b1 = $chunk[2];
- $b2 = $chunk[3];
- $b3 = $chunk[4];
- $b4 = $chunk[5];
- $dest .= static::$method($b0 >> 3 & 31) . static::$method(($b0 << 2 | $b1 >> 6) & 31) . static::$method($b1 >> 1 & 31) . static::$method(($b1 << 4 | $b2 >> 4) & 31) . static::$method(($b2 << 1 | $b3 >> 7) & 31) . static::$method($b3 >> 2 & 31) . static::$method(($b3 << 3 | $b4 >> 5) & 31) . static::$method($b4 & 31);
- }
- // The last chunk, which may have padding:
- if ($i < $srcLen) {
- /** @var array $chunk */
- $chunk = \unpack('C*', Binary::safeSubstr($src, $i, $srcLen - $i));
- $b0 = $chunk[1];
- if ($i + 3 < $srcLen) {
- $b1 = $chunk[2];
- $b2 = $chunk[3];
- $b3 = $chunk[4];
- $dest .= static::$method($b0 >> 3 & 31) . static::$method(($b0 << 2 | $b1 >> 6) & 31) . static::$method($b1 >> 1 & 31) . static::$method(($b1 << 4 | $b2 >> 4) & 31) . static::$method(($b2 << 1 | $b3 >> 7) & 31) . static::$method($b3 >> 2 & 31) . static::$method($b3 << 3 & 31);
- if ($pad) {
- $dest .= '=';
- }
- } elseif ($i + 2 < $srcLen) {
- $b1 = $chunk[2];
- $b2 = $chunk[3];
- $dest .= static::$method($b0 >> 3 & 31) . static::$method(($b0 << 2 | $b1 >> 6) & 31) . static::$method($b1 >> 1 & 31) . static::$method(($b1 << 4 | $b2 >> 4) & 31) . static::$method($b2 << 1 & 31);
- if ($pad) {
- $dest .= '===';
- }
- } elseif ($i + 1 < $srcLen) {
- $b1 = $chunk[2];
- $dest .= static::$method($b0 >> 3 & 31) . static::$method(($b0 << 2 | $b1 >> 6) & 31) . static::$method($b1 >> 1 & 31) . static::$method($b1 << 4 & 31);
- if ($pad) {
- $dest .= '====';
- }
- } else {
- $dest .= static::$method($b0 >> 3 & 31) . static::$method($b0 << 2 & 31);
- if ($pad) {
- $dest .= '======';
- }
- }
- }
- return $dest;
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/paragonie/constant_time_encoding/src/Base32Hex.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/paragonie/constant_time_encoding/src/Base32Hex.php
deleted file mode 100644
index d5c7566..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/paragonie/constant_time_encoding/src/Base32Hex.php
+++ /dev/null
@@ -1,98 +0,0 @@
- 0x30 && $src < 0x3a) ret += $src - 0x2e + 1; // -47
- $ret += (0x2f - $src & $src - 0x3a) >> 8 & $src - 47;
- // if ($src > 0x60 && $src < 0x77) ret += $src - 0x61 + 10 + 1; // -86
- $ret += (0x60 - $src & $src - 0x77) >> 8 & $src - 86;
- return $ret;
- }
- /**
- * Uses bitwise operators instead of table-lookups to turn 5-bit integers
- * into 8-bit integers.
- *
- * @param int $src
- * @return int
- */
- protected static function decode5BitsUpper(int $src) : int
- {
- $ret = -1;
- // if ($src > 0x30 && $src < 0x3a) ret += $src - 0x2e + 1; // -47
- $ret += (0x2f - $src & $src - 0x3a) >> 8 & $src - 47;
- // if ($src > 0x40 && $src < 0x57) ret += $src - 0x41 + 10 + 1; // -54
- $ret += (0x40 - $src & $src - 0x57) >> 8 & $src - 54;
- return $ret;
- }
- /**
- * Uses bitwise operators instead of table-lookups to turn 8-bit integers
- * into 5-bit integers.
- *
- * @param int $src
- * @return string
- */
- protected static function encode5Bits(int $src) : string
- {
- $src += 0x30;
- // if ($src > 0x39) $src += 0x61 - 0x3a; // 39
- $src += 0x39 - $src >> 8 & 39;
- return \pack('C', $src);
- }
- /**
- * Uses bitwise operators instead of table-lookups to turn 8-bit integers
- * into 5-bit integers.
- *
- * Uppercase variant.
- *
- * @param int $src
- * @return string
- */
- protected static function encode5BitsUpper(int $src) : string
- {
- $src += 0x30;
- // if ($src > 0x39) $src += 0x41 - 0x3a; // 7
- $src += 0x39 - $src >> 8 & 7;
- return \pack('C', $src);
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/paragonie/constant_time_encoding/src/Base64.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/paragonie/constant_time_encoding/src/Base64.php
deleted file mode 100644
index 9065117..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/paragonie/constant_time_encoding/src/Base64.php
+++ /dev/null
@@ -1,257 +0,0 @@
- $chunk */
- $chunk = \unpack('C*', Binary::safeSubstr($src, $i, 3));
- $b0 = $chunk[1];
- $b1 = $chunk[2];
- $b2 = $chunk[3];
- $dest .= static::encode6Bits($b0 >> 2) . static::encode6Bits(($b0 << 4 | $b1 >> 4) & 63) . static::encode6Bits(($b1 << 2 | $b2 >> 6) & 63) . static::encode6Bits($b2 & 63);
- }
- // The last chunk, which may have padding:
- if ($i < $srcLen) {
- /** @var array $chunk */
- $chunk = \unpack('C*', Binary::safeSubstr($src, $i, $srcLen - $i));
- $b0 = $chunk[1];
- if ($i + 1 < $srcLen) {
- $b1 = $chunk[2];
- $dest .= static::encode6Bits($b0 >> 2) . static::encode6Bits(($b0 << 4 | $b1 >> 4) & 63) . static::encode6Bits($b1 << 2 & 63);
- if ($pad) {
- $dest .= '=';
- }
- } else {
- $dest .= static::encode6Bits($b0 >> 2) . static::encode6Bits($b0 << 4 & 63);
- if ($pad) {
- $dest .= '==';
- }
- }
- }
- return $dest;
- }
- /**
- * decode from base64 into binary
- *
- * Base64 character set "./[A-Z][a-z][0-9]"
- *
- * @param string $encodedString
- * @param bool $strictPadding
- * @return string
- *
- * @throws RangeException
- * @throws TypeError
- * @psalm-suppress RedundantCondition
- */
- public static function decode(string $encodedString, bool $strictPadding = \false) : string
- {
- // Remove padding
- $srcLen = Binary::safeStrlen($encodedString);
- if ($srcLen === 0) {
- return '';
- }
- if ($strictPadding) {
- if (($srcLen & 3) === 0) {
- if ($encodedString[$srcLen - 1] === '=') {
- $srcLen--;
- if ($encodedString[$srcLen - 1] === '=') {
- $srcLen--;
- }
- }
- }
- if (($srcLen & 3) === 1) {
- throw new RangeException('Incorrect padding');
- }
- if ($encodedString[$srcLen - 1] === '=') {
- throw new RangeException('Incorrect padding');
- }
- } else {
- $encodedString = \rtrim($encodedString, '=');
- $srcLen = Binary::safeStrlen($encodedString);
- }
- $err = 0;
- $dest = '';
- // Main loop (no padding):
- for ($i = 0; $i + 4 <= $srcLen; $i += 4) {
- /** @var array $chunk */
- $chunk = \unpack('C*', Binary::safeSubstr($encodedString, $i, 4));
- $c0 = static::decode6Bits($chunk[1]);
- $c1 = static::decode6Bits($chunk[2]);
- $c2 = static::decode6Bits($chunk[3]);
- $c3 = static::decode6Bits($chunk[4]);
- $dest .= \pack('CCC', ($c0 << 2 | $c1 >> 4) & 0xff, ($c1 << 4 | $c2 >> 2) & 0xff, ($c2 << 6 | $c3) & 0xff);
- $err |= ($c0 | $c1 | $c2 | $c3) >> 8;
- }
- // The last chunk, which may have padding:
- if ($i < $srcLen) {
- /** @var array $chunk */
- $chunk = \unpack('C*', Binary::safeSubstr($encodedString, $i, $srcLen - $i));
- $c0 = static::decode6Bits($chunk[1]);
- if ($i + 2 < $srcLen) {
- $c1 = static::decode6Bits($chunk[2]);
- $c2 = static::decode6Bits($chunk[3]);
- $dest .= \pack('CC', ($c0 << 2 | $c1 >> 4) & 0xff, ($c1 << 4 | $c2 >> 2) & 0xff);
- $err |= ($c0 | $c1 | $c2) >> 8;
- if ($strictPadding) {
- $err |= $c2 << 6 & 0xff;
- }
- } elseif ($i + 1 < $srcLen) {
- $c1 = static::decode6Bits($chunk[2]);
- $dest .= \pack('C', ($c0 << 2 | $c1 >> 4) & 0xff);
- $err |= ($c0 | $c1) >> 8;
- if ($strictPadding) {
- $err |= $c1 << 4 & 0xff;
- }
- } elseif ($strictPadding) {
- $err |= 1;
- }
- }
- $check = $err === 0;
- if (!$check) {
- throw new RangeException('Base64::decode() only expects characters in the correct base64 alphabet');
- }
- return $dest;
- }
- /**
- * @param string $encodedString
- * @return string
- */
- public static function decodeNoPadding(string $encodedString) : string
- {
- $srcLen = Binary::safeStrlen($encodedString);
- if ($srcLen === 0) {
- return '';
- }
- if (($srcLen & 3) === 0) {
- if ($encodedString[$srcLen - 1] === '=') {
- throw new InvalidArgumentException("decodeNoPadding() doesn't tolerate padding");
- }
- if (($srcLen & 3) > 1) {
- if ($encodedString[$srcLen - 2] === '=') {
- throw new InvalidArgumentException("decodeNoPadding() doesn't tolerate padding");
- }
- }
- }
- return static::decode($encodedString, \true);
- }
- /**
- * Uses bitwise operators instead of table-lookups to turn 6-bit integers
- * into 8-bit integers.
- *
- * Base64 character set:
- * [A-Z] [a-z] [0-9] + /
- * 0x41-0x5a, 0x61-0x7a, 0x30-0x39, 0x2b, 0x2f
- *
- * @param int $src
- * @return int
- */
- protected static function decode6Bits(int $src) : int
- {
- $ret = -1;
- // if ($src > 0x40 && $src < 0x5b) $ret += $src - 0x41 + 1; // -64
- $ret += (0x40 - $src & $src - 0x5b) >> 8 & $src - 64;
- // if ($src > 0x60 && $src < 0x7b) $ret += $src - 0x61 + 26 + 1; // -70
- $ret += (0x60 - $src & $src - 0x7b) >> 8 & $src - 70;
- // if ($src > 0x2f && $src < 0x3a) $ret += $src - 0x30 + 52 + 1; // 5
- $ret += (0x2f - $src & $src - 0x3a) >> 8 & $src + 5;
- // if ($src == 0x2b) $ret += 62 + 1;
- $ret += (0x2a - $src & $src - 0x2c) >> 8 & 63;
- // if ($src == 0x2f) ret += 63 + 1;
- $ret += (0x2e - $src & $src - 0x30) >> 8 & 64;
- return $ret;
- }
- /**
- * Uses bitwise operators instead of table-lookups to turn 8-bit integers
- * into 6-bit integers.
- *
- * @param int $src
- * @return string
- */
- protected static function encode6Bits(int $src) : string
- {
- $diff = 0x41;
- // if ($src > 25) $diff += 0x61 - 0x41 - 26; // 6
- $diff += 25 - $src >> 8 & 6;
- // if ($src > 51) $diff += 0x30 - 0x61 - 26; // -75
- $diff -= 51 - $src >> 8 & 75;
- // if ($src > 61) $diff += 0x2b - 0x30 - 10; // -15
- $diff -= 61 - $src >> 8 & 15;
- // if ($src > 62) $diff += 0x2f - 0x2b - 1; // 3
- $diff += 62 - $src >> 8 & 3;
- return \pack('C', $src + $diff);
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/paragonie/constant_time_encoding/src/Base64DotSlash.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/paragonie/constant_time_encoding/src/Base64DotSlash.php
deleted file mode 100644
index 80b8cd7..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/paragonie/constant_time_encoding/src/Base64DotSlash.php
+++ /dev/null
@@ -1,78 +0,0 @@
- 0x2d && $src < 0x30) ret += $src - 0x2e + 1; // -45
- $ret += (0x2d - $src & $src - 0x30) >> 8 & $src - 45;
- // if ($src > 0x40 && $src < 0x5b) ret += $src - 0x41 + 2 + 1; // -62
- $ret += (0x40 - $src & $src - 0x5b) >> 8 & $src - 62;
- // if ($src > 0x60 && $src < 0x7b) ret += $src - 0x61 + 28 + 1; // -68
- $ret += (0x60 - $src & $src - 0x7b) >> 8 & $src - 68;
- // if ($src > 0x2f && $src < 0x3a) ret += $src - 0x30 + 54 + 1; // 7
- $ret += (0x2f - $src & $src - 0x3a) >> 8 & $src + 7;
- return $ret;
- }
- /**
- * Uses bitwise operators instead of table-lookups to turn 8-bit integers
- * into 6-bit integers.
- *
- * @param int $src
- * @return string
- */
- protected static function encode6Bits(int $src) : string
- {
- $src += 0x2e;
- // if ($src > 0x2f) $src += 0x41 - 0x30; // 17
- $src += 0x2f - $src >> 8 & 17;
- // if ($src > 0x5a) $src += 0x61 - 0x5b; // 6
- $src += 0x5a - $src >> 8 & 6;
- // if ($src > 0x7a) $src += 0x30 - 0x7b; // -75
- $src -= 0x7a - $src >> 8 & 75;
- return \pack('C', $src);
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/paragonie/constant_time_encoding/src/Base64DotSlashOrdered.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/paragonie/constant_time_encoding/src/Base64DotSlashOrdered.php
deleted file mode 100644
index cee01f3..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/paragonie/constant_time_encoding/src/Base64DotSlashOrdered.php
+++ /dev/null
@@ -1,74 +0,0 @@
- 0x2d && $src < 0x3a) ret += $src - 0x2e + 1; // -45
- $ret += (0x2d - $src & $src - 0x3a) >> 8 & $src - 45;
- // if ($src > 0x40 && $src < 0x5b) ret += $src - 0x41 + 12 + 1; // -52
- $ret += (0x40 - $src & $src - 0x5b) >> 8 & $src - 52;
- // if ($src > 0x60 && $src < 0x7b) ret += $src - 0x61 + 38 + 1; // -58
- $ret += (0x60 - $src & $src - 0x7b) >> 8 & $src - 58;
- return $ret;
- }
- /**
- * Uses bitwise operators instead of table-lookups to turn 8-bit integers
- * into 6-bit integers.
- *
- * @param int $src
- * @return string
- */
- protected static function encode6Bits(int $src) : string
- {
- $src += 0x2e;
- // if ($src > 0x39) $src += 0x41 - 0x3a; // 7
- $src += 0x39 - $src >> 8 & 7;
- // if ($src > 0x5a) $src += 0x61 - 0x5b; // 6
- $src += 0x5a - $src >> 8 & 6;
- return \pack('C', $src);
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/paragonie/constant_time_encoding/src/Base64UrlSafe.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/paragonie/constant_time_encoding/src/Base64UrlSafe.php
deleted file mode 100644
index b939fd1..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/paragonie/constant_time_encoding/src/Base64UrlSafe.php
+++ /dev/null
@@ -1,82 +0,0 @@
- 0x40 && $src < 0x5b) $ret += $src - 0x41 + 1; // -64
- $ret += (0x40 - $src & $src - 0x5b) >> 8 & $src - 64;
- // if ($src > 0x60 && $src < 0x7b) $ret += $src - 0x61 + 26 + 1; // -70
- $ret += (0x60 - $src & $src - 0x7b) >> 8 & $src - 70;
- // if ($src > 0x2f && $src < 0x3a) $ret += $src - 0x30 + 52 + 1; // 5
- $ret += (0x2f - $src & $src - 0x3a) >> 8 & $src + 5;
- // if ($src == 0x2c) $ret += 62 + 1;
- $ret += (0x2c - $src & $src - 0x2e) >> 8 & 63;
- // if ($src == 0x5f) ret += 63 + 1;
- $ret += (0x5e - $src & $src - 0x60) >> 8 & 64;
- return $ret;
- }
- /**
- * Uses bitwise operators instead of table-lookups to turn 8-bit integers
- * into 6-bit integers.
- *
- * @param int $src
- * @return string
- */
- protected static function encode6Bits(int $src) : string
- {
- $diff = 0x41;
- // if ($src > 25) $diff += 0x61 - 0x41 - 26; // 6
- $diff += 25 - $src >> 8 & 6;
- // if ($src > 51) $diff += 0x30 - 0x61 - 26; // -75
- $diff -= 51 - $src >> 8 & 75;
- // if ($src > 61) $diff += 0x2d - 0x30 - 10; // -13
- $diff -= 61 - $src >> 8 & 13;
- // if ($src > 62) $diff += 0x5f - 0x2b - 1; // 3
- $diff += 62 - $src >> 8 & 49;
- return \pack('C', $src + $diff);
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/paragonie/constant_time_encoding/src/Binary.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/paragonie/constant_time_encoding/src/Binary.php
deleted file mode 100644
index 64a6c22..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/paragonie/constant_time_encoding/src/Binary.php
+++ /dev/null
@@ -1,85 +0,0 @@
- $chunk */
- $chunk = \unpack('C', $binString[$i]);
- $c = $chunk[1] & 0xf;
- $b = $chunk[1] >> 4;
- $hex .= \pack('CC', 87 + $b + ($b - 10 >> 8 & ~38), 87 + $c + ($c - 10 >> 8 & ~38));
- }
- return $hex;
- }
- /**
- * Convert a binary string into a hexadecimal string without cache-timing
- * leaks, returning uppercase letters (as per RFC 4648)
- *
- * @param string $binString (raw binary)
- * @return string
- * @throws TypeError
- */
- public static function encodeUpper(string $binString) : string
- {
- $hex = '';
- $len = Binary::safeStrlen($binString);
- for ($i = 0; $i < $len; ++$i) {
- /** @var array $chunk */
- $chunk = \unpack('C', $binString[$i]);
- $c = $chunk[1] & 0xf;
- $b = $chunk[1] >> 4;
- $hex .= \pack('CC', 55 + $b + ($b - 10 >> 8 & ~6), 55 + $c + ($c - 10 >> 8 & ~6));
- }
- return $hex;
- }
- /**
- * Convert a hexadecimal string into a binary string without cache-timing
- * leaks
- *
- * @param string $encodedString
- * @param bool $strictPadding
- * @return string (raw binary)
- * @throws RangeException
- */
- public static function decode(string $encodedString, bool $strictPadding = \false) : string
- {
- $hex_pos = 0;
- $bin = '';
- $c_acc = 0;
- $hex_len = Binary::safeStrlen($encodedString);
- $state = 0;
- if (($hex_len & 1) !== 0) {
- if ($strictPadding) {
- throw new RangeException('Expected an even number of hexadecimal characters');
- } else {
- $encodedString = '0' . $encodedString;
- ++$hex_len;
- }
- }
- /** @var array $chunk */
- $chunk = \unpack('C*', $encodedString);
- while ($hex_pos < $hex_len) {
- ++$hex_pos;
- $c = $chunk[$hex_pos];
- $c_num = $c ^ 48;
- $c_num0 = $c_num - 10 >> 8;
- $c_alpha = ($c & ~32) - 55;
- $c_alpha0 = ($c_alpha - 10 ^ $c_alpha - 16) >> 8;
- if (($c_num0 | $c_alpha0) === 0) {
- throw new RangeException('Expected hexadecimal character');
- }
- $c_val = $c_num0 & $c_num | $c_alpha & $c_alpha0;
- if ($state === 0) {
- $c_acc = $c_val * 16;
- } else {
- $bin .= \pack('C', $c_acc | $c_val);
- }
- $state ^= 1;
- }
- return $bin;
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/paragonie/constant_time_encoding/src/RFC4648.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/paragonie/constant_time_encoding/src/RFC4648.php
deleted file mode 100644
index 9787155..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/paragonie/constant_time_encoding/src/RFC4648.php
+++ /dev/null
@@ -1,176 +0,0 @@
- "Zm9v"
- *
- * @param string $str
- * @return string
- *
- * @throws TypeError
- */
- public static function base64Encode(string $str) : string
- {
- return Base64::encode($str);
- }
- /**
- * RFC 4648 Base64 decoding
- *
- * "Zm9v" -> "foo"
- *
- * @param string $str
- * @return string
- *
- * @throws TypeError
- */
- public static function base64Decode(string $str) : string
- {
- return Base64::decode($str, \true);
- }
- /**
- * RFC 4648 Base64 (URL Safe) encoding
- *
- * "foo" -> "Zm9v"
- *
- * @param string $str
- * @return string
- *
- * @throws TypeError
- */
- public static function base64UrlSafeEncode(string $str) : string
- {
- return Base64UrlSafe::encode($str);
- }
- /**
- * RFC 4648 Base64 (URL Safe) decoding
- *
- * "Zm9v" -> "foo"
- *
- * @param string $str
- * @return string
- *
- * @throws TypeError
- */
- public static function base64UrlSafeDecode(string $str) : string
- {
- return Base64UrlSafe::decode($str, \true);
- }
- /**
- * RFC 4648 Base32 encoding
- *
- * "foo" -> "MZXW6==="
- *
- * @param string $str
- * @return string
- *
- * @throws TypeError
- */
- public static function base32Encode(string $str) : string
- {
- return Base32::encodeUpper($str);
- }
- /**
- * RFC 4648 Base32 encoding
- *
- * "MZXW6===" -> "foo"
- *
- * @param string $str
- * @return string
- *
- * @throws TypeError
- */
- public static function base32Decode(string $str) : string
- {
- return Base32::decodeUpper($str, \true);
- }
- /**
- * RFC 4648 Base32-Hex encoding
- *
- * "foo" -> "CPNMU==="
- *
- * @param string $str
- * @return string
- *
- * @throws TypeError
- */
- public static function base32HexEncode(string $str) : string
- {
- return Base32::encodeUpper($str);
- }
- /**
- * RFC 4648 Base32-Hex decoding
- *
- * "CPNMU===" -> "foo"
- *
- * @param string $str
- * @return string
- *
- * @throws TypeError
- */
- public static function base32HexDecode(string $str) : string
- {
- return Base32::decodeUpper($str, \true);
- }
- /**
- * RFC 4648 Base16 decoding
- *
- * "foo" -> "666F6F"
- *
- * @param string $str
- * @return string
- *
- * @throws TypeError
- */
- public static function base16Encode(string $str) : string
- {
- return Hex::encodeUpper($str);
- }
- /**
- * RFC 4648 Base16 decoding
- *
- * "666F6F" -> "foo"
- *
- * @param string $str
- * @return string
- */
- public static function base16Decode(string $str) : string
- {
- return Hex::decode($str, \true);
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/paragonie/random_compat/LICENSE b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/paragonie/random_compat/LICENSE
deleted file mode 100644
index 45c7017..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/paragonie/random_compat/LICENSE
+++ /dev/null
@@ -1,22 +0,0 @@
-The MIT License (MIT)
-
-Copyright (c) 2015 Paragon Initiative Enterprises
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/paragonie/random_compat/build-phar.sh b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/paragonie/random_compat/build-phar.sh
deleted file mode 100644
index b4a5ba3..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/paragonie/random_compat/build-phar.sh
+++ /dev/null
@@ -1,5 +0,0 @@
-#!/usr/bin/env bash
-
-basedir=$( dirname $( readlink -f ${BASH_SOURCE[0]} ) )
-
-php -dphar.readonly=0 "$basedir/other/build_phar.php" $*
\ No newline at end of file
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/paragonie/random_compat/dist/random_compat.phar.pubkey b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/paragonie/random_compat/dist/random_compat.phar.pubkey
deleted file mode 100644
index eb50ebf..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/paragonie/random_compat/dist/random_compat.phar.pubkey
+++ /dev/null
@@ -1,5 +0,0 @@
------BEGIN PUBLIC KEY-----
-MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEEd+wCqJDrx5B4OldM0dQE0ZMX+lx1ZWm
-pui0SUqD4G29L3NGsz9UhJ/0HjBdbnkhIK5xviT0X5vtjacF6ajgcCArbTB+ds+p
-+h7Q084NuSuIpNb6YPfoUFgC/CL9kAoc
------END PUBLIC KEY-----
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/paragonie/random_compat/dist/random_compat.phar.pubkey.asc b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/paragonie/random_compat/dist/random_compat.phar.pubkey.asc
deleted file mode 100644
index 6a1d7f3..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/paragonie/random_compat/dist/random_compat.phar.pubkey.asc
+++ /dev/null
@@ -1,11 +0,0 @@
------BEGIN PGP SIGNATURE-----
-Version: GnuPG v2.0.22 (MingW32)
-
-iQEcBAABAgAGBQJWtW1hAAoJEGuXocKCZATaJf0H+wbZGgskK1dcRTsuVJl9IWip
-QwGw/qIKI280SD6/ckoUMxKDCJiFuPR14zmqnS36k7N5UNPnpdTJTS8T11jttSpg
-1LCmgpbEIpgaTah+cELDqFCav99fS+bEiAL5lWDAHBTE/XPjGVCqeehyPYref4IW
-NDBIEsvnHPHPLsn6X5jq4+Yj5oUixgxaMPiR+bcO4Sh+RzOVB6i2D0upWfRXBFXA
-NNnsg9/zjvoC7ZW73y9uSH+dPJTt/Vgfeiv52/v41XliyzbUyLalf02GNPY+9goV
-JHG1ulEEBJOCiUD9cE1PUIJwHA/HqyhHIvV350YoEFiHl8iSwm7SiZu5kPjaq74=
-=B6+8
------END PGP SIGNATURE-----
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/paragonie/random_compat/lib/random.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/paragonie/random_compat/lib/random.php
deleted file mode 100644
index b58ba3b..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/paragonie/random_compat/lib/random.php
+++ /dev/null
@@ -1,34 +0,0 @@
-buildFromDirectory(\dirname(__DIR__) . '/lib');
-\rename(\dirname(__DIR__) . '/lib/index.php', \dirname(__DIR__) . '/lib/random.php');
-/**
- * If we pass an (optional) path to a private key as a second argument, we will
- * sign the Phar with OpenSSL.
- *
- * If you leave this out, it will produce an unsigned .phar!
- */
-if ($argc > 1) {
- if (!@\is_readable($argv[1])) {
- echo 'Could not read the private key file:', $argv[1], "\n";
- exit(255);
- }
- $pkeyFile = \file_get_contents($argv[1]);
- $private = \openssl_get_privatekey($pkeyFile);
- if ($private !== \false) {
- $pkey = '';
- \openssl_pkey_export($private, $pkey);
- $phar->setSignatureAlgorithm(\Phar::OPENSSL, $pkey);
- /**
- * Save the corresponding public key to the file
- */
- if (!@\is_readable($dist . '/random_compat.phar.pubkey')) {
- $details = \openssl_pkey_get_details($private);
- \file_put_contents($dist . '/random_compat.phar.pubkey', $details['key']);
- }
- } else {
- echo 'An error occurred reading the private key from OpenSSL.', "\n";
- exit(255);
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/paragonie/random_compat/psalm-autoload.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/paragonie/random_compat/psalm-autoload.php
deleted file mode 100644
index 86fba44..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/paragonie/random_compat/psalm-autoload.php
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/phpseclib/phpseclib/AUTHORS b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/phpseclib/phpseclib/AUTHORS
deleted file mode 100644
index 9f10d26..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/phpseclib/phpseclib/AUTHORS
+++ /dev/null
@@ -1,7 +0,0 @@
-phpseclib Lead Developer: TerraFrost (Jim Wigginton)
-
-phpseclib Developers: monnerat (Patrick Monnerat)
- bantu (Andreas Fischer)
- petrich (Hans-Jürgen Petrich)
- GrahamCampbell (Graham Campbell)
- hc-jworman
\ No newline at end of file
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/phpseclib/phpseclib/LICENSE b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/phpseclib/phpseclib/LICENSE
deleted file mode 100644
index e7214eb..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/phpseclib/phpseclib/LICENSE
+++ /dev/null
@@ -1,20 +0,0 @@
-Copyright (c) 2011-2019 TerraFrost and other contributors
-
-Permission is hereby granted, free of charge, to any person obtaining
-a copy of this software and associated documentation files (the
-"Software"), to deal in the Software without restriction, including
-without limitation the rights to use, copy, modify, merge, publish,
-distribute, sublicense, and/or sell copies of the Software, and to
-permit persons to whom the Software is furnished to do so, subject to
-the following conditions:
-
-The above copyright notice and this permission notice shall be
-included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/phpseclib/phpseclib/phpseclib/Common/Functions/Strings.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/phpseclib/phpseclib/phpseclib/Common/Functions/Strings.php
deleted file mode 100644
index cc7ca4f..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/phpseclib/phpseclib/phpseclib/Common/Functions/Strings.php
+++ /dev/null
@@ -1,454 +0,0 @@
-
- * @copyright 2016 Jim Wigginton
- * @license http://www.opensource.org/licenses/mit-license.html MIT License
- * @link http://phpseclib.sourceforge.net
- */
-namespace Matomo\Dependencies\SearchEngineKeywordsPerformance\phpseclib3\Common\Functions;
-
-use Matomo\Dependencies\SearchEngineKeywordsPerformance\ParagonIE\ConstantTime\Base64;
-use Matomo\Dependencies\SearchEngineKeywordsPerformance\ParagonIE\ConstantTime\Base64UrlSafe;
-use Matomo\Dependencies\SearchEngineKeywordsPerformance\ParagonIE\ConstantTime\Hex;
-use Matomo\Dependencies\SearchEngineKeywordsPerformance\phpseclib3\Math\BigInteger;
-use Matomo\Dependencies\SearchEngineKeywordsPerformance\phpseclib3\Math\Common\FiniteField;
-/**
- * Common String Functions
- *
- * @author Jim Wigginton
- */
-abstract class Strings
-{
- /**
- * String Shift
- *
- * Inspired by array_shift
- *
- * @param string $string
- * @param int $index
- * @return string
- */
- public static function shift(&$string, $index = 1)
- {
- $substr = substr($string, 0, $index);
- $string = substr($string, $index);
- return $substr;
- }
- /**
- * String Pop
- *
- * Inspired by array_pop
- *
- * @param string $string
- * @param int $index
- * @return string
- */
- public static function pop(&$string, $index = 1)
- {
- $substr = substr($string, -$index);
- $string = substr($string, 0, -$index);
- return $substr;
- }
- /**
- * Parse SSH2-style string
- *
- * Returns either an array or a boolean if $data is malformed.
- *
- * Valid characters for $format are as follows:
- *
- * C = byte
- * b = boolean (true/false)
- * N = uint32
- * Q = uint64
- * s = string
- * i = mpint
- * L = name-list
- *
- * uint64 is not supported.
- *
- * @param string $format
- * @param string $data
- * @return mixed
- */
- public static function unpackSSH2($format, &$data)
- {
- $format = self::formatPack($format);
- $result = [];
- for ($i = 0; $i < strlen($format); $i++) {
- switch ($format[$i]) {
- case 'C':
- case 'b':
- if (!strlen($data)) {
- throw new \LengthException('At least one byte needs to be present for successful C / b decodes');
- }
- break;
- case 'N':
- case 'i':
- case 's':
- case 'L':
- if (strlen($data) < 4) {
- throw new \LengthException('At least four byte needs to be present for successful N / i / s / L decodes');
- }
- break;
- case 'Q':
- if (strlen($data) < 8) {
- throw new \LengthException('At least eight byte needs to be present for successful N / i / s / L decodes');
- }
- break;
- default:
- throw new \InvalidArgumentException('$format contains an invalid character');
- }
- switch ($format[$i]) {
- case 'C':
- $result[] = ord(self::shift($data));
- continue 2;
- case 'b':
- $result[] = ord(self::shift($data)) != 0;
- continue 2;
- case 'N':
- list(, $temp) = unpack('N', self::shift($data, 4));
- $result[] = $temp;
- continue 2;
- case 'Q':
- // pack() added support for Q in PHP 5.6.3 and PHP 5.6 is phpseclib 3's minimum version
- // so in theory we could support this BUT, "64-bit format codes are not available for
- // 32-bit versions" and phpseclib works on 32-bit installs. on 32-bit installs
- // 64-bit floats can be used to get larger numbers then 32-bit signed ints would allow
- // for. sure, you're not gonna get the full precision of 64-bit numbers but just because
- // you need > 32-bit precision doesn't mean you need the full 64-bit precision
- extract(unpack('Nupper/Nlower', self::shift($data, 8)));
- $temp = $upper ? 4294967296 * $upper : 0;
- $temp += $lower < 0 ? ($lower & 0x7ffffffff) + 0x80000000 : $lower;
- // $temp = hexdec(bin2hex(self::shift($data, 8)));
- $result[] = $temp;
- continue 2;
- }
- list(, $length) = unpack('N', self::shift($data, 4));
- if (strlen($data) < $length) {
- throw new \LengthException("{$length} bytes needed; " . strlen($data) . ' bytes available');
- }
- $temp = self::shift($data, $length);
- switch ($format[$i]) {
- case 'i':
- $result[] = new BigInteger($temp, -256);
- break;
- case 's':
- $result[] = $temp;
- break;
- case 'L':
- $result[] = explode(',', $temp);
- }
- }
- return $result;
- }
- /**
- * Create SSH2-style string
- *
- * @param string $format
- * @param string|int|float|array|bool ...$elements
- * @return string
- */
- public static function packSSH2($format, ...$elements)
- {
- $format = self::formatPack($format);
- if (strlen($format) != count($elements)) {
- throw new \InvalidArgumentException('There must be as many arguments as there are characters in the $format string');
- }
- $result = '';
- for ($i = 0; $i < strlen($format); $i++) {
- $element = $elements[$i];
- switch ($format[$i]) {
- case 'C':
- if (!is_int($element)) {
- throw new \InvalidArgumentException('Bytes must be represented as an integer between 0 and 255, inclusive.');
- }
- $result .= pack('C', $element);
- break;
- case 'b':
- if (!is_bool($element)) {
- throw new \InvalidArgumentException('A boolean parameter was expected.');
- }
- $result .= $element ? "\x01" : "\x00";
- break;
- case 'Q':
- if (!is_int($element) && !is_float($element)) {
- throw new \InvalidArgumentException('An integer was expected.');
- }
- // 4294967296 == 1 << 32
- $result .= pack('NN', $element / 4294967296, $element);
- break;
- case 'N':
- if (is_float($element)) {
- $element = (int) $element;
- }
- if (!is_int($element)) {
- throw new \InvalidArgumentException('An integer was expected.');
- }
- $result .= pack('N', $element);
- break;
- case 's':
- if (!self::is_stringable($element)) {
- throw new \InvalidArgumentException('A string was expected.');
- }
- $result .= pack('Na*', strlen($element), $element);
- break;
- case 'i':
- if (!$element instanceof BigInteger && !$element instanceof FiniteField\Integer) {
- throw new \InvalidArgumentException('A phpseclib3\\Math\\BigInteger or phpseclib3\\Math\\Common\\FiniteField\\Integer object was expected.');
- }
- $element = $element->toBytes(\true);
- $result .= pack('Na*', strlen($element), $element);
- break;
- case 'L':
- if (!is_array($element)) {
- throw new \InvalidArgumentException('An array was expected.');
- }
- $element = implode(',', $element);
- $result .= pack('Na*', strlen($element), $element);
- break;
- default:
- throw new \InvalidArgumentException('$format contains an invalid character');
- }
- }
- return $result;
- }
- /**
- * Expand a pack string
- *
- * Converts C5 to CCCCC, for example.
- *
- * @param string $format
- * @return string
- */
- private static function formatPack($format)
- {
- $parts = preg_split('#(\\d+)#', $format, -1, \PREG_SPLIT_DELIM_CAPTURE);
- $format = '';
- for ($i = 1; $i < count($parts); $i += 2) {
- $format .= substr($parts[$i - 1], 0, -1) . str_repeat(substr($parts[$i - 1], -1), $parts[$i]);
- }
- $format .= $parts[$i - 1];
- return $format;
- }
- /**
- * Convert binary data into bits
- *
- * bin2hex / hex2bin refer to base-256 encoded data as binary, whilst
- * decbin / bindec refer to base-2 encoded data as binary. For the purposes
- * of this function, bin refers to base-256 encoded data whilst bits refers
- * to base-2 encoded data
- *
- * @param string $x
- * @return string
- */
- public static function bits2bin($x)
- {
- /*
- // the pure-PHP approach is faster than the GMP approach
- if (function_exists('gmp_export')) {
- return strlen($x) ? gmp_export(gmp_init($x, 2)) : gmp_init(0);
- }
- */
- if (preg_match('#[^01]#', $x)) {
- throw new \RuntimeException('The only valid characters are 0 and 1');
- }
- if (!defined('PHP_INT_MIN')) {
- define('PHP_INT_MIN', ~\PHP_INT_MAX);
- }
- $length = strlen($x);
- if (!$length) {
- return '';
- }
- $block_size = \PHP_INT_SIZE << 3;
- $pad = $block_size - $length % $block_size;
- if ($pad != $block_size) {
- $x = str_repeat('0', $pad) . $x;
- }
- $parts = str_split($x, $block_size);
- $str = '';
- foreach ($parts as $part) {
- $xor = $part[0] == '1' ? \PHP_INT_MIN : 0;
- $part[0] = '0';
- $str .= pack(\PHP_INT_SIZE == 4 ? 'N' : 'J', $xor ^ eval('return 0b' . $part . ';'));
- }
- return ltrim($str, "\x00");
- }
- /**
- * Convert bits to binary data
- *
- * @param string $x
- * @return string
- */
- public static function bin2bits($x, $trim = \true)
- {
- /*
- // the pure-PHP approach is slower than the GMP approach BUT
- // i want to the pure-PHP version to be easily unit tested as well
- if (function_exists('gmp_import')) {
- return gmp_strval(gmp_import($x), 2);
- }
- */
- $len = strlen($x);
- $mod = $len % \PHP_INT_SIZE;
- if ($mod) {
- $x = str_pad($x, $len + \PHP_INT_SIZE - $mod, "\x00", \STR_PAD_LEFT);
- }
- $bits = '';
- if (\PHP_INT_SIZE == 4) {
- $digits = unpack('N*', $x);
- foreach ($digits as $digit) {
- $bits .= sprintf('%032b', $digit);
- }
- } else {
- $digits = unpack('J*', $x);
- foreach ($digits as $digit) {
- $bits .= sprintf('%064b', $digit);
- }
- }
- return $trim ? ltrim($bits, '0') : $bits;
- }
- /**
- * Switch Endianness Bit Order
- *
- * @param string $x
- * @return string
- */
- public static function switchEndianness($x)
- {
- $r = '';
- for ($i = strlen($x) - 1; $i >= 0; $i--) {
- $b = ord($x[$i]);
- if (\PHP_INT_SIZE === 8) {
- // 3 operations
- // from http://graphics.stanford.edu/~seander/bithacks.html#ReverseByteWith64BitsDiv
- $r .= chr(($b * 0x202020202 & 0x10884422010) % 1023);
- } else {
- // 7 operations
- // from http://graphics.stanford.edu/~seander/bithacks.html#ReverseByteWith32Bits
- $p1 = $b * 0x802 & 0x22110;
- $p2 = $b * 0x8020 & 0x88440;
- $r .= chr(($p1 | $p2) * 0x10101 >> 16);
- }
- }
- return $r;
- }
- /**
- * Increment the current string
- *
- * @param string $var
- * @return string
- */
- public static function increment_str(&$var)
- {
- if (function_exists('sodium_increment')) {
- $var = strrev($var);
- sodium_increment($var);
- $var = strrev($var);
- return $var;
- }
- for ($i = 4; $i <= strlen($var); $i += 4) {
- $temp = substr($var, -$i, 4);
- switch ($temp) {
- case "\xff\xff\xff\xff":
- $var = substr_replace($var, "\x00\x00\x00\x00", -$i, 4);
- break;
- case "\xff\xff\xff":
- $var = substr_replace($var, "\x80\x00\x00\x00", -$i, 4);
- return $var;
- default:
- $temp = unpack('Nnum', $temp);
- $var = substr_replace($var, pack('N', $temp['num'] + 1), -$i, 4);
- return $var;
- }
- }
- $remainder = strlen($var) % 4;
- if ($remainder == 0) {
- return $var;
- }
- $temp = unpack('Nnum', str_pad(substr($var, 0, $remainder), 4, "\x00", \STR_PAD_LEFT));
- $temp = substr(pack('N', $temp['num'] + 1), -$remainder);
- $var = substr_replace($var, $temp, 0, $remainder);
- return $var;
- }
- /**
- * Find whether the type of a variable is string (or could be converted to one)
- *
- * @param mixed $var
- * @return bool
- * @psalm-assert-if-true string|\Stringable $var
- */
- public static function is_stringable($var)
- {
- return is_string($var) || is_object($var) && method_exists($var, '__toString');
- }
- /**
- * Constant Time Base64-decoding
- *
- * ParagoneIE\ConstantTime doesn't use libsodium if it's available so we'll do so
- * ourselves. see https://github.com/paragonie/constant_time_encoding/issues/39
- *
- * @param string $data
- * @return string
- */
- public static function base64_decode($data)
- {
- return function_exists('sodium_base642bin') ? sodium_base642bin($data, \SODIUM_BASE64_VARIANT_ORIGINAL_NO_PADDING, '=') : Base64::decode($data);
- }
- /**
- * Constant Time Base64-decoding (URL safe)
- *
- * @param string $data
- * @return string
- */
- public static function base64url_decode($data)
- {
- // return self::base64_decode(str_replace(['-', '_'], ['+', '/'], $data));
- return function_exists('sodium_base642bin') ? sodium_base642bin($data, \SODIUM_BASE64_VARIANT_URLSAFE_NO_PADDING, '=') : Base64UrlSafe::decode($data);
- }
- /**
- * Constant Time Base64-encoding
- *
- * @param string $data
- * @return string
- */
- public static function base64_encode($data)
- {
- return function_exists('sodium_bin2base64') ? sodium_bin2base64($data, \SODIUM_BASE64_VARIANT_ORIGINAL) : Base64::encode($data);
- }
- /**
- * Constant Time Base64-encoding (URL safe)
- *
- * @param string $data
- * @return string
- */
- public static function base64url_encode($data)
- {
- // return str_replace(['+', '/'], ['-', '_'], self::base64_encode($data));
- return function_exists('sodium_bin2base64') ? sodium_bin2base64($data, \SODIUM_BASE64_VARIANT_URLSAFE) : Base64UrlSafe::encode($data);
- }
- /**
- * Constant Time Hex Decoder
- *
- * @param string $data
- * @return string
- */
- public static function hex2bin($data)
- {
- return function_exists('sodium_hex2bin') ? sodium_hex2bin($data) : Hex::decode($data);
- }
- /**
- * Constant Time Hex Encoder
- *
- * @param string $data
- * @return string
- */
- public static function bin2hex($data)
- {
- return function_exists('sodium_bin2hex') ? sodium_bin2hex($data) : Hex::encode($data);
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/phpseclib/phpseclib/phpseclib/Crypt/AES.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/phpseclib/phpseclib/phpseclib/Crypt/AES.php
deleted file mode 100644
index 82f852e..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/phpseclib/phpseclib/phpseclib/Crypt/AES.php
+++ /dev/null
@@ -1,112 +0,0 @@
-
- * setKey('abcdefghijklmnop');
- *
- * $size = 10 * 1024;
- * $plaintext = '';
- * for ($i = 0; $i < $size; $i++) {
- * $plaintext.= 'a';
- * }
- *
- * echo $aes->decrypt($aes->encrypt($plaintext));
- * ?>
- *
- *
- * @author Jim Wigginton
- * @copyright 2008 Jim Wigginton
- * @license http://www.opensource.org/licenses/mit-license.html MIT License
- * @link http://phpseclib.sourceforge.net
- */
-namespace Matomo\Dependencies\SearchEngineKeywordsPerformance\phpseclib3\Crypt;
-
-/**
- * Pure-PHP implementation of AES.
- *
- * @author Jim Wigginton
- */
-class AES extends Rijndael
-{
- /**
- * Dummy function
- *
- * Since \phpseclib3\Crypt\AES extends \phpseclib3\Crypt\Rijndael, this function is, technically, available, but it doesn't do anything.
- *
- * @see \phpseclib3\Crypt\Rijndael::setBlockLength()
- * @param int $length
- * @throws \BadMethodCallException anytime it's called
- */
- public function setBlockLength($length)
- {
- throw new \BadMethodCallException('The block length cannot be set for AES.');
- }
- /**
- * Sets the key length
- *
- * Valid key lengths are 128, 192, and 256. Set the link to bool(false) to disable a fixed key length
- *
- * @see \phpseclib3\Crypt\Rijndael:setKeyLength()
- * @param int $length
- * @throws \LengthException if the key length isn't supported
- */
- public function setKeyLength($length)
- {
- switch ($length) {
- case 128:
- case 192:
- case 256:
- break;
- default:
- throw new \LengthException('Key of size ' . $length . ' not supported by this algorithm. Only keys of sizes 128, 192 or 256 supported');
- }
- parent::setKeyLength($length);
- }
- /**
- * Sets the key.
- *
- * Rijndael supports five different key lengths, AES only supports three.
- *
- * @see \phpseclib3\Crypt\Rijndael:setKey()
- * @see setKeyLength()
- * @param string $key
- * @throws \LengthException if the key length isn't supported
- */
- public function setKey($key)
- {
- switch (strlen($key)) {
- case 16:
- case 24:
- case 32:
- break;
- default:
- throw new \LengthException('Key of size ' . strlen($key) . ' not supported by this algorithm. Only keys of sizes 16, 24 or 32 supported');
- }
- parent::setKey($key);
- }
-}
diff --git a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/phpseclib/phpseclib/phpseclib/Crypt/Blowfish.php b/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/phpseclib/phpseclib/phpseclib/Crypt/Blowfish.php
deleted file mode 100644
index 1befd35..0000000
--- a/files/plugin-SearchEngineKeywordsPerformance-5.0.22/vendor/prefixed/phpseclib/phpseclib/phpseclib/Crypt/Blowfish.php
+++ /dev/null
@@ -1,660 +0,0 @@
- unpack('N*', $x), $blocks); it jumps up by an additional
- * ~90MB, yielding a 106x increase in memory usage. Consequently, it bcrypt calls a different
- * _encryptBlock() then the regular Blowfish does. That said, the Blowfish _encryptBlock() is
- * basically just a thin wrapper around the bcrypt _encryptBlock(), so there's that.
- *
- * This explains 3 of the 4 _encryptBlock() implementations. the last _encryptBlock()
- * implementation can best be understood by doing Ctrl + F and searching for where
- * self::$use_reg_intval is defined.
- *
- * # phpseclib's three different _setupKey() implementations
- *
- * Every bcrypt round is the equivalent of encrypting 512KB of data. Since OpenSSH uses 16
- * rounds by default that's ~8MB of data that's essentially being encrypted whenever
- * you use bcrypt. That's a lot of data, however, bcrypt operates within tighter constraints
- * than regular Blowfish, so we can use that to our advantage. In particular, whereas Blowfish
- * supports variable length keys, in bcrypt, the initial "key" is the sha512 hash of the
- * password. sha512 hashes are 512 bits or 64 bytes long and thus the bcrypt keys are of a
- * fixed length whereas Blowfish keys are not of a fixed length.
- *
- * bcrypt actually has two different key expansion steps. The first one (expandstate) is
- * constantly XOR'ing every _encryptBlock() parameter against the salt prior _encryptBlock()'s
- * being called. The second one (expand0state) is more similar to Blowfish's _setupKey()
- * but it can still use the fixed length key optimization discussed above and can do away with
- * the pack() / unpack() calls.
- *
- * I suppose _setupKey() could be made to be a thin wrapper around expandstate() but idk it's
- * just a lot of work for very marginal benefits as _setupKey() is only called once for
- * regular Blowfish vs the 128 times it's called --per round-- with bcrypt.
- *
- * # blowfish + bcrypt in the same class
- *
- * Altho there's a lot of Blowfish code that bcrypt doesn't re-use, bcrypt does re-use the
- * initial S-boxes, the initial P-array and the int-only _encryptBlock() implementation.
- *
- * # Credit
- *
- * phpseclib's bcrypt implementation is based losely off of OpenSSH's implementation:
- *
- * https://github.com/openssh/openssh-portable/blob/master/openbsd-compat/bcrypt_pbkdf.c
- *
- * Here's a short example of how to use this library:
- *
- * setKey('12345678901234567890123456789012');
- *
- * $plaintext = str_repeat('a', 1024);
- *
- * echo $blowfish->decrypt($blowfish->encrypt($plaintext));
- * ?>
- *
- *
- * @author Jim Wigginton
- * @author Hans-Juergen Petrich