1819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott/* 2819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott * Copyright (C) 2016 The Android Open Source Project 3819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott * 4819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott * Licensed under the Apache License, Version 2.0 (the "License"); 5819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott * you may not use this file except in compliance with the License. 6819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott * You may obtain a copy of the License at 7819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott * 8819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott * http://www.apache.org/licenses/LICENSE-2.0 9819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott * 10819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott * Unless required by applicable law or agreed to in writing, software 11819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott * distributed under the License is distributed on an "AS IS" BASIS, 12819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott * See the License for the specific language governing permissions and 14819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott * limitations under the License. 15819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott */ 16819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerottpackage com.android.contacts.editor; 17819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott 18819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerottimport android.content.Context; 1973b283f03cd2697ad0098711d62cd0956037952fMarcus Hagerottimport android.os.Bundle; 20819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerottimport android.support.annotation.NonNull; 21819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerottimport android.support.annotation.StringRes; 22819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerottimport android.view.View; 23819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerottimport android.widget.AdapterView; 24819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerottimport android.widget.ImageView; 25819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerottimport android.widget.ListPopupWindow; 26819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerottimport android.widget.TextView; 27819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott 28819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerottimport com.android.contacts.R; 2975895e73379aa26a3d4135c772af4ecb8a79b4c9Marcus Hagerottimport com.android.contacts.model.account.AccountInfo; 3069c182afb0e6d82a341a28b4317aa703af768906Gary Maiimport com.android.contacts.model.account.AccountWithDataSet; 3169c182afb0e6d82a341a28b4317aa703af768906Gary Maiimport com.android.contacts.util.AccountsListAdapter; 32819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerottimport com.android.contacts.util.UiClosables; 33819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott 34819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerottimport java.util.List; 35819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott 36819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott/** 37819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott * Controls the display of an account selector or header. 38819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott * 39819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott * TODO: This was mostly copied from {@link RawContactEditorView}. The code in that class 40819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott * should probably be modified to use this instead of leaving it duplicated. 41819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott */ 42819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerottpublic class AccountHeaderPresenter { 43819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott 4473b283f03cd2697ad0098711d62cd0956037952fMarcus Hagerott private static final String KEY_SELECTED_ACCOUNT = "accountHeaderSelectedAccount"; 4573b283f03cd2697ad0098711d62cd0956037952fMarcus Hagerott 46819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott public interface Observer { 47819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott void onChange(AccountHeaderPresenter sender); 48819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott 49819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott public static final Observer NONE = new Observer() { 50819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott @Override 51819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott public void onChange(AccountHeaderPresenter sender) { 52819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott } 53819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott }; 54819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott } 55819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott 56819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott private final Context mContext; 57819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott 5875895e73379aa26a3d4135c772af4ecb8a79b4c9Marcus Hagerott private List<AccountInfo> mAccounts; 59819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott private AccountWithDataSet mCurrentAccount; 60819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott 61819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott // Account header 62819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott private final View mAccountHeaderContainer; 63819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott private TextView mAccountHeaderType; 64819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott private TextView mAccountHeaderName; 65819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott private ImageView mAccountHeaderIcon; 66819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott private ImageView mAccountHeaderExpanderIcon; 67819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott 68819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott // This would be different if the account was readonly 69819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott @StringRes 70819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott private int mSelectorTitle = R.string.editor_account_selector_title; 71819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott 72819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott private Observer mObserver = Observer.NONE; 73819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott 74819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott public AccountHeaderPresenter(View container) { 75819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott mContext = container.getContext(); 76819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott mAccountHeaderContainer = container; 777217e6986c333aebb885b0a07a0a9344ef7a814cMarcus Hagerott // mAccountHeaderType is optional and may not be in the container view in which case 787217e6986c333aebb885b0a07a0a9344ef7a814cMarcus Hagerott // the variable will be null 79819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott mAccountHeaderType = (TextView) container.findViewById(R.id.account_type); 80819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott mAccountHeaderName = (TextView) container.findViewById(R.id.account_name); 81819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott mAccountHeaderIcon = (ImageView) container.findViewById(R.id.account_type_icon); 82819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott mAccountHeaderExpanderIcon = (ImageView) container.findViewById(R.id.account_expander_icon); 83819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott } 84819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott 85819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott public void setObserver(Observer observer) { 86819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott mObserver = observer; 87819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott } 88819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott 89819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott public void setCurrentAccount(@NonNull AccountWithDataSet account) { 90819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott if (mCurrentAccount != null && mCurrentAccount.equals(account)) { 91819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott return; 92819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott } 93819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott mCurrentAccount = account; 94819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott if (mObserver != null) { 95819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott mObserver.onChange(this); 96819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott } 97819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott updateDisplayedAccount(); 98819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott } 99819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott 10075895e73379aa26a3d4135c772af4ecb8a79b4c9Marcus Hagerott public void setAccounts(List<AccountInfo> accounts) { 101e7a71cbbe8929a9d8a7ca0a3b5668646d49a611aMarcus Hagerott mAccounts = accounts; 102a181ca6021333cbb96ff9a6abeec9e64ea19c7f9Marcus Hagerott // If the current account hasn't been set or it has been removed just use the first 103a181ca6021333cbb96ff9a6abeec9e64ea19c7f9Marcus Hagerott // account. 104a181ca6021333cbb96ff9a6abeec9e64ea19c7f9Marcus Hagerott if (mCurrentAccount == null || !AccountInfo.contains(mAccounts, mCurrentAccount)) { 10575895e73379aa26a3d4135c772af4ecb8a79b4c9Marcus Hagerott mCurrentAccount = mAccounts.isEmpty() ? null : accounts.get(0).getAccount(); 106e7a71cbbe8929a9d8a7ca0a3b5668646d49a611aMarcus Hagerott mObserver.onChange(this); 107e7a71cbbe8929a9d8a7ca0a3b5668646d49a611aMarcus Hagerott } 108e7a71cbbe8929a9d8a7ca0a3b5668646d49a611aMarcus Hagerott updateDisplayedAccount(); 109e7a71cbbe8929a9d8a7ca0a3b5668646d49a611aMarcus Hagerott } 110e7a71cbbe8929a9d8a7ca0a3b5668646d49a611aMarcus Hagerott 111819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott public AccountWithDataSet getCurrentAccount() { 11275895e73379aa26a3d4135c772af4ecb8a79b4c9Marcus Hagerott return mCurrentAccount != null ? mCurrentAccount : null; 113819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott } 114819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott 11573b283f03cd2697ad0098711d62cd0956037952fMarcus Hagerott public void onSaveInstanceState(Bundle outState) { 11673b283f03cd2697ad0098711d62cd0956037952fMarcus Hagerott outState.putParcelable(KEY_SELECTED_ACCOUNT, mCurrentAccount); 11773b283f03cd2697ad0098711d62cd0956037952fMarcus Hagerott } 11873b283f03cd2697ad0098711d62cd0956037952fMarcus Hagerott 11973b283f03cd2697ad0098711d62cd0956037952fMarcus Hagerott public void onRestoreInstanceState(Bundle savedInstanceState) { 12073b283f03cd2697ad0098711d62cd0956037952fMarcus Hagerott if (savedInstanceState == null) return; 12173b283f03cd2697ad0098711d62cd0956037952fMarcus Hagerott if (mCurrentAccount == null) { 12273b283f03cd2697ad0098711d62cd0956037952fMarcus Hagerott mCurrentAccount = savedInstanceState.getParcelable(KEY_SELECTED_ACCOUNT); 12373b283f03cd2697ad0098711d62cd0956037952fMarcus Hagerott } 12473b283f03cd2697ad0098711d62cd0956037952fMarcus Hagerott updateDisplayedAccount(); 12573b283f03cd2697ad0098711d62cd0956037952fMarcus Hagerott } 12673b283f03cd2697ad0098711d62cd0956037952fMarcus Hagerott 127819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott private void updateDisplayedAccount() { 128819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott mAccountHeaderContainer.setVisibility(View.GONE); 129819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott if (mCurrentAccount == null) return; 130e7a71cbbe8929a9d8a7ca0a3b5668646d49a611aMarcus Hagerott if (mAccounts == null) return; 131819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott 13275895e73379aa26a3d4135c772af4ecb8a79b4c9Marcus Hagerott final String accountLabel = getAccountLabel(mCurrentAccount); 133819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott 134c2093f312f71e730e1cc4daaa305782fda394215Marcus Hagerott if (mAccounts.size() > 1) { 135819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott addAccountSelector(accountLabel); 136819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott } else { 137819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott addAccountHeader(accountLabel); 138819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott } 139819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott } 140819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott 141819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott private void addAccountHeader(String accountLabel) { 142819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott mAccountHeaderContainer.setVisibility(View.VISIBLE); 143819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott 144819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott // Set the account name 145819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott mAccountHeaderName.setVisibility(View.VISIBLE); 146819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott mAccountHeaderName.setText(accountLabel); 147819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott 148819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott // Set the account type 149819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott final String selectorTitle = mContext.getResources().getString(mSelectorTitle); 1507217e6986c333aebb885b0a07a0a9344ef7a814cMarcus Hagerott if (mAccountHeaderType != null) { 1517217e6986c333aebb885b0a07a0a9344ef7a814cMarcus Hagerott mAccountHeaderType.setText(selectorTitle); 1527217e6986c333aebb885b0a07a0a9344ef7a814cMarcus Hagerott } 153819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott 15475895e73379aa26a3d4135c772af4ecb8a79b4c9Marcus Hagerott final AccountInfo accountInfo = AccountInfo.getAccount(mAccounts, mCurrentAccount); 15575895e73379aa26a3d4135c772af4ecb8a79b4c9Marcus Hagerott 156819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott // Set the icon 15775895e73379aa26a3d4135c772af4ecb8a79b4c9Marcus Hagerott mAccountHeaderIcon.setImageDrawable(accountInfo.getIcon()); 158819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott 159819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott // Set the content description 160819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott mAccountHeaderContainer.setContentDescription( 161819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott EditorUiUtils.getAccountInfoContentDescription(accountLabel, 162819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott selectorTitle)); 163819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott } 164819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott 165819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott private void addAccountSelector(CharSequence nameLabel) { 166819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott final View.OnClickListener onClickListener = new View.OnClickListener() { 167819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott @Override 168819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott public void onClick(View v) { 16973b283f03cd2697ad0098711d62cd0956037952fMarcus Hagerott showPopup(); 170819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott } 171819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott }; 172819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott setUpAccountSelector(nameLabel.toString(), onClickListener); 173819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott } 174819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott 17573b283f03cd2697ad0098711d62cd0956037952fMarcus Hagerott private void showPopup() { 17673b283f03cd2697ad0098711d62cd0956037952fMarcus Hagerott final ListPopupWindow popup = new ListPopupWindow(mContext); 17773b283f03cd2697ad0098711d62cd0956037952fMarcus Hagerott final AccountsListAdapter adapter = 178c2093f312f71e730e1cc4daaa305782fda394215Marcus Hagerott new AccountsListAdapter(mContext, mAccounts, mCurrentAccount); 17973b283f03cd2697ad0098711d62cd0956037952fMarcus Hagerott popup.setWidth(mAccountHeaderContainer.getWidth()); 18073b283f03cd2697ad0098711d62cd0956037952fMarcus Hagerott popup.setAnchorView(mAccountHeaderContainer); 18173b283f03cd2697ad0098711d62cd0956037952fMarcus Hagerott popup.setAdapter(adapter); 18273b283f03cd2697ad0098711d62cd0956037952fMarcus Hagerott popup.setModal(true); 18373b283f03cd2697ad0098711d62cd0956037952fMarcus Hagerott popup.setInputMethodMode(ListPopupWindow.INPUT_METHOD_NOT_NEEDED); 18473b283f03cd2697ad0098711d62cd0956037952fMarcus Hagerott popup.setOnItemClickListener(new AdapterView.OnItemClickListener() { 18573b283f03cd2697ad0098711d62cd0956037952fMarcus Hagerott @Override 18673b283f03cd2697ad0098711d62cd0956037952fMarcus Hagerott public void onItemClick(AdapterView<?> parent, View view, int position, 18773b283f03cd2697ad0098711d62cd0956037952fMarcus Hagerott long id) { 18873b283f03cd2697ad0098711d62cd0956037952fMarcus Hagerott UiClosables.closeQuietly(popup); 18973b283f03cd2697ad0098711d62cd0956037952fMarcus Hagerott final AccountWithDataSet newAccount = adapter.getItem(position); 19073b283f03cd2697ad0098711d62cd0956037952fMarcus Hagerott setCurrentAccount(newAccount); 191d3869c7ab4ff85fc9e3a511ea6644be395698321Marcus Hagerott // Make sure the new selection will be announced once it's changed 192d3869c7ab4ff85fc9e3a511ea6644be395698321Marcus Hagerott mAccountHeaderContainer.setAccessibilityLiveRegion( 193d3869c7ab4ff85fc9e3a511ea6644be395698321Marcus Hagerott View.ACCESSIBILITY_LIVE_REGION_POLITE); 19473b283f03cd2697ad0098711d62cd0956037952fMarcus Hagerott } 19573b283f03cd2697ad0098711d62cd0956037952fMarcus Hagerott }); 19673b283f03cd2697ad0098711d62cd0956037952fMarcus Hagerott mAccountHeaderContainer.post(new Runnable() { 19773b283f03cd2697ad0098711d62cd0956037952fMarcus Hagerott @Override 19873b283f03cd2697ad0098711d62cd0956037952fMarcus Hagerott public void run() { 19973b283f03cd2697ad0098711d62cd0956037952fMarcus Hagerott popup.show(); 20073b283f03cd2697ad0098711d62cd0956037952fMarcus Hagerott } 20173b283f03cd2697ad0098711d62cd0956037952fMarcus Hagerott }); 20273b283f03cd2697ad0098711d62cd0956037952fMarcus Hagerott } 20373b283f03cd2697ad0098711d62cd0956037952fMarcus Hagerott 204819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott private void setUpAccountSelector(String nameLabel, View.OnClickListener listener) { 205819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott addAccountHeader(nameLabel); 206819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott // Add handlers for choosing another account to save to. 207819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott mAccountHeaderExpanderIcon.setVisibility(View.VISIBLE); 2084b11232fdf9e11e73b2ffa41b40f3e153ec3912bMarcus Hagerott // Add the listener to the icon so that it will be announced by talkback as a clickable 2094b11232fdf9e11e73b2ffa41b40f3e153ec3912bMarcus Hagerott // element 2104b11232fdf9e11e73b2ffa41b40f3e153ec3912bMarcus Hagerott mAccountHeaderExpanderIcon.setOnClickListener(listener); 211819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott mAccountHeaderContainer.setOnClickListener(listener); 212819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott } 213819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott 21475895e73379aa26a3d4135c772af4ecb8a79b4c9Marcus Hagerott private String getAccountLabel(AccountWithDataSet account) { 21575895e73379aa26a3d4135c772af4ecb8a79b4c9Marcus Hagerott final AccountInfo accountInfo = AccountInfo.getAccount(mAccounts, account); 21675895e73379aa26a3d4135c772af4ecb8a79b4c9Marcus Hagerott return accountInfo != null ? accountInfo.getNameLabel().toString() : null; 217819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott } 218819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott} 219