UNPKG

@tensorflow/tfjs-core

Version:

Hardware-accelerated JavaScript library for machine intelligence

572 lines 83.2 kB
/** * @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 * as util from '../util'; const NEW_AXIS = -2; const SHRINK_AXIS = -1; export function assertParamsValid(input, begin, size) { const inputRank = input.shape.length; util.assert(inputRank === begin.length, () => `Error in slice${inputRank}D: Length of begin ${begin} must ` + `match the rank of the array (${inputRank}).`); util.assert(inputRank === size.length, () => `Error in slice${inputRank}D: Length of size ${size} must ` + `match the rank of the array (${inputRank}).`); for (let i = 0; i < inputRank; ++i) { util.assert(begin[i] + size[i] <= input.shape[i], () => `Error in slice${inputRank}D: begin[${i}] + size[${i}] ` + `(${begin[i] + size[i]}) would overflow input.shape[${i}] (${input.shape[i]})`); } } /** Converts a binary mask to an array of axes. Used in stridedSlice(). */ export function maskToAxes(mask) { const axes = []; let axis = 0; while (mask > 0) { if (mask & 1) { axes.push(axis); } mask /= 2; axis++; } return axes; } /** Computes the output shape given the strided slice params. */ export function computeOutShape(begin, end, strides) { const size = []; for (let axis = 0; axis < begin.length; axis++) { size[axis] = Math.ceil((end[axis] - begin[axis]) / strides[axis]); } return size; } // Creates full selection at the elided dimensions. If the dimension matches // the ellipsis mask, override the current stride value. Otherwise, insert. export function stridesWithElidedDims(strides, ellipsisInsertionIndex, numElidedAxes, inputShape) { const newStrides = [...strides]; for (let i = newStrides.length; i < inputShape.length; i++) { newStrides.push(1); } for (let i = 0; i < numElidedAxes; i++) { if (i === 0) { newStrides[ellipsisInsertionIndex] = 1; } else { newStrides.splice(ellipsisInsertionIndex, 0 /* num elements to delete */, 1 /* element to add */); newStrides.pop(); } } return newStrides; } function unnormalizeAxis(ellipsisInsertionIndex, numElidedAxes, normalizedAxis) { if (normalizedAxis <= ellipsisInsertionIndex) { return normalizedAxis; } return normalizedAxis - (numElidedAxes - 1); } function getElidedAxes(numElidedAxes, ellipsisInsertionIndex) { const elidedAxes = []; for (let i = 0; i < numElidedAxes; i++) { elidedAxes.push(ellipsisInsertionIndex + i); } return elidedAxes; } // Normalize the start, end and strides. export function getNormalizedAxes(inputShape, ellipsisAxes, numInterpolatedAxes, begin, end, strides, beginMask, endMask, ellipsisMask) { const inputRank = inputShape.length; let normalizedBegin = new Array(inputRank), normalizedEnd = new Array(inputRank), normalizedStrides = new Array(inputRank); if (ellipsisAxes.length && numInterpolatedAxes > 0) { const fullIndex = ellipsisAxes[0]; // The ellipsis applies to the masked index as well as any dimensions // that are interpolated. const numElidedAxes = numInterpolatedAxes + 1; normalizedBegin = startIndicesWithElidedDims(beginMask, fullIndex, numElidedAxes, begin, inputShape); normalizedEnd = stopIndicesWithElidedDims(endMask, fullIndex, numElidedAxes, end, inputShape); normalizedStrides = stridesWithElidedDims(strides, fullIndex, numElidedAxes, inputShape); } else { for (let axis = 0; axis < inputRank; axis++) { normalizedBegin[axis] = startForAxis(beginMask, begin, strides, inputShape, axis, ellipsisMask); normalizedEnd[axis] = stopForAxis(endMask, end, strides, inputShape, axis, ellipsisMask); normalizedStrides[axis] = stridesForAxis(strides, axis, ellipsisMask); } } return { begin: normalizedBegin, end: normalizedEnd, strides: normalizedStrides }; } // Creates full selection at the elided dimensions. If the dimension matches // the ellipsis mask, override the current start value. Otherwise, insert. export function startIndicesWithElidedDims(beginMask, ellipsisInsertionIndex, numElidedAxes, originalBegin, inputShape) { const newIndices = [...inputShape]; const elidedAxes = getElidedAxes(numElidedAxes, ellipsisInsertionIndex); for (let axis = 0; axis < newIndices.length; axis++) { if (elidedAxes.indexOf(axis) > -1) { newIndices[axis] = 0; } else { const originalAxis = unnormalizeAxis(ellipsisInsertionIndex, numElidedAxes, axis); let originalValue = originalBegin[originalAxis]; if (beginMask & 1 << originalAxis) { originalValue = 0; } newIndices[axis] = originalValue; } } return newIndices; } // Creates full selection at the elided dimensions. If the dimension matches // the ellipsis mask, override the current stop value. Otherwise, insert. export function stopIndicesWithElidedDims(endMask, ellipsisInsertionIndex, numElidedAxes, originalEnd, inputShape) { const newIndices = [...inputShape]; const elidedAxes = getElidedAxes(numElidedAxes, ellipsisInsertionIndex); for (let axis = 0; axis < newIndices.length; axis++) { if (elidedAxes.indexOf(axis) > -1) { newIndices[axis] = Number.MAX_SAFE_INTEGER; } else { const originalAxis = unnormalizeAxis(ellipsisInsertionIndex, numElidedAxes, axis); let originalValue = originalEnd[originalAxis]; if (endMask & 1 << originalAxis) { originalValue = Number.MAX_SAFE_INTEGER; } newIndices[axis] = originalValue; } } for (let i = 0; i < newIndices.length; i++) { // Handle negative indices const axisSize = inputShape[i]; if (newIndices[i] < 0) { newIndices[i] += axisSize; } newIndices[i] = util.clamp(0, newIndices[i], inputShape[i]); } return newIndices; } export function stridesForAxis(strides, axis, ellipsisMask) { let stride = strides[axis]; if (ellipsisMask & (1 << axis) || stride == null) { stride = 1; } return stride; } export function startForAxis(beginMask, startIndices, strides, inputShape, axis, ellipsisMask) { // Begin with the specified index let start = startIndices[axis]; const stride = strides[axis] || 1; // Check the axis bit from right of masked axes, or the begin index is not set // for the axis. if (beginMask & 1 << axis || ellipsisMask & 1 << axis || start == null) { if (stride > 0) { // Forward iteration - use the first element. These values will get // clamped below (Note: We could have set them to 0 and axis_size-1, but // use lowest() and max() to maintain symmetry with StopForAxis()) start = Number.MIN_SAFE_INTEGER; } else { // Backward iteration - use the last element. start = Number.MAX_SAFE_INTEGER; } } // Handle negative indices const axisSize = inputShape[axis]; if (start < 0) { start += axisSize; } // Clamping start = util.clamp(0, start, axisSize - 1); return start; } export function stopForAxis(endMask, stopIndices, strides, inputShape, axis, ellipsisMask) { // Begin with the specified index let stop = stopIndices[axis]; const stride = strides[axis] || 1; // Check the axis bit from right of masked axes, or if the stop index is not // set for this axis. if (endMask & (1 << axis) || ellipsisMask & (1 << axis) || stop == null) { if (stride > 0) { // Forward iteration - use the last element. These values will get // clamped below stop = Number.MAX_SAFE_INTEGER; } else { // Backward iteration - use the first element. stop = Number.MIN_SAFE_INTEGER; } } // Handle negative indices const axisSize = inputShape[axis]; if (stop < 0) { stop += axisSize; } // Clamping // Because the end index points one past the last element, we need slightly // different clamping ranges depending on the direction. if (stride > 0) { // Forward iteration stop = util.clamp(0, stop, axisSize); } else { // Backward iteration stop = util.clamp(-1, stop, axisSize - 1); } return stop; } /** * Returns true if the slice occupies a continous set of elements in the * 'flat' space. */ export function isSliceContinous(shape, begin, size) { // Index of the first axis that has size > 1. let firstNonOneAxis = size.length; for (let i = 0; i < size.length; i++) { if (size[i] > 1) { firstNonOneAxis = i; break; } } for (let i = firstNonOneAxis + 1; i < size.length; i++) { if (begin[i] > 0 || size[i] !== shape[i]) { return false; } } return true; } export function computeFlatOffset(begin, strides) { let flatOffset = begin.length > 0 ? begin[begin.length - 1] : 1; for (let i = 0; i < begin.length - 1; i++) { flatOffset += begin[i] * strides[i]; } return flatOffset; } export function parseSliceParams(x, begin, size) { // The following logic allows for more ergonomic calls. let begin_; const xRank = x.shape.length; if (typeof begin === 'number') { begin_ = [begin, ...new Array(xRank - 1).fill(0)]; } else if (begin.length < xRank) { begin_ = begin.concat(new Array(xRank - begin.length).fill(0)); } else { begin_ = begin.slice(); } begin_.forEach(d => { util.assert(d !== -1, () => 'slice() does not support negative begin indexing.'); }); let size_; if (size == null) { size_ = new Array(xRank).fill(-1); } else if (typeof size === 'number') { size_ = [size, ...new Array(xRank - 1).fill(-1)]; } else if (size.length < xRank) { size_ = size.concat(new Array(xRank - size.length).fill(-1)); } else { size_ = size; } size_ = size_.map((d, i) => { if (d >= 0) { return d; } else { util.assert(d === -1, () => `Negative size values should be exactly -1 but got ` + `${d} for the slice() size at index ${i}.`); return x.shape[i] - begin_[i]; } }); return [begin_, size_]; } // Convert the slicing specification from a sparse representation to a dense // representation. This means that all ellipses and newaxis are expanded out. export function sliceInfo(xShape, begin, end, strides, beginMask, endMask, ellipsisMask, newAxisMask, shrinkAxisMask) { let stridesNonNull; if (strides == null) { stridesNonNull = new Array(begin.length); stridesNonNull.fill(1); } else { stridesNonNull = strides; } // Only one non-zero bit is allowed in ellipsisMask, which means ellipsisMask // is a power of 2. Use bit compares to ensure ellipsisMask is 0 or a power // of 2. When i is a power of 2, i & (i - 1) is always 0. // Also ref: // https://stackoverflow.com/questions/600293/how-to-check-if-a-number-is-a-power-of-2 if (ellipsisMask != null && (ellipsisMask & (ellipsisMask - 1)) !== 0) { throw new Error('Multiple ellipses in slice is not allowed.'); } // Step 1: Account for ellipsis and new axis. // Check for ellipsis and count how many non-newaxis there are after. let ellipsisSeen = false; const sparseSpec = { dims: stridesNonNull.length, numAddAxisAfterEllipsis: 0, begin: begin.slice(), end: end.slice(), strides: stridesNonNull.slice(), beginMask, endMask, ellipsisMask, newAxisMask, shrinkAxisMask }; for (let i = 0; i < sparseSpec.dims; i++) { if (ellipsisSeen && ((1 << i) & newAxisMask) !== 0) { sparseSpec.numAddAxisAfterEllipsis++; } if ((1 << i) & ellipsisMask) { ellipsisSeen = true; } } // If no ellipsis insert one at the end. if (!ellipsisSeen) { sparseSpec.ellipsisMask |= (1 << sparseSpec.dims); sparseSpec.dims++; // this effects loop iteration below } // Step 2: Make a sparse spec into a full index spec. // // The sparse spec deos not correspond to the number of dimensions. // Make a dense spec that cooresponds to the number of dimensions. // // For example suppose foo[...,3:] on foo.shape = [2, 2, 3] then we need to // produce the missing beginMask for the first two dimensions i.e. from // beginMaskSpec = 0, endMaskSpec = 2, we achieve beginMask = 6 (110), // endMask = 7 (111). const denseSpec = { dims: xShape.length, beginMask: 0, endMask: 0, beginValid: false, endValid: false }; buildDenseSpec(sparseSpec, denseSpec); // Step 3: Make implicit ranges (non-zero beginMasks and endMasks) explicit // and bounds check. let isIdentity = true; let sliceDim0 = true; let isSimpleSlice = true; const processingShape = []; const finalShape = []; for (let i = 0; i < xShape.length; ++i) { if (denseSpec.strides[i] === 0) { throw Error(`strides[${i}] must be non-zero`); } const shrinkI = !!(denseSpec.shrinkAxisMask & (1 << i)); const dimI = xShape[i]; if (dimI === -1) { processingShape.push(shrinkI ? 1 : -1); continue; } const masks = [denseSpec.beginMask & (1 << i), denseSpec.endMask & (1 << i)]; const validRange = [ denseSpec.strides[i] > 0 ? 0 : -1, denseSpec.strides[i] > 0 ? dimI : dimI - 1 ]; if (shrinkI && denseSpec.strides[i] <= 0) { throw Error('only stride 1 allowed on non-range indexing.'); } isSimpleSlice = isSimpleSlice && (denseSpec.strides[i] === 1); const beginAndEndMasked = !!((denseSpec.beginMask & (1 << i)) && (denseSpec.endMask & (1 << i))); if (denseSpec.beginValid && denseSpec.endValid) { if (shrinkI) { // If we are shrinking, the end index is now possibly incorrect. In // particular foo[-1] produces sparseBegin = -1, sparseEnd = 0. // and canonical puts these to n-1 and 0, which implies a degenerate // interval. Fortunately, it is now safe to re-create end as begin + 1. const xFwd = denseSpec.begin[i] < 0 ? dimI + denseSpec.begin[i] : denseSpec.begin[i]; denseSpec.begin[i] = xFwd; denseSpec.end[i] = denseSpec.begin[i] + 1; if (xFwd < 0 || xFwd >= dimI) { throw Error(`slice index ${denseSpec.begin[i]} of dimension ${i} out of bounds.`); } } else { denseSpec.begin[i] = canonical(denseSpec.begin[i], 0, denseSpec.strides[i], dimI, masks, validRange); denseSpec.end[i] = canonical(denseSpec.end[i], 1, denseSpec.strides[i], dimI, masks, validRange); } // Update optimization values const takeAllInDimension = denseSpec.strides[i] === 1 && denseSpec.begin[i] === 0 && denseSpec.end[i] === dimI; isIdentity = isIdentity && takeAllInDimension; sliceDim0 = sliceDim0 && ((i === 0 && denseSpec.strides[i] === 1) || takeAllInDimension); } else { isIdentity = isIdentity && ((denseSpec.strides[i] === 1) && beginAndEndMasked); sliceDim0 = sliceDim0 && ((i === 0 && denseSpec.strides[i] === 1) || beginAndEndMasked); } // Compute the processing shape (the intermediate Eigen will produce) let intervalLength; let knownInterval = false; if (denseSpec.beginValid && denseSpec.endValid) { intervalLength = denseSpec.end[i] - denseSpec.begin[i]; knownInterval = true; } else if (shrinkI) { // The dimension is still known as 1 for the processingShape, but will be // discarded for the final shape. intervalLength = 1; knownInterval = true; } else if (beginAndEndMasked) { // Even if we don't have values for begin or end, we do know that this // dimension covers the whole interval. If we have shape information for // this dimension, that tells us the interval length. if (dimI >= 0) { if (denseSpec.strides[i] < 0) { intervalLength = -dimI; } else { intervalLength = dimI; } knownInterval = true; } } if (knownInterval) { let sizeI; // Hold zero if the interval is degenerate, otherwise account for // remainder if (intervalLength === 0 || ((intervalLength < 0) !== (denseSpec.strides[i] < 0))) { sizeI = 0; } else { sizeI = Math.trunc(intervalLength / denseSpec.strides[i]) + (intervalLength % denseSpec.strides[i] !== 0 ? 1 : 0); } processingShape.push(sizeI); } else { processingShape.push(-1); } } // Step 4: Compute the final shape // // newAxis will increase dimension by 1 (with a one-size dimension) // slices like foo[3, ...] will reduce dimension by 1. // This cannot be done earlier, because it depends on Step 3. for (let denseDim = 0; denseDim < denseSpec.finalShapeGatherIndices.length; ++denseDim) { const gatherIndex = denseSpec.finalShapeGatherIndices[denseDim]; if (gatherIndex >= 0) { finalShape.push(processingShape[gatherIndex]); } else if (gatherIndex === NEW_AXIS) { finalShape.push(1); } } const finalShapeSparse = finalShape.filter((dim, i) => denseSpec.finalShapeGatherIndices[i] !== NEW_AXIS); return { finalShapeSparse, finalShape, isIdentity, sliceDim0, isSimpleSlice, begin: denseSpec.begin, end: denseSpec.end, strides: denseSpec.strides }; } function buildDenseSpec(sparse, dense) { dense.beginMask = 0; dense.endMask = 0; dense.shrinkAxisMask = 0; let fullIndex = 0; dense.beginValid = sparse.begin != null; dense.endValid = sparse.end != null; dense.begin = new Array(dense.dims); dense.end = new Array(dense.dims); dense.strides = new Array(dense.dims); dense.finalShapeGatherIndices = []; dense.finalShapeGatherIndicesSparse = []; dense.inputShapeGatherIndicesSparse = new Array(dense.dims); for (let i = 0; i < sparse.dims; i++) { if ((1 << i) & sparse.ellipsisMask) { // Only the bit that has ellipsis will fall in this condition. // Expand the ellipsis into the appropriate indices // Note: this only works because we guaranteed one ellipsis. const nextIndex = Math.min(dense.dims - (sparse.dims - i) + 1 + sparse.numAddAxisAfterEllipsis, dense.dims); for (; fullIndex < nextIndex; fullIndex++) { // newAxis aren't real axis so you have to skip. dense.begin[fullIndex] = 0; dense.end[fullIndex] = 0; dense.strides[fullIndex] = 1; dense.beginMask |= (1 << fullIndex); dense.endMask |= (1 << fullIndex); dense.finalShapeGatherIndices.push(fullIndex); dense.finalShapeGatherIndicesSparse.push(-1); dense.inputShapeGatherIndicesSparse[fullIndex] = i; } } else if ((1 << i) & sparse.newAxisMask) { // Only the bit that has newAxis will fall in this condition. dense.finalShapeGatherIndices.push(NEW_AXIS); dense.finalShapeGatherIndicesSparse.push(-1); } else { if (fullIndex === dense.begin.length) { throw Error(`Index out of range using input dim ${fullIndex}; input ` + `has only ${dense.dims} dims, ${dense.begin.length}.`); } // Gather slicing spec into appropriate index. if (sparse.begin != null) { dense.begin[fullIndex] = sparse.begin[i]; } if (sparse.end != null) { dense.end[fullIndex] = sparse.end[i]; } dense.strides[fullIndex] = sparse.strides[i]; if (sparse.beginMask & (1 << i)) { dense.beginMask |= (1 << fullIndex); } if (sparse.endMask & (1 << i)) { dense.endMask |= (1 << fullIndex); } // If shrink, record where to get the dimensionality from (i.e. newAxis) // creates a fake 1 size dimension. Also remember shrink axis (now in // dense form) so we can ignore dense.end below. if (sparse.shrinkAxisMask & (1 << i)) { dense.finalShapeGatherIndices.push(SHRINK_AXIS); dense.finalShapeGatherIndicesSparse.push(-1); dense.shrinkAxisMask |= (1 << fullIndex); } else { dense.finalShapeGatherIndices.push(fullIndex); // Remember that where in the sparse shape the dense dim comes from. dense.finalShapeGatherIndicesSparse.push(i); } dense.inputShapeGatherIndicesSparse[fullIndex] = i; fullIndex++; } } } function canonical(x, c, strideI, dimI, masks, validRange) { if (masks[c]) { return strideI > 0 ? validRange[c] : validRange[(c + 1) & 1]; } else { const xFwd = x < 0 ? dimI + x : x; // make negative indices positive return xFwd < validRange[0] ? validRange[0] : xFwd > validRange[1] ? validRange[1] : xFwd; } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2xpY2VfdXRpbC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3RmanMtY29yZS9zcmMvb3BzL3NsaWNlX3V0aWwudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7Ozs7OztHQWVHO0FBR0gsT0FBTyxLQUFLLElBQUksTUFBTSxTQUFTLENBQUM7QUFFaEMsTUFBTSxRQUFRLEdBQUcsQ0FBQyxDQUFDLENBQUM7QUFDcEIsTUFBTSxXQUFXLEdBQUcsQ0FBQyxDQUFDLENBQUM7QUE2RHZCLE1BQU0sVUFBVSxpQkFBaUIsQ0FDN0IsS0FBaUIsRUFBRSxLQUFlLEVBQUUsSUFBYztJQUNwRCxNQUFNLFNBQVMsR0FBRyxLQUFLLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQztJQUNyQyxJQUFJLENBQUMsTUFBTSxDQUNQLFNBQVMsS0FBSyxLQUFLLENBQUMsTUFBTSxFQUMxQixHQUFHLEVBQUUsQ0FBQyxpQkFBaUIsU0FBUyxzQkFBc0IsS0FBSyxRQUFRO1FBQy9ELGdDQUFnQyxTQUFTLElBQUksQ0FBQyxDQUFDO0lBQ3ZELElBQUksQ0FBQyxNQUFNLENBQ1AsU0FBUyxLQUFLLElBQUksQ0FBQyxNQUFNLEVBQ3pCLEdBQUcsRUFBRSxDQUFDLGlCQUFpQixTQUFTLHFCQUFxQixJQUFJLFFBQVE7UUFDN0QsZ0NBQWdDLFNBQVMsSUFBSSxDQUFDLENBQUM7SUFFdkQsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLFNBQVMsRUFBRSxFQUFFLENBQUMsRUFBRTtRQUNsQyxJQUFJLENBQUMsTUFBTSxDQUNQLEtBQUssQ0FBQyxDQUFDLENBQUMsR0FBRyxJQUFJLENBQUMsQ0FBQyxDQUFDLElBQUksS0FBSyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsRUFDcEMsR0FBRyxFQUFFLENBQUMsaUJBQWlCLFNBQVMsWUFBWSxDQUFDLFlBQVksQ0FBQyxJQUFJO1lBQzFELElBQUksS0FBSyxDQUFD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UyxDQUFDLENBQUM7Z0JBQzlDLG9FQUFvRTtnQkFDcEUsS0FBSyxDQUFDLDZCQUE2QixDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQzthQUM3QztZQUNELEtBQUssQ0FBQyw2QkFBNkIsQ0FBQyxTQUFTLENBQUMsR0FBRyxDQUFDLENBQUM7WUFDbkQsU0FBUyxFQUFFLENBQUM7U0FDYjtLQUNGO0FBQ0gsQ0FBQztBQUVELFNBQVMsU0FBUyxDQUNkLENBQVMsRUFBRSxDQUFTLEVBQUUsT0FBZSxFQUFFLElBQVksRUFBRSxLQUFlLEVBQ3BFLFVBQW9CO0lBQ3RCLElBQUksS0FBSyxDQUFDLENBQUMsQ0FBQyxFQUFFO1FBQ1osT0FBTyxPQUFPLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztLQUM5RDtTQUFNO1FBQ0wsTUFBTSxJQUFJLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUUsaUNBQWlDO1FBQ3JFLE9BQU8sSUFBSSxHQUFHLFVBQVUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDZixJQUFJLEdBQUcsVUFBVSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQztLQUMzRTtBQUNILENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEBsaWNlbnNlXG4gKiBDb3B5cmlnaHQgMjAyMSBHb29nbGUgTExDLiBBbGwgUmlnaHRzIFJlc2VydmVkLlxuICogTGljZW5zZWQgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMCAodGhlIFwiTGljZW5zZVwiKTtcbiAqIHlvdSBtYXkgbm90IHVzZSB0aGlzIGZpbGUgZXhjZXB0IGluIGNvbXBsaWFuY2Ugd2l0aCB0aGUgTGljZW5zZS5cbiAqIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdFxuICpcbiAqIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMFxuICpcbiAqIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvciBhZ3JlZWQgdG8gaW4gd3JpdGluZywgc29mdHdhcmVcbiAqIGRpc3RyaWJ1dGVkIHVuZGVyIHRoZSBMaWNlbnNlIGlzIGRpc3RyaWJ1dGVkIG9uIGFuIFwiQVMgSVNcIiBCQVNJUyxcbiAqIFdJVEhPVVQgV0FSUkFOVElFUyBPUiBDT