gx
chenyc
2025-06-12 7b72ac13a83764a662159d4a49b7fffb90476ecb
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
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * =============================================================================
 */
import { backend_util, buffer, MaxPool3DGrad } from '@tensorflow/tfjs-core';
import { assertNotComplex } from '../cpu_util';
import { maxPool3dPositions } from '../utils/pool_utils';
export function maxPool3DGrad(args) {
    const { inputs, backend, attrs } = args;
    const { dy, input } = inputs;
    const { filterSize, strides, pad, dimRoundingMode } = attrs;
    assertNotComplex([dy, input], 'maxPool3DGrad');
    const convInfo = backend_util.computePool3DInfo(input.shape, filterSize, strides, 1 /* dilations */, pad, dimRoundingMode);
    const inputBuf = backend.bufferSync(input);
    const maxPosBuf = maxPool3dPositions(inputBuf, convInfo);
    const strideDepth = convInfo.strideDepth;
    const strideHeight = convInfo.strideHeight;
    const strideWidth = convInfo.strideWidth;
    const dilationDepth = convInfo.dilationDepth;
    const dilationHeight = convInfo.dilationHeight;
    const dilationWidth = convInfo.dilationWidth;
    const effectiveFilterDepth = convInfo.effectiveFilterDepth;
    const effectiveFilterHeight = convInfo.effectiveFilterHeight;
    const effectiveFilterWidth = convInfo.effectiveFilterWidth;
    const padFront = effectiveFilterDepth - 1 - convInfo.padInfo.front;
    const padLeft = effectiveFilterWidth - 1 - convInfo.padInfo.left;
    const padTop = effectiveFilterHeight - 1 - convInfo.padInfo.top;
    const dx = buffer(input.shape, 'float32');
    const dyBuf = backend.bufferSync(dy);
    for (let batch = 0; batch < convInfo.batchSize; ++batch) {
        for (let channel = 0; channel < convInfo.inChannels; ++channel) {
            for (let dxDepth = 0; dxDepth < convInfo.inDepth; ++dxDepth) {
                for (let dxRow = 0; dxRow < convInfo.inHeight; ++dxRow) {
                    for (let dxCol = 0; dxCol < convInfo.inWidth; ++dxCol) {
                        // Shader code begins
                        const dyDepthCorner = dxDepth - padFront;
                        const dyRowCorner = dxRow - padTop;
                        const dyColCorner = dxCol - padLeft;
                        let dotProd = 0;
                        for (let wDepth = 0; wDepth < effectiveFilterDepth; wDepth += dilationDepth) {
                            const dyDepth = (dyDepthCorner + wDepth) / strideDepth;
                            if (dyDepth < 0 || dyDepth >= convInfo.outDepth ||
                                Math.floor(dyDepth) !== dyDepth) {
                                continue;
                            }
                            for (let wRow = 0; wRow < effectiveFilterHeight; wRow += dilationHeight) {
                                const dyRow = (dyRowCorner + wRow) / strideHeight;
                                if (dyRow < 0 || dyRow >= convInfo.outHeight ||
                                    Math.floor(dyRow) !== dyRow) {
                                    continue;
                                }
                                for (let wCol = 0; wCol < effectiveFilterWidth; wCol += dilationWidth) {
                                    const dyCol = (dyColCorner + wCol) / strideWidth;
                                    if (dyCol < 0 || dyCol >= convInfo.outWidth ||
                                        Math.floor(dyCol) !== dyCol) {
                                        continue;
                                    }
                                    const maxPos = effectiveFilterDepth * effectiveFilterHeight *
                                        effectiveFilterWidth -
                                        1 -
                                        maxPosBuf.get(batch, dyDepth, dyRow, dyCol, channel);
                                    const curPos = wDepth * effectiveFilterHeight * effectiveFilterWidth +
                                        wRow * effectiveFilterWidth + wCol;
                                    const mask = maxPos === curPos ? 1 : 0;
                                    if (mask === 0) {
                                        continue;
                                    }
                                    const pixel = dyBuf.get(batch, dyDepth, dyRow, dyCol, channel);
                                    dotProd += pixel * mask;
                                }
                            }
                        }
                        dx.set(dotProd, batch, dxDepth, dxRow, dxCol, channel);
                    }
                }
            }
        }
    }
    return backend.makeTensorInfo(dx.shape, dx.dtype, dx.values);
}
export const maxPool3DGradConfig = {
    kernelName: MaxPool3DGrad,
    backendName: 'cpu',
    kernelFunc: maxPool3DGrad
};
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTWF4UG9vbDNER3JhZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3RmanMtYmFja2VuZC1jcHUvc3JjL2tlcm5lbHMvTWF4UG9vbDNER3JhZC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7Ozs7O0dBZUc7QUFFSCxPQUFPLEVBQUMsWUFBWSxFQUFFLE1BQU0sRUFBNEIsYUFBYSxFQUE0RCxNQUFNLHVCQUF1QixDQUFDO0FBRy9KLE9BQU8sRUFBQyxnQkFBZ0IsRUFBQyxNQUFNLGFBQWEsQ0FBQztBQUM3QyxPQUFPLEVBQUMsa0JBQWtCLEVBQUMsTUFBTSxxQkFBcUIsQ0FBQztBQUV2RCxNQUFNLFVBQVUsYUFBYSxDQUFDLElBSTdCO0lBQ0MsTUFBTSxFQUFDLE1BQU0sRUFBRSxPQUFPLEVBQUUsS0FBSyxFQUFDLEdBQUcsSUFBSSxDQUFDO0lBQ3RDLE1BQU0sRUFBQyxFQUFFLEVBQUUsS0FBSyxFQUFDLEdBQUcsTUFBTSxDQUFDO0lBQzNCLE1BQU0sRUFBQyxVQUFVLEVBQUUsT0FBTyxFQUFFLEdBQUcsRUFBRSxlQUFlLEVBQUMsR0FBRyxLQUFLLENBQUM7SUFFMUQsZ0JBQWdCLENBQUMsQ0FBQyxFQUFFLEVBQUUsS0FBSyxDQUFDLEVBQUUsZUFBZSxDQUFDLENBQUM7SUFFL0MsTUFBTSxRQUFRLEdBQUcsWUFBWSxDQUFDLGlCQUFpQixDQUMzQyxLQUFLLENBQUMsS0FBaUQsRUFBRSxVQUFVLEVBQ25FLE9BQU8sRUFBRSxDQUFDLENBQUMsZUFBZSxFQUFFLEdBQUcsRUFBRSxlQUFlLENBQUMsQ0FBQztJQUV0RCxNQUFNLFFBQVEsR0FBRyxPQUFPLENBQUMsVUFBVSxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQzNDLE1BQU0sU0FBUyxHQUFHLGtCQUFrQixDQUFDLFFBQVEsRUFBRSxRQUFRLENBQUMsQ0FBQztJQUN6RCxNQUFNLFdBQVcsR0FBRyxRQUFRLENBQUMsV0FBVyxDQUFDO0lBQ3pDLE1BQU0sWUFBWSxHQUFHLFFBQVEsQ0FBQyxZQUFZLENBQUM7SUFDM0MsTUFBTSxXQUFXLEdBQUcsUUFBUSxDQUFDLFdBQVcsQ0FBQztJQUN6QyxNQUFNLGFBQWEsR0FBRyxRQUFRLENBQUMsYUFBYSxDQUFDO0lBQzdDLE1BQU0sY0FBYyxHQUFHLFFBQVEsQ0FBQyxjQUFjLENBQUM7SUFDL0MsTUFBTSxhQUFhLEdBQUcsUUFBUSxDQUFDLGFBQWEsQ0FBQztJQUM3QyxNQUFNLG9CQUFvQixHQUFHLFFBQVEsQ0FBQyxvQkFBb0IsQ0FBQztJQUMzRCxNQUFNLHFCQUFxQixHQUFHLFFBQVEsQ0FBQyxxQkFBcUIsQ0FBQztJQUM3RCxNQUFNLG9CQUFvQixHQUFHLFFBQVEsQ0FBQyxvQkFBb0IsQ0FBQztJQUMzRCxNQUFNLFFBQVEsR0FBRyxvQkFBb0IsR0FBRyxDQUFDLEdBQUcsUUFBUSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUM7SUFDbkUsTUFBTSxPQUFPLEdBQUcsb0JBQW9CLEdBQUcsQ0FBQyxHQUFHLFFBQVEsQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDO0lBQ2pFLE1BQU0sTUFBTSxHQUFHLHFCQUFxQixHQUFHLENBQUMsR0FBRyxRQUFRLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQztJQUNoRSxNQUFNLEVBQUUsR0FBRyxNQUFNLENBQUMsS0FBSyxDQUFDLEtBQUssRUFBRSxTQUFTLENBQUMsQ0FBQztJQUUxQyxNQUFNLEtBQUssR0FBRyxPQUFPLENBQUMsVUFBVSxDQUFrQixFQUFFLENBQUMsQ0FBQztJQUV0RCxLQUFLLElBQUksS0FBSyxHQUFHLENBQUMsRUFBRSxLQUFLLEdBQUcsUUFBUSxDQUFDLFNBQVMsRUFBRSxFQUFFLEtBQUssRUFBRTtRQUN2RCxLQUFLLElBQUksT0FBTyxHQUFHLENBQUMsRUFBRSxPQUFPLEdBQUcsUUFBUSxDQUFDLFVBQVUsRUFBRSxFQUFFLE9BQU8sRUFBRTtZQUM5RCxLQUFLLElBQUksT0FBTyxHQUFHLENBQUMsRUFBRSxPQUFPLEdBQUcsUUFBUSxDQUFDLE9BQU8sRUFBRSxFQUFFLE9BQU8sRUFBRTtnQkFDM0QsS0FBSyxJQUFJLEtBQUssR0FBRyxDQUFDLEVBQUUsS0FBSyxHQUFHLFFBQVEsQ0FBQyxRQUFRLEVBQUUsRUFBRSxLQUFLLEVBQUU7b0JBQ3RELEtBQUssSUFBSSxLQUFLLEdBQUcsQ0FBQyxFQUFFLEtBQUssR0FBRyxRQUFRLENBQUMsT0FBTyxFQUFFLEVBQUUsS0FBSyxFQUFFO3dCQUNyRCxxQkFBcUI7d0JBQ3JCLE1BQU0sYUFBYSxHQUFHLE9BQU8sR0FBRyxRQUFRLENBQUM7d0JBQ3pDLE1BQU0sV0FBVyxHQUFHLEtBQUssR0FBRyxNQUFNLENBQUM7d0JBQ25DLE1BQU0sV0FBVyxHQUFHLEtBQUssR0FBRyxPQUFPLENBQUM7d0JBQ3BDLElBQUksT0FBTyxHQUFHLENBQUMsQ0FBQzt3QkFDaEIsS0FBSyxJQUFJLE1BQU0sR0FBRyxDQUFDLEVBQUUsTUFBTSxHQUFHLG9CQUFvQixFQUM3QyxNQUFNLElBQUksYUFBYSxFQUFFOzRCQUM1QixNQUFNLE9BQU8sR0FBRyxDQUFDLGFBQWEsR0FBRyxNQUFNLENBQUMsR0FBRyxXQUFXLENBQUM7NEJBQ3ZELElBQUksT0FBTyxHQUFHLENBQUMsSUFBSSxPQUFPLElBQUksUUFBUSxDQUFDLFFBQVE7Z0NBQzNDLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLEtBQUssT0FBTyxFQUFFO2dDQUNuQyxTQUFTOzZCQUNWOzRCQUNELEtBQUssSUFBSSxJQUFJLEdBQUcsQ0FBQyxFQUFFLElBQUksR0FBRyxxQkFBcUIsRUFDMUMsSUFBSSxJQUFJLGNBQWMsRUFBRTtnQ0FDM0IsTUFBTSxLQUFLLEdBQUcsQ0FBQyxXQUFXLEdBQUcsSUFBSSxDQUFDLEdBQUcsWUFBWSxDQUFDO2dDQUNsRCxJQUFJLEtBQUssR0FBRyxDQUFDLElBQUksS0FBSyxJQUFJLFFBQVEsQ0FBQyxTQUFTO29DQUN4QyxJQUFJLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQyxLQUFLLEtBQUssRUFBRTtvQ0FDL0IsU0FBUztpQ0FDVjtnQ0FDRCxLQUFLLElBQUksSUFBSSxHQUFHLENBQUMsRUFBRSxJQUFJLEdBQUcsb0JBQW9CLEVBQ3pDLElBQUksSUFBSSxhQUFhLEVBQUU7b0NBQzFCLE1BQU0sS0FBSyxHQUFHLENBQUMsV0FBVyxHQUFHLElBQUksQ0FBQyxHQUFHLFdBQVcsQ0FBQztvQ0FDakQsSUFBSSxLQUFLLEdBQUcsQ0FBQyxJQUFJLEtBQUssSUFBSSxRQUFRLENBQUMsUUFBUTt3Q0FDdkMsSUFBSSxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsS0FBSyxLQUFLLEVBQUU7d0NBQy9CLFNBQVM7cUNBQ1Y7b0NBRUQsTUFBTSxNQUFNLEdBQUcsb0JBQW9CLEdBQUcscUJBQXFCO3dDQUNuRCxvQkFBb0I7d0NBQ3hCLENBQUM7d0NBQ0EsU0FBUyxDQUFDLEdBQUcsQ0FBQyxLQUFLLEVBQUUsT0FBTyxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUUsT0FBTyxDQUM1QyxDQUFDO29DQUNiLE1BQU0sTUFBTSxHQUNSLE1BQU0sR0FBRyxxQkFBcUIsR0FBRyxvQkFBb0I7d0NBQ3JELElBQUksR0FBRyxvQkFBb0IsR0FBRyxJQUFJLENBQUM7b0NBRXZDLE1BQU0sSUFBSSxHQUFHLE1BQU0sS0FBSyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO29DQUN2QyxJQUFJLElBQUksS0FBSyxDQUFDLEVBQUU7d0NBQ2QsU0FBUztxQ0FDVjtvQ0FFRCxNQUFNLEtBQUssR0FDUCxLQUFLLENBQUMsR0FBRyxDQUFDLEtBQUssRUFBRSxPQUFPLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxPQUFPLENBQUMsQ0FBQztvQ0FDckQsT0FBTyxJQUFJLEtBQUssR0FBRyxJQUFJLENBQUM7aUNBQ3pCOzZCQUNGO3lCQUNGO3dCQUNELEVBQUUsQ0FBQyxHQUFHLENBQUMsT0FBTyxFQUFFLEtBQUssRUFBRSxPQUFPLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxPQUFPLENBQUMsQ0FBQztxQkFDeEQ7aUJBQ0Y7YUFDRjtTQUNGO0tBQ0Y7SUFFRCxPQUFPLE9BQU8sQ0FBQyxjQUFjLENBQUMsRUFBRSxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxNQUFNLENBQUMsQ0FBQztBQUMvRCxDQUFDO0FBRUQsTUFBTSxDQUFDLE1BQU0sbUJBQW1CLEdBQWlCO0lBQy9DLFVBQVUsRUFBRSxhQUFhO0lBQ3pCLFdBQVcsRUFBRSxLQUFLO0lBQ2xCLFVBQVUsRUFBRSxhQUFzQztDQUNuRCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBAbGljZW5zZVxuICogQ29weXJpZ2h0IDIwMjAgR29vZ2xlIExMQy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cbiAqIExpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSBcIkxpY2Vuc2VcIik7XG4gKiB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuXG4gKiBZb3UgbWF5IG9idGFpbiBhIGNvcHkgb2YgdGhlIExpY2Vuc2UgYXRcbiAqXG4gKiBodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvTElDRU5TRS0yLjBcbiAqXG4gKiBVbmxlc3MgcmVxdWlyZWQgYnkgYXBwbGljYWJsZSBsYXcgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNvZnR3YXJlXG4gKiBkaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiBcIkFTIElTXCIgQkFTSVMsXG4gKiBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC5cbiAqIFNlZSB0aGUgTGljZW5zZSBmb3IgdGhlIHNwZWNpZmljIGxhbmd1YWdlIGdvdmVybmluZyBwZXJtaXNzaW9ucyBhbmRcbiAqIGxpbWl0YXRpb25zIHVuZGVyIHRoZSBMaWNlbnNlLlxuICogPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAqL1xuXG5pbXBvcnQge2JhY2tlbmRfdXRpbCwgYnVmZmVyLCBLZXJuZWxDb25maWcsIEtlcm5lbEZ1bmMsIE1heFBvb2wzREdyYWQsIE1heFBvb2wzREdyYWRBdHRycywgTWF4UG9vbDNER3JhZElucHV0cywgUmFuaywgVGVuc29ySW5mb30gZnJvbSAnQHRlbnNvcmZsb3cvdGZqcy1jb3JlJztcblxuaW1wb3J0IHtNYXRoQmFja2VuZENQVX0gZnJvbSAnLi4vYmFja2VuZF9jcHUnO1xuaW1wb3J0IHthc3NlcnROb3RDb21wbGV4fSBmcm9tICcuLi9jcHVfdXRpbCc7XG5pbXBvcnQge21heFBvb2wzZFBvc2l0aW9uc30gZnJvbSAnLi4vdXRpbHMvcG9vbF91dGlscyc7XG5cbmV4cG9ydCBmdW5jdGlvbiBtYXhQb29sM0RHcmFkKGFyZ3M6IHtcbiAgaW5wdXRzOiBNYXhQb29sM0RHcmFkSW5wdXRzLFxuICBiYWNrZW5kOiBNYXRoQmFja2VuZENQVSxcbiAgYXR0cnM6IE1heFBvb2wzREdyYWRBdHRyc1xufSk6IFRlbnNvckluZm8ge1xuICBjb25zdCB7aW5wdXRzLCBiYWNrZW5kLCBhdHRyc30gPSBhcmdzO1xuICBjb25zdCB7ZHksIGlucHV0fSA9IGlucHV0cztcbiAgY29uc3Qge2ZpbHRlclNpemUsIHN0cmlkZXMsIHBhZCwgZGltUm91bmRpbmdNb2RlfSA9IGF0dHJzO1xuXG4gIGFzc2VydE5vdENvbXBsZXgoW2R5LCBpbnB1dF0sICdtYXhQb29sM0RHcmFkJyk7XG5cbiAgY29uc3QgY29udkluZm8gPSBiYWNrZW5kX3V0aWwuY29tcHV0ZVBvb2wzREluZm8oXG4gICAgICBpbnB1dC5zaGFwZSBhcyBbbnVtYmVyLCBudW1iZXIsIG51bWJlciwgbnVtYmVyLCBudW1iZXJdLCBmaWx0ZXJTaXplLFxuICAgICAgc3RyaWRlcywgMSAvKiBkaWxhdGlvbnMgKi8sIHBhZCwgZGltUm91bmRpbmdNb2RlKTtcblxuICBjb25zdCBpbnB1dEJ1ZiA9IGJhY2tlbmQuYnVmZmVyU3luYyhpbnB1dCk7XG4gIGNvbnN0IG1heFBvc0J1ZiA9IG1heFBvb2wzZFBvc2l0aW9ucyhpbnB1dEJ1ZiwgY29udkluZm8pO1xuICBjb25zdCBzdHJpZGVEZXB0aCA9IGNvbnZJbmZvLnN0cmlkZURlcHRoO1xuICBjb25zdCBzdHJpZGVIZWlnaHQgPSBjb252SW5mby5zdHJpZGVIZWlnaHQ7XG4gIGNvbnN0IHN0cmlkZVdpZHRoID0gY29udkluZm8uc3RyaWRlV2lkdGg7XG4gIGNvbnN0IGRpbGF0aW9uRGVwdGggPSBjb252SW5mby5kaWxhdGlvbkRlcHRoO1xuICBjb25zdCBkaWxhdGlvbkhlaWdodCA9IGNvbnZJbmZvLmRpbGF0aW9uSGVpZ2h0O1xuICBjb25zdCBkaWxhdGlvbldpZHRoID0gY29udkluZm8uZGlsYXRpb25XaWR0aDtcbiAgY29uc3QgZWZmZWN0aXZlRmlsdGVyRGVwdGggPSBjb252SW5mby5lZmZlY3RpdmVGaWx0ZXJEZXB0aDtcbiAgY29uc3QgZWZmZWN0aXZlRmlsdGVySGVpZ2h0ID0gY29udkluZm8uZWZmZWN0aXZlRmlsdGVySGVpZ2h0O1xuICBjb25zdCBlZmZlY3RpdmVGaWx0ZXJXaWR0aCA9IGNvbnZJbmZvLmVmZmVjdGl2ZUZpbHRlcldpZHRoO1xuICBjb25zdCBwYWRGcm9udCA9IGVmZmVjdGl2ZUZpbHRlckRlcHRoIC0gMSAtIGNvbnZJbmZvLnBhZEluZm8uZnJvbnQ7XG4gIGNvbnN0IHBhZExlZnQgPSBlZmZlY3RpdmVGaWx0ZXJXaWR0aCAtIDEgLSBjb252SW5mby5wYWRJbmZvLmxlZnQ7XG4gIGNvbnN0IHBhZFRvcCA9IGVmZmVjdGl2ZUZpbHRlckhlaWdodCAtIDEgLSBjb252SW5mby5wYWRJbmZvLnRvcDtcbiAgY29uc3QgZHggPSBidWZmZXIoaW5wdXQuc2hhcGUsICdmbG9hdDMyJyk7XG5cbiAgY29uc3QgZHlCdWYgPSBiYWNrZW5kLmJ1ZmZlclN5bmM8UmFuaywgJ2Zsb2F0MzInPihkeSk7XG5cbiAgZm9yIChsZXQgYmF0Y2ggPSAwOyBiYXRjaCA8IGNvbnZJbmZvLmJhdGNoU2l6ZTsgKytiYXRjaCkge1xuICAgIGZvciAobGV0IGNoYW5uZWwgPSAwOyBjaGFubmVsIDwgY29udkluZm8uaW5DaGFubmVsczsgKytjaGFubmVsKSB7XG4gICAgICBmb3IgKGxldCBkeERlcHRoID0gMDsgZHhEZXB0aCA8IGNvbnZJbmZvLmluRGVwdGg7ICsrZHhEZXB0aCkge1xuICAgICAgICBmb3IgKGxldCBkeFJvdyA9IDA7IGR4Um93IDwgY29udkluZm8uaW5IZWlnaHQ7ICsrZHhSb3cpIHtcbiAgICAgICAgICBmb3IgKGxldCBkeENvbCA9IDA7IGR4Q29sIDwgY29udkluZm8uaW5XaWR0aDsgKytkeENvbCkge1xuICAgICAgICAgICAgLy8gU2hhZGVyIGNvZGUgYmVnaW5zXG4gICAgICAgICAgICBjb25zdCBkeURlcHRoQ29ybmVyID0gZHhEZXB0aCAtIHBhZEZyb250O1xuICAgICAgICAgICAgY29uc3QgZHlSb3dDb3JuZXIgPSBkeFJvdyAtIHBhZFRvcDtcbiAgICAgICAgICAgIGNvbnN0IGR5Q29sQ29ybmVyID0gZHhDb2wgLSBwYWRMZWZ0O1xuICAgICAgICAgICAgbGV0IGRvdFByb2QgPSAwO1xuICAgICAgICAgICAgZm9yIChsZXQgd0RlcHRoID0gMDsgd0RlcHRoIDwgZWZmZWN0aXZlRmlsdGVyRGVwdGg7XG4gICAgICAgICAgICAgICAgIHdEZXB0aCArPSBkaWxhdGlvbkRlcHRoKSB7XG4gICAgICAgICAgICAgIGNvbnN0IGR5RGVwdGggPSAoZHlEZXB0aENvcm5lciArIHdEZXB0aCkgLyBzdHJpZGVEZXB0aDtcbiAgICAgICAgICAgICAgaWYgKGR5RGVwdGggPCAwIHx8IGR5RGVwdGggPj0gY29udkluZm8ub3V0RGVwdGggfHxcbiAgICAgICAgICAgICAgICAgIE1hdGguZmxvb3IoZHlEZXB0aCkgIT09IGR5RGVwdGgpIHtcbiAgICAgICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICBmb3IgKGxldCB3Um93ID0gMDsgd1JvdyA8IGVmZmVjdGl2ZUZpbHRlckhlaWdodDtcbiAgICAgICAgICAgICAgICAgICB3Um93ICs9IGRpbGF0aW9uSGVpZ2h0KSB7XG4gICAgICAgICAgICAgICAgY29uc3QgZHlSb3cgPSAoZHlSb3dDb3JuZXIgKyB3Um93KSAvIHN0cmlkZUhlaWdodDtcbiAgICAgICAgICAgICAgICBpZiAoZHlSb3cgPCAwIHx8IGR5Um93ID49IGNvbnZJbmZvLm91dEhlaWdodCB8fFxuICAgICAgICAgICAgICAgICAgICBNYXRoLmZsb29yKGR5Um93KSAhPT0gZHlSb3cpIHtcbiAgICAgICAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBmb3IgKGxldCB3Q29sID0gMDsgd0NvbCA8IGVmZmVjdGl2ZUZpbHRlcldpZHRoO1xuICAgICAgICAgICAgICAgICAgICAgd0NvbCArPSBkaWxhdGlvbldpZHRoKSB7XG4gICAgICAgICAgICAgICAgICBjb25zdCBkeUNvbCA9IChkeUNvbENvcm5lciArIHdDb2wpIC8gc3RyaWRlV2lkdGg7XG4gICAgICAgICAgICAgICAgICBpZiAoZHlDb2wgPCAwIHx8IGR5Q29sID49IGNvbnZJbmZvLm91dFdpZHRoIHx8XG4gICAgICAgICAgICAgICAgICAgICAgTWF0aC5mbG9vcihkeUNvbCkgIT09IGR5Q29sKSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICBjb25zdCBtYXhQb3MgPSBlZmZlY3RpdmVGaWx0ZXJEZXB0aCAqIGVmZmVjdGl2ZUZpbHRlckhlaWdodCAqXG4gICAgICAgICAgICAgICAgICAgICAgICAgIGVmZmVjdGl2ZUZpbHRlcldpZHRoIC1cbiAgICAgICAgICAgICAgICAgICAgICAxIC1cbiAgICAgICAgICAgICAgICAgICAgICAobWF4UG9zQnVmLmdldChiYXRjaCwgZHlEZXB0aCwgZHlSb3csIGR5Q29sLCBjaGFubmVsKSBhc1xuICAgICAgICAgICAgICAgICAgICAgICBudW1iZXIpO1xuICAgICAgICAgICAgICAgICAgY29uc3QgY3VyUG9zID1cbiAgICAgICAgICAgICAgICAgICAgICB3RGVwdGggKiBlZmZlY3RpdmVGaWx0ZXJIZWlnaHQgKiBlZmZlY3RpdmVGaWx0ZXJXaWR0aCArXG4gICAgICAgICAgICAgICAgICAgICAgd1JvdyAqIGVmZmVjdGl2ZUZpbHRlcldpZHRoICsgd0NvbDtcblxuICAgICAgICAgICAgICAgICAgY29uc3QgbWFzayA9IG1heFBvcyA9PT0gY3VyUG9zID8gMSA6IDA7XG4gICAgICAgICAgICAgICAgICBpZiAobWFzayA9PT0gMCkge1xuICAgICAgICAgICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgY29uc3QgcGl4ZWwgPVxuICAgICAgICAgICAgICAgICAgICAgIGR5QnVmLmdldChiYXRjaCwgZHlEZXB0aCwgZHlSb3csIGR5Q29sLCBjaGFubmVsKTtcbiAgICAgICAgICAgICAgICAgIGRvdFByb2QgKz0gcGl4ZWwgKiBtYXNrO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZHguc2V0KGRvdFByb2QsIGJhdGNoLCBkeERlcHRoLCBkeFJvdywgZHhDb2wsIGNoYW5uZWwpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIHJldHVybiBiYWNrZW5kLm1ha2VUZW5zb3JJbmZvKGR4LnNoYXBlLCBkeC5kdHlwZSwgZHgudmFsdWVzKTtcbn1cblxuZXhwb3J0IGNvbnN0IG1heFBvb2wzREdyYWRDb25maWc6IEtlcm5lbENvbmZpZyA9IHtcbiAga2VybmVsTmFtZTogTWF4UG9vbDNER3JhZCxcbiAgYmFja2VuZE5hbWU6ICdjcHUnLFxuICBrZXJuZWxGdW5jOiBtYXhQb29sM0RHcmFkIGFzIHVua25vd24gYXMgS2VybmVsRnVuY1xufTtcbiJdfQ==