PhoneFactory.java revision 8a4c72815186db4187587d4fc62125540a0e42a8
19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* 29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2006 The Android Open Source Project 39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License. 69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at 79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and 149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License. 159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage com.android.internal.telephony; 189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 19f5c6eff63d19a9f7a970a4f90619edac873c006dGilles Debunneimport android.content.ComponentName; 20f5c6eff63d19a9f7a970a4f90619edac873c006dGilles Debunneimport android.content.Context; 219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.net.LocalServerSocket; 229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Looper; 23fcca00accb923d3cbda4e0d6f5540b10e8279cd2Adam Powellimport android.provider.Settings; 24fcca00accb923d3cbda4e0d6f5540b10e8279cd2Adam Powellimport android.telephony.Rlog; 259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.telephony.TelephonyManager; 269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.internal.telephony.cdma.CDMALTEPhone; 289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.internal.telephony.cdma.CDMAPhone; 299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager; 309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.internal.telephony.gsm.GSMPhone; 319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.internal.telephony.sip.SipPhone; 329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.internal.telephony.sip.SipPhoneFactory; 339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.internal.telephony.uicc.UiccController; 349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/** 369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@hide} 379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class PhoneFactory { 399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static final String LOG_TAG = "PhoneFactory"; 409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static final int SOCKET_OPEN_RETRY_MILLIS = 2 * 1000; 419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static final int SOCKET_OPEN_MAX_RETRY = 3; 4241ec65355bd6ded652769725b276d47c54a0d913Scott Main 4341ec65355bd6ded652769725b276d47c54a0d913Scott Main //***** Class Variables 4441ec65355bd6ded652769725b276d47c54a0d913Scott Main 459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static private Phone sProxyPhone = null; 469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static private CommandsInterface sCommandsInterface = null; 479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 489295ada0ec89fa7a666be4a2f1006a4b722adf4fRomain Guy static private boolean sMadeDefaults = false; 499295ada0ec89fa7a666be4a2f1006a4b722adf4fRomain Guy static private PhoneNotifier sPhoneNotifier; 509295ada0ec89fa7a666be4a2f1006a4b722adf4fRomain Guy static private Looper sLooper; 519295ada0ec89fa7a666be4a2f1006a4b722adf4fRomain Guy static private Context sContext; 529295ada0ec89fa7a666be4a2f1006a4b722adf4fRomain Guy 539295ada0ec89fa7a666be4a2f1006a4b722adf4fRomain Guy //***** Class Methods 549295ada0ec89fa7a666be4a2f1006a4b722adf4fRomain Guy 559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static void makeDefaultPhones(Context context) { 569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project makeDefaultPhone(context); 579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * FIXME replace this with some other way of making these 619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * instances 62fcca00accb923d3cbda4e0d6f5540b10e8279cd2Adam Powell */ 63fcca00accb923d3cbda4e0d6f5540b10e8279cd2Adam Powell public static void makeDefaultPhone(Context context) { 64fcca00accb923d3cbda4e0d6f5540b10e8279cd2Adam Powell synchronized(Phone.class) { 65fcca00accb923d3cbda4e0d6f5540b10e8279cd2Adam Powell if (!sMadeDefaults) { 66fcca00accb923d3cbda4e0d6f5540b10e8279cd2Adam Powell sLooper = Looper.myLooper(); 67fcca00accb923d3cbda4e0d6f5540b10e8279cd2Adam Powell sContext = context; 68fcca00accb923d3cbda4e0d6f5540b10e8279cd2Adam Powell 69fcca00accb923d3cbda4e0d6f5540b10e8279cd2Adam Powell if (sLooper == null) { 70fcca00accb923d3cbda4e0d6f5540b10e8279cd2Adam Powell throw new RuntimeException( 71fcca00accb923d3cbda4e0d6f5540b10e8279cd2Adam Powell "PhoneFactory.makeDefaultPhone must be called from Looper thread"); 72fcca00accb923d3cbda4e0d6f5540b10e8279cd2Adam Powell } 73fcca00accb923d3cbda4e0d6f5540b10e8279cd2Adam Powell 74fcca00accb923d3cbda4e0d6f5540b10e8279cd2Adam Powell int retryCount = 0; 75fcca00accb923d3cbda4e0d6f5540b10e8279cd2Adam Powell for(;;) { 76fcca00accb923d3cbda4e0d6f5540b10e8279cd2Adam Powell boolean hasException = false; 77fcca00accb923d3cbda4e0d6f5540b10e8279cd2Adam Powell retryCount ++; 78fcca00accb923d3cbda4e0d6f5540b10e8279cd2Adam Powell 799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // use UNIX domain socket to 819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // prevent subsequent initialization 82bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev new LocalServerSocket("com.android.internal.telephony"); 839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (java.io.IOException ex) { 849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project hasException = true; 859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if ( !hasException ) { 889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (retryCount > SOCKET_OPEN_MAX_RETRY) { 909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new RuntimeException("PhoneFactory probably already running"); 919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 92bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev try { 93c1f9c40c23a756a11394a35f37053f796494b224Karl Rosaen Thread.sleep(SOCKET_OPEN_RETRY_MILLIS); 949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (InterruptedException er) { 959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sPhoneNotifier = new DefaultPhoneNotifier(); 100bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev 1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Get preferred network mode 1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int preferredNetworkMode = RILConstants.PREFERRED_NETWORK_MODE; 103bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev if (TelephonyManager.getLteOnCdmaModeStatic() == PhoneConstants.LTE_ON_CDMA_TRUE) { 1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project preferredNetworkMode = Phone.NT_MODE_GLOBAL; 105bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev } 106bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev int networkMode = Settings.Global.getInt(context.getContentResolver(), 107d68478467e3f837511196c80891d7245d0e163dfDianne Hackborn Settings.Global.PREFERRED_NETWORK_MODE, preferredNetworkMode); 108d68478467e3f837511196c80891d7245d0e163dfDianne Hackborn Rlog.i(LOG_TAG, "Network Mode set to " + Integer.toString(networkMode)); 109d68478467e3f837511196c80891d7245d0e163dfDianne Hackborn 110d68478467e3f837511196c80891d7245d0e163dfDianne Hackborn int cdmaSubscription = CdmaSubscriptionSourceManager.getDefault(context); 111d68478467e3f837511196c80891d7245d0e163dfDianne Hackborn Rlog.i(LOG_TAG, "Cdma Subscription set to " + cdmaSubscription); 112d68478467e3f837511196c80891d7245d0e163dfDianne Hackborn 113d68478467e3f837511196c80891d7245d0e163dfDianne Hackborn //reads the system properties and makes commandsinterface 114d68478467e3f837511196c80891d7245d0e163dfDianne Hackborn sCommandsInterface = new RIL(context, networkMode, cdmaSubscription); 115d68478467e3f837511196c80891d7245d0e163dfDianne Hackborn 116d68478467e3f837511196c80891d7245d0e163dfDianne Hackborn // Instantiate UiccController so that all other classes can just call getInstance() 117d68478467e3f837511196c80891d7245d0e163dfDianne Hackborn UiccController.make(context, sCommandsInterface); 118d68478467e3f837511196c80891d7245d0e163dfDianne Hackborn 119d68478467e3f837511196c80891d7245d0e163dfDianne Hackborn int phoneType = TelephonyManager.getPhoneType(networkMode); 1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (phoneType == PhoneConstants.PHONE_TYPE_GSM) { 121bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev Rlog.i(LOG_TAG, "Creating GSMPhone"); 122bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev sProxyPhone = new PhoneProxy(new GSMPhone(context, 1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sCommandsInterface, sPhoneNotifier)); 1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) { 125bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev switch (TelephonyManager.getLteOnCdmaModeStatic()) { 1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case PhoneConstants.LTE_ON_CDMA_TRUE: 1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Rlog.i(LOG_TAG, "Creating CDMALTEPhone"); 128bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev sProxyPhone = new PhoneProxy(new CDMALTEPhone(context, 1295b1b2417106f161e4bc66296888f4685f213eebdRomain Guy sCommandsInterface, sPhoneNotifier)); 1305b1b2417106f161e4bc66296888f4685f213eebdRomain Guy break; 1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case PhoneConstants.LTE_ON_CDMA_FALSE: 1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project default: 1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Rlog.i(LOG_TAG, "Creating CDMAPhone"); 1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sProxyPhone = new PhoneProxy(new CDMAPhone(context, 1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sCommandsInterface, sPhoneNotifier)); 1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1395b1b2417106f161e4bc66296888f4685f213eebdRomain Guy 1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Ensure that we have a default SMS app. Requesting the app with 141fcca00accb923d3cbda4e0d6f5540b10e8279cd2Adam Powell // updateIfNeeded set to true is enough to configure a default SMS app. 142fcca00accb923d3cbda4e0d6f5540b10e8279cd2Adam Powell ComponentName componentName = 143fcca00accb923d3cbda4e0d6f5540b10e8279cd2Adam Powell SmsApplication.getDefaultSmsApplication(context, true /* updateIfNeeded */); 144fcca00accb923d3cbda4e0d6f5540b10e8279cd2Adam Powell String packageName = "NONE"; 145fcca00accb923d3cbda4e0d6f5540b10e8279cd2Adam Powell if (componentName != null) { 146fcca00accb923d3cbda4e0d6f5540b10e8279cd2Adam Powell packageName = componentName.getPackageName(); 1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Rlog.i(LOG_TAG, "defaultSmsApplication: " + packageName); 1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Set up monitor to watch for changes to SMS packages 1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SmsApplication.initSmsPackageMonitor(context); 1529295ada0ec89fa7a666be4a2f1006a4b722adf4fRomain Guy 1539295ada0ec89fa7a666be4a2f1006a4b722adf4fRomain Guy sMadeDefaults = true; 1549295ada0ec89fa7a666be4a2f1006a4b722adf4fRomain Guy } 1559295ada0ec89fa7a666be4a2f1006a4b722adf4fRomain Guy } 1569295ada0ec89fa7a666be4a2f1006a4b722adf4fRomain Guy } 1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1583f7f7ac30af6ea572aca44df91363cff7fcd9fefAdam Powell public static Phone getDefaultPhone() { 1593f7f7ac30af6ea572aca44df91363cff7fcd9fefAdam Powell if (sLooper != Looper.myLooper()) { 1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new RuntimeException( 1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "PhoneFactory.getDefaultPhone must be called from Looper thread"); 1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!sMadeDefaults) { 1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IllegalStateException("Default phones haven't been made yet!"); 1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return sProxyPhone; 1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static Phone getCdmaPhone() { 1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Phone phone; 1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project synchronized(PhoneProxy.lockForRadioTechnologyChange) { 1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project switch (TelephonyManager.getLteOnCdmaModeStatic()) { 1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case PhoneConstants.LTE_ON_CDMA_TRUE: { 1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project phone = new CDMALTEPhone(sContext, sCommandsInterface, sPhoneNotifier); 1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case PhoneConstants.LTE_ON_CDMA_FALSE: 1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case PhoneConstants.LTE_ON_CDMA_UNKNOWN: 1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project default: { 1819295ada0ec89fa7a666be4a2f1006a4b722adf4fRomain Guy phone = new CDMAPhone(sContext, sCommandsInterface, sPhoneNotifier); 1825b1b2417106f161e4bc66296888f4685f213eebdRomain Guy break; 183fcca00accb923d3cbda4e0d6f5540b10e8279cd2Adam Powell } 184fcca00accb923d3cbda4e0d6f5540b10e8279cd2Adam Powell } 185fcca00accb923d3cbda4e0d6f5540b10e8279cd2Adam Powell } 186fcca00accb923d3cbda4e0d6f5540b10e8279cd2Adam Powell return phone; 1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static Phone getGsmPhone() { 1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project synchronized(PhoneProxy.lockForRadioTechnologyChange) { 191fcca00accb923d3cbda4e0d6f5540b10e8279cd2Adam Powell Phone phone = new GSMPhone(sContext, sCommandsInterface, sPhoneNotifier); 192fcca00accb923d3cbda4e0d6f5540b10e8279cd2Adam Powell return phone; 193fcca00accb923d3cbda4e0d6f5540b10e8279cd2Adam Powell } 194fcca00accb923d3cbda4e0d6f5540b10e8279cd2Adam Powell } 195fcca00accb923d3cbda4e0d6f5540b10e8279cd2Adam Powell 196fcca00accb923d3cbda4e0d6f5540b10e8279cd2Adam Powell /** 197fcca00accb923d3cbda4e0d6f5540b10e8279cd2Adam Powell * Makes a {@link SipPhone} object. 198fcca00accb923d3cbda4e0d6f5540b10e8279cd2Adam Powell * @param sipUri the local SIP URI the phone runs on 199fcca00accb923d3cbda4e0d6f5540b10e8279cd2Adam Powell * @return the {@code SipPhone} object or null if the SIP URI is not valid 200fcca00accb923d3cbda4e0d6f5540b10e8279cd2Adam Powell */ 201fcca00accb923d3cbda4e0d6f5540b10e8279cd2Adam Powell public static SipPhone makeSipPhone(String sipUri) { 202fcca00accb923d3cbda4e0d6f5540b10e8279cd2Adam Powell return SipPhoneFactory.makePhone(sipUri, sContext, sPhoneNotifier); 203fcca00accb923d3cbda4e0d6f5540b10e8279cd2Adam Powell } 204e0a799a2ac1ca78e30fbac9e4e12a063425c08d3Patrick Dubroy} 205e0a799a2ac1ca78e30fbac9e4e12a063425c08d3Patrick Dubroy