LinkProperties.java revision 0a46db5d88461d9a6c85bb2e95982ac4c511d57e
147f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt/* 26e80997a9a7b6a15370544edde322cd8833e9524Wink Saville * Copyright (C) 2010 The Android Open Source Project 347f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt * 447f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt * Licensed under the Apache License, Version 2.0 (the "License"); 547f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt * you may not use this file except in compliance with the License. 647f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt * You may obtain a copy of the License at 747f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt * 847f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt * http://www.apache.org/licenses/LICENSE-2.0 947f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt * 1047f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt * Unless required by applicable law or agreed to in writing, software 1147f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt * distributed under the License is distributed on an "AS IS" BASIS, 1247f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1347f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt * See the License for the specific language governing permissions and 1447f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt * limitations under the License. 1547f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt */ 1647f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt 1747f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwaltpackage android.net; 1847f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt 1937e65ebb7eb932e1a144b1cab262e11ca5fd109bRobert Greenwaltimport android.net.ProxyProperties; 2047f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwaltimport android.os.Parcelable; 2147f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwaltimport android.os.Parcel; 224e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wangimport android.text.TextUtils; 2347f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt 2447f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwaltimport java.net.InetAddress; 2547f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwaltimport java.net.UnknownHostException; 2647f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwaltimport java.util.ArrayList; 2747f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwaltimport java.util.Collection; 2837e65ebb7eb932e1a144b1cab262e11ca5fd109bRobert Greenwaltimport java.util.Collections; 2947f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt 3047f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt/** 3137e65ebb7eb932e1a144b1cab262e11ca5fd109bRobert Greenwalt * Describes the properties of a network link. 32992564e481af13cbcb058ee801f9254a520c54a1Robert Greenwalt * 33992564e481af13cbcb058ee801f9254a520c54a1Robert Greenwalt * A link represents a connection to a network. 34992564e481af13cbcb058ee801f9254a520c54a1Robert Greenwalt * It may have multiple addresses and multiple gateways, 35992564e481af13cbcb058ee801f9254a520c54a1Robert Greenwalt * multiple dns servers but only one http proxy. 36992564e481af13cbcb058ee801f9254a520c54a1Robert Greenwalt * 37992564e481af13cbcb058ee801f9254a520c54a1Robert Greenwalt * Because it's a single network, the dns's 38992564e481af13cbcb058ee801f9254a520c54a1Robert Greenwalt * are interchangeable and don't need associating with 39992564e481af13cbcb058ee801f9254a520c54a1Robert Greenwalt * particular addresses. The gateways similarly don't 40992564e481af13cbcb058ee801f9254a520c54a1Robert Greenwalt * need associating with particular addresses. 41992564e481af13cbcb058ee801f9254a520c54a1Robert Greenwalt * 42992564e481af13cbcb058ee801f9254a520c54a1Robert Greenwalt * A dual stack interface works fine in this model: 43992564e481af13cbcb058ee801f9254a520c54a1Robert Greenwalt * each address has it's own prefix length to describe 44992564e481af13cbcb058ee801f9254a520c54a1Robert Greenwalt * the local network. The dns servers all return 45992564e481af13cbcb058ee801f9254a520c54a1Robert Greenwalt * both v4 addresses and v6 addresses regardless of the 46992564e481af13cbcb058ee801f9254a520c54a1Robert Greenwalt * address family of the server itself (rfc4213) and we 47992564e481af13cbcb058ee801f9254a520c54a1Robert Greenwalt * don't care which is used. The gateways will be 48992564e481af13cbcb058ee801f9254a520c54a1Robert Greenwalt * selected based on the destination address and the 49992564e481af13cbcb058ee801f9254a520c54a1Robert Greenwalt * source address has no relavence. 5047f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt * @hide 5147f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt */ 5237e65ebb7eb932e1a144b1cab262e11ca5fd109bRobert Greenwaltpublic class LinkProperties implements Parcelable { 5347f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt 54ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff String mIfaceName; 55e822225f7a01ef088ff01f7613f953d5d89945edWink Saville private Collection<LinkAddress> mLinkAddresses = new ArrayList<LinkAddress>(); 56e822225f7a01ef088ff01f7613f953d5d89945edWink Saville private Collection<InetAddress> mDnses = new ArrayList<InetAddress>(); 57e822225f7a01ef088ff01f7613f953d5d89945edWink Saville private Collection<RouteInfo> mRoutes = new ArrayList<RouteInfo>(); 5847f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt private ProxyProperties mHttpProxy; 5947f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt 600a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt public static class CompareResult<T> { 610a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt public ArrayList<T> removed = new ArrayList<T>(); 620a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt public ArrayList<T> added = new ArrayList<T>(); 63e822225f7a01ef088ff01f7613f953d5d89945edWink Saville 64e822225f7a01ef088ff01f7613f953d5d89945edWink Saville @Override 65e822225f7a01ef088ff01f7613f953d5d89945edWink Saville public String toString() { 660a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt String retVal = "removed=["; 670a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt for (T addr : removed) retVal += addr.toString() + ","; 680a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt retVal += "] added=["; 690a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt for (T addr : added) retVal += addr.toString() + ","; 70e822225f7a01ef088ff01f7613f953d5d89945edWink Saville retVal += "]"; 71e822225f7a01ef088ff01f7613f953d5d89945edWink Saville return retVal; 72e822225f7a01ef088ff01f7613f953d5d89945edWink Saville } 73e822225f7a01ef088ff01f7613f953d5d89945edWink Saville } 74e822225f7a01ef088ff01f7613f953d5d89945edWink Saville 7537e65ebb7eb932e1a144b1cab262e11ca5fd109bRobert Greenwalt public LinkProperties() { 7647f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt clear(); 7747f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt } 7847f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt 7937e65ebb7eb932e1a144b1cab262e11ca5fd109bRobert Greenwalt // copy constructor instead of clone 8037e65ebb7eb932e1a144b1cab262e11ca5fd109bRobert Greenwalt public LinkProperties(LinkProperties source) { 81ef6c1431fa2039a4b8c604d651bb8f4dc0806581Irfan Sheriff if (source != null) { 82ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff mIfaceName = source.getInterfaceName(); 83ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff mLinkAddresses = source.getLinkAddresses(); 84ef6c1431fa2039a4b8c604d651bb8f4dc0806581Irfan Sheriff mDnses = source.getDnses(); 85aa70f101e08098ed9cb190abe2d7f952561026b8Robert Greenwalt mRoutes = source.getRoutes(); 86be2b058ec1e11e1d33b6d03230c21e5d2d7ac40cWink Saville mHttpProxy = (source.getHttpProxy() == null) ? 87be2b058ec1e11e1d33b6d03230c21e5d2d7ac40cWink Saville null : new ProxyProperties(source.getHttpProxy()); 88ef6c1431fa2039a4b8c604d651bb8f4dc0806581Irfan Sheriff } 8937e65ebb7eb932e1a144b1cab262e11ca5fd109bRobert Greenwalt } 9037e65ebb7eb932e1a144b1cab262e11ca5fd109bRobert Greenwalt 91ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff public void setInterfaceName(String iface) { 92ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff mIfaceName = iface; 9347f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt } 94ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff 9537e65ebb7eb932e1a144b1cab262e11ca5fd109bRobert Greenwalt public String getInterfaceName() { 96ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff return mIfaceName; 9747f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt } 9847f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt 9937e65ebb7eb932e1a144b1cab262e11ca5fd109bRobert Greenwalt public Collection<InetAddress> getAddresses() { 100ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff Collection<InetAddress> addresses = new ArrayList<InetAddress>(); 101ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff for (LinkAddress linkAddress : mLinkAddresses) { 102ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff addresses.add(linkAddress.getAddress()); 103ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff } 104ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff return Collections.unmodifiableCollection(addresses); 105ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff } 106ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff 107ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff public void addLinkAddress(LinkAddress address) { 10804cac40ff86e175444991c07869cb85219db1019Robert Greenwalt if (address != null) mLinkAddresses.add(address); 109ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff } 110ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff 111ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff public Collection<LinkAddress> getLinkAddresses() { 112ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff return Collections.unmodifiableCollection(mLinkAddresses); 11347f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt } 11447f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt 11537e65ebb7eb932e1a144b1cab262e11ca5fd109bRobert Greenwalt public void addDns(InetAddress dns) { 11604cac40ff86e175444991c07869cb85219db1019Robert Greenwalt if (dns != null) mDnses.add(dns); 11747f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt } 118ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff 11937e65ebb7eb932e1a144b1cab262e11ca5fd109bRobert Greenwalt public Collection<InetAddress> getDnses() { 12037e65ebb7eb932e1a144b1cab262e11ca5fd109bRobert Greenwalt return Collections.unmodifiableCollection(mDnses); 12147f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt } 12247f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt 123aa70f101e08098ed9cb190abe2d7f952561026b8Robert Greenwalt public void addRoute(RouteInfo route) { 124aa70f101e08098ed9cb190abe2d7f952561026b8Robert Greenwalt if (route != null) mRoutes.add(route); 12547f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt } 126aa70f101e08098ed9cb190abe2d7f952561026b8Robert Greenwalt public Collection<RouteInfo> getRoutes() { 127aa70f101e08098ed9cb190abe2d7f952561026b8Robert Greenwalt return Collections.unmodifiableCollection(mRoutes); 12847f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt } 12947f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt 13037e65ebb7eb932e1a144b1cab262e11ca5fd109bRobert Greenwalt public void setHttpProxy(ProxyProperties proxy) { 13147f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt mHttpProxy = proxy; 13247f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt } 13337e65ebb7eb932e1a144b1cab262e11ca5fd109bRobert Greenwalt public ProxyProperties getHttpProxy() { 13447f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt return mHttpProxy; 13547f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt } 13647f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt 13737e65ebb7eb932e1a144b1cab262e11ca5fd109bRobert Greenwalt public void clear() { 138ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff mIfaceName = null; 139e822225f7a01ef088ff01f7613f953d5d89945edWink Saville mLinkAddresses.clear(); 140e822225f7a01ef088ff01f7613f953d5d89945edWink Saville mDnses.clear(); 141e822225f7a01ef088ff01f7613f953d5d89945edWink Saville mRoutes.clear(); 14247f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt mHttpProxy = null; 14347f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt } 14447f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt 14547f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt /** 14647f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt * Implement the Parcelable interface 14747f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt * @hide 14847f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt */ 14947f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt public int describeContents() { 15047f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt return 0; 15147f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt } 15247f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt 1531f6408a96c757b3001c553f8f34ef0bda00a224dWink Saville @Override 15437e65ebb7eb932e1a144b1cab262e11ca5fd109bRobert Greenwalt public String toString() { 155ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff String ifaceName = (mIfaceName == null ? "" : "InterfaceName: " + mIfaceName + " "); 15647f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt 157ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff String linkAddresses = "LinkAddresses: ["; 1584e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang for (LinkAddress addr : mLinkAddresses) linkAddresses += addr.toString() + ","; 159ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff linkAddresses += "] "; 16047f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt 16147f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt String dns = "DnsAddresses: ["; 1621f6408a96c757b3001c553f8f34ef0bda00a224dWink Saville for (InetAddress addr : mDnses) dns += addr.getHostAddress() + ","; 16347f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt dns += "] "; 16447f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt 165aa70f101e08098ed9cb190abe2d7f952561026b8Robert Greenwalt String routes = "Routes: ["; 166aa70f101e08098ed9cb190abe2d7f952561026b8Robert Greenwalt for (RouteInfo route : mRoutes) routes += route.toString() + ","; 167aa70f101e08098ed9cb190abe2d7f952561026b8Robert Greenwalt routes += "] "; 16847f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt String proxy = (mHttpProxy == null ? "" : "HttpProxy: " + mHttpProxy.toString() + " "); 16947f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt 170aa70f101e08098ed9cb190abe2d7f952561026b8Robert Greenwalt return ifaceName + linkAddresses + routes + dns + proxy; 17147f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt } 17247f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt 173e822225f7a01ef088ff01f7613f953d5d89945edWink Saville /** 174e822225f7a01ef088ff01f7613f953d5d89945edWink Saville * Compares this {@code LinkProperties} interface name against the target 175e822225f7a01ef088ff01f7613f953d5d89945edWink Saville * 176e822225f7a01ef088ff01f7613f953d5d89945edWink Saville * @param target LinkProperties to compare. 177e822225f7a01ef088ff01f7613f953d5d89945edWink Saville * @return {@code true} if both are identical, {@code false} otherwise. 178e822225f7a01ef088ff01f7613f953d5d89945edWink Saville */ 179e822225f7a01ef088ff01f7613f953d5d89945edWink Saville public boolean isIdenticalInterfaceName(LinkProperties target) { 180e822225f7a01ef088ff01f7613f953d5d89945edWink Saville return TextUtils.equals(getInterfaceName(), target.getInterfaceName()); 181e822225f7a01ef088ff01f7613f953d5d89945edWink Saville } 182e822225f7a01ef088ff01f7613f953d5d89945edWink Saville 183e822225f7a01ef088ff01f7613f953d5d89945edWink Saville /** 184e822225f7a01ef088ff01f7613f953d5d89945edWink Saville * Compares this {@code LinkProperties} interface name against the target 185e822225f7a01ef088ff01f7613f953d5d89945edWink Saville * 186e822225f7a01ef088ff01f7613f953d5d89945edWink Saville * @param target LinkProperties to compare. 187e822225f7a01ef088ff01f7613f953d5d89945edWink Saville * @return {@code true} if both are identical, {@code false} otherwise. 188e822225f7a01ef088ff01f7613f953d5d89945edWink Saville */ 189e822225f7a01ef088ff01f7613f953d5d89945edWink Saville public boolean isIdenticalAddresses(LinkProperties target) { 190e822225f7a01ef088ff01f7613f953d5d89945edWink Saville Collection<InetAddress> targetAddresses = target.getAddresses(); 191e822225f7a01ef088ff01f7613f953d5d89945edWink Saville Collection<InetAddress> sourceAddresses = getAddresses(); 192e822225f7a01ef088ff01f7613f953d5d89945edWink Saville return (sourceAddresses.size() == targetAddresses.size()) ? 193e822225f7a01ef088ff01f7613f953d5d89945edWink Saville sourceAddresses.containsAll(targetAddresses) : false; 194e822225f7a01ef088ff01f7613f953d5d89945edWink Saville } 195e822225f7a01ef088ff01f7613f953d5d89945edWink Saville 196e822225f7a01ef088ff01f7613f953d5d89945edWink Saville /** 197e822225f7a01ef088ff01f7613f953d5d89945edWink Saville * Compares this {@code LinkProperties} DNS addresses against the target 198e822225f7a01ef088ff01f7613f953d5d89945edWink Saville * 199e822225f7a01ef088ff01f7613f953d5d89945edWink Saville * @param target LinkProperties to compare. 200e822225f7a01ef088ff01f7613f953d5d89945edWink Saville * @return {@code true} if both are identical, {@code false} otherwise. 201e822225f7a01ef088ff01f7613f953d5d89945edWink Saville */ 202e822225f7a01ef088ff01f7613f953d5d89945edWink Saville public boolean isIdenticalDnses(LinkProperties target) { 203e822225f7a01ef088ff01f7613f953d5d89945edWink Saville Collection<InetAddress> targetDnses = target.getDnses(); 204e822225f7a01ef088ff01f7613f953d5d89945edWink Saville return (mDnses.size() == targetDnses.size()) ? 205e822225f7a01ef088ff01f7613f953d5d89945edWink Saville mDnses.containsAll(targetDnses) : false; 206e822225f7a01ef088ff01f7613f953d5d89945edWink Saville } 207e822225f7a01ef088ff01f7613f953d5d89945edWink Saville 208e822225f7a01ef088ff01f7613f953d5d89945edWink Saville /** 209e822225f7a01ef088ff01f7613f953d5d89945edWink Saville * Compares this {@code LinkProperties} Routes against the target 210e822225f7a01ef088ff01f7613f953d5d89945edWink Saville * 211e822225f7a01ef088ff01f7613f953d5d89945edWink Saville * @param target LinkProperties to compare. 212e822225f7a01ef088ff01f7613f953d5d89945edWink Saville * @return {@code true} if both are identical, {@code false} otherwise. 213e822225f7a01ef088ff01f7613f953d5d89945edWink Saville */ 214e822225f7a01ef088ff01f7613f953d5d89945edWink Saville public boolean isIdenticalRoutes(LinkProperties target) { 215e822225f7a01ef088ff01f7613f953d5d89945edWink Saville Collection<RouteInfo> targetRoutes = target.getRoutes(); 216e822225f7a01ef088ff01f7613f953d5d89945edWink Saville return (mRoutes.size() == targetRoutes.size()) ? 217e822225f7a01ef088ff01f7613f953d5d89945edWink Saville mRoutes.containsAll(targetRoutes) : false; 218e822225f7a01ef088ff01f7613f953d5d89945edWink Saville } 219e822225f7a01ef088ff01f7613f953d5d89945edWink Saville 220e822225f7a01ef088ff01f7613f953d5d89945edWink Saville /** 221e822225f7a01ef088ff01f7613f953d5d89945edWink Saville * Compares this {@code LinkProperties} HttpProxy against the target 222e822225f7a01ef088ff01f7613f953d5d89945edWink Saville * 223e822225f7a01ef088ff01f7613f953d5d89945edWink Saville * @param target LinkProperties to compare. 224e822225f7a01ef088ff01f7613f953d5d89945edWink Saville * @return {@code true} if both are identical, {@code false} otherwise. 225e822225f7a01ef088ff01f7613f953d5d89945edWink Saville */ 226e822225f7a01ef088ff01f7613f953d5d89945edWink Saville public boolean isIdenticalHttpProxy(LinkProperties target) { 227e822225f7a01ef088ff01f7613f953d5d89945edWink Saville return getHttpProxy() == null ? target.getHttpProxy() == null : 228e822225f7a01ef088ff01f7613f953d5d89945edWink Saville getHttpProxy().equals(target.getHttpProxy()); 229e822225f7a01ef088ff01f7613f953d5d89945edWink Saville } 2304e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang 2314e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang @Override 2324e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang /** 2334e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang * Compares this {@code LinkProperties} instance against the target 2344e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang * LinkProperties in {@code obj}. Two LinkPropertieses are equal if 2354e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang * all their fields are equal in values. 2364e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang * 2374e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang * For collection fields, such as mDnses, containsAll() is used to check 2384e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang * if two collections contains the same elements, independent of order. 2394e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang * There are two thoughts regarding containsAll() 2404e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang * 1. Duplicated elements. eg, (A, B, B) and (A, A, B) are equal. 2414e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang * 2. Worst case performance is O(n^2). 2424e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang * 2434e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang * @param obj the object to be tested for equality. 2444e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang * @return {@code true} if both objects are equal, {@code false} otherwise. 2454e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang */ 2464e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang public boolean equals(Object obj) { 2474e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang if (this == obj) return true; 2484e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang 2494e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang if (!(obj instanceof LinkProperties)) return false; 2504e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang 2514e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang LinkProperties target = (LinkProperties) obj; 2524e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang 253e822225f7a01ef088ff01f7613f953d5d89945edWink Saville return isIdenticalInterfaceName(target) && 254e822225f7a01ef088ff01f7613f953d5d89945edWink Saville isIdenticalAddresses(target) && 255e822225f7a01ef088ff01f7613f953d5d89945edWink Saville isIdenticalDnses(target) && 256e822225f7a01ef088ff01f7613f953d5d89945edWink Saville isIdenticalRoutes(target) && 257e822225f7a01ef088ff01f7613f953d5d89945edWink Saville isIdenticalHttpProxy(target); 258e822225f7a01ef088ff01f7613f953d5d89945edWink Saville } 2594e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang 260e822225f7a01ef088ff01f7613f953d5d89945edWink Saville /** 261e822225f7a01ef088ff01f7613f953d5d89945edWink Saville * Return two lists, a list of addresses that would be removed from 262e822225f7a01ef088ff01f7613f953d5d89945edWink Saville * mLinkAddresses and a list of addresses that would be added to 263e822225f7a01ef088ff01f7613f953d5d89945edWink Saville * mLinkAddress which would then result in target and mLinkAddresses 264e822225f7a01ef088ff01f7613f953d5d89945edWink Saville * being the same list. 265e822225f7a01ef088ff01f7613f953d5d89945edWink Saville * 2660a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt * @param target is a LinkProperties with the new list of addresses 267e822225f7a01ef088ff01f7613f953d5d89945edWink Saville * @return the removed and added lists. 268e822225f7a01ef088ff01f7613f953d5d89945edWink Saville */ 2690a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt public CompareResult<LinkAddress> compareAddresses(LinkProperties target) { 270e822225f7a01ef088ff01f7613f953d5d89945edWink Saville /* 271e822225f7a01ef088ff01f7613f953d5d89945edWink Saville * Duplicate the LinkAddresses into removed, we will be removing 272e822225f7a01ef088ff01f7613f953d5d89945edWink Saville * address which are common between mLinkAddresses and target 273e822225f7a01ef088ff01f7613f953d5d89945edWink Saville * leaving the addresses that are different. And address which 274e822225f7a01ef088ff01f7613f953d5d89945edWink Saville * are in target but not in mLinkAddresses are placed in the 275e822225f7a01ef088ff01f7613f953d5d89945edWink Saville * addedAddresses. 276e822225f7a01ef088ff01f7613f953d5d89945edWink Saville */ 2770a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt CompareResult<LinkAddress> result = new CompareResult<LinkAddress>(); 278e822225f7a01ef088ff01f7613f953d5d89945edWink Saville result.removed = new ArrayList<LinkAddress>(mLinkAddresses); 279e822225f7a01ef088ff01f7613f953d5d89945edWink Saville result.added.clear(); 2800a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt if (target != null) { 2810a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt for (LinkAddress newAddress : target.getLinkAddresses()) { 2820a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt if (! result.removed.remove(newAddress)) { 2830a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt result.added.add(newAddress); 2840a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt } 285e822225f7a01ef088ff01f7613f953d5d89945edWink Saville } 286e822225f7a01ef088ff01f7613f953d5d89945edWink Saville } 287e822225f7a01ef088ff01f7613f953d5d89945edWink Saville return result; 2884e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang } 2894e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang 2900a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt /** 2910a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt * Return two lists, a list of dns addresses that would be removed from 2920a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt * mDnses and a list of addresses that would be added to 2930a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt * mDnses which would then result in target and mDnses 2940a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt * being the same list. 2950a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt * 2960a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt * @param target is a LinkProperties with the new list of dns addresses 2970a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt * @return the removed and added lists. 2980a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt */ 2990a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt public CompareResult<InetAddress> compareDnses(LinkProperties target) { 3000a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt /* 3010a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt * Duplicate the InetAddresses into removed, we will be removing 3020a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt * dns address which are common between mDnses and target 3030a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt * leaving the addresses that are different. And dns address which 3040a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt * are in target but not in mDnses are placed in the 3050a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt * addedAddresses. 3060a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt */ 3070a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt CompareResult<InetAddress> result = new CompareResult<InetAddress>(); 3080a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt 3090a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt result.removed = new ArrayList<InetAddress>(mDnses); 3100a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt result.added.clear(); 3110a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt if (target != null) { 3120a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt for (InetAddress newAddress : target.getDnses()) { 3130a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt if (! result.removed.remove(newAddress)) { 3140a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt result.added.add(newAddress); 3150a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt } 3160a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt } 3170a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt } 3180a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt return result; 3190a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt } 3200a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt 3210a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt /** 3220a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt * Return two lists, a list of routes that would be removed from 3230a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt * mRoutes and a list of routes that would be added to 3240a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt * mRoutes which would then result in target and mRoutes 3250a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt * being the same list. 3260a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt * 3270a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt * @param target is a LinkProperties with the new list of routes 3280a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt * @return the removed and added lists. 3290a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt */ 3300a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt public CompareResult<RouteInfo> compareRoutes(LinkProperties target) { 3310a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt /* 3320a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt * Duplicate the RouteInfos into removed, we will be removing 3330a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt * routes which are common between mDnses and target 3340a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt * leaving the routes that are different. And route address which 3350a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt * are in target but not in mRoutes are placed in added. 3360a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt */ 3370a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt CompareResult<RouteInfo> result = new CompareResult<RouteInfo>(); 3380a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt 3390a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt result.removed = new ArrayList<RouteInfo>(mRoutes); 3400a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt result.added.clear(); 3410a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt if (target != null) { 3420a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt for (RouteInfo r : target.getRoutes()) { 3430a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt if (! result.removed.remove(r)) { 3440a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt result.added.add(r); 3450a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt } 3460a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt } 3470a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt } 3480a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt return result; 3490a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt } 3500a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt 3510a46db5d88461d9a6c85bb2e95982ac4c511d57eRobert Greenwalt 3524e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang @Override 3534e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang /** 3544e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang * generate hashcode based on significant fields 3554e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang * Equal objects must produce the same hash code, while unequal objects 3564e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang * may have the same hash codes. 3574e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang */ 3584e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang public int hashCode() { 3594e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang return ((null == mIfaceName) ? 0 : mIfaceName.hashCode() 3604e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang + mLinkAddresses.size() * 31 3614e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang + mDnses.size() * 37 362aa70f101e08098ed9cb190abe2d7f952561026b8Robert Greenwalt + mRoutes.size() * 41 3634e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang + ((null == mHttpProxy) ? 0 : mHttpProxy.hashCode())); 3644e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang } 3654e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang 36647f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt /** 36747f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt * Implement the Parcelable interface. 36847f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt * @hide 36947f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt */ 37037e65ebb7eb932e1a144b1cab262e11ca5fd109bRobert Greenwalt public void writeToParcel(Parcel dest, int flags) { 37147f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt dest.writeString(getInterfaceName()); 372ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff dest.writeInt(mLinkAddresses.size()); 373ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff for(LinkAddress linkAddress : mLinkAddresses) { 374ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff dest.writeParcelable(linkAddress, flags); 37547f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt } 376ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff 37747f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt dest.writeInt(mDnses.size()); 37847f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt for(InetAddress d : mDnses) { 37947f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt dest.writeByteArray(d.getAddress()); 38047f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt } 381992564e481af13cbcb058ee801f9254a520c54a1Robert Greenwalt 382aa70f101e08098ed9cb190abe2d7f952561026b8Robert Greenwalt dest.writeInt(mRoutes.size()); 383aa70f101e08098ed9cb190abe2d7f952561026b8Robert Greenwalt for(RouteInfo route : mRoutes) { 384aa70f101e08098ed9cb190abe2d7f952561026b8Robert Greenwalt dest.writeParcelable(route, flags); 38547f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt } 386992564e481af13cbcb058ee801f9254a520c54a1Robert Greenwalt 38747f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt if (mHttpProxy != null) { 38847f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt dest.writeByte((byte)1); 38947f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt dest.writeParcelable(mHttpProxy, flags); 39047f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt } else { 39147f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt dest.writeByte((byte)0); 39247f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt } 39347f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt } 39447f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt 39547f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt /** 39647f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt * Implement the Parcelable interface. 39747f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt * @hide 39847f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt */ 39937e65ebb7eb932e1a144b1cab262e11ca5fd109bRobert Greenwalt public static final Creator<LinkProperties> CREATOR = 40037e65ebb7eb932e1a144b1cab262e11ca5fd109bRobert Greenwalt new Creator<LinkProperties>() { 40137e65ebb7eb932e1a144b1cab262e11ca5fd109bRobert Greenwalt public LinkProperties createFromParcel(Parcel in) { 40237e65ebb7eb932e1a144b1cab262e11ca5fd109bRobert Greenwalt LinkProperties netProp = new LinkProperties(); 40347f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt String iface = in.readString(); 40447f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt if (iface != null) { 40547f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt try { 406ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff netProp.setInterfaceName(iface); 40747f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt } catch (Exception e) { 40847f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt return null; 40947f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt } 41047f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt } 41147f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt int addressCount = in.readInt(); 41247f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt for (int i=0; i<addressCount; i++) { 413ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff netProp.addLinkAddress((LinkAddress)in.readParcelable(null)); 41447f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt } 41547f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt addressCount = in.readInt(); 41647f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt for (int i=0; i<addressCount; i++) { 41747f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt try { 4181cf56ab9c68334d9124c52bcede06aaa0b17c730Irfan Sheriff netProp.addDns(InetAddress.getByAddress(in.createByteArray())); 41947f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt } catch (UnknownHostException e) { } 42047f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt } 421992564e481af13cbcb058ee801f9254a520c54a1Robert Greenwalt addressCount = in.readInt(); 422992564e481af13cbcb058ee801f9254a520c54a1Robert Greenwalt for (int i=0; i<addressCount; i++) { 423aa70f101e08098ed9cb190abe2d7f952561026b8Robert Greenwalt netProp.addRoute((RouteInfo)in.readParcelable(null)); 42447f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt } 42547f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt if (in.readByte() == 1) { 42647f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt netProp.setHttpProxy((ProxyProperties)in.readParcelable(null)); 42747f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt } 42847f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt return netProp; 42947f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt } 43047f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt 43137e65ebb7eb932e1a144b1cab262e11ca5fd109bRobert Greenwalt public LinkProperties[] newArray(int size) { 43237e65ebb7eb932e1a144b1cab262e11ca5fd109bRobert Greenwalt return new LinkProperties[size]; 43347f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt } 43447f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt }; 43547f69fe2999e46004f2f2463b70d38de9ff7079aRobert Greenwalt} 436