1ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande/* 2ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande * Copyright (C) 2016 The Android Open Source Project 3ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande * 4ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande * Licensed under the Apache License, Version 2.0 (the "License"); 5ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande * you may not use this file except in compliance with the License. 6ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande * You may obtain a copy of the License at 7ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande * 8ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande * http://www.apache.org/licenses/LICENSE-2.0 9ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande * 10ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande * Unless required by applicable law or agreed to in writing, software 11ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande * distributed under the License is distributed on an "AS IS" BASIS, 12ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande * See the License for the specific language governing permissions and 14ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande * limitations under the License. 15ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande */ 16ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande 17ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpandepackage com.android.server.wifi; 18ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande 19ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpandeimport static org.junit.Assert.assertEquals; 20ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpandeimport static org.junit.Assert.assertNotNull; 21ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpandeimport static org.junit.Assert.assertNull; 22ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpandeimport static org.mockito.Mockito.when; 23ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpandeimport static org.mockito.MockitoAnnotations.initMocks; 24ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande 25ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpandeimport android.net.wifi.ScanResult; 26ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpandeimport android.net.wifi.WifiSsid; 27ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpandeimport android.test.suitebuilder.annotation.SmallTest; 28ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpandeimport android.util.Log; 29ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande 30ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpandeimport com.android.server.wifi.anqp.ANQPElement; 31ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpandeimport com.android.server.wifi.anqp.Constants; 32ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpandeimport com.android.server.wifi.hotspot2.ANQPData; 33ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpandeimport com.android.server.wifi.hotspot2.AnqpCache; 34ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpandeimport com.android.server.wifi.hotspot2.NetworkDetail; 35ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande 36ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpandeimport org.junit.Test; 37ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpandeimport org.mockito.Mock; 38ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande 39ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpandeimport java.util.ArrayList; 40ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpandeimport java.util.Arrays; 41ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpandeimport java.util.HashMap; 42ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpandeimport java.util.List; 43ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpandeimport java.util.Map; 44ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande 45ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande 46ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande/** 47ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande * Unit tests for {@link com.android.server.wifi.hotspot2.AnqpCache}. 48ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande */ 49ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande@SmallTest 50ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpandepublic class AnqpCacheTest { 51ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande 52ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande private static final String TAG = "AnqpCacheTest"; 53ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande 54ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande private static class NetworkDescription { 55ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande ScanDetail[] mScanDetails; 56ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande static int[] sChannels = new int[]{2412, 2437, 2462, 5180, 5220, 5745, 5825}; 57ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande static int[] sRSSIs = new int[]{ -50, -80, -60, -80, -55, -90, -75}; 58ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande 59ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande NetworkDescription(String ssid, String bssidPrefix) { 60ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande WifiSsid wifiSsid = WifiSsid.createFromAsciiEncoded(ssid); 61ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande mScanDetails = new ScanDetail[sChannels.length]; 62ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande for (int i = 0; i < sChannels.length; i++) { 63ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande String bssid = String.format("%s:%02x", bssidPrefix, i); 64ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande ScanResult.InformationElement[] ie = new ScanResult.InformationElement[1]; 65ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande ie[0] = ScanResults.generateSsidIe(ssid); 66ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande List<String> anqpLines = new ArrayList<String>(); 67ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande NetworkDetail nd = new NetworkDetail(bssid, ie, 68ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande new ArrayList<String>(), sChannels[i]); 69ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande mScanDetails[i] = new ScanDetail(nd, wifiSsid, 70ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande bssid, "", sRSSIs[i], sChannels[i], Long.MAX_VALUE, ie, anqpLines); 71ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande } 72ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande } 73ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande } 74ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande 75ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande private static final String ATT_SSID = "att_wifi"; 76ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande private static final String ATT_BSSID_PREFIX = "aa:44:bb:55:cc"; 77ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande private static final String TWC_SSID = "TWCWIFI"; 78ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande private static final String TWC_BSSID_PREFIX = "11:aa:22:bb:33"; 79ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande 80ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande private static ScanDetail[] getAttWifiNetworkDescription() { 81ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande NetworkDescription network = new NetworkDescription(ATT_SSID, ATT_BSSID_PREFIX); 82ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande return network.mScanDetails; 83ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande } 84ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande 85ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande private static ScanDetail[] getTwcWifiNetworkDescription() { 86ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande NetworkDescription network = new NetworkDescription(TWC_SSID, TWC_BSSID_PREFIX); 87ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande return network.mScanDetails; 88ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande } 89ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande 90ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande private static List<Constants.ANQPElementType> buildQueryList() { 91ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande List<Constants.ANQPElementType> list = Arrays.asList( 92ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande Constants.ANQPElementType.class.getEnumConstants()); 93ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande return list; 94ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande } 95ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande 96ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande private static Map<Constants.ANQPElementType, ANQPElement> buildAnqpResult() { 97ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande Map<Constants.ANQPElementType, ANQPElement> elements = new HashMap<>(); 98ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande List<Constants.ANQPElementType> list = Arrays.asList( 99ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande Constants.ANQPElementType.class.getEnumConstants()); 100ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande for (final Constants.ANQPElementType type : list) { 101ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande ANQPElement element = new ANQPElement(type) { 102ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande @Override 103ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande public Constants.ANQPElementType getID() { 104ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande return super.getID(); 105ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande } 106ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande }; 107ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande elements.put(type, element); 108ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande } 109ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande 110ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande return elements; 111ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande } 112ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande 113ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande private void advanceTimeAndTrimCache(long howManyMillis) { 114ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande mCurrentTimeMillis += howManyMillis; 115ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande Log.d(TAG, "Time set to " + mCurrentTimeMillis); 116ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande when(mClock.currentTimeMillis()).thenReturn(mCurrentTimeMillis); 117ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande mCache.clear(false, true); 118ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande } 119ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande 120ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande public AnqpCacheTest() {} 121ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande 122ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande private static final long SECOND_MS = 1000; 123ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande private static final long MINUTE_MS = 60 * SECOND_MS; 124ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande 125ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande @Mock Clock mClock; 126ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande long mCurrentTimeMillis = 1000000000; 127ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande AnqpCache mCache; 128ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande 129ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande /** verify that ANQP data is cached per the (rather abstract) spec */ 130ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande @Test 131ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande public void basicAddQueryAndExpiry() { 132ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande initMocks(this); 133ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande 134ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande AnqpCache cache = mCache = new AnqpCache(mClock); 135ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande advanceTimeAndTrimCache(0); 136ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande 137ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande List<Constants.ANQPElementType> queryList = buildQueryList(); 138ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande 139ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande ScanDetail[] attScanDetails = getAttWifiNetworkDescription(); 140ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande ScanDetail[] twcScanDetails = getTwcWifiNetworkDescription(); 141ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande 142ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande /* query att network at time 0 */ 143ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande for (ScanDetail scanDetail : attScanDetails) { 144ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande cache.initiate(scanDetail.getNetworkDetail(), queryList); 145ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande } 146ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande 147ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande /* verify that no data can be returned */ 148ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande for (ScanDetail scanDetail : attScanDetails) { 149ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande ANQPData data = cache.getEntry(scanDetail.getNetworkDetail()); 150ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande assertNull(data); 151ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande } 152ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande 153ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande /* update ANQP results after 1 min */ 154ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande advanceTimeAndTrimCache(1 * MINUTE_MS); 155ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande 156ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande Map<Constants.ANQPElementType, ANQPElement> anqpResults = buildAnqpResult(); 157ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande 158ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande for (ScanDetail scanDetail : attScanDetails) { 159ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande cache.update(scanDetail.getNetworkDetail(), anqpResults); 160ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande } 161ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande 162ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande /* check ANQP results after another 1 min */ 163ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande advanceTimeAndTrimCache(1 * MINUTE_MS); 164ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande 165ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande for (ScanDetail scanDetail : attScanDetails) { 166ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande ANQPData data = cache.getEntry(scanDetail.getNetworkDetail()); 167ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande assertNotNull(data); 168ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande NetworkDetail nd = data.getNetwork(); 169ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande Map<Constants.ANQPElementType, ANQPElement> anqp = data.getANQPElements(); 170ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande assertEquals(scanDetail.getBSSIDString(), nd.getBSSIDString()); 171ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande assertEquals(anqpResults.size(), anqp.size()); 172ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande } 173ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande 174ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande /* query ANQP results for twcwifi after another 10 min */ 175ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande advanceTimeAndTrimCache(10 * MINUTE_MS); 176ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande 177ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande for (ScanDetail scanDetail : twcScanDetails) { 178ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande cache.initiate(scanDetail.getNetworkDetail(), queryList); 179ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande } 180ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande 181ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande /* update ANQP results for twcwifi after another 10 min */ 182ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande advanceTimeAndTrimCache(1 * MINUTE_MS); 183ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande 184ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande for (ScanDetail scanDetail : twcScanDetails) { 185ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande cache.update(scanDetail.getNetworkDetail(), anqpResults); 186ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande } 187ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande 188ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande /* check all results after 1 minute */ 189ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande advanceTimeAndTrimCache(1 * MINUTE_MS); 190ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande 191ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande for (ScanDetail scanDetail : attScanDetails) { 192ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande ANQPData data = cache.getEntry(scanDetail.getNetworkDetail()); 193ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande assertNull(data); 194ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande } 195ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande 196ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande for (ScanDetail scanDetail : twcScanDetails) { 197ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande ANQPData data = cache.getEntry(scanDetail.getNetworkDetail()); 198ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande assertNotNull(data); 199ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande NetworkDetail nd = data.getNetwork(); 200ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande Map<Constants.ANQPElementType, ANQPElement> anqp = data.getANQPElements(); 201ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande assertEquals(scanDetail.getBSSIDString(), nd.getBSSIDString()); 202ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande assertEquals(anqpResults.size(), anqp.size()); 203ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande } 204ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande } 205ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande} 206ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande 207ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande 208ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande 209ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande 210ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande 211ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande 212ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande 213ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande 214ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande 215ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande 216ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande 217ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande 218ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande 219ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande 220ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande 221ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande 222ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande 223ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande 224ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande 225ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande 226ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande 227ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande 228ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande 229ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande 230ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande 231ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande 232ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande 233ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande 234ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande 235ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande 236ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande 237