<html>
<head>
<style>
.oc {
    --bg-white: #ffffff;
    --bg-light: #f8fafc;
    --bg-gray: #f1f5f9;
    --text-primary: #374151;
    --text-secondary: #64748b;
    --text-title: #4d4d4d;
    --border-color: #b1b1b1;
    --border-light: #e2e8f0;
    --hover-bg: #f8fafc;
    --primary-color: #3b82f6;
    --success-color: #059669;
    --success-dark: #047857;
    --warning-color: #f59e0b;
    --error-color: #dc2626;
    --warning-log: #ff00bb;
    --watch-log: #b300ff;
    --shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
    --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
    --radius-sm: 6px;
    --radius-md: 6px;
    --radius-lg: 8px;
    --transition-fast: 0.15s ease;
    --transition-normal: 0.3s ease;
    
    --control-height: 32px;
    --card-padding: 6px 8px;
    --gap-size: 10px;
    
    --row-1-height: 160px;
    --row-2-height: 140px;
    --row-3-height: 140px;
    --row-4-height: 250px;
}

.oc[data-darkmode="true"] {
    --bg-white: #1f2937;
    --bg-light: #374151;
    --bg-gray: #4b5563;
    --text-primary: #ebebeb;
    --text-secondary: #d0cfcf;
    --text-title: #e5e7eb;
    --border-color: #939393;
    --border-light: #6b7280;
    --hover-bg: #374151;
    --primary-color: #3b82f6;
    --success-color: #34d399;
    --success-dark: #10b981;
    --error-color: #ff7070;
    --warning-color: #f9bb51;
    --warning-log: #fa41c8;
    --watch-log: #c147f5;
}

.oc[data-darkmode="true"] .plugin-toggle-slider {
    background-color: #6b7280;
    border-color: #6b7280;
}

.oc[data-darkmode="true"] .plugin-toggle-switch input:checked + .plugin-toggle-slider {
    background-color: var(--primary-color);
    border-color: var(--primary-color);
}

.oc[data-darkmode="true"] .plugin-toggle-slider:before {
    background-color: #f9fafb;
}

.oc[data-darkmode="true"] .version-display .update-dot {
    background: var(--error-color);
}

.oc[data-darkmode="true"] .announcement-banner {
    background: linear-gradient(135deg, #3555bf, #6c83c5);
}

.oc[data-darkmode="true"] .announcement-banner::before {
    background: linear-gradient(to right, #3555bf 80%, #3555bf 100%);
}

.oc[data-darkmode="true"] #megaphone {
    filter: brightness(0) invert(1);
}

.oc[data-darkmode="true"] .subscription-progress-bar {
    background: #374151;
}

.oc[data-darkmode="true"] .subscription-progress-fill.high {
    background: var(--success-color);
}

.oc[data-darkmode="true"] .subscription-progress-fill.medium {
    background: var(--warning-color);
}

.oc[data-darkmode="true"] .subscription-progress-fill.low {
    background: var(--error-color);
}

.oc[data-darkmode="true"] .subscription-loading,
.oc[data-darkmode="true"] .subscription-error,
.oc[data-darkmode="true"] .subscription-no-info {
    color: var(--text-secondary);
}

.oc[data-darkmode="true"] .subscription-error {
    color: var(--error-color);
}

.oc[data-darkmode="true"] .subscription-nav-arrow.left {
    border-right-color: var(--text-secondary);
}

.oc[data-darkmode="true"] .subscription-nav-arrow.right {
    border-left-color: var(--text-secondary);
}

.oc[data-darkmode="true"] .subscription-nav-arrow.left:hover {
    border-right-color: var(--primary-color);
}

.oc[data-darkmode="true"] .subscription-nav-arrow.right:hover {
    border-left-color: var(--primary-color);
}

.oc[data-darkmode="true"] .dashboard-btn:disabled {
    background: #4b5563 !important;
    color: #9ca3af !important;
}

.oc[data-darkmode="true"] .config-select {
    background: var(--bg-white) !important;
    border-color: var(--border-light) !important;
    color: var(--text-primary) !important;
}

.oc[data-darkmode="true"] .config-select option {
    background: var(--bg-white) !important;
    color: var(--text-primary) !important;
}

.oc[data-darkmode="true"] .config-select:hover {
    border-color: var(--primary-color);
}

.oc[data-darkmode="true"] .config-select:focus {
    border-color: var(--primary-color);
    box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.2);
}

.oc[data-darkmode="true"] .config-selector::after {
    border-top-color: var(--text-secondary);
}

.oc[data-darkmode="true"] svg {
    filter: none;
}

.oc * {
    box-sizing: border-box;
}

.oc {
    font-family: var(--font-family-base);
    line-height: 1.6;
    color: var(--text-primary);
    background-color: var(--bg-light);
    width: 100%;
    max-width: 100%;
    box-sizing: border-box;
    overflow-x: hidden;
    border-radius: var(--radius-lg);
}

.oc .main-cards-container {
    display: grid;
    grid-template-columns: 1fr 1fr;
    grid-template-rows: minmax(60px, auto) 1fr;
    gap: 10px;
    margin: 0 auto;
    align-items: start;
    max-width: 100%;
    width: 100%;
    box-sizing: border-box;
    overflow-x: auto;
    overflow-y: visible;
}

.oc .announcement-card {
    grid-column: 1 / 3;
    grid-row: 1;
    width: 100%;
    max-width: 100%;
    box-sizing: border-box;
    border: 1px solid var(--border-light);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-sm);
    background: var(--bg-white);
    display: flex;
    align-items: stretch;
    margin: 0;
    padding: 12px;
}

.oc .main-card {
    background: var(--bg-white);
    border: 1px solid var(--border-light);
    border-radius: var(--radius-lg);
    padding: 12px;
    box-shadow: var(--shadow-sm);
    transition: all var(--transition-fast);
    display: grid;
    grid-template-rows: var(--row-1-height) var(--row-2-height) var(--row-3-height) var(--row-4-height);
    gap: 8px;
    overflow: visible;
    grid-row: 2;
    max-width: 100%;
    width: 100%;
    box-sizing: border-box;
}

.oc .main-card:first-of-type {
    grid-column: 1;
}

.oc .main-card:last-of-type {
    grid-column: 2;
}

.oc .card-row {
    display: flex;
    gap: 12px;
    align-items: stretch;
    height: 100%;
    max-width: 100%;
    box-sizing: border-box;
    min-width: 250px;
}

.oc .card-row:nth-child(1) {
    min-height: var(--row-1-height);
}

.oc .card-row:nth-child(2) {
    min-height: var(--row-2-height);
}

.oc .card-row:nth-child(3) {
    min-height: var(--row-3-height);
}

.oc .card-row:nth-child(4) {
    min-height: var(--row-4-height);
}

.oc .card-row.full-width .sub-card {
    flex: 1;
    max-width: 100%;
}

.oc .card-row.dual-cards {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 8px;
    max-width: 100%;
}

.oc .card-row.stats-grid {
    display: grid;
    grid-template-columns: repeat(4, 2fr);
    gap: 8px;
    max-width: 100%;
    min-width: auto;
}

.oc .sub-card {
    display: flex;
    flex-direction: column;
    background: var(--bg-gray);
    border: 1px solid var(--border-light);
    border-radius: var(--radius-md);
    padding: var(--card-padding);
    position: relative;
    height: 100%;
    min-height: 0;
    gap: 5px;
    max-width: 100%;
    box-sizing: border-box;
}

.oc .sub-card.stat-item {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 6px;
    padding: 10px 6px;
    min-height: 0;
}

.oc .sub-card.dashboard-container,
.oc .sub-card.quick-actions-container {
    display: flex;
    flex-direction: column;
    justify-content: center;
    min-height: 0;
}

.oc .card-title {
    font-size: clamp(10px, 2.5vw, 14px);
    font-weight: 600;
    color: var(--text-title);
    letter-spacing: 0.5px;
    margin-bottom: 10px;
    display: flex;
    align-items: center;
    gap: 6px;
    height: 20px;
    flex-shrink: 0;
    padding-left: 5px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    min-width: 0;
}

.oc .version-display-container {
    position: absolute;
    right: 10px;
    display: flex;
    gap: 8px;
    z-index: 2;
}

.oc .card-content {
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: 10px;
    flex: 1;
    min-height: 0;
}

.oc .config-file-content {
    display: flex;
    flex-direction: column;
    gap: 10px;
    flex: 1;
    min-height: 0;
}

.oc .config-file-top {
    display: flex;
    align-items: center;
    justify-content: flex-start;
    width: 100%;
}

.oc .card-value {
    font-size: 14px;
    font-weight: 600;
    color: var(--text-primary);
    line-height: 1.4;
    word-break: break-word;
    min-height: var(--control-height);
    display: flex;
    align-items: center;
    white-space: nowrap;
}

.oc .card-controls {
    display: flex;
    flex-direction: column;
    gap: 10px;
    justify-content: center;
    width: 100%;
}

.oc .card-actions {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 6px;
    margin-top: auto;
    flex-wrap: nowrap;
    flex-shrink: 0;
    min-height: 28px;
    padding-top: 3px;
}

.oc .core-status-row .card-actions {
    overflow-x: auto;
}

.oc .core-status-row .sub-card {
    gap: 20px;
}

.oc .core-main-controls {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    flex: 0 0 auto;
    min-height: var(--control-height);
    overflow: hidden;
    min-width: 0; 
}

.oc .core-status-toggle,
.oc .core-control-buttons {
    min-width: 0;
}

.oc .core-status-toggle {
    display: flex;
    align-items: center;
    gap: 10px;
    flex: 1;
}

.oc .core-control-buttons {
    display: flex;
    align-items: center;
    gap: 6px;
    flex-shrink: 0;
    flex-wrap: nowrap;
}

.oc .mode-row .sub-card {
    justify-content: flex-start;
    align-items: stretch;
}

.oc .mode-row .sub-card .card-title {
    height: 20px;
    min-height: 20px;
    margin-bottom: 12px;
    flex-shrink: 0;
}

.oc .mode-row .sub-card:first-child .card-content {
    display: flex;
    flex-direction: row;
    justify-content: flex-start;
    align-items: center;
    gap: 10px;
    flex: 1;
}

.oc .icon-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    min-width: 28px;
    border: 1px solid var(--border-color);
    border-radius: var(--radius-sm);
    background: var(--bg-white);
    color: var(--text-secondary);
    cursor: pointer;
    transition: all var(--transition-fast);
    padding: 0;
    font-size: 0;
    overflow: hidden;
}

.oc .icon-btn:hover {
    background: var(--hover-bg) !important;
    border-color: var(--primary-color) !important;
    color: var(--primary-color) !important;
    transform: translateY(-1px) !important;
    box-shadow: var(--shadow-sm) !important;
}

.oc .icon-btn svg {
    width: 14px !important;
    height: 14px !important;
    flex-shrink: 0 !important;
}

.oc .version-display {
    font-size: 13px;
    font-weight: 500;
    color: var(--text-secondary);
    background: var(--bg-white);
    border: 1px solid var(--border-light);
    border-radius: var(--radius-sm);
    padding: 2px 6px;
    display: flex;
    align-items: center;
    gap: 4px;
    max-width: 160px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    height: 20px;
}

.oc .version-display .version-text {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.oc .version-display .update-dot {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--error-color);
    flex-shrink: 0;
    animation: gentlePulse 4s cubic-bezier(.17,.67,.83,.67) infinite;
}

@keyframes gentlePulse {
    0%, 100% { 
        opacity: 1; 
        transform: scale(1);
    }
    50% { 
        opacity: 0.4; 
        transform: scale(0.9);
    }
}

.oc .version-display:hover {
    background: var(--hover-bg);
    color: var(--text-primary);
}

.oc .config-selector {
    position: relative;
    flex: 1;
}

.oc .config-select {
    width: 100%;
    height: var(--control-height);
    padding: 5px 12px;
    border: 1px solid var(--border-light);
    border-radius: var(--radius-sm);
    background: var(--bg-white);
    color: var(--text-primary);
    font-size: 15px;
    appearance: none;
    cursor: pointer;
    transition: all var(--transition-fast);
    box-sizing: border-box;
    min-width: 0;
    margin: 0 auto;
}

.oc .config-select:hover {
    border-color: var(--primary-color);
}

.oc .config-select:focus {
    outline: none;
    border-color: var(--primary-color);
    box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.1);
}

.oc .config-select option {
    width: 100%;
    padding: 8px 12px;
    font-size: 15px;
    line-height: 1.4;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    background: var(--bg-white);
    color: var(--text-primary);
}

.oc .config-selector::after {
    content: '';
    position: absolute;
    right: 12px;
    top: 50%;
    transform: translateY(-50%);
    width: 0;
    height: 0;
    border-left: 4px solid transparent;
    border-right: 4px solid transparent;
    border-top: 4px solid var(--text-secondary);
    pointer-events: none;
    z-index: 1;
}

.oc .config-file-bottom .card-actions {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 8px;
    flex-shrink: 0;
    margin: 0;
    flex-direction: row;
}

.oc .cbi-button-group {
    display: flex;
    background: var(--bg-white);
    border-radius: var(--radius-sm);
    padding: 2px;
    gap: 2px;
    position: relative;
    border: 1px solid var(--border-light);
    box-shadow: var(--shadow-sm);
    height: var(--control-height);
    align-items: center;
    white-space: nowrap;
    width: 100%;
}

.oc .cbi-button-group input[type="radio"] {
    position: absolute;
    opacity: 0;
    pointer-events: none;
    height: var(--control-height)-4px;
}

.oc .cbi-button-option {
    flex: 1 1 0;
    padding: 5px 10px;
    font-size: 12px;
    font-weight: 500;
    color: var(--text-secondary);
    cursor: pointer;
    border-radius: calc(var(--radius-sm) - 3px);
    transition: all var(--transition-fast);
    user-select: none;
    text-align: center;
    min-width: 0;
    height: calc(var(--control-height) - 6px);
    display: flex;
    align-items: center;
    justify-content: center;
    line-height: 1;
}

.oc .cbi-button-option:hover {
    color: var(--text-primary);
    background: rgba(59, 130, 246, 0.1);
}

.oc input[type="radio"]:checked + .cbi-button-option {
    background: var(--primary-color);
    color: white;
    box-shadow: var(--shadow-sm);
}

.oc .value-indicator {
    font-weight: 500;
    padding: 6px 6px;
    border-radius: var(--radius-sm);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: var(--bg-white);
    color: var(--text-secondary);
    border: 1px solid var(--border-light);
    text-align: center;
    height: var(--control-height);
    min-width: 90px;
    white-space: nowrap;
    line-height: 1.2;
    overflow: hidden;
    text-overflow: ellipsis;
}

.oc .value-indicator b {
    font-size: 12px;
    text-overflow: ellipsis;
    overflow: hidden;
    white-space: nowrap;
    max-width: 100%;
    display: inline-block;
}

.oc .help-link {
    display: inline-flex;
    align-items: center;
    color: var(--primary-color);
    text-decoration: none;
    opacity: 0.7;
    transition: opacity var(--transition-fast);
    margin-bottom: 2px;
    border-radius: var(--radius-sm);
}

.oc .help-link:hover {
    opacity: 1;
    background: rgba(59, 130, 246, 0.1);
}

.oc .help-link svg {
    width: 12px;
    height: 12px;
}

.oc .dashboard-buttons,
.oc .quick-actions-buttons {
    display: flex;
    gap: 8px;
    justify-content: center;
    align-items: center;
    flex: 1;
}

.oc .dashboard-btn {
    font-size: 11px !important;
    font-weight: 500 !important;
    color: white !important;
    cursor: pointer !important;
    border-radius: var(--radius-md) !important;
    border: none !important;
    background: #1473e6;
    background-color: var(--primary-color) !important;
    transition: all var(--transition-fast) !important;
    white-space: normal !important;
    text-align: center !important;
    text-decoration: none !important;
    display: flex !important;
    align-items: center !important;
    justify-content: center !important;
    line-height: 1.2 !important;
    flex: 1 !important;
    height: 42px !important;
    outline: none !important;
    padding: 2px 2px !important;
    min-width: 45px;
    margin: 0 !important;
    word-break: normal;
    overflow-wrap: break-word;
}

.oc .dashboard-btn:hover {
    background: #2563eb !important;
}

.oc .stat-label {
    font-size: 12px;
    font-weight: 600;
    color: var(--text-secondary);
    text-align: center;
    position: relative;
    white-space: nowrap;
    margin-top: 15px;
}

.oc .stat-label::after {
    content: '';
    position: absolute;
    bottom: -5px;
    left: 50%;
    transform: translateX(-50%);
    width: 20px;
    height: 1px;
    background-color: var(--border-color);
}

.oc .stat-value {
    font-family: var(--font-family-mono);
    font-size: clamp(9px, 2.2vw, 12px);
    font-weight: 600;
    color: var(--success-color);
    text-align: center;
    white-space: normal;
    word-break: normal;
    overflow-wrap: break-word;
    margin-top: 5px;
    min-height: 38px;
}

.oc .plugin-toggle-container {
    margin-left: auto;
    display: flex;
    align-items: center;
    justify-content: flex-end;
}

.oc .plugin-toggle-switch {
    position: relative;
    display: inline-block;
    width: 44px;
    height: 22px;
    cursor: pointer;
}

.oc .plugin-toggle-switch input {
    opacity: 0;
    width: 0;
    height: 0;
}

.oc .plugin-toggle-slider {
    position: absolute;
    cursor: pointer;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background-color: #e5e7eb;
    transition: 0.2s;
    border-radius: 22px;
    border: 1px solid var(--border-light);
}

.oc .plugin-toggle-slider:before {
    position: absolute;
    content: "";
    height: 16px;
    width: 16px;
    left: 2px;
    top: 2px;
    background-color: white;
    transition: 0.2s;
    border-radius: 50%;
    box-shadow: 0 1px 2px rgba(0,0,0,0.2);
}

.oc .plugin-toggle-switch input:checked + .plugin-toggle-slider {
    background-color: var(--primary-color);
    border-color: var(--primary-color);
}

.oc .plugin-toggle-switch input:checked + .plugin-toggle-slider:before {
    transform: translateX(22px);
}

.oc #logo_btn,
.oc #edit_overwrite {
    display: inline-flex !important;
    align-items: center !important;
    justify-content: flex-start !important;
    width: auto !important;
    padding: 2px 6px !important;
    gap: 6px !important;
    font-size: 12px !important;
}

.oc #logo_btn .logo-text,
.oc #edit_overwrite .btn-text {
    font-size: 11px;
    color: var(--text-secondary);
    font-weight: 500;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    height: 12px;
}

.oc #logo_btn .mihomo-link {
    color: var(--primary-color);
    font-weight: 500;
}

.oc .config-subscription-info {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    flex: 1;
    min-width: 0;
    margin-left: 16px;
}

.oc .subscription-info-container {
    background: var(--bg-white);
    border: 1px solid var(--border-light);
    border-radius: var(--radius-sm);
    padding: var(--card-padding);
    display: flex;
    flex-direction: column;
    width: 100%;
    box-shadow: var(--shadow-sm);
    transition: all var(--transition-fast);
    position: relative;
}

.oc .subscription-info-container:hover {
    border-color: var(--primary-color);
    box-shadow: var(--shadow-md);
}

.oc .subscription-info-main {
    display: flex;
    flex-direction: column;
    gap: 15px;
    flex: 1;
}

.oc .subscription-info-header {
    display: flex;
    justify-content: space-between;
    flex-direction: row;
    align-items: center;
    min-height: 24px;
    min-width: 0;
    gap: 8px;
}

.oc .subscription-info-details {
    display: flex;
    flex-direction: column;
    gap: 8px;
    flex: 1;
    min-height: 80px;
    padding-left: 20px;
    padding-right: 20px;
}

.oc .subscription-progress {
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.oc .subscription-progress-bar {
    background: var(--bg-gray);
    border-radius: 4px;
    height: 10px;
    position: relative;
    overflow: hidden;
}

.oc .subscription-progress-fill {
    height: 100%;
    border-radius: 4px;
    transition: width 0.3s ease;
}

.oc .subscription-progress-fill.high {
    background: var(--success-color);
}

.oc .subscription-progress-fill.medium {
    background: var(--warning-color);
}

.oc .subscription-progress-fill.low {
    background: var(--error-color);
}

.oc .subscription-info-text {
    font-size: 13px;
    color: var(--text-secondary);
    line-height: 1.4;
    text-overflow: ellipsis;
    overflow: hidden;
    white-space: nowrap;
    display: block;
}

.oc .subscription-loading,
.oc .subscription-error,
.oc .subscription-no-info {
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--text-secondary);
    font-size: 12px;
    text-align: center;
    min-height: 40px;
    flex: 1;
}

.oc .subscription-error {
    color: var(--error-color);
}

