--- a/wp-compress-image-optimizer/addons/cdn/rewriteLogic.php
+++ b/wp-compress-image-optimizer/addons/cdn/rewriteLogic.php
@@ -1,4 +1,5 @@
<?php
+
/**
* Plugin: WP Compress – Instant Performance & Speed Optimization
* Description: Legitimate script handling for WP Compress Optimizer
@@ -948,12 +949,14 @@
let wpcRunningCritical = false;
function handleUserInteraction() {
- if (typeof ngf298gh738qwbdh0s87v_vars === 'undefined') {
- return;
- }
+ if (typeof ngf298gh738qwbdh0s87v_vars === 'undefined') {
+ return;
+ }
+
if (wpcRunningCritical) {
return;
}
+
wpcRunningCritical = true;
var xhr = new XMLHttpRequest();
@@ -967,6 +970,7 @@
}
}
};
+
xhr.send("action=wpc_send_critical_remote&postID={$post->ID}&realUrl={$realUrl}");
removeEventListeners();
@@ -1101,6 +1105,30 @@
return $output;
}
+ function filterCriticalFontFaces(string $critical): string
+ {
+ $blockedFonts = get_option('wps_ic_remove_fonts');
+ if (empty($blockedFonts)) {
+ return $critical;
+ }
+
+ // Match @font-face { ... } blocks (multiline, non-greedy)
+ $pattern = '/@font-faces*{.*?}/is';
+
+ return preg_replace_callback($pattern, function ($match) use ($blockedFonts) {
+ $fontFaceBlock = $match[0];
+
+ foreach ($blockedFonts as $blocked) {
+ if (stripos($fontFaceBlock, $blocked) !== false) {
+ // Remove this @font-face block
+ return '';
+ }
+ }
+
+ // Keep this @font-face block
+ return $fontFaceBlock;
+ }, $critical);
+ }
public function optimizeGoogleFonts($html)
{
@@ -1109,14 +1137,12 @@
return $html;
}
-
public function optimizeGoogleFontsRewrite($html)
{
$html = '';
return $html;
}
-
public function lazyCSS($html)
{
// Run only if the marker exists (handles " or ')
@@ -1130,7 +1156,6 @@
return $html;
}
-
public function cssStyleLazy($html)
{
$fullTag = $html[0];
@@ -1176,7 +1201,6 @@
return $fullTag;
}
-
public function cssLinkLazy($html)
{
@@ -1625,6 +1649,9 @@
return false;
}
+
+ // TODO: Will break sites if always active
+
public function defferFontAwesome($html)
{
// TODO: Fix causes problems with Crsip on WP Compress Site
@@ -1647,8 +1674,6 @@
return $html;
}
-
- // TODO: Will break sites if always active
public function lazyWpFonts($html)
{
$pattern = '/<style[^>]*s*id=['"]wp-fonts-local['"][^>]*>.*?</style>/is';
@@ -1656,7 +1681,6 @@
return $html;
}
-
public function defferAssets($html)
{
// TODO: Fix causes problems with Crsip on WP Compress Site
@@ -1733,7 +1757,6 @@
return $return_tag;
}
-
public function replaceBackgroundDataSetting($image)
{
if (!empty($image[2])) {
@@ -1764,7 +1787,6 @@
return $image[0];
}
-
public function replaceBackgroundImageStylesLocal($image)
{
$tag = $image[0];
@@ -1806,7 +1828,6 @@
}
}
-
public function replaceBackgroundImageStyles($image)
{
if (!empty($image[0])) {
@@ -1862,7 +1883,6 @@
return $html;
}
-
public function replaceImageTags($html)
{
$html = preg_replace_callback('/(?<!["|'])<img[^>]*>/i', [__CLASS__, 'replaceImageTagsDo'], $html);
@@ -1954,11 +1974,7 @@
//todo: above was breaking images without src, only srcset
// Only remove srcset if src attribute exists
- $html[0] = preg_replace(
- '/(<(?:source|img)b(?=[^>]*ssrc=)[^>]*)s+srcset="[^"]*"([^>]*>)/i',
- '$1$2',
- $html[0]
- );
+ $html[0] = preg_replace('/(<(?:source|img)b(?=[^>]*ssrc=)[^>]*)s+srcset="[^"]*"([^>]*>)/i', '$1$2', $html[0]);
}
$html = preg_replace_callback('/(?:https?://|/)[^s]+.(jpg|jpeg|png|gif|svg|webp)/i', [__CLASS__, 'replaceSourceSrcset'], $html);
@@ -2087,14 +2103,7 @@
}
- $lazyExcludes = [
- 'breakdance',
- 'skip-lazy',
- 'notlazy',
- 'nolazy',
- 'jet-image',
- 'data-lazy'
- ];
+ $lazyExcludes = ['breakdance', 'skip-lazy', 'notlazy', 'nolazy', 'jet-image', 'data-lazy'];
foreach ($lazyExcludes as $exclude) {
if (strpos($image[0], $exclude) !== false) {
@@ -2215,7 +2224,7 @@
return print_r(['src_is_empty' => empty($original_img_tag['original_tags']['src']), 'data-src_is_empty' => empty($original_img_tag['original_tags']['data-src']), 'data-cp-src_is_empty' => empty($original_img_tag['original_tags']['data-cp-src']), 'src' => $image_source, 'porto-lazy-src' => $original_img_tag['original_tags']['data-oi'], 'tags' => $original_img_tag], true);
}
- if (!empty($original_img_tag['original_tags']['data-interchange'])){
+ if (!empty($original_img_tag['original_tags']['data-interchange'])) {
// if this is set then JS parses it and finds the correct url to use, but if we put it on cdn we break the parsing, have to exclude
return $image[0];
}
@@ -2486,6 +2495,8 @@
// TODO: Added 23.11.2025 - mozda sjebe lazy load?
// TODO: Maknuto, bilo je problema
// unset($original_img_tag['additional_tags']['data-wpc-loaded']);
+
+ $original_img_tag['src'] = $image_source;
}
$build_image_tag = '<img ';
@@ -2697,7 +2708,6 @@
return $build_image_tag;
}
-
public function ajaxImage($imageElement)
{
if ($this->checkIsSlashed($imageElement)) {
@@ -2771,11 +2781,7 @@
$newSrcSet = '';
- preg_match_all(
- '/((https?://|//)[^s]+S+.(jpg|jpeg|png|gif|svg|webp))s(d{1,5}+[wx])/si',
- $srcset,
- $srcset_links
- );
+ preg_match_all('/((https?://|//)[^s]+S+.(jpg|jpeg|png|gif|svg|webp))s(d{1,5}+[wx])/si', $srcset, $srcset_links);
// Fix max-width setting for img tag
$maxWidthMatches = [];
@@ -2789,7 +2795,7 @@
// otherwise use the largest srcset candidate.
// ---------------------------------------------------------------------
$largestWidth = 0;
- $largestSrc = '';
+ $largestSrc = '';
if (!empty($srcset_links[0])) {
foreach ($srcset_links[0] as $srcsetItem) {
@@ -2797,14 +2803,14 @@
if (count($parts) < 2) continue;
$url = trim($parts[0]);
- $w = trim($parts[1]);
+ $w = trim($parts[1]);
// Only treat "w" candidates as width-based (ignore "x" densities for largest selection)
if (strpos($w, 'w') !== false) {
- $wi = (int) str_replace('w', '', $w);
+ $wi = (int)str_replace('w', '', $w);
if ($wi > $largestWidth) {
$largestWidth = $wi;
- $largestSrc = $url;
+ $largestSrc = $url;
}
}
}
@@ -2846,7 +2852,7 @@
$parts = preg_split('/s+/', trim($srcsetItem));
if (count($parts) < 2) continue;
- $srcset_url = trim($parts[0]);
+ $srcset_url = trim($parts[0]);
$srcset_width = trim($parts[1]);
$webp = '/wp:' . self::$webp;
@@ -2862,10 +2868,10 @@
// Parse descriptor
if (strpos($srcset_width, 'x') !== false) {
$width_url = 1;
- $width_val = (int) str_replace('x', '', $srcset_width);
+ $width_val = (int)str_replace('x', '', $srcset_width);
$extension = 'x';
} else {
- $width_val = (int) str_replace('w', '', $srcset_width);
+ $width_val = (int)str_replace('w', '', $srcset_width);
$width_url = $width_val;
$extension = 'w';
}
@@ -2885,21 +2891,13 @@
}
// Non-retina URL (use the actual candidate URL)
- $newSrcSet .= self::$apiUrl
- . '/r:0' . $webp
- . '/w:' . self::getCurrentMaxWidth($width_url, self::isExcludedFrom('adaptive', $srcset_url))
- . '/u:' . self::reformatUrl($srcset_url)
- . ' ' . $srcsetWidthExtension . ', ';
+ $newSrcSet .= self::$apiUrl . '/r:0' . $webp . '/w:' . self::getCurrentMaxWidth($width_url, self::isExcludedFrom('adaptive', $srcset_url)) . '/u:' . self::reformatUrl($srcset_url) . ' ' . $srcsetWidthExtension . ', ';
// Retina URL (IMPORTANT: use canonical fullSrc, not original_src)
if (self::$settings['retina-in-srcset'] == '1' && !empty($fullSrc)) {
$retinaWidth = (int)$width_url * 2;
- $newSrcSet .= self::$apiUrl
- . '/r:1' . $webp
- . '/w:' . self::getCurrentMaxWidth($retinaWidth, self::isExcludedFrom('adaptive', $fullSrc))
- . '/u:' . self::reformatUrl($fullSrc)
- . ' ' . ($retinaWidth . $extension) . ', ';
+ $newSrcSet .= self::$apiUrl . '/r:1' . $webp . '/w:' . self::getCurrentMaxWidth($retinaWidth, self::isExcludedFrom('adaptive', $fullSrc)) . '/u:' . self::reformatUrl($fullSrc) . ' ' . ($retinaWidth . $extension) . ', ';
}
}
@@ -2927,8 +2925,6 @@
return $srcset;
}
-
-
public function replace_with_480w($srcset)
{
// First check if 480w already exists in the srcset
@@ -2992,30 +2988,5 @@
return $srcset;
}
- function filterCriticalFontFaces(string $critical): string
- {
- $blockedFonts = get_option('wps_ic_remove_fonts');
- if (empty($blockedFonts)){
- return $critical;
- }
-
- // Match @font-face { ... } blocks (multiline, non-greedy)
- $pattern = '/@font-faces*{.*?}/is';
-
- return preg_replace_callback($pattern, function ($match) use ($blockedFonts) {
- $fontFaceBlock = $match[0];
-
- foreach ($blockedFonts as $blocked) {
- if (stripos($fontFaceBlock, $blocked) !== false) {
- // Remove this @font-face block
- return '';
- }
- }
-
- // Keep this @font-face block
- return $fontFaceBlock;
- }, $critical);
- }
-
}
No newline at end of file
--- a/wp-compress-image-optimizer/addons/cf-sdk/cf-sdk.php
+++ b/wp-compress-image-optimizer/addons/cf-sdk/cf-sdk.php
@@ -990,22 +990,6 @@
return $sslCheck;
}
- // Check if record already exists elsewhere
- // Was Causing problems because dns_get_record is cached!!!
-// $records = dns_get_record($cdn_subdomain, DNS_CNAME);
-//
-// if (!empty($records)) {
-// $existing_target = $records[0]['target'];
-//
-// // If it's not pointing to zapwp, return error
-// if (strpos($existing_target, 'zapwp.net') === false) {
-// return new WP_Error(
-// 'dns_exists',
-// 'DNS record already exists',
-// [['message' => "DNS record already exists pointing to {$existing_target}. Please specify a <span class="wpc-cf-cname-popup">different CNAME</span> and try activating again."]]
-// );
-// }
-// }
// Check if record already exists in CF
$existingRecord = $this->findDNSRecord($zoneId, $cdn_subdomain, 'CNAME');
--- a/wp-compress-image-optimizer/addons/legacy/compress.php
+++ b/wp-compress-image-optimizer/addons/legacy/compress.php
@@ -297,7 +297,7 @@
$expected_token = $options['api_key'];
if (empty($apikey) || $apikey !== $expected_token) {
- wp_send_json_error('Unauthorized expected: ' .$expected_token . ' got ' . $apikey, 403);
+ wp_send_json_error('Unauthorized: apikey ' . $apikey, 403);
}
// if API Key is Valid Setup the PHP Limits
--- a/wp-compress-image-optimizer/classes/ajax.class.php
+++ b/wp-compress-image-optimizer/classes/ajax.class.php
@@ -387,51 +387,6 @@
}
- public function wpc_ic_setupCFOld()
- {
- if (!current_user_can('manage_wpc_settings') || !wp_verify_nonce($_POST['wps_ic_nonce'], 'wps_ic_nonce_action')) {
- wp_send_json_error('Forbidden.');
- }
-
- $token = sanitize_text_field($_POST['token']);
- $zoneInput = sanitize_text_field($_POST['zone']);
-
- $cfapi = new WPC_CloudflareAPI($token);
- $whitelist = $cfapi->whitelistIPs($zoneInput);
-
- // TODO: Add functions
- $cf = get_option(WPS_IC_CF);
- // Static Assets & Edge Cache
- $cfapi->updateWPCCacheConfig($zoneInput, 1, 'all');
- // CF Real Time CDN
- $dns_result = $cfapi->addCfCname($zoneInput);
-
- // set custom cname
- $cf['custom_cname'] = $cfapi->getCfCname();
- $cfCname = $cfapi->getCfCname();
- $cf['settings'] = ['assets' => '1', 'edge-cache' => 'all', 'cdn' => '1'];
- update_option(WPS_IC_CF_CNAME, $cfCname);
- update_option(WPS_IC_CF, $cf);
-
- // TODO Save Cname into API
- $requests = new wps_ic_requests();
- $options = get_option(WPS_IC_OPTIONS);
- $apikey = $options['api_key'];
- $requests->GET(WPS_IC_KEYSURL, ['action' => 'cloudflare_setCname', 'apikey' => $apikey, 'cname' => $cfapi->getCfCname(), 'time' => microtime(true)]);
-
- self::$options = get_option(WPS_IC_SETTINGS);
- self::$options['cf'] = $cf['settings'];
- $cfCname = $cfapi->getCfCname();
- update_option(WPS_IC_CF_CNAME, $cfCname);
- update_option(WPS_IC_SETTINGS, self::$options);
-
- if (is_wp_error($whitelist)) {
- wp_send_json_error($whitelist->get_error_message());
- }
-
- wp_send_json_success('whitelisted-successfully');
- }
-
public function wpc_send_critical_remote()
{
$criticalCSS = new wps_criticalCss();
@@ -3100,6 +3055,15 @@
unset($tests['home']);
update_option(WPS_IC_TESTS, $tests);
+ // Save history of tests
+ $history = get_option(WPS_IC_LITE_GPS_HISTORY);
+ if (empty($history)) {
+ $history = [];
+ }
+ $history[time()] = get_option(WPS_IC_LITE_GPS);
+ update_option(WPS_IC_LITE_GPS_HISTORY, $history);
+
+ // Delete data
delete_transient('wpc_test_running');
delete_transient('wpc_initial_test');
delete_option(WPS_IC_LITE_GPS);
--- a/wp-compress-image-optimizer/classes/cname.class.php
+++ b/wp-compress-image-optimizer/classes/cname.class.php
@@ -64,10 +64,6 @@
$requests->GET(WPS_IC_KEYSURL, ['action' => 'cdn_setcname', 'apikey' => $apikey, 'cname' => $cname, 'zone_name' => $zone_name, 'time' => microtime(true)]);
sleep(10);
- //v6 call:
- #$requests->GET(WPS_IC_KEYSURL, ['action' => 'cdn_setcname_v6', 'apikey' => $apikey, 'cname' => $cname, 'zone_name' => $zone_name, 'time' => microtime(true)]);
- #sleep(5);
-
$requests->GET(WPS_IC_KEYSURL, ['action' => 'cdn_purge', 'apikey' => $apikey, 'domain' => site_url(), 'zone_name' => $zone_name, 'time' => microtime(true)]);
// Wait for SSL?
--- a/wp-compress-image-optimizer/defines.php
+++ b/wp-compress-image-optimizer/defines.php
@@ -69,6 +69,7 @@
define('WPS_IC_TESTS', 'wpc-tests');
+define('WPS_IC_LITE_GPS_HISTORY', 'wps_ic_initial_gps_history');
define('WPS_IC_LITE_GPS', 'wps_ic_initial_gps');
define('WPS_IC_GUI', 'wps_ic_gui');
define('WPS_IC_SETTINGS', 'wps_ic_settings');
--- a/wp-compress-image-optimizer/templates/admin/advanced_settings_v4.php
+++ b/wp-compress-image-optimizer/templates/admin/advanced_settings_v4.php
@@ -314,6 +314,9 @@
///CF integration
$cf = get_option(WPS_IC_CF);
+if (!empty($_GET['debugCF'])) {
+ #var_dump($cf);
+}
if (!empty($cf)){
$cfsdk = new WPC_CloudflareAPI($cf['token']);
--- a/wp-compress-image-optimizer/templates/admin/partials/lite/stats.php
+++ b/wp-compress-image-optimizer/templates/admin/partials/lite/stats.php
@@ -74,7 +74,7 @@
<img src="<?php echo WPS_IC_URI; ?>assets/lite/images/refresh.svg"/>
Retest
</a>
- <?php } elseif (empty($initialPageSpeedScore) && $warmupFailing){ ?>
+ <?php } elseif (empty($initialPageSpeedScore) && $warmupFailing) { ?>
<span class="wpc-test-in-progress"> Error, warmup not going.</span>
<a href="#" class="wps-ic-initial-retest">
<img src="<?php echo WPS_IC_URI; ?>assets/lite/images/refresh.svg"/>
@@ -109,6 +109,7 @@
$date->setTimestamp($initialPageSpeedScore['lastRun']);
$lastRun = "Last Tested " . $date->format('F jS, Y @ g:i A');
}
+
?>
<div class="wpc-box-title-right">
<span><?php echo $lastRun; ?></span>
@@ -129,12 +130,13 @@
<span>Usually takes about 10 minutes...</span>
</div>
<?php
- } elseif ($warmupFailing){
+ } elseif ($warmupFailing) {
echo '<div style="padding:35px 15px;text-align: center;">';
echo '<strong>Error! Seems connection to our API was blocked by Firewall on your server.</strong>';
echo '<br/><br/><a href="https://help.wpcompress.com/en-us/article/whitelisting-wp-compress-for-uninterrupted-service-4dwkra/" target="_blank">Whitelisting Tutorial</a>';
echo '</div>';
- } elseif (!empty($options['api_key']) && (empty($initialPageSpeedScore) || !empty($initialTestRunning))) {
+ }
+ elseif (!empty($options['api_key']) && (empty($initialPageSpeedScore) || !empty($initialTestRunning))) {
$home_page_id = get_option('page_on_front');
?>
<script type="text/javascript">
@@ -163,6 +165,32 @@
$desktopDiff = $desktopDiff < 0 ? 0 : '+' . $desktopDiff;
$mobileDiff = $mobileDiff < 0 ? 0 : '+' . $mobileDiff;
+
+ if (!empty($_GET['testFailed'])) {
+ $mobileAfterGPS = 0;
+ $beforeGPS = 0;
+ }
+
+ // if Score is 0 or test failed, check history
+ if (empty($mobileAfterGPS) || empty($beforeGPS) || $mobileAfterGPS == 0 || $beforeGPS == 0) {
+ $gpsHistory = get_option(WPS_IC_LITE_GPS_HISTORY);
+ if (!empty($gpsHistory)) {
+ $gpsHistoryLast = array_key_last($gpsHistory);
+ $gpsHistory = $gpsHistory[$gpsHistoryLast];
+ $initialPageSpeedScore = $gpsHistory['result'];
+
+ $beforeGPS = $initialPageSpeedScore['desktop']['before']['performanceScore'] / 100;
+ $afterGPS = $initialPageSpeedScore['desktop']['after']['performanceScore'] / 100;
+ $mobileBeforeGPS = $initialPageSpeedScore['mobile']['before']['performanceScore'] / 100;
+ $mobileAfterGPS = $initialPageSpeedScore['mobile']['after']['performanceScore'] / 100;
+ $desktopDiff = $initialPageSpeedScore['desktop']['after']['performanceScore'] - $initialPageSpeedScore['desktop']['before']['performanceScore'];
+ $mobileDiff = $initialPageSpeedScore['mobile']['after']['performanceScore'] - $initialPageSpeedScore['mobile']['before']['performanceScore'];
+
+ $desktopDiff = $desktopDiff < 0 ? 0 : '+' . $desktopDiff;
+ $mobileDiff = $mobileDiff < 0 ? 0 : '+' . $mobileDiff;
+ }
+ }
+
?>
<ul class="wpc-pagespeed-score" style="">
<li>
@@ -367,7 +395,8 @@
<div class="wpc-page-speed-footer">
<div class="wpc-ps-f-left">
<div class="wpc-badge-container">
- <p style="text-align: center;font-weight: bold;font-family: 'proxima_semibold';">Ooops! Seems we had some issues with testing your site! Please retry!</p>
+ <p style="text-align: center;font-weight: bold;font-family: 'proxima_semibold';">Ooops! Seems we had some issues with testing your site! Please
+ retry!</p>
</div>
<?php
--- a/wp-compress-image-optimizer/traits/url_key.php
+++ b/wp-compress-image-optimizer/traits/url_key.php
@@ -20,9 +20,11 @@
public function setup($url = '')
{
- if ($url == '') {
- $url = $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
- }
+ if (empty($url)) {
+ $host = $_SERVER['HTTP_HOST'] ?? '';
+ $uri = $_SERVER['REQUEST_URI'] ?? '';
+ $url = $host . $uri;
+ }
$original_url = $url;
--- a/wp-compress-image-optimizer/wp-compress-core.php
+++ b/wp-compress-image-optimizer/wp-compress-core.php
@@ -79,7 +79,7 @@
// Basic plugin info
self::$slug = 'wpcompress';
- self::$version = '6.60.28';
+ self::$version = '6.60.29';
$development = get_option('wps_ic_development');
if (!empty($development) && $development == 'true') {
@@ -432,13 +432,6 @@
// Vars
$body = self::createObjectFromJson($json);
-// var_dump($body);
-// var_dump(site_url());
-// var_dump($body->site->site_url);
-// var_dump(site_url());
-// var_dump($body->site->site_url !== site_url());
-// die('x');
-
//Check if url changed
if ($body->site->site_url !== site_url()){
$options = get_option(WPS_IC_OPTIONS);
@@ -1569,13 +1562,7 @@
}
$criticalCSS = new wps_criticalCss();
-//
-// // Check if LCP Exists
-// $mobileLCP = 'https://critical-css.b-cdn.net/'.$uuidPart.'/lcp-'.$uuid.'-mobile';
-// $desktopLCP = 'https://critical-css.b-cdn.net/'.$uuidPart.'/lcp-'.$uuid.'-desktop';
-//
-// $jobStatus[] = $criticalCSS->saveLCP($urlKey, ['url' => ['desktop' => $desktopLCP, 'mobile' => $mobileLCP]]);
-//
+
$jobStatus[] = $criticalCSS->saveBenchmark($urlKey, $uuid);
$this->debugPageSpeed('Pagespeed Done with uuid ' . $uuid . '!');
@@ -1850,6 +1837,15 @@
self::check_account_status();
}
+ if (!empty($_GET['resetHistory'])) {
+ delete_option(WPS_IC_LITE_GPS_HISTORY);
+ }
+
+ if (!empty($_GET['testHistory'])) {
+ $history = get_option(WPS_IC_LITE_GPS_HISTORY);
+ var_dump($history);
+ }
+
$this->enqueues = new wps_ic_enqueues();
$this->runInitialTest();
@@ -2058,6 +2054,14 @@
// Delete flag which forces the run of the test
delete_transient('wpc_run_initial_test');
+ // Save history of tests
+ $history = get_option(WPS_IC_LITE_GPS_HISTORY);
+ if (empty($history)) {
+ $history = [];
+ }
+ $history[time()] = get_option(WPS_IC_LITE_GPS);
+ update_option(WPS_IC_LITE_GPS_HISTORY, $history);
+
// Remove Tests
delete_option(WPS_IC_TESTS);
delete_option(WPS_IC_LITE_GPS);
--- a/wp-compress-image-optimizer/wp-compress.php
+++ b/wp-compress-image-optimizer/wp-compress.php
@@ -4,7 +4,7 @@
* Plugin URI: https://www.wpcompress.com
* Author: WP Compress
* Author URI: https://www.wpcompress.com
- * Version: 6.60.28
+ * Version: 6.60.29
* Description: Automatically compress and optimize images to shrink image file size, improve times and boost SEO ranks - all without lifting a finger after setup.
* Text Domain: wp-compress-image-optimizer
* Domain Path: /langs