15c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn/*
25c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn * Copyright (C) 2011 The Android Open Source Project
35c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn *
45c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn * Licensed under the Apache License, Version 2.0 (the "License");
55c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn * you may not use this file except in compliance with the License.
65c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn * You may obtain a copy of the License at
75c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn *
85c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn *      http://www.apache.org/licenses/LICENSE-2.0
95c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn *
105c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn * Unless required by applicable law or agreed to in writing, software
115c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn * distributed under the License is distributed on an "AS IS" BASIS,
125c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
135c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn * See the License for the specific language governing permissions and
145c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn * limitations under the License.
155c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn */
165c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn
175c1637087453de15e31861f073eae5133c4e9f7bDianne Hackbornpackage android.support.v4.app;
185c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn
190574ca37da4619afe4e26753f5a1b4de314b6565Svetoslav Ganovimport java.util.ArrayList;
200574ca37da4619afe4e26753f5a1b4de314b6565Svetoslav Ganov
215c1637087453de15e31861f073eae5133c4e9f7bDianne Hackbornimport android.os.Bundle;
225c1637087453de15e31861f073eae5133c4e9f7bDianne Hackbornimport android.os.Parcelable;
235c1637087453de15e31861f073eae5133c4e9f7bDianne Hackbornimport android.support.v4.view.PagerAdapter;
245c1637087453de15e31861f073eae5133c4e9f7bDianne Hackbornimport android.util.Log;
255c1637087453de15e31861f073eae5133c4e9f7bDianne Hackbornimport android.view.View;
26583d8a1ff64c7c59dd4e11759f3d8e994ce878d9Adam Powellimport android.view.ViewGroup;
27583d8a1ff64c7c59dd4e11759f3d8e994ce878d9Adam Powell
280574ca37da4619afe4e26753f5a1b4de314b6565Svetoslav Ganov/**
290574ca37da4619afe4e26753f5a1b4de314b6565Svetoslav Ganov * Implementation of {@link android.support.v4.view.PagerAdapter} that
300574ca37da4619afe4e26753f5a1b4de314b6565Svetoslav Ganov * uses a {@link Fragment} to manage each page. This class also handles
310574ca37da4619afe4e26753f5a1b4de314b6565Svetoslav Ganov * saving and restoring of fragment's state.
327dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn *
337dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * <p>This version of the pager is more useful when there are a large number
347dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * of pages, working more like a list view.  When pages are not visible to
357dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * the user, their entire fragment may be destroyed, only keeping the saved
367dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * state of that fragment.  This allows the pager to hold on to much less
377dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * memory associated with each visited page as compared to
387dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * {@link FragmentPagerAdapter} at the cost of potentially more overhead when
397dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * switching between pages.
407dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn *
417dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * <p>When using FragmentPagerAdapter the host ViewPager must have a
427dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * valid ID set.</p>
437dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn *
447dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * <p>Subclasses only need to implement {@link #getItem(int)}
457dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * and {@link #getCount()} to have a working adapter.
467dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn *
477dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * <p>Here is an example implementation of a pager containing fragments of
487dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * lists:
497dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn *
507dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * {@sample development/samples/Support13Demos/src/com/example/android/supportv13/app/FragmentStatePagerSupport.java
517dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn *      complete}
527dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn *
537dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * <p>The <code>R.layout.fragment_pager</code> resource of the top-level fragment is:
547dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn *
557dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * {@sample development/samples/Support13Demos/res/layout/fragment_pager.xml
567dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn *      complete}
577dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn *
587dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * <p>The <code>R.layout.fragment_pager_list</code> resource containing each
597dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * individual fragment's layout is:
607dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn *
617dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * {@sample development/samples/Support13Demos/res/layout/fragment_pager_list.xml
627dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn *      complete}
630574ca37da4619afe4e26753f5a1b4de314b6565Svetoslav Ganov */
645c1637087453de15e31861f073eae5133c4e9f7bDianne Hackbornpublic abstract class FragmentStatePagerAdapter extends PagerAdapter {
655c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn    private static final String TAG = "FragmentStatePagerAdapter";
665c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn    private static final boolean DEBUG = false;
675c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn
685c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn    private final FragmentManager mFragmentManager;
695c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn    private FragmentTransaction mCurTransaction = null;
705c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn
715c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn    private ArrayList<Fragment.SavedState> mSavedState = new ArrayList<Fragment.SavedState>();
725c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn    private ArrayList<Fragment> mFragments = new ArrayList<Fragment>();
732a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    private Fragment mCurrentPrimaryItem = null;
745c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn
755c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn    public FragmentStatePagerAdapter(FragmentManager fm) {
765c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn        mFragmentManager = fm;
775c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn    }
785c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn
795c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn    /**
805c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn     * Return the Fragment associated with a specified position.
815c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn     */
825c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn    public abstract Fragment getItem(int position);
835c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn
845c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn    @Override
85583d8a1ff64c7c59dd4e11759f3d8e994ce878d9Adam Powell    public void startUpdate(ViewGroup container) {
865c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn    }
875c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn
885c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn    @Override
89583d8a1ff64c7c59dd4e11759f3d8e994ce878d9Adam Powell    public Object instantiateItem(ViewGroup container, int position) {
905c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn        // If we already have this item instantiated, there is nothing
915c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn        // to do.  This can happen when we are restoring the entire pager
925c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn        // from its saved state, where the fragment manager has already
935c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn        // taken care of restoring the fragments we previously had instantiated.
945c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn        if (mFragments.size() > position) {
955c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn            Fragment f = mFragments.get(position);
965c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn            if (f != null) {
975c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn                return f;
985c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn            }
995c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn        }
1005c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn
1015c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn        if (mCurTransaction == null) {
1025c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn            mCurTransaction = mFragmentManager.beginTransaction();
1035c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn        }
1045c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn
1055c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn        Fragment fragment = getItem(position);
1065c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn        if (DEBUG) Log.v(TAG, "Adding item #" + position + ": f=" + fragment);
1075c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn        if (mSavedState.size() > position) {
1085c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn            Fragment.SavedState fss = mSavedState.get(position);
1095c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn            if (fss != null) {
1105c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn                fragment.setInitialSavedState(fss);
1115c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn            }
1125c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn        }
1135c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn        while (mFragments.size() <= position) {
1145c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn            mFragments.add(null);
1155c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn        }
1162a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        fragment.setMenuVisibility(false);
1176d6186b9a2503200844febe1b8ba083206c7cbcdVeeti Paananen        fragment.setUserVisibleHint(false);
1185c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn        mFragments.set(position, fragment);
1195c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn        mCurTransaction.add(container.getId(), fragment);
1205c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn
1215c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn        return fragment;
1225c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn    }
1235c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn
1245c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn    @Override
125583d8a1ff64c7c59dd4e11759f3d8e994ce878d9Adam Powell    public void destroyItem(ViewGroup container, int position, Object object) {
1265c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn        Fragment fragment = (Fragment)object;
1275c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn
1285c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn        if (mCurTransaction == null) {
1295c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn            mCurTransaction = mFragmentManager.beginTransaction();
1305c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn        }
1315c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn        if (DEBUG) Log.v(TAG, "Removing item #" + position + ": f=" + object
1325c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn                + " v=" + ((Fragment)object).getView());
1335c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn        while (mSavedState.size() <= position) {
1345c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn            mSavedState.add(null);
1355c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn        }
1365c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn        mSavedState.set(position, mFragmentManager.saveFragmentInstanceState(fragment));
1375c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn        mFragments.set(position, null);
1385c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn
1395c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn        mCurTransaction.remove(fragment);
1405c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn    }
1415c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn
1425c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn    @Override
143583d8a1ff64c7c59dd4e11759f3d8e994ce878d9Adam Powell    public void setPrimaryItem(ViewGroup container, int position, Object object) {
1442a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        Fragment fragment = (Fragment)object;
1452a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        if (fragment != mCurrentPrimaryItem) {
1462a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            if (mCurrentPrimaryItem != null) {
1472a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                mCurrentPrimaryItem.setMenuVisibility(false);
1486d6186b9a2503200844febe1b8ba083206c7cbcdVeeti Paananen                mCurrentPrimaryItem.setUserVisibleHint(false);
1492a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            }
1502a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            if (fragment != null) {
1512a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                fragment.setMenuVisibility(true);
1526d6186b9a2503200844febe1b8ba083206c7cbcdVeeti Paananen                fragment.setUserVisibleHint(true);
1532a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            }
1542a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            mCurrentPrimaryItem = fragment;
1552a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        }
1562a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    }
1572a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn
1582a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    @Override
159583d8a1ff64c7c59dd4e11759f3d8e994ce878d9Adam Powell    public void finishUpdate(ViewGroup container) {
1605c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn        if (mCurTransaction != null) {
1612a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            mCurTransaction.commitAllowingStateLoss();
1625c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn            mCurTransaction = null;
1635c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn            mFragmentManager.executePendingTransactions();
1645c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn        }
1655c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn    }
1665c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn
1675c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn    @Override
1685c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn    public boolean isViewFromObject(View view, Object object) {
1695c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn        return ((Fragment)object).getView() == view;
1705c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn    }
1715c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn
1725c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn    @Override
1735c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn    public Parcelable saveState() {
1745c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn        Bundle state = null;
1755c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn        if (mSavedState.size() > 0) {
1765c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn            state = new Bundle();
1775c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn            Fragment.SavedState[] fss = new Fragment.SavedState[mSavedState.size()];
1785c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn            mSavedState.toArray(fss);
1795c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn            state.putParcelableArray("states", fss);
1805c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn        }
1815c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn        for (int i=0; i<mFragments.size(); i++) {
1825c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn            Fragment f = mFragments.get(i);
1835c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn            if (f != null) {
1845c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn                if (state == null) {
1855c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn                    state = new Bundle();
1865c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn                }
1875c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn                String key = "f" + i;
1885c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn                mFragmentManager.putFragment(state, key, f);
1895c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn            }
1905c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn        }
1915c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn        return state;
1925c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn    }
1935c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn
1945c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn    @Override
1955c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn    public void restoreState(Parcelable state, ClassLoader loader) {
1965c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn        if (state != null) {
1975c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn            Bundle bundle = (Bundle)state;
1985c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn            bundle.setClassLoader(loader);
1995c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn            Parcelable[] fss = bundle.getParcelableArray("states");
2005c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn            mSavedState.clear();
2015c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn            mFragments.clear();
2025c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn            if (fss != null) {
2035c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn                for (int i=0; i<fss.length; i++) {
2045c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn                    mSavedState.add((Fragment.SavedState)fss[i]);
2055c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn                }
2065c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn            }
2075c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn            Iterable<String> keys = bundle.keySet();
2085c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn            for (String key: keys) {
2095c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn                if (key.startsWith("f")) {
2105c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn                    int index = Integer.parseInt(key.substring(1));
2115c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn                    Fragment f = mFragmentManager.getFragment(bundle, key);
2125c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn                    if (f != null) {
2135c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn                        while (mFragments.size() <= index) {
2145c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn                            mFragments.add(null);
2155c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn                        }
2162a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                        f.setMenuVisibility(false);
2175c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn                        mFragments.set(index, f);
2185c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn                    } else {
2195c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn                        Log.w(TAG, "Bad fragment at key " + key);
2205c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn                    }
2215c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn                }
2225c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn            }
2235c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn        }
2245c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn    }
2255c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn}
226