.oc .subscription-nav-arrow {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    width: 0;
    height: 0;
    cursor: pointer;
    transition: all var(--transition-fast);
    z-index: 3;
    opacity: 0.6;
}

.oc .subscription-nav-arrow:hover {
    opacity: 1;
    transform: translateY(-50%) scale(1.2);
}

.oc .subscription-nav-arrow.disabled {
    opacity: 0.2;
    cursor: not-allowed;
    pointer-events: none;
}

.oc .subscription-nav-arrow.left {
    left: 8px;
    border-top: 6px solid transparent;
    border-bottom: 6px solid transparent;
    border-right: 8px solid var(--text-secondary);
}

.oc .subscription-nav-arrow.right {
    right: 8px;
    border-top: 6px solid transparent;
    border-bottom: 6px solid transparent;
    border-left: 8px solid var(--text-secondary);
}

.oc .subscription-nav-arrow.left:hover {
    border-right-color: var(--primary-color);
}

.oc .subscription-nav-arrow.right:hover {
    border-left-color: var(--primary-color);
}

.oc .config-file-name {
    font-size: 20px;
    font-weight: 600;
    color: var(--text-primary);
    flex: 1 1 0%;
    white-space: nowrap;
    text-overflow: ellipsis;
    min-width: 0;
    max-width: 100%;
    padding-left: 20px;
    overflow: hidden;
}

.oc .config-file-bottom {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    min-height: var(--control-height);
}

.oc .config-file-empty-state {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 20px;
    padding: 40px 20px;
    text-align: center;
}

.oc .config-file-empty-message {
    font-size: 16px;
    color: var(--text-secondary);
    font-weight: 500;
}

.oc .config-upload-btn-large {
    min-width: 200px !important;
    height: 60px !important;
    font-size: 16px !important;
    font-weight: 600 !important;
    padding: 0 30px !important;
    border-radius: var(--radius-lg) !important;
    background: var(--primary-color) !important;
    color: white !important;
    border: none !important;
    cursor: pointer !important;
    transition: all var(--transition-fast) !important;
    box-shadow: var(--shadow-md) !important;
    display: flex !important;
    align-items: center !important;
    justify-content: center !important;
    gap: 12px !important;
}

.oc .config-upload-btn-large:hover {
    background: #2563eb !important;
    transform: translateY(-2px) !important;
    box-shadow: 0 8px 25px rgba(59, 130, 246, 0.3) !important;
}

.oc .config-upload-btn-large svg {
    width: 20px !important;
    height: 20px !important;
}

.oc .config-file-content.empty-state .config-file-bottom {
    display: none;
}

.oc .file-info {
    display: flex;
    flex-wrap: nowrap;
    flex-direction: row;
    gap: 8px;
    font-size: 13px;
    color: var(--text-secondary);
    min-width: 0;
    max-width: 30vw;
    overflow: hidden;
}

.oc .file-info-item {
    display: block;
    align-items: center;
    white-space: nowrap;
    padding-right: 20px;
    font-size: 13px;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 240px;
}

.oc .announcement-banner {
    background: linear-gradient(275deg, var(--primary-color), #1d4ed8);
    color: white;
    padding: 12px;
    border-radius: var(--radius-lg);
    overflow: hidden;
    position: relative;
    height: 38px;
    box-shadow: var(--shadow-md);
    grid-column: 1 / 3;
    grid-row: 1;
    width: 80%;
    max-width: 95%;
    justify-self: center;
    align-self: center;
    box-sizing: border-box;
    margin: 0 auto;
}

.oc .announcement-content {
    position: absolute;
    white-space: nowrap;
    padding-right: 50px;
    left: 100%;
    top: 50%;
    transform: translateY(-50%);
    z-index: 1;
    font-weight: 500;
    opacity: 0;
    transition: opacity 0.3s ease;
    animation-fill-mode: forwards;
    animation-timing-function: linear;
}

.oc .announcement-content.scrolling {
    animation-name: announceScroll;
    opacity: 1;
}

.oc .announcement-content.paused {
    animation-play-state: paused;
}

@keyframes announceScroll {
    0% {
        transform: translateY(-50%) translateX(0);
    }
    100% {
        transform: translateY(-50%) translateX(var(--scroll-distance));
    }
}

.oc .megaphone-container {
    position: absolute;
    left: 0;
    top: 0;
    bottom: 0;
    width: 40px;
    background: rgba(255, 255, 255, 0.1);
    z-index: 2;
    border-top-left-radius: var(--radius-lg);
    border-bottom-left-radius: var(--radius-lg);
    display: flex;
    align-items: center;
    justify-content: center;
}

.oc .announcement-banner::before {
    content: '';
    position: absolute;
    left: 0;
    top: 0;
    bottom: 0;
    width: 45px;
    border-top-left-radius: var(--radius-lg);
    border-bottom-left-radius: var(--radius-lg);
    background: linear-gradient(to right, #1d4ed8 80%, #1d4ed8 100%);
    z-index: 3;
    pointer-events: none;
}

.oc #megaphone {
    position: relative;
    z-index: 4;
    filter: brightness(0) invert(1);
    transform: scaleX(-1);
}

@media screen and (max-width: 1200px) {
    .oc .main-cards-container {
        grid-template-columns: 1fr;
        gap: 11px;
        max-width: 95%;
        width: 95%;
    }
    
    .oc .announcement-banner {
        grid-column: 1;
        width: 80%;
        max-width: 95%;
    }

    .oc .announcement-card {
        grid-column: 1;
        width: 100%;
        max-width: 100%;
    }
    
    .oc .main-card {
        grid-column: 1;
        grid-template-rows: auto auto auto auto;
        max-width: 100%;
        width: 100%;
    }

    .oc .main-card:first-of-type {
        grid-column: 1;
        grid-row: 2;
    }
    
    .oc .main-card:last-of-type {
        grid-column: 1;
        grid-row: 3;
    }

    .oc .card-row.dual-cards {
        grid-template-columns: 1fr 1fr;
    }

    .oc .card-row.stats-grid {
        grid-template-columns: repeat(4, 2fr);
    }

    .oc .config-selector {
        min-width: 200px;
        flex: 1;
    }
    
    .oc .config-select {
        min-width: 200px;
        font-size: 14px;
    }
    
    .oc .config-select option {
        font-size: 14px;
        max-width: 100%;
    }
    
    .oc .card-row:nth-child(1),
    .oc .card-row:nth-child(2),
    .oc .card-row:nth-child(3),
    .oc .card-row:nth-child(4) {
        min-height: auto;
    }
}

@media screen and (max-width: 768px) {
    .oc .main-cards-container {
        max-width: 98%;
        width: 98%;
        gap: 10px;
    }

    .oc .main-card {
        grid-template-rows: auto auto auto auto;
    }

    .oc .sub-card {
        padding: 12px;
        min-height: auto;
    }

    .oc .card-row {
        gap: 12px;
    }

    .oc .card-row.stats-grid {
        grid-template-columns: repeat(2, 2fr);
    }

    .oc .announcement-banner {
        width: 85%;
        max-width: 98%;
    }

    .oc .dashboard-btn {
        font-size: 10px !important;
        height: 40px !important;
    }

    .oc .card-value {
        font-size: 13px;
    }

    .oc .value-indicator {
        font-size: 11px;
        padding: 5px 5px;
    }

    .oc .cbi-button-option {
        padding: 6px 6px;
        font-size: 11px;
    }
    
    .oc .card-row:nth-child(1),
    .oc .card-row:nth-child(2),
    .oc .card-row:nth-child(3),
    .oc .card-row:nth-child(4) {
        min-height: auto;
    }

    .oc .config-file-content {
        flex-direction: column;
        gap: 5px;
    }

    .oc .config-selector {
        min-width: 150px;
        flex: 1;
    }

    .oc .config-select {
        min-width: 150px;
        font-size: 13px;
        padding: 4px 10px;
    }
    
    .oc .config-select option {
        font-size: 13px;
        padding: 6px 10px;
    }
    
    .oc .config-selector::after {
        right: 10px;
        border-left: 3px solid transparent;
        border-right: 3px solid transparent;
        border-top: 3px solid var(--text-secondary);
    }

    .oc .config-subscription-info {
        margin-left: 12px;
    }
    
    .oc .subscription-info-container {
        padding: 8px;
    }

    .oc .subscription-info-header {
        gap: 8px;
    }

    .oc .config-file-name {
        max-width: 100%;
        font-size: 18px;
    }

    .oc .config-file-bottom {
        flex-direction: row;
        align-items: stretch;
        gap: 8px;
    }
    
    .oc .config-file-bottom .card-actions {
        justify-content: center;
        gap: 5px;
    }
    
    .oc .subscription-info-text {
        font-size: 10px;
    }

    .oc .file-info {
        font-size: 10px;
    }

    .oc .file-info-item {
        font-size: 10px;
    }

    .oc .config-upload-btn-large {
        min-width: 180px !important;
        height: 50px !important;
        font-size: 14px !important;
        padding: 0 24px !important;
    }
    
    .oc .config-file-empty-message {
        font-size: 14px;
    }
}

@media screen and (max-width: 575px) {
    .oc .main-cards-container {
        gap: 8px;
        max-width: 100%;
        width: 100%;
    }

    .oc .main-card {
        padding: 8px;
    }

    .oc .card-row {
        gap: 10px;
    }

    .oc .card-row.dual-cards {
        grid-template-columns: 1fr;
    }

    .oc .card-row.stats-grid {
        grid-template-columns: repeat(2, 1fr);
    }

    .oc .announcement-banner {
        width: 90%;
        max-width: 100%;
    }

    .oc .icon-btn {
        width: 24px;
        height: 24px;
        min-width: 24px;
    }

    .oc .icon-btn svg {
        width: 12px !important;
        height: 12px !important;
    }

    .oc .version-display {
        max-width: 100px;
        font-size: 9px;
        padding: 1px 4px;
    }

    .oc .dashboard-btn {
        font-size: 8px !important;
        height: 25px !important;
    }

    .oc .cbi-button-group {
        padding: 2px;
        gap: 1px;
        height: 28px;
    }

    .oc input[type="radio"]:checked + .cbi-button-option {
        height: 22px;
    }

    .oc .cbi-button-option {
        padding: 4px 4px;
        font-size: 10px;
        min-width: 35px;
    }

    .oc .config-file-top {
        flex-direction: column;
        align-items: stretch;
        gap: 12px;
    }
    
    .oc .config-subscription-info {
        margin-left: 0;
        justify-content: center;
    }

    .oc .subscription-info-header {
        gap: 6px;
    }
    
    .oc .file-info {
        gap: 4px;
        font-size: 8px;
    }

    .oc .mode-row .sub-card:first-child .card-content {
        flex-direction: row;
        gap: 8px;
    }
    
    .oc .card-row:nth-child(1),
    .oc .card-row:nth-child(2),
    .oc .card-row:nth-child(3),
    .oc .card-row:nth-child(4) {
        min-height: auto;
    }

    .oc .config-selector {
        min-width: 110px;
        flex: 1;
    }
    
    .oc .config-select {
        min-width: 110px;
        font-size: 12px;
        padding: 4px 8px;
    }
    
    .oc .config-select option {
        font-size: 12px;
        padding: 5px 8px;
    }
    
    .oc .config-selector::after {
        right: 8px;
    }

    .oc .card-value {
        font-size: 11px;
        min-height: 28px;
    }

    .oc .value-indicator {
        padding: 4px 4px;
        min-width: 50px;
        height: 28px;
    }

    .oc .value-indicator b {
        font-size: 10px;
    }

    .oc .stat-label {
        font-size: 9px;
    }

    .oc .stat-value {
        min-height: 30px;
    }

    .oc .subscription-info-text {
        font-size: 10px;
    }

    .oc .config-file-name {
        font-size: 15px;
    }

    .oc .sub-card {
        padding: 8px;
        gap: 4px;
    }

    .oc .sub-card.stat-item {
        padding: 8px 4px;
    }

    .oc .card-content {
        gap: 8px;
    }

    .oc .card-controls {
        gap: 8px;
    }

    .oc .core-main-controls {
        gap: 8px;
        min-height: 28px;
    }

    .oc .core-control-buttons {
        max-width: 120px;
        gap: 6px;
    }

    .oc .card-actions {
        gap: 6px;
        min-height: 24px;
    }

    .oc #logo_btn .logo-text,
    .oc #edit_overwrite .btn-text {
        font-size: 8px;
    }

    .oc #logo_btn .mihomo-link {
        font-size: 8px;
    }

    .oc .file-info-item {
        font-size: 10px;
    }

    .oc .config-upload-btn-large {
        min-width: 160px !important;
        height: 45px !important;
        font-size: 13px !important;
        padding: 0 20px !important;
    }
    
    .oc .config-file-empty-state {
        padding: 30px 15px;
        gap: 15px;
    }
    
    .oc .config-file-empty-message {
        font-size: 13px;
    }
}
</style>
</head>
<%
    local uci = require("luci.model.uci").cursor()
    local fs = require "luci.openclash"
    local RELEASE_BRANCH = fs.uci_get("config", "release_branch")
    local random = tostring(os.time()):reverse():sub(1, 9)
