export const rtorrentConfigSource = " function normalizeRtConfigValue(value, type='text'){\n const raw=String(value ?? '').trim();\n if(type==='bool') return ['1','true','yes','on'].includes(raw.toLowerCase()) ? '1' : '0';\n if(type==='number'){\n if(raw==='') return '0';\n const normalized=Number(raw.replace(',', '.'));\n return Number.isFinite(normalized) ? String(Math.trunc(normalized)) : raw;\n }\n return raw;\n }\n function rtConfigInputValue(input){\n const type=input.dataset.type || rtConfigFieldTypes.get(input.dataset.key) || 'text';\n const value=type==='bool' && input.type==='checkbox' ? (input.checked?'1':'0') : input.value;\n return normalizeRtConfigValue(value, type);\n }\n function rtConfigOriginalValue(input){\n const key=input.dataset.key;\n return normalizeRtConfigValue(input.dataset.original ?? rtConfigOriginal.get(key), input.dataset.type || rtConfigFieldTypes.get(key) || 'text');\n }\n function collectRtConfigChanges(){\n const values={};\n document.querySelectorAll('.rt-config-input').forEach(input=>{\n if(input.disabled) return;\n const cur=rtConfigInputValue(input);\n const orig=rtConfigOriginalValue(input);\n if(cur!==orig) values[input.dataset.key]=cur;\n });\n return values;\n }\n function collectRtConfigClearKeys(){\n const keys=[];\n document.querySelectorAll('.rt-config-input').forEach(input=>{\n if(input.disabled || input.dataset.saved!=='true') return;\n const cur=rtConfigInputValue(input);\n const orig=rtConfigOriginalValue(input);\n if(cur===orig) keys.push(input.dataset.key);\n });\n return keys;\n }\n function updateRtConfigDirty(){\n const changed=collectRtConfigChanges();\n const clearKeys=collectRtConfigClearKeys();\n document.querySelectorAll('.rt-config-input').forEach(input=>{\n const card=input.closest('.rt-config-card');\n // Note: Dirty highlighting belongs to the rendered card; older code used a stale row class.\n if(card) card.classList.toggle('changed', Object.prototype.hasOwnProperty.call(changed,input.dataset.key));\n });\n const configChanges=Object.keys(changed).length;\n const applyChanged=!!$('rtConfigApplyOnStart') && $('rtConfigApplyOnStart').checked!==rtConfigOriginalApplyOnStart;\n const total=configChanges + clearKeys.length + (applyChanged ? 1 : 0);\n if($('rtConfigChangedCount')) $('rtConfigChangedCount').textContent=total?`${total} changed`:'No changes';\n if($('rtConfigGenerateBtn')) $('rtConfigGenerateBtn').disabled=!configChanges;\n if($('rtConfigSaveBtn')) $('rtConfigSaveBtn').disabled=!total;\n }\n function rtConfigHelpText(field){\n const parts = [];\n if(field.description) parts.push(field.description);\n if(field.recommendation) parts.push(`Recommendation: ${field.recommendation}`);\n if(field.runtime_note) parts.push(`Runtime: ${field.runtime_note}`);\n if(field.error) parts.push(`Runtime note: ${field.error}`);\n return parts.join(' ');\n }\n function rtConfigGroupIntro(group){\n const notes = {\n 'Directories': 'Paths used by rTorrent for downloads, state and runtime context.',\n 'Network': 'Connectivity limits, listening ports and HTTP/XML-RPC behavior.',\n 'Peers': 'Peer discovery and peer count targets for downloading and seeding.',\n 'Throttle': 'Global speed, peer slot and scheduler limits that can be changed through SCGI at runtime.',\n 'Ratio': 'Global ratio commands exposed only when the running rTorrent build supports them.',\n 'DHT / PEX': 'Distributed peer discovery options; verify private tracker rules before enabling.',\n 'Protocol': 'Advanced peer protocol behavior. Keep defaults unless you know the tracker/network requirement.',\n 'Files': 'Disk, hashing and piece cache behavior. Tune carefully on busy storage.',\n 'System': 'Runtime identity and filesystem permissions.'\n };\n return notes[group] || 'Additional rTorrent runtime settings.';\n }\n function rtConfigFieldState(field){\n if(!field.ok) return 'Unavailable';\n if(field.readonly) return 'Read only';\n if(field.saved) return 'Saved override';\n return 'Live';\n }\n function rtConfigFieldMarkup(field){\n const disabled=(!field.ok||field.readonly)?'disabled':'';\n const type=['bool','number'].includes(field.type)?field.type:'text';\n const originalValue=normalizeRtConfigValue(field.baseline_value ?? field.current_value ?? field.value, type);\n const displayValue=normalizeRtConfigValue(field.saved ? field.saved_value : (field.value ?? field.current_value), type);\n rtConfigOriginal.set(field.key, originalValue);\n rtConfigFieldTypes.set(field.key, type);\n const originalAttr=esc(originalValue);\n const help=rtConfigHelpText(field);\n const valueNote=field.saved?`Reference: ${esc(originalValue)} \u2192 saved: ${esc(displayValue)}`:'';\n const input=type==='bool'\n ? `${displayValue==='1'?'On':'Off'}`\n : ``;\n // Note: Runtime details stay in the tooltip to keep config cards compact.\n return ``;\n }\n function renderRtConfigGroups(fields){\n const groups = new Map();\n fields.forEach(field=>{\n const group=field.group||'Other';\n if(!groups.has(group)) groups.set(group, []);\n groups.get(group).push(field);\n });\n return [...groups.entries()].map(([group, items])=>` ${esc(group)}${esc(rtConfigGroupIntro(group))}