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
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
/**
 * @license
 * Copyright 2021 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 { Transform, util } from '@tensorflow/tfjs-core';
export function transform(args) {
    const { inputs, attrs, backend } = args;
    const { image, transforms } = inputs;
    const { interpolation, fillMode, fillValue, outputShape } = attrs;
    const [batch, imageHeight, imageWidth, numChannels] = image.shape;
    const [outHeight, outWidth] = outputShape != null ? outputShape : [imageHeight, imageWidth];
    const outShape = [batch, outHeight, outWidth, numChannels];
    const inStrides = util.computeStrides(image.shape);
    const batchInStride = inStrides[0];
    const rowInStride = inStrides[1];
    const colInStride = inStrides[2];
    const outStrides = util.computeStrides(outShape);
    const batchOutStride = outStrides[0];
    const rowOutStride = outStrides[1];
    const colOutStride = outStrides[2];
    const outVals = util.getTypedArrayFromDType(image.dtype, util.sizeFromShape(outShape));
    outVals.fill(fillValue);
    const imageVals = backend.data.get(image.dataId).values;
    const transformVals = backend.data.get(transforms.dataId).values;
    // Ref TF implementation:
    // https://github.com/tensorflow/tensorflow/blob/master/tensorflow/core/kernels/image/image_ops.h
    for (let b = 0; b < batch; ++b) {
        const transform = transforms.shape[0] === 1 ?
            transformVals :
            transformVals.subarray(b * 8, b * 8 + 8);
        for (let outY = 0; outY < outHeight; ++outY) {
            for (let outX = 0; outX < outWidth; ++outX) {
                for (let channel = 0; channel < numChannels; ++channel) {
                    let val;
                    const projection = transform[6] * outX + transform[7] * outY + 1;
                    if (projection === 0) {
                        // Return the fill value for infinite coordinates,
                        // which are outside the input image
                        continue;
                    }
                    const inX = (transform[0] * outX + transform[1] * outY + transform[2]) /
                        projection;
                    const inY = (transform[3] * outX + transform[4] * outY + transform[5]) /
                        projection;
                    const x = mapCoord(inX, imageWidth, fillMode);
                    const y = mapCoord(inY, imageHeight, fillMode);
                    switch (interpolation) {
                        case 'nearest':
                            val = nearestInterpolation(imageVals, imageHeight, imageWidth, batchInStride, rowInStride, colInStride, b, y, x, channel, fillValue);
                            break;
                        case 'bilinear':
                            val = bilinearInterpolation(imageVals, imageHeight, imageWidth, batchInStride, rowInStride, colInStride, b, y, x, channel, fillValue);
                            break;
                        default:
                            throw new Error(`Error in Transform: Expect 'nearest' or ` +
                                `'bilinear', but got ${interpolation}`);
                    }
                    const ind = b * batchOutStride + outY * rowOutStride +
                        outX * colOutStride + channel;
                    outVals[ind] = val;
                }
            }
        }
        return backend.makeTensorInfo(outShape, image.dtype, outVals);
    }
    const dataId = backend.write(outVals, outShape, image.dtype);
    return { dataId, shape: image.shape, dtype: image.dtype };
}
export const transformConfig = {
    kernelName: Transform,
    backendName: 'cpu',
    kernelFunc: transform
};
function mapCoord(outCoord, len, mode) {
    switch (mode) {
        case 'reflect':
            return mapCoordReflect(outCoord, len);
        case 'wrap':
            return mapCoordWrap(outCoord, len);
        case 'nearest':
            return mapCoordNearest(outCoord, len);
        case 'constant':
        default:
            return mapCoordConstant(outCoord, len);
    }
}
function mapCoordReflect(outCoord, len) {
    // Reflect [abcd] to [dcba|abcd|dcba].
    let inCoord = outCoord;
    if (inCoord < 0) {
        if (len <= 1) {
            inCoord = 0;
        }
        else {
            const sz2 = 2 * len;
            if (inCoord < sz2) {
                inCoord = sz2 * Math.trunc(-inCoord / sz2) + inCoord;
            }
            inCoord = inCoord < -len ? inCoord + sz2 : -inCoord - 1;
        }
    }
    else if (inCoord > len - 1) {
        if (len <= 1) {
            inCoord = 0;
        }
        else {
            const sz2 = 2 * len;
            inCoord -= sz2 * Math.trunc(inCoord / sz2);
            if (inCoord >= len) {
                inCoord = sz2 - inCoord - 1;
            }
        }
    }
    // clamp is necessary because when outCoord = 3.5 and len = 4,
    // inCoord = 3.5 and will be rounded to 4 in nearest interpolation.
    return util.clamp(0, inCoord, len - 1);
}
function mapCoordWrap(outCoord, len) {
    // Wrap [abcd] to [abcd|abcd|abcd].
    let inCoord = outCoord;
    if (inCoord < 0) {
        if (len <= 1) {
            inCoord = 0;
        }
        else {
            const sz = len - 1;
            inCoord += len * (Math.trunc(-inCoord / sz) + 1);
        }
    }
    else if (inCoord > len - 1) {
        if (len <= 1) {
            inCoord = 0;
        }
        else {
            const sz = len - 1;
            inCoord -= len * Math.trunc(inCoord / sz);
        }
    }
    // clamp is necessary because when outCoord = -0.5 and len = 4,
    // inCoord = 3.5 and will be rounded to 4 in nearest interpolation.
    return util.clamp(0, inCoord, len - 1);
}
function mapCoordConstant(outCoord, len) {
    return outCoord;
}
function mapCoordNearest(outCoord, len) {
    return util.clamp(0, outCoord, len - 1);
}
function readWithFillValue(imageVals, imageHeight, imageWidth, batchStride, rowStride, colStride, batch, y, x, channel, fillValue) {
    const ind = batch * batchStride + y * rowStride + x * colStride + channel;
    if (0 <= y && y < imageHeight && 0 <= x && x < imageWidth) {
        return imageVals[ind];
    }
    else {
        return fillValue;
    }
}
function nearestInterpolation(imageVals, imageHeight, imageWidth, batchStride, rowStride, colStride, batch, y, x, channel, fillValue) {
    const $y = Math.round(y);
    const $x = Math.round(x);
    return readWithFillValue(imageVals, imageHeight, imageWidth, batchStride, rowStride, colStride, batch, $y, $x, channel, fillValue);
}
function bilinearInterpolation(imageVals, imageHeight, imageWidth, batchStride, rowStride, colStride, batch, y, x, channel, fillValue) {
    const yFloor = Math.floor(y);
    const xFloor = Math.floor(x);
    const yCeil = yFloor + 1;
    const xCeil = xFloor + 1;
    // f(x, yFloor) = (xCeil - x) / (xCeil - xFloor) * f(xFloor, yFloor)
    //               + (x - xFloor) / (xCeil - xFloor) * f(xCeil, yFloor)
    const valueYFloor = (xCeil - x) *
        readWithFillValue(imageVals, imageHeight, imageWidth, batchStride, rowStride, colStride, batch, yFloor, xFloor, channel, fillValue) +
        (x - xFloor) *
            readWithFillValue(imageVals, imageHeight, imageWidth, batchStride, rowStride, colStride, batch, yFloor, xCeil, channel, fillValue);
    // f(x, yCeil) = (xCeil - x) / (xCeil - xFloor) * f(xFloor, yCeil)
    //             + (x - xFloor) / (xCeil - xFloor) * f(xCeil, yCeil)
    const valueYCeil = (xCeil - x) *
        readWithFillValue(imageVals, imageHeight, imageWidth, batchStride, rowStride, colStride, batch, yCeil, xFloor, channel, fillValue) +
        (x - xFloor) *
            readWithFillValue(imageVals, imageHeight, imageWidth, batchStride, rowStride, colStride, batch, yCeil, xCeil, channel, fillValue);
    // f(x, y) = (yCeil - y) / (yCeil - yFloor) * f(x, yFloor)
    //         + (y - yFloor) / (yCeil - yFloor) * f(x, yCeil)
    return (yCeil - y) * valueYFloor + (y - yFloor) * valueYCeil;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiVHJhbnNmb3JtLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vdGZqcy1iYWNrZW5kLWNwdS9zcmMva2VybmVscy9UcmFuc2Zvcm0udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7Ozs7OztHQWVHO0FBRUgsT0FBTyxFQUF3RCxTQUFTLEVBQStDLElBQUksRUFBQyxNQUFNLHVCQUF1QixDQUFDO0FBSTFKLE1BQU0sVUFBVSxTQUFTLENBQUMsSUFJekI7SUFDQyxNQUFNLEVBQUMsTUFBTSxFQUFFLEtBQUssRUFBRSxPQUFPLEVBQUMsR0FBRyxJQUFJLENBQUM7SUFDdEMsTUFBTSxFQUFDLEtBQUssRUFBRSxVQUFVLEVBQUMsR0FBRyxNQUFNLENBQUM7SUFDbkMsTUFBTSxFQUFDLGFBQWEsRUFBRSxRQUFRLEVBQUUsU0FBUyxFQUFFLFdBQVcsRUFBQyxHQUFHLEtBQUssQ0FBQztJQUVoRSxNQUFNLENBQUMsS0FBSyxFQUFFLFdBQVcsRUFBRSxVQUFVLEVBQUUsV0FBVyxDQUFDLEdBQUcsS0FBSyxDQUFDLEtBQUssQ0FBQztJQUNsRSxNQUFNLENBQUMsU0FBUyxFQUFFLFFBQVEsQ0FBQyxHQUN2QixXQUFXLElBQUksSUFBSSxDQUFDLENBQUMsQ0FBQyxXQUFXLENBQUMsQ0FBQyxDQUFDLENBQUMsV0FBVyxFQUFFLFVBQVUsQ0FBQyxDQUFDO0lBQ2xFLE1BQU0sUUFBUSxHQUFHLENBQUMsS0FBSyxFQUFFLFNBQVMsRUFBRSxRQUFRLEVBQUUsV0FBVyxDQUFDLENBQUM7SUFFM0QsTUFBTSxTQUFTLEdBQUcsSUFBSSxDQUFDLGNBQWMsQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDLENBQUM7SUFDbkQsTUFBTSxhQUFhLEdBQUcsU0FBUyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ25DLE1BQU0sV0FBVyxHQUFHLFNBQVMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUNqQyxNQUFNLFdBQVcsR0FBRyxTQUFTLENB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RSxTQUFTLEVBQzFELFNBQVMsRUFBRSxLQUFLLEVBQUUsS0FBSyxFQUFFLE1BQU0sRUFBRSxPQUFPLEVBQUUsU0FBUyxDQUFDO1FBQzVELENBQUMsQ0FBQyxHQUFHLE1BQU0sQ0FBQztZQUNSLGlCQUFpQixDQUNiLFNBQVMsRUFBRSxXQUFXLEVBQUUsVUFBVSxFQUFFLFdBQVcsRUFBRSxTQUFTLEVBQzFELFNBQVMsRUFBRSxLQUFLLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxPQUFPLEVBQUUsU0FBUyxDQUFDLENBQUM7SUFDaEUsMERBQTBEO0lBQzFELDBEQUEwRDtJQUMxRCxPQUFPLENBQUMsS0FBSyxHQUFHLENBQUMsQ0FBQyxHQUFHLFdBQVcsR0FBRyxDQUFDLENBQUMsR0FBRyxNQUFNLENBQUMsR0FBRyxVQUFVLENBQUM7QUFDL0QsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQGxpY2Vuc2VcbiAqIENvcHlyaWdodCAyMDIxIEdvb2dsZSBMTEMuIEFsbCBSaWdodHMgUmVzZXJ2ZWQuXG4gKiBMaWNlbnNlZCB1bmRlciB0aGUgQXBhY2hlIExpY2Vuc2UsIFZlcnNpb24gMi4wICh0aGUgXCJMaWNlbnNlXCIpO1xuICogeW91IG1heSBub3QgdXNlIHRoaXMgZmlsZSBleGNlcHQgaW4gY29tcGxpYW5jZSB3aXRoIHRoZSBMaWNlbnNlLlxuICogWW91IG1heSBvYnRhaW4gYSBjb3B5IG9mIHRoZSBMaWNlbnNlIGF0XG4gKlxuICogaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wXG4gKlxuICogVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZVxuICogZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIExpY2Vuc2UgaXMgZGlzdHJpYnV0ZWQgb24gYW4gXCJBUyBJU1wiIEJBU0lTLFxuICogV0lUSE9VVCBXQVJSQU5USUVTIE9SIENPTkRJVElPTlMgT0YgQU5ZIEtJTkQsIGVpdGhlciBleHByZXNzIG9yIGltcGxpZWQuXG4gKiBTZWUgdGhlIExpY2Vuc2UgZm9yIHRoZSBzcGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnMgYW5kXG4gKiBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS5cbiAqID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gKi9cblxuaW1wb3J0IHtLZXJuZWxDb25maWcsIEtlcm5lbEZ1bmMsIE51bWVyaWNEYXRhVHlwZSwgVGVuc29ySW5mbywgVHJhbnNmb3JtLCBUcmFuc2Zvcm1BdHRycywgVHJhbnNmb3JtSW5wdXRzLCBUeXBlZEFycmF5LCB1dGlsfSBmcm9tICdAdGVuc29yZmxvdy90ZmpzLWNvcmUnO1xuXG5pbXBvcnQge01hdGhCYWNrZW5kQ1BVfSBmcm9tICcuLi9iYWNrZW5kX2NwdSc7XG5cbmV4cG9ydCBmdW5jdGlvbiB0cmFuc2Zvcm0oYXJnczoge1xuICBpbnB1dHM6IFRyYW5zZm9ybUlucHV0cyxcbiAgYXR0cnM6IFRyYW5zZm9ybUF0dHJzLFxuICBiYWNrZW5kOiBNYXRoQmFja2VuZENQVVxufSk6IFRlbnNvckluZm8ge1xuICBjb25zdCB7aW5wdXRzLCBhdHRycywgYmFja2VuZH0gPSBhcmdzO1xuICBjb25zdCB7aW1hZ2UsIHRyYW5zZm9ybXN9ID0gaW5wdXRzO1xuICBjb25zdCB7aW50ZXJwb2xhdGlvbiwgZmlsbE1vZGUsIGZpbGxWYWx1ZSwgb3V0cHV0U2hhcGV9ID0gYXR0cnM7XG5cbiAgY29uc3QgW2JhdGNoLCBpbWFnZUhlaWdodCwgaW1hZ2VXaWR0aCwgbnVtQ2hhbm5lbHNdID0gaW1hZ2Uuc2hhcGU7XG4gIGNvbnN0IFtvdXRIZWlnaHQsIG91dFdpZHRoXSA9XG4gICAgICBvdXRwdXRTaGFwZSAhPSBudWxsID8gb3V0cHV0U2hhcGUgOiBbaW1hZ2VIZWlnaHQsIGltYWdlV2lkdGhdO1xuICBjb25zdCBvdXRTaGFwZSA9IFtiYXRjaCwgb3V0SGVpZ2h0LCBvdXRXaWR0aCwgbnVtQ2hhbm5lbHNdO1xuXG4gIGNvbnN0IGluU3RyaWRlcyA9IHV0aWwuY29tcHV0ZVN0cmlkZXMoaW1hZ2Uuc2hhcGUpO1xuICBjb25zdCBiYXRjaEluU3RyaWRlID0gaW5TdHJpZGVzWzBdO1xuICBjb25zdCByb3dJblN0cmlkZSA9IGluU3RyaWRlc1sxXTtcbiAgY29uc3QgY29sSW5TdHJpZGUgPSBpblN0cmlkZXNbMl07XG5cbiAgY29uc3Qgb3V0U3RyaWRlcyA9IHV0aWwuY29tcHV0ZVN0cmlkZXMob3V0U2hhcGUpO1xuICBjb25zdCBiYXRjaE91dFN0cmlkZSA9IG91dFN0cmlkZXNbMF07XG4gIGNvbnN0IHJvd091dFN0cmlkZSA9IG91dFN0cmlkZXNbMV07XG4gIGNvbnN0IGNvbE91dFN0cmlkZSA9IG91dFN0cmlkZXNbMl07XG5cbiAgY29uc3Qgb3V0VmFscyA9IHV0aWwuZ2V0VHlwZWRBcnJheUZyb21EVHlwZShcbiAgICAgIGltYWdlLmR0eXBlIGFzIE51bWVyaWNEYXRhVHlwZSwgdXRpbC5zaXplRnJvbVNoYXBlKG91dFNoYXBlKSk7XG5cbiAgb3V0VmFscy5maWxsKGZpbGxWYWx1ZSk7XG5cbiAgY29uc3QgaW1hZ2VWYWxzID0gYmFja2VuZC5kYXRhLmdldChpbWFnZS5kYXRhSWQpLnZhbHVlcyBhcyBUeXBlZEFycmF5O1xuICBjb25zdCB0cmFuc2Zvcm1WYWxzID1cbiAgICAgIGJhY2tlbmQuZGF0YS5nZXQodHJhbnNmb3Jtcy5kYXRhSWQpLnZhbHVlcyBhcyBUeXBlZEFycmF5O1xuXG4gIC8vIFJlZiBURiBpbXBsZW1lbnRhdGlvbjpcbiAgLy8gaHR0cHM6Ly9naXRodWIuY29tL3RlbnNvcmZsb3cvdGVuc29yZmxvdy9ibG9iL21hc3Rlci90ZW5zb3JmbG93L2NvcmUva2VybmVscy9pbWFnZS9pbWFnZV9vcHMuaFxuICBmb3IgKGxldCBiID0gMDsgYiA8IGJhdGNoOyArK2IpIHtcbiAgICBjb25zdCB0cmFuc2Zvcm0gPSB0cmFuc2Zvcm1zLnNoYXBlWzBdID09PSAxID9cbiAgICAgICAgdHJhbnNmb3JtVmFscyA6XG4gICAgICAgIHRyYW5zZm9ybVZhbHMuc3ViYXJyYXkoYiAqIDgsIGIgKiA4ICsgOCk7XG5cbiAgICBmb3IgKGxldCBvdXRZID0gMDsgb3V0WSA8IG91dEhlaWdodDsgKytvdXRZKSB7XG4gICAgICBmb3IgKGxldCBvdXRYID0gMDsgb3V0WCA8IG91dFdpZHRoOyArK291dFgpIHtcbiAgICAgICAgZm9yIChsZXQgY2hhbm5lbCA9IDA7IGNoYW5uZWwgPCBudW1DaGFubmVsczsgKytjaGFubmVsKSB7XG4gICAgICAgICAgbGV0IHZhbDtcblxuICAgICAgICAgIGNvbnN0IHByb2plY3Rpb24gPSB0cmFuc2Zvcm1bNl0gKiBvdXRYICsgdHJhbnNmb3JtWzddICogb3V0WSArIDE7XG5cbiAgICAgICAgICBpZiAocHJvamVjdGlvbiA9PT0gMCkge1xuICAgICAgICAgICAgLy8gUmV0dXJuIHRoZSBmaWxsIHZhbHVlIGZvciBpbmZpbml0ZSBjb29yZGluYXRlcyxcbiAgICAgICAgICAgIC8vIHdoaWNoIGFyZSBvdXRzaWRlIHRoZSBpbnB1dCBpbWFnZVxuICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgY29uc3QgaW5YID1cbiAgICAgICAgICAgICAgKHRyYW5zZm9ybVswXSAqIG91dFggKyB0cmFuc2Zvcm1bMV0gKiBvdXRZICsgdHJhbnNmb3JtWzJdKSAvXG4gICAgICAgICAgICAgIHByb2plY3Rpb247XG4gICAgICAgICAgY29uc3QgaW5ZID1cbiAgICAgICAgICAgICAgKHRyYW5zZm9ybVszXSAqIG91dFggKyB0cmFuc2Zvcm1bNF0gKiBvdXRZICsgdHJhbnNmb3JtWzVdKSAvXG4gICAgICAgICAgICAgIHByb2plY3Rpb247XG5cbiAgICAgICAgICBjb25zdCB4ID0gbWFwQ29vcmQoaW5YLCBpbWFnZVdpZHRoLCBmaWxsTW9kZSk7XG4gICAgICAgICAgY29uc3QgeSA9IG1hcENvb3JkKGluWSwgaW1hZ2VIZWlnaHQsIGZpbGxNb2RlKTtcblxuICAgICAgICAgIHN3aXRjaCAoaW50ZXJwb2xhdGlvbikge1xuICAgICAgICAgICAgY2FzZSAnbmVhcmVzdCc6XG4gICAgICAgICAgICAgIHZhbCA9IG5lYXJlc3RJbnRlcnBvbGF0aW9uKFxuICAgICAgICAgICAgICAgICAgaW1hZ2VWYWxzLCBpbWFnZUhlaWdodCwgaW1hZ2VXaWR0aCwgYmF0Y2hJblN0cmlkZSxcbiAgICAgICAgICAgICAgICAgIHJvd0luU3RyaWRlLCBjb2xJblN0cmlkZSwgYiwgeSwgeCwgY2hhbm5lbCwgZmlsbFZhbHVlKTtcbiAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBjYXNlICdiaWxpbmVhcic6XG4gICAgICAgICAgICAgIHZhbCA9IGJpbGluZWFySW50ZXJwb2xhdGlvbihcbiAgICAgICAgICAgICAgICAgIGltYWdlVmFscywgaW1hZ2VIZWlnaHQsIGltYWdlV2lkdGgsIGJhdGNoSW5TdHJpZGUsXG4gICAgICAgICAgICAgICAgICByb3dJblN0cmlkZSwgY29sSW5TdHJpZGUsIGIsIHksIHgsIGNoYW5uZWwsIGZpbGxWYWx1ZSk7XG4gICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAgICAgICAgICAgYEVycm9yIGluIFRyYW5zZm9ybTogRXhwZWN0ICduZWFyZXN0JyBvciBgICtcbiAgICAgICAgICAgICAgICAgIGAnYmlsaW5lYXInLCBidXQgZ290ICR7aW50ZXJwb2xhdGlvbn1gKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBjb25zdCBpbmQgPVxuICAgICAgICAgICAgICBiICogYmF0Y2hPdXRTdHJpZGUgKyBvdXRZICogcm93T3V0U3RyaWRlICtcbiAgICAgICAgICAgICAgb3V0WCAqIGNvbE91dFN0cmlkZSArIGNoYW5uZWw7XG5cbiAgICAgICAgICBvdXRWYWxzW2luZF0gPSB2YWw7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gYmFja2VuZC5tYWtlVGVuc29ySW5mbyhvdXRTaGFwZSwgaW1hZ2UuZHR5cGUsIG91dFZhbHMpO1xuICB9XG5cbiAgY29uc3QgZGF0YUlkID0gYmFja2VuZC53cml0ZShvdXRWYWxzLCBvdXRTaGFwZSwgaW1hZ2UuZHR5cGUpO1xuICByZXR1cm4ge2RhdGFJZCwgc2hhcGU6IGltYWdlLnNoYXBlLCBkdHlwZTogaW1hZ2UuZHR5cGV9O1xufVxuXG5leHBvcnQgY29uc3QgdHJhbnNmb3JtQ29uZmlnOiBLZXJuZWxDb25maWcgPSB7XG4gIGtlcm5lbE5hbWU6IFRyYW5zZm9ybSxcbiAgYmFja2VuZE5hbWU6ICdjcHUnLFxuICBrZXJuZWxGdW5jOiB0cmFuc2Zvcm0gYXMgdW5rbm93biBhcyBLZXJuZWxGdW5jXG59O1xuXG5mdW5jdGlvbiBtYXBDb29yZChcbiAgICBvdXRDb29yZDogbnVtYmVyLCBsZW46IG51bWJlcixcbiAgICBtb2RlOiAnY29uc3RhbnQnfCdyZWZsZWN0J3wnd3JhcCd8J25lYXJlc3QnKSB7XG4gIHN3aXRjaCAobW9kZSkge1xuICAgIGNhc2UgJ3JlZmxlY3QnOlxuICAgICAgcmV0dXJuIG1hcENvb3JkUmVmbGVjdChvdXRDb29yZCwgbGVuKTtcbiAgICBjYXNlICd3cmFwJzpcbiAgICAgIHJldHVybiBtYXBDb29yZFdyYXAob3V0Q29vcmQsIGxlbik7XG4gICAgY2FzZSAnbmVhcmVzdCc6XG4gICAgICByZXR1cm4gbWFwQ29vcmROZWFyZXN0KG91dENvb3JkLCBsZW4pO1xuICAgIGNhc2UgJ2NvbnN0YW50JzpcbiAgICBkZWZhdWx0OlxuICAgICAgcmV0dXJuIG1hcENvb3JkQ29uc3RhbnQob3V0Q29vcmQsIGxlbik7XG4gIH1cbn1cblxuZnVuY3Rpb24gbWFwQ29vcmRSZWZsZWN0KG91dENvb3JkOiBudW1iZXIsIGxlbjogbnVtYmVyKTogbnVtYmVyIHtcbiAgLy8gUmVmbGVjdCBbYWJjZF0gdG8gW2RjYmF8YWJjZHxkY2JhXS5cbiAgbGV0IGluQ29vcmQgPSBvdXRDb29yZDtcbiAgaWYgKGluQ29vcmQgPCAwKSB7XG4gICAgaWYgKGxlbiA8PSAxKSB7XG4gICAgICBpbkNvb3JkID0gMDtcbiAgICB9IGVsc2Uge1xuICAgICAgY29uc3Qgc3oyID0gMiAqIGxlbjtcbiAgICAgIGlmIChpbkNvb3JkIDwgc3oyKSB7XG4gICAgICAgIGluQ29vcmQgPSBzejIgKiBNYXRoLnRydW5jKC1pbkNvb3JkIC8gc3oyKSArIGluQ29vcmQ7XG4gICAgICB9XG4gICAgICBpbkNvb3JkID0gaW5Db29yZCA8IC1sZW4gPyBpbkNvb3JkICsgc3oyIDogLWluQ29vcmQgLSAxO1xuICAgIH1cbiAgfSBlbHNlIGlmIChpbkNvb3JkID4gbGVuIC0gMSkge1xuICAgIGlmIChsZW4gPD0gMSkge1xuICAgICAgaW5Db29yZCA9IDA7XG4gICAgfSBlbHNlIHtcbiAgICAgIGNvbnN0IHN6MiA9IDIgKiBsZW47XG4gICAgICBpbkNvb3JkIC09IHN6MiAqIE1hdGgudHJ1bmMoaW5Db29yZCAvIHN6Mik7XG4gICAgICBpZiAoaW5Db29yZCA+PSBsZW4pIHtcbiAgICAgICAgaW5Db29yZCA9IHN6MiAtIGluQ29vcmQgLSAxO1xuICAgICAgfVxuICAgIH1cbiAgfVxuICAvLyBjbGFtcCBpcyBuZWNlc3NhcnkgYmVjYXVzZSB3aGVuIG91dENvb3JkID0gMy41IGFuZCBsZW4gPSA0LFxuICAvLyBpbkNvb3JkID0gMy41IGFuZCB3aWxsIGJlIHJvdW5kZWQgdG8gNCBpbiBuZWFyZXN0IGludGVycG9sYXRpb24uXG4gIHJldHVybiB1dGlsLmNsYW1wKDAsIGluQ29vcmQsIGxlbiAtIDEpO1xufVxuXG5mdW5jdGlvbiBtYXBDb29yZFdyYXAob3V0Q29vcmQ6IG51bWJlciwgbGVuOiBudW1iZXIpOiBudW1iZXIge1xuICAvLyBXcmFwIFthYmNkXSB0byBbYWJjZHxhYmNkfGFiY2RdLlxuICBsZXQgaW5Db29yZCA9IG91dENvb3JkO1xuICBpZiAoaW5Db29yZCA8IDApIHtcbiAgICBpZiAobGVuIDw9IDEpIHtcbiAgICAgIGluQ29vcmQgPSAwO1xuICAgIH0gZWxzZSB7XG4gICAgICBjb25zdCBzeiA9IGxlbiAtIDE7XG4gICAgICBpbkNvb3JkICs9IGxlbiAqIChNYXRoLnRydW5jKC1pbkNvb3JkIC8gc3opICsgMSk7XG4gICAgfVxuICB9IGVsc2UgaWYgKGluQ29vcmQgPiBsZW4gLSAxKSB7XG4gICAgaWYgKGxlbiA8PSAxKSB7XG4gICAgICBpbkNvb3JkID0gMDtcbiAgICB9IGVsc2Uge1xuICAgICAgY29uc3Qgc3ogPSBsZW4gLSAxO1xuICAgICAgaW5Db29yZCAtPSBsZW4gKiBNYXRoLnRydW5jKGluQ29vcmQgLyBzeik7XG4gICAgfVxuICB9XG4gIC8vIGNsYW1wIGlzIG5lY2Vzc2FyeSBiZWNhdXNlIHdoZW4gb3V0Q29vcmQgPSAtMC41IGFuZCBsZW4gPSA0LFxuICAvLyBpbkNvb3JkID0gMy41IGFuZCB3aWxsIGJlIHJvdW5kZWQgdG8gNCBpbiBuZWFyZXN0IGludGVycG9sYXRpb24uXG4gIHJldHVybiB1dGlsLmNsYW1wKDAsIGluQ29vcmQsIGxlbiAtIDEpO1xufVxuXG5mdW5jdGlvbiBtYXBDb29yZENvbnN0YW50KG91dENvb3JkOiBudW1iZXIsIGxlbjogbnVtYmVyKTogbnVtYmVyIHtcbiAgcmV0dXJuIG91dENvb3JkO1xufVxuXG5mdW5jdGlvbiBtYXBDb29yZE5lYXJlc3Qob3V0Q29vcmQ6IG51bWJlciwgbGVuOiBudW1iZXIpOiBudW1iZXIge1xuICByZXR1cm4gdXRpbC5jbGFtcCgwLCBvdXRDb29yZCwgbGVuIC0gMSk7XG59XG5cbmZ1bmN0aW9uIHJlYWRXaXRoRmlsbFZhbHVlKFxuICAgIGltYWdlVmFsczogVHlwZWRBcnJheSwgaW1hZ2VIZWlnaHQ6IG51bWJlciwgaW1hZ2VXaWR0aDogbnVtYmVyLFxuICAgIGJhdGNoU3RyaWRlOiBudW1iZXIsIHJvd1N0cmlkZTogbnVtYmVyLCBjb2xTdHJpZGU6IG51bWJlciwgYmF0Y2g6IG51bWJlcixcbiAgICB5OiBudW1iZXIsIHg6IG51bWJlciwgY2hhbm5lbDogbnVtYmVyLCBmaWxsVmFsdWU6IG51bWJlcik6IG51bWJlciB7XG4gIGNvbnN0IGluZCA9IGJhdGNoICogYmF0Y2hTdHJpZGUgKyB5ICogcm93U3RyaWRlICsgeCAqIGNvbFN0cmlkZSArIGNoYW5uZWw7XG4gIGlmICgwIDw9IHkgJiYgeSA8IGltYWdlSGVpZ2h0ICYmIDAgPD0geCAmJiB4IDwgaW1hZ2VXaWR0aCkge1xuICAgIHJldHVybiBpbWFnZVZhbHNbaW5kXTtcbiAgfSBlbHNlIHtcbiAgICByZXR1cm4gZmlsbFZhbHVlO1xuICB9XG59XG5cbmZ1bmN0aW9uIG5lYXJlc3RJbnRlcnBvbGF0aW9uKFxuICAgIGltYWdlVmFsczogVHlwZWRBcnJheSwgaW1hZ2VIZWlnaHQ6IG51bWJlciwgaW1hZ2VXaWR0aDogbnVtYmVyLFxuICAgIGJhdGNoU3RyaWRlOiBudW1iZXIsIHJvd1N0cmlkZTogbnVtYmVyLCBjb2xTdHJpZGU6IG51bWJlciwgYmF0Y2g6IG51bWJlcixcbiAgICB5OiBudW1iZXIsIHg6IG51bWJlciwgY2hhbm5lbDogbnVtYmVyLCBmaWxsVmFsdWU6IG51bWJlcik6IG51bWJlciB7XG4gIGNvbnN0ICR5ID0gTWF0aC5yb3VuZCh5KTtcbiAgY29uc3QgJHggPSBNYXRoLnJvdW5kKHgpO1xuXG4gIHJldHVybiByZWFkV2l0aEZpbGxWYWx1ZShcbiAgICAgIGltYWdlVmFscywgaW1hZ2VIZWlnaHQsIGltYWdlV2lkdGgsIGJhdGNoU3RyaWRlLCByb3dTdHJpZGUsIGNvbFN0cmlkZSxcbiAgICAgIGJhdGNoLCAkeSwgJHgsIGNoYW5uZWwsIGZpbGxWYWx1ZSk7XG59XG5cbmZ1bmN0aW9uIGJpbGluZWFySW50ZXJwb2xhdGlvbihcbiAgICBpbWFnZVZhbHM6IFR5cGVkQXJyYXksIGltYWdlSGVpZ2h0OiBudW1iZXIsIGltYWdlV2lkdGg6IG51bWJlcixcbiAgICBiYXRjaFN0cmlkZTogbnVtYmVyLCByb3dTdHJpZGU6IG51bWJlciwgY29sU3RyaWRlOiBudW1iZXIsIGJhdGNoOiBudW1iZXIsXG4gICAgeTogbnVtYmVyLCB4OiBudW1iZXIsIGNoYW5uZWw6IG51bWJlciwgZmlsbFZhbHVlOiBudW1iZXIpIHtcbiAgY29uc3QgeUZsb29yID0gTWF0aC5mbG9vcih5KTtcbiAgY29uc3QgeEZsb29yID0gTWF0aC5mbG9vcih4KTtcbiAgY29uc3QgeUNlaWwgPSB5Rmxvb3IgKyAxO1xuICBjb25zdCB4Q2VpbCA9IHhGbG9vciArIDE7XG4gIC8vIGYoeCwgeUZsb29yKSA9ICh4Q2VpbCAtIHgpIC8gKHhDZWlsIC0geEZsb29yKSAqIGYoeEZsb29yLCB5Rmxvb3IpXG4gIC8vICAgICAgICAgICAgICAgKyAoeCAtIHhGbG9vcikgLyAoeENlaWwgLSB4Rmxvb3IpICogZih4Q2VpbCwgeUZsb29yKVxuICBjb25zdCB2YWx1ZVlGbG9vciA9XG4gICAgICAoeENlaWwgLSB4KSAqXG4gICAgICAgICAgcmVhZFdpdGhGaWxsVmFsdWUoXG4gICAgICAgICAgICAgIGltYWdlVmFscywgaW1hZ2VIZWlnaHQsIGltYWdlV2lkdGgsIGJhdGNoU3RyaWRlLCByb3dTdHJpZGUsXG4gICAgICAgICAgICAgIGNvbFN0cmlkZSwgYmF0Y2gsIHlGbG9vciwgeEZsb29yLCBjaGFubmVsLCBmaWxsVmFsdWUpICtcbiAgICAgICh4IC0geEZsb29yKSAqXG4gICAgICAgICAgcmVhZFdpdGhGaWxsVmFsdWUoXG4gICAgICAgICAgICAgIGltYWdlVmFscywgaW1hZ2VIZWlnaHQsIGltYWdlV2lkdGgsIGJhdGNoU3RyaWRlLCByb3dTdHJpZGUsXG4gICAgICAgICAgICAgIGNvbFN0cmlkZSwgYmF0Y2gsIHlGbG9vciwgeENlaWwsIGNoYW5uZWwsIGZpbGxWYWx1ZSk7XG4gIC8vIGYoeCwgeUNlaWwpID0gKHhDZWlsIC0geCkgLyAoeENlaWwgLSB4Rmxvb3IpICogZih4Rmxvb3IsIHlDZWlsKVxuICAvLyAgICAgICAgICAgICArICh4IC0geEZsb29yKSAvICh4Q2VpbCAtIHhGbG9vcikgKiBmKHhDZWlsLCB5Q2VpbClcbiAgY29uc3QgdmFsdWVZQ2VpbCA9XG4gICAgICAoeENlaWwgLSB4KSAqXG4gICAgICAgICAgcmVhZFdpdGhGaWxsVmFsdWUoXG4gICAgICAgICAgICAgIGltYWdlVmFscywgaW1hZ2VIZWlnaHQsIGltYWdlV2lkdGgsIGJhdGNoU3RyaWRlLCByb3dTdHJpZGUsXG4gICAgICAgICAgICAgIGNvbFN0cmlkZSwgYmF0Y2gsIHlDZWlsLCB4Rmxvb3IsIGNoYW5uZWwsIGZpbGxWYWx1ZSkgK1xuICAgICAgKHggLSB4Rmxvb3IpICpcbiAgICAgICAgICByZWFkV2l0aEZpbGxWYWx1ZShcbiAgICAgICAgICAgICAgaW1hZ2VWYWxzLCBpbWFnZUhlaWdodCwgaW1hZ2VXaWR0aCwgYmF0Y2hTdHJpZGUsIHJvd1N0cmlkZSxcbiAgICAgICAgICAgICAgY29sU3RyaWRlLCBiYXRjaCwgeUNlaWwsIHhDZWlsLCBjaGFubmVsLCBmaWxsVmFsdWUpO1xuICAvLyBmKHgsIHkpID0gKHlDZWlsIC0geSkgLyAoeUNlaWwgLSB5Rmxvb3IpICogZih4LCB5Rmxvb3IpXG4gIC8vICAgICAgICAgKyAoeSAtIHlGbG9vcikgLyAoeUNlaWwgLSB5Rmxvb3IpICogZih4LCB5Q2VpbClcbiAgcmV0dXJuICh5Q2VpbCAtIHkpICogdmFsdWVZRmxvb3IgKyAoeSAtIHlGbG9vcikgKiB2YWx1ZVlDZWlsO1xufVxuIl19