diff --git a/coverage/clover.xml b/coverage/clover.xml new file mode 100644 index 00000000..5b506bc0 --- /dev/null +++ b/coverage/clover.xml @@ -0,0 +1,1531 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/coverage/lcov-report/base.css b/coverage/lcov-report/base.css new file mode 100644 index 00000000..f418035b --- /dev/null +++ b/coverage/lcov-report/base.css @@ -0,0 +1,224 @@ +body, html { + margin:0; padding: 0; + height: 100%; +} +body { + font-family: Helvetica Neue, Helvetica, Arial; + font-size: 14px; + color:#333; +} +.small { font-size: 12px; } +*, *:after, *:before { + -webkit-box-sizing:border-box; + -moz-box-sizing:border-box; + box-sizing:border-box; + } +h1 { font-size: 20px; margin: 0;} +h2 { font-size: 14px; } +pre { + font: 12px/1.4 Consolas, "Liberation Mono", Menlo, Courier, monospace; + margin: 0; + padding: 0; + -moz-tab-size: 2; + -o-tab-size: 2; + tab-size: 2; +} +a { color:#0074D9; text-decoration:none; } +a:hover { text-decoration:underline; } +.strong { font-weight: bold; } +.space-top1 { padding: 10px 0 0 0; } +.pad2y { padding: 20px 0; } +.pad1y { padding: 10px 0; } +.pad2x { padding: 0 20px; } +.pad2 { padding: 20px; } +.pad1 { padding: 10px; } +.space-left2 { padding-left:55px; } +.space-right2 { padding-right:20px; } +.center { text-align:center; } +.clearfix { display:block; } +.clearfix:after { + content:''; + display:block; + height:0; + clear:both; + visibility:hidden; + } +.fl { float: left; } +@media only screen and (max-width:640px) { + .col3 { width:100%; max-width:100%; } + .hide-mobile { display:none!important; } +} + +.quiet { + color: #7f7f7f; + color: rgba(0,0,0,0.5); +} +.quiet a { opacity: 0.7; } + +.fraction { + font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; + font-size: 10px; + color: #555; + background: #E8E8E8; + padding: 4px 5px; + border-radius: 3px; + vertical-align: middle; +} + +div.path a:link, div.path a:visited { color: #333; } +table.coverage { + border-collapse: collapse; + margin: 10px 0 0 0; + padding: 0; +} + +table.coverage td { + margin: 0; + padding: 0; + vertical-align: top; +} +table.coverage td.line-count { + text-align: right; + padding: 0 5px 0 20px; +} +table.coverage td.line-coverage { + text-align: right; + padding-right: 10px; + min-width:20px; +} + +table.coverage td span.cline-any { + display: inline-block; + padding: 0 5px; + width: 100%; +} +.missing-if-branch { + display: inline-block; + margin-right: 5px; + border-radius: 3px; + position: relative; + padding: 0 4px; + background: #333; + color: yellow; +} + +.skip-if-branch { + display: none; + margin-right: 10px; + position: relative; + padding: 0 4px; + background: #ccc; + color: white; +} +.missing-if-branch .typ, .skip-if-branch .typ { + color: inherit !important; +} +.coverage-summary { + border-collapse: collapse; + width: 100%; +} +.coverage-summary tr { border-bottom: 1px solid #bbb; } +.keyline-all { border: 1px solid #ddd; } +.coverage-summary td, .coverage-summary th { padding: 10px; } +.coverage-summary tbody { border: 1px solid #bbb; } +.coverage-summary td { border-right: 1px solid #bbb; } +.coverage-summary td:last-child { border-right: none; } +.coverage-summary th { + text-align: left; + font-weight: normal; + white-space: nowrap; +} +.coverage-summary th.file { border-right: none !important; } +.coverage-summary th.pct { } +.coverage-summary th.pic, +.coverage-summary th.abs, +.coverage-summary td.pct, +.coverage-summary td.abs { text-align: right; } +.coverage-summary td.file { white-space: nowrap; } +.coverage-summary td.pic { min-width: 120px !important; } +.coverage-summary tfoot td { } + +.coverage-summary .sorter { + height: 10px; + width: 7px; + display: inline-block; + margin-left: 0.5em; + background: url(sort-arrow-sprite.png) no-repeat scroll 0 0 transparent; +} +.coverage-summary .sorted .sorter { + background-position: 0 -20px; +} +.coverage-summary .sorted-desc .sorter { + background-position: 0 -10px; +} +.status-line { height: 10px; } +/* yellow */ +.cbranch-no { background: yellow !important; color: #111; } +/* dark red */ +.red.solid, .status-line.low, .low .cover-fill { background:#C21F39 } +.low .chart { border:1px solid #C21F39 } +.highlighted, +.highlighted .cstat-no, .highlighted .fstat-no, .highlighted .cbranch-no{ + background: #C21F39 !important; +} +/* medium red */ +.cstat-no, .fstat-no, .cbranch-no, .cbranch-no { background:#F6C6CE } +/* light red */ +.low, .cline-no { background:#FCE1E5 } +/* light green */ +.high, .cline-yes { background:rgb(230,245,208) } +/* medium green */ +.cstat-yes { background:rgb(161,215,106) } +/* dark green */ +.status-line.high, .high .cover-fill { background:rgb(77,146,33) } +.high .chart { border:1px solid rgb(77,146,33) } +/* dark yellow (gold) */ +.status-line.medium, .medium .cover-fill { background: #f9cd0b; } +.medium .chart { border:1px solid #f9cd0b; } +/* light yellow */ +.medium { background: #fff4c2; } + +.cstat-skip { background: #ddd; color: #111; } +.fstat-skip { background: #ddd; color: #111 !important; } +.cbranch-skip { background: #ddd !important; color: #111; } + +span.cline-neutral { background: #eaeaea; } + +.coverage-summary td.empty { + opacity: .5; + padding-top: 4px; + padding-bottom: 4px; + line-height: 1; + color: #888; +} + +.cover-fill, .cover-empty { + display:inline-block; + height: 12px; +} +.chart { + line-height: 0; +} +.cover-empty { + background: white; +} +.cover-full { + border-right: none !important; +} +pre.prettyprint { + border: none !important; + padding: 0 !important; + margin: 0 !important; +} +.com { color: #999 !important; } +.ignore-none { color: #999; font-weight: normal; } + +.wrapper { + min-height: 100%; + height: auto !important; + height: 100%; + margin: 0 auto -48px; +} +.footer, .push { + height: 48px; +} diff --git a/coverage/lcov-report/block-navigation.js b/coverage/lcov-report/block-navigation.js new file mode 100644 index 00000000..530d1ed2 --- /dev/null +++ b/coverage/lcov-report/block-navigation.js @@ -0,0 +1,87 @@ +/* eslint-disable */ +var jumpToCode = (function init() { + // Classes of code we would like to highlight in the file view + var missingCoverageClasses = ['.cbranch-no', '.cstat-no', '.fstat-no']; + + // Elements to highlight in the file listing view + var fileListingElements = ['td.pct.low']; + + // We don't want to select elements that are direct descendants of another match + var notSelector = ':not(' + missingCoverageClasses.join('):not(') + ') > '; // becomes `:not(a):not(b) > ` + + // Selector that finds elements on the page to which we can jump + var selector = + fileListingElements.join(', ') + + ', ' + + notSelector + + missingCoverageClasses.join(', ' + notSelector); // becomes `:not(a):not(b) > a, :not(a):not(b) > b` + + // The NodeList of matching elements + var missingCoverageElements = document.querySelectorAll(selector); + + var currentIndex; + + function toggleClass(index) { + missingCoverageElements + .item(currentIndex) + .classList.remove('highlighted'); + missingCoverageElements.item(index).classList.add('highlighted'); + } + + function makeCurrent(index) { + toggleClass(index); + currentIndex = index; + missingCoverageElements.item(index).scrollIntoView({ + behavior: 'smooth', + block: 'center', + inline: 'center' + }); + } + + function goToPrevious() { + var nextIndex = 0; + if (typeof currentIndex !== 'number' || currentIndex === 0) { + nextIndex = missingCoverageElements.length - 1; + } else if (missingCoverageElements.length > 1) { + nextIndex = currentIndex - 1; + } + + makeCurrent(nextIndex); + } + + function goToNext() { + var nextIndex = 0; + + if ( + typeof currentIndex === 'number' && + currentIndex < missingCoverageElements.length - 1 + ) { + nextIndex = currentIndex + 1; + } + + makeCurrent(nextIndex); + } + + return function jump(event) { + if ( + document.getElementById('fileSearch') === document.activeElement && + document.activeElement != null + ) { + // if we're currently focused on the search input, we don't want to navigate + return; + } + + switch (event.which) { + case 78: // n + case 74: // j + goToNext(); + break; + case 66: // b + case 75: // k + case 80: // p + goToPrevious(); + break; + } + }; +})(); +window.addEventListener('keydown', jumpToCode); diff --git a/coverage/lcov-report/favicon.png b/coverage/lcov-report/favicon.png new file mode 100644 index 00000000..c1525b81 Binary files /dev/null and b/coverage/lcov-report/favicon.png differ diff --git a/coverage/lcov-report/hooklib/src/index.html b/coverage/lcov-report/hooklib/src/index.html new file mode 100644 index 00000000..1661e63a --- /dev/null +++ b/coverage/lcov-report/hooklib/src/index.html @@ -0,0 +1,131 @@ + + + + + + Code coverage report for hooklib/src + + + + + + + + + +
+
+

All files hooklib/src

+
+ +
+ 100% + Statements + 8/8 +
+ + +
+ 100% + Branches + 0/0 +
+ + +
+ 100% + Functions + 2/2 +
+ + +
+ 100% + Lines + 8/8 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
index.ts +
+
0%0/00%0/00%0/00%0/0
interfaces.ts +
+
100%8/8100%0/0100%2/2100%8/8
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/hooklib/src/index.ts.html b/coverage/lcov-report/hooklib/src/index.ts.html new file mode 100644 index 00000000..388eec60 --- /dev/null +++ b/coverage/lcov-report/hooklib/src/index.ts.html @@ -0,0 +1,91 @@ + + + + + + Code coverage report for hooklib/src/index.ts + + + + + + + + + +
+
+

All files / hooklib/src index.ts

+
+ +
+ 0% + Statements + 0/0 +
+ + +
+ 0% + Branches + 0/0 +
+ + +
+ 0% + Functions + 0/0 +
+ + +
+ 0% + Lines + 0/0 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3  +  + 
export * from './interfaces'
+export * from './utils'
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/hooklib/src/interfaces.ts.html b/coverage/lcov-report/hooklib/src/interfaces.ts.html new file mode 100644 index 00000000..89f8c2a0 --- /dev/null +++ b/coverage/lcov-report/hooklib/src/interfaces.ts.html @@ -0,0 +1,361 @@ + + + + + + Code coverage report for hooklib/src/interfaces.ts + + + + + + + + + +
+
+

All files / hooklib/src interfaces.ts

+
+ +
+ 100% + Statements + 8/8 +
+ + +
+ 100% + Branches + 0/0 +
+ + +
+ 100% + Functions + 2/2 +
+ + +
+ 100% + Lines + 8/8 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +931x +1x +1x +1x +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +1x +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
export enum Command {
+  PrepareJob = 'prepare_job',
+  CleanupJob = 'cleanup_job',
+  RunContainerStep = 'run_container_step',
+  RunScriptStep = 'run_script_step'
+}
+ 
+export interface HookData {
+  command: Command
+  responseFile: string
+  args?: PrepareJobArgs | RunContainerStepArgs | RunScriptStepArgs
+  state?: { [key: string]: any }
+}
+ 
+export interface PrepareJobArgs {
+  container?: JobContainerInfo
+  services?: ServiceContainerInfo[]
+}
+ 
+export type RunContainerStepArgs = StepContainerInfo
+ 
+export interface RunScriptStepArgs {
+  entryPoint: string
+  entryPointArgs: string[]
+  environmentVariables?: { [key: string]: string }
+  prependPath?: string[]
+  workingDirectory: string
+}
+ 
+export interface ContainerInfo {
+  image?: string
+  entryPoint?: string
+  entryPointArgs?: string[]
+  createOptions?: string
+  environmentVariables?: { [key: string]: string }
+  userMountVolumes?: Mount[]
+  systemMountVolumes?: Mount[]
+  registry?: Registry
+  portMappings?: string[]
+}
+ 
+export interface ServiceContainerInfo extends ContainerInfo {
+  contextName: string
+  image: string
+}
+ 
+export interface JobContainerInfo extends ContainerInfo {
+  image: string
+  workingDirectory: string
+  systemMountVolumes: Mount[]
+}
+ 
+export interface StepContainerInfo extends ContainerInfo {
+  prependPath?: string[]
+  workingDirectory: string
+  dockerfile?: string
+  systemMountVolumes: Mount[]
+}
+ 
+export interface Mount {
+  sourceVolumePath: string
+  targetVolumePath: string
+  readOnly: boolean
+}
+ 
+export interface Registry {
+  username?: string
+  password?: string
+  serverUrl: string
+}
+ 
+export enum Protocol {
+  TCP = 'tcp',
+  UDP = 'udp'
+}
+ 
+export interface PrepareJobResponse {
+  state?: object
+  context?: ContainerContext
+  services?: { [key: string]: ContainerContext }
+  alpine: boolean
+}
+ 
+export interface ContainerContext {
+  id?: string
+  network?: string
+  ports?: { [key: string]: string }
+}
+ 
+export interface ContextPorts {
+  [source: string]: string // source -> target
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/hooklib/src/utils/index.html b/coverage/lcov-report/hooklib/src/utils/index.html new file mode 100644 index 00000000..0c2e10cc --- /dev/null +++ b/coverage/lcov-report/hooklib/src/utils/index.html @@ -0,0 +1,116 @@ + + + + + + Code coverage report for hooklib/src/utils + + + + + + + + + +
+
+

All files hooklib/src/utils

+
+ +
+ 58.82% + Statements + 10/17 +
+ + +
+ 100% + Branches + 12/12 +
+ + +
+ 50% + Functions + 2/4 +
+ + +
+ 58.82% + Lines + 10/17 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
index.ts +
+
58.82%10/17100%12/1250%2/458.82%10/17
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/hooklib/src/utils/index.ts.html b/coverage/lcov-report/hooklib/src/utils/index.ts.html new file mode 100644 index 00000000..cefc903f --- /dev/null +++ b/coverage/lcov-report/hooklib/src/utils/index.ts.html @@ -0,0 +1,211 @@ + + + + + + Code coverage report for hooklib/src/utils/index.ts + + + + + + + + + +
+
+

All files / hooklib/src/utils index.ts

+
+ +
+ 58.82% + Statements + 10/17 +
+ + +
+ 100% + Branches + 12/12 +
+ + +
+ 50% + Functions + 2/4 +
+ + +
+ 58.82% + Lines + 10/17 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +16x +1x +  +15x +1x +  +  +14x +  +  +  +  +  +14x +2x +12x +11x +  +1x +  + 
import * as events from 'events'
+import * as fs from 'fs'
+import * as os from 'os'
+import * as readline from 'readline'
+import { HookData } from '../interfaces'
+ 
+export async function getInputFromStdin(): Promise<HookData> {
+  let input = ''
+ 
+  const rl = readline.createInterface({
+    input: process.stdin
+  })
+ 
+  rl.on('line', line => {
+    input = line
+  })
+  await events.default.once(rl, 'close')
+  const inputJson = JSON.parse(input)
+  return inputJson as HookData
+}
+ 
+export function writeToResponseFile(filePath: string, message: any): void {
+  if (!filePath) {
+    throw new Error(`Expected file path`)
+  }
+  if (!fs.existsSync(filePath)) {
+    throw new Error(`Missing file at path: ${filePath}`)
+  }
+ 
+  fs.appendFileSync(filePath, `${toCommandValue(message)}${os.EOL}`, {
+    encoding: 'utf8'
+  })
+}
+ 
+function toCommandValue(input: any): string {
+  if (input === null || input === undefined) {
+    return ''
+  } else if (typeof input === 'string' || input instanceof String) {
+    return input as string
+  }
+  return JSON.stringify(input)
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/index.html b/coverage/lcov-report/index.html new file mode 100644 index 00000000..c2d24aac --- /dev/null +++ b/coverage/lcov-report/index.html @@ -0,0 +1,191 @@ + + + + + + Code coverage report for All files + + + + + + + + + +
+
+

All files

+
+ +
+ 84.41% + Statements + 1257/1489 +
+ + +
+ 81.38% + Branches + 660/811 +
+ + +
+ 82.89% + Functions + 189/228 +
+ + +
+ 84.64% + Lines + 1240/1465 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
hooklib/src +
+
100%8/8100%0/0100%2/2100%8/8
hooklib/src/utils +
+
58.82%10/17100%12/1250%2/458.82%10/17
k8s/src +
+
0%0/220%0/70%0/10%0/22
k8s/src/hooks +
+
95.31%285/29984.81%134/15886.2%25/2995.3%284/298
k8s/src/k8s +
+
75.37%560/74371.71%251/35074.59%91/12275.68%551/728
k8s/src/k8s/utils +
+
98.5%394/40092.6%263/28498.57%69/7098.72%387/392
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/k8s/src/hooks/cleanup-job.ts.html b/coverage/lcov-report/k8s/src/hooks/cleanup-job.ts.html new file mode 100644 index 00000000..e554b4de --- /dev/null +++ b/coverage/lcov-report/k8s/src/hooks/cleanup-job.ts.html @@ -0,0 +1,145 @@ + + + + + + Code coverage report for k8s/src/hooks/cleanup-job.ts + + + + + + + + + +
+
+

All files / k8s/src/hooks cleanup-job.ts

+
+ +
+ 100% + Statements + 5/5 +
+ + +
+ 100% + Branches + 2/2 +
+ + +
+ 100% + Functions + 1/1 +
+ + +
+ 100% + Lines + 5/5 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21  +  +  +  +  +  +  +  +  +  +  +4x +3x +3x +  +1x +  +  +4x +  + 
import * as core from '@actions/core'
+import { formatError } from '../k8s/utils'
+import { prunePods, pruneSecrets } from '../k8s'
+import {
+  collectAndPushNpuMetrics,
+  NPU_COLLECT_TIMEOUT_MS,
+  npuMetricsEnabled,
+  withTimeout
+} from '../k8s/utils/npu-metrics'
+ 
+export async function cleanupJob(): Promise<void> {
+  if (npuMetricsEnabled()) {
+    try {
+      await withTimeout(collectAndPushNpuMetrics(), NPU_COLLECT_TIMEOUT_MS)
+    } catch (err) {
+      core.debug(`npu-metrics: collection failed: ${formatError(err)}`)
+    }
+  }
+  await Promise.all([prunePods(), pruneSecrets()])
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/k8s/src/hooks/constants.ts.html b/coverage/lcov-report/k8s/src/hooks/constants.ts.html new file mode 100644 index 00000000..925ad135 --- /dev/null +++ b/coverage/lcov-report/k8s/src/hooks/constants.ts.html @@ -0,0 +1,280 @@ + + + + + + Code coverage report for k8s/src/hooks/constants.ts + + + + + + + + + +
+
+

All files / k8s/src/hooks constants.ts

+
+ +
+ 75% + Statements + 15/20 +
+ + +
+ 25% + Branches + 1/4 +
+ + +
+ 88.88% + Functions + 8/9 +
+ + +
+ 75% + Lines + 15/20 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66  +  +  +86x +86x +  +  +  +  +86x +  +  +  +42x +  +  +  +  +  +  +18x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +4x +  +  +  +  +  +7x +7x +7x +7x +7x +  +  +  +  +17x +  +  +  +10x +  +  +  +10x +  +  +  +7x +  +  + 
import { v4 as uuidv4 } from 'uuid'
+ 
+export function getRunnerPodName(): string {
+  const name = process.env.ACTIONS_RUNNER_POD_NAME
+  Iif (!name) {
+    throw new Error(
+      "'ACTIONS_RUNNER_POD_NAME' env is required, please contact your self hosted runner administrator"
+    )
+  }
+  return name
+}
+ 
+export function getJobPodName(): string {
+  return `${getRunnerPodName().substring(
+    0,
+    MAX_POD_NAME_LENGTH - '-workflow'.length
+  )}-workflow`
+}
+ 
+export function getStepPodName(): string {
+  return `${getRunnerPodName().substring(
+    0,
+    MAX_POD_NAME_LENGTH - ('-step-'.length + STEP_POD_NAME_SUFFIX_LENGTH)
+  )}-step-${uuidv4().substring(0, STEP_POD_NAME_SUFFIX_LENGTH)}`
+}
+ 
+export function getVolumeClaimName(): string {
+  const name = process.env.ACTIONS_RUNNER_CLAIM_NAME
+  if (!name) {
+    return `${getRunnerPodName()}-work`
+  }
+  return name
+}
+ 
+export function getSecretName(): string {
+  return `${getRunnerPodName().substring(
+    0,
+    MAX_POD_NAME_LENGTH - ('-secret-'.length + STEP_POD_NAME_SUFFIX_LENGTH)
+  )}-secret-${uuidv4().substring(0, STEP_POD_NAME_SUFFIX_LENGTH)}`
+}
+ 
+export const MAX_POD_NAME_LENGTH = 63
+export const STEP_POD_NAME_SUFFIX_LENGTH = 8
+export const CONTAINER_EXTENSION_PREFIX = '$'
+export const JOB_CONTAINER_NAME = 'job'
+export const JOB_CONTAINER_EXTENSION_NAME = '$job'
+ 
+export class RunnerInstanceLabel {
+  private podName: string
+  constructor() {
+    this.podName = getRunnerPodName()
+  }
+ 
+  get key(): string {
+    return 'runner-pod'
+  }
+ 
+  get value(): string {
+    return this.podName
+  }
+ 
+  toString(): string {
+    return `runner-pod=${this.podName}`
+  }
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/k8s/src/hooks/index.html b/coverage/lcov-report/k8s/src/hooks/index.html new file mode 100644 index 00000000..aa7488e6 --- /dev/null +++ b/coverage/lcov-report/k8s/src/hooks/index.html @@ -0,0 +1,191 @@ + + + + + + Code coverage report for k8s/src/hooks + + + + + + + + + +
+
+

All files k8s/src/hooks

+
+ +
+ 95.31% + Statements + 285/299 +
+ + +
+ 84.81% + Branches + 134/158 +
+ + +
+ 86.2% + Functions + 25/29 +
+ + +
+ 95.3% + Lines + 284/298 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
cleanup-job.ts +
+
100%5/5100%2/2100%1/1100%5/5
constants.ts +
+
75%15/2025%1/488.88%8/975%15/20
index.ts +
+
0%0/00%0/00%0/00%0/0
prepare-job.ts +
+
97.63%124/12786.66%78/9088.88%8/997.63%124/127
run-container-step.ts +
+
95.09%97/10286%43/5071.42%5/795.09%97/102
run-script-step.ts +
+
97.77%44/4583.33%10/12100%3/397.72%43/44
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/k8s/src/hooks/index.ts.html b/coverage/lcov-report/k8s/src/hooks/index.ts.html new file mode 100644 index 00000000..14382ac4 --- /dev/null +++ b/coverage/lcov-report/k8s/src/hooks/index.ts.html @@ -0,0 +1,97 @@ + + + + + + Code coverage report for k8s/src/hooks/index.ts + + + + + + + + + +
+
+

All files / k8s/src/hooks index.ts

+
+ +
+ 0% + Statements + 0/0 +
+ + +
+ 0% + Branches + 0/0 +
+ + +
+ 0% + Functions + 0/0 +
+ + +
+ 0% + Lines + 0/0 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5  +  +  +  + 
export * from './cleanup-job'
+export * from './prepare-job'
+export * from './run-script-step'
+export * from './run-container-step'
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/k8s/src/hooks/prepare-job.ts.html b/coverage/lcov-report/k8s/src/hooks/prepare-job.ts.html new file mode 100644 index 00000000..b1421e34 --- /dev/null +++ b/coverage/lcov-report/k8s/src/hooks/prepare-job.ts.html @@ -0,0 +1,1174 @@ + + + + + + Code coverage report for k8s/src/hooks/prepare-job.ts + + + + + + + + + +
+
+

All files / k8s/src/hooks prepare-job.ts

+
+ +
+ 97.63% + Statements + 124/127 +
+ + +
+ 86.66% + Branches + 78/90 +
+ + +
+ 88.88% + Functions + 8/9 +
+ + +
+ 97.63% + Lines + 124/127 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263 +264 +265 +266 +267 +268 +269 +270 +271 +272 +273 +274 +275 +276 +277 +278 +279 +280 +281 +282 +283 +284 +285 +286 +287 +288 +289 +290 +291 +292 +293 +294 +295 +296 +297 +298 +299 +300 +301 +302 +303 +304 +305 +306 +307 +308 +309 +310 +311 +312 +313 +314 +315 +316 +317 +318 +319 +320 +321 +322 +323 +324 +325 +326 +327 +328 +329 +330 +331 +332 +333 +334 +335 +336 +337 +338 +339 +340 +341 +342 +343 +344 +345 +346 +347 +348 +349 +350 +351 +352 +353 +354 +355 +356 +357 +358 +359 +360 +361 +362 +363 +364  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +20x +1x +  +  +19x +  +19x +  +19x +19x +18x +  +  +  +  +  +18x +  +  +19x +19x +19x +4x +4x +6x +6x +  +  +4x +4x +6x +6x +6x +  +  +6x +4x +  +2x +  +  +6x +6x +6x +  +  +  +19x +1x +  +  +18x +18x +18x +  +  +  +  +  +  +  +6x +6x +  +  +  +  +  +  +6x +6x +  +  +  +  +  +  +6x +6x +  +  +6x +  +6x +  +  +6x +  +  +5x +5x +  +  +5x +5x +5x +2x +  +  +2x +  +  +  +  +  +6x +  +  +  +  +  +  +  +  +  +6x +  +  +12x +1x +  +11x +  +  +  +20x +20x +1x +  +10x +  +  +10x +2x +  +  +10x +10x +  +  +  +  +  +  +1x +  +  +  +1x +1x +  +  +9x +  +9x +2x +  +  +  +  +  +2x +2x +2x +  +  +  +  +  +  +  +2x +  +  +9x +  +9x +9x +9x +  +  +  +  +1x +1x +1x +  +8x +8x +  +  +  +  +  +  +  +  +  +8x +  +  +8x +  +  +  +  +  +  +  +8x +8x +  +8x +8x +8x +8x +  +  +  +  +  +8x +  +  +  +  +  +8x +  +4x +  +  +  +4x +10x +  +6x +6x +1x +1x +1x +  +  +  +  +6x +  +  +  +  +  +  +8x +  +  +  +  +  +  +  +  +35x +1x +1x +  +  +35x +  +  +  +  +35x +1x +  +  +35x +28x +  +  +35x +20x +  +  +35x +35x +  +  +2x +1x +  +  +  +35x +  +  +  +  +35x +34x +  +  +  +  +  +35x +  +35x +34x +  +  +1x +1x +  +  +35x +1x +  +  +1x +  + 
import * as core from '@actions/core'
+import * as k8s from '@kubernetes/client-node'
+import {
+  JobContainerInfo,
+  ContextPorts,
+  PrepareJobArgs,
+  writeToResponseFile,
+  ServiceContainerInfo
+} from 'hooklib'
+import {
+  containerPorts,
+  createJobPod,
+  isPodContainerAlpine,
+  prunePods,
+  waitForPodPhases,
+  getPrepareJobTimeoutSeconds,
+  execCpToPod,
+  execPodStep
+} from '../k8s'
+import {
+  CONTAINER_VOLUMES,
+  DEFAULT_CONTAINER_ENTRY_POINT,
+  DEFAULT_CONTAINER_ENTRY_POINT_ARGS,
+  formatError,
+  generateContainerName,
+  mergeContainerWithOptions,
+  readExtensionFromFile,
+  PodPhase,
+  fixArgs,
+  prepareJobScript
+} from '../k8s/utils'
+import {
+  CONTAINER_EXTENSION_PREFIX,
+  getJobPodName,
+  JOB_CONTAINER_NAME
+} from './constants'
+import { maybeInjectNpuMetrics } from '../k8s/utils/npu-metrics'
+import { dirname } from 'path'
+ 
+export async function prepareJob(
+  args: PrepareJobArgs,
+  responseFile
+): Promise<void> {
+  if (!args.container) {
+    throw new Error('Job Container is required.')
+  }
+ 
+  await prunePods()
+ 
+  const extension = readExtensionFromFile()
+ 
+  let container: k8s.V1Container | undefined = undefined
+  if (args.container?.image) {
+    container = createContainerSpec(
+      args.container,
+      JOB_CONTAINER_NAME,
+      true,
+      extension
+    )
+    maybeInjectNpuMetrics(container)
+  }
+ 
+  let services: k8s.V1Container[] = []
+  let serviceNames: string[] = []
+  if (args.services?.length) {
+    const occurrences = new Map<string, number>()
+    for (const s of args.services) {
+      const base = generateContainerName(s.image)
+      occurrences.set(base, (occurrences.get(base) || 0) + 1)
+    }
+ 
+    const indices = new Map<string, number>()
+    services = args.services.map(service => {
+      const base = generateContainerName(service.image)
+      const total = occurrences.get(base) || 0
+      const idx = indices.get(base) || 0
+ 
+      let name: string
+      if (total > 1) {
+        name = `${base}-${idx}`
+      } else {
+        name = base
+      }
+ 
+      indices.set(base, idx + 1)
+      serviceNames.push(name)
+      return createContainerSpec(service, name, false, extension)
+    })
+  }
+ 
+  if (!container && !services?.length) {
+    throw new Error('No containers exist, skipping hook invocation')
+  }
+ 
+  let createdPod: k8s.V1Pod | undefined = undefined
+  try {
+    createdPod = await createJobPod(
+      getJobPodName(),
+      container,
+      services,
+      args.container.registry,
+      extension
+    )
+  } catch (err) {
+    await prunePods()
+    core.debug(`createPod failed: ${JSON.stringify(err)}`)
+    // The k8s client throws HttpException whose message is a multi-line string
+    // containing the raw HTTP dump. Extract the human-readable "message" field
+    // from the embedded JSON body so the log shows something like:
+    //   failed to create job pod:
+    //     spec.volumes[5].name: Duplicate value: "bad-hostpath"
+    // instead of the full HTTP dump.
+    const raw = err instanceof Error ? err.message : String(err)
+    let detail = raw
+    // The k8s HttpException message is a multi-line dump:
+    //   HTTP-Code: 422
+    //   Message: Unknown API Status Code!
+    //   Body: "{\"kind\":\"Status\",\"message\":\"...\\n\"}"
+    //   Headers: {...}
+    // Extract the Body JSON string, unescape it, and pull out "message".
+    try {
+      const bodyStart = raw.indexOf('Body: "')
+      // The boundary may be '"\nHeaders:' (real newline) or the literal
+      // string ends before Headers — use the last '"' before 'Headers:' as fallback
+      const headersIdx = raw.indexOf('Headers:')
+      const bodyEnd =
+        headersIdx !== -1
+          ? raw.lastIndexOf('"', headersIdx) // last " before Headers:
+          : raw.indexOf('"\nHeaders:')
+      if (bodyStart !== -1 && bodyEnd !== -1 && bodyEnd > bodyStart) {
+        // Body content is a JSON string literal (without surrounding quotes).
+        // Wrap it in quotes and JSON.parse to properly unescape \" \\ \n \t etc.
+        const escaped = raw.substring(bodyStart + 7, bodyEnd)
+        const bodyStr = JSON.parse('"' + escaped + '"')
+        // bodyStr may be plain text (e.g. 502 Bad Gateway) instead of JSON.
+        // Parse separately so a non-JSON body still yields a friendly message.
+        try {
+          const parsed = JSON.parse(bodyStr)
+          if (typeof parsed?.message === 'string') {
+            detail = parsed.message
+          }
+        } catch {
+          detail = bodyStr
+        }
+      }
+    } catch {
+      // Parsing failed — fall through and show the raw string
+    }
+    const errorMessage = [
+      'failed to create job pod:',
+      `  ✗ ${detail}`,
+      '-'.repeat(60),
+      '  → Pod spec was rejected by the k8s API. Check:',
+      '    - resources.requests does not exceed resources.limits',
+      '    - volumeMounts reference a volume defined in spec.volumes',
+      '    - envFrom / valueFrom reference existing Secrets / ConfigMaps',
+      '    - Field types match the k8s schema (kubectl explain pod.spec.containers)'
+    ].join('\n')
+    throw new Error(errorMessage)
+  }
+ 
+  if (!createdPod?.metadata?.name) {
+    throw new Error('created pod should have metadata.name')
+  }
+  core.debug(
+    `Job pod created, waiting for it to come online ${createdPod?.metadata?.name}`
+  )
+ 
+  const runnerWorkspaceEnv = process.env.RUNNER_WORKSPACE
+  if (!runnerWorkspaceEnv) {
+    throw new Error('RUNNER_WORKSPACE environment variable is not set')
+  }
+  const runnerWorkspace = dirname(runnerWorkspaceEnv)
+ 
+  let prepareScript: { containerPath: string; runnerPath: string } | undefined
+  if (args.container?.userMountVolumes?.length) {
+    prepareScript = prepareJobScript(args.container.userMountVolumes || [])
+  }
+ 
+  try {
+    await waitForPodPhases(
+      createdPod.metadata.name,
+      new Set([PodPhase.RUNNING]),
+      new Set([PodPhase.PENDING]),
+      getPrepareJobTimeoutSeconds()
+    )
+  } catch (err) {
+    await prunePods()
+    // Unwrap nested "Error: " prefix so the message renders as:
+    //   pod failed to come online:
+    //   <detail from waitForPodPhases, already formatted with sections>
+    const detail = err instanceof Error ? err.message : String(err)
+    throw new Error(`pod failed to come online:\n${detail}`)
+  }
+ 
+  await execCpToPod(createdPod.metadata.name, runnerWorkspace, '/__w')
+ 
+  if (prepareScript) {
+    await execPodStep(
+      ['sh', '-e', prepareScript.containerPath],
+      createdPod.metadata.name,
+      JOB_CONTAINER_NAME
+    )
+ 
+    const promises: Promise<void>[] = []
+    for (const vol of args?.container?.userMountVolumes || []) {
+      promises.push(
+        execCpToPod(
+          createdPod.metadata.name,
+          vol.sourceVolumePath,
+          vol.targetVolumePath
+        )
+      )
+    }
+    await Promise.all(promises)
+  }
+ 
+  core.debug('Job pod is ready for traffic')
+ 
+  let isAlpine = false
+  try {
+    isAlpine = await isPodContainerAlpine(
+      createdPod.metadata.name,
+      JOB_CONTAINER_NAME
+    )
+  } catch (err) {
+    const message = formatError(err)
+    core.debug(`Failed to determine if the pod is alpine: ${message}`)
+    throw new Error(`failed to determine if the pod is alpine: ${message}`)
+  }
+  core.debug(`Setting isAlpine to ${isAlpine}`)
+  generateResponseFile(responseFile, args, createdPod, isAlpine, serviceNames)
+}
+ 
+function generateResponseFile(
+  responseFile: string,
+  args: PrepareJobArgs,
+  appPod: k8s.V1Pod,
+  isAlpine: boolean,
+  serviceNames?: string[]
+): void {
+  Iif (!appPod.metadata?.name) {
+    throw new Error('app pod must have metadata.name specified')
+  }
+  const response = {
+    state: {
+      jobPod: appPod.metadata.name
+    },
+    context: {},
+    isAlpine
+  }
+ 
+  const mainContainer = appPod.spec?.containers?.find(
+    c => c.name === JOB_CONTAINER_NAME
+  )
+  Eif (mainContainer) {
+    const mainContainerContextPorts: ContextPorts = {}
+    Eif (mainContainer?.ports) {
+      for (const port of mainContainer.ports) {
+        mainContainerContextPorts[port.containerPort] =
+          mainContainerContextPorts.hostPort
+      }
+    }
+ 
+    response.context['container'] = {
+      image: mainContainer.image,
+      ports: mainContainerContextPorts
+    }
+  }
+ 
+  if (args.services?.length) {
+    const serviceContainerNames =
+      serviceNames && serviceNames.length
+        ? serviceNames
+        : args.services?.map(s => generateContainerName(s.image)) || []
+ 
+    response.context['services'] = appPod?.spec?.containers
+      ?.filter(c => serviceContainerNames.includes(c.name))
+      .map(c => {
+        const ctxPorts: ContextPorts = {}
+        if (c.ports?.length) {
+          for (const port of c.ports) {
+            Eif (port.containerPort && port.hostPort) {
+              ctxPorts[port.containerPort.toString()] = port.hostPort.toString()
+            }
+          }
+        }
+ 
+        return {
+          image: c.image,
+          ports: ctxPorts
+        }
+      })
+  }
+ 
+  writeToResponseFile(responseFile, JSON.stringify(response))
+}
+ 
+export function createContainerSpec(
+  container: JobContainerInfo | ServiceContainerInfo,
+  name: string,
+  jobContainer = false,
+  extension?: k8s.V1PodTemplateSpec
+): k8s.V1Container {
+  if (!container.entryPoint && jobContainer) {
+    container.entryPoint = DEFAULT_CONTAINER_ENTRY_POINT
+    container.entryPointArgs = DEFAULT_CONTAINER_ENTRY_POINT_ARGS
+  }
+ 
+  const podContainer = {
+    name,
+    image: container.image,
+    ports: containerPorts(container)
+  } as k8s.V1Container
+  if (container['workingDirectory']) {
+    podContainer.workingDir = container['workingDirectory']
+  }
+ 
+  if (container.entryPoint) {
+    podContainer.command = [container.entryPoint]
+  }
+ 
+  if (container.entryPointArgs && container.entryPointArgs.length > 0) {
+    podContainer.args = fixArgs(container.entryPointArgs)
+  }
+ 
+  podContainer.env = []
+  for (const [key, value] of Object.entries(
+    container['environmentVariables'] || {}
+  )) {
+    if (value && key !== 'HOME') {
+      podContainer.env.push({ name: key, value })
+    }
+  }
+ 
+  podContainer.env.push({
+    name: 'GITHUB_ACTIONS',
+    value: 'true'
+  })
+ 
+  if (!('CI' in (container['environmentVariables'] || {}))) {
+    podContainer.env.push({
+      name: 'CI',
+      value: 'true'
+    })
+  }
+ 
+  podContainer.volumeMounts = CONTAINER_VOLUMES
+ 
+  if (!extension) {
+    return podContainer
+  }
+ 
+  const from = extension.spec?.containers?.find(
+    c => c.name === CONTAINER_EXTENSION_PREFIX + name
+  )
+ 
+  if (from) {
+    mergeContainerWithOptions(podContainer, from)
+  }
+ 
+  return podContainer
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/k8s/src/hooks/run-container-step.ts.html b/coverage/lcov-report/k8s/src/hooks/run-container-step.ts.html new file mode 100644 index 00000000..d8f76429 --- /dev/null +++ b/coverage/lcov-report/k8s/src/hooks/run-container-step.ts.html @@ -0,0 +1,898 @@ + + + + + + Code coverage report for k8s/src/hooks/run-container-step.ts + + + + + + + + + +
+
+

All files / k8s/src/hooks run-container-step.ts

+
+ +
+ 95.09% + Statements + 97/102 +
+ + +
+ 86% + Branches + 43/50 +
+ + +
+ 71.42% + Functions + 5/7 +
+ + +
+ 95.09% + Lines + 97/102 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263 +264 +265 +266 +267 +268 +269 +270 +271 +272  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +20x +1x +  +  +19x +1x +  +  +  +  +18x +20x +20x +17x +  +  +18x +  +18x +18x +  +  +18x +18x +  +2x +2x +2x +  +  +16x +1x +  +  +  +  +  +15x +  +15x +15x +  +  +  +  +  +  +14x +14x +14x +1x +  +  +  +13x +13x +13x +13x +1x +  +12x +  +12x +  +  +12x +  +12x +  +  +  +  +  +  +  +12x +  +12x +  +12x +12x +12x +  +  +  +  +10x +3x +  +  +  +  +  +7x +  +  +  +  +7x +  +9x +  +9x +  +  +  +  +7x +  +2x +2x +  +12x +  +  +12x +12x +11x +11x +1x +1x +  +  +  +  +  +  +12x +12x +  +15x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +7x +7x +7x +  +7x +7x +6x +5x +  +7x +7x +4x +  +4x +  +  +  +4x +1x +1x +1x +  +  +  +3x +  +  +3x +  +  +  +  +  +2x +  +6x +1x +  +  +  +  +  +1x +  +  +7x +1x +  +2x +  +1x +  +  +7x +7x +3x +  +7x +  +  +  +  +  +  +18x +18x +18x +18x +18x +18x +  +18x +  +18x +18x +  +  +  +  +  +18x +  +  +  +  +  + 
import * as core from '@actions/core'
+import * as fs from 'fs'
+import * as k8s from '@kubernetes/client-node'
+import { RunContainerStepArgs } from 'hooklib'
+import { dirname } from 'path'
+import {
+  createContainerStepPod,
+  deletePod,
+  describePodFailure,
+  execCpFromPod,
+  execCpToPod,
+  execPodStepWithOutput,
+  getContainerTerminatedErrors,
+  getPodByName,
+  getPrepareJobTimeoutSeconds,
+  getTerminatedReasonHint,
+  waitForPodPhases
+} from '../k8s'
+import {
+  CONTAINER_VOLUMES,
+  formatError,
+  mergeContainerWithOptions,
+  PodPhase,
+  readExtensionFromFile,
+  DEFAULT_CONTAINER_ENTRY_POINT_ARGS,
+  writeContainerStepScript
+} from '../k8s/utils'
+import {
+  getJobPodName,
+  getStepPodName,
+  JOB_CONTAINER_EXTENSION_NAME,
+  JOB_CONTAINER_NAME
+} from './constants'
+import { maybeInjectNpuMetrics } from '../k8s/utils/npu-metrics'
+ 
+export async function runContainerStep(
+  stepContainer: RunContainerStepArgs
+): Promise<number> {
+  if (stepContainer.dockerfile) {
+    throw new Error('Building container actions is not currently supported')
+  }
+ 
+  if (!stepContainer.entryPoint) {
+    throw new Error(
+      'failed to start the container since the entrypoint is overwritten'
+    )
+  }
+ 
+  const envs = stepContainer.environmentVariables || {}
+  envs['GITHUB_ACTIONS'] = 'true'
+  if (!('CI' in envs)) {
+    envs.CI = 'true'
+  }
+ 
+  const extension = readExtensionFromFile()
+ 
+  const container = createContainerSpec(stepContainer, extension)
+  maybeInjectNpuMetrics(container)
+ 
+  let pod: k8s.V1Pod
+  try {
+    pod = await createContainerStepPod(getStepPodName(), container, extension)
+  } catch (err) {
+    const message = formatError(err)
+    core.debug(`createContainerStepPod failed: ${message}`)
+    throw new Error(`failed to run container step: ${message}`)
+  }
+ 
+  if (!pod.metadata?.name) {
+    throw new Error(
+      `Expected job ${JSON.stringify(
+        pod
+      )} to have correctly set the metadata.name`
+    )
+  }
+  const podName = pod.metadata.name
+ 
+  try {
+    await waitForPodPhases(
+      podName,
+      new Set([PodPhase.RUNNING]),
+      new Set([PodPhase.PENDING, PodPhase.UNKNOWN]),
+      getPrepareJobTimeoutSeconds()
+    )
+ 
+    const runnerWorkspaceEnv = process.env.RUNNER_WORKSPACE
+    const githubWorkspaceEnv = process.env.GITHUB_WORKSPACE
+    if (!runnerWorkspaceEnv || !githubWorkspaceEnv) {
+      throw new Error(
+        'RUNNER_WORKSPACE or GITHUB_WORKSPACE environment variable is not set'
+      )
+    }
+    const runnerWorkspace = dirname(runnerWorkspaceEnv)
+    const githubWorkspace = githubWorkspaceEnv
+    const parts = githubWorkspace.split('/').slice(-2)
+    if (parts.length !== 2) {
+      throw new Error(`Invalid github workspace directory: ${githubWorkspace}`)
+    }
+    const relativeWorkspace = parts.join('/')
+ 
+    core.debug(
+      `Copying files from pod ${getJobPodName()} to ${runnerWorkspace}/${relativeWorkspace}`
+    )
+    await execCpFromPod(getJobPodName(), `/__w`, `${runnerWorkspace}`)
+ 
+    const { containerPath, runnerPath } = writeContainerStepScript(
+      `${runnerWorkspace}/__w/_temp`,
+      githubWorkspace,
+      stepContainer.entryPoint,
+      stepContainer.entryPointArgs,
+      envs
+    )
+ 
+    await execCpToPod(podName, `${runnerWorkspace}/__w`, '/__w')
+ 
+    fs.rmSync(`${runnerWorkspace}/__w`, { recursive: true, force: true })
+ 
+    try {
+      core.debug(`Executing container step script in pod ${podName}`)
+      const { code, output } = await execPodStepWithOutput(
+        ['sh', '-e', containerPath],
+        pod.metadata.name,
+        JOB_CONTAINER_NAME
+      )
+      if (code === 0) {
+        return 0
+      }
+      // Non-zero exit: surface a structured error so the user can tell whether
+      // it was their script or the container that failed. Read container
+      // status BEFORE deletePod runs (in the outer finally) to inspect the
+      // terminated reason, if it is already available.
+      const classification = await classifyScriptError(
+        pod.metadata.name,
+        code,
+        output
+      )
+      throw new Error(classification)
+    } catch (err) {
+      core.debug(`execPodStep failed: ${formatError(err)}`)
+      // Re-throw our classified errors verbatim; wrap anything else.
+      if (
+        err instanceof Error &&
+        (err.message.startsWith('Step failed:') ||
+          err.message.startsWith('failed to run script step'))
+      ) {
+        throw err
+      }
+      const message = formatError(err)
+      throw new Error(`failed to run container step: ${message}`)
+    } finally {
+      fs.rmSync(runnerPath, { force: true })
+    }
+  } catch (error) {
+    try {
+      const errorPod = await getPodByName(podName)
+      const terminatedErrors = getContainerTerminatedErrors(errorPod)
+      if (terminatedErrors.length > 0) {
+        const details = await describePodFailure(podName)
+        core.error(
+          `Pod ${podName} has unrecoverable container errors:\n${terminatedErrors.join('\n')}\n${details}`
+        )
+      }
+    } catch {
+      // Best-effort: pod may already be deleted or unreachable
+    }
+    core.error(`Failed to run container step: ${error}`)
+    throw error
+  } finally {
+    await deletePod(podName).catch(err => {
+      core.error(`Failed to delete step pod ${podName}: ${err}`)
+    })
+  }
+}
+ 
+// Inspect the pod's container status to determine whether a non-zero exit
+// code came from the user's script (container terminated cleanly with
+// reason=Completed) or from a container-level failure (OOMKilled, etc.).
+// The container state may not yet be 'terminated' when called (k8s updates
+// it asynchronously), so we default to treating unknown state as a script
+// issue and let the user check their script first.
+async function classifyScriptError(
+  podName: string,
+  exitCode: number,
+  tailOutput: string
+): Promise<string> {
+  const sep = '-'.repeat(60)
+  const errors: string[] = [`  ✗ exit code: ${exitCode}`]
+  const sections: string[] = []
+ 
+  try {
+    const pod = await getPodByName(podName)
+    const cs = pod.status?.containerStatuses?.find(
+      s => s.name === JOB_CONTAINER_NAME
+    )
+    const term = cs?.state?.terminated
+    if (term) {
+      const reason = term.reason ?? 'Completed'
+      const isContainerFault =
+        reason === 'OOMKilled' ||
+        reason === 'Error' ||
+        reason === 'FailedPostStartHookError' ||
+        (term.exitCode === 137 && reason !== 'Completed')
+      if (isContainerFault) {
+        const detail = term.message ? `\n    ${term.message}` : ''
+        const hint = `\n${getTerminatedReasonHint(reason, term.exitCode)}`
+        errors.push(
+          `  ✗ container "${JOB_CONTAINER_NAME}": ${reason} (exit code ${term.exitCode})${detail}${hint}`
+        )
+      } else {
+        errors.push(
+          `  → your script exited with a non-zero code; please check your script for errors`
+        )
+        sections.push(
+          `Container status: ${reason} (exit code ${term.exitCode})`
+        )
+      }
+    } else {
+      // Container state unavailable — treat as script issue by default
+      errors.push(`  → please check your script for errors`)
+    }
+    if (cs?.state?.waiting) {
+      errors.push(
+        `  ✗ container "${JOB_CONTAINER_NAME}" waiting: ${cs.state.waiting.reason ?? 'unknown'}`
+      )
+    }
+  } catch {
+    // pod already gone or API error — default hint
+    errors.push(`  → please check your script for errors`)
+  }
+ 
+  if (tailOutput) {
+    const outputLines = tailOutput
+      .split('\n')
+      .map(l => `  ${l}`)
+      .join('\n')
+    sections.push(`Last output:\n${outputLines}`)
+  }
+ 
+  let result = `failed to run script step:\n${errors.join('\n')}`
+  if (sections.length) {
+    result += `\n${sep}\n${sections.join('\n')}`
+  }
+  return result
+}
+ 
+function createContainerSpec(
+  container: RunContainerStepArgs,
+  extension?: k8s.V1PodTemplateSpec
+): k8s.V1Container {
+  const podContainer = new k8s.V1Container()
+  podContainer.name = JOB_CONTAINER_NAME
+  podContainer.image = container.image
+  podContainer.workingDir = '/__w'
+  podContainer.command = ['tail']
+  podContainer.args = DEFAULT_CONTAINER_ENTRY_POINT_ARGS
+ 
+  podContainer.volumeMounts = CONTAINER_VOLUMES
+ 
+  Eif (!extension) {
+    return podContainer
+  }
+ 
+  const from = extension.spec?.containers?.find(
+    c => c.name === JOB_CONTAINER_EXTENSION_NAME
+  )
+  Iif (from) {
+    mergeContainerWithOptions(podContainer, from)
+  }
+ 
+  return podContainer
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/k8s/src/hooks/run-script-step.ts.html b/coverage/lcov-report/k8s/src/hooks/run-script-step.ts.html new file mode 100644 index 00000000..d5819a23 --- /dev/null +++ b/coverage/lcov-report/k8s/src/hooks/run-script-step.ts.html @@ -0,0 +1,526 @@ + + + + + + Code coverage report for k8s/src/hooks/run-script-step.ts + + + + + + + + + +
+
+

All files / k8s/src/hooks run-script-step.ts

+
+ +
+ 97.77% + Statements + 44/45 +
+ + +
+ 83.33% + Branches + 10/12 +
+ + +
+ 100% + Functions + 3/3 +
+ + +
+ 97.72% + Lines + 43/44 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +2x +2x +  +  +  +2x +2x +2x +  +2x +  +2x +  +2x +2x +2x +  +  +  +  +  +  +  +10x +2x +  +  +  +  +  +8x +8x +  +  +  +  +  +  +  +8x +8x +8x +8x +  +8x +  +  +  +  +  +  +  +  +8x +  +  +  +  +  +8x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +8x +8x +  +  +  +  +  +1x +1x +1x +  +  +  +7x +7x +7x +7x +  +  +  +  +5x +2x +  +  +4x +4x +  +  +  +3x +  +1x +1x +  +7x +7x +  +  +  +  +  +3x +3x +  +  +3x +  +  +  +  +  +1x +  +  + 
/* eslint-disable @typescript-eslint/no-unused-vars */
+import * as fs from 'fs'
+import * as core from '@actions/core'
+import { RunScriptStepArgs } from 'hooklib'
+import {
+  execCpFromPod,
+  execCpToPod,
+  execPodStep,
+  execPodStepWithOutput
+} from '../k8s'
+import { formatError, writeRunScript } from '../k8s/utils'
+import { JOB_CONTAINER_NAME } from './constants'
+import { dirname } from 'path'
+import * as shlex from 'shlex'
+ 
+function formatScriptError(exitCode: number, tailOutput: string): string {
+  const sep = '-'.repeat(60)
+  const errors = [
+    `  ✗ exit code: ${exitCode}`,
+    `  → your script exited with a non-zero code; please check your script for errors`
+  ]
+  const sections: string[] = []
+  Eif (tailOutput) {
+    const outputLines = tailOutput
+      .split('\n')
+      .map(l => `  ${l}`)
+      .join('\n')
+    sections.push(`Last output:\n${outputLines}`)
+  }
+  let result = `failed to run script step:\n${errors.join('\n')}`
+  Eif (sections.length) result += `\n${sep}\n${sections.join('\n')}`
+  return result
+}
+ 
+export async function runScriptStep(
+  args: RunScriptStepArgs,
+  state
+): Promise<void> {
+  // Validate that pod was created successfully (prepareJob succeeded)
+  if (!state?.jobPod) {
+    throw new Error(
+      'jobPod must be set - ensure prepareJob completed successfully before running script steps'
+    )
+  }
+ 
+  // Write the entrypoint first. This will be later coppied to the workflow pod
+  const { entryPoint, entryPointArgs, environmentVariables } = args
+  const { containerPath, runnerPath } = writeRunScript(
+    args.workingDirectory,
+    entryPoint,
+    entryPointArgs,
+    args.prependPath,
+    environmentVariables
+  )
+ 
+  const workdir = dirname(process.env.RUNNER_WORKSPACE as string)
+  const runnerTemp = `${workdir}/_temp`
+  const containerTemp = '/__w/_temp'
+  const containerTempSrc = '/__w/_temp_pre'
+  // Ensure base and staging dirs exist before copying
+  await execPodStep(
+    [
+      'sh',
+      '-c',
+      'mkdir -p /__w && mkdir -p /__w/_temp && mkdir -p /__w/_temp_pre'
+    ],
+    state.jobPod,
+    JOB_CONTAINER_NAME
+  )
+  await execCpToPod(state.jobPod, runnerTemp, containerTempSrc)
+ 
+  // Copy GitHub directories from temp to /github
+  // Merge strategy:
+  // - Overwrite files in _runner_file_commands
+  // - Append files not already present elsewhere
+  const mergeCommands = [
+    'set -e',
+    'mkdir -p /__w/_temp /__w/_temp_pre',
+    'SRC=/__w/_temp_pre',
+    'DST=/__w/_temp',
+    // Overwrite _runner_file_commands
+    'cp -a "$SRC/_runner_file_commands/." "$DST/_runner_file_commands"',
+    `find "$SRC" -type f ! -path "*/_runner_file_commands/*" -exec sh -c '
+    rel="\${1#$2/}"
+    target="$3/$rel"
+    mkdir -p "$(dirname "$target")"
+    cp -a "$1" "$target"
+  ' _ {} "$SRC" "$DST" \\;`,
+    // Remove _temp_pre after merging
+    'rm -rf /__w/_temp_pre'
+  ]
+ 
+  try {
+    await execPodStep(
+      ['sh', '-c', mergeCommands.join(' && ')],
+      state.jobPod,
+      JOB_CONTAINER_NAME
+    )
+  } catch (err) {
+    const message = formatError(err)
+    core.debug(`Failed to merge temp directories: ${message}`)
+    throw new Error(`failed to merge temp dirs: ${message}`)
+  }
+ 
+  // Execute the entrypoint script
+  args.entryPoint = 'sh'
+  args.entryPointArgs = ['-e', containerPath]
+  try {
+    const { code, output } = await execPodStepWithOutput(
+      [args.entryPoint, ...args.entryPointArgs],
+      state.jobPod,
+      JOB_CONTAINER_NAME
+    )
+    if (code !== 0) {
+      throw new Error(formatScriptError(code, output))
+    }
+  } catch (err) {
+    core.debug(`execPodStep failed: ${formatError(err)}`)
+    if (
+      err instanceof Error &&
+      err.message.startsWith('failed to run script step')
+    ) {
+      throw err
+    }
+    const message = formatError(err)
+    throw new Error(`failed to run script step: ${message}`)
+  } finally {
+    try {
+      fs.rmSync(runnerPath, { force: true })
+    } catch (removeErr) {
+      core.debug(`Failed to remove file ${runnerPath}: ${removeErr}`)
+    }
+  }
+ 
+  try {
+    core.debug(
+      `Copying from job pod '${state.jobPod}' ${containerTemp} to ${runnerTemp}`
+    )
+    await execCpFromPod(
+      state.jobPod,
+      `${containerTemp}/_runner_file_commands`,
+      `${workdir}/_temp`
+    )
+  } catch (error) {
+    core.warning('Failed to copy _temp from pod')
+  }
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/k8s/src/index.html b/coverage/lcov-report/k8s/src/index.html new file mode 100644 index 00000000..aa916fa7 --- /dev/null +++ b/coverage/lcov-report/k8s/src/index.html @@ -0,0 +1,116 @@ + + + + + + Code coverage report for k8s/src + + + + + + + + + +
+
+

All files k8s/src

+
+ +
+ 0% + Statements + 0/22 +
+ + +
+ 0% + Branches + 0/7 +
+ + +
+ 0% + Functions + 0/1 +
+ + +
+ 0% + Lines + 0/22 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
index.ts +
+
0%0/220%0/70%0/10%0/22
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/k8s/src/index.ts.html b/coverage/lcov-report/k8s/src/index.ts.html new file mode 100644 index 00000000..b20f21ec --- /dev/null +++ b/coverage/lcov-report/k8s/src/index.ts.html @@ -0,0 +1,253 @@ + + + + + + Code coverage report for k8s/src/index.ts + + + + + + + + + +
+
+

All files / k8s/src index.ts

+
+ +
+ 0% + Statements + 0/22 +
+ + +
+ 0% + Branches + 0/7 +
+ + +
+ 0% + Functions + 0/1 +
+ + +
+ 0% + Lines + 0/22 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import * as core from '@actions/core'
+import {
+  Command,
+  getInputFromStdin,
+  PrepareJobArgs,
+  RunContainerStepArgs,
+  RunScriptStepArgs
+} from 'hooklib'
+import {
+  cleanupJob,
+  prepareJob,
+  runContainerStep,
+  runScriptStep
+} from './hooks'
+import { isAuthPermissionsOK, namespace, requiredPermissions } from './k8s'
+ 
+async function run(): Promise<void> {
+  try {
+    const input = await getInputFromStdin()
+ 
+    const args = input['args']
+    const command = input['command']
+    const responseFile = input['responseFile']
+    const state = input['state']
+    if (!(await isAuthPermissionsOK())) {
+      throw new Error(
+        `The Service account needs the following permissions ${JSON.stringify(
+          requiredPermissions
+        )} on the pod resource in the '${namespace()}' namespace. Please contact your self hosted runner administrator.`
+      )
+    }
+ 
+    let exitCode = 0
+    switch (command) {
+      case Command.PrepareJob:
+        await prepareJob(args as PrepareJobArgs, responseFile)
+        return process.exit(0)
+      case Command.CleanupJob:
+        await cleanupJob()
+        return process.exit(0)
+      case Command.RunScriptStep:
+        await runScriptStep(args as RunScriptStepArgs, state)
+        return process.exit(0)
+      case Command.RunContainerStep:
+        exitCode = await runContainerStep(args as RunContainerStepArgs)
+        return process.exit(exitCode)
+      default:
+        throw new Error(`Command not recognized: ${command}`)
+    }
+  } catch (error) {
+    core.error(error as Error)
+    process.exit(1)
+  }
+}
+ 
+void run()
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/k8s/src/k8s/heartbeat.ts.html b/coverage/lcov-report/k8s/src/k8s/heartbeat.ts.html new file mode 100644 index 00000000..ace7a457 --- /dev/null +++ b/coverage/lcov-report/k8s/src/k8s/heartbeat.ts.html @@ -0,0 +1,493 @@ + + + + + + Code coverage report for k8s/src/k8s/heartbeat.ts + + + + + + + + + +
+
+

All files / k8s/src/k8s heartbeat.ts

+
+ +
+ 95.08% + Statements + 58/61 +
+ + +
+ 86.66% + Branches + 26/30 +
+ + +
+ 100% + Functions + 11/11 +
+ + +
+ 95.08% + Lines + 58/61 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137  +  +  +  +  +  +  +  +  +  +  +  +  +  +22x +22x +  +  +  +20x +20x +20x +2x +  +  +20x +20x +  +  +  +38x +38x +8x +8x +  +30x +  +  +  +21x +8x +  +21x +9x +9x +  +21x +6x +6x +  +  +  +  +16x +  +  +16x +  +16x +9x +1x +1x +  +9x +3x +  +  +3x +3x +3x +  +  +  +3x +  +  +  +  +  +  +  +  +  +16x +  +16x +1x +  +  +1x +1x +  +  +  +16x +1x +1x +  +  +16x +1x +1x +  +  +  +16x +21x +  +4x +  +17x +16x +16x +16x +8x +8x +  +15x +  +  +  +1x +1x +  +  +  +1x +  +  +  +  +1x +  +  +  +  + 
import * as core from '@actions/core'
+ 
+export interface HeartbeatWebSocket {
+  readyState: number
+  ping(): void
+  close(): void
+  on(event: string, listener: (...args: any[]) => void): this
+  once(event: string, listener: (...args: any[]) => void): this
+}
+ 
+export function parsePositiveMsEnv(
+  value: string | undefined,
+  fallback: number
+): number {
+  const parsed = Number.parseInt(value ?? '', 10)
+  return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback
+}
+ 
+export class WebSocketHeartbeat {
+  private pingInterval: ReturnType<typeof setInterval> | null = null
+  private pongTimeout: ReturnType<typeof setTimeout> | null = null
+  private lastHeartbeatLog = 0
+  private static readonly LOG_INTERVAL_MS = 2 * 60 * 1000
+ 
+  constructor(
+    private readonly pingPeriodMs: number,
+    private readonly pongDeadlineMs: number
+  ) {}
+ 
+  private shouldLog(): boolean {
+    const now = Date.now()
+    if (now - this.lastHeartbeatLog >= WebSocketHeartbeat.LOG_INTERVAL_MS) {
+      this.lastHeartbeatLog = now
+      return true
+    }
+    return false
+  }
+ 
+  stop(): void {
+    if (this.shouldLog()) {
+      core.debug('[Heartbeat] stopping heartbeat')
+    }
+    if (this.pingInterval) {
+      clearInterval(this.pingInterval)
+      this.pingInterval = null
+    }
+    if (this.pongTimeout) {
+      clearTimeout(this.pongTimeout)
+      this.pongTimeout = null
+    }
+  }
+ 
+  start(ws: HeartbeatWebSocket, reject: (err: Error) => void): void {
+    core.debug(
+      `[Heartbeat] Starting with period=${this.pingPeriodMs}ms, deadline=${this.pongDeadlineMs}ms`
+    )
+    this.lastHeartbeatLog = Date.now()
+ 
+    const resetPongTimeout = (): void => {
+      if (this.pongTimeout) {
+        clearTimeout(this.pongTimeout)
+        this.pongTimeout = null
+      }
+      this.pongTimeout = setTimeout(() => {
+        core.warning(
+          `[Heartbeat] No pong received in ${this.pongDeadlineMs}ms, closing stale connection`
+        )
+        this.stop()
+        try {
+          ws.close()
+        } catch {
+          // ignore errors closing an already-closing socket
+        }
+        reject(
+          new Error(
+            `WebSocket heartbeat timeout: no pong within ${this.pongDeadlineMs}ms`
+          )
+        )
+      }, this.pongDeadlineMs)
+    }
+ 
+    // Arm the deadline only after the first ping is sent, not immediately on
+    // start, so a slow CONNECTING socket cannot time out before any exchange.
+    let deadlineArmed = false
+ 
+    ws.on('pong', () => {
+      Iif (this.shouldLog()) {
+        core.debug('[Heartbeat] Pong received')
+      }
+      Eif (deadlineArmed) {
+        resetPongTimeout()
+      }
+    })
+ 
+    ws.on('error', (err: Error) => {
+      core.error(`[Heartbeat] WebSocket error: ${err.message}`)
+      this.stop()
+    })
+ 
+    ws.on('close', () => {
+      core.debug('[Heartbeat] WebSocket closed, stopping heartbeat')
+      this.stop()
+    })
+ 
+    // WebSocket readyState: 0 = CONNECTING, 1 = OPEN, 2 = CLOSING, 3 = CLOSED
+    this.pingInterval = setInterval(() => {
+      if (ws.readyState === 0) {
+        // Still connecting — skip this tick but keep the interval alive
+        return
+      }
+      if (ws.readyState === 1) {
+        try {
+          ws.ping()
+          if (!deadlineArmed) {
+            deadlineArmed = true
+            resetPongTimeout()
+          }
+          Iif (this.shouldLog()) {
+            core.debug('[Heartbeat] Ping sent')
+          }
+        } catch (err) {
+          core.error(`[Heartbeat] Ping failed: ${err}`)
+          this.stop()
+        }
+      } else {
+        // CLOSING (2) or CLOSED (3)
+        Iif (this.shouldLog()) {
+          core.debug(
+            `[Heartbeat] WebSocket closing/closed (readyState=${ws.readyState}), stopping heartbeat`
+          )
+        }
+        this.stop()
+      }
+    }, this.pingPeriodMs)
+  }
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/k8s/src/k8s/index.html b/coverage/lcov-report/k8s/src/k8s/index.html new file mode 100644 index 00000000..d8509633 --- /dev/null +++ b/coverage/lcov-report/k8s/src/k8s/index.html @@ -0,0 +1,131 @@ + + + + + + Code coverage report for k8s/src/k8s + + + + + + + + + +
+
+

All files k8s/src/k8s

+
+ +
+ 75.37% + Statements + 560/743 +
+ + +
+ 71.71% + Branches + 251/350 +
+ + +
+ 74.59% + Functions + 91/122 +
+ + +
+ 75.68% + Lines + 551/728 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
heartbeat.ts +
+
95.08%58/6186.66%26/30100%11/1195.08%58/61
index.ts +
+
73.6%502/68270.31%225/32072.07%80/11173.91%493/667
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/k8s/src/k8s/index.ts.html b/coverage/lcov-report/k8s/src/k8s/index.ts.html new file mode 100644 index 00000000..6ea6ceca --- /dev/null +++ b/coverage/lcov-report/k8s/src/k8s/index.ts.html @@ -0,0 +1,5599 @@ + + + + + + Code coverage report for k8s/src/k8s/index.ts + + + + + + + + + +
+
+

All files / k8s/src/k8s index.ts

+
+ +
+ 73.6% + Statements + 502/682 +
+ + +
+ 70.31% + Branches + 225/320 +
+ + +
+ 72.07% + Functions + 80/111 +
+ + +
+ 73.91% + Lines + 493/667 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263 +264 +265 +266 +267 +268 +269 +270 +271 +272 +273 +274 +275 +276 +277 +278 +279 +280 +281 +282 +283 +284 +285 +286 +287 +288 +289 +290 +291 +292 +293 +294 +295 +296 +297 +298 +299 +300 +301 +302 +303 +304 +305 +306 +307 +308 +309 +310 +311 +312 +313 +314 +315 +316 +317 +318 +319 +320 +321 +322 +323 +324 +325 +326 +327 +328 +329 +330 +331 +332 +333 +334 +335 +336 +337 +338 +339 +340 +341 +342 +343 +344 +345 +346 +347 +348 +349 +350 +351 +352 +353 +354 +355 +356 +357 +358 +359 +360 +361 +362 +363 +364 +365 +366 +367 +368 +369 +370 +371 +372 +373 +374 +375 +376 +377 +378 +379 +380 +381 +382 +383 +384 +385 +386 +387 +388 +389 +390 +391 +392 +393 +394 +395 +396 +397 +398 +399 +400 +401 +402 +403 +404 +405 +406 +407 +408 +409 +410 +411 +412 +413 +414 +415 +416 +417 +418 +419 +420 +421 +422 +423 +424 +425 +426 +427 +428 +429 +430 +431 +432 +433 +434 +435 +436 +437 +438 +439 +440 +441 +442 +443 +444 +445 +446 +447 +448 +449 +450 +451 +452 +453 +454 +455 +456 +457 +458 +459 +460 +461 +462 +463 +464 +465 +466 +467 +468 +469 +470 +471 +472 +473 +474 +475 +476 +477 +478 +479 +480 +481 +482 +483 +484 +485 +486 +487 +488 +489 +490 +491 +492 +493 +494 +495 +496 +497 +498 +499 +500 +501 +502 +503 +504 +505 +506 +507 +508 +509 +510 +511 +512 +513 +514 +515 +516 +517 +518 +519 +520 +521 +522 +523 +524 +525 +526 +527 +528 +529 +530 +531 +532 +533 +534 +535 +536 +537 +538 +539 +540 +541 +542 +543 +544 +545 +546 +547 +548 +549 +550 +551 +552 +553 +554 +555 +556 +557 +558 +559 +560 +561 +562 +563 +564 +565 +566 +567 +568 +569 +570 +571 +572 +573 +574 +575 +576 +577 +578 +579 +580 +581 +582 +583 +584 +585 +586 +587 +588 +589 +590 +591 +592 +593 +594 +595 +596 +597 +598 +599 +600 +601 +602 +603 +604 +605 +606 +607 +608 +609 +610 +611 +612 +613 +614 +615 +616 +617 +618 +619 +620 +621 +622 +623 +624 +625 +626 +627 +628 +629 +630 +631 +632 +633 +634 +635 +636 +637 +638 +639 +640 +641 +642 +643 +644 +645 +646 +647 +648 +649 +650 +651 +652 +653 +654 +655 +656 +657 +658 +659 +660 +661 +662 +663 +664 +665 +666 +667 +668 +669 +670 +671 +672 +673 +674 +675 +676 +677 +678 +679 +680 +681 +682 +683 +684 +685 +686 +687 +688 +689 +690 +691 +692 +693 +694 +695 +696 +697 +698 +699 +700 +701 +702 +703 +704 +705 +706 +707 +708 +709 +710 +711 +712 +713 +714 +715 +716 +717 +718 +719 +720 +721 +722 +723 +724 +725 +726 +727 +728 +729 +730 +731 +732 +733 +734 +735 +736 +737 +738 +739 +740 +741 +742 +743 +744 +745 +746 +747 +748 +749 +750 +751 +752 +753 +754 +755 +756 +757 +758 +759 +760 +761 +762 +763 +764 +765 +766 +767 +768 +769 +770 +771 +772 +773 +774 +775 +776 +777 +778 +779 +780 +781 +782 +783 +784 +785 +786 +787 +788 +789 +790 +791 +792 +793 +794 +795 +796 +797 +798 +799 +800 +801 +802 +803 +804 +805 +806 +807 +808 +809 +810 +811 +812 +813 +814 +815 +816 +817 +818 +819 +820 +821 +822 +823 +824 +825 +826 +827 +828 +829 +830 +831 +832 +833 +834 +835 +836 +837 +838 +839 +840 +841 +842 +843 +844 +845 +846 +847 +848 +849 +850 +851 +852 +853 +854 +855 +856 +857 +858 +859 +860 +861 +862 +863 +864 +865 +866 +867 +868 +869 +870 +871 +872 +873 +874 +875 +876 +877 +878 +879 +880 +881 +882 +883 +884 +885 +886 +887 +888 +889 +890 +891 +892 +893 +894 +895 +896 +897 +898 +899 +900 +901 +902 +903 +904 +905 +906 +907 +908 +909 +910 +911 +912 +913 +914 +915 +916 +917 +918 +919 +920 +921 +922 +923 +924 +925 +926 +927 +928 +929 +930 +931 +932 +933 +934 +935 +936 +937 +938 +939 +940 +941 +942 +943 +944 +945 +946 +947 +948 +949 +950 +951 +952 +953 +954 +955 +956 +957 +958 +959 +960 +961 +962 +963 +964 +965 +966 +967 +968 +969 +970 +971 +972 +973 +974 +975 +976 +977 +978 +979 +980 +981 +982 +983 +984 +985 +986 +987 +988 +989 +990 +991 +992 +993 +994 +995 +996 +997 +998 +999 +1000 +1001 +1002 +1003 +1004 +1005 +1006 +1007 +1008 +1009 +1010 +1011 +1012 +1013 +1014 +1015 +1016 +1017 +1018 +1019 +1020 +1021 +1022 +1023 +1024 +1025 +1026 +1027 +1028 +1029 +1030 +1031 +1032 +1033 +1034 +1035 +1036 +1037 +1038 +1039 +1040 +1041 +1042 +1043 +1044 +1045 +1046 +1047 +1048 +1049 +1050 +1051 +1052 +1053 +1054 +1055 +1056 +1057 +1058 +1059 +1060 +1061 +1062 +1063 +1064 +1065 +1066 +1067 +1068 +1069 +1070 +1071 +1072 +1073 +1074 +1075 +1076 +1077 +1078 +1079 +1080 +1081 +1082 +1083 +1084 +1085 +1086 +1087 +1088 +1089 +1090 +1091 +1092 +1093 +1094 +1095 +1096 +1097 +1098 +1099 +1100 +1101 +1102 +1103 +1104 +1105 +1106 +1107 +1108 +1109 +1110 +1111 +1112 +1113 +1114 +1115 +1116 +1117 +1118 +1119 +1120 +1121 +1122 +1123 +1124 +1125 +1126 +1127 +1128 +1129 +1130 +1131 +1132 +1133 +1134 +1135 +1136 +1137 +1138 +1139 +1140 +1141 +1142 +1143 +1144 +1145 +1146 +1147 +1148 +1149 +1150 +1151 +1152 +1153 +1154 +1155 +1156 +1157 +1158 +1159 +1160 +1161 +1162 +1163 +1164 +1165 +1166 +1167 +1168 +1169 +1170 +1171 +1172 +1173 +1174 +1175 +1176 +1177 +1178 +1179 +1180 +1181 +1182 +1183 +1184 +1185 +1186 +1187 +1188 +1189 +1190 +1191 +1192 +1193 +1194 +1195 +1196 +1197 +1198 +1199 +1200 +1201 +1202 +1203 +1204 +1205 +1206 +1207 +1208 +1209 +1210 +1211 +1212 +1213 +1214 +1215 +1216 +1217 +1218 +1219 +1220 +1221 +1222 +1223 +1224 +1225 +1226 +1227 +1228 +1229 +1230 +1231 +1232 +1233 +1234 +1235 +1236 +1237 +1238 +1239 +1240 +1241 +1242 +1243 +1244 +1245 +1246 +1247 +1248 +1249 +1250 +1251 +1252 +1253 +1254 +1255 +1256 +1257 +1258 +1259 +1260 +1261 +1262 +1263 +1264 +1265 +1266 +1267 +1268 +1269 +1270 +1271 +1272 +1273 +1274 +1275 +1276 +1277 +1278 +1279 +1280 +1281 +1282 +1283 +1284 +1285 +1286 +1287 +1288 +1289 +1290 +1291 +1292 +1293 +1294 +1295 +1296 +1297 +1298 +1299 +1300 +1301 +1302 +1303 +1304 +1305 +1306 +1307 +1308 +1309 +1310 +1311 +1312 +1313 +1314 +1315 +1316 +1317 +1318 +1319 +1320 +1321 +1322 +1323 +1324 +1325 +1326 +1327 +1328 +1329 +1330 +1331 +1332 +1333 +1334 +1335 +1336 +1337 +1338 +1339 +1340 +1341 +1342 +1343 +1344 +1345 +1346 +1347 +1348 +1349 +1350 +1351 +1352 +1353 +1354 +1355 +1356 +1357 +1358 +1359 +1360 +1361 +1362 +1363 +1364 +1365 +1366 +1367 +1368 +1369 +1370 +1371 +1372 +1373 +1374 +1375 +1376 +1377 +1378 +1379 +1380 +1381 +1382 +1383 +1384 +1385 +1386 +1387 +1388 +1389 +1390 +1391 +1392 +1393 +1394 +1395 +1396 +1397 +1398 +1399 +1400 +1401 +1402 +1403 +1404 +1405 +1406 +1407 +1408 +1409 +1410 +1411 +1412 +1413 +1414 +1415 +1416 +1417 +1418 +1419 +1420 +1421 +1422 +1423 +1424 +1425 +1426 +1427 +1428 +1429 +1430 +1431 +1432 +1433 +1434 +1435 +1436 +1437 +1438 +1439 +1440 +1441 +1442 +1443 +1444 +1445 +1446 +1447 +1448 +1449 +1450 +1451 +1452 +1453 +1454 +1455 +1456 +1457 +1458 +1459 +1460 +1461 +1462 +1463 +1464 +1465 +1466 +1467 +1468 +1469 +1470 +1471 +1472 +1473 +1474 +1475 +1476 +1477 +1478 +1479 +1480 +1481 +1482 +1483 +1484 +1485 +1486 +1487 +1488 +1489 +1490 +1491 +1492 +1493 +1494 +1495 +1496 +1497 +1498 +1499 +1500 +1501 +1502 +1503 +1504 +1505 +1506 +1507 +1508 +1509 +1510 +1511 +1512 +1513 +1514 +1515 +1516 +1517 +1518 +1519 +1520 +1521 +1522 +1523 +1524 +1525 +1526 +1527 +1528 +1529 +1530 +1531 +1532 +1533 +1534 +1535 +1536 +1537 +1538 +1539 +1540 +1541 +1542 +1543 +1544 +1545 +1546 +1547 +1548 +1549 +1550 +1551 +1552 +1553 +1554 +1555 +1556 +1557 +1558 +1559 +1560 +1561 +1562 +1563 +1564 +1565 +1566 +1567 +1568 +1569 +1570 +1571 +1572 +1573 +1574 +1575 +1576 +1577 +1578 +1579 +1580 +1581 +1582 +1583 +1584 +1585 +1586 +1587 +1588 +1589 +1590 +1591 +1592 +1593 +1594 +1595 +1596 +1597 +1598 +1599 +1600 +1601 +1602 +1603 +1604 +1605 +1606 +1607 +1608 +1609 +1610 +1611 +1612 +1613 +1614 +1615 +1616 +1617 +1618 +1619 +1620 +1621 +1622 +1623 +1624 +1625 +1626 +1627 +1628 +1629 +1630 +1631 +1632 +1633 +1634 +1635 +1636 +1637 +1638 +1639 +1640 +1641 +1642 +1643 +1644 +1645 +1646 +1647 +1648 +1649 +1650 +1651 +1652 +1653 +1654 +1655 +1656 +1657 +1658 +1659 +1660 +1661 +1662 +1663 +1664 +1665 +1666 +1667 +1668 +1669 +1670 +1671 +1672 +1673 +1674 +1675 +1676 +1677 +1678 +1679 +1680 +1681 +1682 +1683 +1684 +1685 +1686 +1687 +1688 +1689 +1690 +1691 +1692 +1693 +1694 +1695 +1696 +1697 +1698 +1699 +1700 +1701 +1702 +1703 +1704 +1705 +1706 +1707 +1708 +1709 +1710 +1711 +1712 +1713 +1714 +1715 +1716 +1717 +1718 +1719 +1720 +1721 +1722 +1723 +1724 +1725 +1726 +1727 +1728 +1729 +1730 +1731 +1732 +1733 +1734 +1735 +1736 +1737 +1738 +1739 +1740 +1741 +1742 +1743 +1744 +1745 +1746 +1747 +1748 +1749 +1750 +1751 +1752 +1753 +1754 +1755 +1756 +1757 +1758 +1759 +1760 +1761 +1762 +1763 +1764 +1765 +1766 +1767 +1768 +1769 +1770 +1771 +1772 +1773 +1774 +1775 +1776 +1777 +1778 +1779 +1780 +1781 +1782 +1783 +1784 +1785 +1786 +1787 +1788 +1789 +1790 +1791 +1792 +1793 +1794 +1795 +1796 +1797 +1798 +1799 +1800 +1801 +1802 +1803 +1804 +1805 +1806 +1807 +1808 +1809 +1810 +1811 +1812 +1813 +1814 +1815 +1816 +1817 +1818 +1819 +1820 +1821 +1822 +1823 +1824 +1825 +1826 +1827 +1828 +1829 +1830 +1831 +1832 +1833 +1834 +1835 +1836 +1837 +1838 +1839  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +  +1x +  +1x +1x +1x +  +1x +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +5x +5x +4x +  +5x +1x +  +  +5x +  +5x +5x +  +5x +5x +  +5x +5x +  +  +5x +  +5x +5x +5x +  +  +  +  +  +5x +5x +  +5x +  +  +  +  +  +  +5x +5x +  +  +5x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +5x +  +5x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +5x +  +  +  +  +  +  +  +  +  +5x +1x +  +  +5x +1x +  +  +5x +  +  +  +  +  +  +  +  +  +  +1x +  +1x +1x +  +1x +1x +  +1x +1x +  +  +1x +  +1x +1x +  +1x +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +  +  +  +1x +  +  +  +1x +  +  +  +  +  +  +3x +  +  +  +  +  +  +  +  +  +  +  +  +7x +7x +  +  +  +7x +  +7x +7x +  +  +  +7x +  +  +  +7x +  +  +  +7x +  +7x +7x +7x +  +7x +  +  +  +  +  +  +  +  +  +  +6x +  +  +  +6x +  +  +6x +6x +6x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +6x +3x +3x +3x +  +3x +  +  +3x +3x +  +  +  +  +6x +6x +6x +4x +  +2x +  +  +  +5x +5x +  +  +5x +5x +2x +2x +  +  +  +  +  +  +2x +1x +1x +  +2x +  +  +  +4x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +5x +5x +  +  +5x +5x +2x +2x +2x +  +  +  +5x +5x +1x +1x +1x +2x +  +  +5x +5x +  +  +  +  +  +  +5x +5x +  +  +  +5x +  +  +  +  +  +5x +  +1x +1x +1x +1x +  +  +  +  +  +5x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +5x +4x +4x +  +  +5x +5x +  +  +  +  +  +  +  +  +  +  +3x +3x +3x +1x +  +  +  +  +2x +2x +1x +  +1x +  +  +  +  +  +  +  +  +  +  +2x +2x +2x +2x +1x +  +1x +  +  +  +  +  +  +  +  +  +  +3x +  +3x +3x +  +2x +2x +2x +  +  +  +  +  +  +3x +3x +  +  +  +  +  +  +  +  +  +  +2x +2x +1x +  +1x +  +  +  +  +  +1x +  +  +  +1x +  +  +1x +  +  +1x +  +4x +  +1x +  +1x +1x +1x +  +  +  +  +  +2x +  +2x +  +  +  +2x +2x +1x +  +2x +2x +2x +  +1x +  +2x +  +1x +  +1x +1x +1x +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +2x +2x +2x +2x +1x +  +  +1x +  +  +  +  +  +  +  +  +2x +  +  +  +  +  +  +  +  +  +  +  +2x +  +2x +2x +2x +2x +2x +2x +2x +2x +  +  +2x +2x +2x +  +  +  +  +  +2x +  +  +  +  +  +  +  +  +2x +  +2x +2x +2x +2x +2x +2x +  +2x +  +  +2x +2x +2x +2x +  +  +2x +  +  +  +2x +  +  +  +3x +  +  +  +  +  +  +2x +  +  +  +2x +1x +  +  +1x +  +  +3x +  +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +28x +28x +26x +  +2x +2x +2x +2x +2x +  +  +2x +  +  +  +  +  +  +21x +21x +20x +  +1x +1x +1x +1x +1x +  +  +1x +  +  +  +  +20x +20x +19x +  +1x +1x +3x +3x +1x +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +11x +26x +  +  +  +  +  +  +  +  +  +  +  +  +15x +15x +5x +1x +  +4x +4x +8x +8x +5x +5x +  +1x +  +  +  +  +4x +4x +4x +  +  +  +10x +  +5x +  +  +  +  +  +  +  +2x +  +2x +  +1x +  +  +  +  +20x +20x +20x +  +  +  +20x +13x +13x +10x +10x +10x +10x +  +  +20x +  +  +  +  +  +  +14x +5x +  +9x +2x +  +7x +6x +  +1x +  +  +  +1x +  +1x +  +3x +  +  +1x +  +  +  +18x +18x +18x +  +  +  +18x +11x +11x +7x +7x +7x +7x +  +  +18x +  +  +  +10x +  +7x +  +  +  +  +  +  +1x +  +  +  +  +  +  +2x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +19x +19x +  +  +  +  +19x +19x +  +  +  +18x +  +1x +  +  +  +  +1x +  +  +18x +18x +18x +14x +  +  +  +  +1x +  +  +  +  +13x +  +  +  +2x +  +  +  +  +2x +  +11x +1x +  +10x +10x +14x +14x +14x +14x +  +18x +  +  +  +  +  +  +  +  +  +  +7x +7x +  +1x +  +  +  +  +6x +6x +  +  +6x +6x +  +  +7x +7x +  +  +  +  +6x +  +  +  +  +  +  +6x +  +  +6x +6x +  +  +  +7x +7x +2x +2x +  +  +1x +  +  +  +  +  +  +2x +  +2x +1x +1x +1x +  +  +  +  +6x +1x +  +  +  +6x +6x +3x +  +  +6x +  +  +6x +  +  +  +  +  +  +  +6x +6x +  +  +  +6x +  +  +  +  +  +  +  +  +  +6x +6x +3x +  +  +3x +  +  +  +3x +  +3x +3x +3x +3x +  +3x +  +  +  +  +3x +  +  +  +  +  +  +  +  +  +9x +  +  +  +  +  +  +  +  +  +  +  +  +  +8x +  +8x +  +8x +  +  +  +8x +  +  +  +  +  +8x +  +  +  +  +  +  +  +  +  +  +  +  +  +6x +6x +6x +  +8x +8x +  +  +  +  +2x +  +  +  +  +2x +2x +  +  +  +  +  +  +  +2x +  +6x +6x +2x +  +  +  +  +  +  +  +4x +1x +1x +1x +  +  +  +  +1x +  +  +  +  +  +  +  +3x +3x +3x +3x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +4x +  +4x +1x +  +  +3x +3x +2x +  +  +2x +  +  +1x +  +  +  +15x +  +  +  +  +  +1x +  +  +  +  +  +  +  +  +13x +3x +  +10x +  +  +  +2x +  +  +  +2x +1x +  +1x +  +  +  +  +  +  +2x +2x +2x +  +  +  +  +2x +  +  +  +  +2x +2x +2x +1x +1x +  +  +  +  +  +2x +  +  +  +2x +1x +  +  +1x +  +2x +  +  +  +  +  +  +  +1x +  +  +  +1x +  +  +  +2x +2x +2x +8x +26x +26x +26x +26x +26x +26x +26x +26x +  +  +  +  +2x +14x +  +  +  +  +  +  +2x +2x +2x +  +  +  +  +  +  +  +  +  +1x +  +  +2x +  +  +  +117x +116x +  +  +1x +1x +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +8x +8x +8x +8x +2x +  +  +  +  +2x +2x +  +2x +2x +  +  +2x +2x +  +2x +  +  +  +  +  +  +  +  +12x +12x +2x +  +10x +11x +11x +1x +  +  +10x +10x +  +  +11x +11x +1x +  +  +9x +13x +13x +3x +  +10x +  +  +9x +5x +  +4x +4x +  +  +6x +  +5x +  +  +  +2x +  +  +  +  +  +  +2x +  +  +  +  +  +  +3x +  +  +  +2x +  + 
import * as core from '@actions/core'
+import * as fs from 'fs'
+import * as path from 'path'
+import { spawn } from 'child_process'
+import * as k8s from '@kubernetes/client-node'
+import tar from 'tar-fs'
+import * as stream from 'stream'
+import { WritableStreamBuffer } from 'stream-buffers'
+import { createHash } from 'crypto'
+import type { ContainerInfo, Registry } from 'hooklib'
+import {
+  getSecretName,
+  JOB_CONTAINER_NAME,
+  RunnerInstanceLabel
+} from '../hooks/constants'
+import {
+  PodPhase,
+  formatError,
+  mergePodSpecWithOptions,
+  mergeObjectMeta,
+  fixArgs,
+  listDirAllCommand,
+  sleep,
+  EXTERNALS_VOLUME_NAME,
+  GITHUB_VOLUME_NAME,
+  WORK_VOLUME
+} from './utils'
+import * as shlex from 'shlex'
+import { parsePositiveMsEnv, WebSocketHeartbeat } from './heartbeat'
+import type { HeartbeatWebSocket } from './heartbeat'
+ 
+const kc = new k8s.KubeConfig()
+ 
+kc.loadFromDefault()
+ 
+const k8sApi = kc.makeApiClient(k8s.CoreV1Api)
+const k8sBatchV1Api = kc.makeApiClient(k8s.BatchV1Api)
+const k8sAuthorizationV1Api = kc.makeApiClient(k8s.AuthorizationV1Api)
+ 
+const DEFAULT_WAIT_FOR_POD_TIME_SECONDS = 10 * 60 // 10 min
+ 
+export const requiredPermissions = [
+  {
+    group: '',
+    verbs: ['get', 'list', 'create', 'delete'],
+    resource: 'pods',
+    subresource: ''
+  },
+  {
+    group: '',
+    verbs: ['get', 'create'],
+    resource: 'pods',
+    subresource: 'exec'
+  },
+  {
+    group: '',
+    verbs: ['get', 'list', 'watch'],
+    resource: 'pods',
+    subresource: 'log'
+  },
+  {
+    group: '',
+    verbs: ['create', 'delete', 'get', 'list'],
+    resource: 'secrets',
+    subresource: ''
+  }
+]
+ 
+export async function createJobPod(
+  name: string,
+  jobContainer?: k8s.V1Container,
+  services?: k8s.V1Container[],
+  registry?: Registry,
+  extension?: k8s.V1PodTemplateSpec
+): Promise<k8s.V1Pod> {
+  const containers: k8s.V1Container[] = []
+  if (jobContainer) {
+    containers.push(jobContainer)
+  }
+  if (services?.length) {
+    containers.push(...services)
+  }
+ 
+  const appPod = new k8s.V1Pod()
+ 
+  appPod.apiVersion = 'v1'
+  appPod.kind = 'Pod'
+ 
+  appPod.metadata = new k8s.V1ObjectMeta()
+  appPod.metadata.name = name
+ 
+  const instanceLabel = new RunnerInstanceLabel()
+  appPod.metadata.labels = {
+    [instanceLabel.key]: instanceLabel.value
+  }
+  appPod.metadata.annotations = {}
+ 
+  appPod.spec = new k8s.V1PodSpec()
+  appPod.spec.containers = containers
+  appPod.spec.securityContext = {
+    fsGroup: 1001
+  }
+ 
+  // Extract working directory from GITHUB_WORKSPACE
+  // GITHUB_WORKSPACE is like /__w/repo-name/repo-name
+  const githubWorkspace = process.env.GITHUB_WORKSPACE
+  const workingDirPath = githubWorkspace?.split('/').slice(-2).join('/') ?? ''
+ 
+  const initCommands = [
+    'mkdir -p /mnt/externals',
+    'mkdir -p /mnt/work',
+    'mkdir -p /mnt/github',
+    'mv /home/runner/externals/* /mnt/externals/'
+  ]
+ 
+  Eif (workingDirPath) {
+    initCommands.push(`mkdir -p /mnt/work/${workingDirPath}`)
+  }
+ 
+  appPod.spec.initContainers = [
+    {
+      name: 'fs-init',
+      image:
+        process.env.ACTIONS_RUNNER_IMAGE ||
+        'ghcr.io/actions/actions-runner:latest',
+      command: ['sh', '-c', initCommands.join(' && ')],
+      securityContext: {
+        runAsGroup: 1001,
+        runAsUser: 1001
+      },
+      volumeMounts: [
+        {
+          name: EXTERNALS_VOLUME_NAME,
+          mountPath: '/mnt/externals'
+        },
+        {
+          name: WORK_VOLUME,
+          mountPath: '/mnt/work'
+        },
+        {
+          name: GITHUB_VOLUME_NAME,
+          mountPath: '/mnt/github'
+        }
+      ]
+    }
+  ]
+ 
+  appPod.spec.restartPolicy = 'Never'
+ 
+  appPod.spec.volumes = [
+    {
+      name: EXTERNALS_VOLUME_NAME,
+      emptyDir: {}
+    },
+    {
+      name: GITHUB_VOLUME_NAME,
+      emptyDir: {}
+    },
+    {
+      name: WORK_VOLUME,
+      emptyDir: {}
+    }
+  ]
+ 
+  Iif (registry) {
+    const secret = await createDockerSecret(registry)
+    if (!secret?.metadata?.name) {
+      throw new Error(`created secret does not have secret.metadata.name`)
+    }
+    const secretReference = new k8s.V1LocalObjectReference()
+    secretReference.name = secret.metadata.name
+    appPod.spec.imagePullSecrets = [secretReference]
+  }
+ 
+  if (extension?.metadata) {
+    mergeObjectMeta(appPod, extension.metadata)
+  }
+ 
+  if (extension?.spec) {
+    mergePodSpecWithOptions(appPod.spec, extension.spec)
+  }
+ 
+  return await k8sApi.createNamespacedPod({
+    namespace: namespace(),
+    body: appPod
+  })
+}
+ 
+export async function createContainerStepPod(
+  name: string,
+  container: k8s.V1Container,
+  extension?: k8s.V1PodTemplateSpec
+): Promise<k8s.V1Pod> {
+  const appPod = new k8s.V1Pod()
+ 
+  appPod.apiVersion = 'v1'
+  appPod.kind = 'Pod'
+ 
+  appPod.metadata = new k8s.V1ObjectMeta()
+  appPod.metadata.name = name
+ 
+  const instanceLabel = new RunnerInstanceLabel()
+  appPod.metadata.labels = {
+    [instanceLabel.key]: instanceLabel.value
+  }
+  appPod.metadata.annotations = {}
+ 
+  appPod.spec = new k8s.V1PodSpec()
+  appPod.spec.containers = [container]
+ 
+  appPod.spec.restartPolicy = 'Never'
+ 
+  appPod.spec.volumes = [
+    {
+      name: EXTERNALS_VOLUME_NAME,
+      emptyDir: {}
+    },
+    {
+      name: GITHUB_VOLUME_NAME,
+      emptyDir: {}
+    },
+    {
+      name: WORK_VOLUME,
+      emptyDir: {}
+    }
+  ]
+ 
+  Iif (extension?.metadata) {
+    mergeObjectMeta(appPod, extension.metadata)
+  }
+ 
+  Iif (extension?.spec) {
+    mergePodSpecWithOptions(appPod.spec, extension.spec)
+  }
+ 
+  return await k8sApi.createNamespacedPod({
+    namespace: namespace(),
+    body: appPod
+  })
+}
+ 
+export async function deletePod(name: string): Promise<void> {
+  await k8sApi.deleteNamespacedPod({
+    name,
+    namespace: namespace(),
+    gracePeriodSeconds: 0
+  })
+}
+ 
+export async function execPodStep(
+  command: string[],
+  podName: string,
+  containerName: string,
+  stdin?: stream.Readable
+): Promise<number> {
+  const exec = new k8s.Exec(kc)
+  core.debug(
+    `[execPodStep] Starting: cmd="${command[0]}" (${command.length} args), pod=${podName}, container=${containerName}`
+  )
+ 
+  command = fixArgs(command)
+ 
+  const DEFAULT_PING_PERIOD_MS = 5000
+  const pingPeriodMs = parsePositiveMsEnv(
+    process.env.ACTIONS_RUNNER_HEARTBEAT_PERIOD_MS,
+    DEFAULT_PING_PERIOD_MS
+  )
+  const pongDeadlineMs = parsePositiveMsEnv(
+    process.env.ACTIONS_RUNNER_HEARTBEAT_DEADLINE_MS,
+    pingPeriodMs * 12 + 1000
+  )
+  core.debug(
+    `[execPodStep] Heartbeat config: pingPeriodMs=${pingPeriodMs}, pongDeadlineMs=${pongDeadlineMs}`
+  )
+ 
+  const heartbeat = new WebSocketHeartbeat(pingPeriodMs, pongDeadlineMs)
+ 
+  return new Promise<number>((resolve, reject) => {
+    core.debug('[execPodStep] About to call exec.exec')
+    let ws: HeartbeatWebSocket | null = null
+ 
+    exec
+      .exec(
+        namespace(),
+        podName,
+        containerName,
+        command,
+        process.stdout,
+        process.stderr,
+        stdin ?? null,
+        false /* tty */,
+        async resp => {
+          core.debug(
+            `[execPodStep] execPodStep response: ${JSON.stringify(resp)}`
+          )
+ 
+          heartbeat.stop()
+ 
+          // Close WebSocket and wait for it before resolving/rejecting
+          const closeWebSocket = async (): Promise<void> => {
+            const socket = ws
+            Iif (
+              socket &&
+              (socket.readyState === 1 || socket.readyState === 0)
+            ) {
+              return new Promise<void>(closeResolve => {
+                const closeTimeout = setTimeout(() => {
+                  core.warning(
+                    '[execPodStep] WebSocket close timeout, forcing cleanup'
+                  )
+                  closeResolve()
+                }, 5000)
+ 
+                socket.once('close', () => {
+                  clearTimeout(closeTimeout)
+                  core.debug('[execPodStep] WebSocket closed cleanly')
+                  closeResolve()
+                })
+                socket.close()
+              })
+            }
+          }
+ 
+          if (resp.status === 'Success') {
+            core.debug(`[execPodStep] Success, code: ${resp.code}`)
+            await closeWebSocket()
+            resolve(resp.code || 0)
+          } else {
+            core.debug(
+              `[execPodStep] Failure: ${JSON.stringify({ message: resp?.message, details: resp?.details })}`
+            )
+            await closeWebSocket()
+            reject(new Error(resp?.message || 'execPodStep failed'))
+          }
+        }
+      )
+      .then(websocket => {
+        core.debug('[execPodStep] exec.exec resolved, ws object received')
+        ws = websocket
+        if (ws) {
+          heartbeat.start(ws, reject)
+        } else {
+          core.warning('[Heartbeat] WebSocket is null, heartbeat not started')
+        }
+      })
+      .catch(async e => {
+        heartbeat.stop()
+        core.error(`[execPodStep] exec.exec threw error: ${e}`)
+ 
+        // Close WebSocket before rejecting with timeout protection
+        const socket = ws
+        if (socket && (socket.readyState === 1 || socket.readyState === 0)) {
+          await new Promise<void>(closeResolve => {
+            const closeTimeout = setTimeout(() => {
+              core.warning(
+                '[execPodStep] WebSocket close timeout in error handler'
+              )
+              closeResolve()
+            }, 5000)
+ 
+            socket.once('close', () => {
+              clearTimeout(closeTimeout)
+              closeResolve()
+            })
+            socket.close()
+          })
+        }
+ 
+        reject(e)
+      })
+  })
+}
+ 
+// Variant of execPodStep that also captures the last `tailLines` lines of
+// combined stdout/stderr so callers can surface the script's own output on
+// failure. Returns the exit code plus the tail (empty string on success or if
+// nothing was emitted). The original streams are still tee'd to
+// process.stdout/process.stderr so GitHub Actions logs are unchanged.
+export async function execPodStepWithOutput(
+  command: string[],
+  podName: string,
+  containerName: string,
+  tailLines = 20,
+  stdin?: stream.Readable
+): Promise<{ code: number; output: string }> {
+  const exec = new k8s.Exec(kc)
+  command = fixArgs(command)
+ 
+  // Ring buffer of the last N non-empty lines (cap to keep memory bounded).
+  const buffer: string[] = []
+  const push = (line: string): void => {
+    Iif (line.length === 0) return
+    buffer.push(line)
+    Iif (buffer.length > tailLines) buffer.shift()
+  }
+ 
+  // Separate pending buffers per stream to prevent stdout/stderr interleaving.
+  let pendingOut = ''
+  const ingestOut = (chunk: Buffer | string): void => {
+    pendingOut += chunk.toString('utf8')
+    const lines = pendingOut.split(/\r?\n/)
+    pendingOut = lines.pop() ?? ''
+    for (const line of lines) push(line)
+  }
+ 
+  let pendingErr = ''
+  const ingestErr = (chunk: Buffer | string): void => {
+    pendingErr += chunk.toString('utf8')
+    const lines = pendingErr.split(/\r?\n/)
+    pendingErr = lines.pop() ?? ''
+    for (const line of lines) push(line)
+  }
+ 
+  const flushPending = (): void => {
+    Iif (pendingOut) {
+      push(pendingOut)
+      pendingOut = ''
+    }
+    Iif (pendingErr) {
+      push(pendingErr)
+      pendingErr = ''
+    }
+  }
+ 
+  const capture = new stream.Writable({
+    write(chunk: Buffer | string, _enc, cb) {
+      try {
+        ingestOut(chunk)
+        process.stdout.write(chunk)
+        cb()
+      } catch (e) {
+        cb(e as Error)
+      }
+    }
+  })
+  const captureErr = new stream.Writable({
+    write(chunk: Buffer | string, _enc, cb) {
+      try {
+        ingestErr(chunk)
+        process.stderr.write(chunk)
+        cb()
+      } catch (e) {
+        cb(e as Error)
+      }
+    }
+  })
+ 
+  // Parse an exit code from a k8s exec error/status message.
+  // Handles both "command terminated with exit code N" and
+  // "command terminated with non-zero exit code: command terminated with exit code N".
+  const parseExitCode = (msg: string | undefined): number | null => {
+    const m = msg?.match(/exit code[:\s]+(\d+)/i)
+    return m ? parseInt(m[1], 10) : null
+  }
+ 
+  return await new Promise(function (resolve, reject) {
+    exec
+      .exec(
+        namespace(),
+        podName,
+        containerName,
+        command,
+        capture,
+        captureErr,
+        stdin ?? null,
+        false /* tty */,
+        resp => {
+          core.debug(`execPodStepWithOutput response: ${JSON.stringify(resp)}`)
+          flushPending()
+          if (resp.status === 'Success') {
+            resolve({ code: resp.code || 0, output: buffer.join('\n') })
+          } else {
+            // k8s exec returns status='Failure' for non-zero script exit.
+            // resp.code may be undefined depending on k8s version; fall back
+            // to parsing the exit code from the message string.
+            const code = parseExitCode(resp?.message)
+            if (code !== null) {
+              resolve({ code, output: buffer.join('\n') })
+            } else {
+              reject(new Error(resp?.message || 'execPodStepWithOutput failed'))
+            }
+          }
+        }
+      )
+      .catch(e => {
+        // In @kubernetes/client-node v1.x the promise returned by exec()
+        // itself rejects for non-zero exits (the status callback may or may
+        // not fire first). Detect this case via the error message so the
+        // caller can classify the error instead of treating it as a hook
+        // failure. Genuine failures (connection drop, etc.) still reject.
+        flushPending()
+        const errMsg = e instanceof Error ? e.message : String(e)
+        const code = parseExitCode(errMsg)
+        if (code !== null) {
+          resolve({ code, output: buffer.join('\n') })
+        } else {
+          reject(e)
+        }
+      })
+  })
+}
+ 
+export async function execCalculateOutputHashSorted(
+  podName: string,
+  containerName: string,
+  command: string[]
+): Promise<{ hash: string; lines: string[] }> {
+  const exec = new k8s.Exec(kc)
+ 
+  let output = ''
+  const outputWriter = new stream.Writable({
+    write(chunk, _enc, cb) {
+      try {
+        output += chunk.toString('utf8')
+        cb()
+      } catch (e) {
+        cb(e as Error)
+      }
+    }
+  })
+ 
+  await new Promise<void>((resolve, reject) => {
+    exec
+      .exec(
+        namespace(),
+        podName,
+        containerName,
+        command,
+        outputWriter, // capture stdout
+        process.stderr,
+        null,
+        false /* tty */,
+        resp => {
+          core.debug(`internalExecOutput response: ${JSON.stringify(resp)}`)
+          if (resp.status === 'Success') {
+            resolve()
+          } else {
+            core.debug(
+              JSON.stringify({
+                message: resp?.message,
+                details: resp?.details
+              })
+            )
+            reject(new Error(resp?.message || 'internalExecOutput failed'))
+          }
+        }
+      )
+      .catch(e => reject(e))
+  })
+ 
+  outputWriter.end()
+ 
+  // Sort lines for consistent ordering across platforms
+  const lines = output
+    .split('\n')
+    .filter(line => line.length > 0)
+    .sort()
+  const sortedOutput = lines.join('\n') + '\n'
+ 
+  const hash = createHash('sha256')
+  hash.update(sortedOutput)
+  return { hash: hash.digest('hex'), lines }
+}
+ 
+export async function localCalculateOutputHashSorted(
+  commands: string[]
+): Promise<{ hash: string; lines: string[] }> {
+  return await new Promise<{ hash: string; lines: string[] }>(
+    (resolve, reject) => {
+      const child = spawn(commands[0], commands.slice(1), {
+        stdio: ['ignore', 'pipe', 'ignore']
+      })
+ 
+      let output = ''
+      child.stdout.on('data', chunk => {
+        output += chunk.toString('utf8')
+      })
+      child.on('error', reject)
+      child.on('close', (code: number) => {
+        if (code === 0) {
+          // Sort lines for consistent ordering across distributions/platforms
+          const lines = output
+            .split('\n')
+            .filter(line => line.length > 0)
+            .sort()
+          const sortedOutput = lines.join('\n') + '\n'
+ 
+          const hash = createHash('sha256')
+          hash.update(sortedOutput)
+          resolve({ hash: hash.digest('hex'), lines })
+        } else {
+          reject(new Error(`child process exited with code ${code}`))
+        }
+      })
+    }
+  )
+}
+ 
+export async function execCpToPod(
+  podName: string,
+  runnerPath: string,
+  containerPath: string
+): Promise<void> {
+  core.debug(`Copying ${runnerPath} to pod ${podName} at ${containerPath}`)
+ 
+  let attempt = 0
+  while (true) {
+    try {
+      const exec = new k8s.Exec(kc)
+      // Use tar to extract with --no-same-owner to avoid ownership issues.
+      // Then use find to fix permissions. The -m flag helps but we also need to fix permissions after.
+      const command = [
+        'sh',
+        '-c',
+        `tar xf - --no-same-owner -C ${shlex.quote(containerPath)} 2>/dev/null; ` +
+          `find ${shlex.quote(containerPath)} -type f -exec chmod u+rw {} \\; 2>/dev/null; ` +
+          `find ${shlex.quote(containerPath)} -type d -exec chmod u+rwx {} \\; 2>/dev/null; ` +
+          `sync 2>/dev/null || true`
+      ]
+      const readStream = tar.pack(runnerPath)
+      const errStream = new WritableStreamBuffer()
+      await new Promise((resolve, reject) => {
+        exec
+          .exec(
+            namespace(),
+            podName,
+            JOB_CONTAINER_NAME,
+            command,
+            null,
+            errStream,
+            readStream,
+            false,
+            async status => {
+              if (errStream.size()) {
+                return reject(
+                  new Error(
+                    `Error from execCpToPod - status: ${status.status}, details: \n ${errStream.getContentsAsString()}`
+                  )
+                )
+              }
+              resolve(status)
+            }
+          )
+          .catch(e => reject(e))
+      })
+      break
+    } catch (error) {
+      core.debug(`cpToPod: Attempt ${attempt + 1} failed: ${error}`)
+      attempt++
+      if (attempt >= 30) {
+        throw new Error(
+          `cpToPod failed after ${attempt} attempts: ${formatError(error)}`
+        )
+      }
+      await sleep(1000)
+    }
+  }
+ 
+  let attempts = 15
+  const delay = 1000
+  for (let i = 0; i < attempts; i++) {
+    try {
+      const { hash: want, lines: wantLines } =
+        await localCalculateOutputHashSorted([
+          'sh',
+          '-c',
+          listDirAllCommand(runnerPath)
+        ])
+ 
+      const { hash: got, lines: gotLines } =
+        await execCalculateOutputHashSorted(podName, JOB_CONTAINER_NAME, [
+          'sh',
+          '-c',
+          listDirAllCommand(containerPath)
+        ])
+ 
+      if (got !== want) {
+        core.debug(
+          `[cpToPod hash mismatch attempt ${i + 1}/${attempts}] want='${want}' got='${got}'`
+        )
+        core.debug(
+          `[cpToPod] runner file count=${wantLines.length} pod file count=${gotLines.length}`
+        )
+        const wantMap = new Map(
+          wantLines.map(l => [l.replace(/^\d+ /, ''), l.split(' ')[0]])
+        )
+        const gotMap = new Map(
+          gotLines.map(l => [l.replace(/^\d+ /, ''), l.split(' ')[0]])
+        )
+        const onlyInWant = wantLines.filter(
+          l => !gotMap.has(l.replace(/^\d+ /, ''))
+        )
+        const onlyInGot = gotLines.filter(
+          l => !wantMap.has(l.replace(/^\d+ /, ''))
+        )
+        const sizeDiff = wantLines
+          .filter(l => {
+            const name = l.replace(/^\d+ /, '')
+            return gotMap.has(name) && gotMap.get(name) !== wantMap.get(name)
+          })
+          .map(l => {
+            const name = l.replace(/^\d+ /, '')
+            return `${name}: runner=${wantMap.get(name)} pod=${gotMap.get(name)}`
+          })
+        core.debug(`[cpToPod] only in runner: ${JSON.stringify(onlyInWant)}`)
+        core.debug(`[cpToPod] only in pod:    ${JSON.stringify(onlyInGot)}`)
+        core.debug(`[cpToPod] size mismatch:  ${JSON.stringify(sizeDiff)}`)
+        await sleep(delay)
+        continue
+      }
+ 
+      break
+    } catch (error) {
+      core.debug(`Attempt ${i + 1} failed: ${error}`)
+      await sleep(delay)
+    }
+  }
+}
+ 
+export async function execCpFromPod(
+  podName: string,
+  containerPath: string,
+  parentRunnerPath: string
+): Promise<void> {
+  const targetRunnerPath = `${parentRunnerPath}/${path.basename(containerPath)}`
+  core.debug(
+    `Copying from pod ${podName} ${containerPath} to ${targetRunnerPath}`
+  )
+ 
+  // Clear target before extracting so deleted-on-pod files don't linger locally.
+  // tar.extract() appends into the destination; without this, stale files (e.g.
+  // git-credentials removed by checkout cleanup inside the pod) cause a permanent
+  // hash mismatch that no amount of retrying can resolve.
+  if (fs.existsSync(targetRunnerPath)) {
+    fs.rmSync(targetRunnerPath, { recursive: true, force: true })
+  }
+ 
+  let attempt = 0
+  while (true) {
+    try {
+      // make temporary directory
+      const exec = new k8s.Exec(kc)
+      const containerPaths = containerPath.split('/')
+      const dirname = containerPaths.pop() as string
+      const command = [
+        'tar',
+        'cf',
+        '-',
+        '-C',
+        containerPaths.join('/') || '/',
+        dirname
+      ]
+      const writerStream = tar.extract(parentRunnerPath)
+      const errStream = new WritableStreamBuffer()
+ 
+      await new Promise((resolve, reject) => {
+        // Resolve only after writerStream finishes flushing to disk.
+        // The k8s status callback fires when the pod-side tar process exits,
+        // but tar-fs may still be writing buffered data to the local filesystem.
+        // Waiting for 'finish' ensures all files are on disk before hash check.
+        writerStream.on('finish', resolve)
+        writerStream.on('error', reject)
+        exec
+          .exec(
+            namespace(),
+            podName,
+            JOB_CONTAINER_NAME,
+            command,
+            writerStream,
+            errStream,
+            null,
+            false,
+            async (_s: k8s.V1Status) => {
+              if (errStream.size()) {
+                return reject(
+                  new Error(
+                    `Error from cpFromPod - details: \n ${errStream.getContentsAsString()}`
+                  )
+                )
+              }
+            }
+          )
+          .catch(e => reject(e))
+      })
+      break
+    } catch (error) {
+      core.debug(`Attempt ${attempt + 1} failed: ${error}`)
+      attempt++
+      if (attempt >= 30) {
+        throw new Error(
+          `execCpFromPod failed after ${attempt} attempts: ${formatError(error)}`
+        )
+      }
+      await sleep(1000)
+    }
+  }
+ 
+  let attempts = 15
+  const delay = 1000
+  for (let i = 0; i < attempts; i++) {
+    try {
+      const { hash: want, lines: wantLines } =
+        await execCalculateOutputHashSorted(podName, JOB_CONTAINER_NAME, [
+          'sh',
+          '-c',
+          listDirAllCommand(containerPath)
+        ])
+ 
+      const { hash: got, lines: gotLines } =
+        await localCalculateOutputHashSorted([
+          'sh',
+          '-c',
+          listDirAllCommand(targetRunnerPath)
+        ])
+ 
+      if (got !== want) {
+        core.debug(
+          `[cpFromPod hash mismatch attempt ${i + 1}/${attempts}] want='${want}' got='${got}'`
+        )
+        core.debug(
+          `[cpFromPod] pod file count=${wantLines.length} runner file count=${gotLines.length}`
+        )
+        const wantMap = new Map(
+          wantLines.map(l => [l.replace(/^\d+ /, ''), l.split(' ')[0]])
+        )
+        const gotMap = new Map(
+          gotLines.map(l => [l.replace(/^\d+ /, ''), l.split(' ')[0]])
+        )
+        const onlyInWant = wantLines.filter(
+          l => !gotMap.has(l.replace(/^\d+ /, ''))
+        )
+        const onlyInGot = gotLines.filter(
+          l => !wantMap.has(l.replace(/^\d+ /, ''))
+        )
+        const sizeDiff = wantLines
+          .filter(l => {
+            const name = l.replace(/^\d+ /, '')
+            return gotMap.has(name) && gotMap.get(name) !== wantMap.get(name)
+          })
+          .map(l => {
+            const name = l.replace(/^\d+ /, '')
+            return `${name}: pod=${wantMap.get(name)} runner=${gotMap.get(name)}`
+          })
+        core.debug(`[cpFromPod] only in pod:    ${JSON.stringify(onlyInWant)}`)
+        core.debug(`[cpFromPod] only in runner: ${JSON.stringify(onlyInGot)}`)
+        core.debug(`[cpFromPod] size mismatch:  ${JSON.stringify(sizeDiff)}`)
+        await sleep(delay)
+        continue
+      }
+ 
+      break
+    } catch (error) {
+      core.debug(`Attempt ${i + 1} failed: ${error}`)
+      await sleep(delay)
+    }
+  }
+}
+ 
+export async function waitForJobToComplete(jobName: string): Promise<void> {
+  const backOffManager = new BackOffManager()
+  while (true) {
+    try {
+      if (await isJobSucceeded(jobName)) {
+        return
+      }
+    } catch (error) {
+      throw new Error(`job ${jobName} has failed: ${formatError(error)}`)
+    }
+    await backOffManager.backOff()
+  }
+}
+ 
+export async function createDockerSecret(
+  registry: Registry
+): Promise<k8s.V1Secret> {
+  const authContent = {
+    auths: {
+      [registry.serverUrl || 'https://index.docker.io/v1/']: {
+        username: registry.username,
+        password: registry.password,
+        auth: Buffer.from(`${registry.username}:${registry.password}`).toString(
+          'base64'
+        )
+      }
+    }
+  }
+ 
+  const runnerInstanceLabel = new RunnerInstanceLabel()
+ 
+  const secretName = getSecretName()
+  const secret = new k8s.V1Secret()
+  secret.immutable = true
+  secret.apiVersion = 'v1'
+  secret.metadata = new k8s.V1ObjectMeta()
+  secret.metadata.name = secretName
+  secret.metadata.namespace = namespace()
+  secret.metadata.labels = {
+    [runnerInstanceLabel.key]: runnerInstanceLabel.value
+  }
+  secret.type = 'kubernetes.io/dockerconfigjson'
+  secret.kind = 'Secret'
+  secret.data = {
+    '.dockerconfigjson': Buffer.from(JSON.stringify(authContent)).toString(
+      'base64'
+    )
+  }
+ 
+  return await k8sApi.createNamespacedSecret({
+    namespace: namespace(),
+    body: secret
+  })
+}
+ 
+export async function createSecretForEnvs(envs: {
+  [key: string]: string
+}): Promise<string> {
+  const runnerInstanceLabel = new RunnerInstanceLabel()
+ 
+  const secret = new k8s.V1Secret()
+  const secretName = getSecretName()
+  secret.immutable = true
+  secret.apiVersion = 'v1'
+  secret.metadata = new k8s.V1ObjectMeta()
+  secret.metadata.name = secretName
+ 
+  secret.metadata.labels = {
+    [runnerInstanceLabel.key]: runnerInstanceLabel.value
+  }
+  secret.kind = 'Secret'
+  secret.data = {}
+  for (const [key, value] of Object.entries(envs)) {
+    secret.data[key] = Buffer.from(value).toString('base64')
+  }
+ 
+  await k8sApi.createNamespacedSecret({
+    namespace: namespace(),
+    body: secret
+  })
+  return secretName
+}
+ 
+export async function deleteSecret(name: string): Promise<void> {
+  await k8sApi.deleteNamespacedSecret({
+    name,
+    namespace: namespace()
+  })
+}
+ 
+export async function pruneSecrets(): Promise<void> {
+  const secretList = await k8sApi.listNamespacedSecret({
+    namespace: namespace(),
+    labelSelector: new RunnerInstanceLabel().toString()
+  })
+  if (!secretList.items.length) {
+    return
+  }
+ 
+  await Promise.all(
+    secretList.items.map(
+      async secret =>
+        secret.metadata?.name && (await deleteSecret(secret.metadata.name))
+    )
+  )
+}
+ 
+export const UNRECOVERABLE_WAITING_REASONS = new Set([
+  // k8s has already retried image pull multiple times with exponential backoff.
+  // ErrImagePull is excluded: it fires on the first failure (could be a transient
+  // TLS timeout or network blip) and k8s will naturally promote it to
+  // ImagePullBackOff after a moment. Fast-failing on ErrImagePull would kill
+  // jobs that would have succeeded on the next pull attempt.
+  'ImagePullBackOff',
+  // Image name is syntactically invalid — cannot self-heal without a config fix.
+  'InvalidImageName',
+  // Container spec is invalid (bad env vars, resource limits, securityContext) —
+  // cannot self-heal without a config fix.
+  'CreateContainerConfigError'
+  // CreateContainerError is excluded: it is sometimes emitted transiently by the
+  // container runtime (e.g. during a node-level runtime restart). It can
+  // self-resolve on the next kubelet retry cycle.
+])
+ 
+// Pod *event* reasons (from the event stream, not container status) that
+// indicate a permanent failure the pod will never recover from on its own.
+// These surface as Warning events on the pod (visible via `kubectl describe`)
+// rather than in container.status.state.waiting.reason, so they need a separate
+// list + a separate (async) detection path.
+//
+//   - FailedMount: a volume cannot be mounted (e.g. hostPath `type: Directory`
+//     pointing at a path that does not exist on the node, missing PVC, missing
+//     Secret/ConfigMap volume). The container stays in `ContainerCreating`
+//     waiting state, which is NOT in UNRECOVERABLE_WAITING_REASONS, so without
+//     this check the hook polls until the 3600s timeout.
+//   - FailedBinding: a PVC could not be bound (no matching PV, storage class
+//     misconfiguration). Usually paired with FailedMount once the pod retries.
+//
+// FailedScheduling is included but gated by PERMANENT_SCHEDULING_PATTERNS:
+// only messages that positively identify a permanent configuration error
+// trigger fast-fail. Resource shortages ("Insufficient cpu/memory/gpu")
+// are silently skipped so the pod keeps queuing until the timeout.
+export const UNRECOVERABLE_EVENT_REASONS = new Set([
+  'FailedMount',
+  'FailedBinding',
+  'FailedScheduling'
+])
+ 
+// Patterns that POSITIVELY IDENTIFY a permanent, unrecoverable scheduling
+// failure in a FailedScheduling event message. Fast-fail fires ONLY when
+// one of these matches. Anything else (resource shortages, unknown format,
+// absent message) is treated as transient — the pod keeps queuing.
+//
+// Permanent examples (WILL fast-fail):
+//   "0/3 nodes: 3 node(s) didn't match Pod's node affinity/selector."
+//   "0/3 nodes: 3 node(s) had untolerated taint {gpu: true}."
+//   "0/3 nodes: persistentvolumeclaim "my-pvc" not found."
+//
+// Transient examples (will NOT fast-fail, keep queuing):
+//   "0/3 nodes: 3 Insufficient nvidia.com/gpu."
+//   "0/3 nodes: 3 Insufficient memory."
+//   "0/1 nodes are available"  ← ambiguous, unknown
+//
+// Extend at runtime via env var ACTIONS_RUNNER_K8S_PERMANENT_SCHEDULING_PATTERNS
+// (comma-separated regex strings; cannot remove built-in entries).
+export const PERMANENT_SCHEDULING_PATTERNS: readonly RegExp[] = [
+  // Node selector / affinity label mismatch — no node carries the required
+  // labels. Will not self-resolve without a pod-spec or node-label change.
+  /node\(s\) didn't match Pod's node affinity\/selector/i,
+  /node\(s\) didn't match node affinity/i,
+  // Untolerated taint — every node carries a taint the pod does not tolerate.
+  // Will not self-resolve without adding a toleration or removing the taint.
+  /node\(s\) had untolerated taint/i,
+  // PVC referenced in the pod spec does not exist in the namespace. The
+  // scheduler refuses to place the pod until the PVC is created. The workflow
+  // job spec is wrong — it won't self-resolve.
+  /persistentvolumeclaim "[^"]+" not found/i
+]
+ 
+export const UNRECOVERABLE_TERMINATED_REASONS = new Set([
+  'OOMKilled',
+  'Error',
+  'FailedPostStartHookError'
+])
+ 
+// Maximum number of Warning events to include in a pod's failure description so
+// that the GitHub Actions log is not flooded.
+const MAX_DIAGNOSTIC_EVENTS = 10
+ 
+// The fast-fail whitelist can be extended (not narrowed) from the environment so
+// operators can add deterministic terminal reasons without a code change. This
+// reuses the same env-var configuration pattern as the prepare-job timeout. When
+// the variable is unset, behaviour is identical to the built-in defaults.
+export function getUnrecoverableWaitingReasons(): Set<string> {
+  const extra = process.env['ACTIONS_RUNNER_K8S_UNRECOVERABLE_WAITING_REASONS']
+  if (!extra) {
+    return UNRECOVERABLE_WAITING_REASONS
+  }
+  const reasons = new Set(UNRECOVERABLE_WAITING_REASONS)
+  for (const reason of extra.split(',')) {
+    const trimmed = reason.trim()
+    Eif (trimmed) {
+      reasons.add(trimmed)
+    }
+  }
+  return reasons
+}
+ 
+// Mirrors getUnrecoverableWaitingReasons() but for pod *event* reasons. The
+// env var ACTIONS_RUNNER_K8S_UNRECOVERABLE_EVENT_REASONS adds to (never removes
+// from) the built-in UNRECOVERABLE_EVENT_REASONS set.
+export function getUnrecoverableEventReasons(): Set<string> {
+  const extra = process.env['ACTIONS_RUNNER_K8S_UNRECOVERABLE_EVENT_REASONS']
+  if (!extra) {
+    return UNRECOVERABLE_EVENT_REASONS
+  }
+  const reasons = new Set(UNRECOVERABLE_EVENT_REASONS)
+  for (const reason of extra.split(',')) {
+    const trimmed = reason.trim()
+    Eif (trimmed) {
+      reasons.add(trimmed)
+    }
+  }
+  return reasons
+}
+ 
+export function getUnrecoverableTerminatedReasons(): Set<string> {
+  const extra =
+    process.env['ACTIONS_RUNNER_K8S_UNRECOVERABLE_TERMINATED_REASONS']
+  if (!extra) {
+    return UNRECOVERABLE_TERMINATED_REASONS
+  }
+  const reasons = new Set(UNRECOVERABLE_TERMINATED_REASONS)
+  for (const reason of extra.split(',')) {
+    const trimmed = reason.trim()
+    if (trimmed) {
+      reasons.add(trimmed)
+    }
+  }
+  return reasons
+}
+ 
+// Returns true when a FailedScheduling event message positively identifies a
+// permanent configuration error that will not self-resolve. Returns false
+// (treat as transient, keep queuing) for:
+//   - absent/empty messages   → unknown, assume transient
+//   - resource shortages      → Insufficient cpu/memory/gpu/etc.
+//   - any unrecognised format → unknown, assume transient
+export function isPermanentSchedulingFailure(
+  message: string | undefined
+): boolean {
+  if (!message) return false
+  return getPermanentSchedulingPatterns().some(p => p.test(message))
+}
+ 
+// Returns PERMANENT_SCHEDULING_PATTERNS extended by any extra patterns from
+// ACTIONS_RUNNER_K8S_PERMANENT_SCHEDULING_PATTERNS (comma-separated regexes).
+// Invalid regex strings are skipped with a warning.
+// The compiled result is cached: env var changes during a single process are
+// rare (effectively never in a runner job), but this avoids repeated split +
+// RegExp construction on every FailedScheduling poll iteration.
+let _cachedSchedulingPatterns: readonly RegExp[] | undefined
+let _lastSchedulingPatternsEnv: string | undefined
+ 
+export function getPermanentSchedulingPatterns(): readonly RegExp[] {
+  const extra = process.env['ACTIONS_RUNNER_K8S_PERMANENT_SCHEDULING_PATTERNS']
+  if (!extra) return PERMANENT_SCHEDULING_PATTERNS
+  if (_cachedSchedulingPatterns && _lastSchedulingPatternsEnv === extra) {
+    return _cachedSchedulingPatterns
+  }
+  const patterns: RegExp[] = [...PERMANENT_SCHEDULING_PATTERNS]
+  for (const raw of extra.split(',')) {
+    const trimmed = raw.trim()
+    if (!trimmed) continue
+    try {
+      patterns.push(new RegExp(trimmed, 'i'))
+    } catch {
+      core.warning(
+        `ACTIONS_RUNNER_K8S_PERMANENT_SCHEDULING_PATTERNS: invalid regex "${trimmed}", skipped`
+      )
+    }
+  }
+  _lastSchedulingPatternsEnv = extra
+  _cachedSchedulingPatterns = patterns
+  return patterns
+}
+ 
+function getWaitingReasonHint(reason: string): string {
+  switch (reason) {
+    case 'ImagePullBackOff':
+      return [
+        `  → Image pull has failed repeatedly (k8s retried with exponential backoff). Check:`,
+        `    - Image name and tag are correct and exist in the registry`,
+        `    - If private registry: imagePullSecret is configured and credentials are valid`,
+        `    - Network connectivity from the node to the registry (DNS, firewall, proxy, TLS)`,
+        `    Run: kubectl describe pod <pod> | grep -A10 "Events"`
+      ].join('\n')
+    case 'InvalidImageName':
+      return `  → Image name is malformed. Check the workflow/job container image configuration.`
+    case 'CreateContainerConfigError':
+      return `  → Container config is invalid. Check env vars, resource limits, and securityContext in the job spec.`
+    default:
+      return `  → Check pod events with: kubectl describe pod <pod>`
+  }
+}
+ 
+export function getContainerErrors(pod: k8s.V1Pod): string[] {
+  const errors: string[] = []
+  const unrecoverableReasons = getUnrecoverableWaitingReasons()
+  const allStatuses = [
+    ...(pod.status?.initContainerStatuses ?? []),
+    ...(pod.status?.containerStatuses ?? [])
+  ]
+  for (const cs of allStatuses) {
+    const waiting = cs.state?.waiting
+    if (waiting?.reason && unrecoverableReasons.has(waiting.reason)) {
+      const reason = `  ✗ container "${cs.name}": ${waiting.reason}`
+      const detail = waiting.message ? `\n    ${waiting.message}` : ''
+      const hint = `\n${getWaitingReasonHint(waiting.reason)}`
+      errors.push(`${reason}${detail}${hint}`)
+    }
+  }
+  return errors
+}
+ 
+export function getTerminatedReasonHint(
+  reason: string,
+  exitCode: number | undefined
+): string {
+  if (reason === 'OOMKilled') {
+    return `  → Container exceeded its memory limit and was killed by the OOM killer.\n    Increase the memory limit in the job spec or reduce memory usage in the script.`
+  }
+  if (reason === 'FailedPostStartHookError') {
+    return `  → The postStart lifecycle hook failed. Check the hook command and its exit code.`
+  }
+  if (reason === 'Error') {
+    switch (exitCode) {
+      case 137:
+        return `  → Exit code 137: process was killed (SIGKILL). Likely OOM or forceful termination.\n    Check memory usage and resource limits.`
+      case 139:
+        return `  → Exit code 139: segmentation fault (SIGSEGV). The process crashed due to a memory access error.`
+      case 126:
+        return `  → Exit code 126: permission denied. The script or binary is not executable.\n    Check file permissions inside the container image.`
+      case 127:
+        return `  → Exit code 127: command not found. The script or binary does not exist in the container.\n    Check the image contents and the command/entrypoint configuration.`
+      default:
+        return `  → Script or process exited with a non-zero code (${exitCode ?? 'unknown'}).\n    Check the step output above for error messages.\n    Common causes: script logic errors, missing dependencies, unhandled exceptions.`
+    }
+  }
+  return `  → Check pod logs with: kubectl logs <pod> -c ${reason}`
+}
+ 
+export function getContainerTerminatedErrors(pod: k8s.V1Pod): string[] {
+  const errors: string[] = []
+  const unrecoverableReasons = getUnrecoverableTerminatedReasons()
+  const allStatuses = [
+    ...(pod.status?.initContainerStatuses ?? []),
+    ...(pod.status?.containerStatuses ?? [])
+  ]
+  for (const cs of allStatuses) {
+    const terminated = cs.state?.terminated
+    if (terminated?.reason && unrecoverableReasons.has(terminated.reason)) {
+      const reason = `  ✗ container "${cs.name}": ${terminated.reason} (exit code ${terminated.exitCode})`
+      const detail = terminated.message ? `\n    ${terminated.message}` : ''
+      const hint = `\n${getTerminatedReasonHint(terminated.reason, terminated.exitCode)}`
+      errors.push(`${reason}${detail}${hint}`)
+    }
+  }
+  return errors
+}
+ 
+function getEventReasonHint(reason: string): string {
+  switch (reason) {
+    case 'FailedMount':
+      return [
+        `  → A volume could not be mounted. Check:`,
+        `    - PVC is bound (kubectl get pvc)`,
+        `    - Secret/ConfigMap referenced in the volume exists`,
+        `    - hostPath directories exist on the scheduled node`
+      ].join('\n')
+    case 'FailedBinding':
+      return [
+        `  → A PVC could not be bound to a PV. Check:`,
+        `    - StorageClass exists and has a provisioner`,
+        `    - Sufficient capacity is available`,
+        `    - Access mode (ReadWriteOnce/ReadWriteMany) matches available PVs`
+      ].join('\n')
+    case 'FailedScheduling':
+      return [
+        `  → Pod cannot be scheduled due to a permanent configuration error. Check:`,
+        `    - nodeSelector / nodeAffinity labels match at least one node`,
+        `    - All tolerations are present for node taints`,
+        `    - PVCs referenced in the pod spec exist in the namespace`
+      ].join('\n')
+    default:
+      return `  → Check pod events with: kubectl describe pod <pod>`
+  }
+}
+ 
+// Inspects the pod's Warning events for reasons in UNRECOVERABLE_EVENT_REASONS.
+// For FailedScheduling, only fast-fails when the message positively matches
+// a known-permanent configuration error (see PERMANENT_SCHEDULING_PATTERNS).
+// Resource shortages ("Insufficient cpu/memory/gpu") are silently skipped so
+// the pod keeps queuing until the timeout. Best-effort: if events cannot be
+// listed (e.g. the optional 'events' RBAC permission is missing) it returns []
+// instead of blocking container-level fast-fail detection. Deduplicates by
+// reason so a repeatedly-retried event is reported once.
+export async function getPodEventErrors(podName: string): Promise<string[]> {
+  const unrecoverableReasons = getUnrecoverableEventReasons()
+  Iif (unrecoverableReasons.size === 0) {
+    return []
+  }
+ 
+  let items: k8s.CoreV1Event[]
+  try {
+    const result = await k8sApi.listNamespacedEvent({
+      namespace: namespace(),
+      fieldSelector: `involvedObject.name=${podName}`
+    })
+    items = result.items ?? []
+  } catch (err) {
+    core.debug(
+      `Could not list events for pod ${podName} during fast-fail check: ${
+        err instanceof Error ? err.message : String(err)
+      }`
+    )
+    return []
+  }
+ 
+  const errors: string[] = []
+  const seenReasons = new Set<string>()
+  for (const e of items) {
+    if (
+      e.type !== 'Warning' ||
+      !e.reason ||
+      !unrecoverableReasons.has(e.reason)
+    ) {
+      continue
+    }
+    // FailedScheduling: only fast-fail when the message positively matches a
+    // known-permanent config error. Resource shortages and unknown messages
+    // are treated as transient — let the pod keep queuing.
+    if (
+      e.reason === 'FailedScheduling' &&
+      !isPermanentSchedulingFailure(e.message)
+    ) {
+      core.debug(
+        `[fast-fail] Skipping FailedScheduling (not a recognised permanent error): ${
+          e.message ?? '(no message)'
+        }`
+      )
+      continue
+    }
+    if (seenReasons.has(e.reason)) {
+      continue
+    }
+    seenReasons.add(e.reason)
+    const count = e.count && e.count > 1 ? ` (x${e.count})` : ''
+    const reason = `  ✗ event: ${e.reason}${count}`
+    const detail = e.message ? `\n    ${e.message}` : ''
+    const hint = getEventReasonHint(e.reason)
+    errors.push(`${reason}${detail}\n${hint}`)
+  }
+  return errors
+}
+ 
+// describePodFailure aggregates everything that might explain why a pod is not
+// healthy into a single human-readable string. It makes NO success/failure
+// judgement of its own (a terminated exitCode=0 container is just reported as
+// such) -- callers decide what is "bad". It never throws: if it cannot read the
+// pod or list events it returns/embeds a best-effort note instead, so it is safe
+// to call from any error path.
+export async function describePodFailure(podName: string): Promise<string> {
+  let pod: k8s.V1Pod
+  try {
+    pod = await readPod(podName)
+  } catch (err) {
+    return `Could not read pod ${podName} for diagnostics: ${
+      err instanceof Error ? err.message : String(err)
+    }`
+  }
+ 
+  const sections: string[] = []
+  const status = pod.status
+ 
+  // --- Pod-level status ---
+  const podLines: string[] = []
+  const phaseLabel = status?.phase
+    ? `${status.phase}${status.reason ? ` (${status.reason})` : ''}`
+    : 'Unknown'
+  podLines.push(`Pod status: ${phaseLabel}`)
+  Iif (status?.message) {
+    podLines.push(`  ${status.message}`)
+  }
+ 
+  // Surface conditions that are False (e.g. PodScheduled=False from FailedScheduling)
+  for (const cond of status?.conditions ?? []) {
+    if (cond.status === 'False') {
+      const reason = cond.reason ? ` (${cond.reason})` : ''
+      const msg = cond.message ? `: ${cond.message}` : ''
+      podLines.push(`  ✗ ${cond.type}=False${reason}${msg}`)
+    }
+  }
+  sections.push(podLines.join('\n'))
+ 
+  // --- Container-level status (non-zero exits and non-unrecoverable waits) ---
+  const unrecoverableReasons = getUnrecoverableWaitingReasons()
+  const allStatuses = [
+    ...(status?.initContainerStatuses ?? []),
+    ...(status?.containerStatuses ?? [])
+  ]
+  const containerLines: string[] = []
+  for (const cs of allStatuses) {
+    const waiting = cs.state?.waiting
+    if (waiting?.reason) {
+      // Skip reasons already surfaced by getContainerErrors() in the caller's
+      // first line to avoid printing the same error twice.
+      Iif (!unrecoverableReasons.has(waiting.reason)) {
+        const msg = waiting.message ? `\n    ${waiting.message}` : ''
+        containerLines.push(
+          `  ✗ container "${cs.name}" waiting: ${waiting.reason}${msg}`
+        )
+      }
+    }
+    const terminated = cs.state?.terminated
+    // Only surface non-zero exits; exit 0 (e.g. fs-init Completed) is noise.
+    if (terminated && terminated.exitCode !== 0) {
+      const reason = terminated.reason ?? 'Unknown'
+      const msg = terminated.message ? `\n    ${terminated.message}` : ''
+      containerLines.push(
+        `  ✗ container "${cs.name}" terminated: ${reason} (exit code ${terminated.exitCode})${msg}`
+      )
+    }
+  }
+  if (containerLines.length) {
+    sections.push(`Container details:\n${containerLines.join('\n')}`)
+  }
+ 
+  // --- Warning events ---
+  const eventLines = await describePodWarningEvents(podName)
+  if (eventLines.length) {
+    sections.push(`Recent warning events:\n${eventLines.join('\n')}`)
+  }
+ 
+  Iif (!sections.length) {
+    return `No additional diagnostic information available for pod ${podName}`
+  }
+  return sections.join('\n\n')
+}
+ 
+// Reads the most recent Warning events for a pod. Best-effort: listing events
+// requires the optional "events" get/list permission, so any error (including
+// RBAC Forbidden) is swallowed and an empty list is returned.
+async function describePodWarningEvents(podName: string): Promise<string[]> {
+  let items: k8s.CoreV1Event[]
+  try {
+    const result = await k8sApi.listNamespacedEvent({
+      namespace: namespace(),
+      fieldSelector: `involvedObject.name=${podName}`
+    })
+    items = result.items ?? []
+  } catch (err) {
+    core.debug(
+      `Could not list events for pod ${podName} (the 'events' permission may be missing): ${
+        err instanceof Error ? err.message : String(err)
+      }`
+    )
+    return []
+  }
+ 
+  const warnings = items.filter(e => e.type === 'Warning')
+  if (!warnings.length) {
+    return []
+  }
+ 
+  const eventTime = (e: k8s.CoreV1Event): number => {
+    const t = e.lastTimestamp ?? e.eventTime ?? e.firstTimestamp
+    return t ? new Date(t).getTime() : 0
+  }
+  warnings.sort((a, b) => eventTime(a) - eventTime(b))
+ 
+  const recent = warnings.slice(-MAX_DIAGNOSTIC_EVENTS)
+  const lines = recent.map(e => {
+    const count = e.count && e.count > 1 ? ` (x${e.count})` : ''
+    return `  [${e.reason ?? 'Warning'}]${count} ${e.message ?? ''}`.trimEnd()
+  })
+  Iif (warnings.length > recent.length) {
+    lines.unshift(
+      `  (showing ${recent.length} of ${warnings.length} warning events)`
+    )
+  }
+  return lines
+}
+ 
+// Inspects the pod's status.conditions for scheduling failures. FailedScheduling
+// is intentionally excluded from fast-fail detection (see UNRECOVERABLE_EVENT_REASONS
+// comment) — scheduling failures are transient resource waits that should queue
+// until the timeout, not terminate early. This function always returns [] as a
+// result, but is kept so checkUnrecoverableErrors compiles and the dedup logic
+// remains intact for future use.
+export function getPodConditionErrors(_p: k8s.V1Pod): string[] {
+  return []
+}
+ 
+// Aggregates the three independent error-detection sources (container waiting
+// reasons, pod Warning events, and pod conditions) into a single list, applying
+// the cross-source deduplication rule (FailedScheduling event + Unschedulable
+// condition = same failure, report once). Returns [] when no unrecoverable
+// error is detected. The caller decides what to do with the list -- typically
+// attach describePodFailure diagnostics and throw.
+export async function checkUnrecoverableErrors(
+  pod: k8s.V1Pod,
+  podName: string
+): Promise<string[]> {
+  // Deterministic terminal errors on a container (e.g. ImagePullBackOff).
+  const containerErrors = getContainerErrors(pod)
+  // Terminated container errors (e.g. OOMKilled, non-zero exit) with hints.
+  const terminatedErrors = getContainerTerminatedErrors(pod)
+  // Best-effort: returns [] when the optional events RBAC permission is absent.
+  const eventErrors = await getPodEventErrors(podName)
+  // Conditions are set near-instantly by the scheduler while events may take
+  // a few extra seconds to propagate, so always run the check. Deduplicate
+  // against events so the same FailedScheduling isn't printed twice.
+  const conditionErrors = getPodConditionErrors(pod).filter(
+    c =>
+      !eventErrors.some(
+        e => e.includes('FailedScheduling') && c.includes('Unschedulable')
+      )
+  )
+  return [
+    ...containerErrors,
+    ...terminatedErrors,
+    ...eventErrors,
+    ...conditionErrors
+  ]
+}
+ 
+export async function waitForPodPhases(
+  podName: string,
+  awaitingPhases: Set<PodPhase>,
+  backOffPhases: Set<PodPhase>,
+  maxTimeSeconds = DEFAULT_WAIT_FOR_POD_TIME_SECONDS
+): Promise<void> {
+  const backOffManager = new BackOffManager(maxTimeSeconds)
+  let phase: PodPhase = PodPhase.UNKNOWN
+  while (true) {
+    let pod: k8s.V1Pod
+    try {
+      pod = await readPod(podName)
+    } catch (err) {
+      // Transient API error (network blip, API server busy): log and back off
+      // rather than crashing the loop. The timeout will eventually fire if the
+      // pod stays permanently unreadable (e.g. RBAC issue).
+      core.warning(
+        `[waitForPodPhases] Could not read pod ${podName}, will retry after backoff: ${
+          err instanceof Error ? err.message : String(err)
+        }`
+      )
+      try {
+        await backOffManager.backOff()
+      } catch {
+        throw new Error(
+          `Pod ${podName} timed out after ${maxTimeSeconds}s (pod read failed: ${
+            err instanceof Error ? err.message : String(err)
+          })\n${'-'.repeat(60)}\n(pod was unreadable; no further diagnostics available)`
+        )
+      }
+      continue
+    }
+    phase = parsePodPhase(pod)
+    if (awaitingPhases.has(phase)) {
+      return
+    }
+ 
+    // The pod reached a phase we are not willing to keep waiting on
+    // (a terminal/unhealthy phase). First check for unrecoverable
+    // container-level errors (e.g. OOMKilled, non-zero exit) so they are
+    // reported with actionable hints. Fall back to the generic "is unhealthy"
+    // message when no specific error is found.
+    if (!backOffPhases.has(phase)) {
+      const errors = await checkUnrecoverableErrors(pod, podName)
+      const details = await describePodFailure(podName)
+      Iif (errors.length > 0) {
+        throw new Error(
+          `Pod ${podName} has unrecoverable errors:\n${errors.join('\n')}\n${'-'.repeat(60)}\n${details}`
+        )
+      }
+      throw new Error(
+        `Pod ${podName} is unhealthy (phase: ${phase})\n${'-'.repeat(60)}\n${details}`
+      )
+    }
+ 
+    // Still in a back-off phase, but a deterministic unrecoverable error
+    // was detected (container / event / condition). Fail fast with
+    // diagnostics instead of waiting out the full timeout.
+    const errors = await checkUnrecoverableErrors(pod, podName)
+    Eif (errors.length > 0) {
+      const details = await describePodFailure(podName)
+      throw new Error(
+        `Pod ${podName} has unrecoverable errors:\n${errors.join('\n')}\n${'-'.repeat(60)}\n${details}`
+      )
+    }
+ 
+    try {
+      await backOffManager.backOff()
+    } catch (_err) {
+      // BackOffManager throws "backoff timeout" when maxTimeSeconds is exceeded.
+      // Don't surface that bare message: collect diagnostics first so the user
+      // can see WHY the pod never became ready.
+      const details = await describePodFailure(podName)
+      throw new Error(
+        `Pod ${podName} timed out after ${maxTimeSeconds}s (phase: ${phase})\n${'-'.repeat(60)}\n${details}`
+      )
+    }
+  }
+}
+ 
+export function getPrepareJobTimeoutSeconds(): number {
+  const envTimeoutSeconds =
+    process.env['ACTIONS_RUNNER_PREPARE_JOB_TIMEOUT_SECONDS']
+ 
+  if (!envTimeoutSeconds) {
+    return DEFAULT_WAIT_FOR_POD_TIME_SECONDS
+  }
+ 
+  const timeoutSeconds = parseInt(envTimeoutSeconds, 10)
+  if (!timeoutSeconds || timeoutSeconds <= 0) {
+    core.warning(
+      `Prepare job timeout is invalid ("${timeoutSeconds}"): use an int > 0`
+    )
+    return DEFAULT_WAIT_FOR_POD_TIME_SECONDS
+  }
+ 
+  return timeoutSeconds
+}
+ 
+async function readPod(podName: string): Promise<k8s.V1Pod> {
+  return await k8sApi.readNamespacedPod({
+    name: podName,
+    namespace: namespace()
+  })
+}
+ 
+const podPhaseLookup = new Set<string>([
+  PodPhase.PENDING,
+  PodPhase.RUNNING,
+  PodPhase.SUCCEEDED,
+  PodPhase.FAILED,
+  PodPhase.UNKNOWN
+])
+ 
+export function parsePodPhase(pod: k8s.V1Pod): PodPhase {
+  if (!pod.status?.phase || !podPhaseLookup.has(pod.status.phase)) {
+    return PodPhase.UNKNOWN
+  }
+  return pod.status.phase as PodPhase
+}
+ 
+async function isJobSucceeded(name: string): Promise<boolean> {
+  const job = await k8sBatchV1Api.readNamespacedJob({
+    name,
+    namespace: namespace()
+  })
+  if (job.status?.failed) {
+    throw new Error(`job ${name} has failed`)
+  }
+  return !!job.status?.succeeded
+}
+ 
+export async function getPodLogs(
+  podName: string,
+  containerName: string
+): Promise<void> {
+  const log = new k8s.Log(kc)
+  const logStream = new stream.PassThrough()
+  logStream.on('data', chunk => {
+    // use write rather than console.log to prevent double line feed
+    process.stdout.write(chunk)
+  })
+ 
+  await log.log(namespace(), podName, containerName, logStream, {
+    follow: true,
+    pretty: false,
+    timestamps: false
+  })
+  await new Promise((resolve, reject) => {
+    logStream.on('end', () => resolve(null))
+    logStream.on('error', err => {
+      process.stderr.write(err.message)
+      reject(err)
+    })
+  })
+}
+ 
+export async function prunePods(): Promise<void> {
+  const podList = await k8sApi.listNamespacedPod({
+    namespace: namespace(),
+    labelSelector: new RunnerInstanceLabel().toString()
+  })
+  if (!podList.items.length) {
+    return
+  }
+ 
+  await Promise.all(
+    podList.items.map(
+      async pod => pod.metadata?.name && (await deletePod(pod.metadata.name))
+    )
+  )
+}
+ 
+export async function getPodStatus(
+  name: string
+): Promise<k8s.V1PodStatus | undefined> {
+  const pod = await k8sApi.readNamespacedPod({
+    name,
+    namespace: namespace()
+  })
+  return pod.status
+}
+ 
+export async function isAuthPermissionsOK(): Promise<boolean> {
+  const sar = new k8s.V1SelfSubjectAccessReview()
+  const asyncs: Promise<k8s.V1SelfSubjectAccessReview>[] = []
+  for (const resource of requiredPermissions) {
+    for (const verb of resource.verbs) {
+      sar.spec = new k8s.V1SelfSubjectAccessReviewSpec()
+      sar.spec.resourceAttributes = new k8s.V1ResourceAttributes()
+      sar.spec.resourceAttributes.verb = verb
+      sar.spec.resourceAttributes.namespace = namespace()
+      sar.spec.resourceAttributes.group = resource.group
+      sar.spec.resourceAttributes.resource = resource.resource
+      sar.spec.resourceAttributes.subresource = resource.subresource
+      asyncs.push(
+        k8sAuthorizationV1Api.createSelfSubjectAccessReview({ body: sar })
+      )
+    }
+  }
+  const responses = await Promise.all(asyncs)
+  return responses.every(resp => resp.status?.allowed)
+}
+ 
+export async function isPodContainerAlpine(
+  podName: string,
+  containerName: string
+): Promise<boolean> {
+  let isAlpine = true
+  try {
+    await execPodStep(
+      [
+        'sh',
+        '-c',
+        `[ $(cat /etc/*release* | grep -i -e "^ID=*alpine*" -c) != 0 ] || exit 1`
+      ],
+      podName,
+      containerName
+    )
+  } catch {
+    isAlpine = false
+  }
+ 
+  return isAlpine
+}
+ 
+export function namespace(): string {
+  if (process.env['ACTIONS_RUNNER_KUBERNETES_NAMESPACE']) {
+    return process.env['ACTIONS_RUNNER_KUBERNETES_NAMESPACE']
+  }
+ 
+  const context = kc.getContexts().find(ctx => ctx.namespace)
+  Eif (context?.namespace) {
+    return context.namespace
+  }
+ 
+  // When running in-cluster the kubeconfig context has no namespace field;
+  // read it from the mounted ServiceAccount file instead.
+  const saNamespaceFile =
+    '/var/run/secrets/kubernetes.io/serviceaccount/namespace'
+  try {
+    const ns = fs.readFileSync(saNamespaceFile, 'utf8').trim()
+    if (ns) {
+      return ns
+    }
+  } catch {
+    // not running in-cluster, fall through to error
+  }
+ 
+  throw new Error(
+    'Failed to determine namespace. Set the ACTIONS_RUNNER_KUBERNETES_NAMESPACE environment variable or ensure the kubeconfig context includes a namespace.'
+  )
+}
+ 
+class BackOffManager {
+  private backOffSeconds = 1
+  totalTime = 0
+  constructor(private throwAfterSeconds?: number) {
+    if (!throwAfterSeconds || throwAfterSeconds < 0) {
+      this.throwAfterSeconds = undefined
+    }
+  }
+ 
+  async backOff(): Promise<void> {
+    await new Promise(resolve =>
+      setTimeout(resolve, this.backOffSeconds * 1000)
+    )
+    this.totalTime += this.backOffSeconds
+    Iif (this.throwAfterSeconds && this.throwAfterSeconds < this.totalTime) {
+      throw new Error('backoff timeout')
+    }
+    Eif (this.backOffSeconds < 20) {
+      this.backOffSeconds *= 2
+    }
+    Iif (this.backOffSeconds > 20) {
+      this.backOffSeconds = 20
+    }
+  }
+}
+ 
+export function containerPorts(
+  container: ContainerInfo
+): k8s.V1ContainerPort[] {
+  const ports: k8s.V1ContainerPort[] = []
+  if (!container.portMappings?.length) {
+    return ports
+  }
+  for (const portDefinition of container.portMappings) {
+    const portProtoSplit = portDefinition.split('/')
+    if (portProtoSplit.length > 2) {
+      throw new Error(`Unexpected port format: ${portDefinition}`)
+    }
+ 
+    const port = new k8s.V1ContainerPort()
+    port.protocol =
+      portProtoSplit.length === 2 ? portProtoSplit[1].toUpperCase() : 'TCP'
+ 
+    const portSplit = portProtoSplit[0].split(':')
+    if (portSplit.length > 2) {
+      throw new Error('ports should have at most one ":" separator')
+    }
+ 
+    const parsePort = (p: string): number => {
+      const num = Number(p)
+      if (!Number.isInteger(num) || num < 1 || num > 65535) {
+        throw new Error(`invalid container port: ${p}`)
+      }
+      return num
+    }
+ 
+    if (portSplit.length === 1) {
+      port.containerPort = parsePort(portSplit[0])
+    } else {
+      port.hostPort = parsePort(portSplit[0])
+      port.containerPort = parsePort(portSplit[1])
+    }
+ 
+    ports.push(port)
+  }
+  return ports
+}
+ 
+export async function getPodByName(name): Promise<k8s.V1Pod> {
+  return await k8sApi.readNamespacedPod({
+    name,
+    namespace: namespace()
+  })
+}
+ 
+export async function getSecretByName(name: string): Promise<k8s.V1Secret> {
+  return await k8sApi.readNamespacedSecret({
+    name,
+    namespace: namespace()
+  })
+}
+ 
+export async function listPodsByRunnerInstance(): Promise<k8s.V1Pod[]> {
+  const podList = await k8sApi.listNamespacedPod({
+    namespace: namespace(),
+    labelSelector: new RunnerInstanceLabel().toString()
+  })
+  return podList.items ?? []
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/k8s/src/k8s/utils/index.html b/coverage/lcov-report/k8s/src/k8s/utils/index.html new file mode 100644 index 00000000..531eaa89 --- /dev/null +++ b/coverage/lcov-report/k8s/src/k8s/utils/index.html @@ -0,0 +1,131 @@ + + + + + + Code coverage report for k8s/src/k8s/utils + + + + + + + + + +
+
+

All files k8s/src/k8s/utils

+
+ +
+ 98.5% + Statements + 394/400 +
+ + +
+ 92.6% + Branches + 263/284 +
+ + +
+ 98.57% + Functions + 69/70 +
+ + +
+ 98.72% + Lines + 387/392 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
index.ts +
+
98.48%130/13295.78%91/95100%19/1998.47%129/131
npu-metrics.ts +
+
98.5%264/26891%172/18998.03%50/5198.85%258/261
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/k8s/src/k8s/utils/index.ts.html b/coverage/lcov-report/k8s/src/k8s/utils/index.ts.html new file mode 100644 index 00000000..05c9207f --- /dev/null +++ b/coverage/lcov-report/k8s/src/k8s/utils/index.ts.html @@ -0,0 +1,1159 @@ + + + + + + Code coverage report for k8s/src/k8s/utils/index.ts + + + + + + + + + +
+
+

All files / k8s/src/k8s/utils index.ts

+
+ +
+ 98.48% + Statements + 130/132 +
+ + +
+ 95.78% + Branches + 91/95 +
+ + +
+ 100% + Functions + 19/19 +
+ + +
+ 98.47% + Lines + 129/131 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263 +264 +265 +266 +267 +268 +269 +270 +271 +272 +273 +274 +275 +276 +277 +278 +279 +280 +281 +282 +283 +284 +285 +286 +287 +288 +289 +290 +291 +292 +293 +294 +295 +296 +297 +298 +299 +300 +301 +302 +303 +304 +305 +306 +307 +308 +309 +310 +311 +312 +313 +314 +315 +316 +317 +318 +319 +320 +321 +322 +323 +324 +325 +326 +327 +328 +329 +330 +331 +332 +333 +334 +335 +336 +337 +338 +339 +340 +341 +342 +343 +344 +345 +346 +347 +348 +349 +350 +351 +352 +353 +354 +355 +356 +357 +358 +359  +  +  +  +  +  +  +  +  +7x +7x +  +7x +7x +  +7x +7x +7x +  +7x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +5x +5x +  +  +5x +  +  +  +  +  +  +5x +5x +5x +5x +  +  +  +  +  +  +  +  +  +  +  +  +16x +16x +  +  +2x +2x +  +  +16x +  +16x +  +  +  +  +  +  +  +  +16x +16x +16x +16x +  +  +  +  +  +  +  +  +  +  +  +  +3x +  +3x +3x +1x +  +  +1x +  +  +  +  +  +  +  +  +  +  +3x +3x +3x +3x +3x +  +  +  +  +  +  +19x +7x +  +12x +12x +14x +  +  +  +  +  +3x +  +  +  +11x +  +  +  +  +  +  +  +  +9x +  +  +  +9x +  +  +  +18x +18x +  +18x +2x +  +  +16x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +5x +9x +2x +  +  +2x +7x +1x +1x +6x +2x +2x +4x +1x +1x +3x +2x +2x +  +1x +  +  +  +  +  +  +  +  +2x +5x +2x +  +1x +  +  +3x +1x +1x +  +2x +  +  +  +  +  +  +  +  +6x +2x +  +  +  +4x +3x +3x +1x +  +3x +  +  +  +4x +3x +3x +1x +  +  +  +3x +  +  +  +  +  +42x +42x +38x +  +4x +4x +1x +  +1x +  +  +  +3x +  +  +7x +7x +7x +7x +7x +7x +7x +  +  +  +6x +6x +1x +  +5x +5x +  +  +  +  +  +35x +8x +  +27x +  +  +  +1x +  +  +  +2x +  +  +  +  +  +  +  +  +  +39x +2x +  +  +  +  +  +37x +  +39x +5x +5x +5x +5x +  +  +  +  +  +32x +27x +  +  +5x +  +  +  +  +3x +3x +1x +  +2x +2x +  +1x +  +  +  +  +  +2x +  + 
import * as k8s from '@kubernetes/client-node'
+import * as fs from 'fs'
+import * as yaml from 'js-yaml'
+import * as core from '@actions/core'
+import { v1 as uuidv4 } from 'uuid'
+import { CONTAINER_EXTENSION_PREFIX } from '../../hooks/constants'
+import * as shlex from 'shlex'
+import { Mount } from 'hooklib'
+ 
+export const DEFAULT_CONTAINER_ENTRY_POINT_ARGS = [`-f`, `/dev/null`]
+export const DEFAULT_CONTAINER_ENTRY_POINT = 'tail'
+ 
+export const ENV_HOOK_TEMPLATE_PATH = 'ACTIONS_RUNNER_CONTAINER_HOOK_TEMPLATE'
+export const ENV_USE_KUBE_SCHEDULER = 'ACTIONS_RUNNER_USE_KUBE_SCHEDULER'
+ 
+export const EXTERNALS_VOLUME_NAME = 'externals'
+export const GITHUB_VOLUME_NAME = 'github'
+export const WORK_VOLUME = 'work'
+ 
+export const CONTAINER_VOLUMES: k8s.V1VolumeMount[] = [
+  {
+    name: EXTERNALS_VOLUME_NAME,
+    mountPath: '/__e'
+  },
+  {
+    name: WORK_VOLUME,
+    mountPath: '/__w'
+  },
+  {
+    name: GITHUB_VOLUME_NAME,
+    mountPath: '/github'
+  }
+]
+ 
+export function prepareJobScript(userVolumeMounts: Mount[]): {
+  containerPath: string
+  runnerPath: string
+} {
+  let mountDirs = userVolumeMounts
+    .map(m => shlex.quote(m.targetVolumePath))
+    .join(' ')
+ 
+  const content = `#!/bin/sh -l
+set -e
+cp -R /__w/_temp/_github_home /github/home
+cp -R /__w/_temp/_github_workflow /github/workflow
+mkdir -p ${mountDirs}
+`
+ 
+  const filename = `${uuidv4()}.sh`
+  const entryPointPath = `${process.env.RUNNER_TEMP}/${filename}`
+  fs.writeFileSync(entryPointPath, content)
+  return {
+    containerPath: `/__w/_temp/${filename}`,
+    runnerPath: entryPointPath
+  }
+}
+ 
+export function writeRunScript(
+  workingDirectory: string,
+  entryPoint: string,
+  entryPointArgs?: string[],
+  prependPath?: string[],
+  environmentVariables?: { [key: string]: string }
+): { containerPath: string; runnerPath: string } {
+  let exportPath = ''
+  if (prependPath?.length) {
+    // TODO: remove compatibility with typeof prependPath === 'string' as we bump to next major version, the hooks will lose PrependPath compat with runners 2.293.0 and older
+    const prepend =
+      typeof prependPath === 'string' ? prependPath : prependPath.join(':')
+    exportPath = `export PATH=${prepend}:$PATH`
+  }
+ 
+  let environmentPrefix = scriptEnv(environmentVariables)
+ 
+  const content = `#!/bin/sh -l
+set -e
+rm "$0" # remove script after running
+${exportPath}
+cd ${workingDirectory} && \
+exec ${environmentPrefix} ${entryPoint} ${
+    entryPointArgs?.length ? entryPointArgs.join(' ') : ''
+  }
+`
+  const filename = `${uuidv4()}.sh`
+  const entryPointPath = `${process.env.RUNNER_TEMP}/${filename}`
+  fs.writeFileSync(entryPointPath, content)
+  return {
+    containerPath: `/__w/_temp/${filename}`,
+    runnerPath: entryPointPath
+  }
+}
+ 
+export function writeContainerStepScript(
+  dst: string,
+  workingDirectory: string,
+  entryPoint: string,
+  entryPointArgs?: string[],
+  environmentVariables?: { [key: string]: string }
+): { containerPath: string; runnerPath: string } {
+  let environmentPrefix = scriptEnv(environmentVariables)
+ 
+  const parts = workingDirectory.split('/').slice(-2)
+  if (parts.length !== 2) {
+    throw new Error(`Invalid working directory: ${workingDirectory}`)
+  }
+ 
+  const content = `#!/bin/sh -l
+rm "$0" # remove script after running
+mv /__w/_temp/_github_home /github/home && \
+mv /__w/_temp/_github_workflow /github/workflow && \
+mv /__w/_temp/_runner_file_commands /github/file_commands || true && \
+mv ${shlex.quote('/__w/' + parts.join('/') + '/')} /github/workspace && \
+cd /github/workspace && \
+exec ${environmentPrefix} ${shlex.quote(entryPoint)} ${
+    entryPointArgs?.length ? entryPointArgs.map(shlex.quote).join(' ') : ''
+  }
+`
+  const filename = `${uuidv4()}.sh`
+  const entryPointPath = `${dst}/${filename}`
+  core.debug(`Writing container step script to ${entryPointPath}`)
+  fs.writeFileSync(entryPointPath, content)
+  return {
+    containerPath: `/__w/_temp/${filename}`,
+    runnerPath: entryPointPath
+  }
+}
+ 
+function scriptEnv(envs?: { [key: string]: string }): string {
+  if (!envs || !Object.entries(envs).length) {
+    return ''
+  }
+  const envBuffer: string[] = []
+  for (const [key, value] of Object.entries(envs)) {
+    if (
+      key.includes(`=`) ||
+      key.includes(`'`) ||
+      key.includes(`"`) ||
+      key.includes(`$`)
+    ) {
+      throw new Error(
+        `environment key ${key} is invalid - the key must not contain =, $, ', or "`
+      )
+    }
+    envBuffer.push(
+      `"${key}=${value
+        .replace(/\\/g, '\\\\')
+        .replace(/"/g, '\\"')
+        .replace(/\$/g, '\\$')
+        .replace(/`/g, '\\`')}"`
+    )
+  }
+ 
+  Iif (!envBuffer?.length) {
+    return ''
+  }
+ 
+  return `env ${envBuffer.join(' ')} `
+}
+ 
+export function generateContainerName(image: string): string {
+  const nameWithTag = image.split('/').pop()
+  const name = nameWithTag?.split(':')[0]
+ 
+  if (!name) {
+    throw new Error(`Image definition '${image}' is invalid`)
+  }
+ 
+  return name
+}
+ 
+// Overwrite or append based on container options
+//
+// Keep in mind, envs and volumes could be passed as fields in container definition
+// so default volume mounts and envs are appended first, and then create options are used
+// to append more values
+//
+// Rest of the fields are just applied
+// For example, container.createOptions.container.image is going to overwrite container.image field
+export function mergeContainerWithOptions(
+  base: k8s.V1Container,
+  from: k8s.V1Container
+): void {
+  for (const [key, value] of Object.entries(from)) {
+    if (key === 'name') {
+      Iif (value !== CONTAINER_EXTENSION_PREFIX + base.name) {
+        core.warning("Skipping name override: name can't be overwritten")
+      }
+      continue
+    } else if (key === 'image') {
+      core.warning("Skipping image override: image can't be overwritten")
+      continue
+    } else if (key === 'env') {
+      const envs = value as k8s.V1EnvVar[]
+      base.env = mergeLists(base.env, envs)
+    } else if (key === 'volumeMounts' && value) {
+      const volumeMounts = value as k8s.V1VolumeMount[]
+      base.volumeMounts = mergeLists(base.volumeMounts, volumeMounts)
+    } else if (key === 'ports' && value) {
+      const ports = value as k8s.V1ContainerPort[]
+      base.ports = mergeLists(base.ports, ports)
+    } else {
+      base[key] = value
+    }
+  }
+}
+ 
+export function mergePodSpecWithOptions(
+  base: k8s.V1PodSpec,
+  from: k8s.V1PodSpec
+): void {
+  for (const [key, value] of Object.entries(from)) {
+    if (key === 'containers') {
+      base.containers.push(
+        ...from.containers.filter(
+          e => !e.name?.startsWith(CONTAINER_EXTENSION_PREFIX)
+        )
+      )
+    } else if (key === 'volumes' && value) {
+      const volumes = value as k8s.V1Volume[]
+      base.volumes = mergeLists(base.volumes, volumes)
+    } else {
+      base[key] = value
+    }
+  }
+}
+ 
+export function mergeObjectMeta(
+  base: { metadata?: k8s.V1ObjectMeta },
+  from: k8s.V1ObjectMeta
+): void {
+  if (!base.metadata?.labels || !base.metadata?.annotations) {
+    throw new Error(
+      "Can't merge metadata: base.metadata or base.annotations field is undefined"
+    )
+  }
+  if (from?.labels) {
+    for (const [key, value] of Object.entries(from.labels)) {
+      if (base.metadata?.labels?.[key]) {
+        core.warning(`Label ${key} is already defined and will be overwritten`)
+      }
+      base.metadata.labels[key] = value
+    }
+  }
+ 
+  if (from?.annotations) {
+    for (const [key, value] of Object.entries(from.annotations)) {
+      if (base.metadata?.annotations?.[key]) {
+        core.warning(
+          `Annotation ${key} is already defined and will be overwritten`
+        )
+      }
+      base.metadata.annotations[key] = value
+    }
+  }
+}
+ 
+export function readExtensionFromFile(): k8s.V1PodTemplateSpec | undefined {
+  const filePath = process.env[ENV_HOOK_TEMPLATE_PATH]
+  if (!filePath) {
+    return undefined
+  }
+  const doc = yaml.load(fs.readFileSync(filePath, 'utf8'))
+  if (!doc || typeof doc !== 'object') {
+    throw new Error(`Failed to parse ${filePath}`)
+  }
+  return doc as k8s.V1PodTemplateSpec
+}
+ 
+export function useKubeScheduler(): boolean {
+  return process.env[ENV_USE_KUBE_SCHEDULER] === 'true'
+}
+ 
+export enum PodPhase {
+  PENDING = 'Pending',
+  RUNNING = 'Running',
+  SUCCEEDED = 'Succeeded',
+  FAILED = 'Failed',
+  UNKNOWN = 'Unknown',
+  COMPLETED = 'Completed'
+}
+ 
+function mergeLists<T>(base?: T[], from?: T[]): T[] {
+  const b: T[] = base || []
+  if (!from?.length) {
+    return b
+  }
+  b.push(...from)
+  return b
+}
+ 
+export function fixArgs(args: string[]): string[] {
+  // Preserve shell command strings passed via `sh -c` without re-tokenizing.
+  // Retokenizing would split the script into multiple args, breaking `sh -c`.
+  if (args.length >= 2 && args[0] === 'sh' && args[1] === '-c') {
+    return args
+  }
+  return shlex.split(args.join(' '))
+}
+ 
+export async function sleep(ms: number): Promise<void> {
+  return new Promise(resolve => setTimeout(resolve, ms))
+}
+ 
+export function listDirAllCommand(dir: string): string {
+  return `cd ${shlex.quote(dir)} && find . -type f -not -path '*/_runner_hook_responses*' -exec stat -c '%s %n' {} \\;`
+}
+ 
+// Safely turn an unknown thrown value into a diagnostic string without
+// throwing. The previous `JSON.stringify(err)` pattern crashed with
+// `TypeError: Converting circular structure to JSON` when err was a
+// @kubernetes/client-node HTTP error (its response embeds a
+// TLSSocket <-> HTTPParser cycle). The thrown TypeError shadowed the
+// original failure in every catch block that used it (issue #329).
+export function formatError(err: unknown): string {
+  if (err === null || err === undefined) {
+    return String(err)
+  }
+ 
+  // @kubernetes/client-node API errors expose the actual server message
+  // under response.body — prefer that when available.
+  const body =
+    (err as { response?: { body?: unknown } })?.response?.body ??
+    (err as { body?: unknown })?.body
+  if (body && typeof body === 'object') {
+    const msg = (body as { message?: unknown }).message
+    const reason = (body as { reason?: unknown }).reason
+    Eif (typeof msg === 'string') {
+      return typeof reason === 'string' && reason.length > 0
+        ? `${msg} (reason: ${reason})`
+        : msg
+    }
+  }
+ 
+  if (err instanceof Error) {
+    return err.message
+  }
+ 
+  if (typeof err === 'object') {
+    // Non-Error objects sometimes carry a top-level message (axios-style
+    // errors, hand-rolled error-likes). Extract before the JSON.stringify
+    // branch so a circular ref doesn't reduce the diagnostic to
+    // "[object Object]".
+    const msg = (err as { message?: unknown }).message
+    if (typeof msg === 'string') {
+      return msg
+    }
+    try {
+      return JSON.stringify(err)
+    } catch {
+      return String(err)
+    }
+  }
+ 
+  // Primitives serialise more readably via String() than JSON.stringify
+  // (which would quote strings and refuse to handle symbols).
+  return String(err)
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/k8s/src/k8s/utils/npu-metrics.ts.html b/coverage/lcov-report/k8s/src/k8s/utils/npu-metrics.ts.html new file mode 100644 index 00000000..72e1233a --- /dev/null +++ b/coverage/lcov-report/k8s/src/k8s/utils/npu-metrics.ts.html @@ -0,0 +1,2359 @@ + + + + + + Code coverage report for k8s/src/k8s/utils/npu-metrics.ts + + + + + + + + + +
+
+

All files / k8s/src/k8s/utils npu-metrics.ts

+
+ +
+ 98.5% + Statements + 264/268 +
+ + +
+ 91% + Branches + 172/189 +
+ + +
+ 98.03% + Functions + 50/51 +
+ + +
+ 98.85% + Lines + 258/261 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263 +264 +265 +266 +267 +268 +269 +270 +271 +272 +273 +274 +275 +276 +277 +278 +279 +280 +281 +282 +283 +284 +285 +286 +287 +288 +289 +290 +291 +292 +293 +294 +295 +296 +297 +298 +299 +300 +301 +302 +303 +304 +305 +306 +307 +308 +309 +310 +311 +312 +313 +314 +315 +316 +317 +318 +319 +320 +321 +322 +323 +324 +325 +326 +327 +328 +329 +330 +331 +332 +333 +334 +335 +336 +337 +338 +339 +340 +341 +342 +343 +344 +345 +346 +347 +348 +349 +350 +351 +352 +353 +354 +355 +356 +357 +358 +359 +360 +361 +362 +363 +364 +365 +366 +367 +368 +369 +370 +371 +372 +373 +374 +375 +376 +377 +378 +379 +380 +381 +382 +383 +384 +385 +386 +387 +388 +389 +390 +391 +392 +393 +394 +395 +396 +397 +398 +399 +400 +401 +402 +403 +404 +405 +406 +407 +408 +409 +410 +411 +412 +413 +414 +415 +416 +417 +418 +419 +420 +421 +422 +423 +424 +425 +426 +427 +428 +429 +430 +431 +432 +433 +434 +435 +436 +437 +438 +439 +440 +441 +442 +443 +444 +445 +446 +447 +448 +449 +450 +451 +452 +453 +454 +455 +456 +457 +458 +459 +460 +461 +462 +463 +464 +465 +466 +467 +468 +469 +470 +471 +472 +473 +474 +475 +476 +477 +478 +479 +480 +481 +482 +483 +484 +485 +486 +487 +488 +489 +490 +491 +492 +493 +494 +495 +496 +497 +498 +499 +500 +501 +502 +503 +504 +505 +506 +507 +508 +509 +510 +511 +512 +513 +514 +515 +516 +517 +518 +519 +520 +521 +522 +523 +524 +525 +526 +527 +528 +529 +530 +531 +532 +533 +534 +535 +536 +537 +538 +539 +540 +541 +542 +543 +544 +545 +546 +547 +548 +549 +550 +551 +552 +553 +554 +555 +556 +557 +558 +559 +560 +561 +562 +563 +564 +565 +566 +567 +568 +569 +570 +571 +572 +573 +574 +575 +576 +577 +578 +579 +580 +581 +582 +583 +584 +585 +586 +587 +588 +589 +590 +591 +592 +593 +594 +595 +596 +597 +598 +599 +600 +601 +602 +603 +604 +605 +606 +607 +608 +609 +610 +611 +612 +613 +614 +615 +616 +617 +618 +619 +620 +621 +622 +623 +624 +625 +626 +627 +628 +629 +630 +631 +632 +633 +634 +635 +636 +637 +638 +639 +640 +641 +642 +643 +644 +645 +646 +647 +648 +649 +650 +651 +652 +653 +654 +655 +656 +657 +658 +659 +660 +661 +662 +663 +664 +665 +666 +667 +668 +669 +670 +671 +672 +673 +674 +675 +676 +677 +678 +679 +680 +681 +682 +683 +684 +685 +686 +687 +688 +689 +690 +691 +692 +693 +694 +695 +696 +697 +698 +699 +700 +701 +702 +703 +704 +705 +706 +707 +708 +709 +710 +711 +712 +713 +714 +715 +716 +717 +718 +719 +720 +721 +722 +723 +724 +725 +726 +727 +728 +729 +730 +731 +732 +733 +734 +735 +736 +737 +738 +739 +740 +741 +742 +743 +744 +745 +746 +747 +748 +749 +750 +751 +752 +753 +754 +755 +756 +757 +758 +759  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +3x +3x +3x +3x +  +3x +3x +3x +  +3x +3x +3x +3x +  +3x +3x +3x +  +3x +3x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +51x +  +  +  +  +  +  +  +5x +5x +1x +  +4x +4x +2x +  +  +2x +  +2x +  +  +  +  +  +9x +9x +7x +  +2x +2x +1x +  +  +1x +  +1x +  +  +  +60x +60x +107x +16x +14x +  +  +  +46x +  +  +  +18x +  +  +  +19x +  +  +  +  +  +8x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +3x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +11x +  +  +  +  +  +  +  +  +  +  +13x +  +  +  +  +  +  +10x +  +  +  +  +  +1x +  +  +  +  +  +9x +2x +  +10x +  +  +  +  +  +  +7x +7x +  +  +  +1x +  +  +6x +  +  +  +1x +  +  +1x +  +  +5x +5x +  +5x +  +  +  +  +  +  +  +7x +  +  +  +  +  +  +  +7x +7x +  +  +  +39x +1x +  +38x +37x +  +1x +  +  +  +  +  +17x +2x +  +15x +15x +2x +  +13x +13x +13x +12x +  +13x +  +15x +15x +  +2x +  +13x +2x +  +11x +11x +11x +2x +  +9x +  +  +  +  +  +  +  +  +  +11x +  +2x +  +  +  +  +  +  +14x +1x +  +15x +  +  +  +111x +  +  +  +8x +88x +88x +  +  +  +3x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +8x +  +  +  +  +  +  +  +  +  +  +8x +8x +8x +8x +8x +8x +8x +8x +8x +  +88x +  +  +8x +8x +8x +8x +8x +  +8x +8x +  +  +8x +  +  +  +3x +  +  +  +  +  +  +  +  +  +  +7x +  +  +  +  +  +  +  +  +3x +3x +3x +  +2x +2x +  +  +1x +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +18x +18x +18x +  +  +18x +5x +  +  +5x +  +17x +17x +  +  +  +  +  +  +  +  +5x +5x +5x +  +  +  +17x +17x +17x +  +  +  +  +  +  +  +  +  +13x +13x +13x +13x +  +13x +25x +12x +  +25x +25x +  +  +  +  +  +  +9x +8x +  +1x +  +16x +  +  +17x +  +  +  +  +  +8x +8x +18x +18x +5x +  +13x +13x +13x +  +  +  +  +8x +8x +3x +  +5x +  +  +  +  +  +  +  +5x +5x +4x +  +1x +  +  +1x +  +  +  +  +11x +  +  +11x +11x +  +  +  +10x +10x +10x +  +  +  +10x +8x +6x +6x +6x +  +  +  +4x +2x +2x +1x +  +  +3x +  +  +  +  +  +  +  +  +  +  +  +9x +9x +9x +9x +9x +  +  +  +18x +8x +8x +8x +8x +  +  +  +  +9x +7x +  +9x +9x +  +  +9x +  +  +  +  +  +  +  +  +  +  +9x +7x +  +2x +9x +9x +1x +  +1x +  +  +  +  +  +12x +12x +1x +  +11x +11x +  +12x +12x +5x +  +6x +1x +  +5x +  +  +  +  +  +4x +  +  +  +8x +1x +  +7x +7x +7x +  +1x +1x +  +6x +16x +  +6x +1x +  +  +5x +5x +5x +5x +  +  +  +  +5x +5x +1x +  +  +1x +  +  +4x +8x +8x +8x +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +8x +7x +1x +1x +  +  +6x +6x +  +  +  +  +  +  +  +  +  +  +  +8x +  +  +  +  +8x +8x +8x +4x +  +2x +2x +2x +  +  +  +  +  + 
import * as core from '@actions/core'
+import * as k8s from '@kubernetes/client-node'
+import * as https from 'https'
+import * as http from 'http'
+import { URL } from 'url'
+import { getRunnerPodName, JOB_CONTAINER_NAME } from '../../hooks/constants'
+import { formatError } from './index'
+import {
+  execPodStepWithOutput,
+  getPodByName,
+  getSecretByName,
+  listPodsByRunnerInstance,
+  namespace
+} from '../index'
+ 
+export const NPU_METRICS_MARKER = 'NPU_METRICS_V1'
+export const ENV_NPU_METRICS_ENABLED = 'ACTIONS_RUNNER_NPU_METRICS'
+export const ENV_NPU_SAMPLE_INTERVAL = 'NPU_SAMPLE_INTERVAL'
+export const ENV_NPU_IDLE_THRESHOLD = 'NPU_IDLE_THRESHOLD'
+ 
+export const DEFAULT_NPU_SAMPLE_INTERVAL_SECONDS = 1
+export const MIN_NPU_SAMPLE_INTERVAL_SECONDS = 0.2
+export const DEFAULT_NPU_IDLE_THRESHOLD_PERCENT = 5
+ 
+export const NPU_SAMPLES_FILE = '/tmp/npu-samples.jsonl'
+export const NPU_TERMINATION_LOG = '/dev/termination-log'
+export const NPU_SAMPLES_MAX_BYTES = 4 * 1024 * 1024
+export const NPU_AGGREGATE_MAX_BYTES = 4096
+ 
+export const NPU_METRICS_SECRET_NAME = 'npu-metrics-pushgw'
+export const NPU_METRICS_PUSH_JOB = 'npu-job-record'
+export const NPU_COLLECT_TIMEOUT_MS = 10_000
+ 
+const NPU_RESOURCE_REGEX = /^huawei\.com\/(ascend\S*)$/i
+const SCALE_SET_NAME_REGEX = /^linux-[a-z0-9]+-[a-z0-9]+-\d+-([a-z][a-z0-9-]*)$/
+ 
+export interface NpuCardAggregate {
+  card: string
+  samples: number
+  peakUtil: number
+  avgUtil: number
+  peakHbm: number
+  firstTs: number
+  lastTs: number
+}
+ 
+export interface NpuAggregatePayload {
+  version: string
+  ts: number
+  cards: NpuCardAggregate[]
+}
+ 
+export interface NpuPushConfig {
+  url: string
+  username?: string
+  password?: string
+}
+ 
+export interface NpuJobLabels {
+  cluster: string
+  namespace: string
+  pod: string
+  podType: string
+  repo: string
+  runId: string
+  npuType: string
+  cardsRequested: string
+  result: string
+}
+ 
+export function npuMetricsEnabled(
+  env: Record<string, string | undefined> = process.env
+): boolean {
+  return (
+    (env[ENV_NPU_METRICS_ENABLED] ?? '').trim().toLowerCase() !== 'disabled'
+  )
+}
+ 
+export function getNpuSampleIntervalSeconds(
+  env: Record<string, string | undefined> = process.env
+): number {
+  const raw = env[ENV_NPU_SAMPLE_INTERVAL]
+  if (!raw) {
+    return DEFAULT_NPU_SAMPLE_INTERVAL_SECONDS
+  }
+  const parsed = Number(raw)
+  if (!Number.isFinite(parsed) || parsed <= 0) {
+    core.warning(
+      `NPU_SAMPLE_INTERVAL is invalid ("${raw}"): use ${DEFAULT_NPU_SAMPLE_INTERVAL_SECONDS}`
+    )
+    return DEFAULT_NPU_SAMPLE_INTERVAL_SECONDS
+  }
+  return Math.max(parsed, MIN_NPU_SAMPLE_INTERVAL_SECONDS)
+}
+ 
+export function getIdleThresholdPercent(
+  env: Record<string, string | undefined> = process.env
+): number {
+  const raw = env[ENV_NPU_IDLE_THRESHOLD]
+  if (!raw) {
+    return DEFAULT_NPU_IDLE_THRESHOLD_PERCENT
+  }
+  const parsed = Number(raw)
+  if (!Number.isFinite(parsed) || parsed < 0) {
+    core.warning(
+      `NPU_IDLE_THRESHOLD is invalid ("${raw}"): use ${DEFAULT_NPU_IDLE_THRESHOLD_PERCENT}`
+    )
+    return DEFAULT_NPU_IDLE_THRESHOLD_PERCENT
+  }
+  return parsed
+}
+ 
+export function containerHasNpuRequest(container: k8s.V1Container): boolean {
+  const resources = [container.resources?.requests, container.resources?.limits]
+  for (const entry of resources) {
+    for (const key of Object.keys(entry ?? {})) {
+      if (NPU_RESOURCE_REGEX.test(key)) {
+        return true
+      }
+    }
+  }
+  return false
+}
+ 
+export function hasNpuRequest(spec: k8s.V1PodSpec | undefined): boolean {
+  return (spec?.containers ?? []).some(c => containerHasNpuRequest(c))
+}
+ 
+function listNpuCardsCommand(): string {
+  return `ls /dev/davinci[0-9]* 2>/dev/null | sed 's|.*/davinci||' | sort -n | uniq | tr '\\n' ' '`
+}
+ 
+export function buildNpuSamplerScript(
+  intervalSeconds = DEFAULT_NPU_SAMPLE_INTERVAL_SECONDS
+): string {
+  return [
+    `# ${NPU_METRICS_MARKER} sampler (detached, best-effort)`,
+    `F=${NPU_SAMPLES_FILE}`,
+    `CARDS=$(${listNpuCardsCommand()})`,
+    `[ -z "$CARDS" ] && exit 0`,
+    `while :; do`,
+    `  NOW=$(date +%s)`,
+    `  for C in $CARDS; do`,
+    `    OUT=$(npu-smi info -t usages -i "$C" 2>/dev/null) || continue`,
+    `    U=$(printf '%s\\n' "$OUT" | awk '{l=$0; gsub(/[ \\t\\r]/, "", l)} l ~ /AICore/ { if (match(l, /[0-9.]+%?$/)) { v = substr(l, RSTART, RLENGTH); sub(/%$/, "", v); print v; exit } }')`,
+    `    H=$(printf '%s\\n' "$OUT" | awk '{l=$0; gsub(/[ \\t\\r]/, "", l)} l ~ /HBM/ { if (match(l, /[0-9.]+%?$/)) { v = substr(l, RSTART, RLENGTH); sub(/%$/, "", v); print v; exit } }')`,
+    `    printf '{"ts":%s,"card":%s,"util":%s,"hbm":%s}\\n' "$NOW" "$C" "\${U:-0}" "\${H:-0}" >> "$F" 2>/dev/null || true`,
+    `  done`,
+    `  SZ=$(wc -c < "$F" 2>/dev/null || echo 0)`,
+    `  if [ "$SZ" -gt ${NPU_SAMPLES_MAX_BYTES} ]; then`,
+    `    tail -n 2000 "$F" > "$F.r" 2>/dev/null && mv "$F.r" "$F" || true`,
+    `  fi`,
+    `  sleep ${intervalSeconds}`,
+    `done`
+  ].join('\n')
+}
+ 
+const AGGREGATE_AWK = [
+  `BEGIN {`,
+  `  n = split(cards, a, " ")`,
+  `  for (i = 1; i <= n; i++) { cnt[a[i]] = 0; pu[a[i]] = 0; ph[a[i]] = 0; su[a[i]] = 0; fs[a[i]] = 0; ls[a[i]] = 0 }`,
+  `}`,
+  `{`,
+  `  ts = $0; sub(/.*"ts":/, "", ts); sub(/[^0-9].*/, "", ts)`,
+  `  c = $0;  sub(/.*"card":/, "", c); sub(/[^0-9].*/, "", c)`,
+  `  u = $0; sub(/.*"util":/, "", u); sub(/[^0-9.].*/, "", u)`,
+  `  h = $0; sub(/.*"hbm":/, "", h); sub(/[^0-9.].*/, "", h)`,
+  `  if (c == "") next`,
+  `  cnt[c]++`,
+  `  if (ts != "") { t = ts + 0; if (fs[c] == 0 || t < fs[c]) fs[c] = t; if (t > ls[c]) ls[c] = t }`,
+  `  if (u + 0 > pu[c]) pu[c] = u + 0`,
+  `  if (h + 0 > ph[c]) ph[c] = h + 0`,
+  `  su[c] += u + 0`,
+  `}`,
+  `END {`,
+  `  printf "{\\"v\\":\\"${NPU_METRICS_MARKER}\\",\\"ts\\":%d,\\"cards\\":[", now`,
+  `  sep = ""`,
+  `  for (c in cnt) {`,
+  `    au = cnt[c] > 0 ? su[c] / cnt[c] : 0`,
+  `    printf "%s{\\"c\\":\\"%s\\",\\"n\\":%d,\\"pu\\":%.1f,\\"au\\":%.1f,\\"ph\\":%.1f,\\"fs\\":%d,\\"ls\\":%d}", sep, c, cnt[c], pu[c], au, ph[c], fs[c], ls[c]`,
+  `    sep = ","`,
+  `  }`,
+  `  printf "]}\\n"`,
+  `}`
+].join('\n')
+ 
+export function buildNpuAggregateScript(): string {
+  return [
+    `# ${NPU_METRICS_MARKER} aggregate`,
+    `F=${NPU_SAMPLES_FILE}`,
+    `CARDS=$(${listNpuCardsCommand()})`,
+    `NOW=$(date +%s)`,
+    `touch "$F" 2>/dev/null || true`,
+    `awk -v now="$NOW" -v cards="$CARDS" '${AGGREGATE_AWK}' "$F" 2>/dev/null`
+  ].join('\n')
+}
+ 
+function commandHasMarker(command: string[] | undefined): boolean {
+  return (command ?? []).join(' ').includes(NPU_METRICS_MARKER)
+}
+ 
+function appendExecCommand(
+  existing: string[] | undefined,
+  appendLines: string[]
+): string[] {
+  if (
+    existing &&
+    existing.length >= 3 &&
+    /(^|\/)sh$/.test(existing[0]) &&
+    existing[1] === '-c'
+  ) {
+    return [
+      existing[0],
+      existing[1],
+      [...existing.slice(2), ...appendLines].join('\n')
+    ]
+  }
+  const prefix = (existing ?? []).map(
+    part => `'${part.replace(/'/g, "'\\''")}'`
+  )
+  return ['sh', '-c', [prefix.join(' '), ...appendLines].join('\n')]
+}
+ 
+export function injectNpuMetrics(
+  container: k8s.V1Container,
+  intervalSeconds = DEFAULT_NPU_SAMPLE_INTERVAL_SECONDS
+): boolean {
+  const lifecycle = container.lifecycle ?? {}
+  if (
+    commandHasMarker(lifecycle.postStart?.exec?.command) ||
+    commandHasMarker(lifecycle.preStop?.exec?.command)
+  ) {
+    return false
+  }
+ 
+  if (
+    (lifecycle.postStart && !lifecycle.postStart.exec) ||
+    (lifecycle.preStop && !lifecycle.preStop.exec)
+  ) {
+    core.warning(
+      'npu-metrics: container already has a non-exec lifecycle handler, skip injection'
+    )
+    return false
+  }
+ 
+  const samplerLine = `(${buildNpuSamplerScript(intervalSeconds)}) >/dev/null 2>&1 &`
+  const aggregateLine = `{ ( ${buildNpuAggregateScript()} ) | head -c ${NPU_AGGREGATE_MAX_BYTES} > ${NPU_TERMINATION_LOG}; } 2>/dev/null || true`
+ 
+  lifecycle.postStart = {
+    exec: {
+      command: appendExecCommand(lifecycle.postStart?.exec?.command, [
+        `# ${NPU_METRICS_MARKER} postStart: start detached npu sampler`,
+        samplerLine
+      ])
+    }
+  }
+  lifecycle.preStop = {
+    exec: {
+      command: appendExecCommand(lifecycle.preStop?.exec?.command, [
+        `# ${NPU_METRICS_MARKER} preStop: write npu aggregate to termination log`,
+        aggregateLine
+      ])
+    }
+  }
+  container.lifecycle = lifecycle
+  return true
+}
+ 
+export function maybeInjectNpuMetrics(container: k8s.V1Container): boolean {
+  if (!npuMetricsEnabled()) {
+    return false
+  }
+  if (!containerHasNpuRequest(container)) {
+    return false
+  }
+  return injectNpuMetrics(container)
+}
+ 
+export function parseNpuAggregate(
+  raw: string | undefined
+): NpuAggregatePayload | undefined {
+  if (!raw) {
+    return undefined
+  }
+  const start = raw.indexOf('{"v":')
+  if (start === -1) {
+    return undefined
+  }
+  const candidates = [raw.slice(start)]
+  const end = raw.lastIndexOf('}')
+  if (end > start) {
+    candidates.push(raw.slice(start, end + 1))
+  }
+  for (const candidate of candidates) {
+    let parsed: any
+    try {
+      parsed = JSON.parse(candidate)
+    } catch {
+      continue
+    }
+    if (parsed?.v !== NPU_METRICS_MARKER || !Array.isArray(parsed.cards)) {
+      continue
+    }
+    const cards: NpuCardAggregate[] = []
+    for (const c of parsed.cards) {
+      if (c === null || typeof c !== 'object' || c.c === undefined) {
+        continue
+      }
+      cards.push({
+        card: String(c.c),
+        samples: Number(c.n) || 0,
+        peakUtil: Number(c.pu) || 0,
+        avgUtil: Number(c.au) || 0,
+        peakHbm: Number(c.ph) || 0,
+        firstTs: Number(c.fs) || 0,
+        lastTs: Number(c.ls) || 0
+      })
+    }
+    return { version: parsed.v, ts: Number(parsed.ts) || 0, cards }
+  }
+  return undefined
+}
+ 
+export function isIdleRecord(
+  cards: NpuCardAggregate[],
+  threshold = DEFAULT_NPU_IDLE_THRESHOLD_PERCENT
+): boolean {
+  if (!cards.length) {
+    return false
+  }
+  return cards.every(c => c.peakUtil < threshold && c.avgUtil < threshold)
+}
+ 
+export function escapePromLabelValue(value: string): string {
+  return value.replace(/\\/g, '\\\\').replace(/"/g, '\\"').replace(/\n/g, '\\n')
+}
+ 
+export function formatPromLabels(labels: Record<string, string>): string {
+  return Object.entries(labels)
+    .filter(([, v]) => v !== undefined)
+    .map(([k, v]) => `${k}="${escapePromLabelValue(v)}"`)
+    .join(',')
+}
+ 
+const NPU_JOB_METRIC_LABEL_KEYS = [
+  'cluster',
+  'namespace',
+  'repo',
+  'run_id',
+  'pod',
+  'pod_type',
+  'card',
+  'npu_type',
+  'cards_requested',
+  'result',
+  'idle'
+]
+ 
+export function buildNpuJobMetricsBody(
+  labels: NpuJobLabels,
+  cards: NpuCardAggregate[],
+  idleThreshold = DEFAULT_NPU_IDLE_THRESHOLD_PERCENT
+): string {
+  const base: Record<string, string> = {
+    cluster: labels.cluster,
+    namespace: labels.namespace,
+    repo: labels.repo,
+    run_id: labels.runId,
+    pod: labels.pod,
+    pod_type: labels.podType,
+    npu_type: labels.npuType,
+    cards_requested: labels.cardsRequested,
+    result: labels.result
+  }
+  const idle = isIdleRecord(cards, idleThreshold) ? 'true' : 'false'
+  const lines: string[] = []
+  lines.push('# TYPE custom_npu_job_peak_util_percent gauge')
+  lines.push('# TYPE custom_npu_job_avg_util_percent gauge')
+  lines.push('# TYPE custom_npu_job_duration_seconds gauge')
+  lines.push('# TYPE custom_npu_job_sample_count gauge')
+  for (const card of cards) {
+    const cardLabels = { ...base, card: card.card, idle }
+    const l = formatPromLabels(
+      Object.fromEntries(
+        NPU_JOB_METRIC_LABEL_KEYS.map(k => [k, cardLabels[k]])
+      ) as Record<string, string>
+    )
+    lines.push(`custom_npu_job_peak_util_percent{${l}} ${card.peakUtil}`)
+    lines.push(`custom_npu_job_avg_util_percent{${l}} ${card.avgUtil}`)
+    const duration = Math.max(card.lastTs - card.firstTs, 0)
+    lines.push(`custom_npu_job_duration_seconds{${l}} ${duration}`)
+    lines.push(`custom_npu_job_sample_count{${l}} ${card.samples}`)
+  }
+  lines.push('# TYPE custom_npu_job_push_total counter')
+  lines.push(
+    `custom_npu_job_push_total{cluster="${escapePromLabelValue(labels.cluster)}",namespace="${escapePromLabelValue(labels.namespace)}",status="success"} 1`
+  )
+  return lines.join('\n') + '\n'
+}
+ 
+export function buildNpuPushFailedBody(labels: NpuJobLabels): string {
+  return (
+    `# TYPE custom_npu_job_push_total counter\n` +
+    `custom_npu_job_push_total{cluster="${escapePromLabelValue(labels.cluster)}",namespace="${escapePromLabelValue(labels.namespace)}",status="failed"} 1\n`
+  )
+}
+ 
+export function buildPushgatewayPath(
+  cluster: string,
+  ns: string,
+  pod: string
+): string {
+  return `/metrics/job/${NPU_METRICS_PUSH_JOB}/cluster/${encodeURIComponent(
+    cluster
+  )}/ns/${encodeURIComponent(ns)}/pod/${encodeURIComponent(pod)}`
+}
+ 
+export async function withTimeout<T>(
+  promise: Promise<T>,
+  timeoutMs: number
+): Promise<T> {
+  return await new Promise<T>((resolve, reject) => {
+    const timer = setTimeout(() => reject(new Error('timeout')), timeoutMs)
+    promise.then(
+      value => {
+        clearTimeout(timer)
+        resolve(value)
+      },
+      err => {
+        clearTimeout(timer)
+        reject(err)
+      }
+    )
+  })
+}
+ 
+export interface PushRequest {
+  url: string
+  method: string
+  body: string
+  username?: string
+  password?: string
+  timeoutMs?: number
+}
+ 
+export type RequestFn = (req: PushRequest) => Promise<{ statusCode: number }>
+ 
+export async function nodeRequest(req: PushRequest): Promise<{
+  statusCode: number
+}> {
+  const target = new URL(req.url)
+  const client = target.protocol === 'http:' ? http : https
+  const headers: Record<string, string> = {
+    'Content-Type': 'text/plain'
+  }
+  if (req.username !== undefined || req.password !== undefined) {
+    const basic = Buffer.from(
+      `${req.username ?? ''}:${req.password ?? ''}`
+    ).toString('base64')
+    headers['Authorization'] = `Basic ${basic}`
+  }
+  return await new Promise((resolve, reject) => {
+    const request = client.request(
+      target,
+      {
+        method: req.method,
+        headers,
+        timeout: req.timeoutMs ?? 5000,
+        rejectUnauthorized: false
+      },
+      response => {
+        response.resume()
+        response.on('end', () =>
+          resolve({ statusCode: response.statusCode ?? 0 })
+        )
+      }
+    )
+    request.on('timeout', () => request.destroy(new Error('request timeout')))
+    request.on('error', reject)
+    request.end(req.body)
+  })
+}
+ 
+export async function pushToPushgateway(
+  config: NpuPushConfig,
+  path: string,
+  body: string,
+  options?: { retries?: number; retryDelayMs?: number; requestFn?: RequestFn }
+): Promise<void> {
+  const retries = options?.retries ?? 2
+  const retryDelayMs = options?.retryDelayMs ?? 1000
+  const requestFn = options?.requestFn ?? nodeRequest
+  const url = `${config.url.replace(/\/+$/, '')}${path}`
+  let lastError: unknown
+  for (let attempt = 0; attempt <= retries; attempt++) {
+    if (attempt > 0) {
+      await new Promise(resolve => setTimeout(resolve, retryDelayMs))
+    }
+    try {
+      const response = await requestFn({
+        url,
+        method: 'POST',
+        body,
+        username: config.username,
+        password: config.password
+      })
+      if (response.statusCode >= 200 && response.statusCode < 300) {
+        return
+      }
+      lastError = new Error(`pushgateway returned ${response.statusCode}`)
+    } catch (err) {
+      lastError = err
+    }
+  }
+  throw lastError instanceof Error ? lastError : new Error(String(lastError))
+}
+ 
+export function decodePushSecret(
+  secret: k8s.V1Secret | undefined
+): NpuPushConfig | undefined {
+  const data = secret?.data ?? {}
+  const decode = (key: string): string | undefined => {
+    const encoded = data[key]
+    if (!encoded) {
+      return undefined
+    }
+    try {
+      const decoded = Buffer.from(encoded, 'base64').toString('utf8')
+      return decoded.length ? decoded : undefined
+    } catch {
+      return undefined
+    }
+  }
+  const url = decode('PUSHGATEWAY_URL')
+  if (!url) {
+    return undefined
+  }
+  return {
+    url,
+    username: decode('PUSHGATEWAY_USER'),
+    password: decode('PUSHGATEWAY_PASSWORD')
+  }
+}
+ 
+export async function readNpuPushConfig(): Promise<NpuPushConfig | undefined> {
+  try {
+    const secret = await getSecretByName(NPU_METRICS_SECRET_NAME)
+    return decodePushSecret(secret)
+  } catch (err) {
+    core.debug(
+      `npu-metrics: secret ${NPU_METRICS_SECRET_NAME} unavailable, skip push: ${formatError(err)}`
+    )
+    return undefined
+  }
+}
+ 
+function parseScaleSetSuffix(value: string | undefined): string | undefined {
+  Iif (!value) {
+    return undefined
+  }
+  const match = value.match(SCALE_SET_NAME_REGEX)
+  return match ? match[1] : undefined
+}
+ 
+export function extractClusterFromRunnerPod(pod: k8s.V1Pod): string {
+  const labels = pod.metadata?.labels ?? {}
+  const annotations = pod.metadata?.annotations ?? {}
+  const entries: [string, string][] = [
+    ...Object.entries(labels),
+    ...Object.entries(annotations)
+  ]
+  for (const [key, value] of entries) {
+    if (/scale[-_]?set|runner[-_]?deployment/i.test(key)) {
+      const suffix = parseScaleSetSuffix(value)
+      Eif (suffix) {
+        return suffix
+      }
+    }
+  }
+  for (const [, value] of entries) {
+    const suffix = parseScaleSetSuffix(value)
+    if (suffix) {
+      return suffix
+    }
+  }
+  return parseScaleSetSuffix(pod.metadata?.name) ?? 'unknown'
+}
+ 
+export function resolveNpuLabelsFromPod(
+  pod: k8s.V1Pod,
+  podName: string
+): {
+  podType: string
+  npuType: string
+  cardsRequested: string
+  result: string
+} {
+  const podType = podName.includes('-step-') ? 'step' : 'workflow'
+  const npuTypes = new Set<string>()
+  let cards = 0
+  for (const container of pod.spec?.containers ?? []) {
+    for (const resources of [
+      container.resources?.requests,
+      container.resources?.limits
+    ]) {
+      for (const [key, quantity] of Object.entries(resources ?? {})) {
+        const match = key.match(NPU_RESOURCE_REGEX)
+        Eif (match) {
+          npuTypes.add(match[1])
+          cards = Math.max(cards, parseInt(String(quantity), 10) || 0)
+        }
+      }
+    }
+  }
+  const mainStatus = (pod.status?.containerStatuses ?? []).find(
+    s => s.name === JOB_CONTAINER_NAME
+  )
+  const terminated = mainStatus?.state?.terminated
+  const result = terminated
+    ? String(terminated.exitCode)
+    : (pod.status?.phase ?? 'unknown')
+  return {
+    podType,
+    npuType: Array.from(npuTypes).sort().join(',') || 'unknown',
+    cardsRequested: String(cards || 0),
+    result
+  }
+}
+ 
+export function repoFromEnv(
+  env: Record<string, string | undefined> = process.env
+): string {
+  if (env.GITHUB_REPOSITORY) {
+    return env.GITHUB_REPOSITORY
+  }
+  const workspace = env.GITHUB_WORKSPACE ?? ''
+  const parts = workspace.split('/').filter(p => p.length > 0)
+  if (parts.length >= 2) {
+    return `${parts[parts.length - 2]}/${parts[parts.length - 1]}`
+  }
+  return 'unknown'
+}
+ 
+export async function collectNpuAggregateFromPod(
+  pod: k8s.V1Pod
+): Promise<NpuAggregatePayload | undefined> {
+  const podName = pod.metadata?.name
+  if (!podName) {
+    return undefined
+  }
+  const mainStatus = (pod.status?.containerStatuses ?? []).find(
+    s => s.name === JOB_CONTAINER_NAME
+  )
+  const terminatedMessage = mainStatus?.state?.terminated?.message
+  if (terminatedMessage) {
+    return parseNpuAggregate(terminatedMessage)
+  }
+  if (!mainStatus?.state?.running) {
+    return undefined
+  }
+  const { output } = await execPodStepWithOutput(
+    ['sh', '-c', buildNpuAggregateScript()],
+    podName,
+    JOB_CONTAINER_NAME,
+    5
+  )
+  return parseNpuAggregate(output)
+}
+ 
+export async function collectAndPushNpuMetrics(): Promise<void> {
+  if (!npuMetricsEnabled()) {
+    return
+  }
+  let pods: k8s.V1Pod[] = []
+  try {
+    pods = await listPodsByRunnerInstance()
+  } catch (err) {
+    core.debug(`npu-metrics: pod list failed: ${formatError(err)}`)
+    return
+  }
+  const npuPods = pods.filter(
+    pod => pod.metadata?.name && hasNpuRequest(pod.spec)
+  )
+  if (!npuPods.length) {
+    return
+  }
+ 
+  let cluster = 'unknown'
+  try {
+    const runnerPod = await getPodByName(getRunnerPodName())
+    cluster = extractClusterFromRunnerPod(runnerPod)
+  } catch (err) {
+    core.debug(`npu-metrics: cluster label unresolved: ${formatError(err)}`)
+  }
+ 
+  const config = await readNpuPushConfig()
+  if (!config) {
+    core.debug(
+      `npu-metrics: push config missing (secret ${NPU_METRICS_SECRET_NAME}), skip push`
+    )
+    return
+  }
+ 
+  for (const pod of npuPods) {
+    const podName = pod.metadata?.name as string
+    try {
+      await collectAndPushForPod(pod, podName, cluster, config)
+    } catch (err) {
+      core.debug(
+        `npu-metrics: collection failed for ${podName}: ${formatError(err)}`
+      )
+    }
+  }
+}
+ 
+async function collectAndPushForPod(
+  pod: k8s.V1Pod,
+  podName: string,
+  cluster: string,
+  config: NpuPushConfig
+): Promise<void> {
+  const payload = await collectNpuAggregateFromPod(pod)
+  if (!payload || !payload.cards.length) {
+    core.debug(`npu-metrics: no aggregate payload for ${podName}, skip`)
+    return
+  }
+ 
+  const npuInfo = resolveNpuLabelsFromPod(pod, podName)
+  const labels: NpuJobLabels = {
+    cluster,
+    namespace: namespace(),
+    pod: podName,
+    podType: npuInfo.podType,
+    repo: repoFromEnv(),
+    runId: process.env.GITHUB_RUN_ID ?? '',
+    npuType: npuInfo.npuType,
+    cardsRequested: npuInfo.cardsRequested,
+    result: npuInfo.result
+  }
+ 
+  const body = buildNpuJobMetricsBody(
+    labels,
+    payload.cards,
+    getIdleThresholdPercent()
+  )
+  const path = buildPushgatewayPath(labels.cluster, labels.namespace, podName)
+  try {
+    await pushToPushgateway(config, path, body)
+    core.debug(`npu-metrics: pushed job record for ${podName}`)
+  } catch (err) {
+    core.warning(`npu-metrics: push failed for ${podName}: ${formatError(err)}`)
+    try {
+      await pushToPushgateway(config, path, buildNpuPushFailedBody(labels))
+    } catch {
+      // pushgateway unreachable, nothing else to record
+    }
+  }
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/prettify.css b/coverage/lcov-report/prettify.css new file mode 100644 index 00000000..b317a7cd --- /dev/null +++ b/coverage/lcov-report/prettify.css @@ -0,0 +1 @@ +.pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun,.opn,.clo{color:#660}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun,.opn,.clo{color:#440}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee} diff --git a/coverage/lcov-report/prettify.js b/coverage/lcov-report/prettify.js new file mode 100644 index 00000000..b3225238 --- /dev/null +++ b/coverage/lcov-report/prettify.js @@ -0,0 +1,2 @@ +/* eslint-disable */ +window.PR_SHOULD_USE_CONTINUATION=true;(function(){var h=["break,continue,do,else,for,if,return,while"];var u=[h,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"];var p=[u,"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"];var l=[p,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"];var x=[p,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"];var R=[x,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"];var r="all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes";var w=[p,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"];var s="caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END";var I=[h,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"];var f=[h,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"];var H=[h,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"];var A=[l,R,w,s+I,f,H];var e=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/;var C="str";var z="kwd";var j="com";var O="typ";var G="lit";var L="pun";var F="pln";var m="tag";var E="dec";var J="src";var P="atn";var n="atv";var N="nocode";var M="(?:^^\\.?|[+-]|\\!|\\!=|\\!==|\\#|\\%|\\%=|&|&&|&&=|&=|\\(|\\*|\\*=|\\+=|\\,|\\-=|\\->|\\/|\\/=|:|::|\\;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|\\?|\\@|\\[|\\^|\\^=|\\^\\^|\\^\\^=|\\{|\\||\\|=|\\|\\||\\|\\|=|\\~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\\s*";function k(Z){var ad=0;var S=false;var ac=false;for(var V=0,U=Z.length;V122)){if(!(al<65||ag>90)){af.push([Math.max(65,ag)|32,Math.min(al,90)|32])}if(!(al<97||ag>122)){af.push([Math.max(97,ag)&~32,Math.min(al,122)&~32])}}}}af.sort(function(av,au){return(av[0]-au[0])||(au[1]-av[1])});var ai=[];var ap=[NaN,NaN];for(var ar=0;arat[0]){if(at[1]+1>at[0]){an.push("-")}an.push(T(at[1]))}}an.push("]");return an.join("")}function W(al){var aj=al.source.match(new RegExp("(?:\\[(?:[^\\x5C\\x5D]|\\\\[\\s\\S])*\\]|\\\\u[A-Fa-f0-9]{4}|\\\\x[A-Fa-f0-9]{2}|\\\\[0-9]+|\\\\[^ux0-9]|\\(\\?[:!=]|[\\(\\)\\^]|[^\\x5B\\x5C\\(\\)\\^]+)","g"));var ah=aj.length;var an=[];for(var ak=0,am=0;ak=2&&ai==="["){aj[ak]=X(ag)}else{if(ai!=="\\"){aj[ak]=ag.replace(/[a-zA-Z]/g,function(ao){var ap=ao.charCodeAt(0);return"["+String.fromCharCode(ap&~32,ap|32)+"]"})}}}}return aj.join("")}var aa=[];for(var V=0,U=Z.length;V=0;){S[ac.charAt(ae)]=Y}}var af=Y[1];var aa=""+af;if(!ag.hasOwnProperty(aa)){ah.push(af);ag[aa]=null}}ah.push(/[\0-\uffff]/);V=k(ah)})();var X=T.length;var W=function(ah){var Z=ah.sourceCode,Y=ah.basePos;var ad=[Y,F];var af=0;var an=Z.match(V)||[];var aj={};for(var ae=0,aq=an.length;ae=5&&"lang-"===ap.substring(0,5);if(am&&!(ai&&typeof ai[1]==="string")){am=false;ap=J}if(!am){aj[ag]=ap}}var ab=af;af+=ag.length;if(!am){ad.push(Y+ab,ap)}else{var al=ai[1];var ak=ag.indexOf(al);var ac=ak+al.length;if(ai[2]){ac=ag.length-ai[2].length;ak=ac-al.length}var ar=ap.substring(5);B(Y+ab,ag.substring(0,ak),W,ad);B(Y+ab+ak,al,q(ar,al),ad);B(Y+ab+ac,ag.substring(ac),W,ad)}}ah.decorations=ad};return W}function i(T){var W=[],S=[];if(T.tripleQuotedStrings){W.push([C,/^(?:\'\'\'(?:[^\'\\]|\\[\s\S]|\'{1,2}(?=[^\']))*(?:\'\'\'|$)|\"\"\"(?:[^\"\\]|\\[\s\S]|\"{1,2}(?=[^\"]))*(?:\"\"\"|$)|\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$))/,null,"'\""])}else{if(T.multiLineStrings){W.push([C,/^(?:\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$)|\`(?:[^\\\`]|\\[\s\S])*(?:\`|$))/,null,"'\"`"])}else{W.push([C,/^(?:\'(?:[^\\\'\r\n]|\\.)*(?:\'|$)|\"(?:[^\\\"\r\n]|\\.)*(?:\"|$))/,null,"\"'"])}}if(T.verbatimStrings){S.push([C,/^@\"(?:[^\"]|\"\")*(?:\"|$)/,null])}var Y=T.hashComments;if(Y){if(T.cStyleComments){if(Y>1){W.push([j,/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,null,"#"])}else{W.push([j,/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\r\n]*)/,null,"#"])}S.push([C,/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,null])}else{W.push([j,/^#[^\r\n]*/,null,"#"])}}if(T.cStyleComments){S.push([j,/^\/\/[^\r\n]*/,null]);S.push([j,/^\/\*[\s\S]*?(?:\*\/|$)/,null])}if(T.regexLiterals){var X=("/(?=[^/*])(?:[^/\\x5B\\x5C]|\\x5C[\\s\\S]|\\x5B(?:[^\\x5C\\x5D]|\\x5C[\\s\\S])*(?:\\x5D|$))+/");S.push(["lang-regex",new RegExp("^"+M+"("+X+")")])}var V=T.types;if(V){S.push([O,V])}var U=(""+T.keywords).replace(/^ | $/g,"");if(U.length){S.push([z,new RegExp("^(?:"+U.replace(/[\s,]+/g,"|")+")\\b"),null])}W.push([F,/^\s+/,null," \r\n\t\xA0"]);S.push([G,/^@[a-z_$][a-z_$@0-9]*/i,null],[O,/^(?:[@_]?[A-Z]+[a-z][A-Za-z_$@0-9]*|\w+_t\b)/,null],[F,/^[a-z_$][a-z_$@0-9]*/i,null],[G,new RegExp("^(?:0x[a-f0-9]+|(?:\\d(?:_\\d+)*\\d*(?:\\.\\d*)?|\\.\\d\\+)(?:e[+\\-]?\\d+)?)[a-z]*","i"),null,"0123456789"],[F,/^\\[\s\S]?/,null],[L,/^.[^\s\w\.$@\'\"\`\/\#\\]*/,null]);return g(W,S)}var K=i({keywords:A,hashComments:true,cStyleComments:true,multiLineStrings:true,regexLiterals:true});function Q(V,ag){var U=/(?:^|\s)nocode(?:\s|$)/;var ab=/\r\n?|\n/;var ac=V.ownerDocument;var S;if(V.currentStyle){S=V.currentStyle.whiteSpace}else{if(window.getComputedStyle){S=ac.defaultView.getComputedStyle(V,null).getPropertyValue("white-space")}}var Z=S&&"pre"===S.substring(0,3);var af=ac.createElement("LI");while(V.firstChild){af.appendChild(V.firstChild)}var W=[af];function ae(al){switch(al.nodeType){case 1:if(U.test(al.className)){break}if("BR"===al.nodeName){ad(al);if(al.parentNode){al.parentNode.removeChild(al)}}else{for(var an=al.firstChild;an;an=an.nextSibling){ae(an)}}break;case 3:case 4:if(Z){var am=al.nodeValue;var aj=am.match(ab);if(aj){var ai=am.substring(0,aj.index);al.nodeValue=ai;var ah=am.substring(aj.index+aj[0].length);if(ah){var ak=al.parentNode;ak.insertBefore(ac.createTextNode(ah),al.nextSibling)}ad(al);if(!ai){al.parentNode.removeChild(al)}}}break}}function ad(ak){while(!ak.nextSibling){ak=ak.parentNode;if(!ak){return}}function ai(al,ar){var aq=ar?al.cloneNode(false):al;var ao=al.parentNode;if(ao){var ap=ai(ao,1);var an=al.nextSibling;ap.appendChild(aq);for(var am=an;am;am=an){an=am.nextSibling;ap.appendChild(am)}}return aq}var ah=ai(ak.nextSibling,0);for(var aj;(aj=ah.parentNode)&&aj.nodeType===1;){ah=aj}W.push(ah)}for(var Y=0;Y=S){ah+=2}if(V>=ap){Z+=2}}}var t={};function c(U,V){for(var S=V.length;--S>=0;){var T=V[S];if(!t.hasOwnProperty(T)){t[T]=U}else{if(window.console){console.warn("cannot override language handler %s",T)}}}}function q(T,S){if(!(T&&t.hasOwnProperty(T))){T=/^\s*]*(?:>|$)/],[j,/^<\!--[\s\S]*?(?:-\->|$)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],[L,/^(?:<[%?]|[%?]>)/],["lang-",/^]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-js",/^]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]),["default-markup","htm","html","mxml","xhtml","xml","xsl"]);c(g([[F,/^[\s]+/,null," \t\r\n"],[n,/^(?:\"[^\"]*\"?|\'[^\']*\'?)/,null,"\"'"]],[[m,/^^<\/?[a-z](?:[\w.:-]*\w)?|\/?>$/i],[P,/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^>\'\"\s]*(?:[^>\'\"\s\/]|\/(?=\s)))/],[L,/^[=<>\/]+/],["lang-js",/^on\w+\s*=\s*\"([^\"]+)\"/i],["lang-js",/^on\w+\s*=\s*\'([^\']+)\'/i],["lang-js",/^on\w+\s*=\s*([^\"\'>\s]+)/i],["lang-css",/^style\s*=\s*\"([^\"]+)\"/i],["lang-css",/^style\s*=\s*\'([^\']+)\'/i],["lang-css",/^style\s*=\s*([^\"\'>\s]+)/i]]),["in.tag"]);c(g([],[[n,/^[\s\S]+/]]),["uq.val"]);c(i({keywords:l,hashComments:true,cStyleComments:true,types:e}),["c","cc","cpp","cxx","cyc","m"]);c(i({keywords:"null,true,false"}),["json"]);c(i({keywords:R,hashComments:true,cStyleComments:true,verbatimStrings:true,types:e}),["cs"]);c(i({keywords:x,cStyleComments:true}),["java"]);c(i({keywords:H,hashComments:true,multiLineStrings:true}),["bsh","csh","sh"]);c(i({keywords:I,hashComments:true,multiLineStrings:true,tripleQuotedStrings:true}),["cv","py"]);c(i({keywords:s,hashComments:true,multiLineStrings:true,regexLiterals:true}),["perl","pl","pm"]);c(i({keywords:f,hashComments:true,multiLineStrings:true,regexLiterals:true}),["rb"]);c(i({keywords:w,cStyleComments:true,regexLiterals:true}),["js"]);c(i({keywords:r,hashComments:3,cStyleComments:true,multilineStrings:true,tripleQuotedStrings:true,regexLiterals:true}),["coffee"]);c(g([],[[C,/^[\s\S]+/]]),["regex"]);function d(V){var U=V.langExtension;try{var S=a(V.sourceNode);var T=S.sourceCode;V.sourceCode=T;V.spans=S.spans;V.basePos=0;q(U,T)(V);D(V)}catch(W){if("console" in window){console.log(W&&W.stack?W.stack:W)}}}function y(W,V,U){var S=document.createElement("PRE");S.innerHTML=W;if(U){Q(S,U)}var T={langExtension:V,numberLines:U,sourceNode:S};d(T);return S.innerHTML}function b(ad){function Y(af){return document.getElementsByTagName(af)}var ac=[Y("pre"),Y("code"),Y("xmp")];var T=[];for(var aa=0;aa=0){var ah=ai.match(ab);var am;if(!ah&&(am=o(aj))&&"CODE"===am.tagName){ah=am.className.match(ab)}if(ah){ah=ah[1]}var al=false;for(var ak=aj.parentNode;ak;ak=ak.parentNode){if((ak.tagName==="pre"||ak.tagName==="code"||ak.tagName==="xmp")&&ak.className&&ak.className.indexOf("prettyprint")>=0){al=true;break}}if(!al){var af=aj.className.match(/\blinenums\b(?::(\d+))?/);af=af?af[1]&&af[1].length?+af[1]:true:false;if(af){Q(aj,af)}S={langExtension:ah,sourceNode:aj,numberLines:af};d(S)}}}if(X]*(?:>|$)/],[PR.PR_COMMENT,/^<\!--[\s\S]*?(?:-\->|$)/],[PR.PR_PUNCTUATION,/^(?:<[%?]|[%?]>)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],["lang-",/^]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-handlebars",/^]*type\s*=\s*['"]?text\/x-handlebars-template['"]?\b[^>]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-js",/^]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i],[PR.PR_DECLARATION,/^{{[#^>/]?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{&?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{{>?\s*[\w.][^}]*}}}/],[PR.PR_COMMENT,/^{{![^}]*}}/]]),["handlebars","hbs"]);PR.registerLangHandler(PR.createSimpleLexer([[PR.PR_PLAIN,/^[ \t\r\n\f]+/,null," \t\r\n\f"]],[[PR.PR_STRING,/^\"(?:[^\n\r\f\\\"]|\\(?:\r\n?|\n|\f)|\\[\s\S])*\"/,null],[PR.PR_STRING,/^\'(?:[^\n\r\f\\\']|\\(?:\r\n?|\n|\f)|\\[\s\S])*\'/,null],["lang-css-str",/^url\(([^\)\"\']*)\)/i],[PR.PR_KEYWORD,/^(?:url|rgb|\!important|@import|@page|@media|@charset|inherit)(?=[^\-\w]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|(?:\\[0-9a-f]+ ?))(?:[_a-z0-9\-]|\\(?:\\[0-9a-f]+ ?))*)\s*:/i],[PR.PR_COMMENT,/^\/\*[^*]*\*+(?:[^\/*][^*]*\*+)*\//],[PR.PR_COMMENT,/^(?:)/],[PR.PR_LITERAL,/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],[PR.PR_LITERAL,/^#(?:[0-9a-f]{3}){1,2}/i],[PR.PR_PLAIN,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i],[PR.PR_PUNCTUATION,/^[^\s\w\'\"]+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_KEYWORD,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_STRING,/^[^\)\"\']+/]]),["css-str"]); diff --git a/coverage/lcov-report/sort-arrow-sprite.png b/coverage/lcov-report/sort-arrow-sprite.png new file mode 100644 index 00000000..6ed68316 Binary files /dev/null and b/coverage/lcov-report/sort-arrow-sprite.png differ diff --git a/coverage/lcov-report/sorter.js b/coverage/lcov-report/sorter.js new file mode 100644 index 00000000..4ed70ae5 --- /dev/null +++ b/coverage/lcov-report/sorter.js @@ -0,0 +1,210 @@ +/* eslint-disable */ +var addSorting = (function() { + 'use strict'; + var cols, + currentSort = { + index: 0, + desc: false + }; + + // returns the summary table element + function getTable() { + return document.querySelector('.coverage-summary'); + } + // returns the thead element of the summary table + function getTableHeader() { + return getTable().querySelector('thead tr'); + } + // returns the tbody element of the summary table + function getTableBody() { + return getTable().querySelector('tbody'); + } + // returns the th element for nth column + function getNthColumn(n) { + return getTableHeader().querySelectorAll('th')[n]; + } + + function onFilterInput() { + const searchValue = document.getElementById('fileSearch').value; + const rows = document.getElementsByTagName('tbody')[0].children; + + // Try to create a RegExp from the searchValue. If it fails (invalid regex), + // it will be treated as a plain text search + let searchRegex; + try { + searchRegex = new RegExp(searchValue, 'i'); // 'i' for case-insensitive + } catch (error) { + searchRegex = null; + } + + for (let i = 0; i < rows.length; i++) { + const row = rows[i]; + let isMatch = false; + + if (searchRegex) { + // If a valid regex was created, use it for matching + isMatch = searchRegex.test(row.textContent); + } else { + // Otherwise, fall back to the original plain text search + isMatch = row.textContent + .toLowerCase() + .includes(searchValue.toLowerCase()); + } + + row.style.display = isMatch ? '' : 'none'; + } + } + + // loads the search box + function addSearchBox() { + var template = document.getElementById('filterTemplate'); + var templateClone = template.content.cloneNode(true); + templateClone.getElementById('fileSearch').oninput = onFilterInput; + template.parentElement.appendChild(templateClone); + } + + // loads all columns + function loadColumns() { + var colNodes = getTableHeader().querySelectorAll('th'), + colNode, + cols = [], + col, + i; + + for (i = 0; i < colNodes.length; i += 1) { + colNode = colNodes[i]; + col = { + key: colNode.getAttribute('data-col'), + sortable: !colNode.getAttribute('data-nosort'), + type: colNode.getAttribute('data-type') || 'string' + }; + cols.push(col); + if (col.sortable) { + col.defaultDescSort = col.type === 'number'; + colNode.innerHTML = + colNode.innerHTML + ''; + } + } + return cols; + } + // attaches a data attribute to every tr element with an object + // of data values keyed by column name + function loadRowData(tableRow) { + var tableCols = tableRow.querySelectorAll('td'), + colNode, + col, + data = {}, + i, + val; + for (i = 0; i < tableCols.length; i += 1) { + colNode = tableCols[i]; + col = cols[i]; + val = colNode.getAttribute('data-value'); + if (col.type === 'number') { + val = Number(val); + } + data[col.key] = val; + } + return data; + } + // loads all row data + function loadData() { + var rows = getTableBody().querySelectorAll('tr'), + i; + + for (i = 0; i < rows.length; i += 1) { + rows[i].data = loadRowData(rows[i]); + } + } + // sorts the table using the data for the ith column + function sortByIndex(index, desc) { + var key = cols[index].key, + sorter = function(a, b) { + a = a.data[key]; + b = b.data[key]; + return a < b ? -1 : a > b ? 1 : 0; + }, + finalSorter = sorter, + tableBody = document.querySelector('.coverage-summary tbody'), + rowNodes = tableBody.querySelectorAll('tr'), + rows = [], + i; + + if (desc) { + finalSorter = function(a, b) { + return -1 * sorter(a, b); + }; + } + + for (i = 0; i < rowNodes.length; i += 1) { + rows.push(rowNodes[i]); + tableBody.removeChild(rowNodes[i]); + } + + rows.sort(finalSorter); + + for (i = 0; i < rows.length; i += 1) { + tableBody.appendChild(rows[i]); + } + } + // removes sort indicators for current column being sorted + function removeSortIndicators() { + var col = getNthColumn(currentSort.index), + cls = col.className; + + cls = cls.replace(/ sorted$/, '').replace(/ sorted-desc$/, ''); + col.className = cls; + } + // adds sort indicators for current column being sorted + function addSortIndicators() { + getNthColumn(currentSort.index).className += currentSort.desc + ? ' sorted-desc' + : ' sorted'; + } + // adds event listeners for all sorter widgets + function enableUI() { + var i, + el, + ithSorter = function ithSorter(i) { + var col = cols[i]; + + return function() { + var desc = col.defaultDescSort; + + if (currentSort.index === i) { + desc = !currentSort.desc; + } + sortByIndex(i, desc); + removeSortIndicators(); + currentSort.index = i; + currentSort.desc = desc; + addSortIndicators(); + }; + }; + for (i = 0; i < cols.length; i += 1) { + if (cols[i].sortable) { + // add the click event handler on the th so users + // dont have to click on those tiny arrows + el = getNthColumn(i).querySelector('.sorter').parentElement; + if (el.addEventListener) { + el.addEventListener('click', ithSorter(i)); + } else { + el.attachEvent('onclick', ithSorter(i)); + } + } + } + } + // adds sorting functionality to the UI + return function() { + if (!getTable()) { + return; + } + cols = loadColumns(); + loadData(); + addSearchBox(); + addSortIndicators(); + enableUI(); + }; +})(); + +window.addEventListener('load', addSorting); diff --git a/coverage/lcov.info b/coverage/lcov.info new file mode 100644 index 00000000..b4f6bc44 --- /dev/null +++ b/coverage/lcov.info @@ -0,0 +1,2858 @@ +TN: +SF:packages/hooklib/src/index.ts +FNF:0 +FNH:0 +LF:0 +LH:0 +BRF:0 +BRH:0 +end_of_record +TN: +SF:packages/hooklib/src/interfaces.ts +FN:1,(anonymous_0) +FN:72,(anonymous_1) +FNF:2 +FNH:2 +FNDA:1,(anonymous_0) +FNDA:1,(anonymous_1) +DA:1,1 +DA:2,1 +DA:3,1 +DA:4,1 +DA:5,1 +DA:72,1 +DA:73,1 +DA:74,1 +LF:8 +LH:8 +BRF:0 +BRH:0 +end_of_record +TN: +SF:packages/hooklib/src/utils/index.ts +FN:7,getInputFromStdin +FN:14,(anonymous_1) +FN:22,writeToResponseFile +FN:35,toCommandValue +FNF:4 +FNH:2 +FNDA:0,getInputFromStdin +FNDA:0,(anonymous_1) +FNDA:16,writeToResponseFile +FNDA:14,toCommandValue +DA:8,0 +DA:10,0 +DA:14,0 +DA:15,0 +DA:17,0 +DA:18,0 +DA:19,0 +DA:23,16 +DA:24,1 +DA:26,15 +DA:27,1 +DA:30,14 +DA:36,14 +DA:37,2 +DA:38,12 +DA:39,11 +DA:41,1 +LF:17 +LH:10 +BRDA:23,0,0,1 +BRDA:23,0,1,15 +BRDA:26,1,0,1 +BRDA:26,1,1,14 +BRDA:36,2,0,2 +BRDA:36,2,1,12 +BRDA:36,3,0,14 +BRDA:36,3,1,13 +BRDA:38,4,0,11 +BRDA:38,4,1,1 +BRDA:38,5,0,12 +BRDA:38,5,1,1 +BRF:12 +BRH:12 +end_of_record +TN: +SF:packages/k8s/src/index.ts +FN:17,run +FNF:1 +FNH:0 +FNDA:0,run +DA:18,0 +DA:19,0 +DA:21,0 +DA:22,0 +DA:23,0 +DA:24,0 +DA:25,0 +DA:26,0 +DA:33,0 +DA:34,0 +DA:36,0 +DA:37,0 +DA:39,0 +DA:40,0 +DA:42,0 +DA:43,0 +DA:45,0 +DA:46,0 +DA:48,0 +DA:51,0 +DA:52,0 +DA:56,0 +LF:22 +LH:0 +BRDA:25,0,0,0 +BRDA:25,0,1,0 +BRDA:34,1,0,0 +BRDA:34,1,1,0 +BRDA:34,1,2,0 +BRDA:34,1,3,0 +BRDA:34,1,4,0 +BRF:7 +BRH:0 +end_of_record +TN: +SF:packages/k8s/src/hooks/cleanup-job.ts +FN:11,cleanupJob +FNF:1 +FNH:1 +FNDA:4,cleanupJob +DA:12,4 +DA:13,3 +DA:14,3 +DA:16,1 +DA:19,4 +LF:5 +LH:5 +BRDA:12,0,0,3 +BRDA:12,0,1,1 +BRF:2 +BRH:2 +end_of_record +TN: +SF:packages/k8s/src/hooks/constants.ts +FN:3,getRunnerPodName +FN:13,getJobPodName +FN:20,getStepPodName +FN:27,getVolumeClaimName +FN:35,getSecretName +FN:50,constructor +FN:54,key +FN:58,value +FN:62,toString +FNF:9 +FNH:8 +FNDA:86,getRunnerPodName +FNDA:42,getJobPodName +FNDA:18,getStepPodName +FNDA:0,getVolumeClaimName +FNDA:4,getSecretName +FNDA:17,constructor +FNDA:10,key +FNDA:10,value +FNDA:7,toString +DA:4,86 +DA:5,86 +DA:6,0 +DA:10,86 +DA:14,42 +DA:21,18 +DA:28,0 +DA:29,0 +DA:30,0 +DA:32,0 +DA:36,4 +DA:42,7 +DA:43,7 +DA:44,7 +DA:45,7 +DA:46,7 +DA:51,17 +DA:55,10 +DA:59,10 +DA:63,7 +LF:20 +LH:15 +BRDA:5,0,0,0 +BRDA:5,0,1,86 +BRDA:29,1,0,0 +BRDA:29,1,1,0 +BRF:4 +BRH:1 +end_of_record +TN: +SF:packages/k8s/src/hooks/index.ts +FNF:0 +FNH:0 +LF:0 +LH:0 +BRF:0 +BRH:0 +end_of_record +TN: +SF:packages/k8s/src/hooks/prepare-job.ts +FN:40,prepareJob +FN:73,(anonymous_1) +FN:235,generateResponseFile +FN:253,(anonymous_3) +FN:275,(anonymous_4) +FN:278,(anonymous_5) +FN:279,(anonymous_6) +FN:299,createContainerSpec +FN:354,(anonymous_8) +FNF:9 +FNH:8 +FNDA:20,prepareJob +FNDA:6,(anonymous_1) +FNDA:8,generateResponseFile +FNDA:8,(anonymous_3) +FNDA:0,(anonymous_4) +FNDA:10,(anonymous_5) +FNDA:6,(anonymous_6) +FNDA:35,createContainerSpec +FNDA:1,(anonymous_8) +DA:44,20 +DA:45,1 +DA:48,19 +DA:50,19 +DA:52,19 +DA:53,19 +DA:54,18 +DA:60,18 +DA:63,19 +DA:64,19 +DA:65,19 +DA:66,4 +DA:67,4 +DA:68,6 +DA:69,6 +DA:72,4 +DA:73,4 +DA:74,6 +DA:75,6 +DA:76,6 +DA:79,6 +DA:80,4 +DA:82,2 +DA:85,6 +DA:86,6 +DA:87,6 +DA:91,19 +DA:92,1 +DA:95,18 +DA:96,18 +DA:97,18 +DA:105,6 +DA:106,6 +DA:113,6 +DA:114,6 +DA:121,6 +DA:122,6 +DA:125,6 +DA:127,6 +DA:130,6 +DA:133,5 +DA:134,5 +DA:137,5 +DA:138,5 +DA:139,5 +DA:140,2 +DA:143,2 +DA:149,6 +DA:159,6 +DA:162,12 +DA:163,1 +DA:165,11 +DA:169,20 +DA:170,20 +DA:171,1 +DA:173,10 +DA:176,10 +DA:177,2 +DA:180,10 +DA:181,10 +DA:188,1 +DA:192,1 +DA:193,1 +DA:196,9 +DA:198,9 +DA:199,2 +DA:205,2 +DA:206,2 +DA:207,2 +DA:215,2 +DA:218,9 +DA:220,9 +DA:221,9 +DA:222,9 +DA:227,1 +DA:228,1 +DA:229,1 +DA:231,8 +DA:232,8 +DA:242,8 +DA:243,0 +DA:245,8 +DA:253,8 +DA:254,8 +DA:256,8 +DA:257,8 +DA:258,8 +DA:259,8 +DA:260,0 +DA:265,8 +DA:271,8 +DA:273,4 +DA:275,0 +DA:277,4 +DA:278,10 +DA:280,6 +DA:281,6 +DA:282,1 +DA:283,1 +DA:284,1 +DA:289,6 +DA:296,8 +DA:305,35 +DA:306,1 +DA:307,1 +DA:310,35 +DA:315,35 +DA:316,1 +DA:319,35 +DA:320,28 +DA:323,35 +DA:324,20 +DA:327,35 +DA:328,35 +DA:331,2 +DA:332,1 +DA:336,35 +DA:341,35 +DA:342,34 +DA:348,35 +DA:350,35 +DA:351,34 +DA:354,1 +DA:355,1 +DA:358,35 +DA:359,1 +DA:362,1 +LF:127 +LH:124 +BRDA:44,0,0,1 +BRDA:44,0,1,19 +BRDA:53,1,0,18 +BRDA:53,1,1,1 +BRDA:65,2,0,4 +BRDA:65,2,1,15 +BRDA:69,3,0,6 +BRDA:69,3,1,4 +BRDA:75,4,0,6 +BRDA:75,4,1,0 +BRDA:76,5,0,6 +BRDA:76,5,1,4 +BRDA:79,6,0,4 +BRDA:79,6,1,2 +BRDA:91,7,0,1 +BRDA:91,7,1,18 +BRDA:91,8,0,19 +BRDA:91,8,1,1 +BRDA:113,9,0,6 +BRDA:113,9,1,0 +BRDA:127,10,0,5 +BRDA:127,10,1,1 +BRDA:130,11,0,5 +BRDA:130,11,1,1 +BRDA:130,12,0,6 +BRDA:130,12,1,5 +BRDA:130,12,2,5 +BRDA:139,13,0,2 +BRDA:139,13,1,3 +BRDA:162,14,0,1 +BRDA:162,14,1,11 +BRDA:170,15,0,1 +BRDA:170,15,1,19 +BRDA:176,16,0,2 +BRDA:176,16,1,8 +BRDA:177,17,0,2 +BRDA:177,17,1,0 +BRDA:192,18,0,1 +BRDA:192,18,1,0 +BRDA:198,19,0,2 +BRDA:198,19,1,7 +BRDA:206,20,0,2 +BRDA:206,20,1,0 +BRDA:242,21,0,0 +BRDA:242,21,1,8 +BRDA:256,22,0,8 +BRDA:256,22,1,0 +BRDA:258,23,0,8 +BRDA:258,23,1,0 +BRDA:271,24,0,4 +BRDA:271,24,1,4 +BRDA:273,25,0,4 +BRDA:273,25,1,0 +BRDA:273,26,0,4 +BRDA:273,26,1,4 +BRDA:275,27,0,0 +BRDA:275,27,1,0 +BRDA:281,28,0,1 +BRDA:281,28,1,5 +BRDA:283,29,0,1 +BRDA:283,29,1,0 +BRDA:283,30,0,1 +BRDA:283,30,1,1 +BRDA:302,31,0,35 +BRDA:305,32,0,1 +BRDA:305,32,1,34 +BRDA:305,33,0,35 +BRDA:305,33,1,8 +BRDA:315,34,0,1 +BRDA:315,34,1,34 +BRDA:319,35,0,28 +BRDA:319,35,1,7 +BRDA:323,36,0,20 +BRDA:323,36,1,15 +BRDA:323,37,0,35 +BRDA:323,37,1,20 +BRDA:329,38,0,35 +BRDA:329,38,1,9 +BRDA:331,39,0,1 +BRDA:331,39,1,1 +BRDA:331,40,0,2 +BRDA:331,40,1,2 +BRDA:341,41,0,34 +BRDA:341,41,1,1 +BRDA:341,42,0,35 +BRDA:341,42,1,9 +BRDA:350,43,0,34 +BRDA:350,43,1,1 +BRDA:358,44,0,1 +BRDA:358,44,1,34 +BRF:90 +BRH:78 +end_of_record +TN: +SF:packages/k8s/src/hooks/run-container-step.ts +FN:36,runContainerStep +FN:169,(anonymous_1) +FN:181,classifyScriptError +FN:192,(anonymous_3) +FN:234,(anonymous_4) +FN:246,createContainerSpec +FN:263,(anonymous_6) +FNF:7 +FNH:5 +FNDA:20,runContainerStep +FNDA:0,(anonymous_1) +FNDA:7,classifyScriptError +FNDA:5,(anonymous_3) +FNDA:2,(anonymous_4) +FNDA:18,createContainerSpec +FNDA:0,(anonymous_6) +DA:39,20 +DA:40,1 +DA:43,19 +DA:44,1 +DA:49,18 +DA:50,20 +DA:51,20 +DA:52,17 +DA:55,18 +DA:57,18 +DA:58,18 +DA:61,18 +DA:62,18 +DA:64,2 +DA:65,2 +DA:66,2 +DA:69,16 +DA:70,1 +DA:76,15 +DA:78,15 +DA:79,15 +DA:86,14 +DA:87,14 +DA:88,14 +DA:89,1 +DA:93,13 +DA:94,13 +DA:95,13 +DA:96,13 +DA:97,1 +DA:99,12 +DA:101,12 +DA:104,12 +DA:106,12 +DA:114,12 +DA:116,12 +DA:118,12 +DA:119,12 +DA:120,12 +DA:125,10 +DA:126,3 +DA:132,7 +DA:137,7 +DA:139,9 +DA:141,9 +DA:146,7 +DA:148,2 +DA:149,2 +DA:151,12 +DA:154,12 +DA:155,12 +DA:156,11 +DA:157,11 +DA:158,1 +DA:159,1 +DA:166,12 +DA:167,12 +DA:169,15 +DA:170,0 +DA:186,7 +DA:187,7 +DA:188,7 +DA:190,7 +DA:191,7 +DA:192,6 +DA:193,5 +DA:195,7 +DA:196,7 +DA:197,4 +DA:199,4 +DA:203,4 +DA:204,1 +DA:205,1 +DA:206,1 +DA:210,3 +DA:213,3 +DA:219,2 +DA:221,6 +DA:222,1 +DA:228,1 +DA:231,7 +DA:232,1 +DA:234,2 +DA:236,1 +DA:239,7 +DA:240,7 +DA:241,3 +DA:243,7 +DA:250,18 +DA:251,18 +DA:252,18 +DA:253,18 +DA:254,18 +DA:255,18 +DA:257,18 +DA:259,18 +DA:260,18 +DA:263,0 +DA:264,0 +DA:266,18 +DA:267,0 +DA:270,0 +LF:102 +LH:97 +BRDA:39,0,0,1 +BRDA:39,0,1,19 +BRDA:43,1,0,1 +BRDA:43,1,1,18 +BRDA:49,2,0,18 +BRDA:49,2,1,0 +BRDA:51,3,0,17 +BRDA:51,3,1,3 +BRDA:69,4,0,1 +BRDA:69,4,1,15 +BRDA:88,5,0,1 +BRDA:88,5,1,13 +BRDA:88,6,0,14 +BRDA:88,6,1,13 +BRDA:96,7,0,1 +BRDA:96,7,1,12 +BRDA:125,8,0,3 +BRDA:125,8,1,7 +BRDA:141,9,0,7 +BRDA:141,9,1,2 +BRDA:142,10,0,9 +BRDA:142,10,1,9 +BRDA:142,10,2,9 +BRDA:157,11,0,1 +BRDA:157,11,1,10 +BRDA:196,12,0,4 +BRDA:196,12,1,2 +BRDA:197,13,0,4 +BRDA:197,13,1,0 +BRDA:199,14,0,4 +BRDA:199,14,1,3 +BRDA:199,14,2,3 +BRDA:199,14,3,3 +BRDA:199,14,4,0 +BRDA:203,15,0,1 +BRDA:203,15,1,3 +BRDA:204,16,0,0 +BRDA:204,16,1,1 +BRDA:221,17,0,1 +BRDA:221,17,1,5 +BRDA:223,18,0,1 +BRDA:223,18,1,0 +BRDA:231,19,0,1 +BRDA:231,19,1,6 +BRDA:240,20,0,3 +BRDA:240,20,1,4 +BRDA:259,21,0,18 +BRDA:259,21,1,0 +BRDA:266,22,0,0 +BRDA:266,22,1,18 +BRF:50 +BRH:43 +end_of_record +TN: +SF:packages/k8s/src/hooks/run-script-step.ts +FN:16,formatScriptError +FN:26,(anonymous_1) +FN:35,runScriptStep +FNF:3 +FNH:3 +FNDA:2,formatScriptError +FNDA:2,(anonymous_1) +FNDA:10,runScriptStep +DA:17,2 +DA:18,2 +DA:22,2 +DA:23,2 +DA:24,2 +DA:26,2 +DA:28,2 +DA:30,2 +DA:31,2 +DA:32,2 +DA:40,10 +DA:41,2 +DA:47,8 +DA:48,8 +DA:56,8 +DA:57,8 +DA:58,8 +DA:59,8 +DA:61,8 +DA:70,8 +DA:76,8 +DA:93,8 +DA:94,8 +DA:100,1 +DA:101,1 +DA:102,1 +DA:106,7 +DA:107,7 +DA:108,7 +DA:109,7 +DA:114,5 +DA:115,2 +DA:118,4 +DA:119,4 +DA:123,3 +DA:125,1 +DA:126,1 +DA:128,7 +DA:129,7 +DA:131,0 +DA:135,3 +DA:136,3 +DA:139,3 +DA:145,1 +LF:44 +LH:43 +BRDA:23,0,0,2 +BRDA:23,0,1,0 +BRDA:31,1,0,2 +BRDA:31,1,1,0 +BRDA:40,2,0,2 +BRDA:40,2,1,8 +BRDA:114,3,0,2 +BRDA:114,3,1,3 +BRDA:119,4,0,3 +BRDA:119,4,1,1 +BRDA:120,5,0,4 +BRDA:120,5,1,4 +BRF:12 +BRH:10 +end_of_record +TN: +SF:packages/k8s/src/k8s/heartbeat.ts +FN:11,parsePositiveMsEnv +FN:25,constructor +FN:30,shouldLog +FN:39,stop +FN:53,start +FN:59,(anonymous_5) +FN:64,(anonymous_6) +FN:86,(anonymous_7) +FN:95,(anonymous_8) +FN:100,(anonymous_9) +FN:106,(anonymous_10) +FNF:11 +FNH:11 +FNDA:22,parsePositiveMsEnv +FNDA:20,constructor +FNDA:38,shouldLog +FNDA:21,stop +FNDA:16,start +FNDA:9,(anonymous_5) +FNDA:3,(anonymous_6) +FNDA:1,(anonymous_7) +FNDA:1,(anonymous_8) +FNDA:1,(anonymous_9) +FNDA:21,(anonymous_10) +DA:15,22 +DA:16,22 +DA:20,20 +DA:21,20 +DA:22,20 +DA:23,2 +DA:26,20 +DA:27,20 +DA:31,38 +DA:32,38 +DA:33,8 +DA:34,8 +DA:36,30 +DA:40,21 +DA:41,8 +DA:43,21 +DA:44,9 +DA:45,9 +DA:47,21 +DA:48,6 +DA:49,6 +DA:54,16 +DA:57,16 +DA:59,16 +DA:60,9 +DA:61,1 +DA:62,1 +DA:64,9 +DA:65,3 +DA:68,3 +DA:69,3 +DA:70,3 +DA:74,3 +DA:84,16 +DA:86,16 +DA:87,1 +DA:88,0 +DA:90,1 +DA:91,1 +DA:95,16 +DA:96,1 +DA:97,1 +DA:100,16 +DA:101,1 +DA:102,1 +DA:106,16 +DA:107,21 +DA:109,4 +DA:111,17 +DA:112,16 +DA:113,16 +DA:114,16 +DA:115,8 +DA:116,8 +DA:118,15 +DA:119,0 +DA:122,1 +DA:123,1 +DA:127,1 +DA:128,0 +DA:132,1 +LF:61 +LH:58 +BRDA:15,0,0,22 +BRDA:15,0,1,15 +BRDA:16,1,0,3 +BRDA:16,1,1,19 +BRDA:16,2,0,22 +BRDA:16,2,1,5 +BRDA:32,3,0,8 +BRDA:32,3,1,30 +BRDA:40,4,0,8 +BRDA:40,4,1,13 +BRDA:43,5,0,9 +BRDA:43,5,1,12 +BRDA:47,6,0,6 +BRDA:47,6,1,15 +BRDA:60,7,0,1 +BRDA:60,7,1,8 +BRDA:87,8,0,0 +BRDA:87,8,1,1 +BRDA:90,9,0,1 +BRDA:90,9,1,0 +BRDA:107,10,0,4 +BRDA:107,10,1,17 +BRDA:111,11,0,16 +BRDA:111,11,1,1 +BRDA:114,12,0,8 +BRDA:114,12,1,8 +BRDA:118,13,0,0 +BRDA:118,13,1,15 +BRDA:127,14,0,0 +BRDA:127,14,1,1 +BRF:30 +BRH:26 +end_of_record +TN: +SF:packages/k8s/src/k8s/index.ts +FN:69,createJobPod +FN:189,createContainerStepPod +FN:242,deletePod +FN:250,execPodStep +FN:278,(anonymous_4) +FN:292,(anonymous_5) +FN:300,(anonymous_6) +FN:306,(anonymous_7) +FN:307,(anonymous_8) +FN:314,(anonymous_9) +FN:337,(anonymous_10) +FN:346,(anonymous_11) +FN:353,(anonymous_12) +FN:354,(anonymous_13) +FN:361,(anonymous_14) +FN:379,execPodStepWithOutput +FN:391,(anonymous_16) +FN:399,(anonymous_17) +FN:407,(anonymous_18) +FN:414,(anonymous_19) +FN:426,write +FN:437,write_2 +FN:451,(anonymous_22) +FN:456,(anonymous_23) +FN:466,(anonymous_24) +FN:485,(anonymous_25) +FN:503,execCalculateOutputHashSorted +FN:512,write_3 +FN:522,(anonymous_28) +FN:532,(anonymous_29) +FN:548,(anonymous_30) +FN:556,(anonymous_31) +FN:565,localCalculateOutputHashSorted +FN:568,(anonymous_33) +FN:575,(anonymous_34) +FN:579,(anonymous_35) +FN:584,(anonymous_36) +FN:599,execCpToPod +FN:622,(anonymous_38) +FN:633,(anonymous_39) +FN:644,(anonymous_40) +FN:685,(anonymous_41) +FN:688,(anonymous_42) +FN:690,(anonymous_43) +FN:693,(anonymous_44) +FN:697,(anonymous_45) +FN:701,(anonymous_46) +FN:720,execCpFromPod +FN:756,(anonymous_48) +FN:773,(anonymous_49) +FN:783,(anonymous_50) +FN:824,(anonymous_51) +FN:827,(anonymous_52) +FN:829,(anonymous_53) +FN:832,(anonymous_54) +FN:836,(anonymous_55) +FN:840,(anonymous_56) +FN:859,waitForJobToComplete +FN:873,createDockerSecret +FN:914,createSecretForEnvs +FN:942,deleteSecret +FN:949,pruneSecrets +FN:960,(anonymous_62) +FN:1052,getUnrecoverableWaitingReasons +FN:1070,getUnrecoverableEventReasons +FN:1085,getUnrecoverableTerminatedReasons +FN:1107,isPermanentSchedulingFailure +FN:1111,(anonymous_67) +FN:1123,getPermanentSchedulingPatterns +FN:1146,getWaitingReasonHint +FN:1165,getContainerErrors +FN:1184,getTerminatedReasonHint +FN:1211,getContainerTerminatedErrors +FN:1230,getEventReasonHint +FN:1266,getPodEventErrors +FN:1331,describePodFailure +FN:1412,describePodWarningEvents +FN:1429,(anonymous_77) +FN:1434,(anonymous_78) +FN:1438,(anonymous_79) +FN:1441,(anonymous_80) +FN:1459,getPodConditionErrors +FN:1469,checkUnrecoverableErrors +FN:1482,(anonymous_83) +FN:1484,(anonymous_84) +FN:1496,waitForPodPhases +FN:1576,getPrepareJobTimeoutSeconds +FN:1595,readPod +FN:1610,parsePodPhase +FN:1617,isJobSucceeded +FN:1628,getPodLogs +FN:1634,(anonymous_91) +FN:1644,(anonymous_92) +FN:1645,(anonymous_93) +FN:1646,(anonymous_94) +FN:1653,prunePods +FN:1664,(anonymous_96) +FN:1669,getPodStatus +FN:1679,isAuthPermissionsOK +FN:1697,(anonymous_99) +FN:1700,isPodContainerAlpine +FN:1722,namespace +FN:1727,(anonymous_102) +FN:1753,constructor +FN:1759,backOff +FN:1760,(anonymous_105) +FN:1776,containerPorts +FN:1798,(anonymous_107) +FN:1818,getPodByName +FN:1825,getSecretByName +FN:1832,listPodsByRunnerInstance +FNF:111 +FNH:80 +FNDA:5,createJobPod +FNDA:1,createContainerStepPod +FNDA:3,deletePod +FNDA:7,execPodStep +FNDA:7,(anonymous_4) +FNDA:6,(anonymous_5) +FNDA:6,(anonymous_6) +FNDA:0,(anonymous_7) +FNDA:0,(anonymous_8) +FNDA:0,(anonymous_9) +FNDA:6,(anonymous_10) +FNDA:5,(anonymous_11) +FNDA:2,(anonymous_12) +FNDA:0,(anonymous_13) +FNDA:1,(anonymous_14) +FNDA:5,execPodStepWithOutput +FNDA:2,(anonymous_16) +FNDA:1,(anonymous_17) +FNDA:0,(anonymous_18) +FNDA:5,(anonymous_19) +FNDA:1,write +FNDA:0,write_2 +FNDA:4,(anonymous_22) +FNDA:5,(anonymous_23) +FNDA:3,(anonymous_24) +FNDA:2,(anonymous_25) +FNDA:3,execCalculateOutputHashSorted +FNDA:2,write_3 +FNDA:3,(anonymous_28) +FNDA:2,(anonymous_29) +FNDA:1,(anonymous_30) +FNDA:4,(anonymous_31) +FNDA:2,localCalculateOutputHashSorted +FNDA:2,(anonymous_33) +FNDA:1,(anonymous_34) +FNDA:2,(anonymous_35) +FNDA:2,(anonymous_36) +FNDA:0,execCpToPod +FNDA:0,(anonymous_38) +FNDA:0,(anonymous_39) +FNDA:0,(anonymous_40) +FNDA:0,(anonymous_41) +FNDA:0,(anonymous_42) +FNDA:0,(anonymous_43) +FNDA:0,(anonymous_44) +FNDA:0,(anonymous_45) +FNDA:0,(anonymous_46) +FNDA:0,execCpFromPod +FNDA:0,(anonymous_48) +FNDA:0,(anonymous_49) +FNDA:0,(anonymous_50) +FNDA:0,(anonymous_51) +FNDA:0,(anonymous_52) +FNDA:0,(anonymous_53) +FNDA:0,(anonymous_54) +FNDA:0,(anonymous_55) +FNDA:0,(anonymous_56) +FNDA:2,waitForJobToComplete +FNDA:2,createDockerSecret +FNDA:2,createSecretForEnvs +FNDA:3,deleteSecret +FNDA:2,pruneSecrets +FNDA:3,(anonymous_62) +FNDA:28,getUnrecoverableWaitingReasons +FNDA:21,getUnrecoverableEventReasons +FNDA:20,getUnrecoverableTerminatedReasons +FNDA:11,isPermanentSchedulingFailure +FNDA:26,(anonymous_67) +FNDA:15,getPermanentSchedulingPatterns +FNDA:10,getWaitingReasonHint +FNDA:20,getContainerErrors +FNDA:14,getTerminatedReasonHint +FNDA:18,getContainerTerminatedErrors +FNDA:10,getEventReasonHint +FNDA:19,getPodEventErrors +FNDA:7,describePodFailure +FNDA:6,describePodWarningEvents +FNDA:3,(anonymous_77) +FNDA:0,(anonymous_78) +FNDA:0,(anonymous_79) +FNDA:3,(anonymous_80) +FNDA:9,getPodConditionErrors +FNDA:8,checkUnrecoverableErrors +FNDA:0,(anonymous_83) +FNDA:0,(anonymous_84) +FNDA:6,waitForPodPhases +FNDA:4,getPrepareJobTimeoutSeconds +FNDA:15,readPod +FNDA:13,parsePodPhase +FNDA:2,isJobSucceeded +FNDA:2,getPodLogs +FNDA:0,(anonymous_91) +FNDA:2,(anonymous_92) +FNDA:1,(anonymous_93) +FNDA:1,(anonymous_94) +FNDA:2,prunePods +FNDA:2,(anonymous_96) +FNDA:1,getPodStatus +FNDA:2,isAuthPermissionsOK +FNDA:14,(anonymous_99) +FNDA:2,isPodContainerAlpine +FNDA:117,namespace +FNDA:1,(anonymous_102) +FNDA:8,constructor +FNDA:2,backOff +FNDA:2,(anonymous_105) +FNDA:12,containerPorts +FNDA:13,(anonymous_107) +FNDA:2,getPodByName +FNDA:2,getSecretByName +FNDA:3,listPodsByRunnerInstance +DA:32,1 +DA:34,1 +DA:36,1 +DA:37,1 +DA:38,1 +DA:40,1 +DA:42,1 +DA:76,5 +DA:77,5 +DA:78,4 +DA:80,5 +DA:81,1 +DA:84,5 +DA:86,5 +DA:87,5 +DA:89,5 +DA:90,5 +DA:92,5 +DA:93,5 +DA:96,5 +DA:98,5 +DA:99,5 +DA:100,5 +DA:106,5 +DA:107,5 +DA:109,5 +DA:116,5 +DA:117,5 +DA:120,5 +DA:148,5 +DA:150,5 +DA:165,5 +DA:166,0 +DA:167,0 +DA:168,0 +DA:170,0 +DA:171,0 +DA:172,0 +DA:175,5 +DA:176,1 +DA:179,5 +DA:180,1 +DA:183,5 +DA:194,1 +DA:196,1 +DA:197,1 +DA:199,1 +DA:200,1 +DA:202,1 +DA:203,1 +DA:206,1 +DA:208,1 +DA:209,1 +DA:211,1 +DA:213,1 +DA:228,1 +DA:229,0 +DA:232,1 +DA:233,0 +DA:236,1 +DA:243,3 +DA:256,7 +DA:257,7 +DA:261,7 +DA:263,7 +DA:264,7 +DA:268,7 +DA:272,7 +DA:276,7 +DA:278,7 +DA:279,7 +DA:280,7 +DA:282,7 +DA:293,6 +DA:297,6 +DA:300,6 +DA:301,6 +DA:302,6 +DA:306,0 +DA:307,0 +DA:308,0 +DA:311,0 +DA:314,0 +DA:315,0 +DA:316,0 +DA:317,0 +DA:319,0 +DA:324,6 +DA:325,3 +DA:326,3 +DA:327,3 +DA:329,3 +DA:332,3 +DA:333,3 +DA:338,6 +DA:339,6 +DA:340,6 +DA:341,4 +DA:343,2 +DA:347,5 +DA:348,5 +DA:351,5 +DA:352,5 +DA:353,2 +DA:354,2 +DA:355,0 +DA:358,0 +DA:361,2 +DA:362,1 +DA:363,1 +DA:365,2 +DA:369,4 +DA:386,5 +DA:387,5 +DA:390,5 +DA:391,5 +DA:392,2 +DA:393,2 +DA:394,2 +DA:398,5 +DA:399,5 +DA:400,1 +DA:401,1 +DA:402,1 +DA:403,2 +DA:406,5 +DA:407,5 +DA:408,0 +DA:409,0 +DA:410,0 +DA:411,0 +DA:414,5 +DA:415,5 +DA:416,0 +DA:417,0 +DA:419,5 +DA:420,0 +DA:421,0 +DA:425,5 +DA:427,1 +DA:428,1 +DA:429,1 +DA:430,1 +DA:432,0 +DA:436,5 +DA:438,0 +DA:439,0 +DA:440,0 +DA:441,0 +DA:443,0 +DA:451,5 +DA:452,4 +DA:453,4 +DA:456,5 +DA:457,5 +DA:468,3 +DA:469,3 +DA:470,3 +DA:471,1 +DA:476,2 +DA:477,2 +DA:478,1 +DA:480,1 +DA:491,2 +DA:492,2 +DA:493,2 +DA:494,2 +DA:495,1 +DA:497,1 +DA:508,3 +DA:510,3 +DA:511,3 +DA:513,2 +DA:514,2 +DA:515,2 +DA:517,0 +DA:522,3 +DA:523,3 +DA:534,2 +DA:535,2 +DA:536,1 +DA:538,1 +DA:544,1 +DA:548,1 +DA:551,1 +DA:554,1 +DA:556,4 +DA:558,1 +DA:560,1 +DA:561,1 +DA:562,1 +DA:568,2 +DA:570,2 +DA:574,2 +DA:575,2 +DA:576,1 +DA:578,2 +DA:579,2 +DA:580,2 +DA:582,1 +DA:584,2 +DA:586,1 +DA:588,1 +DA:589,1 +DA:590,1 +DA:592,1 +DA:604,0 +DA:606,0 +DA:607,0 +DA:608,0 +DA:609,0 +DA:612,0 +DA:620,0 +DA:621,0 +DA:622,0 +DA:623,0 +DA:634,0 +DA:635,0 +DA:641,0 +DA:644,0 +DA:646,0 +DA:648,0 +DA:649,0 +DA:650,0 +DA:651,0 +DA:655,0 +DA:659,0 +DA:660,0 +DA:661,0 +DA:662,0 +DA:664,0 +DA:671,0 +DA:677,0 +DA:678,0 +DA:681,0 +DA:684,0 +DA:685,0 +DA:687,0 +DA:688,0 +DA:690,0 +DA:691,0 +DA:693,0 +DA:694,0 +DA:696,0 +DA:698,0 +DA:699,0 +DA:702,0 +DA:703,0 +DA:705,0 +DA:706,0 +DA:707,0 +DA:708,0 +DA:709,0 +DA:712,0 +DA:714,0 +DA:715,0 +DA:725,0 +DA:726,0 +DA:734,0 +DA:735,0 +DA:738,0 +DA:739,0 +DA:740,0 +DA:742,0 +DA:743,0 +DA:744,0 +DA:745,0 +DA:753,0 +DA:754,0 +DA:756,0 +DA:761,0 +DA:762,0 +DA:763,0 +DA:774,0 +DA:775,0 +DA:783,0 +DA:785,0 +DA:787,0 +DA:788,0 +DA:789,0 +DA:790,0 +DA:794,0 +DA:798,0 +DA:799,0 +DA:800,0 +DA:801,0 +DA:803,0 +DA:810,0 +DA:816,0 +DA:817,0 +DA:820,0 +DA:823,0 +DA:824,0 +DA:826,0 +DA:827,0 +DA:829,0 +DA:830,0 +DA:832,0 +DA:833,0 +DA:835,0 +DA:837,0 +DA:838,0 +DA:841,0 +DA:842,0 +DA:844,0 +DA:845,0 +DA:846,0 +DA:847,0 +DA:848,0 +DA:851,0 +DA:853,0 +DA:854,0 +DA:860,2 +DA:861,2 +DA:862,2 +DA:863,2 +DA:864,1 +DA:867,1 +DA:869,0 +DA:876,2 +DA:888,2 +DA:890,2 +DA:891,2 +DA:892,2 +DA:893,2 +DA:894,2 +DA:895,2 +DA:896,2 +DA:897,2 +DA:900,2 +DA:901,2 +DA:902,2 +DA:908,2 +DA:917,2 +DA:919,2 +DA:920,2 +DA:921,2 +DA:922,2 +DA:923,2 +DA:924,2 +DA:926,2 +DA:929,2 +DA:930,2 +DA:931,2 +DA:932,2 +DA:935,2 +DA:939,2 +DA:943,3 +DA:950,2 +DA:954,2 +DA:955,1 +DA:958,1 +DA:961,3 +DA:966,1 +DA:1001,1 +DA:1024,1 +DA:1038,1 +DA:1046,1 +DA:1053,28 +DA:1054,28 +DA:1055,26 +DA:1057,2 +DA:1058,2 +DA:1059,2 +DA:1060,2 +DA:1061,2 +DA:1064,2 +DA:1071,21 +DA:1072,21 +DA:1073,20 +DA:1075,1 +DA:1076,1 +DA:1077,1 +DA:1078,1 +DA:1079,1 +DA:1082,1 +DA:1087,20 +DA:1088,20 +DA:1089,19 +DA:1091,1 +DA:1092,1 +DA:1093,3 +DA:1094,3 +DA:1095,1 +DA:1098,1 +DA:1110,11 +DA:1111,26 +DA:1124,15 +DA:1125,15 +DA:1126,5 +DA:1127,1 +DA:1129,4 +DA:1130,4 +DA:1131,8 +DA:1132,8 +DA:1133,5 +DA:1134,5 +DA:1136,1 +DA:1141,4 +DA:1142,4 +DA:1143,4 +DA:1147,10 +DA:1149,5 +DA:1157,2 +DA:1159,2 +DA:1161,1 +DA:1166,20 +DA:1167,20 +DA:1168,20 +DA:1172,20 +DA:1173,13 +DA:1174,13 +DA:1175,10 +DA:1176,10 +DA:1177,10 +DA:1178,10 +DA:1181,20 +DA:1188,14 +DA:1189,5 +DA:1191,9 +DA:1192,2 +DA:1194,7 +DA:1195,6 +DA:1197,1 +DA:1199,0 +DA:1201,1 +DA:1203,1 +DA:1205,3 +DA:1208,1 +DA:1212,18 +DA:1213,18 +DA:1214,18 +DA:1218,18 +DA:1219,11 +DA:1220,11 +DA:1221,7 +DA:1222,7 +DA:1223,7 +DA:1224,7 +DA:1227,18 +DA:1231,10 +DA:1233,7 +DA:1240,1 +DA:1247,2 +DA:1254,0 +DA:1267,19 +DA:1268,19 +DA:1269,0 +DA:1273,19 +DA:1274,19 +DA:1278,18 +DA:1280,1 +DA:1285,1 +DA:1288,18 +DA:1289,18 +DA:1290,18 +DA:1291,14 +DA:1296,1 +DA:1301,13 +DA:1305,2 +DA:1310,2 +DA:1312,11 +DA:1313,1 +DA:1315,10 +DA:1316,10 +DA:1317,14 +DA:1318,14 +DA:1319,14 +DA:1320,14 +DA:1322,18 +DA:1333,7 +DA:1334,7 +DA:1336,1 +DA:1341,6 +DA:1342,6 +DA:1345,6 +DA:1346,6 +DA:1349,7 +DA:1350,7 +DA:1351,0 +DA:1355,6 +DA:1356,0 +DA:1357,0 +DA:1358,0 +DA:1359,0 +DA:1362,6 +DA:1365,6 +DA:1366,6 +DA:1370,7 +DA:1371,7 +DA:1372,2 +DA:1373,2 +DA:1376,1 +DA:1377,0 +DA:1378,0 +DA:1383,2 +DA:1385,2 +DA:1386,1 +DA:1387,1 +DA:1388,1 +DA:1393,6 +DA:1394,1 +DA:1398,6 +DA:1399,6 +DA:1400,3 +DA:1403,6 +DA:1404,0 +DA:1406,6 +DA:1414,6 +DA:1415,6 +DA:1419,6 +DA:1421,0 +DA:1426,0 +DA:1429,6 +DA:1430,6 +DA:1431,3 +DA:1434,3 +DA:1435,0 +DA:1436,0 +DA:1438,3 +DA:1440,3 +DA:1441,3 +DA:1442,3 +DA:1443,3 +DA:1445,3 +DA:1446,0 +DA:1450,3 +DA:1460,9 +DA:1474,8 +DA:1476,8 +DA:1478,8 +DA:1482,8 +DA:1484,0 +DA:1485,0 +DA:1488,8 +DA:1502,6 +DA:1503,6 +DA:1504,6 +DA:1506,8 +DA:1507,8 +DA:1512,2 +DA:1517,2 +DA:1518,2 +DA:1520,0 +DA:1526,2 +DA:1528,6 +DA:1529,6 +DA:1530,2 +DA:1538,4 +DA:1539,1 +DA:1540,1 +DA:1541,1 +DA:1542,0 +DA:1546,1 +DA:1554,3 +DA:1555,3 +DA:1556,3 +DA:1557,3 +DA:1562,0 +DA:1563,0 +DA:1568,0 +DA:1569,0 +DA:1578,4 +DA:1580,4 +DA:1581,1 +DA:1584,3 +DA:1585,3 +DA:1586,2 +DA:1589,2 +DA:1592,1 +DA:1596,15 +DA:1602,1 +DA:1611,13 +DA:1612,3 +DA:1614,10 +DA:1618,2 +DA:1622,2 +DA:1623,1 +DA:1625,1 +DA:1632,2 +DA:1633,2 +DA:1634,2 +DA:1636,0 +DA:1639,2 +DA:1644,2 +DA:1645,2 +DA:1646,2 +DA:1647,1 +DA:1648,1 +DA:1654,2 +DA:1658,2 +DA:1659,1 +DA:1662,1 +DA:1664,2 +DA:1672,1 +DA:1676,1 +DA:1680,2 +DA:1681,2 +DA:1682,2 +DA:1683,8 +DA:1684,26 +DA:1685,26 +DA:1686,26 +DA:1687,26 +DA:1688,26 +DA:1689,26 +DA:1690,26 +DA:1691,26 +DA:1696,2 +DA:1697,14 +DA:1704,2 +DA:1705,2 +DA:1706,2 +DA:1716,1 +DA:1719,2 +DA:1723,117 +DA:1724,116 +DA:1727,1 +DA:1728,1 +DA:1729,1 +DA:1735,0 +DA:1736,0 +DA:1737,0 +DA:1738,0 +DA:1739,0 +DA:1745,0 +DA:1751,8 +DA:1752,8 +DA:1753,8 +DA:1754,8 +DA:1755,2 +DA:1760,2 +DA:1761,2 +DA:1763,2 +DA:1764,2 +DA:1765,0 +DA:1767,2 +DA:1768,2 +DA:1770,2 +DA:1771,0 +DA:1779,12 +DA:1780,12 +DA:1781,2 +DA:1783,10 +DA:1784,11 +DA:1785,11 +DA:1786,1 +DA:1789,10 +DA:1790,10 +DA:1793,11 +DA:1794,11 +DA:1795,1 +DA:1798,9 +DA:1799,13 +DA:1800,13 +DA:1801,3 +DA:1803,10 +DA:1806,9 +DA:1807,5 +DA:1809,4 +DA:1810,4 +DA:1813,6 +DA:1815,5 +DA:1819,2 +DA:1826,2 +DA:1833,3 +DA:1837,2 +LF:667 +LH:493 +BRDA:77,0,0,4 +BRDA:77,0,1,1 +BRDA:80,1,0,1 +BRDA:80,1,1,4 +BRDA:107,2,0,5 +BRDA:107,2,1,0 +BRDA:116,3,0,5 +BRDA:116,3,1,0 +BRDA:124,4,0,5 +BRDA:124,4,1,5 +BRDA:165,5,0,0 +BRDA:165,5,1,5 +BRDA:167,6,0,0 +BRDA:167,6,1,0 +BRDA:175,7,0,1 +BRDA:175,7,1,4 +BRDA:179,8,0,1 +BRDA:179,8,1,4 +BRDA:228,9,0,0 +BRDA:228,9,1,1 +BRDA:232,10,0,0 +BRDA:232,10,1,1 +BRDA:290,11,0,7 +BRDA:290,11,1,7 +BRDA:302,12,0,0 +BRDA:302,12,1,6 +BRDA:303,13,0,6 +BRDA:303,13,1,0 +BRDA:303,13,2,0 +BRDA:324,14,0,3 +BRDA:324,14,1,3 +BRDA:327,15,0,3 +BRDA:327,15,1,2 +BRDA:333,16,0,3 +BRDA:333,16,1,0 +BRDA:340,17,0,4 +BRDA:340,17,1,2 +BRDA:352,18,0,2 +BRDA:352,18,1,3 +BRDA:352,19,0,5 +BRDA:352,19,1,4 +BRDA:352,19,2,2 +BRDA:383,20,0,5 +BRDA:392,21,0,0 +BRDA:392,21,1,2 +BRDA:394,22,0,0 +BRDA:394,22,1,2 +BRDA:402,23,0,1 +BRDA:402,23,1,0 +BRDA:410,24,0,0 +BRDA:410,24,1,0 +BRDA:415,25,0,0 +BRDA:415,25,1,5 +BRDA:419,26,0,0 +BRDA:419,26,1,5 +BRDA:453,27,0,2 +BRDA:453,27,1,2 +BRDA:465,28,0,5 +BRDA:465,28,1,5 +BRDA:470,29,0,1 +BRDA:470,29,1,2 +BRDA:471,30,0,1 +BRDA:471,30,1,1 +BRDA:477,31,0,1 +BRDA:477,31,1,1 +BRDA:480,32,0,1 +BRDA:480,32,1,0 +BRDA:492,33,0,2 +BRDA:492,33,1,0 +BRDA:494,34,0,1 +BRDA:494,34,1,1 +BRDA:535,35,0,1 +BRDA:535,35,1,1 +BRDA:544,36,0,1 +BRDA:544,36,1,0 +BRDA:580,37,0,1 +BRDA:580,37,1,1 +BRDA:634,38,0,0 +BRDA:634,38,1,0 +BRDA:650,39,0,0 +BRDA:650,39,1,0 +BRDA:677,40,0,0 +BRDA:677,40,1,0 +BRDA:699,41,0,0 +BRDA:699,41,1,0 +BRDA:734,42,0,0 +BRDA:734,42,1,0 +BRDA:750,43,0,0 +BRDA:750,43,1,0 +BRDA:774,44,0,0 +BRDA:774,44,1,0 +BRDA:789,45,0,0 +BRDA:789,45,1,0 +BRDA:816,46,0,0 +BRDA:816,46,1,0 +BRDA:838,47,0,0 +BRDA:838,47,1,0 +BRDA:863,48,0,1 +BRDA:863,48,1,1 +BRDA:878,49,0,2 +BRDA:878,49,1,1 +BRDA:954,50,0,1 +BRDA:954,50,1,1 +BRDA:961,51,0,3 +BRDA:961,51,1,2 +BRDA:1054,52,0,26 +BRDA:1054,52,1,2 +BRDA:1060,53,0,2 +BRDA:1060,53,1,0 +BRDA:1072,54,0,20 +BRDA:1072,54,1,1 +BRDA:1078,55,0,1 +BRDA:1078,55,1,0 +BRDA:1088,56,0,19 +BRDA:1088,56,1,1 +BRDA:1094,57,0,1 +BRDA:1094,57,1,2 +BRDA:1110,58,0,2 +BRDA:1110,58,1,9 +BRDA:1125,59,0,10 +BRDA:1125,59,1,5 +BRDA:1126,60,0,1 +BRDA:1126,60,1,4 +BRDA:1126,61,0,5 +BRDA:1126,61,1,4 +BRDA:1132,62,0,3 +BRDA:1132,62,1,5 +BRDA:1147,63,0,5 +BRDA:1147,63,1,2 +BRDA:1147,63,2,2 +BRDA:1147,63,3,1 +BRDA:1169,64,0,20 +BRDA:1169,64,1,19 +BRDA:1170,65,0,20 +BRDA:1170,65,1,8 +BRDA:1174,66,0,10 +BRDA:1174,66,1,3 +BRDA:1174,67,0,13 +BRDA:1174,67,1,12 +BRDA:1176,68,0,2 +BRDA:1176,68,1,8 +BRDA:1188,69,0,5 +BRDA:1188,69,1,9 +BRDA:1191,70,0,2 +BRDA:1191,70,1,7 +BRDA:1194,71,0,6 +BRDA:1194,71,1,1 +BRDA:1195,72,0,1 +BRDA:1195,72,1,0 +BRDA:1195,72,2,1 +BRDA:1195,72,3,1 +BRDA:1195,72,4,3 +BRDA:1205,73,0,3 +BRDA:1205,73,1,0 +BRDA:1215,74,0,18 +BRDA:1215,74,1,17 +BRDA:1216,75,0,18 +BRDA:1216,75,1,8 +BRDA:1220,76,0,7 +BRDA:1220,76,1,4 +BRDA:1220,77,0,11 +BRDA:1220,77,1,8 +BRDA:1222,78,0,0 +BRDA:1222,78,1,7 +BRDA:1231,79,0,7 +BRDA:1231,79,1,1 +BRDA:1231,79,2,2 +BRDA:1231,79,3,0 +BRDA:1268,80,0,0 +BRDA:1268,80,1,19 +BRDA:1278,81,0,18 +BRDA:1278,81,1,0 +BRDA:1282,82,0,1 +BRDA:1282,82,1,0 +BRDA:1291,83,0,1 +BRDA:1291,83,1,13 +BRDA:1292,84,0,14 +BRDA:1292,84,1,13 +BRDA:1292,84,2,13 +BRDA:1301,85,0,2 +BRDA:1301,85,1,11 +BRDA:1302,86,0,13 +BRDA:1302,86,1,4 +BRDA:1307,87,0,2 +BRDA:1307,87,1,0 +BRDA:1312,88,0,1 +BRDA:1312,88,1,10 +BRDA:1316,89,0,1 +BRDA:1316,89,1,9 +BRDA:1316,90,0,10 +BRDA:1316,90,1,1 +BRDA:1318,91,0,10 +BRDA:1318,91,1,0 +BRDA:1337,92,0,1 +BRDA:1337,92,1,0 +BRDA:1346,93,0,6 +BRDA:1346,93,1,0 +BRDA:1347,94,0,0 +BRDA:1347,94,1,6 +BRDA:1350,95,0,0 +BRDA:1350,95,1,7 +BRDA:1355,96,0,6 +BRDA:1355,96,1,6 +BRDA:1356,97,0,0 +BRDA:1356,97,1,0 +BRDA:1357,98,0,0 +BRDA:1357,98,1,0 +BRDA:1358,99,0,0 +BRDA:1358,99,1,0 +BRDA:1367,100,0,6 +BRDA:1367,100,1,6 +BRDA:1368,101,0,7 +BRDA:1368,101,1,4 +BRDA:1373,102,0,1 +BRDA:1373,102,1,1 +BRDA:1376,103,0,0 +BRDA:1376,103,1,1 +BRDA:1377,104,0,0 +BRDA:1377,104,1,0 +BRDA:1385,105,0,1 +BRDA:1385,105,1,1 +BRDA:1385,106,0,2 +BRDA:1385,106,1,1 +BRDA:1386,107,0,1 +BRDA:1386,107,1,0 +BRDA:1387,108,0,0 +BRDA:1387,108,1,1 +BRDA:1393,109,0,1 +BRDA:1393,109,1,5 +BRDA:1399,110,0,3 +BRDA:1399,110,1,3 +BRDA:1403,111,0,0 +BRDA:1403,111,1,6 +BRDA:1419,112,0,6 +BRDA:1419,112,1,0 +BRDA:1423,113,0,0 +BRDA:1423,113,1,0 +BRDA:1430,114,0,3 +BRDA:1430,114,1,3 +BRDA:1435,115,0,0 +BRDA:1435,115,1,0 +BRDA:1435,115,2,0 +BRDA:1436,116,0,0 +BRDA:1436,116,1,0 +BRDA:1442,117,0,0 +BRDA:1442,117,1,3 +BRDA:1442,118,0,3 +BRDA:1442,118,1,0 +BRDA:1443,119,0,3 +BRDA:1443,119,1,0 +BRDA:1443,120,0,3 +BRDA:1443,120,1,0 +BRDA:1445,121,0,0 +BRDA:1445,121,1,3 +BRDA:1485,122,0,0 +BRDA:1485,122,1,0 +BRDA:1500,123,0,6 +BRDA:1514,124,0,2 +BRDA:1514,124,1,0 +BRDA:1522,125,0,0 +BRDA:1522,125,1,0 +BRDA:1529,126,0,2 +BRDA:1529,126,1,4 +BRDA:1538,127,0,1 +BRDA:1538,127,1,3 +BRDA:1541,128,0,0 +BRDA:1541,128,1,1 +BRDA:1555,129,0,3 +BRDA:1555,129,1,0 +BRDA:1580,130,0,1 +BRDA:1580,130,1,3 +BRDA:1585,131,0,2 +BRDA:1585,131,1,1 +BRDA:1585,132,0,3 +BRDA:1585,132,1,1 +BRDA:1611,133,0,3 +BRDA:1611,133,1,10 +BRDA:1611,134,0,13 +BRDA:1611,134,1,11 +BRDA:1622,135,0,1 +BRDA:1622,135,1,1 +BRDA:1658,136,0,1 +BRDA:1658,136,1,1 +BRDA:1664,137,0,2 +BRDA:1664,137,1,2 +BRDA:1723,138,0,116 +BRDA:1723,138,1,1 +BRDA:1728,139,0,1 +BRDA:1728,139,1,0 +BRDA:1738,140,0,0 +BRDA:1738,140,1,0 +BRDA:1754,141,0,2 +BRDA:1754,141,1,6 +BRDA:1754,142,0,8 +BRDA:1754,142,1,6 +BRDA:1764,143,0,0 +BRDA:1764,143,1,2 +BRDA:1764,144,0,2 +BRDA:1764,144,1,2 +BRDA:1767,145,0,2 +BRDA:1767,145,1,0 +BRDA:1770,146,0,0 +BRDA:1770,146,1,2 +BRDA:1780,147,0,2 +BRDA:1780,147,1,10 +BRDA:1785,148,0,1 +BRDA:1785,148,1,10 +BRDA:1791,149,0,3 +BRDA:1791,149,1,7 +BRDA:1794,150,0,1 +BRDA:1794,150,1,10 +BRDA:1800,151,0,3 +BRDA:1800,151,1,10 +BRDA:1800,152,0,13 +BRDA:1800,152,1,12 +BRDA:1800,152,2,11 +BRDA:1806,153,0,5 +BRDA:1806,153,1,4 +BRDA:1837,154,0,2 +BRDA:1837,154,1,0 +BRF:320 +BRH:225 +end_of_record +TN: +SF:packages/k8s/src/k8s/utils/index.ts +FN:35,prepareJobScript +FN:40,(anonymous_1) +FN:59,writeRunScript +FN:94,writeContainerStepScript +FN:129,scriptEnv +FN:161,generateContainerName +FN:180,mergeContainerWithOptions +FN:208,mergePodSpecWithOptions +FN:215,(anonymous_8) +FN:228,mergeObjectMeta +FN:258,readExtensionFromFile +FN:270,useKubeScheduler +FN:274,(anonymous_12) +FN:283,mergeLists +FN:292,fixArgs +FN:301,sleep +FN:302,(anonymous_16) +FN:305,listDirAllCommand +FN:315,formatError +FNF:19 +FNH:19 +FNDA:5,prepareJobScript +FNDA:5,(anonymous_1) +FNDA:16,writeRunScript +FNDA:3,writeContainerStepScript +FNDA:19,scriptEnv +FNDA:18,generateContainerName +FNDA:5,mergeContainerWithOptions +FNDA:2,mergePodSpecWithOptions +FNDA:1,(anonymous_8) +FNDA:6,mergeObjectMeta +FNDA:42,readExtensionFromFile +FNDA:3,useKubeScheduler +FNDA:7,(anonymous_12) +FNDA:6,mergeLists +FNDA:35,fixArgs +FNDA:1,sleep +FNDA:1,(anonymous_16) +FNDA:2,listDirAllCommand +FNDA:39,formatError +DA:10,7 +DA:11,7 +DA:13,7 +DA:14,7 +DA:16,7 +DA:17,7 +DA:18,7 +DA:20,7 +DA:39,5 +DA:40,5 +DA:43,5 +DA:50,5 +DA:51,5 +DA:52,5 +DA:53,5 +DA:66,16 +DA:67,16 +DA:70,2 +DA:71,2 +DA:74,16 +DA:76,16 +DA:85,16 +DA:86,16 +DA:87,16 +DA:88,16 +DA:101,3 +DA:103,3 +DA:104,3 +DA:105,1 +DA:108,1 +DA:119,3 +DA:120,3 +DA:121,3 +DA:122,3 +DA:123,3 +DA:130,19 +DA:131,7 +DA:133,12 +DA:134,12 +DA:135,14 +DA:141,3 +DA:145,11 +DA:154,9 +DA:155,0 +DA:158,9 +DA:162,18 +DA:163,18 +DA:165,18 +DA:166,2 +DA:169,16 +DA:184,5 +DA:185,9 +DA:186,2 +DA:187,0 +DA:189,2 +DA:190,7 +DA:191,1 +DA:192,1 +DA:193,6 +DA:194,2 +DA:195,2 +DA:196,4 +DA:197,1 +DA:198,1 +DA:199,3 +DA:200,2 +DA:201,2 +DA:203,1 +DA:212,2 +DA:213,5 +DA:214,2 +DA:216,1 +DA:219,3 +DA:220,1 +DA:221,1 +DA:223,2 +DA:232,6 +DA:233,2 +DA:237,4 +DA:238,3 +DA:239,3 +DA:240,1 +DA:242,3 +DA:246,4 +DA:247,3 +DA:248,3 +DA:249,1 +DA:253,3 +DA:259,42 +DA:260,42 +DA:261,38 +DA:263,4 +DA:264,4 +DA:265,1 +DA:267,1 +DA:271,3 +DA:274,7 +DA:275,7 +DA:276,7 +DA:277,7 +DA:278,7 +DA:279,7 +DA:280,7 +DA:284,6 +DA:285,6 +DA:286,1 +DA:288,5 +DA:289,5 +DA:295,35 +DA:296,8 +DA:298,27 +DA:302,1 +DA:306,2 +DA:316,39 +DA:317,2 +DA:323,37 +DA:325,39 +DA:326,5 +DA:327,5 +DA:328,5 +DA:329,5 +DA:335,32 +DA:336,27 +DA:339,5 +DA:344,3 +DA:345,3 +DA:346,1 +DA:348,2 +DA:349,2 +DA:351,1 +DA:357,2 +LF:131 +LH:129 +BRDA:67,0,0,2 +BRDA:67,0,1,14 +BRDA:70,1,0,1 +BRDA:70,1,1,1 +BRDA:82,2,0,11 +BRDA:82,2,1,3 +BRDA:104,3,0,1 +BRDA:104,3,1,2 +BRDA:116,4,0,1 +BRDA:116,4,1,0 +BRDA:130,5,0,7 +BRDA:130,5,1,12 +BRDA:130,6,0,19 +BRDA:130,6,1,14 +BRDA:135,7,0,3 +BRDA:135,7,1,11 +BRDA:136,8,0,14 +BRDA:136,8,1,12 +BRDA:136,8,2,12 +BRDA:136,8,3,12 +BRDA:154,9,0,0 +BRDA:154,9,1,9 +BRDA:165,10,0,2 +BRDA:165,10,1,16 +BRDA:185,11,0,2 +BRDA:185,11,1,7 +BRDA:186,12,0,0 +BRDA:186,12,1,2 +BRDA:190,13,0,1 +BRDA:190,13,1,6 +BRDA:193,14,0,2 +BRDA:193,14,1,4 +BRDA:196,15,0,1 +BRDA:196,15,1,3 +BRDA:196,16,0,4 +BRDA:196,16,1,1 +BRDA:199,17,0,2 +BRDA:199,17,1,1 +BRDA:199,18,0,3 +BRDA:199,18,1,2 +BRDA:213,19,0,2 +BRDA:213,19,1,3 +BRDA:219,20,0,1 +BRDA:219,20,1,2 +BRDA:219,21,0,3 +BRDA:219,21,1,1 +BRDA:232,22,0,2 +BRDA:232,22,1,4 +BRDA:232,23,0,6 +BRDA:232,23,1,5 +BRDA:237,24,0,3 +BRDA:237,24,1,1 +BRDA:239,25,0,1 +BRDA:239,25,1,2 +BRDA:246,26,0,3 +BRDA:246,26,1,1 +BRDA:248,27,0,1 +BRDA:248,27,1,2 +BRDA:260,28,0,38 +BRDA:260,28,1,4 +BRDA:264,29,0,1 +BRDA:264,29,1,3 +BRDA:264,30,0,4 +BRDA:264,30,1,2 +BRDA:284,31,0,6 +BRDA:284,31,1,1 +BRDA:285,32,0,1 +BRDA:285,32,1,5 +BRDA:295,33,0,8 +BRDA:295,33,1,27 +BRDA:295,34,0,35 +BRDA:295,34,1,30 +BRDA:295,34,2,8 +BRDA:316,35,0,2 +BRDA:316,35,1,37 +BRDA:316,36,0,39 +BRDA:316,36,1,38 +BRDA:323,37,0,37 +BRDA:323,37,1,33 +BRDA:325,38,0,5 +BRDA:325,38,1,34 +BRDA:325,39,0,39 +BRDA:325,39,1,5 +BRDA:328,40,0,5 +BRDA:328,40,1,0 +BRDA:329,41,0,1 +BRDA:329,41,1,4 +BRDA:329,42,0,5 +BRDA:329,42,1,2 +BRDA:335,43,0,27 +BRDA:335,43,1,5 +BRDA:339,44,0,3 +BRDA:339,44,1,2 +BRDA:345,45,0,1 +BRDA:345,45,1,2 +BRF:95 +BRH:91 +end_of_record +TN: +SF:packages/k8s/src/k8s/utils/npu-metrics.ts +FN:71,npuMetricsEnabled +FN:79,getNpuSampleIntervalSeconds +FN:96,getIdleThresholdPercent +FN:113,containerHasNpuRequest +FN:125,hasNpuRequest +FN:126,(anonymous_5) +FN:129,listNpuCardsCommand +FN:133,buildNpuSamplerScript +FN:187,buildNpuAggregateScript +FN:198,commandHasMarker +FN:202,appendExecCommand +FN:218,(anonymous_11) +FN:224,injectNpuMetrics +FN:269,maybeInjectNpuMetrics +FN:279,parseNpuAggregate +FN:324,isIdleRecord +FN:331,(anonymous_16) +FN:334,escapePromLabelValue +FN:338,formatPromLabels +FN:340,(anonymous_19) +FN:341,(anonymous_20) +FN:359,buildNpuJobMetricsBody +FN:385,(anonymous_22) +FN:401,buildNpuPushFailedBody +FN:408,buildPushgatewayPath +FN:418,withTimeout +FN:422,(anonymous_26) +FN:423,(anonymous_27) +FN:424,(anonymous_28) +FN:428,(anonymous_29) +FN:448,nodeRequest +FN:462,(anonymous_31) +FN:470,(anonymous_32) +FN:473,(anonymous_33) +FN:478,(anonymous_34) +FN:484,pushToPushgateway +FN:497,(anonymous_36) +FN:518,decodePushSecret +FN:522,(anonymous_38) +FN:545,readNpuPushConfig +FN:557,parseScaleSetSuffix +FN:565,extractClusterFromRunnerPod +FN:589,resolveNpuLabelsFromPod +FN:615,(anonymous_43) +FN:630,repoFromEnv +FN:637,(anonymous_45) +FN:644,collectNpuAggregateFromPod +FN:651,(anonymous_47) +FN:670,collectAndPushNpuMetrics +FN:681,(anonymous_49) +FN:716,collectAndPushForPod +FNF:51 +FNH:50 +FNDA:51,npuMetricsEnabled +FNDA:5,getNpuSampleIntervalSeconds +FNDA:9,getIdleThresholdPercent +FNDA:60,containerHasNpuRequest +FNDA:18,hasNpuRequest +FNDA:18,(anonymous_5) +FNDA:19,listNpuCardsCommand +FNDA:8,buildNpuSamplerScript +FNDA:11,buildNpuAggregateScript +FNDA:13,commandHasMarker +FNDA:10,appendExecCommand +FNDA:2,(anonymous_11) +FNDA:7,injectNpuMetrics +FNDA:39,maybeInjectNpuMetrics +FNDA:17,parseNpuAggregate +FNDA:14,isIdleRecord +FNDA:15,(anonymous_16) +FNDA:111,escapePromLabelValue +FNDA:8,formatPromLabels +FNDA:88,(anonymous_19) +FNDA:88,(anonymous_20) +FNDA:8,buildNpuJobMetricsBody +FNDA:88,(anonymous_22) +FNDA:3,buildNpuPushFailedBody +FNDA:7,buildPushgatewayPath +FNDA:3,withTimeout +FNDA:3,(anonymous_26) +FNDA:1,(anonymous_27) +FNDA:2,(anonymous_28) +FNDA:1,(anonymous_29) +FNDA:18,nodeRequest +FNDA:17,(anonymous_31) +FNDA:5,(anonymous_32) +FNDA:5,(anonymous_33) +FNDA:0,(anonymous_34) +FNDA:13,pushToPushgateway +FNDA:12,(anonymous_36) +FNDA:8,decodePushSecret +FNDA:18,(anonymous_38) +FNDA:5,readNpuPushConfig +FNDA:11,parseScaleSetSuffix +FNDA:10,extractClusterFromRunnerPod +FNDA:9,resolveNpuLabelsFromPod +FNDA:7,(anonymous_43) +FNDA:9,repoFromEnv +FNDA:5,(anonymous_45) +FNDA:12,collectNpuAggregateFromPod +FNDA:11,(anonymous_47) +FNDA:8,collectAndPushNpuMetrics +FNDA:16,(anonymous_49) +FNDA:8,collectAndPushForPod +DA:16,3 +DA:17,3 +DA:18,3 +DA:19,3 +DA:21,3 +DA:22,3 +DA:23,3 +DA:25,3 +DA:26,3 +DA:27,3 +DA:28,3 +DA:30,3 +DA:31,3 +DA:32,3 +DA:34,3 +DA:35,3 +DA:74,51 +DA:82,5 +DA:83,5 +DA:84,1 +DA:86,4 +DA:87,4 +DA:88,2 +DA:91,2 +DA:93,2 +DA:99,9 +DA:100,9 +DA:101,7 +DA:103,2 +DA:104,2 +DA:105,1 +DA:108,1 +DA:110,1 +DA:114,60 +DA:115,60 +DA:116,107 +DA:117,16 +DA:118,14 +DA:122,46 +DA:126,18 +DA:130,19 +DA:136,8 +DA:158,3 +DA:188,11 +DA:199,13 +DA:206,10 +DA:212,1 +DA:218,9 +DA:219,2 +DA:221,10 +DA:228,7 +DA:229,7 +DA:233,1 +DA:236,6 +DA:240,1 +DA:243,1 +DA:246,5 +DA:247,5 +DA:249,5 +DA:257,7 +DA:265,7 +DA:266,7 +DA:270,39 +DA:271,1 +DA:273,38 +DA:274,37 +DA:276,1 +DA:282,17 +DA:283,2 +DA:285,15 +DA:286,15 +DA:287,2 +DA:289,13 +DA:290,13 +DA:291,13 +DA:292,12 +DA:294,13 +DA:296,15 +DA:297,15 +DA:299,2 +DA:301,13 +DA:302,2 +DA:304,11 +DA:305,11 +DA:306,11 +DA:307,2 +DA:309,9 +DA:319,11 +DA:321,2 +DA:328,14 +DA:329,1 +DA:331,15 +DA:335,111 +DA:339,8 +DA:340,88 +DA:341,88 +DA:345,3 +DA:364,8 +DA:375,8 +DA:376,8 +DA:377,8 +DA:378,8 +DA:379,8 +DA:380,8 +DA:381,8 +DA:382,8 +DA:383,8 +DA:385,88 +DA:388,8 +DA:389,8 +DA:390,8 +DA:391,8 +DA:392,8 +DA:394,8 +DA:395,8 +DA:398,8 +DA:402,3 +DA:413,7 +DA:422,3 +DA:423,3 +DA:424,3 +DA:426,2 +DA:427,2 +DA:430,1 +DA:431,1 +DA:451,18 +DA:452,18 +DA:453,18 +DA:456,18 +DA:457,5 +DA:460,5 +DA:462,17 +DA:463,17 +DA:472,5 +DA:473,5 +DA:474,5 +DA:478,17 +DA:479,17 +DA:480,17 +DA:490,13 +DA:491,13 +DA:492,13 +DA:493,13 +DA:495,13 +DA:496,25 +DA:497,12 +DA:499,25 +DA:500,25 +DA:507,9 +DA:508,8 +DA:510,1 +DA:512,16 +DA:515,17 +DA:521,8 +DA:522,8 +DA:523,18 +DA:524,18 +DA:525,5 +DA:527,13 +DA:528,13 +DA:529,13 +DA:531,0 +DA:534,8 +DA:535,8 +DA:536,3 +DA:538,5 +DA:546,5 +DA:547,5 +DA:548,4 +DA:550,1 +DA:553,1 +DA:558,11 +DA:559,0 +DA:561,11 +DA:562,11 +DA:566,10 +DA:567,10 +DA:568,10 +DA:572,10 +DA:573,8 +DA:574,6 +DA:575,6 +DA:576,6 +DA:580,4 +DA:581,2 +DA:582,2 +DA:583,1 +DA:586,3 +DA:598,9 +DA:599,9 +DA:600,9 +DA:601,9 +DA:602,9 +DA:606,18 +DA:607,8 +DA:608,8 +DA:609,8 +DA:610,8 +DA:615,9 +DA:616,7 +DA:618,9 +DA:619,9 +DA:622,9 +DA:633,9 +DA:634,7 +DA:636,2 +DA:637,9 +DA:638,9 +DA:639,1 +DA:641,1 +DA:647,12 +DA:648,12 +DA:649,1 +DA:651,11 +DA:652,11 +DA:654,12 +DA:655,12 +DA:656,5 +DA:658,6 +DA:659,1 +DA:661,5 +DA:667,4 +DA:671,8 +DA:672,1 +DA:674,7 +DA:675,7 +DA:676,7 +DA:678,1 +DA:679,1 +DA:681,6 +DA:682,16 +DA:684,6 +DA:685,1 +DA:688,5 +DA:689,5 +DA:690,5 +DA:691,5 +DA:693,0 +DA:696,5 +DA:697,5 +DA:698,1 +DA:701,1 +DA:704,4 +DA:705,8 +DA:706,8 +DA:707,8 +DA:709,1 +DA:722,8 +DA:723,7 +DA:724,1 +DA:725,1 +DA:728,6 +DA:729,6 +DA:741,8 +DA:746,8 +DA:747,8 +DA:748,8 +DA:749,4 +DA:751,2 +DA:752,2 +DA:753,2 +LF:261 +LH:258 +BRDA:72,0,0,51 +BRDA:75,1,0,51 +BRDA:75,1,1,46 +BRDA:80,2,0,5 +BRDA:83,3,0,1 +BRDA:83,3,1,4 +BRDA:87,4,0,2 +BRDA:87,4,1,2 +BRDA:87,5,0,4 +BRDA:87,5,1,3 +BRDA:97,6,0,9 +BRDA:100,7,0,7 +BRDA:100,7,1,2 +BRDA:104,8,0,1 +BRDA:104,8,1,1 +BRDA:104,9,0,2 +BRDA:104,9,1,1 +BRDA:116,10,0,107 +BRDA:116,10,1,92 +BRDA:117,11,0,14 +BRDA:117,11,1,2 +BRDA:126,12,0,18 +BRDA:126,12,1,1 +BRDA:134,13,0,8 +BRDA:199,14,0,13 +BRDA:199,14,1,10 +BRDA:206,15,0,1 +BRDA:206,15,1,9 +BRDA:207,16,0,10 +BRDA:207,16,1,2 +BRDA:207,16,2,1 +BRDA:207,16,3,1 +BRDA:218,17,0,9 +BRDA:218,17,1,8 +BRDA:226,18,0,7 +BRDA:228,19,0,7 +BRDA:228,19,1,3 +BRDA:229,20,0,1 +BRDA:229,20,1,6 +BRDA:230,21,0,7 +BRDA:230,21,1,6 +BRDA:236,22,0,1 +BRDA:236,22,1,5 +BRDA:237,23,0,6 +BRDA:237,23,1,3 +BRDA:237,23,2,5 +BRDA:237,23,3,0 +BRDA:270,24,0,1 +BRDA:270,24,1,38 +BRDA:273,25,0,37 +BRDA:273,25,1,1 +BRDA:282,26,0,2 +BRDA:282,26,1,15 +BRDA:286,27,0,2 +BRDA:286,27,1,13 +BRDA:291,28,0,12 +BRDA:291,28,1,1 +BRDA:301,29,0,2 +BRDA:301,29,1,11 +BRDA:301,30,0,13 +BRDA:301,30,1,11 +BRDA:306,31,0,2 +BRDA:306,31,1,9 +BRDA:306,32,0,11 +BRDA:306,32,1,10 +BRDA:306,32,2,10 +BRDA:311,33,0,9 +BRDA:311,33,1,0 +BRDA:312,34,0,11 +BRDA:312,34,1,1 +BRDA:313,35,0,11 +BRDA:313,35,1,1 +BRDA:314,36,0,11 +BRDA:314,36,1,1 +BRDA:315,37,0,11 +BRDA:315,37,1,1 +BRDA:316,38,0,11 +BRDA:316,38,1,1 +BRDA:319,39,0,11 +BRDA:319,39,1,0 +BRDA:326,40,0,14 +BRDA:328,41,0,1 +BRDA:328,41,1,13 +BRDA:331,42,0,15 +BRDA:331,42,1,10 +BRDA:362,43,0,8 +BRDA:375,44,0,5 +BRDA:375,44,1,3 +BRDA:452,45,0,17 +BRDA:452,45,1,0 +BRDA:456,46,0,5 +BRDA:456,46,1,13 +BRDA:456,47,0,18 +BRDA:456,47,1,12 +BRDA:458,48,0,5 +BRDA:458,48,1,0 +BRDA:458,49,0,5 +BRDA:458,49,1,0 +BRDA:468,50,0,17 +BRDA:468,50,1,17 +BRDA:474,51,0,5 +BRDA:474,51,1,0 +BRDA:490,52,0,13 +BRDA:490,52,1,13 +BRDA:491,53,0,13 +BRDA:491,53,1,10 +BRDA:492,54,0,13 +BRDA:492,54,1,8 +BRDA:496,55,0,12 +BRDA:496,55,1,13 +BRDA:507,56,0,8 +BRDA:507,56,1,1 +BRDA:507,57,0,9 +BRDA:507,57,1,9 +BRDA:515,58,0,5 +BRDA:515,58,1,0 +BRDA:521,59,0,8 +BRDA:521,59,1,2 +BRDA:524,60,0,5 +BRDA:524,60,1,13 +BRDA:529,61,0,13 +BRDA:529,61,1,0 +BRDA:535,62,0,3 +BRDA:535,62,1,5 +BRDA:558,63,0,0 +BRDA:558,63,1,11 +BRDA:562,64,0,8 +BRDA:562,64,1,3 +BRDA:566,65,0,10 +BRDA:566,65,1,0 +BRDA:567,66,0,10 +BRDA:567,66,1,10 +BRDA:573,67,0,6 +BRDA:573,67,1,2 +BRDA:575,68,0,6 +BRDA:575,68,1,0 +BRDA:582,69,0,1 +BRDA:582,69,1,1 +BRDA:586,70,0,3 +BRDA:586,70,1,2 +BRDA:598,71,0,5 +BRDA:598,71,1,4 +BRDA:601,72,0,9 +BRDA:601,72,1,0 +BRDA:606,73,0,18 +BRDA:606,73,1,10 +BRDA:608,74,0,8 +BRDA:608,74,1,0 +BRDA:610,75,0,8 +BRDA:610,75,1,0 +BRDA:615,76,0,9 +BRDA:615,76,1,2 +BRDA:619,77,0,5 +BRDA:619,77,1,4 +BRDA:621,78,0,4 +BRDA:621,78,1,1 +BRDA:624,79,0,9 +BRDA:624,79,1,2 +BRDA:625,80,0,9 +BRDA:625,80,1,2 +BRDA:631,81,0,9 +BRDA:633,82,0,7 +BRDA:633,82,1,2 +BRDA:636,83,0,2 +BRDA:636,83,1,1 +BRDA:638,84,0,1 +BRDA:638,84,1,8 +BRDA:648,85,0,1 +BRDA:648,85,1,11 +BRDA:651,86,0,11 +BRDA:651,86,1,0 +BRDA:655,87,0,5 +BRDA:655,87,1,7 +BRDA:658,88,0,1 +BRDA:658,88,1,5 +BRDA:671,89,0,1 +BRDA:671,89,1,7 +BRDA:682,90,0,16 +BRDA:682,90,1,16 +BRDA:684,91,0,1 +BRDA:684,91,1,5 +BRDA:697,92,0,1 +BRDA:697,92,1,4 +BRDA:723,93,0,1 +BRDA:723,93,1,6 +BRDA:723,94,0,7 +BRDA:723,94,1,6 +BRDA:735,95,0,6 +BRDA:735,95,1,0 +BRF:189 +BRH:172 +end_of_record diff --git a/packages/docker/package-lock.json b/packages/docker/package-lock.json index e07593b4..99e446fe 100644 --- a/packages/docker/package-lock.json +++ b/packages/docker/package-lock.json @@ -29,21 +29,6 @@ "typescript": "^5.8.3" } }, - "../hooklib": { - "version": "0.1.0", - "license": "MIT", - "dependencies": { - "@actions/core": "^2.0.2" - }, - "devDependencies": { - "@types/node": "^24.0.14", - "@zeit/ncc": "^0.22.3", - "eslint": "^9.31.0", - "eslint-plugin-github": "^6.0.0", - "prettier": "^3.6.2", - "typescript": "^5.8.3" - } - }, "node_modules/@actions/core": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@actions/core/-/core-2.0.3.tgz", @@ -3207,9 +3192,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -3224,9 +3206,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -3241,9 +3220,6 @@ "loong64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -3258,9 +3234,6 @@ "loong64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -3275,9 +3248,6 @@ "ppc64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -3292,9 +3262,6 @@ "riscv64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -3309,9 +3276,6 @@ "riscv64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -3326,9 +3290,6 @@ "s390x" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -3343,9 +3304,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -3360,9 +3318,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -4807,8 +4762,12 @@ } }, "node_modules/hooklib": { - "resolved": "../hooklib", - "link": true + "version": "0.1.0", + "resolved": "file:../hooklib", + "license": "MIT", + "dependencies": { + "@actions/core": "^2.0.2" + } }, "node_modules/html-escaper": { "version": "2.0.2", diff --git a/packages/k8s/coverage/clover.xml b/packages/k8s/coverage/clover.xml new file mode 100644 index 00000000..396afafb --- /dev/null +++ b/packages/k8s/coverage/clover.xml @@ -0,0 +1,1680 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/k8s/coverage/coverage-final.json b/packages/k8s/coverage/coverage-final.json new file mode 100644 index 00000000..6563388c --- /dev/null +++ b/packages/k8s/coverage/coverage-final.json @@ -0,0 +1,12 @@ +{"/__w/backlog/backlog/work/runner-container-hooks/packages/k8s/src/hooks/cleanup-job.ts": {"path":"/__w/backlog/backlog/work/runner-container-hooks/packages/k8s/src/hooks/cleanup-job.ts","statementMap":{"0":{"start":{"line":11,"column":0},"end":{"line":11,"column":22}},"1":{"start":{"line":1,"column":0},"end":{"line":1,"column":37}},"2":{"start":{"line":2,"column":0},"end":{"line":2,"column":42}},"3":{"start":{"line":3,"column":0},"end":{"line":3,"column":48}},"4":{"start":{"line":4,"column":0},"end":{"line":4,"column":null}},"5":{"start":{"line":12,"column":6},"end":{"line":12,"column":23}},"6":{"start":{"line":14,"column":6},"end":{"line":14,"column":null}},"7":{"start":{"line":16,"column":6},"end":{"line":16,"column":null}},"8":{"start":{"line":19,"column":2},"end":{"line":19,"column":null}}},"fnMap":{"0":{"name":"cleanupJob","decl":{"start":{"line":11,"column":22},"end":{"line":11,"column":32}},"loc":{"start":{"line":11,"column":32},"end":{"line":20,"column":null}}}},"branchMap":{"0":{"loc":{"start":{"line":19,"column":2},"end":{"line":19,"column":null}},"type":"switch","locations":[{"start":{"line":19,"column":2},"end":{"line":19,"column":null}}]},"1":{"loc":{"start":{"line":12,"column":6},"end":{"line":12,"column":23}},"type":"if","locations":[{"start":{"line":12,"column":6},"end":{"line":12,"column":23}},{"start":{},"end":{}}]}},"s":{"0":7,"1":7,"2":7,"3":7,"4":7,"5":21,"6":42,"7":0,"8":42},"f":{"0":21},"b":{"0":[21],"1":[0,21]}} +,"/__w/backlog/backlog/work/runner-container-hooks/packages/k8s/src/hooks/constants.ts": {"path":"/__w/backlog/backlog/work/runner-container-hooks/packages/k8s/src/hooks/constants.ts","statementMap":{"0":{"start":{"line":3,"column":0},"end":{"line":3,"column":16}},"1":{"start":{"line":13,"column":0},"end":{"line":13,"column":16}},"2":{"start":{"line":20,"column":0},"end":{"line":20,"column":16}},"3":{"start":{"line":27,"column":0},"end":{"line":27,"column":16}},"4":{"start":{"line":35,"column":0},"end":{"line":35,"column":16}},"5":{"start":{"line":1,"column":0},"end":{"line":1,"column":35}},"6":{"start":{"line":4,"column":15},"end":{"line":4,"column":50}},"7":{"start":{"line":5,"column":2},"end":{"line":9,"column":3}},"8":{"start":{"line":6,"column":4},"end":{"line":8,"column":null}},"9":{"start":{"line":10,"column":2},"end":{"line":10,"column":null}},"10":{"start":{"line":14,"column":2},"end":{"line":17,"column":null}},"11":{"start":{"line":21,"column":2},"end":{"line":24,"column":null}},"12":{"start":{"line":28,"column":15},"end":{"line":28,"column":52}},"13":{"start":{"line":29,"column":2},"end":{"line":31,"column":3}},"14":{"start":{"line":30,"column":4},"end":{"line":30,"column":null}},"15":{"start":{"line":32,"column":2},"end":{"line":32,"column":null}},"16":{"start":{"line":36,"column":2},"end":{"line":39,"column":null}},"17":{"start":{"line":42,"column":13},"end":{"line":42,"column":null}},"18":{"start":{"line":43,"column":13},"end":{"line":43,"column":null}},"19":{"start":{"line":44,"column":13},"end":{"line":44,"column":null}},"20":{"start":{"line":45,"column":13},"end":{"line":45,"column":null}},"21":{"start":{"line":46,"column":13},"end":{"line":46,"column":null}},"22":{"start":{"line":48,"column":0},"end":{"line":48,"column":13}},"23":{"start":{"line":51,"column":4},"end":{"line":51,"column":null}},"24":{"start":{"line":54,"column":2},"end":{"line":56,"column":null}},"25":{"start":{"line":55,"column":4},"end":{"line":55,"column":null}},"26":{"start":{"line":58,"column":2},"end":{"line":60,"column":null}},"27":{"start":{"line":59,"column":4},"end":{"line":59,"column":null}},"28":{"start":{"line":62,"column":2},"end":{"line":64,"column":null}},"29":{"start":{"line":63,"column":4},"end":{"line":63,"column":null}},"30":{"start":{"line":65,"column":0},"end":{"line":65,"column":null}},"31":{"start":{"line":48,"column":13},"end":{"line":48,"column":32}}},"fnMap":{"0":{"name":"getRunnerPodName","decl":{"start":{"line":3,"column":16},"end":{"line":3,"column":32}},"loc":{"start":{"line":3,"column":32},"end":{"line":11,"column":1}}},"1":{"name":"getJobPodName","decl":{"start":{"line":13,"column":16},"end":{"line":13,"column":29}},"loc":{"start":{"line":13,"column":29},"end":{"line":18,"column":1}}},"2":{"name":"getStepPodName","decl":{"start":{"line":20,"column":16},"end":{"line":20,"column":30}},"loc":{"start":{"line":20,"column":30},"end":{"line":25,"column":1}}},"3":{"name":"getVolumeClaimName","decl":{"start":{"line":27,"column":16},"end":{"line":27,"column":34}},"loc":{"start":{"line":27,"column":34},"end":{"line":33,"column":1}}},"4":{"name":"getSecretName","decl":{"start":{"line":35,"column":16},"end":{"line":35,"column":29}},"loc":{"start":{"line":35,"column":29},"end":{"line":40,"column":1}}},"5":{"name":"(anonymous_5)","decl":{"start":{"line":48,"column":0},"end":{"line":48,"column":13}},"loc":{"start":{"line":48,"column":0},"end":{"line":65,"column":1}}},"6":{"name":"RunnerInstanceLabel","decl":{"start":{"line":50,"column":2},"end":{"line":50,"column":null}},"loc":{"start":{"line":50,"column":2},"end":{"line":52,"column":3}}},"7":{"name":"(anonymous_7)","decl":{"start":{"line":54,"column":2},"end":{"line":54,"column":6}},"loc":{"start":{"line":54,"column":2},"end":{"line":56,"column":3}}},"8":{"name":"(anonymous_8)","decl":{"start":{"line":58,"column":2},"end":{"line":58,"column":6}},"loc":{"start":{"line":58,"column":2},"end":{"line":60,"column":3}}},"9":{"name":"(anonymous_9)","decl":{"start":{"line":62,"column":2},"end":{"line":62,"column":10}},"loc":{"start":{"line":62,"column":2},"end":{"line":64,"column":3}}}},"branchMap":{"0":{"loc":{"start":{"line":5,"column":2},"end":{"line":9,"column":3}},"type":"if","locations":[{"start":{"line":5,"column":2},"end":{"line":9,"column":3}},{"start":{},"end":{}}]},"1":{"loc":{"start":{"line":29,"column":2},"end":{"line":31,"column":3}},"type":"if","locations":[{"start":{"line":29,"column":2},"end":{"line":31,"column":3}},{"start":{},"end":{}}]}},"s":{"0":15,"1":15,"2":15,"3":15,"4":15,"5":15,"6":105,"7":105,"8":74,"9":31,"10":11,"11":17,"12":4,"13":4,"14":3,"15":1,"16":3,"17":15,"18":15,"19":15,"20":15,"21":15,"22":15,"23":67,"24":15,"25":4,"26":15,"27":3,"28":15,"29":1,"30":15,"31":15},"f":{"0":105,"1":11,"2":17,"3":4,"4":3,"5":15,"6":67,"7":4,"8":3,"9":1},"b":{"0":[74,31],"1":[3,1]}} +,"/__w/backlog/backlog/work/runner-container-hooks/packages/k8s/src/hooks/index.ts": {"path":"/__w/backlog/backlog/work/runner-container-hooks/packages/k8s/src/hooks/index.ts","statementMap":{"0":{"start":{"line":1,"column":0},"end":{"line":1,"column":29}},"1":{"start":{"line":2,"column":0},"end":{"line":2,"column":29}},"2":{"start":{"line":3,"column":0},"end":{"line":3,"column":33}},"3":{"start":{"line":4,"column":0},"end":{"line":4,"column":36}}},"fnMap":{},"branchMap":{},"s":{"0":7,"1":7,"2":7,"3":7},"f":{},"b":{}} +,"/__w/backlog/backlog/work/runner-container-hooks/packages/k8s/src/hooks/prepare-job.ts": {"path":"/__w/backlog/backlog/work/runner-container-hooks/packages/k8s/src/hooks/prepare-job.ts","statementMap":{"0":{"start":{"line":40,"column":0},"end":{"line":40,"column":22}},"1":{"start":{"line":299,"column":0},"end":{"line":299,"column":16}},"2":{"start":{"line":1,"column":0},"end":{"line":1,"column":37}},"3":{"start":{"line":3,"column":0},"end":{"line":3,"column":null}},"4":{"start":{"line":10,"column":0},"end":{"line":10,"column":null}},"5":{"start":{"line":20,"column":0},"end":{"line":20,"column":null}},"6":{"start":{"line":32,"column":0},"end":{"line":32,"column":null}},"7":{"start":{"line":37,"column":0},"end":{"line":37,"column":64}},"8":{"start":{"line":38,"column":0},"end":{"line":38,"column":30}},"9":{"start":{"line":44,"column":2},"end":{"line":46,"column":3}},"10":{"start":{"line":45,"column":4},"end":{"line":45,"column":null}},"11":{"start":{"line":48,"column":2},"end":{"line":48,"column":null}},"12":{"start":{"line":50,"column":8},"end":{"line":50,"column":null}},"13":{"start":{"line":52,"column":6},"end":{"line":52,"column":null}},"14":{"start":{"line":53,"column":2},"end":{"line":61,"column":3}},"15":{"start":{"line":54,"column":4},"end":{"line":59,"column":null}},"16":{"start":{"line":60,"column":4},"end":{"line":60,"column":null}},"17":{"start":{"line":63,"column":6},"end":{"line":63,"column":null}},"18":{"start":{"line":64,"column":6},"end":{"line":64,"column":null}},"19":{"start":{"line":65,"column":2},"end":{"line":89,"column":3}},"20":{"start":{"line":66,"column":10},"end":{"line":66,"column":null}},"21":{"start":{"line":67,"column":4},"end":{"line":70,"column":5}},"22":{"start":{"line":67,"column":15},"end":{"line":67,"column":20}},"23":{"start":{"line":68,"column":12},"end":{"line":68,"column":null}},"24":{"start":{"line":69,"column":6},"end":{"line":69,"column":null}},"25":{"start":{"line":72,"column":10},"end":{"line":72,"column":null}},"26":{"start":{"line":73,"column":4},"end":{"line":88,"column":null}},"27":{"start":{"line":74,"column":19},"end":{"line":74,"column":55}},"28":{"start":{"line":75,"column":20},"end":{"line":75,"column":46}},"29":{"start":{"line":76,"column":18},"end":{"line":76,"column":40}},"30":{"start":{"line":79,"column":6},"end":{"line":83,"column":7}},"31":{"start":{"line":80,"column":8},"end":{"line":80,"column":null}},"32":{"start":{"line":82,"column":8},"end":{"line":82,"column":null}},"33":{"start":{"line":85,"column":6},"end":{"line":85,"column":null}},"34":{"start":{"line":86,"column":6},"end":{"line":86,"column":null}},"35":{"start":{"line":87,"column":6},"end":{"line":87,"column":null}},"36":{"start":{"line":91,"column":2},"end":{"line":93,"column":3}},"37":{"start":{"line":92,"column":4},"end":{"line":92,"column":null}},"38":{"start":{"line":95,"column":6},"end":{"line":95,"column":null}},"39":{"start":{"line":97,"column":17},"end":{"line":103,"column":null}},"40":{"start":{"line":97,"column":4},"end":{"line":103,"column":null}},"41":{"start":{"line":105,"column":4},"end":{"line":105,"column":null}},"42":{"start":{"line":106,"column":4},"end":{"line":106,"column":null}},"43":{"start":{"line":113,"column":10},"end":{"line":113,"column":null}},"44":{"start":{"line":114,"column":8},"end":{"line":114,"column":null}},"45":{"start":{"line":121,"column":4},"end":{"line":148,"column":5}},"46":{"start":{"line":122,"column":12},"end":{"line":122,"column":null}},"47":{"start":{"line":125,"column":12},"end":{"line":125,"column":null}},"48":{"start":{"line":126,"column":12},"end":{"line":129,"column":null}},"49":{"start":{"line":130,"column":6},"end":{"line":145,"column":7}},"50":{"start":{"line":133,"column":14},"end":{"line":133,"column":null}},"51":{"start":{"line":134,"column":14},"end":{"line":134,"column":null}},"52":{"start":{"line":137,"column":8},"end":{"line":144,"column":9}},"53":{"start":{"line":138,"column":16},"end":{"line":138,"column":null}},"54":{"start":{"line":139,"column":10},"end":{"line":141,"column":11}},"55":{"start":{"line":140,"column":12},"end":{"line":140,"column":null}},"56":{"start":{"line":143,"column":10},"end":{"line":143,"column":null}},"57":{"start":{"line":149,"column":10},"end":{"line":158,"column":null}},"58":{"start":{"line":159,"column":4},"end":{"line":159,"column":null}},"59":{"start":{"line":162,"column":2},"end":{"line":164,"column":3}},"60":{"start":{"line":163,"column":4},"end":{"line":163,"column":null}},"61":{"start":{"line":165,"column":2},"end":{"line":167,"column":null}},"62":{"start":{"line":169,"column":8},"end":{"line":169,"column":null}},"63":{"start":{"line":170,"column":2},"end":{"line":172,"column":3}},"64":{"start":{"line":171,"column":4},"end":{"line":171,"column":null}},"65":{"start":{"line":173,"column":8},"end":{"line":173,"column":null}},"66":{"start":{"line":176,"column":2},"end":{"line":178,"column":3}},"67":{"start":{"line":177,"column":4},"end":{"line":177,"column":null}},"68":{"start":{"line":181,"column":4},"end":{"line":186,"column":null}},"69":{"start":{"line":188,"column":4},"end":{"line":188,"column":null}},"70":{"start":{"line":192,"column":10},"end":{"line":192,"column":null}},"71":{"start":{"line":193,"column":4},"end":{"line":193,"column":null}},"72":{"start":{"line":196,"column":2},"end":{"line":196,"column":null}},"73":{"start":{"line":198,"column":6},"end":{"line":198,"column":19}},"74":{"start":{"line":199,"column":4},"end":{"line":203,"column":null}},"75":{"start":{"line":205,"column":10},"end":{"line":205,"column":null}},"76":{"start":{"line":206,"column":4},"end":{"line":214,"column":5}},"77":{"start":{"line":206,"column":15},"end":{"line":206,"column":22}},"78":{"start":{"line":207,"column":6},"end":{"line":213,"column":null}},"79":{"start":{"line":215,"column":4},"end":{"line":215,"column":null}},"80":{"start":{"line":218,"column":2},"end":{"line":218,"column":null}},"81":{"start":{"line":220,"column":6},"end":{"line":220,"column":null}},"82":{"start":{"line":222,"column":15},"end":{"line":225,"column":null}},"83":{"start":{"line":222,"column":4},"end":{"line":225,"column":null}},"84":{"start":{"line":227,"column":10},"end":{"line":227,"column":null}},"85":{"start":{"line":228,"column":4},"end":{"line":228,"column":null}},"86":{"start":{"line":229,"column":4},"end":{"line":229,"column":null}},"87":{"start":{"line":231,"column":2},"end":{"line":231,"column":null}},"88":{"start":{"line":232,"column":2},"end":{"line":232,"column":null}},"89":{"start":{"line":242,"column":2},"end":{"line":244,"column":3}},"90":{"start":{"line":243,"column":4},"end":{"line":243,"column":null}},"91":{"start":{"line":245,"column":19},"end":{"line":251,"column":null}},"92":{"start":{"line":253,"column":24},"end":{"line":254,"column":null}},"93":{"start":{"line":254,"column":9},"end":{"line":254,"column":null}},"94":{"start":{"line":256,"column":2},"end":{"line":269,"column":3}},"95":{"start":{"line":257,"column":52},"end":{"line":257,"column":54}},"96":{"start":{"line":258,"column":4},"end":{"line":263,"column":5}},"97":{"start":{"line":259,"column":6},"end":{"line":262,"column":7}},"98":{"start":{"line":259,"column":25},"end":{"line":259,"column":38}},"99":{"start":{"line":259,"column":25},"end":{"line":259,"column":44}},"100":{"start":{"line":259,"column":21},"end":{"line":259,"column":25}},"101":{"start":{"line":260,"column":8},"end":{"line":261,"column":null}},"102":{"start":{"line":265,"column":4},"end":{"line":268,"column":null}},"103":{"start":{"line":271,"column":2},"end":{"line":294,"column":3}},"104":{"start":{"line":273,"column":6},"end":{"line":275,"column":71}},"105":{"start":{"line":275,"column":34},"end":{"line":275,"column":65}},"106":{"start":{"line":277,"column":4},"end":{"line":293,"column":null}},"107":{"start":{"line":278,"column":20},"end":{"line":278,"column":null}},"108":{"start":{"line":280,"column":39},"end":{"line":280,"column":41}},"109":{"start":{"line":281,"column":8},"end":{"line":287,"column":9}},"110":{"start":{"line":282,"column":10},"end":{"line":286,"column":11}},"111":{"start":{"line":282,"column":29},"end":{"line":282,"column":30}},"112":{"start":{"line":282,"column":29},"end":{"line":282,"column":36}},"113":{"start":{"line":282,"column":25},"end":{"line":282,"column":29}},"114":{"start":{"line":283,"column":12},"end":{"line":285,"column":13}},"115":{"start":{"line":284,"column":14},"end":{"line":284,"column":null}},"116":{"start":{"line":289,"column":8},"end":{"line":292,"column":null}},"117":{"start":{"line":296,"column":2},"end":{"line":296,"column":null}},"118":{"start":{"line":302,"column":2},"end":{"line":302,"column":null}},"119":{"start":{"line":305,"column":2},"end":{"line":308,"column":3}},"120":{"start":{"line":306,"column":4},"end":{"line":306,"column":null}},"121":{"start":{"line":307,"column":4},"end":{"line":307,"column":null}},"122":{"start":{"line":310,"column":23},"end":{"line":314,"column":null}},"123":{"start":{"line":315,"column":2},"end":{"line":317,"column":3}},"124":{"start":{"line":316,"column":4},"end":{"line":316,"column":null}},"125":{"start":{"line":319,"column":2},"end":{"line":321,"column":3}},"126":{"start":{"line":320,"column":4},"end":{"line":320,"column":null}},"127":{"start":{"line":323,"column":2},"end":{"line":325,"column":3}},"128":{"start":{"line":324,"column":4},"end":{"line":324,"column":null}},"129":{"start":{"line":327,"column":2},"end":{"line":327,"column":null}},"130":{"start":{"line":328,"column":2},"end":{"line":334,"column":3}},"131":{"start":{"line":328,"column":29},"end":{"line":328,"column":35}},"132":{"start":{"line":328,"column":29},"end":{"line":329,"column":null}},"133":{"start":{"line":328,"column":13},"end":{"line":328,"column":14}},"134":{"start":{"line":328,"column":17},"end":{"line":328,"column":19}},"135":{"start":{"line":328,"column":24},"end":{"line":328,"column":25}},"136":{"start":{"line":331,"column":4},"end":{"line":333,"column":5}},"137":{"start":{"line":332,"column":6},"end":{"line":332,"column":null}},"138":{"start":{"line":336,"column":2},"end":{"line":339,"column":null}},"139":{"start":{"line":341,"column":2},"end":{"line":346,"column":3}},"140":{"start":{"line":342,"column":4},"end":{"line":345,"column":null}},"141":{"start":{"line":348,"column":2},"end":{"line":348,"column":null}},"142":{"start":{"line":350,"column":2},"end":{"line":352,"column":3}},"143":{"start":{"line":351,"column":4},"end":{"line":351,"column":null}},"144":{"start":{"line":354,"column":15},"end":{"line":355,"column":null}},"145":{"start":{"line":355,"column":9},"end":{"line":355,"column":null}},"146":{"start":{"line":358,"column":2},"end":{"line":360,"column":3}},"147":{"start":{"line":359,"column":4},"end":{"line":359,"column":null}},"148":{"start":{"line":362,"column":2},"end":{"line":362,"column":null}}},"fnMap":{"0":{"name":"prepareJob","decl":{"start":{"line":40,"column":22},"end":{"line":40,"column":32}},"loc":{"start":{"line":42,"column":14},"end":{"line":233,"column":null}}},"1":{"name":"(anonymous_25)","decl":{"start":{"line":73,"column":33},"end":{"line":73,"column":40}},"loc":{"start":{"line":73,"column":40},"end":{"line":88,"column":5}}},"2":{"name":"generateResponseFile","decl":{"start":{"line":235,"column":9},"end":{"line":235,"column":29}},"loc":{"start":{"line":240,"column":25},"end":{"line":297,"column":1}}},"3":{"name":"(anonymous_27)","decl":{"start":{"line":254,"column":4},"end":{"line":254,"column":5}},"loc":{"start":{"line":254,"column":5},"end":{"line":254,"column":10}}},"4":{"name":"(anonymous_28)","decl":{"start":{"line":275,"column":29},"end":{"line":275,"column":30}},"loc":{"start":{"line":275,"column":30},"end":{"line":275,"column":55}}},"5":{"name":"(anonymous_29)","decl":{"start":{"line":278,"column":15},"end":{"line":278,"column":16}},"loc":{"start":{"line":278,"column":16},"end":{"line":278,"column":41}}},"6":{"name":"(anonymous_30)","decl":{"start":{"line":279,"column":11},"end":{"line":279,"column":12}},"loc":{"start":{"line":279,"column":12},"end":{"line":293,"column":7}}},"7":{"name":"createContainerSpec","decl":{"start":{"line":299,"column":16},"end":{"line":299,"column":35}},"loc":{"start":{"line":303,"column":35},"end":{"line":363,"column":1}}},"8":{"name":"(anonymous_32)","decl":{"start":{"line":355,"column":4},"end":{"line":355,"column":5}},"loc":{"start":{"line":355,"column":5},"end":{"line":355,"column":10}}}},"branchMap":{"0":{"loc":{"start":{"line":196,"column":2},"end":{"line":196,"column":null}},"type":"switch","locations":[{"start":{"line":196,"column":2},"end":{"line":196,"column":null}}]},"1":{"loc":{"start":{"line":44,"column":2},"end":{"line":46,"column":3}},"type":"if","locations":[{"start":{"line":44,"column":2},"end":{"line":46,"column":3}},{"start":{},"end":{}}]},"2":{"loc":{"start":{"line":53,"column":2},"end":{"line":61,"column":3}},"type":"if","locations":[{"start":{"line":53,"column":2},"end":{"line":61,"column":3}},{"start":{},"end":{}}]},"3":{"loc":{"start":{"line":53,"column":6},"end":{"line":53,"column":27}},"type":"cond-expr","locations":[{"start":{"line":53,"column":20},"end":{"line":53,"column":22}},{"start":{"line":53,"column":20},"end":{"line":53,"column":27}}]},"4":{"loc":{"start":{"line":53,"column":6},"end":{"line":53,"column":22}},"type":"binary-expr","locations":[{"start":{"line":53,"column":6},"end":{"line":53,"column":22}},{"start":{"line":53,"column":20},"end":{"line":53,"column":22}}]},"5":{"loc":{"start":{"line":65,"column":2},"end":{"line":89,"column":3}},"type":"if","locations":[{"start":{"line":65,"column":2},"end":{"line":89,"column":3}},{"start":{},"end":{}}]},"6":{"loc":{"start":{"line":65,"column":6},"end":{"line":65,"column":27}},"type":"cond-expr","locations":[{"start":{"line":65,"column":19},"end":{"line":65,"column":21}},{"start":{"line":65,"column":19},"end":{"line":65,"column":27}}]},"7":{"loc":{"start":{"line":65,"column":6},"end":{"line":65,"column":21}},"type":"binary-expr","locations":[{"start":{"line":65,"column":6},"end":{"line":65,"column":21}},{"start":{"line":65,"column":19},"end":{"line":65,"column":21}}]},"8":{"loc":{"start":{"line":69,"column":29},"end":{"line":69,"column":55}},"type":"binary-expr","locations":[{"start":{"line":69,"column":29},"end":{"line":69,"column":50}},{"start":{"line":69,"column":54},"end":{"line":69,"column":55}}]},"9":{"loc":{"start":{"line":75,"column":20},"end":{"line":75,"column":46}},"type":"binary-expr","locations":[{"start":{"line":75,"column":20},"end":{"line":75,"column":41}},{"start":{"line":75,"column":45},"end":{"line":75,"column":46}}]},"10":{"loc":{"start":{"line":76,"column":18},"end":{"line":76,"column":40}},"type":"binary-expr","locations":[{"start":{"line":76,"column":18},"end":{"line":76,"column":35}},{"start":{"line":76,"column":39},"end":{"line":76,"column":40}}]},"11":{"loc":{"start":{"line":79,"column":6},"end":{"line":83,"column":7}},"type":"if","locations":[{"start":{"line":79,"column":6},"end":{"line":83,"column":7}},{"start":{"line":81,"column":13},"end":{"line":83,"column":7}}]},"12":{"loc":{"start":{"line":91,"column":2},"end":{"line":93,"column":3}},"type":"if","locations":[{"start":{"line":91,"column":2},"end":{"line":93,"column":3}},{"start":{},"end":{}}]},"13":{"loc":{"start":{"line":91,"column":6},"end":{"line":91,"column":39}},"type":"binary-expr","locations":[{"start":{"line":91,"column":6},"end":{"line":91,"column":16}},{"start":{"line":91,"column":20},"end":{"line":91,"column":39}}]},"14":{"loc":{"start":{"line":91,"column":21},"end":{"line":91,"column":37}},"type":"cond-expr","locations":[{"start":{"line":91,"column":29},"end":{"line":91,"column":31}},{"start":{"line":91,"column":21},"end":{"line":91,"column":37}}]},"15":{"loc":{"start":{"line":91,"column":21},"end":{"line":91,"column":31}},"type":"binary-expr","locations":[{"start":{"line":91,"column":21},"end":{"line":91,"column":31}},{"start":{"line":91,"column":21},"end":{"line":91,"column":31}}]},"16":{"loc":{"start":{"line":113,"column":16},"end":{"line":113,"column":64}},"type":"cond-expr","locations":[{"start":{"line":113,"column":39},"end":{"line":113,"column":50}},{"start":{"line":113,"column":53},"end":{"line":113,"column":64}}]},"17":{"loc":{"start":{"line":127,"column":8},"end":{"line":129,"column":38}},"type":"cond-expr","locations":[{"start":{"line":128,"column":12},"end":{"line":128,"column":44}},{"start":{"line":129,"column":12},"end":{"line":129,"column":38}}]},"18":{"loc":{"start":{"line":130,"column":6},"end":{"line":145,"column":7}},"type":"if","locations":[{"start":{"line":130,"column":6},"end":{"line":145,"column":7}},{"start":{},"end":{}}]},"19":{"loc":{"start":{"line":130,"column":10},"end":{"line":130,"column":67}},"type":"binary-expr","locations":[{"start":{"line":130,"column":10},"end":{"line":130,"column":26}},{"start":{"line":130,"column":30},"end":{"line":130,"column":44}},{"start":{"line":130,"column":48},"end":{"line":130,"column":67}}]},"20":{"loc":{"start":{"line":139,"column":10},"end":{"line":141,"column":11}},"type":"if","locations":[{"start":{"line":139,"column":10},"end":{"line":141,"column":11}},{"start":{},"end":{}}]},"21":{"loc":{"start":{"line":139,"column":21},"end":{"line":139,"column":36}},"type":"cond-expr","locations":[{"start":{"line":139,"column":27},"end":{"line":139,"column":29}},{"start":{"line":139,"column":21},"end":{"line":139,"column":36}}]},"22":{"loc":{"start":{"line":139,"column":21},"end":{"line":139,"column":29}},"type":"binary-expr","locations":[{"start":{"line":139,"column":21},"end":{"line":139,"column":29}},{"start":{"line":139,"column":21},"end":{"line":139,"column":29}}]},"23":{"loc":{"start":{"line":162,"column":2},"end":{"line":164,"column":3}},"type":"if","locations":[{"start":{"line":162,"column":2},"end":{"line":164,"column":3}},{"start":{},"end":{}}]},"24":{"loc":{"start":{"line":162,"column":7},"end":{"line":162,"column":33}},"type":"cond-expr","locations":[{"start":{"line":162,"column":27},"end":{"line":162,"column":29}},{"start":{"line":162,"column":27},"end":{"line":162,"column":33}}]},"25":{"loc":{"start":{"line":162,"column":7},"end":{"line":162,"column":29}},"type":"binary-expr","locations":[{"start":{"line":162,"column":7},"end":{"line":162,"column":29}},{"start":{"line":162,"column":27},"end":{"line":162,"column":29}}]},"26":{"loc":{"start":{"line":162,"column":7},"end":{"line":162,"column":27}},"type":"cond-expr","locations":[{"start":{"line":162,"column":17},"end":{"line":162,"column":19}},{"start":{"line":162,"column":7},"end":{"line":162,"column":27}}]},"27":{"loc":{"start":{"line":162,"column":7},"end":{"line":162,"column":19}},"type":"binary-expr","locations":[{"start":{"line":162,"column":7},"end":{"line":162,"column":19}},{"start":{"line":162,"column":7},"end":{"line":162,"column":19}}]},"28":{"loc":{"start":{"line":166,"column":54},"end":{"line":166,"column":80}},"type":"cond-expr","locations":[{"start":{"line":166,"column":74},"end":{"line":166,"column":76}},{"start":{"line":166,"column":74},"end":{"line":166,"column":80}}]},"29":{"loc":{"start":{"line":166,"column":54},"end":{"line":166,"column":76}},"type":"binary-expr","locations":[{"start":{"line":166,"column":54},"end":{"line":166,"column":76}},{"start":{"line":166,"column":74},"end":{"line":166,"column":76}}]},"30":{"loc":{"start":{"line":166,"column":54},"end":{"line":166,"column":74}},"type":"cond-expr","locations":[{"start":{"line":166,"column":64},"end":{"line":166,"column":66}},{"start":{"line":166,"column":54},"end":{"line":166,"column":74}}]},"31":{"loc":{"start":{"line":166,"column":54},"end":{"line":166,"column":66}},"type":"binary-expr","locations":[{"start":{"line":166,"column":54},"end":{"line":166,"column":66}},{"start":{"line":166,"column":54},"end":{"line":166,"column":66}}]},"32":{"loc":{"start":{"line":170,"column":2},"end":{"line":172,"column":3}},"type":"if","locations":[{"start":{"line":170,"column":2},"end":{"line":172,"column":3}},{"start":{},"end":{}}]},"33":{"loc":{"start":{"line":176,"column":2},"end":{"line":178,"column":3}},"type":"if","locations":[{"start":{"line":176,"column":2},"end":{"line":178,"column":3}},{"start":{},"end":{}}]},"34":{"loc":{"start":{"line":176,"column":6},"end":{"line":176,"column":46}},"type":"cond-expr","locations":[{"start":{"line":176,"column":38},"end":{"line":176,"column":40}},{"start":{"line":176,"column":38},"end":{"line":176,"column":46}}]},"35":{"loc":{"start":{"line":176,"column":6},"end":{"line":176,"column":40}},"type":"binary-expr","locations":[{"start":{"line":176,"column":6},"end":{"line":176,"column":40}},{"start":{"line":176,"column":38},"end":{"line":176,"column":40}}]},"36":{"loc":{"start":{"line":176,"column":6},"end":{"line":176,"column":38}},"type":"cond-expr","locations":[{"start":{"line":176,"column":20},"end":{"line":176,"column":22}},{"start":{"line":176,"column":20},"end":{"line":176,"column":38}}]},"37":{"loc":{"start":{"line":176,"column":6},"end":{"line":176,"column":22}},"type":"binary-expr","locations":[{"start":{"line":176,"column":6},"end":{"line":176,"column":22}},{"start":{"line":176,"column":20},"end":{"line":176,"column":22}}]},"38":{"loc":{"start":{"line":177,"column":37},"end":{"line":177,"column":74}},"type":"binary-expr","locations":[{"start":{"line":177,"column":37},"end":{"line":177,"column":68}},{"start":{"line":177,"column":72},"end":{"line":177,"column":74}}]},"39":{"loc":{"start":{"line":192,"column":19},"end":{"line":192,"column":67}},"type":"cond-expr","locations":[{"start":{"line":192,"column":42},"end":{"line":192,"column":53}},{"start":{"line":192,"column":56},"end":{"line":192,"column":67}}]},"40":{"loc":{"start":{"line":198,"column":6},"end":{"line":198,"column":19}},"type":"if","locations":[{"start":{"line":198,"column":6},"end":{"line":198,"column":19}},{"start":{},"end":{}}]},"41":{"loc":{"start":{"line":206,"column":22},"end":{"line":206,"column":61}},"type":"binary-expr","locations":[{"start":{"line":206,"column":22},"end":{"line":206,"column":55}},{"start":{"line":206,"column":59},"end":{"line":206,"column":61}}]},"42":{"loc":{"start":{"line":206,"column":22},"end":{"line":206,"column":55}},"type":"cond-expr","locations":[{"start":{"line":206,"column":37},"end":{"line":206,"column":39}},{"start":{"line":206,"column":37},"end":{"line":206,"column":55}}]},"43":{"loc":{"start":{"line":206,"column":22},"end":{"line":206,"column":39}},"type":"binary-expr","locations":[{"start":{"line":206,"column":22},"end":{"line":206,"column":39}},{"start":{"line":206,"column":37},"end":{"line":206,"column":39}}]},"44":{"loc":{"start":{"line":206,"column":22},"end":{"line":206,"column":37}},"type":"cond-expr","locations":[{"start":{"line":206,"column":26},"end":{"line":206,"column":28}},{"start":{"line":206,"column":22},"end":{"line":206,"column":37}}]},"45":{"loc":{"start":{"line":206,"column":22},"end":{"line":206,"column":28}},"type":"binary-expr","locations":[{"start":{"line":206,"column":22},"end":{"line":206,"column":28}},{"start":{"line":206,"column":22},"end":{"line":206,"column":28}}]},"46":{"loc":{"start":{"line":242,"column":2},"end":{"line":244,"column":3}},"type":"if","locations":[{"start":{"line":242,"column":2},"end":{"line":244,"column":3}},{"start":{},"end":{}}]},"47":{"loc":{"start":{"line":242,"column":7},"end":{"line":242,"column":28}},"type":"cond-expr","locations":[{"start":{"line":242,"column":22},"end":{"line":242,"column":24}},{"start":{"line":242,"column":22},"end":{"line":242,"column":28}}]},"48":{"loc":{"start":{"line":242,"column":7},"end":{"line":242,"column":24}},"type":"binary-expr","locations":[{"start":{"line":242,"column":7},"end":{"line":242,"column":24}},{"start":{"line":242,"column":22},"end":{"line":242,"column":24}}]},"49":{"loc":{"start":{"line":253,"column":24},"end":{"line":254,"column":null}},"type":"cond-expr","locations":[{"start":{"line":253,"column":47},"end":{"line":253,"column":49}},{"start":{"line":253,"column":47},"end":{"line":254,"column":null}}]},"50":{"loc":{"start":{"line":253,"column":24},"end":{"line":253,"column":49}},"type":"binary-expr","locations":[{"start":{"line":253,"column":24},"end":{"line":253,"column":49}},{"start":{"line":253,"column":47},"end":{"line":253,"column":49}}]},"51":{"loc":{"start":{"line":253,"column":24},"end":{"line":253,"column":47}},"type":"cond-expr","locations":[{"start":{"line":253,"column":35},"end":{"line":253,"column":37}},{"start":{"line":253,"column":35},"end":{"line":253,"column":47}}]},"52":{"loc":{"start":{"line":253,"column":24},"end":{"line":253,"column":37}},"type":"binary-expr","locations":[{"start":{"line":253,"column":24},"end":{"line":253,"column":37}},{"start":{"line":253,"column":35},"end":{"line":253,"column":37}}]},"53":{"loc":{"start":{"line":256,"column":2},"end":{"line":269,"column":3}},"type":"if","locations":[{"start":{"line":256,"column":2},"end":{"line":269,"column":3}},{"start":{},"end":{}}]},"54":{"loc":{"start":{"line":258,"column":4},"end":{"line":263,"column":5}},"type":"if","locations":[{"start":{"line":258,"column":4},"end":{"line":263,"column":5}},{"start":{},"end":{}}]},"55":{"loc":{"start":{"line":258,"column":8},"end":{"line":258,"column":28}},"type":"cond-expr","locations":[{"start":{"line":258,"column":21},"end":{"line":258,"column":23}},{"start":{"line":258,"column":8},"end":{"line":258,"column":28}}]},"56":{"loc":{"start":{"line":258,"column":8},"end":{"line":258,"column":23}},"type":"binary-expr","locations":[{"start":{"line":258,"column":8},"end":{"line":258,"column":23}},{"start":{"line":258,"column":8},"end":{"line":258,"column":23}}]},"57":{"loc":{"start":{"line":271,"column":2},"end":{"line":294,"column":3}},"type":"if","locations":[{"start":{"line":271,"column":2},"end":{"line":294,"column":3}},{"start":{},"end":{}}]},"58":{"loc":{"start":{"line":271,"column":6},"end":{"line":271,"column":27}},"type":"cond-expr","locations":[{"start":{"line":271,"column":19},"end":{"line":271,"column":21}},{"start":{"line":271,"column":19},"end":{"line":271,"column":27}}]},"59":{"loc":{"start":{"line":271,"column":6},"end":{"line":271,"column":21}},"type":"binary-expr","locations":[{"start":{"line":271,"column":6},"end":{"line":271,"column":21}},{"start":{"line":271,"column":19},"end":{"line":271,"column":21}}]},"60":{"loc":{"start":{"line":273,"column":6},"end":{"line":275,"column":71}},"type":"cond-expr","locations":[{"start":{"line":274,"column":10},"end":{"line":274,"column":22}},{"start":{"line":275,"column":10},"end":{"line":275,"column":71}}]},"61":{"loc":{"start":{"line":273,"column":6},"end":{"line":273,"column":41}},"type":"binary-expr","locations":[{"start":{"line":273,"column":6},"end":{"line":273,"column":18}},{"start":{"line":273,"column":22},"end":{"line":273,"column":41}}]},"62":{"loc":{"start":{"line":275,"column":10},"end":{"line":275,"column":71}},"type":"binary-expr","locations":[{"start":{"line":275,"column":10},"end":{"line":275,"column":65}},{"start":{"line":275,"column":69},"end":{"line":275,"column":71}}]},"63":{"loc":{"start":{"line":275,"column":10},"end":{"line":275,"column":65}},"type":"cond-expr","locations":[{"start":{"line":275,"column":23},"end":{"line":275,"column":25}},{"start":{"line":275,"column":23},"end":{"line":275,"column":65}}]},"64":{"loc":{"start":{"line":275,"column":10},"end":{"line":275,"column":25}},"type":"binary-expr","locations":[{"start":{"line":275,"column":10},"end":{"line":275,"column":25}},{"start":{"line":275,"column":23},"end":{"line":275,"column":25}}]},"65":{"loc":{"start":{"line":277,"column":35},"end":{"line":293,"column":8}},"type":"cond-expr","locations":[{"start":{"line":277,"column":59},"end":{"line":277,"column":null}},{"start":{"line":277,"column":59},"end":{"line":293,"column":8}}]},"66":{"loc":{"start":{"line":277,"column":35},"end":{"line":277,"column":null}},"type":"binary-expr","locations":[{"start":{"line":277,"column":35},"end":{"line":277,"column":null}},{"start":{"line":277,"column":59},"end":{"line":277,"column":null}}]},"67":{"loc":{"start":{"line":277,"column":35},"end":{"line":277,"column":59}},"type":"cond-expr","locations":[{"start":{"line":277,"column":47},"end":{"line":277,"column":49}},{"start":{"line":277,"column":47},"end":{"line":277,"column":59}}]},"68":{"loc":{"start":{"line":277,"column":35},"end":{"line":277,"column":49}},"type":"binary-expr","locations":[{"start":{"line":277,"column":35},"end":{"line":277,"column":49}},{"start":{"line":277,"column":47},"end":{"line":277,"column":49}}]},"69":{"loc":{"start":{"line":277,"column":35},"end":{"line":277,"column":47}},"type":"cond-expr","locations":[{"start":{"line":277,"column":41},"end":{"line":277,"column":43}},{"start":{"line":277,"column":35},"end":{"line":277,"column":47}}]},"70":{"loc":{"start":{"line":277,"column":35},"end":{"line":277,"column":43}},"type":"binary-expr","locations":[{"start":{"line":277,"column":35},"end":{"line":277,"column":43}},{"start":{"line":277,"column":35},"end":{"line":277,"column":43}}]},"71":{"loc":{"start":{"line":281,"column":8},"end":{"line":287,"column":9}},"type":"if","locations":[{"start":{"line":281,"column":8},"end":{"line":287,"column":9}},{"start":{},"end":{}}]},"72":{"loc":{"start":{"line":281,"column":12},"end":{"line":281,"column":27}},"type":"cond-expr","locations":[{"start":{"line":281,"column":19},"end":{"line":281,"column":21}},{"start":{"line":281,"column":19},"end":{"line":281,"column":27}}]},"73":{"loc":{"start":{"line":281,"column":12},"end":{"line":281,"column":21}},"type":"binary-expr","locations":[{"start":{"line":281,"column":12},"end":{"line":281,"column":21}},{"start":{"line":281,"column":19},"end":{"line":281,"column":21}}]},"74":{"loc":{"start":{"line":283,"column":12},"end":{"line":285,"column":13}},"type":"if","locations":[{"start":{"line":283,"column":12},"end":{"line":285,"column":13}},{"start":{},"end":{}}]},"75":{"loc":{"start":{"line":283,"column":16},"end":{"line":283,"column":51}},"type":"binary-expr","locations":[{"start":{"line":283,"column":16},"end":{"line":283,"column":34}},{"start":{"line":283,"column":38},"end":{"line":283,"column":51}}]},"76":{"loc":{"start":{"line":302,"column":2},"end":{"line":302,"column":null}},"type":"if","locations":[{"start":{"line":302,"column":2},"end":{"line":302,"column":null}},{"start":{},"end":{}}]},"77":{"loc":{"start":{"line":305,"column":2},"end":{"line":308,"column":3}},"type":"if","locations":[{"start":{"line":305,"column":2},"end":{"line":308,"column":3}},{"start":{},"end":{}}]},"78":{"loc":{"start":{"line":305,"column":6},"end":{"line":305,"column":43}},"type":"binary-expr","locations":[{"start":{"line":305,"column":6},"end":{"line":305,"column":27}},{"start":{"line":305,"column":31},"end":{"line":305,"column":43}}]},"79":{"loc":{"start":{"line":315,"column":2},"end":{"line":317,"column":3}},"type":"if","locations":[{"start":{"line":315,"column":2},"end":{"line":317,"column":3}},{"start":{},"end":{}}]},"80":{"loc":{"start":{"line":319,"column":2},"end":{"line":321,"column":3}},"type":"if","locations":[{"start":{"line":319,"column":2},"end":{"line":321,"column":3}},{"start":{},"end":{}}]},"81":{"loc":{"start":{"line":323,"column":2},"end":{"line":325,"column":3}},"type":"if","locations":[{"start":{"line":323,"column":2},"end":{"line":325,"column":3}},{"start":{},"end":{}}]},"82":{"loc":{"start":{"line":323,"column":6},"end":{"line":323,"column":69}},"type":"binary-expr","locations":[{"start":{"line":323,"column":6},"end":{"line":323,"column":30}},{"start":{"line":323,"column":34},"end":{"line":323,"column":69}}]},"83":{"loc":{"start":{"line":329,"column":4},"end":{"line":329,"column":43}},"type":"binary-expr","locations":[{"start":{"line":329,"column":4},"end":{"line":329,"column":37}},{"start":{"line":329,"column":41},"end":{"line":329,"column":43}}]},"84":{"loc":{"start":{"line":331,"column":4},"end":{"line":333,"column":5}},"type":"if","locations":[{"start":{"line":331,"column":4},"end":{"line":333,"column":5}},{"start":{},"end":{}}]},"85":{"loc":{"start":{"line":331,"column":8},"end":{"line":331,"column":31}},"type":"binary-expr","locations":[{"start":{"line":331,"column":8},"end":{"line":331,"column":13}},{"start":{"line":331,"column":17},"end":{"line":331,"column":31}}]},"86":{"loc":{"start":{"line":341,"column":2},"end":{"line":346,"column":3}},"type":"if","locations":[{"start":{"line":341,"column":2},"end":{"line":346,"column":3}},{"start":{},"end":{}}]},"87":{"loc":{"start":{"line":341,"column":17},"end":{"line":341,"column":56}},"type":"binary-expr","locations":[{"start":{"line":341,"column":17},"end":{"line":341,"column":50}},{"start":{"line":341,"column":54},"end":{"line":341,"column":56}}]},"88":{"loc":{"start":{"line":350,"column":2},"end":{"line":352,"column":3}},"type":"if","locations":[{"start":{"line":350,"column":2},"end":{"line":352,"column":3}},{"start":{},"end":{}}]},"89":{"loc":{"start":{"line":354,"column":15},"end":{"line":355,"column":null}},"type":"cond-expr","locations":[{"start":{"line":354,"column":41},"end":{"line":354,"column":43}},{"start":{"line":354,"column":41},"end":{"line":355,"column":null}}]},"90":{"loc":{"start":{"line":354,"column":15},"end":{"line":354,"column":43}},"type":"binary-expr","locations":[{"start":{"line":354,"column":15},"end":{"line":354,"column":43}},{"start":{"line":354,"column":41},"end":{"line":354,"column":43}}]},"91":{"loc":{"start":{"line":354,"column":15},"end":{"line":354,"column":41}},"type":"cond-expr","locations":[{"start":{"line":354,"column":29},"end":{"line":354,"column":31}},{"start":{"line":354,"column":29},"end":{"line":354,"column":41}}]},"92":{"loc":{"start":{"line":354,"column":15},"end":{"line":354,"column":31}},"type":"binary-expr","locations":[{"start":{"line":354,"column":15},"end":{"line":354,"column":31}},{"start":{"line":354,"column":29},"end":{"line":354,"column":31}}]},"93":{"loc":{"start":{"line":358,"column":2},"end":{"line":360,"column":3}},"type":"if","locations":[{"start":{"line":358,"column":2},"end":{"line":360,"column":3}},{"start":{},"end":{}}]}},"s":{"0":8,"1":8,"2":8,"3":8,"4":8,"5":8,"6":8,"7":8,"8":8,"9":10,"10":1,"11":18,"12":9,"13":9,"14":9,"15":8,"16":8,"17":9,"18":9,"19":9,"20":1,"21":1,"22":2,"23":2,"24":2,"25":1,"26":1,"27":2,"28":2,"29":2,"30":2,"31":2,"32":0,"33":2,"34":2,"35":2,"36":9,"37":1,"38":8,"39":8,"40":8,"41":4,"42":2,"43":2,"44":2,"45":2,"46":2,"47":2,"48":2,"49":2,"50":1,"51":1,"52":1,"53":1,"54":1,"55":1,"56":0,"57":2,"58":2,"59":6,"60":0,"61":6,"62":6,"63":6,"64":1,"65":5,"66":5,"67":0,"68":10,"69":2,"70":1,"71":1,"72":8,"73":8,"74":0,"75":0,"76":0,"77":0,"78":0,"79":0,"80":4,"81":4,"82":4,"83":4,"84":1,"85":1,"86":1,"87":3,"88":3,"89":3,"90":0,"91":3,"92":3,"93":1,"94":3,"95":1,"96":1,"97":1,"98":1,"99":1,"100":0,"101":0,"102":1,"103":3,"104":1,"105":0,"106":1,"107":3,"108":2,"109":2,"110":0,"111":0,"112":0,"113":0,"114":0,"115":0,"116":2,"117":3,"118":29,"119":21,"120":1,"121":1,"122":21,"123":21,"124":1,"125":21,"126":18,"127":21,"128":10,"129":21,"130":21,"131":21,"132":21,"133":3,"134":3,"135":3,"136":3,"137":2,"138":21,"139":21,"140":20,"141":21,"142":21,"143":20,"144":1,"145":1,"146":1,"147":1,"148":1},"f":{"0":10,"1":2,"2":3,"3":1,"4":0,"5":3,"6":2,"7":21,"8":1},"b":{"0":[4],"1":[1,9],"2":[8,1],"3":[0,9],"4":[9,9],"5":[1,8],"6":[0,9],"7":[9,9],"8":[2,1],"9":[2,0],"10":[2,1],"11":[2,0],"12":[1,8],"13":[9,1],"14":[0,1],"15":[1,1],"16":[2,0],"17":[1,1],"18":[1,1],"19":[2,1,1],"20":[1,0],"21":[0,1],"22":[1,1],"23":[0,6],"24":[0,6],"25":[6,6],"26":[0,6],"27":[6,6],"28":[0,6],"29":[6,6],"30":[0,6],"31":[6,6],"32":[1,5],"33":[0,5],"34":[0,5],"35":[5,5],"36":[0,5],"37":[5,5],"38":[0,0],"39":[1,0],"40":[4,0],"41":[0,0],"42":[0,0],"43":[0,0],"44":[0,0],"45":[0,0],"46":[0,3],"47":[0,3],"48":[3,3],"49":[2,1],"50":[3,3],"51":[2,1],"52":[3,3],"53":[1,2],"54":[1,0],"55":[0,1],"56":[1,1],"57":[1,2],"58":[0,3],"59":[3,3],"60":[1,0],"61":[1,1],"62":[0,0],"63":[0,0],"64":[0,0],"65":[0,1],"66":[1,1],"67":[0,1],"68":[1,1],"69":[0,1],"70":[1,1],"71":[0,2],"72":[0,2],"73":[2,2],"74":[0,0],"75":[0,0],"76":[8,13],"77":[1,20],"78":[21,4],"79":[1,20],"80":[18,3],"81":[10,11],"82":[21,10],"83":[21,9],"84":[2,1],"85":[3,3],"86":[20,1],"87":[21,9],"88":[20,1],"89":[0,1],"90":[1,1],"91":[0,1],"92":[1,1],"93":[1,0]}} +,"/__w/backlog/backlog/work/runner-container-hooks/packages/k8s/src/hooks/run-container-step.ts": {"path":"/__w/backlog/backlog/work/runner-container-hooks/packages/k8s/src/hooks/run-container-step.ts","statementMap":{"0":{"start":{"line":36,"column":0},"end":{"line":36,"column":22}},"1":{"start":{"line":1,"column":0},"end":{"line":1,"column":37}},"2":{"start":{"line":2,"column":0},"end":{"line":2,"column":24}},"3":{"start":{"line":3,"column":0},"end":{"line":3,"column":46}},"4":{"start":{"line":5,"column":0},"end":{"line":5,"column":30}},"5":{"start":{"line":6,"column":0},"end":{"line":6,"column":null}},"6":{"start":{"line":19,"column":0},"end":{"line":19,"column":null}},"7":{"start":{"line":28,"column":0},"end":{"line":28,"column":null}},"8":{"start":{"line":34,"column":0},"end":{"line":34,"column":64}},"9":{"start":{"line":39,"column":2},"end":{"line":41,"column":3}},"10":{"start":{"line":40,"column":4},"end":{"line":40,"column":null}},"11":{"start":{"line":43,"column":2},"end":{"line":47,"column":3}},"12":{"start":{"line":44,"column":4},"end":{"line":46,"column":null}},"13":{"start":{"line":49,"column":8},"end":{"line":49,"column":null}},"14":{"start":{"line":50,"column":2},"end":{"line":50,"column":null}},"15":{"start":{"line":51,"column":2},"end":{"line":53,"column":3}},"16":{"start":{"line":52,"column":4},"end":{"line":52,"column":null}},"17":{"start":{"line":55,"column":8},"end":{"line":55,"column":null}},"18":{"start":{"line":57,"column":8},"end":{"line":57,"column":null}},"19":{"start":{"line":58,"column":2},"end":{"line":58,"column":null}},"20":{"start":{"line":62,"column":10},"end":{"line":62,"column":null}},"21":{"start":{"line":62,"column":4},"end":{"line":62,"column":null}},"22":{"start":{"line":64,"column":10},"end":{"line":64,"column":null}},"23":{"start":{"line":65,"column":4},"end":{"line":65,"column":null}},"24":{"start":{"line":66,"column":4},"end":{"line":66,"column":null}},"25":{"start":{"line":69,"column":2},"end":{"line":75,"column":3}},"26":{"start":{"line":70,"column":4},"end":{"line":74,"column":null}},"27":{"start":{"line":76,"column":8},"end":{"line":76,"column":null}},"28":{"start":{"line":79,"column":4},"end":{"line":84,"column":null}},"29":{"start":{"line":86,"column":10},"end":{"line":86,"column":null}},"30":{"start":{"line":87,"column":10},"end":{"line":87,"column":null}},"31":{"start":{"line":88,"column":4},"end":{"line":92,"column":5}},"32":{"start":{"line":89,"column":6},"end":{"line":91,"column":null}},"33":{"start":{"line":93,"column":10},"end":{"line":93,"column":null}},"34":{"start":{"line":94,"column":10},"end":{"line":94,"column":null}},"35":{"start":{"line":95,"column":10},"end":{"line":95,"column":null}},"36":{"start":{"line":96,"column":4},"end":{"line":98,"column":5}},"37":{"start":{"line":97,"column":6},"end":{"line":97,"column":null}},"38":{"start":{"line":99,"column":10},"end":{"line":99,"column":null}},"39":{"start":{"line":101,"column":4},"end":{"line":103,"column":null}},"40":{"start":{"line":104,"column":4},"end":{"line":104,"column":null}},"41":{"start":{"line":106,"column":10},"end":{"line":106,"column":42}},"42":{"start":{"line":114,"column":4},"end":{"line":114,"column":null}},"43":{"start":{"line":116,"column":4},"end":{"line":116,"column":null}},"44":{"start":{"line":119,"column":6},"end":{"line":119,"column":null}},"45":{"start":{"line":120,"column":31},"end":{"line":124,"column":null}},"46":{"start":{"line":120,"column":12},"end":{"line":120,"column":31}},"47":{"start":{"line":125,"column":6},"end":{"line":127,"column":7}},"48":{"start":{"line":126,"column":8},"end":{"line":126,"column":null}},"49":{"start":{"line":132,"column":29},"end":{"line":136,"column":null}},"50":{"start":{"line":132,"column":12},"end":{"line":136,"column":null}},"51":{"start":{"line":137,"column":6},"end":{"line":137,"column":null}},"52":{"start":{"line":139,"column":6},"end":{"line":139,"column":null}},"53":{"start":{"line":141,"column":6},"end":{"line":147,"column":7}},"54":{"start":{"line":146,"column":8},"end":{"line":146,"column":null}},"55":{"start":{"line":148,"column":12},"end":{"line":148,"column":null}},"56":{"start":{"line":149,"column":6},"end":{"line":149,"column":null}},"57":{"start":{"line":151,"column":6},"end":{"line":151,"column":null}},"58":{"start":{"line":155,"column":23},"end":{"line":155,"column":null}},"59":{"start":{"line":155,"column":12},"end":{"line":155,"column":null}},"60":{"start":{"line":156,"column":12},"end":{"line":156,"column":null}},"61":{"start":{"line":157,"column":10},"end":{"line":157,"column":26}},"62":{"start":{"line":158,"column":24},"end":{"line":158,"column":null}},"63":{"start":{"line":158,"column":14},"end":{"line":158,"column":null}},"64":{"start":{"line":159,"column":8},"end":{"line":161,"column":null}},"65":{"start":{"line":166,"column":4},"end":{"line":166,"column":null}},"66":{"start":{"line":167,"column":4},"end":{"line":167,"column":null}},"67":{"start":{"line":169,"column":4},"end":{"line":171,"column":null}},"68":{"start":{"line":170,"column":6},"end":{"line":170,"column":null}},"69":{"start":{"line":186,"column":8},"end":{"line":186,"column":null}},"70":{"start":{"line":187,"column":8},"end":{"line":187,"column":null}},"71":{"start":{"line":188,"column":8},"end":{"line":188,"column":null}},"72":{"start":{"line":191,"column":16},"end":{"line":191,"column":null}},"73":{"start":{"line":191,"column":10},"end":{"line":191,"column":null}},"74":{"start":{"line":192,"column":10},"end":{"line":194,"column":null}},"75":{"start":{"line":193,"column":11},"end":{"line":193,"column":null}},"76":{"start":{"line":195,"column":10},"end":{"line":195,"column":null}},"77":{"start":{"line":196,"column":4},"end":{"line":220,"column":5}},"78":{"start":{"line":197,"column":12},"end":{"line":197,"column":null}},"79":{"start":{"line":198,"column":12},"end":{"line":202,"column":null}},"80":{"start":{"line":203,"column":6},"end":{"line":216,"column":7}},"81":{"start":{"line":204,"column":14},"end":{"line":204,"column":null}},"82":{"start":{"line":205,"column":14},"end":{"line":205,"column":null}},"83":{"start":{"line":206,"column":8},"end":{"line":208,"column":null}},"84":{"start":{"line":210,"column":8},"end":{"line":212,"column":null}},"85":{"start":{"line":213,"column":8},"end":{"line":215,"column":null}},"86":{"start":{"line":219,"column":6},"end":{"line":219,"column":null}},"87":{"start":{"line":221,"column":4},"end":{"line":225,"column":5}},"88":{"start":{"line":222,"column":6},"end":{"line":224,"column":null}},"89":{"start":{"line":228,"column":4},"end":{"line":228,"column":null}},"90":{"start":{"line":231,"column":2},"end":{"line":237,"column":3}},"91":{"start":{"line":232,"column":10},"end":{"line":235,"column":null}},"92":{"start":{"line":234,"column":16},"end":{"line":234,"column":25}},"93":{"start":{"line":236,"column":4},"end":{"line":236,"column":null}},"94":{"start":{"line":239,"column":6},"end":{"line":239,"column":null}},"95":{"start":{"line":240,"column":2},"end":{"line":242,"column":3}},"96":{"start":{"line":241,"column":4},"end":{"line":241,"column":null}},"97":{"start":{"line":243,"column":2},"end":{"line":243,"column":null}},"98":{"start":{"line":250,"column":23},"end":{"line":250,"column":44}},"99":{"start":{"line":251,"column":2},"end":{"line":251,"column":null}},"100":{"start":{"line":252,"column":2},"end":{"line":252,"column":null}},"101":{"start":{"line":253,"column":2},"end":{"line":253,"column":null}},"102":{"start":{"line":254,"column":2},"end":{"line":254,"column":null}},"103":{"start":{"line":255,"column":2},"end":{"line":255,"column":null}},"104":{"start":{"line":257,"column":2},"end":{"line":257,"column":null}},"105":{"start":{"line":259,"column":2},"end":{"line":261,"column":3}},"106":{"start":{"line":260,"column":4},"end":{"line":260,"column":null}},"107":{"start":{"line":263,"column":15},"end":{"line":264,"column":null}},"108":{"start":{"line":264,"column":9},"end":{"line":264,"column":null}},"109":{"start":{"line":266,"column":2},"end":{"line":268,"column":3}},"110":{"start":{"line":267,"column":4},"end":{"line":267,"column":null}},"111":{"start":{"line":270,"column":2},"end":{"line":270,"column":null}}},"fnMap":{"0":{"name":"runContainerStep","decl":{"start":{"line":36,"column":22},"end":{"line":36,"column":38}},"loc":{"start":{"line":37,"column":37},"end":{"line":173,"column":null}}},"1":{"name":"(anonymous_25)","decl":{"start":{"line":169,"column":35},"end":{"line":169,"column":38}},"loc":{"start":{"line":169,"column":38},"end":{"line":171,"column":5}}},"2":{"name":"classifyScriptError","decl":{"start":{"line":181,"column":15},"end":{"line":181,"column":34}},"loc":{"start":{"line":184,"column":20},"end":{"line":244,"column":null}}},"3":{"name":"(anonymous_29)","decl":{"start":{"line":193,"column":6},"end":{"line":193,"column":7}},"loc":{"start":{"line":193,"column":7},"end":{"line":193,"column":12}}},"4":{"name":"(anonymous_30)","decl":{"start":{"line":234,"column":11},"end":{"line":234,"column":12}},"loc":{"start":{"line":234,"column":12},"end":{"line":234,"column":21}}},"5":{"name":"createContainerSpec","decl":{"start":{"line":246,"column":9},"end":{"line":246,"column":28}},"loc":{"start":{"line":248,"column":35},"end":{"line":271,"column":1}}},"6":{"name":"(anonymous_32)","decl":{"start":{"line":264,"column":4},"end":{"line":264,"column":5}},"loc":{"start":{"line":264,"column":5},"end":{"line":264,"column":10}}}},"branchMap":{"0":{"loc":{"start":{"line":169,"column":4},"end":{"line":171,"column":null}},"type":"switch","locations":[{"start":{"line":169,"column":4},"end":{"line":171,"column":null}}]},"1":{"loc":{"start":{"line":39,"column":2},"end":{"line":41,"column":3}},"type":"if","locations":[{"start":{"line":39,"column":2},"end":{"line":41,"column":3}},{"start":{},"end":{}}]},"2":{"loc":{"start":{"line":43,"column":2},"end":{"line":47,"column":3}},"type":"if","locations":[{"start":{"line":43,"column":2},"end":{"line":47,"column":3}},{"start":{},"end":{}}]},"3":{"loc":{"start":{"line":49,"column":15},"end":{"line":49,"column":55}},"type":"binary-expr","locations":[{"start":{"line":49,"column":15},"end":{"line":49,"column":49}},{"start":{"line":49,"column":53},"end":{"line":49,"column":55}}]},"4":{"loc":{"start":{"line":51,"column":2},"end":{"line":53,"column":3}},"type":"if","locations":[{"start":{"line":51,"column":2},"end":{"line":53,"column":3}},{"start":{},"end":{}}]},"5":{"loc":{"start":{"line":69,"column":2},"end":{"line":75,"column":3}},"type":"if","locations":[{"start":{"line":69,"column":2},"end":{"line":75,"column":3}},{"start":{},"end":{}}]},"6":{"loc":{"start":{"line":69,"column":7},"end":{"line":69,"column":25}},"type":"cond-expr","locations":[{"start":{"line":69,"column":19},"end":{"line":69,"column":21}},{"start":{"line":69,"column":19},"end":{"line":69,"column":25}}]},"7":{"loc":{"start":{"line":69,"column":7},"end":{"line":69,"column":21}},"type":"binary-expr","locations":[{"start":{"line":69,"column":7},"end":{"line":69,"column":21}},{"start":{"line":69,"column":19},"end":{"line":69,"column":21}}]},"8":{"loc":{"start":{"line":88,"column":4},"end":{"line":92,"column":5}},"type":"if","locations":[{"start":{"line":88,"column":4},"end":{"line":92,"column":5}},{"start":{},"end":{}}]},"9":{"loc":{"start":{"line":88,"column":8},"end":{"line":88,"column":50}},"type":"binary-expr","locations":[{"start":{"line":88,"column":8},"end":{"line":88,"column":27}},{"start":{"line":88,"column":31},"end":{"line":88,"column":50}}]},"10":{"loc":{"start":{"line":96,"column":4},"end":{"line":98,"column":5}},"type":"if","locations":[{"start":{"line":96,"column":4},"end":{"line":98,"column":5}},{"start":{},"end":{}}]},"11":{"loc":{"start":{"line":125,"column":6},"end":{"line":127,"column":7}},"type":"if","locations":[{"start":{"line":125,"column":6},"end":{"line":127,"column":7}},{"start":{},"end":{}}]},"12":{"loc":{"start":{"line":141,"column":6},"end":{"line":147,"column":7}},"type":"if","locations":[{"start":{"line":141,"column":6},"end":{"line":147,"column":7}},{"start":{},"end":{}}]},"13":{"loc":{"start":{"line":142,"column":8},"end":{"line":144,"column":62}},"type":"binary-expr","locations":[{"start":{"line":142,"column":8},"end":{"line":142,"column":28}},{"start":{"line":143,"column":9},"end":{"line":143,"column":47}},{"start":{"line":144,"column":10},"end":{"line":144,"column":61}}]},"14":{"loc":{"start":{"line":157,"column":10},"end":{"line":157,"column":26}},"type":"if","locations":[{"start":{"line":157,"column":10},"end":{"line":157,"column":26}},{"start":{},"end":{}}]},"15":{"loc":{"start":{"line":192,"column":15},"end":{"line":193,"column":null}},"type":"cond-expr","locations":[{"start":{"line":192,"column":44},"end":{"line":192,"column":46}},{"start":{"line":192,"column":44},"end":{"line":193,"column":null}}]},"16":{"loc":{"start":{"line":192,"column":15},"end":{"line":192,"column":46}},"type":"binary-expr","locations":[{"start":{"line":192,"column":15},"end":{"line":192,"column":46}},{"start":{"line":192,"column":44},"end":{"line":192,"column":46}}]},"17":{"loc":{"start":{"line":192,"column":15},"end":{"line":192,"column":44}},"type":"cond-expr","locations":[{"start":{"line":192,"column":25},"end":{"line":192,"column":27}},{"start":{"line":192,"column":25},"end":{"line":192,"column":44}}]},"18":{"loc":{"start":{"line":192,"column":15},"end":{"line":192,"column":27}},"type":"binary-expr","locations":[{"start":{"line":192,"column":15},"end":{"line":192,"column":27}},{"start":{"line":192,"column":25},"end":{"line":192,"column":27}}]},"19":{"loc":{"start":{"line":195,"column":17},"end":{"line":195,"column":38}},"type":"cond-expr","locations":[{"start":{"line":195,"column":26},"end":{"line":195,"column":28}},{"start":{"line":195,"column":26},"end":{"line":195,"column":38}}]},"20":{"loc":{"start":{"line":195,"column":17},"end":{"line":195,"column":28}},"type":"binary-expr","locations":[{"start":{"line":195,"column":17},"end":{"line":195,"column":28}},{"start":{"line":195,"column":26},"end":{"line":195,"column":28}}]},"21":{"loc":{"start":{"line":195,"column":17},"end":{"line":195,"column":26}},"type":"cond-expr","locations":[{"start":{"line":195,"column":19},"end":{"line":195,"column":21}},{"start":{"line":195,"column":17},"end":{"line":195,"column":26}}]},"22":{"loc":{"start":{"line":195,"column":17},"end":{"line":195,"column":21}},"type":"binary-expr","locations":[{"start":{"line":195,"column":17},"end":{"line":195,"column":21}},{"start":{"line":195,"column":17},"end":{"line":195,"column":21}}]},"23":{"loc":{"start":{"line":196,"column":4},"end":{"line":220,"column":5}},"type":"if","locations":[{"start":{"line":196,"column":4},"end":{"line":220,"column":5}},{"start":{"line":217,"column":11},"end":{"line":220,"column":5}}]},"24":{"loc":{"start":{"line":197,"column":21},"end":{"line":197,"column":47}},"type":"cond-expr","locations":[{"start":{"line":197,"column":32},"end":{"line":197,"column":36}},{"start":{"line":197,"column":36},"end":{"line":197,"column":47}}]},"25":{"loc":{"start":{"line":197,"column":21},"end":{"line":197,"column":36}},"type":"binary-expr","locations":[{"start":{"line":197,"column":21},"end":{"line":197,"column":36}},{"start":{"line":197,"column":32},"end":{"line":197,"column":36}}]},"26":{"loc":{"start":{"line":199,"column":8},"end":{"line":202,"column":57}},"type":"binary-expr","locations":[{"start":{"line":199,"column":8},"end":{"line":199,"column":30}},{"start":{"line":200,"column":8},"end":{"line":200,"column":26}},{"start":{"line":201,"column":8},"end":{"line":201,"column":45}},{"start":{"line":202,"column":9},"end":{"line":202,"column":30}},{"start":{"line":202,"column":34},"end":{"line":202,"column":56}}]},"27":{"loc":{"start":{"line":203,"column":6},"end":{"line":216,"column":7}},"type":"if","locations":[{"start":{"line":203,"column":6},"end":{"line":216,"column":7}},{"start":{"line":209,"column":13},"end":{"line":216,"column":7}}]},"28":{"loc":{"start":{"line":204,"column":23},"end":{"line":204,"column":66}},"type":"cond-expr","locations":[{"start":{"line":204,"column":38},"end":{"line":204,"column":61}},{"start":{"line":204,"column":64},"end":{"line":204,"column":66}}]},"29":{"loc":{"start":{"line":221,"column":4},"end":{"line":225,"column":5}},"type":"if","locations":[{"start":{"line":221,"column":4},"end":{"line":225,"column":5}},{"start":{},"end":{}}]},"30":{"loc":{"start":{"line":221,"column":8},"end":{"line":221,"column":26}},"type":"cond-expr","locations":[{"start":{"line":221,"column":17},"end":{"line":221,"column":19}},{"start":{"line":221,"column":17},"end":{"line":221,"column":26}}]},"31":{"loc":{"start":{"line":221,"column":8},"end":{"line":221,"column":19}},"type":"binary-expr","locations":[{"start":{"line":221,"column":8},"end":{"line":221,"column":19}},{"start":{"line":221,"column":17},"end":{"line":221,"column":19}}]},"32":{"loc":{"start":{"line":221,"column":8},"end":{"line":221,"column":17}},"type":"cond-expr","locations":[{"start":{"line":221,"column":10},"end":{"line":221,"column":12}},{"start":{"line":221,"column":8},"end":{"line":221,"column":17}}]},"33":{"loc":{"start":{"line":221,"column":8},"end":{"line":221,"column":12}},"type":"binary-expr","locations":[{"start":{"line":221,"column":8},"end":{"line":221,"column":12}},{"start":{"line":221,"column":8},"end":{"line":221,"column":12}}]},"34":{"loc":{"start":{"line":223,"column":58},"end":{"line":223,"column":94}},"type":"cond-expr","locations":[{"start":{"line":223,"column":81},"end":{"line":223,"column":85}},{"start":{"line":223,"column":85},"end":{"line":223,"column":94}}]},"35":{"loc":{"start":{"line":223,"column":58},"end":{"line":223,"column":85}},"type":"binary-expr","locations":[{"start":{"line":223,"column":58},"end":{"line":223,"column":85}},{"start":{"line":223,"column":81},"end":{"line":223,"column":85}}]},"36":{"loc":{"start":{"line":231,"column":2},"end":{"line":237,"column":3}},"type":"if","locations":[{"start":{"line":231,"column":2},"end":{"line":237,"column":3}},{"start":{},"end":{}}]},"37":{"loc":{"start":{"line":240,"column":2},"end":{"line":242,"column":3}},"type":"if","locations":[{"start":{"line":240,"column":2},"end":{"line":242,"column":3}},{"start":{},"end":{}}]},"38":{"loc":{"start":{"line":259,"column":2},"end":{"line":261,"column":3}},"type":"if","locations":[{"start":{"line":259,"column":2},"end":{"line":261,"column":3}},{"start":{},"end":{}}]},"39":{"loc":{"start":{"line":263,"column":15},"end":{"line":264,"column":null}},"type":"cond-expr","locations":[{"start":{"line":263,"column":41},"end":{"line":263,"column":43}},{"start":{"line":263,"column":41},"end":{"line":264,"column":null}}]},"40":{"loc":{"start":{"line":263,"column":15},"end":{"line":263,"column":43}},"type":"binary-expr","locations":[{"start":{"line":263,"column":15},"end":{"line":263,"column":43}},{"start":{"line":263,"column":41},"end":{"line":263,"column":43}}]},"41":{"loc":{"start":{"line":263,"column":15},"end":{"line":263,"column":41}},"type":"cond-expr","locations":[{"start":{"line":263,"column":29},"end":{"line":263,"column":31}},{"start":{"line":263,"column":29},"end":{"line":263,"column":41}}]},"42":{"loc":{"start":{"line":263,"column":15},"end":{"line":263,"column":31}},"type":"binary-expr","locations":[{"start":{"line":263,"column":15},"end":{"line":263,"column":31}},{"start":{"line":263,"column":29},"end":{"line":263,"column":31}}]},"43":{"loc":{"start":{"line":266,"column":2},"end":{"line":268,"column":3}},"type":"if","locations":[{"start":{"line":266,"column":2},"end":{"line":268,"column":3}},{"start":{},"end":{}}]}},"s":{"0":8,"1":8,"2":8,"3":8,"4":8,"5":8,"6":8,"7":8,"8":8,"9":16,"10":1,"11":15,"12":1,"13":14,"14":14,"15":14,"16":13,"17":14,"18":14,"19":14,"20":14,"21":0,"22":14,"23":14,"24":14,"25":0,"26":0,"27":0,"28":0,"29":0,"30":0,"31":0,"32":0,"33":0,"34":0,"35":0,"36":0,"37":0,"38":0,"39":0,"40":0,"41":0,"42":0,"43":0,"44":0,"45":0,"46":0,"47":0,"48":0,"49":0,"50":0,"51":0,"52":0,"53":0,"54":0,"55":0,"56":0,"57":0,"58":0,"59":0,"60":0,"61":0,"62":0,"63":0,"64":0,"65":0,"66":0,"67":0,"68":0,"69":0,"70":0,"71":0,"72":0,"73":0,"74":0,"75":0,"76":0,"77":0,"78":0,"79":0,"80":0,"81":0,"82":0,"83":0,"84":0,"85":0,"86":0,"87":0,"88":0,"89":0,"90":0,"91":0,"92":0,"93":0,"94":0,"95":0,"96":0,"97":0,"98":14,"99":14,"100":14,"101":14,"102":14,"103":14,"104":14,"105":14,"106":14,"107":0,"108":0,"109":0,"110":0,"111":0},"f":{"0":16,"1":0,"2":0,"3":0,"4":0,"5":14,"6":0},"b":{"0":[0],"1":[1,15],"2":[1,14],"3":[14,5],"4":[13,1],"5":[0,0],"6":[0,0],"7":[0,0],"8":[0,0],"9":[0,0],"10":[0,0],"11":[0,0],"12":[0,0],"13":[0,0,0],"14":[0,0],"15":[0,0],"16":[0,0],"17":[0,0],"18":[0,0],"19":[0,0],"20":[0,0],"21":[0,0],"22":[0,0],"23":[0,0],"24":[0,0],"25":[0,0],"26":[0,0,0,0,0],"27":[0,0],"28":[0,0],"29":[0,0],"30":[0,0],"31":[0,0],"32":[0,0],"33":[0,0],"34":[0,0],"35":[0,0],"36":[0,0],"37":[0,0],"38":[14,0],"39":[0,0],"40":[0,0],"41":[0,0],"42":[0,0],"43":[0,0]}} +,"/__w/backlog/backlog/work/runner-container-hooks/packages/k8s/src/hooks/run-script-step.ts": {"path":"/__w/backlog/backlog/work/runner-container-hooks/packages/k8s/src/hooks/run-script-step.ts","statementMap":{"0":{"start":{"line":35,"column":0},"end":{"line":35,"column":22}},"1":{"start":{"line":2,"column":0},"end":{"line":2,"column":24}},"2":{"start":{"line":3,"column":0},"end":{"line":3,"column":37}},"3":{"start":{"line":5,"column":0},"end":{"line":5,"column":null}},"4":{"start":{"line":11,"column":0},"end":{"line":11,"column":58}},"5":{"start":{"line":12,"column":0},"end":{"line":12,"column":48}},"6":{"start":{"line":13,"column":0},"end":{"line":13,"column":30}},"7":{"start":{"line":17,"column":14},"end":{"line":17,"column":28}},"8":{"start":{"line":18,"column":17},"end":{"line":21,"column":null}},"9":{"start":{"line":22,"column":29},"end":{"line":22,"column":31}},"10":{"start":{"line":23,"column":2},"end":{"line":29,"column":3}},"11":{"start":{"line":24,"column":24},"end":{"line":27,"column":17}},"12":{"start":{"line":26,"column":16},"end":{"line":26,"column":25}},"13":{"start":{"line":28,"column":4},"end":{"line":28,"column":null}},"14":{"start":{"line":30,"column":15},"end":{"line":30,"column":65}},"15":{"start":{"line":31,"column":2},"end":{"line":31,"column":null}},"16":{"start":{"line":31,"column":23},"end":{"line":31,"column":null}},"17":{"start":{"line":32,"column":2},"end":{"line":32,"column":null}},"18":{"start":{"line":40,"column":2},"end":{"line":44,"column":3}},"19":{"start":{"line":41,"column":4},"end":{"line":43,"column":null}},"20":{"start":{"line":47,"column":10},"end":{"line":47,"column":63}},"21":{"start":{"line":48,"column":8},"end":{"line":48,"column":40}},"22":{"start":{"line":56,"column":8},"end":{"line":56,"column":null}},"23":{"start":{"line":57,"column":8},"end":{"line":57,"column":null}},"24":{"start":{"line":58,"column":8},"end":{"line":58,"column":null}},"25":{"start":{"line":59,"column":8},"end":{"line":59,"column":null}},"26":{"start":{"line":61,"column":2},"end":{"line":69,"column":null}},"27":{"start":{"line":70,"column":2},"end":{"line":70,"column":null}},"28":{"start":{"line":76,"column":8},"end":{"line":91,"column":null}},"29":{"start":{"line":94,"column":4},"end":{"line":98,"column":null}},"30":{"start":{"line":100,"column":10},"end":{"line":100,"column":null}},"31":{"start":{"line":101,"column":4},"end":{"line":101,"column":null}},"32":{"start":{"line":102,"column":4},"end":{"line":102,"column":null}},"33":{"start":{"line":106,"column":2},"end":{"line":106,"column":null}},"34":{"start":{"line":107,"column":2},"end":{"line":107,"column":null}},"35":{"start":{"line":109,"column":29},"end":{"line":113,"column":null}},"36":{"start":{"line":109,"column":10},"end":{"line":109,"column":29}},"37":{"start":{"line":114,"column":4},"end":{"line":116,"column":5}},"38":{"start":{"line":115,"column":6},"end":{"line":115,"column":null}},"39":{"start":{"line":118,"column":4},"end":{"line":118,"column":null}},"40":{"start":{"line":119,"column":4},"end":{"line":124,"column":5}},"41":{"start":{"line":123,"column":6},"end":{"line":123,"column":null}},"42":{"start":{"line":125,"column":10},"end":{"line":125,"column":null}},"43":{"start":{"line":126,"column":4},"end":{"line":126,"column":null}},"44":{"start":{"line":128,"column":4},"end":{"line":132,"column":5}},"45":{"start":{"line":129,"column":6},"end":{"line":129,"column":null}},"46":{"start":{"line":131,"column":6},"end":{"line":131,"column":null}},"47":{"start":{"line":136,"column":4},"end":{"line":138,"column":null}},"48":{"start":{"line":139,"column":4},"end":{"line":143,"column":null}},"49":{"start":{"line":145,"column":4},"end":{"line":145,"column":null}}},"fnMap":{"0":{"name":"formatScriptError","decl":{"start":{"line":16,"column":9},"end":{"line":16,"column":26}},"loc":{"start":{"line":16,"column":63},"end":{"line":33,"column":1}}},"1":{"name":"(anonymous_24)","decl":{"start":{"line":26,"column":11},"end":{"line":26,"column":12}},"loc":{"start":{"line":26,"column":12},"end":{"line":26,"column":21}}},"2":{"name":"runScriptStep","decl":{"start":{"line":35,"column":22},"end":{"line":35,"column":35}},"loc":{"start":{"line":37,"column":7},"end":{"line":147,"column":null}}}},"branchMap":{"0":{"loc":{"start":{"line":23,"column":2},"end":{"line":29,"column":3}},"type":"if","locations":[{"start":{"line":23,"column":2},"end":{"line":29,"column":3}},{"start":{},"end":{}}]},"1":{"loc":{"start":{"line":31,"column":2},"end":{"line":31,"column":null}},"type":"if","locations":[{"start":{"line":31,"column":2},"end":{"line":31,"column":null}},{"start":{},"end":{}}]},"2":{"loc":{"start":{"line":40,"column":2},"end":{"line":44,"column":3}},"type":"if","locations":[{"start":{"line":40,"column":2},"end":{"line":44,"column":3}},{"start":{},"end":{}}]},"3":{"loc":{"start":{"line":40,"column":7},"end":{"line":40,"column":20}},"type":"cond-expr","locations":[{"start":{"line":40,"column":12},"end":{"line":40,"column":14}},{"start":{"line":40,"column":7},"end":{"line":40,"column":20}}]},"4":{"loc":{"start":{"line":40,"column":7},"end":{"line":40,"column":14}},"type":"binary-expr","locations":[{"start":{"line":40,"column":7},"end":{"line":40,"column":14}},{"start":{"line":40,"column":7},"end":{"line":40,"column":14}}]},"5":{"loc":{"start":{"line":114,"column":4},"end":{"line":116,"column":5}},"type":"if","locations":[{"start":{"line":114,"column":4},"end":{"line":116,"column":5}},{"start":{},"end":{}}]},"6":{"loc":{"start":{"line":119,"column":4},"end":{"line":124,"column":5}},"type":"if","locations":[{"start":{"line":119,"column":4},"end":{"line":124,"column":5}},{"start":{},"end":{}}]},"7":{"loc":{"start":{"line":120,"column":6},"end":{"line":121,"column":57}},"type":"binary-expr","locations":[{"start":{"line":120,"column":6},"end":{"line":120,"column":26}},{"start":{"line":121,"column":6},"end":{"line":121,"column":57}}]}},"s":{"0":7,"1":7,"2":7,"3":7,"4":7,"5":7,"6":7,"7":3,"8":3,"9":3,"10":3,"11":3,"12":7,"13":3,"14":3,"15":3,"16":3,"17":3,"18":7,"19":2,"20":5,"21":5,"22":5,"23":5,"24":5,"25":5,"26":10,"27":10,"28":5,"29":10,"30":0,"31":0,"32":0,"33":5,"34":5,"35":5,"36":5,"37":4,"38":3,"39":4,"40":4,"41":3,"42":1,"43":1,"44":5,"45":5,"46":0,"47":1,"48":2,"49":0},"f":{"0":3,"1":7,"2":7},"b":{"0":[3,0],"1":[3,0],"2":[2,5],"3":[0,7],"4":[7,7],"5":[3,1],"6":[3,1],"7":[4,4]}} +,"/__w/backlog/backlog/work/runner-container-hooks/packages/k8s/src/k8s/heartbeat.ts": {"path":"/__w/backlog/backlog/work/runner-container-hooks/packages/k8s/src/k8s/heartbeat.ts","statementMap":{"0":{"start":{"line":11,"column":0},"end":{"line":11,"column":16}},"1":{"start":{"line":1,"column":0},"end":{"line":1,"column":37}},"2":{"start":{"line":15,"column":17},"end":{"line":15,"column":49}},"3":{"start":{"line":16,"column":2},"end":{"line":16,"column":null}},"4":{"start":{"line":19,"column":0},"end":{"line":19,"column":13}},"5":{"start":{"line":26,"column":21},"end":{"line":26,"column":41}},"6":{"start":{"line":27,"column":21},"end":{"line":27,"column":43}},"7":{"start":{"line":20,"column":10},"end":{"line":20,"column":null}},"8":{"start":{"line":21,"column":10},"end":{"line":21,"column":null}},"9":{"start":{"line":22,"column":10},"end":{"line":22,"column":null}},"10":{"start":{"line":30,"column":10},"end":{"line":37,"column":null}},"11":{"start":{"line":31,"column":16},"end":{"line":31,"column":26}},"12":{"start":{"line":32,"column":4},"end":{"line":35,"column":5}},"13":{"start":{"line":33,"column":6},"end":{"line":33,"column":null}},"14":{"start":{"line":34,"column":6},"end":{"line":34,"column":null}},"15":{"start":{"line":36,"column":4},"end":{"line":36,"column":null}},"16":{"start":{"line":39,"column":2},"end":{"line":51,"column":null}},"17":{"start":{"line":40,"column":4},"end":{"line":42,"column":5}},"18":{"start":{"line":41,"column":6},"end":{"line":41,"column":null}},"19":{"start":{"line":43,"column":4},"end":{"line":46,"column":5}},"20":{"start":{"line":44,"column":6},"end":{"line":44,"column":null}},"21":{"start":{"line":45,"column":6},"end":{"line":45,"column":null}},"22":{"start":{"line":47,"column":4},"end":{"line":50,"column":5}},"23":{"start":{"line":48,"column":6},"end":{"line":48,"column":null}},"24":{"start":{"line":49,"column":6},"end":{"line":49,"column":null}},"25":{"start":{"line":53,"column":2},"end":{"line":135,"column":null}},"26":{"start":{"line":53,"column":2},"end":{"line":53,"column":7}},"27":{"start":{"line":54,"column":4},"end":{"line":56,"column":null}},"28":{"start":{"line":57,"column":4},"end":{"line":57,"column":null}},"29":{"start":{"line":59,"column":29},"end":{"line":80,"column":5}},"30":{"start":{"line":60,"column":6},"end":{"line":63,"column":7}},"31":{"start":{"line":61,"column":8},"end":{"line":61,"column":null}},"32":{"start":{"line":62,"column":8},"end":{"line":62,"column":null}},"33":{"start":{"line":64,"column":6},"end":{"line":79,"column":null}},"34":{"start":{"line":65,"column":8},"end":{"line":67,"column":null}},"35":{"start":{"line":68,"column":8},"end":{"line":68,"column":null}},"36":{"start":{"line":69,"column":8},"end":{"line":73,"column":9}},"37":{"start":{"line":70,"column":10},"end":{"line":70,"column":null}},"38":{"start":{"line":74,"column":8},"end":{"line":78,"column":null}},"39":{"start":{"line":84,"column":24},"end":{"line":84,"column":29}},"40":{"start":{"line":86,"column":4},"end":{"line":93,"column":null}},"41":{"start":{"line":87,"column":6},"end":{"line":89,"column":7}},"42":{"start":{"line":88,"column":8},"end":{"line":88,"column":null}},"43":{"start":{"line":90,"column":6},"end":{"line":92,"column":7}},"44":{"start":{"line":91,"column":8},"end":{"line":91,"column":null}},"45":{"start":{"line":95,"column":4},"end":{"line":98,"column":null}},"46":{"start":{"line":96,"column":6},"end":{"line":96,"column":null}},"47":{"start":{"line":97,"column":6},"end":{"line":97,"column":null}},"48":{"start":{"line":100,"column":4},"end":{"line":103,"column":null}},"49":{"start":{"line":101,"column":6},"end":{"line":101,"column":null}},"50":{"start":{"line":102,"column":6},"end":{"line":102,"column":null}},"51":{"start":{"line":106,"column":4},"end":{"line":134,"column":null}},"52":{"start":{"line":107,"column":6},"end":{"line":110,"column":7}},"53":{"start":{"line":109,"column":8},"end":{"line":109,"column":14}},"54":{"start":{"line":111,"column":6},"end":{"line":133,"column":7}},"55":{"start":{"line":112,"column":8},"end":{"line":124,"column":9}},"56":{"start":{"line":113,"column":10},"end":{"line":113,"column":null}},"57":{"start":{"line":114,"column":10},"end":{"line":117,"column":11}},"58":{"start":{"line":115,"column":12},"end":{"line":115,"column":null}},"59":{"start":{"line":116,"column":12},"end":{"line":116,"column":null}},"60":{"start":{"line":118,"column":10},"end":{"line":120,"column":11}},"61":{"start":{"line":119,"column":12},"end":{"line":119,"column":null}},"62":{"start":{"line":122,"column":10},"end":{"line":122,"column":null}},"63":{"start":{"line":123,"column":10},"end":{"line":123,"column":null}},"64":{"start":{"line":127,"column":8},"end":{"line":131,"column":9}},"65":{"start":{"line":128,"column":10},"end":{"line":130,"column":null}},"66":{"start":{"line":132,"column":8},"end":{"line":132,"column":null}},"67":{"start":{"line":23,"column":26},"end":{"line":23,"column":null}},"68":{"start":{"line":136,"column":0},"end":{"line":136,"column":null}},"69":{"start":{"line":19,"column":13},"end":{"line":19,"column":31}}},"fnMap":{"0":{"name":"parsePositiveMsEnv","decl":{"start":{"line":11,"column":16},"end":{"line":11,"column":34}},"loc":{"start":{"line":13,"column":18},"end":{"line":17,"column":1}}},"1":{"name":"(anonymous_10)","decl":{"start":{"line":19,"column":0},"end":{"line":19,"column":13}},"loc":{"start":{"line":19,"column":0},"end":{"line":136,"column":null}}},"2":{"name":"WebSocketHeartbeat","decl":{"start":{"line":25,"column":2},"end":{"line":25,"column":null}},"loc":{"start":{"line":27,"column":43},"end":{"line":28,"column":6}}},"3":{"name":"(anonymous_12)","decl":{"start":{"line":30,"column":2},"end":{"line":30,"column":10}},"loc":{"start":{"line":30,"column":2},"end":{"line":37,"column":3}}},"4":{"name":"(anonymous_13)","decl":{"start":{"line":39,"column":2},"end":{"line":39,"column":6}},"loc":{"start":{"line":39,"column":2},"end":{"line":51,"column":3}}},"5":{"name":"(anonymous_14)","decl":{"start":{"line":53,"column":2},"end":{"line":53,"column":7}},"loc":{"start":{"line":53,"column":60},"end":{"line":135,"column":3}}},"6":{"name":"(anonymous_15)","decl":{"start":{"line":59,"column":29},"end":{"line":59,"column":null}},"loc":{"start":{"line":59,"column":29},"end":{"line":80,"column":5}}},"7":{"name":"(anonymous_16)","decl":{"start":{"line":64,"column":36},"end":{"line":64,"column":null}},"loc":{"start":{"line":64,"column":36},"end":{"line":79,"column":7}}},"8":{"name":"(anonymous_17)","decl":{"start":{"line":86,"column":18},"end":{"line":86,"column":null}},"loc":{"start":{"line":86,"column":18},"end":{"line":93,"column":5}}},"9":{"name":"(anonymous_18)","decl":{"start":{"line":95,"column":19},"end":{"line":95,"column":20}},"loc":{"start":{"line":95,"column":30},"end":{"line":98,"column":5}}},"10":{"name":"(anonymous_19)","decl":{"start":{"line":100,"column":19},"end":{"line":100,"column":null}},"loc":{"start":{"line":100,"column":19},"end":{"line":103,"column":5}}},"11":{"name":"(anonymous_20)","decl":{"start":{"line":106,"column":36},"end":{"line":106,"column":null}},"loc":{"start":{"line":106,"column":36},"end":{"line":134,"column":5}}}},"branchMap":{"0":{"loc":{"start":{"line":15,"column":33},"end":{"line":15,"column":44}},"type":"cond-expr","locations":[{"start":{"line":15,"column":33},"end":{"line":15,"column":38}},{"start":{"line":15,"column":42},"end":{"line":15,"column":44}}]},"1":{"loc":{"start":{"line":15,"column":33},"end":{"line":15,"column":42}},"type":"binary-expr","locations":[{"start":{"line":15,"column":33},"end":{"line":15,"column":42}},{"start":{"line":15,"column":33},"end":{"line":15,"column":42}}]},"2":{"loc":{"start":{"line":16,"column":9},"end":{"line":16,"column":66}},"type":"cond-expr","locations":[{"start":{"line":16,"column":49},"end":{"line":16,"column":55}},{"start":{"line":16,"column":58},"end":{"line":16,"column":66}}]},"3":{"loc":{"start":{"line":16,"column":9},"end":{"line":16,"column":46}},"type":"binary-expr","locations":[{"start":{"line":16,"column":9},"end":{"line":16,"column":32}},{"start":{"line":16,"column":36},"end":{"line":16,"column":46}}]},"4":{"loc":{"start":{"line":32,"column":4},"end":{"line":35,"column":5}},"type":"if","locations":[{"start":{"line":32,"column":4},"end":{"line":35,"column":5}},{"start":{},"end":{}}]},"5":{"loc":{"start":{"line":40,"column":4},"end":{"line":42,"column":5}},"type":"if","locations":[{"start":{"line":40,"column":4},"end":{"line":42,"column":5}},{"start":{},"end":{}}]},"6":{"loc":{"start":{"line":43,"column":4},"end":{"line":46,"column":5}},"type":"if","locations":[{"start":{"line":43,"column":4},"end":{"line":46,"column":5}},{"start":{},"end":{}}]},"7":{"loc":{"start":{"line":47,"column":4},"end":{"line":50,"column":5}},"type":"if","locations":[{"start":{"line":47,"column":4},"end":{"line":50,"column":5}},{"start":{},"end":{}}]},"8":{"loc":{"start":{"line":60,"column":6},"end":{"line":63,"column":7}},"type":"if","locations":[{"start":{"line":60,"column":6},"end":{"line":63,"column":7}},{"start":{},"end":{}}]},"9":{"loc":{"start":{"line":87,"column":6},"end":{"line":89,"column":7}},"type":"if","locations":[{"start":{"line":87,"column":6},"end":{"line":89,"column":7}},{"start":{},"end":{}}]},"10":{"loc":{"start":{"line":90,"column":6},"end":{"line":92,"column":7}},"type":"if","locations":[{"start":{"line":90,"column":6},"end":{"line":92,"column":7}},{"start":{},"end":{}}]},"11":{"loc":{"start":{"line":107,"column":6},"end":{"line":110,"column":7}},"type":"if","locations":[{"start":{"line":107,"column":6},"end":{"line":110,"column":7}},{"start":{},"end":{}}]},"12":{"loc":{"start":{"line":111,"column":6},"end":{"line":133,"column":7}},"type":"if","locations":[{"start":{"line":111,"column":6},"end":{"line":133,"column":7}},{"start":{"line":125,"column":13},"end":{"line":133,"column":7}}]},"13":{"loc":{"start":{"line":114,"column":10},"end":{"line":117,"column":11}},"type":"if","locations":[{"start":{"line":114,"column":10},"end":{"line":117,"column":11}},{"start":{},"end":{}}]},"14":{"loc":{"start":{"line":118,"column":10},"end":{"line":120,"column":11}},"type":"if","locations":[{"start":{"line":118,"column":10},"end":{"line":120,"column":11}},{"start":{},"end":{}}]},"15":{"loc":{"start":{"line":127,"column":8},"end":{"line":131,"column":9}},"type":"if","locations":[{"start":{"line":127,"column":8},"end":{"line":131,"column":9}},{"start":{},"end":{}}]}},"s":{"0":14,"1":14,"2":8,"3":8,"4":14,"5":8,"6":8,"7":8,"8":8,"9":8,"10":14,"11":22,"12":22,"13":0,"14":0,"15":22,"16":14,"17":8,"18":0,"19":8,"20":8,"21":8,"22":8,"23":4,"24":4,"25":14,"26":8,"27":8,"28":8,"29":8,"30":5,"31":1,"32":1,"33":5,"34":1,"35":1,"36":1,"37":1,"38":1,"39":8,"40":8,"41":1,"42":0,"43":1,"44":1,"45":8,"46":0,"47":0,"48":8,"49":1,"50":1,"51":8,"52":29,"53":16,"54":13,"55":12,"56":12,"57":12,"58":4,"59":4,"60":12,"61":0,"62":0,"63":0,"64":1,"65":0,"66":1,"67":14,"68":14,"69":14},"f":{"0":8,"1":14,"2":8,"3":22,"4":8,"5":8,"6":5,"7":1,"8":1,"9":0,"10":1,"11":29},"b":{"0":[7,1],"1":[8,8],"2":[2,6],"3":[8,4],"4":[0,22],"5":[0,8],"6":[8,0],"7":[4,4],"8":[1,4],"9":[0,1],"10":[1,0],"11":[16,13],"12":[12,1],"13":[4,8],"14":[0,12],"15":[0,1]}} +,"/__w/backlog/backlog/work/runner-container-hooks/packages/k8s/src/k8s/index.ts": {"path":"/__w/backlog/backlog/work/runner-container-hooks/packages/k8s/src/k8s/index.ts","statementMap":{"0":{"start":{"line":69,"column":0},"end":{"line":69,"column":22}},"1":{"start":{"line":189,"column":0},"end":{"line":189,"column":22}},"2":{"start":{"line":242,"column":0},"end":{"line":242,"column":22}},"3":{"start":{"line":250,"column":0},"end":{"line":250,"column":22}},"4":{"start":{"line":379,"column":0},"end":{"line":379,"column":22}},"5":{"start":{"line":503,"column":0},"end":{"line":503,"column":22}},"6":{"start":{"line":565,"column":0},"end":{"line":565,"column":22}},"7":{"start":{"line":599,"column":0},"end":{"line":599,"column":22}},"8":{"start":{"line":720,"column":0},"end":{"line":720,"column":22}},"9":{"start":{"line":859,"column":0},"end":{"line":859,"column":22}},"10":{"start":{"line":873,"column":0},"end":{"line":873,"column":22}},"11":{"start":{"line":914,"column":0},"end":{"line":914,"column":22}},"12":{"start":{"line":942,"column":0},"end":{"line":942,"column":22}},"13":{"start":{"line":949,"column":0},"end":{"line":949,"column":22}},"14":{"start":{"line":1052,"column":0},"end":{"line":1052,"column":16}},"15":{"start":{"line":1070,"column":0},"end":{"line":1070,"column":16}},"16":{"start":{"line":1085,"column":0},"end":{"line":1085,"column":16}},"17":{"start":{"line":1107,"column":0},"end":{"line":1107,"column":16}},"18":{"start":{"line":1123,"column":0},"end":{"line":1123,"column":16}},"19":{"start":{"line":1165,"column":0},"end":{"line":1165,"column":16}},"20":{"start":{"line":1184,"column":0},"end":{"line":1184,"column":16}},"21":{"start":{"line":1211,"column":0},"end":{"line":1211,"column":16}},"22":{"start":{"line":1266,"column":0},"end":{"line":1266,"column":22}},"23":{"start":{"line":1331,"column":0},"end":{"line":1331,"column":22}},"24":{"start":{"line":1459,"column":0},"end":{"line":1459,"column":16}},"25":{"start":{"line":1469,"column":0},"end":{"line":1469,"column":22}},"26":{"start":{"line":1496,"column":0},"end":{"line":1496,"column":22}},"27":{"start":{"line":1576,"column":0},"end":{"line":1576,"column":16}},"28":{"start":{"line":1610,"column":0},"end":{"line":1610,"column":16}},"29":{"start":{"line":1628,"column":0},"end":{"line":1628,"column":22}},"30":{"start":{"line":1653,"column":0},"end":{"line":1653,"column":22}},"31":{"start":{"line":1669,"column":0},"end":{"line":1669,"column":22}},"32":{"start":{"line":1679,"column":0},"end":{"line":1679,"column":22}},"33":{"start":{"line":1700,"column":0},"end":{"line":1700,"column":22}},"34":{"start":{"line":1722,"column":0},"end":{"line":1722,"column":16}},"35":{"start":{"line":1776,"column":0},"end":{"line":1776,"column":16}},"36":{"start":{"line":1818,"column":0},"end":{"line":1818,"column":22}},"37":{"start":{"line":1825,"column":0},"end":{"line":1825,"column":22}},"38":{"start":{"line":1832,"column":0},"end":{"line":1832,"column":22}},"39":{"start":{"line":1,"column":0},"end":{"line":1,"column":37}},"40":{"start":{"line":2,"column":0},"end":{"line":2,"column":24}},"41":{"start":{"line":3,"column":0},"end":{"line":3,"column":28}},"42":{"start":{"line":4,"column":0},"end":{"line":4,"column":37}},"43":{"start":{"line":5,"column":0},"end":{"line":5,"column":46}},"44":{"start":{"line":6,"column":0},"end":{"line":6,"column":24}},"45":{"start":{"line":7,"column":0},"end":{"line":7,"column":32}},"46":{"start":{"line":8,"column":0},"end":{"line":8,"column":53}},"47":{"start":{"line":9,"column":0},"end":{"line":9,"column":35}},"48":{"start":{"line":11,"column":0},"end":{"line":11,"column":null}},"49":{"start":{"line":16,"column":0},"end":{"line":16,"column":null}},"50":{"start":{"line":28,"column":0},"end":{"line":28,"column":30}},"51":{"start":{"line":29,"column":0},"end":{"line":29,"column":68}},"52":{"start":{"line":32,"column":11},"end":{"line":32,"column":31}},"53":{"start":{"line":34,"column":0},"end":{"line":34,"column":null}},"54":{"start":{"line":36,"column":15},"end":{"line":36,"column":46}},"55":{"start":{"line":37,"column":22},"end":{"line":37,"column":54}},"56":{"start":{"line":38,"column":30},"end":{"line":38,"column":70}},"57":{"start":{"line":40,"column":42},"end":{"line":40,"column":49}},"58":{"start":{"line":42,"column":13},"end":{"line":67,"column":null}},"59":{"start":{"line":76,"column":8},"end":{"line":76,"column":null}},"60":{"start":{"line":77,"column":2},"end":{"line":79,"column":3}},"61":{"start":{"line":78,"column":4},"end":{"line":78,"column":null}},"62":{"start":{"line":80,"column":2},"end":{"line":82,"column":3}},"63":{"start":{"line":81,"column":4},"end":{"line":81,"column":32}},"64":{"start":{"line":84,"column":8},"end":{"line":84,"column":null}},"65":{"start":{"line":86,"column":2},"end":{"line":86,"column":null}},"66":{"start":{"line":87,"column":2},"end":{"line":87,"column":null}},"67":{"start":{"line":89,"column":2},"end":{"line":89,"column":null}},"68":{"start":{"line":90,"column":2},"end":{"line":90,"column":null}},"69":{"start":{"line":92,"column":8},"end":{"line":92,"column":null}},"70":{"start":{"line":93,"column":2},"end":{"line":95,"column":null}},"71":{"start":{"line":96,"column":2},"end":{"line":96,"column":null}},"72":{"start":{"line":98,"column":2},"end":{"line":98,"column":null}},"73":{"start":{"line":99,"column":2},"end":{"line":99,"column":null}},"74":{"start":{"line":100,"column":2},"end":{"line":102,"column":null}},"75":{"start":{"line":106,"column":8},"end":{"line":106,"column":null}},"76":{"start":{"line":107,"column":8},"end":{"line":107,"column":null}},"77":{"start":{"line":109,"column":8},"end":{"line":114,"column":null}},"78":{"start":{"line":116,"column":2},"end":{"line":118,"column":3}},"79":{"start":{"line":117,"column":4},"end":{"line":117,"column":null}},"80":{"start":{"line":120,"column":2},"end":{"line":146,"column":null}},"81":{"start":{"line":148,"column":2},"end":{"line":148,"column":null}},"82":{"start":{"line":150,"column":2},"end":{"line":163,"column":null}},"83":{"start":{"line":165,"column":6},"end":{"line":165,"column":14}},"84":{"start":{"line":166,"column":19},"end":{"line":166,"column":null}},"85":{"start":{"line":166,"column":10},"end":{"line":166,"column":null}},"86":{"start":{"line":167,"column":4},"end":{"line":169,"column":5}},"87":{"start":{"line":168,"column":6},"end":{"line":168,"column":null}},"88":{"start":{"line":170,"column":10},"end":{"line":170,"column":null}},"89":{"start":{"line":171,"column":4},"end":{"line":171,"column":null}},"90":{"start":{"line":172,"column":4},"end":{"line":172,"column":null}},"91":{"start":{"line":175,"column":2},"end":{"line":177,"column":3}},"92":{"start":{"line":176,"column":4},"end":{"line":176,"column":null}},"93":{"start":{"line":179,"column":2},"end":{"line":181,"column":3}},"94":{"start":{"line":180,"column":4},"end":{"line":180,"column":null}},"95":{"start":{"line":183,"column":9},"end":{"line":186,"column":null}},"96":{"start":{"line":183,"column":2},"end":{"line":186,"column":null}},"97":{"start":{"line":194,"column":8},"end":{"line":194,"column":null}},"98":{"start":{"line":196,"column":2},"end":{"line":196,"column":null}},"99":{"start":{"line":197,"column":2},"end":{"line":197,"column":null}},"100":{"start":{"line":199,"column":2},"end":{"line":199,"column":null}},"101":{"start":{"line":200,"column":2},"end":{"line":200,"column":null}},"102":{"start":{"line":202,"column":8},"end":{"line":202,"column":null}},"103":{"start":{"line":203,"column":2},"end":{"line":205,"column":null}},"104":{"start":{"line":206,"column":2},"end":{"line":206,"column":null}},"105":{"start":{"line":208,"column":2},"end":{"line":208,"column":null}},"106":{"start":{"line":209,"column":2},"end":{"line":209,"column":null}},"107":{"start":{"line":211,"column":2},"end":{"line":211,"column":null}},"108":{"start":{"line":213,"column":2},"end":{"line":226,"column":null}},"109":{"start":{"line":228,"column":2},"end":{"line":230,"column":3}},"110":{"start":{"line":229,"column":4},"end":{"line":229,"column":null}},"111":{"start":{"line":232,"column":2},"end":{"line":234,"column":3}},"112":{"start":{"line":233,"column":4},"end":{"line":233,"column":null}},"113":{"start":{"line":236,"column":9},"end":{"line":239,"column":null}},"114":{"start":{"line":236,"column":2},"end":{"line":239,"column":null}},"115":{"start":{"line":243,"column":2},"end":{"line":247,"column":null}},"116":{"start":{"line":256,"column":8},"end":{"line":256,"column":null}},"117":{"start":{"line":257,"column":2},"end":{"line":259,"column":null}},"118":{"start":{"line":261,"column":2},"end":{"line":261,"column":null}},"119":{"start":{"line":263,"column":8},"end":{"line":263,"column":null}},"120":{"start":{"line":264,"column":8},"end":{"line":267,"column":null}},"121":{"start":{"line":268,"column":8},"end":{"line":271,"column":null}},"122":{"start":{"line":272,"column":2},"end":{"line":274,"column":null}},"123":{"start":{"line":276,"column":8},"end":{"line":276,"column":null}},"124":{"start":{"line":278,"column":2},"end":{"line":371,"column":null}},"125":{"start":{"line":279,"column":4},"end":{"line":279,"column":null}},"126":{"start":{"line":280,"column":40},"end":{"line":280,"column":44}},"127":{"start":{"line":282,"column":4},"end":{"line":370,"column":null}},"128":{"start":{"line":292,"column":18},"end":{"line":335,"column":null}},"129":{"start":{"line":293,"column":10},"end":{"line":295,"column":null}},"130":{"start":{"line":297,"column":10},"end":{"line":297,"column":null}},"131":{"start":{"line":300,"column":16},"end":{"line":322,"column":null}},"132":{"start":{"line":300,"column":33},"end":{"line":322,"column":null}},"133":{"start":{"line":301,"column":18},"end":{"line":301,"column":null}},"134":{"start":{"line":302,"column":12},"end":{"line":321,"column":13}},"135":{"start":{"line":306,"column":14},"end":{"line":320,"column":null}},"136":{"start":{"line":307,"column":37},"end":{"line":312,"column":24}},"137":{"start":{"line":308,"column":18},"end":{"line":310,"column":null}},"138":{"start":{"line":311,"column":18},"end":{"line":311,"column":null}},"139":{"start":{"line":314,"column":16},"end":{"line":318,"column":null}},"140":{"start":{"line":315,"column":18},"end":{"line":315,"column":null}},"141":{"start":{"line":316,"column":18},"end":{"line":316,"column":null}},"142":{"start":{"line":317,"column":18},"end":{"line":317,"column":null}},"143":{"start":{"line":319,"column":16},"end":{"line":319,"column":null}},"144":{"start":{"line":324,"column":14},"end":{"line":324,"column":18}},"145":{"start":{"line":325,"column":12},"end":{"line":325,"column":null}},"146":{"start":{"line":326,"column":12},"end":{"line":326,"column":null}},"147":{"start":{"line":327,"column":12},"end":{"line":327,"column":null}},"148":{"start":{"line":329,"column":12},"end":{"line":331,"column":null}},"149":{"start":{"line":332,"column":12},"end":{"line":332,"column":null}},"150":{"start":{"line":333,"column":12},"end":{"line":333,"column":null}},"151":{"start":{"line":338,"column":8},"end":{"line":338,"column":null}},"152":{"start":{"line":339,"column":8},"end":{"line":339,"column":null}},"153":{"start":{"line":340,"column":8},"end":{"line":344,"column":9}},"154":{"start":{"line":341,"column":10},"end":{"line":341,"column":null}},"155":{"start":{"line":343,"column":10},"end":{"line":343,"column":null}},"156":{"start":{"line":346,"column":20},"end":{"line":370,"column":8}},"157":{"start":{"line":347,"column":8},"end":{"line":347,"column":null}},"158":{"start":{"line":348,"column":8},"end":{"line":348,"column":null}},"159":{"start":{"line":351,"column":14},"end":{"line":351,"column":null}},"160":{"start":{"line":352,"column":12},"end":{"line":352,"column":18}},"161":{"start":{"line":353,"column":10},"end":{"line":366,"column":null}},"162":{"start":{"line":354,"column":33},"end":{"line":359,"column":20}},"163":{"start":{"line":355,"column":14},"end":{"line":357,"column":null}},"164":{"start":{"line":358,"column":14},"end":{"line":358,"column":null}},"165":{"start":{"line":361,"column":12},"end":{"line":364,"column":null}},"166":{"start":{"line":362,"column":14},"end":{"line":362,"column":null}},"167":{"start":{"line":363,"column":14},"end":{"line":363,"column":null}},"168":{"start":{"line":365,"column":12},"end":{"line":365,"column":null}},"169":{"start":{"line":369,"column":8},"end":{"line":369,"column":null}},"170":{"start":{"line":383,"column":2},"end":{"line":383,"column":null}},"171":{"start":{"line":386,"column":8},"end":{"line":386,"column":null}},"172":{"start":{"line":387,"column":2},"end":{"line":387,"column":null}},"173":{"start":{"line":390,"column":8},"end":{"line":390,"column":null}},"174":{"start":{"line":391,"column":8},"end":{"line":395,"column":null}},"175":{"start":{"line":392,"column":4},"end":{"line":392,"column":33}},"176":{"start":{"line":392,"column":27},"end":{"line":392,"column":33}},"177":{"start":{"line":393,"column":4},"end":{"line":393,"column":null}},"178":{"start":{"line":394,"column":4},"end":{"line":394,"column":null}},"179":{"start":{"line":394,"column":35},"end":{"line":394,"column":null}},"180":{"start":{"line":398,"column":6},"end":{"line":398,"column":null}},"181":{"start":{"line":399,"column":8},"end":{"line":404,"column":null}},"182":{"start":{"line":400,"column":4},"end":{"line":400,"column":null}},"183":{"start":{"line":401,"column":18},"end":{"line":401,"column":43}},"184":{"start":{"line":402,"column":4},"end":{"line":402,"column":null}},"185":{"start":{"line":403,"column":4},"end":{"line":403,"column":null}},"186":{"start":{"line":403,"column":23},"end":{"line":403,"column":28}},"187":{"start":{"line":403,"column":19},"end":{"line":403,"column":23}},"188":{"start":{"line":403,"column":30},"end":{"line":403,"column":null}},"189":{"start":{"line":406,"column":6},"end":{"line":406,"column":null}},"190":{"start":{"line":407,"column":8},"end":{"line":412,"column":null}},"191":{"start":{"line":408,"column":4},"end":{"line":408,"column":null}},"192":{"start":{"line":409,"column":18},"end":{"line":409,"column":43}},"193":{"start":{"line":410,"column":4},"end":{"line":410,"column":null}},"194":{"start":{"line":411,"column":4},"end":{"line":411,"column":null}},"195":{"start":{"line":411,"column":23},"end":{"line":411,"column":28}},"196":{"start":{"line":411,"column":19},"end":{"line":411,"column":23}},"197":{"start":{"line":411,"column":30},"end":{"line":411,"column":null}},"198":{"start":{"line":414,"column":8},"end":{"line":423,"column":null}},"199":{"start":{"line":415,"column":4},"end":{"line":418,"column":5}},"200":{"start":{"line":416,"column":6},"end":{"line":416,"column":null}},"201":{"start":{"line":417,"column":6},"end":{"line":417,"column":null}},"202":{"start":{"line":419,"column":4},"end":{"line":422,"column":5}},"203":{"start":{"line":420,"column":6},"end":{"line":420,"column":null}},"204":{"start":{"line":421,"column":6},"end":{"line":421,"column":null}},"205":{"start":{"line":425,"column":8},"end":{"line":435,"column":null}},"206":{"start":{"line":427,"column":6},"end":{"line":433,"column":7}},"207":{"start":{"line":428,"column":8},"end":{"line":428,"column":null}},"208":{"start":{"line":429,"column":8},"end":{"line":429,"column":null}},"209":{"start":{"line":430,"column":8},"end":{"line":430,"column":null}},"210":{"start":{"line":432,"column":8},"end":{"line":432,"column":null}},"211":{"start":{"line":436,"column":8},"end":{"line":446,"column":null}},"212":{"start":{"line":438,"column":6},"end":{"line":444,"column":7}},"213":{"start":{"line":439,"column":8},"end":{"line":439,"column":null}},"214":{"start":{"line":440,"column":8},"end":{"line":440,"column":null}},"215":{"start":{"line":441,"column":8},"end":{"line":441,"column":null}},"216":{"start":{"line":443,"column":8},"end":{"line":443,"column":null}},"217":{"start":{"line":451,"column":8},"end":{"line":454,"column":null}},"218":{"start":{"line":452,"column":14},"end":{"line":452,"column":49}},"219":{"start":{"line":453,"column":4},"end":{"line":453,"column":null}},"220":{"start":{"line":456,"column":9},"end":{"line":500,"column":null}},"221":{"start":{"line":457,"column":4},"end":{"line":499,"column":null}},"222":{"start":{"line":468,"column":10},"end":{"line":468,"column":null}},"223":{"start":{"line":469,"column":10},"end":{"line":469,"column":null}},"224":{"start":{"line":470,"column":10},"end":{"line":482,"column":11}},"225":{"start":{"line":471,"column":12},"end":{"line":471,"column":null}},"226":{"start":{"line":476,"column":25},"end":{"line":476,"column":53}},"227":{"start":{"line":477,"column":12},"end":{"line":481,"column":13}},"228":{"start":{"line":478,"column":14},"end":{"line":478,"column":null}},"229":{"start":{"line":480,"column":14},"end":{"line":480,"column":null}},"230":{"start":{"line":491,"column":8},"end":{"line":491,"column":null}},"231":{"start":{"line":492,"column":23},"end":{"line":492,"column":65}},"232":{"start":{"line":493,"column":21},"end":{"line":493,"column":42}},"233":{"start":{"line":494,"column":8},"end":{"line":498,"column":9}},"234":{"start":{"line":495,"column":10},"end":{"line":495,"column":null}},"235":{"start":{"line":497,"column":10},"end":{"line":497,"column":null}},"236":{"start":{"line":456,"column":2},"end":{"line":500,"column":null}},"237":{"start":{"line":508,"column":8},"end":{"line":508,"column":null}},"238":{"start":{"line":510,"column":6},"end":{"line":510,"column":null}},"239":{"start":{"line":511,"column":8},"end":{"line":520,"column":null}},"240":{"start":{"line":513,"column":6},"end":{"line":518,"column":7}},"241":{"start":{"line":514,"column":8},"end":{"line":514,"column":null}},"242":{"start":{"line":515,"column":8},"end":{"line":515,"column":null}},"243":{"start":{"line":517,"column":8},"end":{"line":517,"column":null}},"244":{"start":{"line":522,"column":2},"end":{"line":549,"column":null}},"245":{"start":{"line":523,"column":4},"end":{"line":548,"column":null}},"246":{"start":{"line":534,"column":10},"end":{"line":534,"column":null}},"247":{"start":{"line":535,"column":10},"end":{"line":545,"column":11}},"248":{"start":{"line":536,"column":12},"end":{"line":536,"column":null}},"249":{"start":{"line":538,"column":12},"end":{"line":543,"column":null}},"250":{"start":{"line":544,"column":12},"end":{"line":544,"column":null}},"251":{"start":{"line":548,"column":18},"end":{"line":548,"column":28}},"252":{"start":{"line":551,"column":2},"end":{"line":551,"column":null}},"253":{"start":{"line":554,"column":8},"end":{"line":557,"column":null}},"254":{"start":{"line":556,"column":20},"end":{"line":556,"column":36}},"255":{"start":{"line":558,"column":8},"end":{"line":558,"column":null}},"256":{"start":{"line":560,"column":8},"end":{"line":560,"column":null}},"257":{"start":{"line":561,"column":2},"end":{"line":561,"column":null}},"258":{"start":{"line":562,"column":2},"end":{"line":562,"column":null}},"259":{"start":{"line":568,"column":9},"end":{"line":596,"column":null}},"260":{"start":{"line":570,"column":20},"end":{"line":572,"column":8}},"261":{"start":{"line":574,"column":19},"end":{"line":574,"column":21}},"262":{"start":{"line":575,"column":6},"end":{"line":577,"column":null}},"263":{"start":{"line":576,"column":8},"end":{"line":576,"column":null}},"264":{"start":{"line":578,"column":6},"end":{"line":578,"column":null}},"265":{"start":{"line":579,"column":6},"end":{"line":594,"column":null}},"266":{"start":{"line":580,"column":8},"end":{"line":593,"column":9}},"267":{"start":{"line":582,"column":24},"end":{"line":585,"column":19}},"268":{"start":{"line":584,"column":28},"end":{"line":584,"column":44}},"269":{"start":{"line":586,"column":31},"end":{"line":586,"column":54}},"270":{"start":{"line":588,"column":23},"end":{"line":588,"column":43}},"271":{"start":{"line":589,"column":10},"end":{"line":589,"column":null}},"272":{"start":{"line":590,"column":10},"end":{"line":590,"column":null}},"273":{"start":{"line":592,"column":10},"end":{"line":592,"column":null}},"274":{"start":{"line":568,"column":2},"end":{"line":596,"column":null}},"275":{"start":{"line":604,"column":2},"end":{"line":604,"column":null}},"276":{"start":{"line":606,"column":6},"end":{"line":606,"column":null}},"277":{"start":{"line":609,"column":12},"end":{"line":609,"column":null}},"278":{"start":{"line":612,"column":12},"end":{"line":619,"column":null}},"279":{"start":{"line":620,"column":12},"end":{"line":620,"column":null}},"280":{"start":{"line":621,"column":12},"end":{"line":621,"column":null}},"281":{"start":{"line":622,"column":6},"end":{"line":645,"column":null}},"282":{"start":{"line":623,"column":8},"end":{"line":644,"column":null}},"283":{"start":{"line":633,"column":24},"end":{"line":642,"column":null}},"284":{"start":{"line":634,"column":14},"end":{"line":640,"column":15}},"285":{"start":{"line":635,"column":16},"end":{"line":639,"column":null}},"286":{"start":{"line":641,"column":14},"end":{"line":641,"column":null}},"287":{"start":{"line":644,"column":22},"end":{"line":644,"column":32}},"288":{"start":{"line":648,"column":6},"end":{"line":648,"column":null}},"289":{"start":{"line":649,"column":6},"end":{"line":649,"column":null}},"290":{"start":{"line":650,"column":6},"end":{"line":654,"column":7}},"291":{"start":{"line":651,"column":8},"end":{"line":653,"column":null}},"292":{"start":{"line":655,"column":6},"end":{"line":655,"column":null}},"293":{"start":{"line":607,"column":9},"end":{"line":607,"column":null}},"294":{"start":{"line":607,"column":13},"end":{"line":607,"column":null}},"295":{"start":{"line":659,"column":6},"end":{"line":659,"column":null}},"296":{"start":{"line":660,"column":8},"end":{"line":660,"column":null}},"297":{"start":{"line":664,"column":8},"end":{"line":668,"column":null}},"298":{"start":{"line":663,"column":12},"end":{"line":663,"column":null}},"299":{"start":{"line":671,"column":8},"end":{"line":675,"column":null}},"300":{"start":{"line":670,"column":12},"end":{"line":670,"column":null}},"301":{"start":{"line":677,"column":10},"end":{"line":677,"column":13}},"302":{"start":{"line":678,"column":8},"end":{"line":680,"column":null}},"303":{"start":{"line":681,"column":8},"end":{"line":683,"column":null}},"304":{"start":{"line":684,"column":14},"end":{"line":686,"column":null}},"305":{"start":{"line":685,"column":29},"end":{"line":685,"column":71}},"306":{"start":{"line":687,"column":14},"end":{"line":689,"column":null}},"307":{"start":{"line":688,"column":28},"end":{"line":688,"column":70}},"308":{"start":{"line":690,"column":14},"end":{"line":692,"column":null}},"309":{"start":{"line":691,"column":15},"end":{"line":691,"column":null}},"310":{"start":{"line":693,"column":14},"end":{"line":695,"column":null}},"311":{"start":{"line":694,"column":15},"end":{"line":694,"column":null}},"312":{"start":{"line":696,"column":14},"end":{"line":704,"column":null}},"313":{"start":{"line":698,"column":25},"end":{"line":698,"column":47}},"314":{"start":{"line":699,"column":12},"end":{"line":699,"column":null}},"315":{"start":{"line":702,"column":25},"end":{"line":702,"column":47}},"316":{"start":{"line":703,"column":12},"end":{"line":703,"column":null}},"317":{"start":{"line":705,"column":8},"end":{"line":705,"column":null}},"318":{"start":{"line":706,"column":8},"end":{"line":706,"column":null}},"319":{"start":{"line":707,"column":8},"end":{"line":707,"column":null}},"320":{"start":{"line":708,"column":8},"end":{"line":708,"column":null}},"321":{"start":{"line":714,"column":6},"end":{"line":714,"column":null}},"322":{"start":{"line":715,"column":6},"end":{"line":715,"column":null}},"323":{"start":{"line":661,"column":11},"end":{"line":661,"column":18}},"324":{"start":{"line":661,"column":18},"end":{"line":661,"column":32}},"325":{"start":{"line":661,"column":30},"end":{"line":661,"column":32}},"326":{"start":{"line":661,"column":11},"end":{"line":661,"column":15}},"327":{"start":{"line":661,"column":32},"end":{"line":661,"column":null}},"328":{"start":{"line":725,"column":8},"end":{"line":725,"column":null}},"329":{"start":{"line":726,"column":2},"end":{"line":728,"column":null}},"330":{"start":{"line":734,"column":2},"end":{"line":736,"column":3}},"331":{"start":{"line":735,"column":4},"end":{"line":735,"column":null}},"332":{"start":{"line":738,"column":6},"end":{"line":738,"column":null}},"333":{"start":{"line":742,"column":12},"end":{"line":742,"column":null}},"334":{"start":{"line":743,"column":12},"end":{"line":743,"column":null}},"335":{"start":{"line":744,"column":12},"end":{"line":744,"column":null}},"336":{"start":{"line":745,"column":12},"end":{"line":752,"column":null}},"337":{"start":{"line":753,"column":12},"end":{"line":753,"column":null}},"338":{"start":{"line":754,"column":12},"end":{"line":754,"column":null}},"339":{"start":{"line":756,"column":6},"end":{"line":784,"column":null}},"340":{"start":{"line":761,"column":8},"end":{"line":761,"column":null}},"341":{"start":{"line":762,"column":8},"end":{"line":762,"column":null}},"342":{"start":{"line":763,"column":8},"end":{"line":783,"column":null}},"343":{"start":{"line":773,"column":35},"end":{"line":781,"column":null}},"344":{"start":{"line":774,"column":14},"end":{"line":780,"column":15}},"345":{"start":{"line":775,"column":16},"end":{"line":779,"column":null}},"346":{"start":{"line":783,"column":22},"end":{"line":783,"column":32}},"347":{"start":{"line":787,"column":6},"end":{"line":787,"column":null}},"348":{"start":{"line":788,"column":6},"end":{"line":788,"column":null}},"349":{"start":{"line":789,"column":6},"end":{"line":793,"column":7}},"350":{"start":{"line":790,"column":8},"end":{"line":792,"column":null}},"351":{"start":{"line":794,"column":6},"end":{"line":794,"column":null}},"352":{"start":{"line":739,"column":9},"end":{"line":739,"column":null}},"353":{"start":{"line":739,"column":13},"end":{"line":739,"column":null}},"354":{"start":{"line":798,"column":6},"end":{"line":798,"column":null}},"355":{"start":{"line":799,"column":8},"end":{"line":799,"column":null}},"356":{"start":{"line":803,"column":8},"end":{"line":807,"column":null}},"357":{"start":{"line":802,"column":12},"end":{"line":802,"column":null}},"358":{"start":{"line":810,"column":8},"end":{"line":814,"column":null}},"359":{"start":{"line":809,"column":12},"end":{"line":809,"column":null}},"360":{"start":{"line":816,"column":10},"end":{"line":816,"column":13}},"361":{"start":{"line":817,"column":8},"end":{"line":819,"column":null}},"362":{"start":{"line":820,"column":8},"end":{"line":822,"column":null}},"363":{"start":{"line":823,"column":14},"end":{"line":825,"column":null}},"364":{"start":{"line":824,"column":29},"end":{"line":824,"column":71}},"365":{"start":{"line":826,"column":14},"end":{"line":828,"column":null}},"366":{"start":{"line":827,"column":28},"end":{"line":827,"column":70}},"367":{"start":{"line":829,"column":14},"end":{"line":831,"column":null}},"368":{"start":{"line":830,"column":15},"end":{"line":830,"column":null}},"369":{"start":{"line":832,"column":14},"end":{"line":834,"column":null}},"370":{"start":{"line":833,"column":15},"end":{"line":833,"column":null}},"371":{"start":{"line":835,"column":14},"end":{"line":843,"column":null}},"372":{"start":{"line":837,"column":25},"end":{"line":837,"column":47}},"373":{"start":{"line":838,"column":12},"end":{"line":838,"column":null}},"374":{"start":{"line":841,"column":25},"end":{"line":841,"column":47}},"375":{"start":{"line":842,"column":12},"end":{"line":842,"column":null}},"376":{"start":{"line":844,"column":8},"end":{"line":844,"column":null}},"377":{"start":{"line":845,"column":8},"end":{"line":845,"column":null}},"378":{"start":{"line":846,"column":8},"end":{"line":846,"column":null}},"379":{"start":{"line":847,"column":8},"end":{"line":847,"column":null}},"380":{"start":{"line":853,"column":6},"end":{"line":853,"column":null}},"381":{"start":{"line":854,"column":6},"end":{"line":854,"column":null}},"382":{"start":{"line":800,"column":11},"end":{"line":800,"column":18}},"383":{"start":{"line":800,"column":18},"end":{"line":800,"column":32}},"384":{"start":{"line":800,"column":30},"end":{"line":800,"column":32}},"385":{"start":{"line":800,"column":11},"end":{"line":800,"column":15}},"386":{"start":{"line":800,"column":32},"end":{"line":800,"column":null}},"387":{"start":{"line":860,"column":8},"end":{"line":860,"column":null}},"388":{"start":{"line":861,"column":9},"end":{"line":861,"column":null}},"389":{"start":{"line":861,"column":13},"end":{"line":861,"column":null}},"390":{"start":{"line":863,"column":10},"end":{"line":863,"column":41}},"391":{"start":{"line":863,"column":6},"end":{"line":865,"column":7}},"392":{"start":{"line":864,"column":8},"end":{"line":864,"column":14}},"393":{"start":{"line":867,"column":6},"end":{"line":867,"column":null}},"394":{"start":{"line":869,"column":4},"end":{"line":869,"column":null}},"395":{"start":{"line":876,"column":8},"end":{"line":886,"column":null}},"396":{"start":{"line":888,"column":8},"end":{"line":888,"column":null}},"397":{"start":{"line":890,"column":8},"end":{"line":890,"column":null}},"398":{"start":{"line":891,"column":8},"end":{"line":891,"column":null}},"399":{"start":{"line":892,"column":2},"end":{"line":892,"column":null}},"400":{"start":{"line":893,"column":2},"end":{"line":893,"column":null}},"401":{"start":{"line":894,"column":2},"end":{"line":894,"column":null}},"402":{"start":{"line":895,"column":2},"end":{"line":895,"column":null}},"403":{"start":{"line":896,"column":2},"end":{"line":896,"column":null}},"404":{"start":{"line":897,"column":2},"end":{"line":899,"column":null}},"405":{"start":{"line":900,"column":2},"end":{"line":900,"column":null}},"406":{"start":{"line":901,"column":2},"end":{"line":901,"column":null}},"407":{"start":{"line":902,"column":2},"end":{"line":906,"column":null}},"408":{"start":{"line":908,"column":9},"end":{"line":911,"column":null}},"409":{"start":{"line":908,"column":2},"end":{"line":911,"column":null}},"410":{"start":{"line":917,"column":8},"end":{"line":917,"column":null}},"411":{"start":{"line":919,"column":8},"end":{"line":919,"column":null}},"412":{"start":{"line":920,"column":8},"end":{"line":920,"column":null}},"413":{"start":{"line":921,"column":2},"end":{"line":921,"column":null}},"414":{"start":{"line":922,"column":2},"end":{"line":922,"column":null}},"415":{"start":{"line":923,"column":2},"end":{"line":923,"column":null}},"416":{"start":{"line":924,"column":2},"end":{"line":924,"column":null}},"417":{"start":{"line":926,"column":2},"end":{"line":928,"column":null}},"418":{"start":{"line":929,"column":2},"end":{"line":929,"column":null}},"419":{"start":{"line":930,"column":2},"end":{"line":930,"column":null}},"420":{"start":{"line":931,"column":2},"end":{"line":933,"column":3}},"421":{"start":{"line":931,"column":13},"end":{"line":931,"column":25}},"422":{"start":{"line":932,"column":4},"end":{"line":932,"column":null}},"423":{"start":{"line":935,"column":2},"end":{"line":938,"column":null}},"424":{"start":{"line":939,"column":2},"end":{"line":939,"column":null}},"425":{"start":{"line":943,"column":2},"end":{"line":946,"column":null}},"426":{"start":{"line":950,"column":21},"end":{"line":953,"column":null}},"427":{"start":{"line":950,"column":8},"end":{"line":953,"column":null}},"428":{"start":{"line":954,"column":2},"end":{"line":956,"column":3}},"429":{"start":{"line":955,"column":4},"end":{"line":955,"column":10}},"430":{"start":{"line":958,"column":2},"end":{"line":963,"column":null}},"431":{"start":{"line":960,"column":18},"end":{"line":961,"column":null}},"432":{"start":{"line":961,"column":8},"end":{"line":961,"column":33}},"433":{"start":{"line":961,"column":34},"end":{"line":961,"column":75}},"434":{"start":{"line":961,"column":33},"end":{"line":961,"column":null}},"435":{"start":{"line":961,"column":8},"end":{"line":961,"column":14}},"436":{"start":{"line":966,"column":13},"end":{"line":981,"column":null}},"437":{"start":{"line":1001,"column":13},"end":{"line":1005,"column":null}},"438":{"start":{"line":1024,"column":13},"end":{"line":1036,"column":null}},"439":{"start":{"line":1038,"column":13},"end":{"line":1042,"column":null}},"440":{"start":{"line":1046,"column":30},"end":{"line":1046,"column":32}},"441":{"start":{"line":1053,"column":16},"end":{"line":1053,"column":79}},"442":{"start":{"line":1054,"column":2},"end":{"line":1056,"column":3}},"443":{"start":{"line":1055,"column":4},"end":{"line":1055,"column":null}},"444":{"start":{"line":1057,"column":18},"end":{"line":1057,"column":56}},"445":{"start":{"line":1058,"column":2},"end":{"line":1063,"column":3}},"446":{"start":{"line":1058,"column":23},"end":{"line":1058,"column":28}},"447":{"start":{"line":1058,"column":23},"end":{"line":1058,"column":39}},"448":{"start":{"line":1058,"column":19},"end":{"line":1058,"column":23}},"449":{"start":{"line":1059,"column":20},"end":{"line":1059,"column":33}},"450":{"start":{"line":1060,"column":4},"end":{"line":1062,"column":5}},"451":{"start":{"line":1061,"column":6},"end":{"line":1061,"column":null}},"452":{"start":{"line":1064,"column":2},"end":{"line":1064,"column":null}},"453":{"start":{"line":1071,"column":16},"end":{"line":1071,"column":77}},"454":{"start":{"line":1072,"column":2},"end":{"line":1074,"column":3}},"455":{"start":{"line":1073,"column":4},"end":{"line":1073,"column":null}},"456":{"start":{"line":1075,"column":18},"end":{"line":1075,"column":54}},"457":{"start":{"line":1076,"column":2},"end":{"line":1081,"column":3}},"458":{"start":{"line":1076,"column":23},"end":{"line":1076,"column":28}},"459":{"start":{"line":1076,"column":23},"end":{"line":1076,"column":39}},"460":{"start":{"line":1076,"column":19},"end":{"line":1076,"column":23}},"461":{"start":{"line":1077,"column":20},"end":{"line":1077,"column":33}},"462":{"start":{"line":1078,"column":4},"end":{"line":1080,"column":5}},"463":{"start":{"line":1079,"column":6},"end":{"line":1079,"column":null}},"464":{"start":{"line":1082,"column":2},"end":{"line":1082,"column":null}},"465":{"start":{"line":1087,"column":4},"end":{"line":1087,"column":70}},"466":{"start":{"line":1088,"column":2},"end":{"line":1090,"column":3}},"467":{"start":{"line":1089,"column":4},"end":{"line":1089,"column":null}},"468":{"start":{"line":1091,"column":18},"end":{"line":1091,"column":59}},"469":{"start":{"line":1092,"column":2},"end":{"line":1097,"column":3}},"470":{"start":{"line":1092,"column":23},"end":{"line":1092,"column":28}},"471":{"start":{"line":1092,"column":23},"end":{"line":1092,"column":39}},"472":{"start":{"line":1092,"column":19},"end":{"line":1092,"column":23}},"473":{"start":{"line":1093,"column":20},"end":{"line":1093,"column":33}},"474":{"start":{"line":1094,"column":4},"end":{"line":1096,"column":5}},"475":{"start":{"line":1095,"column":6},"end":{"line":1095,"column":null}},"476":{"start":{"line":1098,"column":2},"end":{"line":1098,"column":null}},"477":{"start":{"line":1110,"column":2},"end":{"line":1110,"column":null}},"478":{"start":{"line":1110,"column":16},"end":{"line":1110,"column":null}},"479":{"start":{"line":1111,"column":2},"end":{"line":1111,"column":null}},"480":{"start":{"line":1111,"column":52},"end":{"line":1111,"column":68}},"481":{"start":{"line":1124,"column":16},"end":{"line":1124,"column":79}},"482":{"start":{"line":1125,"column":2},"end":{"line":1125,"column":null}},"483":{"start":{"line":1125,"column":14},"end":{"line":1125,"column":null}},"484":{"start":{"line":1126,"column":2},"end":{"line":1128,"column":3}},"485":{"start":{"line":1127,"column":4},"end":{"line":1127,"column":null}},"486":{"start":{"line":1129,"column":16},"end":{"line":1129,"column":63}},"487":{"start":{"line":1130,"column":2},"end":{"line":1140,"column":3}},"488":{"start":{"line":1130,"column":20},"end":{"line":1130,"column":25}},"489":{"start":{"line":1130,"column":20},"end":{"line":1130,"column":36}},"490":{"start":{"line":1130,"column":16},"end":{"line":1130,"column":20}},"491":{"start":{"line":1131,"column":20},"end":{"line":1131,"column":30}},"492":{"start":{"line":1132,"column":4},"end":{"line":1132,"column":26}},"493":{"start":{"line":1132,"column":18},"end":{"line":1132,"column":26}},"494":{"start":{"line":1133,"column":4},"end":{"line":1139,"column":5}},"495":{"start":{"line":1134,"column":6},"end":{"line":1134,"column":null}},"496":{"start":{"line":1136,"column":6},"end":{"line":1138,"column":null}},"497":{"start":{"line":1141,"column":2},"end":{"line":1141,"column":null}},"498":{"start":{"line":1142,"column":2},"end":{"line":1142,"column":null}},"499":{"start":{"line":1143,"column":2},"end":{"line":1143,"column":null}},"500":{"start":{"line":1147,"column":2},"end":{"line":1162,"column":3}},"501":{"start":{"line":1149,"column":6},"end":{"line":1155,"column":null}},"502":{"start":{"line":1157,"column":6},"end":{"line":1157,"column":null}},"503":{"start":{"line":1159,"column":6},"end":{"line":1159,"column":null}},"504":{"start":{"line":1161,"column":6},"end":{"line":1161,"column":null}},"505":{"start":{"line":1166,"column":27},"end":{"line":1166,"column":29}},"506":{"start":{"line":1167,"column":31},"end":{"line":1167,"column":63}},"507":{"start":{"line":1168,"column":19},"end":{"line":1170,"column":null}},"508":{"start":{"line":1172,"column":2},"end":{"line":1180,"column":3}},"509":{"start":{"line":1172,"column":19},"end":{"line":1172,"column":30}},"510":{"start":{"line":1172,"column":15},"end":{"line":1172,"column":19}},"511":{"start":{"line":1173,"column":20},"end":{"line":1173,"column":37}},"512":{"start":{"line":1174,"column":4},"end":{"line":1179,"column":5}},"513":{"start":{"line":1175,"column":21},"end":{"line":1175,"column":68}},"514":{"start":{"line":1176,"column":21},"end":{"line":1176,"column":70}},"515":{"start":{"line":1177,"column":19},"end":{"line":1177,"column":62}},"516":{"start":{"line":1178,"column":6},"end":{"line":1178,"column":null}},"517":{"start":{"line":1181,"column":2},"end":{"line":1181,"column":null}},"518":{"start":{"line":1188,"column":2},"end":{"line":1190,"column":3}},"519":{"start":{"line":1189,"column":4},"end":{"line":1189,"column":null}},"520":{"start":{"line":1191,"column":2},"end":{"line":1193,"column":3}},"521":{"start":{"line":1192,"column":4},"end":{"line":1192,"column":null}},"522":{"start":{"line":1194,"column":2},"end":{"line":1207,"column":3}},"523":{"start":{"line":1195,"column":4},"end":{"line":1206,"column":5}},"524":{"start":{"line":1197,"column":8},"end":{"line":1197,"column":null}},"525":{"start":{"line":1199,"column":8},"end":{"line":1199,"column":null}},"526":{"start":{"line":1201,"column":8},"end":{"line":1201,"column":null}},"527":{"start":{"line":1203,"column":8},"end":{"line":1203,"column":null}},"528":{"start":{"line":1205,"column":8},"end":{"line":1205,"column":null}},"529":{"start":{"line":1208,"column":2},"end":{"line":1208,"column":null}},"530":{"start":{"line":1212,"column":27},"end":{"line":1212,"column":29}},"531":{"start":{"line":1213,"column":31},"end":{"line":1213,"column":66}},"532":{"start":{"line":1214,"column":19},"end":{"line":1216,"column":null}},"533":{"start":{"line":1218,"column":2},"end":{"line":1226,"column":3}},"534":{"start":{"line":1218,"column":19},"end":{"line":1218,"column":30}},"535":{"start":{"line":1218,"column":15},"end":{"line":1218,"column":19}},"536":{"start":{"line":1219,"column":23},"end":{"line":1219,"column":43}},"537":{"start":{"line":1220,"column":4},"end":{"line":1225,"column":5}},"538":{"start":{"line":1221,"column":21},"end":{"line":1221,"column":106}},"539":{"start":{"line":1222,"column":21},"end":{"line":1222,"column":76}},"540":{"start":{"line":1223,"column":19},"end":{"line":1223,"column":89}},"541":{"start":{"line":1224,"column":6},"end":{"line":1224,"column":null}},"542":{"start":{"line":1227,"column":2},"end":{"line":1227,"column":null}},"543":{"start":{"line":1231,"column":2},"end":{"line":1255,"column":3}},"544":{"start":{"line":1233,"column":6},"end":{"line":1238,"column":null}},"545":{"start":{"line":1240,"column":6},"end":{"line":1245,"column":null}},"546":{"start":{"line":1247,"column":6},"end":{"line":1252,"column":null}},"547":{"start":{"line":1254,"column":6},"end":{"line":1254,"column":null}},"548":{"start":{"line":1267,"column":8},"end":{"line":1267,"column":null}},"549":{"start":{"line":1268,"column":2},"end":{"line":1270,"column":3}},"550":{"start":{"line":1269,"column":4},"end":{"line":1269,"column":null}},"551":{"start":{"line":1274,"column":19},"end":{"line":1277,"column":null}},"552":{"start":{"line":1274,"column":10},"end":{"line":1277,"column":null}},"553":{"start":{"line":1278,"column":4},"end":{"line":1278,"column":null}},"554":{"start":{"line":1280,"column":4},"end":{"line":1284,"column":null}},"555":{"start":{"line":1285,"column":4},"end":{"line":1285,"column":null}},"556":{"start":{"line":1288,"column":8},"end":{"line":1288,"column":null}},"557":{"start":{"line":1289,"column":8},"end":{"line":1289,"column":null}},"558":{"start":{"line":1290,"column":2},"end":{"line":1321,"column":3}},"559":{"start":{"line":1290,"column":13},"end":{"line":1290,"column":18}},"560":{"start":{"line":1291,"column":4},"end":{"line":1297,"column":5}},"561":{"start":{"line":1296,"column":6},"end":{"line":1296,"column":14}},"562":{"start":{"line":1301,"column":4},"end":{"line":1311,"column":5}},"563":{"start":{"line":1305,"column":6},"end":{"line":1309,"column":null}},"564":{"start":{"line":1310,"column":6},"end":{"line":1310,"column":14}},"565":{"start":{"line":1312,"column":4},"end":{"line":1314,"column":5}},"566":{"start":{"line":1313,"column":6},"end":{"line":1313,"column":14}},"567":{"start":{"line":1315,"column":4},"end":{"line":1315,"column":null}},"568":{"start":{"line":1316,"column":10},"end":{"line":1316,"column":null}},"569":{"start":{"line":1317,"column":10},"end":{"line":1317,"column":null}},"570":{"start":{"line":1318,"column":10},"end":{"line":1318,"column":null}},"571":{"start":{"line":1319,"column":10},"end":{"line":1319,"column":null}},"572":{"start":{"line":1320,"column":4},"end":{"line":1320,"column":null}},"573":{"start":{"line":1322,"column":2},"end":{"line":1322,"column":null}},"574":{"start":{"line":1334,"column":10},"end":{"line":1334,"column":null}},"575":{"start":{"line":1334,"column":4},"end":{"line":1334,"column":null}},"576":{"start":{"line":1336,"column":4},"end":{"line":1338,"column":null}},"577":{"start":{"line":1341,"column":8},"end":{"line":1341,"column":null}},"578":{"start":{"line":1342,"column":8},"end":{"line":1342,"column":null}},"579":{"start":{"line":1345,"column":8},"end":{"line":1345,"column":null}},"580":{"start":{"line":1346,"column":8},"end":{"line":1348,"column":null}},"581":{"start":{"line":1349,"column":2},"end":{"line":1349,"column":null}},"582":{"start":{"line":1350,"column":2},"end":{"line":1352,"column":3}},"583":{"start":{"line":1351,"column":4},"end":{"line":1351,"column":null}},"584":{"start":{"line":1355,"column":2},"end":{"line":1361,"column":3}},"585":{"start":{"line":1355,"column":13},"end":{"line":1355,"column":21}},"586":{"start":{"line":1356,"column":4},"end":{"line":1360,"column":5}},"587":{"start":{"line":1357,"column":12},"end":{"line":1357,"column":null}},"588":{"start":{"line":1358,"column":12},"end":{"line":1358,"column":null}},"589":{"start":{"line":1359,"column":6},"end":{"line":1359,"column":null}},"590":{"start":{"line":1362,"column":2},"end":{"line":1362,"column":null}},"591":{"start":{"line":1365,"column":8},"end":{"line":1365,"column":null}},"592":{"start":{"line":1366,"column":8},"end":{"line":1369,"column":null}},"593":{"start":{"line":1370,"column":8},"end":{"line":1370,"column":null}},"594":{"start":{"line":1371,"column":2},"end":{"line":1392,"column":3}},"595":{"start":{"line":1371,"column":13},"end":{"line":1371,"column":19}},"596":{"start":{"line":1372,"column":10},"end":{"line":1372,"column":null}},"597":{"start":{"line":1373,"column":4},"end":{"line":1382,"column":5}},"598":{"start":{"line":1376,"column":6},"end":{"line":1381,"column":7}},"599":{"start":{"line":1377,"column":14},"end":{"line":1377,"column":null}},"600":{"start":{"line":1378,"column":8},"end":{"line":1380,"column":null}},"601":{"start":{"line":1383,"column":10},"end":{"line":1383,"column":null}},"602":{"start":{"line":1385,"column":4},"end":{"line":1391,"column":5}},"603":{"start":{"line":1386,"column":12},"end":{"line":1386,"column":null}},"604":{"start":{"line":1387,"column":12},"end":{"line":1387,"column":null}},"605":{"start":{"line":1388,"column":6},"end":{"line":1390,"column":null}},"606":{"start":{"line":1393,"column":2},"end":{"line":1395,"column":3}},"607":{"start":{"line":1394,"column":4},"end":{"line":1394,"column":null}},"608":{"start":{"line":1398,"column":21},"end":{"line":1398,"column":null}},"609":{"start":{"line":1398,"column":8},"end":{"line":1398,"column":null}},"610":{"start":{"line":1399,"column":2},"end":{"line":1401,"column":3}},"611":{"start":{"line":1400,"column":4},"end":{"line":1400,"column":null}},"612":{"start":{"line":1403,"column":2},"end":{"line":1405,"column":3}},"613":{"start":{"line":1404,"column":4},"end":{"line":1404,"column":null}},"614":{"start":{"line":1406,"column":2},"end":{"line":1406,"column":null}},"615":{"start":{"line":1415,"column":19},"end":{"line":1418,"column":null}},"616":{"start":{"line":1415,"column":10},"end":{"line":1418,"column":null}},"617":{"start":{"line":1419,"column":4},"end":{"line":1419,"column":null}},"618":{"start":{"line":1421,"column":4},"end":{"line":1425,"column":null}},"619":{"start":{"line":1426,"column":4},"end":{"line":1426,"column":null}},"620":{"start":{"line":1429,"column":8},"end":{"line":1429,"column":null}},"621":{"start":{"line":1429,"column":37},"end":{"line":1429,"column":58}},"622":{"start":{"line":1430,"column":2},"end":{"line":1432,"column":3}},"623":{"start":{"line":1431,"column":4},"end":{"line":1431,"column":null}},"624":{"start":{"line":1434,"column":8},"end":{"line":1437,"column":null}},"625":{"start":{"line":1435,"column":14},"end":{"line":1435,"column":64}},"626":{"start":{"line":1436,"column":4},"end":{"line":1436,"column":null}},"627":{"start":{"line":1438,"column":2},"end":{"line":1438,"column":null}},"628":{"start":{"line":1438,"column":26},"end":{"line":1438,"column":54}},"629":{"start":{"line":1440,"column":8},"end":{"line":1440,"column":null}},"630":{"start":{"line":1441,"column":8},"end":{"line":1444,"column":null}},"631":{"start":{"line":1442,"column":18},"end":{"line":1442,"column":64}},"632":{"start":{"line":1443,"column":4},"end":{"line":1443,"column":null}},"633":{"start":{"line":1445,"column":2},"end":{"line":1449,"column":3}},"634":{"start":{"line":1446,"column":4},"end":{"line":1448,"column":null}},"635":{"start":{"line":1450,"column":2},"end":{"line":1450,"column":null}},"636":{"start":{"line":1460,"column":2},"end":{"line":1460,"column":null}},"637":{"start":{"line":1474,"column":8},"end":{"line":1474,"column":null}},"638":{"start":{"line":1476,"column":8},"end":{"line":1476,"column":null}},"639":{"start":{"line":1478,"column":22},"end":{"line":1478,"column":null}},"640":{"start":{"line":1478,"column":8},"end":{"line":1478,"column":null}},"641":{"start":{"line":1482,"column":8},"end":{"line":1487,"column":null}},"642":{"start":{"line":1484,"column":6},"end":{"line":1486,"column":null}},"643":{"start":{"line":1485,"column":13},"end":{"line":1485,"column":null}},"644":{"start":{"line":1488,"column":2},"end":{"line":1492,"column":null}},"645":{"start":{"line":1500,"column":2},"end":{"line":1500,"column":null}},"646":{"start":{"line":1502,"column":8},"end":{"line":1502,"column":null}},"647":{"start":{"line":1503,"column":6},"end":{"line":1503,"column":null}},"648":{"start":{"line":1504,"column":9},"end":{"line":1504,"column":null}},"649":{"start":{"line":1504,"column":13},"end":{"line":1504,"column":null}},"650":{"start":{"line":1505,"column":8},"end":{"line":1505,"column":null}},"651":{"start":{"line":1507,"column":12},"end":{"line":1507,"column":null}},"652":{"start":{"line":1507,"column":6},"end":{"line":1507,"column":null}},"653":{"start":{"line":1512,"column":6},"end":{"line":1516,"column":null}},"654":{"start":{"line":1518,"column":8},"end":{"line":1518,"column":null}},"655":{"start":{"line":1520,"column":8},"end":{"line":1524,"column":null}},"656":{"start":{"line":1526,"column":6},"end":{"line":1526,"column":14}},"657":{"start":{"line":1528,"column":4},"end":{"line":1528,"column":null}},"658":{"start":{"line":1529,"column":4},"end":{"line":1531,"column":5}},"659":{"start":{"line":1530,"column":6},"end":{"line":1530,"column":12}},"660":{"start":{"line":1538,"column":8},"end":{"line":1538,"column":9}},"661":{"start":{"line":1539,"column":21},"end":{"line":1539,"column":null}},"662":{"start":{"line":1539,"column":12},"end":{"line":1539,"column":null}},"663":{"start":{"line":1540,"column":22},"end":{"line":1540,"column":null}},"664":{"start":{"line":1540,"column":12},"end":{"line":1540,"column":null}},"665":{"start":{"line":1541,"column":6},"end":{"line":1545,"column":7}},"666":{"start":{"line":1542,"column":8},"end":{"line":1544,"column":null}},"667":{"start":{"line":1546,"column":6},"end":{"line":1548,"column":null}},"668":{"start":{"line":1554,"column":19},"end":{"line":1554,"column":null}},"669":{"start":{"line":1554,"column":10},"end":{"line":1554,"column":null}},"670":{"start":{"line":1555,"column":8},"end":{"line":1555,"column":14}},"671":{"start":{"line":1556,"column":22},"end":{"line":1556,"column":null}},"672":{"start":{"line":1556,"column":12},"end":{"line":1556,"column":null}},"673":{"start":{"line":1557,"column":6},"end":{"line":1559,"column":null}},"674":{"start":{"line":1563,"column":6},"end":{"line":1563,"column":null}},"675":{"start":{"line":1568,"column":22},"end":{"line":1568,"column":null}},"676":{"start":{"line":1568,"column":12},"end":{"line":1568,"column":null}},"677":{"start":{"line":1569,"column":6},"end":{"line":1571,"column":null}},"678":{"start":{"line":1578,"column":4},"end":{"line":1578,"column":61}},"679":{"start":{"line":1580,"column":2},"end":{"line":1582,"column":3}},"680":{"start":{"line":1581,"column":4},"end":{"line":1581,"column":null}},"681":{"start":{"line":1584,"column":25},"end":{"line":1584,"column":56}},"682":{"start":{"line":1585,"column":2},"end":{"line":1590,"column":3}},"683":{"start":{"line":1586,"column":4},"end":{"line":1588,"column":null}},"684":{"start":{"line":1589,"column":4},"end":{"line":1589,"column":null}},"685":{"start":{"line":1592,"column":2},"end":{"line":1592,"column":null}},"686":{"start":{"line":1596,"column":9},"end":{"line":1599,"column":null}},"687":{"start":{"line":1596,"column":2},"end":{"line":1599,"column":null}},"688":{"start":{"line":1602,"column":23},"end":{"line":1608,"column":2}},"689":{"start":{"line":1611,"column":2},"end":{"line":1613,"column":3}},"690":{"start":{"line":1612,"column":4},"end":{"line":1612,"column":null}},"691":{"start":{"line":1614,"column":2},"end":{"line":1614,"column":null}},"692":{"start":{"line":1618,"column":14},"end":{"line":1621,"column":null}},"693":{"start":{"line":1618,"column":8},"end":{"line":1621,"column":null}},"694":{"start":{"line":1622,"column":2},"end":{"line":1624,"column":3}},"695":{"start":{"line":1623,"column":4},"end":{"line":1623,"column":null}},"696":{"start":{"line":1625,"column":2},"end":{"line":1625,"column":null}},"697":{"start":{"line":1632,"column":8},"end":{"line":1632,"column":null}},"698":{"start":{"line":1633,"column":8},"end":{"line":1633,"column":null}},"699":{"start":{"line":1634,"column":2},"end":{"line":1637,"column":null}},"700":{"start":{"line":1636,"column":4},"end":{"line":1636,"column":null}},"701":{"start":{"line":1639,"column":2},"end":{"line":1643,"column":null}},"702":{"start":{"line":1644,"column":2},"end":{"line":1650,"column":null}},"703":{"start":{"line":1645,"column":4},"end":{"line":1645,"column":null}},"704":{"start":{"line":1645,"column":30},"end":{"line":1645,"column":44}},"705":{"start":{"line":1646,"column":4},"end":{"line":1649,"column":null}},"706":{"start":{"line":1647,"column":6},"end":{"line":1647,"column":null}},"707":{"start":{"line":1648,"column":6},"end":{"line":1648,"column":null}},"708":{"start":{"line":1654,"column":18},"end":{"line":1657,"column":null}},"709":{"start":{"line":1654,"column":8},"end":{"line":1657,"column":null}},"710":{"start":{"line":1658,"column":2},"end":{"line":1660,"column":3}},"711":{"start":{"line":1659,"column":4},"end":{"line":1659,"column":10}},"712":{"start":{"line":1662,"column":2},"end":{"line":1666,"column":null}},"713":{"start":{"line":1664,"column":15},"end":{"line":1664,"column":null}},"714":{"start":{"line":1664,"column":19},"end":{"line":1664,"column":41}},"715":{"start":{"line":1664,"column":42},"end":{"line":1664,"column":77}},"716":{"start":{"line":1664,"column":41},"end":{"line":1664,"column":null}},"717":{"start":{"line":1664,"column":19},"end":{"line":1664,"column":22}},"718":{"start":{"line":1672,"column":14},"end":{"line":1675,"column":null}},"719":{"start":{"line":1672,"column":8},"end":{"line":1675,"column":null}},"720":{"start":{"line":1676,"column":2},"end":{"line":1676,"column":null}},"721":{"start":{"line":1680,"column":8},"end":{"line":1680,"column":null}},"722":{"start":{"line":1681,"column":8},"end":{"line":1681,"column":null}},"723":{"start":{"line":1682,"column":2},"end":{"line":1695,"column":3}},"724":{"start":{"line":1682,"column":13},"end":{"line":1682,"column":25}},"725":{"start":{"line":1683,"column":4},"end":{"line":1694,"column":5}},"726":{"start":{"line":1683,"column":15},"end":{"line":1683,"column":23}},"727":{"start":{"line":1684,"column":6},"end":{"line":1684,"column":null}},"728":{"start":{"line":1685,"column":6},"end":{"line":1685,"column":null}},"729":{"start":{"line":1686,"column":6},"end":{"line":1686,"column":null}},"730":{"start":{"line":1687,"column":6},"end":{"line":1687,"column":null}},"731":{"start":{"line":1688,"column":6},"end":{"line":1688,"column":null}},"732":{"start":{"line":1689,"column":6},"end":{"line":1689,"column":null}},"733":{"start":{"line":1690,"column":6},"end":{"line":1690,"column":null}},"734":{"start":{"line":1691,"column":6},"end":{"line":1693,"column":null}},"735":{"start":{"line":1696,"column":20},"end":{"line":1696,"column":null}},"736":{"start":{"line":1696,"column":8},"end":{"line":1696,"column":null}},"737":{"start":{"line":1697,"column":2},"end":{"line":1697,"column":null}},"738":{"start":{"line":1697,"column":33},"end":{"line":1697,"column":54}},"739":{"start":{"line":1704,"column":6},"end":{"line":1704,"column":null}},"740":{"start":{"line":1706,"column":4},"end":{"line":1714,"column":null}},"741":{"start":{"line":1716,"column":4},"end":{"line":1716,"column":null}},"742":{"start":{"line":1719,"column":2},"end":{"line":1719,"column":null}},"743":{"start":{"line":1723,"column":2},"end":{"line":1725,"column":3}},"744":{"start":{"line":1724,"column":4},"end":{"line":1724,"column":null}},"745":{"start":{"line":1727,"column":18},"end":{"line":1727,"column":61}},"746":{"start":{"line":1727,"column":47},"end":{"line":1727,"column":61}},"747":{"start":{"line":1728,"column":2},"end":{"line":1730,"column":3}},"748":{"start":{"line":1729,"column":4},"end":{"line":1729,"column":null}},"749":{"start":{"line":1735,"column":4},"end":{"line":1735,"column":61}},"750":{"start":{"line":1736,"column":2},"end":{"line":1743,"column":3}},"751":{"start":{"line":1737,"column":15},"end":{"line":1737,"column":62}},"752":{"start":{"line":1738,"column":4},"end":{"line":1740,"column":5}},"753":{"start":{"line":1739,"column":6},"end":{"line":1739,"column":null}},"754":{"start":{"line":1745,"column":2},"end":{"line":1747,"column":null}},"755":{"start":{"line":1750,"column":0},"end":{"line":1750,"column":null}},"756":{"start":{"line":1753,"column":22},"end":{"line":1753,"column":48}},"757":{"start":{"line":1751,"column":10},"end":{"line":1751,"column":null}},"758":{"start":{"line":1752,"column":2},"end":{"line":1752,"column":null}},"759":{"start":{"line":1754,"column":4},"end":{"line":1756,"column":5}},"760":{"start":{"line":1755,"column":6},"end":{"line":1755,"column":null}},"761":{"start":{"line":1759,"column":8},"end":{"line":1773,"column":null}},"762":{"start":{"line":1760,"column":4},"end":{"line":1762,"column":null}},"763":{"start":{"line":1761,"column":6},"end":{"line":1761,"column":null}},"764":{"start":{"line":1763,"column":4},"end":{"line":1763,"column":null}},"765":{"start":{"line":1764,"column":4},"end":{"line":1766,"column":5}},"766":{"start":{"line":1765,"column":6},"end":{"line":1765,"column":null}},"767":{"start":{"line":1767,"column":4},"end":{"line":1769,"column":5}},"768":{"start":{"line":1768,"column":6},"end":{"line":1768,"column":null}},"769":{"start":{"line":1770,"column":4},"end":{"line":1772,"column":5}},"770":{"start":{"line":1771,"column":6},"end":{"line":1771,"column":null}},"771":{"start":{"line":1774,"column":0},"end":{"line":1774,"column":null}},"772":{"start":{"line":1779,"column":39},"end":{"line":1779,"column":41}},"773":{"start":{"line":1780,"column":2},"end":{"line":1782,"column":3}},"774":{"start":{"line":1781,"column":4},"end":{"line":1781,"column":null}},"775":{"start":{"line":1783,"column":2},"end":{"line":1814,"column":3}},"776":{"start":{"line":1783,"column":31},"end":{"line":1783,"column":40}},"777":{"start":{"line":1783,"column":31},"end":{"line":1783,"column":53}},"778":{"start":{"line":1783,"column":27},"end":{"line":1783,"column":31}},"779":{"start":{"line":1784,"column":27},"end":{"line":1784,"column":52}},"780":{"start":{"line":1785,"column":4},"end":{"line":1787,"column":5}},"781":{"start":{"line":1786,"column":6},"end":{"line":1786,"column":null}},"782":{"start":{"line":1789,"column":17},"end":{"line":1789,"column":42}},"783":{"start":{"line":1790,"column":4},"end":{"line":1791,"column":null}},"784":{"start":{"line":1793,"column":22},"end":{"line":1793,"column":50}},"785":{"start":{"line":1794,"column":4},"end":{"line":1796,"column":5}},"786":{"start":{"line":1795,"column":6},"end":{"line":1795,"column":null}},"787":{"start":{"line":1798,"column":22},"end":{"line":1804,"column":5}},"788":{"start":{"line":1799,"column":18},"end":{"line":1799,"column":27}},"789":{"start":{"line":1800,"column":6},"end":{"line":1802,"column":7}},"790":{"start":{"line":1801,"column":8},"end":{"line":1801,"column":null}},"791":{"start":{"line":1803,"column":6},"end":{"line":1803,"column":null}},"792":{"start":{"line":1806,"column":4},"end":{"line":1811,"column":5}},"793":{"start":{"line":1807,"column":6},"end":{"line":1807,"column":null}},"794":{"start":{"line":1809,"column":6},"end":{"line":1809,"column":null}},"795":{"start":{"line":1810,"column":6},"end":{"line":1810,"column":null}},"796":{"start":{"line":1813,"column":4},"end":{"line":1813,"column":null}},"797":{"start":{"line":1815,"column":2},"end":{"line":1815,"column":null}},"798":{"start":{"line":1819,"column":9},"end":{"line":1822,"column":null}},"799":{"start":{"line":1819,"column":2},"end":{"line":1822,"column":null}},"800":{"start":{"line":1826,"column":9},"end":{"line":1829,"column":null}},"801":{"start":{"line":1826,"column":2},"end":{"line":1829,"column":null}},"802":{"start":{"line":1833,"column":18},"end":{"line":1836,"column":null}},"803":{"start":{"line":1833,"column":8},"end":{"line":1836,"column":null}},"804":{"start":{"line":1837,"column":2},"end":{"line":1837,"column":null}}},"fnMap":{"0":{"name":"createJobPod","decl":{"start":{"line":69,"column":22},"end":{"line":69,"column":34}},"loc":{"start":{"line":74,"column":35},"end":{"line":187,"column":null}}},"1":{"name":"createContainerStepPod","decl":{"start":{"line":189,"column":22},"end":{"line":189,"column":44}},"loc":{"start":{"line":192,"column":35},"end":{"line":240,"column":null}}},"2":{"name":"deletePod","decl":{"start":{"line":242,"column":22},"end":{"line":242,"column":31}},"loc":{"start":{"line":242,"column":44},"end":{"line":248,"column":null}}},"3":{"name":"execPodStep","decl":{"start":{"line":250,"column":22},"end":{"line":250,"column":33}},"loc":{"start":{"line":254,"column":25},"end":{"line":372,"column":null}}},"4":{"name":"(anonymous_36)","decl":{"start":{"line":278,"column":29},"end":{"line":278,"column":30}},"loc":{"start":{"line":278,"column":45},"end":{"line":371,"column":3}}},"5":{"name":"(anonymous_37)","decl":{"start":{"line":292,"column":8},"end":{"line":292,"column":14}},"loc":{"start":{"line":292,"column":18},"end":{"line":335,"column":null}}},"6":{"name":"(anonymous_38)","decl":{"start":{"line":292,"column":18},"end":{"line":292,"column":null}},"loc":{"start":{"line":292,"column":18},"end":{"line":335,"column":null}}},"7":{"name":"(anonymous_40)","decl":{"start":{"line":300,"column":33},"end":{"line":300,"column":null}},"loc":{"start":{"line":300,"column":33},"end":{"line":322,"column":null}}},"8":{"name":"(anonymous_43)","decl":{"start":{"line":306,"column":39},"end":{"line":306,"column":51}},"loc":{"start":{"line":306,"column":51},"end":{"line":320,"column":15}}},"9":{"name":"(anonymous_44)","decl":{"start":{"line":307,"column":48},"end":{"line":307,"column":null}},"loc":{"start":{"line":307,"column":48},"end":{"line":312,"column":17}}},"10":{"name":"(anonymous_45)","decl":{"start":{"line":314,"column":37},"end":{"line":314,"column":null}},"loc":{"start":{"line":314,"column":37},"end":{"line":318,"column":17}}},"11":{"name":"(anonymous_46)","decl":{"start":{"line":337,"column":12},"end":{"line":337,"column":21}},"loc":{"start":{"line":337,"column":21},"end":{"line":345,"column":7}}},"12":{"name":"(anonymous_47)","decl":{"start":{"line":346,"column":13},"end":{"line":346,"column":19}},"loc":{"start":{"line":346,"column":20},"end":{"line":370,"column":8}}},"13":{"name":"(anonymous_48)","decl":{"start":{"line":346,"column":20},"end":{"line":346,"column":null}},"loc":{"start":{"line":346,"column":20},"end":{"line":370,"column":8}}},"14":{"name":"(anonymous_50)","decl":{"start":{"line":353,"column":34},"end":{"line":353,"column":46}},"loc":{"start":{"line":353,"column":46},"end":{"line":366,"column":11}}},"15":{"name":"(anonymous_51)","decl":{"start":{"line":354,"column":44},"end":{"line":354,"column":null}},"loc":{"start":{"line":354,"column":44},"end":{"line":359,"column":13}}},"16":{"name":"(anonymous_52)","decl":{"start":{"line":361,"column":33},"end":{"line":361,"column":null}},"loc":{"start":{"line":361,"column":33},"end":{"line":364,"column":13}}},"17":{"name":"execPodStepWithOutput","decl":{"start":{"line":379,"column":22},"end":{"line":379,"column":43}},"loc":{"start":{"line":379,"column":43},"end":{"line":501,"column":null}}},"18":{"name":"(anonymous_56)","decl":{"start":{"line":391,"column":15},"end":{"line":391,"column":16}},"loc":{"start":{"line":391,"column":28},"end":{"line":395,"column":3}}},"19":{"name":"(anonymous_57)","decl":{"start":{"line":399,"column":20},"end":{"line":399,"column":21}},"loc":{"start":{"line":399,"column":43},"end":{"line":404,"column":3}}},"20":{"name":"(anonymous_58)","decl":{"start":{"line":407,"column":20},"end":{"line":407,"column":21}},"loc":{"start":{"line":407,"column":43},"end":{"line":412,"column":3}}},"21":{"name":"(anonymous_59)","decl":{"start":{"line":414,"column":23},"end":{"line":414,"column":null}},"loc":{"start":{"line":414,"column":23},"end":{"line":423,"column":3}}},"22":{"name":"(anonymous_60)","decl":{"start":{"line":426,"column":9},"end":{"line":426,"column":10}},"loc":{"start":{"line":426,"column":42},"end":{"line":434,"column":5}}},"23":{"name":"(anonymous_61)","decl":{"start":{"line":437,"column":9},"end":{"line":437,"column":10}},"loc":{"start":{"line":437,"column":42},"end":{"line":445,"column":5}}},"24":{"name":"(anonymous_62)","decl":{"start":{"line":451,"column":24},"end":{"line":451,"column":25}},"loc":{"start":{"line":451,"column":48},"end":{"line":454,"column":3}}},"25":{"name":"(anonymous_63)","decl":{"start":{"line":456,"column":27},"end":{"line":456,"column":37}},"loc":{"start":{"line":456,"column":52},"end":{"line":500,"column":3}}},"26":{"name":"(anonymous_64)","decl":{"start":{"line":467,"column":8},"end":{"line":467,"column":12}},"loc":{"start":{"line":467,"column":12},"end":{"line":483,"column":9}}},"27":{"name":"(anonymous_65)","decl":{"start":{"line":485,"column":13},"end":{"line":485,"column":14}},"loc":{"start":{"line":485,"column":14},"end":{"line":499,"column":7}}},"28":{"name":"execCalculateOutputHashSorted","decl":{"start":{"line":503,"column":22},"end":{"line":503,"column":51}},"loc":{"start":{"line":506,"column":19},"end":{"line":563,"column":null}}},"29":{"name":"(anonymous_69)","decl":{"start":{"line":512,"column":9},"end":{"line":512,"column":10}},"loc":{"start":{"line":512,"column":25},"end":{"line":519,"column":5}}},"30":{"name":"(anonymous_70)","decl":{"start":{"line":522,"column":26},"end":{"line":522,"column":27}},"loc":{"start":{"line":522,"column":42},"end":{"line":549,"column":3}}},"31":{"name":"(anonymous_71)","decl":{"start":{"line":533,"column":8},"end":{"line":533,"column":12}},"loc":{"start":{"line":533,"column":12},"end":{"line":546,"column":9}}},"32":{"name":"(anonymous_72)","decl":{"start":{"line":548,"column":13},"end":{"line":548,"column":14}},"loc":{"start":{"line":548,"column":14},"end":{"line":548,"column":24}}},"33":{"name":"(anonymous_73)","decl":{"start":{"line":556,"column":12},"end":{"line":556,"column":16}},"loc":{"start":{"line":556,"column":16},"end":{"line":556,"column":24}}},"34":{"name":"localCalculateOutputHashSorted","decl":{"start":{"line":565,"column":22},"end":{"line":565,"column":52}},"loc":{"start":{"line":566,"column":20},"end":{"line":597,"column":null}}},"35":{"name":"(anonymous_77)","decl":{"start":{"line":569,"column":4},"end":{"line":569,"column":5}},"loc":{"start":{"line":569,"column":20},"end":{"line":595,"column":5}}},"36":{"name":"(anonymous_78)","decl":{"start":{"line":575,"column":30},"end":{"line":575,"column":35}},"loc":{"start":{"line":575,"column":35},"end":{"line":577,"column":7}}},"37":{"name":"(anonymous_79)","decl":{"start":{"line":579,"column":24},"end":{"line":579,"column":25}},"loc":{"start":{"line":579,"column":37},"end":{"line":594,"column":7}}},"38":{"name":"(anonymous_80)","decl":{"start":{"line":584,"column":20},"end":{"line":584,"column":24}},"loc":{"start":{"line":584,"column":24},"end":{"line":584,"column":32}}},"39":{"name":"execCpToPod","decl":{"start":{"line":599,"column":22},"end":{"line":599,"column":33}},"loc":{"start":{"line":602,"column":23},"end":{"line":718,"column":null}}},"40":{"name":"(anonymous_86)","decl":{"start":{"line":622,"column":24},"end":{"line":622,"column":25}},"loc":{"start":{"line":622,"column":40},"end":{"line":645,"column":7}}},"41":{"name":"(anonymous_87)","decl":{"start":{"line":633,"column":12},"end":{"line":633,"column":18}},"loc":{"start":{"line":633,"column":24},"end":{"line":642,"column":null}}},"42":{"name":"(anonymous_88)","decl":{"start":{"line":633,"column":24},"end":{"line":633,"column":null}},"loc":{"start":{"line":633,"column":24},"end":{"line":642,"column":null}}},"43":{"name":"(anonymous_90)","decl":{"start":{"line":644,"column":17},"end":{"line":644,"column":18}},"loc":{"start":{"line":644,"column":18},"end":{"line":644,"column":28}}},"44":{"name":"(anonymous_93)","decl":{"start":{"line":685,"column":24},"end":{"line":685,"column":25}},"loc":{"start":{"line":685,"column":25},"end":{"line":685,"column":30}}},"45":{"name":"(anonymous_94)","decl":{"start":{"line":688,"column":23},"end":{"line":688,"column":24}},"loc":{"start":{"line":688,"column":24},"end":{"line":688,"column":29}}},"46":{"name":"(anonymous_95)","decl":{"start":{"line":691,"column":10},"end":{"line":691,"column":11}},"loc":{"start":{"line":691,"column":11},"end":{"line":691,"column":16}}},"47":{"name":"(anonymous_96)","decl":{"start":{"line":694,"column":10},"end":{"line":694,"column":11}},"loc":{"start":{"line":694,"column":11},"end":{"line":694,"column":16}}},"48":{"name":"(anonymous_97)","decl":{"start":{"line":697,"column":18},"end":{"line":697,"column":19}},"loc":{"start":{"line":697,"column":19},"end":{"line":700,"column":11}}},"49":{"name":"(anonymous_98)","decl":{"start":{"line":701,"column":15},"end":{"line":701,"column":16}},"loc":{"start":{"line":701,"column":16},"end":{"line":704,"column":11}}},"50":{"name":"execCpFromPod","decl":{"start":{"line":720,"column":22},"end":{"line":720,"column":35}},"loc":{"start":{"line":723,"column":26},"end":{"line":857,"column":null}}},"51":{"name":"(anonymous_104)","decl":{"start":{"line":756,"column":24},"end":{"line":756,"column":25}},"loc":{"start":{"line":756,"column":40},"end":{"line":784,"column":7}}},"52":{"name":"(anonymous_105)","decl":{"start":{"line":773,"column":12},"end":{"line":773,"column":19}},"loc":{"start":{"line":773,"column":35},"end":{"line":781,"column":null}}},"53":{"name":"(anonymous_106)","decl":{"start":{"line":773,"column":35},"end":{"line":773,"column":null}},"loc":{"start":{"line":773,"column":35},"end":{"line":781,"column":null}}},"54":{"name":"(anonymous_108)","decl":{"start":{"line":783,"column":17},"end":{"line":783,"column":18}},"loc":{"start":{"line":783,"column":18},"end":{"line":783,"column":28}}},"55":{"name":"(anonymous_111)","decl":{"start":{"line":824,"column":24},"end":{"line":824,"column":25}},"loc":{"start":{"line":824,"column":25},"end":{"line":824,"column":30}}},"56":{"name":"(anonymous_112)","decl":{"start":{"line":827,"column":23},"end":{"line":827,"column":24}},"loc":{"start":{"line":827,"column":24},"end":{"line":827,"column":29}}},"57":{"name":"(anonymous_113)","decl":{"start":{"line":830,"column":10},"end":{"line":830,"column":11}},"loc":{"start":{"line":830,"column":11},"end":{"line":830,"column":16}}},"58":{"name":"(anonymous_114)","decl":{"start":{"line":833,"column":10},"end":{"line":833,"column":11}},"loc":{"start":{"line":833,"column":11},"end":{"line":833,"column":16}}},"59":{"name":"(anonymous_115)","decl":{"start":{"line":836,"column":18},"end":{"line":836,"column":19}},"loc":{"start":{"line":836,"column":19},"end":{"line":839,"column":11}}},"60":{"name":"(anonymous_116)","decl":{"start":{"line":840,"column":15},"end":{"line":840,"column":16}},"loc":{"start":{"line":840,"column":16},"end":{"line":843,"column":11}}},"61":{"name":"waitForJobToComplete","decl":{"start":{"line":859,"column":22},"end":{"line":859,"column":42}},"loc":{"start":{"line":859,"column":58},"end":{"line":871,"column":null}}},"62":{"name":"createDockerSecret","decl":{"start":{"line":873,"column":22},"end":{"line":873,"column":40}},"loc":{"start":{"line":874,"column":20},"end":{"line":912,"column":null}}},"63":{"name":"createSecretForEnvs","decl":{"start":{"line":914,"column":22},"end":{"line":914,"column":41}},"loc":{"start":{"line":916,"column":1},"end":{"line":940,"column":null}}},"64":{"name":"deleteSecret","decl":{"start":{"line":942,"column":22},"end":{"line":942,"column":34}},"loc":{"start":{"line":942,"column":47},"end":{"line":947,"column":null}}},"65":{"name":"pruneSecrets","decl":{"start":{"line":949,"column":22},"end":{"line":949,"column":34}},"loc":{"start":{"line":949,"column":34},"end":{"line":964,"column":null}}},"66":{"name":"(anonymous_132)","decl":{"start":{"line":960,"column":6},"end":{"line":960,"column":12}},"loc":{"start":{"line":960,"column":18},"end":{"line":961,"column":null}}},"67":{"name":"(anonymous_133)","decl":{"start":{"line":960,"column":18},"end":{"line":960,"column":null}},"loc":{"start":{"line":960,"column":18},"end":{"line":961,"column":null}}},"68":{"name":"getUnrecoverableWaitingReasons","decl":{"start":{"line":1052,"column":16},"end":{"line":1052,"column":46}},"loc":{"start":{"line":1052,"column":46},"end":{"line":1065,"column":1}}},"69":{"name":"getUnrecoverableEventReasons","decl":{"start":{"line":1070,"column":16},"end":{"line":1070,"column":44}},"loc":{"start":{"line":1070,"column":44},"end":{"line":1083,"column":1}}},"70":{"name":"getUnrecoverableTerminatedReasons","decl":{"start":{"line":1085,"column":16},"end":{"line":1085,"column":49}},"loc":{"start":{"line":1085,"column":49},"end":{"line":1099,"column":1}}},"71":{"name":"isPermanentSchedulingFailure","decl":{"start":{"line":1107,"column":16},"end":{"line":1107,"column":44}},"loc":{"start":{"line":1108,"column":29},"end":{"line":1112,"column":1}}},"72":{"name":"(anonymous_139)","decl":{"start":{"line":1111,"column":47},"end":{"line":1111,"column":48}},"loc":{"start":{"line":1111,"column":48},"end":{"line":1111,"column":53}}},"73":{"name":"getPermanentSchedulingPatterns","decl":{"start":{"line":1123,"column":16},"end":{"line":1123,"column":46}},"loc":{"start":{"line":1123,"column":46},"end":{"line":1144,"column":1}}},"74":{"name":"getWaitingReasonHint","decl":{"start":{"line":1146,"column":9},"end":{"line":1146,"column":29}},"loc":{"start":{"line":1146,"column":44},"end":{"line":1163,"column":1}}},"75":{"name":"getContainerErrors","decl":{"start":{"line":1165,"column":16},"end":{"line":1165,"column":34}},"loc":{"start":{"line":1165,"column":49},"end":{"line":1182,"column":1}}},"76":{"name":"getTerminatedReasonHint","decl":{"start":{"line":1184,"column":16},"end":{"line":1184,"column":39}},"loc":{"start":{"line":1186,"column":30},"end":{"line":1209,"column":1}}},"77":{"name":"getContainerTerminatedErrors","decl":{"start":{"line":1211,"column":16},"end":{"line":1211,"column":44}},"loc":{"start":{"line":1211,"column":59},"end":{"line":1228,"column":1}}},"78":{"name":"getEventReasonHint","decl":{"start":{"line":1230,"column":9},"end":{"line":1230,"column":27}},"loc":{"start":{"line":1230,"column":42},"end":{"line":1256,"column":1}}},"79":{"name":"getPodEventErrors","decl":{"start":{"line":1266,"column":22},"end":{"line":1266,"column":39}},"loc":{"start":{"line":1266,"column":55},"end":{"line":1323,"column":null}}},"80":{"name":"describePodFailure","decl":{"start":{"line":1331,"column":22},"end":{"line":1331,"column":40}},"loc":{"start":{"line":1331,"column":56},"end":{"line":1407,"column":null}}},"81":{"name":"describePodWarningEvents","decl":{"start":{"line":1412,"column":15},"end":{"line":1412,"column":39}},"loc":{"start":{"line":1412,"column":55},"end":{"line":1451,"column":null}}},"82":{"name":"(anonymous_155)","decl":{"start":{"line":1429,"column":32},"end":{"line":1429,"column":33}},"loc":{"start":{"line":1429,"column":33},"end":{"line":1429,"column":38}}},"83":{"name":"(anonymous_156)","decl":{"start":{"line":1434,"column":20},"end":{"line":1434,"column":21}},"loc":{"start":{"line":1434,"column":39},"end":{"line":1437,"column":3}}},"84":{"name":"(anonymous_157)","decl":{"start":{"line":1438,"column":16},"end":{"line":1438,"column":17}},"loc":{"start":{"line":1438,"column":21},"end":{"line":1438,"column":35}}},"85":{"name":"(anonymous_158)","decl":{"start":{"line":1441,"column":27},"end":{"line":1441,"column":28}},"loc":{"start":{"line":1441,"column":28},"end":{"line":1444,"column":3}}},"86":{"name":"getPodConditionErrors","decl":{"start":{"line":1459,"column":16},"end":{"line":1459,"column":37}},"loc":{"start":{"line":1459,"column":51},"end":{"line":1461,"column":1}}},"87":{"name":"checkUnrecoverableErrors","decl":{"start":{"line":1469,"column":22},"end":{"line":1469,"column":46}},"loc":{"start":{"line":1471,"column":17},"end":{"line":1494,"column":null}}},"88":{"name":"(anonymous_163)","decl":{"start":{"line":1483,"column":4},"end":{"line":1483,"column":5}},"loc":{"start":{"line":1483,"column":5},"end":{"line":1484,"column":7}}},"89":{"name":"(anonymous_164)","decl":{"start":{"line":1485,"column":8},"end":{"line":1485,"column":9}},"loc":{"start":{"line":1485,"column":9},"end":{"line":1485,"column":14}}},"90":{"name":"waitForPodPhases","decl":{"start":{"line":1496,"column":22},"end":{"line":1496,"column":38}},"loc":{"start":{"line":1496,"column":38},"end":{"line":1574,"column":null}}},"91":{"name":"getPrepareJobTimeoutSeconds","decl":{"start":{"line":1576,"column":16},"end":{"line":1576,"column":43}},"loc":{"start":{"line":1576,"column":43},"end":{"line":1593,"column":1}}},"92":{"name":"readPod","decl":{"start":{"line":1595,"column":15},"end":{"line":1595,"column":22}},"loc":{"start":{"line":1595,"column":38},"end":{"line":1600,"column":null}}},"93":{"name":"parsePodPhase","decl":{"start":{"line":1610,"column":16},"end":{"line":1610,"column":29}},"loc":{"start":{"line":1610,"column":44},"end":{"line":1615,"column":1}}},"94":{"name":"isJobSucceeded","decl":{"start":{"line":1617,"column":15},"end":{"line":1617,"column":29}},"loc":{"start":{"line":1617,"column":42},"end":{"line":1626,"column":null}}},"95":{"name":"getPodLogs","decl":{"start":{"line":1628,"column":22},"end":{"line":1628,"column":32}},"loc":{"start":{"line":1630,"column":23},"end":{"line":1651,"column":null}}},"96":{"name":"(anonymous_179)","decl":{"start":{"line":1634,"column":23},"end":{"line":1634,"column":28}},"loc":{"start":{"line":1634,"column":28},"end":{"line":1637,"column":3}}},"97":{"name":"(anonymous_180)","decl":{"start":{"line":1644,"column":20},"end":{"line":1644,"column":21}},"loc":{"start":{"line":1644,"column":36},"end":{"line":1650,"column":3}}},"98":{"name":"(anonymous_181)","decl":{"start":{"line":1645,"column":24},"end":{"line":1645,"column":30}},"loc":{"start":{"line":1645,"column":24},"end":{"line":1645,"column":37}}},"99":{"name":"(anonymous_182)","decl":{"start":{"line":1646,"column":26},"end":{"line":1646,"column":29}},"loc":{"start":{"line":1646,"column":29},"end":{"line":1649,"column":5}}},"100":{"name":"prunePods","decl":{"start":{"line":1653,"column":22},"end":{"line":1653,"column":31}},"loc":{"start":{"line":1653,"column":31},"end":{"line":1667,"column":null}}},"101":{"name":"(anonymous_186)","decl":{"start":{"line":1664,"column":6},"end":{"line":1664,"column":12}},"loc":{"start":{"line":1664,"column":15},"end":{"line":1664,"column":null}}},"102":{"name":"(anonymous_187)","decl":{"start":{"line":1664,"column":15},"end":{"line":1664,"column":19}},"loc":{"start":{"line":1664,"column":15},"end":{"line":1664,"column":null}}},"103":{"name":"getPodStatus","decl":{"start":{"line":1669,"column":22},"end":{"line":1669,"column":34}},"loc":{"start":{"line":1670,"column":14},"end":{"line":1677,"column":null}}},"104":{"name":"isAuthPermissionsOK","decl":{"start":{"line":1679,"column":22},"end":{"line":1679,"column":41}},"loc":{"start":{"line":1679,"column":41},"end":{"line":1698,"column":null}}},"105":{"name":"(anonymous_195)","decl":{"start":{"line":1697,"column":25},"end":{"line":1697,"column":29}},"loc":{"start":{"line":1697,"column":29},"end":{"line":1697,"column":54}}},"106":{"name":"isPodContainerAlpine","decl":{"start":{"line":1700,"column":22},"end":{"line":1700,"column":42}},"loc":{"start":{"line":1702,"column":23},"end":{"line":1720,"column":null}}},"107":{"name":"namespace","decl":{"start":{"line":1722,"column":16},"end":{"line":1722,"column":25}},"loc":{"start":{"line":1722,"column":25},"end":{"line":1748,"column":1}}},"108":{"name":"(anonymous_200)","decl":{"start":{"line":1727,"column":40},"end":{"line":1727,"column":43}},"loc":{"start":{"line":1727,"column":43},"end":{"line":1727,"column":50}}},"109":{"name":"(anonymous_201)","decl":{"start":{"line":1750,"column":0},"end":{"line":1750,"column":null}},"loc":{"start":{"line":1750,"column":0},"end":{"line":1774,"column":1}}},"110":{"name":"BackOffManager","decl":{"start":{"line":1753,"column":2},"end":{"line":1753,"column":22}},"loc":{"start":{"line":1753,"column":48},"end":{"line":1757,"column":3}}},"111":{"name":"(anonymous_203)","decl":{"start":{"line":1759,"column":2},"end":{"line":1759,"column":8}},"loc":{"start":{"line":1759,"column":2},"end":{"line":1773,"column":null}}},"112":{"name":"(anonymous_206)","decl":{"start":{"line":1760,"column":22},"end":{"line":1760,"column":29}},"loc":{"start":{"line":1760,"column":29},"end":{"line":1761,"column":16}}},"113":{"name":"containerPorts","decl":{"start":{"line":1776,"column":16},"end":{"line":1776,"column":30}},"loc":{"start":{"line":1777,"column":26},"end":{"line":1816,"column":1}}},"114":{"name":"(anonymous_208)","decl":{"start":{"line":1798,"column":22},"end":{"line":1798,"column":23}},"loc":{"start":{"line":1798,"column":32},"end":{"line":1804,"column":5}}},"115":{"name":"getPodByName","decl":{"start":{"line":1818,"column":22},"end":{"line":1818,"column":34}},"loc":{"start":{"line":1818,"column":39},"end":{"line":1823,"column":null}}},"116":{"name":"getSecretByName","decl":{"start":{"line":1825,"column":22},"end":{"line":1825,"column":37}},"loc":{"start":{"line":1825,"column":50},"end":{"line":1830,"column":null}}},"117":{"name":"listPodsByRunnerInstance","decl":{"start":{"line":1832,"column":22},"end":{"line":1832,"column":46}},"loc":{"start":{"line":1832,"column":46},"end":{"line":1838,"column":null}}}},"branchMap":{"0":{"loc":{"start":{"line":183,"column":2},"end":{"line":186,"column":null}},"type":"switch","locations":[{"start":{"line":183,"column":2},"end":{"line":186,"column":null}}]},"1":{"loc":{"start":{"line":77,"column":2},"end":{"line":79,"column":3}},"type":"if","locations":[{"start":{"line":77,"column":2},"end":{"line":79,"column":3}},{"start":{},"end":{}}]},"2":{"loc":{"start":{"line":80,"column":2},"end":{"line":82,"column":3}},"type":"if","locations":[{"start":{"line":80,"column":2},"end":{"line":82,"column":3}},{"start":{},"end":{}}]},"3":{"loc":{"start":{"line":80,"column":6},"end":{"line":80,"column":22}},"type":"cond-expr","locations":[{"start":{"line":80,"column":14},"end":{"line":80,"column":16}},{"start":{"line":80,"column":6},"end":{"line":80,"column":22}}]},"4":{"loc":{"start":{"line":80,"column":6},"end":{"line":80,"column":16}},"type":"binary-expr","locations":[{"start":{"line":80,"column":6},"end":{"line":80,"column":16}},{"start":{"line":80,"column":6},"end":{"line":80,"column":16}}]},"5":{"loc":{"start":{"line":107,"column":25},"end":{"line":107,"column":78}},"type":"cond-expr","locations":[{"start":{"line":107,"column":72},"end":{"line":107,"column":76}},{"start":{"line":107,"column":76},"end":{"line":107,"column":78}}]},"6":{"loc":{"start":{"line":107,"column":25},"end":{"line":107,"column":76}},"type":"binary-expr","locations":[{"start":{"line":107,"column":25},"end":{"line":107,"column":76}},{"start":{"line":107,"column":72},"end":{"line":107,"column":76}}]},"7":{"loc":{"start":{"line":107,"column":25},"end":{"line":107,"column":72}},"type":"cond-expr","locations":[{"start":{"line":107,"column":40},"end":{"line":107,"column":42}},{"start":{"line":107,"column":25},"end":{"line":107,"column":72}}]},"8":{"loc":{"start":{"line":107,"column":25},"end":{"line":107,"column":42}},"type":"binary-expr","locations":[{"start":{"line":107,"column":25},"end":{"line":107,"column":42}},{"start":{"line":107,"column":25},"end":{"line":107,"column":42}}]},"9":{"loc":{"start":{"line":116,"column":2},"end":{"line":118,"column":3}},"type":"if","locations":[{"start":{"line":116,"column":2},"end":{"line":118,"column":3}},{"start":{},"end":{}}]},"10":{"loc":{"start":{"line":124,"column":8},"end":{"line":125,"column":47}},"type":"binary-expr","locations":[{"start":{"line":124,"column":8},"end":{"line":124,"column":40}},{"start":{"line":125,"column":8},"end":{"line":125,"column":47}}]},"11":{"loc":{"start":{"line":165,"column":6},"end":{"line":165,"column":14}},"type":"if","locations":[{"start":{"line":165,"column":6},"end":{"line":165,"column":14}},{"start":{},"end":{}}]},"12":{"loc":{"start":{"line":167,"column":4},"end":{"line":169,"column":5}},"type":"if","locations":[{"start":{"line":167,"column":4},"end":{"line":169,"column":5}},{"start":{},"end":{}}]},"13":{"loc":{"start":{"line":167,"column":9},"end":{"line":167,"column":31}},"type":"cond-expr","locations":[{"start":{"line":167,"column":25},"end":{"line":167,"column":27}},{"start":{"line":167,"column":25},"end":{"line":167,"column":31}}]},"14":{"loc":{"start":{"line":167,"column":9},"end":{"line":167,"column":27}},"type":"binary-expr","locations":[{"start":{"line":167,"column":9},"end":{"line":167,"column":27}},{"start":{"line":167,"column":25},"end":{"line":167,"column":27}}]},"15":{"loc":{"start":{"line":167,"column":9},"end":{"line":167,"column":25}},"type":"cond-expr","locations":[{"start":{"line":167,"column":15},"end":{"line":167,"column":17}},{"start":{"line":167,"column":9},"end":{"line":167,"column":25}}]},"16":{"loc":{"start":{"line":167,"column":9},"end":{"line":167,"column":17}},"type":"binary-expr","locations":[{"start":{"line":167,"column":9},"end":{"line":167,"column":17}},{"start":{"line":167,"column":9},"end":{"line":167,"column":17}}]},"17":{"loc":{"start":{"line":175,"column":2},"end":{"line":177,"column":3}},"type":"if","locations":[{"start":{"line":175,"column":2},"end":{"line":177,"column":3}},{"start":{},"end":{}}]},"18":{"loc":{"start":{"line":175,"column":6},"end":{"line":175,"column":25}},"type":"cond-expr","locations":[{"start":{"line":175,"column":15},"end":{"line":175,"column":17}},{"start":{"line":175,"column":6},"end":{"line":175,"column":25}}]},"19":{"loc":{"start":{"line":175,"column":6},"end":{"line":175,"column":17}},"type":"binary-expr","locations":[{"start":{"line":175,"column":6},"end":{"line":175,"column":17}},{"start":{"line":175,"column":6},"end":{"line":175,"column":17}}]},"20":{"loc":{"start":{"line":179,"column":2},"end":{"line":181,"column":3}},"type":"if","locations":[{"start":{"line":179,"column":2},"end":{"line":181,"column":3}},{"start":{},"end":{}}]},"21":{"loc":{"start":{"line":179,"column":6},"end":{"line":179,"column":21}},"type":"cond-expr","locations":[{"start":{"line":179,"column":15},"end":{"line":179,"column":17}},{"start":{"line":179,"column":6},"end":{"line":179,"column":21}}]},"22":{"loc":{"start":{"line":179,"column":6},"end":{"line":179,"column":17}},"type":"binary-expr","locations":[{"start":{"line":179,"column":6},"end":{"line":179,"column":17}},{"start":{"line":179,"column":6},"end":{"line":179,"column":17}}]},"23":{"loc":{"start":{"line":236,"column":2},"end":{"line":239,"column":null}},"type":"switch","locations":[{"start":{"line":236,"column":2},"end":{"line":239,"column":null}}]},"24":{"loc":{"start":{"line":228,"column":2},"end":{"line":230,"column":3}},"type":"if","locations":[{"start":{"line":228,"column":2},"end":{"line":230,"column":3}},{"start":{},"end":{}}]},"25":{"loc":{"start":{"line":228,"column":6},"end":{"line":228,"column":25}},"type":"cond-expr","locations":[{"start":{"line":228,"column":15},"end":{"line":228,"column":17}},{"start":{"line":228,"column":6},"end":{"line":228,"column":25}}]},"26":{"loc":{"start":{"line":228,"column":6},"end":{"line":228,"column":17}},"type":"binary-expr","locations":[{"start":{"line":228,"column":6},"end":{"line":228,"column":17}},{"start":{"line":228,"column":6},"end":{"line":228,"column":17}}]},"27":{"loc":{"start":{"line":232,"column":2},"end":{"line":234,"column":3}},"type":"if","locations":[{"start":{"line":232,"column":2},"end":{"line":234,"column":3}},{"start":{},"end":{}}]},"28":{"loc":{"start":{"line":232,"column":6},"end":{"line":232,"column":21}},"type":"cond-expr","locations":[{"start":{"line":232,"column":15},"end":{"line":232,"column":17}},{"start":{"line":232,"column":6},"end":{"line":232,"column":21}}]},"29":{"loc":{"start":{"line":232,"column":6},"end":{"line":232,"column":17}},"type":"binary-expr","locations":[{"start":{"line":232,"column":6},"end":{"line":232,"column":17}},{"start":{"line":232,"column":6},"end":{"line":232,"column":17}}]},"30":{"loc":{"start":{"line":243,"column":2},"end":{"line":247,"column":null}},"type":"switch","locations":[{"start":{"line":243,"column":2},"end":{"line":247,"column":null}}]},"31":{"loc":{"start":{"line":290,"column":8},"end":{"line":290,"column":21}},"type":"cond-expr","locations":[{"start":{"line":290,"column":8},"end":{"line":290,"column":13}},{"start":{"line":290,"column":17},"end":{"line":290,"column":21}}]},"32":{"loc":{"start":{"line":290,"column":8},"end":{"line":290,"column":17}},"type":"binary-expr","locations":[{"start":{"line":290,"column":8},"end":{"line":290,"column":17}},{"start":{"line":290,"column":8},"end":{"line":290,"column":17}}]},"33":{"loc":{"start":{"line":302,"column":12},"end":{"line":321,"column":13}},"type":"if","locations":[{"start":{"line":302,"column":12},"end":{"line":321,"column":13}},{"start":{},"end":{}}]},"34":{"loc":{"start":{"line":303,"column":14},"end":{"line":304,"column":66}},"type":"binary-expr","locations":[{"start":{"line":303,"column":14},"end":{"line":303,"column":20}},{"start":{"line":304,"column":15},"end":{"line":304,"column":38}},{"start":{"line":304,"column":42},"end":{"line":304,"column":65}}]},"35":{"loc":{"start":{"line":324,"column":14},"end":{"line":324,"column":18}},"type":"if","locations":[{"start":{"line":324,"column":14},"end":{"line":324,"column":18}},{"start":{},"end":{}}]},"36":{"loc":{"start":{"line":327,"column":20},"end":{"line":327,"column":34}},"type":"binary-expr","locations":[{"start":{"line":327,"column":20},"end":{"line":327,"column":29}},{"start":{"line":327,"column":33},"end":{"line":327,"column":34}}]},"37":{"loc":{"start":{"line":330,"column":66},"end":{"line":330,"column":79}},"type":"cond-expr","locations":[{"start":{"line":330,"column":70},"end":{"line":330,"column":72}},{"start":{"line":330,"column":66},"end":{"line":330,"column":79}}]},"38":{"loc":{"start":{"line":330,"column":66},"end":{"line":330,"column":72}},"type":"binary-expr","locations":[{"start":{"line":330,"column":66},"end":{"line":330,"column":72}},{"start":{"line":330,"column":66},"end":{"line":330,"column":72}}]},"39":{"loc":{"start":{"line":330,"column":90},"end":{"line":330,"column":103}},"type":"cond-expr","locations":[{"start":{"line":330,"column":94},"end":{"line":330,"column":96}},{"start":{"line":330,"column":90},"end":{"line":330,"column":103}}]},"40":{"loc":{"start":{"line":330,"column":90},"end":{"line":330,"column":96}},"type":"binary-expr","locations":[{"start":{"line":330,"column":90},"end":{"line":330,"column":96}},{"start":{"line":330,"column":90},"end":{"line":330,"column":96}}]},"41":{"loc":{"start":{"line":333,"column":29},"end":{"line":333,"column":66}},"type":"binary-expr","locations":[{"start":{"line":333,"column":29},"end":{"line":333,"column":42}},{"start":{"line":333,"column":46},"end":{"line":333,"column":66}}]},"42":{"loc":{"start":{"line":333,"column":29},"end":{"line":333,"column":42}},"type":"cond-expr","locations":[{"start":{"line":333,"column":33},"end":{"line":333,"column":35}},{"start":{"line":333,"column":29},"end":{"line":333,"column":42}}]},"43":{"loc":{"start":{"line":333,"column":29},"end":{"line":333,"column":35}},"type":"binary-expr","locations":[{"start":{"line":333,"column":29},"end":{"line":333,"column":35}},{"start":{"line":333,"column":29},"end":{"line":333,"column":35}}]},"44":{"loc":{"start":{"line":340,"column":8},"end":{"line":344,"column":9}},"type":"if","locations":[{"start":{"line":340,"column":8},"end":{"line":344,"column":9}},{"start":{"line":342,"column":15},"end":{"line":344,"column":9}}]},"45":{"loc":{"start":{"line":352,"column":12},"end":{"line":352,"column":18}},"type":"if","locations":[{"start":{"line":352,"column":12},"end":{"line":352,"column":18}},{"start":{},"end":{}}]},"46":{"loc":{"start":{"line":352,"column":12},"end":{"line":352,"column":74}},"type":"binary-expr","locations":[{"start":{"line":352,"column":12},"end":{"line":352,"column":18}},{"start":{"line":352,"column":23},"end":{"line":352,"column":46}},{"start":{"line":352,"column":50},"end":{"line":352,"column":73}}]},"47":{"loc":{"start":{"line":383,"column":2},"end":{"line":383,"column":null}},"type":"if","locations":[{"start":{"line":383,"column":2},"end":{"line":383,"column":null}},{"start":{},"end":{}}]},"48":{"loc":{"start":{"line":456,"column":2},"end":{"line":500,"column":null}},"type":"switch","locations":[{"start":{"line":456,"column":2},"end":{"line":500,"column":null}}]},"49":{"loc":{"start":{"line":392,"column":4},"end":{"line":392,"column":33}},"type":"if","locations":[{"start":{"line":392,"column":4},"end":{"line":392,"column":33}},{"start":{},"end":{}}]},"50":{"loc":{"start":{"line":394,"column":4},"end":{"line":394,"column":null}},"type":"if","locations":[{"start":{"line":394,"column":4},"end":{"line":394,"column":null}},{"start":{},"end":{}}]},"51":{"loc":{"start":{"line":402,"column":17},"end":{"line":402,"column":34}},"type":"cond-expr","locations":[{"start":{"line":402,"column":28},"end":{"line":402,"column":32}},{"start":{"line":402,"column":32},"end":{"line":402,"column":34}}]},"52":{"loc":{"start":{"line":402,"column":17},"end":{"line":402,"column":32}},"type":"binary-expr","locations":[{"start":{"line":402,"column":17},"end":{"line":402,"column":32}},{"start":{"line":402,"column":28},"end":{"line":402,"column":32}}]},"53":{"loc":{"start":{"line":410,"column":17},"end":{"line":410,"column":34}},"type":"cond-expr","locations":[{"start":{"line":410,"column":28},"end":{"line":410,"column":32}},{"start":{"line":410,"column":32},"end":{"line":410,"column":34}}]},"54":{"loc":{"start":{"line":410,"column":17},"end":{"line":410,"column":32}},"type":"binary-expr","locations":[{"start":{"line":410,"column":17},"end":{"line":410,"column":32}},{"start":{"line":410,"column":28},"end":{"line":410,"column":32}}]},"55":{"loc":{"start":{"line":415,"column":4},"end":{"line":418,"column":5}},"type":"if","locations":[{"start":{"line":415,"column":4},"end":{"line":418,"column":5}},{"start":{},"end":{}}]},"56":{"loc":{"start":{"line":419,"column":4},"end":{"line":422,"column":5}},"type":"if","locations":[{"start":{"line":419,"column":4},"end":{"line":422,"column":5}},{"start":{},"end":{}}]},"57":{"loc":{"start":{"line":452,"column":14},"end":{"line":452,"column":49}},"type":"cond-expr","locations":[{"start":{"line":452,"column":17},"end":{"line":452,"column":19}},{"start":{"line":452,"column":14},"end":{"line":452,"column":49}}]},"58":{"loc":{"start":{"line":452,"column":14},"end":{"line":452,"column":19}},"type":"binary-expr","locations":[{"start":{"line":452,"column":14},"end":{"line":452,"column":19}},{"start":{"line":452,"column":14},"end":{"line":452,"column":19}}]},"59":{"loc":{"start":{"line":453,"column":11},"end":{"line":453,"column":40}},"type":"cond-expr","locations":[{"start":{"line":453,"column":15},"end":{"line":453,"column":33}},{"start":{"line":453,"column":36},"end":{"line":453,"column":40}}]},"60":{"loc":{"start":{"line":465,"column":8},"end":{"line":465,"column":21}},"type":"cond-expr","locations":[{"start":{"line":465,"column":8},"end":{"line":465,"column":13}},{"start":{"line":465,"column":17},"end":{"line":465,"column":21}}]},"61":{"loc":{"start":{"line":465,"column":8},"end":{"line":465,"column":17}},"type":"binary-expr","locations":[{"start":{"line":465,"column":8},"end":{"line":465,"column":17}},{"start":{"line":465,"column":8},"end":{"line":465,"column":17}}]},"62":{"loc":{"start":{"line":470,"column":10},"end":{"line":482,"column":11}},"type":"if","locations":[{"start":{"line":470,"column":10},"end":{"line":482,"column":11}},{"start":{"line":472,"column":17},"end":{"line":482,"column":11}}]},"63":{"loc":{"start":{"line":471,"column":28},"end":{"line":471,"column":42}},"type":"binary-expr","locations":[{"start":{"line":471,"column":28},"end":{"line":471,"column":37}},{"start":{"line":471,"column":41},"end":{"line":471,"column":42}}]},"64":{"loc":{"start":{"line":476,"column":39},"end":{"line":476,"column":52}},"type":"cond-expr","locations":[{"start":{"line":476,"column":43},"end":{"line":476,"column":45}},{"start":{"line":476,"column":39},"end":{"line":476,"column":52}}]},"65":{"loc":{"start":{"line":476,"column":39},"end":{"line":476,"column":45}},"type":"binary-expr","locations":[{"start":{"line":476,"column":39},"end":{"line":476,"column":45}},{"start":{"line":476,"column":39},"end":{"line":476,"column":45}}]},"66":{"loc":{"start":{"line":477,"column":12},"end":{"line":481,"column":13}},"type":"if","locations":[{"start":{"line":477,"column":12},"end":{"line":481,"column":13}},{"start":{"line":479,"column":19},"end":{"line":481,"column":13}}]},"67":{"loc":{"start":{"line":480,"column":31},"end":{"line":480,"column":78}},"type":"binary-expr","locations":[{"start":{"line":480,"column":31},"end":{"line":480,"column":44}},{"start":{"line":480,"column":48},"end":{"line":480,"column":78}}]},"68":{"loc":{"start":{"line":480,"column":31},"end":{"line":480,"column":44}},"type":"cond-expr","locations":[{"start":{"line":480,"column":35},"end":{"line":480,"column":37}},{"start":{"line":480,"column":31},"end":{"line":480,"column":44}}]},"69":{"loc":{"start":{"line":480,"column":31},"end":{"line":480,"column":37}},"type":"binary-expr","locations":[{"start":{"line":480,"column":31},"end":{"line":480,"column":37}},{"start":{"line":480,"column":31},"end":{"line":480,"column":37}}]},"70":{"loc":{"start":{"line":492,"column":23},"end":{"line":492,"column":65}},"type":"cond-expr","locations":[{"start":{"line":492,"column":44},"end":{"line":492,"column":53}},{"start":{"line":492,"column":56},"end":{"line":492,"column":65}}]},"71":{"loc":{"start":{"line":494,"column":8},"end":{"line":498,"column":9}},"type":"if","locations":[{"start":{"line":494,"column":8},"end":{"line":498,"column":9}},{"start":{"line":496,"column":15},"end":{"line":498,"column":9}}]},"72":{"loc":{"start":{"line":535,"column":10},"end":{"line":545,"column":11}},"type":"if","locations":[{"start":{"line":535,"column":10},"end":{"line":545,"column":11}},{"start":{"line":537,"column":17},"end":{"line":545,"column":11}}]},"73":{"loc":{"start":{"line":540,"column":25},"end":{"line":540,"column":38}},"type":"cond-expr","locations":[{"start":{"line":540,"column":29},"end":{"line":540,"column":31}},{"start":{"line":540,"column":25},"end":{"line":540,"column":38}}]},"74":{"loc":{"start":{"line":540,"column":25},"end":{"line":540,"column":31}},"type":"binary-expr","locations":[{"start":{"line":540,"column":25},"end":{"line":540,"column":31}},{"start":{"line":540,"column":25},"end":{"line":540,"column":31}}]},"75":{"loc":{"start":{"line":541,"column":25},"end":{"line":541,"column":38}},"type":"cond-expr","locations":[{"start":{"line":541,"column":29},"end":{"line":541,"column":31}},{"start":{"line":541,"column":25},"end":{"line":541,"column":38}}]},"76":{"loc":{"start":{"line":541,"column":25},"end":{"line":541,"column":31}},"type":"binary-expr","locations":[{"start":{"line":541,"column":25},"end":{"line":541,"column":31}},{"start":{"line":541,"column":25},"end":{"line":541,"column":31}}]},"77":{"loc":{"start":{"line":544,"column":29},"end":{"line":544,"column":73}},"type":"binary-expr","locations":[{"start":{"line":544,"column":29},"end":{"line":544,"column":42}},{"start":{"line":544,"column":46},"end":{"line":544,"column":73}}]},"78":{"loc":{"start":{"line":544,"column":29},"end":{"line":544,"column":42}},"type":"cond-expr","locations":[{"start":{"line":544,"column":33},"end":{"line":544,"column":35}},{"start":{"line":544,"column":29},"end":{"line":544,"column":42}}]},"79":{"loc":{"start":{"line":544,"column":29},"end":{"line":544,"column":35}},"type":"binary-expr","locations":[{"start":{"line":544,"column":29},"end":{"line":544,"column":35}},{"start":{"line":544,"column":29},"end":{"line":544,"column":35}}]},"80":{"loc":{"start":{"line":568,"column":9},"end":{"line":596,"column":null}},"type":"switch","locations":[{"start":{"line":568,"column":9},"end":{"line":596,"column":null}},{"start":{"line":568,"column":2},"end":{"line":596,"column":null}}]},"81":{"loc":{"start":{"line":580,"column":8},"end":{"line":593,"column":9}},"type":"if","locations":[{"start":{"line":580,"column":8},"end":{"line":593,"column":9}},{"start":{"line":591,"column":15},"end":{"line":593,"column":9}}]},"82":{"loc":{"start":{"line":634,"column":14},"end":{"line":640,"column":15}},"type":"if","locations":[{"start":{"line":634,"column":14},"end":{"line":640,"column":15}},{"start":{},"end":{}}]},"83":{"loc":{"start":{"line":650,"column":6},"end":{"line":654,"column":7}},"type":"if","locations":[{"start":{"line":650,"column":6},"end":{"line":654,"column":7}},{"start":{},"end":{}}]},"84":{"loc":{"start":{"line":607,"column":9},"end":{"line":607,"column":null}},"type":"if","locations":[{"start":{"line":607,"column":9},"end":{"line":607,"column":null}},{"start":{},"end":{}}]},"85":{"loc":{"start":{"line":677,"column":10},"end":{"line":677,"column":13}},"type":"if","locations":[{"start":{"line":677,"column":10},"end":{"line":677,"column":13}},{"start":{},"end":{}}]},"86":{"loc":{"start":{"line":699,"column":19},"end":{"line":699,"column":77}},"type":"binary-expr","locations":[{"start":{"line":699,"column":19},"end":{"line":699,"column":35}},{"start":{"line":699,"column":39},"end":{"line":699,"column":77}}]},"87":{"loc":{"start":{"line":661,"column":18},"end":{"line":661,"column":32}},"type":"if","locations":[{"start":{"line":661,"column":18},"end":{"line":661,"column":32}},{"start":{},"end":{}}]},"88":{"loc":{"start":{"line":734,"column":2},"end":{"line":736,"column":3}},"type":"if","locations":[{"start":{"line":734,"column":2},"end":{"line":736,"column":3}},{"start":{},"end":{}}]},"89":{"loc":{"start":{"line":750,"column":8},"end":{"line":750,"column":39}},"type":"binary-expr","locations":[{"start":{"line":750,"column":8},"end":{"line":750,"column":32}},{"start":{"line":750,"column":36},"end":{"line":750,"column":39}}]},"90":{"loc":{"start":{"line":774,"column":14},"end":{"line":780,"column":15}},"type":"if","locations":[{"start":{"line":774,"column":14},"end":{"line":780,"column":15}},{"start":{},"end":{}}]},"91":{"loc":{"start":{"line":789,"column":6},"end":{"line":793,"column":7}},"type":"if","locations":[{"start":{"line":789,"column":6},"end":{"line":793,"column":7}},{"start":{},"end":{}}]},"92":{"loc":{"start":{"line":739,"column":9},"end":{"line":739,"column":null}},"type":"if","locations":[{"start":{"line":739,"column":9},"end":{"line":739,"column":null}},{"start":{},"end":{}}]},"93":{"loc":{"start":{"line":816,"column":10},"end":{"line":816,"column":13}},"type":"if","locations":[{"start":{"line":816,"column":10},"end":{"line":816,"column":13}},{"start":{},"end":{}}]},"94":{"loc":{"start":{"line":838,"column":19},"end":{"line":838,"column":77}},"type":"binary-expr","locations":[{"start":{"line":838,"column":19},"end":{"line":838,"column":35}},{"start":{"line":838,"column":39},"end":{"line":838,"column":77}}]},"95":{"loc":{"start":{"line":800,"column":18},"end":{"line":800,"column":32}},"type":"if","locations":[{"start":{"line":800,"column":18},"end":{"line":800,"column":32}},{"start":{},"end":{}}]},"96":{"loc":{"start":{"line":869,"column":4},"end":{"line":869,"column":null}},"type":"switch","locations":[{"start":{"line":869,"column":4},"end":{"line":869,"column":null}}]},"97":{"loc":{"start":{"line":861,"column":9},"end":{"line":861,"column":null}},"type":"if","locations":[{"start":{"line":861,"column":9},"end":{"line":861,"column":null}},{"start":{},"end":{}}]},"98":{"loc":{"start":{"line":863,"column":6},"end":{"line":865,"column":7}},"type":"if","locations":[{"start":{"line":863,"column":6},"end":{"line":865,"column":7}},{"start":{},"end":{}}]},"99":{"loc":{"start":{"line":908,"column":2},"end":{"line":911,"column":null}},"type":"switch","locations":[{"start":{"line":908,"column":2},"end":{"line":911,"column":null}}]},"100":{"loc":{"start":{"line":878,"column":7},"end":{"line":878,"column":58}},"type":"binary-expr","locations":[{"start":{"line":878,"column":7},"end":{"line":878,"column":25}},{"start":{"line":878,"column":29},"end":{"line":878,"column":58}}]},"101":{"loc":{"start":{"line":943,"column":2},"end":{"line":946,"column":null}},"type":"switch","locations":[{"start":{"line":943,"column":2},"end":{"line":946,"column":null}}]},"102":{"loc":{"start":{"line":950,"column":21},"end":{"line":953,"column":null}},"type":"switch","locations":[{"start":{"line":950,"column":21},"end":{"line":953,"column":null}}]},"103":{"loc":{"start":{"line":954,"column":2},"end":{"line":956,"column":3}},"type":"if","locations":[{"start":{"line":954,"column":2},"end":{"line":956,"column":3}},{"start":{},"end":{}}]},"104":{"loc":{"start":{"line":961,"column":8},"end":{"line":961,"column":14}},"type":"switch","locations":[{"start":{"line":961,"column":8},"end":{"line":961,"column":14}}]},"105":{"loc":{"start":{"line":961,"column":8},"end":{"line":961,"column":29}},"type":"cond-expr","locations":[{"start":{"line":961,"column":23},"end":{"line":961,"column":25}},{"start":{"line":961,"column":23},"end":{"line":961,"column":29}}]},"106":{"loc":{"start":{"line":961,"column":8},"end":{"line":961,"column":25}},"type":"binary-expr","locations":[{"start":{"line":961,"column":8},"end":{"line":961,"column":25}},{"start":{"line":961,"column":23},"end":{"line":961,"column":25}}]},"107":{"loc":{"start":{"line":1054,"column":2},"end":{"line":1056,"column":3}},"type":"if","locations":[{"start":{"line":1054,"column":2},"end":{"line":1056,"column":3}},{"start":{},"end":{}}]},"108":{"loc":{"start":{"line":1060,"column":4},"end":{"line":1062,"column":5}},"type":"if","locations":[{"start":{"line":1060,"column":4},"end":{"line":1062,"column":5}},{"start":{},"end":{}}]},"109":{"loc":{"start":{"line":1072,"column":2},"end":{"line":1074,"column":3}},"type":"if","locations":[{"start":{"line":1072,"column":2},"end":{"line":1074,"column":3}},{"start":{},"end":{}}]},"110":{"loc":{"start":{"line":1078,"column":4},"end":{"line":1080,"column":5}},"type":"if","locations":[{"start":{"line":1078,"column":4},"end":{"line":1080,"column":5}},{"start":{},"end":{}}]},"111":{"loc":{"start":{"line":1088,"column":2},"end":{"line":1090,"column":3}},"type":"if","locations":[{"start":{"line":1088,"column":2},"end":{"line":1090,"column":3}},{"start":{},"end":{}}]},"112":{"loc":{"start":{"line":1094,"column":4},"end":{"line":1096,"column":5}},"type":"if","locations":[{"start":{"line":1094,"column":4},"end":{"line":1096,"column":5}},{"start":{},"end":{}}]},"113":{"loc":{"start":{"line":1110,"column":2},"end":{"line":1110,"column":null}},"type":"if","locations":[{"start":{"line":1110,"column":2},"end":{"line":1110,"column":null}},{"start":{},"end":{}}]},"114":{"loc":{"start":{"line":1125,"column":2},"end":{"line":1125,"column":null}},"type":"if","locations":[{"start":{"line":1125,"column":2},"end":{"line":1125,"column":null}},{"start":{},"end":{}}]},"115":{"loc":{"start":{"line":1126,"column":2},"end":{"line":1128,"column":3}},"type":"if","locations":[{"start":{"line":1126,"column":2},"end":{"line":1128,"column":3}},{"start":{},"end":{}}]},"116":{"loc":{"start":{"line":1126,"column":6},"end":{"line":1126,"column":71}},"type":"binary-expr","locations":[{"start":{"line":1126,"column":6},"end":{"line":1126,"column":31}},{"start":{"line":1126,"column":35},"end":{"line":1126,"column":71}}]},"117":{"loc":{"start":{"line":1132,"column":4},"end":{"line":1132,"column":26}},"type":"if","locations":[{"start":{"line":1132,"column":4},"end":{"line":1132,"column":26}},{"start":{},"end":{}}]},"118":{"loc":{"start":{"line":1147,"column":2},"end":{"line":1162,"column":3}},"type":"switch","locations":[{"start":{"line":1148,"column":4},"end":{"line":1155,"column":null}},{"start":{"line":1156,"column":4},"end":{"line":1157,"column":null}},{"start":{"line":1158,"column":4},"end":{"line":1159,"column":null}},{"start":{"line":1160,"column":4},"end":{"line":1161,"column":null}}]},"119":{"loc":{"start":{"line":1169,"column":8},"end":{"line":1169,"column":47}},"type":"cond-expr","locations":[{"start":{"line":1169,"column":41},"end":{"line":1169,"column":45}},{"start":{"line":1169,"column":45},"end":{"line":1169,"column":47}}]},"120":{"loc":{"start":{"line":1169,"column":8},"end":{"line":1169,"column":45}},"type":"binary-expr","locations":[{"start":{"line":1169,"column":8},"end":{"line":1169,"column":45}},{"start":{"line":1169,"column":41},"end":{"line":1169,"column":45}}]},"121":{"loc":{"start":{"line":1169,"column":8},"end":{"line":1169,"column":41}},"type":"cond-expr","locations":[{"start":{"line":1169,"column":18},"end":{"line":1169,"column":20}},{"start":{"line":1169,"column":18},"end":{"line":1169,"column":41}}]},"122":{"loc":{"start":{"line":1169,"column":8},"end":{"line":1169,"column":20}},"type":"binary-expr","locations":[{"start":{"line":1169,"column":8},"end":{"line":1169,"column":20}},{"start":{"line":1169,"column":18},"end":{"line":1169,"column":20}}]},"123":{"loc":{"start":{"line":1170,"column":8},"end":{"line":1170,"column":43}},"type":"cond-expr","locations":[{"start":{"line":1170,"column":37},"end":{"line":1170,"column":41}},{"start":{"line":1170,"column":41},"end":{"line":1170,"column":43}}]},"124":{"loc":{"start":{"line":1170,"column":8},"end":{"line":1170,"column":41}},"type":"binary-expr","locations":[{"start":{"line":1170,"column":8},"end":{"line":1170,"column":41}},{"start":{"line":1170,"column":37},"end":{"line":1170,"column":41}}]},"125":{"loc":{"start":{"line":1170,"column":8},"end":{"line":1170,"column":37}},"type":"cond-expr","locations":[{"start":{"line":1170,"column":18},"end":{"line":1170,"column":20}},{"start":{"line":1170,"column":18},"end":{"line":1170,"column":37}}]},"126":{"loc":{"start":{"line":1170,"column":8},"end":{"line":1170,"column":20}},"type":"binary-expr","locations":[{"start":{"line":1170,"column":8},"end":{"line":1170,"column":20}},{"start":{"line":1170,"column":18},"end":{"line":1170,"column":20}}]},"127":{"loc":{"start":{"line":1173,"column":20},"end":{"line":1173,"column":37}},"type":"cond-expr","locations":[{"start":{"line":1173,"column":28},"end":{"line":1173,"column":30}},{"start":{"line":1173,"column":28},"end":{"line":1173,"column":37}}]},"128":{"loc":{"start":{"line":1173,"column":20},"end":{"line":1173,"column":30}},"type":"binary-expr","locations":[{"start":{"line":1173,"column":20},"end":{"line":1173,"column":30}},{"start":{"line":1173,"column":28},"end":{"line":1173,"column":30}}]},"129":{"loc":{"start":{"line":1174,"column":4},"end":{"line":1179,"column":5}},"type":"if","locations":[{"start":{"line":1174,"column":4},"end":{"line":1179,"column":5}},{"start":{},"end":{}}]},"130":{"loc":{"start":{"line":1174,"column":8},"end":{"line":1174,"column":67}},"type":"binary-expr","locations":[{"start":{"line":1174,"column":8},"end":{"line":1174,"column":23}},{"start":{"line":1174,"column":27},"end":{"line":1174,"column":67}}]},"131":{"loc":{"start":{"line":1174,"column":8},"end":{"line":1174,"column":23}},"type":"cond-expr","locations":[{"start":{"line":1174,"column":15},"end":{"line":1174,"column":17}},{"start":{"line":1174,"column":8},"end":{"line":1174,"column":23}}]},"132":{"loc":{"start":{"line":1174,"column":8},"end":{"line":1174,"column":17}},"type":"binary-expr","locations":[{"start":{"line":1174,"column":8},"end":{"line":1174,"column":17}},{"start":{"line":1174,"column":8},"end":{"line":1174,"column":17}}]},"133":{"loc":{"start":{"line":1176,"column":21},"end":{"line":1176,"column":70}},"type":"cond-expr","locations":[{"start":{"line":1176,"column":39},"end":{"line":1176,"column":65}},{"start":{"line":1176,"column":68},"end":{"line":1176,"column":70}}]},"134":{"loc":{"start":{"line":1188,"column":2},"end":{"line":1190,"column":3}},"type":"if","locations":[{"start":{"line":1188,"column":2},"end":{"line":1190,"column":3}},{"start":{},"end":{}}]},"135":{"loc":{"start":{"line":1191,"column":2},"end":{"line":1193,"column":3}},"type":"if","locations":[{"start":{"line":1191,"column":2},"end":{"line":1193,"column":3}},{"start":{},"end":{}}]},"136":{"loc":{"start":{"line":1194,"column":2},"end":{"line":1207,"column":3}},"type":"if","locations":[{"start":{"line":1194,"column":2},"end":{"line":1207,"column":3}},{"start":{},"end":{}}]},"137":{"loc":{"start":{"line":1195,"column":4},"end":{"line":1206,"column":5}},"type":"switch","locations":[{"start":{"line":1196,"column":6},"end":{"line":1197,"column":null}},{"start":{"line":1198,"column":6},"end":{"line":1199,"column":null}},{"start":{"line":1200,"column":6},"end":{"line":1201,"column":null}},{"start":{"line":1202,"column":6},"end":{"line":1203,"column":null}},{"start":{"line":1204,"column":6},"end":{"line":1205,"column":null}}]},"138":{"loc":{"start":{"line":1205,"column":69},"end":{"line":1205,"column":90}},"type":"cond-expr","locations":[{"start":{"line":1205,"column":69},"end":{"line":1205,"column":77}},{"start":{"line":1205,"column":81},"end":{"line":1205,"column":90}}]},"139":{"loc":{"start":{"line":1205,"column":69},"end":{"line":1205,"column":81}},"type":"binary-expr","locations":[{"start":{"line":1205,"column":69},"end":{"line":1205,"column":81}},{"start":{"line":1205,"column":69},"end":{"line":1205,"column":81}}]},"140":{"loc":{"start":{"line":1215,"column":8},"end":{"line":1215,"column":47}},"type":"cond-expr","locations":[{"start":{"line":1215,"column":41},"end":{"line":1215,"column":45}},{"start":{"line":1215,"column":45},"end":{"line":1215,"column":47}}]},"141":{"loc":{"start":{"line":1215,"column":8},"end":{"line":1215,"column":45}},"type":"binary-expr","locations":[{"start":{"line":1215,"column":8},"end":{"line":1215,"column":45}},{"start":{"line":1215,"column":41},"end":{"line":1215,"column":45}}]},"142":{"loc":{"start":{"line":1215,"column":8},"end":{"line":1215,"column":41}},"type":"cond-expr","locations":[{"start":{"line":1215,"column":18},"end":{"line":1215,"column":20}},{"start":{"line":1215,"column":18},"end":{"line":1215,"column":41}}]},"143":{"loc":{"start":{"line":1215,"column":8},"end":{"line":1215,"column":20}},"type":"binary-expr","locations":[{"start":{"line":1215,"column":8},"end":{"line":1215,"column":20}},{"start":{"line":1215,"column":18},"end":{"line":1215,"column":20}}]},"144":{"loc":{"start":{"line":1216,"column":8},"end":{"line":1216,"column":43}},"type":"cond-expr","locations":[{"start":{"line":1216,"column":37},"end":{"line":1216,"column":41}},{"start":{"line":1216,"column":41},"end":{"line":1216,"column":43}}]},"145":{"loc":{"start":{"line":1216,"column":8},"end":{"line":1216,"column":41}},"type":"binary-expr","locations":[{"start":{"line":1216,"column":8},"end":{"line":1216,"column":41}},{"start":{"line":1216,"column":37},"end":{"line":1216,"column":41}}]},"146":{"loc":{"start":{"line":1216,"column":8},"end":{"line":1216,"column":37}},"type":"cond-expr","locations":[{"start":{"line":1216,"column":18},"end":{"line":1216,"column":20}},{"start":{"line":1216,"column":18},"end":{"line":1216,"column":37}}]},"147":{"loc":{"start":{"line":1216,"column":8},"end":{"line":1216,"column":20}},"type":"binary-expr","locations":[{"start":{"line":1216,"column":8},"end":{"line":1216,"column":20}},{"start":{"line":1216,"column":18},"end":{"line":1216,"column":20}}]},"148":{"loc":{"start":{"line":1219,"column":23},"end":{"line":1219,"column":43}},"type":"cond-expr","locations":[{"start":{"line":1219,"column":31},"end":{"line":1219,"column":33}},{"start":{"line":1219,"column":31},"end":{"line":1219,"column":43}}]},"149":{"loc":{"start":{"line":1219,"column":23},"end":{"line":1219,"column":33}},"type":"binary-expr","locations":[{"start":{"line":1219,"column":23},"end":{"line":1219,"column":33}},{"start":{"line":1219,"column":31},"end":{"line":1219,"column":33}}]},"150":{"loc":{"start":{"line":1220,"column":4},"end":{"line":1225,"column":5}},"type":"if","locations":[{"start":{"line":1220,"column":4},"end":{"line":1225,"column":5}},{"start":{},"end":{}}]},"151":{"loc":{"start":{"line":1220,"column":8},"end":{"line":1220,"column":73}},"type":"binary-expr","locations":[{"start":{"line":1220,"column":8},"end":{"line":1220,"column":26}},{"start":{"line":1220,"column":30},"end":{"line":1220,"column":73}}]},"152":{"loc":{"start":{"line":1220,"column":8},"end":{"line":1220,"column":26}},"type":"cond-expr","locations":[{"start":{"line":1220,"column":18},"end":{"line":1220,"column":20}},{"start":{"line":1220,"column":8},"end":{"line":1220,"column":26}}]},"153":{"loc":{"start":{"line":1220,"column":8},"end":{"line":1220,"column":20}},"type":"binary-expr","locations":[{"start":{"line":1220,"column":8},"end":{"line":1220,"column":20}},{"start":{"line":1220,"column":8},"end":{"line":1220,"column":20}}]},"154":{"loc":{"start":{"line":1222,"column":21},"end":{"line":1222,"column":76}},"type":"cond-expr","locations":[{"start":{"line":1222,"column":42},"end":{"line":1222,"column":71}},{"start":{"line":1222,"column":74},"end":{"line":1222,"column":76}}]},"155":{"loc":{"start":{"line":1231,"column":2},"end":{"line":1255,"column":3}},"type":"switch","locations":[{"start":{"line":1232,"column":4},"end":{"line":1238,"column":null}},{"start":{"line":1239,"column":4},"end":{"line":1245,"column":null}},{"start":{"line":1246,"column":4},"end":{"line":1252,"column":null}},{"start":{"line":1253,"column":4},"end":{"line":1254,"column":null}}]},"156":{"loc":{"start":{"line":1268,"column":2},"end":{"line":1270,"column":3}},"type":"if","locations":[{"start":{"line":1268,"column":2},"end":{"line":1270,"column":3}},{"start":{},"end":{}}]},"157":{"loc":{"start":{"line":1278,"column":12},"end":{"line":1278,"column":30}},"type":"cond-expr","locations":[{"start":{"line":1278,"column":24},"end":{"line":1278,"column":28}},{"start":{"line":1278,"column":28},"end":{"line":1278,"column":30}}]},"158":{"loc":{"start":{"line":1278,"column":12},"end":{"line":1278,"column":28}},"type":"binary-expr","locations":[{"start":{"line":1278,"column":12},"end":{"line":1278,"column":28}},{"start":{"line":1278,"column":24},"end":{"line":1278,"column":28}}]},"159":{"loc":{"start":{"line":1282,"column":8},"end":{"line":1282,"column":56}},"type":"cond-expr","locations":[{"start":{"line":1282,"column":31},"end":{"line":1282,"column":42}},{"start":{"line":1282,"column":45},"end":{"line":1282,"column":56}}]},"160":{"loc":{"start":{"line":1291,"column":4},"end":{"line":1297,"column":5}},"type":"if","locations":[{"start":{"line":1291,"column":4},"end":{"line":1297,"column":5}},{"start":{},"end":{}}]},"161":{"loc":{"start":{"line":1292,"column":6},"end":{"line":1294,"column":41}},"type":"binary-expr","locations":[{"start":{"line":1292,"column":6},"end":{"line":1292,"column":26}},{"start":{"line":1293,"column":6},"end":{"line":1293,"column":15}},{"start":{"line":1294,"column":6},"end":{"line":1294,"column":41}}]},"162":{"loc":{"start":{"line":1301,"column":4},"end":{"line":1311,"column":5}},"type":"if","locations":[{"start":{"line":1301,"column":4},"end":{"line":1311,"column":5}},{"start":{},"end":{}}]},"163":{"loc":{"start":{"line":1302,"column":6},"end":{"line":1303,"column":46}},"type":"binary-expr","locations":[{"start":{"line":1302,"column":6},"end":{"line":1302,"column":37}},{"start":{"line":1303,"column":6},"end":{"line":1303,"column":46}}]},"164":{"loc":{"start":{"line":1307,"column":10},"end":{"line":1307,"column":37}},"type":"cond-expr","locations":[{"start":{"line":1307,"column":19},"end":{"line":1307,"column":23}},{"start":{"line":1307,"column":23},"end":{"line":1307,"column":37}}]},"165":{"loc":{"start":{"line":1307,"column":10},"end":{"line":1307,"column":23}},"type":"binary-expr","locations":[{"start":{"line":1307,"column":10},"end":{"line":1307,"column":23}},{"start":{"line":1307,"column":19},"end":{"line":1307,"column":23}}]},"166":{"loc":{"start":{"line":1312,"column":4},"end":{"line":1314,"column":5}},"type":"if","locations":[{"start":{"line":1312,"column":4},"end":{"line":1314,"column":5}},{"start":{},"end":{}}]},"167":{"loc":{"start":{"line":1316,"column":18},"end":{"line":1316,"column":64}},"type":"cond-expr","locations":[{"start":{"line":1316,"column":43},"end":{"line":1316,"column":59}},{"start":{"line":1316,"column":62},"end":{"line":1316,"column":64}}]},"168":{"loc":{"start":{"line":1316,"column":18},"end":{"line":1316,"column":40}},"type":"binary-expr","locations":[{"start":{"line":1316,"column":18},"end":{"line":1316,"column":25}},{"start":{"line":1316,"column":29},"end":{"line":1316,"column":40}}]},"169":{"loc":{"start":{"line":1318,"column":19},"end":{"line":1318,"column":56}},"type":"cond-expr","locations":[{"start":{"line":1318,"column":31},"end":{"line":1318,"column":51}},{"start":{"line":1318,"column":54},"end":{"line":1318,"column":56}}]},"170":{"loc":{"start":{"line":1337,"column":6},"end":{"line":1337,"column":54}},"type":"cond-expr","locations":[{"start":{"line":1337,"column":29},"end":{"line":1337,"column":40}},{"start":{"line":1337,"column":43},"end":{"line":1337,"column":54}}]},"171":{"loc":{"start":{"line":1346,"column":21},"end":{"line":1348,"column":15}},"type":"cond-expr","locations":[{"start":{"line":1347,"column":6},"end":{"line":1347,"column":68}},{"start":{"line":1348,"column":6},"end":{"line":1348,"column":15}}]},"172":{"loc":{"start":{"line":1346,"column":21},"end":{"line":1346,"column":34}},"type":"cond-expr","locations":[{"start":{"line":1346,"column":27},"end":{"line":1346,"column":29}},{"start":{"line":1346,"column":21},"end":{"line":1346,"column":34}}]},"173":{"loc":{"start":{"line":1346,"column":21},"end":{"line":1346,"column":29}},"type":"binary-expr","locations":[{"start":{"line":1346,"column":21},"end":{"line":1346,"column":29}},{"start":{"line":1346,"column":21},"end":{"line":1346,"column":29}}]},"174":{"loc":{"start":{"line":1347,"column":24},"end":{"line":1347,"column":66}},"type":"cond-expr","locations":[{"start":{"line":1347,"column":40},"end":{"line":1347,"column":61}},{"start":{"line":1347,"column":64},"end":{"line":1347,"column":66}}]},"175":{"loc":{"start":{"line":1350,"column":2},"end":{"line":1352,"column":3}},"type":"if","locations":[{"start":{"line":1350,"column":2},"end":{"line":1352,"column":3}},{"start":{},"end":{}}]},"176":{"loc":{"start":{"line":1350,"column":6},"end":{"line":1350,"column":21}},"type":"cond-expr","locations":[{"start":{"line":1350,"column":12},"end":{"line":1350,"column":14}},{"start":{"line":1350,"column":6},"end":{"line":1350,"column":21}}]},"177":{"loc":{"start":{"line":1350,"column":6},"end":{"line":1350,"column":14}},"type":"binary-expr","locations":[{"start":{"line":1350,"column":6},"end":{"line":1350,"column":14}},{"start":{"line":1350,"column":6},"end":{"line":1350,"column":14}}]},"178":{"loc":{"start":{"line":1355,"column":21},"end":{"line":1355,"column":45}},"type":"cond-expr","locations":[{"start":{"line":1355,"column":39},"end":{"line":1355,"column":43}},{"start":{"line":1355,"column":43},"end":{"line":1355,"column":45}}]},"179":{"loc":{"start":{"line":1355,"column":21},"end":{"line":1355,"column":43}},"type":"binary-expr","locations":[{"start":{"line":1355,"column":21},"end":{"line":1355,"column":43}},{"start":{"line":1355,"column":39},"end":{"line":1355,"column":43}}]},"180":{"loc":{"start":{"line":1355,"column":21},"end":{"line":1355,"column":39}},"type":"cond-expr","locations":[{"start":{"line":1355,"column":27},"end":{"line":1355,"column":29}},{"start":{"line":1355,"column":21},"end":{"line":1355,"column":39}}]},"181":{"loc":{"start":{"line":1355,"column":21},"end":{"line":1355,"column":29}},"type":"binary-expr","locations":[{"start":{"line":1355,"column":21},"end":{"line":1355,"column":29}},{"start":{"line":1355,"column":21},"end":{"line":1355,"column":29}}]},"182":{"loc":{"start":{"line":1356,"column":4},"end":{"line":1360,"column":5}},"type":"if","locations":[{"start":{"line":1356,"column":4},"end":{"line":1360,"column":5}},{"start":{},"end":{}}]},"183":{"loc":{"start":{"line":1357,"column":21},"end":{"line":1357,"column":59}},"type":"cond-expr","locations":[{"start":{"line":1357,"column":35},"end":{"line":1357,"column":54}},{"start":{"line":1357,"column":57},"end":{"line":1357,"column":59}}]},"184":{"loc":{"start":{"line":1358,"column":18},"end":{"line":1358,"column":57}},"type":"cond-expr","locations":[{"start":{"line":1358,"column":33},"end":{"line":1358,"column":52}},{"start":{"line":1358,"column":55},"end":{"line":1358,"column":57}}]},"185":{"loc":{"start":{"line":1367,"column":8},"end":{"line":1367,"column":43}},"type":"cond-expr","locations":[{"start":{"line":1367,"column":37},"end":{"line":1367,"column":41}},{"start":{"line":1367,"column":41},"end":{"line":1367,"column":43}}]},"186":{"loc":{"start":{"line":1367,"column":8},"end":{"line":1367,"column":41}},"type":"binary-expr","locations":[{"start":{"line":1367,"column":8},"end":{"line":1367,"column":41}},{"start":{"line":1367,"column":37},"end":{"line":1367,"column":41}}]},"187":{"loc":{"start":{"line":1367,"column":8},"end":{"line":1367,"column":37}},"type":"cond-expr","locations":[{"start":{"line":1367,"column":14},"end":{"line":1367,"column":16}},{"start":{"line":1367,"column":8},"end":{"line":1367,"column":37}}]},"188":{"loc":{"start":{"line":1367,"column":8},"end":{"line":1367,"column":16}},"type":"binary-expr","locations":[{"start":{"line":1367,"column":8},"end":{"line":1367,"column":16}},{"start":{"line":1367,"column":8},"end":{"line":1367,"column":16}}]},"189":{"loc":{"start":{"line":1368,"column":8},"end":{"line":1368,"column":39}},"type":"cond-expr","locations":[{"start":{"line":1368,"column":33},"end":{"line":1368,"column":37}},{"start":{"line":1368,"column":37},"end":{"line":1368,"column":39}}]},"190":{"loc":{"start":{"line":1368,"column":8},"end":{"line":1368,"column":37}},"type":"binary-expr","locations":[{"start":{"line":1368,"column":8},"end":{"line":1368,"column":37}},{"start":{"line":1368,"column":33},"end":{"line":1368,"column":37}}]},"191":{"loc":{"start":{"line":1368,"column":8},"end":{"line":1368,"column":33}},"type":"cond-expr","locations":[{"start":{"line":1368,"column":14},"end":{"line":1368,"column":16}},{"start":{"line":1368,"column":8},"end":{"line":1368,"column":33}}]},"192":{"loc":{"start":{"line":1368,"column":8},"end":{"line":1368,"column":16}},"type":"binary-expr","locations":[{"start":{"line":1368,"column":8},"end":{"line":1368,"column":16}},{"start":{"line":1368,"column":8},"end":{"line":1368,"column":16}}]},"193":{"loc":{"start":{"line":1372,"column":20},"end":{"line":1372,"column":37}},"type":"cond-expr","locations":[{"start":{"line":1372,"column":28},"end":{"line":1372,"column":30}},{"start":{"line":1372,"column":28},"end":{"line":1372,"column":37}}]},"194":{"loc":{"start":{"line":1372,"column":20},"end":{"line":1372,"column":30}},"type":"binary-expr","locations":[{"start":{"line":1372,"column":20},"end":{"line":1372,"column":30}},{"start":{"line":1372,"column":28},"end":{"line":1372,"column":30}}]},"195":{"loc":{"start":{"line":1373,"column":4},"end":{"line":1382,"column":5}},"type":"if","locations":[{"start":{"line":1373,"column":4},"end":{"line":1382,"column":5}},{"start":{},"end":{}}]},"196":{"loc":{"start":{"line":1373,"column":8},"end":{"line":1373,"column":23}},"type":"cond-expr","locations":[{"start":{"line":1373,"column":15},"end":{"line":1373,"column":17}},{"start":{"line":1373,"column":8},"end":{"line":1373,"column":23}}]},"197":{"loc":{"start":{"line":1373,"column":8},"end":{"line":1373,"column":17}},"type":"binary-expr","locations":[{"start":{"line":1373,"column":8},"end":{"line":1373,"column":17}},{"start":{"line":1373,"column":8},"end":{"line":1373,"column":17}}]},"198":{"loc":{"start":{"line":1376,"column":6},"end":{"line":1381,"column":7}},"type":"if","locations":[{"start":{"line":1376,"column":6},"end":{"line":1381,"column":7}},{"start":{},"end":{}}]},"199":{"loc":{"start":{"line":1377,"column":20},"end":{"line":1377,"column":69}},"type":"cond-expr","locations":[{"start":{"line":1377,"column":38},"end":{"line":1377,"column":64}},{"start":{"line":1377,"column":67},"end":{"line":1377,"column":69}}]},"200":{"loc":{"start":{"line":1383,"column":23},"end":{"line":1383,"column":43}},"type":"cond-expr","locations":[{"start":{"line":1383,"column":31},"end":{"line":1383,"column":33}},{"start":{"line":1383,"column":31},"end":{"line":1383,"column":43}}]},"201":{"loc":{"start":{"line":1383,"column":23},"end":{"line":1383,"column":33}},"type":"binary-expr","locations":[{"start":{"line":1383,"column":23},"end":{"line":1383,"column":33}},{"start":{"line":1383,"column":31},"end":{"line":1383,"column":33}}]},"202":{"loc":{"start":{"line":1385,"column":4},"end":{"line":1391,"column":5}},"type":"if","locations":[{"start":{"line":1385,"column":4},"end":{"line":1391,"column":5}},{"start":{},"end":{}}]},"203":{"loc":{"start":{"line":1385,"column":8},"end":{"line":1385,"column":47}},"type":"binary-expr","locations":[{"start":{"line":1385,"column":8},"end":{"line":1385,"column":18}},{"start":{"line":1385,"column":22},"end":{"line":1385,"column":47}}]},"204":{"loc":{"start":{"line":1386,"column":21},"end":{"line":1386,"column":51}},"type":"cond-expr","locations":[{"start":{"line":1386,"column":38},"end":{"line":1386,"column":42}},{"start":{"line":1386,"column":42},"end":{"line":1386,"column":51}}]},"205":{"loc":{"start":{"line":1386,"column":21},"end":{"line":1386,"column":42}},"type":"binary-expr","locations":[{"start":{"line":1386,"column":21},"end":{"line":1386,"column":42}},{"start":{"line":1386,"column":38},"end":{"line":1386,"column":42}}]},"206":{"loc":{"start":{"line":1387,"column":18},"end":{"line":1387,"column":73}},"type":"cond-expr","locations":[{"start":{"line":1387,"column":39},"end":{"line":1387,"column":68}},{"start":{"line":1387,"column":71},"end":{"line":1387,"column":73}}]},"207":{"loc":{"start":{"line":1393,"column":2},"end":{"line":1395,"column":3}},"type":"if","locations":[{"start":{"line":1393,"column":2},"end":{"line":1395,"column":3}},{"start":{},"end":{}}]},"208":{"loc":{"start":{"line":1399,"column":2},"end":{"line":1401,"column":3}},"type":"if","locations":[{"start":{"line":1399,"column":2},"end":{"line":1401,"column":3}},{"start":{},"end":{}}]},"209":{"loc":{"start":{"line":1403,"column":2},"end":{"line":1405,"column":3}},"type":"if","locations":[{"start":{"line":1403,"column":2},"end":{"line":1405,"column":3}},{"start":{},"end":{}}]},"210":{"loc":{"start":{"line":1419,"column":12},"end":{"line":1419,"column":30}},"type":"cond-expr","locations":[{"start":{"line":1419,"column":24},"end":{"line":1419,"column":28}},{"start":{"line":1419,"column":28},"end":{"line":1419,"column":30}}]},"211":{"loc":{"start":{"line":1419,"column":12},"end":{"line":1419,"column":28}},"type":"binary-expr","locations":[{"start":{"line":1419,"column":12},"end":{"line":1419,"column":28}},{"start":{"line":1419,"column":24},"end":{"line":1419,"column":28}}]},"212":{"loc":{"start":{"line":1423,"column":8},"end":{"line":1423,"column":56}},"type":"cond-expr","locations":[{"start":{"line":1423,"column":31},"end":{"line":1423,"column":42}},{"start":{"line":1423,"column":45},"end":{"line":1423,"column":56}}]},"213":{"loc":{"start":{"line":1430,"column":2},"end":{"line":1432,"column":3}},"type":"if","locations":[{"start":{"line":1430,"column":2},"end":{"line":1432,"column":3}},{"start":{},"end":{}}]},"214":{"loc":{"start":{"line":1435,"column":14},"end":{"line":1435,"column":64}},"type":"cond-expr","locations":[{"start":{"line":1435,"column":44},"end":{"line":1435,"column":48}},{"start":{"line":1435,"column":48},"end":{"line":1435,"column":64}}]},"215":{"loc":{"start":{"line":1435,"column":14},"end":{"line":1435,"column":48}},"type":"binary-expr","locations":[{"start":{"line":1435,"column":14},"end":{"line":1435,"column":48}},{"start":{"line":1435,"column":44},"end":{"line":1435,"column":48}}]},"216":{"loc":{"start":{"line":1435,"column":14},"end":{"line":1435,"column":44}},"type":"cond-expr","locations":[{"start":{"line":1435,"column":29},"end":{"line":1435,"column":33}},{"start":{"line":1435,"column":33},"end":{"line":1435,"column":44}}]},"217":{"loc":{"start":{"line":1435,"column":14},"end":{"line":1435,"column":33}},"type":"binary-expr","locations":[{"start":{"line":1435,"column":14},"end":{"line":1435,"column":33}},{"start":{"line":1435,"column":29},"end":{"line":1435,"column":33}}]},"218":{"loc":{"start":{"line":1436,"column":11},"end":{"line":1436,"column":40}},"type":"cond-expr","locations":[{"start":{"line":1436,"column":15},"end":{"line":1436,"column":36}},{"start":{"line":1436,"column":39},"end":{"line":1436,"column":40}}]},"219":{"loc":{"start":{"line":1442,"column":18},"end":{"line":1442,"column":64}},"type":"cond-expr","locations":[{"start":{"line":1442,"column":43},"end":{"line":1442,"column":59}},{"start":{"line":1442,"column":62},"end":{"line":1442,"column":64}}]},"220":{"loc":{"start":{"line":1442,"column":18},"end":{"line":1442,"column":40}},"type":"binary-expr","locations":[{"start":{"line":1442,"column":18},"end":{"line":1442,"column":25}},{"start":{"line":1442,"column":29},"end":{"line":1442,"column":40}}]},"221":{"loc":{"start":{"line":1443,"column":17},"end":{"line":1443,"column":38}},"type":"cond-expr","locations":[{"start":{"line":1443,"column":25},"end":{"line":1443,"column":29}},{"start":{"line":1443,"column":29},"end":{"line":1443,"column":38}}]},"222":{"loc":{"start":{"line":1443,"column":17},"end":{"line":1443,"column":29}},"type":"binary-expr","locations":[{"start":{"line":1443,"column":17},"end":{"line":1443,"column":29}},{"start":{"line":1443,"column":25},"end":{"line":1443,"column":29}}]},"223":{"loc":{"start":{"line":1443,"column":51},"end":{"line":1443,"column":66}},"type":"cond-expr","locations":[{"start":{"line":1443,"column":60},"end":{"line":1443,"column":64}},{"start":{"line":1443,"column":64},"end":{"line":1443,"column":66}}]},"224":{"loc":{"start":{"line":1443,"column":51},"end":{"line":1443,"column":64}},"type":"binary-expr","locations":[{"start":{"line":1443,"column":51},"end":{"line":1443,"column":64}},{"start":{"line":1443,"column":60},"end":{"line":1443,"column":64}}]},"225":{"loc":{"start":{"line":1445,"column":2},"end":{"line":1449,"column":3}},"type":"if","locations":[{"start":{"line":1445,"column":2},"end":{"line":1449,"column":3}},{"start":{},"end":{}}]},"226":{"loc":{"start":{"line":1485,"column":13},"end":{"line":1485,"column":74}},"type":"binary-expr","locations":[{"start":{"line":1485,"column":13},"end":{"line":1485,"column":43}},{"start":{"line":1485,"column":47},"end":{"line":1485,"column":74}}]},"227":{"loc":{"start":{"line":1500,"column":2},"end":{"line":1500,"column":null}},"type":"if","locations":[{"start":{"line":1500,"column":2},"end":{"line":1500,"column":null}},{"start":{},"end":{}}]},"228":{"loc":{"start":{"line":1526,"column":6},"end":{"line":1526,"column":14}},"type":"switch","locations":[{"start":{"line":1526,"column":6},"end":{"line":1526,"column":14}},{"start":{"line":1554,"column":19},"end":{"line":1554,"column":null}}]},"229":{"loc":{"start":{"line":1504,"column":9},"end":{"line":1504,"column":null}},"type":"if","locations":[{"start":{"line":1504,"column":9},"end":{"line":1504,"column":null}},{"start":{},"end":{}}]},"230":{"loc":{"start":{"line":1514,"column":10},"end":{"line":1514,"column":58}},"type":"cond-expr","locations":[{"start":{"line":1514,"column":33},"end":{"line":1514,"column":44}},{"start":{"line":1514,"column":47},"end":{"line":1514,"column":58}}]},"231":{"loc":{"start":{"line":1522,"column":12},"end":{"line":1522,"column":60}},"type":"cond-expr","locations":[{"start":{"line":1522,"column":35},"end":{"line":1522,"column":46}},{"start":{"line":1522,"column":49},"end":{"line":1522,"column":60}}]},"232":{"loc":{"start":{"line":1529,"column":4},"end":{"line":1531,"column":5}},"type":"if","locations":[{"start":{"line":1529,"column":4},"end":{"line":1531,"column":5}},{"start":{},"end":{}}]},"233":{"loc":{"start":{"line":1538,"column":8},"end":{"line":1538,"column":9}},"type":"if","locations":[{"start":{"line":1538,"column":8},"end":{"line":1538,"column":9}},{"start":{},"end":{}}]},"234":{"loc":{"start":{"line":1541,"column":6},"end":{"line":1545,"column":7}},"type":"if","locations":[{"start":{"line":1541,"column":6},"end":{"line":1545,"column":7}},{"start":{},"end":{}}]},"235":{"loc":{"start":{"line":1555,"column":8},"end":{"line":1555,"column":14}},"type":"if","locations":[{"start":{"line":1555,"column":8},"end":{"line":1555,"column":14}},{"start":{},"end":{}}]},"236":{"loc":{"start":{"line":1580,"column":2},"end":{"line":1582,"column":3}},"type":"if","locations":[{"start":{"line":1580,"column":2},"end":{"line":1582,"column":3}},{"start":{},"end":{}}]},"237":{"loc":{"start":{"line":1585,"column":2},"end":{"line":1590,"column":3}},"type":"if","locations":[{"start":{"line":1585,"column":2},"end":{"line":1590,"column":3}},{"start":{},"end":{}}]},"238":{"loc":{"start":{"line":1585,"column":6},"end":{"line":1585,"column":44}},"type":"binary-expr","locations":[{"start":{"line":1585,"column":6},"end":{"line":1585,"column":21}},{"start":{"line":1585,"column":25},"end":{"line":1585,"column":44}}]},"239":{"loc":{"start":{"line":1596,"column":9},"end":{"line":1599,"column":null}},"type":"switch","locations":[{"start":{"line":1596,"column":9},"end":{"line":1599,"column":null}},{"start":{"line":1596,"column":2},"end":{"line":1599,"column":null}}]},"240":{"loc":{"start":{"line":1611,"column":2},"end":{"line":1613,"column":3}},"type":"if","locations":[{"start":{"line":1611,"column":2},"end":{"line":1613,"column":3}},{"start":{},"end":{}}]},"241":{"loc":{"start":{"line":1611,"column":6},"end":{"line":1611,"column":65}},"type":"binary-expr","locations":[{"start":{"line":1611,"column":6},"end":{"line":1611,"column":28}},{"start":{"line":1611,"column":28},"end":{"line":1611,"column":65}}]},"242":{"loc":{"start":{"line":1611,"column":7},"end":{"line":1611,"column":24}},"type":"cond-expr","locations":[{"start":{"line":1611,"column":17},"end":{"line":1611,"column":19}},{"start":{"line":1611,"column":17},"end":{"line":1611,"column":24}}]},"243":{"loc":{"start":{"line":1611,"column":7},"end":{"line":1611,"column":19}},"type":"binary-expr","locations":[{"start":{"line":1611,"column":7},"end":{"line":1611,"column":19}},{"start":{"line":1611,"column":17},"end":{"line":1611,"column":19}}]},"244":{"loc":{"start":{"line":1618,"column":14},"end":{"line":1621,"column":null}},"type":"switch","locations":[{"start":{"line":1618,"column":14},"end":{"line":1621,"column":null}}]},"245":{"loc":{"start":{"line":1622,"column":2},"end":{"line":1624,"column":3}},"type":"if","locations":[{"start":{"line":1622,"column":2},"end":{"line":1624,"column":3}},{"start":{},"end":{}}]},"246":{"loc":{"start":{"line":1622,"column":6},"end":{"line":1622,"column":24}},"type":"cond-expr","locations":[{"start":{"line":1622,"column":16},"end":{"line":1622,"column":18}},{"start":{"line":1622,"column":16},"end":{"line":1622,"column":24}}]},"247":{"loc":{"start":{"line":1622,"column":6},"end":{"line":1622,"column":18}},"type":"binary-expr","locations":[{"start":{"line":1622,"column":6},"end":{"line":1622,"column":18}},{"start":{"line":1622,"column":16},"end":{"line":1622,"column":18}}]},"248":{"loc":{"start":{"line":1625,"column":11},"end":{"line":1625,"column":32}},"type":"cond-expr","locations":[{"start":{"line":1625,"column":21},"end":{"line":1625,"column":23}},{"start":{"line":1625,"column":21},"end":{"line":1625,"column":32}}]},"249":{"loc":{"start":{"line":1625,"column":11},"end":{"line":1625,"column":23}},"type":"binary-expr","locations":[{"start":{"line":1625,"column":11},"end":{"line":1625,"column":23}},{"start":{"line":1625,"column":21},"end":{"line":1625,"column":23}}]},"250":{"loc":{"start":{"line":1654,"column":18},"end":{"line":1657,"column":null}},"type":"switch","locations":[{"start":{"line":1654,"column":18},"end":{"line":1657,"column":null}}]},"251":{"loc":{"start":{"line":1658,"column":2},"end":{"line":1660,"column":3}},"type":"if","locations":[{"start":{"line":1658,"column":2},"end":{"line":1660,"column":3}},{"start":{},"end":{}}]},"252":{"loc":{"start":{"line":1664,"column":19},"end":{"line":1664,"column":22}},"type":"switch","locations":[{"start":{"line":1664,"column":19},"end":{"line":1664,"column":22}}]},"253":{"loc":{"start":{"line":1664,"column":19},"end":{"line":1664,"column":37}},"type":"cond-expr","locations":[{"start":{"line":1664,"column":31},"end":{"line":1664,"column":33}},{"start":{"line":1664,"column":31},"end":{"line":1664,"column":37}}]},"254":{"loc":{"start":{"line":1664,"column":19},"end":{"line":1664,"column":33}},"type":"binary-expr","locations":[{"start":{"line":1664,"column":19},"end":{"line":1664,"column":33}},{"start":{"line":1664,"column":31},"end":{"line":1664,"column":33}}]},"255":{"loc":{"start":{"line":1672,"column":14},"end":{"line":1675,"column":null}},"type":"switch","locations":[{"start":{"line":1672,"column":14},"end":{"line":1675,"column":null}}]},"256":{"loc":{"start":{"line":1697,"column":33},"end":{"line":1697,"column":53}},"type":"cond-expr","locations":[{"start":{"line":1697,"column":44},"end":{"line":1697,"column":46}},{"start":{"line":1697,"column":44},"end":{"line":1697,"column":53}}]},"257":{"loc":{"start":{"line":1697,"column":33},"end":{"line":1697,"column":46}},"type":"binary-expr","locations":[{"start":{"line":1697,"column":33},"end":{"line":1697,"column":46}},{"start":{"line":1697,"column":44},"end":{"line":1697,"column":46}}]},"258":{"loc":{"start":{"line":1719,"column":2},"end":{"line":1719,"column":null}},"type":"switch","locations":[{"start":{"line":1719,"column":2},"end":{"line":1719,"column":null}}]},"259":{"loc":{"start":{"line":1723,"column":2},"end":{"line":1725,"column":3}},"type":"if","locations":[{"start":{"line":1723,"column":2},"end":{"line":1725,"column":3}},{"start":{},"end":{}}]},"260":{"loc":{"start":{"line":1728,"column":2},"end":{"line":1730,"column":3}},"type":"if","locations":[{"start":{"line":1728,"column":2},"end":{"line":1730,"column":3}},{"start":{},"end":{}}]},"261":{"loc":{"start":{"line":1728,"column":6},"end":{"line":1728,"column":24}},"type":"cond-expr","locations":[{"start":{"line":1728,"column":13},"end":{"line":1728,"column":15}},{"start":{"line":1728,"column":6},"end":{"line":1728,"column":24}}]},"262":{"loc":{"start":{"line":1728,"column":6},"end":{"line":1728,"column":15}},"type":"binary-expr","locations":[{"start":{"line":1728,"column":6},"end":{"line":1728,"column":15}},{"start":{"line":1728,"column":6},"end":{"line":1728,"column":15}}]},"263":{"loc":{"start":{"line":1738,"column":4},"end":{"line":1740,"column":5}},"type":"if","locations":[{"start":{"line":1738,"column":4},"end":{"line":1740,"column":5}},{"start":{},"end":{}}]},"264":{"loc":{"start":{"line":1754,"column":4},"end":{"line":1756,"column":5}},"type":"if","locations":[{"start":{"line":1754,"column":4},"end":{"line":1756,"column":5}},{"start":{},"end":{}}]},"265":{"loc":{"start":{"line":1754,"column":8},"end":{"line":1754,"column":51}},"type":"binary-expr","locations":[{"start":{"line":1754,"column":8},"end":{"line":1754,"column":26}},{"start":{"line":1754,"column":30},"end":{"line":1754,"column":51}}]},"266":{"loc":{"start":{"line":1760,"column":4},"end":{"line":1762,"column":null}},"type":"switch","locations":[{"start":{"line":1760,"column":4},"end":{"line":1762,"column":null}}]},"267":{"loc":{"start":{"line":1764,"column":4},"end":{"line":1766,"column":5}},"type":"if","locations":[{"start":{"line":1764,"column":4},"end":{"line":1766,"column":5}},{"start":{},"end":{}}]},"268":{"loc":{"start":{"line":1764,"column":8},"end":{"line":1764,"column":73}},"type":"binary-expr","locations":[{"start":{"line":1764,"column":8},"end":{"line":1764,"column":30}},{"start":{"line":1764,"column":34},"end":{"line":1764,"column":73}}]},"269":{"loc":{"start":{"line":1767,"column":4},"end":{"line":1769,"column":5}},"type":"if","locations":[{"start":{"line":1767,"column":4},"end":{"line":1769,"column":5}},{"start":{},"end":{}}]},"270":{"loc":{"start":{"line":1770,"column":4},"end":{"line":1772,"column":5}},"type":"if","locations":[{"start":{"line":1770,"column":4},"end":{"line":1772,"column":5}},{"start":{},"end":{}}]},"271":{"loc":{"start":{"line":1780,"column":2},"end":{"line":1782,"column":3}},"type":"if","locations":[{"start":{"line":1780,"column":2},"end":{"line":1782,"column":3}},{"start":{},"end":{}}]},"272":{"loc":{"start":{"line":1780,"column":7},"end":{"line":1780,"column":37}},"type":"cond-expr","locations":[{"start":{"line":1780,"column":29},"end":{"line":1780,"column":31}},{"start":{"line":1780,"column":29},"end":{"line":1780,"column":37}}]},"273":{"loc":{"start":{"line":1780,"column":7},"end":{"line":1780,"column":31}},"type":"binary-expr","locations":[{"start":{"line":1780,"column":7},"end":{"line":1780,"column":31}},{"start":{"line":1780,"column":29},"end":{"line":1780,"column":31}}]},"274":{"loc":{"start":{"line":1785,"column":4},"end":{"line":1787,"column":5}},"type":"if","locations":[{"start":{"line":1785,"column":4},"end":{"line":1787,"column":5}},{"start":{},"end":{}}]},"275":{"loc":{"start":{"line":1791,"column":6},"end":{"line":1791,"column":75}},"type":"cond-expr","locations":[{"start":{"line":1791,"column":36},"end":{"line":1791,"column":67}},{"start":{"line":1791,"column":70},"end":{"line":1791,"column":75}}]},"276":{"loc":{"start":{"line":1794,"column":4},"end":{"line":1796,"column":5}},"type":"if","locations":[{"start":{"line":1794,"column":4},"end":{"line":1796,"column":5}},{"start":{},"end":{}}]},"277":{"loc":{"start":{"line":1800,"column":6},"end":{"line":1802,"column":7}},"type":"if","locations":[{"start":{"line":1800,"column":6},"end":{"line":1802,"column":7}},{"start":{},"end":{}}]},"278":{"loc":{"start":{"line":1800,"column":10},"end":{"line":1800,"column":58}},"type":"binary-expr","locations":[{"start":{"line":1800,"column":10},"end":{"line":1800,"column":32}},{"start":{"line":1800,"column":36},"end":{"line":1800,"column":43}},{"start":{"line":1800,"column":47},"end":{"line":1800,"column":58}}]},"279":{"loc":{"start":{"line":1806,"column":4},"end":{"line":1811,"column":5}},"type":"if","locations":[{"start":{"line":1806,"column":4},"end":{"line":1811,"column":5}},{"start":{"line":1808,"column":11},"end":{"line":1811,"column":5}}]},"280":{"loc":{"start":{"line":1819,"column":9},"end":{"line":1822,"column":null}},"type":"switch","locations":[{"start":{"line":1819,"column":9},"end":{"line":1822,"column":null}},{"start":{"line":1819,"column":2},"end":{"line":1822,"column":null}}]},"281":{"loc":{"start":{"line":1826,"column":9},"end":{"line":1829,"column":null}},"type":"switch","locations":[{"start":{"line":1826,"column":9},"end":{"line":1829,"column":null}},{"start":{"line":1826,"column":2},"end":{"line":1829,"column":null}}]},"282":{"loc":{"start":{"line":1833,"column":18},"end":{"line":1836,"column":null}},"type":"switch","locations":[{"start":{"line":1833,"column":18},"end":{"line":1836,"column":null}}]},"283":{"loc":{"start":{"line":1837,"column":9},"end":{"line":1837,"column":28}},"type":"cond-expr","locations":[{"start":{"line":1837,"column":22},"end":{"line":1837,"column":26}},{"start":{"line":1837,"column":26},"end":{"line":1837,"column":28}}]},"284":{"loc":{"start":{"line":1837,"column":9},"end":{"line":1837,"column":26}},"type":"binary-expr","locations":[{"start":{"line":1837,"column":9},"end":{"line":1837,"column":26}},{"start":{"line":1837,"column":22},"end":{"line":1837,"column":26}}]}},"s":{"0":13,"1":13,"2":13,"3":13,"4":13,"5":13,"6":13,"7":13,"8":13,"9":13,"10":13,"11":13,"12":13,"13":13,"14":13,"15":13,"16":13,"17":13,"18":13,"19":13,"20":13,"21":13,"22":13,"23":13,"24":13,"25":13,"26":13,"27":13,"28":13,"29":13,"30":13,"31":13,"32":13,"33":13,"34":13,"35":13,"36":13,"37":13,"38":13,"39":13,"40":13,"41":13,"42":13,"43":13,"44":13,"45":13,"46":13,"47":13,"48":13,"49":13,"50":13,"51":13,"52":13,"53":13,"54":13,"55":13,"56":13,"57":13,"58":13,"59":0,"60":0,"61":0,"62":0,"63":0,"64":0,"65":0,"66":0,"67":0,"68":0,"69":0,"70":0,"71":0,"72":0,"73":0,"74":0,"75":0,"76":0,"77":0,"78":0,"79":0,"80":0,"81":0,"82":0,"83":0,"84":0,"85":0,"86":0,"87":0,"88":0,"89":0,"90":0,"91":0,"92":0,"93":0,"94":0,"95":0,"96":0,"97":0,"98":0,"99":0,"100":0,"101":0,"102":0,"103":0,"104":0,"105":0,"106":0,"107":0,"108":0,"109":0,"110":0,"111":0,"112":0,"113":0,"114":0,"115":0,"116":0,"117":0,"118":0,"119":0,"120":0,"121":0,"122":0,"123":0,"124":0,"125":0,"126":0,"127":0,"128":0,"129":0,"130":0,"131":0,"132":0,"133":0,"134":0,"135":0,"136":0,"137":0,"138":0,"139":0,"140":0,"141":0,"142":0,"143":0,"144":0,"145":0,"146":0,"147":0,"148":0,"149":0,"150":0,"151":0,"152":0,"153":0,"154":0,"155":0,"156":0,"157":0,"158":0,"159":0,"160":0,"161":0,"162":0,"163":0,"164":0,"165":0,"166":0,"167":0,"168":0,"169":0,"170":13,"171":7,"172":7,"173":7,"174":7,"175":36,"176":0,"177":36,"178":36,"179":25,"180":7,"181":7,"182":35,"183":35,"184":35,"185":35,"186":70,"187":34,"188":34,"189":7,"190":7,"191":3,"192":3,"193":3,"194":3,"195":6,"196":2,"197":2,"198":7,"199":7,"200":0,"201":0,"202":7,"203":0,"204":0,"205":7,"206":35,"207":35,"208":35,"209":35,"210":0,"211":7,"212":3,"213":3,"214":3,"215":3,"216":0,"217":7,"218":4,"219":4,"220":7,"221":7,"222":5,"223":5,"224":5,"225":3,"226":2,"227":2,"228":1,"229":1,"230":2,"231":2,"232":2,"233":2,"234":1,"235":1,"236":7,"237":0,"238":0,"239":0,"240":0,"241":0,"242":0,"243":0,"244":0,"245":0,"246":0,"247":0,"248":0,"249":0,"250":0,"251":0,"252":0,"253":0,"254":0,"255":0,"256":0,"257":0,"258":0,"259":0,"260":0,"261":0,"262":0,"263":0,"264":0,"265":0,"266":0,"267":0,"268":0,"269":0,"270":0,"271":0,"272":0,"273":0,"274":0,"275":3,"276":3,"277":90,"278":90,"279":90,"280":90,"281":180,"282":90,"283":0,"284":0,"285":0,"286":0,"287":90,"288":90,"289":90,"290":90,"291":3,"292":174,"293":90,"294":0,"295":0,"296":0,"297":0,"298":0,"299":0,"300":0,"301":0,"302":0,"303":0,"304":0,"305":0,"306":0,"307":0,"308":0,"309":0,"310":0,"311":0,"312":0,"313":0,"314":0,"315":0,"316":0,"317":0,"318":0,"319":0,"320":0,"321":0,"322":0,"323":0,"324":0,"325":0,"326":0,"327":0,"328":2,"329":2,"330":2,"331":0,"332":2,"333":60,"334":60,"335":60,"336":60,"337":60,"338":60,"339":120,"340":60,"341":60,"342":60,"343":0,"344":0,"345":0,"346":60,"347":60,"348":60,"349":60,"350":2,"351":116,"352":60,"353":0,"354":0,"355":0,"356":0,"357":0,"358":0,"359":0,"360":0,"361":0,"362":0,"363":0,"364":0,"365":0,"366":0,"367":0,"368":0,"369":0,"370":0,"371":0,"372":0,"373":0,"374":0,"375":0,"376":0,"377":0,"378":0,"379":0,"380":0,"381":0,"382":0,"383":0,"384":0,"385":0,"386":0,"387":3,"388":3,"389":0,"390":3,"391":3,"392":0,"393":3,"394":0,"395":0,"396":0,"397":0,"398":0,"399":0,"400":0,"401":0,"402":0,"403":0,"404":0,"405":0,"406":0,"407":0,"408":0,"409":0,"410":0,"411":0,"412":0,"413":0,"414":0,"415":0,"416":0,"417":0,"418":0,"419":0,"420":0,"421":0,"422":0,"423":0,"424":0,"425":0,"426":21,"427":0,"428":0,"429":0,"430":0,"431":0,"432":0,"433":0,"434":0,"435":0,"436":13,"437":13,"438":13,"439":13,"440":13,"441":28,"442":28,"443":26,"444":2,"445":2,"446":2,"447":2,"448":3,"449":3,"450":3,"451":3,"452":2,"453":23,"454":23,"455":21,"456":2,"457":2,"458":2,"459":2,"460":3,"461":3,"462":3,"463":3,"464":2,"465":24,"466":24,"467":21,"468":3,"469":3,"470":3,"471":3,"472":7,"473":7,"474":7,"475":4,"476":3,"477":19,"478":2,"479":17,"480":58,"481":17,"482":17,"483":17,"484":0,"485":0,"486":0,"487":0,"488":0,"489":0,"490":0,"491":0,"492":0,"493":0,"494":0,"495":0,"496":0,"497":0,"498":0,"499":0,"500":9,"501":4,"502":3,"503":1,"504":1,"505":18,"506":18,"507":18,"508":18,"509":36,"510":14,"511":14,"512":14,"513":9,"514":9,"515":9,"516":9,"517":18,"518":11,"519":3,"520":8,"521":2,"522":6,"523":5,"524":1,"525":0,"526":0,"527":1,"528":3,"529":1,"530":21,"531":21,"532":21,"533":21,"534":42,"535":17,"536":17,"537":17,"538":11,"539":11,"540":11,"541":11,"542":21,"543":10,"544":4,"545":1,"546":4,"547":1,"548":21,"549":21,"550":0,"551":21,"552":20,"553":19,"554":2,"555":2,"556":19,"557":19,"558":19,"559":19,"560":19,"561":3,"562":16,"563":5,"564":5,"565":11,"566":1,"567":10,"568":10,"569":10,"570":10,"571":10,"572":10,"573":19,"574":9,"575":9,"576":1,"577":8,"578":8,"579":8,"580":8,"581":8,"582":8,"583":1,"584":8,"585":1,"586":1,"587":1,"588":1,"589":1,"590":8,"591":8,"592":8,"593":8,"594":8,"595":3,"596":3,"597":3,"598":2,"599":1,"600":1,"601":3,"602":3,"603":1,"604":1,"605":1,"606":8,"607":2,"608":8,"609":8,"610":8,"611":3,"612":8,"613":0,"614":8,"615":8,"616":7,"617":6,"618":2,"619":2,"620":6,"621":4,"622":6,"623":3,"624":3,"625":0,"626":0,"627":3,"628":0,"629":3,"630":3,"631":3,"632":3,"633":3,"634":0,"635":3,"636":6,"637":6,"638":6,"639":6,"640":6,"641":6,"642":0,"643":0,"644":6,"645":18,"646":10,"647":10,"648":15,"649":0,"650":15,"651":15,"652":15,"653":6,"654":12,"655":2,"656":4,"657":9,"658":9,"659":3,"660":10,"661":2,"662":2,"663":2,"664":2,"665":2,"666":0,"667":2,"668":4,"669":4,"670":5,"671":3,"672":3,"673":3,"674":2,"675":0,"676":0,"677":0,"678":5,"679":5,"680":5,"681":0,"682":0,"683":0,"684":0,"685":0,"686":24,"687":24,"688":13,"689":16,"690":3,"691":13,"692":3,"693":3,"694":1,"695":1,"696":0,"697":0,"698":0,"699":0,"700":0,"701":0,"702":0,"703":0,"704":0,"705":0,"706":0,"707":0,"708":21,"709":0,"710":0,"711":0,"712":0,"713":0,"714":0,"715":0,"716":0,"717":0,"718":0,"719":0,"720":0,"721":0,"722":0,"723":0,"724":0,"725":0,"726":0,"727":0,"728":0,"729":0,"730":0,"731":0,"732":0,"733":0,"734":0,"735":0,"736":0,"737":0,"738":0,"739":0,"740":0,"741":0,"742":0,"743":276,"744":213,"745":63,"746":63,"747":63,"748":63,"749":0,"750":0,"751":0,"752":0,"753":0,"754":0,"755":13,"756":13,"757":13,"758":13,"759":13,"760":3,"761":13,"762":14,"763":7,"764":7,"765":7,"766":2,"767":5,"768":5,"769":5,"770":0,"771":13,"772":21,"773":21,"774":21,"775":0,"776":0,"777":0,"778":0,"779":0,"780":0,"781":0,"782":0,"783":0,"784":0,"785":0,"786":0,"787":0,"788":0,"789":0,"790":0,"791":0,"792":0,"793":0,"794":0,"795":0,"796":0,"797":0,"798":0,"799":0,"800":0,"801":0,"802":21,"803":0,"804":0},"f":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":7,"18":36,"19":35,"20":3,"21":7,"22":35,"23":3,"24":4,"25":7,"26":5,"27":2,"28":0,"29":0,"30":0,"31":0,"32":0,"33":0,"34":0,"35":0,"36":0,"37":0,"38":0,"39":3,"40":90,"41":0,"42":0,"43":90,"44":0,"45":0,"46":0,"47":0,"48":0,"49":0,"50":2,"51":60,"52":0,"53":0,"54":60,"55":0,"56":0,"57":0,"58":0,"59":0,"60":0,"61":3,"62":0,"63":0,"64":0,"65":21,"66":0,"67":0,"68":28,"69":23,"70":24,"71":19,"72":58,"73":17,"74":9,"75":18,"76":11,"77":21,"78":10,"79":21,"80":9,"81":8,"82":4,"83":0,"84":0,"85":3,"86":6,"87":6,"88":0,"89":0,"90":10,"91":5,"92":24,"93":16,"94":3,"95":0,"96":0,"97":0,"98":0,"99":0,"100":21,"101":0,"102":0,"103":0,"104":0,"105":0,"106":0,"107":276,"108":63,"109":13,"110":13,"111":7,"112":7,"113":21,"114":0,"115":0,"116":0,"117":21},"b":{"0":[0],"1":[0,0],"2":[0,0],"3":[0,0],"4":[0,0],"5":[0,0],"6":[0,0],"7":[0,0],"8":[0,0],"9":[0,0],"10":[0,0],"11":[0,0],"12":[0,0],"13":[0,0],"14":[0,0],"15":[0,0],"16":[0,0],"17":[0,0],"18":[0,0],"19":[0,0],"20":[0,0],"21":[0,0],"22":[0,0],"23":[0],"24":[0,0],"25":[0,0],"26":[0,0],"27":[0,0],"28":[0,0],"29":[0,0],"30":[0],"31":[0,0],"32":[0,0],"33":[0,0],"34":[0,0,0],"35":[0,0],"36":[0,0],"37":[0,0],"38":[0,0],"39":[0,0],"40":[0,0],"41":[0,0],"42":[0,0],"43":[0,0],"44":[0,0],"45":[0,0],"46":[0,0,0],"47":[6,1],"48":[7],"49":[0,36],"50":[25,11],"51":[35,0],"52":[35,35],"53":[3,0],"54":[3,3],"55":[0,7],"56":[0,7],"57":[0,4],"58":[4,4],"59":[2,2],"60":[0,7],"61":[7,7],"62":[3,2],"63":[3,3],"64":[0,2],"65":[2,2],"66":[1,1],"67":[1,0],"68":[0,1],"69":[1,1],"70":[2,0],"71":[1,1],"72":[0,0],"73":[0,0],"74":[0,0],"75":[0,0],"76":[0,0],"77":[0,0],"78":[0,0],"79":[0,0],"80":[0,0],"81":[0,0],"82":[0,0],"83":[3,87],"84":[0,90],"85":[0,0],"86":[0,0],"87":[0,0],"88":[0,2],"89":[60,0],"90":[0,0],"91":[2,58],"92":[0,60],"93":[0,0],"94":[0,0],"95":[0,0],"96":[0],"97":[0,3],"98":[0,0],"99":[0],"100":[0,0],"101":[0],"102":[21],"103":[0,0],"104":[0],"105":[0,0],"106":[0,0],"107":[26,2],"108":[3,0],"109":[21,2],"110":[3,0],"111":[21,3],"112":[4,3],"113":[2,17],"114":[17,0],"115":[0,0],"116":[0,0],"117":[0,0],"118":[4,3,1,1],"119":[1,17],"120":[18,18],"121":[1,17],"122":[18,18],"123":[12,6],"124":[18,18],"125":[1,17],"126":[18,18],"127":[0,14],"128":[14,14],"129":[9,5],"130":[14,13],"131":[1,13],"132":[14,14],"133":[2,7],"134":[3,8],"135":[2,6],"136":[5,1],"137":[1,0,0,1,3],"138":[3,0],"139":[3,3],"140":[1,20],"141":[21,21],"142":[1,20],"143":[21,21],"144":[15,6],"145":[21,21],"146":[1,20],"147":[21,21],"148":[0,17],"149":[17,17],"150":[11,6],"151":[17,13],"152":[4,13],"153":[17,17],"154":[2,9],"155":[4,1,4,1],"156":[0,21],"157":[19,0],"158":[19,19],"159":[2,0],"160":[3,16],"161":[19,18,18],"162":[5,11],"163":[16,9],"164":[4,1],"165":[5,5],"166":[1,10],"167":[2,8],"168":[10,3],"169":[10,0],"170":[1,0],"171":[8,0],"172":[0,8],"173":[8,8],"174":[1,7],"175":[1,7],"176":[0,8],"177":[8,8],"178":[1,7],"179":[8,8],"180":[0,8],"181":[8,8],"182":[1,0],"183":[1,0],"184":[1,0],"185":[0,8],"186":[8,8],"187":[0,8],"188":[8,8],"189":[3,5],"190":[8,8],"191":[0,8],"192":[8,8],"193":[0,3],"194":[3,3],"195":[2,1],"196":[1,2],"197":[3,3],"198":[1,1],"199":[0,1],"200":[0,3],"201":[3,3],"202":[1,2],"203":[3,1],"204":[1,0],"205":[1,1],"206":[0,1],"207":[2,6],"208":[3,5],"209":[0,8],"210":[6,0],"211":[6,6],"212":[2,0],"213":[3,3],"214":[0,0],"215":[0,0],"216":[0,0],"217":[0,0],"218":[0,0],"219":[2,1],"220":[3,2],"221":[3,0],"222":[3,3],"223":[3,0],"224":[3,3],"225":[0,3],"226":[0,0],"227":[8,2],"228":[4,4],"229":[0,15],"230":[6,0],"231":[2,0],"232":[3,6],"233":[4,2],"234":[0,2],"235":[1,3],"236":[5,0],"237":[0,0],"238":[0,0],"239":[24,24],"240":[3,13],"241":[16,14],"242":[1,15],"243":[16,16],"244":[3],"245":[1,0],"246":[0,1],"247":[1,1],"248":[0,0],"249":[0,0],"250":[21],"251":[0,0],"252":[0],"253":[0,0],"254":[0,0],"255":[0],"256":[0,0],"257":[0,0],"258":[0],"259":[213,63],"260":[63,0],"261":[0,63],"262":[63,63],"263":[0,0],"264":[3,10],"265":[13,10],"266":[7],"267":[2,5],"268":[7,7],"269":[5,0],"270":[0,5],"271":[21,0],"272":[11,10],"273":[21,21],"274":[0,0],"275":[0,0],"276":[0,0],"277":[0,0],"278":[0,0,0],"279":[0,0],"280":[0,0],"281":[0,0],"282":[21],"283":[0,0],"284":[0,0]}} +,"/__w/backlog/backlog/work/runner-container-hooks/packages/k8s/src/k8s/utils/index.ts": {"path":"/__w/backlog/backlog/work/runner-container-hooks/packages/k8s/src/k8s/utils/index.ts","statementMap":{"0":{"start":{"line":35,"column":0},"end":{"line":35,"column":16}},"1":{"start":{"line":59,"column":0},"end":{"line":59,"column":16}},"2":{"start":{"line":94,"column":0},"end":{"line":94,"column":16}},"3":{"start":{"line":161,"column":0},"end":{"line":161,"column":16}},"4":{"start":{"line":180,"column":0},"end":{"line":180,"column":16}},"5":{"start":{"line":208,"column":0},"end":{"line":208,"column":16}},"6":{"start":{"line":228,"column":0},"end":{"line":228,"column":16}},"7":{"start":{"line":258,"column":0},"end":{"line":258,"column":16}},"8":{"start":{"line":270,"column":0},"end":{"line":270,"column":16}},"9":{"start":{"line":292,"column":0},"end":{"line":292,"column":16}},"10":{"start":{"line":301,"column":0},"end":{"line":301,"column":22}},"11":{"start":{"line":305,"column":0},"end":{"line":305,"column":16}},"12":{"start":{"line":315,"column":0},"end":{"line":315,"column":16}},"13":{"start":{"line":2,"column":0},"end":{"line":2,"column":24}},"14":{"start":{"line":3,"column":0},"end":{"line":3,"column":31}},"15":{"start":{"line":4,"column":0},"end":{"line":4,"column":37}},"16":{"start":{"line":5,"column":0},"end":{"line":5,"column":35}},"17":{"start":{"line":6,"column":0},"end":{"line":6,"column":66}},"18":{"start":{"line":7,"column":0},"end":{"line":7,"column":30}},"19":{"start":{"line":10,"column":13},"end":{"line":10,"column":null}},"20":{"start":{"line":11,"column":13},"end":{"line":11,"column":null}},"21":{"start":{"line":13,"column":13},"end":{"line":13,"column":null}},"22":{"start":{"line":14,"column":13},"end":{"line":14,"column":null}},"23":{"start":{"line":16,"column":13},"end":{"line":16,"column":null}},"24":{"start":{"line":17,"column":13},"end":{"line":17,"column":null}},"25":{"start":{"line":18,"column":13},"end":{"line":18,"column":null}},"26":{"start":{"line":20,"column":13},"end":{"line":33,"column":null}},"27":{"start":{"line":39,"column":18},"end":{"line":41,"column":14}},"28":{"start":{"line":40,"column":14},"end":{"line":40,"column":46}},"29":{"start":{"line":43,"column":18},"end":{"line":47,"column":null}},"30":{"start":{"line":50,"column":19},"end":{"line":50,"column":35}},"31":{"start":{"line":51,"column":25},"end":{"line":51,"column":65}},"32":{"start":{"line":52,"column":2},"end":{"line":52,"column":null}},"33":{"start":{"line":53,"column":2},"end":{"line":56,"column":null}},"34":{"start":{"line":66,"column":19},"end":{"line":66,"column":21}},"35":{"start":{"line":67,"column":2},"end":{"line":72,"column":3}},"36":{"start":{"line":70,"column":6},"end":{"line":70,"column":75}},"37":{"start":{"line":71,"column":4},"end":{"line":71,"column":null}},"38":{"start":{"line":74,"column":26},"end":{"line":74,"column":57}},"39":{"start":{"line":76,"column":18},"end":{"line":82,"column":null}},"40":{"start":{"line":85,"column":19},"end":{"line":85,"column":35}},"41":{"start":{"line":86,"column":25},"end":{"line":86,"column":65}},"42":{"start":{"line":87,"column":2},"end":{"line":87,"column":null}},"43":{"start":{"line":88,"column":2},"end":{"line":91,"column":null}},"44":{"start":{"line":101,"column":26},"end":{"line":101,"column":57}},"45":{"start":{"line":103,"column":16},"end":{"line":103,"column":53}},"46":{"start":{"line":104,"column":2},"end":{"line":106,"column":3}},"47":{"start":{"line":105,"column":4},"end":{"line":105,"column":null}},"48":{"start":{"line":108,"column":18},"end":{"line":116,"column":null}},"49":{"start":{"line":119,"column":19},"end":{"line":119,"column":35}},"50":{"start":{"line":120,"column":25},"end":{"line":120,"column":45}},"51":{"start":{"line":121,"column":2},"end":{"line":121,"column":null}},"52":{"start":{"line":122,"column":2},"end":{"line":122,"column":null}},"53":{"start":{"line":123,"column":2},"end":{"line":126,"column":null}},"54":{"start":{"line":130,"column":2},"end":{"line":132,"column":3}},"55":{"start":{"line":131,"column":4},"end":{"line":131,"column":null}},"56":{"start":{"line":133,"column":30},"end":{"line":133,"column":32}},"57":{"start":{"line":134,"column":2},"end":{"line":152,"column":3}},"58":{"start":{"line":134,"column":29},"end":{"line":134,"column":35}},"59":{"start":{"line":134,"column":29},"end":{"line":134,"column":49}},"60":{"start":{"line":134,"column":13},"end":{"line":134,"column":14}},"61":{"start":{"line":134,"column":17},"end":{"line":134,"column":19}},"62":{"start":{"line":134,"column":24},"end":{"line":134,"column":25}},"63":{"start":{"line":135,"column":4},"end":{"line":144,"column":5}},"64":{"start":{"line":141,"column":6},"end":{"line":143,"column":null}},"65":{"start":{"line":145,"column":4},"end":{"line":151,"column":null}},"66":{"start":{"line":154,"column":2},"end":{"line":156,"column":3}},"67":{"start":{"line":155,"column":4},"end":{"line":155,"column":null}},"68":{"start":{"line":158,"column":2},"end":{"line":158,"column":null}},"69":{"start":{"line":162,"column":22},"end":{"line":162,"column":44}},"70":{"start":{"line":163,"column":15},"end":{"line":163,"column":41}},"71":{"start":{"line":165,"column":2},"end":{"line":167,"column":3}},"72":{"start":{"line":166,"column":4},"end":{"line":166,"column":null}},"73":{"start":{"line":169,"column":2},"end":{"line":169,"column":null}},"74":{"start":{"line":184,"column":2},"end":{"line":205,"column":3}},"75":{"start":{"line":184,"column":29},"end":{"line":184,"column":35}},"76":{"start":{"line":184,"column":29},"end":{"line":184,"column":49}},"77":{"start":{"line":184,"column":13},"end":{"line":184,"column":14}},"78":{"start":{"line":184,"column":17},"end":{"line":184,"column":19}},"79":{"start":{"line":184,"column":24},"end":{"line":184,"column":25}},"80":{"start":{"line":185,"column":4},"end":{"line":204,"column":5}},"81":{"start":{"line":186,"column":6},"end":{"line":188,"column":7}},"82":{"start":{"line":187,"column":8},"end":{"line":187,"column":null}},"83":{"start":{"line":189,"column":6},"end":{"line":189,"column":14}},"84":{"start":{"line":190,"column":11},"end":{"line":204,"column":5}},"85":{"start":{"line":191,"column":6},"end":{"line":191,"column":null}},"86":{"start":{"line":192,"column":6},"end":{"line":192,"column":14}},"87":{"start":{"line":193,"column":11},"end":{"line":204,"column":5}},"88":{"start":{"line":194,"column":19},"end":{"line":194,"column":42}},"89":{"start":{"line":195,"column":6},"end":{"line":195,"column":null}},"90":{"start":{"line":196,"column":11},"end":{"line":204,"column":5}},"91":{"start":{"line":197,"column":27},"end":{"line":197,"column":55}},"92":{"start":{"line":198,"column":6},"end":{"line":198,"column":null}},"93":{"start":{"line":199,"column":11},"end":{"line":204,"column":5}},"94":{"start":{"line":200,"column":20},"end":{"line":200,"column":50}},"95":{"start":{"line":201,"column":6},"end":{"line":201,"column":null}},"96":{"start":{"line":203,"column":6},"end":{"line":203,"column":null}},"97":{"start":{"line":212,"column":2},"end":{"line":225,"column":3}},"98":{"start":{"line":212,"column":29},"end":{"line":212,"column":35}},"99":{"start":{"line":212,"column":29},"end":{"line":212,"column":49}},"100":{"start":{"line":212,"column":13},"end":{"line":212,"column":14}},"101":{"start":{"line":212,"column":17},"end":{"line":212,"column":19}},"102":{"start":{"line":212,"column":24},"end":{"line":212,"column":25}},"103":{"start":{"line":213,"column":4},"end":{"line":224,"column":5}},"104":{"start":{"line":214,"column":6},"end":{"line":217,"column":null}},"105":{"start":{"line":216,"column":15},"end":{"line":216,"column":null}},"106":{"start":{"line":219,"column":11},"end":{"line":224,"column":5}},"107":{"start":{"line":220,"column":22},"end":{"line":220,"column":45}},"108":{"start":{"line":221,"column":6},"end":{"line":221,"column":null}},"109":{"start":{"line":223,"column":6},"end":{"line":223,"column":null}},"110":{"start":{"line":232,"column":2},"end":{"line":236,"column":3}},"111":{"start":{"line":233,"column":4},"end":{"line":235,"column":null}},"112":{"start":{"line":237,"column":2},"end":{"line":244,"column":3}},"113":{"start":{"line":238,"column":4},"end":{"line":243,"column":5}},"114":{"start":{"line":238,"column":31},"end":{"line":238,"column":37}},"115":{"start":{"line":238,"column":31},"end":{"line":238,"column":58}},"116":{"start":{"line":238,"column":15},"end":{"line":238,"column":16}},"117":{"start":{"line":238,"column":19},"end":{"line":238,"column":21}},"118":{"start":{"line":238,"column":26},"end":{"line":238,"column":27}},"119":{"start":{"line":239,"column":6},"end":{"line":241,"column":7}},"120":{"start":{"line":240,"column":8},"end":{"line":240,"column":null}},"121":{"start":{"line":242,"column":6},"end":{"line":242,"column":null}},"122":{"start":{"line":246,"column":2},"end":{"line":255,"column":3}},"123":{"start":{"line":247,"column":4},"end":{"line":254,"column":5}},"124":{"start":{"line":247,"column":31},"end":{"line":247,"column":37}},"125":{"start":{"line":247,"column":31},"end":{"line":247,"column":63}},"126":{"start":{"line":247,"column":15},"end":{"line":247,"column":16}},"127":{"start":{"line":247,"column":19},"end":{"line":247,"column":21}},"128":{"start":{"line":247,"column":26},"end":{"line":247,"column":27}},"129":{"start":{"line":248,"column":6},"end":{"line":252,"column":7}},"130":{"start":{"line":249,"column":8},"end":{"line":251,"column":null}},"131":{"start":{"line":253,"column":6},"end":{"line":253,"column":null}},"132":{"start":{"line":259,"column":19},"end":{"line":259,"column":54}},"133":{"start":{"line":260,"column":2},"end":{"line":262,"column":3}},"134":{"start":{"line":261,"column":4},"end":{"line":261,"column":null}},"135":{"start":{"line":263,"column":14},"end":{"line":263,"column":58}},"136":{"start":{"line":264,"column":2},"end":{"line":266,"column":3}},"137":{"start":{"line":265,"column":4},"end":{"line":265,"column":null}},"138":{"start":{"line":267,"column":2},"end":{"line":267,"column":null}},"139":{"start":{"line":271,"column":2},"end":{"line":271,"column":null}},"140":{"start":{"line":274,"column":0},"end":{"line":274,"column":null}},"141":{"start":{"line":275,"column":2},"end":{"line":275,"column":null}},"142":{"start":{"line":276,"column":2},"end":{"line":276,"column":null}},"143":{"start":{"line":277,"column":2},"end":{"line":277,"column":null}},"144":{"start":{"line":278,"column":2},"end":{"line":278,"column":null}},"145":{"start":{"line":279,"column":2},"end":{"line":279,"column":null}},"146":{"start":{"line":280,"column":2},"end":{"line":280,"column":null}},"147":{"start":{"line":284,"column":17},"end":{"line":284,"column":27}},"148":{"start":{"line":285,"column":2},"end":{"line":287,"column":3}},"149":{"start":{"line":286,"column":4},"end":{"line":286,"column":null}},"150":{"start":{"line":288,"column":2},"end":{"line":288,"column":17}},"151":{"start":{"line":289,"column":2},"end":{"line":289,"column":null}},"152":{"start":{"line":295,"column":2},"end":{"line":297,"column":3}},"153":{"start":{"line":296,"column":4},"end":{"line":296,"column":null}},"154":{"start":{"line":298,"column":2},"end":{"line":298,"column":null}},"155":{"start":{"line":302,"column":2},"end":{"line":302,"column":null}},"156":{"start":{"line":302,"column":32},"end":{"line":302,"column":56}},"157":{"start":{"line":306,"column":2},"end":{"line":306,"column":null}},"158":{"start":{"line":316,"column":2},"end":{"line":318,"column":3}},"159":{"start":{"line":317,"column":4},"end":{"line":317,"column":null}},"160":{"start":{"line":323,"column":4},"end":{"line":324,"column":37}},"161":{"start":{"line":325,"column":2},"end":{"line":333,"column":3}},"162":{"start":{"line":326,"column":17},"end":{"line":326,"column":55}},"163":{"start":{"line":327,"column":20},"end":{"line":327,"column":56}},"164":{"start":{"line":328,"column":4},"end":{"line":332,"column":5}},"165":{"start":{"line":329,"column":6},"end":{"line":331,"column":null}},"166":{"start":{"line":335,"column":2},"end":{"line":337,"column":3}},"167":{"start":{"line":336,"column":4},"end":{"line":336,"column":null}},"168":{"start":{"line":339,"column":2},"end":{"line":353,"column":3}},"169":{"start":{"line":344,"column":17},"end":{"line":344,"column":54}},"170":{"start":{"line":345,"column":4},"end":{"line":347,"column":5}},"171":{"start":{"line":346,"column":6},"end":{"line":346,"column":null}},"172":{"start":{"line":348,"column":4},"end":{"line":352,"column":5}},"173":{"start":{"line":349,"column":6},"end":{"line":349,"column":null}},"174":{"start":{"line":351,"column":6},"end":{"line":351,"column":null}},"175":{"start":{"line":357,"column":2},"end":{"line":357,"column":null}}},"fnMap":{"0":{"name":"prepareJobScript","decl":{"start":{"line":35,"column":16},"end":{"line":35,"column":32}},"loc":{"start":{"line":35,"column":58},"end":{"line":57,"column":1}}},"1":{"name":"(anonymous_23)","decl":{"start":{"line":40,"column":9},"end":{"line":40,"column":10}},"loc":{"start":{"line":40,"column":10},"end":{"line":40,"column":19}}},"2":{"name":"writeRunScript","decl":{"start":{"line":59,"column":16},"end":{"line":59,"column":30}},"loc":{"start":{"line":64,"column":50},"end":{"line":92,"column":1}}},"3":{"name":"writeContainerStepScript","decl":{"start":{"line":94,"column":16},"end":{"line":94,"column":40}},"loc":{"start":{"line":99,"column":50},"end":{"line":127,"column":1}}},"4":{"name":"scriptEnv","decl":{"start":{"line":129,"column":9},"end":{"line":129,"column":18}},"loc":{"start":{"line":129,"column":51},"end":{"line":159,"column":1}}},"5":{"name":"generateContainerName","decl":{"start":{"line":161,"column":16},"end":{"line":161,"column":37}},"loc":{"start":{"line":161,"column":51},"end":{"line":170,"column":1}}},"6":{"name":"mergeContainerWithOptions","decl":{"start":{"line":180,"column":16},"end":{"line":180,"column":41}},"loc":{"start":{"line":182,"column":23},"end":{"line":206,"column":1}}},"7":{"name":"mergePodSpecWithOptions","decl":{"start":{"line":208,"column":16},"end":{"line":208,"column":39}},"loc":{"start":{"line":210,"column":21},"end":{"line":226,"column":1}}},"8":{"name":"(anonymous_30)","decl":{"start":{"line":216,"column":10},"end":{"line":216,"column":11}},"loc":{"start":{"line":216,"column":11},"end":{"line":216,"column":null}}},"9":{"name":"mergeObjectMeta","decl":{"start":{"line":228,"column":16},"end":{"line":228,"column":31}},"loc":{"start":{"line":230,"column":24},"end":{"line":256,"column":1}}},"10":{"name":"readExtensionFromFile","decl":{"start":{"line":258,"column":16},"end":{"line":258,"column":37}},"loc":{"start":{"line":258,"column":37},"end":{"line":268,"column":1}}},"11":{"name":"useKubeScheduler","decl":{"start":{"line":270,"column":16},"end":{"line":270,"column":32}},"loc":{"start":{"line":270,"column":32},"end":{"line":272,"column":1}}},"12":{"name":"(anonymous_34)","decl":{"start":{"line":274,"column":0},"end":{"line":274,"column":12}},"loc":{"start":{"line":274,"column":20},"end":{"line":281,"column":1}}},"13":{"name":"mergeLists","decl":{"start":{"line":283,"column":9},"end":{"line":283,"column":19}},"loc":{"start":{"line":283,"column":45},"end":{"line":290,"column":1}}},"14":{"name":"fixArgs","decl":{"start":{"line":292,"column":16},"end":{"line":292,"column":23}},"loc":{"start":{"line":292,"column":38},"end":{"line":299,"column":1}}},"15":{"name":"sleep","decl":{"start":{"line":301,"column":22},"end":{"line":301,"column":27}},"loc":{"start":{"line":301,"column":38},"end":{"line":303,"column":null}}},"16":{"name":"(anonymous_40)","decl":{"start":{"line":302,"column":21},"end":{"line":302,"column":28}},"loc":{"start":{"line":302,"column":28},"end":{"line":302,"column":42}}},"17":{"name":"listDirAllCommand","decl":{"start":{"line":305,"column":16},"end":{"line":305,"column":33}},"loc":{"start":{"line":305,"column":45},"end":{"line":307,"column":1}}},"18":{"name":"formatError","decl":{"start":{"line":315,"column":16},"end":{"line":315,"column":27}},"loc":{"start":{"line":315,"column":40},"end":{"line":358,"column":1}}}},"branchMap":{"0":{"loc":{"start":{"line":67,"column":2},"end":{"line":72,"column":3}},"type":"if","locations":[{"start":{"line":67,"column":2},"end":{"line":72,"column":3}},{"start":{},"end":{}}]},"1":{"loc":{"start":{"line":67,"column":6},"end":{"line":67,"column":25}},"type":"cond-expr","locations":[{"start":{"line":67,"column":17},"end":{"line":67,"column":19}},{"start":{"line":67,"column":6},"end":{"line":67,"column":25}}]},"2":{"loc":{"start":{"line":67,"column":6},"end":{"line":67,"column":19}},"type":"binary-expr","locations":[{"start":{"line":67,"column":6},"end":{"line":67,"column":19}},{"start":{"line":67,"column":6},"end":{"line":67,"column":19}}]},"3":{"loc":{"start":{"line":70,"column":6},"end":{"line":70,"column":75}},"type":"cond-expr","locations":[{"start":{"line":70,"column":40},"end":{"line":70,"column":51}},{"start":{"line":70,"column":54},"end":{"line":70,"column":75}}]},"4":{"loc":{"start":{"line":82,"column":4},"end":{"line":82,"column":58}},"type":"cond-expr","locations":[{"start":{"line":82,"column":29},"end":{"line":82,"column":53}},{"start":{"line":82,"column":56},"end":{"line":82,"column":58}}]},"5":{"loc":{"start":{"line":82,"column":4},"end":{"line":82,"column":26}},"type":"cond-expr","locations":[{"start":{"line":82,"column":18},"end":{"line":82,"column":20}},{"start":{"line":82,"column":4},"end":{"line":82,"column":26}}]},"6":{"loc":{"start":{"line":82,"column":4},"end":{"line":82,"column":20}},"type":"binary-expr","locations":[{"start":{"line":82,"column":4},"end":{"line":82,"column":20}},{"start":{"line":82,"column":4},"end":{"line":82,"column":20}}]},"7":{"loc":{"start":{"line":104,"column":2},"end":{"line":106,"column":3}},"type":"if","locations":[{"start":{"line":104,"column":2},"end":{"line":106,"column":3}},{"start":{},"end":{}}]},"8":{"loc":{"start":{"line":116,"column":4},"end":{"line":116,"column":75}},"type":"cond-expr","locations":[{"start":{"line":116,"column":29},"end":{"line":116,"column":70}},{"start":{"line":116,"column":73},"end":{"line":116,"column":75}}]},"9":{"loc":{"start":{"line":116,"column":4},"end":{"line":116,"column":26}},"type":"cond-expr","locations":[{"start":{"line":116,"column":18},"end":{"line":116,"column":20}},{"start":{"line":116,"column":4},"end":{"line":116,"column":26}}]},"10":{"loc":{"start":{"line":116,"column":4},"end":{"line":116,"column":20}},"type":"binary-expr","locations":[{"start":{"line":116,"column":4},"end":{"line":116,"column":20}},{"start":{"line":116,"column":4},"end":{"line":116,"column":20}}]},"11":{"loc":{"start":{"line":130,"column":2},"end":{"line":132,"column":3}},"type":"if","locations":[{"start":{"line":130,"column":2},"end":{"line":132,"column":3}},{"start":{},"end":{}}]},"12":{"loc":{"start":{"line":130,"column":6},"end":{"line":130,"column":43}},"type":"binary-expr","locations":[{"start":{"line":130,"column":6},"end":{"line":130,"column":11}},{"start":{"line":130,"column":15},"end":{"line":130,"column":43}}]},"13":{"loc":{"start":{"line":135,"column":4},"end":{"line":144,"column":5}},"type":"if","locations":[{"start":{"line":135,"column":4},"end":{"line":144,"column":5}},{"start":{},"end":{}}]},"14":{"loc":{"start":{"line":136,"column":6},"end":{"line":139,"column":23}},"type":"binary-expr","locations":[{"start":{"line":136,"column":6},"end":{"line":136,"column":23}},{"start":{"line":137,"column":6},"end":{"line":137,"column":23}},{"start":{"line":138,"column":6},"end":{"line":138,"column":23}},{"start":{"line":139,"column":6},"end":{"line":139,"column":23}}]},"15":{"loc":{"start":{"line":154,"column":2},"end":{"line":156,"column":3}},"type":"if","locations":[{"start":{"line":154,"column":2},"end":{"line":156,"column":3}},{"start":{},"end":{}}]},"16":{"loc":{"start":{"line":154,"column":7},"end":{"line":154,"column":24}},"type":"cond-expr","locations":[{"start":{"line":154,"column":16},"end":{"line":154,"column":18}},{"start":{"line":154,"column":7},"end":{"line":154,"column":24}}]},"17":{"loc":{"start":{"line":154,"column":7},"end":{"line":154,"column":18}},"type":"binary-expr","locations":[{"start":{"line":154,"column":7},"end":{"line":154,"column":18}},{"start":{"line":154,"column":7},"end":{"line":154,"column":18}}]},"18":{"loc":{"start":{"line":163,"column":15},"end":{"line":163,"column":41}},"type":"cond-expr","locations":[{"start":{"line":163,"column":26},"end":{"line":163,"column":28}},{"start":{"line":163,"column":15},"end":{"line":163,"column":41}}]},"19":{"loc":{"start":{"line":163,"column":15},"end":{"line":163,"column":28}},"type":"binary-expr","locations":[{"start":{"line":163,"column":15},"end":{"line":163,"column":28}},{"start":{"line":163,"column":15},"end":{"line":163,"column":28}}]},"20":{"loc":{"start":{"line":165,"column":2},"end":{"line":167,"column":3}},"type":"if","locations":[{"start":{"line":165,"column":2},"end":{"line":167,"column":3}},{"start":{},"end":{}}]},"21":{"loc":{"start":{"line":185,"column":4},"end":{"line":204,"column":5}},"type":"if","locations":[{"start":{"line":185,"column":4},"end":{"line":204,"column":5}},{"start":{"line":190,"column":11},"end":{"line":204,"column":5}}]},"22":{"loc":{"start":{"line":186,"column":6},"end":{"line":188,"column":7}},"type":"if","locations":[{"start":{"line":186,"column":6},"end":{"line":188,"column":7}},{"start":{},"end":{}}]},"23":{"loc":{"start":{"line":190,"column":11},"end":{"line":204,"column":5}},"type":"if","locations":[{"start":{"line":190,"column":11},"end":{"line":204,"column":5}},{"start":{"line":193,"column":11},"end":{"line":204,"column":5}}]},"24":{"loc":{"start":{"line":193,"column":11},"end":{"line":204,"column":5}},"type":"if","locations":[{"start":{"line":193,"column":11},"end":{"line":204,"column":5}},{"start":{"line":196,"column":11},"end":{"line":204,"column":5}}]},"25":{"loc":{"start":{"line":196,"column":11},"end":{"line":204,"column":5}},"type":"if","locations":[{"start":{"line":196,"column":11},"end":{"line":204,"column":5}},{"start":{"line":199,"column":11},"end":{"line":204,"column":5}}]},"26":{"loc":{"start":{"line":196,"column":15},"end":{"line":196,"column":46}},"type":"binary-expr","locations":[{"start":{"line":196,"column":15},"end":{"line":196,"column":37}},{"start":{"line":196,"column":41},"end":{"line":196,"column":46}}]},"27":{"loc":{"start":{"line":199,"column":11},"end":{"line":204,"column":5}},"type":"if","locations":[{"start":{"line":199,"column":11},"end":{"line":204,"column":5}},{"start":{"line":202,"column":11},"end":{"line":204,"column":5}}]},"28":{"loc":{"start":{"line":199,"column":15},"end":{"line":199,"column":39}},"type":"binary-expr","locations":[{"start":{"line":199,"column":15},"end":{"line":199,"column":30}},{"start":{"line":199,"column":34},"end":{"line":199,"column":39}}]},"29":{"loc":{"start":{"line":213,"column":4},"end":{"line":224,"column":5}},"type":"if","locations":[{"start":{"line":213,"column":4},"end":{"line":224,"column":5}},{"start":{"line":219,"column":11},"end":{"line":224,"column":5}}]},"30":{"loc":{"start":{"line":216,"column":16},"end":{"line":216,"column":62}},"type":"cond-expr","locations":[{"start":{"line":216,"column":22},"end":{"line":216,"column":24}},{"start":{"line":216,"column":22},"end":{"line":216,"column":62}}]},"31":{"loc":{"start":{"line":216,"column":16},"end":{"line":216,"column":24}},"type":"binary-expr","locations":[{"start":{"line":216,"column":16},"end":{"line":216,"column":24}},{"start":{"line":216,"column":22},"end":{"line":216,"column":24}}]},"32":{"loc":{"start":{"line":219,"column":11},"end":{"line":224,"column":5}},"type":"if","locations":[{"start":{"line":219,"column":11},"end":{"line":224,"column":5}},{"start":{"line":222,"column":11},"end":{"line":224,"column":5}}]},"33":{"loc":{"start":{"line":219,"column":15},"end":{"line":219,"column":41}},"type":"binary-expr","locations":[{"start":{"line":219,"column":15},"end":{"line":219,"column":32}},{"start":{"line":219,"column":36},"end":{"line":219,"column":41}}]},"34":{"loc":{"start":{"line":232,"column":2},"end":{"line":236,"column":3}},"type":"if","locations":[{"start":{"line":232,"column":2},"end":{"line":236,"column":3}},{"start":{},"end":{}}]},"35":{"loc":{"start":{"line":232,"column":6},"end":{"line":232,"column":61}},"type":"binary-expr","locations":[{"start":{"line":232,"column":6},"end":{"line":232,"column":32}},{"start":{"line":232,"column":32},"end":{"line":232,"column":61}}]},"36":{"loc":{"start":{"line":232,"column":7},"end":{"line":232,"column":28}},"type":"cond-expr","locations":[{"start":{"line":232,"column":20},"end":{"line":232,"column":22}},{"start":{"line":232,"column":20},"end":{"line":232,"column":28}}]},"37":{"loc":{"start":{"line":232,"column":7},"end":{"line":232,"column":22}},"type":"binary-expr","locations":[{"start":{"line":232,"column":7},"end":{"line":232,"column":22}},{"start":{"line":232,"column":20},"end":{"line":232,"column":22}}]},"38":{"loc":{"start":{"line":232,"column":33},"end":{"line":232,"column":59}},"type":"cond-expr","locations":[{"start":{"line":232,"column":46},"end":{"line":232,"column":48}},{"start":{"line":232,"column":46},"end":{"line":232,"column":59}}]},"39":{"loc":{"start":{"line":232,"column":33},"end":{"line":232,"column":48}},"type":"binary-expr","locations":[{"start":{"line":232,"column":33},"end":{"line":232,"column":48}},{"start":{"line":232,"column":46},"end":{"line":232,"column":48}}]},"40":{"loc":{"start":{"line":237,"column":2},"end":{"line":244,"column":3}},"type":"if","locations":[{"start":{"line":237,"column":2},"end":{"line":244,"column":3}},{"start":{},"end":{}}]},"41":{"loc":{"start":{"line":237,"column":6},"end":{"line":237,"column":18}},"type":"cond-expr","locations":[{"start":{"line":237,"column":10},"end":{"line":237,"column":12}},{"start":{"line":237,"column":6},"end":{"line":237,"column":18}}]},"42":{"loc":{"start":{"line":237,"column":6},"end":{"line":237,"column":12}},"type":"binary-expr","locations":[{"start":{"line":237,"column":6},"end":{"line":237,"column":12}},{"start":{"line":237,"column":6},"end":{"line":237,"column":12}}]},"43":{"loc":{"start":{"line":239,"column":6},"end":{"line":241,"column":7}},"type":"if","locations":[{"start":{"line":239,"column":6},"end":{"line":241,"column":7}},{"start":{},"end":{}}]},"44":{"loc":{"start":{"line":239,"column":10},"end":{"line":239,"column":38}},"type":"cond-expr","locations":[{"start":{"line":239,"column":31},"end":{"line":239,"column":34}},{"start":{"line":239,"column":31},"end":{"line":239,"column":38}}]},"45":{"loc":{"start":{"line":239,"column":10},"end":{"line":239,"column":34}},"type":"binary-expr","locations":[{"start":{"line":239,"column":10},"end":{"line":239,"column":34}},{"start":{"line":239,"column":31},"end":{"line":239,"column":34}}]},"46":{"loc":{"start":{"line":239,"column":10},"end":{"line":239,"column":31}},"type":"cond-expr","locations":[{"start":{"line":239,"column":23},"end":{"line":239,"column":25}},{"start":{"line":239,"column":23},"end":{"line":239,"column":31}}]},"47":{"loc":{"start":{"line":239,"column":10},"end":{"line":239,"column":25}},"type":"binary-expr","locations":[{"start":{"line":239,"column":10},"end":{"line":239,"column":25}},{"start":{"line":239,"column":23},"end":{"line":239,"column":25}}]},"48":{"loc":{"start":{"line":246,"column":2},"end":{"line":255,"column":3}},"type":"if","locations":[{"start":{"line":246,"column":2},"end":{"line":255,"column":3}},{"start":{},"end":{}}]},"49":{"loc":{"start":{"line":246,"column":6},"end":{"line":246,"column":23}},"type":"cond-expr","locations":[{"start":{"line":246,"column":10},"end":{"line":246,"column":12}},{"start":{"line":246,"column":6},"end":{"line":246,"column":23}}]},"50":{"loc":{"start":{"line":246,"column":6},"end":{"line":246,"column":12}},"type":"binary-expr","locations":[{"start":{"line":246,"column":6},"end":{"line":246,"column":12}},{"start":{"line":246,"column":6},"end":{"line":246,"column":12}}]},"51":{"loc":{"start":{"line":248,"column":6},"end":{"line":252,"column":7}},"type":"if","locations":[{"start":{"line":248,"column":6},"end":{"line":252,"column":7}},{"start":{},"end":{}}]},"52":{"loc":{"start":{"line":248,"column":10},"end":{"line":248,"column":43}},"type":"cond-expr","locations":[{"start":{"line":248,"column":36},"end":{"line":248,"column":39}},{"start":{"line":248,"column":36},"end":{"line":248,"column":43}}]},"53":{"loc":{"start":{"line":248,"column":10},"end":{"line":248,"column":39}},"type":"binary-expr","locations":[{"start":{"line":248,"column":10},"end":{"line":248,"column":39}},{"start":{"line":248,"column":36},"end":{"line":248,"column":39}}]},"54":{"loc":{"start":{"line":248,"column":10},"end":{"line":248,"column":36}},"type":"cond-expr","locations":[{"start":{"line":248,"column":23},"end":{"line":248,"column":25}},{"start":{"line":248,"column":23},"end":{"line":248,"column":36}}]},"55":{"loc":{"start":{"line":248,"column":10},"end":{"line":248,"column":25}},"type":"binary-expr","locations":[{"start":{"line":248,"column":10},"end":{"line":248,"column":25}},{"start":{"line":248,"column":23},"end":{"line":248,"column":25}}]},"56":{"loc":{"start":{"line":260,"column":2},"end":{"line":262,"column":3}},"type":"if","locations":[{"start":{"line":260,"column":2},"end":{"line":262,"column":3}},{"start":{},"end":{}}]},"57":{"loc":{"start":{"line":264,"column":2},"end":{"line":266,"column":3}},"type":"if","locations":[{"start":{"line":264,"column":2},"end":{"line":266,"column":3}},{"start":{},"end":{}}]},"58":{"loc":{"start":{"line":264,"column":6},"end":{"line":264,"column":37}},"type":"binary-expr","locations":[{"start":{"line":264,"column":6},"end":{"line":264,"column":10}},{"start":{"line":264,"column":14},"end":{"line":264,"column":37}}]},"59":{"loc":{"start":{"line":274,"column":12},"end":{"line":274,"column":null}},"type":"binary-expr","locations":[{"start":{"line":274,"column":12},"end":{"line":274,"column":20}},{"start":{"line":274,"column":20},"end":{"line":274,"column":null}}]},"60":{"loc":{"start":{"line":284,"column":17},"end":{"line":284,"column":27}},"type":"binary-expr","locations":[{"start":{"line":284,"column":17},"end":{"line":284,"column":21}},{"start":{"line":284,"column":25},"end":{"line":284,"column":27}}]},"61":{"loc":{"start":{"line":285,"column":2},"end":{"line":287,"column":3}},"type":"if","locations":[{"start":{"line":285,"column":2},"end":{"line":287,"column":3}},{"start":{},"end":{}}]},"62":{"loc":{"start":{"line":285,"column":7},"end":{"line":285,"column":19}},"type":"cond-expr","locations":[{"start":{"line":285,"column":11},"end":{"line":285,"column":13}},{"start":{"line":285,"column":7},"end":{"line":285,"column":19}}]},"63":{"loc":{"start":{"line":285,"column":7},"end":{"line":285,"column":13}},"type":"binary-expr","locations":[{"start":{"line":285,"column":7},"end":{"line":285,"column":13}},{"start":{"line":285,"column":7},"end":{"line":285,"column":13}}]},"64":{"loc":{"start":{"line":295,"column":2},"end":{"line":297,"column":3}},"type":"if","locations":[{"start":{"line":295,"column":2},"end":{"line":297,"column":3}},{"start":{},"end":{}}]},"65":{"loc":{"start":{"line":295,"column":6},"end":{"line":295,"column":62}},"type":"binary-expr","locations":[{"start":{"line":295,"column":6},"end":{"line":295,"column":22}},{"start":{"line":295,"column":26},"end":{"line":295,"column":42}},{"start":{"line":295,"column":46},"end":{"line":295,"column":62}}]},"66":{"loc":{"start":{"line":316,"column":2},"end":{"line":318,"column":3}},"type":"if","locations":[{"start":{"line":316,"column":2},"end":{"line":318,"column":3}},{"start":{},"end":{}}]},"67":{"loc":{"start":{"line":316,"column":6},"end":{"line":316,"column":39}},"type":"binary-expr","locations":[{"start":{"line":316,"column":6},"end":{"line":316,"column":18}},{"start":{"line":316,"column":22},"end":{"line":316,"column":39}}]},"68":{"loc":{"start":{"line":323,"column":4},"end":{"line":324,"column":37}},"type":"cond-expr","locations":[{"start":{"line":323,"column":62},"end":{"line":323,"column":null}},{"start":{"line":324,"column":5},"end":{"line":324,"column":37}}]},"69":{"loc":{"start":{"line":323,"column":4},"end":{"line":323,"column":null}},"type":"binary-expr","locations":[{"start":{"line":323,"column":4},"end":{"line":323,"column":null}},{"start":{"line":323,"column":62},"end":{"line":323,"column":null}}]},"70":{"loc":{"start":{"line":323,"column":4},"end":{"line":323,"column":62}},"type":"cond-expr","locations":[{"start":{"line":323,"column":56},"end":{"line":323,"column":58}},{"start":{"line":323,"column":56},"end":{"line":323,"column":62}}]},"71":{"loc":{"start":{"line":323,"column":4},"end":{"line":323,"column":58}},"type":"binary-expr","locations":[{"start":{"line":323,"column":4},"end":{"line":323,"column":58}},{"start":{"line":323,"column":56},"end":{"line":323,"column":58}}]},"72":{"loc":{"start":{"line":323,"column":5},"end":{"line":323,"column":56}},"type":"cond-expr","locations":[{"start":{"line":323,"column":8},"end":{"line":323,"column":46}},{"start":{"line":323,"column":5},"end":{"line":323,"column":56}}]},"73":{"loc":{"start":{"line":323,"column":5},"end":{"line":323,"column":46}},"type":"binary-expr","locations":[{"start":{"line":323,"column":5},"end":{"line":323,"column":48}},{"start":{"line":323,"column":5},"end":{"line":323,"column":46}}]},"74":{"loc":{"start":{"line":324,"column":5},"end":{"line":324,"column":37}},"type":"cond-expr","locations":[{"start":{"line":324,"column":8},"end":{"line":324,"column":31}},{"start":{"line":324,"column":5},"end":{"line":324,"column":37}}]},"75":{"loc":{"start":{"line":324,"column":5},"end":{"line":324,"column":31}},"type":"binary-expr","locations":[{"start":{"line":324,"column":5},"end":{"line":324,"column":33}},{"start":{"line":324,"column":5},"end":{"line":324,"column":31}}]},"76":{"loc":{"start":{"line":325,"column":2},"end":{"line":333,"column":3}},"type":"if","locations":[{"start":{"line":325,"column":2},"end":{"line":333,"column":3}},{"start":{},"end":{}}]},"77":{"loc":{"start":{"line":325,"column":6},"end":{"line":325,"column":38}},"type":"binary-expr","locations":[{"start":{"line":325,"column":6},"end":{"line":325,"column":10}},{"start":{"line":325,"column":14},"end":{"line":325,"column":38}}]},"78":{"loc":{"start":{"line":328,"column":4},"end":{"line":332,"column":5}},"type":"if","locations":[{"start":{"line":328,"column":4},"end":{"line":332,"column":5}},{"start":{},"end":{}}]},"79":{"loc":{"start":{"line":329,"column":13},"end":{"line":331,"column":13}},"type":"cond-expr","locations":[{"start":{"line":330,"column":10},"end":{"line":330,"column":38}},{"start":{"line":331,"column":10},"end":{"line":331,"column":13}}]},"80":{"loc":{"start":{"line":329,"column":13},"end":{"line":329,"column":60}},"type":"binary-expr","locations":[{"start":{"line":329,"column":13},"end":{"line":329,"column":39}},{"start":{"line":329,"column":43},"end":{"line":329,"column":60}}]},"81":{"loc":{"start":{"line":335,"column":2},"end":{"line":337,"column":3}},"type":"if","locations":[{"start":{"line":335,"column":2},"end":{"line":337,"column":3}},{"start":{},"end":{}}]},"82":{"loc":{"start":{"line":339,"column":2},"end":{"line":353,"column":3}},"type":"if","locations":[{"start":{"line":339,"column":2},"end":{"line":353,"column":3}},{"start":{},"end":{}}]},"83":{"loc":{"start":{"line":345,"column":4},"end":{"line":347,"column":5}},"type":"if","locations":[{"start":{"line":345,"column":4},"end":{"line":347,"column":5}},{"start":{},"end":{}}]}},"s":{"0":14,"1":14,"2":14,"3":14,"4":14,"5":14,"6":14,"7":14,"8":14,"9":14,"10":14,"11":14,"12":14,"13":14,"14":14,"15":14,"16":14,"17":14,"18":14,"19":14,"20":14,"21":14,"22":14,"23":14,"24":14,"25":14,"26":14,"27":0,"28":0,"29":0,"30":0,"31":0,"32":0,"33":0,"34":0,"35":0,"36":0,"37":0,"38":0,"39":0,"40":0,"41":0,"42":0,"43":0,"44":0,"45":0,"46":0,"47":0,"48":0,"49":0,"50":0,"51":0,"52":0,"53":0,"54":0,"55":0,"56":0,"57":0,"58":0,"59":0,"60":0,"61":0,"62":0,"63":0,"64":0,"65":0,"66":0,"67":0,"68":0,"69":12,"70":12,"71":12,"72":2,"73":10,"74":2,"75":2,"76":2,"77":6,"78":6,"79":6,"80":6,"81":2,"82":1,"83":2,"84":4,"85":1,"86":1,"87":3,"88":1,"89":1,"90":2,"91":0,"92":0,"93":2,"94":1,"95":1,"96":1,"97":1,"98":1,"99":1,"100":4,"101":4,"102":4,"103":4,"104":1,"105":1,"106":3,"107":1,"108":1,"109":2,"110":0,"111":0,"112":0,"113":0,"114":0,"115":0,"116":0,"117":0,"118":0,"119":0,"120":0,"121":0,"122":0,"123":0,"124":0,"125":0,"126":0,"127":0,"128":0,"129":0,"130":0,"131":0,"132":23,"133":23,"134":23,"135":0,"136":0,"137":0,"138":0,"139":0,"140":14,"141":14,"142":14,"143":14,"144":14,"145":14,"146":14,"147":3,"148":3,"149":0,"150":3,"151":3,"152":17,"153":3,"154":14,"155":0,"156":0,"157":0,"158":63,"159":2,"160":61,"161":61,"162":3,"163":3,"164":3,"165":3,"166":58,"167":47,"168":11,"169":6,"170":6,"171":3,"172":3,"173":3,"174":2,"175":5},"f":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":12,"6":2,"7":1,"8":1,"9":0,"10":23,"11":0,"12":14,"13":3,"14":17,"15":0,"16":0,"17":0,"18":63},"b":{"0":[0,0],"1":[0,0],"2":[0,0],"3":[0,0],"4":[0,0],"5":[0,0],"6":[0,0],"7":[0,0],"8":[0,0],"9":[0,0],"10":[0,0],"11":[0,0],"12":[0,0],"13":[0,0],"14":[0,0,0,0],"15":[0,0],"16":[0,0],"17":[0,0],"18":[0,12],"19":[12,12],"20":[2,10],"21":[2,4],"22":[1,1],"23":[1,3],"24":[1,2],"25":[0,2],"26":[2,0],"27":[1,1],"28":[2,1],"29":[1,3],"30":[0,1],"31":[1,1],"32":[1,2],"33":[3,1],"34":[0,0],"35":[0,0],"36":[0,0],"37":[0,0],"38":[0,0],"39":[0,0],"40":[0,0],"41":[0,0],"42":[0,0],"43":[0,0],"44":[0,0],"45":[0,0],"46":[0,0],"47":[0,0],"48":[0,0],"49":[0,0],"50":[0,0],"51":[0,0],"52":[0,0],"53":[0,0],"54":[0,0],"55":[0,0],"56":[23,0],"57":[0,0],"58":[0,0],"59":[14,14],"60":[3,1],"61":[0,3],"62":[0,3],"63":[3,3],"64":[3,14],"65":[17,14,3],"66":[2,61],"67":[63,62],"68":[2,59],"69":[61,61],"70":[57,4],"71":[61,61],"72":[0,61],"73":[61,61],"74":[0,59],"75":[59,59],"76":[3,58],"77":[61,3],"78":[3,0],"79":[1,2],"80":[3,1],"81":[47,11],"82":[6,5],"83":[3,3]}} +,"/__w/backlog/backlog/work/runner-container-hooks/packages/k8s/src/k8s/utils/npu-metrics.ts": {"path":"/__w/backlog/backlog/work/runner-container-hooks/packages/k8s/src/k8s/utils/npu-metrics.ts","statementMap":{"0":{"start":{"line":71,"column":0},"end":{"line":71,"column":16}},"1":{"start":{"line":79,"column":0},"end":{"line":79,"column":16}},"2":{"start":{"line":96,"column":0},"end":{"line":96,"column":16}},"3":{"start":{"line":113,"column":0},"end":{"line":113,"column":16}},"4":{"start":{"line":125,"column":0},"end":{"line":125,"column":16}},"5":{"start":{"line":133,"column":0},"end":{"line":133,"column":16}},"6":{"start":{"line":187,"column":0},"end":{"line":187,"column":16}},"7":{"start":{"line":224,"column":0},"end":{"line":224,"column":16}},"8":{"start":{"line":269,"column":0},"end":{"line":269,"column":16}},"9":{"start":{"line":279,"column":0},"end":{"line":279,"column":16}},"10":{"start":{"line":324,"column":0},"end":{"line":324,"column":16}},"11":{"start":{"line":334,"column":0},"end":{"line":334,"column":16}},"12":{"start":{"line":338,"column":0},"end":{"line":338,"column":16}},"13":{"start":{"line":359,"column":0},"end":{"line":359,"column":16}},"14":{"start":{"line":401,"column":0},"end":{"line":401,"column":16}},"15":{"start":{"line":408,"column":0},"end":{"line":408,"column":16}},"16":{"start":{"line":418,"column":0},"end":{"line":418,"column":22}},"17":{"start":{"line":448,"column":0},"end":{"line":448,"column":22}},"18":{"start":{"line":484,"column":0},"end":{"line":484,"column":22}},"19":{"start":{"line":518,"column":0},"end":{"line":518,"column":16}},"20":{"start":{"line":545,"column":0},"end":{"line":545,"column":22}},"21":{"start":{"line":565,"column":0},"end":{"line":565,"column":16}},"22":{"start":{"line":589,"column":0},"end":{"line":589,"column":16}},"23":{"start":{"line":630,"column":0},"end":{"line":630,"column":16}},"24":{"start":{"line":644,"column":0},"end":{"line":644,"column":22}},"25":{"start":{"line":670,"column":0},"end":{"line":670,"column":22}},"26":{"start":{"line":1,"column":0},"end":{"line":1,"column":37}},"27":{"start":{"line":3,"column":0},"end":{"line":3,"column":30}},"28":{"start":{"line":4,"column":0},"end":{"line":4,"column":28}},"29":{"start":{"line":5,"column":0},"end":{"line":5,"column":25}},"30":{"start":{"line":6,"column":0},"end":{"line":6,"column":76}},"31":{"start":{"line":7,"column":0},"end":{"line":7,"column":37}},"32":{"start":{"line":8,"column":0},"end":{"line":8,"column":null}},"33":{"start":{"line":16,"column":13},"end":{"line":16,"column":null}},"34":{"start":{"line":17,"column":13},"end":{"line":17,"column":null}},"35":{"start":{"line":18,"column":13},"end":{"line":18,"column":null}},"36":{"start":{"line":19,"column":13},"end":{"line":19,"column":null}},"37":{"start":{"line":21,"column":13},"end":{"line":21,"column":null}},"38":{"start":{"line":22,"column":13},"end":{"line":22,"column":null}},"39":{"start":{"line":23,"column":13},"end":{"line":23,"column":null}},"40":{"start":{"line":25,"column":13},"end":{"line":25,"column":null}},"41":{"start":{"line":26,"column":13},"end":{"line":26,"column":null}},"42":{"start":{"line":27,"column":13},"end":{"line":27,"column":null}},"43":{"start":{"line":28,"column":13},"end":{"line":28,"column":null}},"44":{"start":{"line":30,"column":13},"end":{"line":30,"column":null}},"45":{"start":{"line":31,"column":13},"end":{"line":31,"column":null}},"46":{"start":{"line":32,"column":13},"end":{"line":32,"column":null}},"47":{"start":{"line":34,"column":27},"end":{"line":34,"column":56}},"48":{"start":{"line":35,"column":29},"end":{"line":35,"column":80}},"49":{"start":{"line":72,"column":2},"end":{"line":72,"column":null}},"50":{"start":{"line":74,"column":2},"end":{"line":76,"column":null}},"51":{"start":{"line":80,"column":2},"end":{"line":80,"column":null}},"52":{"start":{"line":82,"column":14},"end":{"line":82,"column":42}},"53":{"start":{"line":83,"column":2},"end":{"line":85,"column":3}},"54":{"start":{"line":84,"column":4},"end":{"line":84,"column":null}},"55":{"start":{"line":86,"column":17},"end":{"line":86,"column":28}},"56":{"start":{"line":87,"column":2},"end":{"line":92,"column":3}},"57":{"start":{"line":88,"column":4},"end":{"line":90,"column":null}},"58":{"start":{"line":91,"column":4},"end":{"line":91,"column":null}},"59":{"start":{"line":93,"column":2},"end":{"line":93,"column":null}},"60":{"start":{"line":97,"column":2},"end":{"line":97,"column":null}},"61":{"start":{"line":99,"column":14},"end":{"line":99,"column":41}},"62":{"start":{"line":100,"column":2},"end":{"line":102,"column":3}},"63":{"start":{"line":101,"column":4},"end":{"line":101,"column":null}},"64":{"start":{"line":103,"column":17},"end":{"line":103,"column":28}},"65":{"start":{"line":104,"column":2},"end":{"line":109,"column":3}},"66":{"start":{"line":105,"column":4},"end":{"line":107,"column":null}},"67":{"start":{"line":108,"column":4},"end":{"line":108,"column":null}},"68":{"start":{"line":110,"column":2},"end":{"line":110,"column":null}},"69":{"start":{"line":114,"column":20},"end":{"line":114,"column":80}},"70":{"start":{"line":115,"column":2},"end":{"line":121,"column":3}},"71":{"start":{"line":115,"column":22},"end":{"line":115,"column":31}},"72":{"start":{"line":115,"column":18},"end":{"line":115,"column":22}},"73":{"start":{"line":116,"column":4},"end":{"line":120,"column":5}},"74":{"start":{"line":116,"column":22},"end":{"line":116,"column":28}},"75":{"start":{"line":116,"column":22},"end":{"line":116,"column":46}},"76":{"start":{"line":116,"column":18},"end":{"line":116,"column":22}},"77":{"start":{"line":117,"column":6},"end":{"line":119,"column":7}},"78":{"start":{"line":118,"column":8},"end":{"line":118,"column":null}},"79":{"start":{"line":122,"column":2},"end":{"line":122,"column":null}},"80":{"start":{"line":126,"column":2},"end":{"line":126,"column":null}},"81":{"start":{"line":126,"column":44},"end":{"line":126,"column":70}},"82":{"start":{"line":130,"column":2},"end":{"line":130,"column":null}},"83":{"start":{"line":134,"column":2},"end":{"line":134,"column":null}},"84":{"start":{"line":136,"column":2},"end":{"line":155,"column":null}},"85":{"start":{"line":158,"column":22},"end":{"line":185,"column":12}},"86":{"start":{"line":188,"column":2},"end":{"line":195,"column":null}},"87":{"start":{"line":199,"column":2},"end":{"line":199,"column":null}},"88":{"start":{"line":206,"column":2},"end":{"line":217,"column":3}},"89":{"start":{"line":212,"column":4},"end":{"line":216,"column":null}},"90":{"start":{"line":218,"column":17},"end":{"line":219,"column":null}},"91":{"start":{"line":219,"column":12},"end":{"line":219,"column":null}},"92":{"start":{"line":221,"column":2},"end":{"line":221,"column":null}},"93":{"start":{"line":226,"column":2},"end":{"line":226,"column":null}},"94":{"start":{"line":228,"column":20},"end":{"line":228,"column":45}},"95":{"start":{"line":229,"column":2},"end":{"line":234,"column":3}},"96":{"start":{"line":233,"column":4},"end":{"line":233,"column":null}},"97":{"start":{"line":236,"column":2},"end":{"line":244,"column":3}},"98":{"start":{"line":240,"column":4},"end":{"line":242,"column":null}},"99":{"start":{"line":243,"column":4},"end":{"line":243,"column":null}},"100":{"start":{"line":246,"column":22},"end":{"line":246,"column":85}},"101":{"start":{"line":247,"column":24},"end":{"line":247,"column":145}},"102":{"start":{"line":249,"column":2},"end":{"line":256,"column":null}},"103":{"start":{"line":257,"column":2},"end":{"line":264,"column":null}},"104":{"start":{"line":265,"column":2},"end":{"line":265,"column":null}},"105":{"start":{"line":266,"column":2},"end":{"line":266,"column":null}},"106":{"start":{"line":270,"column":2},"end":{"line":272,"column":3}},"107":{"start":{"line":271,"column":4},"end":{"line":271,"column":null}},"108":{"start":{"line":273,"column":2},"end":{"line":275,"column":3}},"109":{"start":{"line":274,"column":4},"end":{"line":274,"column":null}},"110":{"start":{"line":276,"column":2},"end":{"line":276,"column":null}},"111":{"start":{"line":282,"column":2},"end":{"line":284,"column":3}},"112":{"start":{"line":283,"column":4},"end":{"line":283,"column":null}},"113":{"start":{"line":285,"column":16},"end":{"line":285,"column":36}},"114":{"start":{"line":286,"column":2},"end":{"line":288,"column":3}},"115":{"start":{"line":287,"column":4},"end":{"line":287,"column":null}},"116":{"start":{"line":289,"column":21},"end":{"line":289,"column":39}},"117":{"start":{"line":290,"column":14},"end":{"line":290,"column":34}},"118":{"start":{"line":291,"column":2},"end":{"line":293,"column":3}},"119":{"start":{"line":292,"column":4},"end":{"line":292,"column":null}},"120":{"start":{"line":294,"column":2},"end":{"line":320,"column":3}},"121":{"start":{"line":294,"column":26},"end":{"line":294,"column":36}},"122":{"start":{"line":294,"column":22},"end":{"line":294,"column":26}},"123":{"start":{"line":295,"column":14},"end":{"line":295,"column":19}},"124":{"start":{"line":296,"column":4},"end":{"line":300,"column":5}},"125":{"start":{"line":297,"column":6},"end":{"line":297,"column":null}},"126":{"start":{"line":299,"column":6},"end":{"line":299,"column":14}},"127":{"start":{"line":301,"column":4},"end":{"line":303,"column":5}},"128":{"start":{"line":302,"column":6},"end":{"line":302,"column":14}},"129":{"start":{"line":304,"column":38},"end":{"line":304,"column":40}},"130":{"start":{"line":305,"column":4},"end":{"line":318,"column":5}},"131":{"start":{"line":305,"column":20},"end":{"line":305,"column":26}},"132":{"start":{"line":305,"column":20},"end":{"line":305,"column":32}},"133":{"start":{"line":305,"column":16},"end":{"line":305,"column":20}},"134":{"start":{"line":306,"column":6},"end":{"line":308,"column":7}},"135":{"start":{"line":307,"column":8},"end":{"line":307,"column":16}},"136":{"start":{"line":309,"column":6},"end":{"line":317,"column":null}},"137":{"start":{"line":319,"column":4},"end":{"line":319,"column":null}},"138":{"start":{"line":321,"column":2},"end":{"line":321,"column":null}},"139":{"start":{"line":326,"column":2},"end":{"line":326,"column":null}},"140":{"start":{"line":328,"column":2},"end":{"line":330,"column":3}},"141":{"start":{"line":329,"column":4},"end":{"line":329,"column":null}},"142":{"start":{"line":331,"column":2},"end":{"line":331,"column":null}},"143":{"start":{"line":331,"column":26},"end":{"line":331,"column":74}},"144":{"start":{"line":335,"column":2},"end":{"line":335,"column":null}},"145":{"start":{"line":339,"column":2},"end":{"line":342,"column":null}},"146":{"start":{"line":340,"column":17},"end":{"line":340,"column":18}},"147":{"start":{"line":340,"column":23},"end":{"line":340,"column":39}},"148":{"start":{"line":341,"column":12},"end":{"line":341,"column":14}},"149":{"start":{"line":341,"column":15},"end":{"line":341,"column":16}},"150":{"start":{"line":341,"column":21},"end":{"line":341,"column":57}},"151":{"start":{"line":345,"column":34},"end":{"line":357,"column":null}},"152":{"start":{"line":362,"column":2},"end":{"line":362,"column":null}},"153":{"start":{"line":364,"column":39},"end":{"line":374,"column":null}},"154":{"start":{"line":375,"column":15},"end":{"line":375,"column":68}},"155":{"start":{"line":376,"column":26},"end":{"line":376,"column":28}},"156":{"start":{"line":377,"column":2},"end":{"line":377,"column":null}},"157":{"start":{"line":378,"column":2},"end":{"line":378,"column":null}},"158":{"start":{"line":379,"column":2},"end":{"line":379,"column":null}},"159":{"start":{"line":380,"column":2},"end":{"line":380,"column":null}},"160":{"start":{"line":382,"column":20},"end":{"line":382,"column":57}},"161":{"start":{"line":383,"column":14},"end":{"line":386,"column":null}},"162":{"start":{"line":385,"column":43},"end":{"line":385,"column":62}},"163":{"start":{"line":388,"column":4},"end":{"line":388,"column":null}},"164":{"start":{"line":389,"column":4},"end":{"line":389,"column":null}},"165":{"start":{"line":390,"column":21},"end":{"line":390,"column":60}},"166":{"start":{"line":391,"column":4},"end":{"line":391,"column":null}},"167":{"start":{"line":392,"column":4},"end":{"line":392,"column":null}},"168":{"start":{"line":381,"column":2},"end":{"line":393,"column":null}},"169":{"start":{"line":381,"column":21},"end":{"line":381,"column":26}},"170":{"start":{"line":381,"column":17},"end":{"line":381,"column":21}},"171":{"start":{"line":381,"column":13},"end":{"line":381,"column":21}},"172":{"start":{"line":394,"column":2},"end":{"line":394,"column":null}},"173":{"start":{"line":395,"column":2},"end":{"line":397,"column":null}},"174":{"start":{"line":398,"column":2},"end":{"line":398,"column":null}},"175":{"start":{"line":402,"column":2},"end":{"line":405,"column":null}},"176":{"start":{"line":413,"column":2},"end":{"line":415,"column":null}},"177":{"start":{"line":422,"column":9},"end":{"line":434,"column":null}},"178":{"start":{"line":423,"column":18},"end":{"line":423,"column":75}},"179":{"start":{"line":423,"column":35},"end":{"line":423,"column":65}},"180":{"start":{"line":424,"column":4},"end":{"line":433,"column":null}},"181":{"start":{"line":426,"column":8},"end":{"line":426,"column":null}},"182":{"start":{"line":427,"column":8},"end":{"line":427,"column":null}},"183":{"start":{"line":430,"column":8},"end":{"line":430,"column":null}},"184":{"start":{"line":431,"column":8},"end":{"line":431,"column":null}},"185":{"start":{"line":422,"column":2},"end":{"line":434,"column":null}},"186":{"start":{"line":451,"column":8},"end":{"line":451,"column":null}},"187":{"start":{"line":452,"column":8},"end":{"line":452,"column":null}},"188":{"start":{"line":453,"column":8},"end":{"line":455,"column":null}},"189":{"start":{"line":456,"column":2},"end":{"line":461,"column":3}},"190":{"start":{"line":457,"column":10},"end":{"line":459,"column":null}},"191":{"start":{"line":460,"column":4},"end":{"line":460,"column":null}},"192":{"start":{"line":462,"column":9},"end":{"line":481,"column":null}},"193":{"start":{"line":463,"column":20},"end":{"line":476,"column":null}},"194":{"start":{"line":472,"column":8},"end":{"line":472,"column":null}},"195":{"start":{"line":473,"column":8},"end":{"line":475,"column":null}},"196":{"start":{"line":474,"column":10},"end":{"line":474,"column":null}},"197":{"start":{"line":478,"column":4},"end":{"line":478,"column":null}},"198":{"start":{"line":478,"column":32},"end":{"line":478,"column":78}},"199":{"start":{"line":479,"column":4},"end":{"line":479,"column":null}},"200":{"start":{"line":480,"column":4},"end":{"line":480,"column":null}},"201":{"start":{"line":462,"column":2},"end":{"line":481,"column":null}},"202":{"start":{"line":490,"column":8},"end":{"line":490,"column":null}},"203":{"start":{"line":491,"column":8},"end":{"line":491,"column":null}},"204":{"start":{"line":492,"column":8},"end":{"line":492,"column":null}},"205":{"start":{"line":493,"column":8},"end":{"line":493,"column":null}},"206":{"start":{"line":495,"column":11},"end":{"line":495,"column":24}},"207":{"start":{"line":495,"column":24},"end":{"line":495,"column":44}},"208":{"start":{"line":495,"column":42},"end":{"line":495,"column":44}},"209":{"start":{"line":496,"column":8},"end":{"line":496,"column":15}},"210":{"start":{"line":497,"column":6},"end":{"line":497,"column":null}},"211":{"start":{"line":497,"column":35},"end":{"line":497,"column":69}},"212":{"start":{"line":500,"column":23},"end":{"line":506,"column":null}},"213":{"start":{"line":500,"column":12},"end":{"line":506,"column":null}},"214":{"start":{"line":507,"column":6},"end":{"line":509,"column":7}},"215":{"start":{"line":508,"column":8},"end":{"line":508,"column":14}},"216":{"start":{"line":510,"column":6},"end":{"line":510,"column":null}},"217":{"start":{"line":512,"column":6},"end":{"line":512,"column":null}},"218":{"start":{"line":495,"column":44},"end":{"line":495,"column":null}},"219":{"start":{"line":515,"column":2},"end":{"line":515,"column":null}},"220":{"start":{"line":521,"column":15},"end":{"line":521,"column":33}},"221":{"start":{"line":522,"column":17},"end":{"line":533,"column":3}},"222":{"start":{"line":523,"column":20},"end":{"line":523,"column":29}},"223":{"start":{"line":524,"column":4},"end":{"line":526,"column":5}},"224":{"start":{"line":525,"column":6},"end":{"line":525,"column":null}},"225":{"start":{"line":527,"column":4},"end":{"line":532,"column":5}},"226":{"start":{"line":528,"column":22},"end":{"line":528,"column":69}},"227":{"start":{"line":529,"column":6},"end":{"line":529,"column":null}},"228":{"start":{"line":531,"column":6},"end":{"line":531,"column":null}},"229":{"start":{"line":534,"column":14},"end":{"line":534,"column":39}},"230":{"start":{"line":535,"column":2},"end":{"line":537,"column":3}},"231":{"start":{"line":536,"column":4},"end":{"line":536,"column":null}},"232":{"start":{"line":538,"column":2},"end":{"line":542,"column":null}},"233":{"start":{"line":547,"column":19},"end":{"line":547,"column":null}},"234":{"start":{"line":547,"column":10},"end":{"line":547,"column":null}},"235":{"start":{"line":548,"column":4},"end":{"line":548,"column":null}},"236":{"start":{"line":550,"column":4},"end":{"line":552,"column":null}},"237":{"start":{"line":553,"column":4},"end":{"line":553,"column":null}},"238":{"start":{"line":558,"column":2},"end":{"line":560,"column":3}},"239":{"start":{"line":559,"column":4},"end":{"line":559,"column":null}},"240":{"start":{"line":561,"column":16},"end":{"line":561,"column":49}},"241":{"start":{"line":562,"column":2},"end":{"line":562,"column":null}},"242":{"start":{"line":566,"column":17},"end":{"line":566,"column":43}},"243":{"start":{"line":567,"column":22},"end":{"line":567,"column":53}},"244":{"start":{"line":568,"column":15},"end":{"line":570,"column":null}},"245":{"start":{"line":572,"column":2},"end":{"line":579,"column":3}},"246":{"start":{"line":572,"column":29},"end":{"line":572,"column":36}},"247":{"start":{"line":572,"column":13},"end":{"line":572,"column":14}},"248":{"start":{"line":572,"column":17},"end":{"line":572,"column":19}},"249":{"start":{"line":572,"column":24},"end":{"line":572,"column":25}},"250":{"start":{"line":573,"column":4},"end":{"line":578,"column":5}},"251":{"start":{"line":574,"column":21},"end":{"line":574,"column":47}},"252":{"start":{"line":575,"column":6},"end":{"line":577,"column":7}},"253":{"start":{"line":576,"column":8},"end":{"line":576,"column":null}},"254":{"start":{"line":580,"column":2},"end":{"line":585,"column":3}},"255":{"start":{"line":580,"column":26},"end":{"line":580,"column":33}},"256":{"start":{"line":580,"column":13},"end":{"line":580,"column":16}},"257":{"start":{"line":580,"column":21},"end":{"line":580,"column":22}},"258":{"start":{"line":581,"column":19},"end":{"line":581,"column":45}},"259":{"start":{"line":582,"column":4},"end":{"line":584,"column":5}},"260":{"start":{"line":583,"column":6},"end":{"line":583,"column":null}},"261":{"start":{"line":586,"column":2},"end":{"line":586,"column":null}},"262":{"start":{"line":598,"column":18},"end":{"line":598,"column":66}},"263":{"start":{"line":599,"column":19},"end":{"line":599,"column":36}},"264":{"start":{"line":600,"column":14},"end":{"line":600,"column":15}},"265":{"start":{"line":601,"column":2},"end":{"line":614,"column":3}},"266":{"start":{"line":601,"column":26},"end":{"line":601,"column":29}},"267":{"start":{"line":601,"column":26},"end":{"line":601,"column":52}},"268":{"start":{"line":601,"column":22},"end":{"line":601,"column":26}},"269":{"start":{"line":602,"column":4},"end":{"line":613,"column":5}},"270":{"start":{"line":602,"column":28},"end":{"line":602,"column":null}},"271":{"start":{"line":602,"column":28},"end":{"line":605,"column":7}},"272":{"start":{"line":602,"column":24},"end":{"line":602,"column":28}},"273":{"start":{"line":606,"column":6},"end":{"line":612,"column":7}},"274":{"start":{"line":606,"column":36},"end":{"line":606,"column":42}},"275":{"start":{"line":606,"column":36},"end":{"line":606,"column":67}},"276":{"start":{"line":606,"column":17},"end":{"line":606,"column":18}},"277":{"start":{"line":606,"column":21},"end":{"line":606,"column":23}},"278":{"start":{"line":606,"column":31},"end":{"line":606,"column":32}},"279":{"start":{"line":607,"column":22},"end":{"line":607,"column":51}},"280":{"start":{"line":608,"column":8},"end":{"line":611,"column":9}},"281":{"start":{"line":609,"column":10},"end":{"line":609,"column":null}},"282":{"start":{"line":610,"column":10},"end":{"line":610,"column":null}},"283":{"start":{"line":615,"column":21},"end":{"line":616,"column":null}},"284":{"start":{"line":616,"column":9},"end":{"line":616,"column":null}},"285":{"start":{"line":618,"column":21},"end":{"line":618,"column":50}},"286":{"start":{"line":619,"column":17},"end":{"line":621,"column":38}},"287":{"start":{"line":622,"column":2},"end":{"line":627,"column":null}},"288":{"start":{"line":631,"column":2},"end":{"line":631,"column":null}},"289":{"start":{"line":633,"column":2},"end":{"line":635,"column":3}},"290":{"start":{"line":634,"column":4},"end":{"line":634,"column":null}},"291":{"start":{"line":636,"column":20},"end":{"line":636,"column":46}},"292":{"start":{"line":637,"column":16},"end":{"line":637,"column":62}},"293":{"start":{"line":637,"column":49},"end":{"line":637,"column":62}},"294":{"start":{"line":638,"column":2},"end":{"line":640,"column":3}},"295":{"start":{"line":639,"column":4},"end":{"line":639,"column":null}},"296":{"start":{"line":641,"column":2},"end":{"line":641,"column":null}},"297":{"start":{"line":647,"column":8},"end":{"line":647,"column":null}},"298":{"start":{"line":648,"column":2},"end":{"line":650,"column":3}},"299":{"start":{"line":649,"column":4},"end":{"line":649,"column":null}},"300":{"start":{"line":651,"column":8},"end":{"line":653,"column":null}},"301":{"start":{"line":652,"column":9},"end":{"line":652,"column":null}},"302":{"start":{"line":654,"column":8},"end":{"line":654,"column":null}},"303":{"start":{"line":655,"column":2},"end":{"line":657,"column":3}},"304":{"start":{"line":656,"column":4},"end":{"line":656,"column":null}},"305":{"start":{"line":658,"column":2},"end":{"line":660,"column":3}},"306":{"start":{"line":659,"column":4},"end":{"line":659,"column":null}},"307":{"start":{"line":661,"column":21},"end":{"line":666,"column":null}},"308":{"start":{"line":661,"column":10},"end":{"line":661,"column":21}},"309":{"start":{"line":667,"column":2},"end":{"line":667,"column":null}},"310":{"start":{"line":671,"column":2},"end":{"line":673,"column":3}},"311":{"start":{"line":672,"column":4},"end":{"line":672,"column":10}},"312":{"start":{"line":674,"column":6},"end":{"line":674,"column":null}},"313":{"start":{"line":676,"column":11},"end":{"line":676,"column":null}},"314":{"start":{"line":676,"column":4},"end":{"line":676,"column":null}},"315":{"start":{"line":678,"column":4},"end":{"line":678,"column":null}},"316":{"start":{"line":679,"column":4},"end":{"line":679,"column":10}},"317":{"start":{"line":681,"column":8},"end":{"line":683,"column":null}},"318":{"start":{"line":682,"column":11},"end":{"line":682,"column":null}},"319":{"start":{"line":684,"column":2},"end":{"line":686,"column":3}},"320":{"start":{"line":685,"column":4},"end":{"line":685,"column":10}},"321":{"start":{"line":688,"column":6},"end":{"line":688,"column":null}},"322":{"start":{"line":690,"column":22},"end":{"line":690,"column":null}},"323":{"start":{"line":690,"column":10},"end":{"line":690,"column":null}},"324":{"start":{"line":691,"column":4},"end":{"line":691,"column":null}},"325":{"start":{"line":693,"column":4},"end":{"line":693,"column":null}},"326":{"start":{"line":696,"column":17},"end":{"line":696,"column":null}},"327":{"start":{"line":696,"column":8},"end":{"line":696,"column":null}},"328":{"start":{"line":697,"column":2},"end":{"line":702,"column":3}},"329":{"start":{"line":698,"column":4},"end":{"line":700,"column":null}},"330":{"start":{"line":701,"column":4},"end":{"line":701,"column":10}},"331":{"start":{"line":704,"column":27},"end":{"line":704,"column":null}},"332":{"start":{"line":704,"column":20},"end":{"line":704,"column":null}},"333":{"start":{"line":704,"column":13},"end":{"line":704,"column":20}},"334":{"start":{"line":705,"column":10},"end":{"line":705,"column":null}},"335":{"start":{"line":707,"column":6},"end":{"line":707,"column":null}},"336":{"start":{"line":709,"column":6},"end":{"line":711,"column":null}},"337":{"start":{"line":722,"column":18},"end":{"line":722,"column":null}},"338":{"start":{"line":722,"column":8},"end":{"line":722,"column":null}},"339":{"start":{"line":723,"column":2},"end":{"line":726,"column":3}},"340":{"start":{"line":724,"column":4},"end":{"line":724,"column":null}},"341":{"start":{"line":725,"column":4},"end":{"line":725,"column":10}},"342":{"start":{"line":728,"column":8},"end":{"line":728,"column":null}},"343":{"start":{"line":729,"column":8},"end":{"line":739,"column":null}},"344":{"start":{"line":741,"column":8},"end":{"line":745,"column":null}},"345":{"start":{"line":746,"column":8},"end":{"line":746,"column":null}},"346":{"start":{"line":748,"column":4},"end":{"line":748,"column":null}},"347":{"start":{"line":749,"column":4},"end":{"line":749,"column":null}},"348":{"start":{"line":751,"column":4},"end":{"line":751,"column":null}},"349":{"start":{"line":753,"column":6},"end":{"line":753,"column":null}}},"fnMap":{"0":{"name":"npuMetricsEnabled","decl":{"start":{"line":71,"column":16},"end":{"line":71,"column":33}},"loc":{"start":{"line":72,"column":55},"end":{"line":77,"column":1}}},"1":{"name":"getNpuSampleIntervalSeconds","decl":{"start":{"line":79,"column":16},"end":{"line":79,"column":43}},"loc":{"start":{"line":80,"column":55},"end":{"line":94,"column":1}}},"2":{"name":"getIdleThresholdPercent","decl":{"start":{"line":96,"column":16},"end":{"line":96,"column":39}},"loc":{"start":{"line":97,"column":55},"end":{"line":111,"column":1}}},"3":{"name":"containerHasNpuRequest","decl":{"start":{"line":113,"column":16},"end":{"line":113,"column":38}},"loc":{"start":{"line":113,"column":65},"end":{"line":123,"column":1}}},"4":{"name":"hasNpuRequest","decl":{"start":{"line":125,"column":16},"end":{"line":125,"column":29}},"loc":{"start":{"line":125,"column":61},"end":{"line":127,"column":1}}},"5":{"name":"(anonymous_30)","decl":{"start":{"line":126,"column":39},"end":{"line":126,"column":40}},"loc":{"start":{"line":126,"column":40},"end":{"line":126,"column":66}}},"6":{"name":"listNpuCardsCommand","decl":{"start":{"line":129,"column":9},"end":{"line":129,"column":28}},"loc":{"start":{"line":129,"column":28},"end":{"line":131,"column":1}}},"7":{"name":"buildNpuSamplerScript","decl":{"start":{"line":133,"column":16},"end":{"line":133,"column":37}},"loc":{"start":{"line":134,"column":55},"end":{"line":156,"column":1}}},"8":{"name":"buildNpuAggregateScript","decl":{"start":{"line":187,"column":16},"end":{"line":187,"column":39}},"loc":{"start":{"line":187,"column":39},"end":{"line":196,"column":1}}},"9":{"name":"commandHasMarker","decl":{"start":{"line":198,"column":9},"end":{"line":198,"column":25}},"loc":{"start":{"line":198,"column":55},"end":{"line":200,"column":1}}},"10":{"name":"appendExecCommand","decl":{"start":{"line":202,"column":9},"end":{"line":202,"column":26}},"loc":{"start":{"line":204,"column":23},"end":{"line":222,"column":1}}},"11":{"name":"(anonymous_36)","decl":{"start":{"line":219,"column":4},"end":{"line":219,"column":8}},"loc":{"start":{"line":219,"column":8},"end":{"line":219,"column":16}}},"12":{"name":"injectNpuMetrics","decl":{"start":{"line":224,"column":16},"end":{"line":224,"column":32}},"loc":{"start":{"line":226,"column":55},"end":{"line":267,"column":1}}},"13":{"name":"maybeInjectNpuMetrics","decl":{"start":{"line":269,"column":16},"end":{"line":269,"column":37}},"loc":{"start":{"line":269,"column":64},"end":{"line":277,"column":1}}},"14":{"name":"parseNpuAggregate","decl":{"start":{"line":279,"column":16},"end":{"line":279,"column":33}},"loc":{"start":{"line":280,"column":25},"end":{"line":322,"column":1}}},"15":{"name":"isIdleRecord","decl":{"start":{"line":324,"column":16},"end":{"line":324,"column":28}},"loc":{"start":{"line":326,"column":48},"end":{"line":332,"column":1}}},"16":{"name":"(anonymous_41)","decl":{"start":{"line":331,"column":21},"end":{"line":331,"column":22}},"loc":{"start":{"line":331,"column":22},"end":{"line":331,"column":27}}},"17":{"name":"escapePromLabelValue","decl":{"start":{"line":334,"column":16},"end":{"line":334,"column":36}},"loc":{"start":{"line":334,"column":50},"end":{"line":336,"column":1}}},"18":{"name":"formatPromLabels","decl":{"start":{"line":338,"column":16},"end":{"line":338,"column":32}},"loc":{"start":{"line":338,"column":63},"end":{"line":343,"column":1}}},"19":{"name":"(anonymous_44)","decl":{"start":{"line":340,"column":12},"end":{"line":340,"column":13}},"loc":{"start":{"line":340,"column":18},"end":{"line":340,"column":24}}},"20":{"name":"(anonymous_45)","decl":{"start":{"line":341,"column":9},"end":{"line":341,"column":10}},"loc":{"start":{"line":341,"column":16},"end":{"line":341,"column":24}}},"21":{"name":"buildNpuJobMetricsBody","decl":{"start":{"line":359,"column":16},"end":{"line":359,"column":38}},"loc":{"start":{"line":362,"column":52},"end":{"line":399,"column":1}}},"22":{"name":"(anonymous_48)","decl":{"start":{"line":385,"column":38},"end":{"line":385,"column":39}},"loc":{"start":{"line":385,"column":39},"end":{"line":385,"column":44}}},"23":{"name":"buildNpuPushFailedBody","decl":{"start":{"line":401,"column":16},"end":{"line":401,"column":38}},"loc":{"start":{"line":401,"column":59},"end":{"line":406,"column":1}}},"24":{"name":"buildPushgatewayPath","decl":{"start":{"line":408,"column":16},"end":{"line":408,"column":36}},"loc":{"start":{"line":411,"column":13},"end":{"line":416,"column":1}}},"25":{"name":"withTimeout","decl":{"start":{"line":418,"column":22},"end":{"line":418,"column":33}},"loc":{"start":{"line":420,"column":19},"end":{"line":435,"column":null}}},"26":{"name":"(anonymous_54)","decl":{"start":{"line":422,"column":30},"end":{"line":422,"column":31}},"loc":{"start":{"line":422,"column":46},"end":{"line":434,"column":3}}},"27":{"name":"(anonymous_55)","decl":{"start":{"line":423,"column":29},"end":{"line":423,"column":35}},"loc":{"start":{"line":423,"column":29},"end":{"line":423,"column":41}}},"28":{"name":"(anonymous_56)","decl":{"start":{"line":425,"column":6},"end":{"line":425,"column":11}},"loc":{"start":{"line":425,"column":11},"end":{"line":428,"column":7}}},"29":{"name":"(anonymous_57)","decl":{"start":{"line":429,"column":6},"end":{"line":429,"column":9}},"loc":{"start":{"line":429,"column":9},"end":{"line":432,"column":7}}},"30":{"name":"nodeRequest","decl":{"start":{"line":448,"column":22},"end":{"line":448,"column":33}},"loc":{"start":{"line":448,"column":50},"end":{"line":482,"column":null}}},"31":{"name":"(anonymous_61)","decl":{"start":{"line":462,"column":27},"end":{"line":462,"column":28}},"loc":{"start":{"line":462,"column":43},"end":{"line":481,"column":3}}},"32":{"name":"(anonymous_62)","decl":{"start":{"line":471,"column":6},"end":{"line":471,"column":14}},"loc":{"start":{"line":471,"column":14},"end":{"line":476,"column":7}}},"33":{"name":"(anonymous_63)","decl":{"start":{"line":473,"column":27},"end":{"line":473,"column":null}},"loc":{"start":{"line":473,"column":27},"end":{"line":474,"column":null}}},"34":{"name":"(anonymous_64)","decl":{"start":{"line":478,"column":26},"end":{"line":478,"column":32}},"loc":{"start":{"line":478,"column":26},"end":{"line":478,"column":39}}},"35":{"name":"pushToPushgateway","decl":{"start":{"line":484,"column":22},"end":{"line":484,"column":39}},"loc":{"start":{"line":488,"column":78},"end":{"line":516,"column":null}}},"36":{"name":"(anonymous_68)","decl":{"start":{"line":497,"column":24},"end":{"line":497,"column":31}},"loc":{"start":{"line":497,"column":31},"end":{"line":497,"column":45}}},"37":{"name":"decodePushSecret","decl":{"start":{"line":518,"column":16},"end":{"line":518,"column":32}},"loc":{"start":{"line":519,"column":34},"end":{"line":543,"column":1}}},"38":{"name":"(anonymous_70)","decl":{"start":{"line":522,"column":17},"end":{"line":522,"column":18}},"loc":{"start":{"line":522,"column":29},"end":{"line":533,"column":3}}},"39":{"name":"readNpuPushConfig","decl":{"start":{"line":545,"column":22},"end":{"line":545,"column":39}},"loc":{"start":{"line":545,"column":39},"end":{"line":555,"column":null}}},"40":{"name":"parseScaleSetSuffix","decl":{"start":{"line":557,"column":9},"end":{"line":557,"column":28}},"loc":{"start":{"line":557,"column":54},"end":{"line":563,"column":1}}},"41":{"name":"extractClusterFromRunnerPod","decl":{"start":{"line":565,"column":16},"end":{"line":565,"column":43}},"loc":{"start":{"line":565,"column":58},"end":{"line":587,"column":1}}},"42":{"name":"resolveNpuLabelsFromPod","decl":{"start":{"line":589,"column":16},"end":{"line":589,"column":39}},"loc":{"start":{"line":591,"column":17},"end":{"line":628,"column":1}}},"43":{"name":"(anonymous_77)","decl":{"start":{"line":616,"column":4},"end":{"line":616,"column":5}},"loc":{"start":{"line":616,"column":5},"end":{"line":616,"column":10}}},"44":{"name":"repoFromEnv","decl":{"start":{"line":630,"column":16},"end":{"line":630,"column":27}},"loc":{"start":{"line":631,"column":55},"end":{"line":642,"column":1}}},"45":{"name":"(anonymous_79)","decl":{"start":{"line":637,"column":44},"end":{"line":637,"column":45}},"loc":{"start":{"line":637,"column":45},"end":{"line":637,"column":50}}},"46":{"name":"collectNpuAggregateFromPod","decl":{"start":{"line":644,"column":22},"end":{"line":644,"column":48}},"loc":{"start":{"line":645,"column":16},"end":{"line":668,"column":null}}},"47":{"name":"(anonymous_83)","decl":{"start":{"line":652,"column":4},"end":{"line":652,"column":5}},"loc":{"start":{"line":652,"column":5},"end":{"line":652,"column":10}}},"48":{"name":"collectAndPushNpuMetrics","decl":{"start":{"line":670,"column":22},"end":{"line":670,"column":46}},"loc":{"start":{"line":670,"column":46},"end":{"line":714,"column":null}}},"49":{"name":"(anonymous_87)","decl":{"start":{"line":682,"column":4},"end":{"line":682,"column":7}},"loc":{"start":{"line":682,"column":7},"end":{"line":682,"column":null}}},"50":{"name":"collectAndPushForPod","decl":{"start":{"line":716,"column":15},"end":{"line":716,"column":35}},"loc":{"start":{"line":720,"column":23},"end":{"line":758,"column":null}}}},"branchMap":{"0":{"loc":{"start":{"line":72,"column":2},"end":{"line":72,"column":null}},"type":"if","locations":[{"start":{"line":72,"column":2},"end":{"line":72,"column":null}},{"start":{},"end":{}}]},"1":{"loc":{"start":{"line":75,"column":5},"end":{"line":75,"column":39}},"type":"cond-expr","locations":[{"start":{"line":75,"column":33},"end":{"line":75,"column":37}},{"start":{"line":75,"column":37},"end":{"line":75,"column":39}}]},"2":{"loc":{"start":{"line":75,"column":5},"end":{"line":75,"column":37}},"type":"binary-expr","locations":[{"start":{"line":75,"column":5},"end":{"line":75,"column":37}},{"start":{"line":75,"column":33},"end":{"line":75,"column":37}}]},"3":{"loc":{"start":{"line":80,"column":2},"end":{"line":80,"column":null}},"type":"if","locations":[{"start":{"line":80,"column":2},"end":{"line":80,"column":null}},{"start":{},"end":{}}]},"4":{"loc":{"start":{"line":83,"column":2},"end":{"line":85,"column":3}},"type":"if","locations":[{"start":{"line":83,"column":2},"end":{"line":85,"column":3}},{"start":{},"end":{}}]},"5":{"loc":{"start":{"line":87,"column":2},"end":{"line":92,"column":3}},"type":"if","locations":[{"start":{"line":87,"column":2},"end":{"line":92,"column":3}},{"start":{},"end":{}}]},"6":{"loc":{"start":{"line":87,"column":6},"end":{"line":87,"column":45}},"type":"binary-expr","locations":[{"start":{"line":87,"column":6},"end":{"line":87,"column":30}},{"start":{"line":87,"column":34},"end":{"line":87,"column":45}}]},"7":{"loc":{"start":{"line":97,"column":2},"end":{"line":97,"column":null}},"type":"if","locations":[{"start":{"line":97,"column":2},"end":{"line":97,"column":null}},{"start":{},"end":{}}]},"8":{"loc":{"start":{"line":100,"column":2},"end":{"line":102,"column":3}},"type":"if","locations":[{"start":{"line":100,"column":2},"end":{"line":102,"column":3}},{"start":{},"end":{}}]},"9":{"loc":{"start":{"line":104,"column":2},"end":{"line":109,"column":3}},"type":"if","locations":[{"start":{"line":104,"column":2},"end":{"line":109,"column":3}},{"start":{},"end":{}}]},"10":{"loc":{"start":{"line":104,"column":6},"end":{"line":104,"column":44}},"type":"binary-expr","locations":[{"start":{"line":104,"column":6},"end":{"line":104,"column":30}},{"start":{"line":104,"column":34},"end":{"line":104,"column":44}}]},"11":{"loc":{"start":{"line":114,"column":21},"end":{"line":114,"column":50}},"type":"cond-expr","locations":[{"start":{"line":114,"column":40},"end":{"line":114,"column":42}},{"start":{"line":114,"column":40},"end":{"line":114,"column":50}}]},"12":{"loc":{"start":{"line":114,"column":21},"end":{"line":114,"column":42}},"type":"binary-expr","locations":[{"start":{"line":114,"column":21},"end":{"line":114,"column":42}},{"start":{"line":114,"column":40},"end":{"line":114,"column":42}}]},"13":{"loc":{"start":{"line":114,"column":52},"end":{"line":114,"column":79}},"type":"cond-expr","locations":[{"start":{"line":114,"column":71},"end":{"line":114,"column":73}},{"start":{"line":114,"column":71},"end":{"line":114,"column":79}}]},"14":{"loc":{"start":{"line":114,"column":52},"end":{"line":114,"column":73}},"type":"binary-expr","locations":[{"start":{"line":114,"column":52},"end":{"line":114,"column":73}},{"start":{"line":114,"column":71},"end":{"line":114,"column":73}}]},"15":{"loc":{"start":{"line":116,"column":34},"end":{"line":116,"column":45}},"type":"cond-expr","locations":[{"start":{"line":116,"column":34},"end":{"line":116,"column":39}},{"start":{"line":116,"column":43},"end":{"line":116,"column":45}}]},"16":{"loc":{"start":{"line":116,"column":34},"end":{"line":116,"column":43}},"type":"binary-expr","locations":[{"start":{"line":116,"column":34},"end":{"line":116,"column":43}},{"start":{"line":116,"column":34},"end":{"line":116,"column":43}}]},"17":{"loc":{"start":{"line":117,"column":6},"end":{"line":119,"column":7}},"type":"if","locations":[{"start":{"line":117,"column":6},"end":{"line":119,"column":7}},{"start":{},"end":{}}]},"18":{"loc":{"start":{"line":126,"column":10},"end":{"line":126,"column":32}},"type":"cond-expr","locations":[{"start":{"line":126,"column":26},"end":{"line":126,"column":30}},{"start":{"line":126,"column":30},"end":{"line":126,"column":32}}]},"19":{"loc":{"start":{"line":126,"column":10},"end":{"line":126,"column":30}},"type":"binary-expr","locations":[{"start":{"line":126,"column":10},"end":{"line":126,"column":30}},{"start":{"line":126,"column":26},"end":{"line":126,"column":30}}]},"20":{"loc":{"start":{"line":126,"column":10},"end":{"line":126,"column":26}},"type":"cond-expr","locations":[{"start":{"line":126,"column":14},"end":{"line":126,"column":16}},{"start":{"line":126,"column":10},"end":{"line":126,"column":26}}]},"21":{"loc":{"start":{"line":126,"column":10},"end":{"line":126,"column":16}},"type":"binary-expr","locations":[{"start":{"line":126,"column":10},"end":{"line":126,"column":16}},{"start":{"line":126,"column":10},"end":{"line":126,"column":16}}]},"22":{"loc":{"start":{"line":134,"column":2},"end":{"line":134,"column":null}},"type":"if","locations":[{"start":{"line":134,"column":2},"end":{"line":134,"column":null}},{"start":{},"end":{}}]},"23":{"loc":{"start":{"line":199,"column":10},"end":{"line":199,"column":23}},"type":"cond-expr","locations":[{"start":{"line":199,"column":10},"end":{"line":199,"column":17}},{"start":{"line":199,"column":21},"end":{"line":199,"column":23}}]},"24":{"loc":{"start":{"line":199,"column":10},"end":{"line":199,"column":21}},"type":"binary-expr","locations":[{"start":{"line":199,"column":10},"end":{"line":199,"column":21}},{"start":{"line":199,"column":10},"end":{"line":199,"column":21}}]},"25":{"loc":{"start":{"line":206,"column":2},"end":{"line":217,"column":3}},"type":"if","locations":[{"start":{"line":206,"column":2},"end":{"line":217,"column":3}},{"start":{},"end":{}}]},"26":{"loc":{"start":{"line":207,"column":4},"end":{"line":210,"column":24}},"type":"binary-expr","locations":[{"start":{"line":207,"column":4},"end":{"line":207,"column":12}},{"start":{"line":208,"column":4},"end":{"line":208,"column":24}},{"start":{"line":209,"column":4},"end":{"line":209,"column":33}},{"start":{"line":210,"column":4},"end":{"line":210,"column":24}}]},"27":{"loc":{"start":{"line":218,"column":18},"end":{"line":218,"column":32}},"type":"cond-expr","locations":[{"start":{"line":218,"column":18},"end":{"line":218,"column":26}},{"start":{"line":218,"column":30},"end":{"line":218,"column":32}}]},"28":{"loc":{"start":{"line":218,"column":18},"end":{"line":218,"column":30}},"type":"binary-expr","locations":[{"start":{"line":218,"column":18},"end":{"line":218,"column":30}},{"start":{"line":218,"column":18},"end":{"line":218,"column":30}}]},"29":{"loc":{"start":{"line":226,"column":2},"end":{"line":226,"column":null}},"type":"if","locations":[{"start":{"line":226,"column":2},"end":{"line":226,"column":null}},{"start":{},"end":{}}]},"30":{"loc":{"start":{"line":228,"column":20},"end":{"line":228,"column":45}},"type":"cond-expr","locations":[{"start":{"line":228,"column":39},"end":{"line":228,"column":43}},{"start":{"line":228,"column":43},"end":{"line":228,"column":45}}]},"31":{"loc":{"start":{"line":228,"column":20},"end":{"line":228,"column":43}},"type":"binary-expr","locations":[{"start":{"line":228,"column":20},"end":{"line":228,"column":43}},{"start":{"line":228,"column":39},"end":{"line":228,"column":43}}]},"32":{"loc":{"start":{"line":229,"column":2},"end":{"line":234,"column":3}},"type":"if","locations":[{"start":{"line":229,"column":2},"end":{"line":234,"column":3}},{"start":{},"end":{}}]},"33":{"loc":{"start":{"line":230,"column":4},"end":{"line":231,"column":54}},"type":"binary-expr","locations":[{"start":{"line":230,"column":4},"end":{"line":230,"column":56}},{"start":{"line":231,"column":4},"end":{"line":231,"column":54}}]},"34":{"loc":{"start":{"line":230,"column":21},"end":{"line":230,"column":55}},"type":"cond-expr","locations":[{"start":{"line":230,"column":46},"end":{"line":230,"column":48}},{"start":{"line":230,"column":46},"end":{"line":230,"column":55}}]},"35":{"loc":{"start":{"line":230,"column":21},"end":{"line":230,"column":48}},"type":"binary-expr","locations":[{"start":{"line":230,"column":21},"end":{"line":230,"column":48}},{"start":{"line":230,"column":46},"end":{"line":230,"column":48}}]},"36":{"loc":{"start":{"line":230,"column":21},"end":{"line":230,"column":46}},"type":"cond-expr","locations":[{"start":{"line":230,"column":40},"end":{"line":230,"column":42}},{"start":{"line":230,"column":40},"end":{"line":230,"column":46}}]},"37":{"loc":{"start":{"line":230,"column":21},"end":{"line":230,"column":42}},"type":"binary-expr","locations":[{"start":{"line":230,"column":21},"end":{"line":230,"column":42}},{"start":{"line":230,"column":40},"end":{"line":230,"column":42}}]},"38":{"loc":{"start":{"line":231,"column":21},"end":{"line":231,"column":53}},"type":"cond-expr","locations":[{"start":{"line":231,"column":44},"end":{"line":231,"column":46}},{"start":{"line":231,"column":44},"end":{"line":231,"column":53}}]},"39":{"loc":{"start":{"line":231,"column":21},"end":{"line":231,"column":46}},"type":"binary-expr","locations":[{"start":{"line":231,"column":21},"end":{"line":231,"column":46}},{"start":{"line":231,"column":44},"end":{"line":231,"column":46}}]},"40":{"loc":{"start":{"line":231,"column":21},"end":{"line":231,"column":44}},"type":"cond-expr","locations":[{"start":{"line":231,"column":38},"end":{"line":231,"column":40}},{"start":{"line":231,"column":38},"end":{"line":231,"column":44}}]},"41":{"loc":{"start":{"line":231,"column":21},"end":{"line":231,"column":40}},"type":"binary-expr","locations":[{"start":{"line":231,"column":21},"end":{"line":231,"column":40}},{"start":{"line":231,"column":38},"end":{"line":231,"column":40}}]},"42":{"loc":{"start":{"line":236,"column":2},"end":{"line":244,"column":3}},"type":"if","locations":[{"start":{"line":236,"column":2},"end":{"line":244,"column":3}},{"start":{},"end":{}}]},"43":{"loc":{"start":{"line":237,"column":4},"end":{"line":238,"column":50}},"type":"binary-expr","locations":[{"start":{"line":237,"column":5},"end":{"line":237,"column":24}},{"start":{"line":237,"column":28},"end":{"line":237,"column":53}},{"start":{"line":238,"column":5},"end":{"line":238,"column":22}},{"start":{"line":238,"column":26},"end":{"line":238,"column":49}}]},"44":{"loc":{"start":{"line":251,"column":33},"end":{"line":251,"column":67}},"type":"cond-expr","locations":[{"start":{"line":251,"column":58},"end":{"line":251,"column":60}},{"start":{"line":251,"column":58},"end":{"line":251,"column":67}}]},"45":{"loc":{"start":{"line":251,"column":33},"end":{"line":251,"column":60}},"type":"binary-expr","locations":[{"start":{"line":251,"column":33},"end":{"line":251,"column":60}},{"start":{"line":251,"column":58},"end":{"line":251,"column":60}}]},"46":{"loc":{"start":{"line":251,"column":33},"end":{"line":251,"column":58}},"type":"cond-expr","locations":[{"start":{"line":251,"column":52},"end":{"line":251,"column":54}},{"start":{"line":251,"column":52},"end":{"line":251,"column":58}}]},"47":{"loc":{"start":{"line":251,"column":33},"end":{"line":251,"column":54}},"type":"binary-expr","locations":[{"start":{"line":251,"column":33},"end":{"line":251,"column":54}},{"start":{"line":251,"column":52},"end":{"line":251,"column":54}}]},"48":{"loc":{"start":{"line":259,"column":33},"end":{"line":259,"column":65}},"type":"cond-expr","locations":[{"start":{"line":259,"column":56},"end":{"line":259,"column":58}},{"start":{"line":259,"column":56},"end":{"line":259,"column":65}}]},"49":{"loc":{"start":{"line":259,"column":33},"end":{"line":259,"column":58}},"type":"binary-expr","locations":[{"start":{"line":259,"column":33},"end":{"line":259,"column":58}},{"start":{"line":259,"column":56},"end":{"line":259,"column":58}}]},"50":{"loc":{"start":{"line":259,"column":33},"end":{"line":259,"column":56}},"type":"cond-expr","locations":[{"start":{"line":259,"column":50},"end":{"line":259,"column":52}},{"start":{"line":259,"column":50},"end":{"line":259,"column":56}}]},"51":{"loc":{"start":{"line":259,"column":33},"end":{"line":259,"column":52}},"type":"binary-expr","locations":[{"start":{"line":259,"column":33},"end":{"line":259,"column":52}},{"start":{"line":259,"column":50},"end":{"line":259,"column":52}}]},"52":{"loc":{"start":{"line":270,"column":2},"end":{"line":272,"column":3}},"type":"if","locations":[{"start":{"line":270,"column":2},"end":{"line":272,"column":3}},{"start":{},"end":{}}]},"53":{"loc":{"start":{"line":273,"column":2},"end":{"line":275,"column":3}},"type":"if","locations":[{"start":{"line":273,"column":2},"end":{"line":275,"column":3}},{"start":{},"end":{}}]},"54":{"loc":{"start":{"line":282,"column":2},"end":{"line":284,"column":3}},"type":"if","locations":[{"start":{"line":282,"column":2},"end":{"line":284,"column":3}},{"start":{},"end":{}}]},"55":{"loc":{"start":{"line":286,"column":2},"end":{"line":288,"column":3}},"type":"if","locations":[{"start":{"line":286,"column":2},"end":{"line":288,"column":3}},{"start":{},"end":{}}]},"56":{"loc":{"start":{"line":291,"column":2},"end":{"line":293,"column":3}},"type":"if","locations":[{"start":{"line":291,"column":2},"end":{"line":293,"column":3}},{"start":{},"end":{}}]},"57":{"loc":{"start":{"line":301,"column":4},"end":{"line":303,"column":5}},"type":"if","locations":[{"start":{"line":301,"column":4},"end":{"line":303,"column":5}},{"start":{},"end":{}}]},"58":{"loc":{"start":{"line":301,"column":8},"end":{"line":301,"column":72}},"type":"binary-expr","locations":[{"start":{"line":301,"column":8},"end":{"line":301,"column":40}},{"start":{"line":301,"column":44},"end":{"line":301,"column":72}}]},"59":{"loc":{"start":{"line":301,"column":8},"end":{"line":301,"column":17}},"type":"cond-expr","locations":[{"start":{"line":301,"column":14},"end":{"line":301,"column":16}},{"start":{"line":301,"column":8},"end":{"line":301,"column":17}}]},"60":{"loc":{"start":{"line":301,"column":8},"end":{"line":301,"column":16}},"type":"binary-expr","locations":[{"start":{"line":301,"column":8},"end":{"line":301,"column":16}},{"start":{"line":301,"column":8},"end":{"line":301,"column":16}}]},"61":{"loc":{"start":{"line":306,"column":6},"end":{"line":308,"column":7}},"type":"if","locations":[{"start":{"line":306,"column":6},"end":{"line":308,"column":7}},{"start":{},"end":{}}]},"62":{"loc":{"start":{"line":306,"column":10},"end":{"line":306,"column":66}},"type":"binary-expr","locations":[{"start":{"line":306,"column":10},"end":{"line":306,"column":20}},{"start":{"line":306,"column":24},"end":{"line":306,"column":45}},{"start":{"line":306,"column":49},"end":{"line":306,"column":66}}]},"63":{"loc":{"start":{"line":311,"column":17},"end":{"line":311,"column":33}},"type":"binary-expr","locations":[{"start":{"line":311,"column":17},"end":{"line":311,"column":28}},{"start":{"line":311,"column":32},"end":{"line":311,"column":33}}]},"64":{"loc":{"start":{"line":312,"column":18},"end":{"line":312,"column":35}},"type":"binary-expr","locations":[{"start":{"line":312,"column":18},"end":{"line":312,"column":30}},{"start":{"line":312,"column":34},"end":{"line":312,"column":35}}]},"65":{"loc":{"start":{"line":313,"column":17},"end":{"line":313,"column":34}},"type":"binary-expr","locations":[{"start":{"line":313,"column":17},"end":{"line":313,"column":29}},{"start":{"line":313,"column":33},"end":{"line":313,"column":34}}]},"66":{"loc":{"start":{"line":314,"column":17},"end":{"line":314,"column":34}},"type":"binary-expr","locations":[{"start":{"line":314,"column":17},"end":{"line":314,"column":29}},{"start":{"line":314,"column":33},"end":{"line":314,"column":34}}]},"67":{"loc":{"start":{"line":315,"column":17},"end":{"line":315,"column":34}},"type":"binary-expr","locations":[{"start":{"line":315,"column":17},"end":{"line":315,"column":29}},{"start":{"line":315,"column":33},"end":{"line":315,"column":34}}]},"68":{"loc":{"start":{"line":316,"column":16},"end":{"line":316,"column":33}},"type":"binary-expr","locations":[{"start":{"line":316,"column":16},"end":{"line":316,"column":28}},{"start":{"line":316,"column":32},"end":{"line":316,"column":33}}]},"69":{"loc":{"start":{"line":319,"column":36},"end":{"line":319,"column":58}},"type":"binary-expr","locations":[{"start":{"line":319,"column":36},"end":{"line":319,"column":53}},{"start":{"line":319,"column":57},"end":{"line":319,"column":58}}]},"70":{"loc":{"start":{"line":326,"column":2},"end":{"line":326,"column":null}},"type":"if","locations":[{"start":{"line":326,"column":2},"end":{"line":326,"column":null}},{"start":{},"end":{}}]},"71":{"loc":{"start":{"line":328,"column":2},"end":{"line":330,"column":3}},"type":"if","locations":[{"start":{"line":328,"column":2},"end":{"line":330,"column":3}},{"start":{},"end":{}}]},"72":{"loc":{"start":{"line":331,"column":26},"end":{"line":331,"column":73}},"type":"binary-expr","locations":[{"start":{"line":331,"column":26},"end":{"line":331,"column":48}},{"start":{"line":331,"column":52},"end":{"line":331,"column":73}}]},"73":{"loc":{"start":{"line":362,"column":2},"end":{"line":362,"column":null}},"type":"if","locations":[{"start":{"line":362,"column":2},"end":{"line":362,"column":null}},{"start":{},"end":{}}]},"74":{"loc":{"start":{"line":375,"column":15},"end":{"line":375,"column":68}},"type":"cond-expr","locations":[{"start":{"line":375,"column":52},"end":{"line":375,"column":58}},{"start":{"line":375,"column":61},"end":{"line":375,"column":68}}]},"75":{"loc":{"start":{"line":422,"column":9},"end":{"line":434,"column":null}},"type":"switch","locations":[{"start":{"line":422,"column":9},"end":{"line":434,"column":null}},{"start":{"line":422,"column":2},"end":{"line":434,"column":null}}]},"76":{"loc":{"start":{"line":462,"column":2},"end":{"line":481,"column":null}},"type":"switch","locations":[{"start":{"line":462,"column":2},"end":{"line":481,"column":null}}]},"77":{"loc":{"start":{"line":452,"column":17},"end":{"line":452,"column":59}},"type":"cond-expr","locations":[{"start":{"line":452,"column":47},"end":{"line":452,"column":51}},{"start":{"line":452,"column":54},"end":{"line":452,"column":59}}]},"78":{"loc":{"start":{"line":456,"column":2},"end":{"line":461,"column":3}},"type":"if","locations":[{"start":{"line":456,"column":2},"end":{"line":461,"column":3}},{"start":{},"end":{}}]},"79":{"loc":{"start":{"line":456,"column":6},"end":{"line":456,"column":62}},"type":"binary-expr","locations":[{"start":{"line":456,"column":6},"end":{"line":456,"column":32}},{"start":{"line":456,"column":36},"end":{"line":456,"column":62}}]},"80":{"loc":{"start":{"line":458,"column":9},"end":{"line":458,"column":27}},"type":"cond-expr","locations":[{"start":{"line":458,"column":21},"end":{"line":458,"column":25}},{"start":{"line":458,"column":25},"end":{"line":458,"column":27}}]},"81":{"loc":{"start":{"line":458,"column":9},"end":{"line":458,"column":25}},"type":"binary-expr","locations":[{"start":{"line":458,"column":9},"end":{"line":458,"column":25}},{"start":{"line":458,"column":21},"end":{"line":458,"column":25}}]},"82":{"loc":{"start":{"line":458,"column":31},"end":{"line":458,"column":49}},"type":"cond-expr","locations":[{"start":{"line":458,"column":43},"end":{"line":458,"column":47}},{"start":{"line":458,"column":47},"end":{"line":458,"column":49}}]},"83":{"loc":{"start":{"line":458,"column":31},"end":{"line":458,"column":47}},"type":"binary-expr","locations":[{"start":{"line":458,"column":31},"end":{"line":458,"column":47}},{"start":{"line":458,"column":43},"end":{"line":458,"column":47}}]},"84":{"loc":{"start":{"line":468,"column":17},"end":{"line":468,"column":38}},"type":"cond-expr","locations":[{"start":{"line":468,"column":30},"end":{"line":468,"column":34}},{"start":{"line":468,"column":34},"end":{"line":468,"column":38}}]},"85":{"loc":{"start":{"line":468,"column":17},"end":{"line":468,"column":34}},"type":"binary-expr","locations":[{"start":{"line":468,"column":17},"end":{"line":468,"column":34}},{"start":{"line":468,"column":30},"end":{"line":468,"column":34}}]},"86":{"loc":{"start":{"line":474,"column":32},"end":{"line":474,"column":56}},"type":"cond-expr","locations":[{"start":{"line":474,"column":51},"end":{"line":474,"column":55}},{"start":{"line":474,"column":55},"end":{"line":474,"column":56}}]},"87":{"loc":{"start":{"line":474,"column":32},"end":{"line":474,"column":55}},"type":"binary-expr","locations":[{"start":{"line":474,"column":32},"end":{"line":474,"column":55}},{"start":{"line":474,"column":51},"end":{"line":474,"column":55}}]},"88":{"loc":{"start":{"line":515,"column":2},"end":{"line":515,"column":null}},"type":"switch","locations":[{"start":{"line":515,"column":2},"end":{"line":515,"column":null}}]},"89":{"loc":{"start":{"line":490,"column":18},"end":{"line":490,"column":39}},"type":"cond-expr","locations":[{"start":{"line":490,"column":34},"end":{"line":490,"column":38}},{"start":{"line":490,"column":38},"end":{"line":490,"column":39}}]},"90":{"loc":{"start":{"line":490,"column":18},"end":{"line":490,"column":38}},"type":"binary-expr","locations":[{"start":{"line":490,"column":18},"end":{"line":490,"column":38}},{"start":{"line":490,"column":34},"end":{"line":490,"column":38}}]},"91":{"loc":{"start":{"line":490,"column":18},"end":{"line":490,"column":34}},"type":"cond-expr","locations":[{"start":{"line":490,"column":25},"end":{"line":490,"column":27}},{"start":{"line":490,"column":18},"end":{"line":490,"column":34}}]},"92":{"loc":{"start":{"line":490,"column":18},"end":{"line":490,"column":27}},"type":"binary-expr","locations":[{"start":{"line":490,"column":18},"end":{"line":490,"column":27}},{"start":{"line":490,"column":18},"end":{"line":490,"column":27}}]},"93":{"loc":{"start":{"line":491,"column":23},"end":{"line":491,"column":52}},"type":"cond-expr","locations":[{"start":{"line":491,"column":44},"end":{"line":491,"column":48}},{"start":{"line":491,"column":48},"end":{"line":491,"column":52}}]},"94":{"loc":{"start":{"line":491,"column":23},"end":{"line":491,"column":48}},"type":"binary-expr","locations":[{"start":{"line":491,"column":23},"end":{"line":491,"column":48}},{"start":{"line":491,"column":44},"end":{"line":491,"column":48}}]},"95":{"loc":{"start":{"line":491,"column":23},"end":{"line":491,"column":44}},"type":"cond-expr","locations":[{"start":{"line":491,"column":30},"end":{"line":491,"column":32}},{"start":{"line":491,"column":23},"end":{"line":491,"column":44}}]},"96":{"loc":{"start":{"line":491,"column":23},"end":{"line":491,"column":32}},"type":"binary-expr","locations":[{"start":{"line":491,"column":23},"end":{"line":491,"column":32}},{"start":{"line":491,"column":23},"end":{"line":491,"column":32}}]},"97":{"loc":{"start":{"line":492,"column":20},"end":{"line":492,"column":53}},"type":"cond-expr","locations":[{"start":{"line":492,"column":38},"end":{"line":492,"column":42}},{"start":{"line":492,"column":42},"end":{"line":492,"column":53}}]},"98":{"loc":{"start":{"line":492,"column":20},"end":{"line":492,"column":42}},"type":"binary-expr","locations":[{"start":{"line":492,"column":20},"end":{"line":492,"column":42}},{"start":{"line":492,"column":38},"end":{"line":492,"column":42}}]},"99":{"loc":{"start":{"line":492,"column":20},"end":{"line":492,"column":38}},"type":"cond-expr","locations":[{"start":{"line":492,"column":27},"end":{"line":492,"column":29}},{"start":{"line":492,"column":20},"end":{"line":492,"column":38}}]},"100":{"loc":{"start":{"line":492,"column":20},"end":{"line":492,"column":29}},"type":"binary-expr","locations":[{"start":{"line":492,"column":20},"end":{"line":492,"column":29}},{"start":{"line":492,"column":20},"end":{"line":492,"column":29}}]},"101":{"loc":{"start":{"line":495,"column":24},"end":{"line":495,"column":44}},"type":"if","locations":[{"start":{"line":495,"column":24},"end":{"line":495,"column":44}},{"start":{},"end":{}}]},"102":{"loc":{"start":{"line":496,"column":8},"end":{"line":496,"column":15}},"type":"if","locations":[{"start":{"line":496,"column":8},"end":{"line":496,"column":15}},{"start":{},"end":{}}]},"103":{"loc":{"start":{"line":507,"column":6},"end":{"line":509,"column":7}},"type":"if","locations":[{"start":{"line":507,"column":6},"end":{"line":509,"column":7}},{"start":{},"end":{}}]},"104":{"loc":{"start":{"line":507,"column":10},"end":{"line":507,"column":65}},"type":"binary-expr","locations":[{"start":{"line":507,"column":10},"end":{"line":507,"column":36}},{"start":{"line":507,"column":40},"end":{"line":507,"column":65}}]},"105":{"loc":{"start":{"line":515,"column":8},"end":{"line":515,"column":77}},"type":"cond-expr","locations":[{"start":{"line":515,"column":37},"end":{"line":515,"column":46}},{"start":{"line":515,"column":49},"end":{"line":515,"column":77}}]},"106":{"loc":{"start":{"line":521,"column":15},"end":{"line":521,"column":33}},"type":"cond-expr","locations":[{"start":{"line":521,"column":27},"end":{"line":521,"column":31}},{"start":{"line":521,"column":31},"end":{"line":521,"column":33}}]},"107":{"loc":{"start":{"line":521,"column":15},"end":{"line":521,"column":31}},"type":"binary-expr","locations":[{"start":{"line":521,"column":15},"end":{"line":521,"column":31}},{"start":{"line":521,"column":27},"end":{"line":521,"column":31}}]},"108":{"loc":{"start":{"line":521,"column":15},"end":{"line":521,"column":27}},"type":"cond-expr","locations":[{"start":{"line":521,"column":21},"end":{"line":521,"column":23}},{"start":{"line":521,"column":15},"end":{"line":521,"column":27}}]},"109":{"loc":{"start":{"line":521,"column":15},"end":{"line":521,"column":23}},"type":"binary-expr","locations":[{"start":{"line":521,"column":15},"end":{"line":521,"column":23}},{"start":{"line":521,"column":15},"end":{"line":521,"column":23}}]},"110":{"loc":{"start":{"line":524,"column":4},"end":{"line":526,"column":5}},"type":"if","locations":[{"start":{"line":524,"column":4},"end":{"line":526,"column":5}},{"start":{},"end":{}}]},"111":{"loc":{"start":{"line":529,"column":13},"end":{"line":529,"column":49}},"type":"cond-expr","locations":[{"start":{"line":529,"column":30},"end":{"line":529,"column":37}},{"start":{"line":529,"column":40},"end":{"line":529,"column":49}}]},"112":{"loc":{"start":{"line":535,"column":2},"end":{"line":537,"column":3}},"type":"if","locations":[{"start":{"line":535,"column":2},"end":{"line":537,"column":3}},{"start":{},"end":{}}]},"113":{"loc":{"start":{"line":558,"column":2},"end":{"line":560,"column":3}},"type":"if","locations":[{"start":{"line":558,"column":2},"end":{"line":560,"column":3}},{"start":{},"end":{}}]},"114":{"loc":{"start":{"line":562,"column":9},"end":{"line":562,"column":37}},"type":"cond-expr","locations":[{"start":{"line":562,"column":17},"end":{"line":562,"column":25}},{"start":{"line":562,"column":28},"end":{"line":562,"column":37}}]},"115":{"loc":{"start":{"line":566,"column":17},"end":{"line":566,"column":43}},"type":"cond-expr","locations":[{"start":{"line":566,"column":37},"end":{"line":566,"column":41}},{"start":{"line":566,"column":41},"end":{"line":566,"column":43}}]},"116":{"loc":{"start":{"line":566,"column":17},"end":{"line":566,"column":41}},"type":"binary-expr","locations":[{"start":{"line":566,"column":17},"end":{"line":566,"column":41}},{"start":{"line":566,"column":37},"end":{"line":566,"column":41}}]},"117":{"loc":{"start":{"line":566,"column":17},"end":{"line":566,"column":37}},"type":"cond-expr","locations":[{"start":{"line":566,"column":29},"end":{"line":566,"column":31}},{"start":{"line":566,"column":29},"end":{"line":566,"column":37}}]},"118":{"loc":{"start":{"line":566,"column":17},"end":{"line":566,"column":31}},"type":"binary-expr","locations":[{"start":{"line":566,"column":17},"end":{"line":566,"column":31}},{"start":{"line":566,"column":29},"end":{"line":566,"column":31}}]},"119":{"loc":{"start":{"line":567,"column":22},"end":{"line":567,"column":53}},"type":"cond-expr","locations":[{"start":{"line":567,"column":47},"end":{"line":567,"column":51}},{"start":{"line":567,"column":51},"end":{"line":567,"column":53}}]},"120":{"loc":{"start":{"line":567,"column":22},"end":{"line":567,"column":51}},"type":"binary-expr","locations":[{"start":{"line":567,"column":22},"end":{"line":567,"column":51}},{"start":{"line":567,"column":47},"end":{"line":567,"column":51}}]},"121":{"loc":{"start":{"line":567,"column":22},"end":{"line":567,"column":47}},"type":"cond-expr","locations":[{"start":{"line":567,"column":34},"end":{"line":567,"column":36}},{"start":{"line":567,"column":34},"end":{"line":567,"column":47}}]},"122":{"loc":{"start":{"line":567,"column":22},"end":{"line":567,"column":36}},"type":"binary-expr","locations":[{"start":{"line":567,"column":22},"end":{"line":567,"column":36}},{"start":{"line":567,"column":34},"end":{"line":567,"column":36}}]},"123":{"loc":{"start":{"line":573,"column":4},"end":{"line":578,"column":5}},"type":"if","locations":[{"start":{"line":573,"column":4},"end":{"line":578,"column":5}},{"start":{},"end":{}}]},"124":{"loc":{"start":{"line":575,"column":6},"end":{"line":577,"column":7}},"type":"if","locations":[{"start":{"line":575,"column":6},"end":{"line":577,"column":7}},{"start":{},"end":{}}]},"125":{"loc":{"start":{"line":582,"column":4},"end":{"line":584,"column":5}},"type":"if","locations":[{"start":{"line":582,"column":4},"end":{"line":584,"column":5}},{"start":{},"end":{}}]},"126":{"loc":{"start":{"line":586,"column":9},"end":{"line":586,"column":61}},"type":"cond-expr","locations":[{"start":{"line":586,"column":48},"end":{"line":586,"column":52}},{"start":{"line":586,"column":52},"end":{"line":586,"column":61}}]},"127":{"loc":{"start":{"line":586,"column":9},"end":{"line":586,"column":52}},"type":"binary-expr","locations":[{"start":{"line":586,"column":9},"end":{"line":586,"column":52}},{"start":{"line":586,"column":48},"end":{"line":586,"column":52}}]},"128":{"loc":{"start":{"line":586,"column":29},"end":{"line":586,"column":47}},"type":"cond-expr","locations":[{"start":{"line":586,"column":41},"end":{"line":586,"column":43}},{"start":{"line":586,"column":41},"end":{"line":586,"column":47}}]},"129":{"loc":{"start":{"line":586,"column":29},"end":{"line":586,"column":43}},"type":"binary-expr","locations":[{"start":{"line":586,"column":29},"end":{"line":586,"column":43}},{"start":{"line":586,"column":41},"end":{"line":586,"column":43}}]},"130":{"loc":{"start":{"line":598,"column":18},"end":{"line":598,"column":66}},"type":"cond-expr","locations":[{"start":{"line":598,"column":47},"end":{"line":598,"column":53}},{"start":{"line":598,"column":56},"end":{"line":598,"column":66}}]},"131":{"loc":{"start":{"line":601,"column":26},"end":{"line":601,"column":52}},"type":"cond-expr","locations":[{"start":{"line":601,"column":46},"end":{"line":601,"column":50}},{"start":{"line":601,"column":50},"end":{"line":601,"column":52}}]},"132":{"loc":{"start":{"line":601,"column":26},"end":{"line":601,"column":50}},"type":"binary-expr","locations":[{"start":{"line":601,"column":26},"end":{"line":601,"column":50}},{"start":{"line":601,"column":46},"end":{"line":601,"column":50}}]},"133":{"loc":{"start":{"line":601,"column":26},"end":{"line":601,"column":46}},"type":"cond-expr","locations":[{"start":{"line":601,"column":34},"end":{"line":601,"column":36}},{"start":{"line":601,"column":34},"end":{"line":601,"column":46}}]},"134":{"loc":{"start":{"line":601,"column":26},"end":{"line":601,"column":36}},"type":"binary-expr","locations":[{"start":{"line":601,"column":26},"end":{"line":601,"column":36}},{"start":{"line":601,"column":34},"end":{"line":601,"column":36}}]},"135":{"loc":{"start":{"line":603,"column":6},"end":{"line":603,"column":35}},"type":"cond-expr","locations":[{"start":{"line":603,"column":25},"end":{"line":603,"column":27}},{"start":{"line":603,"column":25},"end":{"line":603,"column":35}}]},"136":{"loc":{"start":{"line":603,"column":6},"end":{"line":603,"column":27}},"type":"binary-expr","locations":[{"start":{"line":603,"column":6},"end":{"line":603,"column":27}},{"start":{"line":603,"column":25},"end":{"line":603,"column":27}}]},"137":{"loc":{"start":{"line":604,"column":6},"end":{"line":604,"column":33}},"type":"cond-expr","locations":[{"start":{"line":604,"column":25},"end":{"line":604,"column":27}},{"start":{"line":604,"column":25},"end":{"line":604,"column":33}}]},"138":{"loc":{"start":{"line":604,"column":6},"end":{"line":604,"column":27}},"type":"binary-expr","locations":[{"start":{"line":604,"column":6},"end":{"line":604,"column":27}},{"start":{"line":604,"column":25},"end":{"line":604,"column":27}}]},"139":{"loc":{"start":{"line":606,"column":51},"end":{"line":606,"column":66}},"type":"cond-expr","locations":[{"start":{"line":606,"column":51},"end":{"line":606,"column":60}},{"start":{"line":606,"column":64},"end":{"line":606,"column":66}}]},"140":{"loc":{"start":{"line":606,"column":51},"end":{"line":606,"column":64}},"type":"binary-expr","locations":[{"start":{"line":606,"column":51},"end":{"line":606,"column":64}},{"start":{"line":606,"column":51},"end":{"line":606,"column":64}}]},"141":{"loc":{"start":{"line":608,"column":8},"end":{"line":611,"column":9}},"type":"if","locations":[{"start":{"line":608,"column":8},"end":{"line":611,"column":9}},{"start":{},"end":{}}]},"142":{"loc":{"start":{"line":610,"column":34},"end":{"line":610,"column":69}},"type":"binary-expr","locations":[{"start":{"line":610,"column":34},"end":{"line":610,"column":64}},{"start":{"line":610,"column":68},"end":{"line":610,"column":69}}]},"143":{"loc":{"start":{"line":615,"column":22},"end":{"line":615,"column":57}},"type":"cond-expr","locations":[{"start":{"line":615,"column":51},"end":{"line":615,"column":55}},{"start":{"line":615,"column":55},"end":{"line":615,"column":57}}]},"144":{"loc":{"start":{"line":615,"column":22},"end":{"line":615,"column":55}},"type":"binary-expr","locations":[{"start":{"line":615,"column":22},"end":{"line":615,"column":55}},{"start":{"line":615,"column":51},"end":{"line":615,"column":55}}]},"145":{"loc":{"start":{"line":615,"column":22},"end":{"line":615,"column":51}},"type":"cond-expr","locations":[{"start":{"line":615,"column":32},"end":{"line":615,"column":34}},{"start":{"line":615,"column":32},"end":{"line":615,"column":51}}]},"146":{"loc":{"start":{"line":615,"column":22},"end":{"line":615,"column":34}},"type":"binary-expr","locations":[{"start":{"line":615,"column":22},"end":{"line":615,"column":34}},{"start":{"line":615,"column":32},"end":{"line":615,"column":34}}]},"147":{"loc":{"start":{"line":618,"column":21},"end":{"line":618,"column":50}},"type":"cond-expr","locations":[{"start":{"line":618,"column":38},"end":{"line":618,"column":40}},{"start":{"line":618,"column":38},"end":{"line":618,"column":50}}]},"148":{"loc":{"start":{"line":618,"column":21},"end":{"line":618,"column":40}},"type":"binary-expr","locations":[{"start":{"line":618,"column":21},"end":{"line":618,"column":40}},{"start":{"line":618,"column":38},"end":{"line":618,"column":40}}]},"149":{"loc":{"start":{"line":618,"column":21},"end":{"line":618,"column":38}},"type":"cond-expr","locations":[{"start":{"line":618,"column":31},"end":{"line":618,"column":33}},{"start":{"line":618,"column":21},"end":{"line":618,"column":38}}]},"150":{"loc":{"start":{"line":618,"column":21},"end":{"line":618,"column":33}},"type":"binary-expr","locations":[{"start":{"line":618,"column":21},"end":{"line":618,"column":33}},{"start":{"line":618,"column":21},"end":{"line":618,"column":33}}]},"151":{"loc":{"start":{"line":619,"column":17},"end":{"line":621,"column":38}},"type":"cond-expr","locations":[{"start":{"line":620,"column":6},"end":{"line":620,"column":33}},{"start":{"line":621,"column":7},"end":{"line":621,"column":37}}]},"152":{"loc":{"start":{"line":621,"column":7},"end":{"line":621,"column":37}},"type":"cond-expr","locations":[{"start":{"line":621,"column":24},"end":{"line":621,"column":28}},{"start":{"line":621,"column":28},"end":{"line":621,"column":37}}]},"153":{"loc":{"start":{"line":621,"column":7},"end":{"line":621,"column":28}},"type":"binary-expr","locations":[{"start":{"line":621,"column":7},"end":{"line":621,"column":28}},{"start":{"line":621,"column":24},"end":{"line":621,"column":28}}]},"154":{"loc":{"start":{"line":621,"column":7},"end":{"line":621,"column":24}},"type":"cond-expr","locations":[{"start":{"line":621,"column":17},"end":{"line":621,"column":19}},{"start":{"line":621,"column":17},"end":{"line":621,"column":24}}]},"155":{"loc":{"start":{"line":621,"column":7},"end":{"line":621,"column":19}},"type":"binary-expr","locations":[{"start":{"line":621,"column":7},"end":{"line":621,"column":19}},{"start":{"line":621,"column":17},"end":{"line":621,"column":19}}]},"156":{"loc":{"start":{"line":624,"column":13},"end":{"line":624,"column":63}},"type":"binary-expr","locations":[{"start":{"line":624,"column":13},"end":{"line":624,"column":50}},{"start":{"line":624,"column":54},"end":{"line":624,"column":63}}]},"157":{"loc":{"start":{"line":625,"column":27},"end":{"line":625,"column":37}},"type":"binary-expr","locations":[{"start":{"line":625,"column":27},"end":{"line":625,"column":32}},{"start":{"line":625,"column":36},"end":{"line":625,"column":37}}]},"158":{"loc":{"start":{"line":631,"column":2},"end":{"line":631,"column":null}},"type":"if","locations":[{"start":{"line":631,"column":2},"end":{"line":631,"column":null}},{"start":{},"end":{}}]},"159":{"loc":{"start":{"line":633,"column":2},"end":{"line":635,"column":3}},"type":"if","locations":[{"start":{"line":633,"column":2},"end":{"line":635,"column":3}},{"start":{},"end":{}}]},"160":{"loc":{"start":{"line":636,"column":20},"end":{"line":636,"column":46}},"type":"cond-expr","locations":[{"start":{"line":636,"column":40},"end":{"line":636,"column":44}},{"start":{"line":636,"column":44},"end":{"line":636,"column":46}}]},"161":{"loc":{"start":{"line":636,"column":20},"end":{"line":636,"column":44}},"type":"binary-expr","locations":[{"start":{"line":636,"column":20},"end":{"line":636,"column":44}},{"start":{"line":636,"column":40},"end":{"line":636,"column":44}}]},"162":{"loc":{"start":{"line":638,"column":2},"end":{"line":640,"column":3}},"type":"if","locations":[{"start":{"line":638,"column":2},"end":{"line":640,"column":3}},{"start":{},"end":{}}]},"163":{"loc":{"start":{"line":647,"column":18},"end":{"line":647,"column":36}},"type":"cond-expr","locations":[{"start":{"line":647,"column":30},"end":{"line":647,"column":32}},{"start":{"line":647,"column":30},"end":{"line":647,"column":36}}]},"164":{"loc":{"start":{"line":647,"column":18},"end":{"line":647,"column":32}},"type":"binary-expr","locations":[{"start":{"line":647,"column":18},"end":{"line":647,"column":32}},{"start":{"line":647,"column":30},"end":{"line":647,"column":32}}]},"165":{"loc":{"start":{"line":648,"column":2},"end":{"line":650,"column":3}},"type":"if","locations":[{"start":{"line":648,"column":2},"end":{"line":650,"column":3}},{"start":{},"end":{}}]},"166":{"loc":{"start":{"line":651,"column":22},"end":{"line":651,"column":57}},"type":"cond-expr","locations":[{"start":{"line":651,"column":51},"end":{"line":651,"column":55}},{"start":{"line":651,"column":55},"end":{"line":651,"column":57}}]},"167":{"loc":{"start":{"line":651,"column":22},"end":{"line":651,"column":55}},"type":"binary-expr","locations":[{"start":{"line":651,"column":22},"end":{"line":651,"column":55}},{"start":{"line":651,"column":51},"end":{"line":651,"column":55}}]},"168":{"loc":{"start":{"line":651,"column":22},"end":{"line":651,"column":51}},"type":"cond-expr","locations":[{"start":{"line":651,"column":32},"end":{"line":651,"column":34}},{"start":{"line":651,"column":32},"end":{"line":651,"column":51}}]},"169":{"loc":{"start":{"line":651,"column":22},"end":{"line":651,"column":34}},"type":"binary-expr","locations":[{"start":{"line":651,"column":22},"end":{"line":651,"column":34}},{"start":{"line":651,"column":32},"end":{"line":651,"column":34}}]},"170":{"loc":{"start":{"line":654,"column":28},"end":{"line":654,"column":66}},"type":"cond-expr","locations":[{"start":{"line":654,"column":57},"end":{"line":654,"column":59}},{"start":{"line":654,"column":57},"end":{"line":654,"column":66}}]},"171":{"loc":{"start":{"line":654,"column":28},"end":{"line":654,"column":59}},"type":"binary-expr","locations":[{"start":{"line":654,"column":28},"end":{"line":654,"column":59}},{"start":{"line":654,"column":57},"end":{"line":654,"column":59}}]},"172":{"loc":{"start":{"line":654,"column":28},"end":{"line":654,"column":57}},"type":"cond-expr","locations":[{"start":{"line":654,"column":45},"end":{"line":654,"column":47}},{"start":{"line":654,"column":45},"end":{"line":654,"column":57}}]},"173":{"loc":{"start":{"line":654,"column":28},"end":{"line":654,"column":47}},"type":"binary-expr","locations":[{"start":{"line":654,"column":28},"end":{"line":654,"column":47}},{"start":{"line":654,"column":45},"end":{"line":654,"column":47}}]},"174":{"loc":{"start":{"line":654,"column":28},"end":{"line":654,"column":45}},"type":"cond-expr","locations":[{"start":{"line":654,"column":38},"end":{"line":654,"column":40}},{"start":{"line":654,"column":28},"end":{"line":654,"column":45}}]},"175":{"loc":{"start":{"line":654,"column":28},"end":{"line":654,"column":40}},"type":"binary-expr","locations":[{"start":{"line":654,"column":28},"end":{"line":654,"column":40}},{"start":{"line":654,"column":28},"end":{"line":654,"column":40}}]},"176":{"loc":{"start":{"line":655,"column":2},"end":{"line":657,"column":3}},"type":"if","locations":[{"start":{"line":655,"column":2},"end":{"line":657,"column":3}},{"start":{},"end":{}}]},"177":{"loc":{"start":{"line":658,"column":2},"end":{"line":660,"column":3}},"type":"if","locations":[{"start":{"line":658,"column":2},"end":{"line":660,"column":3}},{"start":{},"end":{}}]},"178":{"loc":{"start":{"line":658,"column":7},"end":{"line":658,"column":33}},"type":"cond-expr","locations":[{"start":{"line":658,"column":24},"end":{"line":658,"column":26}},{"start":{"line":658,"column":24},"end":{"line":658,"column":33}}]},"179":{"loc":{"start":{"line":658,"column":7},"end":{"line":658,"column":26}},"type":"binary-expr","locations":[{"start":{"line":658,"column":7},"end":{"line":658,"column":26}},{"start":{"line":658,"column":24},"end":{"line":658,"column":26}}]},"180":{"loc":{"start":{"line":658,"column":7},"end":{"line":658,"column":24}},"type":"cond-expr","locations":[{"start":{"line":658,"column":17},"end":{"line":658,"column":19}},{"start":{"line":658,"column":7},"end":{"line":658,"column":24}}]},"181":{"loc":{"start":{"line":658,"column":7},"end":{"line":658,"column":19}},"type":"binary-expr","locations":[{"start":{"line":658,"column":7},"end":{"line":658,"column":19}},{"start":{"line":658,"column":7},"end":{"line":658,"column":19}}]},"182":{"loc":{"start":{"line":696,"column":17},"end":{"line":696,"column":null}},"type":"switch","locations":[{"start":{"line":696,"column":17},"end":{"line":696,"column":null}}]},"183":{"loc":{"start":{"line":671,"column":2},"end":{"line":673,"column":3}},"type":"if","locations":[{"start":{"line":671,"column":2},"end":{"line":673,"column":3}},{"start":{},"end":{}}]},"184":{"loc":{"start":{"line":682,"column":11},"end":{"line":682,"column":56}},"type":"binary-expr","locations":[{"start":{"line":682,"column":11},"end":{"line":682,"column":29}},{"start":{"line":682,"column":33},"end":{"line":682,"column":56}}]},"185":{"loc":{"start":{"line":682,"column":11},"end":{"line":682,"column":29}},"type":"cond-expr","locations":[{"start":{"line":682,"column":23},"end":{"line":682,"column":25}},{"start":{"line":682,"column":23},"end":{"line":682,"column":29}}]},"186":{"loc":{"start":{"line":682,"column":11},"end":{"line":682,"column":25}},"type":"binary-expr","locations":[{"start":{"line":682,"column":11},"end":{"line":682,"column":25}},{"start":{"line":682,"column":23},"end":{"line":682,"column":25}}]},"187":{"loc":{"start":{"line":684,"column":2},"end":{"line":686,"column":3}},"type":"if","locations":[{"start":{"line":684,"column":2},"end":{"line":686,"column":3}},{"start":{},"end":{}}]},"188":{"loc":{"start":{"line":697,"column":2},"end":{"line":702,"column":3}},"type":"if","locations":[{"start":{"line":697,"column":2},"end":{"line":702,"column":3}},{"start":{},"end":{}}]},"189":{"loc":{"start":{"line":704,"column":20},"end":{"line":704,"column":null}},"type":"if","locations":[{"start":{"line":704,"column":20},"end":{"line":704,"column":null}},{"start":{},"end":{}}]},"190":{"loc":{"start":{"line":705,"column":20},"end":{"line":705,"column":48}},"type":"cond-expr","locations":[{"start":{"line":705,"column":32},"end":{"line":705,"column":34}},{"start":{"line":705,"column":32},"end":{"line":705,"column":48}}]},"191":{"loc":{"start":{"line":705,"column":20},"end":{"line":705,"column":34}},"type":"binary-expr","locations":[{"start":{"line":705,"column":20},"end":{"line":705,"column":34}},{"start":{"line":705,"column":32},"end":{"line":705,"column":34}}]},"192":{"loc":{"start":{"line":722,"column":18},"end":{"line":722,"column":null}},"type":"switch","locations":[{"start":{"line":722,"column":18},"end":{"line":722,"column":null}}]},"193":{"loc":{"start":{"line":723,"column":2},"end":{"line":726,"column":3}},"type":"if","locations":[{"start":{"line":723,"column":2},"end":{"line":726,"column":3}},{"start":{},"end":{}}]},"194":{"loc":{"start":{"line":723,"column":6},"end":{"line":723,"column":39}},"type":"binary-expr","locations":[{"start":{"line":723,"column":6},"end":{"line":723,"column":14}},{"start":{"line":723,"column":18},"end":{"line":723,"column":39}}]},"195":{"loc":{"start":{"line":735,"column":11},"end":{"line":735,"column":42}},"type":"cond-expr","locations":[{"start":{"line":735,"column":36},"end":{"line":735,"column":40}},{"start":{"line":735,"column":40},"end":{"line":735,"column":42}}]},"196":{"loc":{"start":{"line":735,"column":11},"end":{"line":735,"column":40}},"type":"binary-expr","locations":[{"start":{"line":735,"column":11},"end":{"line":735,"column":40}},{"start":{"line":735,"column":36},"end":{"line":735,"column":40}}]}},"s":{"0":9,"1":9,"2":9,"3":9,"4":9,"5":9,"6":9,"7":9,"8":9,"9":9,"10":9,"11":9,"12":9,"13":9,"14":9,"15":9,"16":9,"17":9,"18":9,"19":9,"20":9,"21":9,"22":9,"23":9,"24":9,"25":9,"26":9,"27":9,"28":9,"29":9,"30":9,"31":9,"32":9,"33":9,"34":9,"35":9,"36":9,"37":9,"38":9,"39":9,"40":9,"41":9,"42":9,"43":9,"44":9,"45":9,"46":9,"47":9,"48":9,"49":128,"50":64,"51":0,"52":0,"53":0,"54":0,"55":0,"56":0,"57":0,"58":0,"59":0,"60":0,"61":0,"62":0,"63":0,"64":0,"65":0,"66":0,"67":0,"68":0,"69":22,"70":22,"71":44,"72":44,"73":44,"74":44,"75":44,"76":0,"77":0,"78":0,"79":22,"80":0,"81":0,"82":0,"83":0,"84":0,"85":9,"86":0,"87":0,"88":0,"89":0,"90":0,"91":0,"92":0,"93":0,"94":0,"95":0,"96":0,"97":0,"98":0,"99":0,"100":0,"101":0,"102":0,"103":0,"104":0,"105":0,"106":22,"107":0,"108":22,"109":22,"110":0,"111":0,"112":0,"113":0,"114":0,"115":0,"116":0,"117":0,"118":0,"119":0,"120":0,"121":0,"122":0,"123":0,"124":0,"125":0,"126":0,"127":0,"128":0,"129":0,"130":0,"131":0,"132":0,"133":0,"134":0,"135":0,"136":0,"137":0,"138":0,"139":0,"140":0,"141":0,"142":0,"143":0,"144":0,"145":0,"146":0,"147":0,"148":0,"149":0,"150":0,"151":9,"152":0,"153":0,"154":0,"155":0,"156":0,"157":0,"158":0,"159":0,"160":0,"161":0,"162":0,"163":0,"164":0,"165":0,"166":0,"167":0,"168":0,"169":0,"170":0,"171":0,"172":0,"173":0,"174":0,"175":0,"176":0,"177":21,"178":21,"179":0,"180":21,"181":21,"182":21,"183":0,"184":0,"185":21,"186":0,"187":0,"188":0,"189":0,"190":0,"191":0,"192":0,"193":0,"194":0,"195":0,"196":0,"197":0,"198":0,"199":0,"200":0,"201":0,"202":0,"203":0,"204":0,"205":0,"206":0,"207":0,"208":0,"209":0,"210":0,"211":0,"212":0,"213":0,"214":0,"215":0,"216":0,"217":0,"218":0,"219":0,"220":0,"221":0,"222":0,"223":0,"224":0,"225":0,"226":0,"227":0,"228":0,"229":0,"230":0,"231":0,"232":0,"233":0,"234":0,"235":0,"236":0,"237":0,"238":0,"239":0,"240":0,"241":0,"242":0,"243":0,"244":0,"245":0,"246":0,"247":0,"248":0,"249":0,"250":0,"251":0,"252":0,"253":0,"254":0,"255":0,"256":0,"257":0,"258":0,"259":0,"260":0,"261":0,"262":0,"263":0,"264":0,"265":0,"266":0,"267":0,"268":0,"269":0,"270":0,"271":0,"272":0,"273":0,"274":0,"275":0,"276":0,"277":0,"278":0,"279":0,"280":0,"281":0,"282":0,"283":0,"284":0,"285":0,"286":0,"287":0,"288":0,"289":0,"290":0,"291":0,"292":0,"293":0,"294":0,"295":0,"296":0,"297":0,"298":0,"299":0,"300":0,"301":0,"302":0,"303":0,"304":0,"305":0,"306":0,"307":0,"308":0,"309":0,"310":21,"311":0,"312":21,"313":21,"314":21,"315":21,"316":21,"317":0,"318":0,"319":0,"320":0,"321":0,"322":0,"323":0,"324":0,"325":0,"326":0,"327":0,"328":0,"329":0,"330":0,"331":0,"332":0,"333":0,"334":0,"335":0,"336":0,"337":0,"338":0,"339":0,"340":0,"341":0,"342":0,"343":0,"344":0,"345":0,"346":0,"347":0,"348":0,"349":0},"f":{"0":64,"1":0,"2":0,"3":22,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":22,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0,"21":0,"22":0,"23":0,"24":0,"25":21,"26":21,"27":0,"28":21,"29":0,"30":0,"31":0,"32":0,"33":0,"34":0,"35":0,"36":0,"37":0,"38":0,"39":0,"40":0,"41":0,"42":0,"43":0,"44":0,"45":0,"46":0,"47":0,"48":21,"49":0,"50":0},"b":{"0":[64,0],"1":[0,64],"2":[64,64],"3":[0,0],"4":[0,0],"5":[0,0],"6":[0,0],"7":[0,0],"8":[0,0],"9":[0,0],"10":[0,0],"11":[22,0],"12":[22,22],"13":[22,0],"14":[22,22],"15":[0,44],"16":[44,44],"17":[0,0],"18":[0,0],"19":[0,0],"20":[0,0],"21":[0,0],"22":[0,0],"23":[0,0],"24":[0,0],"25":[0,0],"26":[0,0,0,0],"27":[0,0],"28":[0,0],"29":[0,0],"30":[0,0],"31":[0,0],"32":[0,0],"33":[0,0],"34":[0,0],"35":[0,0],"36":[0,0],"37":[0,0],"38":[0,0],"39":[0,0],"40":[0,0],"41":[0,0],"42":[0,0],"43":[0,0,0,0],"44":[0,0],"45":[0,0],"46":[0,0],"47":[0,0],"48":[0,0],"49":[0,0],"50":[0,0],"51":[0,0],"52":[0,22],"53":[22,0],"54":[0,0],"55":[0,0],"56":[0,0],"57":[0,0],"58":[0,0],"59":[0,0],"60":[0,0],"61":[0,0],"62":[0,0,0],"63":[0,0],"64":[0,0],"65":[0,0],"66":[0,0],"67":[0,0],"68":[0,0],"69":[0,0],"70":[0,0],"71":[0,0],"72":[0,0],"73":[0,0],"74":[0,0],"75":[21,21],"76":[0],"77":[0,0],"78":[0,0],"79":[0,0],"80":[0,0],"81":[0,0],"82":[0,0],"83":[0,0],"84":[0,0],"85":[0,0],"86":[0,0],"87":[0,0],"88":[0],"89":[0,0],"90":[0,0],"91":[0,0],"92":[0,0],"93":[0,0],"94":[0,0],"95":[0,0],"96":[0,0],"97":[0,0],"98":[0,0],"99":[0,0],"100":[0,0],"101":[0,0],"102":[0,0],"103":[0,0],"104":[0,0],"105":[0,0],"106":[0,0],"107":[0,0],"108":[0,0],"109":[0,0],"110":[0,0],"111":[0,0],"112":[0,0],"113":[0,0],"114":[0,0],"115":[0,0],"116":[0,0],"117":[0,0],"118":[0,0],"119":[0,0],"120":[0,0],"121":[0,0],"122":[0,0],"123":[0,0],"124":[0,0],"125":[0,0],"126":[0,0],"127":[0,0],"128":[0,0],"129":[0,0],"130":[0,0],"131":[0,0],"132":[0,0],"133":[0,0],"134":[0,0],"135":[0,0],"136":[0,0],"137":[0,0],"138":[0,0],"139":[0,0],"140":[0,0],"141":[0,0],"142":[0,0],"143":[0,0],"144":[0,0],"145":[0,0],"146":[0,0],"147":[0,0],"148":[0,0],"149":[0,0],"150":[0,0],"151":[0,0],"152":[0,0],"153":[0,0],"154":[0,0],"155":[0,0],"156":[0,0],"157":[0,0],"158":[0,0],"159":[0,0],"160":[0,0],"161":[0,0],"162":[0,0],"163":[0,0],"164":[0,0],"165":[0,0],"166":[0,0],"167":[0,0],"168":[0,0],"169":[0,0],"170":[0,0],"171":[0,0],"172":[0,0],"173":[0,0],"174":[0,0],"175":[0,0],"176":[0,0],"177":[0,0],"178":[0,0],"179":[0,0],"180":[0,0],"181":[0,0],"182":[0],"183":[0,21],"184":[0,0],"185":[0,0],"186":[0,0],"187":[0,0],"188":[0,0],"189":[0,0],"190":[0,0],"191":[0,0],"192":[0],"193":[0,0],"194":[0,0],"195":[0,0],"196":[0,0]}} +,"/__w/backlog/backlog/work/runner-container-hooks/packages/k8s/tests/test-setup.ts": {"path":"/__w/backlog/backlog/work/runner-container-hooks/packages/k8s/tests/test-setup.ts","statementMap":{"0":{"start":{"line":1,"column":0},"end":{"line":1,"column":46}},"1":{"start":{"line":2,"column":0},"end":{"line":2,"column":24}},"2":{"start":{"line":4,"column":0},"end":{"line":4,"column":28}},"3":{"start":{"line":5,"column":0},"end":{"line":5,"column":35}},"4":{"start":{"line":7,"column":11},"end":{"line":7,"column":31}},"5":{"start":{"line":9,"column":0},"end":{"line":9,"column":null}},"6":{"start":{"line":11,"column":15},"end":{"line":11,"column":46}},"7":{"start":{"line":13,"column":0},"end":{"line":13,"column":13}},"8":{"start":{"line":20,"column":4},"end":{"line":20,"column":null}},"9":{"start":{"line":21,"column":4},"end":{"line":21,"column":null}},"10":{"start":{"line":22,"column":4},"end":{"line":22,"column":null}},"11":{"start":{"line":23,"column":4},"end":{"line":23,"column":null}},"12":{"start":{"line":26,"column":8},"end":{"line":53,"column":null}},"13":{"start":{"line":27,"column":4},"end":{"line":27,"column":null}},"14":{"start":{"line":28,"column":4},"end":{"line":28,"column":null}},"15":{"start":{"line":29,"column":4},"end":{"line":29,"column":null}},"16":{"start":{"line":30,"column":4},"end":{"line":30,"column":null}},"17":{"start":{"line":31,"column":4},"end":{"line":31,"column":null}},"18":{"start":{"line":33,"column":4},"end":{"line":33,"column":null}},"19":{"start":{"line":34,"column":4},"end":{"line":34,"column":null}},"20":{"start":{"line":35,"column":4},"end":{"line":35,"column":null}},"21":{"start":{"line":36,"column":4},"end":{"line":36,"column":null}},"22":{"start":{"line":37,"column":4},"end":{"line":37,"column":null}},"23":{"start":{"line":38,"column":4},"end":{"line":40,"column":null}},"24":{"start":{"line":42,"column":4},"end":{"line":45,"column":null}},"25":{"start":{"line":47,"column":4},"end":{"line":47,"column":null}},"26":{"start":{"line":49,"column":6},"end":{"line":49,"column":null}},"27":{"start":{"line":51,"column":6},"end":{"line":51,"column":null}},"28":{"start":{"line":55,"column":8},"end":{"line":62,"column":null}},"29":{"start":{"line":57,"column":6},"end":{"line":57,"column":null}},"30":{"start":{"line":58,"column":6},"end":{"line":58,"column":null}},"31":{"start":{"line":64,"column":8},"end":{"line":87,"column":null}},"32":{"start":{"line":65,"column":4},"end":{"line":75,"column":null}},"33":{"start":{"line":72,"column":8},"end":{"line":74,"column":9}},"34":{"start":{"line":73,"column":10},"end":{"line":73,"column":null}},"35":{"start":{"line":76,"column":4},"end":{"line":86,"column":null}},"36":{"start":{"line":83,"column":8},"end":{"line":85,"column":9}},"37":{"start":{"line":84,"column":10},"end":{"line":84,"column":null}},"38":{"start":{"line":88,"column":2},"end":{"line":92,"column":null}},"39":{"start":{"line":89,"column":21},"end":{"line":89,"column":66}},"40":{"start":{"line":90,"column":4},"end":{"line":90,"column":null}},"41":{"start":{"line":91,"column":4},"end":{"line":91,"column":null}},"42":{"start":{"line":94,"column":2},"end":{"line":97,"column":null}},"43":{"start":{"line":95,"column":21},"end":{"line":95,"column":54}},"44":{"start":{"line":96,"column":4},"end":{"line":96,"column":null}},"45":{"start":{"line":99,"column":8},"end":{"line":121,"column":null}},"46":{"start":{"line":100,"column":10},"end":{"line":104,"column":null}},"47":{"start":{"line":106,"column":10},"end":{"line":119,"column":null}},"48":{"start":{"line":120,"column":4},"end":{"line":120,"column":null}},"49":{"start":{"line":123,"column":2},"end":{"line":138,"column":null}},"50":{"start":{"line":124,"column":23},"end":{"line":128,"column":null}},"51":{"start":{"line":131,"column":4},"end":{"line":131,"column":null}},"52":{"start":{"line":132,"column":4},"end":{"line":132,"column":null}},"53":{"start":{"line":133,"column":4},"end":{"line":135,"column":null}},"54":{"start":{"line":134,"column":6},"end":{"line":134,"column":null}},"55":{"start":{"line":137,"column":4},"end":{"line":137,"column":null}},"56":{"start":{"line":140,"column":2},"end":{"line":150,"column":null}},"57":{"start":{"line":141,"column":26},"end":{"line":145,"column":null}},"58":{"start":{"line":148,"column":4},"end":{"line":148,"column":null}},"59":{"start":{"line":149,"column":4},"end":{"line":149,"column":null}},"60":{"start":{"line":152,"column":2},"end":{"line":164,"column":null}},"61":{"start":{"line":153,"column":29},"end":{"line":157,"column":null}},"62":{"start":{"line":160,"column":4},"end":{"line":160,"column":null}},"63":{"start":{"line":161,"column":4},"end":{"line":161,"column":null}},"64":{"start":{"line":162,"column":4},"end":{"line":162,"column":null}},"65":{"start":{"line":163,"column":4},"end":{"line":163,"column":null}},"66":{"start":{"line":165,"column":0},"end":{"line":165,"column":null}},"67":{"start":{"line":13,"column":13},"end":{"line":13,"column":23}}},"fnMap":{"0":{"name":"(anonymous_22)","decl":{"start":{"line":13,"column":0},"end":{"line":13,"column":13}},"loc":{"start":{"line":13,"column":0},"end":{"line":165,"column":1}}},"1":{"name":"TestHelper","decl":{"start":{"line":19,"column":2},"end":{"line":19,"column":null}},"loc":{"start":{"line":19,"column":2},"end":{"line":24,"column":3}}},"2":{"name":"(anonymous_24)","decl":{"start":{"line":26,"column":2},"end":{"line":26,"column":8}},"loc":{"start":{"line":26,"column":2},"end":{"line":53,"column":null}}},"3":{"name":"(anonymous_27)","decl":{"start":{"line":55,"column":2},"end":{"line":55,"column":8}},"loc":{"start":{"line":55,"column":2},"end":{"line":62,"column":null}}},"4":{"name":"(anonymous_30)","decl":{"start":{"line":64,"column":2},"end":{"line":64,"column":8}},"loc":{"start":{"line":64,"column":2},"end":{"line":87,"column":null}}},"5":{"name":"(anonymous_33)","decl":{"start":{"line":71,"column":13},"end":{"line":71,"column":14}},"loc":{"start":{"line":71,"column":38},"end":{"line":75,"column":7}}},"6":{"name":"(anonymous_34)","decl":{"start":{"line":82,"column":13},"end":{"line":82,"column":14}},"loc":{"start":{"line":82,"column":38},"end":{"line":86,"column":7}}},"7":{"name":"(anonymous_35)","decl":{"start":{"line":88,"column":2},"end":{"line":88,"column":12}},"loc":{"start":{"line":88,"column":30},"end":{"line":92,"column":3}}},"8":{"name":"(anonymous_36)","decl":{"start":{"line":94,"column":2},"end":{"line":94,"column":12}},"loc":{"start":{"line":94,"column":29},"end":{"line":97,"column":3}}},"9":{"name":"(anonymous_37)","decl":{"start":{"line":99,"column":2},"end":{"line":99,"column":8}},"loc":{"start":{"line":99,"column":2},"end":{"line":121,"column":null}}},"10":{"name":"(anonymous_40)","decl":{"start":{"line":123,"column":2},"end":{"line":123,"column":25}},"loc":{"start":{"line":123,"column":2},"end":{"line":138,"column":3}}},"11":{"name":"(anonymous_41)","decl":{"start":{"line":133,"column":37},"end":{"line":133,"column":38}},"loc":{"start":{"line":133,"column":38},"end":{"line":135,"column":5}}},"12":{"name":"(anonymous_42)","decl":{"start":{"line":140,"column":2},"end":{"line":140,"column":28}},"loc":{"start":{"line":140,"column":2},"end":{"line":150,"column":3}}},"13":{"name":"(anonymous_43)","decl":{"start":{"line":152,"column":2},"end":{"line":152,"column":31}},"loc":{"start":{"line":152,"column":2},"end":{"line":164,"column":3}}}},"branchMap":{"0":{"loc":{"start":{"line":65,"column":4},"end":{"line":75,"column":null}},"type":"switch","locations":[{"start":{"line":65,"column":4},"end":{"line":75,"column":null}}]},"1":{"loc":{"start":{"line":72,"column":8},"end":{"line":74,"column":9}},"type":"if","locations":[{"start":{"line":72,"column":8},"end":{"line":74,"column":9}},{"start":{},"end":{}}]},"2":{"loc":{"start":{"line":83,"column":8},"end":{"line":85,"column":9}},"type":"if","locations":[{"start":{"line":83,"column":8},"end":{"line":85,"column":9}},{"start":{},"end":{}}]},"3":{"loc":{"start":{"line":89,"column":44},"end":{"line":89,"column":64}},"type":"binary-expr","locations":[{"start":{"line":89,"column":44},"end":{"line":89,"column":52}},{"start":{"line":89,"column":56},"end":{"line":89,"column":64}}]}},"s":{"0":6,"1":6,"2":6,"3":6,"4":6,"5":6,"6":6,"7":6,"8":46,"9":46,"10":46,"11":46,"12":6,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0,"21":0,"22":0,"23":0,"24":0,"25":0,"26":0,"27":0,"28":6,"29":0,"30":0,"31":6,"32":0,"33":0,"34":0,"35":0,"36":0,"37":0,"38":6,"39":0,"40":0,"41":0,"42":6,"43":0,"44":0,"45":6,"46":0,"47":0,"48":0,"49":6,"50":0,"51":0,"52":0,"53":0,"54":0,"55":0,"56":6,"57":0,"58":0,"59":0,"60":6,"61":0,"62":0,"63":0,"64":0,"65":0,"66":6,"67":6},"f":{"0":6,"1":46,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0},"b":{"0":[0],"1":[0,0],"2":[0,0],"3":[0,0]}} +} diff --git a/packages/k8s/coverage/lcov-report/base.css b/packages/k8s/coverage/lcov-report/base.css new file mode 100644 index 00000000..f418035b --- /dev/null +++ b/packages/k8s/coverage/lcov-report/base.css @@ -0,0 +1,224 @@ +body, html { + margin:0; padding: 0; + height: 100%; +} +body { + font-family: Helvetica Neue, Helvetica, Arial; + font-size: 14px; + color:#333; +} +.small { font-size: 12px; } +*, *:after, *:before { + -webkit-box-sizing:border-box; + -moz-box-sizing:border-box; + box-sizing:border-box; + } +h1 { font-size: 20px; margin: 0;} +h2 { font-size: 14px; } +pre { + font: 12px/1.4 Consolas, "Liberation Mono", Menlo, Courier, monospace; + margin: 0; + padding: 0; + -moz-tab-size: 2; + -o-tab-size: 2; + tab-size: 2; +} +a { color:#0074D9; text-decoration:none; } +a:hover { text-decoration:underline; } +.strong { font-weight: bold; } +.space-top1 { padding: 10px 0 0 0; } +.pad2y { padding: 20px 0; } +.pad1y { padding: 10px 0; } +.pad2x { padding: 0 20px; } +.pad2 { padding: 20px; } +.pad1 { padding: 10px; } +.space-left2 { padding-left:55px; } +.space-right2 { padding-right:20px; } +.center { text-align:center; } +.clearfix { display:block; } +.clearfix:after { + content:''; + display:block; + height:0; + clear:both; + visibility:hidden; + } +.fl { float: left; } +@media only screen and (max-width:640px) { + .col3 { width:100%; max-width:100%; } + .hide-mobile { display:none!important; } +} + +.quiet { + color: #7f7f7f; + color: rgba(0,0,0,0.5); +} +.quiet a { opacity: 0.7; } + +.fraction { + font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; + font-size: 10px; + color: #555; + background: #E8E8E8; + padding: 4px 5px; + border-radius: 3px; + vertical-align: middle; +} + +div.path a:link, div.path a:visited { color: #333; } +table.coverage { + border-collapse: collapse; + margin: 10px 0 0 0; + padding: 0; +} + +table.coverage td { + margin: 0; + padding: 0; + vertical-align: top; +} +table.coverage td.line-count { + text-align: right; + padding: 0 5px 0 20px; +} +table.coverage td.line-coverage { + text-align: right; + padding-right: 10px; + min-width:20px; +} + +table.coverage td span.cline-any { + display: inline-block; + padding: 0 5px; + width: 100%; +} +.missing-if-branch { + display: inline-block; + margin-right: 5px; + border-radius: 3px; + position: relative; + padding: 0 4px; + background: #333; + color: yellow; +} + +.skip-if-branch { + display: none; + margin-right: 10px; + position: relative; + padding: 0 4px; + background: #ccc; + color: white; +} +.missing-if-branch .typ, .skip-if-branch .typ { + color: inherit !important; +} +.coverage-summary { + border-collapse: collapse; + width: 100%; +} +.coverage-summary tr { border-bottom: 1px solid #bbb; } +.keyline-all { border: 1px solid #ddd; } +.coverage-summary td, .coverage-summary th { padding: 10px; } +.coverage-summary tbody { border: 1px solid #bbb; } +.coverage-summary td { border-right: 1px solid #bbb; } +.coverage-summary td:last-child { border-right: none; } +.coverage-summary th { + text-align: left; + font-weight: normal; + white-space: nowrap; +} +.coverage-summary th.file { border-right: none !important; } +.coverage-summary th.pct { } +.coverage-summary th.pic, +.coverage-summary th.abs, +.coverage-summary td.pct, +.coverage-summary td.abs { text-align: right; } +.coverage-summary td.file { white-space: nowrap; } +.coverage-summary td.pic { min-width: 120px !important; } +.coverage-summary tfoot td { } + +.coverage-summary .sorter { + height: 10px; + width: 7px; + display: inline-block; + margin-left: 0.5em; + background: url(sort-arrow-sprite.png) no-repeat scroll 0 0 transparent; +} +.coverage-summary .sorted .sorter { + background-position: 0 -20px; +} +.coverage-summary .sorted-desc .sorter { + background-position: 0 -10px; +} +.status-line { height: 10px; } +/* yellow */ +.cbranch-no { background: yellow !important; color: #111; } +/* dark red */ +.red.solid, .status-line.low, .low .cover-fill { background:#C21F39 } +.low .chart { border:1px solid #C21F39 } +.highlighted, +.highlighted .cstat-no, .highlighted .fstat-no, .highlighted .cbranch-no{ + background: #C21F39 !important; +} +/* medium red */ +.cstat-no, .fstat-no, .cbranch-no, .cbranch-no { background:#F6C6CE } +/* light red */ +.low, .cline-no { background:#FCE1E5 } +/* light green */ +.high, .cline-yes { background:rgb(230,245,208) } +/* medium green */ +.cstat-yes { background:rgb(161,215,106) } +/* dark green */ +.status-line.high, .high .cover-fill { background:rgb(77,146,33) } +.high .chart { border:1px solid rgb(77,146,33) } +/* dark yellow (gold) */ +.status-line.medium, .medium .cover-fill { background: #f9cd0b; } +.medium .chart { border:1px solid #f9cd0b; } +/* light yellow */ +.medium { background: #fff4c2; } + +.cstat-skip { background: #ddd; color: #111; } +.fstat-skip { background: #ddd; color: #111 !important; } +.cbranch-skip { background: #ddd !important; color: #111; } + +span.cline-neutral { background: #eaeaea; } + +.coverage-summary td.empty { + opacity: .5; + padding-top: 4px; + padding-bottom: 4px; + line-height: 1; + color: #888; +} + +.cover-fill, .cover-empty { + display:inline-block; + height: 12px; +} +.chart { + line-height: 0; +} +.cover-empty { + background: white; +} +.cover-full { + border-right: none !important; +} +pre.prettyprint { + border: none !important; + padding: 0 !important; + margin: 0 !important; +} +.com { color: #999 !important; } +.ignore-none { color: #999; font-weight: normal; } + +.wrapper { + min-height: 100%; + height: auto !important; + height: 100%; + margin: 0 auto -48px; +} +.footer, .push { + height: 48px; +} diff --git a/packages/k8s/coverage/lcov-report/block-navigation.js b/packages/k8s/coverage/lcov-report/block-navigation.js new file mode 100644 index 00000000..530d1ed2 --- /dev/null +++ b/packages/k8s/coverage/lcov-report/block-navigation.js @@ -0,0 +1,87 @@ +/* eslint-disable */ +var jumpToCode = (function init() { + // Classes of code we would like to highlight in the file view + var missingCoverageClasses = ['.cbranch-no', '.cstat-no', '.fstat-no']; + + // Elements to highlight in the file listing view + var fileListingElements = ['td.pct.low']; + + // We don't want to select elements that are direct descendants of another match + var notSelector = ':not(' + missingCoverageClasses.join('):not(') + ') > '; // becomes `:not(a):not(b) > ` + + // Selector that finds elements on the page to which we can jump + var selector = + fileListingElements.join(', ') + + ', ' + + notSelector + + missingCoverageClasses.join(', ' + notSelector); // becomes `:not(a):not(b) > a, :not(a):not(b) > b` + + // The NodeList of matching elements + var missingCoverageElements = document.querySelectorAll(selector); + + var currentIndex; + + function toggleClass(index) { + missingCoverageElements + .item(currentIndex) + .classList.remove('highlighted'); + missingCoverageElements.item(index).classList.add('highlighted'); + } + + function makeCurrent(index) { + toggleClass(index); + currentIndex = index; + missingCoverageElements.item(index).scrollIntoView({ + behavior: 'smooth', + block: 'center', + inline: 'center' + }); + } + + function goToPrevious() { + var nextIndex = 0; + if (typeof currentIndex !== 'number' || currentIndex === 0) { + nextIndex = missingCoverageElements.length - 1; + } else if (missingCoverageElements.length > 1) { + nextIndex = currentIndex - 1; + } + + makeCurrent(nextIndex); + } + + function goToNext() { + var nextIndex = 0; + + if ( + typeof currentIndex === 'number' && + currentIndex < missingCoverageElements.length - 1 + ) { + nextIndex = currentIndex + 1; + } + + makeCurrent(nextIndex); + } + + return function jump(event) { + if ( + document.getElementById('fileSearch') === document.activeElement && + document.activeElement != null + ) { + // if we're currently focused on the search input, we don't want to navigate + return; + } + + switch (event.which) { + case 78: // n + case 74: // j + goToNext(); + break; + case 66: // b + case 75: // k + case 80: // p + goToPrevious(); + break; + } + }; +})(); +window.addEventListener('keydown', jumpToCode); diff --git a/packages/k8s/coverage/lcov-report/favicon.png b/packages/k8s/coverage/lcov-report/favicon.png new file mode 100644 index 00000000..c1525b81 Binary files /dev/null and b/packages/k8s/coverage/lcov-report/favicon.png differ diff --git a/packages/k8s/coverage/lcov-report/index.html b/packages/k8s/coverage/lcov-report/index.html new file mode 100644 index 00000000..0ed37af4 --- /dev/null +++ b/packages/k8s/coverage/lcov-report/index.html @@ -0,0 +1,161 @@ + + + + + + Code coverage report for All files + + + + + + + + + +
+
+

All files

+
+ +
+ 50.57% + Statements + 923/1825 +
+ + +
+ 39.26% + Branches + 578/1472 +
+ + +
+ 42.62% + Functions + 104/244 +
+ + +
+ 52.11% + Lines + 849/1629 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
src/hooks +
+
70.5%251/35653.64%162/30280%24/3071.68%238/332
src/k8s +
+
53.94%472/87554.1%323/59747.69%62/13054.59%428/784
src/k8s/utils +
+
33.65%177/52616.43%93/56622.85%16/7036.09%161/446
tests +
+
33.82%23/680%0/714.28%2/1432.83%22/67
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/packages/k8s/coverage/lcov-report/prettify.css b/packages/k8s/coverage/lcov-report/prettify.css new file mode 100644 index 00000000..b317a7cd --- /dev/null +++ b/packages/k8s/coverage/lcov-report/prettify.css @@ -0,0 +1 @@ +.pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun,.opn,.clo{color:#660}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun,.opn,.clo{color:#440}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee} diff --git a/packages/k8s/coverage/lcov-report/prettify.js b/packages/k8s/coverage/lcov-report/prettify.js new file mode 100644 index 00000000..b3225238 --- /dev/null +++ b/packages/k8s/coverage/lcov-report/prettify.js @@ -0,0 +1,2 @@ +/* eslint-disable */ +window.PR_SHOULD_USE_CONTINUATION=true;(function(){var h=["break,continue,do,else,for,if,return,while"];var u=[h,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"];var p=[u,"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"];var l=[p,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"];var x=[p,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"];var R=[x,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"];var r="all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes";var w=[p,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"];var s="caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END";var I=[h,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"];var f=[h,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"];var H=[h,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"];var A=[l,R,w,s+I,f,H];var e=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/;var C="str";var z="kwd";var j="com";var O="typ";var G="lit";var L="pun";var F="pln";var m="tag";var E="dec";var J="src";var P="atn";var n="atv";var N="nocode";var M="(?:^^\\.?|[+-]|\\!|\\!=|\\!==|\\#|\\%|\\%=|&|&&|&&=|&=|\\(|\\*|\\*=|\\+=|\\,|\\-=|\\->|\\/|\\/=|:|::|\\;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|\\?|\\@|\\[|\\^|\\^=|\\^\\^|\\^\\^=|\\{|\\||\\|=|\\|\\||\\|\\|=|\\~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\\s*";function k(Z){var ad=0;var S=false;var ac=false;for(var V=0,U=Z.length;V122)){if(!(al<65||ag>90)){af.push([Math.max(65,ag)|32,Math.min(al,90)|32])}if(!(al<97||ag>122)){af.push([Math.max(97,ag)&~32,Math.min(al,122)&~32])}}}}af.sort(function(av,au){return(av[0]-au[0])||(au[1]-av[1])});var ai=[];var ap=[NaN,NaN];for(var ar=0;arat[0]){if(at[1]+1>at[0]){an.push("-")}an.push(T(at[1]))}}an.push("]");return an.join("")}function W(al){var aj=al.source.match(new RegExp("(?:\\[(?:[^\\x5C\\x5D]|\\\\[\\s\\S])*\\]|\\\\u[A-Fa-f0-9]{4}|\\\\x[A-Fa-f0-9]{2}|\\\\[0-9]+|\\\\[^ux0-9]|\\(\\?[:!=]|[\\(\\)\\^]|[^\\x5B\\x5C\\(\\)\\^]+)","g"));var ah=aj.length;var an=[];for(var ak=0,am=0;ak=2&&ai==="["){aj[ak]=X(ag)}else{if(ai!=="\\"){aj[ak]=ag.replace(/[a-zA-Z]/g,function(ao){var ap=ao.charCodeAt(0);return"["+String.fromCharCode(ap&~32,ap|32)+"]"})}}}}return aj.join("")}var aa=[];for(var V=0,U=Z.length;V=0;){S[ac.charAt(ae)]=Y}}var af=Y[1];var aa=""+af;if(!ag.hasOwnProperty(aa)){ah.push(af);ag[aa]=null}}ah.push(/[\0-\uffff]/);V=k(ah)})();var X=T.length;var W=function(ah){var Z=ah.sourceCode,Y=ah.basePos;var ad=[Y,F];var af=0;var an=Z.match(V)||[];var aj={};for(var ae=0,aq=an.length;ae=5&&"lang-"===ap.substring(0,5);if(am&&!(ai&&typeof ai[1]==="string")){am=false;ap=J}if(!am){aj[ag]=ap}}var ab=af;af+=ag.length;if(!am){ad.push(Y+ab,ap)}else{var al=ai[1];var ak=ag.indexOf(al);var ac=ak+al.length;if(ai[2]){ac=ag.length-ai[2].length;ak=ac-al.length}var ar=ap.substring(5);B(Y+ab,ag.substring(0,ak),W,ad);B(Y+ab+ak,al,q(ar,al),ad);B(Y+ab+ac,ag.substring(ac),W,ad)}}ah.decorations=ad};return W}function i(T){var W=[],S=[];if(T.tripleQuotedStrings){W.push([C,/^(?:\'\'\'(?:[^\'\\]|\\[\s\S]|\'{1,2}(?=[^\']))*(?:\'\'\'|$)|\"\"\"(?:[^\"\\]|\\[\s\S]|\"{1,2}(?=[^\"]))*(?:\"\"\"|$)|\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$))/,null,"'\""])}else{if(T.multiLineStrings){W.push([C,/^(?:\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$)|\`(?:[^\\\`]|\\[\s\S])*(?:\`|$))/,null,"'\"`"])}else{W.push([C,/^(?:\'(?:[^\\\'\r\n]|\\.)*(?:\'|$)|\"(?:[^\\\"\r\n]|\\.)*(?:\"|$))/,null,"\"'"])}}if(T.verbatimStrings){S.push([C,/^@\"(?:[^\"]|\"\")*(?:\"|$)/,null])}var Y=T.hashComments;if(Y){if(T.cStyleComments){if(Y>1){W.push([j,/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,null,"#"])}else{W.push([j,/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\r\n]*)/,null,"#"])}S.push([C,/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,null])}else{W.push([j,/^#[^\r\n]*/,null,"#"])}}if(T.cStyleComments){S.push([j,/^\/\/[^\r\n]*/,null]);S.push([j,/^\/\*[\s\S]*?(?:\*\/|$)/,null])}if(T.regexLiterals){var X=("/(?=[^/*])(?:[^/\\x5B\\x5C]|\\x5C[\\s\\S]|\\x5B(?:[^\\x5C\\x5D]|\\x5C[\\s\\S])*(?:\\x5D|$))+/");S.push(["lang-regex",new RegExp("^"+M+"("+X+")")])}var V=T.types;if(V){S.push([O,V])}var U=(""+T.keywords).replace(/^ | $/g,"");if(U.length){S.push([z,new RegExp("^(?:"+U.replace(/[\s,]+/g,"|")+")\\b"),null])}W.push([F,/^\s+/,null," \r\n\t\xA0"]);S.push([G,/^@[a-z_$][a-z_$@0-9]*/i,null],[O,/^(?:[@_]?[A-Z]+[a-z][A-Za-z_$@0-9]*|\w+_t\b)/,null],[F,/^[a-z_$][a-z_$@0-9]*/i,null],[G,new RegExp("^(?:0x[a-f0-9]+|(?:\\d(?:_\\d+)*\\d*(?:\\.\\d*)?|\\.\\d\\+)(?:e[+\\-]?\\d+)?)[a-z]*","i"),null,"0123456789"],[F,/^\\[\s\S]?/,null],[L,/^.[^\s\w\.$@\'\"\`\/\#\\]*/,null]);return g(W,S)}var K=i({keywords:A,hashComments:true,cStyleComments:true,multiLineStrings:true,regexLiterals:true});function Q(V,ag){var U=/(?:^|\s)nocode(?:\s|$)/;var ab=/\r\n?|\n/;var ac=V.ownerDocument;var S;if(V.currentStyle){S=V.currentStyle.whiteSpace}else{if(window.getComputedStyle){S=ac.defaultView.getComputedStyle(V,null).getPropertyValue("white-space")}}var Z=S&&"pre"===S.substring(0,3);var af=ac.createElement("LI");while(V.firstChild){af.appendChild(V.firstChild)}var W=[af];function ae(al){switch(al.nodeType){case 1:if(U.test(al.className)){break}if("BR"===al.nodeName){ad(al);if(al.parentNode){al.parentNode.removeChild(al)}}else{for(var an=al.firstChild;an;an=an.nextSibling){ae(an)}}break;case 3:case 4:if(Z){var am=al.nodeValue;var aj=am.match(ab);if(aj){var ai=am.substring(0,aj.index);al.nodeValue=ai;var ah=am.substring(aj.index+aj[0].length);if(ah){var ak=al.parentNode;ak.insertBefore(ac.createTextNode(ah),al.nextSibling)}ad(al);if(!ai){al.parentNode.removeChild(al)}}}break}}function ad(ak){while(!ak.nextSibling){ak=ak.parentNode;if(!ak){return}}function ai(al,ar){var aq=ar?al.cloneNode(false):al;var ao=al.parentNode;if(ao){var ap=ai(ao,1);var an=al.nextSibling;ap.appendChild(aq);for(var am=an;am;am=an){an=am.nextSibling;ap.appendChild(am)}}return aq}var ah=ai(ak.nextSibling,0);for(var aj;(aj=ah.parentNode)&&aj.nodeType===1;){ah=aj}W.push(ah)}for(var Y=0;Y=S){ah+=2}if(V>=ap){Z+=2}}}var t={};function c(U,V){for(var S=V.length;--S>=0;){var T=V[S];if(!t.hasOwnProperty(T)){t[T]=U}else{if(window.console){console.warn("cannot override language handler %s",T)}}}}function q(T,S){if(!(T&&t.hasOwnProperty(T))){T=/^\s*]*(?:>|$)/],[j,/^<\!--[\s\S]*?(?:-\->|$)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],[L,/^(?:<[%?]|[%?]>)/],["lang-",/^]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-js",/^]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]),["default-markup","htm","html","mxml","xhtml","xml","xsl"]);c(g([[F,/^[\s]+/,null," \t\r\n"],[n,/^(?:\"[^\"]*\"?|\'[^\']*\'?)/,null,"\"'"]],[[m,/^^<\/?[a-z](?:[\w.:-]*\w)?|\/?>$/i],[P,/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^>\'\"\s]*(?:[^>\'\"\s\/]|\/(?=\s)))/],[L,/^[=<>\/]+/],["lang-js",/^on\w+\s*=\s*\"([^\"]+)\"/i],["lang-js",/^on\w+\s*=\s*\'([^\']+)\'/i],["lang-js",/^on\w+\s*=\s*([^\"\'>\s]+)/i],["lang-css",/^style\s*=\s*\"([^\"]+)\"/i],["lang-css",/^style\s*=\s*\'([^\']+)\'/i],["lang-css",/^style\s*=\s*([^\"\'>\s]+)/i]]),["in.tag"]);c(g([],[[n,/^[\s\S]+/]]),["uq.val"]);c(i({keywords:l,hashComments:true,cStyleComments:true,types:e}),["c","cc","cpp","cxx","cyc","m"]);c(i({keywords:"null,true,false"}),["json"]);c(i({keywords:R,hashComments:true,cStyleComments:true,verbatimStrings:true,types:e}),["cs"]);c(i({keywords:x,cStyleComments:true}),["java"]);c(i({keywords:H,hashComments:true,multiLineStrings:true}),["bsh","csh","sh"]);c(i({keywords:I,hashComments:true,multiLineStrings:true,tripleQuotedStrings:true}),["cv","py"]);c(i({keywords:s,hashComments:true,multiLineStrings:true,regexLiterals:true}),["perl","pl","pm"]);c(i({keywords:f,hashComments:true,multiLineStrings:true,regexLiterals:true}),["rb"]);c(i({keywords:w,cStyleComments:true,regexLiterals:true}),["js"]);c(i({keywords:r,hashComments:3,cStyleComments:true,multilineStrings:true,tripleQuotedStrings:true,regexLiterals:true}),["coffee"]);c(g([],[[C,/^[\s\S]+/]]),["regex"]);function d(V){var U=V.langExtension;try{var S=a(V.sourceNode);var T=S.sourceCode;V.sourceCode=T;V.spans=S.spans;V.basePos=0;q(U,T)(V);D(V)}catch(W){if("console" in window){console.log(W&&W.stack?W.stack:W)}}}function y(W,V,U){var S=document.createElement("PRE");S.innerHTML=W;if(U){Q(S,U)}var T={langExtension:V,numberLines:U,sourceNode:S};d(T);return S.innerHTML}function b(ad){function Y(af){return document.getElementsByTagName(af)}var ac=[Y("pre"),Y("code"),Y("xmp")];var T=[];for(var aa=0;aa=0){var ah=ai.match(ab);var am;if(!ah&&(am=o(aj))&&"CODE"===am.tagName){ah=am.className.match(ab)}if(ah){ah=ah[1]}var al=false;for(var ak=aj.parentNode;ak;ak=ak.parentNode){if((ak.tagName==="pre"||ak.tagName==="code"||ak.tagName==="xmp")&&ak.className&&ak.className.indexOf("prettyprint")>=0){al=true;break}}if(!al){var af=aj.className.match(/\blinenums\b(?::(\d+))?/);af=af?af[1]&&af[1].length?+af[1]:true:false;if(af){Q(aj,af)}S={langExtension:ah,sourceNode:aj,numberLines:af};d(S)}}}if(X]*(?:>|$)/],[PR.PR_COMMENT,/^<\!--[\s\S]*?(?:-\->|$)/],[PR.PR_PUNCTUATION,/^(?:<[%?]|[%?]>)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],["lang-",/^]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-handlebars",/^]*type\s*=\s*['"]?text\/x-handlebars-template['"]?\b[^>]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-js",/^]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i],[PR.PR_DECLARATION,/^{{[#^>/]?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{&?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{{>?\s*[\w.][^}]*}}}/],[PR.PR_COMMENT,/^{{![^}]*}}/]]),["handlebars","hbs"]);PR.registerLangHandler(PR.createSimpleLexer([[PR.PR_PLAIN,/^[ \t\r\n\f]+/,null," \t\r\n\f"]],[[PR.PR_STRING,/^\"(?:[^\n\r\f\\\"]|\\(?:\r\n?|\n|\f)|\\[\s\S])*\"/,null],[PR.PR_STRING,/^\'(?:[^\n\r\f\\\']|\\(?:\r\n?|\n|\f)|\\[\s\S])*\'/,null],["lang-css-str",/^url\(([^\)\"\']*)\)/i],[PR.PR_KEYWORD,/^(?:url|rgb|\!important|@import|@page|@media|@charset|inherit)(?=[^\-\w]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|(?:\\[0-9a-f]+ ?))(?:[_a-z0-9\-]|\\(?:\\[0-9a-f]+ ?))*)\s*:/i],[PR.PR_COMMENT,/^\/\*[^*]*\*+(?:[^\/*][^*]*\*+)*\//],[PR.PR_COMMENT,/^(?:)/],[PR.PR_LITERAL,/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],[PR.PR_LITERAL,/^#(?:[0-9a-f]{3}){1,2}/i],[PR.PR_PLAIN,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i],[PR.PR_PUNCTUATION,/^[^\s\w\'\"]+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_KEYWORD,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_STRING,/^[^\)\"\']+/]]),["css-str"]); diff --git a/packages/k8s/coverage/lcov-report/sort-arrow-sprite.png b/packages/k8s/coverage/lcov-report/sort-arrow-sprite.png new file mode 100644 index 00000000..6ed68316 Binary files /dev/null and b/packages/k8s/coverage/lcov-report/sort-arrow-sprite.png differ diff --git a/packages/k8s/coverage/lcov-report/sorter.js b/packages/k8s/coverage/lcov-report/sorter.js new file mode 100644 index 00000000..4ed70ae5 --- /dev/null +++ b/packages/k8s/coverage/lcov-report/sorter.js @@ -0,0 +1,210 @@ +/* eslint-disable */ +var addSorting = (function() { + 'use strict'; + var cols, + currentSort = { + index: 0, + desc: false + }; + + // returns the summary table element + function getTable() { + return document.querySelector('.coverage-summary'); + } + // returns the thead element of the summary table + function getTableHeader() { + return getTable().querySelector('thead tr'); + } + // returns the tbody element of the summary table + function getTableBody() { + return getTable().querySelector('tbody'); + } + // returns the th element for nth column + function getNthColumn(n) { + return getTableHeader().querySelectorAll('th')[n]; + } + + function onFilterInput() { + const searchValue = document.getElementById('fileSearch').value; + const rows = document.getElementsByTagName('tbody')[0].children; + + // Try to create a RegExp from the searchValue. If it fails (invalid regex), + // it will be treated as a plain text search + let searchRegex; + try { + searchRegex = new RegExp(searchValue, 'i'); // 'i' for case-insensitive + } catch (error) { + searchRegex = null; + } + + for (let i = 0; i < rows.length; i++) { + const row = rows[i]; + let isMatch = false; + + if (searchRegex) { + // If a valid regex was created, use it for matching + isMatch = searchRegex.test(row.textContent); + } else { + // Otherwise, fall back to the original plain text search + isMatch = row.textContent + .toLowerCase() + .includes(searchValue.toLowerCase()); + } + + row.style.display = isMatch ? '' : 'none'; + } + } + + // loads the search box + function addSearchBox() { + var template = document.getElementById('filterTemplate'); + var templateClone = template.content.cloneNode(true); + templateClone.getElementById('fileSearch').oninput = onFilterInput; + template.parentElement.appendChild(templateClone); + } + + // loads all columns + function loadColumns() { + var colNodes = getTableHeader().querySelectorAll('th'), + colNode, + cols = [], + col, + i; + + for (i = 0; i < colNodes.length; i += 1) { + colNode = colNodes[i]; + col = { + key: colNode.getAttribute('data-col'), + sortable: !colNode.getAttribute('data-nosort'), + type: colNode.getAttribute('data-type') || 'string' + }; + cols.push(col); + if (col.sortable) { + col.defaultDescSort = col.type === 'number'; + colNode.innerHTML = + colNode.innerHTML + ''; + } + } + return cols; + } + // attaches a data attribute to every tr element with an object + // of data values keyed by column name + function loadRowData(tableRow) { + var tableCols = tableRow.querySelectorAll('td'), + colNode, + col, + data = {}, + i, + val; + for (i = 0; i < tableCols.length; i += 1) { + colNode = tableCols[i]; + col = cols[i]; + val = colNode.getAttribute('data-value'); + if (col.type === 'number') { + val = Number(val); + } + data[col.key] = val; + } + return data; + } + // loads all row data + function loadData() { + var rows = getTableBody().querySelectorAll('tr'), + i; + + for (i = 0; i < rows.length; i += 1) { + rows[i].data = loadRowData(rows[i]); + } + } + // sorts the table using the data for the ith column + function sortByIndex(index, desc) { + var key = cols[index].key, + sorter = function(a, b) { + a = a.data[key]; + b = b.data[key]; + return a < b ? -1 : a > b ? 1 : 0; + }, + finalSorter = sorter, + tableBody = document.querySelector('.coverage-summary tbody'), + rowNodes = tableBody.querySelectorAll('tr'), + rows = [], + i; + + if (desc) { + finalSorter = function(a, b) { + return -1 * sorter(a, b); + }; + } + + for (i = 0; i < rowNodes.length; i += 1) { + rows.push(rowNodes[i]); + tableBody.removeChild(rowNodes[i]); + } + + rows.sort(finalSorter); + + for (i = 0; i < rows.length; i += 1) { + tableBody.appendChild(rows[i]); + } + } + // removes sort indicators for current column being sorted + function removeSortIndicators() { + var col = getNthColumn(currentSort.index), + cls = col.className; + + cls = cls.replace(/ sorted$/, '').replace(/ sorted-desc$/, ''); + col.className = cls; + } + // adds sort indicators for current column being sorted + function addSortIndicators() { + getNthColumn(currentSort.index).className += currentSort.desc + ? ' sorted-desc' + : ' sorted'; + } + // adds event listeners for all sorter widgets + function enableUI() { + var i, + el, + ithSorter = function ithSorter(i) { + var col = cols[i]; + + return function() { + var desc = col.defaultDescSort; + + if (currentSort.index === i) { + desc = !currentSort.desc; + } + sortByIndex(i, desc); + removeSortIndicators(); + currentSort.index = i; + currentSort.desc = desc; + addSortIndicators(); + }; + }; + for (i = 0; i < cols.length; i += 1) { + if (cols[i].sortable) { + // add the click event handler on the th so users + // dont have to click on those tiny arrows + el = getNthColumn(i).querySelector('.sorter').parentElement; + if (el.addEventListener) { + el.addEventListener('click', ithSorter(i)); + } else { + el.attachEvent('onclick', ithSorter(i)); + } + } + } + } + // adds sorting functionality to the UI + return function() { + if (!getTable()) { + return; + } + cols = loadColumns(); + loadData(); + addSearchBox(); + addSortIndicators(); + enableUI(); + }; +})(); + +window.addEventListener('load', addSorting); diff --git a/packages/k8s/coverage/lcov-report/src/hooks/cleanup-job.ts.html b/packages/k8s/coverage/lcov-report/src/hooks/cleanup-job.ts.html new file mode 100644 index 00000000..eecd245d --- /dev/null +++ b/packages/k8s/coverage/lcov-report/src/hooks/cleanup-job.ts.html @@ -0,0 +1,145 @@ + + + + + + Code coverage report for src/hooks/cleanup-job.ts + + + + + + + + + +
+
+

All files / src/hooks cleanup-job.ts

+
+ +
+ 88.88% + Statements + 8/9 +
+ + +
+ 66.66% + Branches + 2/3 +
+ + +
+ 100% + Functions + 1/1 +
+ + +
+ 88.88% + Lines + 8/9 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +217x +7x +7x +7x +  +  +  +  +  +  +7x +21x +  +42x +  +  +  +  +42x +  + 
import * as core from '@actions/core'
+import { formatError } from '../k8s/utils'
+import { prunePods, pruneSecrets } from '../k8s'
+import {
+  collectAndPushNpuMetrics,
+  NPU_COLLECT_TIMEOUT_MS,
+  npuMetricsEnabled,
+  withTimeout
+} from '../k8s/utils/npu-metrics'
+ 
+export async function cleanupJob(): Promise<void> {
+  if (InpuMetricsEnabled()) {
+    try {
+      await withTimeout(collectAndPushNpuMetrics(), NPU_COLLECT_TIMEOUT_MS)
+    } catch (err) {
+      core.debug(`npu-metrics: collection failed: ${formatError(err)}`)
+    }
+  }
+  await Promise.all([prunePods(), pruneSecrets()])
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/packages/k8s/coverage/lcov-report/src/hooks/constants.ts.html b/packages/k8s/coverage/lcov-report/src/hooks/constants.ts.html new file mode 100644 index 00000000..f3494292 --- /dev/null +++ b/packages/k8s/coverage/lcov-report/src/hooks/constants.ts.html @@ -0,0 +1,280 @@ + + + + + + Code coverage report for src/hooks/constants.ts + + + + + + + + + +
+
+

All files / src/hooks constants.ts

+
+ +
+ 100% + Statements + 32/32 +
+ + +
+ 100% + Branches + 4/4 +
+ + +
+ 100% + Functions + 10/10 +
+ + +
+ 100% + Lines + 31/31 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +6615x +  +15x +105x +105x +74x +  +  +  +31x +  +  +15x +11x +  +  +  +  +  +15x +17x +  +  +  +  +  +15x +4x +4x +3x +  +1x +  +  +15x +3x +  +  +  +  +  +15x +15x +15x +15x +15x +  +15x +  +  +67x +  +  +15x +4x +  +  +15x +3x +  +  +15x +1x +  +15x + 
import { v4 as uuidv4 } from 'uuid'
+ 
+export function getRunnerPodName(): string {
+  const name = process.env.ACTIONS_RUNNER_POD_NAME
+  if (!name) {
+    throw new Error(
+      "'ACTIONS_RUNNER_POD_NAME' env is required, please contact your self hosted runner administrator"
+    )
+  }
+  return name
+}
+ 
+export function getJobPodName(): string {
+  return `${getRunnerPodName().substring(
+    0,
+    MAX_POD_NAME_LENGTH - '-workflow'.length
+  )}-workflow`
+}
+ 
+export function getStepPodName(): string {
+  return `${getRunnerPodName().substring(
+    0,
+    MAX_POD_NAME_LENGTH - ('-step-'.length + STEP_POD_NAME_SUFFIX_LENGTH)
+  )}-step-${uuidv4().substring(0, STEP_POD_NAME_SUFFIX_LENGTH)}`
+}
+ 
+export function getVolumeClaimName(): string {
+  const name = process.env.ACTIONS_RUNNER_CLAIM_NAME
+  if (!name) {
+    return `${getRunnerPodName()}-work`
+  }
+  return name
+}
+ 
+export function getSecretName(): string {
+  return `${getRunnerPodName().substring(
+    0,
+    MAX_POD_NAME_LENGTH - ('-secret-'.length + STEP_POD_NAME_SUFFIX_LENGTH)
+  )}-secret-${uuidv4().substring(0, STEP_POD_NAME_SUFFIX_LENGTH)}`
+}
+ 
+export const MAX_POD_NAME_LENGTH = 63
+export const STEP_POD_NAME_SUFFIX_LENGTH = 8
+export const CONTAINER_EXTENSION_PREFIX = '$'
+export const JOB_CONTAINER_NAME = 'job'
+export const JOB_CONTAINER_EXTENSION_NAME = '$job'
+ 
+export class RunnerInstanceLabel {
+  private podName: string
+  constructor() {
+    this.podName = getRunnerPodName()
+  }
+ 
+  get key(): string {
+    return 'runner-pod'
+  }
+ 
+  get value(): string {
+    return this.podName
+  }
+ 
+  toString(): string {
+    return `runner-pod=${this.podName}`
+  }
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/packages/k8s/coverage/lcov-report/src/hooks/index.html b/packages/k8s/coverage/lcov-report/src/hooks/index.html new file mode 100644 index 00000000..4a67a23a --- /dev/null +++ b/packages/k8s/coverage/lcov-report/src/hooks/index.html @@ -0,0 +1,191 @@ + + + + + + Code coverage report for src/hooks + + + + + + + + + +
+
+

All files src/hooks

+
+ +
+ 70.5% + Statements + 251/356 +
+ + +
+ 53.64% + Branches + 162/302 +
+ + +
+ 80% + Functions + 24/30 +
+ + +
+ 71.68% + Lines + 238/332 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
cleanup-job.ts +
+
88.88%8/966.66%2/3100%1/188.88%8/9
constants.ts +
+
100%32/32100%4/4100%10/10100%31/31
index.ts +
+
100%4/4100%0/0100%0/0100%4/4
prepare-job.ts +
+
86.57%129/14971.27%134/18888.88%8/988.8%119/134
run-container-step.ts +
+
29.46%33/1129.89%9/9128.57%2/731.13%33/106
run-script-step.ts +
+
90%45/5081.25%13/16100%3/389.58%43/48
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/packages/k8s/coverage/lcov-report/src/hooks/index.ts.html b/packages/k8s/coverage/lcov-report/src/hooks/index.ts.html new file mode 100644 index 00000000..f8db3058 --- /dev/null +++ b/packages/k8s/coverage/lcov-report/src/hooks/index.ts.html @@ -0,0 +1,97 @@ + + + + + + Code coverage report for src/hooks/index.ts + + + + + + + + + +
+
+

All files / src/hooks index.ts

+
+ +
+ 100% + Statements + 4/4 +
+ + +
+ 100% + Branches + 0/0 +
+ + +
+ 100% + Functions + 0/0 +
+ + +
+ 100% + Lines + 4/4 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +57x +7x +7x +7x + 
export * from './cleanup-job'
+export * from './prepare-job'
+export * from './run-script-step'
+export * from './run-container-step'
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/packages/k8s/coverage/lcov-report/src/hooks/prepare-job.ts.html b/packages/k8s/coverage/lcov-report/src/hooks/prepare-job.ts.html new file mode 100644 index 00000000..b5b281b4 --- /dev/null +++ b/packages/k8s/coverage/lcov-report/src/hooks/prepare-job.ts.html @@ -0,0 +1,1174 @@ + + + + + + Code coverage report for src/hooks/prepare-job.ts + + + + + + + + + +
+
+

All files / src/hooks prepare-job.ts

+
+ +
+ 86.57% + Statements + 129/149 +
+ + +
+ 71.27% + Branches + 134/188 +
+ + +
+ 88.88% + Functions + 8/9 +
+ + +
+ 88.8% + Lines + 119/134 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263 +264 +265 +266 +267 +268 +269 +270 +271 +272 +273 +274 +275 +276 +277 +278 +279 +280 +281 +282 +283 +284 +285 +286 +287 +288 +289 +290 +291 +292 +293 +294 +295 +296 +297 +298 +299 +300 +301 +302 +303 +304 +305 +306 +307 +308 +309 +310 +311 +312 +313 +314 +315 +316 +317 +318 +319 +320 +321 +322 +323 +324 +325 +326 +327 +328 +329 +330 +331 +332 +333 +334 +335 +336 +337 +338 +339 +340 +341 +342 +343 +344 +345 +346 +347 +348 +349 +350 +351 +352 +353 +354 +355 +356 +357 +358 +359 +360 +361 +362 +363 +3648x +  +8x +  +  +  +  +  +  +8x +  +  +  +  +  +  +  +  +  +8x +  +  +  +  +  +  +  +  +  +  +  +8x +  +  +  +  +8x +8x +  +8x +  +  +  +10x +1x +  +  +18x +  +9x +  +9x +9x +8x +  +  +  +  +  +8x +  +  +9x +9x +9x +1x +2x +2x +2x +  +  +1x +1x +2x +2x +2x +  +  +2x +2x +  +  +  +  +2x +2x +2x +  +  +  +9x +1x +  +  +8x +  +8x +  +  +  +  +  +  +  +4x +2x +  +  +  +  +  +  +2x +2x +  +  +  +  +  +  +2x +2x +  +  +2x +2x +  +  +  +2x +  +  +1x +1x +  +  +1x +1x +1x +1x +  +  +  +  +  +  +  +  +2x +  +  +  +  +  +  +  +  +  +2x +  +  +6x +  +  +6x +  +  +  +6x +6x +1x +  +5x +  +  +5x +  +  +  +  +10x +  +  +  +  +  +  +2x +  +  +  +1x +1x +  +  +8x +  +8x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +4x +  +4x +  +4x +  +  +  +  +1x +1x +1x +  +3x +3x +  +  +  +  +  +  +  +  +  +3x +  +  +3x +  +  +  +  +  +  +  +3x +1x +  +3x +1x +1x +1x +  +  +  +  +  +1x +  +  +  +  +  +3x +  +1x +  +  +  +1x +3x +  +2x +2x +  +  +  +  +  +  +  +2x +  +  +  +  +  +  +3x +  +  +8x +  +  +29x +  +  +21x +1x +1x +  +  +21x +  +  +  +  +21x +1x +  +  +21x +18x +  +  +21x +10x +  +  +21x +21x +  +  +3x +2x +  +  +  +21x +  +  +  +  +21x +20x +  +  +  +  +  +21x +  +21x +20x +  +  +1x +1x +  +  +1x +1x +  +  +1x +  + 
import * as core from '@actions/core'
+import * as k8s from '@kubernetes/client-node'
+import {
+  JobContainerInfo,
+  ContextPorts,
+  PrepareJobArgs,
+  writeToResponseFile,
+  ServiceContainerInfo
+} from 'hooklib'
+import {
+  containerPorts,
+  createJobPod,
+  isPodContainerAlpine,
+  prunePods,
+  waitForPodPhases,
+  getPrepareJobTimeoutSeconds,
+  execCpToPod,
+  execPodStep
+} from '../k8s'
+import {
+  CONTAINER_VOLUMES,
+  DEFAULT_CONTAINER_ENTRY_POINT,
+  DEFAULT_CONTAINER_ENTRY_POINT_ARGS,
+  formatError,
+  generateContainerName,
+  mergeContainerWithOptions,
+  readExtensionFromFile,
+  PodPhase,
+  fixArgs,
+  prepareJobScript
+} from '../k8s/utils'
+import {
+  CONTAINER_EXTENSION_PREFIX,
+  getJobPodName,
+  JOB_CONTAINER_NAME
+} from './constants'
+import { maybeInjectNpuMetrics } from '../k8s/utils/npu-metrics'
+import { dirname } from 'path'
+ 
+export async function prepareJob(
+  args: PrepareJobArgs,
+  responseFile
+): Promise<void> {
+  if (!args.container) {
+    throw new Error('Job Container is required.')
+  }
+ 
+  await prunePods()
+ 
+  const extension = readExtensionFromFile()
+ 
+  let container: k8s.V1Container | undefined = undefined
+  if (args.container?.image) {
+    container = createContainerSpec(
+      args.container,
+      JOB_CONTAINER_NAME,
+      true,
+      extension
+    )
+    maybeInjectNpuMetrics(container)
+  }
+ 
+  let services: k8s.V1Container[] = []
+  let serviceNames: string[] = []
+  if (args.services?.length) {
+    const occurrences = new Map<string, number>()
+    for (const s of args.services) {
+      const base = generateContainerName(s.image)
+      occurrences.set(base, (occurrences.get(base) || 0) + 1)
+    }
+ 
+    const indices = new Map<string, number>()
+    services = args.services.map(service => {
+      const base = generateContainerName(service.image)
+      const total = occurrences.get(base) || 0
+      const idx = indices.get(base) || 0
+ 
+      let name: string
+      if (total > 1) {
+        name = `${base}-${idx}`
+      } else E{
+        name = base
+      }
+ 
+      indices.set(base, idx + 1)
+      serviceNames.push(name)
+      return createContainerSpec(service, name, false, extension)
+    })
+  }
+ 
+  if (!container && !services?.length) {
+    throw new Error('No containers exist, skipping hook invocation')
+  }
+ 
+  let createdPod: k8s.V1Pod | undefined = undefined
+  try {
+    createdPod = await createJobPod(
+      getJobPodName(),
+      container,
+      services,
+      args.container.registry,
+      extension
+    )
+  } catch (err) {
+    await prunePods()
+    core.debug(`createPod failed: ${JSON.stringify(err)}`)
+    // The k8s client throws HttpException whose message is a multi-line string
+    // containing the raw HTTP dump. Extract the human-readable "message" field
+    // from the embedded JSON body so the log shows something like:
+    //   failed to create job pod:
+    //     spec.volumes[5].name: Duplicate value: "bad-hostpath"
+    // instead of the full HTTP dump.
+    const raw = err instanceof Error ? err.message : String(err)
+    let detail = raw
+    // The k8s HttpException message is a multi-line dump:
+    //   HTTP-Code: 422
+    //   Message: Unknown API Status Code!
+    //   Body: "{\"kind\":\"Status\",\"message\":\"...\\n\"}"
+    //   Headers: {...}
+    // Extract the Body JSON string, unescape it, and pull out "message".
+    try {
+      const bodyStart = raw.indexOf('Body: "')
+      // The boundary may be '"\nHeaders:' (real newline) or the literal
+      // string ends before Headers — use the last '"' before 'Headers:' as fallback
+      const headersIdx = raw.indexOf('Headers:')
+      const bodyEnd =
+        headersIdx !== -1
+          ? raw.lastIndexOf('"', headersIdx) // last " before Headers:
+          : raw.indexOf('"\nHeaders:')
+      if (bodyStart !== -1 && bodyEnd !== -1 && bodyEnd > bodyStart) {
+        // Body content is a JSON string literal (without surrounding quotes).
+        // Wrap it in quotes and JSON.parse to properly unescape \" \\ \n \t etc.
+        const escaped = raw.substring(bodyStart + 7, bodyEnd)
+        const bodyStr = JSON.parse('"' + escaped + '"')
+        // bodyStr may be plain text (e.g. 502 Bad Gateway) instead of JSON.
+        // Parse separately so a non-JSON body still yields a friendly message.
+        try {
+          const parsed = JSON.parse(bodyStr)
+          Eif (typeof parsed?.message === 'string') {
+            detail = parsed.message
+          }
+        } catch {
+          detail = bodyStr
+        }
+      }
+    } catch {
+      // Parsing failed — fall through and show the raw string
+    }
+    const errorMessage = [
+      'failed to create job pod:',
+      `  ✗ ${detail}`,
+      '-'.repeat(60),
+      '  → Pod spec was rejected by the k8s API. Check:',
+      '    - resources.requests does not exceed resources.limits',
+      '    - volumeMounts reference a volume defined in spec.volumes',
+      '    - envFrom / valueFrom reference existing Secrets / ConfigMaps',
+      '    - Field types match the k8s schema (kubectl explain pod.spec.containers)'
+    ].join('\n')
+    throw new Error(errorMessage)
+  }
+ 
+  Iif (!createdPod?.metadata?.name) {
+    throw new Error('created pod should have metadata.name')
+  }
+  core.debug(
+    `Job pod created, waiting for it to come online ${createdPod?.metadata?.name}`
+  )
+ 
+  const runnerWorkspaceEnv = process.env.RUNNER_WORKSPACE
+  if (!runnerWorkspaceEnv) {
+    throw new Error('RUNNER_WORKSPACE environment variable is not set')
+  }
+  const runnerWorkspace = dirname(runnerWorkspaceEnv)
+ 
+  let prepareScript: { containerPath: string; runnerPath: string } | undefined
+  Iif (args.container?.userMountVolumes?.length) {
+    prepareScript = prepareJobScript(args.container.userMountVolumes || [])
+  }
+ 
+  try {
+    await waitForPodPhases(
+      createdPod.metadata.name,
+      new Set([PodPhase.RUNNING]),
+      new Set([PodPhase.PENDING]),
+      getPrepareJobTimeoutSeconds()
+    )
+  } catch (err) {
+    await prunePods()
+    // Unwrap nested "Error: " prefix so the message renders as:
+    //   pod failed to come online:
+    //   <detail from waitForPodPhases, already formatted with sections>
+    const detail = err instanceof Error ? err.message : String(err)
+    throw new Error(`pod failed to come online:\n${detail}`)
+  }
+ 
+  await execCpToPod(createdPod.metadata.name, runnerWorkspace, '/__w')
+ 
+  if (EprepareScript) {
+    await execPodStep(
+      ['sh', '-e', prepareScript.containerPath],
+      createdPod.metadata.name,
+      JOB_CONTAINER_NAME
+    )
+ 
+    const promises: Promise<void>[] = []
+    for (const vol of args?.container?.userMountVolumes || []) {
+      promises.push(
+        execCpToPod(
+          createdPod.metadata.name,
+          vol.sourceVolumePath,
+          vol.targetVolumePath
+        )
+      )
+    }
+    await Promise.all(promises)
+  }
+ 
+  core.debug('Job pod is ready for traffic')
+ 
+  let isAlpine = false
+  try {
+    isAlpine = await isPodContainerAlpine(
+      createdPod.metadata.name,
+      JOB_CONTAINER_NAME
+    )
+  } catch (err) {
+    const message = formatError(err)
+    core.debug(`Failed to determine if the pod is alpine: ${message}`)
+    throw new Error(`failed to determine if the pod is alpine: ${message}`)
+  }
+  core.debug(`Setting isAlpine to ${isAlpine}`)
+  generateResponseFile(responseFile, args, createdPod, isAlpine, serviceNames)
+}
+ 
+function generateResponseFile(
+  responseFile: string,
+  args: PrepareJobArgs,
+  appPod: k8s.V1Pod,
+  isAlpine: boolean,
+  serviceNames?: string[]
+): void {
+  Iif (!appPod.metadata?.name) {
+    throw new Error('app pod must have metadata.name specified')
+  }
+  const response = {
+    state: {
+      jobPod: appPod.metadata.name
+    },
+    context: {},
+    isAlpine
+  }
+ 
+  const mainContainer = appPod.spec?.containers?.find(
+    c => c.name === JOB_CONTAINER_NAME
+  )
+  if (mainContainer) {
+    const mainContainerContextPorts: ContextPorts = {}
+    Eif (mainContainer?.ports) {
+      for (const port of mainContainer.ports) {
+        mainContainerContextPorts[port.containerPort] =
+          mainContainerContextPorts.hostPort
+      }
+    }
+ 
+    response.context['container'] = {
+      image: mainContainer.image,
+      ports: mainContainerContextPorts
+    }
+  }
+ 
+  if (args.services?.length) {
+    const serviceContainerNames =
+      serviceNames && serviceNames.length
+        ? serviceNames
+        : args.services?.map(s => generateContainerName(s.image)) || []
+ 
+    response.context['services'] = appPod?.spec?.containers
+      ?.filter(c => serviceContainerNames.includes(c.name))
+      .map(c => {
+        const ctxPorts: ContextPorts = {}
+        Iif (c.ports?.length) {
+          for (const port of c.ports) {
+            if (port.containerPort && port.hostPort) {
+              ctxPorts[port.containerPort.toString()] = port.hostPort.toString()
+            }
+          }
+        }
+ 
+        return {
+          image: c.image,
+          ports: ctxPorts
+        }
+      })
+  }
+ 
+  writeToResponseFile(responseFile, JSON.stringify(response))
+}
+ 
+export function createContainerSpec(
+  container: JobContainerInfo | ServiceContainerInfo,
+  name: string,
+  jobContainer = false,
+  extension?: k8s.V1PodTemplateSpec
+): k8s.V1Container {
+  if (!container.entryPoint && jobContainer) {
+    container.entryPoint = DEFAULT_CONTAINER_ENTRY_POINT
+    container.entryPointArgs = DEFAULT_CONTAINER_ENTRY_POINT_ARGS
+  }
+ 
+  const podContainer = {
+    name,
+    image: container.image,
+    ports: containerPorts(container)
+  } as k8s.V1Container
+  if (container['workingDirectory']) {
+    podContainer.workingDir = container['workingDirectory']
+  }
+ 
+  if (container.entryPoint) {
+    podContainer.command = [container.entryPoint]
+  }
+ 
+  if (container.entryPointArgs && container.entryPointArgs.length > 0) {
+    podContainer.args = fixArgs(container.entryPointArgs)
+  }
+ 
+  podContainer.env = []
+  for (const [key, value] of Object.entries(
+    container['environmentVariables'] || {}
+  )) {
+    if (value && key !== 'HOME') {
+      podContainer.env.push({ name: key, value })
+    }
+  }
+ 
+  podContainer.env.push({
+    name: 'GITHUB_ACTIONS',
+    value: 'true'
+  })
+ 
+  if (!('CI' in (container['environmentVariables'] || {}))) {
+    podContainer.env.push({
+      name: 'CI',
+      value: 'true'
+    })
+  }
+ 
+  podContainer.volumeMounts = CONTAINER_VOLUMES
+ 
+  if (!extension) {
+    return podContainer
+  }
+ 
+  const from = extension.spec?.containers?.find(
+    c => c.name === CONTAINER_EXTENSION_PREFIX + name
+  )
+ 
+  Eif (from) {
+    mergeContainerWithOptions(podContainer, from)
+  }
+ 
+  return podContainer
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/packages/k8s/coverage/lcov-report/src/hooks/run-container-step.ts.html b/packages/k8s/coverage/lcov-report/src/hooks/run-container-step.ts.html new file mode 100644 index 00000000..4ce7862b --- /dev/null +++ b/packages/k8s/coverage/lcov-report/src/hooks/run-container-step.ts.html @@ -0,0 +1,898 @@ + + + + + + Code coverage report for src/hooks/run-container-step.ts + + + + + + + + + +
+
+

All files / src/hooks run-container-step.ts

+
+ +
+ 29.46% + Statements + 33/112 +
+ + +
+ 9.89% + Branches + 9/91 +
+ + +
+ 28.57% + Functions + 2/7 +
+ + +
+ 31.13% + Lines + 33/106 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263 +264 +265 +266 +267 +268 +269 +270 +271 +2728x +8x +8x +  +8x +8x +  +  +  +  +  +  +  +  +  +  +  +  +8x +  +  +  +  +  +  +  +  +8x +  +  +  +  +  +8x +  +8x +  +  +16x +1x +  +  +15x +1x +  +  +  +  +14x +14x +14x +13x +  +  +14x +  +14x +14x +  +  +  +14x +  +14x +14x +14x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +14x +14x +14x +14x +14x +14x +  +14x +  +14x +14x +  +  +  +  +  +  +  +  +  +  +  + 
import * as core from '@actions/core'
+import * as fs from 'fs'
+import * as k8s from '@kubernetes/client-node'
+import { RunContainerStepArgs } from 'hooklib'
+import { dirname } from 'path'
+import {
+  createContainerStepPod,
+  deletePod,
+  describePodFailure,
+  execCpFromPod,
+  execCpToPod,
+  execPodStepWithOutput,
+  getContainerTerminatedErrors,
+  getPodByName,
+  getPrepareJobTimeoutSeconds,
+  getTerminatedReasonHint,
+  waitForPodPhases
+} from '../k8s'
+import {
+  CONTAINER_VOLUMES,
+  formatError,
+  mergeContainerWithOptions,
+  PodPhase,
+  readExtensionFromFile,
+  DEFAULT_CONTAINER_ENTRY_POINT_ARGS,
+  writeContainerStepScript
+} from '../k8s/utils'
+import {
+  getJobPodName,
+  getStepPodName,
+  JOB_CONTAINER_EXTENSION_NAME,
+  JOB_CONTAINER_NAME
+} from './constants'
+import { maybeInjectNpuMetrics } from '../k8s/utils/npu-metrics'
+ 
+export async function runContainerStep(
+  stepContainer: RunContainerStepArgs
+): Promise<number> {
+  if (stepContainer.dockerfile) {
+    throw new Error('Building container actions is not currently supported')
+  }
+ 
+  if (!stepContainer.entryPoint) {
+    throw new Error(
+      'failed to start the container since the entrypoint is overwritten'
+    )
+  }
+ 
+  const envs = stepContainer.environmentVariables || {}
+  envs['GITHUB_ACTIONS'] = 'true'
+  if (!('CI' in envs)) {
+    envs.CI = 'true'
+  }
+ 
+  const extension = readExtensionFromFile()
+ 
+  const container = createContainerSpec(stepContainer, extension)
+  maybeInjectNpuMetrics(container)
+ 
+  let pod: k8s.V1Pod
+  try {
+    pod = await createContainerStepPod(getStepPodName(), container, extension)
+  } catch (err) {
+    const message = formatError(err)
+    core.debug(`createContainerStepPod failed: ${message}`)
+    throw new Error(`failed to run container step: ${message}`)
+  }
+ 
+  if (!pod.metadata?.name) {
+    throw new Error(
+      `Expected job ${JSON.stringify(
+        pod
+      )} to have correctly set the metadata.name`
+    )
+  }
+  const podName = pod.metadata.name
+ 
+  try {
+    await waitForPodPhases(
+      podName,
+      new Set([PodPhase.RUNNING]),
+      new Set([PodPhase.PENDING, PodPhase.UNKNOWN]),
+      getPrepareJobTimeoutSeconds()
+    )
+ 
+    const runnerWorkspaceEnv = process.env.RUNNER_WORKSPACE
+    const githubWorkspaceEnv = process.env.GITHUB_WORKSPACE
+    if (!runnerWorkspaceEnv || !githubWorkspaceEnv) {
+      throw new Error(
+        'RUNNER_WORKSPACE or GITHUB_WORKSPACE environment variable is not set'
+      )
+    }
+    const runnerWorkspace = dirname(runnerWorkspaceEnv)
+    const githubWorkspace = githubWorkspaceEnv
+    const parts = githubWorkspace.split('/').slice(-2)
+    if (parts.length !== 2) {
+      throw new Error(`Invalid github workspace directory: ${githubWorkspace}`)
+    }
+    const relativeWorkspace = parts.join('/')
+ 
+    core.debug(
+      `Copying files from pod ${getJobPodName()} to ${runnerWorkspace}/${relativeWorkspace}`
+    )
+    await execCpFromPod(getJobPodName(), `/__w`, `${runnerWorkspace}`)
+ 
+    const { containerPath, runnerPath } = writeContainerStepScript(
+      `${runnerWorkspace}/__w/_temp`,
+      githubWorkspace,
+      stepContainer.entryPoint,
+      stepContainer.entryPointArgs,
+      envs
+    )
+ 
+    await execCpToPod(podName, `${runnerWorkspace}/__w`, '/__w')
+ 
+    fs.rmSync(`${runnerWorkspace}/__w`, { recursive: true, force: true })
+ 
+    try {
+      core.debug(`Executing container step script in pod ${podName}`)
+      const { code, output } = await execPodStepWithOutput(
+        ['sh', '-e', containerPath],
+        pod.metadata.name,
+        JOB_CONTAINER_NAME
+      )
+      if (code === 0) {
+        return 0
+      }
+      // Non-zero exit: surface a structured error so the user can tell whether
+      // it was their script or the container that failed. Read container
+      // status BEFORE deletePod runs (in the outer finally) to inspect the
+      // terminated reason, if it is already available.
+      const classification = await classifyScriptError(
+        pod.metadata.name,
+        code,
+        output
+      )
+      throw new Error(classification)
+    } catch (err) {
+      core.debug(`execPodStep failed: ${formatError(err)}`)
+      // Re-throw our classified errors verbatim; wrap anything else.
+      if (
+        err instanceof Error &&
+        (err.message.startsWith('Step failed:') ||
+          err.message.startsWith('failed to run script step'))
+      ) {
+        throw err
+      }
+      const message = formatError(err)
+      throw new Error(`failed to run container step: ${message}`)
+    } finally {
+      fs.rmSync(runnerPath, { force: true })
+    }
+  } catch (error) {
+    try {
+      const errorPod = await getPodByName(podName)
+      const terminatedErrors = getContainerTerminatedErrors(errorPod)
+      if (terminatedErrors.length > 0) {
+        const details = await describePodFailure(podName)
+        core.error(
+          `Pod ${podName} has unrecoverable container errors:\n${terminatedErrors.join('\n')}\n${details}`
+        )
+      }
+    } catch {
+      // Best-effort: pod may already be deleted or unreachable
+    }
+    core.error(`Failed to run container step: ${error}`)
+    throw error
+  } finally {
+    await deletePod(podName).catch(err => {
+      core.error(`Failed to delete step pod ${podName}: ${err}`)
+    })
+  }
+}
+ 
+// Inspect the pod's container status to determine whether a non-zero exit
+// code came from the user's script (container terminated cleanly with
+// reason=Completed) or from a container-level failure (OOMKilled, etc.).
+// The container state may not yet be 'terminated' when called (k8s updates
+// it asynchronously), so we default to treating unknown state as a script
+// issue and let the user check their script first.
+async function classifyScriptError(
+  podName: string,
+  exitCode: number,
+  tailOutput: string
+): Promise<string> {
+  const sep = '-'.repeat(60)
+  const errors: string[] = [`  ✗ exit code: ${exitCode}`]
+  const sections: string[] = []
+ 
+  try {
+    const pod = await getPodByName(podName)
+    const cs = pod.status?.containerStatuses?.find(
+      s => s.name === JOB_CONTAINER_NAME
+    )
+    const term = cs?.state?.terminated
+    if (term) {
+      const reason = term.reason ?? 'Completed'
+      const isContainerFault =
+        reason === 'OOMKilled' ||
+        reason === 'Error' ||
+        reason === 'FailedPostStartHookError' ||
+        (term.exitCode === 137 && reason !== 'Completed')
+      if (isContainerFault) {
+        const detail = term.message ? `\n    ${term.message}` : ''
+        const hint = `\n${getTerminatedReasonHint(reason, term.exitCode)}`
+        errors.push(
+          `  ✗ container "${JOB_CONTAINER_NAME}": ${reason} (exit code ${term.exitCode})${detail}${hint}`
+        )
+      } else {
+        errors.push(
+          `  → your script exited with a non-zero code; please check your script for errors`
+        )
+        sections.push(
+          `Container status: ${reason} (exit code ${term.exitCode})`
+        )
+      }
+    } else {
+      // Container state unavailable — treat as script issue by default
+      errors.push(`  → please check your script for errors`)
+    }
+    if (cs?.state?.waiting) {
+      errors.push(
+        `  ✗ container "${JOB_CONTAINER_NAME}" waiting: ${cs.state.waiting.reason ?? 'unknown'}`
+      )
+    }
+  } catch {
+    // pod already gone or API error — default hint
+    errors.push(`  → please check your script for errors`)
+  }
+ 
+  if (tailOutput) {
+    const outputLines = tailOutput
+      .split('\n')
+      .map(l => `  ${l}`)
+      .join('\n')
+    sections.push(`Last output:\n${outputLines}`)
+  }
+ 
+  let result = `failed to run script step:\n${errors.join('\n')}`
+  if (sections.length) {
+    result += `\n${sep}\n${sections.join('\n')}`
+  }
+  return result
+}
+ 
+function createContainerSpec(
+  container: RunContainerStepArgs,
+  extension?: k8s.V1PodTemplateSpec
+): k8s.V1Container {
+  const podContainer = new k8s.V1Container()
+  podContainer.name = JOB_CONTAINER_NAME
+  podContainer.image = container.image
+  podContainer.workingDir = '/__w'
+  podContainer.command = ['tail']
+  podContainer.args = DEFAULT_CONTAINER_ENTRY_POINT_ARGS
+ 
+  podContainer.volumeMounts = CONTAINER_VOLUMES
+ 
+  Eif (!extension) {
+    return podContainer
+  }
+ 
+  const from = extension.spec?.containers?.find(
+    c => c.name === JOB_CONTAINER_EXTENSION_NAME
+  )
+  if (from) {
+    mergeContainerWithOptions(podContainer, from)
+  }
+ 
+  return podContainer
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/packages/k8s/coverage/lcov-report/src/hooks/run-script-step.ts.html b/packages/k8s/coverage/lcov-report/src/hooks/run-script-step.ts.html new file mode 100644 index 00000000..a728ac7c --- /dev/null +++ b/packages/k8s/coverage/lcov-report/src/hooks/run-script-step.ts.html @@ -0,0 +1,526 @@ + + + + + + Code coverage report for src/hooks/run-script-step.ts + + + + + + + + + +
+
+

All files / src/hooks run-script-step.ts

+
+ +
+ 90% + Statements + 45/50 +
+ + +
+ 81.25% + Branches + 13/16 +
+ + +
+ 100% + Functions + 3/3 +
+ + +
+ 89.58% + Lines + 43/48 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148  +7x +7x +  +7x +  +  +  +  +  +7x +7x +7x +  +  +  +3x +3x +  +  +  +3x +3x +3x +  +7x +  +3x +  +3x +3x +3x +  +  +7x +  +  +  +  +7x +2x +  +  +  +  +  +5x +5x +  +  +  +  +  +  +  +5x +5x +5x +5x +  +10x +  +  +  +  +  +  +  +  +10x +  +  +  +  +  +5x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +10x +  +  +  +  +  +  +  +  +  +  +  +5x +5x +  +5x +  +  +  +  +4x +3x +  +  +4x +4x +  +  +  +3x +  +1x +1x +  +5x +5x +  +  +  +  +  +  +1x +  +  +2x +  +  +  +  +  +  +  +  + 
/* eslint-disable @typescript-eslint/no-unused-vars */
+import * as fs from 'fs'
+import * as core from '@actions/core'
+import { RunScriptStepArgs } from 'hooklib'
+import {
+  execCpFromPod,
+  execCpToPod,
+  execPodStep,
+  execPodStepWithOutput
+} from '../k8s'
+import { formatError, writeRunScript } from '../k8s/utils'
+import { JOB_CONTAINER_NAME } from './constants'
+import { dirname } from 'path'
+import * as shlex from 'shlex'
+ 
+function formatScriptError(exitCode: number, tailOutput: string): string {
+  const sep = '-'.repeat(60)
+  const errors = [
+    `  ✗ exit code: ${exitCode}`,
+    `  → your script exited with a non-zero code; please check your script for errors`
+  ]
+  const sections: string[] = []
+  Eif (tailOutput) {
+    const outputLines = tailOutput
+      .split('\n')
+      .map(l => `  ${l}`)
+      .join('\n')
+    sections.push(`Last output:\n${outputLines}`)
+  }
+  let result = `failed to run script step:\n${errors.join('\n')}`
+  Eif (sections.length) result += `\n${sep}\n${sections.join('\n')}`
+  return result
+}
+ 
+export async function runScriptStep(
+  args: RunScriptStepArgs,
+  state
+): Promise<void> {
+  // Validate that pod was created successfully (prepareJob succeeded)
+  if (!state?.jobPod) {
+    throw new Error(
+      'jobPod must be set - ensure prepareJob completed successfully before running script steps'
+    )
+  }
+ 
+  // Write the entrypoint first. This will be later coppied to the workflow pod
+  const { entryPoint, entryPointArgs, environmentVariables } = args
+  const { containerPath, runnerPath } = writeRunScript(
+    args.workingDirectory,
+    entryPoint,
+    entryPointArgs,
+    args.prependPath,
+    environmentVariables
+  )
+ 
+  const workdir = dirname(process.env.RUNNER_WORKSPACE as string)
+  const runnerTemp = `${workdir}/_temp`
+  const containerTemp = '/__w/_temp'
+  const containerTempSrc = '/__w/_temp_pre'
+  // Ensure base and staging dirs exist before copying
+  await execPodStep(
+    [
+      'sh',
+      '-c',
+      'mkdir -p /__w && mkdir -p /__w/_temp && mkdir -p /__w/_temp_pre'
+    ],
+    state.jobPod,
+    JOB_CONTAINER_NAME
+  )
+  await execCpToPod(state.jobPod, runnerTemp, containerTempSrc)
+ 
+  // Copy GitHub directories from temp to /github
+  // Merge strategy:
+  // - Overwrite files in _runner_file_commands
+  // - Append files not already present elsewhere
+  const mergeCommands = [
+    'set -e',
+    'mkdir -p /__w/_temp /__w/_temp_pre',
+    'SRC=/__w/_temp_pre',
+    'DST=/__w/_temp',
+    // Overwrite _runner_file_commands
+    'cp -a "$SRC/_runner_file_commands/." "$DST/_runner_file_commands"',
+    `find "$SRC" -type f ! -path "*/_runner_file_commands/*" -exec sh -c '
+    rel="\${1#$2/}"
+    target="$3/$rel"
+    mkdir -p "$(dirname "$target")"
+    cp -a "$1" "$target"
+  ' _ {} "$SRC" "$DST" \\;`,
+    // Remove _temp_pre after merging
+    'rm -rf /__w/_temp_pre'
+  ]
+ 
+  try {
+    await execPodStep(
+      ['sh', '-c', mergeCommands.join(' && ')],
+      state.jobPod,
+      JOB_CONTAINER_NAME
+    )
+  } catch (err) {
+    const message = formatError(err)
+    core.debug(`Failed to merge temp directories: ${message}`)
+    throw new Error(`failed to merge temp dirs: ${message}`)
+  }
+ 
+  // Execute the entrypoint script
+  args.entryPoint = 'sh'
+  args.entryPointArgs = ['-e', containerPath]
+  try {
+    const { code, output } = await execPodStepWithOutput(
+      [args.entryPoint, ...args.entryPointArgs],
+      state.jobPod,
+      JOB_CONTAINER_NAME
+    )
+    if (code !== 0) {
+      throw new Error(formatScriptError(code, output))
+    }
+  } catch (err) {
+    core.debug(`execPodStep failed: ${formatError(err)}`)
+    if (
+      err instanceof Error &&
+      err.message.startsWith('failed to run script step')
+    ) {
+      throw err
+    }
+    const message = formatError(err)
+    throw new Error(`failed to run script step: ${message}`)
+  } finally {
+    try {
+      fs.rmSync(runnerPath, { force: true })
+    } catch (removeErr) {
+      core.debug(`Failed to remove file ${runnerPath}: ${removeErr}`)
+    }
+  }
+ 
+  try {
+    core.debug(
+      `Copying from job pod '${state.jobPod}' ${containerTemp} to ${runnerTemp}`
+    )
+    await execCpFromPod(
+      state.jobPod,
+      `${containerTemp}/_runner_file_commands`,
+      `${workdir}/_temp`
+    )
+  } catch (error) {
+    core.warning('Failed to copy _temp from pod')
+  }
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/packages/k8s/coverage/lcov-report/src/k8s/heartbeat.ts.html b/packages/k8s/coverage/lcov-report/src/k8s/heartbeat.ts.html new file mode 100644 index 00000000..086546fd --- /dev/null +++ b/packages/k8s/coverage/lcov-report/src/k8s/heartbeat.ts.html @@ -0,0 +1,493 @@ + + + + + + Code coverage report for src/k8s/heartbeat.ts + + + + + + + + + +
+
+

All files / src/k8s heartbeat.ts

+
+ +
+ 85.71% + Statements + 60/70 +
+ + +
+ 78.12% + Branches + 25/32 +
+ + +
+ 91.66% + Functions + 11/12 +
+ + +
+ 85.29% + Lines + 58/68 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +13714x +  +  +  +  +  +  +  +  +  +14x +  +  +  +8x +8x +  +  +14x +8x +8x +8x +14x +  +  +8x +8x +  +  +14x +22x +22x +  +  +  +22x +  +  +14x +8x +  +  +8x +8x +8x +  +8x +4x +4x +  +  +  +14x +8x +  +  +8x +  +8x +5x +1x +1x +  +5x +1x +  +  +1x +1x +1x +  +  +  +1x +  +  +  +  +  +  +  +  +  +8x +  +8x +1x +  +  +1x +1x +  +  +  +8x +  +  +  +  +8x +1x +1x +  +  +  +8x +29x +  +16x +  +13x +12x +12x +12x +4x +4x +  +12x +  +  +  +  +  +  +  +  +1x +  +  +  +  +1x +  +  +  +14x + 
import * as core from '@actions/core'
+ 
+export interface HeartbeatWebSocket {
+  readyState: number
+  ping(): void
+  close(): void
+  on(event: string, listener: (...args: any[]) => void): this
+  once(event: string, listener: (...args: any[]) => void): this
+}
+ 
+export function parsePositiveMsEnv(
+  value: string | undefined,
+  fallback: number
+): number {
+  const parsed = Number.parseInt(value ?? '', 10)
+  return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback
+}
+ 
+export class WebSocketHeartbeat {
+  private pingInterval: ReturnType<typeof setInterval> | null = null
+  private pongTimeout: ReturnType<typeof setTimeout> | null = null
+  private lastHeartbeatLog = 0
+  private static readonly LOG_INTERVAL_MS = 2 * 60 * 1000
+ 
+  constructor(
+    private readonly pingPeriodMs: number,
+    private readonly pongDeadlineMs: number
+  ) {}
+ 
+  private shouldLog(): boolean {
+    const now = Date.now()
+    Iif (now - this.lastHeartbeatLog >= WebSocketHeartbeat.LOG_INTERVAL_MS) {
+      this.lastHeartbeatLog = now
+      return true
+    }
+    return false
+  }
+ 
+  stop(): void {
+    Iif (this.shouldLog()) {
+      core.debug('[Heartbeat] stopping heartbeat')
+    }
+    Eif (this.pingInterval) {
+      clearInterval(this.pingInterval)
+      this.pingInterval = null
+    }
+    if (this.pongTimeout) {
+      clearTimeout(this.pongTimeout)
+      this.pongTimeout = null
+    }
+  }
+ 
+  start(ws: HeartbeatWebSocket, reject: (err: Error) => void): void {
+    core.debug(
+      `[Heartbeat] Starting with period=${this.pingPeriodMs}ms, deadline=${this.pongDeadlineMs}ms`
+    )
+    this.lastHeartbeatLog = Date.now()
+ 
+    const resetPongTimeout = (): void => {
+      if (this.pongTimeout) {
+        clearTimeout(this.pongTimeout)
+        this.pongTimeout = null
+      }
+      this.pongTimeout = setTimeout(() => {
+        core.warning(
+          `[Heartbeat] No pong received in ${this.pongDeadlineMs}ms, closing stale connection`
+        )
+        this.stop()
+        try {
+          ws.close()
+        } catch {
+          // ignore errors closing an already-closing socket
+        }
+        reject(
+          new Error(
+            `WebSocket heartbeat timeout: no pong within ${this.pongDeadlineMs}ms`
+          )
+        )
+      }, this.pongDeadlineMs)
+    }
+ 
+    // Arm the deadline only after the first ping is sent, not immediately on
+    // start, so a slow CONNECTING socket cannot time out before any exchange.
+    let deadlineArmed = false
+ 
+    ws.on('pong', () => {
+      Iif (this.shouldLog()) {
+        core.debug('[Heartbeat] Pong received')
+      }
+      Eif (deadlineArmed) {
+        resetPongTimeout()
+      }
+    })
+ 
+    ws.on('error', (err: Error) => {
+      core.error(`[Heartbeat] WebSocket error: ${err.message}`)
+      this.stop()
+    })
+ 
+    ws.on('close', () => {
+      core.debug('[Heartbeat] WebSocket closed, stopping heartbeat')
+      this.stop()
+    })
+ 
+    // WebSocket readyState: 0 = CONNECTING, 1 = OPEN, 2 = CLOSING, 3 = CLOSED
+    this.pingInterval = setInterval(() => {
+      if (ws.readyState === 0) {
+        // Still connecting — skip this tick but keep the interval alive
+        return
+      }
+      if (ws.readyState === 1) {
+        try {
+          ws.ping()
+          if (!deadlineArmed) {
+            deadlineArmed = true
+            resetPongTimeout()
+          }
+          Iif (this.shouldLog()) {
+            core.debug('[Heartbeat] Ping sent')
+          }
+        } catch (err) {
+          core.error(`[Heartbeat] Ping failed: ${err}`)
+          this.stop()
+        }
+      } else {
+        // CLOSING (2) or CLOSED (3)
+        Iif (this.shouldLog()) {
+          core.debug(
+            `[Heartbeat] WebSocket closing/closed (readyState=${ws.readyState}), stopping heartbeat`
+          )
+        }
+        this.stop()
+      }
+    }, this.pingPeriodMs)
+  }
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/packages/k8s/coverage/lcov-report/src/k8s/index.html b/packages/k8s/coverage/lcov-report/src/k8s/index.html new file mode 100644 index 00000000..7abfc014 --- /dev/null +++ b/packages/k8s/coverage/lcov-report/src/k8s/index.html @@ -0,0 +1,131 @@ + + + + + + Code coverage report for src/k8s + + + + + + + + + +
+
+

All files src/k8s

+
+ +
+ 53.94% + Statements + 472/875 +
+ + +
+ 54.1% + Branches + 323/597 +
+ + +
+ 47.69% + Functions + 62/130 +
+ + +
+ 54.59% + Lines + 428/784 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
heartbeat.ts +
+
85.71%60/7078.12%25/3291.66%11/1285.29%58/68
index.ts +
+
51.18%412/80552.74%298/56543.22%51/11851.67%370/716
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/packages/k8s/coverage/lcov-report/src/k8s/index.ts.html b/packages/k8s/coverage/lcov-report/src/k8s/index.ts.html new file mode 100644 index 00000000..b4e20d9b --- /dev/null +++ b/packages/k8s/coverage/lcov-report/src/k8s/index.ts.html @@ -0,0 +1,5599 @@ + + + + + + Code coverage report for src/k8s/index.ts + + + + + + + + + +
+
+

All files / src/k8s index.ts

+
+ +
+ 51.18% + Statements + 412/805 +
+ + +
+ 52.74% + Branches + 298/565 +
+ + +
+ 43.22% + Functions + 51/118 +
+ + +
+ 51.67% + Lines + 370/716 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263 +264 +265 +266 +267 +268 +269 +270 +271 +272 +273 +274 +275 +276 +277 +278 +279 +280 +281 +282 +283 +284 +285 +286 +287 +288 +289 +290 +291 +292 +293 +294 +295 +296 +297 +298 +299 +300 +301 +302 +303 +304 +305 +306 +307 +308 +309 +310 +311 +312 +313 +314 +315 +316 +317 +318 +319 +320 +321 +322 +323 +324 +325 +326 +327 +328 +329 +330 +331 +332 +333 +334 +335 +336 +337 +338 +339 +340 +341 +342 +343 +344 +345 +346 +347 +348 +349 +350 +351 +352 +353 +354 +355 +356 +357 +358 +359 +360 +361 +362 +363 +364 +365 +366 +367 +368 +369 +370 +371 +372 +373 +374 +375 +376 +377 +378 +379 +380 +381 +382 +383 +384 +385 +386 +387 +388 +389 +390 +391 +392 +393 +394 +395 +396 +397 +398 +399 +400 +401 +402 +403 +404 +405 +406 +407 +408 +409 +410 +411 +412 +413 +414 +415 +416 +417 +418 +419 +420 +421 +422 +423 +424 +425 +426 +427 +428 +429 +430 +431 +432 +433 +434 +435 +436 +437 +438 +439 +440 +441 +442 +443 +444 +445 +446 +447 +448 +449 +450 +451 +452 +453 +454 +455 +456 +457 +458 +459 +460 +461 +462 +463 +464 +465 +466 +467 +468 +469 +470 +471 +472 +473 +474 +475 +476 +477 +478 +479 +480 +481 +482 +483 +484 +485 +486 +487 +488 +489 +490 +491 +492 +493 +494 +495 +496 +497 +498 +499 +500 +501 +502 +503 +504 +505 +506 +507 +508 +509 +510 +511 +512 +513 +514 +515 +516 +517 +518 +519 +520 +521 +522 +523 +524 +525 +526 +527 +528 +529 +530 +531 +532 +533 +534 +535 +536 +537 +538 +539 +540 +541 +542 +543 +544 +545 +546 +547 +548 +549 +550 +551 +552 +553 +554 +555 +556 +557 +558 +559 +560 +561 +562 +563 +564 +565 +566 +567 +568 +569 +570 +571 +572 +573 +574 +575 +576 +577 +578 +579 +580 +581 +582 +583 +584 +585 +586 +587 +588 +589 +590 +591 +592 +593 +594 +595 +596 +597 +598 +599 +600 +601 +602 +603 +604 +605 +606 +607 +608 +609 +610 +611 +612 +613 +614 +615 +616 +617 +618 +619 +620 +621 +622 +623 +624 +625 +626 +627 +628 +629 +630 +631 +632 +633 +634 +635 +636 +637 +638 +639 +640 +641 +642 +643 +644 +645 +646 +647 +648 +649 +650 +651 +652 +653 +654 +655 +656 +657 +658 +659 +660 +661 +662 +663 +664 +665 +666 +667 +668 +669 +670 +671 +672 +673 +674 +675 +676 +677 +678 +679 +680 +681 +682 +683 +684 +685 +686 +687 +688 +689 +690 +691 +692 +693 +694 +695 +696 +697 +698 +699 +700 +701 +702 +703 +704 +705 +706 +707 +708 +709 +710 +711 +712 +713 +714 +715 +716 +717 +718 +719 +720 +721 +722 +723 +724 +725 +726 +727 +728 +729 +730 +731 +732 +733 +734 +735 +736 +737 +738 +739 +740 +741 +742 +743 +744 +745 +746 +747 +748 +749 +750 +751 +752 +753 +754 +755 +756 +757 +758 +759 +760 +761 +762 +763 +764 +765 +766 +767 +768 +769 +770 +771 +772 +773 +774 +775 +776 +777 +778 +779 +780 +781 +782 +783 +784 +785 +786 +787 +788 +789 +790 +791 +792 +793 +794 +795 +796 +797 +798 +799 +800 +801 +802 +803 +804 +805 +806 +807 +808 +809 +810 +811 +812 +813 +814 +815 +816 +817 +818 +819 +820 +821 +822 +823 +824 +825 +826 +827 +828 +829 +830 +831 +832 +833 +834 +835 +836 +837 +838 +839 +840 +841 +842 +843 +844 +845 +846 +847 +848 +849 +850 +851 +852 +853 +854 +855 +856 +857 +858 +859 +860 +861 +862 +863 +864 +865 +866 +867 +868 +869 +870 +871 +872 +873 +874 +875 +876 +877 +878 +879 +880 +881 +882 +883 +884 +885 +886 +887 +888 +889 +890 +891 +892 +893 +894 +895 +896 +897 +898 +899 +900 +901 +902 +903 +904 +905 +906 +907 +908 +909 +910 +911 +912 +913 +914 +915 +916 +917 +918 +919 +920 +921 +922 +923 +924 +925 +926 +927 +928 +929 +930 +931 +932 +933 +934 +935 +936 +937 +938 +939 +940 +941 +942 +943 +944 +945 +946 +947 +948 +949 +950 +951 +952 +953 +954 +955 +956 +957 +958 +959 +960 +961 +962 +963 +964 +965 +966 +967 +968 +969 +970 +971 +972 +973 +974 +975 +976 +977 +978 +979 +980 +981 +982 +983 +984 +985 +986 +987 +988 +989 +990 +991 +992 +993 +994 +995 +996 +997 +998 +999 +1000 +1001 +1002 +1003 +1004 +1005 +1006 +1007 +1008 +1009 +1010 +1011 +1012 +1013 +1014 +1015 +1016 +1017 +1018 +1019 +1020 +1021 +1022 +1023 +1024 +1025 +1026 +1027 +1028 +1029 +1030 +1031 +1032 +1033 +1034 +1035 +1036 +1037 +1038 +1039 +1040 +1041 +1042 +1043 +1044 +1045 +1046 +1047 +1048 +1049 +1050 +1051 +1052 +1053 +1054 +1055 +1056 +1057 +1058 +1059 +1060 +1061 +1062 +1063 +1064 +1065 +1066 +1067 +1068 +1069 +1070 +1071 +1072 +1073 +1074 +1075 +1076 +1077 +1078 +1079 +1080 +1081 +1082 +1083 +1084 +1085 +1086 +1087 +1088 +1089 +1090 +1091 +1092 +1093 +1094 +1095 +1096 +1097 +1098 +1099 +1100 +1101 +1102 +1103 +1104 +1105 +1106 +1107 +1108 +1109 +1110 +1111 +1112 +1113 +1114 +1115 +1116 +1117 +1118 +1119 +1120 +1121 +1122 +1123 +1124 +1125 +1126 +1127 +1128 +1129 +1130 +1131 +1132 +1133 +1134 +1135 +1136 +1137 +1138 +1139 +1140 +1141 +1142 +1143 +1144 +1145 +1146 +1147 +1148 +1149 +1150 +1151 +1152 +1153 +1154 +1155 +1156 +1157 +1158 +1159 +1160 +1161 +1162 +1163 +1164 +1165 +1166 +1167 +1168 +1169 +1170 +1171 +1172 +1173 +1174 +1175 +1176 +1177 +1178 +1179 +1180 +1181 +1182 +1183 +1184 +1185 +1186 +1187 +1188 +1189 +1190 +1191 +1192 +1193 +1194 +1195 +1196 +1197 +1198 +1199 +1200 +1201 +1202 +1203 +1204 +1205 +1206 +1207 +1208 +1209 +1210 +1211 +1212 +1213 +1214 +1215 +1216 +1217 +1218 +1219 +1220 +1221 +1222 +1223 +1224 +1225 +1226 +1227 +1228 +1229 +1230 +1231 +1232 +1233 +1234 +1235 +1236 +1237 +1238 +1239 +1240 +1241 +1242 +1243 +1244 +1245 +1246 +1247 +1248 +1249 +1250 +1251 +1252 +1253 +1254 +1255 +1256 +1257 +1258 +1259 +1260 +1261 +1262 +1263 +1264 +1265 +1266 +1267 +1268 +1269 +1270 +1271 +1272 +1273 +1274 +1275 +1276 +1277 +1278 +1279 +1280 +1281 +1282 +1283 +1284 +1285 +1286 +1287 +1288 +1289 +1290 +1291 +1292 +1293 +1294 +1295 +1296 +1297 +1298 +1299 +1300 +1301 +1302 +1303 +1304 +1305 +1306 +1307 +1308 +1309 +1310 +1311 +1312 +1313 +1314 +1315 +1316 +1317 +1318 +1319 +1320 +1321 +1322 +1323 +1324 +1325 +1326 +1327 +1328 +1329 +1330 +1331 +1332 +1333 +1334 +1335 +1336 +1337 +1338 +1339 +1340 +1341 +1342 +1343 +1344 +1345 +1346 +1347 +1348 +1349 +1350 +1351 +1352 +1353 +1354 +1355 +1356 +1357 +1358 +1359 +1360 +1361 +1362 +1363 +1364 +1365 +1366 +1367 +1368 +1369 +1370 +1371 +1372 +1373 +1374 +1375 +1376 +1377 +1378 +1379 +1380 +1381 +1382 +1383 +1384 +1385 +1386 +1387 +1388 +1389 +1390 +1391 +1392 +1393 +1394 +1395 +1396 +1397 +1398 +1399 +1400 +1401 +1402 +1403 +1404 +1405 +1406 +1407 +1408 +1409 +1410 +1411 +1412 +1413 +1414 +1415 +1416 +1417 +1418 +1419 +1420 +1421 +1422 +1423 +1424 +1425 +1426 +1427 +1428 +1429 +1430 +1431 +1432 +1433 +1434 +1435 +1436 +1437 +1438 +1439 +1440 +1441 +1442 +1443 +1444 +1445 +1446 +1447 +1448 +1449 +1450 +1451 +1452 +1453 +1454 +1455 +1456 +1457 +1458 +1459 +1460 +1461 +1462 +1463 +1464 +1465 +1466 +1467 +1468 +1469 +1470 +1471 +1472 +1473 +1474 +1475 +1476 +1477 +1478 +1479 +1480 +1481 +1482 +1483 +1484 +1485 +1486 +1487 +1488 +1489 +1490 +1491 +1492 +1493 +1494 +1495 +1496 +1497 +1498 +1499 +1500 +1501 +1502 +1503 +1504 +1505 +1506 +1507 +1508 +1509 +1510 +1511 +1512 +1513 +1514 +1515 +1516 +1517 +1518 +1519 +1520 +1521 +1522 +1523 +1524 +1525 +1526 +1527 +1528 +1529 +1530 +1531 +1532 +1533 +1534 +1535 +1536 +1537 +1538 +1539 +1540 +1541 +1542 +1543 +1544 +1545 +1546 +1547 +1548 +1549 +1550 +1551 +1552 +1553 +1554 +1555 +1556 +1557 +1558 +1559 +1560 +1561 +1562 +1563 +1564 +1565 +1566 +1567 +1568 +1569 +1570 +1571 +1572 +1573 +1574 +1575 +1576 +1577 +1578 +1579 +1580 +1581 +1582 +1583 +1584 +1585 +1586 +1587 +1588 +1589 +1590 +1591 +1592 +1593 +1594 +1595 +1596 +1597 +1598 +1599 +1600 +1601 +1602 +1603 +1604 +1605 +1606 +1607 +1608 +1609 +1610 +1611 +1612 +1613 +1614 +1615 +1616 +1617 +1618 +1619 +1620 +1621 +1622 +1623 +1624 +1625 +1626 +1627 +1628 +1629 +1630 +1631 +1632 +1633 +1634 +1635 +1636 +1637 +1638 +1639 +1640 +1641 +1642 +1643 +1644 +1645 +1646 +1647 +1648 +1649 +1650 +1651 +1652 +1653 +1654 +1655 +1656 +1657 +1658 +1659 +1660 +1661 +1662 +1663 +1664 +1665 +1666 +1667 +1668 +1669 +1670 +1671 +1672 +1673 +1674 +1675 +1676 +1677 +1678 +1679 +1680 +1681 +1682 +1683 +1684 +1685 +1686 +1687 +1688 +1689 +1690 +1691 +1692 +1693 +1694 +1695 +1696 +1697 +1698 +1699 +1700 +1701 +1702 +1703 +1704 +1705 +1706 +1707 +1708 +1709 +1710 +1711 +1712 +1713 +1714 +1715 +1716 +1717 +1718 +1719 +1720 +1721 +1722 +1723 +1724 +1725 +1726 +1727 +1728 +1729 +1730 +1731 +1732 +1733 +1734 +1735 +1736 +1737 +1738 +1739 +1740 +1741 +1742 +1743 +1744 +1745 +1746 +1747 +1748 +1749 +1750 +1751 +1752 +1753 +1754 +1755 +1756 +1757 +1758 +1759 +1760 +1761 +1762 +1763 +1764 +1765 +1766 +1767 +1768 +1769 +1770 +1771 +1772 +1773 +1774 +1775 +1776 +1777 +1778 +1779 +1780 +1781 +1782 +1783 +1784 +1785 +1786 +1787 +1788 +1789 +1790 +1791 +1792 +1793 +1794 +1795 +1796 +1797 +1798 +1799 +1800 +1801 +1802 +1803 +1804 +1805 +1806 +1807 +1808 +1809 +1810 +1811 +1812 +1813 +1814 +1815 +1816 +1817 +1818 +1819 +1820 +1821 +1822 +1823 +1824 +1825 +1826 +1827 +1828 +1829 +1830 +1831 +1832 +1833 +1834 +1835 +1836 +1837 +1838 +183913x +13x +13x +13x +13x +13x +13x +13x +13x +  +13x +  +  +  +  +13x +  +  +  +  +  +  +  +  +  +  +  +13x +13x +  +  +13x +  +13x +  +13x +13x +13x +  +13x +  +13x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +13x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +13x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +13x +  +  +  +  +  +  +  +13x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +13x +  +  +  +13x +  +  +7x +7x +  +  +7x +7x +36x +36x +36x +  +  +  +7x +7x +35x +35x +35x +70x +  +  +7x +7x +3x +3x +3x +6x +  +  +7x +7x +  +  +  +7x +  +  +  +  +  +7x +  +35x +35x +35x +35x +  +  +  +  +  +7x +  +3x +3x +3x +3x +  +  +  +  +  +  +  +  +  +7x +4x +4x +  +  +7x +7x +  +  +  +  +  +  +  +  +  +  +5x +5x +5x +3x +  +  +  +  +2x +2x +1x +  +1x +  +  +  +  +  +  +  +  +  +  +2x +2x +2x +2x +1x +  +1x +  +  +  +  +  +13x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +13x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +13x +  +  +  +  +3x +  +3x +90x +  +90x +  +  +90x +  +  +  +  +  +  +  +90x +90x +180x +90x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +90x +  +  +  +90x +90x +90x +3x +  +  +  +174x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +13x +  +  +  +  +2x +2x +  +  +  +  +  +  +  +2x +  +  +  +2x +60x +  +  +60x +60x +60x +60x +  +  +  +  +  +  +  +60x +60x +  +120x +  +  +  +  +60x +60x +60x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +60x +  +  +  +60x +60x +60x +2x +  +  +  +116x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +13x +3x +3x +  +3x +  +  +  +3x +  +  +  +  +  +13x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +13x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +13x +  +  +  +  +  +  +13x +21x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +13x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +13x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +13x +  +  +  +  +  +  +  +  +  +  +  +  +  +13x +  +  +  +  +  +  +  +13x +  +  +  +  +  +13x +28x +28x +26x +  +2x +3x +3x +3x +3x +  +  +2x +  +  +  +  +  +13x +23x +23x +21x +  +2x +3x +3x +3x +3x +  +  +2x +  +  +13x +  +24x +24x +21x +  +3x +7x +7x +7x +4x +  +  +3x +  +  +  +  +  +  +  +  +13x +  +  +19x +58x +  +  +  +  +  +  +  +  +  +  +  +13x +17x +17x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +9x +  +4x +  +  +  +  +  +  +  +3x +  +1x +  +1x +  +  +  +13x +18x +18x +18x +  +  +  +36x +14x +14x +9x +9x +9x +9x +  +  +18x +  +  +13x +  +  +  +11x +3x +  +8x +2x +  +6x +5x +  +1x +  +  +  +  +  +1x +  +3x +  +  +1x +  +  +13x +21x +21x +21x +  +  +  +42x +17x +17x +11x +11x +11x +11x +  +  +21x +  +  +  +10x +  +4x +  +  +  +  +  +  +1x +  +  +  +  +  +  +4x +  +  +  +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +13x +21x +21x +  +  +  +  +  +21x +  +  +  +19x +  +2x +  +  +  +  +2x +  +  +19x +19x +19x +19x +  +  +  +  +3x +  +  +  +  +16x +  +  +  +5x +  +  +  +  +5x +  +11x +1x +  +10x +10x +10x +10x +10x +10x +  +19x +  +  +  +  +  +  +  +  +13x +  +  +9x +  +1x +  +  +  +  +8x +8x +  +  +8x +8x +  +  +8x +8x +1x +  +  +  +8x +1x +1x +1x +1x +  +  +8x +  +  +8x +8x +  +  +  +8x +8x +3x +3x +  +  +2x +1x +1x +  +  +  +  +3x +  +3x +1x +1x +1x +  +  +  +  +8x +2x +  +  +  +8x +8x +3x +  +  +8x +  +  +8x +  +  +  +  +  +  +  +  +8x +  +  +  +6x +  +2x +  +  +  +  +2x +  +  +6x +6x +3x +  +  +3x +  +  +  +3x +  +3x +3x +3x +3x +  +3x +  +  +  +  +3x +  +  +  +  +  +  +  +  +13x +6x +  +  +  +  +  +  +  +  +13x +  +  +  +  +6x +  +6x +  +6x +  +  +  +6x +  +  +  +  +  +6x +  +  +  +  +  +  +  +13x +  +  +  +18x +  +10x +10x +15x +15x +  +15x +  +  +  +  +6x +  +  +  +  +  +12x +  +2x +  +  +  +  +  +4x +  +9x +9x +3x +  +  +  +  +  +  +  +10x +2x +2x +2x +  +  +  +  +2x +  +  +  +  +  +  +  +4x +5x +3x +3x +  +  +  +  +  +2x +  +  +  +  +  +  +  +  +  +  +  +  +13x +  +5x +  +5x +5x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +24x +  +  +  +  +  +13x +  +  +  +  +  +  +  +13x +16x +3x +  +13x +  +  +  +3x +  +  +  +1x +1x +  +  +  +  +13x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +13x +21x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +13x +  +  +  +  +  +  +  +  +  +13x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +13x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +13x +276x +213x +  +  +63x +63x +63x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +13x +13x +13x +13x +13x +3x +  +  +  +13x +14x +7x +  +7x +7x +2x +  +5x +5x +  +5x +  +  +  +13x +  +13x +  +  +21x +21x +21x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +13x +  +  +  +  +  +  +13x +  +  +  +  +  +  +13x +21x +  +  +  +  +  + 
import * as core from '@actions/core'
+import * as fs from 'fs'
+import * as path from 'path'
+import { spawn } from 'child_process'
+import * as k8s from '@kubernetes/client-node'
+import tar from 'tar-fs'
+import * as stream from 'stream'
+import { WritableStreamBuffer } from 'stream-buffers'
+import { createHash } from 'crypto'
+import type { ContainerInfo, Registry } from 'hooklib'
+import {
+  getSecretName,
+  JOB_CONTAINER_NAME,
+  RunnerInstanceLabel
+} from '../hooks/constants'
+import {
+  PodPhase,
+  formatError,
+  mergePodSpecWithOptions,
+  mergeObjectMeta,
+  fixArgs,
+  listDirAllCommand,
+  sleep,
+  EXTERNALS_VOLUME_NAME,
+  GITHUB_VOLUME_NAME,
+  WORK_VOLUME
+} from './utils'
+import * as shlex from 'shlex'
+import { parsePositiveMsEnv, WebSocketHeartbeat } from './heartbeat'
+import type { HeartbeatWebSocket } from './heartbeat'
+ 
+const kc = new k8s.KubeConfig()
+ 
+kc.loadFromDefault()
+ 
+const k8sApi = kc.makeApiClient(k8s.CoreV1Api)
+const k8sBatchV1Api = kc.makeApiClient(k8s.BatchV1Api)
+const k8sAuthorizationV1Api = kc.makeApiClient(k8s.AuthorizationV1Api)
+ 
+const DEFAULT_WAIT_FOR_POD_TIME_SECONDS = 10 * 60 // 10 min
+ 
+export const requiredPermissions = [
+  {
+    group: '',
+    verbs: ['get', 'list', 'create', 'delete'],
+    resource: 'pods',
+    subresource: ''
+  },
+  {
+    group: '',
+    verbs: ['get', 'create'],
+    resource: 'pods',
+    subresource: 'exec'
+  },
+  {
+    group: '',
+    verbs: ['get', 'list', 'watch'],
+    resource: 'pods',
+    subresource: 'log'
+  },
+  {
+    group: '',
+    verbs: ['create', 'delete', 'get', 'list'],
+    resource: 'secrets',
+    subresource: ''
+  }
+]
+ 
+export async function createJobPod(
+  name: string,
+  jobContainer?: k8s.V1Container,
+  services?: k8s.V1Container[],
+  registry?: Registry,
+  extension?: k8s.V1PodTemplateSpec
+): Promise<k8s.V1Pod> {
+  const containers: k8s.V1Container[] = []
+  if (jobContainer) {
+    containers.push(jobContainer)
+  }
+  if (services?.length) {
+    containers.push(...services)
+  }
+ 
+  const appPod = new k8s.V1Pod()
+ 
+  appPod.apiVersion = 'v1'
+  appPod.kind = 'Pod'
+ 
+  appPod.metadata = new k8s.V1ObjectMeta()
+  appPod.metadata.name = name
+ 
+  const instanceLabel = new RunnerInstanceLabel()
+  appPod.metadata.labels = {
+    [instanceLabel.key]: instanceLabel.value
+  }
+  appPod.metadata.annotations = {}
+ 
+  appPod.spec = new k8s.V1PodSpec()
+  appPod.spec.containers = containers
+  appPod.spec.securityContext = {
+    fsGroup: 1001
+  }
+ 
+  // Extract working directory from GITHUB_WORKSPACE
+  // GITHUB_WORKSPACE is like /__w/repo-name/repo-name
+  const githubWorkspace = process.env.GITHUB_WORKSPACE
+  const workingDirPath = githubWorkspace?.split('/').slice(-2).join('/') ?? ''
+ 
+  const initCommands = [
+    'mkdir -p /mnt/externals',
+    'mkdir -p /mnt/work',
+    'mkdir -p /mnt/github',
+    'mv /home/runner/externals/* /mnt/externals/'
+  ]
+ 
+  if (workingDirPath) {
+    initCommands.push(`mkdir -p /mnt/work/${workingDirPath}`)
+  }
+ 
+  appPod.spec.initContainers = [
+    {
+      name: 'fs-init',
+      image:
+        process.env.ACTIONS_RUNNER_IMAGE ||
+        'ghcr.io/actions/actions-runner:latest',
+      command: ['sh', '-c', initCommands.join(' && ')],
+      securityContext: {
+        runAsGroup: 1001,
+        runAsUser: 1001
+      },
+      volumeMounts: [
+        {
+          name: EXTERNALS_VOLUME_NAME,
+          mountPath: '/mnt/externals'
+        },
+        {
+          name: WORK_VOLUME,
+          mountPath: '/mnt/work'
+        },
+        {
+          name: GITHUB_VOLUME_NAME,
+          mountPath: '/mnt/github'
+        }
+      ]
+    }
+  ]
+ 
+  appPod.spec.restartPolicy = 'Never'
+ 
+  appPod.spec.volumes = [
+    {
+      name: EXTERNALS_VOLUME_NAME,
+      emptyDir: {}
+    },
+    {
+      name: GITHUB_VOLUME_NAME,
+      emptyDir: {}
+    },
+    {
+      name: WORK_VOLUME,
+      emptyDir: {}
+    }
+  ]
+ 
+  if (registry) {
+    const secret = await createDockerSecret(registry)
+    if (!secret?.metadata?.name) {
+      throw new Error(`created secret does not have secret.metadata.name`)
+    }
+    const secretReference = new k8s.V1LocalObjectReference()
+    secretReference.name = secret.metadata.name
+    appPod.spec.imagePullSecrets = [secretReference]
+  }
+ 
+  if (extension?.metadata) {
+    mergeObjectMeta(appPod, extension.metadata)
+  }
+ 
+  if (extension?.spec) {
+    mergePodSpecWithOptions(appPod.spec, extension.spec)
+  }
+ 
+  return await k8sApi.createNamespacedPod({
+    namespace: namespace(),
+    body: appPod
+  })
+}
+ 
+export async function createContainerStepPod(
+  name: string,
+  container: k8s.V1Container,
+  extension?: k8s.V1PodTemplateSpec
+): Promise<k8s.V1Pod> {
+  const appPod = new k8s.V1Pod()
+ 
+  appPod.apiVersion = 'v1'
+  appPod.kind = 'Pod'
+ 
+  appPod.metadata = new k8s.V1ObjectMeta()
+  appPod.metadata.name = name
+ 
+  const instanceLabel = new RunnerInstanceLabel()
+  appPod.metadata.labels = {
+    [instanceLabel.key]: instanceLabel.value
+  }
+  appPod.metadata.annotations = {}
+ 
+  appPod.spec = new k8s.V1PodSpec()
+  appPod.spec.containers = [container]
+ 
+  appPod.spec.restartPolicy = 'Never'
+ 
+  appPod.spec.volumes = [
+    {
+      name: EXTERNALS_VOLUME_NAME,
+      emptyDir: {}
+    },
+    {
+      name: GITHUB_VOLUME_NAME,
+      emptyDir: {}
+    },
+    {
+      name: WORK_VOLUME,
+      emptyDir: {}
+    }
+  ]
+ 
+  if (extension?.metadata) {
+    mergeObjectMeta(appPod, extension.metadata)
+  }
+ 
+  if (extension?.spec) {
+    mergePodSpecWithOptions(appPod.spec, extension.spec)
+  }
+ 
+  return await k8sApi.createNamespacedPod({
+    namespace: namespace(),
+    body: appPod
+  })
+}
+ 
+export async function deletePod(name: string): Promise<void> {
+  await k8sApi.deleteNamespacedPod({
+    name,
+    namespace: namespace(),
+    gracePeriodSeconds: 0
+  })
+}
+ 
+export async function execPodStep(
+  command: string[],
+  podName: string,
+  containerName: string,
+  stdin?: stream.Readable
+): Promise<number> {
+  const exec = new k8s.Exec(kc)
+  core.debug(
+    `[execPodStep] Starting: cmd="${command[0]}" (${command.length} args), pod=${podName}, container=${containerName}`
+  )
+ 
+  command = fixArgs(command)
+ 
+  const DEFAULT_PING_PERIOD_MS = 5000
+  const pingPeriodMs = parsePositiveMsEnv(
+    process.env.ACTIONS_RUNNER_HEARTBEAT_PERIOD_MS,
+    DEFAULT_PING_PERIOD_MS
+  )
+  const pongDeadlineMs = parsePositiveMsEnv(
+    process.env.ACTIONS_RUNNER_HEARTBEAT_DEADLINE_MS,
+    pingPeriodMs * 12 + 1000
+  )
+  core.debug(
+    `[execPodStep] Heartbeat config: pingPeriodMs=${pingPeriodMs}, pongDeadlineMs=${pongDeadlineMs}`
+  )
+ 
+  const heartbeat = new WebSocketHeartbeat(pingPeriodMs, pongDeadlineMs)
+ 
+  return new Promise<number>((resolve, reject) => {
+    core.debug('[execPodStep] About to call exec.exec')
+    let ws: HeartbeatWebSocket | null = null
+ 
+    exec
+      .exec(
+        namespace(),
+        podName,
+        containerName,
+        command,
+        process.stdout,
+        process.stderr,
+        stdin ?? null,
+        false /* tty */,
+        async resp => {
+          core.debug(
+            `[execPodStep] execPodStep response: ${JSON.stringify(resp)}`
+          )
+ 
+          heartbeat.stop()
+ 
+          // Close WebSocket and wait for it before resolving/rejecting
+          const closeWebSocket = async (): Promise<void> => {
+            const socket = ws
+            if (
+              socket &&
+              (socket.readyState === 1 || socket.readyState === 0)
+            ) {
+              return new Promise<void>(closeResolve => {
+                const closeTimeout = setTimeout(() => {
+                  core.warning(
+                    '[execPodStep] WebSocket close timeout, forcing cleanup'
+                  )
+                  closeResolve()
+                }, 5000)
+ 
+                socket.once('close', () => {
+                  clearTimeout(closeTimeout)
+                  core.debug('[execPodStep] WebSocket closed cleanly')
+                  closeResolve()
+                })
+                socket.close()
+              })
+            }
+          }
+ 
+          if (resp.status === 'Success') {
+            core.debug(`[execPodStep] Success, code: ${resp.code}`)
+            await closeWebSocket()
+            resolve(resp.code || 0)
+          } else {
+            core.debug(
+              `[execPodStep] Failure: ${JSON.stringify({ message: resp?.message, details: resp?.details })}`
+            )
+            await closeWebSocket()
+            reject(new Error(resp?.message || 'execPodStep failed'))
+          }
+        }
+      )
+      .then(websocket => {
+        core.debug('[execPodStep] exec.exec resolved, ws object received')
+        ws = websocket
+        if (ws) {
+          heartbeat.start(ws, reject)
+        } else {
+          core.warning('[Heartbeat] WebSocket is null, heartbeat not started')
+        }
+      })
+      .catch(async e => {
+        heartbeat.stop()
+        core.error(`[execPodStep] exec.exec threw error: ${e}`)
+ 
+        // Close WebSocket before rejecting with timeout protection
+        const socket = ws
+        if (socket && (socket.readyState === 1 || socket.readyState === 0)) {
+          await new Promise<void>(closeResolve => {
+            const closeTimeout = setTimeout(() => {
+              core.warning(
+                '[execPodStep] WebSocket close timeout in error handler'
+              )
+              closeResolve()
+            }, 5000)
+ 
+            socket.once('close', () => {
+              clearTimeout(closeTimeout)
+              closeResolve()
+            })
+            socket.close()
+          })
+        }
+ 
+        reject(e)
+      })
+  })
+}
+ 
+// Variant of execPodStep that also captures the last `tailLines` lines of
+// combined stdout/stderr so callers can surface the script's own output on
+// failure. Returns the exit code plus the tail (empty string on success or if
+// nothing was emitted). The original streams are still tee'd to
+// process.stdout/process.stderr so GitHub Actions logs are unchanged.
+export async function execPodStepWithOutput(
+  command: string[],
+  podName: string,
+  containerName: string,
+  tailLines = 20,
+  stdin?: stream.Readable
+): Promise<{ code: number; output: string }> {
+  const exec = new k8s.Exec(kc)
+  command = fixArgs(command)
+ 
+  // Ring buffer of the last N non-empty lines (cap to keep memory bounded).
+  const buffer: string[] = []
+  const push = (line: string): void => {
+    Iif (line.length === 0) return
+    buffer.push(line)
+    if (buffer.length > tailLines) buffer.shift()
+  }
+ 
+  // Separate pending buffers per stream to prevent stdout/stderr interleaving.
+  let pendingOut = ''
+  const ingestOut = (chunk: Buffer | string): void => {
+    pendingOut += chunk.toString('utf8')
+    const lines = pendingOut.split(/\r?\n/)
+    pendingOut = lines.pop() ?? ''
+    for (const line of lines) push(line)
+  }
+ 
+  let pendingErr = ''
+  const ingestErr = (chunk: Buffer | string): void => {
+    pendingErr += chunk.toString('utf8')
+    const lines = pendingErr.split(/\r?\n/)
+    pendingErr = lines.pop() ?? ''
+    for (const line of lines) push(line)
+  }
+ 
+  const flushPending = (): void => {
+    Iif (pendingOut) {
+      push(pendingOut)
+      pendingOut = ''
+    }
+    Iif (pendingErr) {
+      push(pendingErr)
+      pendingErr = ''
+    }
+  }
+ 
+  const capture = new stream.Writable({
+    write(chunk: Buffer | string, _enc, cb) {
+      try {
+        ingestOut(chunk)
+        process.stdout.write(chunk)
+        cb()
+      } catch (e) {
+        cb(e as Error)
+      }
+    }
+  })
+  const captureErr = new stream.Writable({
+    write(chunk: Buffer | string, _enc, cb) {
+      try {
+        ingestErr(chunk)
+        process.stderr.write(chunk)
+        cb()
+      } catch (e) {
+        cb(e as Error)
+      }
+    }
+  })
+ 
+  // Parse an exit code from a k8s exec error/status message.
+  // Handles both "command terminated with exit code N" and
+  // "command terminated with non-zero exit code: command terminated with exit code N".
+  const parseExitCode = (msg: string | undefined): number | null => {
+    const m = msg?.match(/exit code[:\s]+(\d+)/i)
+    return m ? parseInt(m[1], 10) : null
+  }
+ 
+  return await new Promise(function (resolve, reject) {
+    exec
+      .exec(
+        namespace(),
+        podName,
+        containerName,
+        command,
+        capture,
+        captureErr,
+        stdin ?? null,
+        false /* tty */,
+        resp => {
+          core.debug(`execPodStepWithOutput response: ${JSON.stringify(resp)}`)
+          flushPending()
+          if (resp.status === 'Success') {
+            resolve({ code: resp.code || 0, output: buffer.join('\n') })
+          } else {
+            // k8s exec returns status='Failure' for non-zero script exit.
+            // resp.code may be undefined depending on k8s version; fall back
+            // to parsing the exit code from the message string.
+            const code = parseExitCode(resp?.message)
+            if (code !== null) {
+              resolve({ code, output: buffer.join('\n') })
+            } else {
+              reject(new Error(resp?.message || 'execPodStepWithOutput failed'))
+            }
+          }
+        }
+      )
+      .catch(e => {
+        // In @kubernetes/client-node v1.x the promise returned by exec()
+        // itself rejects for non-zero exits (the status callback may or may
+        // not fire first). Detect this case via the error message so the
+        // caller can classify the error instead of treating it as a hook
+        // failure. Genuine failures (connection drop, etc.) still reject.
+        flushPending()
+        const errMsg = e instanceof Error ? e.message : String(e)
+        const code = parseExitCode(errMsg)
+        if (code !== null) {
+          resolve({ code, output: buffer.join('\n') })
+        } else {
+          reject(e)
+        }
+      })
+  })
+}
+ 
+export async function execCalculateOutputHashSorted(
+  podName: string,
+  containerName: string,
+  command: string[]
+): Promise<{ hash: string; lines: string[] }> {
+  const exec = new k8s.Exec(kc)
+ 
+  let output = ''
+  const outputWriter = new stream.Writable({
+    write(chunk, _enc, cb) {
+      try {
+        output += chunk.toString('utf8')
+        cb()
+      } catch (e) {
+        cb(e as Error)
+      }
+    }
+  })
+ 
+  await new Promise<void>((resolve, reject) => {
+    exec
+      .exec(
+        namespace(),
+        podName,
+        containerName,
+        command,
+        outputWriter, // capture stdout
+        process.stderr,
+        null,
+        false /* tty */,
+        resp => {
+          core.debug(`internalExecOutput response: ${JSON.stringify(resp)}`)
+          if (resp.status === 'Success') {
+            resolve()
+          } else {
+            core.debug(
+              JSON.stringify({
+                message: resp?.message,
+                details: resp?.details
+              })
+            )
+            reject(new Error(resp?.message || 'internalExecOutput failed'))
+          }
+        }
+      )
+      .catch(e => reject(e))
+  })
+ 
+  outputWriter.end()
+ 
+  // Sort lines for consistent ordering across platforms
+  const lines = output
+    .split('\n')
+    .filter(line => line.length > 0)
+    .sort()
+  const sortedOutput = lines.join('\n') + '\n'
+ 
+  const hash = createHash('sha256')
+  hash.update(sortedOutput)
+  return { hash: hash.digest('hex'), lines }
+}
+ 
+export async function localCalculateOutputHashSorted(
+  commands: string[]
+): Promise<{ hash: string; lines: string[] }> {
+  return await new Promise<{ hash: string; lines: string[] }>(
+    (resolve, reject) => {
+      const child = spawn(commands[0], commands.slice(1), {
+        stdio: ['ignore', 'pipe', 'ignore']
+      })
+ 
+      let output = ''
+      child.stdout.on('data', chunk => {
+        output += chunk.toString('utf8')
+      })
+      child.on('error', reject)
+      child.on('close', (code: number) => {
+        if (code === 0) {
+          // Sort lines for consistent ordering across distributions/platforms
+          const lines = output
+            .split('\n')
+            .filter(line => line.length > 0)
+            .sort()
+          const sortedOutput = lines.join('\n') + '\n'
+ 
+          const hash = createHash('sha256')
+          hash.update(sortedOutput)
+          resolve({ hash: hash.digest('hex'), lines })
+        } else {
+          reject(new Error(`child process exited with code ${code}`))
+        }
+      })
+    }
+  )
+}
+ 
+export async function execCpToPod(
+  podName: string,
+  runnerPath: string,
+  containerPath: string
+): Promise<void> {
+  core.debug(`Copying ${runnerPath} to pod ${podName} at ${containerPath}`)
+ 
+  let attempt = 0
+  while (Itrue) {
+    try {
+      const exec = new k8s.Exec(kc)
+      // Use tar to extract with --no-same-owner to avoid ownership issues.
+      // Then use find to fix permissions. The -m flag helps but we also need to fix permissions after.
+      const command = [
+        'sh',
+        '-c',
+        `tar xf - --no-same-owner -C ${shlex.quote(containerPath)} 2>/dev/null; ` +
+          `find ${shlex.quote(containerPath)} -type f -exec chmod u+rw {} \\; 2>/dev/null; ` +
+          `find ${shlex.quote(containerPath)} -type d -exec chmod u+rwx {} \\; 2>/dev/null; ` +
+          `sync 2>/dev/null || true`
+      ]
+      const readStream = tar.pack(runnerPath)
+      const errStream = new WritableStreamBuffer()
+      await new Promise((resolve, reject) => {
+        exec
+          .exec(
+            namespace(),
+            podName,
+            JOB_CONTAINER_NAME,
+            command,
+            null,
+            errStream,
+            readStream,
+            false,
+            async status => {
+              if (errStream.size()) {
+                return reject(
+                  new Error(
+                    `Error from execCpToPod - status: ${status.status}, details: \n ${errStream.getContentsAsString()}`
+                  )
+                )
+              }
+              resolve(status)
+            }
+          )
+          .catch(e => reject(e))
+      })
+      break
+    } catch (error) {
+      core.debug(`cpToPod: Attempt ${attempt + 1} failed: ${error}`)
+      attempt++
+      if (attempt >= 30) {
+        throw new Error(
+          `cpToPod failed after ${attempt} attempts: ${formatError(error)}`
+        )
+      }
+      await sleep(1000)
+    }
+  }
+ 
+  let attempts = 15
+  const delay = 1000
+  for (let i = 0; i < attempts; i++) {
+    try {
+      const { hash: want, lines: wantLines } =
+        await localCalculateOutputHashSorted([
+          'sh',
+          '-c',
+          listDirAllCommand(runnerPath)
+        ])
+ 
+      const { hash: got, lines: gotLines } =
+        await execCalculateOutputHashSorted(podName, JOB_CONTAINER_NAME, [
+          'sh',
+          '-c',
+          listDirAllCommand(containerPath)
+        ])
+ 
+      if (got !== want) {
+        core.debug(
+          `[cpToPod hash mismatch attempt ${i + 1}/${attempts}] want='${want}' got='${got}'`
+        )
+        core.debug(
+          `[cpToPod] runner file count=${wantLines.length} pod file count=${gotLines.length}`
+        )
+        const wantMap = new Map(
+          wantLines.map(l => [l.replace(/^\d+ /, ''), l.split(' ')[0]])
+        )
+        const gotMap = new Map(
+          gotLines.map(l => [l.replace(/^\d+ /, ''), l.split(' ')[0]])
+        )
+        const onlyInWant = wantLines.filter(
+          l => !gotMap.has(l.replace(/^\d+ /, ''))
+        )
+        const onlyInGot = gotLines.filter(
+          l => !wantMap.has(l.replace(/^\d+ /, ''))
+        )
+        const sizeDiff = wantLines
+          .filter(l => {
+            const name = l.replace(/^\d+ /, '')
+            return gotMap.has(name) && gotMap.get(name) !== wantMap.get(name)
+          })
+          .map(l => {
+            const name = l.replace(/^\d+ /, '')
+            return `${name}: runner=${wantMap.get(name)} pod=${gotMap.get(name)}`
+          })
+        core.debug(`[cpToPod] only in runner: ${JSON.stringify(onlyInWant)}`)
+        core.debug(`[cpToPod] only in pod:    ${JSON.stringify(onlyInGot)}`)
+        core.debug(`[cpToPod] size mismatch:  ${JSON.stringify(sizeDiff)}`)
+        await sleep(delay)
+        continue
+      }
+ 
+      break
+    } catch (error) {
+      core.debug(`Attempt ${i + 1} failed: ${error}`)
+      await sleep(delay)
+    }
+  }
+}
+ 
+export async function execCpFromPod(
+  podName: string,
+  containerPath: string,
+  parentRunnerPath: string
+): Promise<void> {
+  const targetRunnerPath = `${parentRunnerPath}/${path.basename(containerPath)}`
+  core.debug(
+    `Copying from pod ${podName} ${containerPath} to ${targetRunnerPath}`
+  )
+ 
+  // Clear target before extracting so deleted-on-pod files don't linger locally.
+  // tar.extract() appends into the destination; without this, stale files (e.g.
+  // git-credentials removed by checkout cleanup inside the pod) cause a permanent
+  // hash mismatch that no amount of retrying can resolve.
+  Iif (fs.existsSync(targetRunnerPath)) {
+    fs.rmSync(targetRunnerPath, { recursive: true, force: true })
+  }
+ 
+  let attempt = 0
+  while (Itrue) {
+    try {
+      // make temporary directory
+      const exec = new k8s.Exec(kc)
+      const containerPaths = containerPath.split('/')
+      const dirname = containerPaths.pop() as string
+      const command = [
+        'tar',
+        'cf',
+        '-',
+        '-C',
+        containerPaths.join('/') || '/',
+        dirname
+      ]
+      const writerStream = tar.extract(parentRunnerPath)
+      const errStream = new WritableStreamBuffer()
+ 
+      await new Promise((resolve, reject) => {
+        // Resolve only after writerStream finishes flushing to disk.
+        // The k8s status callback fires when the pod-side tar process exits,
+        // but tar-fs may still be writing buffered data to the local filesystem.
+        // Waiting for 'finish' ensures all files are on disk before hash check.
+        writerStream.on('finish', resolve)
+        writerStream.on('error', reject)
+        exec
+          .exec(
+            namespace(),
+            podName,
+            JOB_CONTAINER_NAME,
+            command,
+            writerStream,
+            errStream,
+            null,
+            false,
+            async (_s: k8s.V1Status) => {
+              if (errStream.size()) {
+                return reject(
+                  new Error(
+                    `Error from cpFromPod - details: \n ${errStream.getContentsAsString()}`
+                  )
+                )
+              }
+            }
+          )
+          .catch(e => reject(e))
+      })
+      break
+    } catch (error) {
+      core.debug(`Attempt ${attempt + 1} failed: ${error}`)
+      attempt++
+      if (attempt >= 30) {
+        throw new Error(
+          `execCpFromPod failed after ${attempt} attempts: ${formatError(error)}`
+        )
+      }
+      await sleep(1000)
+    }
+  }
+ 
+  let attempts = 15
+  const delay = 1000
+  for (let i = 0; i < attempts; i++) {
+    try {
+      const { hash: want, lines: wantLines } =
+        await execCalculateOutputHashSorted(podName, JOB_CONTAINER_NAME, [
+          'sh',
+          '-c',
+          listDirAllCommand(containerPath)
+        ])
+ 
+      const { hash: got, lines: gotLines } =
+        await localCalculateOutputHashSorted([
+          'sh',
+          '-c',
+          listDirAllCommand(targetRunnerPath)
+        ])
+ 
+      if (got !== want) {
+        core.debug(
+          `[cpFromPod hash mismatch attempt ${i + 1}/${attempts}] want='${want}' got='${got}'`
+        )
+        core.debug(
+          `[cpFromPod] pod file count=${wantLines.length} runner file count=${gotLines.length}`
+        )
+        const wantMap = new Map(
+          wantLines.map(l => [l.replace(/^\d+ /, ''), l.split(' ')[0]])
+        )
+        const gotMap = new Map(
+          gotLines.map(l => [l.replace(/^\d+ /, ''), l.split(' ')[0]])
+        )
+        const onlyInWant = wantLines.filter(
+          l => !gotMap.has(l.replace(/^\d+ /, ''))
+        )
+        const onlyInGot = gotLines.filter(
+          l => !wantMap.has(l.replace(/^\d+ /, ''))
+        )
+        const sizeDiff = wantLines
+          .filter(l => {
+            const name = l.replace(/^\d+ /, '')
+            return gotMap.has(name) && gotMap.get(name) !== wantMap.get(name)
+          })
+          .map(l => {
+            const name = l.replace(/^\d+ /, '')
+            return `${name}: pod=${wantMap.get(name)} runner=${gotMap.get(name)}`
+          })
+        core.debug(`[cpFromPod] only in pod:    ${JSON.stringify(onlyInWant)}`)
+        core.debug(`[cpFromPod] only in runner: ${JSON.stringify(onlyInGot)}`)
+        core.debug(`[cpFromPod] size mismatch:  ${JSON.stringify(sizeDiff)}`)
+        await sleep(delay)
+        continue
+      }
+ 
+      break
+    } catch (error) {
+      core.debug(`Attempt ${i + 1} failed: ${error}`)
+      await sleep(delay)
+    }
+  }
+}
+ 
+export async function waitForJobToComplete(jobName: string): Promise<void> {
+  const backOffManager = new BackOffManager()
+  while (Itrue) {
+    try {
+      if (await isJobSucceeded(jobName)) {
+        return
+      }
+    } catch (error) {
+      throw new Error(`job ${jobName} has failed: ${formatError(error)}`)
+    }
+    await backOffManager.backOff()
+  }
+}
+ 
+export async function createDockerSecret(
+  registry: Registry
+): Promise<k8s.V1Secret> {
+  const authContent = {
+    auths: {
+      [registry.serverUrl || 'https://index.docker.io/v1/']: {
+        username: registry.username,
+        password: registry.password,
+        auth: Buffer.from(`${registry.username}:${registry.password}`).toString(
+          'base64'
+        )
+      }
+    }
+  }
+ 
+  const runnerInstanceLabel = new RunnerInstanceLabel()
+ 
+  const secretName = getSecretName()
+  const secret = new k8s.V1Secret()
+  secret.immutable = true
+  secret.apiVersion = 'v1'
+  secret.metadata = new k8s.V1ObjectMeta()
+  secret.metadata.name = secretName
+  secret.metadata.namespace = namespace()
+  secret.metadata.labels = {
+    [runnerInstanceLabel.key]: runnerInstanceLabel.value
+  }
+  secret.type = 'kubernetes.io/dockerconfigjson'
+  secret.kind = 'Secret'
+  secret.data = {
+    '.dockerconfigjson': Buffer.from(JSON.stringify(authContent)).toString(
+      'base64'
+    )
+  }
+ 
+  return await k8sApi.createNamespacedSecret({
+    namespace: namespace(),
+    body: secret
+  })
+}
+ 
+export async function createSecretForEnvs(envs: {
+  [key: string]: string
+}): Promise<string> {
+  const runnerInstanceLabel = new RunnerInstanceLabel()
+ 
+  const secret = new k8s.V1Secret()
+  const secretName = getSecretName()
+  secret.immutable = true
+  secret.apiVersion = 'v1'
+  secret.metadata = new k8s.V1ObjectMeta()
+  secret.metadata.name = secretName
+ 
+  secret.metadata.labels = {
+    [runnerInstanceLabel.key]: runnerInstanceLabel.value
+  }
+  secret.kind = 'Secret'
+  secret.data = {}
+  for (const [key, value] of Object.entries(envs)) {
+    secret.data[key] = Buffer.from(value).toString('base64')
+  }
+ 
+  await k8sApi.createNamespacedSecret({
+    namespace: namespace(),
+    body: secret
+  })
+  return secretName
+}
+ 
+export async function deleteSecret(name: string): Promise<void> {
+  await k8sApi.deleteNamespacedSecret({
+    name,
+    namespace: namespace()
+  })
+}
+ 
+export async function pruneSecrets(): Promise<void> {
+  const secretList = await k8sApi.listNamespacedSecret({
+    namespace: namespace(),
+    labelSelector: new RunnerInstanceLabel().toString()
+  })
+  if (!secretList.items.length) {
+    return
+  }
+ 
+  await Promise.all(
+    secretList.items.map(
+      async secret =>
+        secret.metadata?.name && (await deleteSecret(secret.metadata.name))
+    )
+  )
+}
+ 
+export const UNRECOVERABLE_WAITING_REASONS = new Set([
+  // k8s has already retried image pull multiple times with exponential backoff.
+  // ErrImagePull is excluded: it fires on the first failure (could be a transient
+  // TLS timeout or network blip) and k8s will naturally promote it to
+  // ImagePullBackOff after a moment. Fast-failing on ErrImagePull would kill
+  // jobs that would have succeeded on the next pull attempt.
+  'ImagePullBackOff',
+  // Image name is syntactically invalid — cannot self-heal without a config fix.
+  'InvalidImageName',
+  // Container spec is invalid (bad env vars, resource limits, securityContext) —
+  // cannot self-heal without a config fix.
+  'CreateContainerConfigError'
+  // CreateContainerError is excluded: it is sometimes emitted transiently by the
+  // container runtime (e.g. during a node-level runtime restart). It can
+  // self-resolve on the next kubelet retry cycle.
+])
+ 
+// Pod *event* reasons (from the event stream, not container status) that
+// indicate a permanent failure the pod will never recover from on its own.
+// These surface as Warning events on the pod (visible via `kubectl describe`)
+// rather than in container.status.state.waiting.reason, so they need a separate
+// list + a separate (async) detection path.
+//
+//   - FailedMount: a volume cannot be mounted (e.g. hostPath `type: Directory`
+//     pointing at a path that does not exist on the node, missing PVC, missing
+//     Secret/ConfigMap volume). The container stays in `ContainerCreating`
+//     waiting state, which is NOT in UNRECOVERABLE_WAITING_REASONS, so without
+//     this check the hook polls until the 3600s timeout.
+//   - FailedBinding: a PVC could not be bound (no matching PV, storage class
+//     misconfiguration). Usually paired with FailedMount once the pod retries.
+//
+// FailedScheduling is included but gated by PERMANENT_SCHEDULING_PATTERNS:
+// only messages that positively identify a permanent configuration error
+// trigger fast-fail. Resource shortages ("Insufficient cpu/memory/gpu")
+// are silently skipped so the pod keeps queuing until the timeout.
+export const UNRECOVERABLE_EVENT_REASONS = new Set([
+  'FailedMount',
+  'FailedBinding',
+  'FailedScheduling'
+])
+ 
+// Patterns that POSITIVELY IDENTIFY a permanent, unrecoverable scheduling
+// failure in a FailedScheduling event message. Fast-fail fires ONLY when
+// one of these matches. Anything else (resource shortages, unknown format,
+// absent message) is treated as transient — the pod keeps queuing.
+//
+// Permanent examples (WILL fast-fail):
+//   "0/3 nodes: 3 node(s) didn't match Pod's node affinity/selector."
+//   "0/3 nodes: 3 node(s) had untolerated taint {gpu: true}."
+//   "0/3 nodes: persistentvolumeclaim "my-pvc" not found."
+//
+// Transient examples (will NOT fast-fail, keep queuing):
+//   "0/3 nodes: 3 Insufficient nvidia.com/gpu."
+//   "0/3 nodes: 3 Insufficient memory."
+//   "0/1 nodes are available"  ← ambiguous, unknown
+//
+// Extend at runtime via env var ACTIONS_RUNNER_K8S_PERMANENT_SCHEDULING_PATTERNS
+// (comma-separated regex strings; cannot remove built-in entries).
+export const PERMANENT_SCHEDULING_PATTERNS: readonly RegExp[] = [
+  // Node selector / affinity label mismatch — no node carries the required
+  // labels. Will not self-resolve without a pod-spec or node-label change.
+  /node\(s\) didn't match Pod's node affinity\/selector/i,
+  /node\(s\) didn't match node affinity/i,
+  // Untolerated taint — every node carries a taint the pod does not tolerate.
+  // Will not self-resolve without adding a toleration or removing the taint.
+  /node\(s\) had untolerated taint/i,
+  // PVC referenced in the pod spec does not exist in the namespace. The
+  // scheduler refuses to place the pod until the PVC is created. The workflow
+  // job spec is wrong — it won't self-resolve.
+  /persistentvolumeclaim "[^"]+" not found/i
+]
+ 
+export const UNRECOVERABLE_TERMINATED_REASONS = new Set([
+  'OOMKilled',
+  'Error',
+  'FailedPostStartHookError'
+])
+ 
+// Maximum number of Warning events to include in a pod's failure description so
+// that the GitHub Actions log is not flooded.
+const MAX_DIAGNOSTIC_EVENTS = 10
+ 
+// The fast-fail whitelist can be extended (not narrowed) from the environment so
+// operators can add deterministic terminal reasons without a code change. This
+// reuses the same env-var configuration pattern as the prepare-job timeout. When
+// the variable is unset, behaviour is identical to the built-in defaults.
+export function getUnrecoverableWaitingReasons(): Set<string> {
+  const extra = process.env['ACTIONS_RUNNER_K8S_UNRECOVERABLE_WAITING_REASONS']
+  if (!extra) {
+    return UNRECOVERABLE_WAITING_REASONS
+  }
+  const reasons = new Set(UNRECOVERABLE_WAITING_REASONS)
+  for (const reason of extra.split(',')) {
+    const trimmed = reason.trim()
+    Eif (trimmed) {
+      reasons.add(trimmed)
+    }
+  }
+  return reasons
+}
+ 
+// Mirrors getUnrecoverableWaitingReasons() but for pod *event* reasons. The
+// env var ACTIONS_RUNNER_K8S_UNRECOVERABLE_EVENT_REASONS adds to (never removes
+// from) the built-in UNRECOVERABLE_EVENT_REASONS set.
+export function getUnrecoverableEventReasons(): Set<string> {
+  const extra = process.env['ACTIONS_RUNNER_K8S_UNRECOVERABLE_EVENT_REASONS']
+  if (!extra) {
+    return UNRECOVERABLE_EVENT_REASONS
+  }
+  const reasons = new Set(UNRECOVERABLE_EVENT_REASONS)
+  for (const reason of extra.split(',')) {
+    const trimmed = reason.trim()
+    Eif (trimmed) {
+      reasons.add(trimmed)
+    }
+  }
+  return reasons
+}
+ 
+export function getUnrecoverableTerminatedReasons(): Set<string> {
+  const extra =
+    process.env['ACTIONS_RUNNER_K8S_UNRECOVERABLE_TERMINATED_REASONS']
+  if (!extra) {
+    return UNRECOVERABLE_TERMINATED_REASONS
+  }
+  const reasons = new Set(UNRECOVERABLE_TERMINATED_REASONS)
+  for (const reason of extra.split(',')) {
+    const trimmed = reason.trim()
+    if (trimmed) {
+      reasons.add(trimmed)
+    }
+  }
+  return reasons
+}
+ 
+// Returns true when a FailedScheduling event message positively identifies a
+// permanent configuration error that will not self-resolve. Returns false
+// (treat as transient, keep queuing) for:
+//   - absent/empty messages   → unknown, assume transient
+//   - resource shortages      → Insufficient cpu/memory/gpu/etc.
+//   - any unrecognised format → unknown, assume transient
+export function isPermanentSchedulingFailure(
+  message: string | undefined
+): boolean {
+  if (!message) return false
+  return getPermanentSchedulingPatterns().some(p => p.test(message))
+}
+ 
+// Returns PERMANENT_SCHEDULING_PATTERNS extended by any extra patterns from
+// ACTIONS_RUNNER_K8S_PERMANENT_SCHEDULING_PATTERNS (comma-separated regexes).
+// Invalid regex strings are skipped with a warning.
+// The compiled result is cached: env var changes during a single process are
+// rare (effectively never in a runner job), but this avoids repeated split +
+// RegExp construction on every FailedScheduling poll iteration.
+let _cachedSchedulingPatterns: readonly RegExp[] | undefined
+let _lastSchedulingPatternsEnv: string | undefined
+ 
+export function getPermanentSchedulingPatterns(): readonly RegExp[] {
+  const extra = process.env['ACTIONS_RUNNER_K8S_PERMANENT_SCHEDULING_PATTERNS']
+  Eif (!extra) return PERMANENT_SCHEDULING_PATTERNS
+  if (_cachedSchedulingPatterns && _lastSchedulingPatternsEnv === extra) {
+    return _cachedSchedulingPatterns
+  }
+  const patterns: RegExp[] = [...PERMANENT_SCHEDULING_PATTERNS]
+  for (const raw of extra.split(',')) {
+    const trimmed = raw.trim()
+    if (!trimmed) continue
+    try {
+      patterns.push(new RegExp(trimmed, 'i'))
+    } catch {
+      core.warning(
+        `ACTIONS_RUNNER_K8S_PERMANENT_SCHEDULING_PATTERNS: invalid regex "${trimmed}", skipped`
+      )
+    }
+  }
+  _lastSchedulingPatternsEnv = extra
+  _cachedSchedulingPatterns = patterns
+  return patterns
+}
+ 
+function getWaitingReasonHint(reason: string): string {
+  switch (reason) {
+    case 'ImagePullBackOff':
+      return [
+        `  → Image pull has failed repeatedly (k8s retried with exponential backoff). Check:`,
+        `    - Image name and tag are correct and exist in the registry`,
+        `    - If private registry: imagePullSecret is configured and credentials are valid`,
+        `    - Network connectivity from the node to the registry (DNS, firewall, proxy, TLS)`,
+        `    Run: kubectl describe pod <pod> | grep -A10 "Events"`
+      ].join('\n')
+    case 'InvalidImageName':
+      return `  → Image name is malformed. Check the workflow/job container image configuration.`
+    case 'CreateContainerConfigError':
+      return `  → Container config is invalid. Check env vars, resource limits, and securityContext in the job spec.`
+    default:
+      return `  → Check pod events with: kubectl describe pod <pod>`
+  }
+}
+ 
+export function getContainerErrors(pod: k8s.V1Pod): string[] {
+  const errors: string[] = []
+  const unrecoverableReasons = getUnrecoverableWaitingReasons()
+  const allStatuses = [
+    ...(pod.status?.initContainerStatuses ?? []),
+    ...(pod.status?.containerStatuses ?? [])
+  ]
+  for (const cs of allStatuses) {
+    const waiting = cs.state?.waiting
+    if (waiting?.reason && unrecoverableReasons.has(waiting.reason)) {
+      const reason = `  ✗ container "${cs.name}": ${waiting.reason}`
+      const detail = waiting.message ? `\n    ${waiting.message}` : ''
+      const hint = `\n${getWaitingReasonHint(waiting.reason)}`
+      errors.push(`${reason}${detail}${hint}`)
+    }
+  }
+  return errors
+}
+ 
+export function getTerminatedReasonHint(
+  reason: string,
+  exitCode: number | undefined
+): string {
+  if (reason === 'OOMKilled') {
+    return `  → Container exceeded its memory limit and was killed by the OOM killer.\n    Increase the memory limit in the job spec or reduce memory usage in the script.`
+  }
+  if (reason === 'FailedPostStartHookError') {
+    return `  → The postStart lifecycle hook failed. Check the hook command and its exit code.`
+  }
+  if (reason === 'Error') {
+    switch (exitCode) {
+      case 137:
+        return `  → Exit code 137: process was killed (SIGKILL). Likely OOM or forceful termination.\n    Check memory usage and resource limits.`
+      case 139:
+        return `  → Exit code 139: segmentation fault (SIGSEGV). The process crashed due to a memory access error.`
+      case 126:
+        return `  → Exit code 126: permission denied. The script or binary is not executable.\n    Check file permissions inside the container image.`
+      case 127:
+        return `  → Exit code 127: command not found. The script or binary does not exist in the container.\n    Check the image contents and the command/entrypoint configuration.`
+      default:
+        return `  → Script or process exited with a non-zero code (${exitCode ?? 'unknown'}).\n    Check the step output above for error messages.\n    Common causes: script logic errors, missing dependencies, unhandled exceptions.`
+    }
+  }
+  return `  → Check pod logs with: kubectl logs <pod> -c ${reason}`
+}
+ 
+export function getContainerTerminatedErrors(pod: k8s.V1Pod): string[] {
+  const errors: string[] = []
+  const unrecoverableReasons = getUnrecoverableTerminatedReasons()
+  const allStatuses = [
+    ...(pod.status?.initContainerStatuses ?? []),
+    ...(pod.status?.containerStatuses ?? [])
+  ]
+  for (const cs of allStatuses) {
+    const terminated = cs.state?.terminated
+    if (terminated?.reason && unrecoverableReasons.has(terminated.reason)) {
+      const reason = `  ✗ container "${cs.name}": ${terminated.reason} (exit code ${terminated.exitCode})`
+      const detail = terminated.message ? `\n    ${terminated.message}` : ''
+      const hint = `\n${getTerminatedReasonHint(terminated.reason, terminated.exitCode)}`
+      errors.push(`${reason}${detail}${hint}`)
+    }
+  }
+  return errors
+}
+ 
+function getEventReasonHint(reason: string): string {
+  switch (reason) {
+    case 'FailedMount':
+      return [
+        `  → A volume could not be mounted. Check:`,
+        `    - PVC is bound (kubectl get pvc)`,
+        `    - Secret/ConfigMap referenced in the volume exists`,
+        `    - hostPath directories exist on the scheduled node`
+      ].join('\n')
+    case 'FailedBinding':
+      return [
+        `  → A PVC could not be bound to a PV. Check:`,
+        `    - StorageClass exists and has a provisioner`,
+        `    - Sufficient capacity is available`,
+        `    - Access mode (ReadWriteOnce/ReadWriteMany) matches available PVs`
+      ].join('\n')
+    case 'FailedScheduling':
+      return [
+        `  → Pod cannot be scheduled due to a permanent configuration error. Check:`,
+        `    - nodeSelector / nodeAffinity labels match at least one node`,
+        `    - All tolerations are present for node taints`,
+        `    - PVCs referenced in the pod spec exist in the namespace`
+      ].join('\n')
+    default:
+      return `  → Check pod events with: kubectl describe pod <pod>`
+  }
+}
+ 
+// Inspects the pod's Warning events for reasons in UNRECOVERABLE_EVENT_REASONS.
+// For FailedScheduling, only fast-fails when the message positively matches
+// a known-permanent configuration error (see PERMANENT_SCHEDULING_PATTERNS).
+// Resource shortages ("Insufficient cpu/memory/gpu") are silently skipped so
+// the pod keeps queuing until the timeout. Best-effort: if events cannot be
+// listed (e.g. the optional 'events' RBAC permission is missing) it returns []
+// instead of blocking container-level fast-fail detection. Deduplicates by
+// reason so a repeatedly-retried event is reported once.
+export async function getPodEventErrors(podName: string): Promise<string[]> {
+  const unrecoverableReasons = getUnrecoverableEventReasons()
+  Iif (unrecoverableReasons.size === 0) {
+    return []
+  }
+ 
+  let items: k8s.CoreV1Event[]
+  try {
+    const result = await k8sApi.listNamespacedEvent({
+      namespace: namespace(),
+      fieldSelector: `involvedObject.name=${podName}`
+    })
+    items = result.items ?? []
+  } catch (err) {
+    core.debug(
+      `Could not list events for pod ${podName} during fast-fail check: ${
+        err instanceof Error ? err.message : String(err)
+      }`
+    )
+    return []
+  }
+ 
+  const errors: string[] = []
+  const seenReasons = new Set<string>()
+  for (const e of items) {
+    if (
+      e.type !== 'Warning' ||
+      !e.reason ||
+      !unrecoverableReasons.has(e.reason)
+    ) {
+      continue
+    }
+    // FailedScheduling: only fast-fail when the message positively matches a
+    // known-permanent config error. Resource shortages and unknown messages
+    // are treated as transient — let the pod keep queuing.
+    if (
+      e.reason === 'FailedScheduling' &&
+      !isPermanentSchedulingFailure(e.message)
+    ) {
+      core.debug(
+        `[fast-fail] Skipping FailedScheduling (not a recognised permanent error): ${
+          e.message ?? '(no message)'
+        }`
+      )
+      continue
+    }
+    if (seenReasons.has(e.reason)) {
+      continue
+    }
+    seenReasons.add(e.reason)
+    const count = e.count && e.count > 1 ? ` (x${e.count})` : ''
+    const reason = `  ✗ event: ${e.reason}${count}`
+    const detail = e.message ? `\n    ${e.message}` : ''
+    const hint = getEventReasonHint(e.reason)
+    errors.push(`${reason}${detail}\n${hint}`)
+  }
+  return errors
+}
+ 
+// describePodFailure aggregates everything that might explain why a pod is not
+// healthy into a single human-readable string. It makes NO success/failure
+// judgement of its own (a terminated exitCode=0 container is just reported as
+// such) -- callers decide what is "bad". It never throws: if it cannot read the
+// pod or list events it returns/embeds a best-effort note instead, so it is safe
+// to call from any error path.
+export async function describePodFailure(podName: string): Promise<string> {
+  let pod: k8s.V1Pod
+  try {
+    pod = await readPod(podName)
+  } catch (err) {
+    return `Could not read pod ${podName} for diagnostics: ${
+      err instanceof Error ? err.message : String(err)
+    }`
+  }
+ 
+  const sections: string[] = []
+  const status = pod.status
+ 
+  // --- Pod-level status ---
+  const podLines: string[] = []
+  const phaseLabel = status?.phase
+    ? `${status.phase}${status.reason ? ` (${status.reason})` : ''}`
+    : 'Unknown'
+  podLines.push(`Pod status: ${phaseLabel}`)
+  if (status?.message) {
+    podLines.push(`  ${status.message}`)
+  }
+ 
+  // Surface conditions that are False (e.g. PodScheduled=False from FailedScheduling)
+  for (const cond of status?.conditions ?? []) {
+    Eif (cond.status === 'False') {
+      const reason = cond.reason ? ` (${cond.reason})` : ''
+      const msg = cond.message ? `: ${cond.message}` : ''
+      podLines.push(`  ✗ ${cond.type}=False${reason}${msg}`)
+    }
+  }
+  sections.push(podLines.join('\n'))
+ 
+  // --- Container-level status (non-zero exits and non-unrecoverable waits) ---
+  const unrecoverableReasons = getUnrecoverableWaitingReasons()
+  const allStatuses = [
+    ...(status?.initContainerStatuses ?? []),
+    ...(status?.containerStatuses ?? [])
+  ]
+  const containerLines: string[] = []
+  for (const cs of allStatuses) {
+    const waiting = cs.state?.waiting
+    if (waiting?.reason) {
+      // Skip reasons already surfaced by getContainerErrors() in the caller's
+      // first line to avoid printing the same error twice.
+      if (!unrecoverableReasons.has(waiting.reason)) {
+        const msg = waiting.message ? `\n    ${waiting.message}` : ''
+        containerLines.push(
+          `  ✗ container "${cs.name}" waiting: ${waiting.reason}${msg}`
+        )
+      }
+    }
+    const terminated = cs.state?.terminated
+    // Only surface non-zero exits; exit 0 (e.g. fs-init Completed) is noise.
+    if (terminated && terminated.exitCode !== 0) {
+      const reason = terminated.reason ?? 'Unknown'
+      const msg = terminated.message ? `\n    ${terminated.message}` : ''
+      containerLines.push(
+        `  ✗ container "${cs.name}" terminated: ${reason} (exit code ${terminated.exitCode})${msg}`
+      )
+    }
+  }
+  if (containerLines.length) {
+    sections.push(`Container details:\n${containerLines.join('\n')}`)
+  }
+ 
+  // --- Warning events ---
+  const eventLines = await describePodWarningEvents(podName)
+  if (eventLines.length) {
+    sections.push(`Recent warning events:\n${eventLines.join('\n')}`)
+  }
+ 
+  Iif (!sections.length) {
+    return `No additional diagnostic information available for pod ${podName}`
+  }
+  return sections.join('\n\n')
+}
+ 
+// Reads the most recent Warning events for a pod. Best-effort: listing events
+// requires the optional "events" get/list permission, so any error (including
+// RBAC Forbidden) is swallowed and an empty list is returned.
+async function describePodWarningEvents(podName: string): Promise<string[]> {
+  let items: k8s.CoreV1Event[]
+  try {
+    const result = await k8sApi.listNamespacedEvent({
+      namespace: namespace(),
+      fieldSelector: `involvedObject.name=${podName}`
+    })
+    items = result.items ?? []
+  } catch (err) {
+    core.debug(
+      `Could not list events for pod ${podName} (the 'events' permission may be missing): ${
+        err instanceof Error ? err.message : String(err)
+      }`
+    )
+    return []
+  }
+ 
+  const warnings = items.filter(e => e.type === 'Warning')
+  if (!warnings.length) {
+    return []
+  }
+ 
+  const eventTime = (e: k8s.CoreV1Event): number => {
+    const t = e.lastTimestamp ?? e.eventTime ?? e.firstTimestamp
+    return t ? new Date(t).getTime() : 0
+  }
+  warnings.sort((a, b) => eventTime(a) - eventTime(b))
+ 
+  const recent = warnings.slice(-MAX_DIAGNOSTIC_EVENTS)
+  const lines = recent.map(e => {
+    const count = e.count && e.count > 1 ? ` (x${e.count})` : ''
+    return `  [${e.reason ?? 'Warning'}]${count} ${e.message ?? ''}`.trimEnd()
+  })
+  Iif (warnings.length > recent.length) {
+    lines.unshift(
+      `  (showing ${recent.length} of ${warnings.length} warning events)`
+    )
+  }
+  return lines
+}
+ 
+// Inspects the pod's status.conditions for scheduling failures. FailedScheduling
+// is intentionally excluded from fast-fail detection (see UNRECOVERABLE_EVENT_REASONS
+// comment) — scheduling failures are transient resource waits that should queue
+// until the timeout, not terminate early. This function always returns [] as a
+// result, but is kept so checkUnrecoverableErrors compiles and the dedup logic
+// remains intact for future use.
+export function getPodConditionErrors(_p: k8s.V1Pod): string[] {
+  return []
+}
+ 
+// Aggregates the three independent error-detection sources (container waiting
+// reasons, pod Warning events, and pod conditions) into a single list, applying
+// the cross-source deduplication rule (FailedScheduling event + Unschedulable
+// condition = same failure, report once). Returns [] when no unrecoverable
+// error is detected. The caller decides what to do with the list -- typically
+// attach describePodFailure diagnostics and throw.
+export async function checkUnrecoverableErrors(
+  pod: k8s.V1Pod,
+  podName: string
+): Promise<string[]> {
+  // Deterministic terminal errors on a container (e.g. ImagePullBackOff).
+  const containerErrors = getContainerErrors(pod)
+  // Terminated container errors (e.g. OOMKilled, non-zero exit) with hints.
+  const terminatedErrors = getContainerTerminatedErrors(pod)
+  // Best-effort: returns [] when the optional events RBAC permission is absent.
+  const eventErrors = await getPodEventErrors(podName)
+  // Conditions are set near-instantly by the scheduler while events may take
+  // a few extra seconds to propagate, so always run the check. Deduplicate
+  // against events so the same FailedScheduling isn't printed twice.
+  const conditionErrors = getPodConditionErrors(pod).filter(
+    c =>
+      !eventErrors.some(
+        e => e.includes('FailedScheduling') && c.includes('Unschedulable')
+      )
+  )
+  return [
+    ...containerErrors,
+    ...terminatedErrors,
+    ...eventErrors,
+    ...conditionErrors
+  ]
+}
+ 
+export async function waitForPodPhases(
+  podName: string,
+  awaitingPhases: Set<PodPhase>,
+  backOffPhases: Set<PodPhase>,
+  maxTimeSeconds = DEFAULT_WAIT_FOR_POD_TIME_SECONDS
+): Promise<void> {
+  const backOffManager = new BackOffManager(maxTimeSeconds)
+  let phase: PodPhase = PodPhase.UNKNOWN
+  while (Itrue) {
+    let pod: k8s.V1Pod
+    try {
+      pod = await readPod(podName)
+    } catch (err) {
+      // Transient API error (network blip, API server busy): log and back off
+      // rather than crashing the loop. The timeout will eventually fire if the
+      // pod stays permanently unreadable (e.g. RBAC issue).
+      core.warning(
+        `[waitForPodPhases] Could not read pod ${podName}, will retry after backoff: ${
+          err instanceof Error ? err.message : String(err)
+        }`
+      )
+      try {
+        await backOffManager.backOff()
+      } catch {
+        throw new Error(
+          `Pod ${podName} timed out after ${maxTimeSeconds}s (pod read failed: ${
+            err instanceof Error ? err.message : String(err)
+          })\n${'-'.repeat(60)}\n(pod was unreadable; no further diagnostics available)`
+        )
+      }
+      continue
+    }
+    phase = parsePodPhase(pod)
+    if (awaitingPhases.has(phase)) {
+      return
+    }
+ 
+    // The pod reached a phase we are not willing to keep waiting on
+    // (a terminal/unhealthy phase). First check for unrecoverable
+    // container-level errors (e.g. OOMKilled, non-zero exit) so they are
+    // reported with actionable hints. Fall back to the generic "is unhealthy"
+    // message when no specific error is found.
+    if (!backOffPhases.has(phase)) {
+      const errors = await checkUnrecoverableErrors(pod, podName)
+      const details = await describePodFailure(podName)
+      Iif (errors.length > 0) {
+        throw new Error(
+          `Pod ${podName} has unrecoverable errors:\n${errors.join('\n')}\n${'-'.repeat(60)}\n${details}`
+        )
+      }
+      throw new Error(
+        `Pod ${podName} is unhealthy (phase: ${phase})\n${'-'.repeat(60)}\n${details}`
+      )
+    }
+ 
+    // Still in a back-off phase, but a deterministic unrecoverable error
+    // was detected (container / event / condition). Fail fast with
+    // diagnostics instead of waiting out the full timeout.
+    const errors = await checkUnrecoverableErrors(pod, podName)
+    if (errors.length > 0) {
+      const details = await describePodFailure(podName)
+      throw new Error(
+        `Pod ${podName} has unrecoverable errors:\n${errors.join('\n')}\n${'-'.repeat(60)}\n${details}`
+      )
+    }
+ 
+    try {
+      await backOffManager.backOff()
+    } catch (_err) {
+      // BackOffManager throws "backoff timeout" when maxTimeSeconds is exceeded.
+      // Don't surface that bare message: collect diagnostics first so the user
+      // can see WHY the pod never became ready.
+      const details = await describePodFailure(podName)
+      throw new Error(
+        `Pod ${podName} timed out after ${maxTimeSeconds}s (phase: ${phase})\n${'-'.repeat(60)}\n${details}`
+      )
+    }
+  }
+}
+ 
+export function getPrepareJobTimeoutSeconds(): number {
+  const envTimeoutSeconds =
+    process.env['ACTIONS_RUNNER_PREPARE_JOB_TIMEOUT_SECONDS']
+ 
+  Eif (!envTimeoutSeconds) {
+    return DEFAULT_WAIT_FOR_POD_TIME_SECONDS
+  }
+ 
+  const timeoutSeconds = parseInt(envTimeoutSeconds, 10)
+  if (!timeoutSeconds || timeoutSeconds <= 0) {
+    core.warning(
+      `Prepare job timeout is invalid ("${timeoutSeconds}"): use an int > 0`
+    )
+    return DEFAULT_WAIT_FOR_POD_TIME_SECONDS
+  }
+ 
+  return timeoutSeconds
+}
+ 
+async function readPod(podName: string): Promise<k8s.V1Pod> {
+  return await k8sApi.readNamespacedPod({
+    name: podName,
+    namespace: namespace()
+  })
+}
+ 
+const podPhaseLookup = new Set<string>([
+  PodPhase.PENDING,
+  PodPhase.RUNNING,
+  PodPhase.SUCCEEDED,
+  PodPhase.FAILED,
+  PodPhase.UNKNOWN
+])
+ 
+export function parsePodPhase(pod: k8s.V1Pod): PodPhase {
+  if (!pod.status?.phase || !podPhaseLookup.has(pod.status.phase)) {
+    return PodPhase.UNKNOWN
+  }
+  return pod.status.phase as PodPhase
+}
+ 
+async function isJobSucceeded(name: string): Promise<boolean> {
+  const job = await k8sBatchV1Api.readNamespacedJob({
+    name,
+    namespace: namespace()
+  })
+  Eif (job.status?.failed) {
+    throw new Error(`job ${name} has failed`)
+  }
+  return !!job.status?.succeeded
+}
+ 
+export async function getPodLogs(
+  podName: string,
+  containerName: string
+): Promise<void> {
+  const log = new k8s.Log(kc)
+  const logStream = new stream.PassThrough()
+  logStream.on('data', chunk => {
+    // use write rather than console.log to prevent double line feed
+    process.stdout.write(chunk)
+  })
+ 
+  await log.log(namespace(), podName, containerName, logStream, {
+    follow: true,
+    pretty: false,
+    timestamps: false
+  })
+  await new Promise((resolve, reject) => {
+    logStream.on('end', () => resolve(null))
+    logStream.on('error', err => {
+      process.stderr.write(err.message)
+      reject(err)
+    })
+  })
+}
+ 
+export async function prunePods(): Promise<void> {
+  const podList = await k8sApi.listNamespacedPod({
+    namespace: namespace(),
+    labelSelector: new RunnerInstanceLabel().toString()
+  })
+  if (!podList.items.length) {
+    return
+  }
+ 
+  await Promise.all(
+    podList.items.map(
+      async pod => pod.metadata?.name && (await deletePod(pod.metadata.name))
+    )
+  )
+}
+ 
+export async function getPodStatus(
+  name: string
+): Promise<k8s.V1PodStatus | undefined> {
+  const pod = await k8sApi.readNamespacedPod({
+    name,
+    namespace: namespace()
+  })
+  return pod.status
+}
+ 
+export async function isAuthPermissionsOK(): Promise<boolean> {
+  const sar = new k8s.V1SelfSubjectAccessReview()
+  const asyncs: Promise<k8s.V1SelfSubjectAccessReview>[] = []
+  for (const resource of requiredPermissions) {
+    for (const verb of resource.verbs) {
+      sar.spec = new k8s.V1SelfSubjectAccessReviewSpec()
+      sar.spec.resourceAttributes = new k8s.V1ResourceAttributes()
+      sar.spec.resourceAttributes.verb = verb
+      sar.spec.resourceAttributes.namespace = namespace()
+      sar.spec.resourceAttributes.group = resource.group
+      sar.spec.resourceAttributes.resource = resource.resource
+      sar.spec.resourceAttributes.subresource = resource.subresource
+      asyncs.push(
+        k8sAuthorizationV1Api.createSelfSubjectAccessReview({ body: sar })
+      )
+    }
+  }
+  const responses = await Promise.all(asyncs)
+  return responses.every(resp => resp.status?.allowed)
+}
+ 
+export async function isPodContainerAlpine(
+  podName: string,
+  containerName: string
+): Promise<boolean> {
+  let isAlpine = true
+  try {
+    await execPodStep(
+      [
+        'sh',
+        '-c',
+        `[ $(cat /etc/*release* | grep -i -e "^ID=*alpine*" -c) != 0 ] || exit 1`
+      ],
+      podName,
+      containerName
+    )
+  } catch {
+    isAlpine = false
+  }
+ 
+  return isAlpine
+}
+ 
+export function namespace(): string {
+  if (process.env['ACTIONS_RUNNER_KUBERNETES_NAMESPACE']) {
+    return process.env['ACTIONS_RUNNER_KUBERNETES_NAMESPACE']
+  }
+ 
+  const context = kc.getContexts().find(ctx => ctx.namespace)
+  Eif (context?.namespace) {
+    return context.namespace
+  }
+ 
+  // When running in-cluster the kubeconfig context has no namespace field;
+  // read it from the mounted ServiceAccount file instead.
+  const saNamespaceFile =
+    '/var/run/secrets/kubernetes.io/serviceaccount/namespace'
+  try {
+    const ns = fs.readFileSync(saNamespaceFile, 'utf8').trim()
+    if (ns) {
+      return ns
+    }
+  } catch {
+    // not running in-cluster, fall through to error
+  }
+ 
+  throw new Error(
+    'Failed to determine namespace. Set the ACTIONS_RUNNER_KUBERNETES_NAMESPACE environment variable or ensure the kubeconfig context includes a namespace.'
+  )
+}
+ 
+class BackOffManager {
+  private backOffSeconds = 1
+  totalTime = 0
+  constructor(private throwAfterSeconds?: number) {
+    if (!throwAfterSeconds || throwAfterSeconds < 0) {
+      this.throwAfterSeconds = undefined
+    }
+  }
+ 
+  async backOff(): Promise<void> {
+    await new Promise(resolve =>
+      setTimeout(resolve, this.backOffSeconds * 1000)
+    )
+    this.totalTime += this.backOffSeconds
+    if (this.throwAfterSeconds && this.throwAfterSeconds < this.totalTime) {
+      throw new Error('backoff timeout')
+    }
+    Eif (this.backOffSeconds < 20) {
+      this.backOffSeconds *= 2
+    }
+    Iif (this.backOffSeconds > 20) {
+      this.backOffSeconds = 20
+    }
+  }
+}
+ 
+export function containerPorts(
+  container: ContainerInfo
+): k8s.V1ContainerPort[] {
+  const ports: k8s.V1ContainerPort[] = []
+  Eif (!container.portMappings?.length) {
+    return ports
+  }
+  for (const portDefinition of container.portMappings) {
+    const portProtoSplit = portDefinition.split('/')
+    if (portProtoSplit.length > 2) {
+      throw new Error(`Unexpected port format: ${portDefinition}`)
+    }
+ 
+    const port = new k8s.V1ContainerPort()
+    port.protocol =
+      portProtoSplit.length === 2 ? portProtoSplit[1].toUpperCase() : 'TCP'
+ 
+    const portSplit = portProtoSplit[0].split(':')
+    if (portSplit.length > 2) {
+      throw new Error('ports should have at most one ":" separator')
+    }
+ 
+    const parsePort = (p: string): number => {
+      const num = Number(p)
+      if (!Number.isInteger(num) || num < 1 || num > 65535) {
+        throw new Error(`invalid container port: ${p}`)
+      }
+      return num
+    }
+ 
+    if (portSplit.length === 1) {
+      port.containerPort = parsePort(portSplit[0])
+    } else {
+      port.hostPort = parsePort(portSplit[0])
+      port.containerPort = parsePort(portSplit[1])
+    }
+ 
+    ports.push(port)
+  }
+  return ports
+}
+ 
+export async function getPodByName(name): Promise<k8s.V1Pod> {
+  return await k8sApi.readNamespacedPod({
+    name,
+    namespace: namespace()
+  })
+}
+ 
+export async function getSecretByName(name: string): Promise<k8s.V1Secret> {
+  return await k8sApi.readNamespacedSecret({
+    name,
+    namespace: namespace()
+  })
+}
+ 
+export async function listPodsByRunnerInstance(): Promise<k8s.V1Pod[]> {
+  const podList = await k8sApi.listNamespacedPod({
+    namespace: namespace(),
+    labelSelector: new RunnerInstanceLabel().toString()
+  })
+  return podList.items ?? []
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/packages/k8s/coverage/lcov-report/src/k8s/utils/index.html b/packages/k8s/coverage/lcov-report/src/k8s/utils/index.html new file mode 100644 index 00000000..aa7bf026 --- /dev/null +++ b/packages/k8s/coverage/lcov-report/src/k8s/utils/index.html @@ -0,0 +1,131 @@ + + + + + + Code coverage report for src/k8s/utils + + + + + + + + + +
+
+

All files src/k8s/utils

+
+ +
+ 33.65% + Statements + 177/526 +
+ + +
+ 16.43% + Branches + 93/566 +
+ + +
+ 22.85% + Functions + 16/70 +
+ + +
+ 36.09% + Lines + 161/446 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
index.ts +
+
57.38%101/17643.85%75/17147.36%9/1960.66%91/150
npu-metrics.ts +
+
21.71%76/3504.55%18/39513.72%7/5123.64%70/296
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/packages/k8s/coverage/lcov-report/src/k8s/utils/index.ts.html b/packages/k8s/coverage/lcov-report/src/k8s/utils/index.ts.html new file mode 100644 index 00000000..c916746e --- /dev/null +++ b/packages/k8s/coverage/lcov-report/src/k8s/utils/index.ts.html @@ -0,0 +1,1159 @@ + + + + + + Code coverage report for src/k8s/utils/index.ts + + + + + + + + + +
+
+

All files / src/k8s/utils index.ts

+
+ +
+ 57.38% + Statements + 101/176 +
+ + +
+ 43.85% + Branches + 75/171 +
+ + +
+ 47.36% + Functions + 9/19 +
+ + +
+ 60.66% + Lines + 91/150 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263 +264 +265 +266 +267 +268 +269 +270 +271 +272 +273 +274 +275 +276 +277 +278 +279 +280 +281 +282 +283 +284 +285 +286 +287 +288 +289 +290 +291 +292 +293 +294 +295 +296 +297 +298 +299 +300 +301 +302 +303 +304 +305 +306 +307 +308 +309 +310 +311 +312 +313 +314 +315 +316 +317 +318 +319 +320 +321 +322 +323 +324 +325 +326 +327 +328 +329 +330 +331 +332 +333 +334 +335 +336 +337 +338 +339 +340 +341 +342 +343 +344 +345 +346 +347 +348 +349 +350 +351 +352 +353 +354 +355 +356 +357 +358 +359  +14x +14x +14x +14x +14x +14x +  +  +14x +14x +  +14x +14x +  +14x +14x +14x +  +14x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +14x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +14x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +14x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +14x +12x +12x +  +12x +2x +  +  +10x +  +  +  +  +  +  +  +  +  +  +14x +  +  +  +6x +6x +2x +1x +  +2x +4x +1x +1x +3x +1x +1x +2x +  +  +2x +1x +1x +  +1x +  +  +  +  +14x +  +  +  +4x +4x +1x +  +1x +  +  +3x +1x +1x +  +2x +  +  +  +  +14x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +14x +23x +23x +23x +  +  +  +  +  +  +  +  +14x +  +  +  +14x +14x +14x +14x +14x +14x +14x +  +  +  +3x +3x +  +  +3x +3x +  +  +14x +  +  +17x +3x +  +14x +  +  +14x +  +  +  +14x +  +  +  +  +  +  +  +  +  +14x +63x +2x +  +  +  +  +  +61x +  +61x +3x +3x +3x +3x +  +  +  +  +  +58x +47x +  +  +11x +  +  +  +  +6x +6x +3x +  +3x +3x +  +2x +  +  +  +  +  +5x +  + 
import * as k8s from '@kubernetes/client-node'
+import * as fs from 'fs'
+import * as yaml from 'js-yaml'
+import * as core from '@actions/core'
+import { v1 as uuidv4 } from 'uuid'
+import { CONTAINER_EXTENSION_PREFIX } from '../../hooks/constants'
+import * as shlex from 'shlex'
+import { Mount } from 'hooklib'
+ 
+export const DEFAULT_CONTAINER_ENTRY_POINT_ARGS = [`-f`, `/dev/null`]
+export const DEFAULT_CONTAINER_ENTRY_POINT = 'tail'
+ 
+export const ENV_HOOK_TEMPLATE_PATH = 'ACTIONS_RUNNER_CONTAINER_HOOK_TEMPLATE'
+export const ENV_USE_KUBE_SCHEDULER = 'ACTIONS_RUNNER_USE_KUBE_SCHEDULER'
+ 
+export const EXTERNALS_VOLUME_NAME = 'externals'
+export const GITHUB_VOLUME_NAME = 'github'
+export const WORK_VOLUME = 'work'
+ 
+export const CONTAINER_VOLUMES: k8s.V1VolumeMount[] = [
+  {
+    name: EXTERNALS_VOLUME_NAME,
+    mountPath: '/__e'
+  },
+  {
+    name: WORK_VOLUME,
+    mountPath: '/__w'
+  },
+  {
+    name: GITHUB_VOLUME_NAME,
+    mountPath: '/github'
+  }
+]
+ 
+export function prepareJobScript(userVolumeMounts: Mount[]): {
+  containerPath: string
+  runnerPath: string
+} {
+  let mountDirs = userVolumeMounts
+    .map(m => shlex.quote(m.targetVolumePath))
+    .join(' ')
+ 
+  const content = `#!/bin/sh -l
+set -e
+cp -R /__w/_temp/_github_home /github/home
+cp -R /__w/_temp/_github_workflow /github/workflow
+mkdir -p ${mountDirs}
+`
+ 
+  const filename = `${uuidv4()}.sh`
+  const entryPointPath = `${process.env.RUNNER_TEMP}/${filename}`
+  fs.writeFileSync(entryPointPath, content)
+  return {
+    containerPath: `/__w/_temp/${filename}`,
+    runnerPath: entryPointPath
+  }
+}
+ 
+export function writeRunScript(
+  workingDirectory: string,
+  entryPoint: string,
+  entryPointArgs?: string[],
+  prependPath?: string[],
+  environmentVariables?: { [key: string]: string }
+): { containerPath: string; runnerPath: string } {
+  let exportPath = ''
+  if (prependPath?.length) {
+    // TODO: remove compatibility with typeof prependPath === 'string' as we bump to next major version, the hooks will lose PrependPath compat with runners 2.293.0 and older
+    const prepend =
+      typeof prependPath === 'string' ? prependPath : prependPath.join(':')
+    exportPath = `export PATH=${prepend}:$PATH`
+  }
+ 
+  let environmentPrefix = scriptEnv(environmentVariables)
+ 
+  const content = `#!/bin/sh -l
+set -e
+rm "$0" # remove script after running
+${exportPath}
+cd ${workingDirectory} && \
+exec ${environmentPrefix} ${entryPoint} ${
+    entryPointArgs?.length ? entryPointArgs.join(' ') : ''
+  }
+`
+  const filename = `${uuidv4()}.sh`
+  const entryPointPath = `${process.env.RUNNER_TEMP}/${filename}`
+  fs.writeFileSync(entryPointPath, content)
+  return {
+    containerPath: `/__w/_temp/${filename}`,
+    runnerPath: entryPointPath
+  }
+}
+ 
+export function writeContainerStepScript(
+  dst: string,
+  workingDirectory: string,
+  entryPoint: string,
+  entryPointArgs?: string[],
+  environmentVariables?: { [key: string]: string }
+): { containerPath: string; runnerPath: string } {
+  let environmentPrefix = scriptEnv(environmentVariables)
+ 
+  const parts = workingDirectory.split('/').slice(-2)
+  if (parts.length !== 2) {
+    throw new Error(`Invalid working directory: ${workingDirectory}`)
+  }
+ 
+  const content = `#!/bin/sh -l
+rm "$0" # remove script after running
+mv /__w/_temp/_github_home /github/home && \
+mv /__w/_temp/_github_workflow /github/workflow && \
+mv /__w/_temp/_runner_file_commands /github/file_commands || true && \
+mv ${shlex.quote('/__w/' + parts.join('/') + '/')} /github/workspace && \
+cd /github/workspace && \
+exec ${environmentPrefix} ${shlex.quote(entryPoint)} ${
+    entryPointArgs?.length ? entryPointArgs.map(shlex.quote).join(' ') : ''
+  }
+`
+  const filename = `${uuidv4()}.sh`
+  const entryPointPath = `${dst}/${filename}`
+  core.debug(`Writing container step script to ${entryPointPath}`)
+  fs.writeFileSync(entryPointPath, content)
+  return {
+    containerPath: `/__w/_temp/${filename}`,
+    runnerPath: entryPointPath
+  }
+}
+ 
+function scriptEnv(envs?: { [key: string]: string }): string {
+  if (!envs || !Object.entries(envs).length) {
+    return ''
+  }
+  const envBuffer: string[] = []
+  for (const [key, value] of Object.entries(envs)) {
+    if (
+      key.includes(`=`) ||
+      key.includes(`'`) ||
+      key.includes(`"`) ||
+      key.includes(`$`)
+    ) {
+      throw new Error(
+        `environment key ${key} is invalid - the key must not contain =, $, ', or "`
+      )
+    }
+    envBuffer.push(
+      `"${key}=${value
+        .replace(/\\/g, '\\\\')
+        .replace(/"/g, '\\"')
+        .replace(/\$/g, '\\$')
+        .replace(/`/g, '\\`')}"`
+    )
+  }
+ 
+  if (!envBuffer?.length) {
+    return ''
+  }
+ 
+  return `env ${envBuffer.join(' ')} `
+}
+ 
+export function generateContainerName(image: string): string {
+  const nameWithTag = image.split('/').pop()
+  const name = nameWithTag?.split(':')[0]
+ 
+  if (!name) {
+    throw new Error(`Image definition '${image}' is invalid`)
+  }
+ 
+  return name
+}
+ 
+// Overwrite or append based on container options
+//
+// Keep in mind, envs and volumes could be passed as fields in container definition
+// so default volume mounts and envs are appended first, and then create options are used
+// to append more values
+//
+// Rest of the fields are just applied
+// For example, container.createOptions.container.image is going to overwrite container.image field
+export function mergeContainerWithOptions(
+  base: k8s.V1Container,
+  from: k8s.V1Container
+): void {
+  for (const [key, value] of Object.entries(from)) {
+    if (key === 'name') {
+      if (value !== CONTAINER_EXTENSION_PREFIX + base.name) {
+        core.warning("Skipping name override: name can't be overwritten")
+      }
+      continue
+    } else if (key === 'image') {
+      core.warning("Skipping image override: image can't be overwritten")
+      continue
+    } else if (key === 'env') {
+      const envs = value as k8s.V1EnvVar[]
+      base.env = mergeLists(base.env, envs)
+    } else Iif (key === 'volumeMounts' && value) {
+      const volumeMounts = value as k8s.V1VolumeMount[]
+      base.volumeMounts = mergeLists(base.volumeMounts, volumeMounts)
+    } else if (key === 'ports' && value) {
+      const ports = value as k8s.V1ContainerPort[]
+      base.ports = mergeLists(base.ports, ports)
+    } else {
+      base[key] = value
+    }
+  }
+}
+ 
+export function mergePodSpecWithOptions(
+  base: k8s.V1PodSpec,
+  from: k8s.V1PodSpec
+): void {
+  for (const [key, value] of Object.entries(from)) {
+    if (key === 'containers') {
+      base.containers.push(
+        ...from.containers.filter(
+          e => !e.name?.startsWith(CONTAINER_EXTENSION_PREFIX)
+        )
+      )
+    } else if (key === 'volumes' && value) {
+      const volumes = value as k8s.V1Volume[]
+      base.volumes = mergeLists(base.volumes, volumes)
+    } else {
+      base[key] = value
+    }
+  }
+}
+ 
+export function mergeObjectMeta(
+  base: { metadata?: k8s.V1ObjectMeta },
+  from: k8s.V1ObjectMeta
+): void {
+  if (!base.metadata?.labels || !base.metadata?.annotations) {
+    throw new Error(
+      "Can't merge metadata: base.metadata or base.annotations field is undefined"
+    )
+  }
+  if (from?.labels) {
+    for (const [key, value] of Object.entries(from.labels)) {
+      if (base.metadata?.labels?.[key]) {
+        core.warning(`Label ${key} is already defined and will be overwritten`)
+      }
+      base.metadata.labels[key] = value
+    }
+  }
+ 
+  if (from?.annotations) {
+    for (const [key, value] of Object.entries(from.annotations)) {
+      if (base.metadata?.annotations?.[key]) {
+        core.warning(
+          `Annotation ${key} is already defined and will be overwritten`
+        )
+      }
+      base.metadata.annotations[key] = value
+    }
+  }
+}
+ 
+export function readExtensionFromFile(): k8s.V1PodTemplateSpec | undefined {
+  const filePath = process.env[ENV_HOOK_TEMPLATE_PATH]
+  Eif (!filePath) {
+    return undefined
+  }
+  const doc = yaml.load(fs.readFileSync(filePath, 'utf8'))
+  if (!doc || typeof doc !== 'object') {
+    throw new Error(`Failed to parse ${filePath}`)
+  }
+  return doc as k8s.V1PodTemplateSpec
+}
+ 
+export function useKubeScheduler(): boolean {
+  return process.env[ENV_USE_KUBE_SCHEDULER] === 'true'
+}
+ 
+export enum PodPhase {
+  PENDING = 'Pending',
+  RUNNING = 'Running',
+  SUCCEEDED = 'Succeeded',
+  FAILED = 'Failed',
+  UNKNOWN = 'Unknown',
+  COMPLETED = 'Completed'
+}
+ 
+function mergeLists<T>(base?: T[], from?: T[]): T[] {
+  const b: T[] = base || []
+  Iif (!from?.length) {
+    return b
+  }
+  b.push(...from)
+  return b
+}
+ 
+export function fixArgs(args: string[]): string[] {
+  // Preserve shell command strings passed via `sh -c` without re-tokenizing.
+  // Retokenizing would split the script into multiple args, breaking `sh -c`.
+  if (args.length >= 2 && args[0] === 'sh' && args[1] === '-c') {
+    return args
+  }
+  return shlex.split(args.join(' '))
+}
+ 
+export async function sleep(ms: number): Promise<void> {
+  return new Promise(resolve => setTimeout(resolve, ms))
+}
+ 
+export function listDirAllCommand(dir: string): string {
+  return `cd ${shlex.quote(dir)} && find . -type f -not -path '*/_runner_hook_responses*' -exec stat -c '%s %n' {} \\;`
+}
+ 
+// Safely turn an unknown thrown value into a diagnostic string without
+// throwing. The previous `JSON.stringify(err)` pattern crashed with
+// `TypeError: Converting circular structure to JSON` when err was a
+// @kubernetes/client-node HTTP error (its response embeds a
+// TLSSocket <-> HTTPParser cycle). The thrown TypeError shadowed the
+// original failure in every catch block that used it (issue #329).
+export function formatError(err: unknown): string {
+  if (err === null || err === undefined) {
+    return String(err)
+  }
+ 
+  // @kubernetes/client-node API errors expose the actual server message
+  // under response.body — prefer that when available.
+  const body =
+    (err as { response?: { body?: unknown } })?.response?.body ??
+    (err as { body?: unknown })?.body
+  if (body && typeof body === 'object') {
+    const msg = (body as { message?: unknown }).message
+    const reason = (body as { reason?: unknown }).reason
+    Eif (typeof msg === 'string') {
+      return typeof reason === 'string' && reason.length > 0
+        ? `${msg} (reason: ${reason})`
+        : msg
+    }
+  }
+ 
+  if (err instanceof Error) {
+    return err.message
+  }
+ 
+  if (typeof err === 'object') {
+    // Non-Error objects sometimes carry a top-level message (axios-style
+    // errors, hand-rolled error-likes). Extract before the JSON.stringify
+    // branch so a circular ref doesn't reduce the diagnostic to
+    // "[object Object]".
+    const msg = (err as { message?: unknown }).message
+    if (typeof msg === 'string') {
+      return msg
+    }
+    try {
+      return JSON.stringify(err)
+    } catch {
+      return String(err)
+    }
+  }
+ 
+  // Primitives serialise more readably via String() than JSON.stringify
+  // (which would quote strings and refuse to handle symbols).
+  return String(err)
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/packages/k8s/coverage/lcov-report/src/k8s/utils/npu-metrics.ts.html b/packages/k8s/coverage/lcov-report/src/k8s/utils/npu-metrics.ts.html new file mode 100644 index 00000000..0eca1983 --- /dev/null +++ b/packages/k8s/coverage/lcov-report/src/k8s/utils/npu-metrics.ts.html @@ -0,0 +1,2359 @@ + + + + + + Code coverage report for src/k8s/utils/npu-metrics.ts + + + + + + + + + +
+
+

All files / src/k8s/utils npu-metrics.ts

+
+ +
+ 21.71% + Statements + 76/350 +
+ + +
+ 4.55% + Branches + 18/395 +
+ + +
+ 13.72% + Functions + 7/51 +
+ + +
+ 23.64% + Lines + 70/296 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263 +264 +265 +266 +267 +268 +269 +270 +271 +272 +273 +274 +275 +276 +277 +278 +279 +280 +281 +282 +283 +284 +285 +286 +287 +288 +289 +290 +291 +292 +293 +294 +295 +296 +297 +298 +299 +300 +301 +302 +303 +304 +305 +306 +307 +308 +309 +310 +311 +312 +313 +314 +315 +316 +317 +318 +319 +320 +321 +322 +323 +324 +325 +326 +327 +328 +329 +330 +331 +332 +333 +334 +335 +336 +337 +338 +339 +340 +341 +342 +343 +344 +345 +346 +347 +348 +349 +350 +351 +352 +353 +354 +355 +356 +357 +358 +359 +360 +361 +362 +363 +364 +365 +366 +367 +368 +369 +370 +371 +372 +373 +374 +375 +376 +377 +378 +379 +380 +381 +382 +383 +384 +385 +386 +387 +388 +389 +390 +391 +392 +393 +394 +395 +396 +397 +398 +399 +400 +401 +402 +403 +404 +405 +406 +407 +408 +409 +410 +411 +412 +413 +414 +415 +416 +417 +418 +419 +420 +421 +422 +423 +424 +425 +426 +427 +428 +429 +430 +431 +432 +433 +434 +435 +436 +437 +438 +439 +440 +441 +442 +443 +444 +445 +446 +447 +448 +449 +450 +451 +452 +453 +454 +455 +456 +457 +458 +459 +460 +461 +462 +463 +464 +465 +466 +467 +468 +469 +470 +471 +472 +473 +474 +475 +476 +477 +478 +479 +480 +481 +482 +483 +484 +485 +486 +487 +488 +489 +490 +491 +492 +493 +494 +495 +496 +497 +498 +499 +500 +501 +502 +503 +504 +505 +506 +507 +508 +509 +510 +511 +512 +513 +514 +515 +516 +517 +518 +519 +520 +521 +522 +523 +524 +525 +526 +527 +528 +529 +530 +531 +532 +533 +534 +535 +536 +537 +538 +539 +540 +541 +542 +543 +544 +545 +546 +547 +548 +549 +550 +551 +552 +553 +554 +555 +556 +557 +558 +559 +560 +561 +562 +563 +564 +565 +566 +567 +568 +569 +570 +571 +572 +573 +574 +575 +576 +577 +578 +579 +580 +581 +582 +583 +584 +585 +586 +587 +588 +589 +590 +591 +592 +593 +594 +595 +596 +597 +598 +599 +600 +601 +602 +603 +604 +605 +606 +607 +608 +609 +610 +611 +612 +613 +614 +615 +616 +617 +618 +619 +620 +621 +622 +623 +624 +625 +626 +627 +628 +629 +630 +631 +632 +633 +634 +635 +636 +637 +638 +639 +640 +641 +642 +643 +644 +645 +646 +647 +648 +649 +650 +651 +652 +653 +654 +655 +656 +657 +658 +659 +660 +661 +662 +663 +664 +665 +666 +667 +668 +669 +670 +671 +672 +673 +674 +675 +676 +677 +678 +679 +680 +681 +682 +683 +684 +685 +686 +687 +688 +689 +690 +691 +692 +693 +694 +695 +696 +697 +698 +699 +700 +701 +702 +703 +704 +705 +706 +707 +708 +709 +710 +711 +712 +713 +714 +715 +716 +717 +718 +719 +720 +721 +722 +723 +724 +725 +726 +727 +728 +729 +730 +731 +732 +733 +734 +735 +736 +737 +738 +739 +740 +741 +742 +743 +744 +745 +746 +747 +748 +749 +750 +751 +752 +753 +754 +755 +756 +757 +758 +7599x +  +9x +9x +9x +9x +9x +9x +  +  +  +  +  +  +  +9x +9x +9x +9x +  +9x +9x +9x +  +9x +9x +9x +9x +  +9x +9x +9x +  +9x +9x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +9x +128x +  +64x +  +  +  +  +9x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +9x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +9x +22x +44x +44x +  +  +  +  +  +22x +  +  +9x +  +  +  +  +  +  +  +9x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +9x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +9x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +9x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +9x +22x +  +  +22x +22x +  +  +  +  +9x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +9x +  +  +  +  +  +  +  +  +  +9x +  +  +  +9x +  +  +  +  +  +  +9x +  +  +  +  +  +  +  +  +  +  +  +  +  +9x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +9x +  +  +  +  +  +  +9x +  +  +  +  +  +  +  +  +  +9x +  +  +  +21x +21x +21x +  +21x +21x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +9x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +9x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +9x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +9x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +9x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +9x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +9x +  +  +  +  +  +  +  +  +  +  +  +  +  +9x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +9x +21x +  +  +21x +  +21x +  +21x +21x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import * as core from '@actions/core'
+import * as k8s from '@kubernetes/client-node'
+import * as https from 'https'
+import * as http from 'http'
+import { URL } from 'url'
+import { getRunnerPodName, JOB_CONTAINER_NAME } from '../../hooks/constants'
+import { formatError } from './index'
+import {
+  execPodStepWithOutput,
+  getPodByName,
+  getSecretByName,
+  listPodsByRunnerInstance,
+  namespace
+} from '../index'
+ 
+export const NPU_METRICS_MARKER = 'NPU_METRICS_V1'
+export const ENV_NPU_METRICS_ENABLED = 'ACTIONS_RUNNER_NPU_METRICS'
+export const ENV_NPU_SAMPLE_INTERVAL = 'NPU_SAMPLE_INTERVAL'
+export const ENV_NPU_IDLE_THRESHOLD = 'NPU_IDLE_THRESHOLD'
+ 
+export const DEFAULT_NPU_SAMPLE_INTERVAL_SECONDS = 1
+export const MIN_NPU_SAMPLE_INTERVAL_SECONDS = 0.2
+export const DEFAULT_NPU_IDLE_THRESHOLD_PERCENT = 5
+ 
+export const NPU_SAMPLES_FILE = '/tmp/npu-samples.jsonl'
+export const NPU_TERMINATION_LOG = '/dev/termination-log'
+export const NPU_SAMPLES_MAX_BYTES = 4 * 1024 * 1024
+export const NPU_AGGREGATE_MAX_BYTES = 4096
+ 
+export const NPU_METRICS_SECRET_NAME = 'npu-metrics-pushgw'
+export const NPU_METRICS_PUSH_JOB = 'npu-job-record'
+export const NPU_COLLECT_TIMEOUT_MS = 10_000
+ 
+const NPU_RESOURCE_REGEX = /^huawei\.com\/(ascend\S*)$/i
+const SCALE_SET_NAME_REGEX = /^linux-[a-z0-9]+-[a-z0-9]+-\d+-([a-z][a-z0-9-]*)$/
+ 
+export interface NpuCardAggregate {
+  card: string
+  samples: number
+  peakUtil: number
+  avgUtil: number
+  peakHbm: number
+  firstTs: number
+  lastTs: number
+}
+ 
+export interface NpuAggregatePayload {
+  version: string
+  ts: number
+  cards: NpuCardAggregate[]
+}
+ 
+export interface NpuPushConfig {
+  url: string
+  username?: string
+  password?: string
+}
+ 
+export interface NpuJobLabels {
+  cluster: string
+  namespace: string
+  pod: string
+  podType: string
+  repo: string
+  runId: string
+  npuType: string
+  cardsRequested: string
+  result: string
+}
+ 
+export function npuMetricsEnabled(
+  Eenv: Record<string, string | undefined> = process.env
+): boolean {
+  return (
+    (env[ENV_NPU_METRICS_ENABLED] ?? '').trim().toLowerCase() !== 'disabled'
+  )
+}
+ 
+export function getNpuSampleIntervalSeconds(
+  env: Record<string, string | undefined> = process.env
+): number {
+  const raw = env[ENV_NPU_SAMPLE_INTERVAL]
+  if (!raw) {
+    return DEFAULT_NPU_SAMPLE_INTERVAL_SECONDS
+  }
+  const parsed = Number(raw)
+  if (!Number.isFinite(parsed) || parsed <= 0) {
+    core.warning(
+      `NPU_SAMPLE_INTERVAL is invalid ("${raw}"): use ${DEFAULT_NPU_SAMPLE_INTERVAL_SECONDS}`
+    )
+    return DEFAULT_NPU_SAMPLE_INTERVAL_SECONDS
+  }
+  return Math.max(parsed, MIN_NPU_SAMPLE_INTERVAL_SECONDS)
+}
+ 
+export function getIdleThresholdPercent(
+  env: Record<string, string | undefined> = process.env
+): number {
+  const raw = env[ENV_NPU_IDLE_THRESHOLD]
+  if (!raw) {
+    return DEFAULT_NPU_IDLE_THRESHOLD_PERCENT
+  }
+  const parsed = Number(raw)
+  if (!Number.isFinite(parsed) || parsed < 0) {
+    core.warning(
+      `NPU_IDLE_THRESHOLD is invalid ("${raw}"): use ${DEFAULT_NPU_IDLE_THRESHOLD_PERCENT}`
+    )
+    return DEFAULT_NPU_IDLE_THRESHOLD_PERCENT
+  }
+  return parsed
+}
+ 
+export function containerHasNpuRequest(container: k8s.V1Container): boolean {
+  const resources = [container.resources?.requests, container.resources?.limits]
+  for (const entry of resources) {
+    for (const key of Object.keys(entry ?? {})) {
+      if (NPU_RESOURCE_REGEX.test(key)) {
+        return true
+      }
+    }
+  }
+  return false
+}
+ 
+export function hasNpuRequest(spec: k8s.V1PodSpec | undefined): boolean {
+  return (spec?.containers ?? []).some(c => containerHasNpuRequest(c))
+}
+ 
+function listNpuCardsCommand(): string {
+  return `ls /dev/davinci[0-9]* 2>/dev/null | sed 's|.*/davinci||' | sort -n | uniq | tr '\\n' ' '`
+}
+ 
+export function buildNpuSamplerScript(
+  intervalSeconds = DEFAULT_NPU_SAMPLE_INTERVAL_SECONDS
+): string {
+  return [
+    `# ${NPU_METRICS_MARKER} sampler (detached, best-effort)`,
+    `F=${NPU_SAMPLES_FILE}`,
+    `CARDS=$(${listNpuCardsCommand()})`,
+    `[ -z "$CARDS" ] && exit 0`,
+    `while :; do`,
+    `  NOW=$(date +%s)`,
+    `  for C in $CARDS; do`,
+    `    OUT=$(npu-smi info -t usages -i "$C" 2>/dev/null) || continue`,
+    `    U=$(printf '%s\\n' "$OUT" | awk '{l=$0; gsub(/[ \\t\\r]/, "", l)} l ~ /AICore/ { if (match(l, /[0-9.]+%?$/)) { v = substr(l, RSTART, RLENGTH); sub(/%$/, "", v); print v; exit } }')`,
+    `    H=$(printf '%s\\n' "$OUT" | awk '{l=$0; gsub(/[ \\t\\r]/, "", l)} l ~ /HBM/ { if (match(l, /[0-9.]+%?$/)) { v = substr(l, RSTART, RLENGTH); sub(/%$/, "", v); print v; exit } }')`,
+    `    printf '{"ts":%s,"card":%s,"util":%s,"hbm":%s}\\n' "$NOW" "$C" "\${U:-0}" "\${H:-0}" >> "$F" 2>/dev/null || true`,
+    `  done`,
+    `  SZ=$(wc -c < "$F" 2>/dev/null || echo 0)`,
+    `  if [ "$SZ" -gt ${NPU_SAMPLES_MAX_BYTES} ]; then`,
+    `    tail -n 2000 "$F" > "$F.r" 2>/dev/null && mv "$F.r" "$F" || true`,
+    `  fi`,
+    `  sleep ${intervalSeconds}`,
+    `done`
+  ].join('\n')
+}
+ 
+const AGGREGATE_AWK = [
+  `BEGIN {`,
+  `  n = split(cards, a, " ")`,
+  `  for (i = 1; i <= n; i++) { cnt[a[i]] = 0; pu[a[i]] = 0; ph[a[i]] = 0; su[a[i]] = 0; fs[a[i]] = 0; ls[a[i]] = 0 }`,
+  `}`,
+  `{`,
+  `  ts = $0; sub(/.*"ts":/, "", ts); sub(/[^0-9].*/, "", ts)`,
+  `  c = $0;  sub(/.*"card":/, "", c); sub(/[^0-9].*/, "", c)`,
+  `  u = $0; sub(/.*"util":/, "", u); sub(/[^0-9.].*/, "", u)`,
+  `  h = $0; sub(/.*"hbm":/, "", h); sub(/[^0-9.].*/, "", h)`,
+  `  if (c == "") next`,
+  `  cnt[c]++`,
+  `  if (ts != "") { t = ts + 0; if (fs[c] == 0 || t < fs[c]) fs[c] = t; if (t > ls[c]) ls[c] = t }`,
+  `  if (u + 0 > pu[c]) pu[c] = u + 0`,
+  `  if (h + 0 > ph[c]) ph[c] = h + 0`,
+  `  su[c] += u + 0`,
+  `}`,
+  `END {`,
+  `  printf "{\\"v\\":\\"${NPU_METRICS_MARKER}\\",\\"ts\\":%d,\\"cards\\":[", now`,
+  `  sep = ""`,
+  `  for (c in cnt) {`,
+  `    au = cnt[c] > 0 ? su[c] / cnt[c] : 0`,
+  `    printf "%s{\\"c\\":\\"%s\\",\\"n\\":%d,\\"pu\\":%.1f,\\"au\\":%.1f,\\"ph\\":%.1f,\\"fs\\":%d,\\"ls\\":%d}", sep, c, cnt[c], pu[c], au, ph[c], fs[c], ls[c]`,
+  `    sep = ","`,
+  `  }`,
+  `  printf "]}\\n"`,
+  `}`
+].join('\n')
+ 
+export function buildNpuAggregateScript(): string {
+  return [
+    `# ${NPU_METRICS_MARKER} aggregate`,
+    `F=${NPU_SAMPLES_FILE}`,
+    `CARDS=$(${listNpuCardsCommand()})`,
+    `NOW=$(date +%s)`,
+    `touch "$F" 2>/dev/null || true`,
+    `awk -v now="$NOW" -v cards="$CARDS" '${AGGREGATE_AWK}' "$F" 2>/dev/null`
+  ].join('\n')
+}
+ 
+function commandHasMarker(command: string[] | undefined): boolean {
+  return (command ?? []).join(' ').includes(NPU_METRICS_MARKER)
+}
+ 
+function appendExecCommand(
+  existing: string[] | undefined,
+  appendLines: string[]
+): string[] {
+  if (
+    existing &&
+    existing.length >= 3 &&
+    /(^|\/)sh$/.test(existing[0]) &&
+    existing[1] === '-c'
+  ) {
+    return [
+      existing[0],
+      existing[1],
+      [...existing.slice(2), ...appendLines].join('\n')
+    ]
+  }
+  const prefix = (existing ?? []).map(
+    part => `'${part.replace(/'/g, "'\\''")}'`
+  )
+  return ['sh', '-c', [prefix.join(' '), ...appendLines].join('\n')]
+}
+ 
+export function injectNpuMetrics(
+  container: k8s.V1Container,
+  intervalSeconds = DEFAULT_NPU_SAMPLE_INTERVAL_SECONDS
+): boolean {
+  const lifecycle = container.lifecycle ?? {}
+  if (
+    commandHasMarker(lifecycle.postStart?.exec?.command) ||
+    commandHasMarker(lifecycle.preStop?.exec?.command)
+  ) {
+    return false
+  }
+ 
+  if (
+    (lifecycle.postStart && !lifecycle.postStart.exec) ||
+    (lifecycle.preStop && !lifecycle.preStop.exec)
+  ) {
+    core.warning(
+      'npu-metrics: container already has a non-exec lifecycle handler, skip injection'
+    )
+    return false
+  }
+ 
+  const samplerLine = `(${buildNpuSamplerScript(intervalSeconds)}) >/dev/null 2>&1 &`
+  const aggregateLine = `{ ( ${buildNpuAggregateScript()} ) | head -c ${NPU_AGGREGATE_MAX_BYTES} > ${NPU_TERMINATION_LOG}; } 2>/dev/null || true`
+ 
+  lifecycle.postStart = {
+    exec: {
+      command: appendExecCommand(lifecycle.postStart?.exec?.command, [
+        `# ${NPU_METRICS_MARKER} postStart: start detached npu sampler`,
+        samplerLine
+      ])
+    }
+  }
+  lifecycle.preStop = {
+    exec: {
+      command: appendExecCommand(lifecycle.preStop?.exec?.command, [
+        `# ${NPU_METRICS_MARKER} preStop: write npu aggregate to termination log`,
+        aggregateLine
+      ])
+    }
+  }
+  container.lifecycle = lifecycle
+  return true
+}
+ 
+export function maybeInjectNpuMetrics(container: k8s.V1Container): boolean {
+  Iif (!npuMetricsEnabled()) {
+    return false
+  }
+  Eif (!containerHasNpuRequest(container)) {
+    return false
+  }
+  return injectNpuMetrics(container)
+}
+ 
+export function parseNpuAggregate(
+  raw: string | undefined
+): NpuAggregatePayload | undefined {
+  if (!raw) {
+    return undefined
+  }
+  const start = raw.indexOf('{"v":')
+  if (start === -1) {
+    return undefined
+  }
+  const candidates = [raw.slice(start)]
+  const end = raw.lastIndexOf('}')
+  if (end > start) {
+    candidates.push(raw.slice(start, end + 1))
+  }
+  for (const candidate of candidates) {
+    let parsed: any
+    try {
+      parsed = JSON.parse(candidate)
+    } catch {
+      continue
+    }
+    if (parsed?.v !== NPU_METRICS_MARKER || !Array.isArray(parsed.cards)) {
+      continue
+    }
+    const cards: NpuCardAggregate[] = []
+    for (const c of parsed.cards) {
+      if (c === null || typeof c !== 'object' || c.c === undefined) {
+        continue
+      }
+      cards.push({
+        card: String(c.c),
+        samples: Number(c.n) || 0,
+        peakUtil: Number(c.pu) || 0,
+        avgUtil: Number(c.au) || 0,
+        peakHbm: Number(c.ph) || 0,
+        firstTs: Number(c.fs) || 0,
+        lastTs: Number(c.ls) || 0
+      })
+    }
+    return { version: parsed.v, ts: Number(parsed.ts) || 0, cards }
+  }
+  return undefined
+}
+ 
+export function isIdleRecord(
+  cards: NpuCardAggregate[],
+  threshold = DEFAULT_NPU_IDLE_THRESHOLD_PERCENT
+): boolean {
+  if (!cards.length) {
+    return false
+  }
+  return cards.every(c => c.peakUtil < threshold && c.avgUtil < threshold)
+}
+ 
+export function escapePromLabelValue(value: string): string {
+  return value.replace(/\\/g, '\\\\').replace(/"/g, '\\"').replace(/\n/g, '\\n')
+}
+ 
+export function formatPromLabels(labels: Record<string, string>): string {
+  return Object.entries(labels)
+    .filter(([, v]) => v !== undefined)
+    .map(([k, v]) => `${k}="${escapePromLabelValue(v)}"`)
+    .join(',')
+}
+ 
+const NPU_JOB_METRIC_LABEL_KEYS = [
+  'cluster',
+  'namespace',
+  'repo',
+  'run_id',
+  'pod',
+  'pod_type',
+  'card',
+  'npu_type',
+  'cards_requested',
+  'result',
+  'idle'
+]
+ 
+export function buildNpuJobMetricsBody(
+  labels: NpuJobLabels,
+  cards: NpuCardAggregate[],
+  idleThreshold = DEFAULT_NPU_IDLE_THRESHOLD_PERCENT
+): string {
+  const base: Record<string, string> = {
+    cluster: labels.cluster,
+    namespace: labels.namespace,
+    repo: labels.repo,
+    run_id: labels.runId,
+    pod: labels.pod,
+    pod_type: labels.podType,
+    npu_type: labels.npuType,
+    cards_requested: labels.cardsRequested,
+    result: labels.result
+  }
+  const idle = isIdleRecord(cards, idleThreshold) ? 'true' : 'false'
+  const lines: string[] = []
+  lines.push('# TYPE custom_npu_job_peak_util_percent gauge')
+  lines.push('# TYPE custom_npu_job_avg_util_percent gauge')
+  lines.push('# TYPE custom_npu_job_duration_seconds gauge')
+  lines.push('# TYPE custom_npu_job_sample_count gauge')
+  for (const card of cards) {
+    const cardLabels = { ...base, card: card.card, idle }
+    const l = formatPromLabels(
+      Object.fromEntries(
+        NPU_JOB_METRIC_LABEL_KEYS.map(k => [k, cardLabels[k]])
+      ) as Record<string, string>
+    )
+    lines.push(`custom_npu_job_peak_util_percent{${l}} ${card.peakUtil}`)
+    lines.push(`custom_npu_job_avg_util_percent{${l}} ${card.avgUtil}`)
+    const duration = Math.max(card.lastTs - card.firstTs, 0)
+    lines.push(`custom_npu_job_duration_seconds{${l}} ${duration}`)
+    lines.push(`custom_npu_job_sample_count{${l}} ${card.samples}`)
+  }
+  lines.push('# TYPE custom_npu_job_push_total counter')
+  lines.push(
+    `custom_npu_job_push_total{cluster="${escapePromLabelValue(labels.cluster)}",namespace="${escapePromLabelValue(labels.namespace)}",status="success"} 1`
+  )
+  return lines.join('\n') + '\n'
+}
+ 
+export function buildNpuPushFailedBody(labels: NpuJobLabels): string {
+  return (
+    `# TYPE custom_npu_job_push_total counter\n` +
+    `custom_npu_job_push_total{cluster="${escapePromLabelValue(labels.cluster)}",namespace="${escapePromLabelValue(labels.namespace)}",status="failed"} 1\n`
+  )
+}
+ 
+export function buildPushgatewayPath(
+  cluster: string,
+  ns: string,
+  pod: string
+): string {
+  return `/metrics/job/${NPU_METRICS_PUSH_JOB}/cluster/${encodeURIComponent(
+    cluster
+  )}/ns/${encodeURIComponent(ns)}/pod/${encodeURIComponent(pod)}`
+}
+ 
+export async function withTimeout<T>(
+  promise: Promise<T>,
+  timeoutMs: number
+): Promise<T> {
+  return await new Promise<T>((resolve, reject) => {
+    const timer = setTimeout(() => reject(new Error('timeout')), timeoutMs)
+    promise.then(
+      value => {
+        clearTimeout(timer)
+        resolve(value)
+      },
+      err => {
+        clearTimeout(timer)
+        reject(err)
+      }
+    )
+  })
+}
+ 
+export interface PushRequest {
+  url: string
+  method: string
+  body: string
+  username?: string
+  password?: string
+  timeoutMs?: number
+}
+ 
+export type RequestFn = (req: PushRequest) => Promise<{ statusCode: number }>
+ 
+export async function nodeRequest(req: PushRequest): Promise<{
+  statusCode: number
+}> {
+  const target = new URL(req.url)
+  const client = target.protocol === 'http:' ? http : https
+  const headers: Record<string, string> = {
+    'Content-Type': 'text/plain'
+  }
+  if (req.username !== undefined || req.password !== undefined) {
+    const basic = Buffer.from(
+      `${req.username ?? ''}:${req.password ?? ''}`
+    ).toString('base64')
+    headers['Authorization'] = `Basic ${basic}`
+  }
+  return await new Promise((resolve, reject) => {
+    const request = client.request(
+      target,
+      {
+        method: req.method,
+        headers,
+        timeout: req.timeoutMs ?? 5000,
+        rejectUnauthorized: false
+      },
+      response => {
+        response.resume()
+        response.on('end', () =>
+          resolve({ statusCode: response.statusCode ?? 0 })
+        )
+      }
+    )
+    request.on('timeout', () => request.destroy(new Error('request timeout')))
+    request.on('error', reject)
+    request.end(req.body)
+  })
+}
+ 
+export async function pushToPushgateway(
+  config: NpuPushConfig,
+  path: string,
+  body: string,
+  options?: { retries?: number; retryDelayMs?: number; requestFn?: RequestFn }
+): Promise<void> {
+  const retries = options?.retries ?? 2
+  const retryDelayMs = options?.retryDelayMs ?? 1000
+  const requestFn = options?.requestFn ?? nodeRequest
+  const url = `${config.url.replace(/\/+$/, '')}${path}`
+  let lastError: unknown
+  for (let attempt = 0; attempt <= retries; attempt++) {
+    if (attempt > 0) {
+      await new Promise(resolve => setTimeout(resolve, retryDelayMs))
+    }
+    try {
+      const response = await requestFn({
+        url,
+        method: 'POST',
+        body,
+        username: config.username,
+        password: config.password
+      })
+      if (response.statusCode >= 200 && response.statusCode < 300) {
+        return
+      }
+      lastError = new Error(`pushgateway returned ${response.statusCode}`)
+    } catch (err) {
+      lastError = err
+    }
+  }
+  throw lastError instanceof Error ? lastError : new Error(String(lastError))
+}
+ 
+export function decodePushSecret(
+  secret: k8s.V1Secret | undefined
+): NpuPushConfig | undefined {
+  const data = secret?.data ?? {}
+  const decode = (key: string): string | undefined => {
+    const encoded = data[key]
+    if (!encoded) {
+      return undefined
+    }
+    try {
+      const decoded = Buffer.from(encoded, 'base64').toString('utf8')
+      return decoded.length ? decoded : undefined
+    } catch {
+      return undefined
+    }
+  }
+  const url = decode('PUSHGATEWAY_URL')
+  if (!url) {
+    return undefined
+  }
+  return {
+    url,
+    username: decode('PUSHGATEWAY_USER'),
+    password: decode('PUSHGATEWAY_PASSWORD')
+  }
+}
+ 
+export async function readNpuPushConfig(): Promise<NpuPushConfig | undefined> {
+  try {
+    const secret = await getSecretByName(NPU_METRICS_SECRET_NAME)
+    return decodePushSecret(secret)
+  } catch (err) {
+    core.debug(
+      `npu-metrics: secret ${NPU_METRICS_SECRET_NAME} unavailable, skip push: ${formatError(err)}`
+    )
+    return undefined
+  }
+}
+ 
+function parseScaleSetSuffix(value: string | undefined): string | undefined {
+  if (!value) {
+    return undefined
+  }
+  const match = value.match(SCALE_SET_NAME_REGEX)
+  return match ? match[1] : undefined
+}
+ 
+export function extractClusterFromRunnerPod(pod: k8s.V1Pod): string {
+  const labels = pod.metadata?.labels ?? {}
+  const annotations = pod.metadata?.annotations ?? {}
+  const entries: [string, string][] = [
+    ...Object.entries(labels),
+    ...Object.entries(annotations)
+  ]
+  for (const [key, value] of entries) {
+    if (/scale[-_]?set|runner[-_]?deployment/i.test(key)) {
+      const suffix = parseScaleSetSuffix(value)
+      if (suffix) {
+        return suffix
+      }
+    }
+  }
+  for (const [, value] of entries) {
+    const suffix = parseScaleSetSuffix(value)
+    if (suffix) {
+      return suffix
+    }
+  }
+  return parseScaleSetSuffix(pod.metadata?.name) ?? 'unknown'
+}
+ 
+export function resolveNpuLabelsFromPod(
+  pod: k8s.V1Pod,
+  podName: string
+): {
+  podType: string
+  npuType: string
+  cardsRequested: string
+  result: string
+} {
+  const podType = podName.includes('-step-') ? 'step' : 'workflow'
+  const npuTypes = new Set<string>()
+  let cards = 0
+  for (const container of pod.spec?.containers ?? []) {
+    for (const resources of [
+      container.resources?.requests,
+      container.resources?.limits
+    ]) {
+      for (const [key, quantity] of Object.entries(resources ?? {})) {
+        const match = key.match(NPU_RESOURCE_REGEX)
+        if (match) {
+          npuTypes.add(match[1])
+          cards = Math.max(cards, parseInt(String(quantity), 10) || 0)
+        }
+      }
+    }
+  }
+  const mainStatus = (pod.status?.containerStatuses ?? []).find(
+    s => s.name === JOB_CONTAINER_NAME
+  )
+  const terminated = mainStatus?.state?.terminated
+  const result = terminated
+    ? String(terminated.exitCode)
+    : (pod.status?.phase ?? 'unknown')
+  return {
+    podType,
+    npuType: Array.from(npuTypes).sort().join(',') || 'unknown',
+    cardsRequested: String(cards || 0),
+    result
+  }
+}
+ 
+export function repoFromEnv(
+  env: Record<string, string | undefined> = process.env
+): string {
+  if (env.GITHUB_REPOSITORY) {
+    return env.GITHUB_REPOSITORY
+  }
+  const workspace = env.GITHUB_WORKSPACE ?? ''
+  const parts = workspace.split('/').filter(p => p.length > 0)
+  if (parts.length >= 2) {
+    return `${parts[parts.length - 2]}/${parts[parts.length - 1]}`
+  }
+  return 'unknown'
+}
+ 
+export async function collectNpuAggregateFromPod(
+  pod: k8s.V1Pod
+): Promise<NpuAggregatePayload | undefined> {
+  const podName = pod.metadata?.name
+  if (!podName) {
+    return undefined
+  }
+  const mainStatus = (pod.status?.containerStatuses ?? []).find(
+    s => s.name === JOB_CONTAINER_NAME
+  )
+  const terminatedMessage = mainStatus?.state?.terminated?.message
+  if (terminatedMessage) {
+    return parseNpuAggregate(terminatedMessage)
+  }
+  if (!mainStatus?.state?.running) {
+    return undefined
+  }
+  const { output } = await execPodStepWithOutput(
+    ['sh', '-c', buildNpuAggregateScript()],
+    podName,
+    JOB_CONTAINER_NAME,
+    5
+  )
+  return parseNpuAggregate(output)
+}
+ 
+export async function collectAndPushNpuMetrics(): Promise<void> {
+  Iif (!npuMetricsEnabled()) {
+    return
+  }
+  let pods: k8s.V1Pod[] = []
+  try {
+    pods = await listPodsByRunnerInstance()
+  } catch (err) {
+    core.debug(`npu-metrics: pod list failed: ${formatError(err)}`)
+    return
+  }
+  const npuPods = pods.filter(
+    pod => pod.metadata?.name && hasNpuRequest(pod.spec)
+  )
+  if (!npuPods.length) {
+    return
+  }
+ 
+  let cluster = 'unknown'
+  try {
+    const runnerPod = await getPodByName(getRunnerPodName())
+    cluster = extractClusterFromRunnerPod(runnerPod)
+  } catch (err) {
+    core.debug(`npu-metrics: cluster label unresolved: ${formatError(err)}`)
+  }
+ 
+  const config = await readNpuPushConfig()
+  if (!config) {
+    core.debug(
+      `npu-metrics: push config missing (secret ${NPU_METRICS_SECRET_NAME}), skip push`
+    )
+    return
+  }
+ 
+  for (const pod of npuPods) {
+    const podName = pod.metadata?.name as string
+    try {
+      await collectAndPushForPod(pod, podName, cluster, config)
+    } catch (err) {
+      core.debug(
+        `npu-metrics: collection failed for ${podName}: ${formatError(err)}`
+      )
+    }
+  }
+}
+ 
+async function collectAndPushForPod(
+  pod: k8s.V1Pod,
+  podName: string,
+  cluster: string,
+  config: NpuPushConfig
+): Promise<void> {
+  const payload = await collectNpuAggregateFromPod(pod)
+  if (!payload || !payload.cards.length) {
+    core.debug(`npu-metrics: no aggregate payload for ${podName}, skip`)
+    return
+  }
+ 
+  const npuInfo = resolveNpuLabelsFromPod(pod, podName)
+  const labels: NpuJobLabels = {
+    cluster,
+    namespace: namespace(),
+    pod: podName,
+    podType: npuInfo.podType,
+    repo: repoFromEnv(),
+    runId: process.env.GITHUB_RUN_ID ?? '',
+    npuType: npuInfo.npuType,
+    cardsRequested: npuInfo.cardsRequested,
+    result: npuInfo.result
+  }
+ 
+  const body = buildNpuJobMetricsBody(
+    labels,
+    payload.cards,
+    getIdleThresholdPercent()
+  )
+  const path = buildPushgatewayPath(labels.cluster, labels.namespace, podName)
+  try {
+    await pushToPushgateway(config, path, body)
+    core.debug(`npu-metrics: pushed job record for ${podName}`)
+  } catch (err) {
+    core.warning(`npu-metrics: push failed for ${podName}: ${formatError(err)}`)
+    try {
+      await pushToPushgateway(config, path, buildNpuPushFailedBody(labels))
+    } catch {
+      // pushgateway unreachable, nothing else to record
+    }
+  }
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/packages/k8s/coverage/lcov-report/tests/index.html b/packages/k8s/coverage/lcov-report/tests/index.html new file mode 100644 index 00000000..bf4c502f --- /dev/null +++ b/packages/k8s/coverage/lcov-report/tests/index.html @@ -0,0 +1,116 @@ + + + + + + Code coverage report for tests + + + + + + + + + +
+
+

All files tests

+
+ +
+ 33.82% + Statements + 23/68 +
+ + +
+ 0% + Branches + 0/7 +
+ + +
+ 14.28% + Functions + 2/14 +
+ + +
+ 32.83% + Lines + 22/67 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
test-setup.ts +
+
33.82%23/680%0/714.28%2/1432.83%22/67
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/packages/k8s/coverage/lcov-report/tests/test-setup.ts.html b/packages/k8s/coverage/lcov-report/tests/test-setup.ts.html new file mode 100644 index 00000000..ae914717 --- /dev/null +++ b/packages/k8s/coverage/lcov-report/tests/test-setup.ts.html @@ -0,0 +1,580 @@ + + + + + + Code coverage report for tests/test-setup.ts + + + + + + + + + +
+
+

All files / tests test-setup.ts

+
+ +
+ 33.82% + Statements + 23/68 +
+ + +
+ 0% + Branches + 0/7 +
+ + +
+ 14.28% + Functions + 2/14 +
+ + +
+ 32.83% + Lines + 22/67 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +1666x +6x +  +6x +6x +  +6x +  +6x +  +6x +  +6x +  +  +  +  +  +  +46x +46x +46x +46x +  +  +6x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +6x +  +  +  +  +  +  +  +  +6x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +6x +  +  +  +  +  +6x +  +  +  +  +6x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +6x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +6x +  +  +  +  +  +  +  +  +  +  +  +6x +  +  +  +  +  +  +  +  +  +  +  +  +6x + 
import * as k8s from '@kubernetes/client-node'
+import * as fs from 'fs'
+import { HookData } from 'hooklib/lib'
+import * as path from 'path'
+import { v4 as uuidv4 } from 'uuid'
+ 
+const kc = new k8s.KubeConfig()
+ 
+kc.loadFromDefault()
+ 
+const k8sApi = kc.makeApiClient(k8s.CoreV1Api)
+ 
+export class TestHelper {
+  private tempDirPath: string
+  private podName: string
+  private runnerWorkdir: string
+  private runnerTemp: string
+ 
+  constructor() {
+    this.tempDirPath = `${__dirname}/_temp/runner`
+    this.runnerWorkdir = `${this.tempDirPath}/_work`
+    this.runnerTemp = `${this.tempDirPath}/_work/_temp`
+    this.podName = uuidv4().replace(/-/g, '')
+  }
+ 
+  async initialize(): Promise<void> {
+    process.env['ACTIONS_RUNNER_POD_NAME'] = `${this.podName}`
+    process.env['RUNNER_WORKSPACE'] = `${this.runnerWorkdir}/repo`
+    process.env['RUNNER_TEMP'] = `${this.runnerTemp}`
+    process.env['GITHUB_WORKSPACE'] = `${this.runnerWorkdir}/repo/repo`
+    process.env['ACTIONS_RUNNER_KUBERNETES_NAMESPACE'] = 'default'
+ 
+    fs.mkdirSync(`${this.runnerWorkdir}/repo/repo`, { recursive: true })
+    fs.mkdirSync(`${this.tempDirPath}/externals`, { recursive: true })
+    fs.mkdirSync(this.runnerTemp, { recursive: true })
+    fs.mkdirSync(`${this.runnerTemp}/_github_workflow`, { recursive: true })
+    fs.mkdirSync(`${this.runnerTemp}/_github_home`, { recursive: true })
+    fs.mkdirSync(`${this.runnerTemp}/_runner_file_commands`, {
+      recursive: true
+    })
+ 
+    fs.copyFileSync(
+      path.resolve(`${__dirname}/../../../examples/example-script.sh`),
+      `${this.runnerTemp}/example-script.sh`
+    )
+ 
+    await this.cleanupK8sResources()
+    try {
+      await this.createTestJobPod()
+    } catch (e) {
+      console.log(e)
+    }
+  }
+ 
+  async cleanup(): Promise<void> {
+    try {
+      await this.cleanupK8sResources()
+      fs.rmSync(this.tempDirPath, { recursive: true })
+    } catch {
+      // Ignore errors during cleanup
+    }
+  }
+ 
+  async cleanupK8sResources(): Promise<void> {
+    await k8sApi
+      .deleteNamespacedPod({
+        name: this.podName,
+        namespace: 'default',
+        gracePeriodSeconds: 0
+      })
+      .catch((e: k8s.ApiException<any>) => {
+        if (e.code !== 404) {
+          console.error(JSON.stringify(e))
+        }
+      })
+    await k8sApi
+      .deleteNamespacedPod({
+        name: `${this.podName}-workflow`,
+        namespace: 'default',
+        gracePeriodSeconds: 0
+      })
+      .catch((e: k8s.ApiException<any>) => {
+        if (e.code !== 404) {
+          console.error(JSON.stringify(e))
+        }
+      })
+  }
+  createFile(fileName?: string): string {
+    const filePath = `${this.tempDirPath}/${fileName || uuidv4()}`
+    fs.writeFileSync(filePath, '')
+    return filePath
+  }
+ 
+  removeFile(fileName: string): void {
+    const filePath = `${this.tempDirPath}/${fileName}`
+    fs.rmSync(filePath)
+  }
+ 
+  async createTestJobPod(): Promise<void> {
+    const container = {
+      name: 'runner',
+      image: 'ghcr.io/actions/actions-runner:latest',
+      imagePullPolicy: 'IfNotPresent'
+    } as k8s.V1Container
+ 
+    const pod: k8s.V1Pod = {
+      metadata: {
+        name: this.podName
+      },
+      spec: {
+        restartPolicy: 'Never',
+        containers: [container],
+        securityContext: {
+          runAsUser: 1001,
+          runAsGroup: 1001,
+          fsGroup: 1001
+        }
+      }
+    } as k8s.V1Pod
+    await k8sApi.createNamespacedPod({ namespace: 'default', body: pod })
+  }
+ 
+  getPrepareJobDefinition(): HookData {
+    const prepareJob = JSON.parse(
+      fs.readFileSync(
+        path.resolve(__dirname + '/../../../examples/prepare-job.json'),
+        'utf8'
+      )
+    )
+ 
+    prepareJob.args.container.userMountVolumes = undefined
+    prepareJob.args.container.registry = null
+    prepareJob.args.services.forEach(s => {
+      s.registry = null
+    })
+ 
+    return prepareJob
+  }
+ 
+  getRunScriptStepDefinition(): HookData {
+    const runScriptStep = JSON.parse(
+      fs.readFileSync(
+        path.resolve(__dirname + '/../../../examples/run-script-step.json'),
+        'utf8'
+      )
+    )
+ 
+    runScriptStep.args.entryPointArgs[1] = `/__w/_temp/example-script.sh`
+    return runScriptStep
+  }
+ 
+  getRunContainerStepDefinition(): HookData {
+    const runContainerStep = JSON.parse(
+      fs.readFileSync(
+        path.resolve(__dirname + '/../../../examples/run-container-step.json'),
+        'utf8'
+      )
+    )
+ 
+    runContainerStep.args.entryPointArgs[1] = `/__w/_temp/example-script.sh`
+    runContainerStep.args.userMountVolumes = undefined
+    runContainerStep.args.registry = null
+    return runContainerStep
+  }
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/packages/k8s/coverage/lcov.info b/packages/k8s/coverage/lcov.info new file mode 100644 index 00000000..e2164134 --- /dev/null +++ b/packages/k8s/coverage/lcov.info @@ -0,0 +1,3688 @@ +TN: +SF:src/hooks/cleanup-job.ts +FN:11,cleanupJob +FNF:1 +FNH:1 +FNDA:21,cleanupJob +DA:1,7 +DA:2,7 +DA:3,7 +DA:4,7 +DA:11,7 +DA:12,21 +DA:14,42 +DA:16,0 +DA:19,42 +LF:9 +LH:8 +BRDA:19,0,0,21 +BRDA:12,1,0,0 +BRDA:12,1,1,21 +BRF:3 +BRH:2 +end_of_record +TN: +SF:src/hooks/constants.ts +FN:3,getRunnerPodName +FN:13,getJobPodName +FN:20,getStepPodName +FN:27,getVolumeClaimName +FN:35,getSecretName +FN:48,(anonymous_5) +FN:50,RunnerInstanceLabel +FN:54,(anonymous_7) +FN:58,(anonymous_8) +FN:62,(anonymous_9) +FNF:10 +FNH:10 +FNDA:105,getRunnerPodName +FNDA:11,getJobPodName +FNDA:17,getStepPodName +FNDA:4,getVolumeClaimName +FNDA:3,getSecretName +FNDA:15,(anonymous_5) +FNDA:67,RunnerInstanceLabel +FNDA:4,(anonymous_7) +FNDA:3,(anonymous_8) +FNDA:1,(anonymous_9) +DA:1,15 +DA:3,15 +DA:4,105 +DA:5,105 +DA:6,74 +DA:10,31 +DA:13,15 +DA:14,11 +DA:20,15 +DA:21,17 +DA:27,15 +DA:28,4 +DA:29,4 +DA:30,3 +DA:32,1 +DA:35,15 +DA:36,3 +DA:42,15 +DA:43,15 +DA:44,15 +DA:45,15 +DA:46,15 +DA:48,15 +DA:51,67 +DA:54,15 +DA:55,4 +DA:58,15 +DA:59,3 +DA:62,15 +DA:63,1 +DA:65,15 +LF:31 +LH:31 +BRDA:5,0,0,74 +BRDA:5,0,1,31 +BRDA:29,1,0,3 +BRDA:29,1,1,1 +BRF:4 +BRH:4 +end_of_record +TN: +SF:src/hooks/index.ts +FNF:0 +FNH:0 +DA:1,7 +DA:2,7 +DA:3,7 +DA:4,7 +LF:4 +LH:4 +BRF:0 +BRH:0 +end_of_record +TN: +SF:src/hooks/prepare-job.ts +FN:40,prepareJob +FN:73,(anonymous_25) +FN:235,generateResponseFile +FN:254,(anonymous_27) +FN:275,(anonymous_28) +FN:278,(anonymous_29) +FN:279,(anonymous_30) +FN:299,createContainerSpec +FN:355,(anonymous_32) +FNF:9 +FNH:8 +FNDA:10,prepareJob +FNDA:2,(anonymous_25) +FNDA:3,generateResponseFile +FNDA:1,(anonymous_27) +FNDA:0,(anonymous_28) +FNDA:3,(anonymous_29) +FNDA:2,(anonymous_30) +FNDA:21,createContainerSpec +FNDA:1,(anonymous_32) +DA:1,8 +DA:3,8 +DA:10,8 +DA:20,8 +DA:32,8 +DA:37,8 +DA:38,8 +DA:40,8 +DA:44,10 +DA:45,1 +DA:48,18 +DA:50,9 +DA:52,9 +DA:53,9 +DA:54,8 +DA:60,8 +DA:63,9 +DA:64,9 +DA:65,9 +DA:66,1 +DA:67,2 +DA:68,2 +DA:69,2 +DA:72,1 +DA:73,1 +DA:74,2 +DA:75,2 +DA:76,2 +DA:79,2 +DA:80,2 +DA:82,0 +DA:85,2 +DA:86,2 +DA:87,2 +DA:91,9 +DA:92,1 +DA:95,8 +DA:97,8 +DA:105,4 +DA:106,2 +DA:113,2 +DA:114,2 +DA:121,2 +DA:122,2 +DA:125,2 +DA:126,2 +DA:130,2 +DA:133,1 +DA:134,1 +DA:137,1 +DA:138,1 +DA:139,1 +DA:140,1 +DA:143,0 +DA:149,2 +DA:159,2 +DA:162,6 +DA:163,0 +DA:165,6 +DA:169,6 +DA:170,6 +DA:171,1 +DA:173,5 +DA:176,5 +DA:177,0 +DA:181,10 +DA:188,2 +DA:192,1 +DA:193,1 +DA:196,8 +DA:198,8 +DA:199,0 +DA:205,0 +DA:206,0 +DA:207,0 +DA:215,0 +DA:218,4 +DA:220,4 +DA:222,4 +DA:227,1 +DA:228,1 +DA:229,1 +DA:231,3 +DA:232,3 +DA:242,3 +DA:243,0 +DA:245,3 +DA:253,3 +DA:254,1 +DA:256,3 +DA:257,1 +DA:258,1 +DA:259,1 +DA:260,0 +DA:265,1 +DA:271,3 +DA:273,1 +DA:275,0 +DA:277,1 +DA:278,3 +DA:280,2 +DA:281,2 +DA:282,0 +DA:283,0 +DA:284,0 +DA:289,2 +DA:296,3 +DA:299,8 +DA:302,29 +DA:305,21 +DA:306,1 +DA:307,1 +DA:310,21 +DA:315,21 +DA:316,1 +DA:319,21 +DA:320,18 +DA:323,21 +DA:324,10 +DA:327,21 +DA:328,21 +DA:331,3 +DA:332,2 +DA:336,21 +DA:341,21 +DA:342,20 +DA:348,21 +DA:350,21 +DA:351,20 +DA:354,1 +DA:355,1 +DA:358,1 +DA:359,1 +DA:362,1 +LF:134 +LH:119 +BRDA:196,0,0,4 +BRDA:44,1,0,1 +BRDA:44,1,1,9 +BRDA:53,2,0,8 +BRDA:53,2,1,1 +BRDA:53,3,0,0 +BRDA:53,3,1,9 +BRDA:53,4,0,9 +BRDA:53,4,1,9 +BRDA:65,5,0,1 +BRDA:65,5,1,8 +BRDA:65,6,0,0 +BRDA:65,6,1,9 +BRDA:65,7,0,9 +BRDA:65,7,1,9 +BRDA:69,8,0,2 +BRDA:69,8,1,1 +BRDA:75,9,0,2 +BRDA:75,9,1,0 +BRDA:76,10,0,2 +BRDA:76,10,1,1 +BRDA:79,11,0,2 +BRDA:79,11,1,0 +BRDA:91,12,0,1 +BRDA:91,12,1,8 +BRDA:91,13,0,9 +BRDA:91,13,1,1 +BRDA:91,14,0,0 +BRDA:91,14,1,1 +BRDA:91,15,0,1 +BRDA:91,15,1,1 +BRDA:113,16,0,2 +BRDA:113,16,1,0 +BRDA:127,17,0,1 +BRDA:127,17,1,1 +BRDA:130,18,0,1 +BRDA:130,18,1,1 +BRDA:130,19,0,2 +BRDA:130,19,1,1 +BRDA:130,19,2,1 +BRDA:139,20,0,1 +BRDA:139,20,1,0 +BRDA:139,21,0,0 +BRDA:139,21,1,1 +BRDA:139,22,0,1 +BRDA:139,22,1,1 +BRDA:162,23,0,0 +BRDA:162,23,1,6 +BRDA:162,24,0,0 +BRDA:162,24,1,6 +BRDA:162,25,0,6 +BRDA:162,25,1,6 +BRDA:162,26,0,0 +BRDA:162,26,1,6 +BRDA:162,27,0,6 +BRDA:162,27,1,6 +BRDA:166,28,0,0 +BRDA:166,28,1,6 +BRDA:166,29,0,6 +BRDA:166,29,1,6 +BRDA:166,30,0,0 +BRDA:166,30,1,6 +BRDA:166,31,0,6 +BRDA:166,31,1,6 +BRDA:170,32,0,1 +BRDA:170,32,1,5 +BRDA:176,33,0,0 +BRDA:176,33,1,5 +BRDA:176,34,0,0 +BRDA:176,34,1,5 +BRDA:176,35,0,5 +BRDA:176,35,1,5 +BRDA:176,36,0,0 +BRDA:176,36,1,5 +BRDA:176,37,0,5 +BRDA:176,37,1,5 +BRDA:177,38,0,0 +BRDA:177,38,1,0 +BRDA:192,39,0,1 +BRDA:192,39,1,0 +BRDA:198,40,0,4 +BRDA:198,40,1,0 +BRDA:206,41,0,0 +BRDA:206,41,1,0 +BRDA:206,42,0,0 +BRDA:206,42,1,0 +BRDA:206,43,0,0 +BRDA:206,43,1,0 +BRDA:206,44,0,0 +BRDA:206,44,1,0 +BRDA:206,45,0,0 +BRDA:206,45,1,0 +BRDA:242,46,0,0 +BRDA:242,46,1,3 +BRDA:242,47,0,0 +BRDA:242,47,1,3 +BRDA:242,48,0,3 +BRDA:242,48,1,3 +BRDA:253,49,0,2 +BRDA:253,49,1,1 +BRDA:253,50,0,3 +BRDA:253,50,1,3 +BRDA:253,51,0,2 +BRDA:253,51,1,1 +BRDA:253,52,0,3 +BRDA:253,52,1,3 +BRDA:256,53,0,1 +BRDA:256,53,1,2 +BRDA:258,54,0,1 +BRDA:258,54,1,0 +BRDA:258,55,0,0 +BRDA:258,55,1,1 +BRDA:258,56,0,1 +BRDA:258,56,1,1 +BRDA:271,57,0,1 +BRDA:271,57,1,2 +BRDA:271,58,0,0 +BRDA:271,58,1,3 +BRDA:271,59,0,3 +BRDA:271,59,1,3 +BRDA:273,60,0,1 +BRDA:273,60,1,0 +BRDA:273,61,0,1 +BRDA:273,61,1,1 +BRDA:275,62,0,0 +BRDA:275,62,1,0 +BRDA:275,63,0,0 +BRDA:275,63,1,0 +BRDA:275,64,0,0 +BRDA:275,64,1,0 +BRDA:277,65,0,0 +BRDA:277,65,1,1 +BRDA:277,66,0,1 +BRDA:277,66,1,1 +BRDA:277,67,0,0 +BRDA:277,67,1,1 +BRDA:277,68,0,1 +BRDA:277,68,1,1 +BRDA:277,69,0,0 +BRDA:277,69,1,1 +BRDA:277,70,0,1 +BRDA:277,70,1,1 +BRDA:281,71,0,0 +BRDA:281,71,1,2 +BRDA:281,72,0,0 +BRDA:281,72,1,2 +BRDA:281,73,0,2 +BRDA:281,73,1,2 +BRDA:283,74,0,0 +BRDA:283,74,1,0 +BRDA:283,75,0,0 +BRDA:283,75,1,0 +BRDA:302,76,0,8 +BRDA:302,76,1,13 +BRDA:305,77,0,1 +BRDA:305,77,1,20 +BRDA:305,78,0,21 +BRDA:305,78,1,4 +BRDA:315,79,0,1 +BRDA:315,79,1,20 +BRDA:319,80,0,18 +BRDA:319,80,1,3 +BRDA:323,81,0,10 +BRDA:323,81,1,11 +BRDA:323,82,0,21 +BRDA:323,82,1,10 +BRDA:329,83,0,21 +BRDA:329,83,1,9 +BRDA:331,84,0,2 +BRDA:331,84,1,1 +BRDA:331,85,0,3 +BRDA:331,85,1,3 +BRDA:341,86,0,20 +BRDA:341,86,1,1 +BRDA:341,87,0,21 +BRDA:341,87,1,9 +BRDA:350,88,0,20 +BRDA:350,88,1,1 +BRDA:354,89,0,0 +BRDA:354,89,1,1 +BRDA:354,90,0,1 +BRDA:354,90,1,1 +BRDA:354,91,0,0 +BRDA:354,91,1,1 +BRDA:354,92,0,1 +BRDA:354,92,1,1 +BRDA:358,93,0,1 +BRDA:358,93,1,0 +BRF:188 +BRH:134 +end_of_record +TN: +SF:src/hooks/run-container-step.ts +FN:36,runContainerStep +FN:169,(anonymous_25) +FN:181,classifyScriptError +FN:193,(anonymous_29) +FN:234,(anonymous_30) +FN:246,createContainerSpec +FN:264,(anonymous_32) +FNF:7 +FNH:2 +FNDA:16,runContainerStep +FNDA:0,(anonymous_25) +FNDA:0,classifyScriptError +FNDA:0,(anonymous_29) +FNDA:0,(anonymous_30) +FNDA:14,createContainerSpec +FNDA:0,(anonymous_32) +DA:1,8 +DA:2,8 +DA:3,8 +DA:5,8 +DA:6,8 +DA:19,8 +DA:28,8 +DA:34,8 +DA:36,8 +DA:39,16 +DA:40,1 +DA:43,15 +DA:44,1 +DA:49,14 +DA:50,14 +DA:51,14 +DA:52,13 +DA:55,14 +DA:57,14 +DA:58,14 +DA:62,14 +DA:64,14 +DA:65,14 +DA:66,14 +DA:69,0 +DA:70,0 +DA:76,0 +DA:79,0 +DA:86,0 +DA:87,0 +DA:88,0 +DA:89,0 +DA:93,0 +DA:94,0 +DA:95,0 +DA:96,0 +DA:97,0 +DA:99,0 +DA:101,0 +DA:104,0 +DA:106,0 +DA:114,0 +DA:116,0 +DA:119,0 +DA:120,0 +DA:125,0 +DA:126,0 +DA:132,0 +DA:137,0 +DA:139,0 +DA:141,0 +DA:146,0 +DA:148,0 +DA:149,0 +DA:151,0 +DA:155,0 +DA:156,0 +DA:157,0 +DA:158,0 +DA:159,0 +DA:166,0 +DA:167,0 +DA:169,0 +DA:170,0 +DA:186,0 +DA:187,0 +DA:188,0 +DA:191,0 +DA:192,0 +DA:193,0 +DA:195,0 +DA:196,0 +DA:197,0 +DA:198,0 +DA:203,0 +DA:204,0 +DA:205,0 +DA:206,0 +DA:210,0 +DA:213,0 +DA:219,0 +DA:221,0 +DA:222,0 +DA:228,0 +DA:231,0 +DA:232,0 +DA:234,0 +DA:236,0 +DA:239,0 +DA:240,0 +DA:241,0 +DA:243,0 +DA:250,14 +DA:251,14 +DA:252,14 +DA:253,14 +DA:254,14 +DA:255,14 +DA:257,14 +DA:259,14 +DA:260,14 +DA:263,0 +DA:264,0 +DA:266,0 +DA:267,0 +DA:270,0 +LF:106 +LH:33 +BRDA:169,0,0,0 +BRDA:39,1,0,1 +BRDA:39,1,1,15 +BRDA:43,2,0,1 +BRDA:43,2,1,14 +BRDA:49,3,0,14 +BRDA:49,3,1,5 +BRDA:51,4,0,13 +BRDA:51,4,1,1 +BRDA:69,5,0,0 +BRDA:69,5,1,0 +BRDA:69,6,0,0 +BRDA:69,6,1,0 +BRDA:69,7,0,0 +BRDA:69,7,1,0 +BRDA:88,8,0,0 +BRDA:88,8,1,0 +BRDA:88,9,0,0 +BRDA:88,9,1,0 +BRDA:96,10,0,0 +BRDA:96,10,1,0 +BRDA:125,11,0,0 +BRDA:125,11,1,0 +BRDA:141,12,0,0 +BRDA:141,12,1,0 +BRDA:142,13,0,0 +BRDA:142,13,1,0 +BRDA:142,13,2,0 +BRDA:157,14,0,0 +BRDA:157,14,1,0 +BRDA:192,15,0,0 +BRDA:192,15,1,0 +BRDA:192,16,0,0 +BRDA:192,16,1,0 +BRDA:192,17,0,0 +BRDA:192,17,1,0 +BRDA:192,18,0,0 +BRDA:192,18,1,0 +BRDA:195,19,0,0 +BRDA:195,19,1,0 +BRDA:195,20,0,0 +BRDA:195,20,1,0 +BRDA:195,21,0,0 +BRDA:195,21,1,0 +BRDA:195,22,0,0 +BRDA:195,22,1,0 +BRDA:196,23,0,0 +BRDA:196,23,1,0 +BRDA:197,24,0,0 +BRDA:197,24,1,0 +BRDA:197,25,0,0 +BRDA:197,25,1,0 +BRDA:199,26,0,0 +BRDA:199,26,1,0 +BRDA:199,26,2,0 +BRDA:199,26,3,0 +BRDA:199,26,4,0 +BRDA:203,27,0,0 +BRDA:203,27,1,0 +BRDA:204,28,0,0 +BRDA:204,28,1,0 +BRDA:221,29,0,0 +BRDA:221,29,1,0 +BRDA:221,30,0,0 +BRDA:221,30,1,0 +BRDA:221,31,0,0 +BRDA:221,31,1,0 +BRDA:221,32,0,0 +BRDA:221,32,1,0 +BRDA:221,33,0,0 +BRDA:221,33,1,0 +BRDA:223,34,0,0 +BRDA:223,34,1,0 +BRDA:223,35,0,0 +BRDA:223,35,1,0 +BRDA:231,36,0,0 +BRDA:231,36,1,0 +BRDA:240,37,0,0 +BRDA:240,37,1,0 +BRDA:259,38,0,14 +BRDA:259,38,1,0 +BRDA:263,39,0,0 +BRDA:263,39,1,0 +BRDA:263,40,0,0 +BRDA:263,40,1,0 +BRDA:263,41,0,0 +BRDA:263,41,1,0 +BRDA:263,42,0,0 +BRDA:263,42,1,0 +BRDA:266,43,0,0 +BRDA:266,43,1,0 +BRF:91 +BRH:9 +end_of_record +TN: +SF:src/hooks/run-script-step.ts +FN:16,formatScriptError +FN:26,(anonymous_24) +FN:35,runScriptStep +FNF:3 +FNH:3 +FNDA:3,formatScriptError +FNDA:7,(anonymous_24) +FNDA:7,runScriptStep +DA:2,7 +DA:3,7 +DA:5,7 +DA:11,7 +DA:12,7 +DA:13,7 +DA:17,3 +DA:18,3 +DA:22,3 +DA:23,3 +DA:24,3 +DA:26,7 +DA:28,3 +DA:30,3 +DA:31,3 +DA:32,3 +DA:35,7 +DA:40,7 +DA:41,2 +DA:47,5 +DA:48,5 +DA:56,5 +DA:57,5 +DA:58,5 +DA:59,5 +DA:61,10 +DA:70,10 +DA:76,5 +DA:94,10 +DA:100,0 +DA:101,0 +DA:102,0 +DA:106,5 +DA:107,5 +DA:109,5 +DA:114,4 +DA:115,3 +DA:118,4 +DA:119,4 +DA:123,3 +DA:125,1 +DA:126,1 +DA:128,5 +DA:129,5 +DA:131,0 +DA:136,1 +DA:139,2 +DA:145,0 +LF:48 +LH:43 +BRDA:23,0,0,3 +BRDA:23,0,1,0 +BRDA:31,1,0,3 +BRDA:31,1,1,0 +BRDA:40,2,0,2 +BRDA:40,2,1,5 +BRDA:40,3,0,0 +BRDA:40,3,1,7 +BRDA:40,4,0,7 +BRDA:40,4,1,7 +BRDA:114,5,0,3 +BRDA:114,5,1,1 +BRDA:119,6,0,3 +BRDA:119,6,1,1 +BRDA:120,7,0,4 +BRDA:120,7,1,4 +BRF:16 +BRH:13 +end_of_record +TN: +SF:src/k8s/heartbeat.ts +FN:11,parsePositiveMsEnv +FN:19,(anonymous_10) +FN:25,WebSocketHeartbeat +FN:30,(anonymous_12) +FN:39,(anonymous_13) +FN:53,(anonymous_14) +FN:59,(anonymous_15) +FN:64,(anonymous_16) +FN:86,(anonymous_17) +FN:95,(anonymous_18) +FN:100,(anonymous_19) +FN:106,(anonymous_20) +FNF:12 +FNH:11 +FNDA:8,parsePositiveMsEnv +FNDA:14,(anonymous_10) +FNDA:8,WebSocketHeartbeat +FNDA:22,(anonymous_12) +FNDA:8,(anonymous_13) +FNDA:8,(anonymous_14) +FNDA:5,(anonymous_15) +FNDA:1,(anonymous_16) +FNDA:1,(anonymous_17) +FNDA:0,(anonymous_18) +FNDA:1,(anonymous_19) +FNDA:29,(anonymous_20) +DA:1,14 +DA:11,14 +DA:15,8 +DA:16,8 +DA:19,14 +DA:20,8 +DA:21,8 +DA:22,8 +DA:23,14 +DA:26,8 +DA:27,8 +DA:30,14 +DA:31,22 +DA:32,22 +DA:33,0 +DA:34,0 +DA:36,22 +DA:39,14 +DA:40,8 +DA:41,0 +DA:43,8 +DA:44,8 +DA:45,8 +DA:47,8 +DA:48,4 +DA:49,4 +DA:53,14 +DA:54,8 +DA:57,8 +DA:59,8 +DA:60,5 +DA:61,1 +DA:62,1 +DA:64,5 +DA:65,1 +DA:68,1 +DA:69,1 +DA:70,1 +DA:74,1 +DA:84,8 +DA:86,8 +DA:87,1 +DA:88,0 +DA:90,1 +DA:91,1 +DA:95,8 +DA:96,0 +DA:97,0 +DA:100,8 +DA:101,1 +DA:102,1 +DA:106,8 +DA:107,29 +DA:109,16 +DA:111,13 +DA:112,12 +DA:113,12 +DA:114,12 +DA:115,4 +DA:116,4 +DA:118,12 +DA:119,0 +DA:122,0 +DA:123,0 +DA:127,1 +DA:128,0 +DA:132,1 +DA:136,14 +LF:68 +LH:58 +BRDA:15,0,0,7 +BRDA:15,0,1,1 +BRDA:15,1,0,8 +BRDA:15,1,1,8 +BRDA:16,2,0,2 +BRDA:16,2,1,6 +BRDA:16,3,0,8 +BRDA:16,3,1,4 +BRDA:32,4,0,0 +BRDA:32,4,1,22 +BRDA:40,5,0,0 +BRDA:40,5,1,8 +BRDA:43,6,0,8 +BRDA:43,6,1,0 +BRDA:47,7,0,4 +BRDA:47,7,1,4 +BRDA:60,8,0,1 +BRDA:60,8,1,4 +BRDA:87,9,0,0 +BRDA:87,9,1,1 +BRDA:90,10,0,1 +BRDA:90,10,1,0 +BRDA:107,11,0,16 +BRDA:107,11,1,13 +BRDA:111,12,0,12 +BRDA:111,12,1,1 +BRDA:114,13,0,4 +BRDA:114,13,1,8 +BRDA:118,14,0,0 +BRDA:118,14,1,12 +BRDA:127,15,0,0 +BRDA:127,15,1,1 +BRF:32 +BRH:25 +end_of_record +TN: +SF:src/k8s/index.ts +FN:69,createJobPod +FN:189,createContainerStepPod +FN:242,deletePod +FN:250,execPodStep +FN:278,(anonymous_36) +FN:292,(anonymous_37) +FN:292,(anonymous_38) +FN:300,(anonymous_40) +FN:306,(anonymous_43) +FN:307,(anonymous_44) +FN:314,(anonymous_45) +FN:337,(anonymous_46) +FN:346,(anonymous_47) +FN:346,(anonymous_48) +FN:353,(anonymous_50) +FN:354,(anonymous_51) +FN:361,(anonymous_52) +FN:379,execPodStepWithOutput +FN:391,(anonymous_56) +FN:399,(anonymous_57) +FN:407,(anonymous_58) +FN:414,(anonymous_59) +FN:426,(anonymous_60) +FN:437,(anonymous_61) +FN:451,(anonymous_62) +FN:456,(anonymous_63) +FN:467,(anonymous_64) +FN:485,(anonymous_65) +FN:503,execCalculateOutputHashSorted +FN:512,(anonymous_69) +FN:522,(anonymous_70) +FN:533,(anonymous_71) +FN:548,(anonymous_72) +FN:556,(anonymous_73) +FN:565,localCalculateOutputHashSorted +FN:569,(anonymous_77) +FN:575,(anonymous_78) +FN:579,(anonymous_79) +FN:584,(anonymous_80) +FN:599,execCpToPod +FN:622,(anonymous_86) +FN:633,(anonymous_87) +FN:633,(anonymous_88) +FN:644,(anonymous_90) +FN:685,(anonymous_93) +FN:688,(anonymous_94) +FN:691,(anonymous_95) +FN:694,(anonymous_96) +FN:697,(anonymous_97) +FN:701,(anonymous_98) +FN:720,execCpFromPod +FN:756,(anonymous_104) +FN:773,(anonymous_105) +FN:773,(anonymous_106) +FN:783,(anonymous_108) +FN:824,(anonymous_111) +FN:827,(anonymous_112) +FN:830,(anonymous_113) +FN:833,(anonymous_114) +FN:836,(anonymous_115) +FN:840,(anonymous_116) +FN:859,waitForJobToComplete +FN:873,createDockerSecret +FN:914,createSecretForEnvs +FN:942,deleteSecret +FN:949,pruneSecrets +FN:960,(anonymous_132) +FN:960,(anonymous_133) +FN:1052,getUnrecoverableWaitingReasons +FN:1070,getUnrecoverableEventReasons +FN:1085,getUnrecoverableTerminatedReasons +FN:1107,isPermanentSchedulingFailure +FN:1111,(anonymous_139) +FN:1123,getPermanentSchedulingPatterns +FN:1146,getWaitingReasonHint +FN:1165,getContainerErrors +FN:1184,getTerminatedReasonHint +FN:1211,getContainerTerminatedErrors +FN:1230,getEventReasonHint +FN:1266,getPodEventErrors +FN:1331,describePodFailure +FN:1412,describePodWarningEvents +FN:1429,(anonymous_155) +FN:1434,(anonymous_156) +FN:1438,(anonymous_157) +FN:1441,(anonymous_158) +FN:1459,getPodConditionErrors +FN:1469,checkUnrecoverableErrors +FN:1483,(anonymous_163) +FN:1485,(anonymous_164) +FN:1496,waitForPodPhases +FN:1576,getPrepareJobTimeoutSeconds +FN:1595,readPod +FN:1610,parsePodPhase +FN:1617,isJobSucceeded +FN:1628,getPodLogs +FN:1634,(anonymous_179) +FN:1644,(anonymous_180) +FN:1645,(anonymous_181) +FN:1646,(anonymous_182) +FN:1653,prunePods +FN:1664,(anonymous_186) +FN:1664,(anonymous_187) +FN:1669,getPodStatus +FN:1679,isAuthPermissionsOK +FN:1697,(anonymous_195) +FN:1700,isPodContainerAlpine +FN:1722,namespace +FN:1727,(anonymous_200) +FN:1750,(anonymous_201) +FN:1753,BackOffManager +FN:1759,(anonymous_203) +FN:1760,(anonymous_206) +FN:1776,containerPorts +FN:1798,(anonymous_208) +FN:1818,getPodByName +FN:1825,getSecretByName +FN:1832,listPodsByRunnerInstance +FNF:118 +FNH:51 +FNDA:0,createJobPod +FNDA:0,createContainerStepPod +FNDA:0,deletePod +FNDA:0,execPodStep +FNDA:0,(anonymous_36) +FNDA:0,(anonymous_37) +FNDA:0,(anonymous_38) +FNDA:0,(anonymous_40) +FNDA:0,(anonymous_43) +FNDA:0,(anonymous_44) +FNDA:0,(anonymous_45) +FNDA:0,(anonymous_46) +FNDA:0,(anonymous_47) +FNDA:0,(anonymous_48) +FNDA:0,(anonymous_50) +FNDA:0,(anonymous_51) +FNDA:0,(anonymous_52) +FNDA:7,execPodStepWithOutput +FNDA:36,(anonymous_56) +FNDA:35,(anonymous_57) +FNDA:3,(anonymous_58) +FNDA:7,(anonymous_59) +FNDA:35,(anonymous_60) +FNDA:3,(anonymous_61) +FNDA:4,(anonymous_62) +FNDA:7,(anonymous_63) +FNDA:5,(anonymous_64) +FNDA:2,(anonymous_65) +FNDA:0,execCalculateOutputHashSorted +FNDA:0,(anonymous_69) +FNDA:0,(anonymous_70) +FNDA:0,(anonymous_71) +FNDA:0,(anonymous_72) +FNDA:0,(anonymous_73) +FNDA:0,localCalculateOutputHashSorted +FNDA:0,(anonymous_77) +FNDA:0,(anonymous_78) +FNDA:0,(anonymous_79) +FNDA:0,(anonymous_80) +FNDA:3,execCpToPod +FNDA:90,(anonymous_86) +FNDA:0,(anonymous_87) +FNDA:0,(anonymous_88) +FNDA:90,(anonymous_90) +FNDA:0,(anonymous_93) +FNDA:0,(anonymous_94) +FNDA:0,(anonymous_95) +FNDA:0,(anonymous_96) +FNDA:0,(anonymous_97) +FNDA:0,(anonymous_98) +FNDA:2,execCpFromPod +FNDA:60,(anonymous_104) +FNDA:0,(anonymous_105) +FNDA:0,(anonymous_106) +FNDA:60,(anonymous_108) +FNDA:0,(anonymous_111) +FNDA:0,(anonymous_112) +FNDA:0,(anonymous_113) +FNDA:0,(anonymous_114) +FNDA:0,(anonymous_115) +FNDA:0,(anonymous_116) +FNDA:3,waitForJobToComplete +FNDA:0,createDockerSecret +FNDA:0,createSecretForEnvs +FNDA:0,deleteSecret +FNDA:21,pruneSecrets +FNDA:0,(anonymous_132) +FNDA:0,(anonymous_133) +FNDA:28,getUnrecoverableWaitingReasons +FNDA:23,getUnrecoverableEventReasons +FNDA:24,getUnrecoverableTerminatedReasons +FNDA:19,isPermanentSchedulingFailure +FNDA:58,(anonymous_139) +FNDA:17,getPermanentSchedulingPatterns +FNDA:9,getWaitingReasonHint +FNDA:18,getContainerErrors +FNDA:11,getTerminatedReasonHint +FNDA:21,getContainerTerminatedErrors +FNDA:10,getEventReasonHint +FNDA:21,getPodEventErrors +FNDA:9,describePodFailure +FNDA:8,describePodWarningEvents +FNDA:4,(anonymous_155) +FNDA:0,(anonymous_156) +FNDA:0,(anonymous_157) +FNDA:3,(anonymous_158) +FNDA:6,getPodConditionErrors +FNDA:6,checkUnrecoverableErrors +FNDA:0,(anonymous_163) +FNDA:0,(anonymous_164) +FNDA:10,waitForPodPhases +FNDA:5,getPrepareJobTimeoutSeconds +FNDA:24,readPod +FNDA:16,parsePodPhase +FNDA:3,isJobSucceeded +FNDA:0,getPodLogs +FNDA:0,(anonymous_179) +FNDA:0,(anonymous_180) +FNDA:0,(anonymous_181) +FNDA:0,(anonymous_182) +FNDA:21,prunePods +FNDA:0,(anonymous_186) +FNDA:0,(anonymous_187) +FNDA:0,getPodStatus +FNDA:0,isAuthPermissionsOK +FNDA:0,(anonymous_195) +FNDA:0,isPodContainerAlpine +FNDA:276,namespace +FNDA:63,(anonymous_200) +FNDA:13,(anonymous_201) +FNDA:13,BackOffManager +FNDA:7,(anonymous_203) +FNDA:7,(anonymous_206) +FNDA:21,containerPorts +FNDA:0,(anonymous_208) +FNDA:0,getPodByName +FNDA:0,getSecretByName +FNDA:21,listPodsByRunnerInstance +DA:1,13 +DA:2,13 +DA:3,13 +DA:4,13 +DA:5,13 +DA:6,13 +DA:7,13 +DA:8,13 +DA:9,13 +DA:11,13 +DA:16,13 +DA:28,13 +DA:29,13 +DA:32,13 +DA:34,13 +DA:36,13 +DA:37,13 +DA:38,13 +DA:40,13 +DA:42,13 +DA:69,13 +DA:76,0 +DA:77,0 +DA:78,0 +DA:80,0 +DA:81,0 +DA:84,0 +DA:86,0 +DA:87,0 +DA:89,0 +DA:90,0 +DA:92,0 +DA:93,0 +DA:96,0 +DA:98,0 +DA:99,0 +DA:100,0 +DA:106,0 +DA:107,0 +DA:109,0 +DA:116,0 +DA:117,0 +DA:120,0 +DA:148,0 +DA:150,0 +DA:165,0 +DA:166,0 +DA:167,0 +DA:168,0 +DA:170,0 +DA:171,0 +DA:172,0 +DA:175,0 +DA:176,0 +DA:179,0 +DA:180,0 +DA:183,0 +DA:189,13 +DA:194,0 +DA:196,0 +DA:197,0 +DA:199,0 +DA:200,0 +DA:202,0 +DA:203,0 +DA:206,0 +DA:208,0 +DA:209,0 +DA:211,0 +DA:213,0 +DA:228,0 +DA:229,0 +DA:232,0 +DA:233,0 +DA:236,0 +DA:242,13 +DA:243,0 +DA:250,13 +DA:256,0 +DA:257,0 +DA:261,0 +DA:263,0 +DA:264,0 +DA:268,0 +DA:272,0 +DA:276,0 +DA:278,0 +DA:279,0 +DA:280,0 +DA:282,0 +DA:292,0 +DA:293,0 +DA:297,0 +DA:300,0 +DA:301,0 +DA:302,0 +DA:306,0 +DA:307,0 +DA:308,0 +DA:311,0 +DA:314,0 +DA:315,0 +DA:316,0 +DA:317,0 +DA:319,0 +DA:324,0 +DA:325,0 +DA:326,0 +DA:327,0 +DA:329,0 +DA:332,0 +DA:333,0 +DA:338,0 +DA:339,0 +DA:340,0 +DA:341,0 +DA:343,0 +DA:346,0 +DA:347,0 +DA:348,0 +DA:351,0 +DA:352,0 +DA:353,0 +DA:354,0 +DA:355,0 +DA:358,0 +DA:361,0 +DA:362,0 +DA:363,0 +DA:365,0 +DA:369,0 +DA:379,13 +DA:383,13 +DA:386,7 +DA:387,7 +DA:390,7 +DA:391,7 +DA:392,36 +DA:393,36 +DA:394,36 +DA:398,7 +DA:399,7 +DA:400,35 +DA:401,35 +DA:402,35 +DA:403,70 +DA:406,7 +DA:407,7 +DA:408,3 +DA:409,3 +DA:410,3 +DA:411,6 +DA:414,7 +DA:415,7 +DA:416,0 +DA:417,0 +DA:419,7 +DA:420,0 +DA:421,0 +DA:425,7 +DA:427,35 +DA:428,35 +DA:429,35 +DA:430,35 +DA:432,0 +DA:436,7 +DA:438,3 +DA:439,3 +DA:440,3 +DA:441,3 +DA:443,0 +DA:451,7 +DA:452,4 +DA:453,4 +DA:456,7 +DA:457,7 +DA:468,5 +DA:469,5 +DA:470,5 +DA:471,3 +DA:476,2 +DA:477,2 +DA:478,1 +DA:480,1 +DA:491,2 +DA:492,2 +DA:493,2 +DA:494,2 +DA:495,1 +DA:497,1 +DA:503,13 +DA:508,0 +DA:510,0 +DA:511,0 +DA:513,0 +DA:514,0 +DA:515,0 +DA:517,0 +DA:522,0 +DA:523,0 +DA:534,0 +DA:535,0 +DA:536,0 +DA:538,0 +DA:544,0 +DA:548,0 +DA:551,0 +DA:554,0 +DA:556,0 +DA:558,0 +DA:560,0 +DA:561,0 +DA:562,0 +DA:565,13 +DA:568,0 +DA:570,0 +DA:574,0 +DA:575,0 +DA:576,0 +DA:578,0 +DA:579,0 +DA:580,0 +DA:582,0 +DA:584,0 +DA:586,0 +DA:588,0 +DA:589,0 +DA:590,0 +DA:592,0 +DA:599,13 +DA:604,3 +DA:606,3 +DA:607,90 +DA:609,90 +DA:612,90 +DA:620,90 +DA:621,90 +DA:622,180 +DA:623,90 +DA:633,0 +DA:634,0 +DA:635,0 +DA:641,0 +DA:644,90 +DA:648,90 +DA:649,90 +DA:650,90 +DA:651,3 +DA:655,174 +DA:659,0 +DA:660,0 +DA:661,0 +DA:663,0 +DA:664,0 +DA:670,0 +DA:671,0 +DA:677,0 +DA:678,0 +DA:681,0 +DA:684,0 +DA:685,0 +DA:687,0 +DA:688,0 +DA:690,0 +DA:691,0 +DA:693,0 +DA:694,0 +DA:696,0 +DA:698,0 +DA:699,0 +DA:702,0 +DA:703,0 +DA:705,0 +DA:706,0 +DA:707,0 +DA:708,0 +DA:714,0 +DA:715,0 +DA:720,13 +DA:725,2 +DA:726,2 +DA:734,2 +DA:735,0 +DA:738,2 +DA:739,60 +DA:742,60 +DA:743,60 +DA:744,60 +DA:745,60 +DA:753,60 +DA:754,60 +DA:756,120 +DA:761,60 +DA:762,60 +DA:763,60 +DA:773,0 +DA:774,0 +DA:775,0 +DA:783,60 +DA:787,60 +DA:788,60 +DA:789,60 +DA:790,2 +DA:794,116 +DA:798,0 +DA:799,0 +DA:800,0 +DA:802,0 +DA:803,0 +DA:809,0 +DA:810,0 +DA:816,0 +DA:817,0 +DA:820,0 +DA:823,0 +DA:824,0 +DA:826,0 +DA:827,0 +DA:829,0 +DA:830,0 +DA:832,0 +DA:833,0 +DA:835,0 +DA:837,0 +DA:838,0 +DA:841,0 +DA:842,0 +DA:844,0 +DA:845,0 +DA:846,0 +DA:847,0 +DA:853,0 +DA:854,0 +DA:859,13 +DA:860,3 +DA:861,3 +DA:863,3 +DA:864,0 +DA:867,3 +DA:869,0 +DA:873,13 +DA:876,0 +DA:888,0 +DA:890,0 +DA:891,0 +DA:892,0 +DA:893,0 +DA:894,0 +DA:895,0 +DA:896,0 +DA:897,0 +DA:900,0 +DA:901,0 +DA:902,0 +DA:908,0 +DA:914,13 +DA:917,0 +DA:919,0 +DA:920,0 +DA:921,0 +DA:922,0 +DA:923,0 +DA:924,0 +DA:926,0 +DA:929,0 +DA:930,0 +DA:931,0 +DA:932,0 +DA:935,0 +DA:939,0 +DA:942,13 +DA:943,0 +DA:949,13 +DA:950,21 +DA:954,0 +DA:955,0 +DA:958,0 +DA:960,0 +DA:961,0 +DA:966,13 +DA:1001,13 +DA:1024,13 +DA:1038,13 +DA:1046,13 +DA:1052,13 +DA:1053,28 +DA:1054,28 +DA:1055,26 +DA:1057,2 +DA:1058,3 +DA:1059,3 +DA:1060,3 +DA:1061,3 +DA:1064,2 +DA:1070,13 +DA:1071,23 +DA:1072,23 +DA:1073,21 +DA:1075,2 +DA:1076,3 +DA:1077,3 +DA:1078,3 +DA:1079,3 +DA:1082,2 +DA:1085,13 +DA:1087,24 +DA:1088,24 +DA:1089,21 +DA:1091,3 +DA:1092,7 +DA:1093,7 +DA:1094,7 +DA:1095,4 +DA:1098,3 +DA:1107,13 +DA:1110,19 +DA:1111,58 +DA:1123,13 +DA:1124,17 +DA:1125,17 +DA:1126,0 +DA:1127,0 +DA:1129,0 +DA:1130,0 +DA:1131,0 +DA:1132,0 +DA:1133,0 +DA:1134,0 +DA:1136,0 +DA:1141,0 +DA:1142,0 +DA:1143,0 +DA:1147,9 +DA:1149,4 +DA:1157,3 +DA:1159,1 +DA:1161,1 +DA:1165,13 +DA:1166,18 +DA:1167,18 +DA:1168,18 +DA:1172,36 +DA:1173,14 +DA:1174,14 +DA:1175,9 +DA:1176,9 +DA:1177,9 +DA:1178,9 +DA:1181,18 +DA:1184,13 +DA:1188,11 +DA:1189,3 +DA:1191,8 +DA:1192,2 +DA:1194,6 +DA:1195,5 +DA:1197,1 +DA:1199,0 +DA:1201,0 +DA:1203,1 +DA:1205,3 +DA:1208,1 +DA:1211,13 +DA:1212,21 +DA:1213,21 +DA:1214,21 +DA:1218,42 +DA:1219,17 +DA:1220,17 +DA:1221,11 +DA:1222,11 +DA:1223,11 +DA:1224,11 +DA:1227,21 +DA:1231,10 +DA:1233,4 +DA:1240,1 +DA:1247,4 +DA:1254,1 +DA:1266,13 +DA:1267,21 +DA:1268,21 +DA:1269,0 +DA:1274,21 +DA:1278,19 +DA:1280,2 +DA:1285,2 +DA:1288,19 +DA:1289,19 +DA:1290,19 +DA:1291,19 +DA:1296,3 +DA:1301,16 +DA:1305,5 +DA:1310,5 +DA:1312,11 +DA:1313,1 +DA:1315,10 +DA:1316,10 +DA:1317,10 +DA:1318,10 +DA:1319,10 +DA:1320,10 +DA:1322,19 +DA:1331,13 +DA:1334,9 +DA:1336,1 +DA:1341,8 +DA:1342,8 +DA:1345,8 +DA:1346,8 +DA:1349,8 +DA:1350,8 +DA:1351,1 +DA:1355,8 +DA:1356,1 +DA:1357,1 +DA:1358,1 +DA:1359,1 +DA:1362,8 +DA:1365,8 +DA:1366,8 +DA:1370,8 +DA:1371,8 +DA:1372,3 +DA:1373,3 +DA:1376,2 +DA:1377,1 +DA:1378,1 +DA:1383,3 +DA:1385,3 +DA:1386,1 +DA:1387,1 +DA:1388,1 +DA:1393,8 +DA:1394,2 +DA:1398,8 +DA:1399,8 +DA:1400,3 +DA:1403,8 +DA:1404,0 +DA:1406,8 +DA:1415,8 +DA:1419,6 +DA:1421,2 +DA:1426,2 +DA:1429,6 +DA:1430,6 +DA:1431,3 +DA:1434,3 +DA:1435,0 +DA:1436,0 +DA:1438,3 +DA:1440,3 +DA:1441,3 +DA:1442,3 +DA:1443,3 +DA:1445,3 +DA:1446,0 +DA:1450,3 +DA:1459,13 +DA:1460,6 +DA:1469,13 +DA:1474,6 +DA:1476,6 +DA:1478,6 +DA:1482,6 +DA:1484,0 +DA:1485,0 +DA:1488,6 +DA:1496,13 +DA:1500,18 +DA:1502,10 +DA:1503,10 +DA:1504,15 +DA:1505,15 +DA:1507,15 +DA:1512,6 +DA:1518,12 +DA:1520,2 +DA:1526,4 +DA:1528,9 +DA:1529,9 +DA:1530,3 +DA:1538,10 +DA:1539,2 +DA:1540,2 +DA:1541,2 +DA:1542,0 +DA:1546,2 +DA:1554,4 +DA:1555,5 +DA:1556,3 +DA:1557,3 +DA:1563,2 +DA:1568,0 +DA:1569,0 +DA:1576,13 +DA:1578,5 +DA:1580,5 +DA:1581,5 +DA:1584,0 +DA:1585,0 +DA:1586,0 +DA:1589,0 +DA:1592,0 +DA:1596,24 +DA:1602,13 +DA:1610,13 +DA:1611,16 +DA:1612,3 +DA:1614,13 +DA:1618,3 +DA:1622,1 +DA:1623,1 +DA:1625,0 +DA:1628,13 +DA:1632,0 +DA:1633,0 +DA:1634,0 +DA:1636,0 +DA:1639,0 +DA:1644,0 +DA:1645,0 +DA:1646,0 +DA:1647,0 +DA:1648,0 +DA:1653,13 +DA:1654,21 +DA:1658,0 +DA:1659,0 +DA:1662,0 +DA:1664,0 +DA:1669,13 +DA:1672,0 +DA:1676,0 +DA:1679,13 +DA:1680,0 +DA:1681,0 +DA:1682,0 +DA:1683,0 +DA:1684,0 +DA:1685,0 +DA:1686,0 +DA:1687,0 +DA:1688,0 +DA:1689,0 +DA:1690,0 +DA:1691,0 +DA:1696,0 +DA:1697,0 +DA:1700,13 +DA:1704,0 +DA:1706,0 +DA:1716,0 +DA:1719,0 +DA:1722,13 +DA:1723,276 +DA:1724,213 +DA:1727,63 +DA:1728,63 +DA:1729,63 +DA:1735,0 +DA:1736,0 +DA:1737,0 +DA:1738,0 +DA:1739,0 +DA:1745,0 +DA:1750,13 +DA:1751,13 +DA:1752,13 +DA:1753,13 +DA:1754,13 +DA:1755,3 +DA:1759,13 +DA:1760,14 +DA:1761,7 +DA:1763,7 +DA:1764,7 +DA:1765,2 +DA:1767,5 +DA:1768,5 +DA:1770,5 +DA:1771,0 +DA:1774,13 +DA:1776,13 +DA:1779,21 +DA:1780,21 +DA:1781,21 +DA:1783,0 +DA:1784,0 +DA:1785,0 +DA:1786,0 +DA:1789,0 +DA:1790,0 +DA:1793,0 +DA:1794,0 +DA:1795,0 +DA:1798,0 +DA:1799,0 +DA:1800,0 +DA:1801,0 +DA:1803,0 +DA:1806,0 +DA:1807,0 +DA:1809,0 +DA:1810,0 +DA:1813,0 +DA:1815,0 +DA:1818,13 +DA:1819,0 +DA:1825,13 +DA:1826,0 +DA:1832,13 +DA:1833,21 +DA:1837,0 +LF:716 +LH:370 +BRDA:183,0,0,0 +BRDA:77,1,0,0 +BRDA:77,1,1,0 +BRDA:80,2,0,0 +BRDA:80,2,1,0 +BRDA:80,3,0,0 +BRDA:80,3,1,0 +BRDA:80,4,0,0 +BRDA:80,4,1,0 +BRDA:107,5,0,0 +BRDA:107,5,1,0 +BRDA:107,6,0,0 +BRDA:107,6,1,0 +BRDA:107,7,0,0 +BRDA:107,7,1,0 +BRDA:107,8,0,0 +BRDA:107,8,1,0 +BRDA:116,9,0,0 +BRDA:116,9,1,0 +BRDA:124,10,0,0 +BRDA:124,10,1,0 +BRDA:165,11,0,0 +BRDA:165,11,1,0 +BRDA:167,12,0,0 +BRDA:167,12,1,0 +BRDA:167,13,0,0 +BRDA:167,13,1,0 +BRDA:167,14,0,0 +BRDA:167,14,1,0 +BRDA:167,15,0,0 +BRDA:167,15,1,0 +BRDA:167,16,0,0 +BRDA:167,16,1,0 +BRDA:175,17,0,0 +BRDA:175,17,1,0 +BRDA:175,18,0,0 +BRDA:175,18,1,0 +BRDA:175,19,0,0 +BRDA:175,19,1,0 +BRDA:179,20,0,0 +BRDA:179,20,1,0 +BRDA:179,21,0,0 +BRDA:179,21,1,0 +BRDA:179,22,0,0 +BRDA:179,22,1,0 +BRDA:236,23,0,0 +BRDA:228,24,0,0 +BRDA:228,24,1,0 +BRDA:228,25,0,0 +BRDA:228,25,1,0 +BRDA:228,26,0,0 +BRDA:228,26,1,0 +BRDA:232,27,0,0 +BRDA:232,27,1,0 +BRDA:232,28,0,0 +BRDA:232,28,1,0 +BRDA:232,29,0,0 +BRDA:232,29,1,0 +BRDA:243,30,0,0 +BRDA:290,31,0,0 +BRDA:290,31,1,0 +BRDA:290,32,0,0 +BRDA:290,32,1,0 +BRDA:302,33,0,0 +BRDA:302,33,1,0 +BRDA:303,34,0,0 +BRDA:303,34,1,0 +BRDA:303,34,2,0 +BRDA:324,35,0,0 +BRDA:324,35,1,0 +BRDA:327,36,0,0 +BRDA:327,36,1,0 +BRDA:330,37,0,0 +BRDA:330,37,1,0 +BRDA:330,38,0,0 +BRDA:330,38,1,0 +BRDA:330,39,0,0 +BRDA:330,39,1,0 +BRDA:330,40,0,0 +BRDA:330,40,1,0 +BRDA:333,41,0,0 +BRDA:333,41,1,0 +BRDA:333,42,0,0 +BRDA:333,42,1,0 +BRDA:333,43,0,0 +BRDA:333,43,1,0 +BRDA:340,44,0,0 +BRDA:340,44,1,0 +BRDA:352,45,0,0 +BRDA:352,45,1,0 +BRDA:352,46,0,0 +BRDA:352,46,1,0 +BRDA:352,46,2,0 +BRDA:383,47,0,6 +BRDA:383,47,1,1 +BRDA:456,48,0,7 +BRDA:392,49,0,0 +BRDA:392,49,1,36 +BRDA:394,50,0,25 +BRDA:394,50,1,11 +BRDA:402,51,0,35 +BRDA:402,51,1,0 +BRDA:402,52,0,35 +BRDA:402,52,1,35 +BRDA:410,53,0,3 +BRDA:410,53,1,0 +BRDA:410,54,0,3 +BRDA:410,54,1,3 +BRDA:415,55,0,0 +BRDA:415,55,1,7 +BRDA:419,56,0,0 +BRDA:419,56,1,7 +BRDA:452,57,0,0 +BRDA:452,57,1,4 +BRDA:452,58,0,4 +BRDA:452,58,1,4 +BRDA:453,59,0,2 +BRDA:453,59,1,2 +BRDA:465,60,0,0 +BRDA:465,60,1,7 +BRDA:465,61,0,7 +BRDA:465,61,1,7 +BRDA:470,62,0,3 +BRDA:470,62,1,2 +BRDA:471,63,0,3 +BRDA:471,63,1,3 +BRDA:476,64,0,0 +BRDA:476,64,1,2 +BRDA:476,65,0,2 +BRDA:476,65,1,2 +BRDA:477,66,0,1 +BRDA:477,66,1,1 +BRDA:480,67,0,1 +BRDA:480,67,1,0 +BRDA:480,68,0,0 +BRDA:480,68,1,1 +BRDA:480,69,0,1 +BRDA:480,69,1,1 +BRDA:492,70,0,2 +BRDA:492,70,1,0 +BRDA:494,71,0,1 +BRDA:494,71,1,1 +BRDA:535,72,0,0 +BRDA:535,72,1,0 +BRDA:540,73,0,0 +BRDA:540,73,1,0 +BRDA:540,74,0,0 +BRDA:540,74,1,0 +BRDA:541,75,0,0 +BRDA:541,75,1,0 +BRDA:541,76,0,0 +BRDA:541,76,1,0 +BRDA:544,77,0,0 +BRDA:544,77,1,0 +BRDA:544,78,0,0 +BRDA:544,78,1,0 +BRDA:544,79,0,0 +BRDA:544,79,1,0 +BRDA:568,80,0,0 +BRDA:568,80,1,0 +BRDA:580,81,0,0 +BRDA:580,81,1,0 +BRDA:634,82,0,0 +BRDA:634,82,1,0 +BRDA:650,83,0,3 +BRDA:650,83,1,87 +BRDA:607,84,0,0 +BRDA:607,84,1,90 +BRDA:677,85,0,0 +BRDA:677,85,1,0 +BRDA:699,86,0,0 +BRDA:699,86,1,0 +BRDA:661,87,0,0 +BRDA:661,87,1,0 +BRDA:734,88,0,0 +BRDA:734,88,1,2 +BRDA:750,89,0,60 +BRDA:750,89,1,0 +BRDA:774,90,0,0 +BRDA:774,90,1,0 +BRDA:789,91,0,2 +BRDA:789,91,1,58 +BRDA:739,92,0,0 +BRDA:739,92,1,60 +BRDA:816,93,0,0 +BRDA:816,93,1,0 +BRDA:838,94,0,0 +BRDA:838,94,1,0 +BRDA:800,95,0,0 +BRDA:800,95,1,0 +BRDA:869,96,0,0 +BRDA:861,97,0,0 +BRDA:861,97,1,3 +BRDA:863,98,0,0 +BRDA:863,98,1,0 +BRDA:908,99,0,0 +BRDA:878,100,0,0 +BRDA:878,100,1,0 +BRDA:943,101,0,0 +BRDA:950,102,0,21 +BRDA:954,103,0,0 +BRDA:954,103,1,0 +BRDA:961,104,0,0 +BRDA:961,105,0,0 +BRDA:961,105,1,0 +BRDA:961,106,0,0 +BRDA:961,106,1,0 +BRDA:1054,107,0,26 +BRDA:1054,107,1,2 +BRDA:1060,108,0,3 +BRDA:1060,108,1,0 +BRDA:1072,109,0,21 +BRDA:1072,109,1,2 +BRDA:1078,110,0,3 +BRDA:1078,110,1,0 +BRDA:1088,111,0,21 +BRDA:1088,111,1,3 +BRDA:1094,112,0,4 +BRDA:1094,112,1,3 +BRDA:1110,113,0,2 +BRDA:1110,113,1,17 +BRDA:1125,114,0,17 +BRDA:1125,114,1,0 +BRDA:1126,115,0,0 +BRDA:1126,115,1,0 +BRDA:1126,116,0,0 +BRDA:1126,116,1,0 +BRDA:1132,117,0,0 +BRDA:1132,117,1,0 +BRDA:1147,118,0,4 +BRDA:1147,118,1,3 +BRDA:1147,118,2,1 +BRDA:1147,118,3,1 +BRDA:1169,119,0,1 +BRDA:1169,119,1,17 +BRDA:1169,120,0,18 +BRDA:1169,120,1,18 +BRDA:1169,121,0,1 +BRDA:1169,121,1,17 +BRDA:1169,122,0,18 +BRDA:1169,122,1,18 +BRDA:1170,123,0,12 +BRDA:1170,123,1,6 +BRDA:1170,124,0,18 +BRDA:1170,124,1,18 +BRDA:1170,125,0,1 +BRDA:1170,125,1,17 +BRDA:1170,126,0,18 +BRDA:1170,126,1,18 +BRDA:1173,127,0,0 +BRDA:1173,127,1,14 +BRDA:1173,128,0,14 +BRDA:1173,128,1,14 +BRDA:1174,129,0,9 +BRDA:1174,129,1,5 +BRDA:1174,130,0,14 +BRDA:1174,130,1,13 +BRDA:1174,131,0,1 +BRDA:1174,131,1,13 +BRDA:1174,132,0,14 +BRDA:1174,132,1,14 +BRDA:1176,133,0,2 +BRDA:1176,133,1,7 +BRDA:1188,134,0,3 +BRDA:1188,134,1,8 +BRDA:1191,135,0,2 +BRDA:1191,135,1,6 +BRDA:1194,136,0,5 +BRDA:1194,136,1,1 +BRDA:1195,137,0,1 +BRDA:1195,137,1,0 +BRDA:1195,137,2,0 +BRDA:1195,137,3,1 +BRDA:1195,137,4,3 +BRDA:1205,138,0,3 +BRDA:1205,138,1,0 +BRDA:1205,139,0,3 +BRDA:1205,139,1,3 +BRDA:1215,140,0,1 +BRDA:1215,140,1,20 +BRDA:1215,141,0,21 +BRDA:1215,141,1,21 +BRDA:1215,142,0,1 +BRDA:1215,142,1,20 +BRDA:1215,143,0,21 +BRDA:1215,143,1,21 +BRDA:1216,144,0,15 +BRDA:1216,144,1,6 +BRDA:1216,145,0,21 +BRDA:1216,145,1,21 +BRDA:1216,146,0,1 +BRDA:1216,146,1,20 +BRDA:1216,147,0,21 +BRDA:1216,147,1,21 +BRDA:1219,148,0,0 +BRDA:1219,148,1,17 +BRDA:1219,149,0,17 +BRDA:1219,149,1,17 +BRDA:1220,150,0,11 +BRDA:1220,150,1,6 +BRDA:1220,151,0,17 +BRDA:1220,151,1,13 +BRDA:1220,152,0,4 +BRDA:1220,152,1,13 +BRDA:1220,153,0,17 +BRDA:1220,153,1,17 +BRDA:1222,154,0,2 +BRDA:1222,154,1,9 +BRDA:1231,155,0,4 +BRDA:1231,155,1,1 +BRDA:1231,155,2,4 +BRDA:1231,155,3,1 +BRDA:1268,156,0,0 +BRDA:1268,156,1,21 +BRDA:1278,157,0,19 +BRDA:1278,157,1,0 +BRDA:1278,158,0,19 +BRDA:1278,158,1,19 +BRDA:1282,159,0,2 +BRDA:1282,159,1,0 +BRDA:1291,160,0,3 +BRDA:1291,160,1,16 +BRDA:1292,161,0,19 +BRDA:1292,161,1,18 +BRDA:1292,161,2,18 +BRDA:1301,162,0,5 +BRDA:1301,162,1,11 +BRDA:1302,163,0,16 +BRDA:1302,163,1,9 +BRDA:1307,164,0,4 +BRDA:1307,164,1,1 +BRDA:1307,165,0,5 +BRDA:1307,165,1,5 +BRDA:1312,166,0,1 +BRDA:1312,166,1,10 +BRDA:1316,167,0,2 +BRDA:1316,167,1,8 +BRDA:1316,168,0,10 +BRDA:1316,168,1,3 +BRDA:1318,169,0,10 +BRDA:1318,169,1,0 +BRDA:1337,170,0,1 +BRDA:1337,170,1,0 +BRDA:1346,171,0,8 +BRDA:1346,171,1,0 +BRDA:1346,172,0,0 +BRDA:1346,172,1,8 +BRDA:1346,173,0,8 +BRDA:1346,173,1,8 +BRDA:1347,174,0,1 +BRDA:1347,174,1,7 +BRDA:1350,175,0,1 +BRDA:1350,175,1,7 +BRDA:1350,176,0,0 +BRDA:1350,176,1,8 +BRDA:1350,177,0,8 +BRDA:1350,177,1,8 +BRDA:1355,178,0,1 +BRDA:1355,178,1,7 +BRDA:1355,179,0,8 +BRDA:1355,179,1,8 +BRDA:1355,180,0,0 +BRDA:1355,180,1,8 +BRDA:1355,181,0,8 +BRDA:1355,181,1,8 +BRDA:1356,182,0,1 +BRDA:1356,182,1,0 +BRDA:1357,183,0,1 +BRDA:1357,183,1,0 +BRDA:1358,184,0,1 +BRDA:1358,184,1,0 +BRDA:1367,185,0,0 +BRDA:1367,185,1,8 +BRDA:1367,186,0,8 +BRDA:1367,186,1,8 +BRDA:1367,187,0,0 +BRDA:1367,187,1,8 +BRDA:1367,188,0,8 +BRDA:1367,188,1,8 +BRDA:1368,189,0,3 +BRDA:1368,189,1,5 +BRDA:1368,190,0,8 +BRDA:1368,190,1,8 +BRDA:1368,191,0,0 +BRDA:1368,191,1,8 +BRDA:1368,192,0,8 +BRDA:1368,192,1,8 +BRDA:1372,193,0,0 +BRDA:1372,193,1,3 +BRDA:1372,194,0,3 +BRDA:1372,194,1,3 +BRDA:1373,195,0,2 +BRDA:1373,195,1,1 +BRDA:1373,196,0,1 +BRDA:1373,196,1,2 +BRDA:1373,197,0,3 +BRDA:1373,197,1,3 +BRDA:1376,198,0,1 +BRDA:1376,198,1,1 +BRDA:1377,199,0,0 +BRDA:1377,199,1,1 +BRDA:1383,200,0,0 +BRDA:1383,200,1,3 +BRDA:1383,201,0,3 +BRDA:1383,201,1,3 +BRDA:1385,202,0,1 +BRDA:1385,202,1,2 +BRDA:1385,203,0,3 +BRDA:1385,203,1,1 +BRDA:1386,204,0,1 +BRDA:1386,204,1,0 +BRDA:1386,205,0,1 +BRDA:1386,205,1,1 +BRDA:1387,206,0,0 +BRDA:1387,206,1,1 +BRDA:1393,207,0,2 +BRDA:1393,207,1,6 +BRDA:1399,208,0,3 +BRDA:1399,208,1,5 +BRDA:1403,209,0,0 +BRDA:1403,209,1,8 +BRDA:1419,210,0,6 +BRDA:1419,210,1,0 +BRDA:1419,211,0,6 +BRDA:1419,211,1,6 +BRDA:1423,212,0,2 +BRDA:1423,212,1,0 +BRDA:1430,213,0,3 +BRDA:1430,213,1,3 +BRDA:1435,214,0,0 +BRDA:1435,214,1,0 +BRDA:1435,215,0,0 +BRDA:1435,215,1,0 +BRDA:1435,216,0,0 +BRDA:1435,216,1,0 +BRDA:1435,217,0,0 +BRDA:1435,217,1,0 +BRDA:1436,218,0,0 +BRDA:1436,218,1,0 +BRDA:1442,219,0,2 +BRDA:1442,219,1,1 +BRDA:1442,220,0,3 +BRDA:1442,220,1,2 +BRDA:1443,221,0,3 +BRDA:1443,221,1,0 +BRDA:1443,222,0,3 +BRDA:1443,222,1,3 +BRDA:1443,223,0,3 +BRDA:1443,223,1,0 +BRDA:1443,224,0,3 +BRDA:1443,224,1,3 +BRDA:1445,225,0,0 +BRDA:1445,225,1,3 +BRDA:1485,226,0,0 +BRDA:1485,226,1,0 +BRDA:1500,227,0,8 +BRDA:1500,227,1,2 +BRDA:1526,228,0,4 +BRDA:1526,228,1,4 +BRDA:1504,229,0,0 +BRDA:1504,229,1,15 +BRDA:1514,230,0,6 +BRDA:1514,230,1,0 +BRDA:1522,231,0,2 +BRDA:1522,231,1,0 +BRDA:1529,232,0,3 +BRDA:1529,232,1,6 +BRDA:1538,233,0,4 +BRDA:1538,233,1,2 +BRDA:1541,234,0,0 +BRDA:1541,234,1,2 +BRDA:1555,235,0,1 +BRDA:1555,235,1,3 +BRDA:1580,236,0,5 +BRDA:1580,236,1,0 +BRDA:1585,237,0,0 +BRDA:1585,237,1,0 +BRDA:1585,238,0,0 +BRDA:1585,238,1,0 +BRDA:1596,239,0,24 +BRDA:1596,239,1,24 +BRDA:1611,240,0,3 +BRDA:1611,240,1,13 +BRDA:1611,241,0,16 +BRDA:1611,241,1,14 +BRDA:1611,242,0,1 +BRDA:1611,242,1,15 +BRDA:1611,243,0,16 +BRDA:1611,243,1,16 +BRDA:1618,244,0,3 +BRDA:1622,245,0,1 +BRDA:1622,245,1,0 +BRDA:1622,246,0,0 +BRDA:1622,246,1,1 +BRDA:1622,247,0,1 +BRDA:1622,247,1,1 +BRDA:1625,248,0,0 +BRDA:1625,248,1,0 +BRDA:1625,249,0,0 +BRDA:1625,249,1,0 +BRDA:1654,250,0,21 +BRDA:1658,251,0,0 +BRDA:1658,251,1,0 +BRDA:1664,252,0,0 +BRDA:1664,253,0,0 +BRDA:1664,253,1,0 +BRDA:1664,254,0,0 +BRDA:1664,254,1,0 +BRDA:1672,255,0,0 +BRDA:1697,256,0,0 +BRDA:1697,256,1,0 +BRDA:1697,257,0,0 +BRDA:1697,257,1,0 +BRDA:1719,258,0,0 +BRDA:1723,259,0,213 +BRDA:1723,259,1,63 +BRDA:1728,260,0,63 +BRDA:1728,260,1,0 +BRDA:1728,261,0,0 +BRDA:1728,261,1,63 +BRDA:1728,262,0,63 +BRDA:1728,262,1,63 +BRDA:1738,263,0,0 +BRDA:1738,263,1,0 +BRDA:1754,264,0,3 +BRDA:1754,264,1,10 +BRDA:1754,265,0,13 +BRDA:1754,265,1,10 +BRDA:1760,266,0,7 +BRDA:1764,267,0,2 +BRDA:1764,267,1,5 +BRDA:1764,268,0,7 +BRDA:1764,268,1,7 +BRDA:1767,269,0,5 +BRDA:1767,269,1,0 +BRDA:1770,270,0,0 +BRDA:1770,270,1,5 +BRDA:1780,271,0,21 +BRDA:1780,271,1,0 +BRDA:1780,272,0,11 +BRDA:1780,272,1,10 +BRDA:1780,273,0,21 +BRDA:1780,273,1,21 +BRDA:1785,274,0,0 +BRDA:1785,274,1,0 +BRDA:1791,275,0,0 +BRDA:1791,275,1,0 +BRDA:1794,276,0,0 +BRDA:1794,276,1,0 +BRDA:1800,277,0,0 +BRDA:1800,277,1,0 +BRDA:1800,278,0,0 +BRDA:1800,278,1,0 +BRDA:1800,278,2,0 +BRDA:1806,279,0,0 +BRDA:1806,279,1,0 +BRDA:1819,280,0,0 +BRDA:1819,280,1,0 +BRDA:1826,281,0,0 +BRDA:1826,281,1,0 +BRDA:1833,282,0,21 +BRDA:1837,283,0,0 +BRDA:1837,283,1,0 +BRDA:1837,284,0,0 +BRDA:1837,284,1,0 +BRF:565 +BRH:298 +end_of_record +TN: +SF:src/k8s/utils/index.ts +FN:35,prepareJobScript +FN:40,(anonymous_23) +FN:59,writeRunScript +FN:94,writeContainerStepScript +FN:129,scriptEnv +FN:161,generateContainerName +FN:180,mergeContainerWithOptions +FN:208,mergePodSpecWithOptions +FN:216,(anonymous_30) +FN:228,mergeObjectMeta +FN:258,readExtensionFromFile +FN:270,useKubeScheduler +FN:274,(anonymous_34) +FN:283,mergeLists +FN:292,fixArgs +FN:301,sleep +FN:302,(anonymous_40) +FN:305,listDirAllCommand +FN:315,formatError +FNF:19 +FNH:9 +FNDA:0,prepareJobScript +FNDA:0,(anonymous_23) +FNDA:0,writeRunScript +FNDA:0,writeContainerStepScript +FNDA:0,scriptEnv +FNDA:12,generateContainerName +FNDA:2,mergeContainerWithOptions +FNDA:1,mergePodSpecWithOptions +FNDA:1,(anonymous_30) +FNDA:0,mergeObjectMeta +FNDA:23,readExtensionFromFile +FNDA:0,useKubeScheduler +FNDA:14,(anonymous_34) +FNDA:3,mergeLists +FNDA:17,fixArgs +FNDA:0,sleep +FNDA:0,(anonymous_40) +FNDA:0,listDirAllCommand +FNDA:63,formatError +DA:2,14 +DA:3,14 +DA:4,14 +DA:5,14 +DA:6,14 +DA:7,14 +DA:10,14 +DA:11,14 +DA:13,14 +DA:14,14 +DA:16,14 +DA:17,14 +DA:18,14 +DA:20,14 +DA:35,14 +DA:39,0 +DA:40,0 +DA:43,0 +DA:50,0 +DA:51,0 +DA:52,0 +DA:53,0 +DA:59,14 +DA:66,0 +DA:67,0 +DA:70,0 +DA:71,0 +DA:74,0 +DA:76,0 +DA:85,0 +DA:86,0 +DA:87,0 +DA:88,0 +DA:94,14 +DA:101,0 +DA:103,0 +DA:104,0 +DA:105,0 +DA:108,0 +DA:119,0 +DA:120,0 +DA:121,0 +DA:122,0 +DA:123,0 +DA:130,0 +DA:131,0 +DA:133,0 +DA:134,0 +DA:135,0 +DA:141,0 +DA:145,0 +DA:154,0 +DA:155,0 +DA:158,0 +DA:161,14 +DA:162,12 +DA:163,12 +DA:165,12 +DA:166,2 +DA:169,10 +DA:180,14 +DA:184,6 +DA:185,6 +DA:186,2 +DA:187,1 +DA:189,2 +DA:190,4 +DA:191,1 +DA:192,1 +DA:193,3 +DA:194,1 +DA:195,1 +DA:196,2 +DA:197,0 +DA:198,0 +DA:199,2 +DA:200,1 +DA:201,1 +DA:203,1 +DA:208,14 +DA:212,4 +DA:213,4 +DA:214,1 +DA:216,1 +DA:219,3 +DA:220,1 +DA:221,1 +DA:223,2 +DA:228,14 +DA:232,0 +DA:233,0 +DA:237,0 +DA:238,0 +DA:239,0 +DA:240,0 +DA:242,0 +DA:246,0 +DA:247,0 +DA:248,0 +DA:249,0 +DA:253,0 +DA:258,14 +DA:259,23 +DA:260,23 +DA:261,23 +DA:263,0 +DA:264,0 +DA:265,0 +DA:267,0 +DA:270,14 +DA:271,0 +DA:274,14 +DA:275,14 +DA:276,14 +DA:277,14 +DA:278,14 +DA:279,14 +DA:280,14 +DA:284,3 +DA:285,3 +DA:286,0 +DA:288,3 +DA:289,3 +DA:292,14 +DA:295,17 +DA:296,3 +DA:298,14 +DA:301,14 +DA:302,0 +DA:305,14 +DA:306,0 +DA:315,14 +DA:316,63 +DA:317,2 +DA:323,61 +DA:325,61 +DA:326,3 +DA:327,3 +DA:328,3 +DA:329,3 +DA:335,58 +DA:336,47 +DA:339,11 +DA:344,6 +DA:345,6 +DA:346,3 +DA:348,3 +DA:349,3 +DA:351,2 +DA:357,5 +LF:150 +LH:91 +BRDA:67,0,0,0 +BRDA:67,0,1,0 +BRDA:67,1,0,0 +BRDA:67,1,1,0 +BRDA:67,2,0,0 +BRDA:67,2,1,0 +BRDA:70,3,0,0 +BRDA:70,3,1,0 +BRDA:82,4,0,0 +BRDA:82,4,1,0 +BRDA:82,5,0,0 +BRDA:82,5,1,0 +BRDA:82,6,0,0 +BRDA:82,6,1,0 +BRDA:104,7,0,0 +BRDA:104,7,1,0 +BRDA:116,8,0,0 +BRDA:116,8,1,0 +BRDA:116,9,0,0 +BRDA:116,9,1,0 +BRDA:116,10,0,0 +BRDA:116,10,1,0 +BRDA:130,11,0,0 +BRDA:130,11,1,0 +BRDA:130,12,0,0 +BRDA:130,12,1,0 +BRDA:135,13,0,0 +BRDA:135,13,1,0 +BRDA:136,14,0,0 +BRDA:136,14,1,0 +BRDA:136,14,2,0 +BRDA:136,14,3,0 +BRDA:154,15,0,0 +BRDA:154,15,1,0 +BRDA:154,16,0,0 +BRDA:154,16,1,0 +BRDA:154,17,0,0 +BRDA:154,17,1,0 +BRDA:163,18,0,0 +BRDA:163,18,1,12 +BRDA:163,19,0,12 +BRDA:163,19,1,12 +BRDA:165,20,0,2 +BRDA:165,20,1,10 +BRDA:185,21,0,2 +BRDA:185,21,1,4 +BRDA:186,22,0,1 +BRDA:186,22,1,1 +BRDA:190,23,0,1 +BRDA:190,23,1,3 +BRDA:193,24,0,1 +BRDA:193,24,1,2 +BRDA:196,25,0,0 +BRDA:196,25,1,2 +BRDA:196,26,0,2 +BRDA:196,26,1,0 +BRDA:199,27,0,1 +BRDA:199,27,1,1 +BRDA:199,28,0,2 +BRDA:199,28,1,1 +BRDA:213,29,0,1 +BRDA:213,29,1,3 +BRDA:216,30,0,0 +BRDA:216,30,1,1 +BRDA:216,31,0,1 +BRDA:216,31,1,1 +BRDA:219,32,0,1 +BRDA:219,32,1,2 +BRDA:219,33,0,3 +BRDA:219,33,1,1 +BRDA:232,34,0,0 +BRDA:232,34,1,0 +BRDA:232,35,0,0 +BRDA:232,35,1,0 +BRDA:232,36,0,0 +BRDA:232,36,1,0 +BRDA:232,37,0,0 +BRDA:232,37,1,0 +BRDA:232,38,0,0 +BRDA:232,38,1,0 +BRDA:232,39,0,0 +BRDA:232,39,1,0 +BRDA:237,40,0,0 +BRDA:237,40,1,0 +BRDA:237,41,0,0 +BRDA:237,41,1,0 +BRDA:237,42,0,0 +BRDA:237,42,1,0 +BRDA:239,43,0,0 +BRDA:239,43,1,0 +BRDA:239,44,0,0 +BRDA:239,44,1,0 +BRDA:239,45,0,0 +BRDA:239,45,1,0 +BRDA:239,46,0,0 +BRDA:239,46,1,0 +BRDA:239,47,0,0 +BRDA:239,47,1,0 +BRDA:246,48,0,0 +BRDA:246,48,1,0 +BRDA:246,49,0,0 +BRDA:246,49,1,0 +BRDA:246,50,0,0 +BRDA:246,50,1,0 +BRDA:248,51,0,0 +BRDA:248,51,1,0 +BRDA:248,52,0,0 +BRDA:248,52,1,0 +BRDA:248,53,0,0 +BRDA:248,53,1,0 +BRDA:248,54,0,0 +BRDA:248,54,1,0 +BRDA:248,55,0,0 +BRDA:248,55,1,0 +BRDA:260,56,0,23 +BRDA:260,56,1,0 +BRDA:264,57,0,0 +BRDA:264,57,1,0 +BRDA:264,58,0,0 +BRDA:264,58,1,0 +BRDA:274,59,0,14 +BRDA:274,59,1,14 +BRDA:284,60,0,3 +BRDA:284,60,1,1 +BRDA:285,61,0,0 +BRDA:285,61,1,3 +BRDA:285,62,0,0 +BRDA:285,62,1,3 +BRDA:285,63,0,3 +BRDA:285,63,1,3 +BRDA:295,64,0,3 +BRDA:295,64,1,14 +BRDA:295,65,0,17 +BRDA:295,65,1,14 +BRDA:295,65,2,3 +BRDA:316,66,0,2 +BRDA:316,66,1,61 +BRDA:316,67,0,63 +BRDA:316,67,1,62 +BRDA:323,68,0,2 +BRDA:323,68,1,59 +BRDA:323,69,0,61 +BRDA:323,69,1,61 +BRDA:323,70,0,57 +BRDA:323,70,1,4 +BRDA:323,71,0,61 +BRDA:323,71,1,61 +BRDA:323,72,0,0 +BRDA:323,72,1,61 +BRDA:323,73,0,61 +BRDA:323,73,1,61 +BRDA:324,74,0,0 +BRDA:324,74,1,59 +BRDA:324,75,0,59 +BRDA:324,75,1,59 +BRDA:325,76,0,3 +BRDA:325,76,1,58 +BRDA:325,77,0,61 +BRDA:325,77,1,3 +BRDA:328,78,0,3 +BRDA:328,78,1,0 +BRDA:329,79,0,1 +BRDA:329,79,1,2 +BRDA:329,80,0,3 +BRDA:329,80,1,1 +BRDA:335,81,0,47 +BRDA:335,81,1,11 +BRDA:339,82,0,6 +BRDA:339,82,1,5 +BRDA:345,83,0,3 +BRDA:345,83,1,3 +BRF:171 +BRH:75 +end_of_record +TN: +SF:src/k8s/utils/npu-metrics.ts +FN:71,npuMetricsEnabled +FN:79,getNpuSampleIntervalSeconds +FN:96,getIdleThresholdPercent +FN:113,containerHasNpuRequest +FN:125,hasNpuRequest +FN:126,(anonymous_30) +FN:129,listNpuCardsCommand +FN:133,buildNpuSamplerScript +FN:187,buildNpuAggregateScript +FN:198,commandHasMarker +FN:202,appendExecCommand +FN:219,(anonymous_36) +FN:224,injectNpuMetrics +FN:269,maybeInjectNpuMetrics +FN:279,parseNpuAggregate +FN:324,isIdleRecord +FN:331,(anonymous_41) +FN:334,escapePromLabelValue +FN:338,formatPromLabels +FN:340,(anonymous_44) +FN:341,(anonymous_45) +FN:359,buildNpuJobMetricsBody +FN:385,(anonymous_48) +FN:401,buildNpuPushFailedBody +FN:408,buildPushgatewayPath +FN:418,withTimeout +FN:422,(anonymous_54) +FN:423,(anonymous_55) +FN:425,(anonymous_56) +FN:429,(anonymous_57) +FN:448,nodeRequest +FN:462,(anonymous_61) +FN:471,(anonymous_62) +FN:473,(anonymous_63) +FN:478,(anonymous_64) +FN:484,pushToPushgateway +FN:497,(anonymous_68) +FN:518,decodePushSecret +FN:522,(anonymous_70) +FN:545,readNpuPushConfig +FN:557,parseScaleSetSuffix +FN:565,extractClusterFromRunnerPod +FN:589,resolveNpuLabelsFromPod +FN:616,(anonymous_77) +FN:630,repoFromEnv +FN:637,(anonymous_79) +FN:644,collectNpuAggregateFromPod +FN:652,(anonymous_83) +FN:670,collectAndPushNpuMetrics +FN:682,(anonymous_87) +FN:716,collectAndPushForPod +FNF:51 +FNH:7 +FNDA:64,npuMetricsEnabled +FNDA:0,getNpuSampleIntervalSeconds +FNDA:0,getIdleThresholdPercent +FNDA:22,containerHasNpuRequest +FNDA:0,hasNpuRequest +FNDA:0,(anonymous_30) +FNDA:0,listNpuCardsCommand +FNDA:0,buildNpuSamplerScript +FNDA:0,buildNpuAggregateScript +FNDA:0,commandHasMarker +FNDA:0,appendExecCommand +FNDA:0,(anonymous_36) +FNDA:0,injectNpuMetrics +FNDA:22,maybeInjectNpuMetrics +FNDA:0,parseNpuAggregate +FNDA:0,isIdleRecord +FNDA:0,(anonymous_41) +FNDA:0,escapePromLabelValue +FNDA:0,formatPromLabels +FNDA:0,(anonymous_44) +FNDA:0,(anonymous_45) +FNDA:0,buildNpuJobMetricsBody +FNDA:0,(anonymous_48) +FNDA:0,buildNpuPushFailedBody +FNDA:0,buildPushgatewayPath +FNDA:21,withTimeout +FNDA:21,(anonymous_54) +FNDA:0,(anonymous_55) +FNDA:21,(anonymous_56) +FNDA:0,(anonymous_57) +FNDA:0,nodeRequest +FNDA:0,(anonymous_61) +FNDA:0,(anonymous_62) +FNDA:0,(anonymous_63) +FNDA:0,(anonymous_64) +FNDA:0,pushToPushgateway +FNDA:0,(anonymous_68) +FNDA:0,decodePushSecret +FNDA:0,(anonymous_70) +FNDA:0,readNpuPushConfig +FNDA:0,parseScaleSetSuffix +FNDA:0,extractClusterFromRunnerPod +FNDA:0,resolveNpuLabelsFromPod +FNDA:0,(anonymous_77) +FNDA:0,repoFromEnv +FNDA:0,(anonymous_79) +FNDA:0,collectNpuAggregateFromPod +FNDA:0,(anonymous_83) +FNDA:21,collectAndPushNpuMetrics +FNDA:0,(anonymous_87) +FNDA:0,collectAndPushForPod +DA:1,9 +DA:3,9 +DA:4,9 +DA:5,9 +DA:6,9 +DA:7,9 +DA:8,9 +DA:16,9 +DA:17,9 +DA:18,9 +DA:19,9 +DA:21,9 +DA:22,9 +DA:23,9 +DA:25,9 +DA:26,9 +DA:27,9 +DA:28,9 +DA:30,9 +DA:31,9 +DA:32,9 +DA:34,9 +DA:35,9 +DA:71,9 +DA:72,128 +DA:74,64 +DA:79,9 +DA:80,0 +DA:82,0 +DA:83,0 +DA:84,0 +DA:86,0 +DA:87,0 +DA:88,0 +DA:91,0 +DA:93,0 +DA:96,9 +DA:97,0 +DA:99,0 +DA:100,0 +DA:101,0 +DA:103,0 +DA:104,0 +DA:105,0 +DA:108,0 +DA:110,0 +DA:113,9 +DA:114,22 +DA:115,44 +DA:116,44 +DA:117,0 +DA:118,0 +DA:122,22 +DA:125,9 +DA:126,0 +DA:130,0 +DA:133,9 +DA:134,0 +DA:136,0 +DA:158,9 +DA:187,9 +DA:188,0 +DA:199,0 +DA:206,0 +DA:212,0 +DA:218,0 +DA:219,0 +DA:221,0 +DA:224,9 +DA:226,0 +DA:228,0 +DA:229,0 +DA:233,0 +DA:236,0 +DA:240,0 +DA:243,0 +DA:246,0 +DA:247,0 +DA:249,0 +DA:257,0 +DA:265,0 +DA:266,0 +DA:269,9 +DA:270,22 +DA:271,0 +DA:273,22 +DA:274,22 +DA:276,0 +DA:279,9 +DA:282,0 +DA:283,0 +DA:285,0 +DA:286,0 +DA:287,0 +DA:289,0 +DA:290,0 +DA:291,0 +DA:292,0 +DA:294,0 +DA:295,0 +DA:296,0 +DA:297,0 +DA:299,0 +DA:301,0 +DA:302,0 +DA:304,0 +DA:305,0 +DA:306,0 +DA:307,0 +DA:309,0 +DA:319,0 +DA:321,0 +DA:324,9 +DA:326,0 +DA:328,0 +DA:329,0 +DA:331,0 +DA:334,9 +DA:335,0 +DA:338,9 +DA:339,0 +DA:340,0 +DA:341,0 +DA:345,9 +DA:359,9 +DA:362,0 +DA:364,0 +DA:375,0 +DA:376,0 +DA:377,0 +DA:378,0 +DA:379,0 +DA:380,0 +DA:381,0 +DA:382,0 +DA:383,0 +DA:385,0 +DA:388,0 +DA:389,0 +DA:390,0 +DA:391,0 +DA:392,0 +DA:394,0 +DA:395,0 +DA:398,0 +DA:401,9 +DA:402,0 +DA:408,9 +DA:413,0 +DA:418,9 +DA:422,21 +DA:423,21 +DA:424,21 +DA:426,21 +DA:427,21 +DA:430,0 +DA:431,0 +DA:448,9 +DA:451,0 +DA:452,0 +DA:453,0 +DA:456,0 +DA:457,0 +DA:460,0 +DA:462,0 +DA:463,0 +DA:472,0 +DA:473,0 +DA:474,0 +DA:478,0 +DA:479,0 +DA:480,0 +DA:484,9 +DA:490,0 +DA:491,0 +DA:492,0 +DA:493,0 +DA:495,0 +DA:496,0 +DA:497,0 +DA:500,0 +DA:507,0 +DA:508,0 +DA:510,0 +DA:512,0 +DA:515,0 +DA:518,9 +DA:521,0 +DA:522,0 +DA:523,0 +DA:524,0 +DA:525,0 +DA:527,0 +DA:528,0 +DA:529,0 +DA:531,0 +DA:534,0 +DA:535,0 +DA:536,0 +DA:538,0 +DA:545,9 +DA:547,0 +DA:548,0 +DA:550,0 +DA:553,0 +DA:558,0 +DA:559,0 +DA:561,0 +DA:562,0 +DA:565,9 +DA:566,0 +DA:567,0 +DA:568,0 +DA:572,0 +DA:573,0 +DA:574,0 +DA:575,0 +DA:576,0 +DA:580,0 +DA:581,0 +DA:582,0 +DA:583,0 +DA:586,0 +DA:589,9 +DA:598,0 +DA:599,0 +DA:600,0 +DA:601,0 +DA:602,0 +DA:606,0 +DA:607,0 +DA:608,0 +DA:609,0 +DA:610,0 +DA:615,0 +DA:616,0 +DA:618,0 +DA:619,0 +DA:622,0 +DA:630,9 +DA:631,0 +DA:633,0 +DA:634,0 +DA:636,0 +DA:637,0 +DA:638,0 +DA:639,0 +DA:641,0 +DA:644,9 +DA:647,0 +DA:648,0 +DA:649,0 +DA:651,0 +DA:652,0 +DA:654,0 +DA:655,0 +DA:656,0 +DA:658,0 +DA:659,0 +DA:661,0 +DA:667,0 +DA:670,9 +DA:671,21 +DA:672,0 +DA:674,21 +DA:676,21 +DA:678,21 +DA:679,21 +DA:681,0 +DA:682,0 +DA:684,0 +DA:685,0 +DA:688,0 +DA:690,0 +DA:691,0 +DA:693,0 +DA:696,0 +DA:697,0 +DA:698,0 +DA:701,0 +DA:704,0 +DA:705,0 +DA:707,0 +DA:709,0 +DA:722,0 +DA:723,0 +DA:724,0 +DA:725,0 +DA:728,0 +DA:729,0 +DA:741,0 +DA:746,0 +DA:748,0 +DA:749,0 +DA:751,0 +DA:753,0 +LF:296 +LH:70 +BRDA:72,0,0,64 +BRDA:72,0,1,0 +BRDA:75,1,0,0 +BRDA:75,1,1,64 +BRDA:75,2,0,64 +BRDA:75,2,1,64 +BRDA:80,3,0,0 +BRDA:80,3,1,0 +BRDA:83,4,0,0 +BRDA:83,4,1,0 +BRDA:87,5,0,0 +BRDA:87,5,1,0 +BRDA:87,6,0,0 +BRDA:87,6,1,0 +BRDA:97,7,0,0 +BRDA:97,7,1,0 +BRDA:100,8,0,0 +BRDA:100,8,1,0 +BRDA:104,9,0,0 +BRDA:104,9,1,0 +BRDA:104,10,0,0 +BRDA:104,10,1,0 +BRDA:114,11,0,22 +BRDA:114,11,1,0 +BRDA:114,12,0,22 +BRDA:114,12,1,22 +BRDA:114,13,0,22 +BRDA:114,13,1,0 +BRDA:114,14,0,22 +BRDA:114,14,1,22 +BRDA:116,15,0,0 +BRDA:116,15,1,44 +BRDA:116,16,0,44 +BRDA:116,16,1,44 +BRDA:117,17,0,0 +BRDA:117,17,1,0 +BRDA:126,18,0,0 +BRDA:126,18,1,0 +BRDA:126,19,0,0 +BRDA:126,19,1,0 +BRDA:126,20,0,0 +BRDA:126,20,1,0 +BRDA:126,21,0,0 +BRDA:126,21,1,0 +BRDA:134,22,0,0 +BRDA:134,22,1,0 +BRDA:199,23,0,0 +BRDA:199,23,1,0 +BRDA:199,24,0,0 +BRDA:199,24,1,0 +BRDA:206,25,0,0 +BRDA:206,25,1,0 +BRDA:207,26,0,0 +BRDA:207,26,1,0 +BRDA:207,26,2,0 +BRDA:207,26,3,0 +BRDA:218,27,0,0 +BRDA:218,27,1,0 +BRDA:218,28,0,0 +BRDA:218,28,1,0 +BRDA:226,29,0,0 +BRDA:226,29,1,0 +BRDA:228,30,0,0 +BRDA:228,30,1,0 +BRDA:228,31,0,0 +BRDA:228,31,1,0 +BRDA:229,32,0,0 +BRDA:229,32,1,0 +BRDA:230,33,0,0 +BRDA:230,33,1,0 +BRDA:230,34,0,0 +BRDA:230,34,1,0 +BRDA:230,35,0,0 +BRDA:230,35,1,0 +BRDA:230,36,0,0 +BRDA:230,36,1,0 +BRDA:230,37,0,0 +BRDA:230,37,1,0 +BRDA:231,38,0,0 +BRDA:231,38,1,0 +BRDA:231,39,0,0 +BRDA:231,39,1,0 +BRDA:231,40,0,0 +BRDA:231,40,1,0 +BRDA:231,41,0,0 +BRDA:231,41,1,0 +BRDA:236,42,0,0 +BRDA:236,42,1,0 +BRDA:237,43,0,0 +BRDA:237,43,1,0 +BRDA:237,43,2,0 +BRDA:237,43,3,0 +BRDA:251,44,0,0 +BRDA:251,44,1,0 +BRDA:251,45,0,0 +BRDA:251,45,1,0 +BRDA:251,46,0,0 +BRDA:251,46,1,0 +BRDA:251,47,0,0 +BRDA:251,47,1,0 +BRDA:259,48,0,0 +BRDA:259,48,1,0 +BRDA:259,49,0,0 +BRDA:259,49,1,0 +BRDA:259,50,0,0 +BRDA:259,50,1,0 +BRDA:259,51,0,0 +BRDA:259,51,1,0 +BRDA:270,52,0,0 +BRDA:270,52,1,22 +BRDA:273,53,0,22 +BRDA:273,53,1,0 +BRDA:282,54,0,0 +BRDA:282,54,1,0 +BRDA:286,55,0,0 +BRDA:286,55,1,0 +BRDA:291,56,0,0 +BRDA:291,56,1,0 +BRDA:301,57,0,0 +BRDA:301,57,1,0 +BRDA:301,58,0,0 +BRDA:301,58,1,0 +BRDA:301,59,0,0 +BRDA:301,59,1,0 +BRDA:301,60,0,0 +BRDA:301,60,1,0 +BRDA:306,61,0,0 +BRDA:306,61,1,0 +BRDA:306,62,0,0 +BRDA:306,62,1,0 +BRDA:306,62,2,0 +BRDA:311,63,0,0 +BRDA:311,63,1,0 +BRDA:312,64,0,0 +BRDA:312,64,1,0 +BRDA:313,65,0,0 +BRDA:313,65,1,0 +BRDA:314,66,0,0 +BRDA:314,66,1,0 +BRDA:315,67,0,0 +BRDA:315,67,1,0 +BRDA:316,68,0,0 +BRDA:316,68,1,0 +BRDA:319,69,0,0 +BRDA:319,69,1,0 +BRDA:326,70,0,0 +BRDA:326,70,1,0 +BRDA:328,71,0,0 +BRDA:328,71,1,0 +BRDA:331,72,0,0 +BRDA:331,72,1,0 +BRDA:362,73,0,0 +BRDA:362,73,1,0 +BRDA:375,74,0,0 +BRDA:375,74,1,0 +BRDA:422,75,0,21 +BRDA:422,75,1,21 +BRDA:462,76,0,0 +BRDA:452,77,0,0 +BRDA:452,77,1,0 +BRDA:456,78,0,0 +BRDA:456,78,1,0 +BRDA:456,79,0,0 +BRDA:456,79,1,0 +BRDA:458,80,0,0 +BRDA:458,80,1,0 +BRDA:458,81,0,0 +BRDA:458,81,1,0 +BRDA:458,82,0,0 +BRDA:458,82,1,0 +BRDA:458,83,0,0 +BRDA:458,83,1,0 +BRDA:468,84,0,0 +BRDA:468,84,1,0 +BRDA:468,85,0,0 +BRDA:468,85,1,0 +BRDA:474,86,0,0 +BRDA:474,86,1,0 +BRDA:474,87,0,0 +BRDA:474,87,1,0 +BRDA:515,88,0,0 +BRDA:490,89,0,0 +BRDA:490,89,1,0 +BRDA:490,90,0,0 +BRDA:490,90,1,0 +BRDA:490,91,0,0 +BRDA:490,91,1,0 +BRDA:490,92,0,0 +BRDA:490,92,1,0 +BRDA:491,93,0,0 +BRDA:491,93,1,0 +BRDA:491,94,0,0 +BRDA:491,94,1,0 +BRDA:491,95,0,0 +BRDA:491,95,1,0 +BRDA:491,96,0,0 +BRDA:491,96,1,0 +BRDA:492,97,0,0 +BRDA:492,97,1,0 +BRDA:492,98,0,0 +BRDA:492,98,1,0 +BRDA:492,99,0,0 +BRDA:492,99,1,0 +BRDA:492,100,0,0 +BRDA:492,100,1,0 +BRDA:495,101,0,0 +BRDA:495,101,1,0 +BRDA:496,102,0,0 +BRDA:496,102,1,0 +BRDA:507,103,0,0 +BRDA:507,103,1,0 +BRDA:507,104,0,0 +BRDA:507,104,1,0 +BRDA:515,105,0,0 +BRDA:515,105,1,0 +BRDA:521,106,0,0 +BRDA:521,106,1,0 +BRDA:521,107,0,0 +BRDA:521,107,1,0 +BRDA:521,108,0,0 +BRDA:521,108,1,0 +BRDA:521,109,0,0 +BRDA:521,109,1,0 +BRDA:524,110,0,0 +BRDA:524,110,1,0 +BRDA:529,111,0,0 +BRDA:529,111,1,0 +BRDA:535,112,0,0 +BRDA:535,112,1,0 +BRDA:558,113,0,0 +BRDA:558,113,1,0 +BRDA:562,114,0,0 +BRDA:562,114,1,0 +BRDA:566,115,0,0 +BRDA:566,115,1,0 +BRDA:566,116,0,0 +BRDA:566,116,1,0 +BRDA:566,117,0,0 +BRDA:566,117,1,0 +BRDA:566,118,0,0 +BRDA:566,118,1,0 +BRDA:567,119,0,0 +BRDA:567,119,1,0 +BRDA:567,120,0,0 +BRDA:567,120,1,0 +BRDA:567,121,0,0 +BRDA:567,121,1,0 +BRDA:567,122,0,0 +BRDA:567,122,1,0 +BRDA:573,123,0,0 +BRDA:573,123,1,0 +BRDA:575,124,0,0 +BRDA:575,124,1,0 +BRDA:582,125,0,0 +BRDA:582,125,1,0 +BRDA:586,126,0,0 +BRDA:586,126,1,0 +BRDA:586,127,0,0 +BRDA:586,127,1,0 +BRDA:586,128,0,0 +BRDA:586,128,1,0 +BRDA:586,129,0,0 +BRDA:586,129,1,0 +BRDA:598,130,0,0 +BRDA:598,130,1,0 +BRDA:601,131,0,0 +BRDA:601,131,1,0 +BRDA:601,132,0,0 +BRDA:601,132,1,0 +BRDA:601,133,0,0 +BRDA:601,133,1,0 +BRDA:601,134,0,0 +BRDA:601,134,1,0 +BRDA:603,135,0,0 +BRDA:603,135,1,0 +BRDA:603,136,0,0 +BRDA:603,136,1,0 +BRDA:604,137,0,0 +BRDA:604,137,1,0 +BRDA:604,138,0,0 +BRDA:604,138,1,0 +BRDA:606,139,0,0 +BRDA:606,139,1,0 +BRDA:606,140,0,0 +BRDA:606,140,1,0 +BRDA:608,141,0,0 +BRDA:608,141,1,0 +BRDA:610,142,0,0 +BRDA:610,142,1,0 +BRDA:615,143,0,0 +BRDA:615,143,1,0 +BRDA:615,144,0,0 +BRDA:615,144,1,0 +BRDA:615,145,0,0 +BRDA:615,145,1,0 +BRDA:615,146,0,0 +BRDA:615,146,1,0 +BRDA:618,147,0,0 +BRDA:618,147,1,0 +BRDA:618,148,0,0 +BRDA:618,148,1,0 +BRDA:618,149,0,0 +BRDA:618,149,1,0 +BRDA:618,150,0,0 +BRDA:618,150,1,0 +BRDA:619,151,0,0 +BRDA:619,151,1,0 +BRDA:621,152,0,0 +BRDA:621,152,1,0 +BRDA:621,153,0,0 +BRDA:621,153,1,0 +BRDA:621,154,0,0 +BRDA:621,154,1,0 +BRDA:621,155,0,0 +BRDA:621,155,1,0 +BRDA:624,156,0,0 +BRDA:624,156,1,0 +BRDA:625,157,0,0 +BRDA:625,157,1,0 +BRDA:631,158,0,0 +BRDA:631,158,1,0 +BRDA:633,159,0,0 +BRDA:633,159,1,0 +BRDA:636,160,0,0 +BRDA:636,160,1,0 +BRDA:636,161,0,0 +BRDA:636,161,1,0 +BRDA:638,162,0,0 +BRDA:638,162,1,0 +BRDA:647,163,0,0 +BRDA:647,163,1,0 +BRDA:647,164,0,0 +BRDA:647,164,1,0 +BRDA:648,165,0,0 +BRDA:648,165,1,0 +BRDA:651,166,0,0 +BRDA:651,166,1,0 +BRDA:651,167,0,0 +BRDA:651,167,1,0 +BRDA:651,168,0,0 +BRDA:651,168,1,0 +BRDA:651,169,0,0 +BRDA:651,169,1,0 +BRDA:654,170,0,0 +BRDA:654,170,1,0 +BRDA:654,171,0,0 +BRDA:654,171,1,0 +BRDA:654,172,0,0 +BRDA:654,172,1,0 +BRDA:654,173,0,0 +BRDA:654,173,1,0 +BRDA:654,174,0,0 +BRDA:654,174,1,0 +BRDA:654,175,0,0 +BRDA:654,175,1,0 +BRDA:655,176,0,0 +BRDA:655,176,1,0 +BRDA:658,177,0,0 +BRDA:658,177,1,0 +BRDA:658,178,0,0 +BRDA:658,178,1,0 +BRDA:658,179,0,0 +BRDA:658,179,1,0 +BRDA:658,180,0,0 +BRDA:658,180,1,0 +BRDA:658,181,0,0 +BRDA:658,181,1,0 +BRDA:696,182,0,0 +BRDA:671,183,0,0 +BRDA:671,183,1,21 +BRDA:682,184,0,0 +BRDA:682,184,1,0 +BRDA:682,185,0,0 +BRDA:682,185,1,0 +BRDA:682,186,0,0 +BRDA:682,186,1,0 +BRDA:684,187,0,0 +BRDA:684,187,1,0 +BRDA:697,188,0,0 +BRDA:697,188,1,0 +BRDA:704,189,0,0 +BRDA:704,189,1,0 +BRDA:705,190,0,0 +BRDA:705,190,1,0 +BRDA:705,191,0,0 +BRDA:705,191,1,0 +BRDA:722,192,0,0 +BRDA:723,193,0,0 +BRDA:723,193,1,0 +BRDA:723,194,0,0 +BRDA:723,194,1,0 +BRDA:735,195,0,0 +BRDA:735,195,1,0 +BRDA:735,196,0,0 +BRDA:735,196,1,0 +BRF:395 +BRH:18 +end_of_record +TN: +SF:tests/test-setup.ts +FN:13,(anonymous_22) +FN:19,TestHelper +FN:26,(anonymous_24) +FN:55,(anonymous_27) +FN:64,(anonymous_30) +FN:71,(anonymous_33) +FN:82,(anonymous_34) +FN:88,(anonymous_35) +FN:94,(anonymous_36) +FN:99,(anonymous_37) +FN:123,(anonymous_40) +FN:133,(anonymous_41) +FN:140,(anonymous_42) +FN:152,(anonymous_43) +FNF:14 +FNH:2 +FNDA:6,(anonymous_22) +FNDA:46,TestHelper +FNDA:0,(anonymous_24) +FNDA:0,(anonymous_27) +FNDA:0,(anonymous_30) +FNDA:0,(anonymous_33) +FNDA:0,(anonymous_34) +FNDA:0,(anonymous_35) +FNDA:0,(anonymous_36) +FNDA:0,(anonymous_37) +FNDA:0,(anonymous_40) +FNDA:0,(anonymous_41) +FNDA:0,(anonymous_42) +FNDA:0,(anonymous_43) +DA:1,6 +DA:2,6 +DA:4,6 +DA:5,6 +DA:7,6 +DA:9,6 +DA:11,6 +DA:13,6 +DA:20,46 +DA:21,46 +DA:22,46 +DA:23,46 +DA:26,6 +DA:27,0 +DA:28,0 +DA:29,0 +DA:30,0 +DA:31,0 +DA:33,0 +DA:34,0 +DA:35,0 +DA:36,0 +DA:37,0 +DA:38,0 +DA:42,0 +DA:47,0 +DA:49,0 +DA:51,0 +DA:55,6 +DA:57,0 +DA:58,0 +DA:64,6 +DA:65,0 +DA:72,0 +DA:73,0 +DA:76,0 +DA:83,0 +DA:84,0 +DA:88,6 +DA:89,0 +DA:90,0 +DA:91,0 +DA:94,6 +DA:95,0 +DA:96,0 +DA:99,6 +DA:100,0 +DA:106,0 +DA:120,0 +DA:123,6 +DA:124,0 +DA:131,0 +DA:132,0 +DA:133,0 +DA:134,0 +DA:137,0 +DA:140,6 +DA:141,0 +DA:148,0 +DA:149,0 +DA:152,6 +DA:153,0 +DA:160,0 +DA:161,0 +DA:162,0 +DA:163,0 +DA:165,6 +LF:67 +LH:22 +BRDA:65,0,0,0 +BRDA:72,1,0,0 +BRDA:72,1,1,0 +BRDA:83,2,0,0 +BRDA:83,2,1,0 +BRDA:89,3,0,0 +BRDA:89,3,1,0 +BRF:7 +BRH:0 +end_of_record diff --git a/packages/k8s/package-lock.json b/packages/k8s/package-lock.json index 1adbd434..ac6bd613 100644 --- a/packages/k8s/package-lock.json +++ b/packages/k8s/package-lock.json @@ -32,21 +32,6 @@ "typescript": "^5.9.2" } }, - "../hooklib": { - "version": "0.1.0", - "license": "MIT", - "dependencies": { - "@actions/core": "^2.0.2" - }, - "devDependencies": { - "@types/node": "^24.0.14", - "@zeit/ncc": "^0.22.3", - "eslint": "^9.31.0", - "eslint-plugin-github": "^6.0.0", - "prettier": "^3.6.2", - "typescript": "^5.8.3" - } - }, "node_modules/@actions/core": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@actions/core/-/core-2.0.3.tgz", @@ -4175,9 +4160,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -4192,9 +4174,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -4209,9 +4188,6 @@ "loong64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -4226,9 +4202,6 @@ "loong64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -4243,9 +4216,6 @@ "ppc64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -4260,9 +4230,6 @@ "riscv64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -4277,9 +4244,6 @@ "riscv64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -4294,9 +4258,6 @@ "s390x" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -4311,9 +4272,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -4328,9 +4286,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -5711,8 +5666,12 @@ } }, "node_modules/hooklib": { - "resolved": "../hooklib", - "link": true + "version": "0.1.0", + "resolved": "file:../hooklib", + "license": "MIT", + "dependencies": { + "@actions/core": "^2.0.2" + } }, "node_modules/hpagent": { "version": "1.2.0", diff --git a/packages/k8s/src/hooks/cleanup-job.spec.ts b/packages/k8s/src/hooks/cleanup-job.spec.ts new file mode 100644 index 00000000..8e09600f --- /dev/null +++ b/packages/k8s/src/hooks/cleanup-job.spec.ts @@ -0,0 +1,69 @@ +vi.mock('@actions/core', () => ({ + debug: vi.fn(), + error: vi.fn(), + warning: vi.fn(), + info: vi.fn() +})) + +vi.mock('../k8s', () => ({ + prunePods: vi.fn().mockResolvedValue(undefined), + pruneSecrets: vi.fn().mockResolvedValue(undefined) +})) + +const collectAndPushNpuMetrics = vi.fn().mockResolvedValue(undefined) +const npuMetricsEnabled = vi.fn().mockReturnValue(true) + +vi.mock('../k8s/utils/npu-metrics', () => ({ + collectAndPushNpuMetrics: (...args: unknown[]) => + collectAndPushNpuMetrics(...args), + npuMetricsEnabled: () => npuMetricsEnabled(), + withTimeout: async (promise: Promise) => promise, + NPU_COLLECT_TIMEOUT_MS: 10000 +})) + +import { cleanupJob } from './cleanup-job' +import * as k8sMod from '../k8s' + +describe('cleanupJob', () => { + afterEach(() => { + vi.clearAllMocks() + npuMetricsEnabled.mockReturnValue(true) + collectAndPushNpuMetrics.mockResolvedValue(undefined) + }) + + it('always prunes pods and secrets', async () => { + await cleanupJob() + expect(k8sMod.prunePods).toHaveBeenCalledTimes(1) + expect(k8sMod.pruneSecrets).toHaveBeenCalledTimes(1) + }) + + it('collects npu metrics before pruning', async () => { + const order: string[] = [] + collectAndPushNpuMetrics.mockImplementation(async () => { + order.push('collect') + }) + vi.mocked(k8sMod.prunePods).mockImplementation(async () => { + order.push('prunePods') + }) + vi.mocked(k8sMod.pruneSecrets).mockImplementation(async () => { + order.push('pruneSecrets') + }) + await cleanupJob() + expect(order[0]).toBe('collect') + expect(order.slice(1).sort()).toEqual(['prunePods', 'pruneSecrets']) + }) + + it('keeps pruning when collection fails', async () => { + collectAndPushNpuMetrics.mockRejectedValue(new Error('collect exploded')) + await expect(cleanupJob()).resolves.toBeUndefined() + expect(k8sMod.prunePods).toHaveBeenCalledTimes(1) + expect(k8sMod.pruneSecrets).toHaveBeenCalledTimes(1) + }) + + it('skips collection when the feature flag is disabled', async () => { + npuMetricsEnabled.mockReturnValue(false) + await cleanupJob() + expect(collectAndPushNpuMetrics).not.toHaveBeenCalled() + expect(k8sMod.prunePods).toHaveBeenCalledTimes(1) + }) +}) diff --git a/packages/k8s/src/hooks/cleanup-job.ts b/packages/k8s/src/hooks/cleanup-job.ts index acec1064..33590208 100644 --- a/packages/k8s/src/hooks/cleanup-job.ts +++ b/packages/k8s/src/hooks/cleanup-job.ts @@ -1,5 +1,20 @@ +import * as core from '@actions/core' +import { formatError } from '../k8s/utils' import { prunePods, pruneSecrets } from '../k8s' +import { + collectAndPushNpuMetrics, + NPU_COLLECT_TIMEOUT_MS, + npuMetricsEnabled, + withTimeout +} from '../k8s/utils/npu-metrics' export async function cleanupJob(): Promise { + if (npuMetricsEnabled()) { + try { + await withTimeout(collectAndPushNpuMetrics(), NPU_COLLECT_TIMEOUT_MS) + } catch (err) { + core.debug(`npu-metrics: collection failed: ${formatError(err)}`) + } + } await Promise.all([prunePods(), pruneSecrets()]) } diff --git a/packages/k8s/src/hooks/prepare-job.ts b/packages/k8s/src/hooks/prepare-job.ts index 602ef5b0..7615243f 100644 --- a/packages/k8s/src/hooks/prepare-job.ts +++ b/packages/k8s/src/hooks/prepare-job.ts @@ -34,6 +34,7 @@ import { getJobPodName, JOB_CONTAINER_NAME } from './constants' +import { maybeInjectNpuMetrics } from '../k8s/utils/npu-metrics' import { dirname } from 'path' export async function prepareJob( @@ -56,6 +57,7 @@ export async function prepareJob( true, extension ) + maybeInjectNpuMetrics(container) } let services: k8s.V1Container[] = [] diff --git a/packages/k8s/src/hooks/run-container-step.ts b/packages/k8s/src/hooks/run-container-step.ts index 648f701f..d36e8f7d 100644 --- a/packages/k8s/src/hooks/run-container-step.ts +++ b/packages/k8s/src/hooks/run-container-step.ts @@ -31,6 +31,7 @@ import { JOB_CONTAINER_EXTENSION_NAME, JOB_CONTAINER_NAME } from './constants' +import { maybeInjectNpuMetrics } from '../k8s/utils/npu-metrics' export async function runContainerStep( stepContainer: RunContainerStepArgs @@ -54,6 +55,7 @@ export async function runContainerStep( const extension = readExtensionFromFile() const container = createContainerSpec(stepContainer, extension) + maybeInjectNpuMetrics(container) let pod: k8s.V1Pod try { diff --git a/packages/k8s/src/k8s/index.ts b/packages/k8s/src/k8s/index.ts index 061b048c..d90ae3c0 100644 --- a/packages/k8s/src/k8s/index.ts +++ b/packages/k8s/src/k8s/index.ts @@ -1821,3 +1821,18 @@ export async function getPodByName(name): Promise { namespace: namespace() }) } + +export async function getSecretByName(name: string): Promise { + return await k8sApi.readNamespacedSecret({ + name, + namespace: namespace() + }) +} + +export async function listPodsByRunnerInstance(): Promise { + const podList = await k8sApi.listNamespacedPod({ + namespace: namespace(), + labelSelector: new RunnerInstanceLabel().toString() + }) + return podList.items ?? [] +} diff --git a/packages/k8s/src/k8s/utils/k8s-index.spec.ts b/packages/k8s/src/k8s/utils/k8s-index.spec.ts index 986736b1..10b51d98 100644 --- a/packages/k8s/src/k8s/utils/k8s-index.spec.ts +++ b/packages/k8s/src/k8s/utils/k8s-index.spec.ts @@ -36,6 +36,8 @@ import { containerPorts, getPodLogs, getPodByName, + getSecretByName, + listPodsByRunnerInstance, execPodStepWithOutput, execPodStep } from '../index' @@ -862,10 +864,20 @@ describe('namespace fallbacks', () => { delete process.env['ACTIONS_RUNNER_KUBERNETES_NAMESPACE'] }) - it('throws when no namespace source is available', () => { + it('resolves a fallback or throws when no namespace source is available', () => { delete process.env['ACTIONS_RUNNER_KUBERNETES_NAMESPACE'] - // ServiceAccount file does not exist on dev/CI machines → throws ENOENT - expect(() => namespace()).toThrow(/Failed to determine namespace/) + // Outside a pod: no kubeconfig namespace and no ServiceAccount file → + // throws ENOENT. Inside a pod (e.g. CI runners): the SA file (or a + // kubeconfig context) legitimately resolves the namespace. + let resolved: string | undefined + try { + resolved = namespace() + } catch (err) { + expect(String(err)).toMatch(/Failed to determine namespace/) + return + } + expect(typeof resolved).toBe('string') + expect(resolved?.length).toBeGreaterThan(0) }) }) @@ -1754,6 +1766,86 @@ describe('getPodByName', () => { }) }) +// ── getSecretByName ─────────────────────────────────────────────────────────── + +describe('getSecretByName', () => { + let readSpy: ReturnType + + beforeEach(() => { + process.env['ACTIONS_RUNNER_KUBERNETES_NAMESPACE'] = 'default' + readSpy = vi.spyOn(k8s.CoreV1Api.prototype, 'readNamespacedSecret' as any) + }) + + afterEach(() => { + vi.restoreAllMocks() + delete process.env['ACTIONS_RUNNER_KUBERNETES_NAMESPACE'] + }) + + it('returns the secret from the API', async () => { + const fakeSecret = { + data: { PUSHGATEWAY_URL: 'aHR0cDovL3Bndzo5MDkx' } + } as k8s.V1Secret + readSpy.mockResolvedValue(fakeSecret as never) + const secret = await getSecretByName('npu-metrics-pushgw') + expect(readSpy).toHaveBeenCalledWith( + expect.objectContaining({ + name: 'npu-metrics-pushgw', + namespace: 'default' + }) + ) + expect(secret).toBe(fakeSecret) + }) + + it('propagates API errors', async () => { + readSpy.mockRejectedValue(new Error('forbidden') as never) + await expect(getSecretByName('nope')).rejects.toThrow('forbidden') + }) +}) + +// ── listPodsByRunnerInstance ────────────────────────────────────────────────── + +describe('listPodsByRunnerInstance', () => { + let listSpy: ReturnType + + beforeEach(() => { + process.env['ACTIONS_RUNNER_POD_NAME'] = 'my-runner-pod' + process.env['ACTIONS_RUNNER_KUBERNETES_NAMESPACE'] = 'default' + listSpy = vi.spyOn(k8s.CoreV1Api.prototype, 'listNamespacedPod' as any) + }) + + afterEach(() => { + vi.restoreAllMocks() + delete process.env['ACTIONS_RUNNER_KUBERNETES_NAMESPACE'] + delete process.env['ACTIONS_RUNNER_POD_NAME'] + }) + + it('lists pods with the runner-pod label selector', async () => { + const fakeList = { + items: [buildPod('Running'), buildPod('Succeeded')] + } as never + listSpy.mockResolvedValue(fakeList) + const pods = await listPodsByRunnerInstance() + expect(listSpy).toHaveBeenCalledWith( + expect.objectContaining({ + namespace: 'default', + labelSelector: 'runner-pod=my-runner-pod' + }) + ) + expect(pods).toHaveLength(2) + }) + + it('returns an empty list when no pods match', async () => { + listSpy.mockResolvedValue({ items: [] } as never) + const pods = await listPodsByRunnerInstance() + expect(pods).toEqual([]) + }) + + it('propagates API errors', async () => { + listSpy.mockRejectedValue(new Error('forbidden') as never) + await expect(listPodsByRunnerInstance()).rejects.toThrow('forbidden') + }) +}) + // ── execPodStep ─────────────────────────────────────────────────────────────── describe('execPodStep', () => { diff --git a/packages/k8s/src/k8s/utils/npu-metrics.spec.ts b/packages/k8s/src/k8s/utils/npu-metrics.spec.ts new file mode 100644 index 00000000..d4c6a992 --- /dev/null +++ b/packages/k8s/src/k8s/utils/npu-metrics.spec.ts @@ -0,0 +1,1002 @@ +import * as k8s from '@kubernetes/client-node' +import * as http from 'http' +import * as net from 'net' +import type { AddressInfo } from 'net' + +vi.mock('@actions/core', () => ({ + debug: vi.fn(), + error: vi.fn(), + warning: vi.fn(), + info: vi.fn() +})) + +vi.mock('../index', () => ({ + execPodStepWithOutput: vi.fn(), + getPodByName: vi.fn(), + getSecretByName: vi.fn(), + listPodsByRunnerInstance: vi.fn(), + namespace: vi.fn().mockReturnValue('test-ns') +})) + +import { + NPU_METRICS_MARKER, + buildNpuAggregateScript, + buildNpuJobMetricsBody, + buildNpuPushFailedBody, + buildNpuSamplerScript, + buildPushgatewayPath, + collectAndPushNpuMetrics, + collectNpuAggregateFromPod, + containerHasNpuRequest, + decodePushSecret, + escapePromLabelValue, + extractClusterFromRunnerPod, + getIdleThresholdPercent, + getNpuSampleIntervalSeconds, + hasNpuRequest, + injectNpuMetrics, + isIdleRecord, + maybeInjectNpuMetrics, + nodeRequest, + npuMetricsEnabled, + parseNpuAggregate, + pushToPushgateway, + repoFromEnv, + resolveNpuLabelsFromPod, + withTimeout +} from './npu-metrics' +import * as k8sMod from '../index' + +function makeContainer( + overrides: Partial = {} +): k8s.V1Container { + return { + name: 'job', + image: 'ubuntu:latest', + ...overrides + } as k8s.V1Container +} + +function b64(value: string): string { + return Buffer.from(value, 'utf8').toString('base64') +} + +// ── toggles and thresholds ───────────────────────────────────────────────────── + +describe('npuMetricsEnabled', () => { + it('defaults to enabled', () => { + expect(npuMetricsEnabled({})).toBe(true) + }) + it('disables on disabled', () => { + expect( + npuMetricsEnabled({ + ACTIONS_RUNNER_NPU_METRICS: 'disabled' + }) + ).toBe(false) + }) + it('is case-insensitive and trims', () => { + expect( + npuMetricsEnabled({ + ACTIONS_RUNNER_NPU_METRICS: ' DISABLED ' + }) + ).toBe(false) + }) + it('keeps enabled for other values', () => { + expect( + npuMetricsEnabled({ + ACTIONS_RUNNER_NPU_METRICS: 'enabled' + }) + ).toBe(true) + }) +}) + +describe('getNpuSampleIntervalSeconds', () => { + it('defaults to 1s', () => { + expect(getNpuSampleIntervalSeconds({})).toBe(1) + }) + it('parses a valid value', () => { + expect( + getNpuSampleIntervalSeconds({ + NPU_SAMPLE_INTERVAL: '0.5' + }) + ).toBe(0.5) + }) + it('clamps to the 0.2s minimum', () => { + expect( + getNpuSampleIntervalSeconds({ + NPU_SAMPLE_INTERVAL: '0.01' + }) + ).toBe(0.2) + }) + it('falls back to default on invalid input', () => { + expect( + getNpuSampleIntervalSeconds({ + NPU_SAMPLE_INTERVAL: 'abc' + }) + ).toBe(1) + expect( + getNpuSampleIntervalSeconds({ + NPU_SAMPLE_INTERVAL: '-2' + }) + ).toBe(1) + }) +}) + +describe('getIdleThresholdPercent', () => { + it('defaults to 5', () => { + expect(getIdleThresholdPercent({})).toBe(5) + }) + it('parses a custom threshold', () => { + expect(getIdleThresholdPercent({ NPU_IDLE_THRESHOLD: '10' })).toBe(10) + }) + it('falls back to default on invalid input', () => { + expect( + getIdleThresholdPercent({ + NPU_IDLE_THRESHOLD: 'oops' + }) + ).toBe(5) + }) +}) + +// ── detection ────────────────────────────────────────────────────────────────── + +describe('containerHasNpuRequest / hasNpuRequest', () => { + it('detects ascend resource requests', () => { + const c = makeContainer({ + resources: { requests: { 'huawei.com/ascend-1980': '8' } } + }) + expect(containerHasNpuRequest(c)).toBe(true) + }) + it('detects ascend resource limits only', () => { + const c = makeContainer({ + resources: { limits: { 'huawei.com/ascend-310': '1' } } + }) + expect(containerHasNpuRequest(c)).toBe(true) + }) + it('rejects non-ascend resources', () => { + const c = makeContainer({ + resources: { requests: { cpu: '2', 'nvidia.com/gpu': '1' } } + }) + expect(containerHasNpuRequest(c)).toBe(false) + }) + it('handles empty resources', () => { + expect(containerHasNpuRequest(makeContainer())).toBe(false) + expect(hasNpuRequest(undefined)).toBe(false) + }) + it('hasNpuRequest scans all containers', () => { + const spec = { + containers: [ + makeContainer({ name: 'a' }), + makeContainer({ + name: 'b', + resources: { requests: { 'huawei.com/ascend-910b': '2' } } + }) + ] + } as k8s.V1PodSpec + expect(hasNpuRequest(spec)).toBe(true) + }) +}) + +// ── shell scripts ────────────────────────────────────────────────────────────── + +describe('buildNpuSamplerScript', () => { + it('embeds the marker, card enumeration and interval', () => { + const script = buildNpuSamplerScript(1) + expect(script).toContain(NPU_METRICS_MARKER) + expect(script).toContain('/dev/davinci[0-9]*') + expect(script).toContain('npu-smi info -t usages') + expect(script).toContain('sleep 1') + expect(script).toContain('/tmp/npu-samples.jsonl') + }) + it('rotates the samples file above the size cap', () => { + expect(buildNpuSamplerScript()).toContain('-gt 4194304') + }) + it('substitutes the requested interval', () => { + expect(buildNpuSamplerScript(0.25)).toContain('sleep 0.25') + }) +}) + +describe('buildNpuAggregateScript', () => { + it('aggregates samples and prints the marker payload', () => { + const script = buildNpuAggregateScript() + expect(script).toContain(NPU_METRICS_MARKER) + expect(script).toContain('awk -v now=') + expect(script).toContain('touch "$F"') + }) +}) + +// ── injection ────────────────────────────────────────────────────────────────── + +describe('injectNpuMetrics / maybeInjectNpuMetrics', () => { + afterEach(() => { + delete process.env.ACTIONS_RUNNER_NPU_METRICS + }) + + it('injects lifecycle hooks on a bare container', () => { + const c = makeContainer() + expect(injectNpuMetrics(c)).toBe(true) + expect(c.lifecycle?.postStart?.exec?.command?.[0]).toBe('sh') + expect(c.lifecycle?.postStart?.exec?.command?.[1]).toBe('-c') + expect(c.lifecycle?.postStart?.exec?.command?.[2]).toContain( + NPU_METRICS_MARKER + ) + expect(c.lifecycle?.postStart?.exec?.command?.[2]).toContain( + '/tmp/npu-samples.jsonl' + ) + expect(c.lifecycle?.preStop?.exec?.command?.[2]).toContain( + `head -c 4096 > /dev/termination-log` + ) + }) + + it('appends to an existing sh -c postStart without touching it', () => { + const c = makeContainer({ + lifecycle: { + postStart: { + exec: { command: ['/bin/sh', '-c', 'echo npu-precheck'] } + } + } + }) + expect(injectNpuMetrics(c)).toBe(true) + const command = c.lifecycle?.postStart?.exec?.command + expect(command?.[0]).toBe('/bin/sh') + const script = command?.[2] ?? '' + expect(script).toContain('echo npu-precheck') + expect(script).toContain(NPU_METRICS_MARKER) + const lines = script.split('\n') + expect(lines[0]).toBe('echo npu-precheck') + }) + + it('wraps an arbitrary existing command', () => { + const c = makeContainer({ + lifecycle: { + postStart: { exec: { command: ['/usr/bin/check', '--flag'] } } + } + }) + expect(injectNpuMetrics(c)).toBe(true) + const command = c.lifecycle?.postStart?.exec?.command + expect(command?.[0]).toBe('sh') + expect(command?.[1]).toBe('-c') + expect(command?.[2]).toContain(`'/usr/bin/check' '--flag'`) + expect(command?.[2]).toContain(NPU_METRICS_MARKER) + }) + + it('is idempotent via the marker', () => { + const c = makeContainer() + injectNpuMetrics(c) + const frozen = JSON.stringify(c.lifecycle) + expect(injectNpuMetrics(c)).toBe(false) + expect(JSON.stringify(c.lifecycle)).toBe(frozen) + }) + + it('skips when a non-exec handler already exists', () => { + const c = makeContainer({ + lifecycle: { + postStart: { httpGet: { path: '/x', port: 80 } } + } + }) + expect(injectNpuMetrics(c)).toBe(false) + expect(c.lifecycle?.postStart?.httpGet?.path).toBe('/x') + }) + + it('maybeInject skips when disabled', () => { + process.env.ACTIONS_RUNNER_NPU_METRICS = 'disabled' + const c = makeContainer({ + resources: { requests: { 'huawei.com/ascend-1980': '8' } } + }) + expect(maybeInjectNpuMetrics(c)).toBe(false) + expect(c.lifecycle).toBeUndefined() + }) + + it('maybeInject skips without an npu request', () => { + const c = makeContainer() + expect(maybeInjectNpuMetrics(c)).toBe(false) + expect(c.lifecycle).toBeUndefined() + }) + + it('maybeInject injects with an npu request', () => { + const c = makeContainer({ + resources: { requests: { 'huawei.com/ascend-1980': '8' } } + }) + expect(maybeInjectNpuMetrics(c)).toBe(true) + expect(c.lifecycle?.postStart).toBeDefined() + }) +}) + +// ── parsing and idle ─────────────────────────────────────────────────────────── + +describe('parseNpuAggregate', () => { + it('parses a valid payload', () => { + const payload = parseNpuAggregate( + `{"v":"NPU_METRICS_V1","ts":1690000100,"cards":[{"c":"0","n":3,"pu":88.5,"au":51.2,"ph":77,"fs":1690000000,"ls":1690000002}]}\n` + ) + expect(payload?.version).toBe(NPU_METRICS_MARKER) + expect(payload?.cards).toHaveLength(1) + expect(payload?.cards[0]).toEqual({ + card: '0', + samples: 3, + peakUtil: 88.5, + avgUtil: 51.2, + peakHbm: 77, + firstTs: 1690000000, + lastTs: 1690000002 + }) + }) + it('parses payload embedded in junk (termination message)', () => { + const payload = parseNpuAggregate(`pre {"v":"NPU_METRICS_V1"`) + expect(payload).toBeUndefined() + }) + it('extracts payload with prefix and suffix junk', () => { + const payload = parseNpuAggregate( + `some-prefix {"v":"NPU_METRICS_V1","ts":1,"cards":[]} trailing` + ) + expect(payload?.version).toBe(NPU_METRICS_MARKER) + expect(payload?.cards).toHaveLength(0) + }) + it('returns undefined for missing or invalid input', () => { + expect(parseNpuAggregate(undefined)).toBeUndefined() + expect(parseNpuAggregate('')).toBeUndefined() + expect(parseNpuAggregate('no json here')).toBeUndefined() + expect(parseNpuAggregate('{"v":"OTHER","ts":1,"cards":[]}')).toBeUndefined() + }) + it('drops malformed card entries', () => { + const payload = parseNpuAggregate( + `{"v":"NPU_METRICS_V1","ts":1,"cards":[{"c":"0","n":1},null,{"x":1}]}` + ) + expect(payload?.cards).toHaveLength(1) + expect(payload?.cards[0].samples).toBe(1) + }) +}) + +describe('isIdleRecord', () => { + const card = (pu: number, au: number) => ({ + card: '0', + samples: 5, + peakUtil: pu, + avgUtil: au, + peakHbm: 10, + firstTs: 1, + lastTs: 2 + }) + it('marks all-low records idle', () => { + expect(isIdleRecord([card(4.9, 1.2), card(0, 0)])).toBe(true) + }) + it('marks records with any busy card as not idle', () => { + expect(isIdleRecord([card(4.9, 1.2), card(12, 3)])).toBe(false) + }) + it('treats the 5% threshold as exclusive', () => { + expect(isIdleRecord([card(5, 1)])).toBe(false) + expect(isIdleRecord([card(4.99, 4.99)])).toBe(true) + }) + it('honours a custom threshold', () => { + expect(isIdleRecord([card(8, 8)], 10)).toBe(true) + }) + it('empty records are not idle', () => { + expect(isIdleRecord([])).toBe(false) + }) +}) + +// ── prometheus text ──────────────────────────────────────────────────────────── + +describe('prometheus formatting', () => { + const labels = { + cluster: 'gy005', + namespace: 'test-ns', + pod: 'runner-x-workflow', + podType: 'workflow', + repo: 'org/repo', + runId: '123', + npuType: 'ascend-1980', + cardsRequested: '8', + result: '0' + } + const card = { + card: '1', + samples: 4, + peakUtil: 88, + avgUtil: 40, + peakHbm: 66, + firstTs: 100, + lastTs: 145 + } + + it('escapes label values', () => { + expect(escapePromLabelValue('a"b\\c\nd')).toBe('a\\"b\\\\c\\nd') + }) + + it('emits one series per metric per card with the idle label', () => { + const body = buildNpuJobMetricsBody(labels, [card]) + const expectedLabels = + `cluster="gy005",namespace="test-ns",repo="org/repo",run_id="123",` + + `pod="runner-x-workflow",pod_type="workflow",card="1",` + + `npu_type="ascend-1980",cards_requested="8",result="0",idle="false"` + expect(body).toContain( + `custom_npu_job_peak_util_percent{${expectedLabels}} 88` + ) + expect(body).toContain( + `custom_npu_job_avg_util_percent{${expectedLabels}} 40` + ) + expect(body).toContain( + `custom_npu_job_duration_seconds{${expectedLabels}} 45` + ) + expect(body).toContain(`custom_npu_job_sample_count{${expectedLabels}} 4`) + expect(body).toContain( + `custom_npu_job_push_total{cluster="gy005",namespace="test-ns",status="success"} 1` + ) + }) + + it('marks idle records', () => { + const idleCard = { ...card, peakUtil: 0, avgUtil: 0 } + expect(buildNpuJobMetricsBody(labels, [idleCard])).toContain('idle="true"') + }) + + it('emits a failed counter body', () => { + expect(buildNpuPushFailedBody(labels)).toContain('status="failed"') + }) + + it('builds the pushgateway grouping path with encoding', () => { + expect(buildPushgatewayPath('gy005', 'ns-a', 'pod/b')).toBe( + '/metrics/job/npu-job-record/cluster/gy005/ns/ns-a/pod/pod%2Fb' + ) + }) +}) + +// ── timeout / http ───────────────────────────────────────────────────────────── + +describe('withTimeout', () => { + it('passes the value through when fast', async () => { + await expect(withTimeout(Promise.resolve(7), 1000)).resolves.toBe(7) + }) + it('rejects when the promise exceeds the budget', async () => { + const slow = new Promise(resolve => setTimeout(resolve, 500, 'late')) + await expect(withTimeout(slow, 20)).rejects.toThrow('timeout') + }) + it('propagates promise rejections', async () => { + await expect( + withTimeout(Promise.reject(new Error('boom')), 1000) + ).rejects.toThrow('boom') + }) +}) + +describe('nodeRequest', () => { + let server: http.Server + let port: number + let seen: { auth?: string; body?: string; path?: string } + + beforeAll(async () => { + seen = {} + server = http.createServer((req, res) => { + let body = '' + req.on('data', chunk => (body += chunk)) + req.on('end', () => { + seen = { auth: req.headers.authorization, body, path: req.url } + res.statusCode = 204 + res.end() + }) + }) + await new Promise(resolve => { + server.listen(0, '127.0.0.1', () => resolve()) + }) + port = (server.address() as AddressInfo).port + }) + + afterAll(async () => { + await new Promise(resolve => server.close(resolve)) + }) + + it('posts the body with basic auth over http', async () => { + const response = await nodeRequest({ + url: `http://127.0.0.1:${port}/metrics/job/npu-job-record`, + method: 'POST', + body: 'custom_npu_job_peak_util_percent 1', + username: 'user', + password: 'pass' + }) + expect(response.statusCode).toBe(204) + expect(seen.path).toBe('/metrics/job/npu-job-record') + expect(seen.auth).toBe( + `Basic ${Buffer.from('user:pass').toString('base64')}` + ) + expect(seen.body).toContain('custom_npu_job_peak_util_percent') + }) + + it('rejects on connection errors', async () => { + const socket = new net.Socket() + const freePort = (socket.address() as AddressInfo)?.port + socket.destroy() + await expect( + nodeRequest({ + url: `http://127.0.0.1:${freePort + 1}/metrics`, + method: 'POST', + body: 'x', + timeoutMs: 1000 + }) + ).rejects.toThrow() + }) +}) + +describe('pushToPushgateway', () => { + const config = { url: 'http://pgw.example', username: 'u', password: 'p' } + + it('succeeds on 2xx without retries', async () => { + const requestFn = vi.fn().mockResolvedValue({ statusCode: 200 }) + await pushToPushgateway(config, '/metrics/job/x', 'body', { requestFn }) + expect(requestFn).toHaveBeenCalledTimes(1) + expect(requestFn).toHaveBeenCalledWith( + expect.objectContaining({ + url: 'http://pgw.example/metrics/job/x', + method: 'POST', + body: 'body', + username: 'u', + password: 'p' + }) + ) + }) + + it('retries failures and succeeds eventually', async () => { + const requestFn = vi + .fn() + .mockRejectedValueOnce(new Error('conn reset')) + .mockResolvedValueOnce({ statusCode: 202 }) + await pushToPushgateway(config, '/metrics/job/x', 'body', { + requestFn, + retryDelayMs: 0 + }) + expect(requestFn).toHaveBeenCalledTimes(2) + }) + + it('gives up after the configured retries', async () => { + const requestFn = vi.fn().mockRejectedValue(new Error('down')) + await expect( + pushToPushgateway(config, '/metrics/job/x', 'body', { + requestFn, + retryDelayMs: 0 + }) + ).rejects.toThrow('down') + expect(requestFn).toHaveBeenCalledTimes(3) + }) + + it('treats non-2xx as failure and retries', async () => { + const requestFn = vi + .fn() + .mockResolvedValueOnce({ statusCode: 500 }) + .mockResolvedValue({ statusCode: 200 }) + await pushToPushgateway(config, '/metrics/job/x', 'body', { + requestFn, + retryDelayMs: 0 + }) + expect(requestFn).toHaveBeenCalledTimes(2) + }) + + it('strips trailing slashes from the base url', async () => { + const requestFn = vi.fn().mockResolvedValue({ statusCode: 200 }) + await pushToPushgateway( + { url: 'http://pgw.example/' }, + '/metrics/job/x', + 'body', + { requestFn } + ) + expect(requestFn).toHaveBeenCalledWith( + expect.objectContaining({ url: 'http://pgw.example/metrics/job/x' }) + ) + }) +}) + +// ── secret / labels ──────────────────────────────────────────────────────────── + +describe('decodePushSecret', () => { + it('decodes url, user and password', () => { + const secret = { + data: { + PUSHGATEWAY_URL: b64('http://pgw:9091'), + PUSHGATEWAY_USER: b64('u'), + PUSHGATEWAY_PASSWORD: b64('p') + } + } as k8s.V1Secret + expect(decodePushSecret(secret)).toEqual({ + url: 'http://pgw:9091', + username: 'u', + password: 'p' + }) + }) + it('requires the url key', () => { + expect( + decodePushSecret({ data: { PUSHGATEWAY_USER: b64('u') } } as k8s.V1Secret) + ).toBeUndefined() + expect(decodePushSecret(undefined)).toBeUndefined() + expect(decodePushSecret({} as k8s.V1Secret)).toBeUndefined() + }) +}) + +describe('extractClusterFromRunnerPod', () => { + it('prefers scale-set-like label keys', () => { + const pod = { + metadata: { + name: 'ephemeral-abc', + labels: { + 'actions.github.com/scale-set-name': 'linux-aarch64-a3-2-gy005' + } + } + } as k8s.V1Pod + expect(extractClusterFromRunnerPod(pod)).toBe('gy005') + }) + it('falls back to any label value shaped like a scale set name', () => { + const pod = { + metadata: { + name: 'pod', + labels: { misc: 'linux-aarch64-910b-8-wlcb-001' } + } + } as k8s.V1Pod + expect(extractClusterFromRunnerPod(pod)).toBe('wlcb-001') + }) + it('falls back to the pod name', () => { + const pod = { + metadata: { name: 'linux-aarch64-a3-2-cn12-001', labels: {} } + } as k8s.V1Pod + expect(extractClusterFromRunnerPod(pod)).toBe('cn12-001') + }) + it('returns unknown when nothing matches', () => { + const pod = { + metadata: { name: 'linux-aarch64-a3-2', labels: { app: 'x' } } + } as k8s.V1Pod + expect(extractClusterFromRunnerPod(pod)).toBe('unknown') + }) + it('does not treat a numeric suffix as a cluster', () => { + const pod = { + metadata: { name: 'linux-aarch64-a3-2', labels: {} } + } as k8s.V1Pod + expect(extractClusterFromRunnerPod(pod)).toBe('unknown') + }) +}) + +describe('resolveNpuLabelsFromPod', () => { + it('derives step pod type and aggregates npu types', () => { + const pod = { + metadata: { name: 'runner-x-step-abc12345' }, + spec: { + containers: [ + { + name: 'job', + resources: { requests: { 'huawei.com/ascend-310': '2' } } + }, + { + name: 'side', + resources: { requests: { 'huawei.com/ascend-1980': '8' } } + } + ] + }, + status: { phase: 'Running' } + } as unknown as k8s.V1Pod + const labels = resolveNpuLabelsFromPod(pod, 'runner-x-step-abc12345') + expect(labels.podType).toBe('step') + expect(labels.npuType).toBe('ascend-1980,ascend-310') + expect(labels.cardsRequested).toBe('8') + expect(labels.result).toBe('Running') + }) + it('uses the terminated exit code as result', () => { + const pod = { + metadata: { name: 'runner-x-workflow' }, + spec: { containers: [{ name: 'job' }] }, + status: { + phase: 'Succeeded', + containerStatuses: [ + { name: 'job', state: { terminated: { exitCode: 0, message: '' } } } + ] + } + } as unknown as k8s.V1Pod + expect(resolveNpuLabelsFromPod(pod, 'runner-x-workflow').result).toBe('0') + }) + it('handles a pod without status', () => { + const pod = { + metadata: { name: 'p' }, + spec: { containers: [] } + } as unknown as k8s.V1Pod + const labels = resolveNpuLabelsFromPod(pod, 'p') + expect(labels.podType).toBe('workflow') + expect(labels.npuType).toBe('unknown') + expect(labels.cardsRequested).toBe('0') + expect(labels.result).toBe('unknown') + }) +}) + +describe('repoFromEnv', () => { + afterEach(() => { + delete process.env.GITHUB_REPOSITORY + delete process.env.GITHUB_WORKSPACE + }) + it('prefers GITHUB_REPOSITORY', () => { + process.env.GITHUB_REPOSITORY = 'org/repo' + expect(repoFromEnv()).toBe('org/repo') + }) + it('falls back to the last two GITHUB_WORKSPACE segments', () => { + process.env.GITHUB_WORKSPACE = '/__w/repo-name/repo-name' + expect(repoFromEnv()).toBe('repo-name/repo-name') + }) + it('returns unknown without envs', () => { + expect(repoFromEnv({})).toBe('unknown') + }) +}) + +// ── collection from pods ─────────────────────────────────────────────────────── + +describe('collectNpuAggregateFromPod', () => { + afterEach(() => { + vi.clearAllMocks() + }) + + it('parses the termination message when the container terminated', async () => { + const pod = { + metadata: { name: 'job-pod' }, + status: { + containerStatuses: [ + { + name: 'job', + state: { + terminated: { + exitCode: 0, + message: + '{"v":"NPU_METRICS_V1","ts":9,"cards":[{"c":"0","n":1,"pu":2,"au":1,"ph":1,"fs":1,"ls":2}]}' + } + } + } + ] + } + } as unknown as k8s.V1Pod + const payload = await collectNpuAggregateFromPod(pod) + expect(payload?.cards[0].peakUtil).toBe(2) + expect(k8sMod.execPodStepWithOutput).not.toHaveBeenCalled() + }) + + it('execs the aggregate script when the container is running', async () => { + vi.mocked(k8sMod.execPodStepWithOutput).mockResolvedValue({ + code: 0, + output: '{"v":"NPU_METRICS_V1","ts":9,"cards":[]}' + }) + const pod = { + metadata: { name: 'job-pod' }, + status: { + phase: 'Running', + containerStatuses: [ + { name: 'job', state: { running: { startedAt: new Date() } } } + ] + } + } as unknown as k8s.V1Pod + const payload = await collectNpuAggregateFromPod(pod) + expect(k8sMod.execPodStepWithOutput).toHaveBeenCalledWith( + expect.arrayContaining(['sh', '-c']), + 'job-pod', + 'job', + 5 + ) + expect(payload?.version).toBe(NPU_METRICS_MARKER) + }) + + it('returns undefined when the pod has no name', async () => { + expect(await collectNpuAggregateFromPod({} as k8s.V1Pod)).toBeUndefined() + }) + + it('returns undefined when the container is pending', async () => { + const pod = { + metadata: { name: 'job-pod' }, + status: { + containerStatuses: [{ name: 'job', state: { waiting: {} } }] + } + } as unknown as k8s.V1Pod + expect(await collectNpuAggregateFromPod(pod)).toBeUndefined() + }) +}) + +// ── end to end collection and push ───────────────────────────────────────────── + +describe('collectAndPushNpuMetrics', () => { + let server: http.Server + let port: number + let received: { path?: string; body?: string }[] + + beforeAll(async () => { + received = [] + server = http.createServer((req, res) => { + let body = '' + req.on('data', chunk => (body += chunk)) + req.on('end', () => { + received.push({ path: req.url, body }) + res.statusCode = 200 + res.end('ok') + }) + }) + await new Promise(resolve => server.listen(0, '127.0.0.1', resolve)) + port = (server.address() as AddressInfo).port + }) + + afterAll(async () => { + await new Promise(resolve => server.close(resolve)) + }) + + beforeEach(() => { + received.length = 0 + process.env.ACTIONS_RUNNER_POD_NAME = 'runner-x' + process.env.GITHUB_REPOSITORY = 'org/repo' + process.env.GITHUB_RUN_ID = '42' + const jobPod = { + metadata: { + name: 'runner-x-workflow', + labels: { 'runner-pod': 'runner-x' } + }, + spec: { + containers: [ + { + name: 'job', + resources: { requests: { 'huawei.com/ascend-1980': '2' } } + } + ] + }, + status: { + phase: 'Running', + containerStatuses: [ + { name: 'job', state: { running: { startedAt: new Date() } } } + ] + } + } as unknown as k8s.V1Pod + const stepPod = { + metadata: { + name: 'runner-x-step-ab12cd34', + labels: { 'runner-pod': 'runner-x' } + }, + spec: { + containers: [ + { + name: 'job', + resources: { requests: { 'huawei.com/ascend-1980': '2' } } + } + ] + }, + status: { + phase: 'Succeeded', + containerStatuses: [ + { + name: 'job', + state: { + terminated: { + exitCode: 0, + message: + '{"v":"NPU_METRICS_V1","ts":9,"cards":[{"c":"1","n":1,"pu":1,"au":0.5,"ph":1,"fs":10,"ls":11}]}' + } + } + } + ] + } + } as unknown as k8s.V1Pod + const cpuPod = { + metadata: { + name: 'runner-x-cpu-extra', + labels: { 'runner-pod': 'runner-x' } + }, + spec: { containers: [{ name: 'job' }] }, + status: { phase: 'Running' } + } as unknown as k8s.V1Pod + const runnerPod = { + metadata: { + name: 'runner-x', + labels: { + 'actions.github.com/scale-set-name': 'linux-aarch64-a3-2-gy005' + } + } + } as k8s.V1Pod + vi.mocked(k8sMod.listPodsByRunnerInstance).mockResolvedValue([ + jobPod, + stepPod, + cpuPod + ]) + vi.mocked(k8sMod.getPodByName).mockImplementation(async (name: string) => { + if (name === 'runner-x') return runnerPod + throw new Error(`unexpected pod ${name}`) + }) + vi.mocked(k8sMod.execPodStepWithOutput).mockResolvedValue({ + code: 0, + output: + '{"v":"NPU_METRICS_V1","ts":9,"cards":[{"c":"0","n":2,"pu":88,"au":50,"ph":70,"fs":100,"last":0,"ls":160}]}' + }) + vi.mocked(k8sMod.getSecretByName).mockResolvedValue({ + data: { + PUSHGATEWAY_URL: b64(`http://127.0.0.1:${port}`), + PUSHGATEWAY_USER: b64('push-user'), + PUSHGATEWAY_PASSWORD: b64('push-pass') + } + } as k8s.V1Secret) + }) + + afterEach(() => { + vi.clearAllMocks() + delete process.env.ACTIONS_RUNNER_POD_NAME + delete process.env.GITHUB_REPOSITORY + delete process.env.GITHUB_RUN_ID + delete process.env.ACTIONS_RUNNER_NPU_METRICS + }) + + it('collects from job and step pods and pushes one record per pod', async () => { + await collectAndPushNpuMetrics() + const paths = received.map(r => r.path) + expect(paths).toContain( + '/metrics/job/npu-job-record/cluster/gy005/ns/test-ns/pod/runner-x-workflow' + ) + expect(paths).toContain( + '/metrics/job/npu-job-record/cluster/gy005/ns/test-ns/pod/runner-x-step-ab12cd34' + ) + expect(received).toHaveLength(2) + + const workflowBody = received.find(r => + r.path?.endsWith('runner-x-workflow') + )?.body + expect(workflowBody).toContain('custom_npu_job_peak_util_percent') + expect(workflowBody).toContain('idle="false"') + expect(workflowBody).toContain('pod_type="workflow"') + expect(workflowBody).toContain('repo="org/repo"') + expect(workflowBody).toContain('run_id="42"') + expect(workflowBody).toContain('npu_type="ascend-1980"') + expect(workflowBody).toContain('cards_requested="2"') + expect(workflowBody).toContain('custom_npu_job_push_total') + expect(workflowBody).toContain('custom_npu_job_duration_seconds{') + + const stepBody = received.find(r => r.path?.endsWith('ab12cd34'))?.body + expect(stepBody).toContain('pod_type="step"') + expect(stepBody).toContain('idle="true"') + expect(stepBody).toContain('card="1"') + }) + + it('skips everything when disabled', async () => { + process.env.ACTIONS_RUNNER_NPU_METRICS = 'disabled' + await collectAndPushNpuMetrics() + expect(k8sMod.listPodsByRunnerInstance).not.toHaveBeenCalled() + }) + + it('skips push when the secret is missing', async () => { + vi.mocked(k8sMod.getSecretByName).mockRejectedValue( + new Error('secrets "npu-metrics-pushgw" not found') + ) + await expect(collectAndPushNpuMetrics()).resolves.toBeUndefined() + expect(k8sMod.listPodsByRunnerInstance).toHaveBeenCalled() + }) + + it('skips when no aggregate payload can be read', async () => { + vi.mocked(k8sMod.execPodStepWithOutput).mockResolvedValue({ + code: 0, + output: 'no sampler output' + }) + await expect(collectAndPushNpuMetrics()).resolves.toBeUndefined() + expect(received).toHaveLength(1) // only the step pod termination message + }) + + it('survives an unreachable pushgateway', async () => { + vi.mocked(k8sMod.getSecretByName).mockResolvedValue({ + data: { PUSHGATEWAY_URL: b64('http://127.0.0.1:1') } + } as k8s.V1Secret) + await expect(collectAndPushNpuMetrics()).resolves.toBeUndefined() + }, 30000) + + it('returns silently when the pod list fails', async () => { + vi.mocked(k8sMod.listPodsByRunnerInstance).mockRejectedValue( + new Error('404') + ) + await expect(collectAndPushNpuMetrics()).resolves.toBeUndefined() + }) + + it('keeps going when one pod collection throws', async () => { + vi.mocked(k8sMod.execPodStepWithOutput).mockRejectedValue( + new Error('exec boom') + ) + await expect(collectAndPushNpuMetrics()).resolves.toBeUndefined() + expect(received).toHaveLength(1) // step pod record still pushed + }) + + it('does nothing for pods without npu requests', async () => { + vi.mocked(k8sMod.listPodsByRunnerInstance).mockResolvedValue([ + { + metadata: { name: 'cpu-only', labels: { 'runner-pod': 'runner-x' } }, + spec: { containers: [{ name: 'job' }] }, + status: { phase: 'Succeeded' } + } as unknown as k8s.V1Pod + ]) + await collectAndPushNpuMetrics() + expect(k8sMod.execPodStepWithOutput).not.toHaveBeenCalled() + expect(received).toHaveLength(0) + }) +}) diff --git a/packages/k8s/src/k8s/utils/npu-metrics.ts b/packages/k8s/src/k8s/utils/npu-metrics.ts new file mode 100644 index 00000000..20af4d12 --- /dev/null +++ b/packages/k8s/src/k8s/utils/npu-metrics.ts @@ -0,0 +1,758 @@ +import * as core from '@actions/core' +import * as k8s from '@kubernetes/client-node' +import * as https from 'https' +import * as http from 'http' +import { URL } from 'url' +import { getRunnerPodName, JOB_CONTAINER_NAME } from '../../hooks/constants' +import { formatError } from './index' +import { + execPodStepWithOutput, + getPodByName, + getSecretByName, + listPodsByRunnerInstance, + namespace +} from '../index' + +export const NPU_METRICS_MARKER = 'NPU_METRICS_V1' +export const ENV_NPU_METRICS_ENABLED = 'ACTIONS_RUNNER_NPU_METRICS' +export const ENV_NPU_SAMPLE_INTERVAL = 'NPU_SAMPLE_INTERVAL' +export const ENV_NPU_IDLE_THRESHOLD = 'NPU_IDLE_THRESHOLD' + +export const DEFAULT_NPU_SAMPLE_INTERVAL_SECONDS = 1 +export const MIN_NPU_SAMPLE_INTERVAL_SECONDS = 0.2 +export const DEFAULT_NPU_IDLE_THRESHOLD_PERCENT = 5 + +export const NPU_SAMPLES_FILE = '/tmp/npu-samples.jsonl' +export const NPU_TERMINATION_LOG = '/dev/termination-log' +export const NPU_SAMPLES_MAX_BYTES = 4 * 1024 * 1024 +export const NPU_AGGREGATE_MAX_BYTES = 4096 + +export const NPU_METRICS_SECRET_NAME = 'npu-metrics-pushgw' +export const NPU_METRICS_PUSH_JOB = 'npu-job-record' +export const NPU_COLLECT_TIMEOUT_MS = 10_000 + +const NPU_RESOURCE_REGEX = /^huawei\.com\/(ascend\S*)$/i +const SCALE_SET_NAME_REGEX = /^linux-[a-z0-9]+-[a-z0-9]+-\d+-([a-z][a-z0-9-]*)$/ + +export interface NpuCardAggregate { + card: string + samples: number + peakUtil: number + avgUtil: number + peakHbm: number + firstTs: number + lastTs: number +} + +export interface NpuAggregatePayload { + version: string + ts: number + cards: NpuCardAggregate[] +} + +export interface NpuPushConfig { + url: string + username?: string + password?: string +} + +export interface NpuJobLabels { + cluster: string + namespace: string + pod: string + podType: string + repo: string + runId: string + npuType: string + cardsRequested: string + result: string +} + +export function npuMetricsEnabled( + env: Record = process.env +): boolean { + return ( + (env[ENV_NPU_METRICS_ENABLED] ?? '').trim().toLowerCase() !== 'disabled' + ) +} + +export function getNpuSampleIntervalSeconds( + env: Record = process.env +): number { + const raw = env[ENV_NPU_SAMPLE_INTERVAL] + if (!raw) { + return DEFAULT_NPU_SAMPLE_INTERVAL_SECONDS + } + const parsed = Number(raw) + if (!Number.isFinite(parsed) || parsed <= 0) { + core.warning( + `NPU_SAMPLE_INTERVAL is invalid ("${raw}"): use ${DEFAULT_NPU_SAMPLE_INTERVAL_SECONDS}` + ) + return DEFAULT_NPU_SAMPLE_INTERVAL_SECONDS + } + return Math.max(parsed, MIN_NPU_SAMPLE_INTERVAL_SECONDS) +} + +export function getIdleThresholdPercent( + env: Record = process.env +): number { + const raw = env[ENV_NPU_IDLE_THRESHOLD] + if (!raw) { + return DEFAULT_NPU_IDLE_THRESHOLD_PERCENT + } + const parsed = Number(raw) + if (!Number.isFinite(parsed) || parsed < 0) { + core.warning( + `NPU_IDLE_THRESHOLD is invalid ("${raw}"): use ${DEFAULT_NPU_IDLE_THRESHOLD_PERCENT}` + ) + return DEFAULT_NPU_IDLE_THRESHOLD_PERCENT + } + return parsed +} + +export function containerHasNpuRequest(container: k8s.V1Container): boolean { + const resources = [container.resources?.requests, container.resources?.limits] + for (const entry of resources) { + for (const key of Object.keys(entry ?? {})) { + if (NPU_RESOURCE_REGEX.test(key)) { + return true + } + } + } + return false +} + +export function hasNpuRequest(spec: k8s.V1PodSpec | undefined): boolean { + return (spec?.containers ?? []).some(c => containerHasNpuRequest(c)) +} + +function listNpuCardsCommand(): string { + return `ls /dev/davinci[0-9]* 2>/dev/null | sed 's|.*/davinci||' | sort -n | uniq | tr '\\n' ' '` +} + +export function buildNpuSamplerScript( + intervalSeconds = DEFAULT_NPU_SAMPLE_INTERVAL_SECONDS +): string { + return [ + `# ${NPU_METRICS_MARKER} sampler (detached, best-effort)`, + `F=${NPU_SAMPLES_FILE}`, + `CARDS=$(${listNpuCardsCommand()})`, + `[ -z "$CARDS" ] && exit 0`, + `while :; do`, + ` NOW=$(date +%s)`, + ` for C in $CARDS; do`, + ` OUT=$(npu-smi info -t usages -i "$C" 2>/dev/null) || continue`, + ` U=$(printf '%s\\n' "$OUT" | awk '{l=$0; gsub(/[ \\t\\r]/, "", l)} l ~ /AICore/ { if (match(l, /[0-9.]+%?$/)) { v = substr(l, RSTART, RLENGTH); sub(/%$/, "", v); print v; exit } }')`, + ` H=$(printf '%s\\n' "$OUT" | awk '{l=$0; gsub(/[ \\t\\r]/, "", l)} l ~ /HBM/ { if (match(l, /[0-9.]+%?$/)) { v = substr(l, RSTART, RLENGTH); sub(/%$/, "", v); print v; exit } }')`, + ` printf '{"ts":%s,"card":%s,"util":%s,"hbm":%s}\\n' "$NOW" "$C" "\${U:-0}" "\${H:-0}" >> "$F" 2>/dev/null || true`, + ` done`, + ` SZ=$(wc -c < "$F" 2>/dev/null || echo 0)`, + ` if [ "$SZ" -gt ${NPU_SAMPLES_MAX_BYTES} ]; then`, + ` tail -n 2000 "$F" > "$F.r" 2>/dev/null && mv "$F.r" "$F" || true`, + ` fi`, + ` sleep ${intervalSeconds}`, + `done` + ].join('\n') +} + +const AGGREGATE_AWK = [ + `BEGIN {`, + ` n = split(cards, a, " ")`, + ` for (i = 1; i <= n; i++) { cnt[a[i]] = 0; pu[a[i]] = 0; ph[a[i]] = 0; su[a[i]] = 0; fs[a[i]] = 0; ls[a[i]] = 0 }`, + `}`, + `{`, + ` ts = $0; sub(/.*"ts":/, "", ts); sub(/[^0-9].*/, "", ts)`, + ` c = $0; sub(/.*"card":/, "", c); sub(/[^0-9].*/, "", c)`, + ` u = $0; sub(/.*"util":/, "", u); sub(/[^0-9.].*/, "", u)`, + ` h = $0; sub(/.*"hbm":/, "", h); sub(/[^0-9.].*/, "", h)`, + ` if (c == "") next`, + ` cnt[c]++`, + ` if (ts != "") { t = ts + 0; if (fs[c] == 0 || t < fs[c]) fs[c] = t; if (t > ls[c]) ls[c] = t }`, + ` if (u + 0 > pu[c]) pu[c] = u + 0`, + ` if (h + 0 > ph[c]) ph[c] = h + 0`, + ` su[c] += u + 0`, + `}`, + `END {`, + ` printf "{\\"v\\":\\"${NPU_METRICS_MARKER}\\",\\"ts\\":%d,\\"cards\\":[", now`, + ` sep = ""`, + ` for (c in cnt) {`, + ` au = cnt[c] > 0 ? su[c] / cnt[c] : 0`, + ` printf "%s{\\"c\\":\\"%s\\",\\"n\\":%d,\\"pu\\":%.1f,\\"au\\":%.1f,\\"ph\\":%.1f,\\"fs\\":%d,\\"ls\\":%d}", sep, c, cnt[c], pu[c], au, ph[c], fs[c], ls[c]`, + ` sep = ","`, + ` }`, + ` printf "]}\\n"`, + `}` +].join('\n') + +export function buildNpuAggregateScript(): string { + return [ + `# ${NPU_METRICS_MARKER} aggregate`, + `F=${NPU_SAMPLES_FILE}`, + `CARDS=$(${listNpuCardsCommand()})`, + `NOW=$(date +%s)`, + `touch "$F" 2>/dev/null || true`, + `awk -v now="$NOW" -v cards="$CARDS" '${AGGREGATE_AWK}' "$F" 2>/dev/null` + ].join('\n') +} + +function commandHasMarker(command: string[] | undefined): boolean { + return (command ?? []).join(' ').includes(NPU_METRICS_MARKER) +} + +function appendExecCommand( + existing: string[] | undefined, + appendLines: string[] +): string[] { + if ( + existing && + existing.length >= 3 && + /(^|\/)sh$/.test(existing[0]) && + existing[1] === '-c' + ) { + return [ + existing[0], + existing[1], + [...existing.slice(2), ...appendLines].join('\n') + ] + } + const prefix = (existing ?? []).map( + part => `'${part.replace(/'/g, "'\\''")}'` + ) + return ['sh', '-c', [prefix.join(' '), ...appendLines].join('\n')] +} + +export function injectNpuMetrics( + container: k8s.V1Container, + intervalSeconds = DEFAULT_NPU_SAMPLE_INTERVAL_SECONDS +): boolean { + const lifecycle = container.lifecycle ?? {} + if ( + commandHasMarker(lifecycle.postStart?.exec?.command) || + commandHasMarker(lifecycle.preStop?.exec?.command) + ) { + return false + } + + if ( + (lifecycle.postStart && !lifecycle.postStart.exec) || + (lifecycle.preStop && !lifecycle.preStop.exec) + ) { + core.warning( + 'npu-metrics: container already has a non-exec lifecycle handler, skip injection' + ) + return false + } + + const samplerLine = `(${buildNpuSamplerScript(intervalSeconds)}) >/dev/null 2>&1 &` + const aggregateLine = `{ ( ${buildNpuAggregateScript()} ) | head -c ${NPU_AGGREGATE_MAX_BYTES} > ${NPU_TERMINATION_LOG}; } 2>/dev/null || true` + + lifecycle.postStart = { + exec: { + command: appendExecCommand(lifecycle.postStart?.exec?.command, [ + `# ${NPU_METRICS_MARKER} postStart: start detached npu sampler`, + samplerLine + ]) + } + } + lifecycle.preStop = { + exec: { + command: appendExecCommand(lifecycle.preStop?.exec?.command, [ + `# ${NPU_METRICS_MARKER} preStop: write npu aggregate to termination log`, + aggregateLine + ]) + } + } + container.lifecycle = lifecycle + return true +} + +export function maybeInjectNpuMetrics(container: k8s.V1Container): boolean { + if (!npuMetricsEnabled()) { + return false + } + if (!containerHasNpuRequest(container)) { + return false + } + return injectNpuMetrics(container) +} + +export function parseNpuAggregate( + raw: string | undefined +): NpuAggregatePayload | undefined { + if (!raw) { + return undefined + } + const start = raw.indexOf('{"v":') + if (start === -1) { + return undefined + } + const candidates = [raw.slice(start)] + const end = raw.lastIndexOf('}') + if (end > start) { + candidates.push(raw.slice(start, end + 1)) + } + for (const candidate of candidates) { + let parsed: any + try { + parsed = JSON.parse(candidate) + } catch { + continue + } + if (parsed?.v !== NPU_METRICS_MARKER || !Array.isArray(parsed.cards)) { + continue + } + const cards: NpuCardAggregate[] = [] + for (const c of parsed.cards) { + if (c === null || typeof c !== 'object' || c.c === undefined) { + continue + } + cards.push({ + card: String(c.c), + samples: Number(c.n) || 0, + peakUtil: Number(c.pu) || 0, + avgUtil: Number(c.au) || 0, + peakHbm: Number(c.ph) || 0, + firstTs: Number(c.fs) || 0, + lastTs: Number(c.ls) || 0 + }) + } + return { version: parsed.v, ts: Number(parsed.ts) || 0, cards } + } + return undefined +} + +export function isIdleRecord( + cards: NpuCardAggregate[], + threshold = DEFAULT_NPU_IDLE_THRESHOLD_PERCENT +): boolean { + if (!cards.length) { + return false + } + return cards.every(c => c.peakUtil < threshold && c.avgUtil < threshold) +} + +export function escapePromLabelValue(value: string): string { + return value.replace(/\\/g, '\\\\').replace(/"/g, '\\"').replace(/\n/g, '\\n') +} + +export function formatPromLabels(labels: Record): string { + return Object.entries(labels) + .filter(([, v]) => v !== undefined) + .map(([k, v]) => `${k}="${escapePromLabelValue(v)}"`) + .join(',') +} + +const NPU_JOB_METRIC_LABEL_KEYS = [ + 'cluster', + 'namespace', + 'repo', + 'run_id', + 'pod', + 'pod_type', + 'card', + 'npu_type', + 'cards_requested', + 'result', + 'idle' +] + +export function buildNpuJobMetricsBody( + labels: NpuJobLabels, + cards: NpuCardAggregate[], + idleThreshold = DEFAULT_NPU_IDLE_THRESHOLD_PERCENT +): string { + const base: Record = { + cluster: labels.cluster, + namespace: labels.namespace, + repo: labels.repo, + run_id: labels.runId, + pod: labels.pod, + pod_type: labels.podType, + npu_type: labels.npuType, + cards_requested: labels.cardsRequested, + result: labels.result + } + const idle = isIdleRecord(cards, idleThreshold) ? 'true' : 'false' + const lines: string[] = [] + lines.push('# TYPE custom_npu_job_peak_util_percent gauge') + lines.push('# TYPE custom_npu_job_avg_util_percent gauge') + lines.push('# TYPE custom_npu_job_duration_seconds gauge') + lines.push('# TYPE custom_npu_job_sample_count gauge') + for (const card of cards) { + const cardLabels = { ...base, card: card.card, idle } + const l = formatPromLabels( + Object.fromEntries( + NPU_JOB_METRIC_LABEL_KEYS.map(k => [k, cardLabels[k]]) + ) as Record + ) + lines.push(`custom_npu_job_peak_util_percent{${l}} ${card.peakUtil}`) + lines.push(`custom_npu_job_avg_util_percent{${l}} ${card.avgUtil}`) + const duration = Math.max(card.lastTs - card.firstTs, 0) + lines.push(`custom_npu_job_duration_seconds{${l}} ${duration}`) + lines.push(`custom_npu_job_sample_count{${l}} ${card.samples}`) + } + lines.push('# TYPE custom_npu_job_push_total counter') + lines.push( + `custom_npu_job_push_total{cluster="${escapePromLabelValue(labels.cluster)}",namespace="${escapePromLabelValue(labels.namespace)}",status="success"} 1` + ) + return lines.join('\n') + '\n' +} + +export function buildNpuPushFailedBody(labels: NpuJobLabels): string { + return ( + `# TYPE custom_npu_job_push_total counter\n` + + `custom_npu_job_push_total{cluster="${escapePromLabelValue(labels.cluster)}",namespace="${escapePromLabelValue(labels.namespace)}",status="failed"} 1\n` + ) +} + +export function buildPushgatewayPath( + cluster: string, + ns: string, + pod: string +): string { + return `/metrics/job/${NPU_METRICS_PUSH_JOB}/cluster/${encodeURIComponent( + cluster + )}/ns/${encodeURIComponent(ns)}/pod/${encodeURIComponent(pod)}` +} + +export async function withTimeout( + promise: Promise, + timeoutMs: number +): Promise { + return await new Promise((resolve, reject) => { + const timer = setTimeout(() => reject(new Error('timeout')), timeoutMs) + promise.then( + value => { + clearTimeout(timer) + resolve(value) + }, + err => { + clearTimeout(timer) + reject(err) + } + ) + }) +} + +export interface PushRequest { + url: string + method: string + body: string + username?: string + password?: string + timeoutMs?: number +} + +export type RequestFn = (req: PushRequest) => Promise<{ statusCode: number }> + +export async function nodeRequest(req: PushRequest): Promise<{ + statusCode: number +}> { + const target = new URL(req.url) + const client = target.protocol === 'http:' ? http : https + const headers: Record = { + 'Content-Type': 'text/plain' + } + if (req.username !== undefined || req.password !== undefined) { + const basic = Buffer.from( + `${req.username ?? ''}:${req.password ?? ''}` + ).toString('base64') + headers['Authorization'] = `Basic ${basic}` + } + return await new Promise((resolve, reject) => { + const request = client.request( + target, + { + method: req.method, + headers, + timeout: req.timeoutMs ?? 5000, + rejectUnauthorized: false + }, + response => { + response.resume() + response.on('end', () => + resolve({ statusCode: response.statusCode ?? 0 }) + ) + } + ) + request.on('timeout', () => request.destroy(new Error('request timeout'))) + request.on('error', reject) + request.end(req.body) + }) +} + +export async function pushToPushgateway( + config: NpuPushConfig, + path: string, + body: string, + options?: { retries?: number; retryDelayMs?: number; requestFn?: RequestFn } +): Promise { + const retries = options?.retries ?? 2 + const retryDelayMs = options?.retryDelayMs ?? 1000 + const requestFn = options?.requestFn ?? nodeRequest + const url = `${config.url.replace(/\/+$/, '')}${path}` + let lastError: unknown + for (let attempt = 0; attempt <= retries; attempt++) { + if (attempt > 0) { + await new Promise(resolve => setTimeout(resolve, retryDelayMs)) + } + try { + const response = await requestFn({ + url, + method: 'POST', + body, + username: config.username, + password: config.password + }) + if (response.statusCode >= 200 && response.statusCode < 300) { + return + } + lastError = new Error(`pushgateway returned ${response.statusCode}`) + } catch (err) { + lastError = err + } + } + throw lastError instanceof Error ? lastError : new Error(String(lastError)) +} + +export function decodePushSecret( + secret: k8s.V1Secret | undefined +): NpuPushConfig | undefined { + const data = secret?.data ?? {} + const decode = (key: string): string | undefined => { + const encoded = data[key] + if (!encoded) { + return undefined + } + try { + const decoded = Buffer.from(encoded, 'base64').toString('utf8') + return decoded.length ? decoded : undefined + } catch { + return undefined + } + } + const url = decode('PUSHGATEWAY_URL') + if (!url) { + return undefined + } + return { + url, + username: decode('PUSHGATEWAY_USER'), + password: decode('PUSHGATEWAY_PASSWORD') + } +} + +export async function readNpuPushConfig(): Promise { + try { + const secret = await getSecretByName(NPU_METRICS_SECRET_NAME) + return decodePushSecret(secret) + } catch (err) { + core.debug( + `npu-metrics: secret ${NPU_METRICS_SECRET_NAME} unavailable, skip push: ${formatError(err)}` + ) + return undefined + } +} + +function parseScaleSetSuffix(value: string | undefined): string | undefined { + if (!value) { + return undefined + } + const match = value.match(SCALE_SET_NAME_REGEX) + return match ? match[1] : undefined +} + +export function extractClusterFromRunnerPod(pod: k8s.V1Pod): string { + const labels = pod.metadata?.labels ?? {} + const annotations = pod.metadata?.annotations ?? {} + const entries: [string, string][] = [ + ...Object.entries(labels), + ...Object.entries(annotations) + ] + for (const [key, value] of entries) { + if (/scale[-_]?set|runner[-_]?deployment/i.test(key)) { + const suffix = parseScaleSetSuffix(value) + if (suffix) { + return suffix + } + } + } + for (const [, value] of entries) { + const suffix = parseScaleSetSuffix(value) + if (suffix) { + return suffix + } + } + return parseScaleSetSuffix(pod.metadata?.name) ?? 'unknown' +} + +export function resolveNpuLabelsFromPod( + pod: k8s.V1Pod, + podName: string +): { + podType: string + npuType: string + cardsRequested: string + result: string +} { + const podType = podName.includes('-step-') ? 'step' : 'workflow' + const npuTypes = new Set() + let cards = 0 + for (const container of pod.spec?.containers ?? []) { + for (const resources of [ + container.resources?.requests, + container.resources?.limits + ]) { + for (const [key, quantity] of Object.entries(resources ?? {})) { + const match = key.match(NPU_RESOURCE_REGEX) + if (match) { + npuTypes.add(match[1]) + cards = Math.max(cards, parseInt(String(quantity), 10) || 0) + } + } + } + } + const mainStatus = (pod.status?.containerStatuses ?? []).find( + s => s.name === JOB_CONTAINER_NAME + ) + const terminated = mainStatus?.state?.terminated + const result = terminated + ? String(terminated.exitCode) + : (pod.status?.phase ?? 'unknown') + return { + podType, + npuType: Array.from(npuTypes).sort().join(',') || 'unknown', + cardsRequested: String(cards || 0), + result + } +} + +export function repoFromEnv( + env: Record = process.env +): string { + if (env.GITHUB_REPOSITORY) { + return env.GITHUB_REPOSITORY + } + const workspace = env.GITHUB_WORKSPACE ?? '' + const parts = workspace.split('/').filter(p => p.length > 0) + if (parts.length >= 2) { + return `${parts[parts.length - 2]}/${parts[parts.length - 1]}` + } + return 'unknown' +} + +export async function collectNpuAggregateFromPod( + pod: k8s.V1Pod +): Promise { + const podName = pod.metadata?.name + if (!podName) { + return undefined + } + const mainStatus = (pod.status?.containerStatuses ?? []).find( + s => s.name === JOB_CONTAINER_NAME + ) + const terminatedMessage = mainStatus?.state?.terminated?.message + if (terminatedMessage) { + return parseNpuAggregate(terminatedMessage) + } + if (!mainStatus?.state?.running) { + return undefined + } + const { output } = await execPodStepWithOutput( + ['sh', '-c', buildNpuAggregateScript()], + podName, + JOB_CONTAINER_NAME, + 5 + ) + return parseNpuAggregate(output) +} + +export async function collectAndPushNpuMetrics(): Promise { + if (!npuMetricsEnabled()) { + return + } + let pods: k8s.V1Pod[] = [] + try { + pods = await listPodsByRunnerInstance() + } catch (err) { + core.debug(`npu-metrics: pod list failed: ${formatError(err)}`) + return + } + const npuPods = pods.filter( + pod => pod.metadata?.name && hasNpuRequest(pod.spec) + ) + if (!npuPods.length) { + return + } + + let cluster = 'unknown' + try { + const runnerPod = await getPodByName(getRunnerPodName()) + cluster = extractClusterFromRunnerPod(runnerPod) + } catch (err) { + core.debug(`npu-metrics: cluster label unresolved: ${formatError(err)}`) + } + + const config = await readNpuPushConfig() + if (!config) { + core.debug( + `npu-metrics: push config missing (secret ${NPU_METRICS_SECRET_NAME}), skip push` + ) + return + } + + for (const pod of npuPods) { + const podName = pod.metadata?.name as string + try { + await collectAndPushForPod(pod, podName, cluster, config) + } catch (err) { + core.debug( + `npu-metrics: collection failed for ${podName}: ${formatError(err)}` + ) + } + } +} + +async function collectAndPushForPod( + pod: k8s.V1Pod, + podName: string, + cluster: string, + config: NpuPushConfig +): Promise { + const payload = await collectNpuAggregateFromPod(pod) + if (!payload || !payload.cards.length) { + core.debug(`npu-metrics: no aggregate payload for ${podName}, skip`) + return + } + + const npuInfo = resolveNpuLabelsFromPod(pod, podName) + const labels: NpuJobLabels = { + cluster, + namespace: namespace(), + pod: podName, + podType: npuInfo.podType, + repo: repoFromEnv(), + runId: process.env.GITHUB_RUN_ID ?? '', + npuType: npuInfo.npuType, + cardsRequested: npuInfo.cardsRequested, + result: npuInfo.result + } + + const body = buildNpuJobMetricsBody( + labels, + payload.cards, + getIdleThresholdPercent() + ) + const path = buildPushgatewayPath(labels.cluster, labels.namespace, podName) + try { + await pushToPushgateway(config, path, body) + core.debug(`npu-metrics: pushed job record for ${podName}`) + } catch (err) { + core.warning(`npu-metrics: push failed for ${podName}: ${formatError(err)}`) + try { + await pushToPushgateway(config, path, buildNpuPushFailedBody(labels)) + } catch { + // pushgateway unreachable, nothing else to record + } + } +}