perf: aggressive webp re-compression + max-width 1920 resize
- recompress every webp at q=70-82 depending on size band - resize anything wider than 1920px to 1920 max - convert remaining png/jpg holdouts (mine, thermal, dex3-1 etc) to webp - restore apple-touch-icon.png (iOS requires png) - 86 files recompressed, saved 4.36 MB - public/ images: 11.7 MB -> 6.69 MB (-43%) - total trajectory: 23.3 MB -> 6.69 MB (-71%) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 8.8 KiB After Width: | Height: | Size: 7.9 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 38 KiB |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 35 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 9.6 KiB |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 127 KiB After Width: | Height: | Size: 107 KiB |
|
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 47 KiB |
|
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 36 KiB |
|
Before Width: | Height: | Size: 340 KiB After Width: | Height: | Size: 109 KiB |
|
Before Width: | Height: | Size: 268 KiB |
BIN
public/images/accessories/unitree-dex3-1.webp
Normal file
|
After Width: | Height: | Size: 298 KiB |
|
Before Width: | Height: | Size: 268 KiB |
BIN
public/images/accessories/unitree-dex3-1/diagram.webp
Normal file
|
After Width: | Height: | Size: 298 KiB |
|
Before Width: | Height: | Size: 244 KiB After Width: | Height: | Size: 86 KiB |
|
Before Width: | Height: | Size: 244 KiB After Width: | Height: | Size: 86 KiB |
|
Before Width: | Height: | Size: 282 KiB After Width: | Height: | Size: 260 KiB |
|
Before Width: | Height: | Size: 96 KiB |
BIN
public/images/accessories/unitree-l2.webp
Normal file
|
After Width: | Height: | Size: 91 KiB |
|
Before Width: | Height: | Size: 86 KiB After Width: | Height: | Size: 75 KiB |
|
Before Width: | Height: | Size: 346 KiB After Width: | Height: | Size: 42 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 9.4 KiB |
|
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 94 KiB After Width: | Height: | Size: 53 KiB |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 166 KiB After Width: | Height: | Size: 134 KiB |
|
Before Width: | Height: | Size: 136 KiB After Width: | Height: | Size: 98 KiB |
|
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 42 KiB |
|
Before Width: | Height: | Size: 99 KiB After Width: | Height: | Size: 85 KiB |
|
Before Width: | Height: | Size: 51 KiB After Width: | Height: | Size: 46 KiB |
|
Before Width: | Height: | Size: 191 KiB After Width: | Height: | Size: 64 KiB |
|
Before Width: | Height: | Size: 104 KiB After Width: | Height: | Size: 92 KiB |
|
Before Width: | Height: | Size: 145 KiB After Width: | Height: | Size: 115 KiB |
|
Before Width: | Height: | Size: 210 KiB |
BIN
public/images/robots/unitree-go2-w.webp
Normal file
|
After Width: | Height: | Size: 361 KiB |
|
Before Width: | Height: | Size: 99 KiB After Width: | Height: | Size: 86 KiB |
|
Before Width: | Height: | Size: 881 KiB After Width: | Height: | Size: 260 KiB |
|
Before Width: | Height: | Size: 76 KiB After Width: | Height: | Size: 67 KiB |
|
Before Width: | Height: | Size: 68 KiB After Width: | Height: | Size: 61 KiB |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 494 KiB After Width: | Height: | Size: 150 KiB |
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 403 KiB After Width: | Height: | Size: 120 KiB |
|
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 43 KiB |
|
Before Width: | Height: | Size: 264 KiB After Width: | Height: | Size: 86 KiB |
|
Before Width: | Height: | Size: 92 KiB After Width: | Height: | Size: 36 KiB |
|
Before Width: | Height: | Size: 86 KiB After Width: | Height: | Size: 78 KiB |
|
Before Width: | Height: | Size: 192 KiB After Width: | Height: | Size: 68 KiB |
|
Before Width: | Height: | Size: 384 KiB After Width: | Height: | Size: 118 KiB |
|
Before Width: | Height: | Size: 267 KiB After Width: | Height: | Size: 146 KiB |
|
Before Width: | Height: | Size: 154 KiB After Width: | Height: | Size: 75 KiB |
|
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 43 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 329 KiB After Width: | Height: | Size: 160 KiB |
|
Before Width: | Height: | Size: 184 KiB After Width: | Height: | Size: 88 KiB |
|
Before Width: | Height: | Size: 512 KiB After Width: | Height: | Size: 205 KiB |
|
Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 328 KiB After Width: | Height: | Size: 146 KiB |
|
Before Width: | Height: | Size: 243 KiB |
BIN
public/industries/unitree/mine.webp
Normal file
|
After Width: | Height: | Size: 228 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 255 KiB After Width: | Height: | Size: 103 KiB |
|
Before Width: | Height: | Size: 115 KiB After Width: | Height: | Size: 113 KiB |
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 76 KiB After Width: | Height: | Size: 65 KiB |
|
Before Width: | Height: | Size: 76 KiB After Width: | Height: | Size: 71 KiB |
|
Before Width: | Height: | Size: 179 KiB After Width: | Height: | Size: 86 KiB |
|
Before Width: | Height: | Size: 409 KiB After Width: | Height: | Size: 154 KiB |
|
Before Width: | Height: | Size: 593 KiB After Width: | Height: | Size: 279 KiB |
|
Before Width: | Height: | Size: 468 KiB |
BIN
public/industries/unitree/thermal.webp
Normal file
|
After Width: | Height: | Size: 174 KiB |
|
Before Width: | Height: | Size: 124 KiB After Width: | Height: | Size: 110 KiB |
85
scripts/aggressive-compress.mjs
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
import { promises as fs } from 'node:fs';
|
||||||
|
import path from 'node:path';
|
||||||
|
import sharp from 'sharp';
|
||||||
|
|
||||||
|
const ROOT = path.resolve('public');
|
||||||
|
const SKIP = new Set(['favicon.ico']);
|
||||||
|
const MAX_W = 1920; // cap any image wider than this
|
||||||
|
|
||||||
|
const exts = new Set(['.jpg', '.jpeg', '.png', '.gif', '.webp']);
|
||||||
|
let convertedCount = 0;
|
||||||
|
let savedBytes = 0;
|
||||||
|
let skippedCount = 0;
|
||||||
|
|
||||||
|
async function walk(dir) {
|
||||||
|
const entries = await fs.readdir(dir, { withFileTypes: true });
|
||||||
|
for (const e of entries) {
|
||||||
|
const p = path.join(dir, e.name);
|
||||||
|
if (e.isDirectory()) await walk(p);
|
||||||
|
else if (exts.has(path.extname(p).toLowerCase())) await compress(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function qualityFor(bytes) {
|
||||||
|
if (bytes > 700 * 1024) return 70;
|
||||||
|
if (bytes > 300 * 1024) return 75;
|
||||||
|
if (bytes > 120 * 1024) return 78;
|
||||||
|
return 82;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function compress(input) {
|
||||||
|
const base = path.basename(input);
|
||||||
|
if (SKIP.has(base)) return;
|
||||||
|
const ext = path.extname(input).toLowerCase();
|
||||||
|
const isGif = ext === '.gif';
|
||||||
|
const relRoot = path.relative(process.cwd(), input).split(path.sep).join('/');
|
||||||
|
|
||||||
|
try {
|
||||||
|
const stIn = await fs.stat(input);
|
||||||
|
if (stIn.size < 8 * 1024) {
|
||||||
|
// tiny: leave
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const target = input.slice(0, -ext.length) + '.webp';
|
||||||
|
// Read into memory first, then close handle
|
||||||
|
const srcBuf = await fs.readFile(input);
|
||||||
|
const meta = await sharp(srcBuf, { animated: isGif }).metadata();
|
||||||
|
let pipeline = sharp(srcBuf, { animated: isGif });
|
||||||
|
if (meta.width && meta.width > MAX_W) {
|
||||||
|
pipeline = pipeline.resize({ width: MAX_W, withoutEnlargement: true });
|
||||||
|
}
|
||||||
|
const q = qualityFor(stIn.size);
|
||||||
|
pipeline = pipeline.webp({
|
||||||
|
quality: q,
|
||||||
|
alphaQuality: 88,
|
||||||
|
effort: 6,
|
||||||
|
smartSubsample: true,
|
||||||
|
...(isGif ? { loop: 0 } : {}),
|
||||||
|
});
|
||||||
|
const buf = await pipeline.toBuffer();
|
||||||
|
if (buf.length >= stIn.size && ext === '.webp') {
|
||||||
|
skippedCount++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// write via temp file then rename for atomicity
|
||||||
|
const tmp = target + '.tmp';
|
||||||
|
await fs.writeFile(tmp, buf);
|
||||||
|
if (target !== input) {
|
||||||
|
try { await fs.unlink(input); } catch {}
|
||||||
|
}
|
||||||
|
await fs.rename(tmp, target);
|
||||||
|
convertedCount++;
|
||||||
|
savedBytes += stIn.size - buf.length;
|
||||||
|
const inKB = (stIn.size / 1024).toFixed(0);
|
||||||
|
const outKB = (buf.length / 1024).toFixed(0);
|
||||||
|
console.log(`OK q=${q} ${relRoot} ${inKB}KB -> ${outKB}KB${meta.width && meta.width > MAX_W ? ' (resized)' : ''}`);
|
||||||
|
} catch (err) {
|
||||||
|
console.log(`FAIL ${relRoot}: ${err.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await walk(ROOT);
|
||||||
|
const savedMB = (savedBytes / 1024 / 1024).toFixed(2);
|
||||||
|
console.log('\n---');
|
||||||
|
console.log(`compressed: ${convertedCount} skipped: ${skippedCount}`);
|
||||||
|
console.log(`saved: ${savedMB} MB`);
|
||||||
@ -529,6 +529,21 @@ html {
|
|||||||
/* === Layout helpers === */
|
/* === Layout helpers === */
|
||||||
.container-wide { max-width: 1320px; margin: 0 auto; padding-left: clamp(1rem, 4vw, 2rem); padding-right: clamp(1rem, 4vw, 2rem); }
|
.container-wide { max-width: 1320px; margin: 0 auto; padding-left: clamp(1rem, 4vw, 2rem); padding-right: clamp(1rem, 4vw, 2rem); }
|
||||||
|
|
||||||
|
/* === Navbar responsive === */
|
||||||
|
.nav-desktop { display: none; }
|
||||||
|
.nav-desktop-cta { display: inline-flex; }
|
||||||
|
.nav-mobile-toggle { display: none !important; }
|
||||||
|
@media (min-width: 900px) {
|
||||||
|
.nav-desktop { display: flex !important; }
|
||||||
|
.nav-desktop-cta { display: inline-flex !important; }
|
||||||
|
.nav-mobile-toggle { display: none !important; }
|
||||||
|
}
|
||||||
|
@media (max-width: 899px) {
|
||||||
|
.nav-desktop { display: none !important; }
|
||||||
|
.nav-desktop-cta { display: none !important; }
|
||||||
|
.nav-mobile-toggle { display: inline-flex !important; }
|
||||||
|
}
|
||||||
|
|
||||||
.eyebrow {
|
.eyebrow {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|||||||
@ -315,7 +315,7 @@ export const ACCESSORIES: Accessory[] = [
|
|||||||
'12–58 V operating voltage',
|
'12–58 V operating voltage',
|
||||||
'1 kHz communication rate',
|
'1 kHz communication rate',
|
||||||
],
|
],
|
||||||
image: '/images/accessories/unitree-dex3-1.jpg',
|
image: '/images/accessories/unitree-dex3-1.webp',
|
||||||
accent: GOLD_BRONZE,
|
accent: GOLD_BRONZE,
|
||||||
officialUrl: 'https://www.unitree.com/Dex3-1',
|
officialUrl: 'https://www.unitree.com/Dex3-1',
|
||||||
compatibility: ['Unitree G1'],
|
compatibility: ['Unitree G1'],
|
||||||
@ -402,7 +402,7 @@ export const ACCESSORIES: Accessory[] = [
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
paramsImage: '/images/accessories/unitree-dex3-1/diagram.png',
|
paramsImage: '/images/accessories/unitree-dex3-1/diagram.webp',
|
||||||
footnotes: [
|
footnotes: [
|
||||||
'Size refers to the dexterous hand in flat state.',
|
'Size refers to the dexterous hand in flat state.',
|
||||||
'Pressure data refers to force exerted by the dexterous hand when pressed by a vertical 1 cm diameter cylinder. Varies in different application scenarios.',
|
'Pressure data refers to force exerted by the dexterous hand when pressed by a vertical 1 cm diameter cylinder. Varies in different application scenarios.',
|
||||||
@ -718,7 +718,7 @@ export const ACCESSORIES: Accessory[] = [
|
|||||||
'ENET UDP / TTL UART communication',
|
'ENET UDP / TTL UART communication',
|
||||||
'Open POINT-LIO SLAM solution',
|
'Open POINT-LIO SLAM solution',
|
||||||
],
|
],
|
||||||
image: '/images/accessories/unitree-l2.jpg',
|
image: '/images/accessories/unitree-l2.webp',
|
||||||
accent: GOLD_CHAMPAGNE,
|
accent: GOLD_CHAMPAGNE,
|
||||||
officialUrl: 'https://www.unitree.com/L2',
|
officialUrl: 'https://www.unitree.com/L2',
|
||||||
compatibility: ['Unitree Go2', 'Unitree quadrupeds', 'Third-party robots'],
|
compatibility: ['Unitree Go2', 'Unitree quadrupeds', 'Third-party robots'],
|
||||||
|
|||||||
@ -329,7 +329,7 @@ export const INDUSTRY_PAGES: Record<string, IndustryPageContent> = {
|
|||||||
{ src: '/images/robots/pudu-cc1.webp', alt: 'PUDU CC1 auto-scrubber', caption: 'PUDU CC1 — auto-scrubber for large floors.', credit: 'Pudu' },
|
{ src: '/images/robots/pudu-cc1.webp', alt: 'PUDU CC1 auto-scrubber', caption: 'PUDU CC1 — auto-scrubber for large floors.', credit: 'Pudu' },
|
||||||
{ src: '/images/robots/pudu-kettybot.webp', alt: 'KettyBot wayfinding and ad display', caption: 'KettyBot Pro — wayfinding and promo runs.', credit: 'Pudu' },
|
{ src: '/images/robots/pudu-kettybot.webp', alt: 'KettyBot wayfinding and ad display', caption: 'KettyBot Pro — wayfinding and promo runs.', credit: 'Pudu' },
|
||||||
{ src: '/images/robots/unitree-go2.webp', alt: 'Unitree Go2 night patrol', caption: 'Unitree Go2 — night patrol across decks.', credit: 'Unitree' },
|
{ src: '/images/robots/unitree-go2.webp', alt: 'Unitree Go2 night patrol', caption: 'Unitree Go2 — night patrol across decks.', credit: 'Unitree' },
|
||||||
{ src: '/industries/unitree/thermal.jpg', alt: 'Thermal + LiDAR patrol sensors', caption: 'Thermal + LiDAR sensors for after-hours rounds.', credit: 'Unitree' },
|
{ src: '/industries/unitree/thermal.webp', alt: 'Thermal + LiDAR patrol sensors', caption: 'Thermal + LiDAR sensors for after-hours rounds.', credit: 'Unitree' },
|
||||||
],
|
],
|
||||||
problemPoints: [
|
problemPoints: [
|
||||||
'Large floor areas are hard to clean and patrol consistently.',
|
'Large floor areas are hard to clean and patrol consistently.',
|
||||||
@ -606,12 +606,12 @@ export const INDUSTRY_PAGES: Record<string, IndustryPageContent> = {
|
|||||||
],
|
],
|
||||||
gallery: [
|
gallery: [
|
||||||
{ src: '/industries/unitree/terrain.webp', alt: 'Quadruped robot on mixed industrial terrain', caption: 'Stairs, gullies, and uneven ground handled on one platform.', credit: 'Unitree' },
|
{ src: '/industries/unitree/terrain.webp', alt: 'Quadruped robot on mixed industrial terrain', caption: 'Stairs, gullies, and uneven ground handled on one platform.', credit: 'Unitree' },
|
||||||
{ src: '/industries/unitree/thermal.jpg', alt: 'Thermal imaging and laser-radar detection', caption: 'Thermal, laser-radar, and AI imaging for routine monitoring.', credit: 'Unitree' },
|
{ src: '/industries/unitree/thermal.webp', alt: 'Thermal imaging and laser-radar detection', caption: 'Thermal, laser-radar, and AI imaging for routine monitoring.', credit: 'Unitree' },
|
||||||
{ src: '/industries/unitree/substation.webp', alt: 'Power substation patrol', caption: 'Substation patrol — switchgear and transformer scans.', credit: 'Unitree' },
|
{ src: '/industries/unitree/substation.webp', alt: 'Power substation patrol', caption: 'Substation patrol — switchgear and transformer scans.', credit: 'Unitree' },
|
||||||
{ src: '/industries/unitree/pipeline.webp', alt: 'Pipeline corridor patrol', caption: 'Pipeline and refinery corridor inspection rounds.', credit: 'Unitree' },
|
{ src: '/industries/unitree/pipeline.webp', alt: 'Pipeline corridor patrol', caption: 'Pipeline and refinery corridor inspection rounds.', credit: 'Unitree' },
|
||||||
{ src: '/industries/unitree/industrial-park.webp', alt: 'Industrial park perimeter coverage', caption: 'Industrial park and large-compound perimeter coverage.', credit: 'Unitree' },
|
{ src: '/industries/unitree/industrial-park.webp', alt: 'Industrial park perimeter coverage', caption: 'Industrial park and large-compound perimeter coverage.', credit: 'Unitree' },
|
||||||
{ src: '/industries/unitree/utility-room.webp', alt: 'Utility plant room inspection', caption: 'Utility and plant-room routine checks.', credit: 'Unitree' },
|
{ src: '/industries/unitree/utility-room.webp', alt: 'Utility plant room inspection', caption: 'Utility and plant-room routine checks.', credit: 'Unitree' },
|
||||||
{ src: '/industries/unitree/mine.jpg', alt: 'Tunnel inspection', caption: 'Tunnel and confined-zone inspection.', credit: 'Unitree' },
|
{ src: '/industries/unitree/mine.webp', alt: 'Tunnel inspection', caption: 'Tunnel and confined-zone inspection.', credit: 'Unitree' },
|
||||||
{ src: '/industries/unitree/terrain-night.webp', alt: 'Quadruped robot on night patrol', caption: 'After-hours rounds with consistent route timing.', credit: 'Unitree' },
|
{ src: '/industries/unitree/terrain-night.webp', alt: 'Quadruped robot on night patrol', caption: 'After-hours rounds with consistent route timing.', credit: 'Unitree' },
|
||||||
{ src: '/industries/unitree/b2-render.webp', alt: 'Unitree B2 industrial quadruped render', caption: 'B2 — industrial-grade quadruped platform.', credit: 'Unitree' },
|
{ src: '/industries/unitree/b2-render.webp', alt: 'Unitree B2 industrial quadruped render', caption: 'B2 — industrial-grade quadruped platform.', credit: 'Unitree' },
|
||||||
],
|
],
|
||||||
|
|||||||
@ -288,7 +288,7 @@ export const ROBOTS: Robot[] = [
|
|||||||
{ label: 'Battery', value: '1.5–3 h' },
|
{ label: 'Battery', value: '1.5–3 h' },
|
||||||
SPEC_CONSULT,
|
SPEC_CONSULT,
|
||||||
],
|
],
|
||||||
image: '/images/robots/unitree-go2-w.png',
|
image: '/images/robots/unitree-go2-w.webp',
|
||||||
imageType: 'photo',
|
imageType: 'photo',
|
||||||
accent: GOLD_BRAND,
|
accent: GOLD_BRAND,
|
||||||
officialUrl: 'https://www.unitree.com/go2-w',
|
officialUrl: 'https://www.unitree.com/go2-w',
|
||||||
|
|||||||