2011-11-18 18:28:17 +00:00
|
|
|
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
|
2012-05-21 11:12:37 +00:00
|
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
2011-11-18 18:28:17 +00:00
|
|
|
|
|
|
|
package org.mozilla.gecko;
|
|
|
|
|
|
|
|
import android.content.Context;
|
2013-02-13 16:50:56 +00:00
|
|
|
import android.graphics.drawable.ColorDrawable;
|
2012-11-16 08:50:28 +00:00
|
|
|
import android.graphics.drawable.StateListDrawable;
|
2012-11-12 18:49:25 +00:00
|
|
|
import android.support.v4.view.PagerAdapter;
|
2013-04-08 07:51:56 +00:00
|
|
|
import android.support.v4.view.ViewPager;
|
2011-11-18 18:28:17 +00:00
|
|
|
import android.util.AttributeSet;
|
|
|
|
import android.util.Log;
|
|
|
|
import android.view.LayoutInflater;
|
|
|
|
import android.view.MotionEvent;
|
|
|
|
import android.view.View;
|
|
|
|
import android.view.ViewGroup;
|
|
|
|
import android.view.inputmethod.InputMethodManager;
|
|
|
|
import android.widget.TabHost;
|
2012-07-02 18:22:29 +00:00
|
|
|
import android.widget.TabWidget;
|
2011-11-18 18:28:17 +00:00
|
|
|
|
2012-12-26 19:10:43 +00:00
|
|
|
public class AwesomeBarTabs extends TabHost
|
|
|
|
implements LightweightTheme.OnChangeListener {
|
2011-11-18 18:28:17 +00:00
|
|
|
private static final String LOGTAG = "GeckoAwesomeBarTabs";
|
|
|
|
|
|
|
|
private Context mContext;
|
2012-12-26 19:10:43 +00:00
|
|
|
private GeckoActivity mActivity;
|
|
|
|
|
2011-12-07 23:12:51 +00:00
|
|
|
private boolean mInflated;
|
2012-03-27 17:05:41 +00:00
|
|
|
private LayoutInflater mInflater;
|
2011-11-18 18:28:17 +00:00
|
|
|
private OnUrlOpenListener mUrlOpenListener;
|
2012-06-28 18:21:24 +00:00
|
|
|
private View.OnTouchListener mListTouchListener;
|
2012-11-12 18:49:25 +00:00
|
|
|
private boolean mSearching = false;
|
2012-11-16 08:50:28 +00:00
|
|
|
private String mTarget;
|
2012-11-12 18:49:25 +00:00
|
|
|
private ViewPager mViewPager;
|
|
|
|
private AwesomePagerAdapter mPagerAdapter;
|
2011-11-18 18:28:17 +00:00
|
|
|
|
2013-04-13 12:34:13 +00:00
|
|
|
private AwesomeBarTab mTabs[];
|
2011-11-18 18:28:17 +00:00
|
|
|
|
|
|
|
public interface OnUrlOpenListener {
|
2012-12-28 21:46:08 +00:00
|
|
|
public void onUrlOpen(String url, String title);
|
2013-05-10 00:07:53 +00:00
|
|
|
public void onSearch(SearchEngine engine, String text);
|
2012-06-05 21:07:14 +00:00
|
|
|
public void onEditSuggestion(String suggestion);
|
2013-04-30 17:21:15 +00:00
|
|
|
public void onSwitchToTab(final int tabId);
|
2011-11-18 18:28:17 +00:00
|
|
|
}
|
|
|
|
|
2012-11-12 18:49:25 +00:00
|
|
|
private class AwesomePagerAdapter extends PagerAdapter {
|
|
|
|
public AwesomePagerAdapter() {
|
|
|
|
super();
|
|
|
|
}
|
|
|
|
|
2013-03-13 20:20:57 +00:00
|
|
|
@Override
|
2012-11-12 18:49:25 +00:00
|
|
|
public Object instantiateItem(ViewGroup group, int index) {
|
|
|
|
AwesomeBarTab tab = mTabs[index];
|
|
|
|
group.addView(tab.getView());
|
|
|
|
return tab;
|
|
|
|
}
|
|
|
|
|
2013-03-13 20:20:57 +00:00
|
|
|
@Override
|
2012-11-12 18:49:25 +00:00
|
|
|
public void destroyItem(ViewGroup group, int index, Object obj) {
|
|
|
|
AwesomeBarTab tab = (AwesomeBarTab)obj;
|
|
|
|
group.removeView(tab.getView());
|
|
|
|
}
|
|
|
|
|
2013-03-13 20:20:57 +00:00
|
|
|
@Override
|
2012-11-12 18:49:25 +00:00
|
|
|
public int getCount() {
|
|
|
|
if (mSearching)
|
|
|
|
return 1;
|
|
|
|
return mTabs.length;
|
|
|
|
}
|
|
|
|
|
2013-03-13 20:20:57 +00:00
|
|
|
@Override
|
2012-11-12 18:49:25 +00:00
|
|
|
public boolean isViewFromObject(View view, Object object) {
|
|
|
|
return getAwesomeBarTabForView(view) == object;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-06-18 19:39:13 +00:00
|
|
|
private AwesomeBarTab getCurrentAwesomeBarTab() {
|
2012-11-12 18:49:25 +00:00
|
|
|
int index = mViewPager.getCurrentItem();
|
|
|
|
return mTabs[index];
|
2012-06-18 19:39:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public AwesomeBarTab getAwesomeBarTabForView(View view) {
|
|
|
|
String tag = (String)view.getTag();
|
|
|
|
return getAwesomeBarTabForTag(tag);
|
|
|
|
}
|
2012-06-19 00:23:15 +00:00
|
|
|
|
2012-06-18 19:39:13 +00:00
|
|
|
public AwesomeBarTab getAwesomeBarTabForTag(String tag) {
|
|
|
|
for (AwesomeBarTab tab : mTabs) {
|
2012-11-12 18:49:25 +00:00
|
|
|
if (tag.equals(tab.getTag())) {
|
2012-06-18 19:39:13 +00:00
|
|
|
return tab;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
2012-06-19 00:23:15 +00:00
|
|
|
|
2012-06-18 19:39:13 +00:00
|
|
|
public boolean onBackPressed() {
|
|
|
|
AwesomeBarTab tab = getCurrentAwesomeBarTab();
|
|
|
|
if (tab == null)
|
|
|
|
return false;
|
|
|
|
return tab.onBackPressed();
|
2012-06-19 00:23:15 +00:00
|
|
|
}
|
|
|
|
|
2011-11-18 18:28:17 +00:00
|
|
|
public AwesomeBarTabs(Context context, AttributeSet attrs) {
|
|
|
|
super(context, attrs);
|
|
|
|
|
|
|
|
Log.d(LOGTAG, "Creating AwesomeBarTabs");
|
|
|
|
|
|
|
|
mContext = context;
|
2012-12-26 19:10:43 +00:00
|
|
|
mActivity = (GeckoActivity) context;
|
|
|
|
|
2011-12-07 23:12:51 +00:00
|
|
|
mInflated = false;
|
2012-03-27 17:05:41 +00:00
|
|
|
mInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
2011-12-07 23:12:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
protected void onFinishInflate() {
|
|
|
|
super.onFinishInflate();
|
2011-11-18 18:28:17 +00:00
|
|
|
|
2011-12-07 23:12:51 +00:00
|
|
|
// HACK: Without this, the onFinishInflate is called twice
|
|
|
|
// This issue is due to a bug when Android inflates a layout with a
|
|
|
|
// parent. Fixed in Honeycomb
|
|
|
|
if (mInflated)
|
|
|
|
return;
|
2011-11-18 18:28:17 +00:00
|
|
|
|
2011-12-07 23:12:51 +00:00
|
|
|
mInflated = true;
|
2011-11-18 18:28:17 +00:00
|
|
|
|
|
|
|
// This should be called before adding any tabs
|
|
|
|
// to the TabHost.
|
|
|
|
setup();
|
|
|
|
|
2012-06-28 18:21:24 +00:00
|
|
|
mListTouchListener = new View.OnTouchListener() {
|
2013-02-27 05:48:00 +00:00
|
|
|
@Override
|
2012-06-28 18:21:24 +00:00
|
|
|
public boolean onTouch(View view, MotionEvent event) {
|
2013-04-29 18:36:23 +00:00
|
|
|
if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
|
|
|
|
// take focus away from awesome bar to hide the keyboard
|
|
|
|
requestFocus();
|
|
|
|
}
|
2012-06-28 18:21:24 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2012-06-18 19:39:13 +00:00
|
|
|
mTabs = new AwesomeBarTab[] {
|
|
|
|
new AllPagesTab(mContext),
|
|
|
|
new BookmarksTab(mContext),
|
|
|
|
new HistoryTab(mContext)
|
|
|
|
};
|
|
|
|
|
2012-11-12 18:49:25 +00:00
|
|
|
final TabWidget tabWidget = (TabWidget) findViewById(android.R.id.tabs);
|
|
|
|
// hide the strip since we aren't using the TabHost...
|
|
|
|
tabWidget.setStripEnabled(false);
|
|
|
|
|
|
|
|
mViewPager = (ViewPager) findViewById(R.id.tabviewpager);
|
|
|
|
mPagerAdapter = new AwesomePagerAdapter();
|
|
|
|
mViewPager.setAdapter(mPagerAdapter);
|
2013-04-13 12:34:13 +00:00
|
|
|
|
2012-11-12 18:49:25 +00:00
|
|
|
mViewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
|
2013-03-13 20:20:57 +00:00
|
|
|
@Override
|
2012-11-12 18:49:25 +00:00
|
|
|
public void onPageScrollStateChanged(int state) { }
|
2013-03-13 20:20:57 +00:00
|
|
|
@Override
|
2012-11-12 18:49:25 +00:00
|
|
|
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { }
|
2013-03-13 20:20:57 +00:00
|
|
|
@Override
|
2012-11-12 18:49:25 +00:00
|
|
|
public void onPageSelected(int position) {
|
|
|
|
tabWidget.setCurrentTab(position);
|
|
|
|
styleSelectedTab();
|
2013-04-29 18:36:23 +00:00
|
|
|
// take focus away from awesome bar to hide the keyboard
|
|
|
|
requestFocus();
|
2012-11-12 18:49:25 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
for (int i = 0; i < mTabs.length; i++) {
|
2013-04-02 19:48:18 +00:00
|
|
|
mTabs[i].setListTouchListener(mListTouchListener);
|
2012-11-12 18:49:25 +00:00
|
|
|
addAwesomeTab(mTabs[i].getTag(),
|
|
|
|
mTabs[i].getTitleStringId(),
|
|
|
|
i);
|
2012-06-18 19:39:13 +00:00
|
|
|
}
|
2012-06-18 19:39:13 +00:00
|
|
|
|
2013-03-11 22:27:24 +00:00
|
|
|
// Initialize "All Pages" list with no filter
|
2013-04-17 16:13:49 +00:00
|
|
|
filter("", null);
|
2012-06-18 19:39:13 +00:00
|
|
|
}
|
|
|
|
|
2012-12-26 19:10:43 +00:00
|
|
|
@Override
|
|
|
|
public void onAttachedToWindow() {
|
|
|
|
super.onAttachedToWindow();
|
|
|
|
mActivity.getLightweightTheme().addListener(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onDetachedFromWindow() {
|
|
|
|
super.onDetachedFromWindow();
|
|
|
|
mActivity.getLightweightTheme().removeListener(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onLightweightThemeChanged() {
|
|
|
|
styleSelectedTab();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onLightweightThemeReset() {
|
|
|
|
styleSelectedTab();
|
|
|
|
}
|
|
|
|
|
2013-03-11 22:27:24 +00:00
|
|
|
public void setCurrentItemByTag(String tag) {
|
2013-04-13 12:34:13 +00:00
|
|
|
mViewPager.setCurrentItem(getTabIdByTag(tag));
|
|
|
|
}
|
|
|
|
|
|
|
|
public int getTabIdByTag(String tag) {
|
2013-03-11 22:27:24 +00:00
|
|
|
for (int i = 0; i < mTabs.length; i++) {
|
|
|
|
if (tag.equals(mTabs[i].getTag())) {
|
2013-04-13 12:34:13 +00:00
|
|
|
return i;
|
2013-03-11 22:27:24 +00:00
|
|
|
}
|
|
|
|
}
|
2013-04-13 12:34:13 +00:00
|
|
|
return -1;
|
2013-03-11 22:27:24 +00:00
|
|
|
}
|
|
|
|
|
2012-07-02 18:22:29 +00:00
|
|
|
private void styleSelectedTab() {
|
2012-11-12 18:49:25 +00:00
|
|
|
int selIndex = mViewPager.getCurrentItem();
|
2012-07-02 18:22:29 +00:00
|
|
|
TabWidget tabWidget = getTabWidget();
|
2012-12-26 19:10:43 +00:00
|
|
|
boolean isPrivate = false;
|
|
|
|
|
|
|
|
if (mTarget != null && mTarget.equals(AwesomeBar.Target.CURRENT_TAB.name())) {
|
|
|
|
Tab tab = Tabs.getInstance().getSelectedTab();
|
|
|
|
if (tab != null)
|
|
|
|
isPrivate = tab.isPrivate();
|
|
|
|
}
|
2012-11-16 08:50:28 +00:00
|
|
|
|
2012-07-02 18:22:29 +00:00
|
|
|
for (int i = 0; i < tabWidget.getTabCount(); i++) {
|
2012-11-16 08:50:28 +00:00
|
|
|
GeckoTextView view = (GeckoTextView) tabWidget.getChildTabViewAt(i);
|
2012-12-26 19:10:43 +00:00
|
|
|
if (isPrivate) {
|
2013-02-26 23:32:53 +00:00
|
|
|
view.resetTheme();
|
2012-12-26 19:10:43 +00:00
|
|
|
view.setPrivateMode((i == selIndex) ? false : true);
|
|
|
|
} else {
|
|
|
|
if (i == selIndex)
|
|
|
|
view.resetTheme();
|
|
|
|
else if (mActivity.getLightweightTheme().isEnabled())
|
|
|
|
view.setTheme(mActivity.getLightweightTheme().isLightTheme());
|
|
|
|
else
|
|
|
|
view.resetTheme();
|
2012-11-16 08:50:28 +00:00
|
|
|
}
|
|
|
|
|
2013-03-02 03:19:14 +00:00
|
|
|
if (i < (selIndex - 1))
|
|
|
|
view.getBackground().setLevel(3);
|
|
|
|
else if (i == (selIndex - 1))
|
2012-11-16 08:50:28 +00:00
|
|
|
view.getBackground().setLevel(1);
|
|
|
|
else if (i == (selIndex + 1))
|
|
|
|
view.getBackground().setLevel(2);
|
2013-03-02 03:19:14 +00:00
|
|
|
else if (i > (selIndex + 1))
|
|
|
|
view.getBackground().setLevel(4);
|
2012-07-02 18:22:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (selIndex == 0)
|
|
|
|
findViewById(R.id.tab_widget_left).getBackground().setLevel(1);
|
|
|
|
else
|
|
|
|
findViewById(R.id.tab_widget_left).getBackground().setLevel(0);
|
|
|
|
|
|
|
|
if (selIndex == (tabWidget.getTabCount() - 1))
|
|
|
|
findViewById(R.id.tab_widget_right).getBackground().setLevel(2);
|
|
|
|
else
|
|
|
|
findViewById(R.id.tab_widget_right).getBackground().setLevel(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-11-12 18:49:25 +00:00
|
|
|
private View addAwesomeTab(String id, int titleId, final int contentId) {
|
2012-11-16 08:50:28 +00:00
|
|
|
GeckoTextView indicatorView = (GeckoTextView) mInflater.inflate(R.layout.awesomebar_tab_indicator, null);
|
2012-07-02 18:22:29 +00:00
|
|
|
indicatorView.setText(titleId);
|
2011-11-18 18:28:17 +00:00
|
|
|
|
2012-11-12 18:49:25 +00:00
|
|
|
getTabWidget().addView(indicatorView);
|
|
|
|
|
|
|
|
// this MUST be done after tw.addView to overwrite the listener added by tabWidget
|
|
|
|
// which delegates to TabHost (which we don't have)
|
|
|
|
indicatorView.setOnClickListener(new View.OnClickListener() {
|
2013-02-27 05:48:00 +00:00
|
|
|
@Override
|
2012-11-12 18:49:25 +00:00
|
|
|
public void onClick(View v) {
|
|
|
|
mViewPager.setCurrentItem(contentId, true);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
return indicatorView;
|
2011-11-18 18:28:17 +00:00
|
|
|
}
|
|
|
|
|
2012-06-19 00:23:15 +00:00
|
|
|
public void setOnUrlOpenListener(OnUrlOpenListener listener) {
|
|
|
|
mUrlOpenListener = listener;
|
2012-06-18 19:39:13 +00:00
|
|
|
for (AwesomeBarTab tab : mTabs) {
|
|
|
|
tab.setUrlListener(listener);
|
|
|
|
}
|
2012-06-18 19:39:13 +00:00
|
|
|
}
|
|
|
|
|
2012-06-19 00:23:15 +00:00
|
|
|
public void destroy() {
|
2012-06-18 19:39:13 +00:00
|
|
|
for (AwesomeBarTab tab : mTabs) {
|
|
|
|
tab.destroy();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public AllPagesTab getAllPagesTab() {
|
|
|
|
return (AllPagesTab)getAwesomeBarTabForTag("allPages");
|
|
|
|
}
|
|
|
|
|
|
|
|
public BookmarksTab getBookmarksTab() {
|
|
|
|
return (BookmarksTab)getAwesomeBarTabForTag("bookmarks");
|
|
|
|
}
|
|
|
|
|
|
|
|
public HistoryTab getHistoryTab() {
|
|
|
|
return (HistoryTab)getAwesomeBarTabForTag("history");
|
2011-11-18 18:28:17 +00:00
|
|
|
}
|
|
|
|
|
2013-04-17 16:13:49 +00:00
|
|
|
public void filter(String searchTerm, AutocompleteHandler handler) {
|
2011-11-18 18:28:17 +00:00
|
|
|
|
2013-04-13 12:34:13 +00:00
|
|
|
// If searching, disable left / right tab swipes
|
2012-11-12 18:49:25 +00:00
|
|
|
mSearching = searchTerm.length() != 0;
|
2013-04-13 12:34:13 +00:00
|
|
|
|
2012-11-12 18:49:25 +00:00
|
|
|
// reset the pager adapter to force repopulating the cache
|
|
|
|
mViewPager.setAdapter(mPagerAdapter);
|
2013-04-13 12:34:13 +00:00
|
|
|
|
|
|
|
// Ensure the 'All Pages' tab is selected
|
|
|
|
AllPagesTab allPages = getAllPagesTab();
|
|
|
|
getTabWidget().setCurrentTab(getTabIdByTag(allPages.getTag()));
|
|
|
|
styleSelectedTab();
|
2011-11-18 18:28:17 +00:00
|
|
|
|
|
|
|
// Perform the actual search
|
2013-04-17 16:13:49 +00:00
|
|
|
allPages.filter(searchTerm, handler);
|
2013-04-13 12:34:13 +00:00
|
|
|
|
|
|
|
// If searching, hide the tabs bar
|
|
|
|
findViewById(R.id.tab_widget_container).setVisibility(mSearching ? View.GONE : View.VISIBLE);
|
2011-12-08 01:52:07 +00:00
|
|
|
}
|
|
|
|
|
2012-06-02 18:23:45 +00:00
|
|
|
public boolean isInReadingList() {
|
2012-06-18 19:39:13 +00:00
|
|
|
return getBookmarksTab().isInReadingList();
|
2012-06-02 18:23:45 +00:00
|
|
|
}
|
2012-11-01 05:12:45 +00:00
|
|
|
|
2012-11-16 08:50:28 +00:00
|
|
|
public void setTarget(String target) {
|
|
|
|
mTarget = target;
|
|
|
|
styleSelectedTab();
|
|
|
|
if (mTarget.equals(AwesomeBar.Target.CURRENT_TAB.name())) {
|
|
|
|
Tab tab = Tabs.getInstance().getSelectedTab();
|
|
|
|
if (tab != null && tab.isPrivate())
|
2013-02-25 20:15:00 +00:00
|
|
|
((BackgroundLayout) findViewById(R.id.tab_widget_container)).setPrivateMode(true);
|
2012-11-16 08:50:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-02-26 23:32:53 +00:00
|
|
|
public static class BackgroundLayout extends GeckoLinearLayout {
|
2012-11-01 05:12:45 +00:00
|
|
|
private GeckoActivity mActivity;
|
|
|
|
|
2013-02-25 20:15:00 +00:00
|
|
|
public BackgroundLayout(Context context, AttributeSet attrs) {
|
2012-11-01 05:12:45 +00:00
|
|
|
super(context, attrs);
|
|
|
|
mActivity = (GeckoActivity) context;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onLightweightThemeChanged() {
|
2012-12-13 21:13:36 +00:00
|
|
|
LightweightThemeDrawable drawable = mActivity.getLightweightTheme().getColorDrawable(this);
|
2012-11-01 05:12:45 +00:00
|
|
|
if (drawable == null)
|
|
|
|
return;
|
|
|
|
|
2012-12-13 21:13:36 +00:00
|
|
|
drawable.setAlpha(255, 0);
|
|
|
|
|
|
|
|
StateListDrawable stateList = new StateListDrawable();
|
2013-02-26 23:32:53 +00:00
|
|
|
stateList.addState(new int[] { R.attr.state_private }, new ColorDrawable(mActivity.getResources().getColor(R.color.background_private)));
|
2012-12-13 21:13:36 +00:00
|
|
|
stateList.addState(new int[] {}, drawable);
|
2012-11-16 08:50:28 +00:00
|
|
|
|
2012-11-01 05:12:45 +00:00
|
|
|
int[] padding = new int[] { getPaddingLeft(),
|
|
|
|
getPaddingTop(),
|
|
|
|
getPaddingRight(),
|
|
|
|
getPaddingBottom()
|
|
|
|
};
|
2012-11-16 08:50:28 +00:00
|
|
|
setBackgroundDrawable(stateList);
|
2012-11-01 05:12:45 +00:00
|
|
|
setPadding(padding[0], padding[1], padding[2], padding[3]);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onLightweightThemeReset() {
|
|
|
|
int[] padding = new int[] { getPaddingLeft(),
|
|
|
|
getPaddingTop(),
|
|
|
|
getPaddingRight(),
|
|
|
|
getPaddingBottom()
|
|
|
|
};
|
2013-02-13 16:50:56 +00:00
|
|
|
setBackgroundResource(R.drawable.address_bar_bg);
|
2012-11-01 05:12:45 +00:00
|
|
|
setPadding(padding[0], padding[1], padding[2], padding[3]);
|
|
|
|
}
|
|
|
|
}
|
2011-11-18 18:28:17 +00:00
|
|
|
}
|