| 164 | } |
| 165 | |
| 166 | function linearSlope(samples: MemorySample[], field: "heapUsedBytes" | "rssBytes") { |
| 167 | if (samples.length < 2) { |
| 168 | return 0; |
| 169 | } |
| 170 | |
| 171 | const meanX = samples.reduce((sum, sample) => sum + sample.navigation, 0) / samples.length; |
| 172 | const meanY = samples.reduce((sum, sample) => sum + sample[field], 0) / samples.length; |
| 173 | const numerator = samples.reduce( |
| 174 | (sum, sample) => sum + (sample.navigation - meanX) * (sample[field] - meanY), |
| 175 | 0, |
| 176 | ); |
| 177 | const denominator = samples.reduce((sum, sample) => sum + (sample.navigation - meanX) ** 2, 0); |
| 178 | return denominator === 0 ? 0 : numerator / denominator; |
| 179 | } |
| 180 | |
| 181 | /** Resolve the next keyboard action and logical position for one hunk-per-file navigation. */ |
| 182 | function nextNavigationKey( |