<?xml version="1.0" encoding="utf-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0"><channel><title>凯特网</title><link>https://caterwang.cn/</link><description>一个专注分享电子电路应用知识和C语言应用的网站</description><item><title>在线基于MedidPipe的人脸裁剪与背景替换工具</title><link>https://caterwang.cn/?id=173</link><description>&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;zh-CN&quot;&gt;
&lt;head&gt;
    &lt;meta charset=&quot;UTF-8&quot;&gt;
    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0, user-scalable=no&quot;&gt;
    &lt;title&gt;人脸标准化处理 - 质量评估+多引擎&lt;/title&gt;

    &lt;script src=&quot;https://cdn.jsdelivr.net/npm/@mediapipe/selfie_segmentation/selfie_segmentation.js&quot; crossorigin=&quot;anonymous&quot;&gt;&lt;/script&gt;
    &lt;script src=&quot;https://cdn.jsdelivr.net/npm/@mediapipe/face_mesh/face_mesh.js&quot; crossorigin=&quot;anonymous&quot;&gt;&lt;/script&gt;
    &lt;script src=&quot;https://cdn.jsdelivr.net/npm/@mediapipe/face_detection/face_detection.js&quot; crossorigin=&quot;anonymous&quot;&gt;&lt;/script&gt;
    &lt;style&gt;
        * { margin: 0; padding: 0; box-sizing: border-box; }
        body {
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Microsoft YaHei', sans-serif;
            background: #f0f4f9;
            padding: 20px;
            color: #0f172a;
        }
        .app-container {
            max-width: 1600px;
            margin: 0 auto;
            background: white;
            border-radius: 28px;
            box-shadow: 0 20px 35px -12px rgba(0,0,0,0.1);
            overflow: hidden;
        }
        .header {
            padding: 18px 28px;
            background: #ffffff;
            border-bottom: 1px solid #e9edf2;
        }
        .header h1 { font-size: 1.7rem; font-weight: 600; letter-spacing: -0.3px; background: linear-gradient(135deg, #1e2b3c, #2c4c6e); background-clip: text; -webkit-background-clip: text; color: transparent; }
        .header p { font-size: 0.85rem; color: #4a5b6e; margin-top: 6px; }
        
        .main-grid { display: flex; flex-wrap: wrap; }
        .control-panel {
            width: 360px;
            background: #fefefe;
            border-right: 1px solid #eef2f8;
            padding: 20px;
            display: flex;
            flex-direction: column;
            gap: 20px;
        }
        .content-panel { flex: 1; padding: 24px 28px; background: #ffffff; }
        
        .param-group {
            background: #f9fafc;
            border-radius: 20px;
            padding: 18px 16px;
            border: 1px solid #eef2f6;
        }
        .param-title {
            font-weight: 600;
            font-size: 1rem;
            margin-bottom: 14px;
            display: flex;
            align-items: center;
            gap: 8px;
        }
        .upload-area {
            border: 1.5px dashed #cbd5e1;
            border-radius: 24px;
            padding: 20px 12px;
            text-align: center;
            background: #fafcff;
            cursor: pointer;
            transition: 0.2s;
        }
        .upload-area:hover { border-color: #3b82f6; background: #eff6ff; }
        .file-input { display: none; }
        .option-row { margin-bottom: 16px; }
        .option-row label { font-size: 0.8rem; font-weight: 500; display: block; margin-bottom: 6px; color: #2c3e50; }
        select, input[type=&quot;range&quot;], input[type=&quot;number&quot;] {
            width: 100%; padding: 8px 12px; border-radius: 14px; border: 1px solid #cbd5e6;
            background: white; font-size: 0.85rem;
        }
        .range-value { display: flex; justify-content: space-between; font-size: 0.7rem; margin-top: 5px; }
        .crop-inputs {
            display: grid;
            grid-template-columns: 1fr 1fr;
            gap: 12px;
            margin-top: 8px;
        }
        .crop-inputs div { display: flex; flex-direction: column; }
        .crop-inputs span { font-size: 0.7rem; color: #4b5563; margin-bottom: 4px; }
        button {
            background: #1e293b; border: none; color: white; font-weight: 500; padding: 10px 16px;
            border-radius: 40px; font-size: 0.85rem; cursor: pointer; width: 100%; transition: 0.2s;
        }
        button.primary { background: #3b82f6; box-shadow: 0 2px 6px rgba(59,130,246,0.2); }
        button.primary:hover { background: #2563eb; transform: translateY(-1px); }
        button.secondary { background: #f1f5f9; color: #1e293b; border: 1px solid #cbd5e1; }
        .btn-group { display: flex; gap: 12px; margin-top: 8px; }
        
        .image-card {
            background: #ffffff;
            border-radius: 24px;
            border: 1px solid #eef2f8;
            margin-bottom: 20px;
            padding: 16px;
        }
        .card-header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 14px;
            flex-wrap: wrap;
            gap: 10px;
        }
        .img-name { font-weight: 600; font-size: 0.9rem; background: #eef2ff; padding: 4px 12px; border-radius: 40px; }
        .action-buttons { display: flex; gap: 8px; }
        .single-process-btn, .single-save-btn {
            background: #eef2ff; color: #1e40af; padding: 6px 16px; border-radius: 30px; font-size: 0.75rem; width: auto;
            border: none; cursor: pointer;
        }
        .single-save-btn { background: #e0f2e9; color: #0e6b42; }
        .three-windows {
            display: flex;
            flex-wrap: wrap;
            gap: 16px;
            margin: 16px 0 8px;
            justify-content: space-between;
        }
        .window {
            flex: 1;
            min-width: 160px;
            background: #fbfdff;
            border-radius: 20px;
            border: 1px solid #eef2fa;
            overflow: hidden;
        }
        .window-title {
            font-size: 0.7rem;
            font-weight: 600;
            background: #f8fafc;
            padding: 8px 12px;
            border-bottom: 1px solid #eef2f6;
            text-align: center;
        }
        .window-content {
            display: flex;
            justify-content: center;
            align-items: center;
            background: #fefefe;
            min-height: 170px;
            padding: 12px;
        }
        .window-img {
            max-width: 100%;
            max-height: 170px;
            border-radius: 12px;
            object-fit: contain;
        }
        .stats-log-area {
            margin-top: 24px;
            background: #f8fafc;
            border-radius: 20px;
            padding: 16px;
        }
        .stats {
            display: flex;
            gap: 20px;
            margin-bottom: 12px;
            flex-wrap: wrap;
            align-items: center;
        }
        .stat-badge { background: white; padding: 6px 16px; border-radius: 40px; font-size: 0.8rem; font-weight: 500; }
        .save-all-btn { background: #0f766e; margin-left: auto; width: auto; padding: 6px 20px; font-size: 0.8rem; }
        .log-box {
            background: #0f172a;
            color: #cbd5e6;
            border-radius: 18px;
            padding: 12px;
            font-family: monospace;
            font-size: 0.7rem;
            height: 130px;
            overflow-y: auto;
        }
        .log-entry { border-bottom: 1px solid #2d3a4a; padding: 4px 0; }
        @media (max-width: 900px) {
            .control-panel { width: 100%; border-right: none; border-bottom: 1px solid #eef2f6; }
            .three-windows { flex-direction: column; }
            .save-all-btn { margin-left: 0; width: 100%; margin-top: 10px; }
        }
        .quality-score { font-size: 0.7rem; font-weight: 600; margin-top: 6px; }
        .score-good { color: #10b981; }
        .score-poor { color: #ef4444; }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;div class=&quot;app-container&quot;&gt;
    &lt;div class=&quot;header&quot;&gt;
        &lt;h1&gt;&amp;#x1F4F8; 人脸标准化工作台 · 质量评估+多引擎&lt;/h1&gt;
        &lt;p&gt;分辨率 | 姿态 | 光照 | 遮挡 综合评分 | 背景替换/人脸检测多方案可选&lt;/p&gt;
    &lt;/div&gt;
    &lt;div class=&quot;main-grid&quot;&gt;
        &lt;div class=&quot;control-panel&quot;&gt;
            &lt;div class=&quot;upload-area&quot; id=&quot;uploadTrigger&quot;&gt;
                &lt;div style=&quot;font-size: 28px;&quot;&gt;&amp;#x1F4E4;&lt;/div&gt;
                &lt;div&gt;上传图片 (JPG/PNG)&lt;/div&gt;
                &lt;input type=&quot;file&quot; id=&quot;fileInput&quot; multiple accept=&quot;image/jpeg,image/png,image/jpg&quot; class=&quot;file-input&quot;&gt;
            &lt;/div&gt;

            &lt;div class=&quot;param-group&quot;&gt;
                &lt;div class=&quot;param-title&quot;&gt;&amp;#x1F9E0; 人脸质量评估 (百分制)&lt;/div&gt;
                &lt;div class=&quot;option-row&quot;&gt;
                    &lt;label&gt;质量阈值 (低于此分数将拒绝处理)&lt;/label&gt;
                    &lt;input type=&quot;range&quot; id=&quot;qualityThreshold&quot; min=&quot;0&quot; max=&quot;100&quot; step=&quot;1&quot; value=&quot;45&quot;&gt;
                    &lt;div class=&quot;range-value&quot;&gt;&lt;span&gt;宽松&lt;/span&gt;&lt;span&gt;阈值: &lt;span id=&quot;qualityVal&quot;&gt;45&lt;/span&gt;分&lt;/span&gt;&lt;span&gt;严格&lt;/span&gt;&lt;/div&gt;
                &lt;/div&gt;
                &lt;div style=&quot;font-size:0.7rem; color:#6b7280;&quot;&gt;评估维度: 分辨率(&gt;80x80)、姿态(偏航&lt;35°,俯仰&lt;20°)、光照(亮度&amp;对比度)、清晰度(拉普拉斯方差)&lt;/div&gt;
            &lt;/div&gt;

            &lt;div class=&quot;param-group&quot;&gt;
                &lt;div class=&quot;param-title&quot;&gt;&amp;#x1F3A8; 背景替换引擎&lt;/div&gt;
                &lt;div class=&quot;option-row&quot;&gt;
                    &lt;label&gt;选择方法&lt;/label&gt;
                    &lt;select id=&quot;bgMethod&quot;&gt;
                        &lt;option value=&quot;mediapipe_general&quot;&gt;MediaPipe 自拍分割 (通用)&lt;/option&gt;
                        &lt;option value=&quot;mediapipe_landscape&quot;&gt;MediaPipe 自拍分割 (风景/全身)&lt;/option&gt;
                    &lt;/select&gt;
                &lt;/div&gt;
                &lt;div class=&quot;option-row&quot; id=&quot;bgThresholdRow&quot;&gt;
                    &lt;label&gt;掩码阈值 &lt;span id=&quot;thresholdVal&quot;&gt;0.5&lt;/span&gt;&lt;/label&gt;
                    &lt;input type=&quot;range&quot; id=&quot;maskThreshold&quot; min=&quot;0.1&quot; max=&quot;0.95&quot; step=&quot;0.01&quot; value=&quot;0.5&quot;&gt;
                &lt;/div&gt;
                &lt;div class=&quot;option-row&quot;&gt;
                    &lt;label&gt;背景颜色&lt;/label&gt;
                    &lt;select id=&quot;bgColorSelect&quot;&gt;
						&lt;option value=&quot;white&quot;&gt;⚪ 纯白&lt;/option&gt;
                        &lt;option value=&quot;blue&quot;&gt;&amp;#x1F535; 标准证件蓝&lt;/option&gt;                        
                    &lt;/select&gt;
                &lt;/div&gt;
            &lt;/div&gt;

            &lt;div class=&quot;param-group&quot;&gt;
                &lt;div class=&quot;param-title&quot;&gt;&amp;#x1F464; 人脸检测引擎&lt;/div&gt;
                &lt;div class=&quot;option-row&quot;&gt;
                    &lt;label&gt;选择方法&lt;/label&gt;
                    &lt;select id=&quot;faceDetectMethod&quot;&gt;
                        &lt;option value=&quot;facemesh&quot;&gt;MediaPipe FaceMesh (468点, 高精度)&lt;/option&gt;
                    &lt;/select&gt;
                &lt;/div&gt;
                &lt;div class=&quot;param-title&quot; style=&quot;margin-top: 12px;&quot;&gt;✂️ 裁剪扩展 (百分比)&lt;/div&gt;
                &lt;div class=&quot;crop-inputs&quot;&gt;
                    &lt;div&gt;&lt;span&gt;上 (%)&lt;/span&gt;&lt;input type=&quot;number&quot; id=&quot;cropTopPercent&quot; value=&quot;40&quot; step=&quot;1&quot; min=&quot;0&quot; max=&quot;100&quot;&gt;&lt;/div&gt;
                    &lt;div&gt;&lt;span&gt;下 (%)&lt;/span&gt;&lt;input type=&quot;number&quot; id=&quot;cropBottomPercent&quot; value=&quot;40&quot; step=&quot;1&quot; min=&quot;0&quot; max=&quot;100&quot;&gt;&lt;/div&gt;
                    &lt;div&gt;&lt;span&gt;左 (%)&lt;/span&gt;&lt;input type=&quot;number&quot; id=&quot;cropLeftPercent&quot; value=&quot;30&quot; step=&quot;1&quot; min=&quot;0&quot; max=&quot;100&quot;&gt;&lt;/div&gt;
                    &lt;div&gt;&lt;span&gt;右 (%)&lt;/span&gt;&lt;input type=&quot;number&quot; id=&quot;cropRightPercent&quot; value=&quot;30&quot; step=&quot;1&quot; min=&quot;0&quot; max=&quot;100&quot;&gt;&lt;/div&gt;
                &lt;/div&gt;
            &lt;/div&gt;

            &lt;div class=&quot;param-group&quot;&gt;
                &lt;div class=&quot;param-title&quot;&gt;&amp;#x1F4D0; 输出尺寸 (像素)&lt;/div&gt;
                &lt;div class=&quot;crop-inputs&quot;&gt;
                    &lt;div&gt;&lt;span&gt;宽度&lt;/span&gt;&lt;input type=&quot;number&quot; id=&quot;outputWidth&quot; value=&quot;320&quot; step=&quot;1&quot; min=&quot;1&quot; max=&quot;4096&quot;&gt;&lt;/div&gt;
                    &lt;div&gt;&lt;span&gt;高度&lt;/span&gt;&lt;input type=&quot;number&quot; id=&quot;outputHeight&quot; value=&quot;400&quot; step=&quot;1&quot; min=&quot;1&quot; max=&quot;4096&quot;&gt;&lt;/div&gt;
                &lt;/div&gt;
            &lt;/div&gt;

            &lt;div class=&quot;param-group&quot;&gt;
                &lt;button id=&quot;batchProcessBtn&quot; class=&quot;primary&quot;&gt;&amp;#x1F680; 批量处理全部&lt;/button&gt;
                &lt;div class=&quot;btn-group&quot;&gt;
                    &lt;button id=&quot;clearAllBtn&quot; class=&quot;secondary&quot;&gt;&amp;#x1F5D1; 清空所有&lt;/button&gt;
                &lt;/div&gt;
            &lt;/div&gt;
        &lt;/div&gt;

        &lt;div class=&quot;content-panel&quot;&gt;
            &lt;div id=&quot;imageGrid&quot; style=&quot;max-height: 580px; overflow-y: auto; padding-right: 6px;&quot;&gt;
                &lt;div style=&quot;text-align: center; padding: 60px; color: #94a3b8;&quot;&gt;⬅️ 上传图片，将显示原图 / 预裁剪 / 最终效果&lt;/div&gt;
            &lt;/div&gt;
            &lt;div class=&quot;stats-log-area&quot;&gt;
                &lt;div class=&quot;stats&quot;&gt;
                    &lt;div class=&quot;stat-badge&quot;&gt;✅ 成功: &lt;span id=&quot;successCount&quot;&gt;0&lt;/span&gt;&lt;/div&gt;
                    &lt;div class=&quot;stat-badge&quot;&gt;❌ 失败: &lt;span id=&quot;failCount&quot;&gt;0&lt;/span&gt;&lt;/div&gt;
                    &lt;div class=&quot;stat-badge&quot;&gt;&amp;#x1F4CB; 总计: &lt;span id=&quot;totalCount&quot;&gt;0&lt;/span&gt;&lt;/div&gt;
                    &lt;button id=&quot;saveAllToDirBtn&quot; class=&quot;save-all-btn&quot;&gt;&amp;#x1F4C1; 保存所有结果(JPEG)&lt;/button&gt;
                &lt;/div&gt;
                &lt;div class=&quot;log-box&quot; id=&quot;logContainer&quot;&gt;&lt;div class=&quot;log-entry&quot;&gt;✨ 初始化模型...&lt;/div&gt;&lt;/div&gt;
            &lt;/div&gt;
        &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;

&lt;script&gt;
    (function() {
        // ---------- 全局变量 ----------
        let selfieSegmentation = null;
        let faceMesh = null;
        let faceDetection = null;
        let modelsReady = { segmentation: false, face: false };
        
        // Paddle.js 模型
        let paddleFaceDetector = null;
        let paddleHumanSeg = null;
        let paddleModelsReady = { face: false, segmentation: false };
        
        let imageItems = [];
        let nextId = 1;
        let successTotal = 0, failTotal = 0;
        
        // DOM 元素
        const qualitySlider = document.getElementById('qualityThreshold');
        const qualitySpan = document.getElementById('qualityVal');
        const bgMethodSelect = document.getElementById('bgMethod');
        const bgThresholdRow = document.getElementById('bgThresholdRow');
        const maskThreshold = document.getElementById('maskThreshold');
        const thresholdSpan = document.getElementById('thresholdVal');
        const faceDetectMethod = document.getElementById('faceDetectMethod');
        const cropTopPercent = document.getElementById('cropTopPercent');
        const cropBottomPercent = document.getElementById('cropBottomPercent');
        const cropLeftPercent = document.getElementById('cropLeftPercent');
        const cropRightPercent = document.getElementById('cropRightPercent');
        const outputWidth = document.getElementById('outputWidth');
        const outputHeight = document.getElementById('outputHeight');
        const batchBtn = document.getElementById('batchProcessBtn');
        const clearBtn = document.getElementById('clearAllBtn');
        const saveAllBtn = document.getElementById('saveAllToDirBtn');
        const uploadTrigger = document.getElementById('uploadTrigger');
        const fileInput = document.getElementById('fileInput');
        
        // 辅助函数
        function addLog(msg, isError = false) {
            const logDiv = document.getElementById('logContainer');
            const entry = document.createElement('div');
            entry.className = 'log-entry';
            entry.style.color = isError ? '#f87171' : '#b9c7d9';
            entry.innerHTML = `[${new Date().toLocaleTimeString()}] ${msg}`;
            logDiv.appendChild(entry);
            entry.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
            while(logDiv.children.length &gt; 200) logDiv.removeChild(logDiv.firstChild);
        }
        
        function updateStatsUI() {
            document.getElementById('successCount').innerText = successTotal;
            document.getElementById('failCount').innerText = failTotal;
            document.getElementById('totalCount').innerText = imageItems.length;
        }
        
        // 质量评估函数 (分辨率、姿态、光照、清晰度)
        async function evaluateFaceQuality(imgElement, faceData, methodType) {
            const width = imgElement.width, height = imgElement.height;
            let score = 100;
            const details = [];
            
            // 1. 分辨率 (权重25)
            let resScore = 25;
            if (width &lt; 80 || height &lt; 80) resScore = 0;
            else if (width &lt; 120 || height &lt; 120) resScore = 15;
            else if (width &lt; 200 || height &lt; 200) resScore = 20;
            details.push(`分辨率: ${width}x${height} -&gt; ${resScore}/25`);
            score = score - 25 + resScore;
            
            // 2. 头部姿态 (权重30) 仅facemesh有足够关键点
            let poseScore = 30;
            if (methodType === 'facemesh' &amp;&amp; faceData.landmarks &amp;&amp; faceData.landmarks.length &gt;= 468) {
                const lm = faceData.landmarks;
                const leftEye = lm[33], rightEye = lm[263];
                const dx = rightEye.x - leftEye.x;
                const dy = rightEye.y - leftEye.y;
                let yaw = Math.atan2(dx, dy) * 180 / Math.PI;
                yaw = Math.abs(yaw);
                const noseTip = lm[4];
                const chin = lm[152];
                const pitch = Math.abs(Math.atan2(chin.y - noseTip.y, chin.x - noseTip.x) * 180 / Math.PI);
                if (yaw &gt; 35) poseScore -= 20;
                else if (yaw &gt; 25) poseScore -= 10;
                if (pitch &gt; 20) poseScore -= 15;
                else if (pitch &gt; 12) poseScore -= 8;
                details.push(`姿态: 偏航=${yaw.toFixed(1)}°,俯仰=${pitch.toFixed(1)}° -&gt; ${Math.max(0,poseScore)}/30`);
            } else {
                poseScore = 25;
                details.push(`姿态: 无法精确估算 -&gt; 25/30`);
            }
            score = score - 30 + Math.max(0, poseScore);
            
            // 3. 光照评估 (亮度&amp;对比度) 权重25
            const canvas = document.createElement('canvas');
            canvas.width = width; canvas.height = height;
            const ctx = canvas.getContext('2d');
            ctx.drawImage(imgElement, 0, 0);
            const imgData = ctx.getImageData(0, 0, width, height);
            let sum = 0, sumSq = 0;
            for (let i=0; i&lt;imgData.data.length; i+=4) {
                const brightness = (imgData.data[i] + imgData.data[i+1] + imgData.data[i+2]) / 3;
                sum += brightness;
                sumSq += brightness * brightness;
            }
            const mean = sum / (width*height);
            const variance = (sumSq / (width*height)) - mean*mean;
            let lightScore = 25;
            if (mean &lt; 30 || mean &gt; 230) lightScore -= 10;
            else if (mean &lt; 50 || mean &gt; 210) lightScore -= 5;
            if (variance &lt; 100) lightScore -= 10;
            else if (variance &lt; 300) lightScore -= 5;
            lightScore = Math.max(0, lightScore);
            details.push(`光照: 亮度${mean.toFixed(0)},对比度${Math.sqrt(variance).toFixed(0)} -&gt; ${lightScore}/25`);
            score = score - 25 + lightScore;
            
            // 4. 清晰度 (拉普拉斯方差) 权重20
            const grayCanvas = document.createElement('canvas');
            grayCanvas.width = width; grayCanvas.height = height;
            const gCtx = grayCanvas.getContext('2d');
            gCtx.drawImage(imgElement, 0, 0);
            const grayData = gCtx.getImageData(0,0,width,height);
            let lapSum = 0;
            for (let y=1; y&lt;height-1; y++) {
                for (let x=1; x&lt;width-1; x++) {
                    const idx = (y*width + x)*4;
                    const val = grayData.data[idx];
                    const laplacian = Math.abs(4*val - 
                        (grayData.data[idx - 4] + grayData.data[idx + 4] + grayData.data[idx - width*4] + grayData.data[idx + width*4]));
                    lapSum += laplacian;
                }
            }
            const lapVar = lapSum / ((width-2)*(height-2));
            let blurScore = 20;
            if (lapVar &lt; 30) blurScore = 0;
            else if (lapVar &lt; 50) blurScore = 8;
            else if (lapVar &lt; 100) blurScore = 14;
            details.push(`清晰度(拉普拉斯): ${lapVar.toFixed(0)} -&gt; ${blurScore}/20`);
            score = score - 20 + blurScore;
            
            score = Math.min(100, Math.max(0, Math.round(score)));
            return { score, details: details.join('; ') };
        }
        
        // 加载 Paddle.js 人脸检测模型
        async function loadPaddleFaceDetect() {
            if (paddleFaceDetector) return paddleFaceDetector;
            try {
                addLog(&quot;加载 Paddle.js FaceDetect 模型...&quot;);
                // 通过 script 标签加载
                return new Promise((resolve, reject) =&gt; {
                    const script = document.createElement('script');
                    script.src = './models/paddlejs/facedetect/lib/index.js';
                    let timeoutId = setTimeout(() =&gt; {
                        reject(new Error('加载超时 (30秒)'));
                    }, 30000);
                    
                    script.onload = async () =&gt; {
                        clearTimeout(timeoutId);
                        try {
                            // 调试：查看全局变量
                            console.log('Paddle.js facedetect 脚本加载完成，检查全局变量...');
                            console.log('window.paddlejs:', window.paddlejs);
                            console.log('window.paddlejs?.facedetect:', window.paddlejs?.facedetect);
                            console.log('window.FaceDetector:', window.FaceDetector);
                            // 模块可能全局暴露为 paddlejs.facedetect 或 facedetect
                            let FaceDetectorClass;
                            if (window.paddlejs &amp;&amp; window.paddlejs.facedetect &amp;&amp; window.paddlejs.facedetect.FaceDetector) {
                                FaceDetectorClass = window.paddlejs.facedetect.FaceDetector;
                                console.log('从 window.paddlejs.facedetect.FaceDetector 获取类');
                            } else if (window.FaceDetector) {
                                FaceDetectorClass = window.FaceDetector;
                                console.log('从 window.FaceDetector 获取类');
                            } else {
                                // 尝试查找其他可能的导出
                                console.log('搜索包含 paddle 的全局变量...');
                                for (let key in window) {
                                    if (key.toLowerCase().includes('paddle') &amp;&amp; window[key] &amp;&amp; window[key].FaceDetector) {
                                        console.log(`找到 FaceDetector 类在全局变量 ${key}`);
                                        FaceDetectorClass = window[key].FaceDetector;
                                        break;
                                    }
                                }
                            }
                            if (!FaceDetectorClass) {
                                console.error('未找到 FaceDetector 类，所有全局变量:', Object.keys(window).filter(k =&gt; k.toLowerCase().includes('paddle')));
                                throw new Error('未找到 FaceDetector 类，请检查 Paddle.js facedetect 模块');
                            }
                            console.log('创建 FaceDetector 实例...');
                            paddleFaceDetector = new FaceDetectorClass();
                            console.log('调用 init() 方法...');
                            await paddleFaceDetector.init();
                            paddleModelsReady.face = true;
                            addLog(&quot;✅ Paddle.js FaceDetect 就绪&quot;);
                            resolve(paddleFaceDetector);
                        } catch (error) {
                            console.error('FaceDetect 加载过程中出错:', error);
                            reject(error);
                        }
                    };
                    script.onerror = (error) =&gt; {
                        clearTimeout(timeoutId);
                        console.error('FaceDetect 脚本加载失败:', error);
                        reject(new Error(`脚本加载失败: ${error}`));
                    };
                    document.head.appendChild(script);
                });
            } catch (error) {
                addLog(`❌ Paddle.js FaceDetect 加载失败: ${error.message}`, true);
                throw error;
            }
        }
        
        // 人脸检测 (多引擎)
        async function detectFaceWithMethod(imgElement, method) {
            if (method === 'paddle_facedetect') {
                try {
                    const detector = await loadPaddleFaceDetect();
                    const res = await detector.detect(imgElement, { shrink: 0.4, threshold: 0.6 });
                    if (res &amp;&amp; res.length &gt; 0) {
                        const face = res[0]; // 取第一个检测到的人脸
                        const bbox = {
                            xMin: face.left,
                            yMin: face.top,
                            xMax: face.left + face.width,
                            yMax: face.top + face.height,
                            width: face.width,
                            height: face.height
                        };
                        return { bbox, landmarks: null, method: 'paddle_facedetect' };
                    }
                    return null;
                } catch (error) {
                    addLog(`Paddle.js 人脸检测失败: ${error.message}`, true);
                    return null;
                }
            }
            if (method === 'facemesh') {
                if (!faceMesh) throw new Error(&quot;FaceMesh未就绪&quot;);
                return new Promise((resolve) =&gt; {
                    faceMesh.onResults((results) =&gt; {
                        if (results.multiFaceLandmarks &amp;&amp; results.multiFaceLandmarks.length &gt; 0) {
                            const landmarks = results.multiFaceLandmarks[0];
                            let minX=Infinity, minY=Infinity, maxX=-Infinity, maxY=-Infinity;
                            landmarks.forEach(lm =&gt; {
                                const x = lm.x * imgElement.width;
                                const y = lm.y * imgElement.height;
                                minX = Math.min(minX, x); minY = Math.min(minY, y);
                                maxX = Math.max(maxX, x); maxY = Math.max(maxY, y);
                            });
                            const bbox = { xMin: minX, yMin: minY, xMax: maxX, yMax: maxY, width: maxX-minX, height: maxY-minY };
                            resolve({ bbox, landmarks, method: 'facemesh' });
                        } else resolve(null);
                    });
                    faceMesh.send({ image: imgElement }).catch(() =&gt; resolve(null));
                });
            } else {
                if (!faceDetection) throw new Error(&quot;FaceDetection未就绪&quot;);
                return new Promise((resolve) =&gt; {
                    faceDetection.onResults((results) =&gt; {
                        if (results.detections &amp;&amp; results.detections.length &gt; 0) {
                            const det = results.detections[0];
                            const bbox = det.boundingBox;
                            bbox.width = bbox.width; bbox.height = bbox.height;
                            resolve({ bbox, landmarks: null, method: 'facedetection' });
                        } else resolve(null);
                    });
                    faceDetection.send({ image: imgElement }).catch(() =&gt; resolve(null));
                });
            }
        }
        
        // 加载 Paddle.js HumanSeg 模型
        async function loadPaddleHumanSeg() {
            if (paddleHumanSeg) return paddleHumanSeg;
            try {
                addLog(&quot;加载 Paddle.js HumanSeg 模型...&quot;);
                // 通过 script 标签加载
                return new Promise((resolve, reject) =&gt; {
                    // 检查是否已经存在相同 src 的脚本
                    const existingScript = document.querySelector(`script[src=&quot;./models/paddlejs/humanseg/lib/index.js&quot;]`);
                    if (existingScript) {
                        addLog(&quot;HumanSeg 脚本已存在，等待加载完成...&quot;);
                        // 如果脚本已经存在，等待它加载完成
                        const checkInterval = setInterval(() =&gt; {
                            if (paddleHumanSeg) {
                                clearInterval(checkInterval);
                                resolve(paddleHumanSeg);
                            }
                        }, 500);
                        setTimeout(() =&gt; {
                            clearInterval(checkInterval);
                            if (!paddleHumanSeg) {
                                reject(new Error('HumanSeg 脚本已存在但未完成加载'));
                            }
                        }, 30000);
                        return;
                    }
                    
                    const script = document.createElement('script');
                    script.src = './models/paddlejs/humanseg/lib/index.js';
                    let timeoutId = setTimeout(() =&gt; {
                        reject(new Error('加载超时 (30秒)'));
                    }, 30000);
                    
                    script.onload = async () =&gt; {
                        clearTimeout(timeoutId);
                        try {
                            // 调试：查看全局变量
                            console.log('Paddle.js humanseg 脚本加载完成，检查全局变量...');
                            console.log('window.humanseg:', window.humanseg);
                            console.log('window.paddlejs:', window.paddlejs);
                            console.log('window.paddlejs?.humanseg:', window.paddlejs?.humanseg);
                            // 模块可能全局暴露为 humanseg 或 paddlejs.humanseg
                            let humansegModule = window.humanseg || window.paddlejs?.humanseg;
                            if (!humansegModule) {
                                // 尝试从默认导出中获取
                                humansegModule = window.humanseg?.default || window.paddlejs?.humanseg?.default;
                            }
                            if (!humansegModule) {
                                // 尝试查找其他可能的导出
                                console.log('搜索包含 humanseg 或 paddle 的全局变量...');
                                for (let key in window) {
                                    if (key.toLowerCase().includes('humanseg') || key.toLowerCase().includes('paddle')) {
                                        console.log(`检查全局变量 ${key}:`, window[key]);
                                        if (window[key] &amp;&amp; typeof window[key].load === 'function') {
                                            humansegModule = window[key];
                                            console.log(`找到匹配的模块: ${key}`);
                                            break;
                                        }
                                    }
                                }
                            }
                            if (!humansegModule) {
                                console.error('未找到 humanseg 模块，所有全局变量:', Object.keys(window).filter(k =&gt; k.toLowerCase().includes('humanseg') || k.toLowerCase().includes('paddle')));
                                throw new Error('未找到 humanseg 模块，请检查 Paddle.js humanseg 模块');
                            }
                            console.log('找到 humanseg 模块，调用 load()...', humansegModule);
                            await humansegModule.load();
                            paddleHumanSeg = humansegModule;
                            paddleModelsReady.segmentation = true;
                            addLog(&quot;✅ Paddle.js HumanSeg 就绪&quot;);
                            resolve(paddleHumanSeg);
                        } catch (error) {
                            console.error('HumanSeg 加载过程中出错:', error);
                            reject(error);
                        }
                    };
                    script.onerror = (error) =&gt; {
                        clearTimeout(timeoutId);
                        console.error('HumanSeg 脚本加载失败:', error);
                        reject(new Error(`脚本加载失败: ${error}`));
                    };
                    document.head.appendChild(script);
                    console.log('已添加 HumanSeg 脚本标签');
                });
            } catch (error) {
                console.error('loadPaddleHumanSeg 函数出错:', error);
                addLog(`❌ Paddle.js HumanSeg 加载失败: ${error.message}`, true);
                throw error;
            }
        }
        
        // 背景替换 (多引擎)
        async function replaceBackgroundWithMethod(imgElement, method, bgColorType, threshold) {
            addLog(`背景替换: 方法=${method}, 颜色=${bgColorType}, 阈值=${threshold}, selfieSegmentation=${!!selfieSegmentation}`);
            if (method === 'paddle_humanseg') {
                try {
                    const humanseg = await loadPaddleHumanSeg();
                    // 获取灰度值
                    const { data } = await humanseg.getGrayValue(imgElement);
                    // 创建画布
                    const canvas = document.createElement('canvas');
                    canvas.width = imgElement.width;
                    canvas.height = imgElement.height;
                    const ctx = canvas.getContext('2d');
                    // 先绘制原图
                    ctx.drawImage(imgElement, 0, 0);
                    // 创建背景画布
                    const bgCanvas = document.createElement('canvas');
                    bgCanvas.width = imgElement.width;
                    bgCanvas.height = imgElement.height;
                    const bgCtx = bgCanvas.getContext('2d');
                    // 设置背景颜色
                    const bgRGB = bgColorType === 'blue' ? [0, 98, 204] : [255, 255, 255];
                    bgCtx.fillStyle = `rgb(${bgRGB[0]}, ${bgRGB[1]}, ${bgRGB[2]})`;
                    bgCtx.fillRect(0, 0, bgCanvas.width, bgCanvas.height);
                    // 绘制人像分割结果
                    humanseg.drawHumanSeg(data, canvas, bgCanvas);
                    return canvas;
                } catch (error) {
                    addLog(`Paddle.js 背景替换失败: ${error.message}`, true);
                    throw error;
                }
            }
            if (method === 'none') {
                const canvas = document.createElement('canvas');
                canvas.width = imgElement.width;
                canvas.height = imgElement.height;
                const ctx = canvas.getContext('2d');
                ctx.drawImage(imgElement, 0, 0);
                return canvas;
            }
            if (!selfieSegmentation) throw new Error(&quot;分割模型未就绪&quot;);
            const modelSelection = method === 'mediapipe_general' ? 0 : 1;
            selfieSegmentation.setOptions({ modelSelection, selfieMode: false });
            const bgRGB = bgColorType === 'blue' ? [0, 98, 204] : [255, 255, 255];
            const canvas = document.createElement('canvas');
            const ctx = canvas.getContext('2d');
            canvas.width = imgElement.width;
            canvas.height = imgElement.height;
            ctx.drawImage(imgElement, 0, 0);
            return new Promise((resolve, reject) =&gt; {
                selfieSegmentation.onResults((results) =&gt; {
                    if (!results.segmentationMask) reject(new Error(&quot;无分割掩码&quot;));
                    const maskCanvas = document.createElement('canvas');
                    maskCanvas.width = canvas.width;
                    maskCanvas.height = canvas.height;
                    const maskCtx = maskCanvas.getContext('2d');
                    maskCtx.drawImage(results.segmentationMask, 0, 0, canvas.width, canvas.height);
                    const maskData = maskCtx.getImageData(0, 0, canvas.width, canvas.height);
                    const imgData = ctx.getImageData(0, 0, canvas.width, canvas.height);
                    for (let i=0; i&lt;maskData.data.length; i+=4) {
                        const conf = maskData.data[i] / 255;
                        if (conf &lt;= threshold) {
                            imgData.data[i] = bgRGB[0];
                            imgData.data[i+1] = bgRGB[1];
                            imgData.data[i+2] = bgRGB[2];
                        }
                    }
                    ctx.putImageData(imgData, 0, 0);
                    resolve(canvas);
                });
                selfieSegmentation.send({ image: imgElement }).catch(reject);
                setTimeout(() =&gt; reject(new Error(&quot;分割超时&quot;)), 8000);
            });
        }
        
        // 裁剪
        function cropWithPercent(canvas, bbox, percentTop, percentBottom, percentLeft, percentRight) {
            const faceW = bbox.width;
            const faceH = bbox.height;
            const expandTop = faceH * (percentTop / 100);
            const expandBottom = faceH * (percentBottom / 100);
            const expandLeft = faceW * (percentLeft / 100);
            const expandRight = faceW * (percentRight / 100);
            let cropX = Math.max(0, bbox.xMin - expandLeft);
            let cropY = Math.max(0, bbox.yMin - expandTop);
            let cropW = Math.min(canvas.width - cropX, (bbox.width) + expandLeft + expandRight);
            let cropH = Math.min(canvas.height - cropY, (bbox.height) + expandTop + expandBottom);
            if (cropW &lt;= 0 || cropH &lt;= 0) throw new Error(&quot;裁剪区域无效&quot;);
            // 检查裁剪框面积是否超过原始图片的80%
            const cropArea = cropW * cropH;
            const originalArea = canvas.width * canvas.height;
            const cropRatio = cropArea / originalArea;
            if (cropRatio &gt;= 0.8) {
                // 不裁剪，返回原始图片
                const outCanvas = document.createElement('canvas');
                outCanvas.width = canvas.width;
                outCanvas.height = canvas.height;
                const ctx = outCanvas.getContext('2d');
                ctx.drawImage(canvas, 0, 0);
                return outCanvas;
            }
            const outCanvas = document.createElement('canvas');
            outCanvas.width = cropW;
            outCanvas.height = cropH;
            const ctx = outCanvas.getContext('2d');
            ctx.drawImage(canvas, cropX, cropY, cropW, cropH, 0, 0, cropW, cropH);
            return outCanvas;
        }

        // 调整输出尺寸，保持原始比例
        function resizeCanvas(canvas, targetWidth, targetHeight, bgColorType = 'white') {
            if (targetWidth &lt;= 0 || targetHeight &lt;= 0) return canvas;
            
            // 获取背景颜色的RGB值
            const bgRGB = bgColorType === 'blue' ? [0, 98, 204] : [255, 255, 255];
            
            // 计算源图像和目标矩形的宽高比
            const srcRatio = canvas.width / canvas.height;
            const dstRatio = targetWidth / targetHeight;
            
            let drawWidth, drawHeight, offsetX, offsetY;
            
            if (srcRatio &gt; dstRatio) {
                // 源图像更宽，以宽度为基准
                drawWidth = targetWidth;
                drawHeight = targetWidth / srcRatio;
                offsetX = 0;
                offsetY = (targetHeight - drawHeight) / 2;
            } else {
                // 源图像更高，以高度为基准
                drawHeight = targetHeight;
                drawWidth = targetHeight * srcRatio;
                offsetX = (targetWidth - drawWidth) / 2;
                offsetY = 0;
            }
            
            // 确保尺寸和位置为整数，避免抗锯齿问题
            drawWidth = Math.round(drawWidth);
            drawHeight = Math.round(drawHeight);
            offsetX = Math.round(offsetX);
            offsetY = Math.round(offsetY);
            
            // 确保最小尺寸
            if (drawWidth &lt; 1) drawWidth = 1;
            if (drawHeight &lt; 1) drawHeight = 1;
            
            const outCanvas = document.createElement('canvas');
            outCanvas.width = targetWidth;
            outCanvas.height = targetHeight;
            const ctx = outCanvas.getContext('2d');
            
            // 用背景颜色填充整个画布
            ctx.fillStyle = `rgb(${bgRGB[0]}, ${bgRGB[1]}, ${bgRGB[2]})`;
            ctx.fillRect(0, 0, targetWidth, targetHeight);
            
            // 将源图像绘制到居中位置，保持原始比例
            if (drawWidth &gt; 0 &amp;&amp; drawHeight &gt; 0) {
                ctx.drawImage(canvas, 0, 0, canvas.width, canvas.height, offsetX, offsetY, drawWidth, drawHeight);
            }
            return outCanvas;
        }
        
        // 生成预裁剪预览
        async function generatePreCropCanvas(item) {
            if (!item.originalImgElement) return null;
            const faceMethod = faceDetectMethod.value;
            // 检查人脸检测模型就绪状态
            // 对于 MediaPipe，需要模型已加载
            // 对于 Paddle.js，detectFaceWithMethod 会处理懒加载
            if (faceMethod === 'facemesh' || faceMethod === 'facedetection') {
                if (!modelsReady.face) return null;
            }
            // 对于 Paddle.js，不在这里检查，让 detectFaceWithMethod 处理
            const img = item.originalImgElement;
            const faceData = await detectFaceWithMethod(img, faceMethod);
            if (!faceData) return null;
            const { bbox } = faceData;
            const pTop = parseFloat(cropTopPercent.value) || 0;
            const pBottom = parseFloat(cropBottomPercent.value) || 0;
            const pLeft = parseFloat(cropLeftPercent.value) || 0;
            const pRight = parseFloat(cropRightPercent.value) || 0;
            const faceW = bbox.width, faceH = bbox.height;
            const expandTop = faceH * (pTop/100), expandBottom = faceH * (pBottom/100);
            const expandLeft = faceW * (pLeft/100), expandRight = faceW * (pRight/100);
            let cropX = Math.max(0, bbox.xMin - expandLeft), cropY = Math.max(0, bbox.yMin - expandTop);
            let cropW = Math.min(img.width - cropX, faceW + expandLeft + expandRight);
            let cropH = Math.min(img.height - cropY, faceH + expandTop + expandBottom);
            const canvas = document.createElement('canvas');
            canvas.width = img.width; canvas.height = img.height;
            const ctx = canvas.getContext('2d');
            ctx.drawImage(img, 0, 0);
            ctx.strokeStyle = '#10b981'; ctx.lineWidth = 2;
            ctx.strokeRect(bbox.xMin, bbox.yMin, bbox.width, bbox.height);
            if (faceData.landmarks) {
                const indices = [133, 362, 1, 61, 291, 152];
                indices.forEach(idx =&gt; {
                    const lm = faceData.landmarks[idx];
                    if (lm) {
                        const x = lm.x * img.width, y = lm.y * img.height;
                        ctx.fillStyle = '#ef4444';
                        ctx.beginPath(); ctx.arc(x, y, 4, 0, 2*Math.PI); ctx.fill();
                    }
                });
            }
            ctx.strokeStyle = '#ff0000'; ctx.setLineDash([8,6]); ctx.lineWidth = 2.5;
            ctx.strokeRect(cropX, cropY, cropW, cropH);
            ctx.setLineDash([]);
            return canvas;
        }
        
        // 处理单张图片
        async function processOneItem(item) {
            const faceMethod = faceDetectMethod.value;
            const bgMethod = bgMethodSelect.value;
            // 调试日志
            addLog(`处理开始: 人脸方法=${faceMethod}, 背景方法=${bgMethod}, MediaPipe分割就绪=${modelsReady.segmentation}, MediaPipe人脸就绪=${modelsReady.face}, Paddle分割就绪=${paddleModelsReady.segmentation}, Paddle人脸就绪=${paddleModelsReady.face}`);
            // 检查模型就绪状态
            let segmentationReady = false;
            let faceReady = false;
            
            if (bgMethod.startsWith('mediapipe')) {
                segmentationReady = modelsReady.segmentation;
            } else if (bgMethod === 'paddle_humanseg') {
                // Paddle.js HumanSeg 懒加载
                if (!paddleModelsReady.segmentation) {
                    try {
                        await loadPaddleHumanSeg();
                        segmentationReady = true;
                    } catch (error) {
                        addLog(`❌ Paddle.js HumanSeg 加载失败: ${error.message}`, true);
                        return;
                    }
                } else {
                    segmentationReady = true;
                }
            } else if (bgMethod === 'none') {
                segmentationReady = true; // 不需要分割模型
            }
            
            if (faceMethod === 'facemesh' || faceMethod === 'facedetection') {
                faceReady = modelsReady.face;
            } else if (faceMethod === 'paddle_facedetect') {
                // Paddle.js FaceDetect 懒加载
                if (!paddleModelsReady.face) {
                    addLog(&quot;正在加载 Paddle.js FaceDetect 模型...&quot;);
                    try {
                        await loadPaddleFaceDetect();
                        faceReady = true;
                    } catch (error) {
                        addLog(`Paddle.js FaceDetect 加载失败: ${error.message}`, true);
                        return;
                    }
                } else {
                    faceReady = true;
                }
            }
            
            if (!segmentationReady || !faceReady) { 
                addLog(`模型未就绪 (分割:${segmentationReady}, 人脸:${faceReady})，请等待模型加载完成`, true); 
                return; 
            }
            addLog(`✅ 模型检查通过 (分割:${segmentationReady}, 人脸:${faceReady})，开始处理图片`);
            if (item.status === '处理中') return;
            item.status = '处理中';
            updateStatusLabel(item.id, '处理中...');
            addLog(`开始处理: ${item.file.name}`);
            try {
                const img = item.originalImgElement;
                const faceData = await detectFaceWithMethod(img, faceMethod);
                if (!faceData) throw new Error(&quot;未检测到人脸&quot;);
                const quality = await evaluateFaceQuality(img, faceData, faceMethod);
                item.qualityScore = quality.score;
                if (quality.score &lt; parseInt(qualitySlider.value)) {
                    throw new Error(`质量评估不通过 (${quality.score}分 &lt; ${qualitySlider.value}分): ${quality.details}`);
                }
                addLog(`质量评分: ${quality.score}分 - ${quality.details}`);
                const bgColor = document.getElementById('bgColorSelect').value;
                const thresh = parseFloat(maskThreshold.value);
                let bgCanvas;
                if (bgMethod === 'none') {
                    bgCanvas = document.createElement('canvas');
                    bgCanvas.width = img.width; bgCanvas.height = img.height;
                    bgCanvas.getContext('2d').drawImage(img, 0, 0);
                } else {
                    bgCanvas = await replaceBackgroundWithMethod(img, bgMethod, bgColor, thresh);
                }
                const pTop = parseFloat(cropTopPercent.value);
                const pBottom = parseFloat(cropBottomPercent.value);
                const pLeft = parseFloat(cropLeftPercent.value);
                const pRight = parseFloat(cropRightPercent.value);
                let finalCanvas = cropWithPercent(bgCanvas, faceData.bbox, pTop, pBottom, pLeft, pRight);
                // 调整输出尺寸
                const targetWidth = parseInt(outputWidth.value) || 0;
                const targetHeight = parseInt(outputHeight.value) || 0;
                if (targetWidth &gt; 0 &amp;&amp; targetHeight &gt; 0) {
                    finalCanvas = resizeCanvas(finalCanvas, targetWidth, targetHeight, bgColor);
                }
                const finalUrl = finalCanvas.toDataURL('image/jpeg', 0.92);
                item.processedFinalUrl = finalUrl;
                item.processedBlob = await (await fetch(finalUrl)).blob();
                item.status = '成功';
                successTotal++;
                updateStatusLabel(item.id, `成功 (质量${quality.score})`);
                updateWindowPreview(item.id, finalUrl);
                addLog(`✅ 处理成功: ${item.file.name} (JPEG)`);
            } catch (err) {
                item.status = '失败';
                failTotal++;
                updateStatusLabel(item.id, `失败: ${err.message.slice(0, 60)}`);
                addLog(`❌ 处理失败: ${item.file.name} - ${err.message}`, true);
            } finally {
                updateStatsUI();
                renderAllCards();
            }
        }
        
        function updateStatusLabel(id, text) {
            const span = document.getElementById(`statusLabel-${id}`);
            if (span) span.innerText = `状态: ${text}`;
        }
        function updateWindowPreview(itemId, finalUrl) {
            const card = document.querySelector(`.image-card[data-id='${itemId}']`);
            if (card) {
                const finalImg = card.querySelector('.window-final-img');
                if (finalImg) finalImg.src = finalUrl;
            }
        }
        
        async function refreshAllPreCropPreviews() {
            const faceMethod = faceDetectMethod.value;
            // 检查人脸检测模型就绪状态
            // 对于 MediaPipe，需要模型已加载
            // 对于 Paddle.js，generatePreCropCanvas 会通过 detectFaceWithMethod 处理懒加载
            if (faceMethod === 'facemesh' || faceMethod === 'facedetection') {
                if (!modelsReady.face) return;
            }
            // 对于 Paddle.js，不在这里检查
            for (let item of imageItems) {
                if (item.originalImgElement) {
                    const preCanvas = await generatePreCropCanvas(item);
                    if (preCanvas) {
                        item.preCropUrl = preCanvas.toDataURL();
                        const preImg = document.querySelector(`.image-card[data-id='${item.id}'] .window-pre-img`);
                        if (preImg) preImg.src = item.preCropUrl;
                    }
                }
            }
        }
        
        function renderAllCards() {
            const grid = document.getElementById('imageGrid');
            if (imageItems.length === 0) { grid.innerHTML = '&lt;div style=&quot;text-align: center; padding: 60px; color: #94a3b8;&quot;&gt;上传图片开始处理&lt;/div&gt;'; return; }
            grid.innerHTML = '';
            for (let item of imageItems) {
                const card = document.createElement('div');
                card.className = 'image-card';
                card.setAttribute('data-id', item.id);
                const qualityHtml = item.qualityScore ? `&lt;div class=&quot;quality-score ${item.qualityScore&gt;=60?'score-good':'score-poor'}&quot;&gt;质量评分: ${item.qualityScore}/100&lt;/div&gt;` : '';
                card.innerHTML = `
                    &lt;div class=&quot;card-header&quot;&gt;
                        &lt;span class=&quot;img-name&quot;&gt;&amp;#x1F4F7; ${escapeHtml(item.file.name)}&lt;/span&gt;
                        &lt;div class=&quot;action-buttons&quot;&gt;
                            &lt;button class=&quot;single-process-btn&quot; data-id=&quot;${item.id}&quot;&gt;✨ 处理&lt;/button&gt;
                            &lt;button class=&quot;single-save-btn&quot; data-id=&quot;${item.id}&quot;&gt;&amp;#x1F4BE; 保存&lt;/button&gt;
                        &lt;/div&gt;
                    &lt;/div&gt;
                    &lt;div class=&quot;three-windows&quot;&gt;
                        &lt;div class=&quot;window&quot;&gt;&lt;div class=&quot;window-title&quot;&gt;原图&lt;/div&gt;&lt;div class=&quot;window-content&quot;&gt;&lt;img class=&quot;window-img&quot; src=&quot;${item.originalUrl}&quot;&gt;&lt;/div&gt;&lt;/div&gt;
                        &lt;div class=&quot;window&quot;&gt;&lt;div class=&quot;window-title&quot;&gt;预裁剪(框+关键点)&lt;/div&gt;&lt;div class=&quot;window-content&quot;&gt;${item.preCropUrl ? `&lt;img class=&quot;window-img window-pre-img&quot; src=&quot;${item.preCropUrl}&quot;&gt;` : '&lt;div class=&quot;placeholder-text&quot;&gt;等待预览&lt;/div&gt;'}&lt;/div&gt;&lt;/div&gt;
                        &lt;div class=&quot;window&quot;&gt;&lt;div class=&quot;window-title&quot;&gt;最终效果(JPEG)&lt;/div&gt;&lt;div class=&quot;window-content&quot;&gt;${item.processedFinalUrl ? `&lt;img class=&quot;window-img window-final-img&quot; src=&quot;${item.processedFinalUrl}&quot;&gt;` : '&lt;div class=&quot;placeholder-text&quot;&gt;未处理&lt;/div&gt;'}&lt;/div&gt;&lt;/div&gt;
                    &lt;/div&gt;
                    &lt;div style=&quot;font-size:0.7rem; margin-top: 8px;&quot; id=&quot;statusLabel-${item.id}&quot;&gt;状态: ${item.status || '待处理'} ${qualityHtml}&lt;/div&gt;
                `;
                grid.appendChild(card);
            }
            document.querySelectorAll('.single-process-btn').forEach(btn =&gt; {
                btn.addEventListener('click', (e) =&gt; {
                    const id = parseInt(btn.dataset.id);
                    const target = imageItems.find(i =&gt; i.id === id);
                    if (target) processOneItem(target);
                });
            });
            document.querySelectorAll('.single-save-btn').forEach(btn =&gt; {
                btn.addEventListener('click', async (e) =&gt; {
                    const id = parseInt(btn.dataset.id);
                    const target = imageItems.find(i =&gt; i.id === id);
                    if (target &amp;&amp; target.processedFinalUrl) await saveSingleImage(target);
                    else addLog(&quot;请先处理图片&quot;, true);
                });
            });
        }
        
        async function saveSingleImage(item) {
            const blob = item.processedBlob || await (await fetch(item.processedFinalUrl)).blob();
            const fileName = item.file.name.replace(/\.[^/.]+$/, '') + '_standard.jpg';
            if ('showDirectoryPicker' in window) {
                try {
                    const dirHandle = await window.showDirectoryPicker();
                    const fileHandle = await dirHandle.getFileHandle(fileName, { create: true });
                    const writable = await fileHandle.createWritable();
                    await writable.write(blob);
                    await writable.close();
                    addLog(`✅ 已保存: ${fileName}`);
                    return;
                } catch(e) { if(e.name!=='AbortError') addLog(`保存失败: ${e.message}`, true); }
            }
            const link = document.createElement('a');
            link.href = item.processedFinalUrl;
            link.download = fileName;
            link.click();
            addLog(`⬇️ 下载: ${fileName}`);
        }
        
        async function saveAllToDirectory() {
            const successItems = imageItems.filter(i =&gt; i.status === '成功' &amp;&amp; i.processedFinalUrl);
            if (!successItems.length) { addLog(&quot;无成功结果&quot;, true); return; }
            if (!('showDirectoryPicker' in window)) {
                for(let i of successItems) await saveSingleImage(i);
                return;
            }
            try {
                const dir = await window.showDirectoryPicker();
                for(let item of successItems) {
                    const blob = item.processedBlob || await (await fetch(item.processedFinalUrl)).blob();
                    const fileName = item.file.name.replace(/\.[^/.]+$/, '') + '_standard.jpg';
                    const fh = await dir.getFileHandle(fileName, { create: true });
                    const w = await fh.createWritable();
                    await w.write(blob);
                    await w.close();
                    addLog(`&amp;#x1F4C1; 保存: ${fileName}`);
                }
                addLog(`&amp;#x1F389; 已保存 ${successItems.length} 张`);
            } catch(e) { if(e.name!=='AbortError') addLog(`批量失败: ${e.message}`, true); }
        }
        
        async function batchProcess() {
            const faceMethod = faceDetectMethod.value;
            const bgMethod = bgMethodSelect.value;
            let segmentationReady = false;
            let faceReady = false;
            
            // 对于 MediaPipe 模型，检查是否已加载
            // 对于 Paddle.js 模型，processOneItem 会处理懒加载
            if (bgMethod.startsWith('mediapipe')) {
                segmentationReady = modelsReady.segmentation;
                if (!segmentationReady) {
                    addLog(&quot;MediaPipe 分割模型未加载，请刷新页面重试&quot;, true);
                    return;
                }
            } else if (bgMethod === 'paddle_humanseg') {
                // Paddle.js HumanSeg 会在 processOneItem 中懒加载
                segmentationReady = true;
            } else if (bgMethod === 'none') {
                segmentationReady = true;
            }
            
            if (faceMethod === 'facemesh' || faceMethod === 'facedetection') {
                faceReady = modelsReady.face;
                if (!faceReady) {
                    addLog(&quot;MediaPipe 人脸检测模型未加载，请刷新页面重试&quot;, true);
                    return;
                }
            } else if (faceMethod === 'paddle_facedetect') {
                // Paddle.js FaceDetect 会在 processOneItem 中懒加载
                faceReady = true;
            }
            
            if (!segmentationReady || !faceReady) { addLog(&quot;模型未完全加载&quot;, true); return; }
            if (imageItems.length === 0) { addLog(&quot;无图片&quot;, true); return; }
            successTotal = 0; failTotal = 0;
            for(let item of imageItems) { if(item.status !== '成功') { item.processedFinalUrl = null; item.status = '待处理'; } }
            updateStatsUI(); renderAllCards();
            addLog(`开始批量处理 ${imageItems.length} 张`);
            for(let item of imageItems) { await processOneItem(item); await new Promise(r=&gt;setTimeout(r,200)); }
            addLog(&quot;批量完成&quot;);
        }
        
        function escapeHtml(str) { return str.replace(/[&amp;&lt;&gt;]/g, m=&gt; m==='&amp;'?'&amp;amp;': m==='&lt;'?'&amp;lt;':'&amp;gt;'); }
        
        async function initModels() {
            addLog(&quot;加载模型: SelfieSegmentation, FaceMesh, FaceDetection&quot;);
            try {
                selfieSegmentation = new SelfieSegmentation({ locateFile: f=&gt;`https://cdn.jsdelivr.net/npm/@mediapipe/selfie_segmentation/${f}` });
                await selfieSegmentation.initialize();
                modelsReady.segmentation = true;
                faceMesh = new FaceMesh({ locateFile: f=&gt;`https://cdn.jsdelivr.net/npm/@mediapipe/face_mesh/${f}` });
                await faceMesh.initialize();
                faceDetection = new FaceDetection({ locateFile: f=&gt;`https://cdn.jsdelivr.net/npm/@mediapipe/face_detection/${f}` });
                await faceDetection.initialize();
                modelsReady.face = true;
                addLog(&quot;✅ 所有模型就绪&quot;);
                refreshAllPreCropPreviews();
            } catch(e) { addLog(`模型加载失败: ${e.message}`, true); }
        }
        
        function setupUpload() {
            if (!uploadTrigger || !fileInput) return;
            uploadTrigger.addEventListener('click', () =&gt; fileInput.click());
            fileInput.addEventListener('change', async (e) =&gt; {
                for(let file of Array.from(e.target.files)) {
                    if(!file.type.startsWith('image/')) continue;
                    const url = URL.createObjectURL(file);
                    const img = new Image();
                    await new Promise(r=&gt;{img.onload=r; img.src=url;});
                    const newItem = {
                        id: nextId++,
                        file: file,
                        originalUrl: url,
                        originalImgElement: img,
                        processedFinalUrl: null,
                        processedBlob: null,
                        status: '待处理',
                        qualityScore: null,
                        preCropUrl: null
                    };
                    imageItems.push(newItem);
                    if(modelsReady.face) {
                        const preCanvas = await generatePreCropCanvas(newItem);
                        if(preCanvas) newItem.preCropUrl = preCanvas.toDataURL();
                    }
                    renderAllCards();
                    updateStatsUI();
                    addLog(`已添加: ${file.name}`);
                }
                fileInput.value = '';
            });
        }
        
        // 事件绑定
        qualitySlider.addEventListener('input', () =&gt; qualitySpan.innerText = qualitySlider.value);
        bgMethodSelect.addEventListener('change', () =&gt; {
            bgThresholdRow.style.display = (bgMethodSelect.value === 'none' || bgMethodSelect.value === 'paddle_humanseg') ? 'none' : 'block';
        });
        maskThreshold.addEventListener('input', () =&gt; thresholdSpan.innerText = maskThreshold.value);
        faceDetectMethod.addEventListener('change', () =&gt; refreshAllPreCropPreviews());
        const percentIds = ['cropTopPercent', 'cropBottomPercent', 'cropLeftPercent', 'cropRightPercent'];
        percentIds.forEach(id =&gt; {
            document.getElementById(id).addEventListener('input', () =&gt; refreshAllPreCropPreviews());
        });
        batchBtn.addEventListener('click', batchProcess);
        clearBtn.addEventListener('click', () =&gt; {
            imageItems.forEach(i=&gt;URL.revokeObjectURL(i.originalUrl));
            imageItems = []; successTotal=0; failTotal=0;
            updateStatsUI(); renderAllCards(); addLog(&quot;已清空&quot;);
        });
        saveAllBtn.addEventListener('click', saveAllToDirectory);
        
        // 启动
        initModels();
        setupUpload();
        bgThresholdRow.style.display = (bgMethodSelect.value === 'none' || bgMethodSelect.value === 'paddle_humanseg') ? 'none' : 'block';
        qualitySpan.innerText = qualitySlider.value;
        thresholdSpan.innerText = maskThreshold.value;
    })();
&lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;</description><pubDate>Tue, 28 Apr 2026 17:13:59 +0800</pubDate></item><item><title>人民币大写在线转换工具</title><link>https://caterwang.cn/?id=171</link><description>&lt;meta charset=&quot;UTF-8&quot;/&gt;&lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;/&gt;&lt;title&gt;人民币大写在线转换工具&lt;/title&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css&quot;/&gt;&lt;style&gt;* {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            font-family: 'Segoe UI', 'Microsoft YaHei', sans-serif;
        }
        
        body {
            background: linear-gradient(135deg, #f5f7fa 0%, #e4edf5 100%);
            color: #333;
            line-height: 1.6;
            min-height: 100vh;
            padding: 20px;
        }
        
        .container {
            max-width: 900px;
            margin: 0 auto;
        }
        
        header {
            text-align: center;
            margin-bottom: 30px;
            padding: 25px;
            background-color: #fff;
            border-radius: 12px;
            box-shadow: 0 5px 15px rgba(0, 0, 0, 0.08);
        }
        
        h1 {
            color: #c62828;
            margin-bottom: 10px;
            font-size: 2.5rem;
            display: flex;
            align-items: center;
            justify-content: center;
            gap: 15px;
        }
        
        h1 i {
            color: #ff9800;
        }
        
        .subtitle {
            color: #666;
            font-size: 1.1rem;
            max-width: 800px;
            margin: 0 auto;
        }
        
        .converter-card {
            background-color: #fff;
            border-radius: 12px;
            padding: 30px;
            box-shadow: 0 5px 15px rgba(0, 0, 0, 0.08);
            margin-bottom: 25px;
        }
        
        .section-title {
            color: #2c3e50;
            border-bottom: 2px solid #3498db;
            padding-bottom: 10px;
            margin-bottom: 20px;
            font-size: 1.5rem;
            display: flex;
            align-items: center;
            gap: 10px;
        }
        
        .section-title i {
            color: #3498db;
        }
        
        .input-group {
            margin-bottom: 25px;
        }
        
        label {
            display: block;
            margin-bottom: 8px;
            font-weight: 600;
            color: #444;
        }
        
        .input-with-icon {
            position: relative;
        }
        
        .currency-symbol {
            position: absolute;
            left: 15px;
            top: 50%;
            transform: translateY(-50%);
            font-weight: bold;
            color: #888;
            font-size: 1.2rem;
        }
        
        input, textarea {
            width: 100%;
            padding: 15px 15px 15px 40px;
            border: 2px solid #ddd;
            border-radius: 8px;
            font-size: 1.1rem;
            transition: all 0.3s;
        }
        
        input:focus, textarea:focus {
            outline: none;
            border-color: #3498db;
            box-shadow: 0 0 0 3px rgba(52, 152, 219, 0.2);
        }
        
        textarea {
            min-height: 120px;
            resize: vertical;
            font-family: monospace;
            font-size: 1.2rem;
            color: #c62828;
            font-weight: bold;
        }
        
        .btn-convert {
            background-color: #3498db;
            color: white;
            border: none;
            padding: 15px 25px;
            border-radius: 8px;
            cursor: pointer;
            font-size: 1.1rem;
            font-weight: 600;
            width: 100%;
            transition: all 0.3s;
            display: flex;
            align-items: center;
            justify-content: center;
            gap: 10px;
            margin-bottom: 15px;
        }
        
        .btn-convert:hover {
            background-color: #2980b9;
            transform: translateY(-2px);
            box-shadow: 0 5px 15px rgba(41, 128, 185, 0.3);
        }
        
        .btn-copy {
            background-color: #27ae60;
            color: white;
            border: none;
            padding: 12px 20px;
            border-radius: 8px;
            cursor: pointer;
            font-size: 1rem;
            width: 100%;
            transition: all 0.3s;
            display: flex;
            align-items: center;
            justify-content: center;
            gap: 10px;
        }
        
        .btn-copy:hover {
            background-color: #219653;
            transform: translateY(-2px);
            box-shadow: 0 5px 15px rgba(39, 174, 96, 0.3);
        }
        
        .reference-tables {
            display: flex;
            flex-wrap: wrap;
            gap: 20px;
            margin-top: 25px;
        }
        
        .table-wrapper {
            flex: 1;
            min-width: 200px;
        }
        
        .table-title {
            background-color: #3498db;
            color: white;
            padding: 10px;
            border-radius: 6px 6px 0 0;
            font-weight: 600;
            text-align: center;
        }
        
        table {
            width: 100%;
            border-collapse: collapse;
        }
        
        th, td {
            padding: 12px 15px;
            text-align: center;
            border: 1px solid #ddd;
        }
        
        th {
            background-color: #f8f9fa;
            font-weight: 600;
        }
        
        .red-text {
            color: #c62828;
            font-weight: bold;
        }
        
        .example-box {
            background-color: #f8f9fa;
            padding: 20px;
            border-radius: 8px;
            margin-top: 25px;
            border-left: 4px solid #3498db;
        }
        
        .example-title {
            font-weight: 600;
            margin-bottom: 10px;
            color: #2c3e50;
            display: flex;
            align-items: center;
            gap: 8px;
        }
        
        .example-content {
            line-height: 1.8;
        }
        
        .example-item {
            margin-bottom: 8px;
        }
        
        .symbols-container {
            display: flex;
            flex-wrap: wrap;
            gap: 15px;
            margin-top: 20px;
        }
        
        .symbol-item {
            background-color: #f8f9fa;
            padding: 10px 15px;
            border-radius: 6px;
            font-weight: 600;
            border: 1px solid #ddd;
            min-width: 120px;
        }
        
        .instructions {
            margin-top: 30px;
            padding: 25px;
            background-color: #fff;
            border-radius: 12px;
            box-shadow: 0 5px 15px rgba(0, 0, 0, 0.08);
        }
        
        .instructions h3 {
            color: #2c3e50;
            margin-bottom: 15px;
            font-size: 1.3rem;
            display: flex;
            align-items: center;
            gap: 10px;
        }
        
        .instructions ul {
            padding-left: 20px;
            margin-bottom: 15px;
        }
        
        .instructions li {
            margin-bottom: 8px;
        }
        
        .success-message {
            background-color: #d4edda;
            color: #155724;
            padding: 12px;
            border-radius: 6px;
            margin-top: 15px;
            text-align: center;
            display: none;
        }
        
        footer {
            text-align: center;
            margin-top: 40px;
            padding: 20px;
            color: #666;
            font-size: 0.9rem;
            border-top: 1px solid #ddd;
        }
        
        @media (max-width: 768px) {
            .reference-tables {
                flex-direction: column;
            }
            
            h1 {
                font-size: 2rem;
            }
            
            .symbol-item {
                min-width: 100px;
            }
        }
        
        @media (max-width: 480px) {
            .container {
                padding: 10px;
            }
            
            .converter-card, .instructions {
                padding: 20px;
            }
            
            h1 {
                font-size: 1.8rem;
            }
        }&lt;/style&gt;&lt;div class=&quot;container&quot;&gt;&lt;header&gt;&lt;h1&gt;&lt;em class=&quot;fas fa-money-bill-wave&quot;&gt;&lt;/em&gt;人民币大写在线转换工具&lt;/h1&gt;&lt;p class=&quot;subtitle&quot;&gt;在线将阿拉伯数字转换成中文大写、人民币大写转换工具&lt;/p&gt;&lt;/header&gt;&lt;main&gt;&lt;!-- 人民币大写转换器 --&gt;&lt;section class=&quot;converter-card&quot;&gt;&lt;h2 class=&quot;section-title&quot;&gt;&lt;em class=&quot;fas fa-exchange-alt&quot;&gt;&lt;/em&gt;人民币大写转换器&lt;/h2&gt;&lt;div class=&quot;input-group&quot;&gt;&lt;label for=&quot;amountInput&quot;&gt;输入小写数字金额：&lt;/label&gt;&lt;div class=&quot;input-with-icon&quot;&gt;&lt;span class=&quot;currency-symbol&quot;&gt;¥&lt;/span&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;input type=&quot;text&quot; id=&quot;amountInput&quot; placeholder=&quot;例如：123456.78&quot; value=&quot;206000.75&quot;/&gt;&lt;/div&gt;&lt;/div&gt;&lt;button class=&quot;btn-convert&quot; id=&quot;convertBtn&quot;&gt;&lt;em class=&quot;fas fa-sync-alt&quot;&gt;&lt;/em&gt;转换为大写金额&lt;/button&gt;&lt;div class=&quot;input-group&quot;&gt;&lt;label for=&quot;resultOutput&quot;&gt;显示中文大写金额：&lt;/label&gt;&lt;textarea id=&quot;resultOutput&quot; readonly=&quot;&quot; placeholder=&quot;转换结果将显示在这里&quot;&gt;&lt;/textarea&gt;&lt;/div&gt;&lt;button class=&quot;btn-copy&quot; id=&quot;copyBtn&quot;&gt;&lt;em class=&quot;far fa-copy&quot;&gt;&lt;/em&gt;复制大写金额&lt;/button&gt;&lt;div class=&quot;success-message&quot; id=&quot;copySuccess&quot;&gt;&lt;em class=&quot;fas fa-check-circle&quot;&gt;&lt;/em&gt; 已成功复制到剪贴板！&lt;/div&gt;&lt;/section&gt;&lt;!-- 大写对照表 --&gt;&lt;section class=&quot;converter-card&quot;&gt;&lt;h2 class=&quot;section-title&quot;&gt;&lt;em class=&quot;fas fa-table&quot;&gt;&lt;/em&gt;大写对照表&lt;/h2&gt;&lt;div class=&quot;reference-tables&quot;&gt;&lt;div class=&quot;table-wrapper&quot;&gt;&lt;div class=&quot;table-title&quot;&gt;数字转大写&lt;/div&gt;&lt;table id=&quot;digitTable&quot;&gt;&lt;thead&gt;&lt;tr class=&quot;firstRow&quot;&gt;&lt;th&gt;数字&lt;/th&gt;&lt;th&gt;大写&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;!-- 表格内容将由JavaScript生成 --&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;div class=&quot;table-wrapper&quot;&gt;&lt;div class=&quot;table-title&quot;&gt;金额单位&lt;/div&gt;&lt;table id=&quot;unitTable&quot;&gt;&lt;thead&gt;&lt;tr class=&quot;firstRow&quot;&gt;&lt;th&gt;单位&lt;/th&gt;&lt;th&gt;大写&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;!-- 表格内容将由JavaScript生成 --&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;/div&gt;&lt;!-- 常用货币符号 --&gt;&lt;div class=&quot;symbols-container&quot;&gt;&lt;div class=&quot;symbol-item&quot;&gt;人民币符号：¥&lt;/div&gt;&lt;div class=&quot;symbol-item&quot;&gt;美元符号：$&lt;/div&gt;&lt;div class=&quot;symbol-item&quot;&gt;欧元符号：€&lt;/div&gt;&lt;div class=&quot;symbol-item&quot;&gt;英镑符号：￡&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;!-- 转换示例 --&gt;&lt;section class=&quot;converter-card&quot;&gt;&lt;h2 class=&quot;section-title&quot;&gt;&lt;em class=&quot;fas fa-lightbulb&quot;&gt;&lt;/em&gt;转换示例&lt;/h2&gt;&lt;div class=&quot;example-box&quot;&gt;&lt;div class=&quot;example-title&quot;&gt;&lt;em class=&quot;fas fa-info-circle&quot;&gt;&lt;/em&gt;转换规则说明：&lt;/div&gt;&lt;div class=&quot;example-content&quot;&gt;&lt;div class=&quot;example-item&quot;&gt;中文大写金额数字前应标明&amp;quot;人民币&amp;quot;字样，大写金额数字应紧接&amp;quot;人民币&amp;quot;字样填写，不得留有空白。&lt;/div&gt;&lt;div class=&quot;example-item&quot;&gt;阿拉伯数字小写金额数字中有&amp;quot;0&amp;quot;时，中文大写应按照汉语语言规律、金额数字构成和防止涂改的要求进行书写。&lt;/div&gt;&lt;div class=&quot;example-item&quot;&gt;中文大写金额数字到&amp;quot;元&amp;quot;为止的，在&amp;quot;元&amp;quot;之后、应写&amp;quot;整&amp;quot;(或&amp;quot;正&amp;quot;)字；在&amp;quot;角&amp;quot;之后，可以不写&amp;quot;整&amp;quot;(或&amp;quot;正&amp;quot;)字；大写金额数字有&amp;quot;分&amp;quot;的，&amp;quot;分&amp;quot;后面不写&amp;quot;整&amp;quot;(或&amp;quot;正&amp;quot;)字。&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;example-box&quot;&gt;&lt;div class=&quot;example-title&quot;&gt;&lt;em class=&quot;fas fa-eye&quot;&gt;&lt;/em&gt;具体示例：&lt;/div&gt;&lt;div class=&quot;example-content&quot;&gt;&lt;div class=&quot;example-item&quot;&gt;&lt;strong&gt;输入：&lt;/strong&gt;¥206000.75&lt;/div&gt;&lt;div class=&quot;example-item&quot;&gt;&lt;strong&gt;输出：&lt;/strong&gt;&lt;span class=&quot;red-text&quot;&gt;人民币贰拾万陆仟元零柒角伍分&lt;/span&gt;，或 &lt;span class=&quot;red-text&quot;&gt;人民币贰拾万零陆仟元柒角伍分&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;example-item&quot;&gt;&lt;strong&gt;输入：&lt;/strong&gt;¥1001.00&lt;/div&gt;&lt;div class=&quot;example-item&quot;&gt;&lt;strong&gt;输出：&lt;/strong&gt;&lt;span class=&quot;red-text&quot;&gt;人民币壹仟零壹元整&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;example-item&quot;&gt;&lt;strong&gt;输入：&lt;/strong&gt;¥0.56&lt;/div&gt;&lt;div class=&quot;example-item&quot;&gt;&lt;strong&gt;输出：&lt;/strong&gt;&lt;span class=&quot;red-text&quot;&gt;人民币伍角陆分&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;example-item&quot;&gt;&lt;strong&gt;输入：&lt;/strong&gt;¥888.80&lt;/div&gt;&lt;div class=&quot;example-item&quot;&gt;&lt;strong&gt;输出：&lt;/strong&gt;&lt;span class=&quot;red-text&quot;&gt;人民币捌佰捌拾捌元捌角&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;!-- 使用说明 --&gt;&lt;section class=&quot;instructions&quot;&gt;&lt;h3&gt;&lt;em class=&quot;fas fa-info-circle&quot;&gt;&lt;/em&gt;使用说明&lt;/h3&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;在&amp;quot;输入小写数字金额&amp;quot;框中输入或粘贴阿拉伯数字金额（例如：123456.78）&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;点击&amp;quot;转换为大写金额&amp;quot;按钮，转换结果将显示在&amp;quot;显示中文大写金额&amp;quot;框中&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;点击&amp;quot;复制大写金额&amp;quot;按钮，将转换结果复制到剪贴板&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;上方对照表提供了数字与大写的对应关系，方便查阅&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;转换示例展示了不同金额的转换规则和结果&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;如需清空输入框，可直接删除内容并重新输入&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/section&gt;&lt;/main&gt;&lt;footer&gt;&lt;p&gt;人民币大写在线转换工具 © 2025 | 根据金融规范实现&lt;/p&gt;&lt;/footer&gt;&lt;/div&gt;&lt;script&gt;document.addEventListener('DOMContentLoaded', function() {
            // 初始化数字对照表
            initDigitTable();
            
            // 初始化单位对照表
            initUnitTable();
            
            // 绑定转换按钮事件
            document.getElementById('convertBtn').addEventListener('click', convertAmount);
            
            // 绑定复制按钮事件
            document.getElementById('copyBtn').addEventListener('click', copyResult);
            
            // 输入框回车键转换
            document.getElementById('amountInput').addEventListener('keypress', function(e) {
                if (e.key === 'Enter') {
                    convertAmount();
                }
            });
            
            // 初始转换
            convertAmount();
        });
        
        // 初始化数字对照表
        function initDigitTable() {
            const digitData = [
                ['0', '零'],
                ['1', '壹'],
                ['2', '贰'],
                ['3', '叁'],
                ['4', '肆'],
                ['5', '伍'],
                ['6', '陆'],
                ['7', '柒'],
                ['8', '捌'],
                ['9', '玖']
            ];
            
            const tableBody = document.querySelector('#digitTable tbody');
            tableBody.innerHTML = '';
            
            digitData.forEach(item =&gt; {
                const row = document.createElement('tr');
                row.innerHTML = `&lt;td&gt;${item[0]}&lt;/td&gt;&lt;td class=&quot;red-text&quot;&gt;${item[1]}&lt;/td&gt;`;
                tableBody.appendChild(row);
            });
        }
        
        // 初始化单位对照表
        function initUnitTable() {
            const unitData = [
                ['亿', '亿'],
                ['万', '万'],
                ['千', '仟'],
                ['百', '佰'],
                ['十', '拾'],
                ['元', '元(圆)'],
                ['角', '角'],
                ['分', '分'],
                ['正', '正'],
                ['整', '整']
            ];
            
            const tableBody = document.querySelector('#unitTable tbody');
            tableBody.innerHTML = '';
            
            unitData.forEach(item =&gt; {
                const row = document.createElement('tr');
                row.innerHTML = `&lt;td&gt;${item[0]}&lt;/td&gt;&lt;td&gt;${item[1]}&lt;/td&gt;`;
                tableBody.appendChild(row);
            });
        }
        
        // 转换金额函数
        function convertAmount() {
            const amountInput = document.getElementById('amountInput').value.trim();
            const resultOutput = document.getElementById('resultOutput');
            
            if (!amountInput) {
                resultOutput.value = &quot;请输入金额&quot;;
                return;
            }
            
            // 清理输入，只保留数字和小数点
            let cleanedInput = amountInput.replace(/[^\d.-]/g, '');
            
            // 检查是否包含多个小数点
            if ((cleanedInput.match(/\./g) || []).length &gt; 1) {
                resultOutput.value = &quot;金额格式错误：不能有多个小数点&quot;;
                return;
            }
            
            // 如果输入为空，使用0
            if (!cleanedInput) {
                cleanedInput = &quot;0&quot;;
            }
            
            // 转换数字为中文大写金额
            const result = convertToChineseUpper(cleanedInput);
            resultOutput.value = result;
        }
        
        // 将数字转换为中文大写金额
        function convertToChineseUpper(numStr) {
            // 中文数字字符
            const chineseDigits = ['零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖'];
            
            // 中文单位
            const chineseUnits = ['', '拾', '佰', '仟'];
            const chineseBigUnits = ['', '万', '亿'];
            
            // 处理负数
            let isNegative = false;
            if (numStr.startsWith('-')) {
                isNegative = true;
                numStr = numStr.substring(1);
            }
            
            // 分割整数和小数部分
            let integerPart = '';
            let decimalPart = '';
            
            if (numStr.includes('.')) {
                const parts = numStr.split('.');
                integerPart = parts[0];
                decimalPart = parts[1].substring(0, 2); // 只保留两位小数
            } else {
                integerPart = numStr;
            }
            
            // 处理整数部分
            let chineseInteger = '';
            
            // 处理整数部分为0的情况
            if (integerPart === '0' || integerPart === '') {
                chineseInteger = '零';
            } else {
                // 将整数部分分组（每4位一组）
                const groups = [];
                for (let i = integerPart.length; i &gt; 0; i -= 4) {
                    groups.push(integerPart.substring(Math.max(0, i - 4), i));
                }
                groups.reverse();
                
                // 处理每一组
                for (let i = 0; i &lt; groups.length; i++) {
                    const group = groups[i];
                    let groupResult = '';
                    
                    // 处理组内每一位
                    for (let j = 0; j &lt; group.length; j++) {
                        const digit = parseInt(group[j]);
                        const unit = chineseUnits[group.length - 1 - j];
                        
                        if (digit === 0) {
                            // 如果当前位是0，且前一位不是0，则添加零
                            if (groupResult.charAt(groupResult.length - 1) !== '零') {
                                groupResult += '零';
                            }
                        } else {
                            // 去除可能多余的零
                            if (groupResult.charAt(groupResult.length - 1) === '零') {
                                groupResult = groupResult.substring(0, groupResult.length - 1);
                            }
                            groupResult += chineseDigits[digit] + unit;
                        }
                    }
                    
                    // 去除末尾的零
                    if (groupResult.endsWith('零')) {
                        groupResult = groupResult.substring(0, groupResult.length - 1);
                    }
                    
                    // 如果组不为空，添加大单位
                    if (groupResult !== '') {
                        chineseInteger += groupResult + chineseBigUnits[groups.length - 1 - i];
                    }
                }
                
                // 处理连续的零
                chineseInteger = chineseInteger.replace(/零+/g, '零');
                
                // 处理开头和结尾的零
                if (chineseInteger.startsWith('零')) {
                    chineseInteger = chineseInteger.substring(1);
                }
                if (chineseInteger.endsWith('零')) {
                    chineseInteger = chineseInteger.substring(0, chineseInteger.length - 1);
                }
                
                // 处理一十开头的特殊情况
                if (chineseInteger.startsWith('壹拾')) {
                    // 保持原样，因为金融规范中&quot;一十&quot;应写为&quot;拾&quot;
                }
            }
            
            // 处理小数部分
            let chineseDecimal = '';
            if (decimalPart) {
                // 角
                if (decimalPart.length &gt;= 1) {
                    const jiaoDigit = parseInt(decimalPart[0]);
                    if (jiaoDigit &gt; 0) {
                        chineseDecimal += chineseDigits[jiaoDigit] + '角';
                    } else if (integerPart !== '0') {
                        // 如果整数部分不为0，且角为0，需要添加&quot;零&quot;
                        chineseDecimal += '零';
                    }
                }
                
                // 分
                if (decimalPart.length &gt;= 2) {
                    const fenDigit = parseInt(decimalPart[1]);
                    if (fenDigit &gt; 0) {
                        // 如果角为0且整数部分不为0，需要先去除多余的&quot;零&quot;
                        if (chineseDecimal === '零') {
                            chineseDecimal = '';
                        }
                        chineseDecimal += chineseDigits[fenDigit] + '分';
                    }
                }
            }
            
            // 组合结果
            let result = '';
            if (isNegative) {
                result += '负';
            }
            
            result += '人民币';
            
            // 如果整数部分不为空，添加整数部分和&quot;元&quot;
            if (chineseInteger !== '' &amp;&amp; chineseInteger !== '零') {
                result += chineseInteger + '元';
            } else if (chineseInteger === '零') {
                // 如果整数部分为0，且没有小数部分或小数部分也为0
                if (!decimalPart || (parseInt(decimalPart) === 0)) {
                    result += '零元';
                } else {
                    result += '';
                }
            } else {
                // 整数部分为空
                result += '';
            }
            
            // 添加小数部分
            result += chineseDecimal;
            
            // 处理&quot;整&quot;字
            if (chineseDecimal === '') {
                if (chineseInteger !== '' &amp;&amp; chineseInteger !== '零') {
                    result += '整';
                } else if (chineseInteger === '零' &amp;&amp; (!decimalPart || parseInt(decimalPart) === 0)) {
                    result += '整';
                }
            }
            
            // 特殊情况处理：去除可能出现的&quot;人民币零整&quot;
            if (result === '人民币零整') {
                result = '人民币零元整';
            }
            
            // 去除可能的&quot;零零&quot;情况
            result = result.replace(/零零/g, '零');
            
            return result;
        }
        
        // 复制结果到剪贴板
        function copyResult() {
            const resultOutput = document.getElementById('resultOutput');
            const successMessage = document.getElementById('copySuccess');
            
            if (!resultOutput.value || resultOutput.value === &quot;请输入金额&quot;) {
                successMessage.textContent = &quot;没有可复制的内容&quot;;
                successMessage.style.backgroundColor = &quot;#f8d7da&quot;;
                successMessage.style.color = &quot;#721c24&quot;;
                successMessage.style.display = &quot;block&quot;;
                setTimeout(() =&gt; {
                    successMessage.style.display = &quot;none&quot;;
                }, 2000);
                return;
            }
            
            // 使用现代剪贴板API
            navigator.clipboard.writeText(resultOutput.value).then(() =&gt; {
                successMessage.textContent = &quot;已成功复制到剪贴板！&quot;;
                successMessage.style.backgroundColor = &quot;#d4edda&quot;;
                successMessage.style.color = &quot;#155724&quot;;
                successMessage.style.display = &quot;block&quot;;
                
                setTimeout(() =&gt; {
                    successMessage.style.display = &quot;none&quot;;
                }, 2000);
            }).catch(err =&gt; {
                // 降级方案：使用旧式方法
                resultOutput.select();
                document.execCommand('copy');
                
                successMessage.textContent = &quot;已成功复制到剪贴板！&quot;;
                successMessage.style.backgroundColor = &quot;#d4edda&quot;;
                successMessage.style.color = &quot;#155724&quot;;
                successMessage.style.display = &quot;block&quot;;
                
                setTimeout(() =&gt; {
                    successMessage.style.display = &quot;none&quot;;
                }, 2000);
            });
        }&lt;/script&gt;&lt;!--!doctype--&gt;</description><pubDate>Fri, 30 Jan 2026 17:09:50 +0800</pubDate></item><item><title>MODBUS-RTU CRC16 在线计算器</title><link>https://caterwang.cn/?id=170</link><description>&lt;meta charset=&quot;UTF-8&quot;/&gt;&lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;/&gt;&lt;title&gt;CRC16计算器 - 多组数据&lt;/title&gt;&lt;style&gt;* {
            box-sizing: border-box;
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
        }
        
        body {
            background-color: #f5f7fa;
            color: #333;
            line-height: 1.6;
            margin: 0;
            padding: 20px;
            display: flex;
            flex-direction: column;
            align-items: center;
            min-height: 100vh;
        }
        
        .container {
            max-width: 1000px;
            width: 100%;
            background-color: white;
            border-radius: 12px;
            box-shadow: 0 5px 15px rgba(0, 0, 0, 0.08);
            padding: 30px;
            margin-top: 20px;
        }
        
        h1 {
            color: #2c3e50;
            text-align: center;
            margin-bottom: 5px;
            border-bottom: 2px solid #3498db;
            padding-bottom: 10px;
        }
        
        .description {
            color: #7f8c8d;
            text-align: center;
            margin-bottom: 30px;
            font-size: 0.95rem;
        }
        
        .input-section, .output-section {
            margin-bottom: 30px;
        }
        
        label {
            display: block;
            margin-bottom: 8px;
            font-weight: 600;
            color: #2c3e50;
        }
        
        .input-hint {
            font-size: 0.85rem;
            color: #7f8c8d;
            margin-top: 5px;
            font-style: italic;
        }
        
        textarea {
            width: 100%;
            padding: 12px 15px;
            border: 2px solid #ddd;
            border-radius: 6px;
            font-size: 16px;
            transition: border-color 0.3s;
            resize: vertical;
            min-height: 120px;
            font-family: 'Courier New', monospace;
            background-color: #f8f9fa;
        }
        
        textarea:focus {
            border-color: #3498db;
            outline: none;
        }
        
        .output-box {
            background-color: #f8f9fa;
            border: 2px solid #e9ecef;
            border-radius: 6px;
            padding: 15px;
            font-family: 'Courier New', monospace;
            word-wrap: break-word;
            min-height: 100px;
            color: #2c3e50;
            white-space: pre-wrap;
        }
        
        .group-container {
            margin-top: 20px;
            border: 1px solid #e0e0e0;
            border-radius: 8px;
            overflow: hidden;
        }
        
        .group-header {
            background-color: #f8f9fa;
            padding: 12px 15px;
            border-bottom: 1px solid #e0e0e0;
            font-weight: bold;
            color: #2c3e50;
            display: flex;
            justify-content: space-between;
            align-items: center;
        }
        
        .group-content {
            padding: 15px;
        }
        
        .crc-result {
            margin-top: 10px;
            padding: 12px;
            background-color: #e8f4fc;
            border-left: 4px solid #3498db;
            border-radius: 4px;
            font-family: 'Courier New', monospace;
        }
        
        .crc-value {
            font-weight: bold;
            color: #e74c3c;
        }
        
        .example {
            background-color: #f9f9f9;
            border-left: 4px solid #2ecc71;
            padding: 15px;
            margin-top: 20px;
            border-radius: 4px;
            font-size: 0.9rem;
        }
        
        .example h3 {
            margin-top: 0;
            color: #27ae60;
        }
        
        .footer {
            margin-top: 30px;
            text-align: center;
            color: #95a5a6;
            font-size: 0.85rem;
        }
        
        .byte-order {
            display: flex;
            align-items: center;
            margin-top: 5px;
            font-size: 0.9rem;
            color: #3498db;
        }
        
        .byte-order span {
            margin-left: 5px;
        }
        
        .test-result {
            background-color: #fff8e1;
            border-left: 4px solid #ffc107;
            padding: 10px;
            margin-top: 15px;
            border-radius: 4px;
            font-size: 0.9rem;
        }
        
        .correct {
            color: #28a745;
            font-weight: bold;
        }
        
        .incorrect {
            color: #dc3545;
            font-weight: bold;
        }
        
        .summary {
            margin-top: 20px;
            padding: 15px;
            background-color: #f0f7ff;
            border-radius: 8px;
            border-left: 4px solid #3498db;
        }
        
        .summary h3 {
            margin-top: 0;
            color: #2c3e50;
        }
        
        @media (max-width: 600px) {
            .container {
                padding: 20px;
            }
            
            h1 {
                font-size: 1.5rem;
            }
        }&lt;/style&gt;&lt;div class=&quot;container&quot;&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;可输入多组16进制数串（用英文逗号分隔每组），实时计算每组数据的CRC16值。使用查表法计算，输出结果包含带0x前缀的输入数据和CRC16值（低字节在前）。&lt;/p&gt;&lt;div class=&quot;input-section&quot;&gt;&lt;label for=&quot;hexInput&quot;&gt;输入多组16进制数串（用英文逗号分隔每组，组内用空格分隔数字）:&lt;/label&gt;&lt;textarea id=&quot;hexInput&quot; placeholder=&quot;例如: 
01 02 03 04 05,
0A 0B 0C,
FF 00 AA BB CC&quot;&gt;&lt;/textarea&gt;&lt;div class=&quot;input-hint&quot;&gt;请输入多组16进制数字，每组用英文逗号分隔，组内用空格分隔数字。无需添加0x前缀，支持大写和小写字母。&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;output-section&quot;&gt;&lt;label&gt;输出结果 (共&lt;span id=&quot;groupCount&quot;&gt;0&lt;/span&gt;组):&lt;/label&gt;&lt;div class=&quot;output-box&quot; id=&quot;outputBox&quot;&gt;等待输入...&lt;/div&gt;&lt;div class=&quot;summary&quot; id=&quot;summaryBox&quot; style=&quot;display: none;&quot;&gt;&lt;h3&gt;计算结果摘要&lt;/h3&gt;&lt;div id=&quot;summaryContent&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id=&quot;testResult&quot; class=&quot;test-result&quot;&gt;&lt;strong&gt;测试提示:&lt;/strong&gt; 使用&amp;quot;01 02 03 04 05&amp;quot;测试，正确CRC16应为: 0xBB2A (低字节: 0x2A, 高字节: 0xBB)&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;example&quot;&gt;&lt;h3&gt;示例:&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;输入:&lt;/strong&gt; 01 02 03 04 05, 0A 0B 0C, FF 00 AA BB CC&lt;/p&gt;&lt;p&gt;&lt;strong&gt;输出:&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;第1组: 0x01 0x02 0x03 0x04 0x05 0x2A 0xBB&lt;/p&gt;&lt;p&gt;第2组: 0x0A 0x0B 0x0C 0x4A 0x7B&lt;/p&gt;&lt;p&gt;第3组: 0xFF 0x00 0xAA 0xBB 0xCC 0x04 0xBC&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;script&gt;// CRC16查表法计算函数 - 根据您提供的C代码实现
        function calculateCRC16(hexArray) {
            // 初始化CRC高字节和低字节为0xFF
            let uchCRCHi = 0xFF;  // 高CRC字节
            let uchCRCLo = 0xFF;  // 低CRC字节
            
            // CRC高位字节值表
            const auchCRCHi = [
                0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 
                0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 
                0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 
                0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 
                0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 
                0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 
                0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 
                0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 
                0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 
                0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 
                0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 
                0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 
                0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 
                0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 
                0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 
                0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 
                0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 
                0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 
                0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 
                0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 
                0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 
                0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 
                0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 
                0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 
                0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 
                0x80, 0x41, 0x00, 0xC1, 0x81, 0x40
            ];
            
            // CRC低位字节值表
            const auchCRCLo = [
                0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 
                0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD, 
                0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09, 
                0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A, 
                0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, 0x14, 0xD4, 
                0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3, 
                0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 
                0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4, 
                0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A, 
                0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29, 
                0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED, 
                0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26, 
                0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 
                0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67, 
                0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F, 
                0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68, 
                0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, 0xBE, 0x7E, 
                0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5, 
                0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 
                0x70, 0xB0, 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92, 
                0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C, 
                0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B, 
                0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B, 
                0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C, 
                0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 
                0x43, 0x83, 0x41, 0x81, 0x80, 0x40
            ];
            
            // 对每个输入字节计算CRC - 严格按照您的C代码实现
            for (let i = 0; i &lt; hexArray.length; i++) {
                const byte = hexArray[i];
                
                // 计算索引：高CRC字节 XOR 当前数据字节
                const uIndex = uchCRCHi ^ byte;
                
                // 更新CRC值
                uchCRCHi = uchCRCLo ^ auchCRCHi[uIndex];
                uchCRCLo = auchCRCLo[uIndex];
            }
            
            // 返回结果：低字节左移8位 | 高字节
            return (uchCRCLo &lt;&lt; 8) | uchCRCHi;
        }
        
        // 解析单组数据
        function parseSingleGroup(groupStr) {
            const parts = groupStr.trim().split(/\s+/);
            const hexArray = [];
            const validHexArray = [];
            
            // 过滤和转换有效的16进制数字
            for (let i = 0; i &lt; parts.length; i++) {
                const part = parts[i].trim();
                if (!part) continue;
                
                // 检查是否为有效的16进制数字
                const hexRegex = /^[0-9A-Fa-f]+$/;
                if (hexRegex.test(part)) {
                    // 将16进制字符串转换为数字
                    const value = parseInt(part, 16);
                    if (!isNaN(value) &amp;&amp; value &gt;= 0 &amp;&amp; value &lt;= 255) {
                        hexArray.push(value);
                        validHexArray.push(part.toUpperCase());
                    }
                }
            }
            
            return {
                hexArray,
                validHexArray,
                isValid: hexArray.length &gt; 0
            };
        }
        
        // 处理输入并更新输出
        function processInput() {
            const input = document.getElementById('hexInput').value.trim();
            const outputBox = document.getElementById('outputBox');
            const groupCountElement = document.getElementById('groupCount');
            const summaryBox = document.getElementById('summaryBox');
            const summaryContent = document.getElementById('summaryContent');
            const testResult = document.getElementById('testResult');
            
            // 如果没有输入
            if (!input) {
                outputBox.textContent = '等待输入...';
                groupCountElement.textContent = '0';
                summaryBox.style.display = 'none';
                testResult.innerHTML = '&lt;strong&gt;测试提示:&lt;/strong&gt; 使用&quot;01 02 03 04 05&quot;测试，正确CRC16应为: 0xBB2A (低字节: 0x2A, 高字节: 0xBB)';
                return;
            }
            
            // 按英文逗号分割成多组
            const groups = input.split(',').map(g =&gt; g.trim()).filter(g =&gt; g.length &gt; 0);
            let outputText = '';
            let summaryHTML = '';
            let validGroupCount = 0;
            let hasTestGroup = false;
            let testGroupResult = '';
            
            // 处理每一组数据
            groups.forEach((groupStr, groupIndex) =&gt; {
                const result = parseSingleGroup(groupStr);
                
                if (result.isValid) {
                    validGroupCount++;
                    
                    // 计算CRC16
                    const crc = calculateCRC16(result.hexArray);
                    
                    // 分离CRC的高字节和低字节
                    const crcHigh = (crc &gt;&gt; 8) &amp; 0xFF;  // 高字节
                    const crcLow = crc &amp; 0xFF;   // 低字节
                    
                    // 格式化输入数据
                    const formattedInput = result.validHexArray.map(hex =&gt; `0x${hex}`).join(' ');
                    
                    // 格式化CRC输出（低字节在前）
                    const formattedCRC = `0x${crcLow.toString(16).padStart(2, '0').toUpperCase()} 0x${crcHigh.toString(16).padStart(2, '0').toUpperCase()}`;
                    
                    // 添加到输出文本
                    // outputText += `第${groupIndex + 1}组: ${formattedInput} ${formattedCRC}\n`;
					outputText += `${formattedInput} ${formattedCRC}\n`;
                    
                    // 添加到摘要
                    summaryHTML += `&lt;div style=&quot;margin-bottom: 8px;&quot;&gt;&lt;strong&gt;第${groupIndex + 1}组&lt;/strong&gt;: CRC16 = 0x${crc.toString(16).padStart(4, '0').toUpperCase()} 
                        (低字节: 0x${crcLow.toString(16).padStart(2, '0').toUpperCase()}, 高字节: 0x${crcHigh.toString(16).padStart(2, '0').toUpperCase()})&lt;/div&gt;`;
                    
                    // 检查是否是测试用例
                    if (groupStr.trim().toUpperCase() === &quot;01 02 03 04 05&quot;) {
                        hasTestGroup = true;
                        const expectedCRC = 0xBB2A;
                        if (crc === expectedCRC) {
                            testGroupResult = `&lt;span class=&quot;correct&quot;&gt;✓ 第${groupIndex + 1}组测试通过!&lt;/span&gt;`;
                        } else {
                            testGroupResult = `&lt;span class=&quot;incorrect&quot;&gt;✗ 第${groupIndex + 1}组测试失败! 应为: 0xBB2A，实际: 0x${crc.toString(16).padStart(4, '0').toUpperCase()}&lt;/span&gt;`;
                        }
                    }
                } else {
                    // 无效的组
                    outputText += `第${groupIndex + 1}组: 无效数据 (请确保输入16进制数字，用空格分隔)\n`;
                }
            });
            
            // 更新输出
            outputBox.textContent = outputText || '未找到有效数据';
            groupCountElement.textContent = validGroupCount;
            
            // 更新摘要
            if (validGroupCount &gt; 0) {
                summaryContent.innerHTML = summaryHTML;
                summaryBox.style.display = 'block';
            } else {
                summaryBox.style.display = 'none';
            }
            
            // 更新测试结果
            if (hasTestGroup) {
                testResult.innerHTML = `&lt;strong&gt;测试结果:&lt;/strong&gt; ${testGroupResult}`;
            } else {
                testResult.innerHTML = `&lt;strong&gt;测试提示:&lt;/strong&gt; 您可以输入&quot;01 02 03 04 05&quot;测试，正确CRC16应为: 0xBB2A (低字节: 0x2A, 高字节: 0xBB)`;
            }
        }
        
        // 添加事件监听器
        document.getElementById('hexInput').addEventListener('input', processInput);
        
        // 页面加载时处理示例输入
        window.addEventListener('DOMContentLoaded', function() {
            // 设置示例输入
            document.getElementById('hexInput').value = &quot;01 02 03 04 05,\n0A 0B 0C,\nFF 00 AA BB CC&quot;;
            // 处理示例
            processInput();
        });
        
        // 测试函数
        function testCRCFunction() {
            // 测试用例: &quot;01 02 03 04 05&quot;
            const testData = [0x01, 0x02, 0x03, 0x04, 0x05];
            const crc = calculateCRC16(testData);
            console.log(`测试数据: 01 02 03 04 05`);
            console.log(`计算得到的CRC16: 0x${crc.toString(16).padStart(4, '0').toUpperCase()}`);
            console.log(`期望的CRC16: 0xBB2A`);
            console.log(`测试结果: ${crc === 0xBB2A ? '通过' : '失败'}`);
            return crc === 0xBB2A;
        }
        
        // 在控制台运行测试
        setTimeout(testCRCFunction, 1000);&lt;/script&gt;&lt;!--!doctype--&gt;</description><pubDate>Wed, 10 Dec 2025 12:16:52 +0800</pubDate></item><item><title>总结，如何查阅valgrind内存泄漏检测报告</title><link>https://caterwang.cn/?id=168</link><description>&lt;p&gt;检测命令&lt;br/&gt;&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-bash&quot;&gt;valgrind&amp;nbsp;--tool=memcheck&amp;nbsp;--leak-check=full&amp;nbsp;--log-file=valgring.log&amp;nbsp;./hriExecCtrl&lt;/pre&gt;&lt;p&gt;报告结论&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-bash&quot;&gt;==417113==&amp;nbsp;LEAK&amp;nbsp;SUMMARY:
==417113==&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;definitely&amp;nbsp;lost:&amp;nbsp;14,528&amp;nbsp;bytes&amp;nbsp;in&amp;nbsp;96&amp;nbsp;blocks
==417113==&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;indirectly&amp;nbsp;lost:&amp;nbsp;1,302,289&amp;nbsp;bytes&amp;nbsp;in&amp;nbsp;273&amp;nbsp;blocks
==417113==&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;possibly&amp;nbsp;lost:&amp;nbsp;16,400&amp;nbsp;bytes&amp;nbsp;in&amp;nbsp;41&amp;nbsp;blocks
==417113==&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;still&amp;nbsp;reachable:&amp;nbsp;6,568,169&amp;nbsp;bytes&amp;nbsp;in&amp;nbsp;13,367&amp;nbsp;blocks
==417113==&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;of&amp;nbsp;which&amp;nbsp;reachable&amp;nbsp;via&amp;nbsp;heuristic:
==417113==&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;stdstring&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;:&amp;nbsp;31,621&amp;nbsp;bytes&amp;nbsp;in&amp;nbsp;839&amp;nbsp;blocks
==417113==&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;newarray&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;:&amp;nbsp;1,104&amp;nbsp;bytes&amp;nbsp;in&amp;nbsp;4&amp;nbsp;blocks
==417113==&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;suppressed:&amp;nbsp;0&amp;nbsp;bytes&amp;nbsp;in&amp;nbsp;0&amp;nbsp;blocks
==417113==&amp;nbsp;Reachable&amp;nbsp;blocks&amp;nbsp;(those&amp;nbsp;to&amp;nbsp;which&amp;nbsp;a&amp;nbsp;pointer&amp;nbsp;was&amp;nbsp;found)&amp;nbsp;are&amp;nbsp;not&amp;nbsp;shown.
==417113==&amp;nbsp;To&amp;nbsp;see&amp;nbsp;them,&amp;nbsp;rerun&amp;nbsp;with:&amp;nbsp;--leak-check=full&amp;nbsp;--show-leak-kinds=all
==417113==&amp;nbsp;
==417113==&amp;nbsp;Use&amp;nbsp;--track-origins=yes&amp;nbsp;to&amp;nbsp;see&amp;nbsp;where&amp;nbsp;uninitialised&amp;nbsp;values&amp;nbsp;come&amp;nbsp;from
==417113==&amp;nbsp;For&amp;nbsp;lists&amp;nbsp;of&amp;nbsp;detected&amp;nbsp;and&amp;nbsp;suppressed&amp;nbsp;errors,&amp;nbsp;rerun&amp;nbsp;with:&amp;nbsp;-s
==417113==&amp;nbsp;ERROR&amp;nbsp;SUMMARY:&amp;nbsp;4871&amp;nbsp;errors&amp;nbsp;from&amp;nbsp;197&amp;nbsp;contexts&amp;nbsp;(suppressed:&amp;nbsp;0&amp;nbsp;from&amp;nbsp;0)&lt;/pre&gt;&lt;p&gt;报告解析&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-actionscript&quot;&gt;1.&amp;nbsp;泄漏分类总结
Valgrind&amp;nbsp;将内存泄漏分为&amp;nbsp;4&amp;nbsp;类（按严重性排序）：
(1)&amp;nbsp;Definitely&amp;nbsp;Lost（明确泄漏）14,528&amp;nbsp;bytes&amp;nbsp;in&amp;nbsp;96&amp;nbsp;blocks
	最严重的泄漏：程序直接丢失了动态分配的内存（如&amp;nbsp;malloc/new&amp;nbsp;但未释放）。
	可能原因：忘记调用&amp;nbsp;free()/delete，或指针丢失后无法释放。
	修复建议：检查&amp;nbsp;96&amp;nbsp;处分配点的代码，确保每次分配都有对应的释放。
(2)&amp;nbsp;Indirectly&amp;nbsp;Lost（间接泄漏）1,302,289&amp;nbsp;bytes&amp;nbsp;in&amp;nbsp;273&amp;nbsp;blocks
	关联结构体/类的内存泄漏：例如，某个结构体指针泄漏导致其内部成员指针也无法释放。
	可能原因：复杂数据结构（如链表、树）的根节点泄漏，或析构函数未正确释放成员。
	修复建议：检查数据结构的生命周期管理，确保根节点释放时能递归释放所有成员。
(3)&amp;nbsp;Possibly&amp;nbsp;Lost（可能泄漏）16,400&amp;nbsp;bytes&amp;nbsp;in&amp;nbsp;41&amp;nbsp;blocks
	潜在指针错误：分配的内存指针可能被错误计算（如&amp;nbsp;ptr+1&amp;nbsp;导致&amp;nbsp;free(ptr)&amp;nbsp;无法匹配）。
	可能原因：指针运算错误或数组越界。
	修复建议：检查这&amp;nbsp;41&amp;nbsp;处指针的使用逻辑，确保&amp;nbsp;free()&amp;nbsp;的参数与&amp;nbsp;malloc()&amp;nbsp;完全一致。
(4)&amp;nbsp;Still&amp;nbsp;Reachable（仍可访问）6,568,169&amp;nbsp;bytes&amp;nbsp;in&amp;nbsp;13,367&amp;nbsp;blocks
	非泄漏但未释放的内存：程序退出时这些内存仍被全局/静态指针引用（如全局变量、单例模式）。
	常见情况：
	程序未主动释放全局资源（如缓存、配置对象）。
	C++&amp;nbsp;的&amp;nbsp;std::string&amp;nbsp;或容器（如&amp;nbsp;std::vector）在全局对象中持有内存。
	是否需要修复？
	如果这些内存是故意保留的（如程序重启时复用），可以忽略。
	如果是临时缓存，应在程序退出前手动释放。
	细分提示：
	stdstring:&amp;nbsp;31,621&amp;nbsp;bytes&amp;nbsp;in&amp;nbsp;839&amp;nbsp;blocks：大量字符串未释放。
	newarray:&amp;nbsp;1,104&amp;nbsp;bytes&amp;nbsp;in&amp;nbsp;4&amp;nbsp;blocks：动态数组未释放。
2.&amp;nbsp;其他关键信息
	ERROR&amp;nbsp;SUMMARY:&amp;nbsp;4871&amp;nbsp;errors&amp;nbsp;from&amp;nbsp;197&amp;nbsp;contexts
	程序存在&amp;nbsp;4871&amp;nbsp;处内存错误（如非法读写、使用未初始化值等），需结合完整日志分析。
	使用&amp;nbsp;--track-origins=yes&amp;nbsp;定位未初始化值的来源。
	Reachable&amp;nbsp;blocks&amp;nbsp;are&amp;nbsp;not&amp;nbsp;shown	默认不显示“仍可访问”的内存详情。&lt;/pre&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;</description><pubDate>Fri, 11 Jul 2025 11:53:42 +0800</pubDate></item><item><title>openEuler 24.03 docker 存储路径修改实操</title><link>https://caterwang.cn/?id=167</link><description>&lt;ul class=&quot; list-paddingleft-2&quot; style=&quot;list-style-type: disc;&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;确认原始存储路径&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;安装完docker后，它的默认存储路径是&lt;br/&gt;&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-bash&quot;&gt;/var/lib/docker&lt;/pre&gt;&lt;p&gt;如果不确定，可以通过指令&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-bash&quot;&gt;docker&amp;nbsp;info&lt;/pre&gt;&lt;p&gt;也可以直接通过指令查看&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-bash&quot;&gt;docker&amp;nbsp;info&amp;nbsp;|&amp;nbsp;grep&amp;nbsp;&amp;quot;Docker&amp;nbsp;Root&amp;nbsp;Dir&amp;quot;&lt;/pre&gt;&lt;p&gt;确认好后，记录好。&lt;/p&gt;&lt;!--more--&gt;&lt;ul class=&quot; list-paddingleft-2&quot; style=&quot;list-style-type: disc;&quot;&gt;&lt;li&gt;&lt;p&gt;停止docker服务&lt;br/&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre class=&quot;prism-highlight prism-language-bash&quot;&gt;systemctl&amp;nbsp;stop&amp;nbsp;docker.service&lt;/pre&gt;&lt;ul class=&quot; list-paddingleft-2&quot; style=&quot;list-style-type: disc;&quot;&gt;&lt;li&gt;&lt;p&gt;创建新的存储路径&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre class=&quot;prism-highlight prism-language-bash&quot;&gt;mkdir&amp;nbsp;-p&amp;nbsp;/home2/docker
chown&amp;nbsp;-R&amp;nbsp;root:root&amp;nbsp;/home2/docker&lt;/pre&gt;&lt;ul class=&quot; list-paddingleft-2&quot; style=&quot;list-style-type: disc;&quot;&gt;&lt;li&gt;&lt;p&gt;迁移同步原来存储路径的资料到新的存储路径&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre class=&quot;prism-highlight prism-language-bash&quot;&gt;rsync&amp;nbsp;-avz&amp;nbsp;/var/lib/docker/&amp;nbsp;/home2/docker&lt;/pre&gt;&lt;ul class=&quot; list-paddingleft-2&quot; style=&quot;list-style-type: disc;&quot;&gt;&lt;li&gt;&lt;p&gt;修改docker服务配置文件&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre class=&quot;prism-highlight prism-language-bash&quot;&gt;vim&amp;nbsp;/etc/systemd/system/multi-user.target.wants/docker.service&lt;/pre&gt;&lt;p&gt;找到以下位置&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-bash&quot;&gt;[Service]
ExecStart=/usr/bin/dockerd&amp;nbsp;-H&amp;nbsp;fd://&amp;nbsp;--containerd=/run/containerd/containerd.sock&lt;/pre&gt;&lt;p&gt;修改成以下内容&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-bash&quot;&gt;[Service]
ExecStart=ExecStart=/usr/bin/dockerd&amp;nbsp;--data-root=/home2/docker&lt;/pre&gt;&lt;p&gt;&lt;img class=&quot;ue-image&quot; src=&quot;https://caterwang.cn/zb_users/upload/2025/04/202504021743560310475363.png&quot; title=&quot;微信截图_20250402101806.png&quot; alt=&quot;微信截图_20250402101806.png&quot;/&gt;&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot; style=&quot;list-style-type: disc;&quot;&gt;&lt;li&gt;&lt;p&gt;重新启动docker服务&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre class=&quot;prism-highlight prism-language-bash&quot;&gt;systemctl&amp;nbsp;daemon-reload
systemctl&amp;nbsp;start&amp;nbsp;docker&lt;/pre&gt;&lt;ul class=&quot; list-paddingleft-2&quot; style=&quot;list-style-type: disc;&quot;&gt;&lt;li&gt;&lt;p&gt;查看docker服务状态&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre class=&quot;prism-highlight prism-language-bash&quot;&gt;systemctl&amp;nbsp;status&amp;nbsp;docker&lt;/pre&gt;&lt;p&gt;&lt;img class=&quot;ue-image&quot; src=&quot;https://caterwang.cn/zb_users/upload/2025/04/202504021743560030269641.png&quot; title=&quot;微信截图_20250402101211.png&quot; alt=&quot;微信截图_20250402101211.png&quot; width=&quot;860&quot; height=&quot;250&quot; border=&quot;0&quot; vspace=&quot;0&quot; style=&quot;width: 860px; height: 250px;&quot;/&gt;&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;</description><pubDate>Wed, 02 Apr 2025 09:46:50 +0800</pubDate></item><item><title>NTC热敏电阻在线计算器</title><link>https://caterwang.cn/?id=166</link><description>&lt;meta charset=&quot;UTF-8&quot;/&gt;&lt;title&gt;NTC热敏电阻计算器&lt;/title&gt;&lt;style&gt;body {
            font-family: Arial, sans-serif;
            margin: 20px;
        }
        .container {
            max-width: 600px;
            margin: 0 auto;
            padding: 20px;
            border: 1px solid #ccc;
            border-radius: 5px;
        }
        .input-group {
            margin-bottom: 15px;
        }
        label {
            display: inline-block;
            width: 120px;
        }
        input[type=&quot;number&quot;] {
            width: 150px;
            padding: 5px;
        }
        button {
            padding: 8px 15px;
            background-color: #4CAF50;
            color: white;
            border: none;
            border-radius: 4px;
            cursor: pointer;
        }
        button:hover {
            background-color: #45a049;
        }
        #result {
            margin-top: 15px;
            padding: 10px;
            border: 1px solid #ddd;
            white-space: pre-wrap;
            font-family: monospace;
        }&lt;/style&gt;&lt;div class=&quot;container&quot;&gt;&lt;h2&gt;NTC热敏电阻计算器&lt;/h2&gt;&lt;div class=&quot;input-group&quot;&gt;&lt;label&gt;B值：&lt;/label&gt;&lt;input type=&quot;number&quot; id=&quot;bValue&quot; step=&quot;any&quot; value=&quot;3275&quot; required=&quot;&quot;/&gt;&lt;/div&gt;&lt;div class=&quot;input-group&quot;&gt;&lt;label&gt;25℃标称电阻(Ω)：&lt;/label&gt;&lt;input type=&quot;number&quot; id=&quot;nominalR&quot; step=&quot;any&quot; value=&quot;10000&quot; required=&quot;&quot;/&gt;&lt;/div&gt;&lt;div class=&quot;input-group&quot;&gt;&lt;label&gt;起始温度(℃)：&lt;/label&gt;&lt;input type=&quot;number&quot; id=&quot;startTemp&quot; step=&quot;any&quot; value=&quot;-10&quot; required=&quot;&quot;/&gt;&lt;/div&gt;&lt;div class=&quot;input-group&quot;&gt;&lt;label&gt;结束温度(℃)：&lt;/label&gt;&lt;input type=&quot;number&quot; id=&quot;endTemp&quot; step=&quot;any&quot; value=&quot;10&quot; required=&quot;&quot;/&gt;&lt;/div&gt;&lt;div class=&quot;input-group&quot;&gt;&lt;label&gt;步进值(℃)：&lt;/label&gt;&lt;input type=&quot;number&quot; id=&quot;step&quot; step=&quot;any&quot; value=&quot;1&quot; required=&quot;&quot;/&gt;&lt;/div&gt;&lt;button onclick=&quot;calculate()&quot;&gt;计算&lt;/button&gt;&lt;div id=&quot;outputInfo&quot; style=&quot;margin-top: 10px; color: #666;&quot;&gt;以下输出电阻值的顺序对应的是起始温度到结束温度，单位为欧姆，步进大小与上面设置相关。&lt;/div&gt;&lt;div id=&quot;result&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;script&gt;function calculate() {
            const bValue = parseFloat(document.getElementById('bValue').value);
            const startTemp = parseFloat(document.getElementById('startTemp').value);
            const endTemp = parseFloat(document.getElementById('endTemp').value);
            const step = parseFloat(document.getElementById('step').value);
            const nominalR = parseFloat(document.getElementById('nominalR').value);
            const t0 = 25 + 273.15; // 参考温度25℃对应的开尔文温度

            let result = '';
            let count = 0;

            for (let temp = startTemp; temp &lt;= endTemp; temp += step) {
                const t1 = temp + 273.15; // 当前温度转换为开尔文温度
                const rt = nominalR * Math.exp(bValue * (1 / t1 - 1 / t0));
                result += `${rt.toFixed(2)},`;
                
                count++;
                if (count % 10 === 0) {
                    result += '\n'; // 每10个值添加换行
                }
            }

            document.getElementById('result').textContent = result;
        }&lt;/script&gt;&lt;/body&gt;&lt;/html&gt;&lt;/script&gt;&lt;!--!doctype--&gt;</description><pubDate>Tue, 25 Mar 2025 22:52:39 +0800</pubDate></item><item><title>U盘安装openEuler 24.03 LTS SP1实操记</title><link>https://caterwang.cn/?id=164</link><description>&lt;p style=&quot;-en-clipboard:true;&quot;&gt;网上虽然有安装指南，但是个人认为非常不接地气，可能是有特殊原因吧。我这里来一个接地气的，综合总结了前人的经验。重点介绍如何改造U盘内容以适应安装，确保一次成功。&lt;/p&gt;&lt;p style=&quot;-en-clipboard:true;&quot;&gt;不改造U盘内容的话会出现卡住的情况，提示：“Insaller errors encountered during boot:....”&lt;/p&gt;&lt;p style=&quot;-en-clipboard:true;&quot;&gt;&lt;img class=&quot;ue-image&quot; src=&quot;https://caterwang.cn/zb_users/upload/2025/03/202503101741598816872053.png&quot; title=&quot;微信截图_20250310172638.png&quot; alt=&quot;微信截图_20250310172638.png&quot; width=&quot;328&quot; height=&quot;287&quot; style=&quot;width: 328px; height: 287px;&quot;/&gt;&lt;img class=&quot;ue-image&quot; src=&quot;https://caterwang.cn/zb_users/upload/2025/03/202503101741598853553949.png&quot; title=&quot;微信截图_20250310172719.png&quot; alt=&quot;微信截图_20250310172719.png&quot; width=&quot;373&quot; height=&quot;290&quot; border=&quot;0&quot; vspace=&quot;0&quot; style=&quot;width: 373px; height: 290px;&quot;/&gt;&lt;/p&gt;&lt;!--more--&gt;&lt;div style=&quot;-en-clipboard:true;&quot;&gt;1.下载工具，UltraISO&lt;/div&gt;&lt;p&gt;（请自行网上搜索下载）&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;div&gt;2.下载系统镜像文件&lt;/div&gt;&lt;p&gt;&lt;a href=&quot;https://www.openeuler.org/zh/download/#openEuler%2024.03%20LTS%20SP1&quot;&gt;https://www.openeuler.org/zh/download/#openEuler%2024.03%20LTS%20SP1&lt;/a&gt;&lt;/p&gt;&lt;p style=&quot;text-align:center&quot;&gt;&lt;img class=&quot;ue-image&quot; src=&quot;https://caterwang.cn/zb_users/upload/2025/03/202503101741597885308586.png&quot; title=&quot;Image.png&quot; alt=&quot;Image.png&quot; width=&quot;900&quot; height=&quot;413&quot; border=&quot;0&quot; vspace=&quot;0&quot; style=&quot;width: 900px; height: 413px;&quot;/&gt;&lt;/p&gt;&lt;div style=&quot;-en-clipboard:true;&quot;&gt;3.制作刷机U盘&lt;/div&gt;&lt;div&gt;3.1.启动&amp;nbsp;UltraISO&lt;/div&gt;&lt;div&gt;3.2.加载下载好的镜像文件&lt;/div&gt;&lt;p style=&quot;text-align: center;&quot;&gt;&lt;img class=&quot;ue-image&quot; src=&quot;https://caterwang.cn/zb_users/upload/2025/03/202503101741597961424568.png&quot; title=&quot;Image [2].png&quot; alt=&quot;Image [2].png&quot; width=&quot;900&quot; height=&quot;555&quot; border=&quot;0&quot; vspace=&quot;0&quot; style=&quot;width: 900px; height: 555px;&quot;/&gt;&lt;/p&gt;&lt;p&gt;3.3.写入硬盘映像&lt;/p&gt;&lt;p style=&quot;text-align:center&quot;&gt;&lt;img class=&quot;ue-image&quot; src=&quot;https://caterwang.cn/zb_users/upload/2025/03/202503101741598033403177.png&quot; title=&quot;Image [2].png&quot; alt=&quot;Image [2].png&quot; width=&quot;900&quot; height=&quot;663&quot; border=&quot;0&quot; vspace=&quot;0&quot; style=&quot;width: 900px; height: 663px;&quot;/&gt;&lt;/p&gt;&lt;p style=&quot;text-align:center&quot;&gt;&lt;img class=&quot;ue-image&quot; src=&quot;https://caterwang.cn/zb_users/upload/2025/03/202503101741598088674446.png&quot; style=&quot;width: 900px; height: 664px;&quot; title=&quot;1.png&quot; width=&quot;900&quot; height=&quot;664&quot; border=&quot;0&quot; vspace=&quot;0&quot; alt=&quot;1.png&quot;/&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center;&quot;&gt;&lt;img class=&quot;ue-image&quot; src=&quot;https://caterwang.cn/zb_users/upload/2025/03/202503101741598088154707.png&quot; title=&quot;2.png&quot; width=&quot;775&quot; height=&quot;571&quot; border=&quot;0&quot; vspace=&quot;0&quot; alt=&quot;2.png&quot; style=&quot;width: 775px; height: 571px;&quot;/&gt;&lt;/p&gt;&lt;div style=&quot;-en-clipboard:true;&quot;&gt;4.修改U盘中的启动文件&lt;/div&gt;&lt;div&gt;4.1.打开“我的电脑”查看U盘标签，这里是“openEuler-2”记录好，后面要用&lt;/div&gt;&lt;p style=&quot;text-align: center;&quot;&gt;&lt;img class=&quot;ue-image&quot; src=&quot;https://caterwang.cn/zb_users/upload/2025/03/202503101741598170565155.png&quot; title=&quot;4.png&quot; alt=&quot;4.png&quot; width=&quot;900&quot; height=&quot;403&quot; border=&quot;0&quot; vspace=&quot;0&quot; style=&quot;width: 900px; height: 403px;&quot;/&gt;&lt;/p&gt;&lt;p&gt;4.2.打开U盘进入目录“H:\EFI\BOOT”&lt;/p&gt;&lt;p&gt;&lt;img class=&quot;ue-image&quot; src=&quot;https://caterwang.cn/zb_users/upload/2025/03/202503101741598226707962.png&quot; title=&quot;5.png&quot; alt=&quot;5.png&quot; width=&quot;900&quot; height=&quot;334&quot; border=&quot;0&quot; vspace=&quot;0&quot; style=&quot;width: 900px; height: 334px;&quot;/&gt;&lt;/p&gt;&lt;p&gt;编辑文件“grub.cfg”&lt;/p&gt;&lt;p&gt;&lt;img class=&quot;ue-image&quot; src=&quot;https://caterwang.cn/zb_users/upload/2025/03/202503101741598279606712.png&quot; style=&quot;width: 960px; height: 325px;&quot; title=&quot;7.png&quot; width=&quot;960&quot; height=&quot;325&quot; border=&quot;0&quot; vspace=&quot;0&quot; alt=&quot;7.png&quot;/&gt;&lt;/p&gt;&lt;p&gt;&lt;img class=&quot;ue-image&quot; src=&quot;https://caterwang.cn/zb_users/upload/2025/03/202503101741598280273912.png&quot; style=&quot;width: 960px; height: 312px;&quot; title=&quot;8.png&quot; width=&quot;960&quot; height=&quot;312&quot; border=&quot;0&quot; vspace=&quot;0&quot; alt=&quot;8.png&quot;/&gt;&lt;/p&gt;&lt;div style=&quot;-en-clipboard:true;&quot;&gt;5.准备刷机，U盘插到目标机的USU口上&lt;/div&gt;&lt;div&gt;5.1.进入主机BIOS设置为UEFI模式（&lt;strong&gt;如果主板不支持传统模式就不用改了&lt;/strong&gt;）&lt;/div&gt;&lt;p style=&quot;text-align: center;&quot;&gt;&lt;img class=&quot;ue-image&quot; src=&quot;https://caterwang.cn/zb_users/upload/2025/03/202503101741598324676674.png&quot; title=&quot;11.png&quot; alt=&quot;11.png&quot; width=&quot;900&quot; height=&quot;535&quot; border=&quot;0&quot; vspace=&quot;0&quot; style=&quot;width: 900px; height: 535px;&quot;/&gt;&lt;/p&gt;&lt;p&gt;5.2.重启选择从U盘启动--微星主板按F11/F12(要么是F11要么是F12，我是交替按，直到看到以下画面)&lt;/p&gt;&lt;p style=&quot;text-align: center;&quot;&gt;&lt;img class=&quot;ue-image&quot; src=&quot;https://caterwang.cn/zb_users/upload/2025/03/202503101741598375211097.png&quot; title=&quot;12.png&quot; alt=&quot;12.png&quot; width=&quot;900&quot; height=&quot;447&quot; border=&quot;0&quot; vspace=&quot;0&quot; style=&quot;width: 900px; height: 447px;&quot;/&gt;&lt;/p&gt;&lt;p&gt;5.3.进入启动选项，选择第二项&lt;/p&gt;&lt;p style=&quot;text-align: center;&quot;&gt;&lt;img class=&quot;ue-image&quot; src=&quot;https://caterwang.cn/zb_users/upload/2025/03/202503101741598425813494.png&quot; title=&quot;13.png&quot; alt=&quot;13.png&quot; width=&quot;900&quot; height=&quot;549&quot; border=&quot;0&quot; vspace=&quot;0&quot; style=&quot;width: 900px; height: 549px;&quot;/&gt;&lt;/p&gt;&lt;p&gt;等待一会......&lt;/p&gt;&lt;p style=&quot;text-align: center;&quot;&gt;&lt;img class=&quot;ue-image&quot; src=&quot;https://caterwang.cn/zb_users/upload/2025/03/202503101741598478664829.png&quot; title=&quot;13 [2].png&quot; alt=&quot;13 [2].png&quot; width=&quot;900&quot; height=&quot;535&quot; border=&quot;0&quot; vspace=&quot;0&quot; style=&quot;width: 900px; height: 535px;&quot;/&gt;&lt;/p&gt;&lt;div&gt;接下来就是愉快的安装过程了哈。&lt;/div&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;</description><pubDate>Mon, 10 Mar 2025 17:10:24 +0800</pubDate></item><item><title>Linux Shell脚本实现INI文件添加、删除、修改及读取操作</title><link>https://caterwang.cn/?id=163</link><description>&lt;p&gt;感谢DeepSeek大模型，生成的脚本，稍作修改即可使用。先上使用说明，后附完整代码。&lt;/p&gt;&lt;p style=&quot;text-align: center;&quot;&gt;&lt;img class=&quot;ue-image&quot; src=&quot;https://caterwang.cn/zb_users/upload/2025/03/202503061741232677313365.png&quot; title=&quot;微信截图_20250306114354.png&quot; alt=&quot;微信截图_20250306114354.png&quot; width=&quot;860&quot; height=&quot;725&quot; border=&quot;0&quot; vspace=&quot;0&quot; style=&quot;width: 860px; height: 725px;&quot;/&gt;&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-bash&quot;&gt;#!/bin/bash

VERSION=&amp;quot;1.0&amp;quot;
SCRIPT_NAME=$(basename&amp;nbsp;&amp;quot;$0&amp;quot;)

show_help()&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cat&amp;nbsp;&amp;lt;&amp;lt;&amp;nbsp;EOF
Usage:&amp;nbsp;$SCRIPT_NAME&amp;nbsp;&amp;lt;command&amp;gt;&amp;nbsp;[options]

Commands:
&amp;nbsp;&amp;nbsp;add&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Add&amp;nbsp;a&amp;nbsp;new&amp;nbsp;key-value&amp;nbsp;pair&amp;nbsp;to&amp;nbsp;a&amp;nbsp;section
&amp;nbsp;&amp;nbsp;update&amp;nbsp;&amp;nbsp;&amp;nbsp;Update&amp;nbsp;an&amp;nbsp;existing&amp;nbsp;key-value&amp;nbsp;pair
&amp;nbsp;&amp;nbsp;delete&amp;nbsp;&amp;nbsp;&amp;nbsp;Delete&amp;nbsp;a&amp;nbsp;key&amp;nbsp;or&amp;nbsp;entire&amp;nbsp;section
&amp;nbsp;&amp;nbsp;read&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Read&amp;nbsp;a&amp;nbsp;value&amp;nbsp;from&amp;nbsp;the&amp;nbsp;INI&amp;nbsp;file

Options:
&amp;nbsp;&amp;nbsp;-f,&amp;nbsp;--file&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;INI&amp;nbsp;file&amp;nbsp;path&amp;nbsp;(required)
&amp;nbsp;&amp;nbsp;-s,&amp;nbsp;--section&amp;nbsp;Section&amp;nbsp;name&amp;nbsp;(required&amp;nbsp;for&amp;nbsp;all&amp;nbsp;commands)
&amp;nbsp;&amp;nbsp;-k,&amp;nbsp;--key&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Key&amp;nbsp;name&amp;nbsp;(required&amp;nbsp;for&amp;nbsp;add/update/delete/read)
&amp;nbsp;&amp;nbsp;-v,&amp;nbsp;--value&amp;nbsp;&amp;nbsp;&amp;nbsp;Value&amp;nbsp;to&amp;nbsp;set&amp;nbsp;(required&amp;nbsp;for&amp;nbsp;add/update)

Examples:
&amp;nbsp;&amp;nbsp;$SCRIPT_NAME&amp;nbsp;add&amp;nbsp;-f&amp;nbsp;config.ini&amp;nbsp;-s&amp;nbsp;Database&amp;nbsp;-k&amp;nbsp;host&amp;nbsp;-v&amp;nbsp;localhost
&amp;nbsp;&amp;nbsp;$SCRIPT_NAME&amp;nbsp;read&amp;nbsp;-f&amp;nbsp;config.ini&amp;nbsp;-s&amp;nbsp;Database&amp;nbsp;-k&amp;nbsp;host
EOF
}

add_ini()&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;local&amp;nbsp;file=&amp;quot;$1&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;local&amp;nbsp;section=&amp;quot;$2&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;local&amp;nbsp;key=&amp;quot;$3&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;local&amp;nbsp;value=&amp;quot;$4&amp;quot;

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;Create&amp;nbsp;file&amp;nbsp;if&amp;nbsp;not&amp;nbsp;exists
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;[&amp;nbsp;-f&amp;nbsp;&amp;quot;$file&amp;quot;&amp;nbsp;]&amp;nbsp;||&amp;nbsp;touch&amp;nbsp;&amp;quot;$file&amp;quot;

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;Check&amp;nbsp;if&amp;nbsp;key&amp;nbsp;already&amp;nbsp;exists
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;grep&amp;nbsp;-q&amp;nbsp;&amp;quot;^\[$section\]&amp;quot;&amp;nbsp;&amp;quot;$file&amp;quot;;&amp;nbsp;then
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;awk&amp;nbsp;-v&amp;nbsp;section=&amp;quot;$section&amp;quot;&amp;nbsp;-v&amp;nbsp;key=&amp;quot;$key&amp;quot;&amp;nbsp;&amp;#39;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;BEGIN&amp;nbsp;{&amp;nbsp;in_section&amp;nbsp;=&amp;nbsp;0&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;/^\[.*\]$/&amp;nbsp;{&amp;nbsp;in_section&amp;nbsp;=&amp;nbsp;($0&amp;nbsp;==&amp;nbsp;&amp;quot;[&amp;quot;&amp;nbsp;section&amp;nbsp;&amp;quot;]&amp;quot;)&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;in_section&amp;nbsp;&amp;amp;&amp;amp;&amp;nbsp;$1&amp;nbsp;==&amp;nbsp;key&amp;nbsp;{&amp;nbsp;found&amp;nbsp;=&amp;nbsp;1;&amp;nbsp;exit&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;END&amp;nbsp;{&amp;nbsp;exit&amp;nbsp;!found&amp;nbsp;}&amp;#39;&amp;nbsp;FS=&amp;#39;=&amp;#39;&amp;nbsp;&amp;quot;$file&amp;quot;;&amp;nbsp;then
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;echo&amp;nbsp;&amp;quot;Error:&amp;nbsp;Key&amp;nbsp;&amp;#39;$key&amp;#39;&amp;nbsp;already&amp;nbsp;exists&amp;nbsp;in&amp;nbsp;section&amp;nbsp;[$section]&amp;quot;&amp;nbsp;&amp;gt;&amp;amp;2
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;1
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;fi
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;fi

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;Add&amp;nbsp;new&amp;nbsp;entry
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;!&amp;nbsp;grep&amp;nbsp;-q&amp;nbsp;&amp;quot;^\[$section\]&amp;quot;&amp;nbsp;&amp;quot;$file&amp;quot;;&amp;nbsp;then
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;Section&amp;nbsp;doesn&amp;#39;t&amp;nbsp;exist,&amp;nbsp;append&amp;nbsp;to&amp;nbsp;end
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;printf&amp;nbsp;&amp;quot;\n[%s]\n%s=%s\n&amp;quot;&amp;nbsp;&amp;quot;$section&amp;quot;&amp;nbsp;&amp;quot;$key&amp;quot;&amp;nbsp;&amp;quot;$value&amp;quot;&amp;nbsp;&amp;gt;&amp;gt;&amp;nbsp;&amp;quot;$file&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;Section&amp;nbsp;exists,&amp;nbsp;insert&amp;nbsp;after&amp;nbsp;section&amp;nbsp;header
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sed&amp;nbsp;-i.bak&amp;nbsp;-e&amp;nbsp;&amp;quot;/^\[$section\]/a&amp;nbsp;$key=$value&amp;quot;&amp;nbsp;&amp;quot;$file&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;fi
}

update_ini()&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;local&amp;nbsp;file=&amp;quot;$1&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;local&amp;nbsp;section=&amp;quot;$2&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;local&amp;nbsp;key=&amp;quot;$3&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;local&amp;nbsp;value=&amp;quot;$4&amp;quot;

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;Verify&amp;nbsp;section&amp;nbsp;exists
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;!&amp;nbsp;grep&amp;nbsp;-q&amp;nbsp;&amp;quot;^\[$section\]&amp;quot;&amp;nbsp;&amp;quot;$file&amp;quot;;&amp;nbsp;then
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;echo&amp;nbsp;&amp;quot;Error:&amp;nbsp;Section&amp;nbsp;[$section]&amp;nbsp;does&amp;nbsp;not&amp;nbsp;exist&amp;quot;&amp;nbsp;&amp;gt;&amp;amp;2
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;1
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;fi

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;Verify&amp;nbsp;key&amp;nbsp;exists
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;!&amp;nbsp;awk&amp;nbsp;-v&amp;nbsp;section=&amp;quot;$section&amp;quot;&amp;nbsp;-v&amp;nbsp;key=&amp;quot;$key&amp;quot;&amp;nbsp;&amp;#39;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;BEGIN&amp;nbsp;{&amp;nbsp;in_section&amp;nbsp;=&amp;nbsp;0&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;/^\[.*\]$/&amp;nbsp;{&amp;nbsp;in_section&amp;nbsp;=&amp;nbsp;($0&amp;nbsp;==&amp;nbsp;&amp;quot;[&amp;quot;&amp;nbsp;section&amp;nbsp;&amp;quot;]&amp;quot;)&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;in_section&amp;nbsp;&amp;amp;&amp;amp;&amp;nbsp;$1&amp;nbsp;==&amp;nbsp;key&amp;nbsp;{&amp;nbsp;found&amp;nbsp;=&amp;nbsp;1;&amp;nbsp;exit&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;END&amp;nbsp;{&amp;nbsp;exit&amp;nbsp;!found&amp;nbsp;}&amp;#39;&amp;nbsp;FS=&amp;#39;=&amp;#39;&amp;nbsp;&amp;quot;$file&amp;quot;;&amp;nbsp;then
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;echo&amp;nbsp;&amp;quot;Error:&amp;nbsp;Key&amp;nbsp;&amp;#39;$key&amp;#39;&amp;nbsp;not&amp;nbsp;found&amp;nbsp;in&amp;nbsp;section&amp;nbsp;[$section]&amp;quot;&amp;nbsp;&amp;gt;&amp;amp;2
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;1
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;fi

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;Update&amp;nbsp;value
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sed&amp;nbsp;-i.bak&amp;nbsp;-e&amp;nbsp;&amp;quot;/^\[$section\]/,/^\[/s/^$key\s*=.*/$key=$value/&amp;quot;&amp;nbsp;&amp;quot;$file&amp;quot;
}

delete_ini()&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;local&amp;nbsp;file=&amp;quot;$1&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;local&amp;nbsp;section=&amp;quot;$2&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;local&amp;nbsp;key=&amp;quot;$3&amp;quot;

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;[&amp;nbsp;-z&amp;nbsp;&amp;quot;$key&amp;quot;&amp;nbsp;];&amp;nbsp;then
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;Delete&amp;nbsp;entire&amp;nbsp;section
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sed&amp;nbsp;-i.bak&amp;nbsp;-e&amp;nbsp;&amp;quot;/^\[$section\]/,/^\[.*\]/&amp;nbsp;{&amp;nbsp;/^\[$section\]/d;&amp;nbsp;/^\[.*\]/!d;&amp;nbsp;}&amp;quot;&amp;nbsp;&amp;quot;$file&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;Delete&amp;nbsp;specific&amp;nbsp;key
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sed&amp;nbsp;-i.bak&amp;nbsp;-e&amp;nbsp;&amp;quot;/^\[$section\]/,/^\[/&amp;nbsp;{&amp;nbsp;/^$key\s*=/d&amp;nbsp;}&amp;quot;&amp;nbsp;&amp;quot;$file&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;fi
}

read_ini()&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;local&amp;nbsp;file=&amp;quot;$1&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;local&amp;nbsp;section=&amp;quot;$2&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;local&amp;nbsp;key=&amp;quot;$3&amp;quot;
	local&amp;nbsp;found=0
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;awk&amp;nbsp;-v&amp;nbsp;section=&amp;quot;$section&amp;quot;&amp;nbsp;-v&amp;nbsp;key=&amp;quot;$key&amp;quot;&amp;nbsp;&amp;#39;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;BEGIN&amp;nbsp;{&amp;nbsp;FS&amp;nbsp;=&amp;nbsp;&amp;quot;=&amp;quot;;&amp;nbsp;in_section&amp;nbsp;=&amp;nbsp;0&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;/^\[.*\]$/&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;in_section&amp;nbsp;=&amp;nbsp;($0&amp;nbsp;==&amp;nbsp;&amp;quot;[&amp;quot;&amp;nbsp;section&amp;nbsp;&amp;quot;]&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;in_section&amp;nbsp;&amp;amp;&amp;amp;&amp;nbsp;$1&amp;nbsp;==&amp;nbsp;key&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print&amp;nbsp;$2
			found&amp;nbsp;=&amp;nbsp;1
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;exit
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;END&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;(!found)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;(!in_section)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print&amp;nbsp;&amp;quot;Error:&amp;nbsp;Section&amp;nbsp;[$section]&amp;nbsp;not&amp;nbsp;found&amp;quot;&amp;nbsp;&amp;gt;&amp;nbsp;&amp;quot;/dev/stderr&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&amp;nbsp;else&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print&amp;nbsp;&amp;quot;Error:&amp;nbsp;Key&amp;nbsp;&amp;#39;$key&amp;#39;&amp;nbsp;not&amp;nbsp;found&amp;quot;&amp;nbsp;&amp;gt;&amp;nbsp;&amp;quot;/dev/stderr&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;exit&amp;nbsp;1
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;&amp;nbsp;&amp;quot;$file&amp;quot;
}

#&amp;nbsp;Main&amp;nbsp;command&amp;nbsp;processing
case&amp;nbsp;$1&amp;nbsp;in
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;add|update|delete|read)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cmd=$1
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;shift
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;;;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;-h|--help)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;show_help
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;exit&amp;nbsp;0
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;;;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;-v|--version)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;echo&amp;nbsp;&amp;quot;$SCRIPT_NAME&amp;nbsp;version&amp;nbsp;$VERSION&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;exit&amp;nbsp;0
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;;;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;*)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;echo&amp;nbsp;&amp;quot;Error:&amp;nbsp;Unknown&amp;nbsp;command&amp;nbsp;&amp;#39;$1&amp;#39;&amp;quot;&amp;nbsp;&amp;gt;&amp;amp;2
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;show_help
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;exit&amp;nbsp;1
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;;;
esac

#&amp;nbsp;Parse&amp;nbsp;common&amp;nbsp;options
file=&amp;quot;&amp;quot;
section=&amp;quot;&amp;quot;
key=&amp;quot;&amp;quot;
value=&amp;quot;&amp;quot;

while&amp;nbsp;[[&amp;nbsp;$#&amp;nbsp;-gt&amp;nbsp;0&amp;nbsp;]];&amp;nbsp;do
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;case&amp;nbsp;$1&amp;nbsp;in
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;-f|--file)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;file=&amp;quot;$2&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;shift&amp;nbsp;2
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;;;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;-s|--section)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;section=&amp;quot;$2&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;shift&amp;nbsp;2
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;;;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;-k|--key)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;key=&amp;quot;$2&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;shift&amp;nbsp;2
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;;;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;-v|--value)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;value=&amp;quot;$2&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;shift&amp;nbsp;2
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;;;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;--)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;shift
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;break
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;;;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;-*)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;echo&amp;nbsp;&amp;quot;Error:&amp;nbsp;Invalid&amp;nbsp;option&amp;nbsp;&amp;#39;$1&amp;#39;&amp;quot;&amp;nbsp;&amp;gt;&amp;amp;2
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;exit&amp;nbsp;1
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;;;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;*)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;break
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;;;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;esac
done

