{"id":24865,"date":"2026-09-09T01:18:00","date_gmt":"2026-09-09T01:18:00","guid":{"rendered":"https:\/\/www.mechstream.com\/?p=24865"},"modified":"2026-09-09T01:37:53","modified_gmt":"2026-09-09T01:37:53","slug":"thermal-expansion-calculator","status":"publish","type":"post","link":"https:\/\/www.mechstream.com\/es\/thermal-expansion-calculator\/","title":{"rendered":"Thermal Expansion Calculator"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">The <strong>Thermal Expansion Calculator<\/strong> is a practical engineering tool designed to calculate dimensional changes in materials caused by temperature variations. By entering the original dimension, temperature change, and coefficient of thermal expansion, users can quickly estimate thermal expansion, contraction, final length, and thermal strain. The Thermal Expansion Calculator is useful for mechanical design, piping systems, shafts, bearings, structural components, precision assemblies, and material comparison where temperature-related dimensional changes must be considered.<\/p>\n\n\n\n<!-- Thermal Expansion Calculator: paste ALL of this into a WordPress Custom HTML block -->\n<style>\n\/**\n * Thermal Expansion Calculator styles\n * All rules scoped under #thermal-expansion-calculator\n * so WordPress (or any host page) styles outside the widget are not affected.\n *\/\n\n#thermal-expansion-calculator {\n    --tec-primary: #1a5276;\n    --tec-primary-light: #2471a3;\n    --tec-primary-dark: #0e3d5c;\n    --tec-accent: #e67e22;\n    --tec-accent-hover: #d35400;\n    --tec-success: #27ae60;\n    --tec-warning: #f39c12;\n    --tec-danger: #c0392b;\n    --tec-bg: #f4f6f8;\n    --tec-card-bg: #ffffff;\n    --tec-text: #2c3e50;\n    --tec-text-muted: #7f8c8d;\n    --tec-border: #dce1e6;\n    --tec-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);\n    --tec-shadow-lg: 0 4px 16px rgba(0, 0, 0, 0.12);\n    --tec-radius: 8px;\n    --tec-radius-lg: 12px;\n    --tec-font: 'Segoe UI', system-ui, -apple-system, sans-serif;\n    --tec-mono: 'Consolas', 'Monaco', monospace;\n\n    display: block;\n    max-width: 1400px;\n    margin: 0 auto;\n    padding: 0;\n    font-family: var(--tec-font);\n    font-size: 15px;\n    line-height: 1.6;\n    color: var(--tec-text);\n    background: var(--tec-bg);\n    box-sizing: border-box;\n    text-align: left;\n    -webkit-text-size-adjust: 100%;\n}\n\n#thermal-expansion-calculator *,\n#thermal-expansion-calculator *::before,\n#thermal-expansion-calculator *::after {\n    box-sizing: border-box;\n}\n\n#thermal-expansion-calculator .app-container {\n    max-width: 1400px;\n    margin: 0 auto;\n    padding: 20px;\n}\n\n\/* Header *\/\n#thermal-expansion-calculator .app-header {\n    text-align: center;\n    padding: 32px 20px 24px;\n    background: linear-gradient(135deg, var(--tec-primary-dark), var(--tec-primary));\n    color: #fff;\n    border-radius: var(--tec-radius-lg);\n    margin-bottom: 24px;\n}\n\n#thermal-expansion-calculator .app-header h1 {\n    font-size: 2rem;\n    font-weight: 700;\n    margin: 0 0 8px;\n    padding: 0;\n    color: #fff;\n    line-height: 1.3;\n}\n\n#thermal-expansion-calculator .subtitle {\n    font-size: 0.95rem;\n    opacity: 0.9;\n    margin: 0;\n}\n\n\/* Cards *\/\n#thermal-expansion-calculator .card {\n    background: var(--tec-card-bg);\n    border-radius: var(--tec-radius-lg);\n    box-shadow: var(--tec-shadow);\n    padding: 24px;\n    margin-bottom: 20px;\n}\n\n#thermal-expansion-calculator .seo-intro {\n    border-left: 4px solid var(--tec-primary);\n    font-size: 0.95rem;\n    color: var(--tec-text-muted);\n}\n\n#thermal-expansion-calculator .seo-intro strong {\n    color: var(--tec-primary);\n}\n\n\/* Layout *\/\n#thermal-expansion-calculator .calculator-layout {\n    display: grid;\n    grid-template-columns: 1fr;\n    gap: 24px;\n    align-items: start;\n}\n\n#thermal-expansion-calculator .panel-header {\n    display: flex;\n    justify-content: space-between;\n    align-items: center;\n    flex-wrap: wrap;\n    gap: 12px;\n    margin-bottom: 20px;\n    padding-bottom: 16px;\n    border-bottom: 2px solid var(--tec-border);\n}\n\n#thermal-expansion-calculator .panel-header h2 {\n    font-size: 1.25rem;\n    color: var(--tec-primary);\n    margin: 0;\n    padding: 0;\n    font-weight: 700;\n}\n\n\/* Unit Toggle *\/\n#thermal-expansion-calculator .unit-system-toggle {\n    display: flex;\n    align-items: center;\n    gap: 8px;\n    font-size: 0.875rem;\n}\n\n#thermal-expansion-calculator .toggle-group {\n    display: flex;\n    border: 1px solid var(--tec-border);\n    border-radius: var(--tec-radius);\n    overflow: hidden;\n}\n\n#thermal-expansion-calculator .toggle-btn {\n    padding: 6px 16px;\n    border: none;\n    background: #fff;\n    cursor: pointer;\n    font-size: 0.875rem;\n    font-family: var(--tec-font);\n    color: var(--tec-text);\n    transition: all 0.2s;\n    line-height: 1.4;\n}\n\n#thermal-expansion-calculator .toggle-btn.active {\n    background: var(--tec-primary);\n    color: #fff;\n}\n\n#thermal-expansion-calculator .toggle-btn:hover:not(.active) {\n    background: var(--tec-bg);\n}\n\n\/* Form Elements *\/\n#thermal-expansion-calculator .form-group {\n    margin-bottom: 16px;\n}\n\n#thermal-expansion-calculator .form-group label {\n    display: block;\n    font-weight: 600;\n    font-size: 0.875rem;\n    margin-bottom: 6px;\n    color: var(--tec-text);\n}\n\n#thermal-expansion-calculator .input-grid {\n    display: grid;\n    grid-template-columns: 1fr 1fr;\n    gap: 12px;\n}\n\n#thermal-expansion-calculator .input-with-unit {\n    display: flex;\n    gap: 8px;\n}\n\n#thermal-expansion-calculator .input-with-unit input {\n    flex: 1;\n    min-width: 0;\n}\n\n#thermal-expansion-calculator .input-with-unit select,\n#thermal-expansion-calculator .unit-label {\n    flex-shrink: 0;\n    min-width: 90px;\n}\n\n#thermal-expansion-calculator .unit-label {\n    display: flex;\n    align-items: center;\n    padding: 0 10px;\n    background: var(--tec-bg);\n    border: 1px solid var(--tec-border);\n    border-radius: var(--tec-radius);\n    font-size: 0.8rem;\n    color: var(--tec-text-muted);\n}\n\n#thermal-expansion-calculator input[type=\"number\"],\n#thermal-expansion-calculator input[type=\"text\"],\n#thermal-expansion-calculator select {\n    width: 100%;\n    max-width: 100%;\n    padding: 10px 12px;\n    margin: 0;\n    border: 1px solid var(--tec-border);\n    border-radius: var(--tec-radius);\n    font-size: 0.9rem;\n    font-family: var(--tec-font);\n    color: var(--tec-text);\n    transition: border-color 0.2s, box-shadow 0.2s;\n    background: #fff;\n    line-height: 1.4;\n    height: auto;\n    box-shadow: none;\n    appearance: auto;\n    -webkit-appearance: auto;\n}\n\n#thermal-expansion-calculator input:focus,\n#thermal-expansion-calculator select:focus {\n    outline: none;\n    border-color: var(--tec-primary-light);\n    box-shadow: 0 0 0 3px rgba(36, 113, 163, 0.15);\n}\n\n#thermal-expansion-calculator .hint {\n    display: block;\n    font-size: 0.78rem;\n    color: var(--tec-text-muted);\n    margin-top: 4px;\n}\n\n#thermal-expansion-calculator .section-title {\n    font-size: 0.95rem;\n    color: var(--tec-primary);\n    margin: 16px 0 12px;\n    padding-top: 8px;\n    border-top: 1px solid var(--tec-border);\n    font-weight: 700;\n}\n\n\/* Tooltip *\/\n#thermal-expansion-calculator .tooltip {\n    display: inline-flex;\n    align-items: center;\n    justify-content: center;\n    width: 16px;\n    height: 16px;\n    background: var(--tec-primary-light);\n    color: #fff;\n    border-radius: 50%;\n    font-size: 0.7rem;\n    cursor: help;\n    position: relative;\n    margin-left: 4px;\n    vertical-align: middle;\n}\n\n#thermal-expansion-calculator .tooltip::after {\n    content: attr(data-tip);\n    position: absolute;\n    bottom: calc(100% + 8px);\n    left: 50%;\n    transform: translateX(-50%);\n    background: var(--tec-text);\n    color: #fff;\n    padding: 8px 12px;\n    border-radius: var(--tec-radius);\n    font-size: 0.75rem;\n    font-weight: 400;\n    white-space: normal;\n    width: max-content;\n    max-width: 260px;\n    opacity: 0;\n    visibility: hidden;\n    transition: opacity 0.2s;\n    z-index: 100;\n    pointer-events: none;\n}\n\n#thermal-expansion-calculator .tooltip:hover::after {\n    opacity: 1;\n    visibility: visible;\n}\n\n\/* Advanced Sections *\/\n#thermal-expansion-calculator .advanced-section,\n#thermal-expansion-calculator .formula-section {\n    margin: 16px 0;\n    border: 1px solid var(--tec-border);\n    border-radius: var(--tec-radius);\n}\n\n#thermal-expansion-calculator .advanced-section summary,\n#thermal-expansion-calculator .formula-section summary {\n    padding: 12px 16px;\n    cursor: pointer;\n    font-weight: 600;\n    font-size: 0.875rem;\n    color: var(--tec-primary);\n    background: var(--tec-bg);\n    border-radius: var(--tec-radius);\n    user-select: none;\n}\n\n#thermal-expansion-calculator .advanced-section[open] summary,\n#thermal-expansion-calculator .formula-section[open] summary {\n    border-bottom: 1px solid var(--tec-border);\n    border-radius: var(--tec-radius) var(--tec-radius) 0 0;\n}\n\n#thermal-expansion-calculator .advanced-content,\n#thermal-expansion-calculator .formula-content {\n    padding: 16px;\n}\n\n#thermal-expansion-calculator .formula-content dl {\n    display: grid;\n    grid-template-columns: auto 1fr;\n    gap: 4px 16px;\n    font-size: 0.875rem;\n    margin: 0 0 12px;\n}\n\n#thermal-expansion-calculator .formula-content dt {\n    font-weight: 600;\n    color: var(--tec-primary);\n}\n\n#thermal-expansion-calculator .formula-content dd {\n    font-family: var(--tec-mono);\n    font-size: 0.82rem;\n    margin: 0;\n}\n\n#thermal-expansion-calculator .assumptions-list {\n    font-size: 0.82rem;\n    color: var(--tec-text-muted);\n    padding-left: 20px;\n    margin: 0;\n}\n\n#thermal-expansion-calculator .assumptions-list li {\n    margin-bottom: 4px;\n}\n\n\/* Buttons *\/\n#thermal-expansion-calculator .button-group {\n    display: flex;\n    gap: 12px;\n    margin-top: 20px;\n    flex-wrap: wrap;\n    justify-content: center;\n}\n\n#thermal-expansion-calculator .btn-primary,\n#thermal-expansion-calculator .btn-secondary {\n    padding: 12px 24px;\n    border: none;\n    border-radius: var(--tec-radius);\n    font-size: 0.95rem;\n    font-weight: 600;\n    font-family: var(--tec-font);\n    cursor: pointer;\n    transition: all 0.2s;\n    line-height: 1.4;\n    text-decoration: none;\n    display: inline-block;\n}\n\n#thermal-expansion-calculator .btn-primary {\n    background: var(--tec-primary);\n    color: #fff;\n    flex: 0 0 auto;\n    width: 20%;\n    min-width: 160px;\n}\n\n#thermal-expansion-calculator .btn-primary:hover {\n    background: var(--tec-primary-light);\n    transform: translateY(-1px);\n    box-shadow: var(--tec-shadow);\n    color: #fff;\n}\n\n#thermal-expansion-calculator .btn-secondary {\n    background: #fff;\n    color: var(--tec-text);\n    border: 1px solid var(--tec-border);\n}\n\n#thermal-expansion-calculator .btn-secondary:hover {\n    background: var(--tec-bg);\n}\n\n#thermal-expansion-calculator .btn-sm {\n    padding: 6px 14px;\n    font-size: 0.82rem;\n}\n\n\/* Results *\/\n#thermal-expansion-calculator .results-card h2,\n#thermal-expansion-calculator .diagram-card h2,\n#thermal-expansion-calculator .chart-card h2 {\n    font-size: 1.15rem;\n    color: var(--tec-primary);\n    margin: 0 0 16px;\n    padding: 0 0 12px;\n    border-bottom: 2px solid var(--tec-border);\n    font-weight: 700;\n}\n\n#thermal-expansion-calculator .results-grid {\n    display: grid;\n    grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));\n    gap: 12px;\n}\n\n#thermal-expansion-calculator .result-item {\n    background: var(--tec-bg);\n    border-radius: var(--tec-radius);\n    padding: 14px;\n    border-left: 3px solid var(--tec-primary-light);\n}\n\n#thermal-expansion-calculator .result-item.highlight {\n    border-left-color: var(--tec-accent);\n    background: #fef9f3;\n}\n\n#thermal-expansion-calculator .result-label {\n    font-size: 0.78rem;\n    color: var(--tec-text-muted);\n    text-transform: uppercase;\n    letter-spacing: 0.03em;\n    margin-bottom: 4px;\n}\n\n#thermal-expansion-calculator .result-value {\n    font-size: 1.15rem;\n    font-weight: 700;\n    color: var(--tec-text);\n    font-family: var(--tec-mono);\n}\n\n#thermal-expansion-calculator .result-unit {\n    font-size: 0.82rem;\n    font-weight: 400;\n    color: var(--tec-text-muted);\n}\n\n#thermal-expansion-calculator .placeholder-text {\n    color: var(--tec-text-muted);\n    font-style: italic;\n    grid-column: 1 \/ -1;\n    margin: 0;\n}\n\n\/* Messages *\/\n#thermal-expansion-calculator .error-messages,\n#thermal-expansion-calculator .warning-messages {\n    padding: 12px 16px;\n    border-radius: var(--tec-radius);\n    margin-bottom: 16px;\n    font-size: 0.875rem;\n}\n\n#thermal-expansion-calculator .error-messages {\n    background: #fdecea;\n    border: 1px solid #f5c6cb;\n    color: var(--tec-danger);\n}\n\n#thermal-expansion-calculator .warning-messages {\n    background: #fff8e1;\n    border: 1px solid #ffe082;\n    color: #e65100;\n}\n\n#thermal-expansion-calculator .error-messages ul,\n#thermal-expansion-calculator .warning-messages ul {\n    padding-left: 20px;\n    margin: 0;\n}\n\n\/* Interpretation & Recommendations *\/\n#thermal-expansion-calculator .interpretation,\n#thermal-expansion-calculator .recommendations {\n    margin-top: 20px;\n    padding: 16px;\n    border-radius: var(--tec-radius);\n    font-size: 0.875rem;\n}\n\n#thermal-expansion-calculator .interpretation {\n    background: #e8f4fd;\n    border-left: 4px solid var(--tec-primary-light);\n}\n\n#thermal-expansion-calculator .recommendations {\n    background: #eafaf1;\n    border-left: 4px solid var(--tec-success);\n}\n\n#thermal-expansion-calculator .interpretation h3,\n#thermal-expansion-calculator .recommendations h3 {\n    font-size: 0.9rem;\n    margin: 0 0 8px;\n    color: var(--tec-primary);\n}\n\n#thermal-expansion-calculator .interpretation ul,\n#thermal-expansion-calculator .recommendations ul {\n    padding-left: 20px;\n    margin: 0;\n}\n\n#thermal-expansion-calculator .interpretation li,\n#thermal-expansion-calculator .recommendations li {\n    margin-bottom: 4px;\n}\n\n\/* Clearance Status *\/\n#thermal-expansion-calculator .clearance-status {\n    display: inline-block;\n    padding: 4px 12px;\n    border-radius: 20px;\n    font-size: 0.82rem;\n    font-weight: 600;\n    margin-top: 8px;\n}\n\n#thermal-expansion-calculator .clearance-safe { background: #d5f5e3; color: #1e8449; }\n#thermal-expansion-calculator .clearance-reduced { background: #fef9e7; color: #b7950b; }\n#thermal-expansion-calculator .clearance-near { background: #fdebd0; color: #d35400; }\n#thermal-expansion-calculator .clearance-interference { background: #fadbd8; color: var(--tec-danger); }\n\n\/* Comparison Table *\/\n#thermal-expansion-calculator .comparison-table {\n    width: 100%;\n    border-collapse: collapse;\n    font-size: 0.85rem;\n    margin-top: 12px;\n}\n\n#thermal-expansion-calculator .comparison-table th,\n#thermal-expansion-calculator .comparison-table td {\n    padding: 10px 12px;\n    text-align: left;\n    border-bottom: 1px solid var(--tec-border);\n}\n\n#thermal-expansion-calculator .comparison-table th {\n    background: var(--tec-bg);\n    font-weight: 600;\n    color: var(--tec-primary);\n    font-size: 0.78rem;\n    text-transform: uppercase;\n}\n\n#thermal-expansion-calculator .comparison-table tr:hover td {\n    background: #f8f9fa;\n}\n\n#thermal-expansion-calculator .comparison-table .rank {\n    font-weight: 700;\n    color: var(--tec-accent);\n}\n\n\/* Diagram *\/\n#thermal-expansion-calculator .diagram-container {\n    min-height: 180px;\n    display: flex;\n    align-items: center;\n    justify-content: center;\n}\n\n#thermal-expansion-calculator .diagram-container svg {\n    max-width: 100%;\n    height: auto;\n}\n\n\/* Charts *\/\n#thermal-expansion-calculator .chart-tabs {\n    display: flex;\n    gap: 4px;\n    margin-bottom: 16px;\n    flex-wrap: wrap;\n}\n\n#thermal-expansion-calculator .chart-tab {\n    padding: 8px 14px;\n    border: 1px solid var(--tec-border);\n    background: #fff;\n    border-radius: var(--tec-radius);\n    font-size: 0.78rem;\n    font-family: var(--tec-font);\n    color: var(--tec-text);\n    cursor: pointer;\n    transition: all 0.2s;\n}\n\n#thermal-expansion-calculator .chart-tab.active {\n    background: var(--tec-primary);\n    color: #fff;\n    border-color: var(--tec-primary);\n}\n\n#thermal-expansion-calculator .chart-tab:hover:not(.active) {\n    background: var(--tec-bg);\n}\n\n#thermal-expansion-calculator .chart-container {\n    position: relative;\n    height: 280px;\n}\n\n\/* Comparison Material Row *\/\n#thermal-expansion-calculator .comparison-row {\n    display: grid;\n    grid-template-columns: 1fr 100px auto;\n    gap: 8px;\n    align-items: end;\n    margin-bottom: 8px;\n}\n\n#thermal-expansion-calculator .comparison-row .remove-btn {\n    padding: 10px;\n    background: none;\n    border: 1px solid var(--tec-border);\n    border-radius: var(--tec-radius);\n    cursor: pointer;\n    color: var(--tec-danger);\n    font-size: 1rem;\n    line-height: 1;\n    font-family: var(--tec-font);\n}\n\n#thermal-expansion-calculator .comparison-row .remove-btn:hover {\n    background: #fdecea;\n}\n\n\/* Piecewise rows *\/\n#thermal-expansion-calculator .piecewise-row {\n    display: grid;\n    grid-template-columns: 1fr 1fr auto;\n    gap: 8px;\n    margin-bottom: 8px;\n    align-items: end;\n}\n\n#thermal-expansion-calculator .piecewise-row .remove-btn {\n    padding: 10px;\n    background: none;\n    border: 1px solid var(--tec-border);\n    border-radius: var(--tec-radius);\n    cursor: pointer;\n    color: var(--tec-danger);\n    font-family: var(--tec-font);\n}\n\n\/* Limitations & Disclaimer *\/\n#thermal-expansion-calculator .limitations {\n    border-left: 4px solid var(--tec-warning);\n}\n\n#thermal-expansion-calculator .limitations h2 {\n    font-size: 1.1rem;\n    color: var(--tec-primary);\n    margin: 0 0 12px;\n}\n\n#thermal-expansion-calculator .limitations ul {\n    padding-left: 20px;\n    font-size: 0.875rem;\n    color: var(--tec-text-muted);\n    margin: 0;\n}\n\n#thermal-expansion-calculator .limitations li {\n    margin-bottom: 4px;\n}\n\n#thermal-expansion-calculator .disclaimer {\n    text-align: center;\n    padding: 24px;\n    font-size: 0.82rem;\n    color: var(--tec-text-muted);\n    border-top: 1px solid var(--tec-border);\n    margin-top: 12px;\n}\n\n#thermal-expansion-calculator .disclaimer strong {\n    color: var(--tec-text);\n}\n\n#thermal-expansion-calculator .hidden {\n    display: none !important;\n}\n\n#thermal-expansion-calculator p,\n#thermal-expansion-calculator ul,\n#thermal-expansion-calculator ol,\n#thermal-expansion-calculator table {\n    max-width: none;\n}\n\n#thermal-expansion-calculator a {\n    color: var(--tec-primary-light);\n}\n\n\/* Responsive \u2014 still scoped *\/\n@media (max-width: 1024px) {\n    #thermal-expansion-calculator .calculator-layout {\n        grid-template-columns: 1fr;\n    }\n}\n\n@media (max-width: 640px) {\n    #thermal-expansion-calculator .app-container {\n        padding: 12px;\n    }\n\n    #thermal-expansion-calculator .app-header h1 {\n        font-size: 1.5rem;\n    }\n\n    #thermal-expansion-calculator .input-grid {\n        grid-template-columns: 1fr;\n    }\n\n    #thermal-expansion-calculator .panel-header {\n        flex-direction: column;\n        align-items: flex-start;\n    }\n\n    #thermal-expansion-calculator .results-grid {\n        grid-template-columns: 1fr;\n    }\n\n    #thermal-expansion-calculator .button-group {\n        flex-direction: column;\n        align-items: center;\n    }\n\n    #thermal-expansion-calculator .btn-primary {\n        width: 100%;\n        max-width: 280px;\n    }\n\n    #thermal-expansion-calculator .comparison-row {\n        grid-template-columns: 1fr;\n    }\n\n    #thermal-expansion-calculator .chart-container {\n        height: 220px;\n    }\n}\n\n\n\/* WordPress theme shield \u2014 neutralize theme form styles inside calculator only *\/\n#thermal-expansion-calculator input,\n#thermal-expansion-calculator select,\n#thermal-expansion-calculator button,\n#thermal-expansion-calculator textarea,\n#thermal-expansion-calculator summary {\n  -webkit-appearance: none !important;\n  -moz-appearance: none !important;\n  appearance: none !important;\n  background-image: none !important;\n  box-shadow: none !important;\n  text-shadow: none !important;\n  float: none !important;\n  clear: none !important;\n  max-width: 100% !important;\n  min-height: 0 !important;\n  height: auto !important;\n  line-height: 1.4 !important;\n  letter-spacing: normal !important;\n  text-indent: 0 !important;\n  text-transform: none !important;\n  vertical-align: middle;\n}\n#thermal-expansion-calculator input[type=\"number\"],\n#thermal-expansion-calculator input[type=\"text\"] {\n  background-color: #fff !important;\n  border: 1px solid var(--tec-border) !important;\n  border-radius: var(--tec-radius) !important;\n  padding: 10px 12px !important;\n  margin: 0 !important;\n  width: 100% !important;\n  color: var(--tec-text) !important;\n  font-size: 0.9rem !important;\n  font-family: var(--tec-font) !important;\n}\n#thermal-expansion-calculator select {\n  background-color: #fff !important;\n  border: 1px solid var(--tec-border) !important;\n  border-radius: var(--tec-radius) !important;\n  padding: 10px 28px 10px 12px !important;\n  margin: 0 !important;\n  width: 100% !important;\n  color: var(--tec-text) !important;\n  font-size: 0.9rem !important;\n  font-family: var(--tec-font) !important;\n  background-image: url(\"data:image\/svg+xml,%3Csvg xmlns='http:\/\/www.w3.org\/2000\/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath fill='%232c3e50' d='M1 1l5 5 5-5'\/%3E%3C\/svg%3E\") !important;\n  background-repeat: no-repeat !important;\n  background-position: right 10px center !important;\n  background-size: 12px 8px !important;\n  cursor: pointer;\n}\n#thermal-expansion-calculator .input-with-unit {\n  display: flex !important;\n  align-items: stretch !important;\n  gap: 8px !important;\n  width: 100% !important;\n}\n#thermal-expansion-calculator .input-with-unit input {\n  flex: 1 1 auto !important;\n  width: auto !important;\n  min-width: 0 !important;\n}\n#thermal-expansion-calculator .input-with-unit select {\n  flex: 0 0 auto !important;\n  width: auto !important;\n  min-width: 90px !important;\n  max-width: 140px !important;\n}\n#thermal-expansion-calculator .input-with-unit .unit-label {\n  flex: 0 0 auto !important;\n  width: auto !important;\n  min-width: 90px !important;\n  display: flex !important;\n  align-items: center !important;\n  padding: 0 10px !important;\n  background: var(--tec-bg) !important;\n  border: 1px solid var(--tec-border) !important;\n  border-radius: var(--tec-radius) !important;\n  font-size: 0.8rem !important;\n  color: var(--tec-text-muted) !important;\n}\n#thermal-expansion-calculator .btn-primary {\n  background: var(--tec-primary) !important;\n  color: #fff !important;\n  border: none !important;\n  border-radius: var(--tec-radius) !important;\n  padding: 12px 24px !important;\n  font-weight: 600 !important;\n  font-size: 0.95rem !important;\n  font-family: var(--tec-font) !important;\n  width: 20% !important;\n  min-width: 160px !important;\n  cursor: pointer !important;\n}\n#thermal-expansion-calculator .btn-secondary {\n  background: #fff !important;\n  color: var(--tec-text) !important;\n  border: 1px solid var(--tec-border) !important;\n  width: auto !important;\n  min-width: 0 !important;\n}\n#thermal-expansion-calculator .toggle-btn {\n  background: #fff !important;\n  color: var(--tec-text) !important;\n  border: none !important;\n  border-radius: 0 !important;\n  box-shadow: none !important;\n  padding: 6px 16px !important;\n  width: auto !important;\n  min-width: 0 !important;\n}\n#thermal-expansion-calculator .toggle-btn.active {\n  background: var(--tec-primary) !important;\n  color: #fff !important;\n}\n#thermal-expansion-calculator .card {\n  background: #fff !important;\n  border: 1px solid var(--tec-border);\n  box-shadow: var(--tec-shadow) !important;\n}\n#thermal-expansion-calculator .form-group label {\n  display: block !important;\n  width: auto !important;\n  float: none !important;\n  margin-bottom: 6px !important;\n}\n#thermal-expansion-calculator details summary {\n  list-style: none;\n}\n#thermal-expansion-calculator details summary::-webkit-details-marker {\n  display: none;\n}\n#thermal-expansion-calculator .hidden {\n  display: none !important;\n}\n\n<\/style>\n<div id=\"thermal-expansion-calculator\">\n    <div class=\"app-container\">\n        <main class=\"calculator-layout\">\n            <!-- Input Panel -->\n            <section class=\"input-panel card\">\n                <div class=\"panel-header\">\n                    <h2>Calculation Inputs<\/h2>\n                    <div class=\"unit-system-toggle\">\n                        <label>Unit System:<\/label>\n                        <div class=\"toggle-group\" role=\"group\" aria-label=\"Unit system\">\n                            <button type=\"button\" class=\"toggle-btn active\" data-system=\"metric\">Metric<\/button>\n                            <button type=\"button\" class=\"toggle-btn\" data-system=\"imperial\">Imperial<\/button>\n                        <\/div>\n                    <\/div>\n                <\/div>\n\n                <!-- Calculation Mode -->\n                <div class=\"form-group\">\n                    <label for=\"calcMode\">\n                        Calculation Mode\n                        <span class=\"tooltip\" data-tip=\"Select the type of thermal expansion calculation\">?<\/span>\n                    <\/label>\n                    <select id=\"calcMode\">\n                        <option value=\"linear\">Linear Thermal Expansion<\/option>\n                        <option value=\"finalLength\">Final Length Calculation<\/option>\n                        <option value=\"tempChange\">Temperature Change Calculation<\/option>\n                        <option value=\"coefficient\">Thermal Expansion Coefficient Calculation<\/option>\n                        <option value=\"area\">Area Expansion<\/option>\n                        <option value=\"volume\">Volumetric Expansion<\/option>\n                        <option value=\"comparison\">Material Comparison<\/option>\n                        <option value=\"clearance\">Thermal Clearance Check<\/option>\n                    <\/select>\n                <\/div>\n\n                <!-- Expansion Method -->\n                <div class=\"form-group\" id=\"expansionMethodGroup\">\n                    <label for=\"expansionMethod\">\n                        Calculation Method\n                        <span class=\"tooltip\" data-tip=\"Engineering approximation uses \u0394L=\u03b1L\u2080\u0394T. Geometric method uses (1+\u03b1\u0394T)\u207f for higher precision.\">?<\/span>\n                    <\/label>\n                    <select id=\"expansionMethod\">\n                        <option value=\"engineering\">Engineering Linear Approximation<\/option>\n                        <option value=\"geometric\">Geometric Expansion Method<\/option>\n                    <\/select>\n                <\/div>\n\n                <!-- Material Selection -->\n                <div class=\"form-group\" id=\"materialGroup\">\n                    <label for=\"materialSearch\">Material Preset<\/label>\n                    <input type=\"text\" id=\"materialSearch\" placeholder=\"Search materials...\" autocomplete=\"off\">\n                    <select id=\"materialSelect\"><\/select>\n                    <small class=\"hint\">Preset values are approximate and editable.<\/small>\n                <\/div>\n\n                <!-- Alpha Mode (Advanced) -->\n                <details class=\"advanced-section\" id=\"alphaModeSection\">\n                    <summary>Advanced: Temperature-Dependent Coefficient<\/summary>\n                    <div class=\"advanced-content\">\n                        <div class=\"form-group\">\n                            <label for=\"alphaMode\">Coefficient Mode<\/label>\n                            <select id=\"alphaMode\">\n                                <option value=\"constant\">Constant \u03b1<\/option>\n                                <option value=\"average\">Average \u03b1 over temperature range<\/option>\n                                <option value=\"piecewise\">User-defined piecewise \u03b1 values<\/option>\n                            <\/select>\n                        <\/div>\n                        <div id=\"piecewiseAlphaContainer\" class=\"hidden\">\n                            <p class=\"hint\">Enter \u03b1 values at temperature breakpoints (\u00b0C). \u0394L = L\u2080 \u00d7 \u03a3(\u03b1\u1d62 \u00d7 \u0394T\u1d62)<\/p>\n                            <div id=\"piecewiseRows\"><\/div>\n                            <button type=\"button\" class=\"btn-secondary btn-sm\" id=\"addPiecewiseRow\">+ Add Breakpoint<\/button>\n                        <\/div>\n                    <\/div>\n                <\/details>\n\n                <!-- Core Inputs -->\n                <div class=\"input-grid\" id=\"coreInputs\">\n                    <div class=\"form-group\" data-input=\"alpha\">\n                        <label for=\"alpha\">\n                            Thermal Expansion Coefficient (\u03b1)\n                            <span class=\"tooltip\" data-tip=\"Linear coefficient of thermal expansion. Typical metals: 10\u201324 \u00d710\u207b\u2076\/\u00b0C\">?<\/span>\n                        <\/label>\n                        <div class=\"input-with-unit\">\n                            <input type=\"number\" id=\"alpha\" value=\"12\" step=\"any\">\n                            <select id=\"alphaUnit\">\n                                <option value=\"1e-6_per_C\">\u00d710\u207b\u2076\/\u00b0C<\/option>\n                                <option value=\"per_C\">1\/\u00b0C<\/option>\n                                <option value=\"um_per_m_C\">\u00b5m\/m\u00b7\u00b0C<\/option>\n                                <option value=\"per_F\">1\/\u00b0F<\/option>\n                            <\/select>\n                        <\/div>\n                    <\/div>\n\n                    <div class=\"form-group\" data-input=\"length\">\n                        <label for=\"length\">Original Length (L\u2080)<\/label>\n                        <div class=\"input-with-unit\">\n                            <input type=\"number\" id=\"length\" value=\"1000\" step=\"any\" min=\"0\">\n                            <select id=\"lengthUnit\">\n                                <option value=\"mm\">mm<\/option>\n                                <option value=\"cm\">cm<\/option>\n                                <option value=\"m\">m<\/option>\n                                <option value=\"in\">in<\/option>\n                                <option value=\"ft\">ft<\/option>\n                            <\/select>\n                        <\/div>\n                    <\/div>\n\n                    <div class=\"form-group\" data-input=\"area\">\n                        <label for=\"area\">Original Area (A\u2080)<\/label>\n                        <div class=\"input-with-unit\">\n                            <input type=\"number\" id=\"area\" value=\"100\" step=\"any\" min=\"0\">\n                            <select id=\"areaUnit\">\n                                <option value=\"mm2\">mm\u00b2<\/option>\n                                <option value=\"cm2\">cm\u00b2<\/option>\n                                <option value=\"m2\">m\u00b2<\/option>\n                                <option value=\"in2\">in\u00b2<\/option>\n                                <option value=\"ft2\">ft\u00b2<\/option>\n                            <\/select>\n                        <\/div>\n                    <\/div>\n\n                    <div class=\"form-group\" data-input=\"volume\">\n                        <label for=\"volume\">Original Volume (V\u2080)<\/label>\n                        <div class=\"input-with-unit\">\n                            <input type=\"number\" id=\"volume\" value=\"1000\" step=\"any\" min=\"0\">\n                            <select id=\"volumeUnit\">\n                                <option value=\"mm3\">mm\u00b3<\/option>\n                                <option value=\"cm3\">cm\u00b3<\/option>\n                                <option value=\"m3\">m\u00b3<\/option>\n                                <option value=\"in3\">in\u00b3<\/option>\n                                <option value=\"ft3\">ft\u00b3<\/option>\n                            <\/select>\n                        <\/div>\n                    <\/div>\n\n                    <div class=\"form-group\" data-input=\"temp1\">\n                        <label for=\"temp1\">Initial Temperature (T\u2081)<\/label>\n                        <div class=\"input-with-unit\">\n                            <input type=\"number\" id=\"temp1\" value=\"20\" step=\"any\">\n                            <select id=\"tempUnit\">\n                                <option value=\"C\">\u00b0C<\/option>\n                                <option value=\"F\">\u00b0F<\/option>\n                                <option value=\"K\">K<\/option>\n                            <\/select>\n                        <\/div>\n                    <\/div>\n\n                    <div class=\"form-group\" data-input=\"temp2\">\n                        <label for=\"temp2\">Final Temperature (T\u2082)<\/label>\n                        <div class=\"input-with-unit\">\n                            <input type=\"number\" id=\"temp2\" value=\"80\" step=\"any\">\n                            <span class=\"unit-label\" id=\"temp2UnitLabel\">\u00b0C<\/span>\n                            <select id=\"tempUnit2\" class=\"hidden\" aria-hidden=\"true\">\n                                <option value=\"C\">\u00b0C<\/option>\n                                <option value=\"F\">\u00b0F<\/option>\n                                <option value=\"K\">K<\/option>\n                            <\/select>\n                        <\/div>\n                    <\/div>\n\n                    <div class=\"form-group\" data-input=\"deltaL\">\n                        <label for=\"deltaL\">Length Change (\u0394L)<\/label>\n                        <div class=\"input-with-unit\">\n                            <input type=\"number\" id=\"deltaL\" value=\"0.72\" step=\"any\">\n                            <select id=\"deltaLUnit\">\n                                <option value=\"mm\">mm<\/option>\n                                <option value=\"um\">\u00b5m<\/option>\n                                <option value=\"m\">m<\/option>\n                                <option value=\"in\">in<\/option>\n                            <\/select>\n                        <\/div>\n                    <\/div>\n\n                    <div class=\"form-group\" data-input=\"finalLength\">\n                        <label for=\"finalLength\">Final Length (L\u2082)<\/label>\n                        <div class=\"input-with-unit\">\n                            <input type=\"number\" id=\"finalLength\" value=\"1000.72\" step=\"any\" min=\"0\">\n                            <select id=\"finalLengthUnit\">\n                                <option value=\"mm\">mm<\/option>\n                                <option value=\"cm\">cm<\/option>\n                                <option value=\"m\">m<\/option>\n                                <option value=\"in\">in<\/option>\n                                <option value=\"ft\">ft<\/option>\n                            <\/select>\n                        <\/div>\n                    <\/div>\n\n                    <div class=\"form-group\" data-input=\"deltaT\">\n                        <label for=\"deltaT\">\n                            Temperature Change (\u0394T)\n                            <span class=\"tooltip\" data-tip=\"\u0394T = T\u2082 \u2212 T\u2081. Positive = expansion, negative = contraction.\">?<\/span>\n                        <\/label>\n                        <div class=\"input-with-unit\">\n                            <input type=\"number\" id=\"deltaT\" value=\"60\" step=\"any\">\n                            <select id=\"deltaTUnit\">\n                                <option value=\"C\">\u00b0C<\/option>\n                                <option value=\"F\">\u00b0F<\/option>\n                                <option value=\"K\">K<\/option>\n                            <\/select>\n                        <\/div>\n                    <\/div>\n                <\/div>\n\n                <!-- Clearance Mode Inputs -->\n                <div id=\"clearanceInputs\" class=\"hidden\">\n                    <h3 class=\"section-title\">Component 1 (e.g., Shaft)<\/h3>\n                    <div class=\"input-grid\">\n                        <div class=\"form-group\">\n                            <label for=\"clearAlpha1\">\u03b1 (Component 1)<\/label>\n                            <div class=\"input-with-unit\">\n                                <input type=\"number\" id=\"clearAlpha1\" value=\"23\" step=\"any\">\n                                <span class=\"unit-label\">\u00d710\u207b\u2076\/\u00b0C<\/span>\n                            <\/div>\n                        <\/div>\n                        <div class=\"form-group\">\n                            <label for=\"clearLength1\">Length L\u2081<\/label>\n                            <div class=\"input-with-unit\">\n                                <input type=\"number\" id=\"clearLength1\" value=\"100\" step=\"any\">\n                                <select id=\"clearLengthUnit\"><option value=\"mm\">mm<\/option><\/select>\n                            <\/div>\n                        <\/div>\n                    <\/div>\n                    <h3 class=\"section-title\">Component 2 (e.g., Housing)<\/h3>\n                    <div class=\"input-grid\">\n                        <div class=\"form-group\">\n                            <label for=\"clearAlpha2\">\u03b1 (Component 2)<\/label>\n                            <div class=\"input-with-unit\">\n                                <input type=\"number\" id=\"clearAlpha2\" value=\"12\" step=\"any\">\n                                <span class=\"unit-label\">\u00d710\u207b\u2076\/\u00b0C<\/span>\n                            <\/div>\n                        <\/div>\n                        <div class=\"form-group\">\n                            <label for=\"clearLength2\">Length L\u2082<\/label>\n                            <div class=\"input-with-unit\">\n                                <input type=\"number\" id=\"clearLength2\" value=\"100\" step=\"any\">\n                                <select id=\"clearLength2Unit\"><option value=\"mm\">mm<\/option><\/select>\n                            <\/div>\n                        <\/div>\n                    <\/div>\n                    <div class=\"form-group\">\n                        <label for=\"initialClearance\">Initial Clearance (optional)<\/label>\n                        <div class=\"input-with-unit\">\n                            <input type=\"number\" id=\"initialClearance\" value=\"0.5\" step=\"any\" min=\"0\">\n                            <select id=\"clearanceUnit\"><option value=\"mm\">mm<\/option><\/select>\n                        <\/div>\n                    <\/div>\n                    <h3 class=\"section-title\">Temperature<\/h3>\n                    <div class=\"input-grid\">\n                        <div class=\"form-group\">\n                            <label for=\"clearTemp1\">Initial Temperature (T\u2081)<\/label>\n                            <div class=\"input-with-unit\">\n                                <input type=\"number\" id=\"clearTemp1\" value=\"20\" step=\"any\">\n                                <select id=\"clearTempUnit\"><option value=\"C\">\u00b0C<\/option><\/select>\n                            <\/div>\n                        <\/div>\n                        <div class=\"form-group\">\n                            <label for=\"clearTemp2\">Final Temperature (T\u2082)<\/label>\n                            <div class=\"input-with-unit\">\n                                <input type=\"number\" id=\"clearTemp2\" value=\"80\" step=\"any\">\n                                <select id=\"clearTempUnit2\"><option value=\"C\">\u00b0C<\/option><\/select>\n                            <\/div>\n                        <\/div>\n                    <\/div>\n                <\/div>\n\n                <!-- Material Comparison -->\n                <div id=\"comparisonInputs\" class=\"hidden\">\n                    <h3 class=\"section-title\">Compare Materials (2\u20136)<\/h3>\n                    <div id=\"comparisonMaterialList\"><\/div>\n                    <button type=\"button\" class=\"btn-secondary btn-sm\" id=\"addComparisonMaterial\">+ Add Material<\/button>\n                    <div class=\"form-group\">\n                        <label for=\"comparisonLength\">Reference Length (L\u2080)<\/label>\n                        <div class=\"input-with-unit\">\n                            <input type=\"number\" id=\"comparisonLength\" value=\"1000\" step=\"any\">\n                            <select id=\"comparisonLengthUnit\"><option value=\"mm\">mm<\/option><\/select>\n                        <\/div>\n                    <\/div>\n                    <div class=\"input-grid\">\n                        <div class=\"form-group\">\n                            <label for=\"comparisonTemp1\">T\u2081<\/label>\n                            <input type=\"number\" id=\"comparisonTemp1\" value=\"20\">\n                        <\/div>\n                        <div class=\"form-group\">\n                            <label for=\"comparisonTemp2\">T\u2082<\/label>\n                            <input type=\"number\" id=\"comparisonTemp2\" value=\"100\">\n                        <\/div>\n                    <\/div>\n                    <div class=\"form-group\">\n                        <label for=\"comparisonRank\">Rank By<\/label>\n                        <select id=\"comparisonRank\">\n                            <option value=\"lowest\">Lowest Thermal Expansion<\/option>\n                            <option value=\"highest\">Highest Thermal Expansion<\/option>\n                        <\/select>\n                    <\/div>\n                <\/div>\n\n                <!-- Thermal Stress (Optional) -->\n                <details class=\"advanced-section\" id=\"stressSection\">\n                    <summary>Optional: Restrained Thermal Stress<\/summary>\n                    <div class=\"advanced-content\">\n                        <p class=\"hint\">\u03c3<sub>thermal<\/sub> = E \u00d7 \u03b1 \u00d7 \u0394T (fully restrained, linear elasticity)<\/p>\n                        <div class=\"input-grid\">\n                            <div class=\"form-group\">\n                                <label for=\"youngsModulus\">Young&#8217;s Modulus (E)<\/label>\n                                <div class=\"input-with-unit\">\n                                    <input type=\"number\" id=\"youngsModulus\" value=\"200\" step=\"any\">\n                                    <select id=\"modulusUnit\">\n                                        <option value=\"GPa\">GPa<\/option>\n                                        <option value=\"MPa\">MPa<\/option>\n                                        <option value=\"ksi\">ksi<\/option>\n                                    <\/select>\n                                <\/div>\n                            <\/div>\n                            <div class=\"form-group\">\n                                <label for=\"allowableStress\">Allowable Stress<\/label>\n                                <div class=\"input-with-unit\">\n                                    <input type=\"number\" id=\"allowableStress\" value=\"250\" step=\"any\">\n                                    <select id=\"stressUnit\">\n                                        <option value=\"MPa\">MPa<\/option>\n                                        <option value=\"GPa\">GPa<\/option>\n                                        <option value=\"ksi\">ksi<\/option>\n                                    <\/select>\n                                <\/div>\n                            <\/div>\n                            <div class=\"form-group\">\n                                <label for=\"restraintCondition\">Restraint Condition<\/label>\n                                <select id=\"restraintCondition\">\n                                    <option value=\"free\">Free Expansion<\/option>\n                                    <option value=\"full\">Fully Restrained<\/option>\n                                <\/select>\n                            <\/div>\n                        <\/div>\n                    <\/div>\n                <\/details>\n\n                <div class=\"button-group\">\n                    <button type=\"button\" class=\"btn-primary\" id=\"calculateBtn\">Calculate<\/button>\n                <\/div>\n            <\/section>\n\n            <!-- Results Panel -->\n            <section class=\"results-panel hidden\" id=\"resultsPanel\">\n                <div class=\"card results-card\" id=\"resultsCard\">\n                    <h2>Results<\/h2>\n                    <div id=\"errorMessages\" class=\"error-messages hidden\"><\/div>\n                    <div id=\"warningMessages\" class=\"warning-messages hidden\"><\/div>\n                    <div id=\"resultsContent\" class=\"results-grid\">\n                        <p class=\"placeholder-text\">Enter values and click Calculate to see results.<\/p>\n                    <\/div>\n                    <div id=\"interpretation\" class=\"interpretation hidden\"><\/div>\n                    <div id=\"recommendations\" class=\"recommendations hidden\"><\/div>\n                <\/div>\n\n            <\/section>\n        <\/main>\n    <\/div>\n    <\/div>\n<script>\n(function(){\nvar b=\"LyoqDQogKiBNYXRlcmlhbCBwcmVzZXRzIC0gYXBwcm94aW1hdGUgcmVmZXJlbmNlIHZhbHVlcyBhdCByb29tIHRlbXBlcmF0dXJlDQogKiBBbGwgdmFsdWVzIGVkaXRhYmxlIGJ5IHVzZXIuIFx1MDNiMSBpbiBcdTAwZDcxMFx1MjA3Ylx1MjA3Ni9cdTAwYjBDDQogKi8NCmNvbnN0IE1BVEVSSUFMUyA9IFsNCiAgICB7IGlkOiAnY2FyYm9uX3N0ZWVsJywgbmFtZTogJ0NhcmJvbiBTdGVlbCcsIGFscGhhOiAxMiwgYWxwaGFNaW46IDExLCBhbHBoYU1heDogMTMsIGNhdGVnb3J5OiAnU3RlZWwnIH0sDQogICAgeyBpZDogJ3N0YWlubGVzc19zdGVlbCcsIG5hbWU6ICdTdGFpbmxlc3MgU3RlZWwnLCBhbHBoYTogMTYuNSwgYWxwaGFNaW46IDE1LCBhbHBoYU1heDogMTgsIGNhdGVnb3J5OiAnU3RlZWwnIH0sDQogICAgeyBpZDogJ2Nhc3RfaXJvbicsIG5hbWU6ICdDYXN0IElyb24nLCBhbHBoYTogMTEsIGFscGhhTWluOiAxMCwgYWxwaGFNYXg6IDEyLCBjYXRlZ29yeTogJ0lyb24nIH0sDQogICAgeyBpZDogJ2FsdW1pbnVtJywgbmFtZTogJ0FsdW1pbnVtIEFsbG95JywgYWxwaGE6IDIzLCBhbHBoYU1pbjogMjIsIGFscGhhTWF4OiAyNCwgY2F0ZWdvcnk6ICdBbHVtaW51bScgfSwNCiAgICB7IGlkOiAnY29wcGVyJywgbmFtZTogJ0NvcHBlcicsIGFscGhhOiAxNi41LCBhbHBoYU1pbjogMTYsIGFscGhhTWF4OiAxNywgY2F0ZWdvcnk6ICdDb3BwZXInIH0sDQogICAgeyBpZDogJ2JyYXNzJywgbmFtZTogJ0JyYXNzJywgYWxwaGE6IDE5LCBhbHBoYU1pbjogMTgsIGFscGhhTWF4OiAyMCwgY2F0ZWdvcnk6ICdDb3BwZXInIH0sDQogICAgeyBpZDogJ3RpdGFuaXVtJywgbmFtZTogJ1RpdGFuaXVtJywgYWxwaGE6IDksIGFscGhhTWluOiA4LCBhbHBoYU1heDogMTAsIGNhdGVnb3J5OiAnVGl0YW5pdW0nIH0sDQogICAgeyBpZDogJ2ludmFyJywgbmFtZTogJ0ludmFyJywgYWxwaGE6IDEuNSwgYWxwaGFNaW46IDEsIGFscGhhTWF4OiAyLCBjYXRlZ29yeTogJ1NwZWNpYWwnIH0sDQogICAgeyBpZDogJ2dsYXNzJywgbmFtZTogJ0dsYXNzJywgYWxwaGE6IDYsIGFscGhhTWluOiAzLCBhbHBoYU1heDogOSwgY2F0ZWdvcnk6ICdDZXJhbWljJyB9LA0KICAgIHsgaWQ6ICdjb25jcmV0ZScsIG5hbWU6ICdDb25jcmV0ZScsIGFscGhhOiAxMCwgYWxwaGFNaW46IDgsIGFscGhhTWF4OiAxMiwgY2F0ZWdvcnk6ICdDb21wb3NpdGUnIH0sDQogICAgeyBpZDogJ2Jyb256ZScsIG5hbWU6ICdCcm9uemUnLCBhbHBoYTogMTgsIGFscGhhTWluOiAxNywgYWxwaGFNYXg6IDE5LCBjYXRlZ29yeTogJ0NvcHBlcicgfSwNCiAgICB7IGlkOiAnbmlja2VsJywgbmFtZTogJ05pY2tlbCcsIGFscGhhOiAxMywgYWxwaGFNaW46IDEyLCBhbHBoYU1heDogMTQsIGNhdGVnb3J5OiAnTmlja2VsJyB9LA0KICAgIHsgaWQ6ICd0dW5nc3RlbicsIG5hbWU6ICdUdW5nc3RlbicsIGFscGhhOiA0LjUsIGFscGhhTWluOiA0LCBhbHBoYU1heDogNSwgY2F0ZWdvcnk6ICdSZWZyYWN0b3J5JyB9LA0KICAgIHsgaWQ6ICdtYWduZXNpdW0nLCBuYW1lOiAnTWFnbmVzaXVtIEFsbG95JywgYWxwaGE6IDI2LCBhbHBoYU1pbjogMjQsIGFscGhhTWF4OiAyOCwgY2F0ZWdvcnk6ICdNYWduZXNpdW0nIH0sDQogICAgeyBpZDogJ3ppbmMnLCBuYW1lOiAnWmluYycsIGFscGhhOiAzMCwgYWxwaGFNaW46IDI4LCBhbHBoYU1heDogMzIsIGNhdGVnb3J5OiAnWmluYycgfSwNCiAgICB7IGlkOiAnbGVhZCcsIG5hbWU6ICdMZWFkJywgYWxwaGE6IDI5LCBhbHBoYU1pbjogMjgsIGFscGhhTWF4OiAzMCwgY2F0ZWdvcnk6ICdMZWFkJyB9LA0KICAgIHsgaWQ6ICdwdmMnLCBuYW1lOiAnUFZDIChQbGFzdGljKScsIGFscGhhOiA3MCwgYWxwaGFNaW46IDUwLCBhbHBoYU1heDogOTAsIGNhdGVnb3J5OiAnUGxhc3RpYycgfSwNCiAgICB7IGlkOiAnbnlsb24nLCBuYW1lOiAnTnlsb24gKFBBKScsIGFscGhhOiA4MCwgYWxwaGFNaW46IDcwLCBhbHBoYU1heDogOTAsIGNhdGVnb3J5OiAnUGxhc3RpYycgfSwNCiAgICB7IGlkOiAncHRmZScsIG5hbWU6ICdQVEZFIChUZWZsb24pJywgYWxwaGE6IDEzNSwgYWxwaGFNaW46IDEyMCwgYWxwaGFNYXg6IDE1MCwgY2F0ZWdvcnk6ICdQbGFzdGljJyB9LA0KICAgIHsgaWQ6ICdjZXJhbWljJywgbmFtZTogJ0FsdW1pbmEgQ2VyYW1pYycsIGFscGhhOiA3LCBhbHBoYU1pbjogNiwgYWxwaGFNYXg6IDgsIGNhdGVnb3J5OiAnQ2VyYW1pYycgfSwNCiAgICB7IGlkOiAnY3VzdG9tJywgbmFtZTogJ0N1c3RvbSBNYXRlcmlhbCcsIGFscGhhOiAxMiwgYWxwaGFNaW46IDAsIGFscGhhTWF4OiAyMDAsIGNhdGVnb3J5OiAnQ3VzdG9tJyB9DQpdOw0KDQovKiogWW91bmcncyBtb2R1bHVzIHByZXNldHMgKEdQYSkgZm9yIHRoZXJtYWwgc3RyZXNzICovDQpjb25zdCBNT0RVTFVTX1BSRVNFVFMgPSB7DQogICAgY2FyYm9uX3N0ZWVsOiAyMDAsDQogICAgc3RhaW5sZXNzX3N0ZWVsOiAxOTMsDQogICAgY2FzdF9pcm9uOiAxMTAsDQogICAgYWx1bWludW06IDY5LA0KICAgIGNvcHBlcjogMTE3LA0KICAgIGJyYXNzOiA5NywNCiAgICB0aXRhbml1bTogMTE2LA0KICAgIGludmFyOiAxNDEsDQogICAgZ2xhc3M6IDcwLA0KICAgIGNvbmNyZXRlOiAzMCwNCiAgICBjdXN0b206IDIwMA0KfTsNCg0KZnVuY3Rpb24gZ2V0TWF0ZXJpYWxCeUlkKGlkKSB7DQogICAgcmV0dXJuIE1BVEVSSUFMUy5maW5kKG0gPT4gbS5pZCA9PT0gaWQpIHx8IE1BVEVSSUFMU1swXTsNCn0NCg0KZnVuY3Rpb24gc2VhcmNoTWF0ZXJpYWxzKHF1ZXJ5KSB7DQogICAgY29uc3QgcSA9IChxdWVyeSB8fCAnJykudG9Mb3dlckNhc2UoKS50cmltKCk7DQogICAgaWYgKCFxKSByZXR1cm4gTUFURVJJQUxTOw0KICAgIHJldHVybiBNQVRFUklBTFMuZmlsdGVyKG0gPT4NCiAgICAgICAgbS5uYW1lLnRvTG93ZXJDYXNlKCkuaW5jbHVkZXMocSkgfHwNCiAgICAgICAgbS5jYXRlZ29yeS50b0xvd2VyQ2FzZSgpLmluY2x1ZGVzKHEpDQogICAgKTsNCn0NCg0KCgovKioNCiAqIFVuaXQgY29udmVyc2lvbiB1dGlsaXRpZXMNCiAqIEludGVybmFsIGJhc2UgdW5pdHM6IG1tLCBcdTAwYjBDLCBcdTAzYjEgaW4gMS9cdTAwYjBDDQogKi8NCmNvbnN0IFVuaXRzID0gew0KICAgIC8vIExlbmd0aCB0byBtbQ0KICAgIGxlbmd0aFRvTW06IHsNCiAgICAgICAgbW06IDEsDQogICAgICAgIHVtOiAwLjAwMSwNCiAgICAgICAgY206IDEwLA0KICAgICAgICBtOiAxMDAwLA0KICAgICAgICBpbjogMjUuNCwNCiAgICAgICAgZnQ6IDMwNC44DQogICAgfSwNCg0KICAgIC8vIEFyZWEgdG8gbW1cdTAwYjINCiAgICBhcmVhVG9NbTI6IHsNCiAgICAgICAgbW0yOiAxLA0KICAgICAgICBjbTI6IDEwMCwNCiAgICAgICAgbTI6IDFlNiwNCiAgICAgICAgaW4yOiA2NDUuMTYsDQogICAgICAgIGZ0MjogOTI5MDMuMDQNCiAgICB9LA0KDQogICAgLy8gVm9sdW1lIHRvIG1tXHUwMGIzDQogICAgdm9sdW1lVG9NbTM6IHsNCiAgICAgICAgbW0zOiAxLA0KICAgICAgICBjbTM6IDEwMDAsDQogICAgICAgIG0zOiAxZTksDQogICAgICAgIGluMzogMTYzODcuMDY0LA0KICAgICAgICBmdDM6IDI4MzE2ODQ2LjU5Mg0KICAgIH0sDQoNCiAgICAvKiogQ29udmVydCBhYnNvbHV0ZSB0ZW1wZXJhdHVyZSB0byBcdTAwYjBDICovDQogICAgdG9DZWxzaXVzKHRlbXAsIHVuaXQpIHsNCiAgICAgICAgc3dpdGNoICh1bml0KSB7DQogICAgICAgICAgICBjYXNlICdDJzogcmV0dXJuIHRlbXA7DQogICAgICAgICAgICBjYXNlICdGJzogcmV0dXJuICh0ZW1wIC0gMzIpICogNSAvIDk7DQogICAgICAgICAgICBjYXNlICdLJzogcmV0dXJuIHRlbXAgLSAyNzMuMTU7DQogICAgICAgICAgICBkZWZhdWx0OiByZXR1cm4gdGVtcDsNCiAgICAgICAgfQ0KICAgIH0sDQoNCiAgICAvKiogQ29udmVydCBcdTAwYjBDIHRvIGRpc3BsYXkgdW5pdCAqLw0KICAgIGZyb21DZWxzaXVzKHRlbXBDLCB1bml0KSB7DQogICAgICAgIHN3aXRjaCAodW5pdCkgew0KICAgICAgICAgICAgY2FzZSAnQyc6IHJldHVybiB0ZW1wQzsNCiAgICAgICAgICAgIGNhc2UgJ0YnOiByZXR1cm4gdGVtcEMgKiA5IC8gNSArIDMyOw0KICAgICAgICAgICAgY2FzZSAnSyc6IHJldHVybiB0ZW1wQyArIDI3My4xNTsNCiAgICAgICAgICAgIGRlZmF1bHQ6IHJldHVybiB0ZW1wQzsNCiAgICAgICAgfQ0KICAgIH0sDQoNCiAgICAvKiogVGVtcGVyYXR1cmUgZGlmZmVyZW5jZTogXHUwMzk0VChcdTAwYjBGKSA9IDEuOCBcdTAwZDcgXHUwMzk0VChcdTAwYjBDKSBcdTIwMTQgbm8gb2Zmc2V0ICovDQogICAgZGVsdGFUVG9DZWxzaXVzKGRlbHRhVCwgdW5pdCkgew0KICAgICAgICBzd2l0Y2ggKHVuaXQpIHsNCiAgICAgICAgICAgIGNhc2UgJ0MnOg0KICAgICAgICAgICAgY2FzZSAnSyc6DQogICAgICAgICAgICAgICAgcmV0dXJuIGRlbHRhVDsNCiAgICAgICAgICAgIGNhc2UgJ0YnOg0KICAgICAgICAgICAgICAgIHJldHVybiBkZWx0YVQgLyAxLjg7DQogICAgICAgICAgICBkZWZhdWx0Og0KICAgICAgICAgICAgICAgIHJldHVybiBkZWx0YVQ7DQogICAgICAgIH0NCiAgICB9LA0KDQogICAgZnJvbUNlbHNpdXNEZWx0YShkZWx0YVRDLCB1bml0KSB7DQogICAgICAgIHN3aXRjaCAodW5pdCkgew0KICAgICAgICAgICAgY2FzZSAnQyc6DQogICAgICAgICAgICBjYXNlICdLJzoNCiAgICAgICAgICAgICAgICByZXR1cm4gZGVsdGFUQzsNCiAgICAgICAgICAgIGNhc2UgJ0YnOg0KICAgICAgICAgICAgICAgIHJldHVybiBkZWx0YVRDICogMS44Ow0KICAgICAgICAgICAgZGVmYXVsdDoNCiAgICAgICAgICAgICAgICByZXR1cm4gZGVsdGFUQzsNCiAgICAgICAgfQ0KICAgIH0sDQoNCiAgICAvKiogXHUwM2IxIHRvIGludGVybmFsIDEvXHUwMGIwQyAqLw0KICAgIGFscGhhVG9QZXJDKGFscGhhLCB1bml0KSB7DQogICAgICAgIHN3aXRjaCAodW5pdCkgew0KICAgICAgICAgICAgY2FzZSAnMWUtNl9wZXJfQyc6DQogICAgICAgICAgICAgICAgcmV0dXJuIGFscGhhICogMWUtNjsNCiAgICAgICAgICAgIGNhc2UgJ3Blcl9DJzoNCiAgICAgICAgICAgICAgICByZXR1cm4gYWxwaGE7DQogICAgICAgICAgICBjYXNlICd1bV9wZXJfbV9DJzoNCiAgICAgICAgICAgICAgICByZXR1cm4gYWxwaGEgKiAxZS02Ow0KICAgICAgICAgICAgY2FzZSAncGVyX0YnOg0KICAgICAgICAgICAgICAgIHJldHVybiBhbHBoYSAvIDEuODsNCiAgICAgICAgICAgIGRlZmF1bHQ6DQogICAgICAgICAgICAgICAgcmV0dXJuIGFscGhhICogMWUtNjsNCiAgICAgICAgfQ0KICAgIH0sDQoNCiAgICAvKiogMS9cdTAwYjBDIHRvIGRpc3BsYXkgKi8NCiAgICBhbHBoYUZyb21QZXJDKGFscGhhUGVyQywgdW5pdCkgew0KICAgICAgICBzd2l0Y2ggKHVuaXQpIHsNCiAgICAgICAgICAgIGNhc2UgJzFlLTZfcGVyX0MnOg0KICAgICAgICAgICAgICAgIHJldHVybiBhbHBoYVBlckMgLyAxZS02Ow0KICAgICAgICAgICAgY2FzZSAncGVyX0MnOg0KICAgICAgICAgICAgICAgIHJldHVybiBhbHBoYVBlckM7DQogICAgICAgICAgICBjYXNlICd1bV9wZXJfbV9DJzoNCiAgICAgICAgICAgICAgICByZXR1cm4gYWxwaGFQZXJDIC8gMWUtNjsNCiAgICAgICAgICAgIGNhc2UgJ3Blcl9GJzoNCiAgICAgICAgICAgICAgICByZXR1cm4gYWxwaGFQZXJDICogMS44Ow0KICAgICAgICAgICAgZGVmYXVsdDoNCiAgICAgICAgICAgICAgICByZXR1cm4gYWxwaGFQZXJDIC8gMWUtNjsNCiAgICAgICAgfQ0KICAgIH0sDQoNCiAgICBjb252ZXJ0TGVuZ3RoKHZhbHVlLCBmcm9tVW5pdCwgdG9Vbml0KSB7DQogICAgICAgIGNvbnN0IG1tID0gdmFsdWUgKiAodGhpcy5sZW5ndGhUb01tW2Zyb21Vbml0XSB8fCAxKTsNCiAgICAgICAgcmV0dXJuIG1tIC8gKHRoaXMubGVuZ3RoVG9NbVt0b1VuaXRdIHx8IDEpOw0KICAgIH0sDQoNCiAgICBjb252ZXJ0QXJlYSh2YWx1ZSwgZnJvbVVuaXQsIHRvVW5pdCkgew0KICAgICAgICBjb25zdCBtbTIgPSB2YWx1ZSAqICh0aGlzLmFyZWFUb01tMltmcm9tVW5pdF0gfHwgMSk7DQogICAgICAgIHJldHVybiBtbTIgLyAodGhpcy5hcmVhVG9NbTJbdG9Vbml0XSB8fCAxKTsNCiAgICB9LA0KDQogICAgY29udmVydFZvbHVtZSh2YWx1ZSwgZnJvbVVuaXQsIHRvVW5pdCkgew0KICAgICAgICBjb25zdCBtbTMgPSB2YWx1ZSAqICh0aGlzLnZvbHVtZVRvTW0zW2Zyb21Vbml0XSB8fCAxKTsNCiAgICAgICAgcmV0dXJuIG1tMyAvICh0aGlzLnZvbHVtZVRvTW0zW3RvVW5pdF0gfHwgMSk7DQogICAgfSwNCg0KICAgIC8qKiBTdHJlc3MgdG8gTVBhICovDQogICAgc3RyZXNzVG9NUGEodmFsdWUsIHVuaXQpIHsNCiAgICAgICAgc3dpdGNoICh1bml0KSB7DQogICAgICAgICAgICBjYXNlICdHUGEnOiByZXR1cm4gdmFsdWUgKiAxMDAwOw0KICAgICAgICAgICAgY2FzZSAnTVBhJzogcmV0dXJuIHZhbHVlOw0KICAgICAgICAgICAgY2FzZSAna3NpJzogcmV0dXJuIHZhbHVlICogNi44OTQ3NjsNCiAgICAgICAgICAgIGRlZmF1bHQ6IHJldHVybiB2YWx1ZTsNCiAgICAgICAgfQ0KICAgIH0sDQoNCiAgICAvKiogTVBhIHRvIGRpc3BsYXkgdW5pdCAqLw0KICAgIHN0cmVzc0Zyb21NUGEodmFsdWUsIHVuaXQpIHsNCiAgICAgICAgc3dpdGNoICh1bml0KSB7DQogICAgICAgICAgICBjYXNlICdHUGEnOiByZXR1cm4gdmFsdWUgLyAxMDAwOw0KICAgICAgICAgICAgY2FzZSAnTVBhJzogcmV0dXJuIHZhbHVlOw0KICAgICAgICAgICAgY2FzZSAna3NpJzogcmV0dXJuIHZhbHVlIC8gNi44OTQ3NjsNCiAgICAgICAgICAgIGRlZmF1bHQ6IHJldHVybiB2YWx1ZTsNCiAgICAgICAgfQ0KICAgIH0sDQoNCiAgICAvKiogR2V0IGRlZmF1bHQgdW5pdHMgZm9yIG1ldHJpYy9pbXBlcmlhbCAqLw0KICAgIGdldERlZmF1bHRzKHN5c3RlbSkgew0KICAgICAgICBpZiAoc3lzdGVtID09PSAnaW1wZXJpYWwnKSB7DQogICAgICAgICAgICByZXR1cm4gew0KICAgICAgICAgICAgICAgIGxlbmd0aDogJ2luJywNCiAgICAgICAgICAgICAgICBhcmVhOiAnaW4yJywNCiAgICAgICAgICAgICAgICB2b2x1bWU6ICdpbjMnLA0KICAgICAgICAgICAgICAgIHRlbXA6ICdGJywNCiAgICAgICAgICAgICAgICBhbHBoYTogJ3Blcl9GJywNCiAgICAgICAgICAgICAgICBkZWx0YUw6ICdpbicsDQogICAgICAgICAgICAgICAgc3RyZXNzOiAna3NpJywNCiAgICAgICAgICAgICAgICBtb2R1bHVzOiAna3NpJw0KICAgICAgICAgICAgfTsNCiAgICAgICAgfQ0KICAgICAgICByZXR1cm4gew0KICAgICAgICAgICAgbGVuZ3RoOiAnbW0nLA0KICAgICAgICAgICAgYXJlYTogJ21tMicsDQogICAgICAgICAgICB2b2x1bWU6ICdtbTMnLA0KICAgICAgICAgICAgdGVtcDogJ0MnLA0KICAgICAgICAgICAgYWxwaGE6ICcxZS02X3Blcl9DJywNCiAgICAgICAgICAgIGRlbHRhTDogJ21tJywNCiAgICAgICAgICAgIHN0cmVzczogJ01QYScsDQogICAgICAgICAgICBtb2R1bHVzOiAnR1BhJw0KICAgICAgICB9Ow0KICAgIH0sDQoNCiAgICBmb3JtYXROdW1iZXIodmFsdWUsIGRlY2ltYWxzID0gNCkgew0KICAgICAgICBpZiAodmFsdWUgPT09IG51bGwgfHwgdmFsdWUgPT09IHVuZGVmaW5lZCB8fCBpc05hTih2YWx1ZSkpIHJldHVybiAnLSc7DQogICAgICAgIGlmIChNYXRoLmFicyh2YWx1ZSkgPj0gMWU2IHx8IChNYXRoLmFicyh2YWx1ZSkgPCAwLjAwMDEgJiYgdmFsdWUgIT09IDApKSB7DQogICAgICAgICAgICByZXR1cm4gdmFsdWUudG9FeHBvbmVudGlhbChkZWNpbWFscyk7DQogICAgICAgIH0NCiAgICAgICAgY29uc3QgYWJzID0gTWF0aC5hYnModmFsdWUpOw0KICAgICAgICBsZXQgZCA9IGRlY2ltYWxzOw0KICAgICAgICBpZiAoYWJzID49IDEwMDApIGQgPSAyOw0KICAgICAgICBlbHNlIGlmIChhYnMgPj0gMTAwKSBkID0gMzsNCiAgICAgICAgZWxzZSBpZiAoYWJzID49IDEpIGQgPSA0Ow0KICAgICAgICBlbHNlIGlmIChhYnMgPj0gMC4wMSkgZCA9IDU7DQogICAgICAgIGVsc2UgZCA9IDY7DQogICAgICAgIHJldHVybiBwYXJzZUZsb2F0KHZhbHVlLnRvRml4ZWQoZCkpLnRvU3RyaW5nKCk7DQogICAgfSwNCg0KICAgIGxlbmd0aExhYmVsKHVuaXQpIHsNCiAgICAgICAgY29uc3QgbGFiZWxzID0geyBtbTogJ21tJywgdW06ICdcdTAwYjVtJywgY206ICdjbScsIG06ICdtJywgaW46ICdpbicsIGZ0OiAnZnQnIH07DQogICAgICAgIHJldHVybiBsYWJlbHNbdW5pdF0gfHwgdW5pdDsNCiAgICB9LA0KDQogICAgdGVtcExhYmVsKHVuaXQpIHsNCiAgICAgICAgY29uc3QgbGFiZWxzID0geyBDOiAnXHUwMGIwQycsIEY6ICdcdTAwYjBGJywgSzogJ0snIH07DQogICAgICAgIHJldHVybiBsYWJlbHNbdW5pdF0gfHwgdW5pdDsNCiAgICB9DQp9Ow0KDQoKCi8qKg0KICogVGhlcm1hbCBFeHBhbnNpb24gQ2FsY3VsYXRpb24gRW5naW5lDQogKi8NCmNvbnN0IFRoZXJtYWxFbmdpbmUgPSB7DQogICAgLyoqDQogICAgICogQ2FsY3VsYXRlIGVmZmVjdGl2ZSBcdTAzYjEgY29uc2lkZXJpbmcgcGllY2V3aXNlIG9yIGF2ZXJhZ2UgbW9kZXMNCiAgICAgKi8NCiAgICBnZXRFZmZlY3RpdmVBbHBoYShwYXJhbXMpIHsNCiAgICAgICAgY29uc3QgeyBhbHBoYVBlckMsIGFscGhhTW9kZSwgdGVtcDFDLCB0ZW1wMkMsIHBpZWNld2lzZURhdGEgfSA9IHBhcmFtczsNCiAgICAgICAgY29uc3QgZGVsdGFUID0gdGVtcDJDIC0gdGVtcDFDOw0KDQogICAgICAgIGlmIChhbHBoYU1vZGUgPT09ICdwaWVjZXdpc2UnICYmIHBpZWNld2lzZURhdGEgJiYgcGllY2V3aXNlRGF0YS5sZW5ndGggPj0gMikgew0KICAgICAgICAgICAgY29uc3Qgc29ydGVkID0gWy4uLnBpZWNld2lzZURhdGFdLnNvcnQoKGEsIGIpID0+IGEudGVtcCAtIGIudGVtcCk7DQogICAgICAgICAgICBsZXQgdG90YWxTdHJhaW4gPSAwOw0KICAgICAgICAgICAgY29uc3QgdE1pbiA9IE1hdGgubWluKHRlbXAxQywgdGVtcDJDKTsNCiAgICAgICAgICAgIGNvbnN0IHRNYXggPSBNYXRoLm1heCh0ZW1wMUMsIHRlbXAyQyk7DQogICAgICAgICAgICBjb25zdCBzaWduID0gZGVsdGFUID49IDAgPyAxIDogLTE7DQoNCiAgICAgICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgc29ydGVkLmxlbmd0aCAtIDE7IGkrKykgew0KICAgICAgICAgICAgICAgIGNvbnN0IHNlZ1N0YXJ0ID0gc29ydGVkW2ldLnRlbXA7DQogICAgICAgICAgICAgICAgY29uc3Qgc2VnRW5kID0gc29ydGVkW2kgKyAxXS50ZW1wOw0KICAgICAgICAgICAgICAgIGNvbnN0IGFscGhhID0gc29ydGVkW2ldLmFscGhhICogMWUtNjsNCg0KICAgICAgICAgICAgICAgIGNvbnN0IG92ZXJsYXBTdGFydCA9IE1hdGgubWF4KHNlZ1N0YXJ0LCB0TWluKTsNCiAgICAgICAgICAgICAgICBjb25zdCBvdmVybGFwRW5kID0gTWF0aC5taW4oc2VnRW5kLCB0TWF4KTsNCiAgICAgICAgICAgICAgICBpZiAob3ZlcmxhcEVuZCA+IG92ZXJsYXBTdGFydCkgew0KICAgICAgICAgICAgICAgICAgICB0b3RhbFN0cmFpbiArPSBhbHBoYSAqIChvdmVybGFwRW5kIC0gb3ZlcmxhcFN0YXJ0KSAqIHNpZ247DQogICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgfQ0KICAgICAgICAgICAgcmV0dXJuIE1hdGguYWJzKGRlbHRhVCkgPiAwID8gdG90YWxTdHJhaW4gLyBkZWx0YVQgOiBhbHBoYVBlckM7DQogICAgICAgIH0NCg0KICAgICAgICBpZiAoYWxwaGFNb2RlID09PSAnYXZlcmFnZScpIHsNCiAgICAgICAgICAgIC8vIFNpbXBsZSBhdmVyYWdlOiB1c2UgbWlkcG9pbnQgXHUwM2IxIGFkanVzdG1lbnQgKGFwcHJveGltYXRpb24pDQogICAgICAgICAgICByZXR1cm4gYWxwaGFQZXJDOw0KICAgICAgICB9DQoNCiAgICAgICAgcmV0dXJuIGFscGhhUGVyQzsNCiAgICB9LA0KDQogICAgLyoqIExpbmVhciBleHBhbnNpb246IFx1MDM5NEwgPSBcdTAzYjEgXHUwMGQ3IExcdTIwODAgXHUwMGQ3IFx1MDM5NFQgKi8NCiAgICBsaW5lYXJFeHBhbnNpb24oTDBtbSwgYWxwaGFQZXJDLCBkZWx0YVRDLCBtZXRob2QgPSAnZW5naW5lZXJpbmcnKSB7DQogICAgICAgIGlmIChtZXRob2QgPT09ICdnZW9tZXRyaWMnKSB7DQogICAgICAgICAgICBjb25zdCBmYWN0b3IgPSAxICsgYWxwaGFQZXJDICogZGVsdGFUQzsNCiAgICAgICAgICAgIGNvbnN0IEwyID0gTDBtbSAqIGZhY3RvcjsNCiAgICAgICAgICAgIHJldHVybiB7IGRlbHRhTDogTDIgLSBMMG1tLCBMMiwgc3RyYWluOiBhbHBoYVBlckMgKiBkZWx0YVRDIH07DQogICAgICAgIH0NCiAgICAgICAgY29uc3QgZGVsdGFMID0gYWxwaGFQZXJDICogTDBtbSAqIGRlbHRhVEM7DQogICAgICAgIGNvbnN0IEwyID0gTDBtbSArIGRlbHRhTDsNCiAgICAgICAgY29uc3Qgc3RyYWluID0gTDBtbSA+IDAgPyBkZWx0YUwgLyBMMG1tIDogMDsNCiAgICAgICAgcmV0dXJuIHsgZGVsdGFMLCBMMiwgc3RyYWluIH07DQogICAgfSwNCg0KICAgIC8qKiBSZXZlcnNlOiBcdTAzOTRUIGZyb20gXHUwMzk0TCAqLw0KICAgIHRlbXBlcmF0dXJlRnJvbUV4cGFuc2lvbihkZWx0YUxtbSwgTDBtbSwgYWxwaGFQZXJDKSB7DQogICAgICAgIGNvbnN0IGRlbm9tID0gYWxwaGFQZXJDICogTDBtbTsNCiAgICAgICAgaWYgKE1hdGguYWJzKGRlbm9tKSA8IDFlLTE1KSByZXR1cm4gbnVsbDsNCiAgICAgICAgcmV0dXJuIGRlbHRhTG1tIC8gZGVub207DQogICAgfSwNCg0KICAgIC8qKiBSZXZlcnNlOiBcdTAzYjEgZnJvbSBcdTAzOTRMICovDQogICAgYWxwaGFGcm9tRXhwYW5zaW9uKGRlbHRhTG1tLCBMMG1tLCBkZWx0YVRDKSB7DQogICAgICAgIGNvbnN0IGRlbm9tID0gTDBtbSAqIGRlbHRhVEM7DQogICAgICAgIGlmIChNYXRoLmFicyhkZW5vbSkgPCAxZS0xNSkgcmV0dXJuIG51bGw7DQogICAgICAgIHJldHVybiBkZWx0YUxtbSAvIGRlbm9tOw0KICAgIH0sDQoNCiAgICAvKiogUmV2ZXJzZTogTFx1MjA4MCBmcm9tIFx1MDM5NEwgKi8NCiAgICBvcmlnaW5hbExlbmd0aEZyb21FeHBhbnNpb24oZGVsdGFMbW0sIGFscGhhUGVyQywgZGVsdGFUQykgew0KICAgICAgICBjb25zdCBkZW5vbSA9IGFscGhhUGVyQyAqIGRlbHRhVEM7DQogICAgICAgIGlmIChNYXRoLmFicyhkZW5vbSkgPCAxZS0xNSkgcmV0dXJuIG51bGw7DQogICAgICAgIHJldHVybiBkZWx0YUxtbSAvIGRlbm9tOw0KICAgIH0sDQoNCiAgICAvKiogTFx1MjA4MCBmcm9tIExcdTIwODIgKi8NCiAgICBvcmlnaW5hbExlbmd0aEZyb21GaW5hbChMMm1tLCBhbHBoYVBlckMsIGRlbHRhVEMsIG1ldGhvZCA9ICdlbmdpbmVlcmluZycpIHsNCiAgICAgICAgaWYgKG1ldGhvZCA9PT0gJ2dlb21ldHJpYycpIHsNCiAgICAgICAgICAgIGNvbnN0IGZhY3RvciA9IDEgKyBhbHBoYVBlckMgKiBkZWx0YVRDOw0KICAgICAgICAgICAgaWYgKE1hdGguYWJzKGZhY3RvcikgPCAxZS0xNSkgcmV0dXJuIG51bGw7DQogICAgICAgICAgICByZXR1cm4gTDJtbSAvIGZhY3RvcjsNCiAgICAgICAgfQ0KICAgICAgICByZXR1cm4gTDJtbSAtIGFscGhhUGVyQyAqIEwybW0gKiBkZWx0YVRDIC8gKDEgKyBhbHBoYVBlckMgKiBkZWx0YVRDKTsNCiAgICB9LA0KDQogICAgLyoqIEFyZWEgZXhwYW5zaW9uICovDQogICAgYXJlYUV4cGFuc2lvbihBMG1tMiwgYWxwaGFQZXJDLCBkZWx0YVRDLCBtZXRob2QgPSAnZW5naW5lZXJpbmcnKSB7DQogICAgICAgIGlmIChtZXRob2QgPT09ICdnZW9tZXRyaWMnKSB7DQogICAgICAgICAgICBjb25zdCBmYWN0b3IgPSBNYXRoLnBvdygxICsgYWxwaGFQZXJDICogZGVsdGFUQywgMik7DQogICAgICAgICAgICBjb25zdCBBMiA9IEEwbW0yICogZmFjdG9yOw0KICAgICAgICAgICAgcmV0dXJuIHsgZGVsdGFBOiBBMiAtIEEwbW0yLCBBMiwgYmV0YTogMiAqIGFscGhhUGVyQyB9Ow0KICAgICAgICB9DQogICAgICAgIGNvbnN0IGJldGEgPSAyICogYWxwaGFQZXJDOw0KICAgICAgICBjb25zdCBkZWx0YUEgPSBiZXRhICogQTBtbTIgKiBkZWx0YVRDOw0KICAgICAgICBjb25zdCBBMiA9IEEwbW0yICsgZGVsdGFBOw0KICAgICAgICByZXR1cm4geyBkZWx0YUEsIEEyLCBiZXRhIH07DQogICAgfSwNCg0KICAgIC8qKiBWb2x1bWUgZXhwYW5zaW9uICovDQogICAgdm9sdW1lRXhwYW5zaW9uKFYwbW0zLCBhbHBoYVBlckMsIGRlbHRhVEMsIG1ldGhvZCA9ICdlbmdpbmVlcmluZycpIHsNCiAgICAgICAgaWYgKG1ldGhvZCA9PT0gJ2dlb21ldHJpYycpIHsNCiAgICAgICAgICAgIGNvbnN0IGZhY3RvciA9IE1hdGgucG93KDEgKyBhbHBoYVBlckMgKiBkZWx0YVRDLCAzKTsNCiAgICAgICAgICAgIGNvbnN0IFYyID0gVjBtbTMgKiBmYWN0b3I7DQogICAgICAgICAgICByZXR1cm4geyBkZWx0YVY6IFYyIC0gVjBtbTMsIFYyLCBnYW1tYTogMyAqIGFscGhhUGVyQyB9Ow0KICAgICAgICB9DQogICAgICAgIGNvbnN0IGdhbW1hID0gMyAqIGFscGhhUGVyQzsNCiAgICAgICAgY29uc3QgZGVsdGFWID0gZ2FtbWEgKiBWMG1tMyAqIGRlbHRhVEM7DQogICAgICAgIGNvbnN0IFYyID0gVjBtbTMgKyBkZWx0YVY7DQogICAgICAgIHJldHVybiB7IGRlbHRhViwgVjIsIGdhbW1hIH07DQogICAgfSwNCg0KICAgIC8qKiBUaGVybWFsIHN0cmFpbiBmb3JtYXRzICovDQogICAgZm9ybWF0U3RyYWluKHN0cmFpbikgew0KICAgICAgICByZXR1cm4gew0KICAgICAgICAgICAgZGltZW5zaW9ubGVzczogc3RyYWluLA0KICAgICAgICAgICAgbWljcm9zdHJhaW46IHN0cmFpbiAqIDFlNiwNCiAgICAgICAgICAgIHBlcmNlbnQ6IHN0cmFpbiAqIDEwMA0KICAgICAgICB9Ow0KICAgIH0sDQoNCiAgICAvKiogUmVsYXRpdmUgZXhwYW5zaW9uIGZvciBjbGVhcmFuY2U6IFx1MDM5NExfcmVsID0gKFx1MDNiMVx1MjA4MUxcdTIwODEgLSBcdTAzYjFcdTIwODJMXHUyMDgyKSBcdTAwZDcgXHUwMzk0VCAqLw0KICAgIHJlbGF0aXZlRXhwYW5zaW9uKGFscGhhMSwgTDFtbSwgYWxwaGEyLCBMMm1tLCBkZWx0YVRDKSB7DQogICAgICAgIGNvbnN0IGV4cGFuc2lvbjEgPSBhbHBoYTEgKiBMMW1tICogZGVsdGFUQzsNCiAgICAgICAgY29uc3QgZXhwYW5zaW9uMiA9IGFscGhhMiAqIEwybW0gKiBkZWx0YVRDOw0KICAgICAgICBjb25zdCByZWxhdGl2ZSA9IGV4cGFuc2lvbjEgLSBleHBhbnNpb24yOw0KICAgICAgICByZXR1cm4gew0KICAgICAgICAgICAgZXhwYW5zaW9uMSwNCiAgICAgICAgICAgIGV4cGFuc2lvbjIsDQogICAgICAgICAgICByZWxhdGl2ZSwNCiAgICAgICAgICAgIGNsZWFyYW5jZVJlcXVpcmVkOiBNYXRoLm1heCgwLCByZWxhdGl2ZSkNCiAgICAgICAgfTsNCiAgICB9LA0KDQogICAgLyoqIENsZWFyYW5jZSBjaGVjayB3aXRoIGluaXRpYWwgY2xlYXJhbmNlICovDQogICAgY2xlYXJhbmNlQ2hlY2socmVsYXRpdmVFeHBhbnNpb24sIGluaXRpYWxDbGVhcmFuY2VNbSkgew0KICAgICAgICBjb25zdCByZW1haW5pbmcgPSBpbml0aWFsQ2xlYXJhbmNlTW0gLSByZWxhdGl2ZUV4cGFuc2lvbjsNCiAgICAgICAgbGV0IHN0YXR1cywgc3RhdHVzQ2xhc3M7DQogICAgICAgIGlmIChyZW1haW5pbmcgPD0gMCkgew0KICAgICAgICAgICAgc3RhdHVzID0gJ0ludGVyZmVyZW5jZSBSaXNrJzsNCiAgICAgICAgICAgIHN0YXR1c0NsYXNzID0gJ2NsZWFyYW5jZS1pbnRlcmZlcmVuY2UnOw0KICAgICAgICB9IGVsc2UgaWYgKHJlbWFpbmluZyA8IGluaXRpYWxDbGVhcmFuY2VNbSAqIDAuMSkgew0KICAgICAgICAgICAgc3RhdHVzID0gJ05lYXIgQ29udGFjdCc7DQogICAgICAgICAgICBzdGF0dXNDbGFzcyA9ICdjbGVhcmFuY2UtbmVhcic7DQogICAgICAgIH0gZWxzZSBpZiAocmVtYWluaW5nIDwgaW5pdGlhbENsZWFyYW5jZU1tICogMC41KSB7DQogICAgICAgICAgICBzdGF0dXMgPSAnUmVkdWNlZCBDbGVhcmFuY2UnOw0KICAgICAgICAgICAgc3RhdHVzQ2xhc3MgPSAnY2xlYXJhbmNlLXJlZHVjZWQnOw0KICAgICAgICB9IGVsc2Ugew0KICAgICAgICAgICAgc3RhdHVzID0gJ1NhZmUgQ2xlYXJhbmNlJzsNCiAgICAgICAgICAgIHN0YXR1c0NsYXNzID0gJ2NsZWFyYW5jZS1zYWZlJzsNCiAgICAgICAgfQ0KICAgICAgICByZXR1cm4geyByZW1haW5pbmcsIHN0YXR1cywgc3RhdHVzQ2xhc3MgfTsNCiAgICB9LA0KDQogICAgLyoqIFJlc3RyYWluZWQgdGhlcm1hbCBzdHJlc3M6IFx1MDNjMyA9IEUgXHUwMGQ3IFx1MDNiMSBcdTAwZDcgXHUwMzk0VCAqLw0KICAgIHRoZXJtYWxTdHJlc3MoRV9HUGEsIGFscGhhUGVyQywgZGVsdGFUQykgew0KICAgICAgICBjb25zdCBFX01QYSA9IEVfR1BhICogMTAwMDsNCiAgICAgICAgcmV0dXJuIEVfTVBhICogYWxwaGFQZXJDICogZGVsdGFUQzsNCiAgICB9LA0KDQogICAgLyoqIE1hdGVyaWFsIGNvbXBhcmlzb24gKi8NCiAgICBjb21wYXJlTWF0ZXJpYWxzKG1hdGVyaWFscywgTDBtbSwgZGVsdGFUQywgbWV0aG9kID0gJ2VuZ2luZWVyaW5nJykgew0KICAgICAgICBjb25zdCByZXN1bHRzID0gbWF0ZXJpYWxzLm1hcCgobWF0LCBpbmRleCkgPT4gew0KICAgICAgICAgICAgY29uc3QgYWxwaGEgPSBtYXQuYWxwaGEgKiAxZS02Ow0KICAgICAgICAgICAgY29uc3QgeyBkZWx0YUwsIEwyLCBzdHJhaW4gfSA9IHRoaXMubGluZWFyRXhwYW5zaW9uKEwwbW0sIGFscGhhLCBkZWx0YVRDLCBtZXRob2QpOw0KICAgICAgICAgICAgcmV0dXJuIHsNCiAgICAgICAgICAgICAgICBpbmRleCwNCiAgICAgICAgICAgICAgICBuYW1lOiBtYXQubmFtZSwNCiAgICAgICAgICAgICAgICBhbHBoYTogbWF0LmFscGhhLA0KICAgICAgICAgICAgICAgIGFscGhhUGVyQzogYWxwaGEsDQogICAgICAgICAgICAgICAgZGVsdGFMLA0KICAgICAgICAgICAgICAgIEwyLA0KICAgICAgICAgICAgICAgIHN0cmFpbiwNCiAgICAgICAgICAgICAgICBzdHJhaW5Gb3JtYXR0ZWQ6IHRoaXMuZm9ybWF0U3RyYWluKHN0cmFpbikNCiAgICAgICAgICAgIH07DQogICAgICAgIH0pOw0KDQogICAgICAgIHJlc3VsdHMuc29ydCgoYSwgYikgPT4gYS5kZWx0YUwgLSBiLmRlbHRhTCk7DQogICAgICAgIHJlc3VsdHMuZm9yRWFjaCgociwgaSkgPT4geyByLnJhbmsgPSBpICsgMTsgfSk7DQoNCiAgICAgICAgY29uc3QgYmFzZWxpbmUgPSByZXN1bHRzWzBdPy5kZWx0YUwgfHwgMDsNCiAgICAgICAgcmVzdWx0cy5mb3JFYWNoKHIgPT4gew0KICAgICAgICAgICAgci5yZWxhdGl2ZUV4cGFuc2lvbiA9IHIuZGVsdGFMIC0gYmFzZWxpbmU7DQogICAgICAgIH0pOw0KDQogICAgICAgIHJldHVybiByZXN1bHRzOw0KICAgIH0sDQoNCiAgICAvKiogVmFsaWRhdGUgaW5wdXRzICovDQogICAgdmFsaWRhdGUocGFyYW1zKSB7DQogICAgICAgIGNvbnN0IGVycm9ycyA9IFtdOw0KICAgICAgICBjb25zdCB3YXJuaW5ncyA9IFtdOw0KDQogICAgICAgIGlmIChwYXJhbXMuTDBtbSAhPT0gdW5kZWZpbmVkICYmIHBhcmFtcy5MMG1tIDw9IDApIHsNCiAgICAgICAgICAgIGVycm9ycy5wdXNoKCdPcmlnaW5hbCBkaW1lbnNpb24gbXVzdCBiZSBncmVhdGVyIHRoYW4gemVyby4nKTsNCiAgICAgICAgfQ0KICAgICAgICBpZiAocGFyYW1zLkEwbW0yICE9PSB1bmRlZmluZWQgJiYgcGFyYW1zLkEwbW0yIDw9IDApIHsNCiAgICAgICAgICAgIGVycm9ycy5wdXNoKCdPcmlnaW5hbCBhcmVhIG11c3QgYmUgZ3JlYXRlciB0aGFuIHplcm8uJyk7DQogICAgICAgIH0NCiAgICAgICAgaWYgKHBhcmFtcy5WMG1tMyAhPT0gdW5kZWZpbmVkICYmIHBhcmFtcy5WMG1tMyA8PSAwKSB7DQogICAgICAgICAgICBlcnJvcnMucHVzaCgnT3JpZ2luYWwgdm9sdW1lIG11c3QgYmUgZ3JlYXRlciB0aGFuIHplcm8uJyk7DQogICAgICAgIH0NCiAgICAgICAgaWYgKHBhcmFtcy5hbHBoYVBlckMgIT09IHVuZGVmaW5lZCAmJiAoaXNOYU4ocGFyYW1zLmFscGhhUGVyQykgfHwgcGFyYW1zLmFscGhhUGVyQyA9PT0gMCkpIHsNCiAgICAgICAgICAgIGVycm9ycy5wdXNoKCdUaGVybWFsIGV4cGFuc2lvbiBjb2VmZmljaWVudCBtdXN0IGJlIGEgdmFsaWQgbm9uLXplcm8gdmFsdWUuJyk7DQogICAgICAgIH0NCg0KICAgICAgICBpZiAocGFyYW1zLmRlbHRhVEMgIT09IHVuZGVmaW5lZCAmJiBNYXRoLmFicyhwYXJhbXMuZGVsdGFUQykgPiA1MDApIHsNCiAgICAgICAgICAgIHdhcm5pbmdzLnB1c2goJ0xhcmdlIHRlbXBlcmF0dXJlIGNoYW5nZSBkZXRlY3RlZC4gQSBjb25zdGFudCBhbHBoYSBtYXkgbm90IGJlIHN1aXRhYmxlIC0gY29uc2lkZXIgdGVtcGVyYXR1cmUtZGVwZW5kZW50IGNvZWZmaWNpZW50IG1vZGUuJyk7DQogICAgICAgIH0NCg0KICAgICAgICBpZiAocGFyYW1zLm1hdGVyaWFsICYmIHBhcmFtcy50ZW1wMUMgIT09IHVuZGVmaW5lZCkgew0KICAgICAgICAgICAgaWYgKHBhcmFtcy50ZW1wMUMgPCAtMjAwIHx8IHBhcmFtcy50ZW1wMkMgPiAxMDAwKSB7DQogICAgICAgICAgICAgICAgd2FybmluZ3MucHVzaCgnVGVtcGVyYXR1cmUgZXhjZWVkcyB0eXBpY2FsIHZhbGlkIHJhbmdlIGZvciBtYXRlcmlhbCBwcmVzZXQuIFZlcmlmeSBtYXRlcmlhbCBkYXRhLicpOw0KICAgICAgICAgICAgfQ0KICAgICAgICB9DQoNCiAgICAgICAgcmV0dXJuIHsgZXJyb3JzLCB3YXJuaW5ncyB9Ow0KICAgIH0sDQoNCiAgICAvKiogR2VuZXJhdGUgaW50ZXJwcmV0YXRpb24gbWVzc2FnZXMgKi8NCiAgICBpbnRlcnByZXQocmVzdWx0cykgew0KICAgICAgICBjb25zdCBtZXNzYWdlcyA9IFtdOw0KICAgICAgICBjb25zdCBkZWx0YUwgPSByZXN1bHRzLmRlbHRhTDsNCg0KICAgICAgICBpZiAoZGVsdGFMICE9PSB1bmRlZmluZWQpIHsNCiAgICAgICAgICAgIGlmIChkZWx0YUwgPiAwKSB7DQogICAgICAgICAgICAgICAgbWVzc2FnZXMucHVzaCgnUG9zaXRpdmUgZGltZW5zaW9uYWwgY2hhbmdlIGluZGljYXRlcyB0aGVybWFsIGV4cGFuc2lvbi4nKTsNCiAgICAgICAgICAgIH0gZWxzZSBpZiAoZGVsdGFMIDwgMCkgew0KICAgICAgICAgICAgICAgIG1lc3NhZ2VzLnB1c2goJ05lZ2F0aXZlIGRpbWVuc2lvbmFsIGNoYW5nZSBpbmRpY2F0ZXMgdGhlcm1hbCBjb250cmFjdGlvbi4nKTsNCiAgICAgICAgICAgIH0NCg0KICAgICAgICAgICAgY29uc3QgYWJzRGVsdGFMID0gTWF0aC5hYnMoZGVsdGFMKTsNCiAgICAgICAgICAgIGNvbnN0IEwwID0gcmVzdWx0cy5MMG1tIHx8IDE7DQogICAgICAgICAgICBpZiAoYWJzRGVsdGFMIC8gTDAgPiAwLjAwMSkgew0KICAgICAgICAgICAgICAgIG1lc3NhZ2VzLnB1c2goJ0xhcmdlIHRoZXJtYWwgZ3Jvd3RoIGRldGVjdGVkIC0gYWRkaXRpb25hbCBhc3NlbWJseSBjbGVhcmFuY2UgbWF5IGJlIHJlcXVpcmVkLicpOw0KICAgICAgICAgICAgfQ0KICAgICAgICB9DQoNCiAgICAgICAgaWYgKHJlc3VsdHMuZGVsdGFUQyAhPT0gdW5kZWZpbmVkICYmIE1hdGguYWJzKHJlc3VsdHMuZGVsdGFUQykgPiAxMDApIHsNCiAgICAgICAgICAgIG1lc3NhZ2VzLnB1c2goJ1NpZ25pZmljYW50IHRlbXBlcmF0dXJlIGNoYW5nZSAtIGRpZmZlcmVudGlhbCB0aGVybWFsIGV4cGFuc2lvbiBiZXR3ZWVuIGRpc3NpbWlsYXIgbWF0ZXJpYWxzIHNob3VsZCBiZSBldmFsdWF0ZWQuJyk7DQogICAgICAgIH0NCg0KICAgICAgICBpZiAocmVzdWx0cy5hbHBoYVBlckMgIT09IHVuZGVmaW5lZCAmJiByZXN1bHRzLmFscGhhUGVyQyA8IDVlLTYpIHsNCiAgICAgICAgICAgIG1lc3NhZ2VzLnB1c2goJ0xvdy1leHBhbnNpb24gbWF0ZXJpYWwgLSBwcmVmZXJhYmxlIGZvciBwcmVjaXNpb24gZGltZW5zaW9uYWwgc3RhYmlsaXR5LicpOw0KICAgICAgICB9DQoNCiAgICAgICAgcmV0dXJuIG1lc3NhZ2VzOw0KICAgIH0sDQoNCiAgICAvKiogR2VuZXJhdGUgcmVjb21tZW5kYXRpb25zICovDQogICAgcmVjb21tZW5kKHJlc3VsdHMsIG1vZGUpIHsNCiAgICAgICAgY29uc3QgcmVjcyA9IFtdOw0KDQogICAgICAgIGlmIChNYXRoLmFicyhyZXN1bHRzLmRlbHRhTCB8fCAwKSA+IDAuMSkgew0KICAgICAgICAgICAgcmVjcy5wdXNoKCdQcm92aWRlIHN1ZmZpY2llbnQgdGhlcm1hbCBjbGVhcmFuY2UgZm9yIG1vdmluZyBvciBzbGlkaW5nIHBhcnRzLicpOw0KICAgICAgICB9DQoNCiAgICAgICAgcmVjcy5wdXNoKCdDb25zaWRlciBkaWZmZXJlbnRpYWwgdGhlcm1hbCBleHBhbnNpb24gd2hlbiBqb2luaW5nIGRpc3NpbWlsYXIgbWF0ZXJpYWxzLicpOw0KDQogICAgICAgIGlmIChyZXN1bHRzLmFscGhhUGVyQyAmJiByZXN1bHRzLmFscGhhUGVyQyA+IDIwZS02KSB7DQogICAgICAgICAgICByZWNzLnB1c2goJ0hpZ2gtZXhwYW5zaW9uIG1hdGVyaWFsIC0gaW5jbHVkZSBleHBhbnNpb24gam9pbnRzIGluIGxvbmcgc3RydWN0dXJhbCBvciBwaXBpbmcgc3lzdGVtcy4nKTsNCiAgICAgICAgfQ0KDQogICAgICAgIGlmIChtb2RlID09PSAnY2xlYXJhbmNlJyAmJiByZXN1bHRzLmNsZWFyYW5jZVN0YXR1cyA9PT0gJ0ludGVyZmVyZW5jZSBSaXNrJykgew0KICAgICAgICAgICAgcmVjcy5wdXNoKCdJbnRlcmZlcmVuY2UgcmlzayBkZXRlY3RlZCAtIGluY3JlYXNlIGluaXRpYWwgY2xlYXJhbmNlIG9yIHNlbGVjdCBsb3dlci1leHBhbnNpb24gbWF0ZXJpYWxzLicpOw0KICAgICAgICB9DQoNCiAgICAgICAgcmVjcy5wdXNoKCdDaGVjayBiZWFyaW5nLCBzaGFmdCwgYW5kIGhvdXNpbmcgZml0cyBhdCBvcGVyYXRpbmcgdGVtcGVyYXR1cmUuJyk7DQogICAgICAgIHJlY3MucHVzaCgnVXNlIHRlbXBlcmF0dXJlLWRlcGVuZGVudCBtYXRlcmlhbCBkYXRhIHdoZW4gdGhlIHRlbXBlcmF0dXJlIHJhbmdlIGlzIGxhcmdlLicpOw0KDQogICAgICAgIHJldHVybiByZWNzLnNsaWNlKDAsIDUpOw0KICAgIH0NCn07DQoNCgoKLyoqDQogKiBUaGVybWFsIEV4cGFuc2lvbiBDYWxjdWxhdG9yIC0gTWFpbiBBcHBsaWNhdGlvbg0KICovDQooZnVuY3Rpb24gKCkgew0KICAgICd1c2Ugc3RyaWN0JzsNCg0KICAgIGNvbnN0IHN0YXRlID0gew0KICAgICAgICB1bml0U3lzdGVtOiAnbWV0cmljJywNCiAgICAgICAgbW9kZTogJ2xpbmVhcicsDQogICAgICAgIGxhc3RSZXN1bHRzOiBudWxsLA0KICAgICAgICBjb21wYXJpc29uTWF0ZXJpYWxzOiBbXQ0KICAgIH07DQoNCiAgICBjb25zdCBERUZBVUxUUyA9IHsNCiAgICAgICAgbW9kZTogJ2xpbmVhcicsDQogICAgICAgIG1hdGVyaWFsOiAnY2FyYm9uX3N0ZWVsJywNCiAgICAgICAgbGVuZ3RoOiAxMDAwLA0KICAgICAgICB0ZW1wMTogMjAsDQogICAgICAgIHRlbXAyOiA4MCwNCiAgICAgICAgYWxwaGE6IDEyDQogICAgfTsNCg0KICAgIC8vIERPTSByZWZzIFx1MjAxNCBwcmVmZXIgbm9kZXMgaW5zaWRlIGNhbGN1bGF0b3Igcm9vdA0KICAgIGNvbnN0ICQgPSBpZCA9PiBkb2N1bWVudC5nZXRFbGVtZW50QnlJZChpZCk7DQogICAgY29uc3Qgcm9vdCA9ICgpID0+IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCd0aGVybWFsLWV4cGFuc2lvbi1jYWxjdWxhdG9yJyk7DQogICAgY29uc3QgJCQgPSAoc2VsKSA9PiAocm9vdCgpIHx8IGRvY3VtZW50KS5xdWVyeVNlbGVjdG9yQWxsKHNlbCk7DQoNCiAgICBmdW5jdGlvbiBpbml0KCkgew0KICAgICAgICBwb3B1bGF0ZU1hdGVyaWFsU2VsZWN0KCk7DQogICAgICAgIGluaXRDb21wYXJpc29uTWF0ZXJpYWxzKCk7DQogICAgICAgIGluaXRQaWVjZXdpc2VSb3dzKCk7DQogICAgICAgIGJpbmRFdmVudHMoKTsNCiAgICAgICAgYXBwbHlVbml0U3lzdGVtKCdtZXRyaWMnKTsNCiAgICAgICAgdXBkYXRlSW5wdXRWaXNpYmlsaXR5KCk7DQogICAgfQ0KDQogICAgZnVuY3Rpb24gcG9wdWxhdGVNYXRlcmlhbFNlbGVjdChmaWx0ZXIpIHsNCiAgICAgICAgY29uc3Qgc2VsZWN0ID0gJCgnbWF0ZXJpYWxTZWxlY3QnKTsNCiAgICAgICAgY29uc3QgbWF0ZXJpYWxzID0gc2VhcmNoTWF0ZXJpYWxzKGZpbHRlciB8fCAnJyk7DQogICAgICAgIHNlbGVjdC5pbm5lckhUTUwgPSBtYXRlcmlhbHMubWFwKG0gPT4NCiAgICAgICAgICAgIGA8b3B0aW9uIHZhbHVlPSIke20uaWR9Ij4ke20ubmFtZX0gKCR7bS5hbHBoYU1pbn1cdTIwMTMke20uYWxwaGFNYXh9IFx1MDBkNzEwXHUyMDdiXHUyMDc2L1x1MDBiMEMpPC9vcHRpb24+YA0KICAgICAgICApLmpvaW4oJycpOw0KICAgICAgICBzZWxlY3QudmFsdWUgPSBERUZBVUxUUy5tYXRlcmlhbDsNCiAgICB9DQoNCiAgICBmdW5jdGlvbiBpbml0Q29tcGFyaXNvbk1hdGVyaWFscygpIHsNCiAgICAgICAgc3RhdGUuY29tcGFyaXNvbk1hdGVyaWFscyA9IFsNCiAgICAgICAgICAgIHsgaWQ6ICdjYXJib25fc3RlZWwnLCBuYW1lOiAnQ2FyYm9uIFN0ZWVsJywgYWxwaGE6IDEyIH0sDQogICAgICAgICAgICB7IGlkOiAnYWx1bWludW0nLCBuYW1lOiAnQWx1bWludW0gQWxsb3knLCBhbHBoYTogMjMgfSwNCiAgICAgICAgICAgIHsgaWQ6ICdzdGFpbmxlc3Nfc3RlZWwnLCBuYW1lOiAnU3RhaW5sZXNzIFN0ZWVsJywgYWxwaGE6IDE2LjUgfQ0KICAgICAgICBdOw0KICAgICAgICByZW5kZXJDb21wYXJpc29uTWF0ZXJpYWxzKCk7DQogICAgfQ0KDQogICAgZnVuY3Rpb24gcmVuZGVyQ29tcGFyaXNvbk1hdGVyaWFscygpIHsNCiAgICAgICAgY29uc3QgY29udGFpbmVyID0gJCgnY29tcGFyaXNvbk1hdGVyaWFsTGlzdCcpOw0KICAgICAgICBjb250YWluZXIuaW5uZXJIVE1MID0gc3RhdGUuY29tcGFyaXNvbk1hdGVyaWFscy5tYXAoKG1hdCwgaSkgPT4gYA0KICAgICAgICAgICAgPGRpdiBjbGFzcz0iY29tcGFyaXNvbi1yb3ciIGRhdGEtaW5kZXg9IiR7aX0iPg0KICAgICAgICAgICAgICAgIDxzZWxlY3QgY2xhc3M9ImNvbXAtbWF0ZXJpYWwtc2VsZWN0IiBkYXRhLWluZGV4PSIke2l9Ij4NCiAgICAgICAgICAgICAgICAgICAgJHtNQVRFUklBTFMuZmlsdGVyKG0gPT4gbS5pZCAhPT0gJ2N1c3RvbScpLm1hcChtID0+DQogICAgICAgICAgICAgICAgICAgICAgICBgPG9wdGlvbiB2YWx1ZT0iJHttLmlkfSIgJHttLmlkID09PSBtYXQuaWQgPyAnc2VsZWN0ZWQnIDogJyd9PiR7bS5uYW1lfTwvb3B0aW9uPmANCiAgICAgICAgICAgICAgICAgICAgKS5qb2luKCcnKX0NCiAgICAgICAgICAgICAgICA8L3NlbGVjdD4NCiAgICAgICAgICAgICAgICA8aW5wdXQgdHlwZT0ibnVtYmVyIiBjbGFzcz0iY29tcC1hbHBoYSIgZGF0YS1pbmRleD0iJHtpfSIgdmFsdWU9IiR7bWF0LmFscGhhfSIgc3RlcD0iYW55IiB0aXRsZT0iXHUwM2IxIFx1MDBkNzEwXHUyMDdiXHUyMDc2L1x1MDBiMEMiPg0KICAgICAgICAgICAgICAgIDxidXR0b24gdHlwZT0iYnV0dG9uIiBjbGFzcz0icmVtb3ZlLWJ0biBjb21wLXJlbW92ZSIgZGF0YS1pbmRleD0iJHtpfSIgJHtzdGF0ZS5jb21wYXJpc29uTWF0ZXJpYWxzLmxlbmd0aCA8PSAyID8gJ2Rpc2FibGVkJyA6ICcnfT5cdTAwZDc8L2J1dHRvbj4NCiAgICAgICAgICAgIDwvZGl2Pg0KICAgICAgICBgKS5qb2luKCcnKTsNCg0KICAgICAgICBjb250YWluZXIucXVlcnlTZWxlY3RvckFsbCgnLmNvbXAtbWF0ZXJpYWwtc2VsZWN0JykuZm9yRWFjaChzZWwgPT4gew0KICAgICAgICAgICAgc2VsLmFkZEV2ZW50TGlzdGVuZXIoJ2NoYW5nZScsIGUgPT4gew0KICAgICAgICAgICAgICAgIGNvbnN0IGlkeCA9ICtlLnRhcmdldC5kYXRhc2V0LmluZGV4Ow0KICAgICAgICAgICAgICAgIGNvbnN0IG1hdCA9IGdldE1hdGVyaWFsQnlJZChlLnRhcmdldC52YWx1ZSk7DQogICAgICAgICAgICAgICAgc3RhdGUuY29tcGFyaXNvbk1hdGVyaWFsc1tpZHhdID0geyBpZDogbWF0LmlkLCBuYW1lOiBtYXQubmFtZSwgYWxwaGE6IG1hdC5hbHBoYSB9Ow0KICAgICAgICAgICAgICAgIHJlbmRlckNvbXBhcmlzb25NYXRlcmlhbHMoKTsNCiAgICAgICAgICAgIH0pOw0KICAgICAgICB9KTsNCiAgICAgICAgY29udGFpbmVyLnF1ZXJ5U2VsZWN0b3JBbGwoJy5jb21wLWFscGhhJykuZm9yRWFjaChpbnAgPT4gew0KICAgICAgICAgICAgaW5wLmFkZEV2ZW50TGlzdGVuZXIoJ2lucHV0JywgZSA9PiB7DQogICAgICAgICAgICAgICAgc3RhdGUuY29tcGFyaXNvbk1hdGVyaWFsc1srZS50YXJnZXQuZGF0YXNldC5pbmRleF0uYWxwaGEgPSBwYXJzZUZsb2F0KGUudGFyZ2V0LnZhbHVlKSB8fCAwOw0KICAgICAgICAgICAgfSk7DQogICAgICAgIH0pOw0KICAgICAgICBjb250YWluZXIucXVlcnlTZWxlY3RvckFsbCgnLmNvbXAtcmVtb3ZlJykuZm9yRWFjaChidG4gPT4gew0KICAgICAgICAgICAgYnRuLmFkZEV2ZW50TGlzdGVuZXIoJ2NsaWNrJywgZSA9PiB7DQogICAgICAgICAgICAgICAgY29uc3QgaWR4ID0gK2UudGFyZ2V0LmRhdGFzZXQuaW5kZXg7DQogICAgICAgICAgICAgICAgaWYgKHN0YXRlLmNvbXBhcmlzb25NYXRlcmlhbHMubGVuZ3RoID4gMikgew0KICAgICAgICAgICAgICAgICAgICBzdGF0ZS5jb21wYXJpc29uTWF0ZXJpYWxzLnNwbGljZShpZHgsIDEpOw0KICAgICAgICAgICAgICAgICAgICByZW5kZXJDb21wYXJpc29uTWF0ZXJpYWxzKCk7DQogICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgfSk7DQogICAgICAgIH0pOw0KICAgIH0NCg0KICAgIGZ1bmN0aW9uIGluaXRQaWVjZXdpc2VSb3dzKCkgew0KICAgICAgICBjb25zdCBjb250YWluZXIgPSAkKCdwaWVjZXdpc2VSb3dzJyk7DQogICAgICAgIGNvbnN0IGRlZmF1bHRzID0gWw0KICAgICAgICAgICAgeyB0ZW1wOiAyMCwgYWxwaGE6IDEyIH0sDQogICAgICAgICAgICB7IHRlbXA6IDEwMCwgYWxwaGE6IDEyLjUgfSwNCiAgICAgICAgICAgIHsgdGVtcDogMjAwLCBhbHBoYTogMTMgfSwNCiAgICAgICAgICAgIHsgdGVtcDogNDAwLCBhbHBoYTogMTMuNSB9DQogICAgICAgIF07DQogICAgICAgIGNvbnRhaW5lci5pbm5lckhUTUwgPSBkZWZhdWx0cy5tYXAoKHJvdywgaSkgPT4gcGllY2V3aXNlUm93SFRNTChyb3csIGkpKS5qb2luKCcnKTsNCiAgICB9DQoNCiAgICBmdW5jdGlvbiBwaWVjZXdpc2VSb3dIVE1MKHJvdywgaW5kZXgpIHsNCiAgICAgICAgcmV0dXJuIGANCiAgICAgICAgICAgIDxkaXYgY2xhc3M9InBpZWNld2lzZS1yb3ciIGRhdGEtaW5kZXg9IiR7aW5kZXh9Ij4NCiAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPSJmb3JtLWdyb3VwIj4NCiAgICAgICAgICAgICAgICAgICAgPGxhYmVsPlQgKFx1MDBiMEMpPC9sYWJlbD4NCiAgICAgICAgICAgICAgICAgICAgPGlucHV0IHR5cGU9Im51bWJlciIgY2xhc3M9InB3LXRlbXAiIHZhbHVlPSIke3Jvdy50ZW1wfSIgc3RlcD0iYW55Ij4NCiAgICAgICAgICAgICAgICA8L2Rpdj4NCiAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPSJmb3JtLWdyb3VwIj4NCiAgICAgICAgICAgICAgICAgICAgPGxhYmVsPlx1MDNiMSAoXHUwMGQ3MTBcdTIwN2JcdTIwNzYvXHUwMGIwQyk8L2xhYmVsPg0KICAgICAgICAgICAgICAgICAgICA8aW5wdXQgdHlwZT0ibnVtYmVyIiBjbGFzcz0icHctYWxwaGEiIHZhbHVlPSIke3Jvdy5hbHBoYX0iIHN0ZXA9ImFueSI+DQogICAgICAgICAgICAgICAgPC9kaXY+DQogICAgICAgICAgICAgICAgPGJ1dHRvbiB0eXBlPSJidXR0b24iIGNsYXNzPSJyZW1vdmUtYnRuIHB3LXJlbW92ZSI+XHUwMGQ3PC9idXR0b24+DQogICAgICAgICAgICA8L2Rpdj4NCiAgICAgICAgYDsNCiAgICB9DQoNCiAgICBmdW5jdGlvbiBnZXRQaWVjZXdpc2VEYXRhKCkgew0KICAgICAgICBjb25zdCByb3dzID0gJCgncGllY2V3aXNlUm93cycpLnF1ZXJ5U2VsZWN0b3JBbGwoJy5waWVjZXdpc2Utcm93Jyk7DQogICAgICAgIHJldHVybiBBcnJheS5mcm9tKHJvd3MpLm1hcChyb3cgPT4gKHsNCiAgICAgICAgICAgIHRlbXA6IHBhcnNlRmxvYXQocm93LnF1ZXJ5U2VsZWN0b3IoJy5wdy10ZW1wJykudmFsdWUpIHx8IDAsDQogICAgICAgICAgICBhbHBoYTogcGFyc2VGbG9hdChyb3cucXVlcnlTZWxlY3RvcignLnB3LWFscGhhJykudmFsdWUpIHx8IDANCiAgICAgICAgfSkpOw0KICAgIH0NCg0KICAgIGZ1bmN0aW9uIGJpbmRFdmVudHMoKSB7DQogICAgICAgICQoJ2NhbGN1bGF0ZUJ0bicpLmFkZEV2ZW50TGlzdGVuZXIoJ2NsaWNrJywgY2FsY3VsYXRlKTsNCg0KICAgICAgICAkKCdjYWxjTW9kZScpLmFkZEV2ZW50TGlzdGVuZXIoJ2NoYW5nZScsIGUgPT4gew0KICAgICAgICAgICAgc3RhdGUubW9kZSA9IGUudGFyZ2V0LnZhbHVlOw0KICAgICAgICAgICAgdXBkYXRlSW5wdXRWaXNpYmlsaXR5KCk7DQogICAgICAgIH0pOw0KDQogICAgICAgICQkKCcudG9nZ2xlLWJ0bicpLmZvckVhY2goYnRuID0+IHsNCiAgICAgICAgICAgIGJ0bi5hZGRFdmVudExpc3RlbmVyKCdjbGljaycsICgpID0+IHsNCiAgICAgICAgICAgICAgICAkJCgnLnRvZ2dsZS1idG4nKS5mb3JFYWNoKGIgPT4gYi5jbGFzc0xpc3QucmVtb3ZlKCdhY3RpdmUnKSk7DQogICAgICAgICAgICAgICAgYnRuLmNsYXNzTGlzdC5hZGQoJ2FjdGl2ZScpOw0KICAgICAgICAgICAgICAgIGFwcGx5VW5pdFN5c3RlbShidG4uZGF0YXNldC5zeXN0ZW0pOw0KICAgICAgICAgICAgfSk7DQogICAgICAgIH0pOw0KDQogICAgICAgICQkKCcuY2hhcnQtdGFiJykuZm9yRWFjaCh0YWIgPT4gew0KICAgICAgICAgICAgdGFiLmFkZEV2ZW50TGlzdGVuZXIoJ2NsaWNrJywgKCkgPT4gew0KICAgICAgICAgICAgICAgICQkKCcuY2hhcnQtdGFiJykuZm9yRWFjaCh0ID0+IHQuY2xhc3NMaXN0LnJlbW92ZSgnYWN0aXZlJykpOw0KICAgICAgICAgICAgICAgIHRhYi5jbGFzc0xpc3QuYWRkKCdhY3RpdmUnKTsNCiAgICAgICAgICAgIH0pOw0KICAgICAgICB9KTsNCg0KICAgICAgICAkKCdtYXRlcmlhbFNlbGVjdCcpLmFkZEV2ZW50TGlzdGVuZXIoJ2NoYW5nZScsIG9uTWF0ZXJpYWxDaGFuZ2UpOw0KICAgICAgICAkKCdtYXRlcmlhbFNlYXJjaCcpLmFkZEV2ZW50TGlzdGVuZXIoJ2lucHV0JywgZSA9PiBwb3B1bGF0ZU1hdGVyaWFsU2VsZWN0KGUudGFyZ2V0LnZhbHVlKSk7DQoNCiAgICAgICAgJCgnYWxwaGFNb2RlJykuYWRkRXZlbnRMaXN0ZW5lcignY2hhbmdlJywgZSA9PiB7DQogICAgICAgICAgICAkKCdwaWVjZXdpc2VBbHBoYUNvbnRhaW5lcicpLmNsYXNzTGlzdC50b2dnbGUoJ2hpZGRlbicsIGUudGFyZ2V0LnZhbHVlICE9PSAncGllY2V3aXNlJyk7DQogICAgICAgIH0pOw0KDQogICAgICAgICQoJ2FkZFBpZWNld2lzZVJvdycpLmFkZEV2ZW50TGlzdGVuZXIoJ2NsaWNrJywgKCkgPT4gew0KICAgICAgICAgICAgY29uc3QgY29udGFpbmVyID0gJCgncGllY2V3aXNlUm93cycpOw0KICAgICAgICAgICAgY29uc3QgaWR4ID0gY29udGFpbmVyLmNoaWxkcmVuLmxlbmd0aDsNCiAgICAgICAgICAgIGNvbnRhaW5lci5pbnNlcnRBZGphY2VudEhUTUwoJ2JlZm9yZWVuZCcsIHBpZWNld2lzZVJvd0hUTUwoeyB0ZW1wOiAwLCBhbHBoYTogMTIgfSwgaWR4KSk7DQogICAgICAgIH0pOw0KDQogICAgICAgICQoJ2FkZENvbXBhcmlzb25NYXRlcmlhbCcpLmFkZEV2ZW50TGlzdGVuZXIoJ2NsaWNrJywgKCkgPT4gew0KICAgICAgICAgICAgaWYgKHN0YXRlLmNvbXBhcmlzb25NYXRlcmlhbHMubGVuZ3RoIDwgNikgew0KICAgICAgICAgICAgICAgIHN0YXRlLmNvbXBhcmlzb25NYXRlcmlhbHMucHVzaCh7IGlkOiAnY29wcGVyJywgbmFtZTogJ0NvcHBlcicsIGFscGhhOiAxNi41IH0pOw0KICAgICAgICAgICAgICAgIHJlbmRlckNvbXBhcmlzb25NYXRlcmlhbHMoKTsNCiAgICAgICAgICAgIH0NCiAgICAgICAgfSk7DQoNCiAgICAgICAgLy8gU3luYyB0ZW1wIHVuaXQgc2VsZWN0b3JzICsgVFx1MjA4MiB1bml0IGxhYmVsDQogICAgICAgICQoJ3RlbXBVbml0JykuYWRkRXZlbnRMaXN0ZW5lcignY2hhbmdlJywgZSA9PiB7DQogICAgICAgICAgICBpZiAoJCgndGVtcFVuaXQyJykpICQoJ3RlbXBVbml0MicpLnZhbHVlID0gZS50YXJnZXQudmFsdWU7DQogICAgICAgICAgICBjb25zdCBsYWJlbCA9ICQoJ3RlbXAyVW5pdExhYmVsJyk7DQogICAgICAgICAgICBpZiAobGFiZWwpIHsNCiAgICAgICAgICAgICAgICBjb25zdCBtYXAgPSB7IEM6ICdcdTAwYjBDJywgRjogJ1x1MDBiMEYnLCBLOiAnSycgfTsNCiAgICAgICAgICAgICAgICBsYWJlbC50ZXh0Q29udGVudCA9IG1hcFtlLnRhcmdldC52YWx1ZV0gfHwgJ1x1MDBiMEMnOw0KICAgICAgICAgICAgfQ0KICAgICAgICB9KTsNCiAgICB9DQoNCiAgICBmdW5jdGlvbiBvbk1hdGVyaWFsQ2hhbmdlKCkgew0KICAgICAgICBjb25zdCBtYXQgPSBnZXRNYXRlcmlhbEJ5SWQoJCgnbWF0ZXJpYWxTZWxlY3QnKS52YWx1ZSk7DQogICAgICAgICQoJ2FscGhhJykudmFsdWUgPSBtYXQuYWxwaGE7DQogICAgICAgIGNvbnN0IG1vZHVsdXMgPSBNT0RVTFVTX1BSRVNFVFNbbWF0LmlkXTsNCiAgICAgICAgaWYgKG1vZHVsdXMpICQoJ3lvdW5nc01vZHVsdXMnKS52YWx1ZSA9IG1vZHVsdXM7DQogICAgfQ0KDQogICAgZnVuY3Rpb24gYXBwbHlVbml0U3lzdGVtKHN5c3RlbSkgew0KICAgICAgICBzdGF0ZS51bml0U3lzdGVtID0gc3lzdGVtOw0KICAgICAgICBjb25zdCBkZWZzID0gVW5pdHMuZ2V0RGVmYXVsdHMoc3lzdGVtKTsNCg0KICAgICAgICAkKCdsZW5ndGhVbml0JykudmFsdWUgPSBkZWZzLmxlbmd0aDsNCiAgICAgICAgJCgnZmluYWxMZW5ndGhVbml0JykudmFsdWUgPSBkZWZzLmxlbmd0aDsNCiAgICAgICAgJCgnZGVsdGFMVW5pdCcpLnZhbHVlID0gZGVmcy5kZWx0YUw7DQogICAgICAgICQoJ2FyZWFVbml0JykudmFsdWUgPSBkZWZzLmFyZWE7DQogICAgICAgICQoJ3ZvbHVtZVVuaXQnKS52YWx1ZSA9IGRlZnMudm9sdW1lOw0KICAgICAgICAkKCd0ZW1wVW5pdCcpLnZhbHVlID0gZGVmcy50ZW1wOw0KICAgICAgICAkKCd0ZW1wVW5pdDInKS52YWx1ZSA9IGRlZnMudGVtcDsNCiAgICAgICAgJCgnZGVsdGFUVW5pdCcpLnZhbHVlID0gZGVmcy50ZW1wOw0KICAgICAgICAkKCdhbHBoYVVuaXQnKS52YWx1ZSA9IGRlZnMuYWxwaGE7DQogICAgICAgICQoJ21vZHVsdXNVbml0JykudmFsdWUgPSBkZWZzLm1vZHVsdXM7DQogICAgICAgICQoJ3N0cmVzc1VuaXQnKS52YWx1ZSA9IGRlZnMuc3RyZXNzOw0KDQogICAgICAgIGNvbnN0IHQyTGFiZWwgPSAkKCd0ZW1wMlVuaXRMYWJlbCcpOw0KICAgICAgICBpZiAodDJMYWJlbCkgew0KICAgICAgICAgICAgY29uc3QgbWFwID0geyBDOiAnXHUwMGIwQycsIEY6ICdcdTAwYjBGJywgSzogJ0snIH07DQogICAgICAgICAgICB0MkxhYmVsLnRleHRDb250ZW50ID0gbWFwW2RlZnMudGVtcF0gfHwgJ1x1MDBiMEMnOw0KICAgICAgICB9DQoNCiAgICAgICAgWydjbGVhckxlbmd0aFVuaXQnLCAnY2xlYXJMZW5ndGgyVW5pdCcsICdjbGVhcmFuY2VVbml0JywgJ2NvbXBhcmlzb25MZW5ndGhVbml0J10uZm9yRWFjaChpZCA9PiB7DQogICAgICAgICAgICBjb25zdCBlbCA9ICQoaWQpOw0KICAgICAgICAgICAgaWYgKGVsKSBlbC52YWx1ZSA9IGRlZnMubGVuZ3RoOw0KICAgICAgICB9KTsNCiAgICAgICAgWydjbGVhclRlbXBVbml0JywgJ2NsZWFyVGVtcFVuaXQyJ10uZm9yRWFjaChpZCA9PiB7DQogICAgICAgICAgICBjb25zdCBlbCA9ICQoaWQpOw0KICAgICAgICAgICAgaWYgKGVsKSBlbC52YWx1ZSA9IGRlZnMudGVtcDsNCiAgICAgICAgfSk7DQogICAgfQ0KDQogICAgZnVuY3Rpb24gdXBkYXRlSW5wdXRWaXNpYmlsaXR5KCkgew0KICAgICAgICBjb25zdCBtb2RlID0gJCgnY2FsY01vZGUnKS52YWx1ZTsNCiAgICAgICAgc3RhdGUubW9kZSA9IG1vZGU7DQoNCiAgICAgICAgY29uc3Qgc2hvdyA9IHsNCiAgICAgICAgICAgIGFscGhhOiBbJ2xpbmVhcicsICdmaW5hbExlbmd0aCcsICdhcmVhJywgJ3ZvbHVtZScsICdjb2VmZmljaWVudCddLmluY2x1ZGVzKG1vZGUpLA0KICAgICAgICAgICAgbGVuZ3RoOiBbJ2xpbmVhcicsICdmaW5hbExlbmd0aCcsICd0ZW1wQ2hhbmdlJywgJ2NvZWZmaWNpZW50JywgJ2FyZWEnLCAndm9sdW1lJ10uaW5jbHVkZXMobW9kZSksDQogICAgICAgICAgICBhcmVhOiBtb2RlID09PSAnYXJlYScsDQogICAgICAgICAgICB2b2x1bWU6IG1vZGUgPT09ICd2b2x1bWUnLA0KICAgICAgICAgICAgdGVtcDE6ICFbJ2NvZWZmaWNpZW50J10uaW5jbHVkZXMobW9kZSkgfHwgbW9kZSA9PT0gJ2xpbmVhcicsDQogICAgICAgICAgICB0ZW1wMjogWydsaW5lYXInLCAnZmluYWxMZW5ndGgnLCAnYXJlYScsICd2b2x1bWUnLCAnY2xlYXJhbmNlJ10uaW5jbHVkZXMobW9kZSkgfHwgbW9kZSA9PT0gJ2xpbmVhcicsDQogICAgICAgICAgICBkZWx0YUw6IFsndGVtcENoYW5nZScsICdjb2VmZmljaWVudCddLmluY2x1ZGVzKG1vZGUpLA0KICAgICAgICAgICAgZmluYWxMZW5ndGg6IG1vZGUgPT09ICdmaW5hbExlbmd0aCcsDQogICAgICAgICAgICBkZWx0YVQ6IGZhbHNlDQogICAgICAgIH07DQoNCiAgICAgICAgLy8gVGVtcCBpbnB1dHMgZm9yIG1vc3QgbW9kZXMNCiAgICAgICAgaWYgKFsnbGluZWFyJywgJ2ZpbmFsTGVuZ3RoJywgJ2FyZWEnLCAndm9sdW1lJ10uaW5jbHVkZXMobW9kZSkpIHsNCiAgICAgICAgICAgIHNob3cudGVtcDEgPSB0cnVlOw0KICAgICAgICAgICAgc2hvdy50ZW1wMiA9IHRydWU7DQogICAgICAgIH0NCiAgICAgICAgaWYgKG1vZGUgPT09ICd0ZW1wQ2hhbmdlJykgew0KICAgICAgICAgICAgc2hvdy50ZW1wMSA9IGZhbHNlOw0KICAgICAgICAgICAgc2hvdy50ZW1wMiA9IGZhbHNlOw0KICAgICAgICAgICAgc2hvdy5kZWx0YUwgPSB0cnVlOw0KICAgICAgICAgICAgc2hvdy5hbHBoYSA9IHRydWU7DQogICAgICAgICAgICBzaG93Lmxlbmd0aCA9IHRydWU7DQogICAgICAgIH0NCiAgICAgICAgaWYgKG1vZGUgPT09ICdjb2VmZmljaWVudCcpIHsNCiAgICAgICAgICAgIHNob3cudGVtcDEgPSBmYWxzZTsNCiAgICAgICAgICAgIHNob3cudGVtcDIgPSBmYWxzZTsNCiAgICAgICAgICAgIHNob3cuZGVsdGFMID0gdHJ1ZTsNCiAgICAgICAgICAgIHNob3cuZGVsdGFUID0gdHJ1ZTsNCiAgICAgICAgICAgIHNob3cuYWxwaGEgPSBmYWxzZTsNCiAgICAgICAgICAgIHNob3cubGVuZ3RoID0gdHJ1ZTsNCiAgICAgICAgfQ0KDQogICAgICAgIGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3JBbGwoJyNjb3JlSW5wdXRzIC5mb3JtLWdyb3VwW2RhdGEtaW5wdXRdJykuZm9yRWFjaChlbCA9PiB7DQogICAgICAgICAgICBjb25zdCBrZXkgPSBlbC5kYXRhc2V0LmlucHV0Ow0KICAgICAgICAgICAgZWwuY2xhc3NMaXN0LnRvZ2dsZSgnaGlkZGVuJywgIXNob3dba2V5XSk7DQogICAgICAgIH0pOw0KDQogICAgICAgICQoJ21hdGVyaWFsR3JvdXAnKS5jbGFzc0xpc3QudG9nZ2xlKCdoaWRkZW4nLCBtb2RlID09PSAnY29tcGFyaXNvbicgfHwgbW9kZSA9PT0gJ2NsZWFyYW5jZScpOw0KICAgICAgICAkKCdleHBhbnNpb25NZXRob2RHcm91cCcpLmNsYXNzTGlzdC50b2dnbGUoJ2hpZGRlbicsICFbJ2xpbmVhcicsICdmaW5hbExlbmd0aCcsICdhcmVhJywgJ3ZvbHVtZSddLmluY2x1ZGVzKG1vZGUpKTsNCiAgICAgICAgJCgnYWxwaGFNb2RlU2VjdGlvbicpLmNsYXNzTGlzdC50b2dnbGUoJ2hpZGRlbicsIG1vZGUgPT09ICdjb21wYXJpc29uJyB8fCBtb2RlID09PSAnY2xlYXJhbmNlJyk7DQogICAgICAgICQoJ2NsZWFyYW5jZUlucHV0cycpLmNsYXNzTGlzdC50b2dnbGUoJ2hpZGRlbicsIG1vZGUgIT09ICdjbGVhcmFuY2UnKTsNCiAgICAgICAgJCgnY29tcGFyaXNvbklucHV0cycpLmNsYXNzTGlzdC50b2dnbGUoJ2hpZGRlbicsIG1vZGUgIT09ICdjb21wYXJpc29uJyk7DQogICAgICAgICQoJ2NvcmVJbnB1dHMnKS5jbGFzc0xpc3QudG9nZ2xlKCdoaWRkZW4nLCBtb2RlID09PSAnY29tcGFyaXNvbicgfHwgbW9kZSA9PT0gJ2NsZWFyYW5jZScpOw0KICAgICAgICAkKCdzdHJlc3NTZWN0aW9uJykuY2xhc3NMaXN0LnRvZ2dsZSgnaGlkZGVuJywgbW9kZSA9PT0gJ2NvbXBhcmlzb24nKTsNCiAgICB9DQoNCiAgICBmdW5jdGlvbiBnYXRoZXJJbnB1dHMoKSB7DQogICAgICAgIGNvbnN0IG1vZGUgPSAkKCdjYWxjTW9kZScpLnZhbHVlOw0KICAgICAgICBjb25zdCB0ZW1wVW5pdCA9ICQoJ3RlbXBVbml0JykudmFsdWU7DQogICAgICAgIGNvbnN0IGFscGhhVW5pdCA9ICQoJ2FscGhhVW5pdCcpLnZhbHVlOw0KDQogICAgICAgIGNvbnN0IHRlbXAxQyA9IFVuaXRzLnRvQ2Vsc2l1cyhwYXJzZUZsb2F0KCQoJ3RlbXAxJykudmFsdWUpIHx8IDAsIHRlbXBVbml0KTsNCiAgICAgICAgY29uc3QgdGVtcDJDID0gVW5pdHMudG9DZWxzaXVzKHBhcnNlRmxvYXQoJCgndGVtcDInKS52YWx1ZSkgfHwgMCwgdGVtcFVuaXQpOw0KICAgICAgICBsZXQgZGVsdGFUQyA9IHRlbXAyQyAtIHRlbXAxQzsNCg0KICAgICAgICBjb25zdCBhbHBoYVJhdyA9IHBhcnNlRmxvYXQoJCgnYWxwaGEnKS52YWx1ZSkgfHwgMDsNCiAgICAgICAgbGV0IGFscGhhUGVyQyA9IFVuaXRzLmFscGhhVG9QZXJDKGFscGhhUmF3LCBhbHBoYVVuaXQpOw0KDQogICAgICAgIGNvbnN0IGFscGhhTW9kZSA9ICQoJ2FscGhhTW9kZScpLnZhbHVlOw0KICAgICAgICBjb25zdCBwaWVjZXdpc2VEYXRhID0gYWxwaGFNb2RlID09PSAncGllY2V3aXNlJyA\/IGdldFBpZWNld2lzZURhdGEoKSA6IG51bGw7DQoNCiAgICAgICAgYWxwaGFQZXJDID0gVGhlcm1hbEVuZ2luZS5nZXRFZmZlY3RpdmVBbHBoYSh7DQogICAgICAgICAgICBhbHBoYVBlckMsIGFscGhhTW9kZSwgdGVtcDFDLCB0ZW1wMkMsIHBpZWNld2lzZURhdGENCiAgICAgICAgfSk7DQoNCiAgICAgICAgY29uc3QgTDBtbSA9IFVuaXRzLmNvbnZlcnRMZW5ndGgocGFyc2VGbG9hdCgkKCdsZW5ndGgnKS52YWx1ZSkgfHwgMCwgJCgnbGVuZ3RoVW5pdCcpLnZhbHVlLCAnbW0nKTsNCiAgICAgICAgY29uc3QgQTBtbTIgPSBVbml0cy5jb252ZXJ0QXJlYShwYXJzZUZsb2F0KCQoJ2FyZWEnKS52YWx1ZSkgfHwgMCwgJCgnYXJlYVVuaXQnKS52YWx1ZSwgJ21tMicpOw0KICAgICAgICBjb25zdCBWMG1tMyA9IFVuaXRzLmNvbnZlcnRWb2x1bWUocGFyc2VGbG9hdCgkKCd2b2x1bWUnKS52YWx1ZSkgfHwgMCwgJCgndm9sdW1lVW5pdCcpLnZhbHVlLCAnbW0zJyk7DQogICAgICAgIGNvbnN0IGRlbHRhTG1tID0gVW5pdHMuY29udmVydExlbmd0aChwYXJzZUZsb2F0KCQoJ2RlbHRhTCcpLnZhbHVlKSB8fCAwLCAkKCdkZWx0YUxVbml0JykudmFsdWUsICdtbScpOw0KICAgICAgICBjb25zdCBMMm1tID0gVW5pdHMuY29udmVydExlbmd0aChwYXJzZUZsb2F0KCQoJ2ZpbmFsTGVuZ3RoJykudmFsdWUpIHx8IDAsICQoJ2ZpbmFsTGVuZ3RoVW5pdCcpLnZhbHVlLCAnbW0nKTsNCg0KICAgICAgICBpZiAoJCgnZGVsdGFUJykgJiYgISQoJ2RlbHRhVCcpLmNsb3Nlc3QoJy5oaWRkZW4nKSkgew0KICAgICAgICAgICAgZGVsdGFUQyA9IFVuaXRzLmRlbHRhVFRvQ2Vsc2l1cyhwYXJzZUZsb2F0KCQoJ2RlbHRhVCcpLnZhbHVlKSB8fCAwLCAkKCdkZWx0YVRVbml0JykudmFsdWUpOw0KICAgICAgICB9DQoNCiAgICAgICAgY29uc3QgbWV0aG9kID0gJCgnZXhwYW5zaW9uTWV0aG9kJykudmFsdWU7DQogICAgICAgIGNvbnN0IHJlc3RyYWludCA9ICQoJ3Jlc3RyYWludENvbmRpdGlvbicpLnZhbHVlOw0KICAgICAgICBjb25zdCBFX0dQYSA9ICQoJ21vZHVsdXNVbml0JykudmFsdWUgPT09ICdHUGEnDQogICAgICAgICAgICA\/IHBhcnNlRmxvYXQoJCgneW91bmdzTW9kdWx1cycpLnZhbHVlKSB8fCAyMDANCiAgICAgICAgICAgIDogVW5pdHMuc3RyZXNzVG9NUGEocGFyc2VGbG9hdCgkKCd5b3VuZ3NNb2R1bHVzJykudmFsdWUpIHx8IDIwMCwgJCgnbW9kdWx1c1VuaXQnKS52YWx1ZSkgLyAxMDAwOw0KDQogICAgICAgIHJldHVybiB7DQogICAgICAgICAgICBtb2RlLCB0ZW1wMUMsIHRlbXAyQywgZGVsdGFUQywgYWxwaGFQZXJDLCBhbHBoYVJhdywgYWxwaGFVbml0LA0KICAgICAgICAgICAgTDBtbSwgQTBtbTIsIFYwbW0zLCBkZWx0YUxtbSwgTDJtbSwgbWV0aG9kLCBhbHBoYU1vZGUsDQogICAgICAgICAgICByZXN0cmFpbnQsIEVfR1BhLA0KICAgICAgICAgICAgYWxsb3dhYmxlTVBhOiBVbml0cy5zdHJlc3NUb01QYShwYXJzZUZsb2F0KCQoJ2FsbG93YWJsZVN0cmVzcycpLnZhbHVlKSB8fCAyNTAsICQoJ3N0cmVzc1VuaXQnKS52YWx1ZSksDQogICAgICAgICAgICBsZW5ndGhVbml0OiAkKCdsZW5ndGhVbml0JykudmFsdWUsDQogICAgICAgICAgICB0ZW1wVW5pdCwgbWF0ZXJpYWw6IGdldE1hdGVyaWFsQnlJZCgkKCdtYXRlcmlhbFNlbGVjdCcpLnZhbHVlKQ0KICAgICAgICB9Ow0KICAgIH0NCg0KICAgIGZ1bmN0aW9uIGNhbGN1bGF0ZSgpIHsNCiAgICAgICAgY29uc3QgcGFuZWwgPSAkKCdyZXN1bHRzUGFuZWwnKTsNCiAgICAgICAgaWYgKHBhbmVsKSBwYW5lbC5jbGFzc0xpc3QucmVtb3ZlKCdoaWRkZW4nKTsNCiAgICAgICAgaGlkZU1lc3NhZ2VzKCk7DQogICAgICAgIGNvbnN0IGlucHV0cyA9IGdhdGhlcklucHV0cygpOw0KICAgICAgICBsZXQgcmVzdWx0cyA9IHsgLi4uaW5wdXRzIH07DQogICAgICAgIGNvbnN0IGVycm9ycyA9IFtdOw0KDQogICAgICAgIHRyeSB7DQogICAgICAgICAgICBzd2l0Y2ggKGlucHV0cy5tb2RlKSB7DQogICAgICAgICAgICAgICAgY2FzZSAnbGluZWFyJzoNCiAgICAgICAgICAgICAgICAgICAgcmVzdWx0cyA9IGNhbGN1bGF0ZUxpbmVhcihpbnB1dHMpOw0KICAgICAgICAgICAgICAgICAgICBicmVhazsNCiAgICAgICAgICAgICAgICBjYXNlICdmaW5hbExlbmd0aCc6DQogICAgICAgICAgICAgICAgICAgIHJlc3VsdHMgPSBjYWxjdWxhdGVGaW5hbExlbmd0aChpbnB1dHMpOw0KICAgICAgICAgICAgICAgICAgICBicmVhazsNCiAgICAgICAgICAgICAgICBjYXNlICd0ZW1wQ2hhbmdlJzoNCiAgICAgICAgICAgICAgICAgICAgcmVzdWx0cyA9IGNhbGN1bGF0ZVRlbXBDaGFuZ2UoaW5wdXRzKTsNCiAgICAgICAgICAgICAgICAgICAgYnJlYWs7DQogICAgICAgICAgICAgICAgY2FzZSAnY29lZmZpY2llbnQnOg0KICAgICAgICAgICAgICAgICAgICByZXN1bHRzID0gY2FsY3VsYXRlQ29lZmZpY2llbnQoaW5wdXRzKTsNCiAgICAgICAgICAgICAgICAgICAgYnJlYWs7DQogICAgICAgICAgICAgICAgY2FzZSAnYXJlYSc6DQogICAgICAgICAgICAgICAgICAgIHJlc3VsdHMgPSBjYWxjdWxhdGVBcmVhKGlucHV0cyk7DQogICAgICAgICAgICAgICAgICAgIGJyZWFrOw0KICAgICAgICAgICAgICAgIGNhc2UgJ3ZvbHVtZSc6DQogICAgICAgICAgICAgICAgICAgIHJlc3VsdHMgPSBjYWxjdWxhdGVWb2x1bWUoaW5wdXRzKTsNCiAgICAgICAgICAgICAgICAgICAgYnJlYWs7DQogICAgICAgICAgICAgICAgY2FzZSAnY29tcGFyaXNvbic6DQogICAgICAgICAgICAgICAgICAgIHJlc3VsdHMgPSBjYWxjdWxhdGVDb21wYXJpc29uKGlucHV0cyk7DQogICAgICAgICAgICAgICAgICAgIGJyZWFrOw0KICAgICAgICAgICAgICAgIGNhc2UgJ2NsZWFyYW5jZSc6DQogICAgICAgICAgICAgICAgICAgIHJlc3VsdHMgPSBjYWxjdWxhdGVDbGVhcmFuY2UoaW5wdXRzKTsNCiAgICAgICAgICAgICAgICAgICAgYnJlYWs7DQogICAgICAgICAgICB9DQogICAgICAgIH0gY2F0Y2ggKGVycikgew0KICAgICAgICAgICAgZXJyb3JzLnB1c2goZXJyLm1lc3NhZ2UgfHwgJ0NhbGN1bGF0aW9uIGVycm9yIG9jY3VycmVkLicpOw0KICAgICAgICB9DQoNCiAgICAgICAgY29uc3QgdmFsaWRhdGlvbiA9IFRoZXJtYWxFbmdpbmUudmFsaWRhdGUoew0KICAgICAgICAgICAgTDBtbTogcmVzdWx0cy5MMG1tLA0KICAgICAgICAgICAgQTBtbTI6IHJlc3VsdHMuQTBtbTIsDQogICAgICAgICAgICBWMG1tMzogcmVzdWx0cy5WMG1tMywNCiAgICAgICAgICAgIGFscGhhUGVyQzogcmVzdWx0cy5hbHBoYVBlckMsDQogICAgICAgICAgICBkZWx0YVRDOiByZXN1bHRzLmRlbHRhVEMsDQogICAgICAgICAgICB0ZW1wMUM6IHJlc3VsdHMudGVtcDFDLA0KICAgICAgICAgICAgdGVtcDJDOiByZXN1bHRzLnRlbXAyQywNCiAgICAgICAgICAgIG1hdGVyaWFsOiByZXN1bHRzLm1hdGVyaWFsDQogICAgICAgIH0pOw0KDQogICAgICAgIGlmICh2YWxpZGF0aW9uLmVycm9ycy5sZW5ndGgpIHNob3dFcnJvcnModmFsaWRhdGlvbi5lcnJvcnMpOw0KICAgICAgICBpZiAodmFsaWRhdGlvbi53YXJuaW5ncy5sZW5ndGgpIHNob3dXYXJuaW5ncyh2YWxpZGF0aW9uLndhcm5pbmdzKTsNCiAgICAgICAgaWYgKGVycm9ycy5sZW5ndGgpIHNob3dFcnJvcnMoZXJyb3JzKTsNCg0KICAgICAgICBpZiAodmFsaWRhdGlvbi5lcnJvcnMubGVuZ3RoID09PSAwICYmIGVycm9ycy5sZW5ndGggPT09IDApIHsNCiAgICAgICAgICAgIGlmIChpbnB1dHMucmVzdHJhaW50ID09PSAnZnVsbCcpIHsNCiAgICAgICAgICAgICAgICByZXN1bHRzLnRoZXJtYWxTdHJlc3NNUGEgPSBUaGVybWFsRW5naW5lLnRoZXJtYWxTdHJlc3MoaW5wdXRzLkVfR1BhLCBpbnB1dHMuYWxwaGFQZXJDLCBpbnB1dHMuZGVsdGFUQyk7DQogICAgICAgICAgICAgICAgcmVzdWx0cy5zdHJlc3NVdGlsaXphdGlvbiA9IGlucHV0cy5hbGxvd2FibGVNUGEgPiAwDQogICAgICAgICAgICAgICAgICAgID8gKHJlc3VsdHMudGhlcm1hbFN0cmVzc01QYSAvIGlucHV0cy5hbGxvd2FibGVNUGEpICogMTAwDQogICAgICAgICAgICAgICAgICAgIDogbnVsbDsNCiAgICAgICAgICAgIH0NCg0KICAgICAgICAgICAgc3RhdGUubGFzdFJlc3VsdHMgPSByZXN1bHRzOw0KICAgICAgICAgICAgcmVuZGVyUmVzdWx0cyhyZXN1bHRzKTsNCiAgICAgICAgfSBlbHNlIGlmIChlcnJvcnMubGVuZ3RoIHx8IHZhbGlkYXRpb24uZXJyb3JzLmxlbmd0aCkgew0KICAgICAgICAgICAgLy8gU3RpbGwgc2hvdyB0aGUgcmVzdWx0cyBjYXJkIHdpdGggZXJyb3IgbWVzc2FnZXMNCiAgICAgICAgICAgIHJlbmRlclJlc3VsdHMocmVzdWx0cyk7DQogICAgICAgIH0NCiAgICB9DQoNCiAgICBmdW5jdGlvbiBjYWxjdWxhdGVMaW5lYXIoaW5wdXRzKSB7DQogICAgICAgIGNvbnN0IHsgZGVsdGFMLCBMMiwgc3RyYWluIH0gPSBUaGVybWFsRW5naW5lLmxpbmVhckV4cGFuc2lvbigNCiAgICAgICAgICAgIGlucHV0cy5MMG1tLCBpbnB1dHMuYWxwaGFQZXJDLCBpbnB1dHMuZGVsdGFUQywgaW5wdXRzLm1ldGhvZA0KICAgICAgICApOw0KICAgICAgICBjb25zdCBzdHJhaW5GID0gVGhlcm1hbEVuZ2luZS5mb3JtYXRTdHJhaW4oc3RyYWluKTsNCiAgICAgICAgcmV0dXJuIHsNCiAgICAgICAgICAgIC4uLmlucHV0cywgZGVsdGFMbW06IGRlbHRhTCwgTDJtbTogTDIsIHN0cmFpbiwgc3RyYWluRiwNCiAgICAgICAgICAgIGRlbHRhTCwgTDINCiAgICAgICAgfTsNCiAgICB9DQoNCiAgICBmdW5jdGlvbiBjYWxjdWxhdGVGaW5hbExlbmd0aChpbnB1dHMpIHsNCiAgICAgICAgY29uc3QgeyBkZWx0YUwsIEwyLCBzdHJhaW4gfSA9IFRoZXJtYWxFbmdpbmUubGluZWFyRXhwYW5zaW9uKA0KICAgICAgICAgICAgaW5wdXRzLkwwbW0sIGlucHV0cy5hbHBoYVBlckMsIGlucHV0cy5kZWx0YVRDLCBpbnB1dHMubWV0aG9kDQogICAgICAgICk7DQogICAgICAgIHJldHVybiB7DQogICAgICAgICAgICAuLi5pbnB1dHMsIGRlbHRhTG1tOiBkZWx0YUwsIEwybW06IEwyLCBzdHJhaW4sDQogICAgICAgICAgICBzdHJhaW5GOiBUaGVybWFsRW5naW5lLmZvcm1hdFN0cmFpbihzdHJhaW4pLCBkZWx0YUwsIEwyDQogICAgICAgIH07DQogICAgfQ0KDQogICAgZnVuY3Rpb24gY2FsY3VsYXRlVGVtcENoYW5nZShpbnB1dHMpIHsNCiAgICAgICAgY29uc3QgZGVsdGFUQyA9IFRoZXJtYWxFbmdpbmUudGVtcGVyYXR1cmVGcm9tRXhwYW5zaW9uKGlucHV0cy5kZWx0YUxtbSwgaW5wdXRzLkwwbW0sIGlucHV0cy5hbHBoYVBlckMpOw0KICAgICAgICBpZiAoZGVsdGFUQyA9PT0gbnVsbCkgdGhyb3cgbmV3IEVycm9yKCdDYW5ub3QgY2FsY3VsYXRlIHRlbXBlcmF0dXJlIGNoYW5nZTogZGl2aXNpb24gYnkgemVybyAoXHUwM2IxIFx1MDBkNyBMXHUyMDgwID0gMCkuJyk7DQogICAgICAgIHJldHVybiB7DQogICAgICAgICAgICAuLi5pbnB1dHMsIGRlbHRhVEMsDQogICAgICAgICAgICB0ZW1wMkM6IGlucHV0cy50ZW1wMUMgKyBkZWx0YVRDLA0KICAgICAgICAgICAgZGVsdGFMOiBpbnB1dHMuZGVsdGFMbW0sDQogICAgICAgICAgICBzdHJhaW5GOiBUaGVybWFsRW5naW5lLmZvcm1hdFN0cmFpbihpbnB1dHMuZGVsdGFMbW0gLyBpbnB1dHMuTDBtbSkNCiAgICAgICAgfTsNCiAgICB9DQoNCiAgICBmdW5jdGlvbiBjYWxjdWxhdGVDb2VmZmljaWVudChpbnB1dHMpIHsNCiAgICAgICAgY29uc3QgYWxwaGFQZXJDID0gVGhlcm1hbEVuZ2luZS5hbHBoYUZyb21FeHBhbnNpb24oaW5wdXRzLmRlbHRhTG1tLCBpbnB1dHMuTDBtbSwgaW5wdXRzLmRlbHRhVEMpOw0KICAgICAgICBpZiAoYWxwaGFQZXJDID09PSBudWxsKSB0aHJvdyBuZXcgRXJyb3IoJ0Nhbm5vdCBjYWxjdWxhdGUgXHUwM2IxOiBkaXZpc2lvbiBieSB6ZXJvIChMXHUyMDgwIFx1MDBkNyBcdTAzOTRUID0gMCkuJyk7DQogICAgICAgIHJldHVybiB7DQogICAgICAgICAgICAuLi5pbnB1dHMsIGFscGhhUGVyQywNCiAgICAgICAgICAgIGFscGhhUmF3OiBVbml0cy5hbHBoYUZyb21QZXJDKGFscGhhUGVyQywgaW5wdXRzLmFscGhhVW5pdCksDQogICAgICAgICAgICBkZWx0YUw6IGlucHV0cy5kZWx0YUxtbSwNCiAgICAgICAgICAgIHN0cmFpbkY6IFRoZXJtYWxFbmdpbmUuZm9ybWF0U3RyYWluKGlucHV0cy5kZWx0YUxtbSAvIGlucHV0cy5MMG1tKQ0KICAgICAgICB9Ow0KICAgIH0NCg0KICAgIGZ1bmN0aW9uIGNhbGN1bGF0ZUFyZWEoaW5wdXRzKSB7DQogICAgICAgIGNvbnN0IHsgZGVsdGFBLCBBMiwgYmV0YSB9ID0gVGhlcm1hbEVuZ2luZS5hcmVhRXhwYW5zaW9uKA0KICAgICAgICAgICAgaW5wdXRzLkEwbW0yLCBpbnB1dHMuYWxwaGFQZXJDLCBpbnB1dHMuZGVsdGFUQywgaW5wdXRzLm1ldGhvZA0KICAgICAgICApOw0KICAgICAgICBjb25zdCBsaW5lYXJSZXN1bHQgPSBUaGVybWFsRW5naW5lLmxpbmVhckV4cGFuc2lvbihpbnB1dHMuTDBtbSwgaW5wdXRzLmFscGhhUGVyQywgaW5wdXRzLmRlbHRhVEMsIGlucHV0cy5tZXRob2QpOw0KICAgICAgICByZXR1cm4gew0KICAgICAgICAgICAgLi4uaW5wdXRzLCBkZWx0YUFtbTI6IGRlbHRhQSwgQTJtbTI6IEEyLCBiZXRhLA0KICAgICAgICAgICAgZGVsdGFMbW06IGxpbmVhclJlc3VsdC5kZWx0YUwsIEwybW06IGxpbmVhclJlc3VsdC5MMiwNCiAgICAgICAgICAgIHN0cmFpbkY6IFRoZXJtYWxFbmdpbmUuZm9ybWF0U3RyYWluKGxpbmVhclJlc3VsdC5zdHJhaW4pLA0KICAgICAgICAgICAgZGVsdGFMOiBsaW5lYXJSZXN1bHQuZGVsdGFMLCBkZWx0YUEsIEEyDQogICAgICAgIH07DQogICAgfQ0KDQogICAgZnVuY3Rpb24gY2FsY3VsYXRlVm9sdW1lKGlucHV0cykgew0KICAgICAgICBjb25zdCB7IGRlbHRhViwgVjIsIGdhbW1hIH0gPSBUaGVybWFsRW5naW5lLnZvbHVtZUV4cGFuc2lvbigNCiAgICAgICAgICAgIGlucHV0cy5WMG1tMywgaW5wdXRzLmFscGhhUGVyQywgaW5wdXRzLmRlbHRhVEMsIGlucHV0cy5tZXRob2QNCiAgICAgICAgKTsNCiAgICAgICAgY29uc3QgbGluZWFyUmVzdWx0ID0gVGhlcm1hbEVuZ2luZS5saW5lYXJFeHBhbnNpb24oaW5wdXRzLkwwbW0sIGlucHV0cy5hbHBoYVBlckMsIGlucHV0cy5kZWx0YVRDLCBpbnB1dHMubWV0aG9kKTsNCiAgICAgICAgcmV0dXJuIHsNCiAgICAgICAgICAgIC4uLmlucHV0cywgZGVsdGFWbW0zOiBkZWx0YVYsIFYybW0zOiBWMiwgZ2FtbWEsDQogICAgICAgICAgICBkZWx0YUxtbTogbGluZWFyUmVzdWx0LmRlbHRhTCwgTDJtbTogbGluZWFyUmVzdWx0LkwyLA0KICAgICAgICAgICAgc3RyYWluRjogVGhlcm1hbEVuZ2luZS5mb3JtYXRTdHJhaW4obGluZWFyUmVzdWx0LnN0cmFpbiksDQogICAgICAgICAgICBkZWx0YUw6IGxpbmVhclJlc3VsdC5kZWx0YUwsIGRlbHRhViwgVjINCiAgICAgICAgfTsNCiAgICB9DQoNCiAgICBmdW5jdGlvbiBjYWxjdWxhdGVDb21wYXJpc29uKGlucHV0cykgew0KICAgICAgICBjb25zdCBMMG1tID0gVW5pdHMuY29udmVydExlbmd0aCgNCiAgICAgICAgICAgIHBhcnNlRmxvYXQoJCgnY29tcGFyaXNvbkxlbmd0aCcpLnZhbHVlKSB8fCAxMDAwLA0KICAgICAgICAgICAgJCgnY29tcGFyaXNvbkxlbmd0aFVuaXQnKS52YWx1ZSwgJ21tJw0KICAgICAgICApOw0KICAgICAgICBjb25zdCB0ZW1wMUMgPSBVbml0cy50b0NlbHNpdXMocGFyc2VGbG9hdCgkKCdjb21wYXJpc29uVGVtcDEnKS52YWx1ZSkgfHwgMjAsICdDJyk7DQogICAgICAgIGNvbnN0IHRlbXAyQyA9IFVuaXRzLnRvQ2Vsc2l1cyhwYXJzZUZsb2F0KCQoJ2NvbXBhcmlzb25UZW1wMicpLnZhbHVlKSB8fCAxMDAsICdDJyk7DQogICAgICAgIGNvbnN0IGRlbHRhVEMgPSB0ZW1wMkMgLSB0ZW1wMUM7DQogICAgICAgIGNvbnN0IG1ldGhvZCA9ICQoJ2V4cGFuc2lvbk1ldGhvZCcpLnZhbHVlOw0KDQogICAgICAgIGNvbnN0IGNvbXBhcmlzb25SZXN1bHRzID0gVGhlcm1hbEVuZ2luZS5jb21wYXJlTWF0ZXJpYWxzKA0KICAgICAgICAgICAgc3RhdGUuY29tcGFyaXNvbk1hdGVyaWFscywgTDBtbSwgZGVsdGFUQywgbWV0aG9kDQogICAgICAgICk7DQoNCiAgICAgICAgY29uc3QgcmFua09yZGVyID0gJCgnY29tcGFyaXNvblJhbmsnKS52YWx1ZTsNCiAgICAgICAgaWYgKHJhbmtPcmRlciA9PT0gJ2hpZ2hlc3QnKSB7DQogICAgICAgICAgICBjb21wYXJpc29uUmVzdWx0cy5yZXZlcnNlKCk7DQogICAgICAgICAgICBjb21wYXJpc29uUmVzdWx0cy5mb3JFYWNoKChyLCBpKSA9PiB7IHIucmFuayA9IGkgKyAxOyB9KTsNCiAgICAgICAgfQ0KDQogICAgICAgIHJldHVybiB7DQogICAgICAgICAgICAuLi5pbnB1dHMsIG1vZGU6ICdjb21wYXJpc29uJywgTDBtbSwgZGVsdGFUQywgdGVtcDFDLCB0ZW1wMkMsDQogICAgICAgICAgICBjb21wYXJpc29uUmVzdWx0cywgbGVuZ3RoVW5pdDogJCgnY29tcGFyaXNvbkxlbmd0aFVuaXQnKS52YWx1ZQ0KICAgICAgICB9Ow0KICAgIH0NCg0KICAgIGZ1bmN0aW9uIGNhbGN1bGF0ZUNsZWFyYW5jZShpbnB1dHMpIHsNCiAgICAgICAgY29uc3QgYWxwaGExID0gKHBhcnNlRmxvYXQoJCgnY2xlYXJBbHBoYTEnKS52YWx1ZSkgfHwgMCkgKiAxZS02Ow0KICAgICAgICBjb25zdCBhbHBoYTIgPSAocGFyc2VGbG9hdCgkKCdjbGVhckFscGhhMicpLnZhbHVlKSB8fCAwKSAqIDFlLTY7DQogICAgICAgIGNvbnN0IEwxbW0gPSBVbml0cy5jb252ZXJ0TGVuZ3RoKHBhcnNlRmxvYXQoJCgnY2xlYXJMZW5ndGgxJykudmFsdWUpIHx8IDAsICQoJ2NsZWFyTGVuZ3RoVW5pdCcpLnZhbHVlLCAnbW0nKTsNCiAgICAgICAgY29uc3QgTDJtbSA9IFVuaXRzLmNvbnZlcnRMZW5ndGgocGFyc2VGbG9hdCgkKCdjbGVhckxlbmd0aDInKS52YWx1ZSkgfHwgMCwgJCgnY2xlYXJMZW5ndGgyVW5pdCcpLnZhbHVlLCAnbW0nKTsNCiAgICAgICAgY29uc3QgaW5pdGlhbENsZWFyYW5jZSA9IFVuaXRzLmNvbnZlcnRMZW5ndGgoDQogICAgICAgICAgICBwYXJzZUZsb2F0KCQoJ2luaXRpYWxDbGVhcmFuY2UnKS52YWx1ZSkgfHwgMCwgJCgnY2xlYXJhbmNlVW5pdCcpLnZhbHVlLCAnbW0nDQogICAgICAgICk7DQoNCiAgICAgICAgY29uc3QgY2xlYXJUZW1wVW5pdCA9ICQoJ2NsZWFyVGVtcFVuaXQnKS52YWx1ZTsNCiAgICAgICAgY29uc3QgdGVtcDFDID0gVW5pdHMudG9DZWxzaXVzKHBhcnNlRmxvYXQoJCgnY2xlYXJUZW1wMScpLnZhbHVlKSB8fCAyMCwgY2xlYXJUZW1wVW5pdCk7DQogICAgICAgIGNvbnN0IHRlbXAyQyA9IFVuaXRzLnRvQ2Vsc2l1cyhwYXJzZUZsb2F0KCQoJ2NsZWFyVGVtcDInKS52YWx1ZSkgfHwgODAsIGNsZWFyVGVtcFVuaXQpOw0KICAgICAgICBjb25zdCBkZWx0YVRDID0gdGVtcDJDIC0gdGVtcDFDOw0KDQogICAgICAgIGNvbnN0IHJlbCA9IFRoZXJtYWxFbmdpbmUucmVsYXRpdmVFeHBhbnNpb24oYWxwaGExLCBMMW1tLCBhbHBoYTIsIEwybW0sIGRlbHRhVEMpOw0KICAgICAgICBjb25zdCBjaGVjayA9IFRoZXJtYWxFbmdpbmUuY2xlYXJhbmNlQ2hlY2socmVsLnJlbGF0aXZlLCBpbml0aWFsQ2xlYXJhbmNlKTsNCg0KICAgICAgICBpZiAoY2hlY2sucmVtYWluaW5nIDw9IDApIHsNCiAgICAgICAgICAgIHNob3dXYXJuaW5ncyhbJ1JlbWFpbmluZyB0aGVybWFsIGNsZWFyYW5jZSBpcyB6ZXJvIG9yIG5lZ2F0aXZlIC0gaW50ZXJmZXJlbmNlIHJpc2shJ10pOw0KICAgICAgICB9DQoNCiAgICAgICAgcmV0dXJuIHsNCiAgICAgICAgICAgIC4uLmlucHV0cywgbW9kZTogJ2NsZWFyYW5jZScsIGRlbHRhVEMsIHRlbXAxQywgdGVtcDJDLA0KICAgICAgICAgICAgYWxwaGExLCBhbHBoYTIsIEwxbW0sIEwybW06IEwybW0sDQogICAgICAgICAgICBleHBhbnNpb24xOiByZWwuZXhwYW5zaW9uMSwgZXhwYW5zaW9uMjogcmVsLmV4cGFuc2lvbjIsDQogICAgICAgICAgICByZWxhdGl2ZTogcmVsLnJlbGF0aXZlLCBjbGVhcmFuY2VSZXF1aXJlZDogcmVsLmNsZWFyYW5jZVJlcXVpcmVkLA0KICAgICAgICAgICAgaW5pdGlhbENsZWFyYW5jZSwgcmVtYWluaW5nOiBjaGVjay5yZW1haW5pbmcsDQogICAgICAgICAgICBjbGVhcmFuY2VTdGF0dXM6IGNoZWNrLnN0YXR1cywgY2xlYXJhbmNlQ2xhc3M6IGNoZWNrLnN0YXR1c0NsYXNzLA0KICAgICAgICAgICAgZGVsdGFMbW06IHJlbC5yZWxhdGl2ZSwgZGVsdGFMOiByZWwucmVsYXRpdmUNCiAgICAgICAgfTsNCiAgICB9DQoNCiAgICBmdW5jdGlvbiByZW5kZXJSZXN1bHRzKHJlc3VsdHMpIHsNCiAgICAgICAgY29uc3QgY29udGFpbmVyID0gJCgncmVzdWx0c0NvbnRlbnQnKTsNCiAgICAgICAgY29udGFpbmVyLmlubmVySFRNTCA9ICcnOw0KDQogICAgICAgIGlmIChyZXN1bHRzLm1vZGUgPT09ICdjb21wYXJpc29uJykgew0KICAgICAgICAgICAgcmVuZGVyQ29tcGFyaXNvblRhYmxlKGNvbnRhaW5lciwgcmVzdWx0cyk7DQogICAgICAgIH0gZWxzZSBpZiAocmVzdWx0cy5tb2RlID09PSAnY2xlYXJhbmNlJykgew0KICAgICAgICAgICAgcmVuZGVyQ2xlYXJhbmNlUmVzdWx0cyhjb250YWluZXIsIHJlc3VsdHMpOw0KICAgICAgICB9IGVsc2Ugew0KICAgICAgICAgICAgcmVuZGVyU3RhbmRhcmRSZXN1bHRzKGNvbnRhaW5lciwgcmVzdWx0cyk7DQogICAgICAgIH0NCg0KICAgICAgICAvLyBJbnRlcnByZXRhdGlvbg0KICAgICAgICBjb25zdCBpbnRlcnAgPSBUaGVybWFsRW5naW5lLmludGVycHJldChyZXN1bHRzKTsNCiAgICAgICAgY29uc3QgaW50ZXJwRWwgPSAkKCdpbnRlcnByZXRhdGlvbicpOw0KICAgICAgICBpZiAoaW50ZXJwLmxlbmd0aCkgew0KICAgICAgICAgICAgaW50ZXJwRWwuY2xhc3NMaXN0LnJlbW92ZSgnaGlkZGVuJyk7DQogICAgICAgICAgICBpbnRlcnBFbC5pbm5lckhUTUwgPSBgPGgzPlJlc3VsdCBJbnRlcnByZXRhdGlvbjwvaDM+PHVsPiR7aW50ZXJwLm1hcChtID0+IGA8bGk+JHttfTwvbGk+YCkuam9pbignJyl9PC91bD5gOw0KICAgICAgICB9IGVsc2Ugew0KICAgICAgICAgICAgaW50ZXJwRWwuY2xhc3NMaXN0LmFkZCgnaGlkZGVuJyk7DQogICAgICAgIH0NCg0KICAgICAgICAvLyBSZWNvbW1lbmRhdGlvbnMNCiAgICAgICAgY29uc3QgcmVjcyA9IFRoZXJtYWxFbmdpbmUucmVjb21tZW5kKHJlc3VsdHMsIHJlc3VsdHMubW9kZSk7DQogICAgICAgIGNvbnN0IHJlY0VsID0gJCgncmVjb21tZW5kYXRpb25zJyk7DQogICAgICAgIGlmIChyZWNzLmxlbmd0aCkgew0KICAgICAgICAgICAgcmVjRWwuY2xhc3NMaXN0LnJlbW92ZSgnaGlkZGVuJyk7DQogICAgICAgICAgICByZWNFbC5pbm5lckhUTUwgPSBgPGgzPkVuZ2luZWVyaW5nIFJlY29tbWVuZGF0aW9uczwvaDM+PHVsPiR7cmVjcy5tYXAociA9PiBgPGxpPiR7cn08L2xpPmApLmpvaW4oJycpfTwvdWw+YDsNCiAgICAgICAgfSBlbHNlIHsNCiAgICAgICAgICAgIHJlY0VsLmNsYXNzTGlzdC5hZGQoJ2hpZGRlbicpOw0KICAgICAgICB9DQogICAgfQ0KDQogICAgZnVuY3Rpb24gcmVzdWx0SXRlbShsYWJlbCwgdmFsdWUsIHVuaXQsIGhpZ2hsaWdodCkgew0KICAgICAgICByZXR1cm4gYDxkaXYgY2xhc3M9InJlc3VsdC1pdGVtJHtoaWdobGlnaHQgPyAnIGhpZ2hsaWdodCcgOiAnJ30iPg0KICAgICAgICAgICAgPGRpdiBjbGFzcz0icmVzdWx0LWxhYmVsIj4ke2xhYmVsfTwvZGl2Pg0KICAgICAgICAgICAgPGRpdiBjbGFzcz0icmVzdWx0LXZhbHVlIj4ke3ZhbHVlfSA8c3BhbiBjbGFzcz0icmVzdWx0LXVuaXQiPiR7dW5pdCB8fCAnJ308L3NwYW4+PC9kaXY+DQogICAgICAgIDwvZGl2PmA7DQogICAgfQ0KDQogICAgZnVuY3Rpb24gcmVuZGVyU3RhbmRhcmRSZXN1bHRzKGNvbnRhaW5lciwgcikgew0KICAgICAgICBjb25zdCBsdSA9IFVuaXRzLmxlbmd0aExhYmVsKHIubGVuZ3RoVW5pdCB8fCAnbW0nKTsNCiAgICAgICAgY29uc3QgdHUgPSBVbml0cy50ZW1wTGFiZWwoci50ZW1wVW5pdCB8fCAnQycpOw0KDQogICAgICAgIGNvbnN0IGl0ZW1zID0gW107DQoNCiAgICAgICAgaWYgKHIuZGVsdGFUQyAhPT0gdW5kZWZpbmVkKSB7DQogICAgICAgICAgICBpdGVtcy5wdXNoKHJlc3VsdEl0ZW0oJ1RlbXBlcmF0dXJlIENoYW5nZSAoXHUwMzk0VCknLA0KICAgICAgICAgICAgICAgIFVuaXRzLmZvcm1hdE51bWJlcihVbml0cy5mcm9tQ2Vsc2l1c0RlbHRhKHIuZGVsdGFUQywgci50ZW1wVW5pdCkpLCB0dSwNCiAgICAgICAgICAgICAgICBNYXRoLmFicyhyLmRlbHRhVEMpID4gNTApKTsNCiAgICAgICAgfQ0KDQogICAgICAgIGlmIChyLmFscGhhUGVyQyAhPT0gdW5kZWZpbmVkICYmIHIubW9kZSAhPT0gJ2NvZWZmaWNpZW50Jykgew0KICAgICAgICAgICAgaXRlbXMucHVzaChyZXN1bHRJdGVtKCdUaGVybWFsIEV4cGFuc2lvbiBDb2VmZmljaWVudCAoXHUwM2IxKScsDQogICAgICAgICAgICAgICAgVW5pdHMuZm9ybWF0TnVtYmVyKHIuYWxwaGFQZXJDIC8gMWUtNiksICdcdTAwZDcxMFx1MjA3Ylx1MjA3Ni9cdTAwYjBDJykpOw0KICAgICAgICB9DQoNCiAgICAgICAgaWYgKHIubW9kZSA9PT0gJ2NvZWZmaWNpZW50JyAmJiByLmFscGhhUmF3ICE9PSB1bmRlZmluZWQpIHsNCiAgICAgICAgICAgIGl0ZW1zLnB1c2gocmVzdWx0SXRlbSgnQ2FsY3VsYXRlZCBcdTAzYjEnLA0KICAgICAgICAgICAgICAgIFVuaXRzLmZvcm1hdE51bWJlcihyLmFscGhhUmF3KSwNCiAgICAgICAgICAgICAgICByLmFscGhhVW5pdCA9PT0gJzFlLTZfcGVyX0MnID8gJ1x1MDBkNzEwXHUyMDdiXHUyMDc2L1x1MDBiMEMnIDogJzEvXHUwMGIwQycsIHRydWUpKTsNCiAgICAgICAgfQ0KDQogICAgICAgIGlmIChyLkwwbW0gIT09IHVuZGVmaW5lZCAmJiByLm1vZGUgIT09ICdjb2VmZmljaWVudCcpIHsNCiAgICAgICAgICAgIGl0ZW1zLnB1c2gocmVzdWx0SXRlbSgnT3JpZ2luYWwgTGVuZ3RoIChMXHUyMDgwKScsDQogICAgICAgICAgICAgICAgVW5pdHMuZm9ybWF0TnVtYmVyKFVuaXRzLmNvbnZlcnRMZW5ndGgoci5MMG1tLCAnbW0nLCByLmxlbmd0aFVuaXQpKSwgbHUpKTsNCiAgICAgICAgfQ0KDQogICAgICAgIGlmIChyLmRlbHRhTG1tICE9PSB1bmRlZmluZWQgfHwgci5kZWx0YUwgIT09IHVuZGVmaW5lZCkgew0KICAgICAgICAgICAgY29uc3QgZEwgPSByLmRlbHRhTG1tID8\/IHIuZGVsdGFMOw0KICAgICAgICAgICAgaXRlbXMucHVzaChyZXN1bHRJdGVtKCdMZW5ndGggQ2hhbmdlIChcdTAzOTRMKScsDQogICAgICAgICAgICAgICAgKGRMID49IDAgPyAnKycgOiAnJykgKyBVbml0cy5mb3JtYXROdW1iZXIoVW5pdHMuY29udmVydExlbmd0aChkTCwgJ21tJywgci5sZW5ndGhVbml0KSksIGx1LCB0cnVlKSk7DQogICAgICAgIH0NCg0KICAgICAgICBpZiAoci5MMm1tICE9PSB1bmRlZmluZWQpIHsNCiAgICAgICAgICAgIGl0ZW1zLnB1c2gocmVzdWx0SXRlbSgnRmluYWwgTGVuZ3RoIChMXHUyMDgyKScsDQogICAgICAgICAgICAgICAgVW5pdHMuZm9ybWF0TnVtYmVyKFVuaXRzLmNvbnZlcnRMZW5ndGgoci5MMm1tLCAnbW0nLCByLmxlbmd0aFVuaXQpKSwgbHUpKTsNCiAgICAgICAgfQ0KDQogICAgICAgIGlmIChyLnN0cmFpbkYpIHsNCiAgICAgICAgICAgIGl0ZW1zLnB1c2gocmVzdWx0SXRlbSgnVGhlcm1hbCBTdHJhaW4gKFx1MDNiNSknLA0KICAgICAgICAgICAgICAgIFVuaXRzLmZvcm1hdE51bWJlcihyLnN0cmFpbkYubWljcm9zdHJhaW4pLCAnXHUwM2JjXHUwM2I1JykpOw0KICAgICAgICAgICAgaXRlbXMucHVzaChyZXN1bHRJdGVtKCdTdHJhaW4gKCUpJywNCiAgICAgICAgICAgICAgICBVbml0cy5mb3JtYXROdW1iZXIoci5zdHJhaW5GLnBlcmNlbnQpLCAnJScpKTsNCiAgICAgICAgfQ0KDQogICAgICAgIGlmIChyLmRlbHRhQW1tMiAhPT0gdW5kZWZpbmVkKSB7DQogICAgICAgICAgICBpdGVtcy5wdXNoKHJlc3VsdEl0ZW0oJ0FyZWEgQ2hhbmdlIChcdTAzOTRBKScsDQogICAgICAgICAgICAgICAgKHIuZGVsdGFBID49IDAgPyAnKycgOiAnJykgKyBVbml0cy5mb3JtYXROdW1iZXIoci5kZWx0YUFtbTIpLCAnbW1cdTAwYjInKSk7DQogICAgICAgICAgICBpdGVtcy5wdXNoKHJlc3VsdEl0ZW0oJ0ZpbmFsIEFyZWEgKEFcdTIwODIpJywNCiAgICAgICAgICAgICAgICBVbml0cy5mb3JtYXROdW1iZXIoci5BMm1tMiksICdtbVx1MDBiMicpKTsNCiAgICAgICAgfQ0KDQogICAgICAgIGlmIChyLmRlbHRhVm1tMyAhPT0gdW5kZWZpbmVkKSB7DQogICAgICAgICAgICBpdGVtcy5wdXNoKHJlc3VsdEl0ZW0oJ1ZvbHVtZSBDaGFuZ2UgKFx1MDM5NFYpJywNCiAgICAgICAgICAgICAgICAoci5kZWx0YVYgPj0gMCA\/ICcrJyA6ICcnKSArIFVuaXRzLmZvcm1hdE51bWJlcihyLmRlbHRhVm1tMyksICdtbVx1MDBiMycpKTsNCiAgICAgICAgICAgIGl0ZW1zLnB1c2gocmVzdWx0SXRlbSgnRmluYWwgVm9sdW1lIChWXHUyMDgyKScsDQogICAgICAgICAgICAgICAgVW5pdHMuZm9ybWF0TnVtYmVyKHIuVjJtbTMpLCAnbW1cdTAwYjMnKSk7DQogICAgICAgIH0NCg0KICAgICAgICBpZiAoci5tb2RlID09PSAndGVtcENoYW5nZScgJiYgci50ZW1wMkMgIT09IHVuZGVmaW5lZCkgew0KICAgICAgICAgICAgaXRlbXMucHVzaChyZXN1bHRJdGVtKCdDYWxjdWxhdGVkIFRcdTIwODInLA0KICAgICAgICAgICAgICAgIFVuaXRzLmZvcm1hdE51bWJlcihVbml0cy5mcm9tQ2Vsc2l1cyhyLnRlbXAyQywgci50ZW1wVW5pdCkpLCB0dSwgdHJ1ZSkpOw0KICAgICAgICB9DQoNCiAgICAgICAgaWYgKHIudGhlcm1hbFN0cmVzc01QYSAhPT0gdW5kZWZpbmVkKSB7DQogICAgICAgICAgICBpdGVtcy5wdXNoKHJlc3VsdEl0ZW0oJ1RoZXJtYWwgU3RyZXNzIChcdTAzYzMpJywNCiAgICAgICAgICAgICAgICBVbml0cy5mb3JtYXROdW1iZXIoVW5pdHMuc3RyZXNzRnJvbU1QYShNYXRoLmFicyhyLnRoZXJtYWxTdHJlc3NNUGEpLCAkKCdzdHJlc3NVbml0JykudmFsdWUpKSwNCiAgICAgICAgICAgICAgICAkKCdzdHJlc3NVbml0JykudmFsdWUsIHRydWUpKTsNCiAgICAgICAgICAgIGlmIChyLnN0cmVzc1V0aWxpemF0aW9uICE9PSBudWxsKSB7DQogICAgICAgICAgICAgICAgaXRlbXMucHVzaChyZXN1bHRJdGVtKCdTdHJlc3MgVXRpbGl6YXRpb24nLA0KICAgICAgICAgICAgICAgICAgICBVbml0cy5mb3JtYXROdW1iZXIoci5zdHJlc3NVdGlsaXphdGlvbiksICclJywNCiAgICAgICAgICAgICAgICAgICAgci5zdHJlc3NVdGlsaXphdGlvbiA+IDgwKSk7DQogICAgICAgICAgICB9DQogICAgICAgIH0NCg0KICAgICAgICBjb250YWluZXIuaW5uZXJIVE1MID0gaXRlbXMuam9pbignJyk7DQogICAgfQ0KDQogICAgZnVuY3Rpb24gcmVuZGVyQ2xlYXJhbmNlUmVzdWx0cyhjb250YWluZXIsIHIpIHsNCiAgICAgICAgY29uc3QgbHUgPSBVbml0cy5sZW5ndGhMYWJlbCgkKCdjbGVhcmFuY2VVbml0JykudmFsdWUpOw0KICAgICAgICBjb250YWluZXIuaW5uZXJIVE1MID0gWw0KICAgICAgICAgICAgcmVzdWx0SXRlbSgnQ29tcG9uZW50IDEgRXhwYW5zaW9uJywgJysnICsgVW5pdHMuZm9ybWF0TnVtYmVyKFVuaXRzLmNvbnZlcnRMZW5ndGgoci5leHBhbnNpb24xLCAnbW0nLCBsdSkpLCBsdSksDQogICAgICAgICAgICByZXN1bHRJdGVtKCdDb21wb25lbnQgMiBFeHBhbnNpb24nLCAnKycgKyBVbml0cy5mb3JtYXROdW1iZXIoVW5pdHMuY29udmVydExlbmd0aChyLmV4cGFuc2lvbjIsICdtbScsIGx1KSksIGx1KSwNCiAgICAgICAgICAgIHJlc3VsdEl0ZW0oJ1JlbGF0aXZlIEV4cGFuc2lvbiAoXHUwMzk0TF9yZWwpJywNCiAgICAgICAgICAgICAgICBVbml0cy5mb3JtYXROdW1iZXIoVW5pdHMuY29udmVydExlbmd0aChyLnJlbGF0aXZlLCAnbW0nLCBsdSkpLCBsdSwgdHJ1ZSksDQogICAgICAgICAgICByZXN1bHRJdGVtKCdDbGVhcmFuY2UgUmVxdWlyZWQgKG1pbiknLA0KICAgICAgICAgICAgICAgIFVuaXRzLmZvcm1hdE51bWJlcihVbml0cy5jb252ZXJ0TGVuZ3RoKHIuY2xlYXJhbmNlUmVxdWlyZWQsICdtbScsIGx1KSksIGx1KSwNCiAgICAgICAgICAgIHJlc3VsdEl0ZW0oJ0luaXRpYWwgQ2xlYXJhbmNlJywNCiAgICAgICAgICAgICAgICBVbml0cy5mb3JtYXROdW1iZXIoVW5pdHMuY29udmVydExlbmd0aChyLmluaXRpYWxDbGVhcmFuY2UsICdtbScsIGx1KSksIGx1KSwNCiAgICAgICAgICAgIHJlc3VsdEl0ZW0oJ1JlbWFpbmluZyBDbGVhcmFuY2UnLA0KICAgICAgICAgICAgICAgIFVuaXRzLmZvcm1hdE51bWJlcihVbml0cy5jb252ZXJ0TGVuZ3RoKHIucmVtYWluaW5nLCAnbW0nLCBsdSkpLCBsdSwgci5yZW1haW5pbmcgPD0gMCksDQogICAgICAgICAgICBgPGRpdiBjbGFzcz0icmVzdWx0LWl0ZW0gaGlnaGxpZ2h0Ij48ZGl2IGNsYXNzPSJyZXN1bHQtbGFiZWwiPlN0YXR1czwvZGl2Pg0KICAgICAgICAgICAgIDxzcGFuIGNsYXNzPSJjbGVhcmFuY2Utc3RhdHVzICR7ci5jbGVhcmFuY2VDbGFzc30iPiR7ci5jbGVhcmFuY2VTdGF0dXN9PC9zcGFuPjwvZGl2PmANCiAgICAgICAgXS5qb2luKCcnKTsNCiAgICB9DQoNCiAgICBmdW5jdGlvbiByZW5kZXJDb21wYXJpc29uVGFibGUoY29udGFpbmVyLCByKSB7DQogICAgICAgIGNvbnN0IGx1ID0gVW5pdHMubGVuZ3RoTGFiZWwoci5sZW5ndGhVbml0IHx8ICdtbScpOw0KICAgICAgICBjb25zdCB0YWJsZSA9IGANCiAgICAgICAgICAgIDx0YWJsZSBjbGFzcz0iY29tcGFyaXNvbi10YWJsZSI+DQogICAgICAgICAgICAgICAgPHRoZWFkPg0KICAgICAgICAgICAgICAgICAgICA8dHI+DQogICAgICAgICAgICAgICAgICAgICAgICA8dGg+UmFuazwvdGg+PHRoPk1hdGVyaWFsPC90aD48dGg+XHUwM2IxIChcdTAwZDcxMFx1MjA3Ylx1MjA3Ni9cdTAwYjBDKTwvdGg+DQogICAgICAgICAgICAgICAgICAgICAgICA8dGg+XHUwMzk0TCAoJHtsdX0pPC90aD48dGg+TFx1MjA4MiAoJHtsdX0pPC90aD48dGg+U3RyYWluIChcdTAzYmNcdTAzYjUpPC90aD48dGg+UmVsYXRpdmUgXHUwMzk0TDwvdGg+DQogICAgICAgICAgICAgICAgICAgIDwvdHI+DQogICAgICAgICAgICAgICAgPC90aGVhZD4NCiAgICAgICAgICAgICAgICA8dGJvZHk+DQogICAgICAgICAgICAgICAgICAgICR7ci5jb21wYXJpc29uUmVzdWx0cy5tYXAobSA9PiBgDQogICAgICAgICAgICAgICAgICAgICAgICA8dHI+DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRkIGNsYXNzPSJyYW5rIj4jJHttLnJhbmt9PC90ZD4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dGQ+JHttLm5hbWV9PC90ZD4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dGQ+JHtVbml0cy5mb3JtYXROdW1iZXIobS5hbHBoYSl9PC90ZD4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dGQ+JHtVbml0cy5mb3JtYXROdW1iZXIoVW5pdHMuY29udmVydExlbmd0aChtLmRlbHRhTCwgJ21tJywgbHUpKX08L3RkPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0ZD4ke1VuaXRzLmZvcm1hdE51bWJlcihVbml0cy5jb252ZXJ0TGVuZ3RoKG0uTDIsICdtbScsIGx1KSl9PC90ZD4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dGQ+JHtVbml0cy5mb3JtYXROdW1iZXIobS5zdHJhaW5Gb3JtYXR0ZWQubWljcm9zdHJhaW4pfTwvdGQ+DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRkPiR7VW5pdHMuZm9ybWF0TnVtYmVyKFVuaXRzLmNvbnZlcnRMZW5ndGgobS5yZWxhdGl2ZUV4cGFuc2lvbiwgJ21tJywgbHUpKX08L3RkPg0KICAgICAgICAgICAgICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgICAgICAgICAgYCkuam9pbignJyl9DQogICAgICAgICAgICAgICAgPC90Ym9keT4NCiAgICAgICAgICAgIDwvdGFibGU+DQogICAgICAgIGA7DQogICAgICAgIGNvbnRhaW5lci5pbm5lckhUTUwgPSB0YWJsZTsNCiAgICB9DQoNCiAgICBmdW5jdGlvbiBzaG93RXJyb3JzKGVycm9ycykgew0KICAgICAgICBjb25zdCBlbCA9ICQoJ2Vycm9yTWVzc2FnZXMnKTsNCiAgICAgICAgZWwuY2xhc3NMaXN0LnJlbW92ZSgnaGlkZGVuJyk7DQogICAgICAgIGVsLmlubmVySFRNTCA9IGA8dWw+JHtlcnJvcnMubWFwKGUgPT4gYDxsaT4ke2V9PC9saT5gKS5qb2luKCcnKX08L3VsPmA7DQogICAgfQ0KDQogICAgZnVuY3Rpb24gc2hvd1dhcm5pbmdzKHdhcm5pbmdzKSB7DQogICAgICAgIGNvbnN0IGVsID0gJCgnd2FybmluZ01lc3NhZ2VzJyk7DQogICAgICAgIGVsLmNsYXNzTGlzdC5yZW1vdmUoJ2hpZGRlbicpOw0KICAgICAgICBlbC5pbm5lckhUTUwgPSBgPHVsPiR7d2FybmluZ3MubWFwKHcgPT4gYDxsaT4ke3d9PC9saT5gKS5qb2luKCcnKX08L3VsPmA7DQogICAgfQ0KDQogICAgZnVuY3Rpb24gaGlkZU1lc3NhZ2VzKCkgew0KICAgICAgICAkKCdlcnJvck1lc3NhZ2VzJykuY2xhc3NMaXN0LmFkZCgnaGlkZGVuJyk7DQogICAgICAgICQoJ3dhcm5pbmdNZXNzYWdlcycpLmNsYXNzTGlzdC5hZGQoJ2hpZGRlbicpOw0KICAgIH0NCg0KICAgIC8vIFdvcmRQcmVzcyBtYXkgaW5qZWN0IEhUTUwgYWZ0ZXIgRE9NQ29udGVudExvYWRlZDsgc3VwcG9ydCBib3RoIGNhc2VzDQogICAgaWYgKGRvY3VtZW50LnJlYWR5U3RhdGUgPT09ICdsb2FkaW5nJykgew0KICAgICAgICBkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKCdET01Db250ZW50TG9hZGVkJywgaW5pdCk7DQogICAgfSBlbHNlIHsNCiAgICAgICAgaW5pdCgpOw0KICAgIH0NCn0pKCk7DQo=\";\nvar s=document.createElement(\"script\");\ns.type=\"text\/javascript\";\ns.text=atob(b);\nvar r=document.getElementById(\"thermal-expansion-calculator\");\nif(r){r.appendChild(s);}else{document.body.appendChild(s);}\n})();\n<\/script>\n","protected":false},"excerpt":{"rendered":"<p>The Thermal Expansion Calculator is a practical engineering tool designed to calculate dimensional changes in materials caused by temperature variations. By entering the original dimension,&#8230;<\/p>","protected":false},"author":2,"featured_media":24866,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"pmpro_default_level":"","_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_feature_clip_id":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_post_was_ever_published":false},"categories":[8647],"tags":[8712,8713,8583,8711],"class_list":["post-24865","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-materials-science-and-properties","tag-material-expansion","tag-temperature-change","tag-thermal-expansion","tag-thermal-growth","pmpro-has-access"],"acf":[],"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"https:\/\/www.mechstream.com\/wp-content\/uploads\/2026\/09\/Thermal-Expansion-Calculator.png","_links":{"self":[{"href":"https:\/\/www.mechstream.com\/es\/wp-json\/wp\/v2\/posts\/24865","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.mechstream.com\/es\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.mechstream.com\/es\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.mechstream.com\/es\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.mechstream.com\/es\/wp-json\/wp\/v2\/comments?post=24865"}],"version-history":[{"count":0,"href":"https:\/\/www.mechstream.com\/es\/wp-json\/wp\/v2\/posts\/24865\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.mechstream.com\/es\/wp-json\/wp\/v2\/media\/24866"}],"wp:attachment":[{"href":"https:\/\/www.mechstream.com\/es\/wp-json\/wp\/v2\/media?parent=24865"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.mechstream.com\/es\/wp-json\/wp\/v2\/categories?post=24865"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.mechstream.com\/es\/wp-json\/wp\/v2\/tags?post=24865"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}