%>
<fieldset class="cbi-section">
    <table width="100%">
    <tr>
        <td colspan="4">
            <div class="oc">
                <div class="main-cards-container">
                    <div class="announcement-card">
                        <div id="announcement-banner" class="announcement-banner">
                            <div class="megaphone-container"></div>
                            <svg id="megaphone" xmlns="http://www.w3.org/2000/svg" width="15" height="15" fill="currentColor" viewBox="0 0 256 256">
                                <path d="M228.54,86.66l-176.06-54A16,16,0,0,0,32,48V192a16,16,0,0,0,16,16,16,16,0,0,0,4.52-.65L136,181.73V192a16,16,0,0,0,16,16h32a16,16,0,0,0,16-16v-29.9l28.54-8.75A16.09,16.09,0,0,0,240,138V102A16.09,16.09,0,0,0,228.54,86.66ZM136,165,48,192V48l88,27Zm48,27H152V176.82L184,167Zm40-54-.11,0L152,160.08V79.92l71.89,22,.11,0v36Z"></path>
                            </svg>
                            <div id="announcement-content" class="announcement-content"></div>
                        </div>
                    </div>
                    <div class="main-card">
                        <!-- Row 1: Running Status -->
                        <div class="card-row full-width core-status-row">
                            <div class="sub-card">
                                <div class="card-title"><%:Running Status%></div>
                                <div class="version-display-container">
                                    <div class="version-display" id="plugin-version-display" style="display: none;">
                                        <span class="version-text" id="plugin-version-text">-</span>
                                    </div>
                                    <div class="version-display" id="core-version-display" style="display: none;">
                                        <span class="version-text" id="core-version-text">-</span>
                                    </div>
                                </div>
                                <div class="core-main-controls">
                                    <div class="core-status-toggle">
                                        <span id="_clash" class="value-indicator"><%:Collecting data...%></span>
                                        <span id="_oclog" class="value-indicator" style="display: none;"><%:Collecting data...%></span>
                                        <div class="plugin-toggle-container">
                                            <label class="plugin-toggle-switch">
                                                <input type="checkbox" id="plugin_toggle" onchange="togglePlugin(this)">
                                                <span class="plugin-toggle-slider"></span>
                                            </label>
                                        </div>
                                    </div>
                                    <div class="core-control-buttons">
                                        <button type="button" class="icon-btn action-btn" id="restart_core" title="<%:Restart%>" onclick="return restartCore()">
                                            <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M23 4v6h-6"></path><path d="M20.49 15a9 9 0 1 1-2.12-9.36L23 10"></path></svg>
                                        </button>
                                        <button type="button" class="icon-btn action-btn" id="edit_overwrite" title="<%:Overwrite Module%>" onclick="return editOverwrite()">
                                            <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="currentColor" viewBox="0 0 256 256">
                                                <path d="M12,111l112,64a8,8,0,0,0,7.94,0l112-64a8,8,0,0,0,0-13.9l-112-64a8,8,0,0,0-7.94,0l-112,64A8,8,0,0,0,12,111ZM128,49.21,223.87,104,128,158.79,32.13,104ZM246.94,140A8,8,0,0,1,244,151L132,215a8,8,0,0,1-7.94,0L12,151A8,8,0,0,1,20,137.05l108,61.74,108-61.74A8,8,0,0,1,246.94,140Z"></path>
                                            </svg>
                                            <span class="btn-text"><%:Overwrite Module%></span>
                                        </button>
                                    </div>
                                </div>
                                <div class="card-actions">
                                    <button type="button" class="icon-btn action-btn" id="go_wiki" title="<%:Wiki%>" onclick="return wikipage()"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M22 10v6M2 10l10-5 10 5-10 5z"></path><path d="M6 12v5c3 3 9 3 12 0v-5"></path></svg></button>
                                    <button type="button" class="icon-btn action-btn" id="go_tutorials" title="<%:Tutorials%>" onclick="return gitbookpage()"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"></path><path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"></path></svg></button>
                                    <button type="button" class="icon-btn action-btn" id="go_star" title="<%:Star%>" onclick="return homepage()"><svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor"><path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/></svg></button>
                                    <button type="button" class="icon-btn action-btn" id="go_telegram" title="<%:Telegram%>" onclick="return telegrampage()"><svg width="14" height="14" viewBox="0 0 256 256" fill="none" stroke="currentColor" stroke-width="20"><path d="M80,134.87,170.26,214a8,8,0,0,0,13.09-4.21L224,33.22a1,1,0,0,0-1.34-1.15L20,111.38A6.23,6.23,0,0,0,21,123.3Z" stroke-linecap="round" stroke-linejoin="round"/><line x1="80" y1="134.87" x2="223.41" y2="32.09" stroke-linecap="round" stroke-linejoin="round"/><path d="M124.37,173.78,93.76,205.54A8,8,0,0,1,80,200V134.87" stroke-linecap="round" stroke-linejoin="round"/></svg></button>
                                    <button type="button" class="icon-btn action-btn" id="go_sponsor" title="<%:Sponsor%>" onclick="return sponsorpage()"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z"></path></svg></button>
                                    <button type="button" class="icon-btn action-btn" id="logo_btn" title="Mihomo" onclick="return go_mihomo();">
                                        <img id="_logo" src="/luci-static/resources/openclash/img/logo.png?<%=random%>" loading="lazy" width="14px" height="14px" alt="Mihomo"/>
                                        <span class="logo-text">Powered by <span class="mihomo-link">Mihomo</span></span>
                                    </button>
                                </div>
                            </div>
                        </div>

                        <!-- Row 2: Running Mode & Proxy Mode -->
                        <div class="card-row dual-cards mode-row">
                            <div class="sub-card">
                                <div class="card-title"><%:Running Mode%></div>
                                <div class="card-content">
                                    <div class="card-value"><span id="_mode" class="value-indicator"><%:Collecting data...%></span></div>
                                    <div class="card-controls">
                                        <div id="radio-ru-mode" class="cbi-button-group" style="display: inline-flex;">
                                            <input type="radio" id="normal" name="radios-ru" value="" checked onclick="return switch_run_mode(this.value)"/><label for="normal" id="run_normal" class="cbi-button-option"><%:Compat%></label>
                                            <input type="radio" id="tun" name="radios-ru" value="-tun" onclick="return switch_run_mode(this.value)"/><label for="tun" class="cbi-button-option"><%:TUN%></label>
                                            <input type="radio" id="mix" name="radios-ru" value="-mix" onclick="return switch_run_mode(this.value)"/><label for="mix" class="cbi-button-option"><%:Mix%></label>
                                        </div>
                                    </div>
                                </div>
                            </div>
                            <div class="sub-card">
                                <div class="card-title"><%:Proxy Mode%></div>
                                <div class="card-content">
                                    <div class="card-controls">
                                        <div id="radio-mode" class="cbi-button-group" style="display: inline-flex;">
                                            <input type="radio" id="rule" name="radios" value="rule" checked onclick="return switch_rule_mode(this.value)"/><label for="rule" class="cbi-button-option"><%:Rule%></label>
                                            <input type="radio" id="global" name="radios" value="global" onclick="return switch_rule_mode(this.value)"/><label for="global" class="cbi-button-option"><%:Global%></label>
                                            <input type="radio" id="direct" name="radios" value="direct" onclick="return switch_rule_mode(this.value)"/><label for="direct" class="cbi-button-option"><%:Direct%></label>
                                        </div>
                                    </div>
                                </div>
                            </div>
                        </div>

                        <!-- Row 3: Settings -->
                        <div class="card-row stats-grid">
                            <div class="sub-card">
                                <div class="card-title"><%:Area Bypass%><div class="help-link" title="<%:Bypass Specified Regions Network Flows, Improve Performance, If Inaccessibility on Bypass Gateway, Try to Enable Bypass Gateway Compatible Option%>"><svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"></circle><path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"></path><line x1="12" y1="17" x2="12.01" y2="17"></line></svg></div></div>
                                <div class="card-content">
                                    <div class="card-controls">
                                        <div id="oc-setting-oversea" class="cbi-button-group" style="display: inline-flex;">
                                            <input type="radio" id="oc_setting_oversea_1" name="oc-setting-oversea" value="1" onclick="return switch_oc_setting_oversea('1')"/><label for="oc_setting_oversea_1" class="cbi-button-option"><%:Mainland%></label>
                                            <input type="radio" id="oc_setting_oversea_2" name="oc-setting-oversea" value="2" onclick="return switch_oc_setting_oversea('2')"/><label for="oc_setting_oversea_2" class="cbi-button-option"><%:Oversea%></label>
                                            <input type="radio" id="oc_setting_oversea_0" name="oc-setting-oversea" value="0" onclick="return switch_oc_setting_oversea('0')"/><label for="oc_setting_oversea_0" class="cbi-button-option"><%:Off%></label>
                                        </div>
                                    </div>
                                </div>
                            </div>
                            <div class="sub-card">
                                <div class="card-title"><%:Sniffer%><a href="javascript:void(0);" onclick="window.open('https://wiki.metacubex.one/config/sniff/?h=sniff#_1', '_blank');" class="help-link" title="<%:Sniff the domain name of the traffics to avoid rule-based proxy failure%>"><svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"></circle><path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"></path><line x1="12" y1="17" x2="12.01" y2="17"></line></svg></a></div>
                                <div class="card-content">
                                    <div class="card-controls">
                                        <div id="dns-setting-sniffer" class="cbi-button-group" style="display: inline-flex;">
                                            <input type="radio" id="meta_sniffer_on" name="meta-sniffer-radios" value="1" onclick="return switch_meta_sniffer('1')"/><label for="meta_sniffer_on" class="cbi-button-option"><%:On%></label>
                                            <input type="radio" id="meta_sniffer_off" name="meta-sniffer-radios" value="0" onclick="return switch_meta_sniffer('0')"/><label for="meta_sniffer_off" class="cbi-button-option"><%:Off%></label>
                                        </div>
                                    </div>
                                </div>
                            </div>
                            <div class="sub-card">
                                <div class="card-title"><%:DNS Proxy%><a href="javascript:void(0);" onclick="window.open('https://wiki.metacubex.one/config/dns/?h=res#respect-rules', '_blank');" class="help-link" title="<%:DNS querys respect-rules to preventing access failure%>"><svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"></circle><path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"></path><line x1="12" y1="17" x2="12.01" y2="17"></line></svg></a></div>
                                <div class="card-content">
                                    <div class="card-controls">
                                        <div id="dns-setting-respect" class="cbi-button-group" style="display: inline-flex;">
                                            <input type="radio" id="respect_rules_on" name="respect-rules-radios" value="1" onclick="return switch_respect_rules('1')"/><label for="respect_rules_on" class="cbi-button-option"><%:On%></label>
                                            <input type="radio" id="respect_rules_off" name="respect-rules-radios" value="0" onclick="return switch_respect_rules('0')"/><label for="respect_rules_off" class="cbi-button-option"><%:Off%></label>
                                        </div>
                                    </div>
                                </div>
                            </div>
                            <div class="sub-card">
                                <div class="card-title"><%:Stream Unlock%><div class="help-link" title="<%:Auto Select Proxy For Streaming Unlock, Support Netflix, Disney Plus, HBO And YouTube Premium, etc%>"><svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"></circle><path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"></path><line x1="12" y1="17" x2="12.01" y2="17"></line></svg></div></div>
                                <div class="card-content">
                                    <div class="card-controls">
                                        <div id="stream-unlock-setting" class="cbi-button-group" style="display: inline-flex;">
                                            <input type="radio" id="stream_unlock_on" name="stream-unlock-radios" value="1" onclick="return switch_stream_unlock('1')"/><label for="stream_unlock_on" class="cbi-button-option"><%:On%></label>
                                            <input type="radio" id="stream_unlock_off" name="stream-unlock-radios" value="0" onclick="return switch_stream_unlock('0')"/><label for="stream_unlock_off" class="cbi-button-option"><%:Off%></label>
                                        </div>
                                    </div>
                                </div>
                            </div>
                        </div>

                        <!-- Row 4: Config File -->
                        <div class="card-row full-width">
                            <div class="sub-card">
                                <div class="card-title"><%:Config File%></div>
                                <div class="config-file-content">
                                    <div id="subscription-info-display" class="subscription-info-container" style="display: none;">
                                        <div class="subscription-nav-arrow left" id="subscription-prev-arrow" onclick="switchToPreviousConfig()" title="<%:Previous%>"></div>
                                        <div class="subscription-nav-arrow right" id="subscription-next-arrow" onclick="switchToNextConfig()" title="<%:Next%>"></div>
                                        <div class="subscription-info-main">
                                            <div class="subscription-info-header">
                                                <div class="config-file-name" id="current-config-name"><%:No Config Selected%></div>
                                                <div class="file-info" id="file-info-section">
                                                    <span id="file-modify-time" class="file-info-item"><%:Modified: %> --</span>
                                                </div>
                                            </div>
                                            <div class="subscription-info-details">
                                                <div class="subscription-progress" id="subscription-progress-section" style="display: none;">
                                                    <div class="subscription-progress-bar">
                                                        <div id="subscription-progress-fill" class="subscription-progress-fill high" style="width: 0%"></div>
                                                    </div>
                                                    <div id="subscription-info-text" class="subscription-info-text"><%:Collecting data...%></div>
                                                </div>
                                                <div class="card-actions">
                                                    <button type="button" class="icon-btn action-btn" id="refresh-subscription" title="<%:Refresh%>" onclick="return refreshSubscriptionInfo()">
                                                        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
                                                            <path d="M23 4v6h-6"></path>
                                                            <path d="M20.49 15a9 9 0 1 1-2.12-9.36L23 10"></path>
                                                        </svg>
                                                    </button>
                                                    <button type="button" class="icon-btn action-btn" id="config-subscription-url" title="<%:Specify URL%>" onclick="return setSubscriptionUrl()">
                                                        <svg width="32" height="32" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
                                                            <path d="M18.2838 43.1713C14.9327 42.1736 11.9498 40.3213 9.58787 37.867C10.469 36.8227 11 35.4734 11 34.0001C11 30.6864 8.31371 28.0001 5 28.0001C4.79955 28.0001 4.60139 28.01 4.40599 28.0292C4.13979 26.7277 4 25.3803 4 24.0001C4 21.9095 4.32077 19.8938 4.91579 17.9995C4.94381 17.9999 4.97188 18.0001 5 18.0001C8.31371 18.0001 11 15.3138 11 12.0001C11 11.0488 10.7786 10.1493 10.3846 9.35011C12.6975 7.1995 15.5205 5.59002 18.6521 4.72314C19.6444 6.66819 21.6667 8.00013 24 8.00013C26.3333 8.00013 28.3556 6.66819 29.3479 4.72314C32.4795 5.59002 35.3025 7.1995 37.6154 9.35011C37.2214 10.1493 37 11.0488 37 12.0001C37 15.3138 39.6863 18.0001 43 18.0001C43.0281 18.0001 43.0562 17.9999 43.0842 17.9995C43.6792 19.8938 44 21.9095 44 24.0001C44 25.3803 43.8602 26.7277 43.594 28.0292C43.3986 28.01 43.2005 28.0001 43 28.0001C39.6863 28.0001 37 30.6864 37 34.0001C37 35.4734 37.531 36.8227 38.4121 37.867C36.0502 40.3213 33.0673 42.1736 29.7162 43.1713C28.9428 40.752 26.676 39.0001 24 39.0001C21.324 39.0001 19.0572 40.752 18.2838 43.1713Z" fill="none" stroke="currentColor" stroke-width="4" stroke-linejoin="round"/>
                                                            <path d="M24 31C27.866 31 31 27.866 31 24C31 20.134 27.866 17 24 17C20.134 17 17 20.134 17 24C17 27.866 20.134 31 24 31Z" fill="none" stroke="currentColor" stroke-width="4" stroke-linejoin="round"/>
                                                        </svg>
                                                    </button>
                                                </div>
                                            </div>
                                        </div>
                                    </div>

                                    <div id="config-file-empty-state" class="config-file-empty-state" style="display: none;">
                                        <div class="config-file-empty-message"><%:No config files found, Please upload a config file to get started%></div>
                                        <button type="button" class="config-upload-btn-large" id="upload_config_large" onclick="return uploadConfig()">
                                            <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
                                                <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path>
                                                <polyline points="17,8 12,3 7,8"></polyline>
                                                <line x1="12" y1="3" x2="12" y2="15"></line>
                                            </svg>
                                            <%:Upload Config File%>
                                        </button>
                                    </div>
                                    
                                    <div class="config-file-bottom">
                                        <div class="config-selector">
                                            <select id="config_file_select" class="config-select"><option value=""><%:Collecting data...%></option></select>
                                        </div>
                                        <div class="card-actions">
                                            <button type="button" class="icon-btn action-btn" id="switch_config" title="<%:SwiTch%>" onclick="return switchConfig()"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="17 1 21 5 17 9"></polyline><path d="M3 11V9a4 4 0 0 1 4-4h14"></path><polyline points="7 23 3 19 7 15"></polyline><path d="M21 13v2a4 4 0 0 1-4 4H3"></path></svg></button>
                                            <button type="button" class="icon-btn action-btn" id="update_config" title="<%:Update%>" onclick="return updateConfig()"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 12a9 9 0 0 0-9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"></path><path d="M3 3v5h5"></path><path d="M3 12a9 9 0 0 0 9 9 9.75 9.75 0 0 0 6.74-2.74L21 16"></path><path d="M21 21v-5h-5"></path></svg></button>
                                            <button type="button" class="icon-btn action-btn" id="edit_config" title="<%:Edit%>" onclick="return editConfig()"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"></path><path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"></path></svg></button>
                                            <button type="button" class="icon-btn action-btn" id="upload_config" title="<%:Add%>" onclick="return uploadConfig()"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="12" y1="5" x2="12" y2="19"></line><line x1="5" y1="12" x2="19" y2="12"></line></svg></button>
                                        </div>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>

                    <div class="main-card">
                        <!-- Row 1: Control Panel & Mix Proxy -->
                        <div class="card-row dual-cards">
                            <div class="sub-card">
                                <div class="card-title"><%:Control Panel%></div>
                                <div class="card-content">
                                    <div class="card-value">
                                        <span id="_daip" class="value-indicator"><%:Collecting data...%></span>
                                    </div>
                                </div>
                                <div class="card-actions">
                                    <button type="button" class="icon-btn copy-btn" id="copy_address" title="<%:Copy Address%>" onclick="return copyAddress()"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg></button>
                                    <button type="button" class="icon-btn copy-btn" id="copy_secret" title="<%:Copy Secret%>" onclick="return copySecret()"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="11" width="18" height="11" rx="2" ry="2"></rect><circle cx="12" cy="16" r="1"></circle><path d="M7 11V7a5 5 0 0 1 10 0v4"></path></svg></button>
                                </div>
                            </div>
                            <div class="sub-card">
                                <div class="card-title"><%:Mix Proxy%></div>
                                <div class="card-content">
                                    <div class="card-value">
                                        <span id="_mix_proxy" class="value-indicator"><%:Collecting data...%></span>
                                    </div>
                                </div>
                                <div class="card-actions">
                                    <button type="button" class="icon-btn copy-btn" id="copy_mix_address" title="<%:Copy Address%>" onclick="return copyMixAddress()"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg></button>
                                    <button type="button" class="icon-btn action-btn" id="copy_pac_config" title="<%:Get PAC Config%>" onclick="return generatePacConfig()"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"></circle><path d="M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20"></path><path d="M2 12h20"></path></svg></button>
                                    <button type="button" class="icon-btn copy-btn" id="copy_mix_secret" title="<%:Copy Auth Info%>" onclick="return copyMixAuth()"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="11" width="18" height="11" rx="2" ry="2"></rect><circle cx="12" cy="16" r="1"></circle><path d="M7 11V7a5 5 0 0 1 10 0v4"></path></svg></button>
                                </div>
                            </div>
                        </div>

                        <!-- Row 2: Dashboards -->
                        <div class="card-row full-width">
                            <div class="sub-card dashboard-container">
                                <div class="card-title"><%:Control Panel%></div>
                                <div class="dashboard-buttons">
                                    <button class="dashboard-btn" id="_web"><%:Collecting data...%></button>
                                    <button class="dashboard-btn" id="_webm"><%:Collecting data...%></button>
                                    <button class="dashboard-btn" id="_webz"><%:Collecting data...%></button>
                                    <button class="dashboard-btn" id="_webo"><%:Collecting data...%></button>
                                </div>
                            </div>
                        </div>

                        <!-- Row 3: Quick Actions -->
                        <div class="card-row full-width">
                            <div class="sub-card quick-actions-container">
                                <div class="card-title"><%:Quick Action%></div>
                                <div class="quick-actions-buttons">
                                    <button class="dashboard-btn" id="_close_all_connection_btn"><%:Collecting data...%></button>
                                    <button class="dashboard-btn" id="_reload_firewall_btn"><%:Collecting data...%></button>
                                    <button class="dashboard-btn" id="_flush_dns_cache_btn"><%:Collecting data...%></button>
                                    <button class="dashboard-btn" id="_one_key_update_btn"><%:Collecting data...%></button>
                                </div>
                            </div>
                        </div>

                        <!-- Row 4: Statistics -->
                        <div class="card-row stats-grid">
                            <div class="sub-card stat-item"><span class="stat-label"><%:Up%></span><span id="upload_" class="stat-value">0 KB/S</span></div>
                            <div class="sub-card stat-item"><span class="stat-label"><%:Down%></span><span id="download_" class="stat-value">0 KB/S</span></div>
                            <div class="sub-card stat-item"><span class="stat-label"><%:Up Total%></span><span id="uploadtotal_" class="stat-value">0 KB</span></div>
                            <div class="sub-card stat-item"><span class="stat-label"><%:Down Total%></span><span id="downloadtotal_" class="stat-value">0 KB</span></div>
                            <div class="sub-card stat-item"><span class="stat-label"><%:Connect%></span><span id="connect_t" class="stat-value">0</span></div>
                            <div class="sub-card stat-item"><span class="stat-label"><%:Ram%></span><span id="mem_t" class="stat-value">0 KB</span></div>
                            <div class="sub-card stat-item"><span class="stat-label"><%:CPU%></span><span id="cpu_t" class="stat-value">0 %</span></div>
                            <div class="sub-card stat-item"><span class="stat-label"><%:Load Avg%></span><span id="load_a" class="stat-value">0</span></div>
                        </div>
                    </div>
                </div>
            </div>
        </td>
    </tr>
</table>
</fieldset>

