12f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall/*
22f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall * Copyright (C) 2015 The Android Open Source Project
32f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall *
42f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall * Licensed under the Apache License, Version 2.0 (the "License");
52f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall * you may not use this file except in compliance with the License.
62f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall * You may obtain a copy of the License at
72f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall *
82f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall *      http://www.apache.org/licenses/LICENSE-2.0
92f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall *
102f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall * Unless required by applicable law or agreed to in writing, software
112f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall * distributed under the License is distributed on an "AS IS" BASIS,
122f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
132f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall * See the License for the specific language governing permissions and
142f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall * limitations under the License.
152f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall */
162f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall
172f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lallpackage com.android.camera.util;
182f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall
192f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lallimport android.graphics.Rect;
202f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall
212f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lallimport com.google.common.base.Objects;
222f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall
232f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lallimport java.math.BigInteger;
242f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall
252f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lallimport javax.annotation.ParametersAreNonnullByDefault;
262f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall
272f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall/**
282f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall * Contains precise (integer) logic for handling aspect ratios as rational
292f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall * numbers.
302f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall */
312f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall@ParametersAreNonnullByDefault
322f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lallpublic final class AspectRatio {
33cc6139467c1c9545de1f098d938409e182c9b7adSenpo Hu    private static final AspectRatio ASPECT_RATIO_4x3 = AspectRatio.of(4, 3);
34cc6139467c1c9545de1f098d938409e182c9b7adSenpo Hu    private static final AspectRatio ASPECT_RATIO_16x9 = AspectRatio.of(16, 9);
35cc6139467c1c9545de1f098d938409e182c9b7adSenpo Hu
362f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall    private final int mWidth;
372f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall    private final int mHeight;
382f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall
392f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall    /**
402f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall     * @param width The width of the aspect ratio, after simplification.
412f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall     * @param height The height of the aspect ratio, after simplification.
422f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall     */
432f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall    private AspectRatio(int width, int height) {
442f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall        mWidth = width;
452f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall        mHeight = height;
462f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall    }
472f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall
482f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall    public static AspectRatio of(int width, int height) {
492f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall        int gcd = BigInteger.valueOf(width).gcd(BigInteger.valueOf(height)).intValue();
502f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall        int simplifiedWidth = width / gcd;
512f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall        int simplifiedHeight = height / gcd;
522f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall        return new AspectRatio(simplifiedWidth, simplifiedHeight);
532f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall    }
542f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall
552f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall    public static AspectRatio of(Size size) {
562f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall        return of(size.width(), size.height());
572f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall    }
582f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall
59cc6139467c1c9545de1f098d938409e182c9b7adSenpo Hu    public static AspectRatio of4x3() {
60cc6139467c1c9545de1f098d938409e182c9b7adSenpo Hu        return ASPECT_RATIO_4x3;
61cc6139467c1c9545de1f098d938409e182c9b7adSenpo Hu    }
62cc6139467c1c9545de1f098d938409e182c9b7adSenpo Hu
63cc6139467c1c9545de1f098d938409e182c9b7adSenpo Hu    public static AspectRatio of16x9() {
64cc6139467c1c9545de1f098d938409e182c9b7adSenpo Hu        return ASPECT_RATIO_16x9;
65cc6139467c1c9545de1f098d938409e182c9b7adSenpo Hu    }
66cc6139467c1c9545de1f098d938409e182c9b7adSenpo Hu
672f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall    public int getHeight() {
682f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall        return mHeight;
692f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall    }
702f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall
712f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall    public int getWidth() {
722f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall        return mWidth;
732f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall    }
742f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall
75cc6139467c1c9545de1f098d938409e182c9b7adSenpo Hu    public float toFloat() {
76cc6139467c1c9545de1f098d938409e182c9b7adSenpo Hu        return (float) mWidth / (float) mHeight;
77cc6139467c1c9545de1f098d938409e182c9b7adSenpo Hu    }
78cc6139467c1c9545de1f098d938409e182c9b7adSenpo Hu
792f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall    @Override
802f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall    public boolean equals(Object o) {
812f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall        if (this == o)
822f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall            return true;
832f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall        if (!(o instanceof AspectRatio))
842f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall            return false;
852f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall
862f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall        AspectRatio that = (AspectRatio) o;
872f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall
882f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall        if (mHeight != that.mHeight)
892f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall            return false;
902f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall        if (mWidth != that.mWidth)
912f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall            return false;
922f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall
932f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall        return true;
942f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall    }
952f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall
962f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall    @Override
972f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall    public int hashCode() {
982f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall        return Objects.hashCode(mWidth, mHeight);
992f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall    }
1002f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall
1012f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall    @Override
1022f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall    public String toString() {
1032f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall        return String.format("AspectRatio[%d:%d]", getWidth(), getHeight());
1042f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall    }
1052f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall
1062f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall    /**
1072f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall     * @return The transpose of this aspect ratio.
1082f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall     */
1092f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall    public AspectRatio transpose() {
1102f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall        return of(mHeight, mWidth);
1112f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall    }
1122f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall
1132f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall    /**
1142f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall     * @return The landscape version of this aspect ratio.
1152f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall     */
1162f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall    public AspectRatio asLandscape() {
1172f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall        if (isLandscape()) {
1182f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall            return this;
1192f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall        } else {
1202f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall            return transpose();
1212f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall        }
1222f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall    }
1232f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall
1242f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall    /**
1252f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall     * @return The portrait version of this aspect ratio.
1262f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall     */
1272f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall    public AspectRatio asPortrait() {
1282f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall        if (isPortrait()) {
1292f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall            return this;
1302f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall        } else {
1312f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall            return transpose();
1322f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall        }
1332f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall    }
1342f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall
1352f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall    /**
1362f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall     * @return The version of this aspect ratio in the same orientation
1372f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall     *         (portrait vs. landscape) of the other.
1382f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall     */
1392f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall    public AspectRatio withOrientationOf(AspectRatio other) {
1402f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall        if (other.isPortrait()) {
1412f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall            return asPortrait();
1422f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall        } else {
1432f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall            return asLandscape();
1442f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall        }
1452f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall    }
1462f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall
1472f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall    /**
1482f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall     * @return True if this aspect ratio is wider than the other.
1492f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall     */
1502f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall    public boolean isWiderThan(AspectRatio other) {
1512f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall        // this.mWidth other.mWidth
1522f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall        // ----------- > ------------
1532f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall        // this.mHeight other.mHeight
1542f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall        return this.mWidth * other.mHeight > other.mWidth * this.mHeight;
1552f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall    }
1562f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall
1572f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall    /**
1582f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall     * @return True if this aspect ratio is taller than the other.
1592f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall     */
1602f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall    public boolean isTallerThan(AspectRatio other) {
1612f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall        // this.mWidth other.mWidth
1622f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall        // ----------- < ------------
1632f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall        // this.mHeight other.mHeight
1642f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall        return this.mWidth * other.mHeight < other.mWidth * this.mHeight;
1652f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall    }
1662f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall
1672f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall    /**
1682f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall     * @return The largest centered region of area with this aspect ratio. For
1692f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall     *         non-integer values, the returned rectangle coordinates are the
1702f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall     *         *floor* of the result.
1712f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall     */
1722f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall    public Rect getLargestCenterCrop(Size area) {
1732f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall        AspectRatio original = of(area);
1742f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall
1752f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall        if (this.isWiderThan(original)) {
1762f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall            // Crop off the top and bottom...
1772f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall            int cropHeight = area.width() * mHeight / mWidth;
1782f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall            int cropTop = (area.height() - cropHeight) / 2;
1792f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall            int cropBottom = cropTop + cropHeight;
1802f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall            int cropLeft = 0;
1812f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall            int cropRight = area.width();
1822f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall            return new Rect(cropLeft, cropTop, cropRight, cropBottom);
1832f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall        } else {
1842f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall            // Crop off the left and right...
1852f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall            int cropWidth = area.height() * mWidth / mHeight;
1862f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall            int cropLeft = (area.width() - cropWidth) / 2;
1872f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall            int cropRight = cropLeft + cropWidth;
1882f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall            int cropTop = 0;
1892f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall            int cropBottom = area.height();
1902f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall            return new Rect(cropLeft, cropTop, cropRight, cropBottom);
1912f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall        }
1922f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall    }
1932f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall
1942f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall    /**
1952f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall     * @return True if this aspect ratio is in landscape orientation. Square
1962f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall     *         aspect ratios are both portrait *and* landscape.
1972f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall     */
1982f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall    private boolean isLandscape() {
1992f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall        return mWidth >= mHeight;
2002f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall    }
2012f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall
2022f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall    /**
2032f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall     * @return True if this aspect ratio is in portrait orientation. Square
2042f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall     *         aspect ratios are both portrait *and* landscape.
2052f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall     */
2062f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall    private boolean isPortrait() {
2072f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall        return mWidth <= mHeight;
2082f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall    }
2092f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall
2102f6fe6f07a6d43d8bb49156a7a73e86896ab7d1ePuneet Lall}
211