#&amp;nbsp;Validate&amp;nbsp;required&amp;nbsp;parameters
[&amp;nbsp;-z&amp;nbsp;&amp;quot;$file&amp;quot;&amp;nbsp;]&amp;nbsp;&amp;amp;&amp;amp;&amp;nbsp;{&amp;nbsp;echo&amp;nbsp;&amp;quot;Error:&amp;nbsp;Missing&amp;nbsp;--file&amp;nbsp;parameter&amp;quot;&amp;nbsp;&amp;gt;&amp;amp;2;&amp;nbsp;exit&amp;nbsp;1;&amp;nbsp;}
[&amp;nbsp;-z&amp;nbsp;&amp;quot;$section&amp;quot;&amp;nbsp;]&amp;nbsp;&amp;amp;&amp;amp;&amp;nbsp;{&amp;nbsp;echo&amp;nbsp;&amp;quot;Error:&amp;nbsp;Missing&amp;nbsp;--section&amp;nbsp;parameter&amp;quot;&amp;nbsp;&amp;gt;&amp;amp;2;&amp;nbsp;exit&amp;nbsp;1;&amp;nbsp;}

case&amp;nbsp;$cmd&amp;nbsp;in
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;add|update)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;[&amp;nbsp;-z&amp;nbsp;&amp;quot;$key&amp;quot;&amp;nbsp;]&amp;nbsp;&amp;amp;&amp;amp;&amp;nbsp;{&amp;nbsp;echo&amp;nbsp;&amp;quot;Error:&amp;nbsp;Missing&amp;nbsp;--key&amp;nbsp;parameter&amp;quot;&amp;nbsp;&amp;gt;&amp;amp;2;&amp;nbsp;exit&amp;nbsp;1;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;[&amp;nbsp;-z&amp;nbsp;&amp;quot;$value&amp;quot;&amp;nbsp;]&amp;nbsp;&amp;amp;&amp;amp;&amp;nbsp;{&amp;nbsp;echo&amp;nbsp;&amp;quot;Error:&amp;nbsp;Missing&amp;nbsp;--value&amp;nbsp;parameter&amp;quot;&amp;nbsp;&amp;gt;&amp;amp;2;&amp;nbsp;exit&amp;nbsp;1;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;;;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;delete|read)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;[&amp;nbsp;-z&amp;nbsp;&amp;quot;$key&amp;quot;&amp;nbsp;]&amp;nbsp;&amp;amp;&amp;amp;&amp;nbsp;key=&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;;;
esac

#&amp;nbsp;Execute&amp;nbsp;command
case&amp;nbsp;$cmd&amp;nbsp;in
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;add)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;add_ini&amp;nbsp;&amp;quot;$file&amp;quot;&amp;nbsp;&amp;quot;$section&amp;quot;&amp;nbsp;&amp;quot;$key&amp;quot;&amp;nbsp;&amp;quot;$value&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;;;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;update)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;update_ini&amp;nbsp;&amp;quot;$file&amp;quot;&amp;nbsp;&amp;quot;$section&amp;quot;&amp;nbsp;&amp;quot;$key&amp;quot;&amp;nbsp;&amp;quot;$value&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;;;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;delete)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;delete_ini&amp;nbsp;&amp;quot;$file&amp;quot;&amp;nbsp;&amp;quot;$section&amp;quot;&amp;nbsp;&amp;quot;$key&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;;;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;read)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;read_ini&amp;nbsp;&amp;quot;$file&amp;quot;&amp;nbsp;&amp;quot;$section&amp;quot;&amp;nbsp;&amp;quot;$key&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;;;
esac&lt;/pre&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;</description><pubDate>Thu, 06 Mar 2025 11:39:27 +0800</pubDate></item><item><title>DeepSeek 的 Coder、Chat 和 Reasoner 模型的区别</title><link>https://caterwang.cn/?id=162</link><description>&lt;p&gt;&lt;span style=&quot;font-size: 16px;&quot;&gt;&lt;strong&gt;&lt;span style=&quot;color: #FF0000;&quot;&gt;以下内容引自DeepSeek问答，仅供参考&lt;/span&gt;&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;&lt;h3 style=&quot;font-weight: var(--ds-font-weight-strong); font-size: calc(var(--ds-md-zoom)*16px); line-height: 1.5; margin: calc(var(--ds-md-zoom)*16px)0 calc(var(--ds-md-zoom)*12px)0; color: rgb(64, 64, 64); font-family: Inter, system-ui, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, &amp;quot;Noto Sans&amp;quot;, Ubuntu, Cantarell, &amp;quot;Helvetica Neue&amp;quot;, Oxygen, &amp;quot;Open Sans&amp;quot;, sans-serif; text-wrap-mode: wrap;&quot;&gt;&lt;strong&gt;1. DeepSeek-Coder&lt;/strong&gt;&lt;/h3&gt;&lt;ul style=&quot;margin: calc(var(--ds-md-zoom)*12px)0; padding-left: calc(var(--ds-md-zoom)*24px); color: rgb(64, 64, 64); font-family: Inter, system-ui, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, &amp;quot;Noto Sans&amp;quot;, Ubuntu, Cantarell, &amp;quot;Helvetica Neue&amp;quot;, Oxygen, &amp;quot;Open Sans&amp;quot;, sans-serif; font-size: 16.002px; text-wrap-mode: wrap;&quot; class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p style=&quot;margin-top: 0px; font-size: var(--ds-md-font-size); line-height: var(--ds-md-line-height); margin-bottom: 0px !important;&quot;&gt;&lt;strong&gt;定位&lt;/strong&gt;：&lt;strong&gt;代码生成与理解&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&quot;margin-top: 0px; margin-bottom: 4px; font-size: var(--ds-md-font-size); line-height: var(--ds-md-line-height);&quot;&gt;&lt;strong&gt;特点&lt;/strong&gt;：&lt;/p&gt;&lt;/li&gt;&lt;ul style=&quot;list-style-type: square;&quot; class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p style=&quot;margin-top: 0px; font-size: var(--ds-md-font-size); line-height: var(--ds-md-line-height); margin-bottom: 0px !important;&quot;&gt;&lt;strong&gt;支持 300+ 编程语言&lt;/strong&gt;，擅长生成代码片段、补全代码、修复错误、代码注释等。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&quot;margin-top: 0px; font-size: var(--ds-md-font-size); line-height: var(--ds-md-line-height); margin-bottom: 0px !important;&quot;&gt;&lt;strong&gt;长上下文支持&lt;/strong&gt;：最高支持&amp;nbsp;&lt;strong&gt;16K Token&lt;/strong&gt;&amp;nbsp;上下文，适合处理复杂代码工程。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&quot;margin-top: 0px; font-size: var(--ds-md-font-size); line-height: var(--ds-md-line-height); margin-bottom: 0px !important;&quot;&gt;&lt;strong&gt;评测表现&lt;/strong&gt;：在 HumanEval、MBPP 等代码评测中超越同规模模型（如 CodeLlama）。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&quot;margin-top: 0px; font-size: var(--ds-md-font-size); line-height: var(--ds-md-line-height); margin-bottom: 0px !important;&quot;&gt;&lt;strong&gt;规模选择&lt;/strong&gt;：提供 1.3B、5.7B、6.7B、33B 多种参数版本，适配不同算力需求。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;&lt;p style=&quot;margin-top: 0px; margin-bottom: 4px; font-size: var(--ds-md-font-size); line-height: var(--ds-md-line-height);&quot;&gt;&lt;strong&gt;适用场景&lt;/strong&gt;：&lt;/p&gt;&lt;/li&gt;&lt;ul style=&quot;list-style-type: square;&quot; class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p style=&quot;margin-top: 0px; font-size: var(--ds-md-font-size); line-height: var(--ds-md-line-height); margin-bottom: 0px !important;&quot;&gt;开发者辅助编程工具&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&quot;margin-top: 0px; font-size: var(--ds-md-font-size); line-height: var(--ds-md-line-height); margin-bottom: 0px !important;&quot;&gt;代码库分析与自动化&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&quot;margin-top: 0px; font-size: var(--ds-md-font-size); line-height: var(--ds-md-line-height); margin-bottom: 0px !important;&quot;&gt;编程教育（如代码纠错教学）&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;hr style=&quot;height: 1px; margin: calc(var(--ds-md-zoom)*12px)0; background-image: ; background-position-x: ; background-position-y: ; background-size: ; background-repeat: ; background-attachment: ; background-origin: ; background-clip: ; border: none; color: rgb(64, 64, 64); font-family: Inter, system-ui, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, &amp;quot;Noto Sans&amp;quot;, Ubuntu, Cantarell, &amp;quot;Helvetica Neue&amp;quot;, Oxygen, &amp;quot;Open Sans&amp;quot;, sans-serif; font-size: 16.002px; text-wrap-mode: wrap;&quot;/&gt;&lt;h3 style=&quot;font-weight: var(--ds-font-weight-strong); font-size: calc(var(--ds-md-zoom)*16px); line-height: 1.5; margin: calc(var(--ds-md-zoom)*16px)0 calc(var(--ds-md-zoom)*12px)0; color: rgb(64, 64, 64); font-family: Inter, system-ui, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, &amp;quot;Noto Sans&amp;quot;, Ubuntu, Cantarell, &amp;quot;Helvetica Neue&amp;quot;, Oxygen, &amp;quot;Open Sans&amp;quot;, sans-serif; text-wrap-mode: wrap;&quot;&gt;&lt;strong&gt;2. DeepSeek-Chat&lt;/strong&gt;&lt;/h3&gt;&lt;ul style=&quot;margin: calc(var(--ds-md-zoom)*12px)0; padding-left: calc(var(--ds-md-zoom)*24px); color: rgb(64, 64, 64); font-family: Inter, system-ui, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, &amp;quot;Noto Sans&amp;quot;, Ubuntu, Cantarell, &amp;quot;Helvetica Neue&amp;quot;, Oxygen, &amp;quot;Open Sans&amp;quot;, sans-serif; font-size: 16.002px; text-wrap-mode: wrap;&quot; class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p style=&quot;margin-top: 0px; font-size: var(--ds-md-font-size); line-height: var(--ds-md-line-height); margin-bottom: 0px !important;&quot;&gt;&lt;strong&gt;定位&lt;/strong&gt;：&lt;strong&gt;通用对话与交互&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&quot;margin-top: 0px; margin-bottom: 4px; font-size: var(--ds-md-font-size); line-height: var(--ds-md-line-height);&quot;&gt;&lt;strong&gt;特点&lt;/strong&gt;：&lt;/p&gt;&lt;/li&gt;&lt;ul style=&quot;list-style-type: square;&quot; class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p style=&quot;margin-top: 0px; font-size: var(--ds-md-font-size); line-height: var(--ds-md-line-height); margin-bottom: 0px !important;&quot;&gt;&lt;strong&gt;多轮对话优化&lt;/strong&gt;：擅长理解上下文、生成自然流畅的回复。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&quot;margin-top: 0px; font-size: var(--ds-md-font-size); line-height: var(--ds-md-line-height); margin-bottom: 0px !important;&quot;&gt;&lt;strong&gt;多语言支持&lt;/strong&gt;：中英文表现均衡，兼顾知识问答、文本创作、逻辑推理等综合能力。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&quot;margin-top: 0px; font-size: var(--ds-md-font-size); line-height: var(--ds-md-line-height); margin-bottom: 0px !important;&quot;&gt;&lt;strong&gt;安全对齐&lt;/strong&gt;：通过 RLHF 等技术减少有害输出，符合实际应用需求。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&quot;margin-top: 0px; font-size: var(--ds-md-font-size); line-height: var(--ds-md-line-height); margin-bottom: 0px !important;&quot;&gt;&lt;strong&gt;模型规模&lt;/strong&gt;：通常基于 7B/67B 参数版本，支持 4K~32K Token 上下文。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;&lt;p style=&quot;margin-top: 0px; margin-bottom: 4px; font-size: var(--ds-md-font-size); line-height: var(--ds-md-line-height);&quot;&gt;&lt;strong&gt;适用场景&lt;/strong&gt;：&lt;/p&gt;&lt;/li&gt;&lt;ul style=&quot;list-style-type: square;&quot; class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p style=&quot;margin-top: 0px; font-size: var(--ds-md-font-size); line-height: var(--ds-md-line-height); margin-bottom: 0px !important;&quot;&gt;智能客服、虚拟助手&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&quot;margin-top: 0px; font-size: var(--ds-md-font-size); line-height: var(--ds-md-line-height); margin-bottom: 0px !important;&quot;&gt;内容创作（如文案生成）&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&quot;margin-top: 0px; font-size: var(--ds-md-font-size); line-height: var(--ds-md-line-height); margin-bottom: 0px !important;&quot;&gt;日常问答与信息检索&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;hr style=&quot;height: 1px; margin: calc(var(--ds-md-zoom)*12px)0; background-image: ; background-position-x: ; background-position-y: ; background-size: ; background-repeat: ; background-attachment: ; background-origin: ; background-clip: ; border: none; color: rgb(64, 64, 64); font-family: Inter, system-ui, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, &amp;quot;Noto Sans&amp;quot;, Ubuntu, Cantarell, &amp;quot;Helvetica Neue&amp;quot;, Oxygen, &amp;quot;Open Sans&amp;quot;, sans-serif; font-size: 16.002px; text-wrap-mode: wrap;&quot;/&gt;&lt;h3 style=&quot;font-weight: var(--ds-font-weight-strong); font-size: calc(var(--ds-md-zoom)*16px); line-height: 1.5; margin: calc(var(--ds-md-zoom)*16px)0 calc(var(--ds-md-zoom)*12px)0; color: rgb(64, 64, 64); font-family: Inter, system-ui, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, &amp;quot;Noto Sans&amp;quot;, Ubuntu, Cantarell, &amp;quot;Helvetica Neue&amp;quot;, Oxygen, &amp;quot;Open Sans&amp;quot;, sans-serif; text-wrap-mode: wrap;&quot;&gt;&lt;strong&gt;3. DeepSeek-Reasoner&lt;/strong&gt;&lt;/h3&gt;&lt;ul style=&quot;margin: calc(var(--ds-md-zoom)*12px)0; padding-left: calc(var(--ds-md-zoom)*24px); color: rgb(64, 64, 64); font-family: Inter, system-ui, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, &amp;quot;Noto Sans&amp;quot;, Ubuntu, Cantarell, &amp;quot;Helvetica Neue&amp;quot;, Oxygen, &amp;quot;Open Sans&amp;quot;, sans-serif; font-size: 16.002px; text-wrap-mode: wrap;&quot; class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p style=&quot;margin-top: 0px; font-size: var(--ds-md-font-size); line-height: var(--ds-md-line-height); margin-bottom: 0px !important;&quot;&gt;&lt;strong&gt;定位&lt;/strong&gt;：&lt;strong&gt;数学与逻辑推理&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&quot;margin-top: 0px; margin-bottom: 4px; font-size: var(--ds-md-font-size); line-height: var(--ds-md-line-height);&quot;&gt;&lt;strong&gt;特点&lt;/strong&gt;：&lt;/p&gt;&lt;/li&gt;&lt;ul style=&quot;list-style-type: square;&quot; class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p style=&quot;margin-top: 0px; font-size: var(--ds-md-font-size); line-height: var(--ds-md-line-height); margin-bottom: 0px !important;&quot;&gt;&lt;strong&gt;推理过程优化&lt;/strong&gt;：通过强化学习（RL）和过程监督（Process Supervision）提升分步推理能力。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&quot;margin-top: 0px; font-size: var(--ds-md-font-size); line-height: var(--ds-md-line-height); margin-bottom: 0px !important;&quot;&gt;&lt;strong&gt;数学能力突出&lt;/strong&gt;：在 MATH、GSM8K 等数学评测中达到 SOTA（尤其是 7B 小模型）。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&quot;margin-top: 0px; font-size: var(--ds-md-font-size); line-height: var(--ds-md-line-height); margin-bottom: 0px !important;&quot;&gt;&lt;strong&gt;可解释性&lt;/strong&gt;：生成详细解题步骤，便于验证逻辑正确性。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&quot;margin-top: 0px; font-size: var(--ds-md-font-size); line-height: var(--ds-md-line-height); margin-bottom: 0px !important;&quot;&gt;&lt;strong&gt;训练数据&lt;/strong&gt;：融合数学问题、定理证明、符号推理等专项数据。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;&lt;p style=&quot;margin-top: 0px; margin-bottom: 4px; font-size: var(--ds-md-font-size); line-height: var(--ds-md-line-height);&quot;&gt;&lt;strong&gt;适用场景&lt;/strong&gt;：&lt;/p&gt;&lt;/li&gt;&lt;ul style=&quot;list-style-type: square;&quot; class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p style=&quot;margin-top: 0px; font-size: var(--ds-md-font-size); line-height: var(--ds-md-line-height); margin-bottom: 0px !important;&quot;&gt;数学题目求解与辅导&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&quot;margin-top: 0px; font-size: var(--ds-md-font-size); line-height: var(--ds-md-line-height); margin-bottom: 0px !important;&quot;&gt;复杂逻辑问题分析&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&quot;margin-top: 0px; font-size: var(--ds-md-font-size); line-height: var(--ds-md-line-height); margin-bottom: 0px !important;&quot;&gt;学术研究中的符号推理任务&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;hr style=&quot;height: 1px; margin: calc(var(--ds-md-zoom)*12px)0; background-image: ; background-position-x: ; background-position-y: ; background-size: ; background-repeat: ; background-attachment: ; background-origin: ; background-clip: ; border: none; color: rgb(64, 64, 64); font-family: Inter, system-ui, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, &amp;quot;Noto Sans&amp;quot;, Ubuntu, Cantarell, &amp;quot;Helvetica Neue&amp;quot;, Oxygen, &amp;quot;Open Sans&amp;quot;, sans-serif; font-size: 16.002px; text-wrap-mode: wrap;&quot;/&gt;&lt;h3 style=&quot;font-weight: var(--ds-font-weight-strong); font-size: calc(var(--ds-md-zoom)*16px); line-height: 1.5; margin: calc(var(--ds-md-zoom)*16px)0 calc(var(--ds-md-zoom)*12px)0; color: rgb(64, 64, 64); font-family: Inter, system-ui, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, &amp;quot;Noto Sans&amp;quot;, Ubuntu, Cantarell, &amp;quot;Helvetica Neue&amp;quot;, Oxygen, &amp;quot;Open Sans&amp;quot;, sans-serif; text-wrap-mode: wrap;&quot;&gt;&lt;strong&gt;对比总结&lt;/strong&gt;&lt;/h3&gt;&lt;table&gt;&lt;thead&gt;&lt;tr class=&quot;firstRow&quot;&gt;&lt;th style=&quot;color: rgb(var(--ds-rgb-label-1)); padding-left: 0px; border-bottom: 1px solid rgb(var(--ds-rgb-label-3)); border-top: 1px solid rgb(var(--ds-rgb-label-3)); text-align: left;&quot;&gt;&lt;strong&gt;维度&lt;/strong&gt;&lt;/th&gt;&lt;th style=&quot;color: rgb(var(--ds-rgb-label-1)); padding: calc(var(--ds-md-zoom)*6px)calc(var(--ds-md-zoom)*12px); border-bottom: 1px solid rgb(var(--ds-rgb-label-3)); border-top: 1px solid rgb(var(--ds-rgb-label-3)); text-align: left;&quot;&gt;&lt;strong&gt;Coder&lt;/strong&gt;&lt;/th&gt;&lt;th style=&quot;color: rgb(var(--ds-rgb-label-1)); padding: calc(var(--ds-md-zoom)*6px)calc(var(--ds-md-zoom)*12px); border-bottom: 1px solid rgb(var(--ds-rgb-label-3)); border-top: 1px solid rgb(var(--ds-rgb-label-3)); text-align: left;&quot;&gt;&lt;strong&gt;Chat&lt;/strong&gt;&lt;/th&gt;&lt;th style=&quot;color: rgb(var(--ds-rgb-label-1)); padding: calc(var(--ds-md-zoom)*6px)calc(var(--ds-md-zoom)*12px); border-bottom: 1px solid rgb(var(--ds-rgb-label-3)); border-top: 1px solid rgb(var(--ds-rgb-label-3)); text-align: left;&quot;&gt;&lt;strong&gt;Reasoner&lt;/strong&gt;&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=&quot;padding-top: ; padding-right: ; padding-bottom: ; padding-left: 0px; border-bottom: 1px solid rgb(var(--ds-rgb-label-3));&quot;&gt;&lt;strong&gt;核心能力&lt;/strong&gt;&lt;/td&gt;&lt;td style=&quot;padding: calc(var(--ds-md-zoom)*6px)calc(var(--ds-md-zoom)*12px); border-bottom: 1px solid rgb(var(--ds-rgb-label-3));&quot;&gt;代码生成与理解&lt;/td&gt;&lt;td style=&quot;padding: calc(var(--ds-md-zoom)*6px)calc(var(--ds-md-zoom)*12px); border-bottom: 1px solid rgb(var(--ds-rgb-label-3));&quot;&gt;通用对话交互&lt;/td&gt;&lt;td style=&quot;padding: calc(var(--ds-md-zoom)*6px)calc(var(--ds-md-zoom)*12px); border-bottom: 1px solid rgb(var(--ds-rgb-label-3));&quot;&gt;数学与逻辑推理&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;padding-top: ; padding-right: ; padding-bottom: ; padding-left: 0px; border-bottom: 1px solid rgb(var(--ds-rgb-label-3));&quot;&gt;&lt;strong&gt;关键数据&lt;/strong&gt;&lt;/td&gt;&lt;td style=&quot;padding: calc(var(--ds-md-zoom)*6px)calc(var(--ds-md-zoom)*12px); border-bottom: 1px solid rgb(var(--ds-rgb-label-3));&quot;&gt;代码仓库、编程文档&lt;/td&gt;&lt;td style=&quot;padding: calc(var(--ds-md-zoom)*6px)calc(var(--ds-md-zoom)*12px); border-bottom: 1px solid rgb(var(--ds-rgb-label-3));&quot;&gt;多轮对话语料、百科知识&lt;/td&gt;&lt;td style=&quot;padding: calc(var(--ds-md-zoom)*6px)calc(var(--ds-md-zoom)*12px); border-bottom: 1px solid rgb(var(--ds-rgb-label-3));&quot;&gt;数学问题、定理证明&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;padding-top: ; padding-right: ; padding-bottom: ; padding-left: 0px; border-bottom: 1px solid rgb(var(--ds-rgb-label-3));&quot;&gt;&lt;strong&gt;技术亮点&lt;/strong&gt;&lt;/td&gt;&lt;td style=&quot;padding: calc(var(--ds-md-zoom)*6px)calc(var(--ds-md-zoom)*12px); border-bottom: 1px solid rgb(var(--ds-rgb-label-3));&quot;&gt;长上下文代码建模&lt;/td&gt;&lt;td style=&quot;padding: calc(var(--ds-md-zoom)*6px)calc(var(--ds-md-zoom)*12px); border-bottom: 1px solid rgb(var(--ds-rgb-label-3));&quot;&gt;安全对齐与多轮交互优化&lt;/td&gt;&lt;td style=&quot;padding: calc(var(--ds-md-zoom)*6px)calc(var(--ds-md-zoom)*12px); border-bottom: 1px solid rgb(var(--ds-rgb-label-3));&quot;&gt;过程监督强化推理&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;padding-top: ; padding-right: ; padding-bottom: ; padding-left: 0px; border-bottom: 1px solid rgb(var(--ds-rgb-label-3));&quot;&gt;&lt;strong&gt;典型应用&lt;/strong&gt;&lt;/td&gt;&lt;td style=&quot;padding: calc(var(--ds-md-zoom)*6px)calc(var(--ds-md-zoom)*12px); border-bottom: 1px solid rgb(var(--ds-rgb-label-3));&quot;&gt;IDE 插件、代码自动化&lt;/td&gt;&lt;td style=&quot;padding: calc(var(--ds-md-zoom)*6px)calc(var(--ds-md-zoom)*12px); border-bottom: 1px solid rgb(var(--ds-rgb-label-3));&quot;&gt;客服、内容生成&lt;/td&gt;&lt;td style=&quot;padding: calc(var(--ds-md-zoom)*6px)calc(var(--ds-md-zoom)*12px); border-bottom: 1px solid rgb(var(--ds-rgb-label-3));&quot;&gt;教育、科研分析&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;hr style=&quot;height: 1px; margin: calc(var(--ds-md-zoom)*12px)0; background-image: ; background-position-x: ; background-position-y: ; background-size: ; background-repeat: ; background-attachment: ; background-origin: ; background-clip: ; border: none; color: rgb(64, 64, 64); font-family: Inter, system-ui, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, &amp;quot;Noto Sans&amp;quot;, Ubuntu, Cantarell, &amp;quot;Helvetica Neue&amp;quot;, Oxygen, &amp;quot;Open Sans&amp;quot;, sans-serif; font-size: 16.002px; text-wrap-mode: wrap;&quot;/&gt;&lt;h3 style=&quot;font-weight: var(--ds-font-weight-strong); font-size: calc(var(--ds-md-zoom)*16px); line-height: 1.5; margin: calc(var(--ds-md-zoom)*16px)0 calc(var(--ds-md-zoom)*12px)0; color: rgb(64, 64, 64); font-family: Inter, system-ui, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, &amp;quot;Noto Sans&amp;quot;, Ubuntu, Cantarell, &amp;quot;Helvetica Neue&amp;quot;, Oxygen, &amp;quot;Open Sans&amp;quot;, sans-serif; text-wrap-mode: wrap;&quot;&gt;&lt;strong&gt;选择建议&lt;/strong&gt;&lt;/h3&gt;&lt;ul style=&quot;margin: calc(var(--ds-md-zoom)*12px)0; padding-left: calc(var(--ds-md-zoom)*24px); color: rgb(64, 64, 64); font-family: Inter, system-ui, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, &amp;quot;Noto Sans&amp;quot;, Ubuntu, Cantarell, &amp;quot;Helvetica Neue&amp;quot;, Oxygen, &amp;quot;Open Sans&amp;quot;, sans-serif; font-size: 16.002px; text-wrap-mode: wrap;&quot; class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p style=&quot;margin-top: 0px; font-size: var(--ds-md-font-size); line-height: var(--ds-md-line-height); margin-bottom: 0px !important;&quot;&gt;需要&lt;strong&gt;编程辅助&lt;/strong&gt;&amp;nbsp;➔ 选&amp;nbsp;&lt;strong&gt;Coder&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&quot;margin-top: 0px; font-size: var(--ds-md-font-size); line-height: var(--ds-md-line-height); margin-bottom: 0px !important;&quot;&gt;需要&lt;strong&gt;通用对话或多任务处理&lt;/strong&gt;&amp;nbsp;➔ 选&amp;nbsp;&lt;strong&gt;Chat&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&quot;margin-top: 0px; font-size: var(--ds-md-font-size); line-height: var(--ds-md-line-height); margin-bottom: 0px !important;&quot;&gt;需解决&lt;strong&gt;数学问题或复杂逻辑&lt;/strong&gt;&amp;nbsp;➔ 选&amp;nbsp;&lt;strong&gt;Reasoner&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&quot;font-size: 16.002px; line-height: var(--ds-md-line-height); color: rgb(64, 64, 64); font-family: Inter, system-ui, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, &amp;quot;Noto Sans&amp;quot;, Ubuntu, Cantarell, &amp;quot;Helvetica Neue&amp;quot;, Oxygen, &amp;quot;Open Sans&amp;quot;, sans-serif; text-wrap-mode: wrap; margin-bottom: 0px !important;&quot;&gt;可通过 DeepSeek 的官方仓库（&lt;a href=&quot;https://github.com/deepseek-ai&quot; target=&quot;_blank&quot; rel=&quot;noreferrer&quot; style=&quot;transition: box-shadow var(--ds-transition-duration)var(--ds-ease-in-out); border-radius: calc(var(--ds-md-zoom)*6px); border-left: 3px solid rgba(var(--ds-rgba-transparent)); border-right: 3px solid rgba(var(--ds-rgba-transparent)); border-top: 2px solid rgba(var(--ds-rgba-transparent)); border-bottom: 2px solid rgba(var(--ds-rgba-transparent)); margin-left: -3px; margin-right: -3px; text-decoration-line: none; position: relative;&quot;&gt;GitHub&lt;/a&gt;）和&amp;nbsp;&lt;a href=&quot;https://huggingface.co/deepseek-ai&quot; target=&quot;_blank&quot; rel=&quot;noreferrer&quot; style=&quot;transition: box-shadow var(--ds-transition-duration)var(--ds-ease-in-out); border-radius: calc(var(--ds-md-zoom)*6px); border-left: 3px solid rgba(var(--ds-rgba-transparent)); border-right: 3px solid rgba(var(--ds-rgba-transparent)); border-top: 2px solid rgba(var(--ds-rgba-transparent)); border-bottom: 2px solid rgba(var(--ds-rgba-transparent)); margin-left: -3px; margin-right: -3px; text-decoration-line: none; position: relative;&quot;&gt;Hugging Face&lt;/a&gt;&amp;nbsp;获取模型细节与试用。&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;</description><pubDate>Tue, 04 Mar 2025 16:20:34 +0800</pubDate></item><item><title>STM32F405 SPI模式读写SD卡挂载失败的一种原因</title><link>https://caterwang.cn/?id=161</link><description>&lt;p&gt;最近研究通过SPI的模式读写SD卡，调试时发现，在调用&amp;nbsp;f_mount 挂载SD卡时，程序就会卡死，进入到&amp;nbsp;HardFault_Handler 死循环中。单步时发现是在&lt;span style=&quot;text-wrap-mode: wrap;&quot;&gt;f_mount 函数中 调&amp;nbsp;find_volume 时跑飞的。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center;&quot;&gt;&lt;img class=&quot;ue-image&quot; src=&quot;https://caterwang.cn/zb_users/upload/2024/12/202412241735045431100956.png&quot; title=&quot;微信截图_20241224210327.png&quot; alt=&quot;微信截图_20241224210327.png&quot; width=&quot;960&quot; height=&quot;521&quot; border=&quot;0&quot; vspace=&quot;0&quot; style=&quot;width: 960px; height: 521px;&quot;/&gt;&lt;/p&gt;&lt;p&gt;&lt;img class=&quot;ue-image&quot; src=&quot;https://caterwang.cn/zb_users/upload/2024/12/202412241735045688646484.png&quot; title=&quot;微信截图_20241224210750.png&quot; alt=&quot;微信截图_20241224210750.png&quot; width=&quot;960&quot; height=&quot;477&quot; border=&quot;0&quot; vspace=&quot;0&quot; style=&quot;width: 960px; height: 477px;&quot;/&gt;由于第一次使用SD卡，也没有什么调试经验，在网上刨了一下，最终让我找到了情况与我类似的。&lt;a href=&quot;https://shequ.stmicroelectronics.cn/thread-620714-1-1.html&quot; target=&quot;_blank&quot; title=&quot;FATFS0.12c到f_mount()卡死，求助&quot;&gt;https://shequ.stmicroelectronics.cn/thread-620714-1-1.html&lt;/a&gt;&lt;/p&gt;&lt;p&gt;于是照着改了代码，确实成功了，在此分享。&lt;/p&gt;&lt;p style=&quot;text-align: center;&quot;&gt;&lt;img class=&quot;ue-image&quot; src=&quot;https://caterwang.cn/zb_users/upload/2024/12/202412241735045880530601.png&quot; title=&quot;微信截图_20241224211107.png&quot; alt=&quot;微信截图_20241224211107.png&quot; width=&quot;960&quot; height=&quot;510&quot; border=&quot;0&quot; vspace=&quot;0&quot; style=&quot;width: 960px; height: 510px;&quot;/&gt;&lt;/p&gt;&lt;p&gt;上面圈出来的两个值，开始时被设置成了相同的值都是512，把_MAX_SS改成4096试了下就成功了。&lt;/p&gt;</description><pubDate>Tue, 24 Dec 2024 21:00:46 +0800</pubDate></item></channel></rss>