<script type="text/javascript">//<![CDATA[
    var DOMCache = {
        clash: document.getElementById('_clash'),
        mode: document.getElementById('_mode'),
        web: document.getElementById('_web'),
        webo: document.getElementById('_webo'),
        webm: document.getElementById('_webm'),
        webz: document.getElementById('_webz'),
        daip: document.getElementById('_daip'),
        dase: document.getElementById('_dase'),
        oclog: document.getElementById('_oclog'),
        close_all_connection: document.getElementById('_close_all_connection'),
        reload_firewall: document.getElementById('_reload_firewall'),
        one_key_update: document.getElementById('_one_key_update'),
        flush_dns_cache: document.getElementById('_flush_dns_cache'),
        radio_mode: document.getElementById('radio-mode'),
        radio: document.getElementsByName("radios"),
        radio_ru: document.getElementsByName("radios-ru"),
        radio_run_normal: document.getElementById("run_normal"),
        copy_secret: document.getElementById('copy_secret'),
        copy_address: document.getElementById('copy_address'),
        copy_mix_address: document.getElementById('copy_mix_address'),
        copy_mix_secret: document.getElementById('copy_mix_secret'),
        copy_pac_config: document.getElementById('copy_pac_config'),
        mix_proxy: document.getElementById('_mix_proxy'),
        dns_setting_sniffer: document.getElementById('dns-setting-sniffer'),
        dns_setting_respect: document.getElementById('dns-setting-respect'),
        meta_sniffer_on: document.getElementById('meta_sniffer_on'),
        meta_sniffer_off: document.getElementById('meta_sniffer_off'),
        respect_rules_on: document.getElementById('respect_rules_on'),
        respect_rules_off: document.getElementById('respect_rules_off'),
        oc_setting_oversea: document.getElementById('oc-setting-oversea'),
        oc_setting_oversea_0: document.getElementById('oc_setting_oversea_0'),
        oc_setting_oversea_1: document.getElementById('oc_setting_oversea_1'),
        oc_setting_oversea_2: document.getElementById('oc_setting_oversea_2'),
        stream_unlock_setting: document.getElementById('stream-unlock-setting'),
        stream_unlock_on: document.getElementById('stream_unlock_on'),
        stream_unlock_off: document.getElementById('stream_unlock_off'),
        core_version_display: document.getElementById('core-version-display'),
        core_version_text: document.getElementById('core-version-text'),
        plugin_version_display: document.getElementById('plugin-version-display'),
        plugin_version_text: document.getElementById('plugin-version-text')
    };

    var DarkModeDetector = {
        init: function() {
            this.applyDarkMode();
        },
        
        applyDarkMode: function() {
            var ocContainers = document.querySelectorAll('.oc');
            if (!ocContainers.length) return;
            
            var prefersDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
            var isDarkBg = this.isDarkBackground(document.body);
            var shouldUseDark = prefersDark || isDarkBg;
            
            ocContainers.forEach(function(ocContainer) {
                if (shouldUseDark) {
                    ocContainer.setAttribute('data-darkmode', 'true');
                } else {
                    ocContainer.removeAttribute('data-darkmode');
                }
            });
        },
        
        isDarkBackground: function(element) {
            try {
                var style = window.getComputedStyle(element);
                var bgColor = style.backgroundColor;
                
                if (!bgColor || bgColor === 'transparent' || bgColor === 'rgba(0, 0, 0, 0)') {
                    var parent = element.parentElement;
                    if (parent && parent !== element) {
                        return this.isDarkBackground(parent);
                    }
                    return false;
                }
                
                var r, g, b;
                
                if (/rgba?\(/.test(bgColor)) {
                    var rgb = bgColor.match(/[\d.]+/g);
                    r = parseFloat(rgb[0]);
                    g = parseFloat(rgb[1]);
                    b = parseFloat(rgb[2]);
                } else if (/#/.test(bgColor)) {
                    if (bgColor.length === 4) {
                        r = parseInt(bgColor[1] + bgColor[1], 16);
                        g = parseInt(bgColor[2] + bgColor[2], 16);
                        b = parseInt(bgColor[3] + bgColor[3], 16);
                    } else if (bgColor.length === 7) {
                        r = parseInt(bgColor.slice(1, 3), 16);
                        g = parseInt(bgColor.slice(3, 5), 16);
                        b = parseInt(bgColor.slice(5, 7), 16);
                    }
                } else {
                    return false;
                }
                
                var luminance = 0.2126 * r + 0.7152 * g + 0.0722 * b;
                return luminance < 128;
            } catch (e) {
                return false;
            }
        }
    };

    var StateManager = {
        current_status: {},
        cached_proxy_info: null,
        last_request_time: {},
        request_cache: {},
        cache_ttl: 5000,
        pending_requests: new Map(),
        
        _cachedXHR: function(url, params, callback, force) {
            var cacheKey = params ? url + JSON.stringify(params) : url;
            var now = Date.now();

            if (this.pending_requests.has(cacheKey)) {
                this.pending_requests.get(cacheKey).push(callback);
                return;
            }

            var cacheExists = this.request_cache.hasOwnProperty(cacheKey);
            var isCacheStale = cacheExists && (now - this.last_request_time[cacheKey] >= this.cache_ttl);

            if (!force && cacheExists && !isCacheStale) {
                setTimeout(function() {
                    callback({ status: 200, fromCache: true }, StateManager.request_cache[cacheKey]);
                }, 0);
                return;
            }
            
            if (!force && cacheExists && isCacheStale) {
                setTimeout(function() {
                    callback({ status: 200, fromCache: true, stale: true }, StateManager.request_cache[cacheKey]);
                }, 0);
            }

            this.pending_requests.set(cacheKey, [callback]);
            var self = this;

            XHR.get(url, params, function(x, data) {
                var callbacks = self.pending_requests.get(cacheKey) || [];
                self.pending_requests.delete(cacheKey);

                if (x && x.status == 200 && data) {
                    self.request_cache[cacheKey] = data;
                    self.last_request_time[cacheKey] = Date.now();
                }

                callbacks.forEach(function(cb) {
                    try {
                        cb(x, data);
                    } catch (e) {
                    }
                });
            });
        },

        cachedXHRGet: function(url, callback, force) {
            this._cachedXHR(url, null, callback, force);
        },

        cachedXHRGetWithParams: function(url, params, callback, force) {
            this._cachedXHR(url, params, callback, force);
        },
        
        clearCache: function(url, params) {
            var cacheKey = params ? url + JSON.stringify(params) : url;
            delete this.request_cache[cacheKey];
            delete this.last_request_time[cacheKey];
        },
        
        clearAllCache: function() {
            this.request_cache = {};
            this.last_request_time = {};
        },
        
        hasCache: function(url, params) {
            var cacheKey = params ? url + JSON.stringify(params) : url;
            return !!this.request_cache[cacheKey];
        },
        
        getCacheAge: function(url, params) {
            var cacheKey = params ? url + JSON.stringify(params) : url;
            if (!this.last_request_time[cacheKey]) {
                return null;
            }
            return Date.now() - this.last_request_time[cacheKey];
        },
        
        setCacheTTL: function(ttl) {
            this.cache_ttl = ttl;
        },
        
        batchUpdateDOM: function(updates) {
            var fragment = document.createDocumentFragment();
            for (var i = 0; i < updates.length; i++) {
                var update = updates[i];
                if (update.element && update.content !== undefined) {
                    update.element.innerHTML = update.content;
                }
            }
        },
        
        cachedXHRGetWithRetry: function(url, params, callback, force, maxRetries) {
            maxRetries = maxRetries || 3;
            var retryCount = 0;
            var self = this;
            
            function attemptRequest() {
                self.cachedXHRGetWithParams(url, params, function(x, data) {
                    if (x && x.status == 200) {
                        callback(x, data);
                    } else if (retryCount < maxRetries) {
                        retryCount++;
                        setTimeout(attemptRequest, 1000 * retryCount);
                    } else {
                        callback(x, data);
                    }
                }, force && retryCount === 0);
            }
            
            attemptRequest();
        }
    };

    var WSManager = {
        connections: {},
        connectionStates: {
            CONNECTING: 0,
            CONNECTED: 1,
            DISCONNECTED: 2,
            ERROR: 3
        },
        retryAttempts: {},
        maxRetries: 3,
        reconnectDelay: 2000,
        heartbeatInterval: 30000,
        heartbeatTimers: {},
        _ws_connect: false,
        _ws_error: false,
        _ws_retry: 0,
        _allowedCloseCodes: [1000, 1001, 1005, 1006],

        isSupported: function() {
            return typeof window.WebSocket !== "undefined";
        },

        createConnection: function(type, url, messageHandler, options) {
            options = options || {};

            this.closeConnection(type);

            if (!this.isSupported()) {
                this.enableFallbackMode();
                return null;
            }

            try {
                var ws = new window.WebSocket(url);

                this.connections[type] = {
                    socket: ws,
                    url: url,
                    messageHandler: messageHandler,
                    state: this.connectionStates.CONNECTING,
                    lastActivity: Date.now(),
                    options: options
                };

                this.retryAttempts[type] = 0;

                if (ws.addEventListener) {
                    ws.addEventListener('open', this.handleOpen.bind(this, type));
                    ws.addEventListener('message', this.handleMessage.bind(this, type));
                    ws.addEventListener('error', this.handleError.bind(this, type));
                    ws.addEventListener('close', this.handleClose.bind(this, type));
                } else {
                    ws.onopen = this.handleOpen.bind(this, type);
                    ws.onmessage = this.handleMessage.bind(this, type);
                    ws.onerror = this.handleError.bind(this, type);
                    ws.onclose = this.handleClose.bind(this, type);
                }

                return ws;
            } catch (error) {
                this.handleConnectionError(type, error);
                return null;
            }
        },

        startHeartbeat: function(type) {
            var self = this;
            this.stopHeartbeat(type);

            this.heartbeatTimers[type] = setInterval(function() {
                var connection = self.connections[type];
                if (connection && connection.socket && connection.state === self.connectionStates.CONNECTED) {
                    var timeSinceLastActivity = Date.now() - connection.lastActivity;
                    if (timeSinceLastActivity > self.heartbeatInterval * 3) {
                        self.reconnectConnection(type);
                    }
                }
            }, this.heartbeatInterval);

            if (!this._visibilityHandlerAdded) {
                document.addEventListener('visibilitychange', function() {
                    if (document.hidden) {
                        self.stopHeartbeat(type);
                    } else {
                        self.startHeartbeat(type);
                    }
                });
                this._visibilityHandlerAdded = true;
            }
        },

        stopHeartbeat: function(type) {
            if (this.heartbeatTimers[type]) {
                clearInterval(this.heartbeatTimers[type]);
                delete this.heartbeatTimers[type];
            }
        },

        reconnectConnection: function(type) {
            var connection = this.connections[type];
            if (connection) {
                this.createConnection(type, connection.url, connection.messageHandler, connection.options);
            }
        },

        closeConnection: function(type) {
            var connection = this.connections[type];
            if (connection && connection.socket) {
                this.stopHeartbeat(type);
                try {
                    connection.socket.close(1000, 'Normal closure');
                } catch (error) {}
                delete this.connections[type];
            }
        },

        closeAll: function() {
            var types = Object.keys(this.connections);
            for (var i = 0; i < types.length; i++) {
                this.closeConnection(types[i]);
            }
            this._ws_connect = false;
            this._ws_error = false;
            this._ws_retry = 0;
        },

        handleMessage: function(type, event) {
            var connection = this.connections[type];
            if (connection && connection.messageHandler) {
                connection.lastActivity = Date.now();
                try {
                    var data;
                    try {
                        data = JSON.parse(event.data);
                    } catch (e) {
                        data = event.data;
                    }
                    connection.messageHandler({ data: data, raw: event.data, event: event });
                } catch (error) {
                }
            }
        },

        handleOpen: function(type, event) {
            var connection = this.connections[type];
            if (connection) {
                connection.state = this.connectionStates.CONNECTED;
                connection.lastActivity = Date.now();
            }
            this.retryAttempts[type] = 0;
            this.startHeartbeat(type);

            if (type === 'traffic' || Object.keys(this.connections).length === 3) {
                this._ws_connect = true;
                this._ws_error = false;
                this._ws_retry = 0;
            }
        },

        handleError: function(type, error) {
            var connection = this.connections[type];
            if (connection) {
                connection.state = this.connectionStates.ERROR;
            }
            this._ws_error = true;
            this.stopHeartbeat(type);

            if (type === 'traffic') {
                this.enableFallbackMode();
            }
        },

        handleClose: function(type, event) {
            var connection = this.connections[type];
            if (connection) {
                connection.state = this.connectionStates.DISCONNECTED;
            }
            this.stopHeartbeat(type);

            if (this._allowedCloseCodes.indexOf(event.code) === -1) {
                this.scheduleReconnect(type);
            }
        },

        handleConnectionError: function(type, error) {
            var connection = this.connections[type];
            if (connection) {
                connection.state = this.connectionStates.ERROR;
            }
            this._ws_error = true;
            this.enableFallbackMode();
        },

        scheduleReconnect: function(type) {
            var self = this;
            var connection = this.connections[type];

            if (!connection || this.retryAttempts[type] >= this.maxRetries) {
                this.enableFallbackMode();
                return;
            }

            this.retryAttempts[type] = (this.retryAttempts[type] || 0) + 1;
            var delay = this.reconnectDelay * Math.pow(1.5, this.retryAttempts[type] - 1);

            setTimeout(function() {
                if (self.connections[type] && self.connections[type].state !== self.connectionStates.CONNECTED) {
                    self.createConnection(type, connection.url, connection.messageHandler, connection.options);
                }
            }, delay);
        },

        enableFallbackMode: function() {
            this._ws_connect = false;
            this.closeAll();
            if (typeof NetworkStatsManager !== "undefined" && !NetworkStatsManager.isEnabled) {
                NetworkStatsManager.start();
            }
        },

        getConnectionState: function(type) {
            var connection = this.connections[type];
            return connection ? connection.state : this.connectionStates.DISCONNECTED;
        },

        getAllConnectionStates: function() {
            var states = {};
            for (var type in this.connections) {
                states[type] = this.getConnectionState(type);
            }
            return states;
        },

        hasActiveConnections: function() {
            for (var type in this.connections) {
                if (this.getConnectionState(type) === this.connectionStates.CONNECTED) {
                    return true;
                }
            }
            return false;
        },

        resetRetryCount: function(type) {
            if (type) {
                this.retryAttempts[type] = 0;
            } else {
                this.retryAttempts = {};
            }
        }
    };

    var ConfigFileManager = {
        configList: [],
        currentConfig: '',
        currentConfigIndex: -1,
        selectElement: null,
        rawCurrentConfig: '',
        
        init: function() {
            this.selectElement = document.getElementById('config_file_select');
            if (this.selectElement) {
                this.loadConfigFileList();
                this.setupEventListeners();
            }
        },
        
        setupEventListeners: function() {
            if (this.selectElement) {
                this.selectElement.addEventListener('change', this.onConfigChange.bind(this));
            }
        },
        
        loadConfigFileList: function() {
            this.updateSelectOptions([{value: '', text: '<%:Collecting data...%>', disabled: true}]);
            
            StateManager.cachedXHRGet('<%=luci.dispatcher.build_url("admin", "services", "openclash", "config_file_list")%>', function(x, data) {
                if (x && x.status == 200) {
                    ConfigFileManager.handleConfigListResponse(data);
                } else {
                    ConfigFileManager.handleConfigListError();
                }
            }, true);
        },
        
        handleConfigListResponse: function(data) {
            try {
                var configFiles = [];
                var currentConfigFile = '';
                var currentFileInfo = null;
                
                if (data.config_files && Array.isArray(data.config_files)) {
                    configFiles = data.config_files;
                } else if (data.files && Array.isArray(data.files)) {
                    configFiles = data.files;
                } else {
                    configFiles = data.config_list || [];
                }
                
                if (data.current_config) {
                    currentConfigFile = data.current_config;
                } else if (data.current) {
                    currentConfigFile = data.current;
                }
                
                this.rawCurrentConfig = currentConfigFile;
                this.configList = configFiles;
                this.currentConfig = currentConfigFile;
                this.currentConfigIndex = -1;

                this.toggleEmptyState(configFiles.length === 0);
                
                this.updateConfigSelect(configFiles, currentConfigFile);

                if (configFiles.length > 0) {
                    if (currentConfigFile) {
                        for (var i = 0; i < configFiles.length; i++) {
                            var file = configFiles[i];
                            var filePath = typeof file === 'string' ? file : (file.path || file.filepath || file);
                            
                            if (filePath === currentConfigFile) {
                                this.currentConfigIndex = i;
                                if (typeof file === 'object' && file.mtime && file.size) {
                                    currentFileInfo = {
                                        mtime: file.mtime,
                                        size: file.size
                                    };
                                }
                                break;
                            }
                        }
                    }
                    
                    this.updateSubscriptionDisplay(currentConfigFile, currentFileInfo);
                    
                    if (currentConfigFile && SubscriptionManager.currentConfigFile !== currentConfigFile) {
                        SubscriptionManager.currentConfigFile = currentConfigFile;
                        SubscriptionManager.getSubscriptionInfo();
                    }
                } else {
                    this.hideSubscriptionDisplay();
                    SubscriptionManager.currentConfigFile = '';
                }
                
                this.updateNavigationArrows();

                if (this._retryGetConfigList) {
                    clearInterval(this._retryGetConfigList);
                    this._retryGetConfigList = null;
                }
                
            } catch (e) {
                this.handleConfigListError();
            }
        },
        
        handleConfigListError: function() {
            this.updateSelectOptions([
                {value: '', text: '<%:Failed to load config files%>', disabled: true}
            ]);
            
            this.toggleEmptyState(true);
            this.hideSubscriptionDisplay();

            if (!this._retryGetConfigList) {
                var self = this;
                this._retryGetConfigList = setInterval(function() {
                    self.loadConfigFileList();
                }, 5000);
            }
        },

        toggleEmptyState: function(isEmpty) {
            var emptyStateElement = document.getElementById('config-file-empty-state');
            var configFileBottom = document.querySelector('.config-file-bottom');
            var configFileContent = document.querySelector('.config-file-content');
            
            if (isEmpty) {
                if (emptyStateElement) {
                    emptyStateElement.style.display = 'flex';
                }
                if (configFileBottom) {
                    configFileBottom.style.display = 'none';
                }
                if (configFileContent) {
                    configFileContent.classList.add('empty-state');
                }
                this.hideSubscriptionDisplay();
            } else {
                if (emptyStateElement) {
                    emptyStateElement.style.display = 'none';
                }
                if (configFileBottom) {
                    configFileBottom.style.display = 'flex';
                }
                if (configFileContent) {
                    configFileContent.classList.remove('empty-state');
                }
            }
        },
        
        hideSubscriptionDisplay: function() {
            var subscriptionDisplay = document.getElementById('subscription-info-display');
            if (subscriptionDisplay) {
                subscriptionDisplay.style.display = 'none';
            }
        },
        
        updateConfigSelect: function(configFiles, currentConfig) {
            var options = [];
            
            if (!configFiles || configFiles.length === 0) {
                options.push({
                    value: '',
                    text: '<%:No config files found%>',
                    disabled: true
                });
            } else {
                options.push({
                    value: '',
                    text: '<%:Please select a config file%>',
                    disabled: false
                });
                
                configFiles.forEach(function(file) {
                    var fileName, filePath;
                    
                    if (typeof file === 'string') {
                        fileName = file;
                        filePath = file;
                    } else {
                        fileName = file.name || file.filename || file.path || file;
                        filePath = file.path || file.filepath || file.name || file;
                    }
                    
                    var displayName = fileName;
                    
                    options.push({
                        value: filePath,
                        text: displayName,
                        disabled: false,
                        selected: filePath === currentConfig || fileName === currentConfig
                    });
                });
            }
            
            this.updateSelectOptions(options);
        },
        
        updateSelectOptions: function(options) {
            if (!this.selectElement) return;
            
            this.selectElement.innerHTML = '';
            
            options.forEach(function(option) {
                var optionElement = document.createElement('option');
                optionElement.value = option.value;
                optionElement.textContent = option.text;
                optionElement.disabled = option.disabled || false;
                optionElement.selected = option.selected || false;
                
                this.selectElement.appendChild(optionElement);
            }, this);
        },

        updateSubscriptionDisplay: function(configFile, fileInfo) {
            var container = document.getElementById('subscription-info-display');
            var configNameElement = document.getElementById('current-config-name');
            var fileModifyTimeElement = document.getElementById('file-modify-time');
            var detailsSection = document.getElementById('subscription-info-details');
            
            if (!container) return;
            
            if (this.configList.length === 0) {
                container.style.display = 'none';
                return;
            }
            
            if (!configFile) {
                container.style.display = 'none';
                return;
            }
            
            var configFileContent = document.querySelector('.config-file-content');
            if (configFileContent && configFileContent.classList.contains('empty-state')) {
                container.style.display = 'none';
                return;
            }
            
            container.style.display = 'flex';

            if (configNameElement) {
                var displayName = this.formatDisplayName(configFile);
                if (configFile === this.rawCurrentConfig) {
                    configNameElement.innerHTML =
                        '<svg width="0.6em" height="0.6em" viewBox="0 0 24 24" fill="var(--primary-color)" style="vertical-align:middle;margin-right:0.2em;margin-bottom:0.2em;">' +
                        '<circle cx="12" cy="12" r="8" fill="var(--primary-color)"/>' +
                        '</svg>' + displayName;
                } else {
                    configNameElement.textContent = displayName;
                }
                if (configNameElement.scrollWidth > configNameElement.clientWidth) {
                    configNameElement.title = displayName;
                } else {
                    configNameElement.title = '';
                }
            }
            
            if (fileInfo) {
                if (fileModifyTimeElement) {
                    var modifyTime = this.formatUnixTime(fileInfo.mtime);
                    fileModifyTimeElement.textContent = '<%:Update Time%>: ' + modifyTime;
                    if (fileModifyTimeElement.scrollWidth > fileModifyTimeElement.clientWidth) {
                        fileModifyTimeElement.title = fileModifyTimeElement.textContent;
                    } else {
                        fileModifyTimeElement.title = '';
                    }
                }
                
                if (detailsSection) {
                    detailsSection.style.display = 'flex';
                }
            } else {
                if (fileModifyTimeElement) {
                    fileModifyTimeElement.textContent = '<%:Update Time%> --';
                }
                
                if (detailsSection) {
                    detailsSection.style.display = 'none';
                }
            }
        },

        formatUnixTime: function(unixTimestamp) {
            if (!unixTimestamp || unixTimestamp === 0) {
                return '--';
            }
            
            try {
                var date = new Date(unixTimestamp * 1000);
                var year = date.getFullYear();
                var month = String(date.getMonth() + 1).padStart(2, '0');
                var day = String(date.getDate()).padStart(2, '0');
                var hour = String(date.getHours()).padStart(2, '0');
                var minute = String(date.getMinutes()).padStart(2, '0');
                var second = String(date.getSeconds()).padStart(2, '0');
                
                return year + '-' + month + '-' + day + ' ' + hour + ':' + minute + ':' + second;
            } catch (e) {
                return '--';
            }
        },

        formatFileSize: function(bytes) {
            if (!bytes || bytes === 0) return '--';
            
            var sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
            var i = Math.floor(Math.log(bytes) / Math.log(1024));
            
            if (i === 0) {
                return bytes + ' ' + sizes[i];
            }
            
            return (bytes / Math.pow(1024, i)).toFixed(1) + ' ' + sizes[i];
        },
        
        formatDisplayName: function(fileName) {
            if (!fileName) return '<%:Unknown%>';
            
            var name = fileName.split('/').pop().split('\\').pop();
            
            //name = name.replace(/\.(yaml|yml)$/i, '');
            
            if (name.length > 30) {
                name = name.substring(0, 27) + '...';
            }
            
            return name;
        },
        
        onConfigChange: function(event) {
            var selectedValue = event.target.value;
            
            if (selectedValue) {
                this.currentConfig = selectedValue;
                
                for (var i = 0; i < this.configList.length; i++) {
                    var file = this.configList[i];
                    var filePath = typeof file === 'string' ? file : (file.path || file.filepath || file);
                    
                    if (filePath === selectedValue) {
                        this.currentConfigIndex = i;
                        break;
                    }
                }
                
                var selectedFileInfo = this.getConfigFileInfo(selectedValue);
                this.updateSubscriptionDisplay(selectedValue, selectedFileInfo);
                this.updateNavigationArrows();
                
                if (SubscriptionManager.currentConfigFile !== selectedValue) {
                    SubscriptionManager.currentConfigFile = selectedValue;
                    var detailsSection = document.getElementById('subscription-info-details');
                    if (detailsSection) {
                        detailsSection.style.display = 'none';
                    }
                    SubscriptionManager.getSubscriptionInfo();
                }
            } else {
                this.currentConfig = '';
                this.currentConfigIndex = -1;
                SubscriptionManager.currentConfigFile = '';
                this.hideSubscriptionDisplay();
                this.updateNavigationArrows();
            }
        },

        getConfigFileInfo: function(selectedValue) {
            var selectedFileInfo = null;
            for (var i = 0; i < this.configList.length; i++) {
                var file = this.configList[i];
                var filePath = typeof file === 'string' ? file : (file.path || file.filepath || file);
                
                if (filePath === selectedValue) {
                    if (typeof file === 'object' && file.mtime && file.size) {
                        selectedFileInfo = {
                            mtime: file.mtime,
                            size: file.size
                        };
                    }
                    break;
                }
            }
            return selectedFileInfo;
        },
        
        updateNavigationArrows: function() {
            var prevArrow = document.getElementById('subscription-prev-arrow');
            var nextArrow = document.getElementById('subscription-next-arrow');
            
            if (!prevArrow || !nextArrow) return;
            
            var hasMultipleConfigs = this.configList.length > 1;
            var currentIndex = this.currentConfigIndex;
            
            if (!hasMultipleConfigs || currentIndex === -1) {
                prevArrow.style.display = 'none';
                nextArrow.style.display = 'none';
                return;
            }
            
            prevArrow.style.display = 'block';
            nextArrow.style.display = 'block';
            
            prevArrow.classList.remove('disabled');
            nextArrow.classList.remove('disabled');
        },
        
        switchToConfigByIndex: function(index) {
            if (this.configList.length === 0) {
                return false;
            }
            
            if (index < 0) {
                index = this.configList.length - 1; 
            } else if (index >= this.configList.length) {
                index = 0;
            }
            
            var file = this.configList[index];
            var filePath = typeof file === 'string' ? file : (file.path || file.filepath || file);
            
            if (this.selectElement) {
                this.selectElement.value = filePath;
            }
            
            this.currentConfig = filePath;
            this.currentConfigIndex = index;
            
            var fileInfo = this.getConfigFileInfo(filePath);
            this.updateSubscriptionDisplay(filePath, fileInfo);
            this.updateNavigationArrows();
            
            if (SubscriptionManager.currentConfigFile !== filePath) {
                SubscriptionManager.currentConfigFile = filePath;
                var detailsSection = document.getElementById('subscription-info-details');
                if (detailsSection) {
                    detailsSection.style.display = 'none';
                }
                SubscriptionManager.getSubscriptionInfo();
            }
            
            return true;
        },
        
        refreshConfigList: function() {
            this.loadConfigFileList();
        },
        
        getCurrentConfig: function() {
            return this.currentConfig;
        },
        
        getSelectedConfig: function() {
            return this.selectElement ? this.selectElement.value : '';
        }
    };

    var SubscriptionManager = {
        currentConfigFile: '',
        retryCount: 0,
        maxRetries: 3,
        updateTimer: null,
        isInitialized: false,
        
        init: function() {
            if (this.isInitialized) return;
            this.isInitialized = true;
            
            setTimeout(function() {
                SubscriptionManager.loadSubscriptionInfo();
                SubscriptionManager.startAutoUpdate();
            }, 500);
        },
        
        loadSubscriptionInfo: function() {
            var currentConfig = ConfigFileManager.getCurrentConfig() || ConfigFileManager.getSelectedConfig();
            if (currentConfig && currentConfig !== this.currentConfigFile) {
                this.currentConfigFile = currentConfig;
                this.getSubscriptionInfo();
            }
        },
        
        getSubscriptionInfo: function() {
            if (ConfigFileManager.configList.length === 0) {
                return;
            }
            
            if (!this.currentConfigFile) return;
            
            var requestConfigFile = this.currentConfigFile;
            var filename = this.extractFilename(this.currentConfigFile);
            if (!filename) return;
            
            var cachedData = localStorage.getItem('sub_info_' + filename);
            var shouldFetchNew = true;
            
            if (cachedData) {
                try {
                    var parsedData = JSON.parse(cachedData);

                    if (parsedData.sub_info && parsedData.sub_info !== "No Sub Info Found") {
                        if (this.currentConfigFile === requestConfigFile) {
                            this.displaySubscriptionInfo(parsedData);
                        }
                    } else if (parsedData.sub_info === "No Sub Info Found") {
                        if (this.currentConfigFile === requestConfigFile) {
                            this.showNoInfo();
                        }
                    }
                    
                    if (parsedData.get_time) {
                        var currentTime = Math.floor(Date.now() / 1000);
                        var cacheTime = parseInt(parsedData.get_time);
                        var timeDiff = currentTime - cacheTime;
                        var halfHourInSeconds = 30 * 60;
                        
                        if (timeDiff <= halfHourInSeconds) {
                            shouldFetchNew = false;
                        }
                    }
                } catch (e) {
                    shouldFetchNew = true;
                }
            }
            
            if (shouldFetchNew) {
                StateManager.cachedXHRGetWithParams('<%=luci.dispatcher.build_url("admin", "services", "openclash", "sub_info_get")%>', {filename: filename}, function(x, status) {
                    if (SubscriptionManager.currentConfigFile !== requestConfigFile) {
                        return;
                    }
                    if (x && x.status == 200 && status.sub_info && status.sub_info !== "No Sub Info Found") {
                        SubscriptionManager.retryCount = 0;
                        localStorage.setItem('sub_info_' + filename, JSON.stringify(status));
                        SubscriptionManager.displaySubscriptionInfo(status);
                    } else if (x && x.status == 200 && status.sub_info === "No Sub Info Found") {
                        SubscriptionManager.retryCount = 0;
                        localStorage.setItem('sub_info_' + filename, JSON.stringify(status));
                        SubscriptionManager.showNoInfo();
                    } else {
                        SubscriptionManager.handleError();
                    }
                }, true);
            }
        },
        
        displaySubscriptionInfo: function(data) {
            if (ConfigFileManager.configList.length === 0) {
                return;
            }
            
            var container = document.getElementById('subscription-info-display');
            var progressSection = document.getElementById('subscription-progress-section');
            var detailsSection = document.getElementById('subscription-info-details');
            var progressFill = document.getElementById('subscription-progress-fill');
            var infoText = document.getElementById('subscription-info-text');
            
            if (!container) return;

            var configFileContent = document.querySelector('.config-file-content');
            if (configFileContent && configFileContent.classList.contains('empty-state')) {
                return;
            }

            container.style.display = 'flex';
            
            if (data && data.sub_info && data.sub_info !== "No Sub Info Found") {
                if (progressSection) {
                    progressSection.style.display = 'flex';
                }
                
                if (!progressFill || !infoText) return;
                
                var percent = data.percent || 0;
                var used = data.surplus || data.used || '0 B';
                var total = data.total || '0 B';
                var expire = data.expire || '';
                var daysLeft = data.day_left || 0;
                
                progressFill.style.width = percent + '%';
                progressFill.className = 'subscription-progress-fill ' + 
                    (percent >= 50 ? 'high' : (percent >= 20 ? 'medium' : 'low'));
                
                var infoString = used + ' / ' + total + ' (' + percent + '%)';
                if (expire && daysLeft > 0) {
                    infoString += ' • ' + '<%:Remaining%> ' + daysLeft + ' <%:days%>';
                    infoString += ' • ' + '<%:Expire Date%>: ' + expire;
                }
                
                infoText.textContent = infoString;
                if (infoText.scrollWidth > infoText.clientWidth) {
                    infoText.title = infoString;
                } else {
                    infoText.title = '';
                }
                
            } else {
                if (progressSection) {
                    progressSection.style.display = 'none';
                }
            }
            
            if (detailsSection) {
                detailsSection.style.display = 'flex';
            }
        },
        
        showNoInfo: function() {
            if (ConfigFileManager.configList.length === 0) {
                return;
            }
            
            var container = document.getElementById('subscription-info-display');
            var progressSection = document.getElementById('subscription-progress-section');
            var detailsSection = document.getElementById('subscription-info-details');
            
            if (!container) return;
            
            var configFileContent = document.querySelector('.config-file-content');
            if (configFileContent && configFileContent.classList.contains('empty-state')) {
                return;
            }
            
            container.style.display = 'flex';
            
            if (progressSection) {
                progressSection.style.display = 'none';
            }
            
            if (detailsSection) {
                var fileModifyTimeElement = document.getElementById('file-modify-time');
                
                var hasFileInfo = false;
                if (fileModifyTimeElement) {
                    var modifyTimeText = fileModifyTimeElement.textContent || '';
                    hasFileInfo = !modifyTimeText.includes('--');
                }
                
                detailsSection.style.display = hasFileInfo ? 'flex' : 'none';
            }
        },
        
        showError: function() {
            if (ConfigFileManager.configList.length === 0) {
                return;
            }
            
            var container = document.getElementById('subscription-info-display');
            var progressSection = document.getElementById('subscription-progress-section');
            var detailsSection = document.getElementById('subscription-info-details');
            
            if (!container) return;
            
            var configFileContent = document.querySelector('.config-file-content');
            if (configFileContent && configFileContent.classList.contains('empty-state')) {
                return;
            }
            
            container.style.display = 'flex';
            
            if (progressSection) {
                progressSection.style.display = 'none';
            }
            if (detailsSection) {
                detailsSection.style.display = 'none';
            }
        },
        
        handleError: function() {
            if (this.retryCount >= this.maxRetries) {
                this.showError();
                this.retryCount = 0;
                if (this.currentConfigFile) {
                    localStorage.removeItem('sub_info_' + this.extractFilename(this.currentConfigFile));
                }
            } else {
                this.retryCount++;
                setTimeout(function() {
                    SubscriptionManager.getSubscriptionInfo();
                }, 2000);
            }
        },
        
        extractFilename: function(path) {
            if (!path) return '';
            var parts = path.split('/');
            var filename = parts[parts.length - 1];
            
            if (filename.endsWith('.yaml')) {
                filename = filename.slice(0, -5);
            } else if (filename.endsWith('.yml')) {
                filename = filename.slice(0, -4);
            }
            
            return filename;
        },
        
        startAutoUpdate: function() {
            if (this.updateTimer) {
                clearTimeout(this.updateTimer);
            }
            
            this.updateTimer = setTimeout(function() {
                SubscriptionManager.getSubscriptionInfo();
                SubscriptionManager.startAutoUpdate();
            }, 60000 * 15);
        },
        
        stopAutoUpdate: function() {
            if (this.updateTimer) {
                clearTimeout(this.updateTimer);
                this.updateTimer = null;
            }
        }
    };

    var LogManager = {
        isPolling: false,
        pollTimer: null,
        maxPollTime: 15000,
        pollInterval: 1000,
        startTime: 0,
        lastLogContent: '',
        retryCount: 0,
        maxRetries: 3,
        retryDelay: 1000,

        startLogDisplay: function(initialMessage) {
            if (this.isPolling) {
                this.stopLogDisplay();
            }
            if (this.pollTimer) {
                clearTimeout(this.pollTimer);
                this.pollTimer = null;
            }

            StateManager.clearCache('<%=luci.dispatcher.build_url("admin", "services", "openclash", "startlog")%>');

            if (DOMCache.oclog) {
                DOMCache.oclog.style.display = 'inline-flex';
                DOMCache.oclog.innerHTML = '<b style="color:var(--warning-color)">' + (initialMessage || '<%:Processing...%>') + '</b>';
            }
            
            this.isPolling = true;
            this.startTime = Date.now();
            this.lastLogContent = '';
            this.retryCount = 0;
            
            var self = this;
            setTimeout(function() {
                if (self.isPolling) {
                    self.pollLog();
                }
            }, 2000);
        },
        
        stopLogDisplay: function() {
            this.isPolling = false;
            if (this.pollTimer) {
                clearTimeout(this.pollTimer);
                this.pollTimer = null;
            }
            this.lastLogContent = '';
            this.retryCount = 0;
            if (DOMCache.oclog) {
                setTimeout(function() {
                    if (!LogManager.isPolling) {
                        DOMCache.oclog.style.display = 'none';
                    }
                }, 1000);
            }
        },
        
        pollLog: function() {
            if (!this.isPolling) return;
            
            if (Date.now() - this.startTime > this.maxPollTime) {
                this.stopLogDisplay();
                return;
            }
            
            var self = this;
            StateManager.cachedXHRGet('<%=luci.dispatcher.build_url("admin", "services", "openclash", "startlog")%>', function(x, status) {
                if (!self.isPolling) return;

                if (x && x.status == 200 && status && typeof status.startlog !== 'undefined') {
                    var logContent = (status.startlog || '').trim();

                    if (self.checkForErrors(logContent)) {
                        self.stopLogDisplay();
                        return;
                    }

                    var contentToDisplay = logContent.replace('##FINISH##', '').trim();
                    if (contentToDisplay && contentToDisplay !== self.lastLogContent) {
                        self.displayLog(contentToDisplay);
                    }

                    if (logContent.includes('##FINISH##')) {
                        setTimeout(function() {
                            self.stopLogDisplay();
                        }, 3000);
                        return;
                    }
                    
                    if (logContent !== '') {
                        self.retryCount = 0;
                        self.scheduleNextPoll(self.pollInterval);
                    } else {
                        self.handleEmptyResponse();
                    }
                } else {
                    self.handleFailure();
                }
            }, true);
        },

        handleEmptyResponse: function() {
            this.scheduleNextPoll(this.pollInterval);
        },

        handleFailure: function() {
            if (this.retryCount < this.maxRetries) {
                this.retryCount++;
                var delay = Math.min(this.retryDelay * Math.pow(2, this.retryCount - 1), 5000);
                this.scheduleNextPoll(delay);
            } else {
                this.stopLogDisplay();
            }
        },

        scheduleNextPoll: function(delay) {
            var self = this;
            this.pollTimer = setTimeout(function() {
                self.pollLog();
            }, delay);
        },
        
        checkForErrors: function(log) {
            if (!log) return false;
            if (log.match(/level=fatal|level=error|FTL \[Config]/)) {
                XHR.get('<%=luci.dispatcher.build_url("admin", "services", "openclash", "del_start_log")%>', null, function(x) {});
                
                var errorMsg;
                if (log.match(/level=(fatal|error)/)) {
                    var msgParts = log.split('msg=');
                    errorMsg = msgParts.length > 1 ? msgParts[1].replace(/"/g, '') : log;
                } else { // FTL [Config]
                    var ftlParts = log.split('FTL [Config] ');
                    errorMsg = ftlParts.length > 1 ? ftlParts[1] : log;
                }
                
                setTimeout(function() {
                    alert('<%:OpenClash Start Failed%>:\n\n' + errorMsg);
                }, 500);
                
                return true;
            }
            return false;
        },
        
        displayLog: function(logContent) {
            if (!this.isPolling || !DOMCache.oclog) return;
            
            var cleanLog = this.cleanLogContent(logContent);
            this.lastLogContent = cleanLog;

            var color = this.getLogColor(cleanLog);
            var displayText = this.formatLogText(cleanLog);
            
            DOMCache.oclog.innerHTML = '<b style="color:' + color + '">' + displayText + '</b>';
        },
        
        cleanLogContent: function(content) {
            return content ? content.replace(/[\r\n]+/g, ' ').replace('##FINISH##', '').trim() : '';
        },
        
        getLogColor: function(log) {
            if (log.includes("Tip:") || log.includes("提示：")) {
                return 'var(--warning-color)';
            } else if (log.includes("Error:") || log.includes("错误：") || log.includes("level=error")) {
                return 'var(--error-color)';
            } else if (log.includes("Warning:") || log.includes("警告：") || log.includes("level=warning")) {
                return 'var(--warning-log)';
            } else if (log.includes("Watchdog:") || log.includes("守护程序：")) {
                return 'var(--watch-log)';
            } else if (log.match(/level=info|Success|Started|Ready/)) {
                return 'var(--success-color)';
            } else {
                return 'var(--text-secondary)';
            }
        },
        
        formatLogText: function(log) {
            if (!log) return '<%:Processing...%>';
            
            var cleanText = log.replace(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}[.\d]*Z?\s*/, '')
                            .replace(/^time="[^"]*"\s*/, '')
                            .replace(/^level=\w+\s*/, '')
                            .replace(/^msg="?([^"]*)"?\s*/, '$1');
            
            if (cleanText.length > 60) {
                cleanText = cleanText.substring(0, 57) + '...';
            }
            
            return this.escapeHtml(cleanText) || '<%:Processing...%>';
        },
        
        escapeHtml: function(text) {
            var div = document.createElement('div');
            div.textContent = text;
            return div.innerHTML;
        }
    };

    var SystemStatusManager = {
        pollTimer: null,
        pollInterval: 5000,
        retryCount: 0,
        maxRetries: 3,
        isEnabled: false,
        
        start: function() {
            if (this.isEnabled) return;
            this.isEnabled = true;
            this.retryCount = 0;
            this.poll();
        },
        
        stop: function() {
            this.isEnabled = false;
            if (this.pollTimer) {
                clearTimeout(this.pollTimer);
                this.pollTimer = null;
            }
        },
        
        poll: function() {
            if (!this.isEnabled) return;
            
            var self = this;
            StateManager.cachedXHRGet('<%=luci.dispatcher.build_url("admin", "services", "openclash", "toolbar_show_sys")%>', function(x, status) {
                if (x && x.status == 200 && x.responseText != "") {
                    self.retryCount = 0;
                    var cpuColor = status.cpu <= 50 ? "var(--success-color)" : (status.cpu <= 80 ? "var(--warning-color)" : "var(--error-color)");
                    var cpuValue = status.cpu <= 100 ? status.cpu + " %" : "0 %";
                    document.getElementById("cpu_t").innerHTML = "<font style=\"color:"+cpuColor+"\">"+cpuValue+"</font>";
                    
                    var loadValue = parseFloat(status.load_avg) || 0;
                    var loadColor = loadValue <= 1.0 ? "var(--success-color)" : (loadValue <= 2.0 ? "var(--warning-color)" : "var(--error-color)");
                    document.getElementById("load_a").innerHTML = "<font style=\"color:"+loadColor+"\">"+status.load_avg+"</font>";
                } else {
                    self.handleError();
                }
                
                if (self.isEnabled) {
                    self.pollTimer = setTimeout(function() {
                        self.poll();
                    }, self.pollInterval);
                }
            }, true);
        },
        
        handleError: function() {
            this.retryCount++;
            
            if (this.retryCount >= this.maxRetries) {
                document.getElementById("cpu_t").innerHTML = "<font style=\"color:var(--success-color)\">0 %</font>";
                document.getElementById("load_a").innerHTML = "<font style=\"color:var(--success-color)\">0</font>";
                this.retryCount = 0;
            }
        },
        
        setPollInterval: function(interval) {
            this.pollInterval = interval;
        }
    };

    var NetworkStatsManager = {
        pollTimer: null,
        pollInterval: 3000,
        retryCount: 0,
        maxRetries: 3,
        isEnabled: false,
        
        start: function() {
            if (this.isEnabled) return;
            this.isEnabled = true;
            this.retryCount = 0;
            this.poll();
        },
        
        stop: function() {
            this.isEnabled = false;
            if (this.pollTimer) {
                clearTimeout(this.pollTimer);
                this.pollTimer = null;
            }
        },
        
        poll: function() {
            if (!this.isEnabled) return;
            
            var self = this;
            StateManager.cachedXHRGet('<%=luci.dispatcher.build_url("admin", "services", "openclash", "toolbar_show")%>', function(x, status) {
                if (x && x.status == 200 && x.responseText != "") {
                    self.retryCount = 0;
                    self.updateNetworkStats(status);
                } else {
                    self.handleError();
                }
                
                if (self.isEnabled) {
                    self.pollTimer = setTimeout(function() {
                        self.poll();
                    }, self.pollInterval);
                }
            }, true);
        },
        
        updateNetworkStats: function(status) {
            var updates = [
                {element: document.getElementById("upload_"), content: "<font style=\"color:var(--success-color)\">"+status.up+"</font>"},
                {element: document.getElementById("download_"), content: "<font style=\"color:var(--success-color)\">"+status.down+"</font>"},
                {element: document.getElementById("uploadtotal_"), content: "<font style=\"color:var(--success-color)\">"+status.up_total+"</font>"},
                {element: document.getElementById("downloadtotal_"), content: "<font style=\"color:var(--success-color)\">"+status.down_total+"</font>"},
                {element: document.getElementById("mem_t"), content: "<font style=\"color:var(--success-color)\">"+status.mem+"</font>"},
                {element: document.getElementById("connect_t"), content: "<font style=\"color:var(--success-color)\">"+status.connections+"</font>"}
            ];
            
            if (!SystemStatusManager.isEnabled) {
                var cpuColor = status.cpu <= 50 ? "var(--success-color)" : (status.cpu <= 80 ? "var(--warning-color)" : "var(--error-color)");
                var cpuValue = status.cpu <= 100 ? status.cpu + " %" : "0 %";
                updates.push({element: document.getElementById("cpu_t"), content: "<font style=\"color:"+cpuColor+"\">"+cpuValue+"</font>"});
                
                var loadValue = parseFloat(status.load_avg) || 0;
                var loadColor = loadValue <= 1.0 ? "var(--success-color)" : (loadValue <= 2.0 ? "var(--warning-color)" : "var(--error-color)");
                updates.push({element: document.getElementById("load_a"), content: "<font style=\"color:"+loadColor+"\">"+status.load_avg+"</font>"});
            }
            
            StateManager.batchUpdateDOM(updates);
        },
        
        handleError: function() {
            this.retryCount++;
            
            if (this.retryCount >= this.maxRetries) {
                var fallbackUpdates = [
                    {element: document.getElementById("upload_"), content: "<font style=\"color:var(--success-color)\">0 B/S</font>"},
                    {element: document.getElementById("download_"), content: "<font style=\"color:var(--success-color)\">0 B/S</font>"},
                    {element: document.getElementById("uploadtotal_"), content: "<font style=\"color:var(--success-color)\">0 KB</font>"},
                    {element: document.getElementById("downloadtotal_"), content: "<font style=\"color:var(--success-color)\">0 KB</font>"},
                    {element: document.getElementById("mem_t"), content: "<font style=\"color:var(--success-color)\">0 KB</font>"},
                    {element: document.getElementById("connect_t"), content: "<font style=\"color:var(--success-color)\">0</font>"}
                ];
                
                if (!SystemStatusManager.isEnabled) {
                    fallbackUpdates.push({element: document.getElementById("cpu_t"), content: "<font style=\"color:var(--success-color)\">0 %</font>"});
                    fallbackUpdates.push({element: document.getElementById("load_a"), content: "<font style=\"color:var(--success-color)\">0</font>"});
                }
                
                StateManager.batchUpdateDOM(fallbackUpdates);
                this.retryCount = 0;
            }
        },
        
        setPollInterval: function(interval) {
            this.pollInterval = interval;
        }
    };

    var SettingsManager = {
        pendingOperations: new Set(),
        pausedPolls: new Set(),
        
        pausePoll: function(pollName, duration) {
            this.pausedPolls.add(pollName);
            setTimeout(() => {
                this.pausedPolls.delete(pollName);
            }, duration || 3000);
        },
        
        isPollPaused: function(pollName) {
            return this.pausedPolls.has(pollName);
        },
        
        updateUIState: function(setting, value) {
            setTimeout(() => {
                function setCheckedAndDisabled(elements, checkedIndex) {
                    for (let i = 0; i < elements.length; i++) {
                        elements[i].checked = (i === checkedIndex);
                        elements[i].disabled = true;
                    }
                }
                switch(setting) {
                    case 'meta_sniffer':
                        var metaSnifferOn = document.getElementById('meta_sniffer_on');
                        var metaSnifferOff = document.getElementById('meta_sniffer_off');
                        if (metaSnifferOn && metaSnifferOff) {
                            setCheckedAndDisabled([metaSnifferOn, metaSnifferOff], value === '1' ? 0 : 1);
                            var changeEvent = new Event('change', { bubbles: true });
                            (value === '1' ? metaSnifferOn : metaSnifferOff).dispatchEvent(changeEvent);
                        }
                        break;
                    case 'respect_rules':
                        var respectRulesOn = document.getElementById('respect_rules_on');
                        var respectRulesOff = document.getElementById('respect_rules_off');
                        if (respectRulesOn && respectRulesOff) {
                            setCheckedAndDisabled([respectRulesOn, respectRulesOff], value === '1' ? 0 : 1);
                            var changeEvent = new Event('change', { bubbles: true });
                            (value === '1' ? respectRulesOn : respectRulesOff).dispatchEvent(changeEvent);
                        }
                        break;
                    case 'oversea':
                        var oversea0 = document.getElementById('oc_setting_oversea_0');
                        var oversea1 = document.getElementById('oc_setting_oversea_1');
                        var oversea2 = document.getElementById('oc_setting_oversea_2');
                        if (oversea0 && oversea1 && oversea2) {
                            setCheckedAndDisabled([oversea0, oversea1, oversea2], value === '0' ? 0 : (value === '1' ? 1 : 2));
                            var changeEvent = new Event('change', { bubbles: true });
                            [oversea0, oversea1, oversea2][value === '0' ? 0 : (value === '1' ? 1 : 2)].dispatchEvent(changeEvent);
                        }
                        break;
                    case 'stream_unlock':
                        var streamUnlockOn = document.getElementById('stream_unlock_on');
                        var streamUnlockOff = document.getElementById('stream_unlock_off');
                        if (streamUnlockOn && streamUnlockOff) {
                            setCheckedAndDisabled([streamUnlockOn, streamUnlockOff], value === '1' ? 0 : 1);
                            var changeEvent = new Event('change', { bubbles: true });
                            (value === '1' ? streamUnlockOn : streamUnlockOff).dispatchEvent(changeEvent);
                        }
                        break;
                    case 'rule_mode':
                        var radioElements = document.getElementsByName("radios");
                        if (radioElements && radioElements.length > 0) {
                            for (var i = 0; i < radioElements.length; i++) {
                                radioElements[i].checked = radioElements[i].value === value;
                                radioElements[i].disabled = true;
                                if (radioElements[i].checked) {
                                    var changeEvent = new Event('change', { bubbles: true });
                                    radioElements[i].dispatchEvent(changeEvent);
                                }
                            }
                        }
                        break;
                    case 'run_mode':
                        var radioRuElements = document.getElementsByName("radios-ru");
                        if (radioRuElements && radioRuElements.length > 0) {
                            for (var i = 0; i < radioRuElements.length; i++) {
                                radioRuElements[i].checked = radioRuElements[i].value === value;
                                radioRuElements[i].disabled = true;
                                if (radioRuElements[i].checked) {
                                    var changeEvent = new Event('change', { bubbles: true });
                                    radioRuElements[i].dispatchEvent(changeEvent);
                                }
                            }
                        }
                        break;
                }
            }, 10);
        },
        
        switchSetting: function(setting, value, endpoint, additionalParams) {
            var operationKey = setting + '_' + value;

            if (this.pendingOperations.has(operationKey)) {
                return false;
            }

            this.pendingOperations.add(operationKey);

            try {
                this.updateUIState(setting, value);
            } catch (e) {}

            let pollName;
            if (setting === 'rule_mode') {
                pollName = 'rule_mode';
            } else if (setting === 'run_mode') {
                pollName = 'run_mode';
            } else {
                pollName = 'oc_settings';
            }
            this.pausedPolls.add(pollName);

            var params = Object.assign({}, additionalParams || {});
            if (setting !== 'rule_mode' && setting !== 'run_mode') {
                params.setting = setting;
                params.value = value;
            } else if (setting === 'rule_mode') {
                params.rule_mode = value;
            } else if (setting === 'run_mode') {
                params.run_mode = value;
            }

            var self = this;

            XHR.get(endpoint, params, function(x, status) {
                setTimeout(function() {
                    self.pendingOperations.delete(operationKey);

                    switch(setting) {
                        case 'meta_sniffer':
                            var metaSnifferOn = document.getElementById('meta_sniffer_on');
                            var metaSnifferOff = document.getElementById('meta_sniffer_off');
                            if (metaSnifferOn) metaSnifferOn.disabled = false;
                            if (metaSnifferOff) metaSnifferOff.disabled = false;
                            break;
                        case 'respect_rules':
                            var respectRulesOn = document.getElementById('respect_rules_on');
                            var respectRulesOff = document.getElementById('respect_rules_off');
                            if (respectRulesOn) respectRulesOn.disabled = false;
                            if (respectRulesOff) respectRulesOff.disabled = false;
                            break;
                        case 'oversea':
                            var oversea0 = document.getElementById('oc_setting_oversea_0');
                            var oversea1 = document.getElementById('oc_setting_oversea_1');
                            var oversea2 = document.getElementById('oc_setting_oversea_2');
                            if (oversea0) oversea0.disabled = false;
                            if (oversea1) oversea1.disabled = false;
                            if (oversea2) oversea2.disabled = false;
                            break;
                        case 'stream_unlock':
                            var streamUnlockOn = document.getElementById('stream_unlock_on');
                            var streamUnlockOff = document.getElementById('stream_unlock_off');
                            if (streamUnlockOn) streamUnlockOn.disabled = false;
                            if (streamUnlockOff) streamUnlockOff.disabled = false;
                            break;
                        case 'rule_mode':
                            var radioElements = document.getElementsByName("radios");
                            if (radioElements && radioElements.length > 0) {
                                for (var i = 0; i < radioElements.length; i++) {
                                    radioElements[i].disabled = false;
                                }
                            }
                            break;
                        case 'run_mode':
                            var radioRuElements = document.getElementsByName("radios-ru");
                            if (radioRuElements && radioRuElements.length > 0) {
                                for (var i = 0; i < radioRuElements.length; i++) {
                                    radioRuElements[i].disabled = false;
                                }
                            }
                            break;
                    }

                    self.pausedPolls.delete(pollName);

                    if (!x || x.status !== 200) {
                        alert(self.getErrorMessage(setting));
                    }
                }, 1500);
            });

            return false;
        },
        
        getErrorMessage: function(setting) {
            var messages = {
                'meta_sniffer': '<%:Sniffer setting failed%>',
                'respect_rules': '<%:Respect Rules setting failed%>',
                'oversea': '<%:Area bypass setting failed%>',
                'stream_unlock': '<%:Stream Unlock setting failed%>',
                'rule_mode': '<%:Proxy Mode switching failed!%>',
                'run_mode': '<%:Running Mode switching failed!%>'
            };
            return messages[setting] || '<%:Operation failed%>';
        }
    };

    var script_radio, script_radio_label;
    var s, gr;
    var pluginToggleUserAction = false;

    document.addEventListener('DOMContentLoaded', function() {
        DarkModeDetector.init();
        ConfigFileManager.init();

        setTimeout(function() {
            SubscriptionManager.init();
        }, 300);

        setTimeout(function() {
            check_core();
        }, 1000);

        setTimeout(function() {
            loadAnnouncement();
        }, 2000);
    });

    XHR.poll(5, '<%=luci.dispatcher.build_url("admin", "services", "openclash", "status")%>', null, function(x, status) {
        if (x && x.status == 200) {
            var updates = [];
        
            if (!pluginToggleUserAction) {
                updates.push({
                    element: DOMCache.clash,
                    content: status.clash ? '<b style=color:var(--success-color)>' + status.core_type +'&nbsp;<%:Running%></b>' : '<b style=color:var(--error-color)><%:Not Running%></b>'
                });
                
                updatePluginToggleState(status.clash);
            }

			get_run_mode();
            get_rule_mode();
            get_oc_settings();
            
            var webContent = status.clash ? '<input type="button" class="dashboard-btn" value="<%:Yacd%>" onclick="return ycad_dashboard(this)"/>' : '<input type="button" class="dashboard-btn" value="<%:Yacd%>" onclick="event.preventDefault(); event.stopPropagation(); return false;"/>';
            updates.push({element: DOMCache.web, content: webContent});

            var weboContent = status.clash ? '<input type="button" class="dashboard-btn" value="<%:Dashboard%>" onclick="return net_dashboard(this)"/>' : '<input type="button" class="dashboard-btn" value="<%:Dashboard%>" onclick="event.preventDefault(); event.stopPropagation(); return false;"/>';
            updates.push({element: DOMCache.webo, content: weboContent});

            var webmContent = status.clash ? '<input type="button" class="dashboard-btn" value="<%:Metacubexd%>" onclick="return meta_dashboard(this)"/>' : '<input type="button" class="dashboard-btn" value="<%:Metacubexd%>" onclick="event.preventDefault(); event.stopPropagation(); return false;"/>';
            updates.push({element: DOMCache.webm, content: webmContent});

            var webzContent = status.clash ? '<input type="button" class="dashboard-btn" value="<%:Zashboard%>" onclick="return net_zashboard(this)"/>' : '<input type="button" class="dashboard-btn" value="<%:Zashboard%>" onclick="event.preventDefault(); event.stopPropagation(); return false;"/>';
            updates.push({element: DOMCache.webz, content: webzContent});


            var closeConnContent = status.clash ? '<input type="button" class="dashboard-btn" value="<%:Close Connect%>" onclick="return b_close_all_connection(this)"/>' : '<input type="button" class="dashboard-btn" value="<%:Close Connect%>" onclick="event.preventDefault(); event.stopPropagation(); return false;"/>';
            updates.push({element: document.getElementById('_close_all_connection_btn'), content: closeConnContent});

            var reloadFwContent = status.clash ? '<input type="button" class="dashboard-btn" value="<%:Reload Firewall%>" onclick="return b_reload_firewall(this)"/>' : '<input type="button" class="dashboard-btn" value="<%:Reload Firewall%>" onclick="event.preventDefault(); event.stopPropagation(); return false;"/>';
            updates.push({element: document.getElementById('_reload_firewall_btn'), content: reloadFwContent});

            var flushCacheContent = status.clash ? '<input type="button" class="dashboard-btn" value="<%:Flush DNS Cache%>" onclick="return b_flush_dns_cache(this)"/>' : '<input type="button" class="dashboard-btn" value="<%:Flush DNS Cache%>" onclick="event.preventDefault(); event.stopPropagation(); return false;"/>';
            updates.push({element: document.getElementById('_flush_dns_cache_btn'), content: flushCacheContent});

            var oneKeyUpdateContent = '<input type="button" class="dashboard-btn" value="<%:Check Update%>" onclick="return all_one_key_update(this)"/>';
            updates.push({element: document.getElementById('_one_key_update_btn'), content: oneKeyUpdateContent});

            StateManager.batchUpdateDOM(updates);

            StateManager.current_status = status;
            
            if (status.daip) {
                var daipContent, dapoContent;
                
                if (status.daip && window.location.hostname == status.daip) {
                    dapoContent = status.cn_port ? ":"+status.cn_port : "";
                    daipContent = status.daip ? "<b style=color:var(--success-color)>"+status.daip+dapoContent+"</b>" : "<b style=color:var(--error-color)>"+"<%:Not Set%>"+"</b>";
                } else if (status.daip && window.location.hostname != status.daip && status.db_foward_domain && status.db_foward_port) {
                    dapoContent = status.db_foward_port ? ":"+status.db_foward_port : "";
                    daipContent = status.db_foward_domain ? "<b style=color:var(--success-color)>"+status.db_foward_domain+dapoContent+"</b>" : "<b style=color:var(--error-color)>"+"<%:Not Set%>"+"</b>";
                } else {
                    dapoContent = status.cn_port ? ":"+status.cn_port : "";
                    daipContent = status.daip ? "<b style=color:var(--success-color)>"+status.daip+dapoContent+"</b>" : "<b style=color:var(--error-color)>"+"<%:Not Set%>"+"</b>";
                }
                
                DOMCache.daip.innerHTML = daipContent;   

                StateManager.cachedXHRGet('<%=luci.dispatcher.build_url("admin", "services", "openclash", "proxy_info")%>', function(x, proxy_info) {
                    if (x && x.status == 200) {
                        StateManager.cached_proxy_info = proxy_info;
                        var proxy_ip = status.daip;
                        var mix_addr = proxy_ip + ':' + (proxy_info.mixed_port || '7893');
                        DOMCache.mix_proxy.innerHTML = "<b style=color:var(--success-color)>" + mix_addr + "</b>";
                    } else {
                        StateManager.cached_proxy_info = null;
                        DOMCache.mix_proxy.innerHTML = "<b style=color:var(--error-color)><%:Not Available%></b>";
                    }
                });
                
                DOMCache.copy_secret.style.display = "inline";
                DOMCache.copy_address.style.display = "inline";
                DOMCache.copy_mix_address.style.display = "inline";
                DOMCache.copy_mix_secret.style.display = "inline";
                DOMCache.copy_pac_config.style.display = "inline";
            } else {
                DOMCache.daip.innerHTML = "<b style=color:var(--error-color)><%:Not Available%></b>";
                StateManager.cached_proxy_info = null;
                DOMCache.mix_proxy.innerHTML = "<b style=color:var(--error-color)><%:Not Available%></b>";
                DOMCache.copy_secret.style.display = "none";
                DOMCache.copy_address.style.display = "none";
                DOMCache.copy_mix_address.style.display = "none";
                DOMCache.copy_mix_secret.style.display = "none";
                DOMCache.copy_pac_config.style.display = "none";
            }
            
            if (status.clash && status.daip) {
                if (!WSManager.hasActiveConnections()) {
                    if (!WSManager._ws_error || WSManager._ws_retry < 3) {
                        if (initializeWebSocketConnections(status)) {
                            WSManager._ws_retry++;
                        }
                    } else {
                        WSManager.enableFallbackMode();
                    }
                } else {
                    if (NetworkStatsManager && NetworkStatsManager.isEnabled) {
                        NetworkStatsManager.stop();
                    }
                    
                    if (SystemStatusManager && !SystemStatusManager.isEnabled) {
                        SystemStatusManager.start();
                    }
                }
            } else {
                WSManager.closeAll();
                SystemStatusManager.stop();
                NetworkStatsManager.stop();
            }
        }
        clashversion_check();
    });

    window.addEventListener('beforeunload', function() {
        WSManager.closeAll();
        SystemStatusManager.stop();
        NetworkStatsManager.stop();
    });

    function initializeWebSocketConnections(status) {
        if (!status || !status.clash || !status.daip) {
            return false;
        }
        
        var protocol = getWebSocketProtocol(status);
        var token = status.dase;
        
        var connections = [
            {
                type: 'traffic',
                endpoint: '/traffic',
                handler: ws_tmessage
            },
            {
                type: 'connections', 
                endpoint: '/connections',
                handler: ws_cmessage
            },
            {
                type: 'memory',
                endpoint: '/memory', 
                handler: ws_mmessage
            }
        ];
        
        connections.forEach(function(conn) {
            var url = protocol + conn.endpoint + (token ? '?token=' + token : '');
            WSManager.createConnection(conn.type, url, conn.handler);
        });
        
        return true;
    }

    function getWebSocketProtocol(status) {
        var protocol = window.location.protocol === "https:" ? "wss://" : "ws://";
        var host, port;
        
        if (status.daip && window.location.hostname === status.daip) {
            host = status.daip;
            port = status.cn_port;
        } else if (status.daip && window.location.hostname !== status.daip && 
                   status.db_foward_domain && status.db_foward_port) {
            host = status.db_foward_domain;
            port = status.db_foward_port;
        } else {
            host = status.daip;
            port = status.cn_port;
        }
        
        return protocol + host + ":" + port;
    }

    function loadAnnouncement() {
        var userLang = navigator.language || navigator.userLanguage; 
        var isChineseUser = userLang.indexOf('zh') === 0;
        
        var tips = [
            '<%:Tip: You can modify the profile on the profile page (for content that is not taken over)%>',
            '<%:Tip: click the version icon above to jump to the client publishing page%>',
            '<%:Tip: do not write configuration files? Try to create one click on the server page%>',
            '<%:Tip: some website are abnormal? Try switching modes or using third-party rules%>',
            '<%:Tip: using the fake IP mode can get a faster access experience%>',
            '<%:Tip: query DNS by TLS & TCP & HTTPS can get better anti pollution effect%>',
            '<%:Tip: the nameserver group must have at least one server set when using custom DNS%>',
            '<%:Tip: after started, please wait patiently until the connection is normal%>',
            '<%:Tip: if you don not use IPv6, please turn off the DHCP service of IPv6, otherwise the connection will be abnormal%>',
            '<%:Tip: you can update the version in the settings page%>',
            '<%:Note: It is not recommended to enable IPv6 and related services for routing. Most of the network connection problems reported so far are related to it%>',
            '<%:Note: Turning on secure DNS in the browser will cause abnormal shunting, please be careful to turn it off%>',
            '<%:Note: Some software will modify the device HOSTS, which will cause abnormal shunt, please pay attention to check%>',
            '<%:Note: The default proxy routes local traffic, BT, PT download, etc., please use Redir-Host mode as much as possible and pay attention to traffic avoidance%>'
        ];
        
        function calculateAnimationDuration(bannerWidth, contentWidth) {
            var screenWidth = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
            var refreshRate = window.screen && window.screen.refreshRate ? window.screen.refreshRate : 60;
            if (refreshRate <= 0) refreshRate = 60;
            
            if (refreshRate > 480) refreshRate = 480;
            
            var baseDuration;
            if (screenWidth <= 575) {
                baseDuration = 12000;
            } else if (screenWidth <= 768) {
                baseDuration = 11000;
            } else if (screenWidth <= 1200) {
                baseDuration = 10000;
            } else {
                baseDuration = 9000;
            }
            
            var refreshRateMultiplier = 1;
            if (refreshRate > 60) {
                refreshRateMultiplier = 1 + (refreshRate - 60) / 240;
            }
            
            var duration = baseDuration * refreshRateMultiplier;
            
            return Math.max(4000, Math.min(duration, 18000));
        }
        
        function updateScrollAnimation(banner, content, duration) {
            var bannerWidth = banner.offsetWidth;
            var contentWidth = content.offsetWidth;
            var scrollDistance = -(contentWidth + bannerWidth);
            
            banner.style.setProperty('--scroll-distance', scrollDistance + 'px');
            
            content.style.animationDuration = duration + 'ms';
        }
        
        function getRandomTips(count) {
            var shuffled = tips.slice();
            for (var i = shuffled.length - 1; i > 0; i--) {
                var j = Math.floor(Math.random() * (i + 1));
                var temp = shuffled[i];
                shuffled[i] = shuffled[j];
                shuffled[j] = temp;
            }
            return shuffled.slice(0, count);
        }
        
        function updateIcon(isRandomTips) {
            var megaphoneElement = document.getElementById('megaphone');
            if (!megaphoneElement) return;
            
            if (isRandomTips) {
                megaphoneElement.innerHTML = '<path d="M176,232a8,8,0,0,1-8,8H88a8,8,0,0,1,0-16h80A8,8,0,0,1,176,232Zm40-128a87.55,87.55,0,0,1-33.64,69.21A16.24,16.24,0,0,0,176,186v6a16,16,0,0,1-16,16H96a16,16,0,0,1-16-16v-6a16,16,0,0,0-6.23-12.66A87.59,87.59,0,0,1,40,104.49C39.74,56.83,78.26,17.14,125.88,16A88,88,0,0,1,216,104Zm-16,0a72,72,0,0,0-73.74-72c-39,.92-70.47,33.39-70.26,72.39a71.65,71.65,0,0,0,27.64,56.3A32,32,0,0,1,96,186v6h64v-6a32.15,32.15,0,0,1,12.47-25.35A71.65,71.65,0,0,0,200,104Zm-16.11-9.34a57.6,57.6,0,0,0-46.56-46.55,8,8,0,0,0-2.66,15.78c16.57,2.79,30.63,16.85,33.44,33.45A8,8,0,0,0,176,104a9,9,0,0,0,1.35-.11A8,8,0,0,0,183.89,94.66Z" stroke-width="2"></path>';
                megaphoneElement.setAttribute('viewBox', '0 0 256 256');
                megaphoneElement.setAttribute('stroke-width', '3');
            } else {
                megaphoneElement.innerHTML = '<path d="M228.54,86.66l-176.06-54A16,16,0,0,0,32,48V192a16,16,0,0,0,16,16,16,16,0,0,0,4.52-.65L136,181.73V192a16,16,0,0,0,16,16h32a16,16,0,0,0,16-16v-29.9l28.54-8.75A16.09,16.09,0,0,0,240,138V102A16.09,16.09,0,0,0,228.54,86.66ZM136,165,48,192V48l88,27Zm48,27H152V176.82L184,167Zm40-54-.11,0L152,160.08V79.92l71.89,22,.11,0v36Z"></path>';
                megaphoneElement.setAttribute('viewBox', '0 0 256 256');
            }
        }
        
        StateManager.cachedXHRGet('<%=luci.dispatcher.build_url("admin", "services", "openclash", "announcement")%>', function(x, status) {
            var banner = document.getElementById('announcement-banner');
            var content = document.getElementById('announcement-content');
            var announcements = [];
            var isRandomTips = false;
            
            if (!banner || !content) return;
            
            if (x && x.status == 200 && status.content) {
                try {
                    var contentData = status.content;
                    if (typeof contentData === 'string') {
                        contentData = JSON.parse(contentData);
                    }
                    
                    if (Array.isArray(contentData)) {
                        if (contentData.length > 0 && (contentData[0].zh || contentData[0].en)) {
                            contentData.forEach(function(item) {
                                if (isChineseUser && item.zh) {
                                    announcements.push(item.zh);
                                } else if (item.en) {
                                    announcements.push(item.en);
                                } else if (item.zh) {
                                    announcements.push(item.zh);
                                }
                            });
                        } else {
                            announcements = contentData.filter(function(item) {
                                return typeof item === 'string' && item.trim() !== '';
                            });
                        }
                    } else if (typeof contentData === 'string' && contentData.trim() !== '') {
                        announcements = [contentData];
                    }
                } catch (e) {
                    if (typeof status.content === 'string' && status.content.trim() !== '') {
                        announcements = [status.content];
                    }
                }
            }
            
            if (announcements.length === 0) {
                announcements = getRandomTips(3);
                isRandomTips = true;
            }
            
            updateIcon(isRandomTips);
            banner.style.display = 'block';
            
            var currentIndex = 0;
            var isHovered = false;
            var pauseTimeout = null;
            var nextAnimationTimeout = null;
            
            banner.addEventListener('mouseenter', function() { 
                isHovered = true;
                content.classList.add('paused');
            });
            banner.addEventListener('mouseleave', function() { 
                isHovered = false;
                content.classList.remove('paused');
            });
            
            var resizeTimeout;
            window.addEventListener('resize', function() {
                clearTimeout(resizeTimeout);
                resizeTimeout = setTimeout(function() {
                    if (content.classList.contains('scrolling')) {
                        var duration = calculateAnimationDuration(banner.offsetWidth, content.offsetWidth);
                        updateScrollAnimation(banner, content, duration);
                    }
                }, 250);
            });
            
            function startScrollAnimation() {
                if (nextAnimationTimeout) {
                    clearTimeout(nextAnimationTimeout);
                    nextAnimationTimeout = null;
                }
                
                content.textContent = announcements[currentIndex];
                
                setTimeout(function() {
                    var duration = calculateAnimationDuration(banner.offsetWidth, content.offsetWidth);
                    updateScrollAnimation(banner, content, duration);
                    
                    content.classList.remove('scrolling');
                    content.offsetHeight;
                    content.classList.add('scrolling');
                    
                    var onAnimationEnd = function(e) {
                        if (e.target === content && e.animationName === 'announceScroll') {
                            content.removeEventListener('animationend', onAnimationEnd);
                            
                            pauseTimeout = setTimeout(function() {
                                if (!isHovered) {
                                    currentIndex = (currentIndex + 1) % announcements.length;
                                    
                                    if (isRandomTips && currentIndex === 0) {
                                        announcements = getRandomTips(3);
                                    }
                                    
                                    startScrollAnimation();
                                }
                            }, 2000);
                        }
                    };
                    
                    content.addEventListener('animationend', onAnimationEnd);
                    
                }, 50);
            }
            
            setTimeout(function() {
                startScrollAnimation();
            }, 300);
            
            window.addEventListener('beforeunload', function() {
                if (pauseTimeout) clearTimeout(pauseTimeout);
                if (nextAnimationTimeout) clearTimeout(nextAnimationTimeout);
            });
        });
    }

    function get_rule_mode() {
        if (SettingsManager.isPollPaused('rule_mode')) {
            return;
        }
        
        StateManager.cachedXHRGet('<%=luci.dispatcher.build_url("admin", "services", "openclash", "rule_mode")%>', function(x, status) {
            if (x && x.status == 200 && status.mode != "") {
                if (!SettingsManager.pendingOperations.has('rule_mode_' + status.mode)) {
                    for (var i = 0; i < DOMCache.radio.length; i++) {
                        if (DOMCache.radio[i].value == status.mode && !DOMCache.radio[i].checked) {
                            DOMCache.radio[i].checked = true;
                            break;
                        }
                    }
                }
            }
        }, true);
    }

    function switch_rule_mode(value) {
        return SettingsManager.switchSetting(
            'rule_mode', 
            value, 
            '<%=luci.dispatcher.build_url("admin", "services", "openclash", "switch_rule_mode")%>'
        );
    }
    
    function get_run_mode() {
        if (SettingsManager.isPollPaused('run_mode')) {
            return;
        }
        
        StateManager.cachedXHRGet('<%=luci.dispatcher.build_url("admin", "services", "openclash", "get_run_mode")%>', function(x, status) {
            if (x && x.status == 200 && status.mode) {
                if (status.mode == "fake-ip" || status.mode == "fake-ip-tun" || status.mode == "fake-ip-mix") {
                    DOMCache.mode.innerHTML = "<b style=color:var(--success-color)><%:Fake-IP%></b>";
                    DOMCache.radio_run_normal.innerHTML = "<%:Enhance%>";
                } else if (status.mode == "redir-host" || status.mode == "redir-host-tun" ||  status.mode == "redir-host-mix") {
                    DOMCache.mode.innerHTML = "<b style=color:var(--success-color)><%:Redir-Host%></b>";
                    DOMCache.radio_run_normal.innerHTML = "<%:Compat%>";
                }
                
                var expectedValue = status["mode"].split("-")[2] == undefined ? "" : ("-" + status["mode"].split("-")[2]);
                var operationKey = 'run_mode_' + status.mode;
                
                if (!SettingsManager.pendingOperations.has(operationKey)) {
                    for (var i = 0; i < DOMCache.radio_ru.length; i++) {
                        if (DOMCache.radio_ru[i].value == expectedValue && !DOMCache.radio_ru[i].checked) {
                            DOMCache.radio_ru[i].checked = true;
                        }
                    }
                }
            }
        }, true);
    }

    function switch_run_mode(value) {
        LogManager.startLogDisplay('<%:Saving...%>');
        return SettingsManager.switchSetting(
            'run_mode', 
            value, 
            '<%=luci.dispatcher.build_url("admin", "services", "openclash", "switch_run_mode")%>'
        );
    }

    function winOpen(url) {
        var winOpen = window.open(url);
        if (winOpen == null || typeof(winOpen) == 'undefined') {
            window.location.href = url;
        }
    }
     
    function ws_terror() {
        WSManager._ws_error = true;
        
        NetworkStatsManager.start();
    }

    function ws_tmessage(event) {
        var dataObj = event && event.data !== undefined ? event.data : event;
        var data;
        if (typeof dataObj === 'string') {
            try {
                data = JSON.parse(dataObj);
            } catch (e) {
                data = {};
            }
        } else {
            data = dataObj;
        }
        var uploadElement = document.getElementById("upload_");
        var downloadElement = document.getElementById("download_");
        uploadElement.innerHTML = data.up ? "<font style=\"color:var(--success-color)\">"+bytesToSize(data.up)+"/S</font>" : "<font style=\"color:var(--success-color)\">0 B/S</font>";
        downloadElement.innerHTML = data.down ? "<font style=\"color:var(--success-color)\">"+bytesToSize(data.down)+"/S</font>" : "<font style=\"color:var(--success-color)\">0 B/S</font>";
    }
    
    function ws_cmessage(event) {
        var dataObj = event && event.data !== undefined ? event.data : event;
        var data;
        if (typeof dataObj === 'string') {
            try {
                data = JSON.parse(dataObj);
            } catch (e) {
                data = {};
            }
        } else {
            data = dataObj;
        }
        var updates = [
            {
                element: document.getElementById("uploadtotal_"),
                content: data.uploadTotal ? "<font style=\"color:var(--success-color)\">"+bytesToSize(data.uploadTotal)+"</font>" : "<font style=\"color:var(--success-color)\">0 KB</font>"
            },
            {
                element: document.getElementById("downloadtotal_"),
                content: data.downloadTotal ? "<font style=\"color:var(--success-color)\">"+bytesToSize(data.downloadTotal)+"</font>" : "<font style=\"color:var(--success-color)\">0 KB</font>"
            },
            {
                element: document.getElementById("connect_t"),
                content: data.connections ? "<font style=\"color:var(--success-color)\">"+Object.keys(data.connections).length+"</font>" : "<font style=\"color:var(--success-color)\">0</font>"
            }
        ];
        StateManager.batchUpdateDOM(updates);
    }

    function ws_mmessage(event) {
        var dataObj = event && event.data !== undefined ? event.data : event;
        var data;
        if (typeof dataObj === 'string') {
            try {
                data = JSON.parse(dataObj);
            } catch (e) {
                data = {};
            }
        } else {
            data = dataObj;
        }
        var memElement = document.getElementById("mem_t");
        memElement.innerHTML = data.inuse ? "<font style=\"color:var(--success-color)\">"+bytesToSize(data.inuse)+"</font>" : "<font style=\"color:var(--success-color)\">0 KB</font>";
        if (!SystemStatusManager.isEnabled) {
            SystemStatusManager.start();
        }
    }

    function bytesToSize(bytes) {
        var sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB'];
        if (bytes == 0) return '0 B';
        var i = Math.floor(Math.log(bytes) / Math.log(1024));
        return i == 0 ? (bytes / Math.pow(1024, i)) + ' ' + sizes[i] : (bytes / Math.pow(1024, i)).toFixed(1) + ' ' + sizes[i];
    }

    var buttonDebounce = {};
    function debounceButton(fn, delay) {
        return function(btn) {
            var key = btn.id || btn.value;
            if (buttonDebounce[key]) {
                clearTimeout(buttonDebounce[key]);
            }
            buttonDebounce[key] = setTimeout(function() {
                fn(btn);
                delete buttonDebounce[key];
            }, delay || 300);
            return false; 
        };
    }
      
    var all_one_key_update = debounceButton(function(btn) {
        btn.value = '<%:Check Update%>';
        btn.disabled = false;
        select_git_cdn();
        return false;
    });
    
    var b_flush_dns_cache = debounceButton(function(btn) {
        btn.disabled = true;
        btn.value = '<%:Flushing...%> ';
        XHR.get('<%=luci.dispatcher.build_url("admin", "services", "openclash","flush_dns_cache")%>', null, function(x, status) {
            if (x && x.status == 200) {
                btn.value = (status.flush_status == "0" || status.flush_status != "") ? '<%:Flush Failed%>' : '<%:Flush Successful%>';
            } else {
                btn.value = '<%:Flush Timeout%>';
            }
        });
        btn.disabled = false;
        return false;
    });
    
    var b_reload_firewall = debounceButton(function(btn) {
        btn.disabled = true;
        btn.value = '<%:Reloading...%>';
        LogManager.startLogDisplay('<%:Reloading...%>');
        XHR.get('<%=luci.dispatcher.build_url("admin", "services", "openclash", "reload_firewall")%>', null, function(x, status) {
            btn.disabled = false;
            btn.value = (x && x.status == 200) ? '<%:Reload Firewall%>' : '<%:Firewall Rules Reset Failed%>';
        });
        return false;
    });

    var b_close_all_connection = debounceButton(function(btn) {
        btn.disabled = true;
        btn.value = '<%:Reloading...%>';
        XHR.get('<%=luci.dispatcher.build_url("admin", "services", "openclash", "close_all_connection")%>', null, function(x, status) {
            btn.disabled = false;
            btn.value = (x && x.status == 200) ? '<%:Close Connect%>' : '<%:Close Connect Failed%>';
        });
        return false;
    });
        
    function net_zashboard(btn) {
        if (StateManager.current_status) {
            var status = StateManager.current_status;
        } else {
            setTimeout(function() {
                net_zashboard(btn)
            }, 1000);
            return false;
        }

        btn.disabled = true;
        btn.value = '<%:Zashboard%>';
        var url9;
        if (status.daip && window.location.hostname == status.daip) {
            url9 = 'http://' + window.location.hostname + ':' + status.cn_port + '/ui/zashboard/#/setup?hostname=' + window.location.hostname + '&port=' + status.cn_port + '&secret=' + status.dase;
        } else if (status.daip && window.location.hostname != status.daip && status.db_foward_domain && status.db_foward_port) {
            var ui_proto = status.db_forward_ssl == 0 ? 'http://' : 'https://';
            url9 = ui_proto + status.db_foward_domain + ':' + status.db_foward_port + '/ui/zashboard/#/setup?hostname=' + status.db_foward_domain + '&port=' + status.db_foward_port + '&secret=' + status.dase;
        } else {
            url9 = 'http://' + window.location.hostname + ':' + status.cn_port + '/ui/zashboard/#/';
        }
        winOpen(url9);
        return false;
    }

    function meta_dashboard(btn) {
        if (StateManager.current_status) {
            var status = StateManager.current_status;
        } else {
            setTimeout(function() {
                meta_dashboard(btn)
            }, 1000);
            return false;
        }

        btn.disabled = true;
        btn.value = '<%:Metacubexd%>';
        var url9;
        if (status.daip && window.location.hostname == status.daip) {
            url9 = 'http://' + window.location.hostname + ':' + status.cn_port + '/ui/metacubexd/#/setup?hostname=' + window.location.hostname + '&port=' + status.cn_port + '&secret=' + status.dase;
        } else if (status.daip && window.location.hostname != status.daip && status.db_foward_domain && status.db_foward_port) {
            var ui_proto = status.db_forward_ssl == 0 ? 'http://' : 'https://';
            url9 = ui_proto + status.db_foward_domain + ':' + status.db_foward_port + '/ui/metacubexd/#/setup?hostname=' + status.db_foward_domain + '&port=' + status.db_foward_port + '&secret=' + status.dase;
        } else {
            url9 = 'http://' + window.location.hostname + ':' + status.cn_port + '/ui/metacubexd/#/';
        }
        winOpen(url9);
        return false;
    }

    function ycad_dashboard(btn) {
        if (StateManager.current_status) {
            var status = StateManager.current_status;
        } else {
            setTimeout(function() {
                ycad_dashboard(btn)
            }, 1000);
            return false;
        }

        btn.disabled = true;
        btn.value = '<%:Yacd%>';
        var url1;
        if (status.daip && window.location.hostname == status.daip) {
            url1 = 'http://' + window.location.hostname + ':' + status.cn_port + '/ui/yacd/?hostname=' + window.location.hostname + '&port=' + status.cn_port + '&secret=' + status.dase;
        } else if (status.daip && window.location.hostname != status.daip && status.db_foward_domain && status.db_foward_port) {
            var ui_proto = status.db_forward_ssl == 0 ? 'http://' : 'https://';
            url1 = ui_proto + status.db_foward_domain + ':' + status.db_foward_port + '/ui/yacd/?hostname=' + status.db_foward_domain + '&port=' + status.db_foward_port + '&secret=' + status.dase;
        } else {
            url1 = 'http://' + window.location.hostname + ':' + status.cn_port + '/ui/yacd/';
        }
        winOpen(url1);
        return false;
    }
    
    function net_dashboard(btn) {
        if (StateManager.current_status) {
            var status = StateManager.current_status;
        } else {
            setTimeout(function() {
                net_dashboard(btn)
            }, 1000);
            return false;
        }

        btn.disabled = true;
        btn.value = '<%:Dashboard%>';
        var url2;
        if (status.daip && window.location.hostname == status.daip) {
            url2 = 'http://' + window.location.hostname + ':' + status.cn_port + '/ui/dashboard/#/?host=' + window.location.hostname + '&port=' + status.cn_port + '&secret=' + status.dase;
        } else if (status.daip && window.location.hostname != status.daip && status.db_foward_domain && status.db_foward_port) {
            var ui_proto = status.db_forward_ssl == 0 ? 'http://' : 'https://';
            url2 = ui_proto + status.db_foward_domain + ':' + status.db_foward_port + '/ui/dashboard/#/?host=' + status.db_foward_domain + '&port=' + status.db_foward_port + '&secret=' + status.dase;
        } else {
            url2 = 'http://' + window.location.hostname + ':' + status.cn_port + '/ui/dashboard/';
        }
        winOpen(url2);
        return false;
    }
    
    function homepage() {
        url3 = 'https://github.com/vernesong/OpenClash';
        winOpen(url3);
    }
    
    function gitbookpage() {
        url8 = 'https://wiki.metacubex.one';
        winOpen(url8);
    }

    function wikipage() {
        url5 = 'https://github.com/vernesong/OpenClash/wiki';
        winOpen(url5);
    }
    
    function telegrampage() {
        url6 = 'https://t.me/ctcgfw_openwrt_discuss';
        winOpen(url6);
    }
    
    function sponsorpage() {
        url7 = 'https://ko-fi.com/vernesong';
        winOpen(url7);
    }

    function go_mihomo() {
        var url4 = 'https://www.github.com/metacubex/mihomo';
        winOpen(url4);
    }

    function clashversion_check() {
        function compareVersions(v1, v2) {
            if (!v1 || !v2) return 0;
            var ver1 = v1.replace(/^v/, '').split('.');
            var ver2 = v2.replace(/^v/, '').split('.');
            
            var maxLen = Math.max(ver1.length, ver2.length);
            while (ver1.length < maxLen) ver1.push('0');
            while (ver2.length < maxLen) ver2.push('0');
            
            for (var i = 0; i < maxLen; i++) {
                var num1 = parseInt(ver1[i], 10) || 0;
                var num2 = parseInt(ver2[i], 10) || 0;
                if (num1 > num2) return 1;
                if (num1 < num2) return -1;
            }
            return 0;
        }

        StateManager.cachedXHRGet('<%=luci.dispatcher.build_url("admin", "services", "openclash", "update")%>', function(x, status) {
            if (x && x.status == 200) {
                if (status.coremetacv && status.coremetacv !== "0") {
                    var coreVersionText = status.coremetacv;
                    var hasUpdate = false;

                    if (status.corelv && status.corelv !== "" && status.corelv !== "loading..." && status.corelv !== status.coremetacv) {
                        hasUpdate = true;
                    }
                    
                    DOMCache.core_version_text.textContent = coreVersionText;
                    if (DOMCache.core_version_text.scrollWidth > DOMCache.core_version_text.clientWidth) {
                        DOMCache.core_version_text.title = coreVersionText;
                    } else {
                        DOMCache.core_version_text.title = '';
                    }
                    DOMCache.core_version_display.style.display = 'flex';
                    
                    var existingDot = DOMCache.core_version_display.querySelector('.update-dot');
                    if (existingDot) {
                        existingDot.remove();
                    }
                    
                    if (hasUpdate) {
                        var updateDot = document.createElement('span');
                        updateDot.className = 'update-dot';
                        DOMCache.core_version_display.appendChild(updateDot);
                        DOMCache.core_version_display.title = '<%:New version available%>: ' + status.corelv;
                        DOMCache.core_version_text.removeAttribute('title');
                    } else {
                        DOMCache.core_version_display.title = '';
                    }
                } else {
                    DOMCache.core_version_display.style.display = 'none';
                    DOMCache.core_version_display.title = '';
                }
                
                if (status.opcv && status.opcv !== "0") {
                    var pluginVersionText = status.opcv;
                    var hasUpdate = false;
                    
                    if (status.oplv && status.oplv !== "" && status.oplv !== "loading...") {
                        if (compareVersions(status.oplv, status.opcv) > 0) {
                            hasUpdate = true;
                        }
                    }
                    
                    DOMCache.plugin_version_text.textContent = pluginVersionText;
                    if (DOMCache.plugin_version_text.scrollWidth > DOMCache.plugin_version_text.clientWidth) {
                        DOMCache.plugin_version_text.title = pluginVersionText;
                    } else {
                        DOMCache.plugin_version_text.title = '';
                    }
                    DOMCache.plugin_version_display.style.display = 'flex';
                    
                    var existingDot = DOMCache.plugin_version_display.querySelector('.update-dot');
                    if (existingDot) {
                        existingDot.remove();
                    }
                    
                    if (hasUpdate) {
                        var updateDot = document.createElement('span');
                        updateDot.className = 'update-dot';
                        DOMCache.plugin_version_display.appendChild(updateDot);
                        DOMCache.plugin_version_display.title = '<%:New version available%>: ' + status.oplv;
                        DOMCache.plugin_version_text.removeAttribute('title');
                    } else {
                        DOMCache.plugin_version_display.title = '';
                    }
                } else {
                    DOMCache.plugin_version_display.style.display = 'none';
                    DOMCache.plugin_version_display.title = '';
                }
            }
        });
    }

    function logo_error(imgobj, imgSrc) {
        imgobj.src = imgSrc;
    }
    
    function imgerrorfuns(imgobj, imgSrc) {
        setTimeout(function() {
            imgobj.src = imgSrc;
            imgobj.loading = "lazy";
        }, 10000);
    }

    function check_core() {
        StateManager.cachedXHRGet('<%=luci.dispatcher.build_url("admin", "services", "openclash", "check_core")%>', function(x, status) {
            if (x && x.status == 200) {
                if (status.core_status != "1") {
                    var r = confirm("<%:You have not installed the core yet, do you want to download and install it now?%>");
                    if (r == true) {
                        return select_git_cdn("core_download");
                    }
                }
            }
        });
    }

    function copyToClipboard(text, successMessage) {
        if (navigator.clipboard && window.isSecureContext) {
            navigator.clipboard.writeText(text).then(function() {
                prompt(successMessage, text);
            }).catch(function(err) {
                fallbackCopyTextToClipboard(text, successMessage);
            });
        } else {
            fallbackCopyTextToClipboard(text, successMessage);
        }
    }

    function copyAddress() {
        var status = StateManager.current_status;
        var address;
        
        if (status.daip && window.location.hostname == status.daip) {
            address = 'http://' + status.daip + ':' + (status.cn_port || '9090') + '/ui/zashboard/#/setup?hostname=' + status.daip + '&port=' + (status.cn_port || '9090') + (status.dase ? '&secret=' + status.dase : '');
        } else if (status.daip && window.location.hostname != status.daip && status.db_foward_domain && status.db_foward_port) {
            var ui_proto = status.db_forward_ssl == 0 ? 'http://' : 'https://';
            address = ui_proto + status.db_foward_domain + ':' + status.db_foward_port + '/ui/zashboard/#/setup?hostname=' + status.db_foward_domain + '&port=' + status.db_foward_port + (status.dase ? '&secret=' + status.dase : '');
        } else {
            address = 'http://' + (status.daip || 'unknown') + ':' + (status.cn_port || '9090') + '/ui/zashboard/#/';
        }
        
        copyToClipboard(address, '<%:Control panel address copied:%> ');
        return false;
    }

    function copySecret() {
        var secret = StateManager.current_status.dase || '';
        if (secret === '') {
            alert('<%:No control panel secret set%>');
            return false;
        }
        copyToClipboard(secret, '<%:Control panel secret copied:%> ');
        return false;
    }

    function copyMixAuth() {
        if (StateManager.cached_proxy_info) {
            if (StateManager.cached_proxy_info.auth_user && StateManager.cached_proxy_info.auth_pass) {
                var authText = StateManager.cached_proxy_info.auth_user + ':' + StateManager.cached_proxy_info.auth_pass;
                copyToClipboard(authText, '<%:Proxy auth info copied:%> ');
            } else {
                alert('<%:No proxy auth info set%>');
            }
        } else {
            alert('<%:Proxy info not available, please try again later%>');
        }
        return false;
    }

    function copyMixAddress() {
        if (StateManager.cached_proxy_info && StateManager.current_status.daip) {
            var mixPort = StateManager.cached_proxy_info.mixed_port || '7893';
            var proxyIp = StateManager.current_status.daip;
            var proxyText = proxyIp + ':' + mixPort;
            copyToClipboard(proxyText, '<%:Mix proxy address copied:%> ');
        } else {
            alert('<%:Proxy info not available, please try again later%>');
        }
        return false;
    }

    function get_oc_settings() {
        if (SettingsManager.isPollPaused('oc_settings')) {
            return;
        }
        
        StateManager.cachedXHRGet('<%=luci.dispatcher.build_url("admin", "services", "openclash", "oc_settings")%>', function(x, info) {
            if (x && x.status == 200) {
                if (!SettingsManager.pendingOperations.has('meta_sniffer_' + info.meta_sniffer)) {
                    DOMCache.meta_sniffer_on.checked = info.meta_sniffer == "1";
                    DOMCache.meta_sniffer_off.checked = info.meta_sniffer != "1";
                }
                
                if (!SettingsManager.pendingOperations.has('respect_rules_' + info.respect_rules)) {
                    DOMCache.respect_rules_on.checked = info.respect_rules == "1";
                    DOMCache.respect_rules_off.checked = info.respect_rules != "1";
                }
                
                if (!SettingsManager.pendingOperations.has('oversea_' + info.oversea)) {
                    if (info.oversea == "0") {
                        DOMCache.oc_setting_oversea_0.checked = true;
                    } else if (info.oversea == "1") {
                        DOMCache.oc_setting_oversea_1.checked = true;
                    } else if (info.oversea == "2") {
                        DOMCache.oc_setting_oversea_2.checked = true;
                    }
                }

                if (!SettingsManager.pendingOperations.has('stream_unlock_' + info.stream_unlock)) {
                    DOMCache.stream_unlock_on.checked = info.stream_unlock === '1';
                    DOMCache.stream_unlock_off.checked = info.stream_unlock !== '1';
                }
            }
        }, true);
    }

    function switch_oc_setting_oversea(value) {
        LogManager.startLogDisplay('<%:Saving...%>');
        return SettingsManager.switchSetting(
            'oversea', 
            value, 
            '<%=luci.dispatcher.build_url("admin", "services", "openclash", "switch_oc_setting")%>'
        );
    }

    function switch_meta_sniffer(value) {
        return SettingsManager.switchSetting(
            'meta_sniffer', 
            value, 
            '<%=luci.dispatcher.build_url("admin", "services", "openclash", "switch_oc_setting")%>'
        );
    }

    function switch_respect_rules(value) {
        return SettingsManager.switchSetting(
            'respect_rules', 
            value, 
            '<%=luci.dispatcher.build_url("admin", "services", "openclash", "switch_oc_setting")%>'
        );
    }

    function switch_stream_unlock(value) {
        return SettingsManager.switchSetting(
            'stream_unlock',
            value,
            '<%=luci.dispatcher.build_url("admin", "services", "openclash", "switch_oc_setting")%>'
        );
    }

    function generatePacConfig() {
        if (StateManager.current_status.daip) {
            var currentUrl = {
                protocol: window.location.protocol,
                hostname: window.location.hostname,
                host: window.location.host,
                port: window.location.port,
                href: window.location.href
            };
            
            XHR.get('<%=luci.dispatcher.build_url("admin", "services", "openclash", "generate_pac")%>', {
                client_protocol: currentUrl.protocol.replace(':', ''),
                client_hostname: currentUrl.hostname,
                client_host: currentUrl.host,
                client_port: currentUrl.port || '',
                client_href: currentUrl.href
            }, function(x, data) {
                if (x && x.status == 200 && data.pac_url) {
                    if (data.error && data.error.indexOf("warning:") === 0) {
                        var warningMsg = data.error.replace("warning: ", "");
                        var warningTranslations = {
                            'No authentication configured, please be aware of the risk of information leakage!': '<%:No authentication configured, please be aware of the risk of information leakage!%>'
                        };
                        var translatedWarning = warningTranslations[warningMsg] || warningMsg;
                        alert('<%:Warning:%> ' + translatedWarning);
                    }
                    copyToClipboard(data.pac_url, '<%:PAC file URL copied:%> ');
                } else if (data.error) {
                    errorinfos = {
                        'Proxy service not running': '<%:Proxy service not running%>',
                        'Unable to get proxy IP': '<%:Unable to get proxy IP%>',
                        'Failed to write PAC file': '<%:Failed to write PAC file%>'
                    };
                    var errorMsg = errorinfos[data.error] || data.error;
                    alert('<%:PAC file generation failed%>: ' + errorMsg);
                } else {
                    alert('<%:PAC file generation failed%>');
                }
            });
        } else {
            alert('<%:Proxy service not available, please try again later%>');
        }
        return false;
    }

    function fallbackCopyTextToClipboard(text, successMessage) {
        var textArea = document.createElement("textarea");
        textArea.value = text;
        textArea.style.top = "0";
        textArea.style.left = "0";
        textArea.style.position = "fixed";
        textArea.style.opacity = "0";
        
        document.body.appendChild(textArea);
        textArea.focus();
        textArea.select();
        
        try {
            var successful = document.execCommand('copy');
            document.body.removeChild(textArea);
            
            if (successful) {
                prompt(successMessage, text);
            } else {
                prompt('<%:Copy failed, please copy manually:%>', text);
            }
        } catch (err) {
            document.body.removeChild(textArea);
            prompt('<%:Copy failed, please copy manually:%>', text);
        }
    }

    function togglePlugin(toggleElement) {
        var isEnabled = toggleElement.checked;
        
        if (isEnabled) {
            var currentConfig = ConfigFileManager.getCurrentConfig() || ConfigFileManager.getSelectedConfig();
            if (!currentConfig) {
                toggleElement.checked = false;
                alert('<%:Please select a config file first%>');
                return false;
            }
        }

        toggleElement.disabled = true;
        pluginToggleUserAction = true;
        var action = isEnabled ? 'start' : 'stop';
        var initialMessage = isEnabled ? '<%:Starting...%>' : '<%:Stopping...%>';
        
        LogManager.startLogDisplay(initialMessage);
        
        var requestParams = { action: action };
        
        if (isEnabled) {
            var currentConfig = ConfigFileManager.getCurrentConfig();
            var selectedConfig = ConfigFileManager.getSelectedConfig();
            
            if (!currentConfig && selectedConfig) {
                requestParams.config_file = configFileName;
            }
        }
        
        XHR.get('<%=luci.dispatcher.build_url("admin", "services", "openclash", "action")%>', requestParams, function(x, status) {
            if (x && x.status == 200) {
                setTimeout(function() {
                    pluginToggleUserAction = false;
                    updatePluginToggleState(StateManager.current_status.clash || false);
                }, 3000);
            } else {
                toggleElement.checked = !isEnabled;
                
                var errorMessage = isEnabled ? 
                    '<%:Failed to start OpenClash%>' : 
                    '<%:Failed to stop OpenClash%>';
                alert(errorMessage);

                if (DOMCache.clash) {
                    DOMCache.clash.innerHTML = '<b style="color:var(--error-color)"><%:Operation Failed%></b>';
                }
                
                pluginToggleUserAction = false;
            }
            toggleElement.disabled = false;
        });
    }

    function updatePluginToggleState(isRunning) {
        if (pluginToggleUserAction) {
            return;
        }
        
        var toggleElement = document.getElementById('plugin_toggle');
        if (toggleElement) {
            toggleElement.checked = isRunning;
            toggleElement.disabled = false;
            
            if (DOMCache.clash && StateManager.current_status) {
                DOMCache.clash.innerHTML = isRunning ? 
                    '<b style=color:var(--success-color)>' + StateManager.current_status.core_type +'&nbsp;<%:Running%></b>' : 
                    '<b style=color:var(--error-color)><%:Not Running%></b>';
            }
            
            if (!isRunning && StateManager.current_status && !StateManager.current_status.clash) {
                setTimeout(function() {
                    updatePluginToggleState(StateManager.current_status.clash || false);
                }, 3000);
            }
        }
    }

    function switchConfig() {
        var currentConfig = ConfigFileManager.getSelectedConfig();
        if (!currentConfig) {
            alert('<%:Please select a config file first%>');
            return false;
        }
        
        pluginToggleUserAction = true;
        
        LogManager.startLogDisplay('<%:Switching Config...%>');
        
        XHR.get('<%=luci.dispatcher.build_url("admin", "services", "openclash", "switch_config")%>', {
            config_file: currentConfig
        }, function(x, status) {
            if (x && x.status == 200 && status.status === 'success') {
                ConfigFileManager.refreshConfigList();
                setTimeout(function() {
                    pluginToggleUserAction = false;
                    updatePluginToggleState(StateManager.current_status.clash || false);
                }, 4000);
            } else {
                alert('<%:Failed to switch config file:%> ' + (status.message || '<%:Unknown error%>'));
                
                if (DOMCache.oclog) {
                    DOMCache.oclog.innerHTML = '<b style="color:var(--error-color)"><%:Switch Failed%></b>';
                }
                
                pluginToggleUserAction = false;
            }
        });

        return false;
    }
    
    function updateConfig() {
        var currentConfig = ConfigFileManager.getSelectedConfig();
        if (!currentConfig) {
            alert('<%:Please select a config file first%>');
            return false;
        }
        
        var filename = SubscriptionManager.extractFilename(currentConfig);
        if (!filename) {
            alert('<%:Invalid config file selected%>');
            return false;
        }

        pluginToggleUserAction = true;
        
        LogManager.startLogDisplay('<%:Updating Config...%>');

        XHR.get('<%=luci.dispatcher.build_url("admin", "services", "openclash", "update_config")%>', {
            filename: filename
        }, function(x, status) {
            if (x && x.status == 200) {
                if (status.status === 'success') {
                    setTimeout(function() {
                        
                        refreshSubscriptionInfo();
                        
                        ConfigFileManager.refreshConfigList();
                        
                        pluginToggleUserAction = false;
                        
                    }, 2000);
                } else {
                    pluginToggleUserAction = false;
                    
                    if (DOMCache.oclog) {
                        DOMCache.oclog.innerHTML = '<b style="color:var(--error-color)"><%:Update Failed%></b>';
                    }
                    
                    alert('<%:Failed to update config file:%> ' + (status.message || status.error || '<%:Unknown error%>'));
                }
            } else {
                pluginToggleUserAction = false;
                
                if (DOMCache.oclog) {
                    DOMCache.oclog.innerHTML = '<b style="color:var(--error-color)"><%:Update Failed%></b>';
                }
                
                alert('<%:Failed to update config file, please try again later%>');
            }
        });

        return false;
    }

    function restartCore() {
        var currentConfig = ConfigFileManager.getCurrentConfig() || ConfigFileManager.getSelectedConfig();
        if (!currentConfig) {
            alert('<%:Please select a config file first%>');
            return false;
        }

        pluginToggleUserAction = true;
        
        var toggleElement = document.getElementById('plugin_toggle');
        if (toggleElement) {
            toggleElement.disabled = true;
        }
        
        LogManager.startLogDisplay('<%:Restarting...%>');
        
        var requestParams = { action: 'restart' };
        
        var currentConfigValue = ConfigFileManager.getCurrentConfig();
        var selectedConfig = ConfigFileManager.getSelectedConfig();
        
        if (!currentConfigValue && selectedConfig) {
            requestParams.config_file = configFileName;
        }
        
        XHR.get('<%=luci.dispatcher.build_url("admin", "services", "openclash", "action")%>', requestParams, function(x, status) {
            if (x && x.status == 200) {
                setTimeout(function() {
                    pluginToggleUserAction = false;
                    updatePluginToggleState(StateManager.current_status.clash || false);
                }, 5000);
                ConfigFileManager.refreshConfigList();
            } else {
                if (toggleElement) {
                    toggleElement.disabled = false;
                }
                alert('<%:Failed to restart core%>');
                
                pluginToggleUserAction = false;
            }
        });
        return false;
    }

    function refreshSubscriptionInfo() {
        var currentConfig = ConfigFileManager.getSelectedConfig();
        if (!currentConfig) {
            alert('<%:Please select a config file first%>');
            return false;
        }
        
        SubscriptionManager.currentConfigFile = currentConfig;
        SubscriptionManager.retryCount = 0;
        
        var filename = SubscriptionManager.extractFilename(currentConfig);
        localStorage.removeItem('sub_info_' + filename);
        SubscriptionManager.getSubscriptionInfo();
        return false;
    }
    
    function setSubscriptionUrl() {
        var currentConfig = ConfigFileManager.getSelectedConfig();
        if (!currentConfig) {
            alert('<%:Please select a config file first%>');
            return false;
        }
        
        var filename = SubscriptionManager.extractFilename(currentConfig);
        if (!filename) {
            alert('<%:Invalid config file selected%>');
            return false;
        }
        
        var newUrl = prompt('<%:Paste the new url of subscribe infos sources here:%>', '');
        if (newUrl === null) {
            return false;
        }
        
        XHR.get('<%=luci.dispatcher.build_url("admin", "services", "openclash", "set_subinfo_url")%>', {
            filename: filename,
            url: newUrl
        }, function(x, status) {
            if (x && x.status == 200 && status.info === "Success") {
                refreshSubscriptionInfo();
            } else if (x && x.status == 200 && status.info === "Delete success") {
                refreshSubscriptionInfo();
            } else {
                alert('<%:Specify subscribe infos sources url failed:%>\n' + (status.info || '<%:Unknown error%>'));
            }
        });
        
        return false;
    }

    function uploadConfig() {
        if (typeof ConfigUploader !== 'undefined' && ConfigUploader.show) {
            ConfigUploader.show();
        } else {
            setTimeout(function() {
                if (typeof ConfigUploader !== 'undefined' && ConfigUploader.show) {
                    ConfigUploader.show();
                } else {
                    alert('<%:Config uploader not ready, please try again%>');
                }
            }, 500);
        }
        
        return false;
    }

    function editConfig() {
        var currentConfig = ConfigFileManager.getSelectedConfig();
        if (!currentConfig) {
            alert('<%:Please select a config file first%>');
            return false;
        }
        
        if (typeof ConfigEditor !== 'undefined' && ConfigEditor.show) {
            ConfigEditor.show(currentConfig);
        } else {
            setTimeout(function() {
                if (typeof ConfigEditor !== 'undefined' && ConfigEditor.show) {
                    ConfigEditor.show(currentConfig);
                } else {
                    alert('<%:Config editor not ready, please try again%>');
                }
            }, 500);
        }
        
        return false;
    }

    function editOverwrite() {
        if (typeof ConfigEditor !== 'undefined' && ConfigEditor.showOverwrite) {
            ConfigEditor.showOverwrite();
        } else {
            setTimeout(function() {
                if (typeof ConfigEditor !== 'undefined' && ConfigEditor.showOverwrite) {
                    ConfigEditor.showOverwrite();
                } else {
                    alert('<%:Config editor not ready, please try again%>');
                }
            }, 500);
        }
        
        return false;
    }

    function switchToPreviousConfig() {
        if (ConfigFileManager.configList.length > 1) {
            var newIndex = ConfigFileManager.currentConfigIndex - 1;
            if (newIndex < 0) {
                newIndex = ConfigFileManager.configList.length - 1;
            }
            ConfigFileManager.switchToConfigByIndex(newIndex);
        }
        return false;
    }

    function switchToNextConfig() {
        if (ConfigFileManager.configList.length > 1) {
            var newIndex = ConfigFileManager.currentConfigIndex + 1;
            if (newIndex >= ConfigFileManager.configList.length) {
                newIndex = 0;
            }
            ConfigFileManager.switchToConfigByIndex(newIndex);
        }
        return false;
    }

    function isDarkBackground(element) {
        var style = window.getComputedStyle(element);
        var bgColor = style.backgroundColor;
        let r, g, b;
        if (/rgb\(/.test(bgColor)) {
            var rgb = bgColor.match(/\d+/g);
            r = parseInt(rgb);
            g = parseInt(rgb);
            b = parseInt(rgb);
        } else if (/#/.test(bgColor)) {
            if (bgColor.length === 4) {
            r = parseInt(bgColor + bgColor, 16);
            g = parseInt(bgColor + bgColor, 16);
            b = parseInt(bgColor + bgColor, 16);
            } else {
            r = parseInt(bgColor.slice(1, 3), 16);
            g = parseInt(bgColor.slice(3, 5), 16);
            b = parseInt(bgColor.slice(5, 7), 16);
            }
        } else {
            return false;
        }
        var luminance = 0.2126 * r + 0.7152 * g + 0.0722 * b;
        return luminance < 128;
    };
//]]></script>
</html>